From patchwork Thu Mar 22 21:51:12 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Lindner X-Patchwork-Id: 1609 Return-Path: Received: from nm7.bullet.mail.ukl.yahoo.com (nm7.bullet.mail.ukl.yahoo.com [217.146.182.248]) by open-mesh.org (Postfix) with SMTP id 9DBC36006C9 for ; Thu, 22 Mar 2012 22:51:40 +0100 (CET) Authentication-Results: open-mesh.org; dkim=pass (1024-bit key) header.i=@yahoo.de; dkim-adsp=none Received: from [217.146.183.217] by nm7.bullet.mail.ukl.yahoo.com with NNFMP; 22 Mar 2012 21:51:40 -0000 Received: from [217.146.182.88] by tm10.bullet.mail.ukl.yahoo.com with NNFMP; 22 Mar 2012 21:51:40 -0000 Received: from [127.0.0.1] by smtp151.mail.ukl.yahoo.com with NNFMP; 22 Mar 2012 21:51:40 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.de; s=s1024; t=1332453100; bh=qZinoOJ3i8Kr9C67mxrlA0w8q+ZSBdPQnQmSZt9wdqs=; h=X-Yahoo-Newman-Id:X-Yahoo-Newman-Property:X-YMail-OSG:X-Yahoo-SMTP:Received:From:To:Cc:Subject:Date:Message-Id:X-Mailer:In-Reply-To:References; b=FZGtVeUjllmEdr52WdGqW8N4uL6G1HXfhdT+vuGyPxV0psqz1ARtwGpMvpST1B7ta3yfFmDZP/Ra8JTjHqiKviiWuMTGQL5A/4TcHmN3qPEg3qLIe9Ji1zhLMKPuez2hfwmgDcvsWYZArMVj2N6dodSFo30a6vVSyoSig5WoraM= X-Yahoo-Newman-Id: 43743.89341.bm@smtp151.mail.ukl.yahoo.com X-Yahoo-Newman-Property: ymail-3 X-YMail-OSG: BKtEx5wVM1lBRqk6OEiWx_FwRGG.8KzSU8Vs7ZKrfCXb3dZ b6HlhKSo7XDsHs3scsEblvRf7jiVV.fb3Kv.WrQCi3ngU4bwlfSVwI_93LMj H.36b0ZjTpZqQlLWJi2_DhlRwY5ZUvMaB5FMODw342CoXScFneLwmlJl8mIc yrw8QjwqHK6XuY5GtNdr2vhC6tHL8I.nB7X.QM.qqzi7StkjQTfhW6LjUP0t wiak4YMN8dqqKEZH6Hg.ISvPZlReqWitvHWa2OQ_ev0Lu0TtVpfZmPDOPdVK eldFX74I96pzGpN.NfVOB.SiN4AkaqA801Kh27tzACC_7KgUemL.kssbY3K3 JDhln6bAD61NbKW85c2opOT9w_TEK2NyYHUIx2Lt6CeAG3P62qwUMq_QRyaX Cuwc- X-Yahoo-SMTP: tW.h3tiswBBMXO2coYcbPigGD5Lt6zY_.Zc- Received: from localhost (lindner_marek@217.85.92.241 with plain) by smtp151.mail.ukl.yahoo.com with SMTP; 22 Mar 2012 14:51:36 -0700 PDT From: Marek Lindner To: b.a.t.m.a.n@lists.open-mesh.org Date: Thu, 22 Mar 2012 22:51:12 +0100 Message-Id: <1332453075-27999-2-git-send-email-lindner_marek@yahoo.de> X-Mailer: git-send-email 1.7.9.1 In-Reply-To: <1332453075-27999-1-git-send-email-lindner_marek@yahoo.de> References: <201203222250.31309.lindner_marek@yahoo.de> <1332453075-27999-1-git-send-email-lindner_marek@yahoo.de> Cc: Marek Lindner Subject: [B.A.T.M.A.N.] [RFC 2/5] batman-adv: ELP - creating neighbor structures, updating LQs 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: Thu, 22 Mar 2012 21:51:41 -0000 From: Linus Luessing Developed by Linus during a 6 months trainee study period in Ascom (Switzerland) AG. Signed-off-by: Linus Luessing Signed-off-by: Marek Lindner --- bat_v_elp.c | 255 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- packet.h | 6 ++ types.h | 8 ++ 3 files changed, 267 insertions(+), 2 deletions(-) diff --git a/bat_v_elp.c b/bat_v_elp.c index c2dee5c..e252c04 100644 --- a/bat_v_elp.c +++ b/bat_v_elp.c @@ -23,6 +23,8 @@ #include "hard-interface.h" #include "send.h" #include "bat_algo.h" +#include "originator.h" +#include "routing.h" static void bat_v_elp_start_timer(struct hard_iface *hard_iface) { @@ -35,12 +37,78 @@ static void bat_v_elp_start_timer(struct hard_iface *hard_iface) &hard_iface->elp_wq, elp_interval); } +static struct neigh_node *bat_v_elp_neigh_new(struct hard_iface *hard_iface, + uint8_t *neigh_addr, + uint32_t seqno) +{ + struct neigh_node *neigh_node; + + neigh_node = neigh_node_new(hard_iface, neigh_addr, seqno); + if (!neigh_node) + goto out; + + neigh_node->last_recv_seqno = seqno - 1; + + spin_lock_bh(&hard_iface->neigh_list_lock); + hlist_add_head_rcu(&neigh_node->list, &hard_iface->neigh_list); + spin_unlock_bh(&hard_iface->neigh_list_lock); + +out: + return neigh_node; +} + +static struct neigh_node *bat_v_elp_neigh_get(struct hard_iface *hard_iface, + uint8_t *neigh_addr) +{ + struct neigh_node *neigh_node = NULL, *neigh_node_tmp; + struct hlist_node *node; + + rcu_read_lock(); + hlist_for_each_entry_rcu(neigh_node_tmp, node, + &hard_iface->neigh_list, list) { + if (!compare_eth(neigh_node_tmp->addr, neigh_addr)) + continue; + + if (!atomic_inc_not_zero(&neigh_node_tmp->refcount)) + continue; + + neigh_node = neigh_node_tmp; + break; + } + rcu_read_unlock(); + + return neigh_node; +} + +static void bat_v_elp_neigh_purge(struct hard_iface *hard_iface) +{ + struct neigh_node *neigh_node; + struct hlist_node *node, *node_tmp; + + spin_lock_bh(&hard_iface->neigh_list_lock); + hlist_for_each_entry_safe(neigh_node, node, node_tmp, + &hard_iface->neigh_list, list) { + + if ((!has_timed_out(neigh_node->last_seen, PURGE_TIMEOUT)) && + (hard_iface->if_status == IF_ACTIVE)) + continue; + + hlist_del_rcu(&neigh_node->list); + neigh_node_free_ref(neigh_node); + } + spin_unlock_bh(&hard_iface->neigh_list_lock); +} + static void bat_v_elp_send_outstanding(struct work_struct *work) { struct hard_iface *hard_iface; struct bat_priv *bat_priv; struct batman_elp_packet *elp_packet; + struct elp_neigh_entry *elp_neigh_entry; + struct neigh_node *neigh_node; + struct hlist_node *node; struct sk_buff *skb; + unsigned int max_len; hard_iface = container_of(work, struct hard_iface, elp_wq.work); bat_priv = netdev_priv(hard_iface->soft_iface); @@ -48,6 +116,7 @@ static void bat_v_elp_send_outstanding(struct work_struct *work) if (atomic_read(&bat_priv->mesh_state) == MESH_DEACTIVATING) goto out; + /* we are in the process of shutting this interface down */ if ((hard_iface->if_status == IF_NOT_IN_USE) || (hard_iface->if_status == IF_TO_BE_REMOVED)) goto out; @@ -56,14 +125,40 @@ static void bat_v_elp_send_outstanding(struct work_struct *work) if (hard_iface->if_status != IF_ACTIVE) goto restart_timer; + max_len = min_t(unsigned int, ETH_DATA_LEN, hard_iface->net_dev->mtu); + skb = skb_copy(hard_iface->elp_skb, GFP_ATOMIC); if (!skb) goto out; + /* purge outdated entries first */ + bat_v_elp_neigh_purge(hard_iface); + elp_packet = (struct batman_elp_packet *)skb->data; elp_packet->seqno = htonl(atomic_read(&hard_iface->elp_seqno)); elp_packet->num_neighbors = 0; + elp_neigh_entry = (struct elp_neigh_entry *)(elp_packet + 1); + + rcu_read_lock(); + hlist_for_each_entry_rcu(neigh_node, node, + &hard_iface->neigh_list, list) { + if (skb->len + sizeof(struct elp_neigh_entry) > max_len) { + if (printk_ratelimit()) + bat_err(hard_iface->net_dev, + "Skipping ELP neigh entries: " + "packet length exhausted\n"); + break; + } + + memcpy(elp_neigh_entry->addr, neigh_node->addr, ETH_ALEN); + elp_neigh_entry->rq = neigh_node->rq; + elp_packet->num_neighbors++; + elp_neigh_entry++; + skb_put(skb, sizeof(struct elp_neigh_entry)); + } + rcu_read_unlock(); + bat_dbg(DBG_BATMAN, bat_priv, "Sending elp packet on interface %s, seqno %d\n", hard_iface->net_dev->name, atomic_read(&hard_iface->elp_seqno)); @@ -71,8 +166,9 @@ static void bat_v_elp_send_outstanding(struct work_struct *work) send_skb_packet(skb, hard_iface, broadcast_addr); atomic_inc(&hard_iface->elp_seqno); - bat_v_elp_start_timer(hard_iface); +restart_timer: + bat_v_elp_start_timer(hard_iface); out: return; } @@ -117,6 +213,8 @@ static void bat_v_elp_iface_disable(struct hard_iface *hard_iface) dev_kfree_skb(hard_iface->elp_skb); hard_iface->elp_skb = NULL; + + bat_v_elp_neigh_purge(hard_iface); } static void bat_v_elp_iface_update_mac(struct hard_iface *hard_iface) @@ -158,6 +256,143 @@ static void bat_v_ogm_emit(struct forw_packet *forw_packet) return; } +/* extract my own tq to neighbor from the elp packet */ +static uint8_t bat_v_elp_fetch_tq(uint8_t *my_iface_addr, + struct batman_elp_packet *elp_packet, + int elp_packet_len) +{ + struct elp_neigh_entry *elp_neigh_entry; + uint8_t tq = 0; + int i; + + elp_neigh_entry = (struct elp_neigh_entry *)(elp_packet + 1); + elp_packet_len -= BATMAN_ELP_HLEN; + + for (i = 0; i < elp_packet->num_neighbors; i++) { + if (!compare_eth(my_iface_addr, elp_neigh_entry->addr)) + goto next; + + tq = elp_neigh_entry->rq; + break; + + next: + elp_packet_len -= sizeof(struct elp_neigh_entry); + if (elp_packet_len < 0) + break; + + elp_neigh_entry++; + } + + return tq; +} + +static void bat_v_elp_neigh_update_lq(struct hard_iface *hard_iface, + struct neigh_node *neigh_node, + uint8_t my_tq, uint32_t seqno) +{ + struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface); + int32_t seq_diff; + int neigh_packet_count; + bool is_new_seqno; + + seq_diff = seqno - neigh_node->last_recv_seqno; + + is_new_seqno = bit_get_packet(bat_priv, neigh_node->elp_rq_bits, + seq_diff, 1); + if (!is_new_seqno) + return; + + bat_dbg(DBG_BATMAN, bat_priv, + "Updating last_seqno of neighbor %pM: old %d, new %d\n", + neigh_node->addr, neigh_node->last_recv_seqno, seqno); + + /*** + * we only update the tq/last seen/last seqno fields upon + * receival of a newer ELP sequence number + */ + neigh_node->tq = my_tq; + neigh_node->last_seen = jiffies; + neigh_node->last_recv_seqno = seqno; + + neigh_packet_count = bitmap_weight(neigh_node->elp_rq_bits, + TQ_LOCAL_WINDOW_SIZE); + neigh_node->rq = (neigh_packet_count * TQ_MAX_VALUE) / + TQ_LOCAL_WINDOW_SIZE; + + bat_dbg(DBG_BATMAN, bat_priv, + "New rq/tq of neighbor %pM: rq %d, tq %d\n", + neigh_node->addr, neigh_node->rq, neigh_node->tq); +} + +void bat_v_elp_neigh_update(uint8_t *neigh_addr, + struct hard_iface *if_incoming, + struct batman_elp_packet *elp_packet, + int elp_packet_len) +{ + struct neigh_node *neigh_node; + uint8_t my_tq; + + neigh_node = bat_v_elp_neigh_get(if_incoming, neigh_addr); + if (!neigh_node) { + neigh_node = bat_v_elp_neigh_new(if_incoming, neigh_addr, + elp_packet->seqno); + if (!neigh_node) + goto out; + } + + my_tq = bat_v_elp_fetch_tq(if_incoming->net_dev->dev_addr, + elp_packet, elp_packet_len); + + spin_lock_bh(&neigh_node->lq_update_lock); + bat_v_elp_neigh_update_lq(if_incoming, neigh_node, + my_tq, elp_packet->seqno); + spin_unlock_bh(&neigh_node->lq_update_lock); + +out: + if (neigh_node) + neigh_node_free_ref(neigh_node); +} + +static int bat_v_elp_packet_recv(struct sk_buff *skb, + struct hard_iface *if_incoming) +{ + struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); + struct batman_elp_packet *elp_packet; + struct hard_iface *primary_if; + struct ethhdr *ethhdr; + bool ret; + + ret = check_management_packet(skb, if_incoming, BATMAN_ELP_HLEN); + if (!ret) + return NET_RX_DROP; + + /* did we receive a B.A.T.M.A.N. V ELP packet on an interface + * that does not have B.A.T.M.A.N. V ELP enabled ? */ + if (bat_priv->bat_algo_ops->bat_ogm_emit != bat_v_ogm_emit) + return NET_RX_DROP; + + primary_if = primary_if_get_selected(bat_priv); + if (!primary_if) + goto out; + + ethhdr = (struct ethhdr *)skb_mac_header(skb); + elp_packet = (struct batman_elp_packet *)skb->data; + + /* our own ELP packet */ + if (compare_eth(primary_if->net_dev->dev_addr, elp_packet->orig)) + goto out; + + elp_packet->seqno = ntohl(elp_packet->seqno); + + bat_v_elp_neigh_update(ethhdr->h_source, if_incoming, + elp_packet, skb_headlen(skb)); + +out: + if (primary_if) + hardif_free_ref(primary_if); + dev_kfree_skb(skb); + return NET_RX_SUCCESS; +} static struct bat_algo_ops batman_v __read_mostly = { .name = "BATMAN V", @@ -171,5 +406,21 @@ static struct bat_algo_ops batman_v __read_mostly = { int __init bat_v_init(void) { - return bat_algo_register(&batman_v); + int ret; + + /* batman v echo location protocol packet */ + ret = recv_handler_register(BAT_V_ELP, bat_v_elp_packet_recv); + if (ret < 0) + goto out; + + ret = bat_algo_register(&batman_v); + if (ret < 0) + goto handler_unregister; + + goto out; + +handler_unregister: + recv_handler_unregister(BAT_V_ELP); +out: + return ret; } diff --git a/packet.h b/packet.h index cf516dc..ea1683f 100644 --- a/packet.h +++ b/packet.h @@ -148,6 +148,12 @@ struct batman_elp_packet { #define BATMAN_ELP_HLEN sizeof(struct batman_elp_packet) +struct elp_neigh_entry { + uint8_t addr[ETH_ALEN]; + uint8_t rq; + uint8_t align; +} __attribute__((packed)); + struct icmp_packet { struct batman_header header; uint8_t msg_type; /* see ICMP message types above */ diff --git a/types.h b/types.h index 86f2250..abe27dd 100644 --- a/types.h +++ b/types.h @@ -61,6 +61,8 @@ struct hard_iface { #ifdef CONFIG_BATMAN_ADV_BATMAN_V atomic_t elp_interval; atomic_t elp_seqno; + struct hlist_head neigh_list; + spinlock_t neigh_list_lock; struct sk_buff *elp_skb; struct delayed_work elp_wq; #endif /* CONFIG_BATMAN_ADV_BATMAN_V */ @@ -158,6 +160,12 @@ struct neigh_node { struct orig_node *orig_node; struct hard_iface *if_incoming; spinlock_t lq_update_lock; /* protects: tq_recv, tq_index */ +#ifdef CONFIG_BATMAN_ADV_BATMAN_V + uint8_t rq; + uint8_t tq; + uint32_t last_recv_seqno; + DECLARE_BITMAP(elp_rq_bits, TQ_LOCAL_WINDOW_SIZE); +#endif }; #ifdef CONFIG_BATMAN_ADV_BLA