This patch fails checkpatch.pl --strict.
On Sun, Oct 30, 2011 at 09:56:01AM +0100, Antonio Quartulli wrote:
> +bool arp_snoop_outgoing_request(struct bat_priv *bat_priv, struct sk_buff *skb)
> [...]
> + arp_neigh_update(bat_priv, ip_src, hw_src);
> +
> + n = neigh_lookup(&arp_tbl, &ip_dst, primary_if->soft_iface);
> + /* check if it is a valid neigh entry */
> + if (n && (n->nud_state & NUD_CONNECTED)) {
> + skb_new = arp_create(ARPOP_REPLY, ETH_P_ARP, ip_src,
> + primary_if->soft_iface, ip_dst, hw_src, n->ha,
> + hw_src);
> + unicast_send_skb(skb_new, bat_priv);
> + bat_dbg(DBG_ARP, bat_priv, "ARP request replied locally\n");
This function is hooked up in the tx patch, why do we send the unicast reply to
the mesh? Shouldn't it be sent on the soft interface instead? I don't really understand this one ...
> + } else
> + /* Send the request on the DHT */
> + ret = dht_send_data(bat_priv, skb, ip_dst);
> + if (n)
> + neigh_release(n);
> +out:
> + if (primary_if)
> + hardif_free_ref(primary_if);
> + return ret;
> +}
> +
> diff --git a/routing.c b/routing.c
> index ef24a72..4f2b417 100644
> --- a/routing.c
> +++ b/routing.c
> @@ -965,6 +966,7 @@ int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
> /* packet for me */
> if (is_my_mac(unicast_packet->dest)) {
> interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size);
> +
> return NET_RX_SUCCESS;
> }
>
This added newline is useless.
On Mon, Oct 31, 2011 at 01:12:21AM +0100, Simon Wunderlich wrote:
> This patch fails checkpatch.pl --strict.
>
> On Sun, Oct 30, 2011 at 09:56:01AM +0100, Antonio Quartulli wrote:
> > +bool arp_snoop_outgoing_request(struct bat_priv *bat_priv, struct sk_buff *skb)
> > [...]
> > + arp_neigh_update(bat_priv, ip_src, hw_src);
> > +
> > + n = neigh_lookup(&arp_tbl, &ip_dst, primary_if->soft_iface);
> > + /* check if it is a valid neigh entry */
> > + if (n && (n->nud_state & NUD_CONNECTED)) {
> > + skb_new = arp_create(ARPOP_REPLY, ETH_P_ARP, ip_src,
> > + primary_if->soft_iface, ip_dst, hw_src, n->ha,
> > + hw_src);
> > + unicast_send_skb(skb_new, bat_priv);
> > + bat_dbg(DBG_ARP, bat_priv, "ARP request replied locally\n");
>
> This function is hooked up in the tx patch, why do we send the unicast reply to
> the mesh? Shouldn't it be sent on the soft interface instead? I don't really understand this one ...
You are right. As we have already discussed on IRC, I should use netif_rx()
directly here (to deliver the packet to the soft_iface).
> > if (is_my_mac(unicast_packet->dest)) {
> > interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size);
> > +
> > return NET_RX_SUCCESS;
> > }
> >
>
> This added newline is useless.
Yeah :D
Thanks,
@@ -25,7 +25,7 @@ ifeq ($(MAKING_MODULES),1)
-include $(TOPDIR)/Rules.make
endif
-# ccflags-y += -DCONFIG_BATMAN_ADV_DEBUG
+ccflags-y += -DCONFIG_BATMAN_ADV_DEBUG
ifneq ($(REVISION),)
ccflags-y += -DSOURCE_VERSION=\"$(REVISION)\"
@@ -21,6 +21,8 @@
#include <linux/if_ether.h>
#include <linux/if_arp.h>
+/* needed to use arp_tbl */
+#include <net/arp.h>
#include "main.h"
#include "arp.h"
@@ -184,6 +186,31 @@ out:
return ret;
}
+/* Update the neighbour entry corresponding to the IP passed as parameter with
+ * the hw address hw. If the neighbour entry doesn't exists, then it will be
+ * created */
+static void arp_neigh_update(struct bat_priv *bat_priv, uint32_t ip,
+ uint8_t *hw)
+{
+ struct neighbour *n = NULL;
+ struct hard_iface *primary_if = primary_if_get_selected(bat_priv);
+ if (!primary_if)
+ goto out;
+
+ n = __neigh_lookup(&arp_tbl, &ip, primary_if->soft_iface, 1);
+ if (!n)
+ goto out;
+
+ bat_dbg(DBG_ARP, bat_priv, "Updating neighbour: %pI4 - %pM\n", &ip, hw);
+
+ neigh_update(n, hw, NUD_CONNECTED, NEIGH_UPDATE_F_OVERRIDE);
+out:
+ if (n && !IS_ERR(n))
+ neigh_release(n);
+ if (primary_if)
+ hardif_free_ref(primary_if);
+}
+
/* Returns arphdr->ar_op if the skb contains a valid ARP packet, otherwise
* returns 0 */
uint16_t arp_get_type(struct bat_priv *bat_priv, struct sk_buff *skb)
@@ -200,7 +227,7 @@ uint16_t arp_get_type(struct bat_priv *bat_priv, struct sk_buff *skb)
if (ethhdr->h_proto != htons(ETH_P_ARP))
goto out;
- if (unlikely(!pskb_may_pull(skb, ETH_HLEN + arp_hdr_len(skb->dev) + 8 + 12)))
+ if (unlikely(!pskb_may_pull(skb, ETH_HLEN + arp_hdr_len(skb->dev))))
goto out;
arphdr = (struct arphdr *)(skb->data + sizeof(struct ethhdr));
@@ -226,3 +253,169 @@ uint16_t arp_get_type(struct bat_priv *bat_priv, struct sk_buff *skb)
out:
return type;
}
+
+/* return true if the message has been sent to the dht candidates, false
+ * otherwise. In case of true the message has to be enqueued to permit the
+ * fallback */
+bool arp_snoop_outgoing_request(struct bat_priv *bat_priv, struct sk_buff *skb)
+{
+ uint16_t type = 0;
+ uint32_t ip_dst, ip_src;
+ uint8_t *hw_src;
+ bool ret = false;
+ struct neighbour *n = NULL;
+ struct hard_iface *primary_if = NULL;
+ struct sk_buff *skb_new;
+
+ type = arp_get_type(bat_priv, skb);
+ /* If we get an ARP_REQUEST we have to send the unicast message to the
+ * selected DHT candidates */
+ if (type != ARPOP_REQUEST)
+ goto out;
+
+ bat_dbg(DBG_ARP, bat_priv, "Snooped outgoing ARP request\n");
+
+ ip_src = ARP_IP_SRC(skb);
+ hw_src = ARP_HW_SRC(skb);
+ ip_dst = ARP_IP_DST(skb);
+
+ primary_if = primary_if_get_selected(bat_priv);
+ if (!primary_if)
+ goto out;
+
+ arp_neigh_update(bat_priv, ip_src, hw_src);
+
+ n = neigh_lookup(&arp_tbl, &ip_dst, primary_if->soft_iface);
+ /* check if it is a valid neigh entry */
+ if (n && (n->nud_state & NUD_CONNECTED)) {
+ skb_new = arp_create(ARPOP_REPLY, ETH_P_ARP, ip_src,
+ primary_if->soft_iface, ip_dst, hw_src, n->ha,
+ hw_src);
+ unicast_send_skb(skb_new, bat_priv);
+ bat_dbg(DBG_ARP, bat_priv, "ARP request replied locally\n");
+ } else
+ /* Send the request on the DHT */
+ ret = dht_send_data(bat_priv, skb, ip_dst);
+ if (n)
+ neigh_release(n);
+out:
+ if (primary_if)
+ hardif_free_ref(primary_if);
+ return ret;
+}
+
+/* This function is meant to be invoked for an ARP request which is coming into
+ * the bat0 interfaces from the mesh network. It will check for the needed data
+ * into the local table. If found, an ARP reply is sent immediatly, otherwise the
+ * caller has to deliver the ARP request to the upper layer */
+bool arp_snoop_incoming_request(struct bat_priv *bat_priv, struct sk_buff *skb)
+{
+ uint16_t type;
+ uint32_t ip_src, ip_dst;
+ uint8_t *hw_src;
+ struct hard_iface *primary_if = NULL;
+ struct sk_buff *skb_new;
+ struct neighbour *n = NULL;
+ bool ret = false;
+
+ type = arp_get_type(bat_priv, skb);
+ if (type != ARPOP_REQUEST)
+ goto out;
+
+ hw_src = ARP_HW_SRC(skb);
+ ip_src = ARP_IP_SRC(skb);
+ ip_dst = ARP_IP_DST(skb);
+
+ bat_dbg(DBG_ARP, bat_priv, "Snooped incoming ARP request\n");
+
+ primary_if = primary_if_get_selected(bat_priv);
+ if (!primary_if)
+ goto out;
+
+ arp_neigh_update(bat_priv, ip_src, hw_src);
+
+ n = neigh_lookup(&arp_tbl, &ip_dst, primary_if->soft_iface);
+ /* check if it is a valid neigh entry */
+ if (!n || !(n->nud_state & NUD_CONNECTED))
+ goto out;
+
+ skb_new = arp_create(ARPOP_REPLY, ETH_P_ARP, ip_src,
+ primary_if->soft_iface, ip_dst, hw_src, n->ha,
+ hw_src);
+
+ unicast_send_skb(skb_new, bat_priv);
+
+ ret = true;
+out:
+ if (n)
+ neigh_release(n);
+ if (primary_if)
+ hardif_free_ref(primary_if);
+ if (ret)
+ kfree_skb(skb);
+ return ret;
+}
+
+/* This function is meant to be invoked on an ARP reply packet going into the
+ * soft interface. The related neighbour entry has to be updated and the DHT has
+ * to be populated as well */
+bool arp_snoop_outgoing_reply(struct bat_priv *bat_priv, struct sk_buff *skb)
+{
+ uint16_t type;
+ uint32_t ip_src, ip_dst;
+ uint8_t *hw_src, *hw_dst;
+ bool ret = false;
+
+ type = arp_get_type(bat_priv, skb);
+ if (type != ARPOP_REPLY)
+ goto out;
+
+ bat_dbg(DBG_ARP, bat_priv, "Snooped outgoing ARP reply\n");
+
+ hw_src = ARP_HW_SRC(skb);
+ ip_src = ARP_IP_SRC(skb);
+ hw_dst = ARP_HW_DST(skb);
+ ip_dst = ARP_IP_DST(skb);
+
+
+ arp_neigh_update(bat_priv, ip_src, hw_src);
+ arp_neigh_update(bat_priv, ip_dst, hw_dst);
+
+ /* Send the ARP reply to the candidates for both the IP addresses we
+ * fetched from the ARP reply */
+ dht_send_data(bat_priv, skb, ip_src);
+ dht_send_data(bat_priv, skb, ip_dst);
+ ret = true;
+out:
+ return ret;
+}
+
+/* This function has to be invoked on an ARP reply coming into the soft
+ * interface from the mesh network. The local table has to be updated */
+bool arp_snoop_incoming_reply(struct bat_priv *bat_priv, struct sk_buff *skb)
+{
+ uint16_t type;
+ uint32_t ip_src, ip_dst;
+ uint8_t *hw_src, *hw_dst;
+ bool ret = false;
+
+ type = arp_get_type(bat_priv, skb);
+ if (type != ARPOP_REPLY)
+ goto out;
+
+ bat_dbg(DBG_ARP, bat_priv, "Snooped incoming ARP reply\n");
+
+ hw_src = ARP_HW_SRC(skb);
+ ip_src = ARP_IP_SRC(skb);
+ hw_dst = ARP_HW_DST(skb);
+ ip_dst = ARP_IP_DST(skb);
+
+ /* Update our internal cache with both the IP addresses we fetched from
+ * the ARP reply */
+ arp_neigh_update(bat_priv, ip_src, hw_src);
+ arp_neigh_update(bat_priv, ip_dst, hw_dst);
+
+ ret = true;
+out:
+ return ret;
+}
@@ -28,6 +28,12 @@
#define ARP_IP_DST(skb) (*(uint32_t *)(ARP_HW_SRC(skb) + ETH_ALEN * 2 + 4))
uint16_t arp_get_type(struct bat_priv *bat_priv, struct sk_buff *skb);
+bool arp_snoop_outgoing_request(struct bat_priv *bat_priv,
+ struct sk_buff *skb);
+bool arp_snoop_incoming_request(struct bat_priv *bat_priv,
+ struct sk_buff *skb);
+bool arp_snoop_outgoing_reply(struct bat_priv *bat_priv, struct sk_buff *skb);
+bool arp_snoop_incoming_reply(struct bat_priv *bat_priv, struct sk_buff *skb);
/* hash function to choose an entry in a hash table of given size */
/* hash algorithm from http://en.wikipedia.org/wiki/Hash_table */
@@ -64,6 +64,8 @@
#define NULL_IFINDEX 0 /* dummy ifindex used to avoid iface checks */
+/* msecs after which an ARP_REQUEST is sent in broadcast as fallback */
+#define ARP_REQ_DELAY 250
/* numbers of originator to contact for any STORE/GET DHT operation */
#define DHT_CANDIDATES_NUM 3
@@ -20,6 +20,7 @@
*/
#include "main.h"
+#include "arp.h"
#include "routing.h"
#include "send.h"
#include "soft-interface.h"
@@ -965,6 +966,7 @@ int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
/* packet for me */
if (is_my_mac(unicast_packet->dest)) {
interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size);
+
return NET_RX_SUCCESS;
}
@@ -20,6 +20,7 @@
*/
#include "main.h"
+#include "arp.h"
#include "send.h"
#include "routing.h"
#include "translation-table.h"
@@ -30,6 +31,8 @@
#include "originator.h"
#include "bat_ogm.h"
+#include <net/arp.h>
+
static void send_outstanding_bcast_packet(struct work_struct *work);
/* send out an already prepared packet to the given address via the
@@ -267,6 +270,7 @@ static void send_outstanding_bcast_packet(struct work_struct *work)
struct sk_buff *skb1;
struct net_device *soft_iface = forw_packet->if_incoming->soft_iface;
struct bat_priv *bat_priv = netdev_priv(soft_iface);
+ struct neighbour *n;
spin_lock_bh(&bat_priv->forw_bcast_list_lock);
hlist_del(&forw_packet->list);
@@ -275,6 +279,20 @@ static void send_outstanding_bcast_packet(struct work_struct *work)
if (atomic_read(&bat_priv->mesh_state) == MESH_DEACTIVATING)
goto out;
+ /* If this packet is an ARP_REQUEST and we already have the information
+ * that it is going to ask, we can drop the packet */
+ if (!forw_packet->num_packets &&
+ (arp_get_type(bat_priv, forw_packet->skb) ==
+ ARPOP_REQUEST)) {
+ n = neigh_lookup(&arp_tbl, &ARP_IP_DST(forw_packet->skb),
+ soft_iface);
+ /* check if we already know this neigh */
+ if (n && (n->nud_state & NUD_CONNECTED))
+ goto out;
+
+ bat_dbg(DBG_ARP, bat_priv, "ARP request: fallback\n");
+ }
+
/* rebroadcast packet */
rcu_read_lock();
list_for_each_entry_rcu(hard_iface, &hardif_list, list) {
@@ -565,9 +565,12 @@ static int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
struct vlan_ethhdr *vhdr;
struct softif_neigh *curr_softif_neigh = NULL;
unsigned int header_len = 0;
+ struct orig_node *orig_node = NULL;
+ struct sk_buff *arp_skb = NULL;
int data_len = skb->len, ret;
short vid = -1;
bool do_bcast = false;
+ unsigned long brd_delay = 1;
if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE)
goto dropped;
@@ -629,6 +632,9 @@ static int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
if (!primary_if)
goto dropped;
+ if (arp_snoop_outgoing_request(bat_priv, skb))
+ brd_delay = msecs_to_jiffies(ARP_REQ_DELAY);
+
if (my_skb_head_push(skb, sizeof(*bcast_packet)) < 0)
goto dropped;
@@ -648,7 +654,7 @@ static int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
bcast_packet->seqno =
htonl(atomic_inc_return(&bat_priv->bcast_seqno));
- add_bcast_packet_to_list(bat_priv, skb, 1);
+ add_bcast_packet_to_list(bat_priv, skb, brd_delay);
/* a copy is stored in the bcast list, therefore removing
* the original skb. */
@@ -662,7 +668,12 @@ static int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
goto dropped;
}
+ /* Increase the refcount to avoid to make the kernel consume
+ * the skb */
+ arp_skb = skb_clone(skb, GFP_ATOMIC);
ret = unicast_send_skb(skb, bat_priv);
+
+ arp_snoop_outgoing_reply(bat_priv, arp_skb);
if (ret != 0)
goto dropped_freed;
}
@@ -680,6 +691,10 @@ end:
softif_neigh_free_ref(curr_softif_neigh);
if (primary_if)
hardif_free_ref(primary_if);
+ if (orig_node)
+ orig_node_free_ref(orig_node);
+ if (arp_skb)
+ kfree_skb(arp_skb);
return NETDEV_TX_OK;
}
@@ -717,6 +732,11 @@ void interface_rx(struct net_device *soft_iface,
goto dropped;
}
+ if (arp_snoop_incoming_request(bat_priv, skb))
+ goto out;
+
+ arp_snoop_incoming_reply(bat_priv, skb);
+
/**
* if we have a another chosen mesh exit node in range
* it will transport the packets to the non-mesh network