From patchwork Sun Feb 26 18:23:21 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Antonio Quartulli X-Patchwork-Id: 1559 Return-Path: Received: from confino.investici.org (investici.nine.ch [217.150.252.179]) by open-mesh.org (Postfix) with ESMTPS id 6ECFD60080C for ; Sun, 26 Feb 2012 19:24:53 +0100 (CET) Authentication-Results: open-mesh.org; dkim=pass (1024-bit key) header.i=@autistici.org; dkim-adsp=pass Received: from [217.150.252.179] (confino [217.150.252.179]) (Authenticated sender: ordex@autistici.org) by localhost (Postfix) with ESMTPSA id CD80DC8660; Sun, 26 Feb 2012 18:24:52 +0000 (UTC) X-DKIM: Sendmail DKIM Filter v2.8.2 confino.investici.org CD80DC8660 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=autistici.org; s=stigmate; t=1330280693; bh=mCuk4WOdoPHRaBqLc7nro22EFWR/VsXh8Noq4a+bIs4=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=fxxqcN4oFRmPP1Udc6HuAimibfmvwz4lfHZAxsYLAuq8FTewwmSHc7qCjzL9JTx/d dpJr1jyvWQXNYa4OceBuVQdu/qGyGOpJ00FBSzKTlbDVId0Zzxys5HnqpvqjpPUVLw D54uLnc5TuOiHJNiNAGycU8FH5/l8c9xf5Z2UOYM= From: Antonio Quartulli To: b.a.t.m.a.n@lists.open-mesh.org Date: Sun, 26 Feb 2012 19:23:21 +0100 Message-Id: <1330280603-25510-6-git-send-email-ordex@autistici.org> X-Mailer: git-send-email 1.7.3.4 In-Reply-To: <1330280603-25510-1-git-send-email-ordex@autistici.org> References: <1330280603-25510-1-git-send-email-ordex@autistici.org> Subject: [B.A.T.M.A.N.] [PATCHv7 5/7] batman-adv: Distributed ARP Table - add snooping functions for ARP messages X-BeenThere: b.a.t.m.a.n@lists.open-mesh.org X-Mailman-Version: 2.1.13 Precedence: list Reply-To: The list for a Better Approach To Mobile Ad-hoc Networking List-Id: The list for a Better Approach To Mobile Ad-hoc Networking List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 26 Feb 2012 18:24:53 -0000 In case of an ARP message going in or out the soft_iface, it is intercepted and a special action is performed. In particular the DHT helper functions previously implemented are used to store all the ARP entries belonging to the network in order to provide a fast and unicast lookup instead of the classic broadcast flooding mechanism. Each node stores the entries it is responsible for (following the DHT rules) in its soft_iface ARP table. This makes it possible to reuse the kernel data structures and functions for ARP management. Signed-off-by: Antonio Quartulli --- distributed-arp-table.c | 246 +++++++++++++++++++++++++++++++++++++++++++++++ distributed-arp-table.h | 11 ++ main.h | 2 + send.c | 4 + soft-interface.c | 18 ++++- 5 files changed, 280 insertions(+), 1 deletions(-) diff --git a/distributed-arp-table.c b/distributed-arp-table.c index a436e5d..148481e 100644 --- a/distributed-arp-table.c +++ b/distributed-arp-table.c @@ -21,6 +21,8 @@ #include #include +/* needed to use arp_tbl */ +#include #include "main.h" #include "distributed-arp-table.h" @@ -28,6 +30,7 @@ #include "originator.h" #include "send.h" #include "types.h" +#include "translation-table.h" #include "unicast.h" #ifdef CONFIG_BATMAN_ADV_DEBUG @@ -262,6 +265,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_REACHABLE, 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 */ static uint16_t arp_get_type(struct bat_priv *bat_priv, struct sk_buff *skb, @@ -313,3 +341,221 @@ static 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 dat_snoop_outgoing_arp_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, 0); + /* 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_arp(bat_priv, skb, type, 0, "Parsing outgoing ARP REQUEST"); + + ip_src = ARP_IP_SRC(skb, 0); + hw_src = ARP_HW_SRC(skb, 0); + ip_dst = ARP_IP_DST(skb, 0); + + 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); + if (!skb_new) + goto out; + + skb_reset_mac_header(skb_new); + skb_new->protocol = eth_type_trans(skb_new, + primary_if->soft_iface); + bat_priv->stats.rx_packets++; + bat_priv->stats.rx_bytes += skb->len + ETH_HLEN; + primary_if->soft_iface->last_rx = jiffies; + + netif_rx(skb_new); + 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, BAT_P_DAT_DHT_GET); +out: + if (n) + neigh_release(n); + 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 immediately, otherwise + * the caller has to deliver the ARP request to the upper layer */ +bool dat_snoop_incoming_arp_request(struct bat_priv *bat_priv, + struct sk_buff *skb, int hdr_size) +{ + 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, hdr_size); + if (type != ARPOP_REQUEST) + goto out; + + hw_src = ARP_HW_SRC(skb, hdr_size); + ip_src = ARP_IP_SRC(skb, hdr_size); + ip_dst = ARP_IP_DST(skb, hdr_size); + + bat_dbg_arp(bat_priv, skb, type, hdr_size, + "Parsing incoming ARP REQUEST"); + + 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); + + if (!skb_new) + goto out; + + unicast_4addr_send_skb(skb_new, bat_priv, BAT_P_DAT_CACHE_REPLY); + + 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 dat_snoop_outgoing_arp_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, 0); + if (type != ARPOP_REPLY) + goto out; + + bat_dbg_arp(bat_priv, skb, type, 0, "Parsing outgoing ARP REPLY"); + + hw_src = ARP_HW_SRC(skb, 0); + ip_src = ARP_IP_SRC(skb, 0); + hw_dst = ARP_HW_DST(skb, 0); + ip_dst = ARP_IP_DST(skb, 0); + + 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, BAT_P_DAT_DHT_PUT); + dht_send_data(bat_priv, skb, ip_dst, BAT_P_DAT_DHT_PUT); + 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 dat_snoop_incoming_arp_reply(struct bat_priv *bat_priv, + struct sk_buff *skb, int hdr_size) +{ + 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, hdr_size); + if (type != ARPOP_REPLY) + goto out; + + bat_dbg_arp(bat_priv, skb, type, hdr_size, + "Parsing incoming ARP REPLY"); + + hw_src = ARP_HW_SRC(skb, hdr_size); + ip_src = ARP_IP_SRC(skb, hdr_size); + hw_dst = ARP_HW_DST(skb, hdr_size); + ip_dst = ARP_IP_DST(skb, hdr_size); + + /* 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); + + /* if this REPLY is directed to a client of mine, let's deliver the + * packet to the interface */ + ret = !is_my_client(bat_priv, hw_dst); +out: + /* if ret == false packet has to be delivered to the interface */ + return ret; +} + +bool dat_drop_broadcast_packet(struct bat_priv *bat_priv, + struct forw_packet *forw_packet) +{ + struct neighbour *n; + + /* 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, + sizeof(struct bcast_packet)) == + ARPOP_REQUEST)) { + n = neigh_lookup(&arp_tbl, + &ARP_IP_DST(forw_packet->skb, + sizeof(struct bcast_packet)), + forw_packet->if_incoming->soft_iface); + /* check if we already know this neigh */ + if (n && (n->nud_state & NUD_CONNECTED)) { + bat_dbg(DBG_ARP, bat_priv, "ARP Request for %pI4: " + "fallback prevented\n", + &ARP_IP_DST(forw_packet->skb, + sizeof(struct bcast_packet))); + return true; + } + + bat_dbg(DBG_ARP, bat_priv, "ARP Request for %pI4: fallback\n", + &ARP_IP_DST(forw_packet->skb, + sizeof(struct bcast_packet))); + } + return false; +} diff --git a/distributed-arp-table.h b/distributed-arp-table.h index b5bf2d1..21c5d5e 100644 --- a/distributed-arp-table.h +++ b/distributed-arp-table.h @@ -37,6 +37,17 @@ #define ARP_IP_DST(skb, hdr_size) (*(uint32_t *)(ARP_HW_SRC(skb, hdr_size) + \ ETH_ALEN * 2 + 4)) +bool dat_snoop_outgoing_arp_request(struct bat_priv *bat_priv, + struct sk_buff *skb); +bool dat_snoop_incoming_arp_request(struct bat_priv *bat_priv, + struct sk_buff *skb, int hdr_size); +bool dat_snoop_outgoing_arp_reply(struct bat_priv *bat_priv, + struct sk_buff *skb); +bool dat_snoop_incoming_arp_reply(struct bat_priv *bat_priv, + struct sk_buff *skb, int hdr_size); +bool dat_drop_broadcast_packet(struct bat_priv *bat_priv, + struct forw_packet *forw_packet); + /* hash function to choose an entry in a hash table of given size */ /* hash algorithm from http://en.wikipedia.org/wiki/Hash_table */ static inline uint32_t hash_ipv4(const void *data, uint32_t size) diff --git a/main.h b/main.h index ffefc33..24dca8e 100644 --- a/main.h +++ b/main.h @@ -67,6 +67,8 @@ #define NUM_WORDS BITS_TO_LONGS(TQ_LOCAL_WINDOW_SIZE) +/* msecs after which an ARP_REQUEST is sent in broadcast as fallback */ +#define ARP_REQ_DELAY 250 /* numbers of originator to contact for any PUT/GET DHT operation */ #define DHT_CANDIDATES_NUM 3 diff --git a/send.c b/send.c index 1d5353f..f7f5e3a 100644 --- a/send.c +++ b/send.c @@ -20,6 +20,7 @@ */ #include "main.h" +#include "distributed-arp-table.h" #include "send.h" #include "routing.h" #include "translation-table.h" @@ -274,6 +275,9 @@ static void send_outstanding_bcast_packet(struct work_struct *work) if (atomic_read(&bat_priv->mesh_state) == MESH_DEACTIVATING) goto out; + if (dat_drop_broadcast_packet(bat_priv, forw_packet)) + goto out; + /* rebroadcast packet */ rcu_read_lock(); list_for_each_entry_rcu(hard_iface, &hardif_list, list) { diff --git a/soft-interface.c b/soft-interface.c index 8d76abf..0a78feb 100644 --- a/soft-interface.c +++ b/soft-interface.c @@ -22,6 +22,7 @@ #include "main.h" #include "soft-interface.h" #include "hard-interface.h" +#include "distributed-arp-table.h" #include "routing.h" #include "send.h" #include "bat_debugfs.h" @@ -135,6 +136,7 @@ static int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) int data_len = skb->len, ret; short vid __maybe_unused = -1; bool do_bcast = false; + unsigned long brd_delay = 1; if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE) goto dropped; @@ -195,6 +197,9 @@ static int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) if (!primary_if) goto dropped; + if (dat_snoop_outgoing_arp_request(bat_priv, skb)) + brd_delay = msecs_to_jiffies(ARP_REQ_DELAY); + if (my_skb_head_push(skb, sizeof(*bcast_packet)) < 0) goto dropped; @@ -214,7 +219,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. */ @@ -228,6 +233,8 @@ static int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) goto dropped; } + dat_snoop_outgoing_arp_reply(bat_priv, skb); + ret = unicast_send_skb(skb, bat_priv); if (ret != 0) goto dropped_freed; @@ -252,6 +259,7 @@ void interface_rx(struct net_device *soft_iface, int hdr_size) { struct bat_priv *bat_priv = netdev_priv(soft_iface); + struct unicast_4addr_packet *unicast_4addr_packet; struct ethhdr *ethhdr; struct vlan_ethhdr *vhdr; short vid __maybe_unused = -1; @@ -260,6 +268,14 @@ void interface_rx(struct net_device *soft_iface, if (!pskb_may_pull(skb, hdr_size)) goto dropped; + unicast_4addr_packet = (struct unicast_4addr_packet *)skb->data; + + if (dat_snoop_incoming_arp_request(bat_priv, skb, hdr_size)) + goto out; + + if (dat_snoop_incoming_arp_reply(bat_priv, skb, hdr_size)) + goto out; + skb_pull_rcsum(skb, hdr_size); skb_reset_mac_header(skb);