Hi everyone,
thanks for all the feedback and reviewing again. The following updated patches address Marek's comments and suggestions: * Introducing a commit for renaming only * batman_packet_ogm -> ogm_packet, batman_packet_ndp -> ndp_packet * BAT_UNICAST followed by BAT_UNICAST_FRAG * structs introduced in the patches where they're used, not earlier (ndp_packet, neigh_entry) * moved own_ndp_send_time to ndp.c * checkpatch cleaning * avoid losing ndp-interval setting on interface down/up * fixed a potential memory leak in error cases * skb_copy instead of skb_clone * rebased to trunk * removal of unnecessary include * hlist instead of doubly linked list * added a break in one list traversal * secure neigh_list with rcu-locking + ref-counting * rename rq_real_bits to ndp_rq_window * use msecs_to_jiffies instead of manual HZ multiplication * fix get_batman_if_by_netdev usage / refcounting * adding licenses
Furthermore I've changed the following: * use dev_kfree_skb instead of kfree_skb in case of successful ndp packet reception and processing (so no simple NET_RX_DROP return value) * adding include guards for ndp.h * use "= seqno - 1" in ndp_create_neighbor(), otherwise ndp_update_neighbor_lq() does not update tq/rq/last_valid on first ndp packet
Would be great if someone could check the usage of rcu-locking + refcounting. I was also a little confused because in "Documentation/RCU/listRCU.txt" list_del_rcu() and list_add_rcu() are not protected with a spinlock for the list here, but in the batman-adv code we are usually having those extra locks. Do I have to leave those spinlocks or can I remove them for adding/deleting entries in the neigh_list?
Cheers, Linus
We are going to introduce two separate packet types, namely originator messages (OGM) and NDP (neighbor discovery protocol). This commit renames the structures, the packet type name and scheduling functions for OGMs to clearly indicate their purpose.
Signed-off-by: Linus Lüssing linus.luessing@ascom.ch --- aggregation.c | 43 +++++++++---------- aggregation.h | 3 +- hard-interface.c | 45 ++++++++++---------- packet.h | 7 ++- routing.c | 103 +++++++++++++++++++++++----------------------- routing.h | 2 +- send.c | 114 +++++++++++++++++++++++++------------------------- send.h | 4 +- soft-interface.c | 16 ++++---- translation-table.c | 2 +- 10 files changed, 171 insertions(+), 168 deletions(-)
diff --git a/aggregation.c b/aggregation.c index 3850a3e..208a1ab 100644 --- a/aggregation.c +++ b/aggregation.c @@ -25,21 +25,21 @@ #include "routing.h"
/* calculate the size of the hna information for a given packet */ -static int hna_len(struct batman_packet *batman_packet) +static int hna_len(struct ogm_packet *ogm_packet) { - return batman_packet->num_hna * ETH_ALEN; + return ogm_packet->num_hna * ETH_ALEN; }
/* return true if new_packet can be aggregated with forw_packet */ -static bool can_aggregate_with(struct batman_packet *new_batman_packet, +static bool can_aggregate_with(struct ogm_packet *new_ogm_packet, int packet_len, unsigned long send_time, bool directlink, struct batman_if *if_incoming, struct forw_packet *forw_packet) { - struct batman_packet *batman_packet = - (struct batman_packet *)forw_packet->skb->data; + struct ogm_packet *ogm_packet = + (struct ogm_packet *)forw_packet->skb->data; int aggregated_bytes = forw_packet->packet_len + packet_len;
/** @@ -68,8 +68,8 @@ static bool can_aggregate_with(struct batman_packet *new_batman_packet, /* packets without direct link flag and high TTL * are flooded through the net */ if ((!directlink) && - (!(batman_packet->flags & DIRECTLINK)) && - (batman_packet->ttl != 1) && + (!(ogm_packet->flags & DIRECTLINK)) && + (ogm_packet->ttl != 1) &&
/* own packets originating non-primary * interfaces leave only that interface */ @@ -80,13 +80,13 @@ static bool can_aggregate_with(struct batman_packet *new_batman_packet, /* if the incoming packet is sent via this one * interface only - we still can aggregate */ if ((directlink) && - (new_batman_packet->ttl == 1) && + (new_ogm_packet->ttl == 1) && (forw_packet->if_incoming == if_incoming) &&
/* packets from direct neighbors or * own secondary interface packets * (= secondary interface packets in general) */ - (batman_packet->flags & DIRECTLINK || + (ogm_packet->flags & DIRECTLINK || (forw_packet->own && forw_packet->if_incoming->if_num != 0))) return true; @@ -197,9 +197,8 @@ void add_bat_packet_to_list(struct bat_priv *bat_priv, */ struct forw_packet *forw_packet_aggr = NULL, *forw_packet_pos = NULL; struct hlist_node *tmp_node; - struct batman_packet *batman_packet = - (struct batman_packet *)packet_buff; - bool direct_link = batman_packet->flags & DIRECTLINK ? 1 : 0; + struct ogm_packet *ogm_packet = (struct ogm_packet *)packet_buff; + bool direct_link = ogm_packet->flags & DIRECTLINK ? 1 : 0;
/* find position for the packet in the forward queue */ spin_lock_bh(&bat_priv->forw_bat_list_lock); @@ -207,7 +206,7 @@ void add_bat_packet_to_list(struct bat_priv *bat_priv, if ((atomic_read(&bat_priv->aggregated_ogms)) && (!own_packet)) { hlist_for_each_entry(forw_packet_pos, tmp_node, &bat_priv->forw_bat_list, list) { - if (can_aggregate_with(batman_packet, + if (can_aggregate_with(ogm_packet, packet_len, send_time, direct_link, @@ -249,25 +248,25 @@ void add_bat_packet_to_list(struct bat_priv *bat_priv, void receive_aggr_bat_packet(struct ethhdr *ethhdr, unsigned char *packet_buff, int packet_len, struct batman_if *if_incoming) { - struct batman_packet *batman_packet; + struct ogm_packet *ogm_packet; int buff_pos = 0; unsigned char *hna_buff;
- batman_packet = (struct batman_packet *)packet_buff; + ogm_packet = (struct ogm_packet *)packet_buff;
do { /* network to host order for our 32bit seqno, and the orig_interval. */ - batman_packet->seqno = ntohl(batman_packet->seqno); + ogm_packet->seqno = ntohl(ogm_packet->seqno);
- hna_buff = packet_buff + buff_pos + BAT_PACKET_LEN; - receive_bat_packet(ethhdr, batman_packet, - hna_buff, hna_len(batman_packet), + hna_buff = packet_buff + buff_pos + BAT_PACKET_OGM_LEN; + receive_bat_packet(ethhdr, ogm_packet, + hna_buff, hna_len(ogm_packet), if_incoming);
- buff_pos += BAT_PACKET_LEN + hna_len(batman_packet); - batman_packet = (struct batman_packet *) + buff_pos += BAT_PACKET_OGM_LEN + hna_len(ogm_packet); + ogm_packet = (struct ogm_packet *) (packet_buff + buff_pos); } while (aggregated_packet(buff_pos, packet_len, - batman_packet->num_hna)); + ogm_packet->num_hna)); } diff --git a/aggregation.h b/aggregation.h index 71a91b3..667ef2d 100644 --- a/aggregation.h +++ b/aggregation.h @@ -27,7 +27,8 @@ /* is there another aggregated packet here? */ static inline int aggregated_packet(int buff_pos, int packet_len, int num_hna) { - int next_buff_pos = buff_pos + BAT_PACKET_LEN + (num_hna * ETH_ALEN); + int next_buff_pos = buff_pos + BAT_PACKET_OGM_LEN + + (num_hna * ETH_ALEN);
return (next_buff_pos <= packet_len) && (next_buff_pos <= MAX_AGGREGATION_BYTES); diff --git a/hard-interface.c b/hard-interface.c index 4f95777..a992113 100644 --- a/hard-interface.c +++ b/hard-interface.c @@ -128,7 +128,7 @@ static void update_primary_addr(struct bat_priv *bat_priv) static void set_primary_if(struct bat_priv *bat_priv, struct batman_if *batman_if) { - struct batman_packet *batman_packet; + struct ogm_packet *ogm_packet; struct batman_if *old_if;
if (batman_if) @@ -143,9 +143,9 @@ static void set_primary_if(struct bat_priv *bat_priv, if (!bat_priv->primary_if) return;
- batman_packet = (struct batman_packet *)(batman_if->packet_buff); - batman_packet->flags = PRIMARIES_FIRST_HOP; - batman_packet->ttl = TTL; + ogm_packet = (struct ogm_packet *)batman_if->packet_buff; + ogm_packet->flags = PRIMARIES_FIRST_HOP; + ogm_packet->ttl = TTL;
update_primary_addr(bat_priv);
@@ -166,9 +166,10 @@ static bool hardif_is_iface_up(struct batman_if *batman_if)
static void update_mac_addresses(struct batman_if *batman_if) { - memcpy(((struct batman_packet *)(batman_if->packet_buff))->orig, + memcpy(((struct ogm_packet *)(batman_if->packet_buff))->orig, batman_if->net_dev->dev_addr, ETH_ALEN); - memcpy(((struct batman_packet *)(batman_if->packet_buff))->prev_sender, + memcpy(((struct ogm_packet *) + (batman_if->packet_buff))->prev_sender, batman_if->net_dev->dev_addr, ETH_ALEN); }
@@ -279,7 +280,7 @@ static void hardif_deactivate_interface(struct batman_if *batman_if) int hardif_enable_interface(struct batman_if *batman_if, char *iface_name) { struct bat_priv *bat_priv; - struct batman_packet *batman_packet; + struct ogm_packet *ogm_packet;
if (batman_if->if_status != IF_NOT_IN_USE) goto out; @@ -297,7 +298,7 @@ int hardif_enable_interface(struct batman_if *batman_if, char *iface_name) }
bat_priv = netdev_priv(batman_if->soft_iface); - batman_if->packet_len = BAT_PACKET_LEN; + batman_if->packet_len = BAT_PACKET_OGM_LEN; batman_if->packet_buff = kmalloc(batman_if->packet_len, GFP_ATOMIC);
if (!batman_if->packet_buff) { @@ -306,13 +307,13 @@ int hardif_enable_interface(struct batman_if *batman_if, char *iface_name) goto err; }
- batman_packet = (struct batman_packet *)(batman_if->packet_buff); - batman_packet->packet_type = BAT_PACKET; - batman_packet->version = COMPAT_VERSION; - batman_packet->flags = 0; - batman_packet->ttl = 2; - batman_packet->tq = TQ_MAX_VALUE; - batman_packet->num_hna = 0; + ogm_packet = (struct ogm_packet *)(batman_if->packet_buff); + ogm_packet->packet_type = BAT_PACKET_OGM; + ogm_packet->version = COMPAT_VERSION; + ogm_packet->flags = 0; + ogm_packet->ttl = 2; + ogm_packet->tq = TQ_MAX_VALUE; + ogm_packet->num_hna = 0;
batman_if->if_num = bat_priv->num_ifaces; bat_priv->num_ifaces++; @@ -359,7 +360,7 @@ int hardif_enable_interface(struct batman_if *batman_if, char *iface_name) batman_if->net_dev->name);
/* begin scheduling originator messages on that interface */ - schedule_own_packet(batman_if); + schedule_own_ogm_packet(batman_if);
out: return 0; @@ -553,7 +554,7 @@ int batman_skb_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype, struct net_device *orig_dev) { struct bat_priv *bat_priv; - struct batman_packet *batman_packet; + struct ogm_packet *ogm_packet; struct batman_if *batman_if; int ret;
@@ -585,21 +586,21 @@ int batman_skb_recv(struct sk_buff *skb, struct net_device *dev, if (batman_if->if_status != IF_ACTIVE) goto err_free;
- batman_packet = (struct batman_packet *)skb->data; + ogm_packet = (struct ogm_packet *)skb->data;
- if (batman_packet->version != COMPAT_VERSION) { + if (ogm_packet->version != COMPAT_VERSION) { bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: incompatible batman version (%i)\n", - batman_packet->version); + ogm_packet->version); goto err_free; }
/* all receive handlers return whether they received or reused * the supplied skb. if not, we have to free the skb. */
- switch (batman_packet->packet_type) { + switch (ogm_packet->packet_type) { /* batman originator packet */ - case BAT_PACKET: + case BAT_PACKET_OGM: ret = recv_bat_packet(skb, batman_if); break;
diff --git a/packet.h b/packet.h index b49fdf7..681052d 100644 --- a/packet.h +++ b/packet.h @@ -24,7 +24,7 @@
#define ETH_P_BATMAN 0x4305 /* unofficial/not registered Ethertype */
-#define BAT_PACKET 0x01 +#define BAT_PACKET_OGM 0x01 #define BAT_ICMP 0x02 #define BAT_UNICAST 0x03 #define BAT_BCAST 0x04 @@ -51,7 +51,8 @@ /* fragmentation defines */ #define UNI_FRAG_HEAD 0x01
-struct batman_packet { +/* Originator message packet */ +struct ogm_packet { uint8_t packet_type; uint8_t version; /* batman version field */ uint8_t flags; /* 0x40: DIRECTLINK flag, 0x20 VIS_SERVER flag... */ @@ -65,7 +66,7 @@ struct batman_packet { uint8_t align; } __attribute__((packed));
-#define BAT_PACKET_LEN sizeof(struct batman_packet) +#define BAT_PACKET_OGM_LEN sizeof(struct ogm_packet)
struct icmp_packet { uint8_t packet_type; diff --git a/routing.c b/routing.c index 90ca129..1782777 100644 --- a/routing.c +++ b/routing.c @@ -145,7 +145,7 @@ void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node,
static int is_bidirectional_neigh(struct orig_node *orig_node, struct orig_node *orig_neigh_node, - struct batman_packet *batman_packet, + struct ogm_packet *ogm_packet, struct batman_if *if_incoming) { struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); @@ -234,7 +234,7 @@ static int is_bidirectional_neigh(struct orig_node *orig_node, TQ_LOCAL_WINDOW_SIZE * TQ_LOCAL_WINDOW_SIZE);
- batman_packet->tq = ((batman_packet->tq * + ogm_packet->tq = ((ogm_packet->tq * orig_neigh_node->tq_own * orig_neigh_node->tq_asym_penalty) / (TQ_MAX_VALUE * TQ_MAX_VALUE)); @@ -246,11 +246,11 @@ static int is_bidirectional_neigh(struct orig_node *orig_node, "total tq: %3i\n", orig_node->orig, orig_neigh_node->orig, total_count, neigh_node->real_packet_count, orig_neigh_node->tq_own, - orig_neigh_node->tq_asym_penalty, batman_packet->tq); + orig_neigh_node->tq_asym_penalty, ogm_packet->tq);
/* if link has the minimum required transmission quality * consider it bidirectional */ - if (batman_packet->tq >= TQ_TOTAL_BIDRECT_LIMIT) + if (ogm_packet->tq >= TQ_TOTAL_BIDRECT_LIMIT) return 1;
return 0; @@ -259,7 +259,7 @@ static int is_bidirectional_neigh(struct orig_node *orig_node, static void update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node, struct ethhdr *ethhdr, - struct batman_packet *batman_packet, + struct ogm_packet *ogm_packet, struct batman_if *if_incoming, unsigned char *hna_buff, int hna_buff_len, char is_duplicate) @@ -305,21 +305,21 @@ static void update_orig(struct bat_priv *bat_priv, bat_dbg(DBG_BATMAN, bat_priv, "Updating existing last-hop neighbor of originator\n");
- orig_node->flags = batman_packet->flags; + orig_node->flags = ogm_packet->flags; neigh_node->last_valid = jiffies;
ring_buffer_set(neigh_node->tq_recv, &neigh_node->tq_index, - batman_packet->tq); + ogm_packet->tq); neigh_node->tq_avg = ring_buffer_avg(neigh_node->tq_recv);
if (!is_duplicate) { - orig_node->last_ttl = batman_packet->ttl; - neigh_node->last_ttl = batman_packet->ttl; + orig_node->last_ttl = ogm_packet->ttl; + neigh_node->last_ttl = ogm_packet->ttl; }
- tmp_hna_buff_len = (hna_buff_len > batman_packet->num_hna * ETH_ALEN ? - batman_packet->num_hna * ETH_ALEN : hna_buff_len); + tmp_hna_buff_len = (hna_buff_len > ogm_packet->num_hna * ETH_ALEN ? + ogm_packet->num_hna * ETH_ALEN : hna_buff_len);
/* if this neighbor already is our next hop there is nothing * to change */ @@ -348,10 +348,11 @@ update_hna: hna_buff, tmp_hna_buff_len);
update_gw: - if (orig_node->gw_flags != batman_packet->gw_flags) - gw_node_update(bat_priv, orig_node, batman_packet->gw_flags); + if (orig_node->gw_flags != ogm_packet->gw_flags) + gw_node_update(bat_priv, orig_node, + ogm_packet->gw_flags);
- orig_node->gw_flags = batman_packet->gw_flags; + orig_node->gw_flags = ogm_packet->gw_flags;
/* restart gateway selection if fast or late switching was enabled */ if ((orig_node->gw_flags) && @@ -394,7 +395,7 @@ static int window_protected(struct bat_priv *bat_priv, * was protected. Caller should drop it. */ static char count_real_packets(struct ethhdr *ethhdr, - struct batman_packet *batman_packet, + struct ogm_packet *ogm_packet, struct batman_if *if_incoming) { struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); @@ -406,11 +407,11 @@ static char count_real_packets(struct ethhdr *ethhdr, int need_update = 0; int set_mark;
- orig_node = get_orig_node(bat_priv, batman_packet->orig); + orig_node = get_orig_node(bat_priv, ogm_packet->orig); if (!orig_node) return 0;
- seq_diff = batman_packet->seqno - orig_node->last_real_seqno; + seq_diff = ogm_packet->seqno - orig_node->last_real_seqno;
/* signalize caller that the packet is to be dropped. */ if (window_protected(bat_priv, seq_diff, @@ -423,7 +424,7 @@ static char count_real_packets(struct ethhdr *ethhdr,
is_duplicate |= get_bit_status(tmp_neigh_node->real_bits, orig_node->last_real_seqno, - batman_packet->seqno); + ogm_packet->seqno);
if (compare_orig(tmp_neigh_node->addr, ethhdr->h_source) && (tmp_neigh_node->if_incoming == if_incoming)) @@ -444,8 +445,8 @@ static char count_real_packets(struct ethhdr *ethhdr, if (need_update) { bat_dbg(DBG_BATMAN, bat_priv, "updating last_seqno: old %d, new %d\n", - orig_node->last_real_seqno, batman_packet->seqno); - orig_node->last_real_seqno = batman_packet->seqno; + orig_node->last_real_seqno, ogm_packet->seqno); + orig_node->last_real_seqno = ogm_packet->seqno; }
return is_duplicate; @@ -454,10 +455,10 @@ static char count_real_packets(struct ethhdr *ethhdr, /* copy primary address for bonding */ static void mark_bonding_address(struct orig_node *orig_node, struct orig_node *orig_neigh_node, - struct batman_packet *batman_packet) + struct ogm_packet *ogm_packet)
{ - if (batman_packet->flags & PRIMARIES_FIRST_HOP) + if (ogm_packet->flags & PRIMARIES_FIRST_HOP) memcpy(orig_neigh_node->primary_addr, orig_node->orig, ETH_ALEN);
@@ -565,7 +566,7 @@ void update_bonding_candidates(struct orig_node *orig_node) }
void receive_bat_packet(struct ethhdr *ethhdr, - struct batman_packet *batman_packet, + struct ogm_packet *ogm_packet, unsigned char *hna_buff, int hna_buff_len, struct batman_if *if_incoming) { @@ -586,30 +587,30 @@ void receive_bat_packet(struct ethhdr *ethhdr, * it as an additional length. * * TODO: A more sane solution would be to have a bit in the - * batman_packet to detect whether the packet is the last + * ogm_packet to detect whether the packet is the last * packet in an aggregation. Here we expect that the padding * is always zero (or not 0x01) */ - if (batman_packet->packet_type != BAT_PACKET) + if (ogm_packet->packet_type != BAT_PACKET_OGM) return;
- /* could be changed by schedule_own_packet() */ + /* could be changed by schedule_own_ogm_packet() */ if_incoming_seqno = atomic_read(&if_incoming->seqno);
- has_directlink_flag = (batman_packet->flags & DIRECTLINK ? 1 : 0); + has_directlink_flag = (ogm_packet->flags & DIRECTLINK ? 1 : 0);
is_single_hop_neigh = (compare_orig(ethhdr->h_source, - batman_packet->orig) ? 1 : 0); + ogm_packet->orig) ? 1 : 0);
bat_dbg(DBG_BATMAN, bat_priv, "Received BATMAN packet via NB: %pM, IF: %s [%pM] " "(from OG: %pM, via prev OG: %pM, seqno %d, tq %d, " "TTL %d, V %d, IDF %d)\n", ethhdr->h_source, if_incoming->net_dev->name, - if_incoming->net_dev->dev_addr, batman_packet->orig, - batman_packet->prev_sender, batman_packet->seqno, - batman_packet->tq, batman_packet->ttl, batman_packet->version, - has_directlink_flag); + if_incoming->net_dev->dev_addr, ogm_packet->orig, + ogm_packet->prev_sender, ogm_packet->seqno, + ogm_packet->tq, ogm_packet->ttl, + ogm_packet->version, has_directlink_flag);
rcu_read_lock(); list_for_each_entry_rcu(batman_if, &if_list, list) { @@ -623,11 +624,11 @@ void receive_bat_packet(struct ethhdr *ethhdr, batman_if->net_dev->dev_addr)) is_my_addr = 1;
- if (compare_orig(batman_packet->orig, + if (compare_orig(ogm_packet->orig, batman_if->net_dev->dev_addr)) is_my_orig = 1;
- if (compare_orig(batman_packet->prev_sender, + if (compare_orig(ogm_packet->prev_sender, batman_if->net_dev->dev_addr)) is_my_oldorig = 1;
@@ -636,10 +637,10 @@ void receive_bat_packet(struct ethhdr *ethhdr, } rcu_read_unlock();
- if (batman_packet->version != COMPAT_VERSION) { + if (ogm_packet->version != COMPAT_VERSION) { bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: incompatible batman version (%i)\n", - batman_packet->version); + ogm_packet->version); return; }
@@ -673,8 +674,8 @@ void receive_bat_packet(struct ethhdr *ethhdr, * seqno for bidirectional check */ if (has_directlink_flag && compare_orig(if_incoming->net_dev->dev_addr, - batman_packet->orig) && - (batman_packet->seqno - if_incoming_seqno + 2 == 0)) { + ogm_packet->orig) && + (ogm_packet->seqno - if_incoming_seqno + 2 == 0)) { offset = if_incoming->if_num * NUM_WORDS; word = &(orig_neigh_node->bcast_own[offset]); bit_mark(word, 0); @@ -694,11 +695,11 @@ void receive_bat_packet(struct ethhdr *ethhdr, return; }
- orig_node = get_orig_node(bat_priv, batman_packet->orig); + orig_node = get_orig_node(bat_priv, ogm_packet->orig); if (!orig_node) return;
- is_duplicate = count_real_packets(ethhdr, batman_packet, if_incoming); + is_duplicate = count_real_packets(ethhdr, ogm_packet, if_incoming);
if (is_duplicate == -1) { bat_dbg(DBG_BATMAN, bat_priv, @@ -707,7 +708,7 @@ void receive_bat_packet(struct ethhdr *ethhdr, return; }
- if (batman_packet->tq == 0) { + if (ogm_packet->tq == 0) { bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: originator packet with tq equal 0\n"); return; @@ -717,8 +718,8 @@ void receive_bat_packet(struct ethhdr *ethhdr, if ((orig_node->router) && (orig_node->router->orig_node->router) && (compare_orig(orig_node->router->addr, - batman_packet->prev_sender)) && - !(compare_orig(batman_packet->orig, batman_packet->prev_sender)) && + ogm_packet->prev_sender)) && + !(compare_orig(ogm_packet->orig, ogm_packet->prev_sender)) && (compare_orig(orig_node->router->addr, orig_node->router->orig_node->router->addr))) { bat_dbg(DBG_BATMAN, bat_priv, @@ -744,25 +745,25 @@ void receive_bat_packet(struct ethhdr *ethhdr, }
is_bidirectional = is_bidirectional_neigh(orig_node, orig_neigh_node, - batman_packet, if_incoming); + ogm_packet, if_incoming);
/* update ranking if it is not a duplicate or has the same * seqno and similar ttl as the non-duplicate */ if (is_bidirectional && (!is_duplicate || - ((orig_node->last_real_seqno == batman_packet->seqno) && - (orig_node->last_ttl - 3 <= batman_packet->ttl)))) - update_orig(bat_priv, orig_node, ethhdr, batman_packet, + ((orig_node->last_real_seqno == ogm_packet->seqno) && + (orig_node->last_ttl - 3 <= ogm_packet->ttl)))) + update_orig(bat_priv, orig_node, ethhdr, ogm_packet, if_incoming, hna_buff, hna_buff_len, is_duplicate);
- mark_bonding_address(orig_node, orig_neigh_node, batman_packet); + mark_bonding_address(orig_node, orig_neigh_node, ogm_packet); update_bonding_candidates(orig_node);
/* is single hop (direct) neighbor */ if (is_single_hop_neigh) {
/* mark direct link on incoming interface */ - schedule_forward_packet(orig_node, ethhdr, batman_packet, + schedule_forward_packet(orig_node, ethhdr, ogm_packet, 1, hna_buff_len, if_incoming);
bat_dbg(DBG_BATMAN, bat_priv, "Forwarding packet: " @@ -785,7 +786,7 @@ void receive_bat_packet(struct ethhdr *ethhdr,
bat_dbg(DBG_BATMAN, bat_priv, "Forwarding packet: rebroadcast originator packet\n"); - schedule_forward_packet(orig_node, ethhdr, batman_packet, + schedule_forward_packet(orig_node, ethhdr, ogm_packet, 0, hna_buff_len, if_incoming); }
@@ -795,7 +796,7 @@ int recv_bat_packet(struct sk_buff *skb, struct batman_if *batman_if) struct ethhdr *ethhdr;
/* drop packet if it has not necessary minimum size */ - if (unlikely(!pskb_may_pull(skb, sizeof(struct batman_packet)))) + if (unlikely(!pskb_may_pull(skb, sizeof(struct ogm_packet)))) return NET_RX_DROP;
ethhdr = (struct ethhdr *)skb_mac_header(skb); diff --git a/routing.h b/routing.h index 725cc38..0c62015 100644 --- a/routing.h +++ b/routing.h @@ -26,7 +26,7 @@
void slide_own_bcast_window(struct batman_if *batman_if); void receive_bat_packet(struct ethhdr *ethhdr, - struct batman_packet *batman_packet, + struct ogm_packet *ogm_packet, unsigned char *hna_buff, int hna_buff_len, struct batman_if *if_incoming); void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node, diff --git a/send.c b/send.c index 77f8297..5af04a9 100644 --- a/send.c +++ b/send.c @@ -40,8 +40,8 @@ static uint8_t hop_penalty(const uint8_t tq, struct bat_priv *bat_priv) return (tq * (TQ_MAX_VALUE - hop_penalty)) / (TQ_MAX_VALUE); }
-/* when do we schedule our own packet to be sent */ -static unsigned long own_send_time(struct bat_priv *bat_priv) +/* when do we schedule our own originator packet to be sent */ +static unsigned long own_ogm_send_time(struct bat_priv *bat_priv) { return jiffies + msecs_to_jiffies( atomic_read(&bat_priv->orig_interval) - @@ -109,7 +109,7 @@ static void send_packet_to_if(struct forw_packet *forw_packet, char *fwd_str; uint8_t packet_num; int16_t buff_pos; - struct batman_packet *batman_packet; + struct ogm_packet *ogm_packet; struct sk_buff *skb;
if (batman_if->if_status != IF_ACTIVE) @@ -117,20 +117,20 @@ static void send_packet_to_if(struct forw_packet *forw_packet,
packet_num = 0; buff_pos = 0; - batman_packet = (struct batman_packet *)forw_packet->skb->data; + ogm_packet = (struct ogm_packet *)forw_packet->skb->data;
/* adjust all flags and log packets */ while (aggregated_packet(buff_pos, forw_packet->packet_len, - batman_packet->num_hna)) { + ogm_packet->num_hna)) {
/* we might have aggregated direct link packets with an * ordinary base packet */ if ((forw_packet->direct_link_flags & (1 << packet_num)) && (forw_packet->if_incoming == batman_if)) - batman_packet->flags |= DIRECTLINK; + ogm_packet->flags |= DIRECTLINK; else - batman_packet->flags &= ~DIRECTLINK; + ogm_packet->flags &= ~DIRECTLINK;
fwd_str = (packet_num > 0 ? "Forwarding" : (forw_packet->own ? "Sending own" : @@ -139,16 +139,16 @@ static void send_packet_to_if(struct forw_packet *forw_packet, "%s %spacket (originator %pM, seqno %d, TQ %d, TTL %d," " IDF %s) on interface %s [%pM]\n", fwd_str, (packet_num > 0 ? "aggregated " : ""), - batman_packet->orig, ntohl(batman_packet->seqno), - batman_packet->tq, batman_packet->ttl, - (batman_packet->flags & DIRECTLINK ? + ogm_packet->orig, ntohl(ogm_packet->seqno), + ogm_packet->tq, ogm_packet->ttl, + (ogm_packet->flags & DIRECTLINK ? "on" : "off"), batman_if->net_dev->name, batman_if->net_dev->dev_addr);
- buff_pos += sizeof(struct batman_packet) + - (batman_packet->num_hna * ETH_ALEN); + buff_pos += sizeof(struct ogm_packet) + + (ogm_packet->num_hna * ETH_ALEN); packet_num++; - batman_packet = (struct batman_packet *) + ogm_packet = (struct ogm_packet *) (forw_packet->skb->data + buff_pos); }
@@ -164,9 +164,9 @@ static void send_packet(struct forw_packet *forw_packet) struct batman_if *batman_if; struct net_device *soft_iface; struct bat_priv *bat_priv; - struct batman_packet *batman_packet = - (struct batman_packet *)(forw_packet->skb->data); - unsigned char directlink = (batman_packet->flags & DIRECTLINK ? 1 : 0); + struct ogm_packet *ogm_packet = + (struct ogm_packet *)(forw_packet->skb->data); + unsigned char directlink = (ogm_packet->flags & DIRECTLINK ? 1 : 0);
if (!forw_packet->if_incoming) { pr_err("Error - can't forward packet: incoming iface not " @@ -182,7 +182,7 @@ static void send_packet(struct forw_packet *forw_packet)
/* multihomed peer assumed */ /* non-primary OGMs are only broadcasted on their interface */ - if ((directlink && (batman_packet->ttl == 1)) || + if ((directlink && (ogm_packet->ttl == 1)) || (forw_packet->own && (forw_packet->if_incoming->if_num > 0))) {
/* FIXME: what about aggregated packets ? */ @@ -190,8 +190,9 @@ static void send_packet(struct forw_packet *forw_packet) "%s packet (originator %pM, seqno %d, TTL %d) " "on interface %s [%pM]\n", (forw_packet->own ? "Sending own" : "Forwarding"), - batman_packet->orig, ntohl(batman_packet->seqno), - batman_packet->ttl, + ogm_packet->orig, + ntohl(ogm_packet->seqno), + ogm_packet->ttl, forw_packet->if_incoming->net_dev->name, forw_packet->if_incoming->net_dev->dev_addr);
@@ -214,26 +215,26 @@ static void send_packet(struct forw_packet *forw_packet) rcu_read_unlock(); }
-static void rebuild_batman_packet(struct bat_priv *bat_priv, - struct batman_if *batman_if) +static void rebuild_ogm_packet(struct bat_priv *bat_priv, + struct batman_if *batman_if) { int new_len; unsigned char *new_buff; - struct batman_packet *batman_packet; + struct ogm_packet *ogm_packet;
- new_len = sizeof(struct batman_packet) + + new_len = sizeof(struct ogm_packet) + (bat_priv->num_local_hna * ETH_ALEN); new_buff = kmalloc(new_len, GFP_ATOMIC);
/* keep old buffer if kmalloc should fail */ if (new_buff) { memcpy(new_buff, batman_if->packet_buff, - sizeof(struct batman_packet)); - batman_packet = (struct batman_packet *)new_buff; + sizeof(struct ogm_packet)); + ogm_packet = (struct ogm_packet *)new_buff;
- batman_packet->num_hna = hna_local_fill_buffer(bat_priv, - new_buff + sizeof(struct batman_packet), - new_len - sizeof(struct batman_packet)); + ogm_packet->num_hna = hna_local_fill_buffer(bat_priv, + new_buff + sizeof(struct ogm_packet), + new_len - sizeof(struct ogm_packet));
kfree(batman_if->packet_buff); batman_if->packet_buff = new_buff; @@ -241,11 +242,11 @@ static void rebuild_batman_packet(struct bat_priv *bat_priv, } }
-void schedule_own_packet(struct batman_if *batman_if) +void schedule_own_ogm_packet(struct batman_if *batman_if) { struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface); unsigned long send_time; - struct batman_packet *batman_packet; + struct ogm_packet *ogm_packet; int vis_server;
if ((batman_if->if_status == IF_NOT_IN_USE) || @@ -267,34 +268,34 @@ void schedule_own_packet(struct batman_if *batman_if) /* if local hna has changed and interface is a primary interface */ if ((atomic_read(&bat_priv->hna_local_changed)) && (batman_if == bat_priv->primary_if)) - rebuild_batman_packet(bat_priv, batman_if); + rebuild_ogm_packet(bat_priv, batman_if);
/** * NOTE: packet_buff might just have been re-allocated in - * rebuild_batman_packet() + * rebuild_ogm_packet() */ - batman_packet = (struct batman_packet *)batman_if->packet_buff; + ogm_packet = (struct ogm_packet *)batman_if->packet_buff;
/* change sequence number to network order */ - batman_packet->seqno = + ogm_packet->seqno = htonl((uint32_t)atomic_read(&batman_if->seqno));
if (vis_server == VIS_TYPE_SERVER_SYNC) - batman_packet->flags |= VIS_SERVER; + ogm_packet->flags |= VIS_SERVER; else - batman_packet->flags &= ~VIS_SERVER; + ogm_packet->flags &= ~VIS_SERVER;
if ((batman_if == bat_priv->primary_if) && (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER)) - batman_packet->gw_flags = + ogm_packet->gw_flags = (uint8_t)atomic_read(&bat_priv->gw_bandwidth); else - batman_packet->gw_flags = 0; + ogm_packet->gw_flags = 0;
atomic_inc(&batman_if->seqno);
slide_own_bcast_window(batman_if); - send_time = own_send_time(bat_priv); + send_time = own_ogm_send_time(bat_priv); add_bat_packet_to_list(bat_priv, batman_if->packet_buff, batman_if->packet_len, @@ -303,7 +304,7 @@ void schedule_own_packet(struct batman_if *batman_if)
void schedule_forward_packet(struct orig_node *orig_node, struct ethhdr *ethhdr, - struct batman_packet *batman_packet, + struct ogm_packet *ogm_packet, uint8_t directlink, int hna_buff_len, struct batman_if *if_incoming) { @@ -311,16 +312,16 @@ void schedule_forward_packet(struct orig_node *orig_node, unsigned char in_tq, in_ttl, tq_avg = 0; unsigned long send_time;
- if (batman_packet->ttl <= 1) { + if (ogm_packet->ttl <= 1) { bat_dbg(DBG_BATMAN, bat_priv, "ttl exceeded\n"); return; }
- in_tq = batman_packet->tq; - in_ttl = batman_packet->ttl; + in_tq = ogm_packet->tq; + in_ttl = ogm_packet->ttl;
- batman_packet->ttl--; - memcpy(batman_packet->prev_sender, ethhdr->h_source, ETH_ALEN); + ogm_packet->ttl--; + memcpy(ogm_packet->prev_sender, ethhdr->h_source, ETH_ALEN);
/* rebroadcast tq of our best ranking neighbor to ensure the rebroadcast * of our best tq value */ @@ -328,10 +329,10 @@ void schedule_forward_packet(struct orig_node *orig_node,
/* rebroadcast ogm of best ranking neighbor as is */ if (!compare_orig(orig_node->router->addr, ethhdr->h_source)) { - batman_packet->tq = orig_node->router->tq_avg; + ogm_packet->tq = orig_node->router->tq_avg;
if (orig_node->router->last_ttl) - batman_packet->ttl = orig_node->router->last_ttl + ogm_packet->ttl = orig_node->router->last_ttl - 1; }
@@ -339,27 +340,26 @@ void schedule_forward_packet(struct orig_node *orig_node, }
/* apply hop penalty */ - batman_packet->tq = hop_penalty(batman_packet->tq, bat_priv); + ogm_packet->tq = hop_penalty(ogm_packet->tq, bat_priv);
bat_dbg(DBG_BATMAN, bat_priv, "Forwarding packet: tq_orig: %i, tq_avg: %i, " "tq_forw: %i, ttl_orig: %i, ttl_forw: %i\n", - in_tq, tq_avg, batman_packet->tq, in_ttl - 1, - batman_packet->ttl); + in_tq, tq_avg, ogm_packet->tq, in_ttl - 1, ogm_packet->ttl);
- batman_packet->seqno = htonl(batman_packet->seqno); + ogm_packet->seqno = htonl(ogm_packet->seqno);
/* switch of primaries first hop flag when forwarding */ - batman_packet->flags &= ~PRIMARIES_FIRST_HOP; + ogm_packet->flags &= ~PRIMARIES_FIRST_HOP; if (directlink) - batman_packet->flags |= DIRECTLINK; + ogm_packet->flags |= DIRECTLINK; else - batman_packet->flags &= ~DIRECTLINK; + ogm_packet->flags &= ~DIRECTLINK;
send_time = forward_send_time(); add_bat_packet_to_list(bat_priv, - (unsigned char *)batman_packet, - sizeof(struct batman_packet) + hna_buff_len, + (unsigned char *)ogm_packet, + sizeof(struct ogm_packet) + hna_buff_len, if_incoming, 0, send_time); }
@@ -511,7 +511,7 @@ void send_outstanding_bat_packet(struct work_struct *work) * shutting down */ if (forw_packet->own) - schedule_own_packet(forw_packet->if_incoming); + schedule_own_ogm_packet(forw_packet->if_incoming);
out: /* don't count own packet */ diff --git a/send.h b/send.h index c4cefa8..2ac1b98 100644 --- a/send.h +++ b/send.h @@ -27,10 +27,10 @@ int send_skb_packet(struct sk_buff *skb, struct batman_if *batman_if, uint8_t *dst_addr); -void schedule_own_packet(struct batman_if *batman_if); +void schedule_own_ogm_packet(struct batman_if *batman_if); void schedule_forward_packet(struct orig_node *orig_node, struct ethhdr *ethhdr, - struct batman_packet *batman_packet, + struct ogm_packet *ogm_packet, uint8_t directlink, int hna_buff_len, struct batman_if *if_outgoing); int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb); diff --git a/soft-interface.c b/soft-interface.c index e89ede1..f9f98fb 100644 --- a/soft-interface.c +++ b/soft-interface.c @@ -221,28 +221,28 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, { struct bat_priv *bat_priv = netdev_priv(dev); struct ethhdr *ethhdr = (struct ethhdr *)skb->data; - struct batman_packet *batman_packet; + struct ogm_packet *ogm_packet; struct softif_neigh *softif_neigh, *softif_neigh_tmp;
if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) - batman_packet = (struct batman_packet *) + ogm_packet = (struct ogm_packet *) (skb->data + ETH_HLEN + VLAN_HLEN); else - batman_packet = (struct batman_packet *)(skb->data + ETH_HLEN); + ogm_packet = (struct ogm_packet *) (skb->data + ETH_HLEN);
- if (batman_packet->version != COMPAT_VERSION) + if (ogm_packet->version != COMPAT_VERSION) goto err;
- if (batman_packet->packet_type != BAT_PACKET) + if (ogm_packet->packet_type != BAT_PACKET_OGM) goto err;
- if (!(batman_packet->flags & PRIMARIES_FIRST_HOP)) + if (!(ogm_packet->flags & PRIMARIES_FIRST_HOP)) goto err;
- if (is_my_mac(batman_packet->orig)) + if (is_my_mac(ogm_packet->orig)) goto err;
- softif_neigh = softif_neigh_get(bat_priv, batman_packet->orig, vid); + softif_neigh = softif_neigh_get(bat_priv, ogm_packet->orig, vid);
if (!softif_neigh) goto err; diff --git a/translation-table.c b/translation-table.c index a633b5a..a758c7c 100644 --- a/translation-table.c +++ b/translation-table.c @@ -76,7 +76,7 @@ void hna_local_add(struct net_device *soft_iface, uint8_t *addr) space in batman_packet->num_hna That also should give a limit to MAC-flooding. */ required_bytes = (bat_priv->num_local_hna + 1) * ETH_ALEN; - required_bytes += BAT_PACKET_LEN; + required_bytes += BAT_PACKET_OGM_LEN;
if ((required_bytes > ETH_DATA_LEN) || (atomic_read(&bat_priv->aggregated_ogms) &&
The new neighbor discovery packets will later need their own interval per interface. For instance on a wifi interface which has regularly changing link qualities the ndp interval should be faster than on a static cable link where we would need some probes from time to time only.
This patch adds a workqueue per interface used by batman-adv. When an interface is active, a ndp_send() with the according batman_if structure will be called every second now.
Signed-off-by: Linus Lüssing linus.luessing@ascom.ch --- Makefile.kbuild | 1 + hard-interface.c | 9 +++++++ ndp.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ ndp.h | 31 +++++++++++++++++++++++ types.h | 3 ++ 5 files changed, 115 insertions(+), 0 deletions(-) create mode 100644 ndp.c create mode 100644 ndp.h
diff --git a/Makefile.kbuild b/Makefile.kbuild index e99c198..094eb31 100644 --- a/Makefile.kbuild +++ b/Makefile.kbuild @@ -42,6 +42,7 @@ batman-adv-y += hard-interface.o batman-adv-y += hash.o batman-adv-y += icmp_socket.o batman-adv-y += main.o +batman-adv-y += ndp.o batman-adv-y += originator.o batman-adv-y += ring_buffer.o batman-adv-y += routing.o diff --git a/hard-interface.c b/hard-interface.c index a992113..aba895f 100644 --- a/hard-interface.c +++ b/hard-interface.c @@ -26,6 +26,7 @@ #include "translation-table.h" #include "routing.h" #include "bat_sysfs.h" +#include "ndp.h" #include "originator.h" #include "hash.h"
@@ -260,6 +261,7 @@ static void hardif_activate_interface(struct batman_if *batman_if) batman_if->net_dev->name);
update_min_mtu(batman_if->soft_iface); + ndp_start_timer(batman_if); return; }
@@ -274,6 +276,7 @@ static void hardif_deactivate_interface(struct batman_if *batman_if) bat_info(batman_if->soft_iface, "Interface deactivated: %s\n", batman_if->net_dev->name);
+ ndp_stop_timer(batman_if); update_min_mtu(batman_if->soft_iface); }
@@ -328,6 +331,8 @@ int hardif_enable_interface(struct batman_if *batman_if, char *iface_name)
atomic_set(&batman_if->seqno, 1); atomic_set(&batman_if->frag_seqno, 1); + ndp_init(batman_if); + bat_info(batman_if->soft_iface, "Adding interface: %s\n", batman_if->net_dev->name);
@@ -381,6 +386,7 @@ void hardif_disable_interface(struct batman_if *batman_if)
bat_info(batman_if->soft_iface, "Removing interface: %s\n", batman_if->net_dev->name); + ndp_free(batman_if); dev_remove_pack(&batman_if->batman_adv_ptype); kref_put(&batman_if->refcount, hardif_free_ref);
@@ -435,6 +441,9 @@ static struct batman_if *hardif_add_interface(struct net_device *net_dev) if (ret) goto free_if;
+ atomic_set(&batman_if->ndp_interval, 500); + atomic_set(&batman_if->ndp_seqno, 0); + batman_if->if_num = -1; batman_if->net_dev = net_dev; batman_if->soft_iface = NULL; diff --git a/ndp.c b/ndp.c new file mode 100644 index 0000000..60631b0 --- /dev/null +++ b/ndp.c @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2010 B.A.T.M.A.N. contributors: + * + * Linus Lüssing + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * + */ + +#include "main.h" +#include "send.h" +#include "ndp.h" + +/* when do we schedule our own neighbor discovery packet to be sent */ +static unsigned long own_ndp_send_time(struct batman_if *batman_if) +{ + return jiffies + msecs_to_jiffies( + atomic_read(&batman_if->ndp_interval) - + JITTER + (random32() % 2*JITTER)); +} + +void ndp_start_timer(struct batman_if *batman_if) +{ + /* adding some jitter */ + unsigned long ndp_interval = own_ndp_send_time(batman_if); + queue_delayed_work(bat_event_workqueue, &batman_if->ndp_wq, + ndp_interval - jiffies); +} + +void ndp_stop_timer(struct batman_if *batman_if) +{ + cancel_delayed_work_sync(&batman_if->ndp_wq); +} + +static void ndp_send(struct work_struct *work) +{ + struct batman_if *batman_if = container_of(work, struct batman_if, + ndp_wq.work); + struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface); + + bat_dbg(DBG_BATMAN, bat_priv, + "batman-adv:Sending ndp packet on interface %s, seqno %d\n", + batman_if->net_dev, atomic_read(&batman_if->ndp_seqno)); + + atomic_inc(&batman_if->ndp_seqno); + ndp_start_timer(batman_if); +} + +int ndp_init(struct batman_if *batman_if) +{ + INIT_DELAYED_WORK(&batman_if->ndp_wq, ndp_send); + + return 0; +} + +void ndp_free(struct batman_if *batman_if) +{ + ndp_stop_timer(batman_if); +} diff --git a/ndp.h b/ndp.h new file mode 100644 index 0000000..1405e6b --- /dev/null +++ b/ndp.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2010 B.A.T.M.A.N. contributors: + * + * Linus Lüssing + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * + */ + +#ifndef _NET_BATMAN_ADV_NDP_H_ +#define _NET_BATMAN_ADV_NDP_H_ + +void ndp_start_timer(struct batman_if *batman_if); +void ndp_stop_timer(struct batman_if *batman_if); + +int ndp_init(struct batman_if *batman_if); +void ndp_free(struct batman_if *batman_if); + +#endif /* _NET_BATMAN_ADV_NDP_H_ */ diff --git a/types.h b/types.h index 09d18d8..3ef48a6 100644 --- a/types.h +++ b/types.h @@ -47,6 +47,9 @@ struct batman_if { struct packet_type batman_adv_ptype; struct net_device *soft_iface; struct rcu_head rcu; + atomic_t ndp_interval; + atomic_t ndp_seqno; + struct delayed_work ndp_wq; };
/**
This patch makes use of the previously introduced periodic tasks per interface and actually sends neighbor discovery packets on these now. Note: The TQ values of each neighbor are not being added yet to these NDPs and also no evaluation of these packets is being done.
Also most of the packet type numbers got changed due to their reordering.
Signed-off-by: Linus Lüssing linus.luessing@ascom.ch --- hard-interface.c | 12 +++++++++++- ndp.c | 35 ++++++++++++++++++++++++++++++++++- packet.h | 23 +++++++++++++++++------ types.h | 1 + 4 files changed, 63 insertions(+), 8 deletions(-)
diff --git a/hard-interface.c b/hard-interface.c index aba895f..3dc24f1 100644 --- a/hard-interface.c +++ b/hard-interface.c @@ -284,6 +284,7 @@ int hardif_enable_interface(struct batman_if *batman_if, char *iface_name) { struct bat_priv *bat_priv; struct ogm_packet *ogm_packet; + int ret;
if (batman_if->if_status != IF_NOT_IN_USE) goto out; @@ -331,7 +332,9 @@ int hardif_enable_interface(struct batman_if *batman_if, char *iface_name)
atomic_set(&batman_if->seqno, 1); atomic_set(&batman_if->frag_seqno, 1); - ndp_init(batman_if); + ret = ndp_init(batman_if); + if (ret) + goto free;
bat_info(batman_if->soft_iface, "Adding interface: %s\n", batman_if->net_dev->name); @@ -369,7 +372,14 @@ int hardif_enable_interface(struct batman_if *batman_if, char *iface_name)
out: return 0; +free: + dev_remove_pack(&batman_if->batman_adv_ptype); + kref_put(&batman_if->refcount, hardif_free_ref);
+ bat_priv->num_ifaces--; + orig_hash_del_if(batman_if, bat_priv->num_ifaces); + + kfree(batman_if->packet_buff); err: return -ENOMEM; } diff --git a/ndp.c b/ndp.c index 60631b0..3269d67 100644 --- a/ndp.c +++ b/ndp.c @@ -49,10 +49,21 @@ static void ndp_send(struct work_struct *work) struct batman_if *batman_if = container_of(work, struct batman_if, ndp_wq.work); struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface); + struct batman_packet_ndp *ndp_packet; + struct sk_buff *skb; + + skb = skb_copy(batman_if->ndp_skb, GFP_ATOMIC); + ndp_packet = (struct batman_packet_ndp *)skb->data; + ndp_packet->seqno = htonl(atomic_read(&batman_if->ndp_seqno)); + ndp_packet->num_neighbors = 0; + memcpy(ndp_packet->orig, bat_priv->primary_if->net_dev->dev_addr, + ETH_ALEN);
bat_dbg(DBG_BATMAN, bat_priv, "batman-adv:Sending ndp packet on interface %s, seqno %d\n", - batman_if->net_dev, atomic_read(&batman_if->ndp_seqno)); + batman_if->net_dev, ntohl(ndp_packet->seqno)); + + send_skb_packet(skb, batman_if, broadcast_addr);
atomic_inc(&batman_if->ndp_seqno); ndp_start_timer(batman_if); @@ -60,12 +71,34 @@ static void ndp_send(struct work_struct *work)
int ndp_init(struct batman_if *batman_if) { + struct batman_packet_ndp *ndp_packet; + + batman_if->ndp_skb = + dev_alloc_skb(ETH_DATA_LEN + sizeof(struct ethhdr)); + if (!batman_if->ndp_skb) { + printk(KERN_ERR "batman-adv: Can't add " + "local interface packet (%s): out of memory\n", + batman_if->net_dev->name); + goto err; + } + skb_reserve(batman_if->ndp_skb, sizeof(struct ethhdr) + + sizeof(struct batman_packet_ndp)); + ndp_packet = (struct batman_packet_ndp *) + skb_push(batman_if->ndp_skb, sizeof(struct batman_packet_ndp)); + memset(ndp_packet, 0, sizeof(struct batman_packet_ndp)); + + ndp_packet->packet_type = BAT_PACKET_NDP; + ndp_packet->version = COMPAT_VERSION; + INIT_DELAYED_WORK(&batman_if->ndp_wq, ndp_send);
return 0; +err: + return 1; }
void ndp_free(struct batman_if *batman_if) { ndp_stop_timer(batman_if); + dev_kfree_skb(batman_if->ndp_skb); } diff --git a/packet.h b/packet.h index 681052d..0b0c453 100644 --- a/packet.h +++ b/packet.h @@ -24,12 +24,13 @@
#define ETH_P_BATMAN 0x4305 /* unofficial/not registered Ethertype */
-#define BAT_PACKET_OGM 0x01 -#define BAT_ICMP 0x02 -#define BAT_UNICAST 0x03 -#define BAT_BCAST 0x04 -#define BAT_VIS 0x05 -#define BAT_UNICAST_FRAG 0x06 +#define BAT_PACKET_NDP 0x01 +#define BAT_PACKET_OGM 0x02 +#define BAT_ICMP 0x03 +#define BAT_UNICAST 0x04 +#define BAT_UNICAST_FRAG 0x05 +#define BAT_BCAST 0x06 +#define BAT_VIS 0x07
/* this file is included by batctl which needs these defines */ #define COMPAT_VERSION 12 @@ -51,6 +52,16 @@ /* fragmentation defines */ #define UNI_FRAG_HEAD 0x01
+/* Neighbor discovery packet */ +struct batman_packet_ndp { + uint8_t packet_type; + uint8_t version; /* batman version field */ + uint8_t orig[6]; + uint32_t seqno; + uint8_t num_neighbors; + uint8_t align[3]; +} __attribute__((packed)); + /* Originator message packet */ struct ogm_packet { uint8_t packet_type; diff --git a/types.h b/types.h index 3ef48a6..f81d0ba 100644 --- a/types.h +++ b/types.h @@ -49,6 +49,7 @@ struct batman_if { struct rcu_head rcu; atomic_t ndp_interval; atomic_t ndp_seqno; + struct sk_buff *ndp_skb; struct delayed_work ndp_wq; };
It will now be checked if a neighbor discovery packet from a new neighbor on a certain interface has been received. If so, structures in memory will be allocated for further seqno-tracking and RQ calculations, and TQ reception, which will be updated frequently from this commit on.
Signed-off-by: Linus Lüssing linus.luessing@ascom.ch --- hard-interface.c | 5 ++ ndp.c | 145 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ ndp.h | 4 ++ routing.c | 42 +++++++++++++++- routing.h | 1 + types.h | 9 +++ 6 files changed, 205 insertions(+), 1 deletions(-)
diff --git a/hard-interface.c b/hard-interface.c index 3dc24f1..f4bbb1a 100644 --- a/hard-interface.c +++ b/hard-interface.c @@ -618,6 +618,11 @@ int batman_skb_recv(struct sk_buff *skb, struct net_device *dev, * the supplied skb. if not, we have to free the skb. */
switch (ogm_packet->packet_type) { + /* batman neighbor discovery protocol packet */ + case BAT_PACKET_NDP: + ret = recv_ndp_packet(skb, batman_if); + break; + /* batman originator packet */ case BAT_PACKET_OGM: ret = recv_bat_packet(skb, batman_if); diff --git a/ndp.c b/ndp.c index 3269d67..23e3bcd 100644 --- a/ndp.c +++ b/ndp.c @@ -22,6 +22,7 @@ #include "main.h" #include "send.h" #include "ndp.h" +#include "originator.h"
/* when do we schedule our own neighbor discovery packet to be sent */ static unsigned long own_ndp_send_time(struct batman_if *batman_if) @@ -50,6 +51,10 @@ static void ndp_send(struct work_struct *work) ndp_wq.work); struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface); struct batman_packet_ndp *ndp_packet; + struct neigh_entry *neigh_entry; + struct neigh_node *neigh_node; + struct hlist_node *node; + int entries_len = 0; struct sk_buff *skb;
skb = skb_copy(batman_if->ndp_skb, GFP_ATOMIC); @@ -59,6 +64,22 @@ static void ndp_send(struct work_struct *work) memcpy(ndp_packet->orig, bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN);
+ neigh_entry = (struct neigh_entry *)(ndp_packet + 1); + spin_lock_bh(&batman_if->neigh_list_lock); + hlist_for_each_entry(neigh_node, node, &batman_if->neigh_list, list) { + if (entries_len + sizeof(struct neigh_entry) > + skb_tailroom(skb)) + break; + + memcpy(neigh_entry->addr, neigh_node->addr, ETH_ALEN); + neigh_entry->rq = neigh_node->rq; + ndp_packet->num_neighbors++; + neigh_entry++; + entries_len += sizeof(struct neigh_entry); + } + spin_unlock_bh(&batman_if->neigh_list_lock); + skb_put(skb, entries_len); + bat_dbg(DBG_BATMAN, bat_priv, "batman-adv:Sending ndp packet on interface %s, seqno %d\n", batman_if->net_dev, ntohl(ndp_packet->seqno)); @@ -90,6 +111,9 @@ int ndp_init(struct batman_if *batman_if) ndp_packet->packet_type = BAT_PACKET_NDP; ndp_packet->version = COMPAT_VERSION;
+ INIT_HLIST_HEAD(&batman_if->neigh_list); + spin_lock_init(&batman_if->neigh_list_lock); + INIT_DELAYED_WORK(&batman_if->ndp_wq, ndp_send);
return 0; @@ -102,3 +126,124 @@ void ndp_free(struct batman_if *batman_if) ndp_stop_timer(batman_if); dev_kfree_skb(batman_if->ndp_skb); } + +/* extract my own tq to neighbor from the ndp packet */ +uint8_t ndp_fetch_tq(struct batman_packet_ndp *packet, + uint8_t *my_if_addr) +{ + struct neigh_entry *neigh_entry = (struct neigh_entry *)(packet + 1); + uint8_t tq = 0; + int i; + + for (i = 0; i < packet->num_neighbors; i++) { + if (compare_orig(my_if_addr, neigh_entry->addr)) { + tq = neigh_entry->rq; + break; + } + neigh_entry++; + } + return tq; +} + +static void ndp_update_neighbor_lq(uint8_t tq, uint32_t seqno, + struct neigh_node *neigh_node, + struct bat_priv *bat_priv) +{ + char is_duplicate = 0; + int32_t seq_diff; + int need_update = 0; + + seq_diff = seqno - neigh_node->last_rq_seqno; + + is_duplicate |= get_bit_status(neigh_node->ndp_rq_window, + neigh_node->last_rq_seqno, + seqno); + + /* if the window moved, set the update flag. */ + need_update |= bit_get_packet(bat_priv, neigh_node->ndp_rq_window, + seq_diff, 1); + /* TODO: rename TQ_LOCAL_WINDOW_SIZE to RQ_LOCAL... */ + neigh_node->rq = + (bit_packet_count(neigh_node->ndp_rq_window) * TQ_MAX_VALUE) + / TQ_LOCAL_WINDOW_SIZE; + + if (need_update) { + bat_dbg(DBG_BATMAN, bat_priv, "batman-adv: ndp: " + "updating last_seqno of neighbor %pM: old %d, new %d\n", + neigh_node->addr, neigh_node->last_rq_seqno, seqno); + /* TODO: this is not really an average here, + need to change the variable name later */ + neigh_node->tq_avg = tq; + neigh_node->last_valid = jiffies; + neigh_node->last_rq_seqno = seqno; + } + + if (is_duplicate) + bat_dbg(DBG_BATMAN, bat_priv, + "seqno %d of neighbor %pM was a duplicate!\n", + seqno, neigh_node->addr); + + bat_dbg(DBG_BATMAN, bat_priv, "batman-adv: ndp: " + "new rq/tq of neighbor %pM: rq %d, tq %d\n", + neigh_node->addr, neigh_node->rq, neigh_node->tq_avg); +} + +static struct neigh_node *ndp_create_neighbor(uint8_t my_tq, uint32_t seqno, + uint8_t *neigh_addr, + struct bat_priv *bat_priv) +{ + struct neigh_node *neigh_node; + + bat_dbg(DBG_BATMAN, bat_priv, + "batman-adv: ndp: Creating new neighbor %pM, " + "initial tq %d, initial seqno %d\n", + neigh_addr, my_tq, seqno); + + neigh_node = kzalloc(sizeof(struct neigh_node), GFP_ATOMIC); + if (!neigh_node) + return NULL; + + INIT_HLIST_NODE(&neigh_node->list); + memcpy(neigh_node->addr, neigh_addr, ETH_ALEN); + neigh_node->last_rq_seqno = seqno - 1; + + return neigh_node; +} + +int ndp_update_neighbor(uint8_t my_tq, uint32_t seqno, + struct batman_if *batman_if, uint8_t *neigh_addr) +{ + struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface); + struct neigh_node *neigh_node = NULL, *tmp_neigh_node; + struct hlist_node *node; + int ret = 1; + + spin_lock_bh(&batman_if->neigh_list_lock); + /* old neighbor? */ + hlist_for_each_entry(tmp_neigh_node, node, &batman_if->neigh_list, + list) { + if (!compare_orig(tmp_neigh_node->addr, neigh_addr)) + continue; + + neigh_node = tmp_neigh_node; + break; + } + + /* new neighbor? */ + if (!neigh_node) { + neigh_node = ndp_create_neighbor(my_tq, seqno, neigh_addr, + bat_priv); + if (!neigh_node) + goto ret; + + hlist_add_head(&neigh_node->list, &batman_if->neigh_list); + } + + ndp_update_neighbor_lq(my_tq, seqno, neigh_node, bat_priv); + + ret = 0; + +ret: + spin_unlock_bh(&batman_if->neigh_list_lock); + return ret; +} diff --git a/ndp.h b/ndp.h index 1405e6b..2496c3f 100644 --- a/ndp.h +++ b/ndp.h @@ -27,5 +27,9 @@ void ndp_stop_timer(struct batman_if *batman_if);
int ndp_init(struct batman_if *batman_if); void ndp_free(struct batman_if *batman_if); +uint8_t ndp_fetch_tq(struct batman_packet_ndp *packet, + uint8_t *my_if_addr); +int ndp_update_neighbor(uint8_t my_tq, uint32_t seqno, + struct batman_if *batman_if, uint8_t *neigh_addr);
#endif /* _NET_BATMAN_ADV_NDP_H_ */ diff --git a/routing.c b/routing.c index 1782777..947592f 100644 --- a/routing.c +++ b/routing.c @@ -27,6 +27,7 @@ #include "hard-interface.h" #include "icmp_socket.h" #include "translation-table.h" +#include "ndp.h" #include "originator.h" #include "types.h" #include "ring_buffer.h" @@ -790,7 +791,46 @@ void receive_bat_packet(struct ethhdr *ethhdr, 0, hna_buff_len, if_incoming); }
-int recv_bat_packet(struct sk_buff *skb, struct batman_if *batman_if) +int recv_ndp_packet(struct sk_buff *skb, struct batman_if *batman_if) +{ + struct ethhdr *ethhdr; + struct batman_packet_ndp *packet; + int ret; + uint8_t my_tq; + + /* keep skb linear */ + if (skb_linearize(skb) < 0) + return NET_RX_DROP; + + /* drop packet if it has not necessary minimum size */ + if (unlikely(!pskb_may_pull(skb, sizeof(struct batman_packet_ndp)))) + return NET_RX_DROP; + + ethhdr = (struct ethhdr *)skb_mac_header(skb); + + /* packet with broadcast indication but unicast recipient */ + if (!is_broadcast_ether_addr(ethhdr->h_dest)) + return NET_RX_DROP; + + /* packet with broadcast sender address */ + if (is_broadcast_ether_addr(ethhdr->h_source)) + return NET_RX_DROP; + + packet = (struct batman_packet_ndp *)(ethhdr + 1); + + my_tq = ndp_fetch_tq(packet, batman_if->net_dev->dev_addr); + + ret = ndp_update_neighbor(my_tq, ntohl(packet->seqno), + batman_if, ethhdr->h_source); + if (ret) + return NET_RX_DROP; + + dev_kfree_skb(skb); + return NET_RX_SUCCESS; +} + +int recv_bat_packet(struct sk_buff *skb, + struct batman_if *batman_if) { struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface); struct ethhdr *ethhdr; diff --git a/routing.h b/routing.h index 0c62015..24567f9 100644 --- a/routing.h +++ b/routing.h @@ -39,6 +39,7 @@ int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if); int recv_ucast_frag_packet(struct sk_buff *skb, struct batman_if *recv_if); int recv_bcast_packet(struct sk_buff *skb, struct batman_if *recv_if); int recv_vis_packet(struct sk_buff *skb, struct batman_if *recv_if); +int recv_ndp_packet(struct sk_buff *skb, struct batman_if *recv_if); int recv_bat_packet(struct sk_buff *skb, struct batman_if *recv_if); struct neigh_node *find_router(struct bat_priv *bat_priv, struct orig_node *orig_node, struct batman_if *recv_if); diff --git a/types.h b/types.h index f81d0ba..43721cf 100644 --- a/types.h +++ b/types.h @@ -51,6 +51,8 @@ struct batman_if { atomic_t ndp_seqno; struct sk_buff *ndp_skb; struct delayed_work ndp_wq; + struct hlist_head neigh_list; + spinlock_t neigh_list_lock; };
/** @@ -113,6 +115,9 @@ struct neigh_node { struct hlist_node list; uint8_t addr[ETH_ALEN]; uint8_t real_packet_count; + uint8_t rq; + uint32_t last_rq_seqno; + unsigned long ndp_rq_window[NUM_WORDS]; uint8_t tq_recv[TQ_GLOBAL_WINDOW_SIZE]; uint8_t tq_index; uint8_t tq_avg; @@ -126,6 +131,10 @@ struct neigh_node { struct batman_if *if_incoming; };
+struct neigh_entry { + uint8_t addr[ETH_ALEN]; + uint8_t rq; +};
struct bat_priv { atomic_t mesh_state;
If no new packet has been received from a neighbour for a while, then delete it from memory.
Signed-off-by: Linus Lüssing linus.luessing@ascom.ch --- ndp.c | 28 ++++++++++++++++++++++++++++ ndp.h | 1 + originator.c | 2 ++ 3 files changed, 31 insertions(+), 0 deletions(-)
diff --git a/ndp.c b/ndp.c index 23e3bcd..dbb0e9e 100644 --- a/ndp.c +++ b/ndp.c @@ -22,6 +22,7 @@ #include "main.h" #include "send.h" #include "ndp.h" +#include "hard-interface.h" #include "originator.h"
/* when do we schedule our own neighbor discovery packet to be sent */ @@ -210,6 +211,33 @@ static struct neigh_node *ndp_create_neighbor(uint8_t my_tq, uint32_t seqno, return neigh_node; }
+void ndp_purge_neighbors(void) +{ + struct neigh_node *neigh_node; + struct hlist_node *node, *node_tmp; + struct batman_if *batman_if; + + rcu_read_lock(); + list_for_each_entry_rcu(batman_if, &if_list, list) { + if (batman_if->if_status != IF_ACTIVE) + continue; + + spin_lock_bh(&batman_if->neigh_list_lock); + hlist_for_each_entry_safe(neigh_node, node, node_tmp, + &batman_if->neigh_list, list) { + if (time_before(jiffies, neigh_node->last_valid + + msecs_to_jiffies(PURGE_TIMEOUT * + 1000))) + continue; + + hlist_del(&neigh_node->list); + kfree(neigh_node); + } + spin_unlock_bh(&batman_if->neigh_list_lock); + } + rcu_read_unlock(); +} + int ndp_update_neighbor(uint8_t my_tq, uint32_t seqno, struct batman_if *batman_if, uint8_t *neigh_addr) { diff --git a/ndp.h b/ndp.h index 2496c3f..a828362 100644 --- a/ndp.h +++ b/ndp.h @@ -29,6 +29,7 @@ int ndp_init(struct batman_if *batman_if); void ndp_free(struct batman_if *batman_if); uint8_t ndp_fetch_tq(struct batman_packet_ndp *packet, uint8_t *my_if_addr); +void ndp_purge_neighbors(void); int ndp_update_neighbor(uint8_t my_tq, uint32_t seqno, struct batman_if *batman_if, uint8_t *neigh_addr);
diff --git a/originator.c b/originator.c index c043bf8..e98add5 100644 --- a/originator.c +++ b/originator.c @@ -22,6 +22,7 @@ /* increase the reference counter for this originator */
#include "main.h" +#include "ndp.h" #include "originator.h" #include "hash.h" #include "translation-table.h" @@ -334,6 +335,7 @@ static void purge_orig(struct work_struct *work) container_of(delayed_work, struct bat_priv, orig_work);
_purge_orig(bat_priv); + ndp_purge_neighbors(); start_purge_timer(bat_priv); }
Lists all neighbours and their tq/rq values detected and measured by the Neighbor Discovery Protocol (NDP).
Signed-off-by: Linus Lüssing linus.luessing@ascom.ch --- bat_debugfs.c | 9 ++++++++ ndp.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ndp.h | 1 + 3 files changed, 70 insertions(+), 0 deletions(-)
diff --git a/bat_debugfs.c b/bat_debugfs.c index 0ae81d0..602aa15 100644 --- a/bat_debugfs.c +++ b/bat_debugfs.c @@ -25,6 +25,7 @@
#include "bat_debugfs.h" #include "translation-table.h" +#include "ndp.h" #include "originator.h" #include "hard-interface.h" #include "gateway_common.h" @@ -222,6 +223,12 @@ static void debug_log_cleanup(struct bat_priv *bat_priv) } #endif
+static int neighbors_open(struct inode *inode, struct file *file) +{ + struct net_device *net_dev = (struct net_device *)inode->i_private; + return single_open(file, ndp_seq_print_text, net_dev); +} + static int originators_open(struct inode *inode, struct file *file) { struct net_device *net_dev = (struct net_device *)inode->i_private; @@ -275,6 +282,7 @@ struct bat_debuginfo bat_debuginfo_##_name = { \ } \ };
+static BAT_DEBUGINFO(neighbors, S_IRUGO, neighbors_open); static BAT_DEBUGINFO(originators, S_IRUGO, originators_open); static BAT_DEBUGINFO(gateways, S_IRUGO, gateways_open); static BAT_DEBUGINFO(softif_neigh, S_IRUGO, softif_neigh_open); @@ -283,6 +291,7 @@ static BAT_DEBUGINFO(transtable_local, S_IRUGO, transtable_local_open); static BAT_DEBUGINFO(vis_data, S_IRUGO, vis_data_open);
static struct bat_debuginfo *mesh_debuginfos[] = { + &bat_debuginfo_neighbors, &bat_debuginfo_originators, &bat_debuginfo_gateways, &bat_debuginfo_softif_neigh, diff --git a/ndp.c b/ndp.c index dbb0e9e..9f498f9 100644 --- a/ndp.c +++ b/ndp.c @@ -275,3 +275,63 @@ ret: spin_unlock_bh(&batman_if->neigh_list_lock); return ret; } + +int ndp_seq_print_text(struct seq_file *seq, void *offset) +{ + struct neigh_node *neigh_node; + struct batman_if *batman_if; + struct hlist_node *node; + int last_seen_secs; + int last_seen_msecs; + int batman_count = 0; + struct net_device *net_dev = (struct net_device *)seq->private; + struct bat_priv *bat_priv = netdev_priv(net_dev); + + if ((!bat_priv->primary_if) || + (bat_priv->primary_if->if_status != IF_ACTIVE)) { + if (!bat_priv->primary_if) + return seq_printf(seq, "BATMAN mesh %s disabled - " + "please specify interfaces to enable it\n", + net_dev->name); + + return seq_printf(seq, "BATMAN mesh %s " + "disabled - primary interface not active\n", + net_dev->name); + } + + seq_printf(seq, "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n", + SOURCE_VERSION, REVISION_VERSION_STR, + bat_priv->primary_if->net_dev->name, + bat_priv->primary_if->net_dev->dev_addr, net_dev->name); + seq_printf(seq, " %-15s %s (%s/%i) [%10s]\n", + "Neighbor", "last-seen", "#TQ,#RQ", TQ_MAX_VALUE, "IF"); + + rcu_read_lock(); + list_for_each_entry_rcu(batman_if, &if_list, list) { + if (batman_if->if_status != IF_ACTIVE) + continue; + + spin_lock_bh(&batman_if->neigh_list_lock); + hlist_for_each_entry(neigh_node, node, &batman_if->neigh_list, + list) { + last_seen_secs = jiffies_to_msecs(jiffies - + neigh_node->last_valid) / 1000; + last_seen_msecs = jiffies_to_msecs(jiffies - + neigh_node->last_valid) % 1000; + + seq_printf(seq, "%pM %4i.%03is (%3i,%3i) [%10s]\n", + neigh_node->addr, last_seen_secs, + last_seen_msecs, neigh_node->tq_avg, + neigh_node->rq, batman_if->net_dev->name); + + batman_count++; + } + spin_unlock_bh(&batman_if->neigh_list_lock); + } + rcu_read_unlock(); + + if ((batman_count == 0)) + seq_printf(seq, "No batman nodes in range ...\n"); + + return 0; +} diff --git a/ndp.h b/ndp.h index a828362..f528bcf 100644 --- a/ndp.h +++ b/ndp.h @@ -32,5 +32,6 @@ uint8_t ndp_fetch_tq(struct batman_packet_ndp *packet, void ndp_purge_neighbors(void); int ndp_update_neighbor(uint8_t my_tq, uint32_t seqno, struct batman_if *batman_if, uint8_t *neigh_addr); +int ndp_seq_print_text(struct seq_file *seq, void *offset);
#endif /* _NET_BATMAN_ADV_NDP_H_ */
This allows us to easily add a sysfs parameter for an unsigned int later, which is not for a batman mesh interface (e.g. bat0), but for a common interface instead. It allows reading and writing an atomic_t in batman_if (instead of bat_priv compared to the mesh variant).
Signed-off-by: Linus Lüssing linus.luessing@ascom.ch --- bat_sysfs.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 43 insertions(+), 0 deletions(-)
diff --git a/bat_sysfs.c b/bat_sysfs.c index cd7bb51..5954389 100644 --- a/bat_sysfs.c +++ b/bat_sysfs.c @@ -94,6 +94,49 @@ ssize_t show_##_name(struct kobject *kobj, struct attribute *attr, \ static BAT_ATTR(_name, _mode, show_##_name, store_##_name)
+#define BAT_ATTR_IF_STORE_UINT(_name, _min, _max, _post_func) \ +ssize_t store_##_name(struct kobject *kobj, struct attribute *attr, \ + char *buff, size_t count) \ +{ \ + struct net_device *net_dev = kobj_to_netdev(kobj); \ + struct batman_if *batman_if = get_batman_if_by_netdev(net_dev); \ + ssize_t length; \ + \ + if (!batman_if) \ + return 0; \ + \ + length = __store_uint_attr(buff, count, _min, _max, _post_func, \ + attr, &batman_if->_name, net_dev); \ + \ + kref_put(&batman_if->refcount, hardif_free_ref); \ + return length; \ +} + +#define BAT_ATTR_IF_SHOW_UINT(_name) \ +ssize_t show_##_name(struct kobject *kobj, struct attribute *attr, \ + char *buff) \ +{ \ + struct net_device *net_dev = kobj_to_netdev(kobj); \ + struct batman_if *batman_if = get_batman_if_by_netdev(net_dev); \ + ssize_t length; \ + \ + if (!batman_if) \ + return 0; \ + \ + length = sprintf(buff, "%i\n", atomic_read(&batman_if->_name)); \ + \ + kref_put(&batman_if->refcount, hardif_free_ref); \ + return length; \ +} + +/* Use this, if you are going to set [name] in batman_if to unsigned integer + * values only */ +#define BAT_ATTR_IF_UINT(_name, _mode, _min, _max, _post_func) \ + static BAT_ATTR_IF_STORE_UINT(_name, _min, _max, _post_func) \ + static BAT_ATTR_IF_SHOW_UINT(_name) \ + static BAT_ATTR(_name, _mode, show_##_name, store_##_name) + + static int store_bool_attr(char *buff, size_t count, struct net_device *net_dev, char *attr_name, atomic_t *attr)
This parameter can be set individually on each interface and allows the configuration of the ndp interval for the link quality measurements during runtime. Usually it is desirable to set it to a higher (= slower) value on interfaces which have a more static characteristic (e.g. wired interfaces) or very dense neighbourhoods to reduce overhead.
Signed-off-by: Linus Lüssing linus.luessing@ascom.ch --- bat_sysfs.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/bat_sysfs.c b/bat_sysfs.c index 5954389..ae15a94 100644 --- a/bat_sysfs.c +++ b/bat_sysfs.c @@ -588,10 +588,12 @@ static ssize_t show_iface_status(struct kobject *kobj, struct attribute *attr, static BAT_ATTR(mesh_iface, S_IRUGO | S_IWUSR, show_mesh_iface, store_mesh_iface); static BAT_ATTR(iface_status, S_IRUGO, show_iface_status, NULL); +BAT_ATTR_IF_UINT(ndp_interval, S_IRUGO | S_IWUSR, 2 * JITTER, INT_MAX, NULL);
static struct bat_attribute *batman_attrs[] = { &bat_attr_mesh_iface, &bat_attr_iface_status, + &bat_attr_ndp_interval, NULL, };
With this commit not the local transmit quality values determined by the OGMs themselves are applied on received OGMs, but the local transmit quality detemined by NDP instead. Usually the link quality measurements of NDP are more up-to-date than the one of the OGMs, as NDP is using a more frequent interval because NDP's packets are not being flooded through the whole mesh.
Signed-off-by: Linus Lüssing linus.luessing@ascom.ch --- routing.c | 64 ++++++++++++++++++++++++++++-------------------------------- 1 files changed, 30 insertions(+), 34 deletions(-)
diff --git a/routing.c b/routing.c index 947592f..8a3acfa 100644 --- a/routing.c +++ b/routing.c @@ -152,7 +152,7 @@ static int is_bidirectional_neigh(struct orig_node *orig_node, struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL; struct hlist_node *node; - unsigned char total_count; + uint8_t local_tq = 0, local_rq = 0;
if (orig_node == orig_neigh_node) { rcu_read_lock(); @@ -199,25 +199,23 @@ static int is_bidirectional_neigh(struct orig_node *orig_node, return 0; }
- orig_node->last_valid = jiffies; + /* note, bottom halves are already deactivated outside in + * recv_bat_packet() */ + spin_lock(&if_incoming->neigh_list_lock); + hlist_for_each_entry(neigh_node, node, &if_incoming->neigh_list, + list) { + if (!compare_orig(neigh_node->addr, orig_neigh_node->orig)) + continue;
- /* pay attention to not get a value bigger than 100 % */ - total_count = (orig_neigh_node->bcast_own_sum[if_incoming->if_num] > - neigh_node->real_packet_count ? - neigh_node->real_packet_count : - orig_neigh_node->bcast_own_sum[if_incoming->if_num]); + orig_node->last_valid = jiffies; + local_tq = neigh_node->tq_avg; + local_rq = neigh_node->rq; + break; + } + spin_unlock(&if_incoming->neigh_list_lock);
- /* if we have too few packets (too less data) we set tq_own to zero */ - /* if we receive too few packets it is not considered bidirectional */ - if ((total_count < TQ_LOCAL_BIDRECT_SEND_MINIMUM) || - (neigh_node->real_packet_count < TQ_LOCAL_BIDRECT_RECV_MINIMUM)) - orig_neigh_node->tq_own = 0; - else - /* neigh_node->real_packet_count is never zero as we - * only purge old information when getting new - * information */ - orig_neigh_node->tq_own = (TQ_MAX_VALUE * total_count) / - neigh_node->real_packet_count; + if (local_tq == 0) + return 0;
/* * 1 - ((1-x) ** 3), normalized to TQ_MAX_VALUE this does @@ -228,25 +226,22 @@ static int is_bidirectional_neigh(struct orig_node *orig_node, orig_neigh_node->tq_asym_penalty = TQ_MAX_VALUE - (TQ_MAX_VALUE * - (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count) * - (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count) * - (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count)) / - (TQ_LOCAL_WINDOW_SIZE * - TQ_LOCAL_WINDOW_SIZE * - TQ_LOCAL_WINDOW_SIZE); - - ogm_packet->tq = ((ogm_packet->tq * - orig_neigh_node->tq_own * - orig_neigh_node->tq_asym_penalty) / - (TQ_MAX_VALUE * TQ_MAX_VALUE)); + (TQ_MAX_VALUE - local_rq) * + (TQ_MAX_VALUE - local_rq) * + (TQ_MAX_VALUE - local_rq)) / + (TQ_MAX_VALUE * + TQ_MAX_VALUE * + TQ_MAX_VALUE); + + ogm_packet->tq = ((ogm_packet->tq * local_tq * + orig_neigh_node->tq_asym_penalty) / + (TQ_MAX_VALUE * TQ_MAX_VALUE));
bat_dbg(DBG_BATMAN, bat_priv, "bidirectional: " - "orig = %-15pM neigh = %-15pM => own_bcast = %2i, " - "real recv = %2i, local tq: %3i, asym_penalty: %3i, " - "total tq: %3i\n", - orig_node->orig, orig_neigh_node->orig, total_count, - neigh_node->real_packet_count, orig_neigh_node->tq_own, + "orig = %-15pM neigh = %-15pM => local tq = %3i, " + "local rq: %3i, asym_penalty: %3i, total tq: %3i\n", + orig_node->orig, orig_neigh_node->orig, local_tq, local_rq, orig_neigh_node->tq_asym_penalty, ogm_packet->tq);
/* if link has the minimum required transmission quality @@ -859,6 +854,7 @@ int recv_bat_packet(struct sk_buff *skb,
ethhdr = (struct ethhdr *)skb_mac_header(skb);
+ /* note, is_bidirectional_neigh() relies on deactivated bottom halves */ spin_lock_bh(&bat_priv->orig_hash_lock); receive_aggr_bat_packet(ethhdr, skb->data,
With this commit only spinlocking for reading/writing variables inside a neigh_node for NDP is used. The neigh_list traversal and entry deleting/adding is done with rcu-locking and reference counting instead to greatly reduce the time of (concurrent) spinlocking.
Signed-off-by: Linus Lüssing linus.luessing@ascom.ch --- ndp.c | 54 ++++++++++++++++++++++++++++++++++++++---------------- originator.c | 2 +- originator.h | 1 + routing.c | 14 +++++++++----- types.h | 2 ++ 5 files changed, 51 insertions(+), 22 deletions(-)
diff --git a/ndp.c b/ndp.c index 9f498f9..0793564 100644 --- a/ndp.c +++ b/ndp.c @@ -66,19 +66,23 @@ static void ndp_send(struct work_struct *work) ETH_ALEN);
neigh_entry = (struct neigh_entry *)(ndp_packet + 1); - spin_lock_bh(&batman_if->neigh_list_lock); - hlist_for_each_entry(neigh_node, node, &batman_if->neigh_list, list) { + rcu_read_lock(); + hlist_for_each_entry_rcu(neigh_node, node, &batman_if->neigh_list, + list) { if (entries_len + sizeof(struct neigh_entry) > skb_tailroom(skb)) break;
+ spin_lock_bh(&neigh_node->update_lock); memcpy(neigh_entry->addr, neigh_node->addr, ETH_ALEN); neigh_entry->rq = neigh_node->rq; + spin_unlock_bh(&neigh_node->update_lock); + ndp_packet->num_neighbors++; neigh_entry++; entries_len += sizeof(struct neigh_entry); } - spin_unlock_bh(&batman_if->neigh_list_lock); + rcu_read_unlock(); skb_put(skb, entries_len);
bat_dbg(DBG_BATMAN, bat_priv, @@ -205,6 +209,9 @@ static struct neigh_node *ndp_create_neighbor(uint8_t my_tq, uint32_t seqno, return NULL;
INIT_HLIST_NODE(&neigh_node->list); + spin_lock_init(&neigh_node->update_lock); + kref_init(&neigh_node->refcount); + memcpy(neigh_node->addr, neigh_addr, ETH_ALEN); neigh_node->last_rq_seqno = seqno - 1;
@@ -216,6 +223,7 @@ void ndp_purge_neighbors(void) struct neigh_node *neigh_node; struct hlist_node *node, *node_tmp; struct batman_if *batman_if; + unsigned long last_valid;
rcu_read_lock(); list_for_each_entry_rcu(batman_if, &if_list, list) { @@ -225,13 +233,17 @@ void ndp_purge_neighbors(void) spin_lock_bh(&batman_if->neigh_list_lock); hlist_for_each_entry_safe(neigh_node, node, node_tmp, &batman_if->neigh_list, list) { - if (time_before(jiffies, neigh_node->last_valid + + spin_lock(&neigh_node->update_lock); + last_valid = neigh_node->last_valid; + spin_unlock(&neigh_node->update_lock); + + if (time_before(jiffies, last_valid + msecs_to_jiffies(PURGE_TIMEOUT * 1000))) continue;
- hlist_del(&neigh_node->list); - kfree(neigh_node); + hlist_del_rcu(&neigh_node->list); + call_rcu(&neigh_node->rcu, neigh_node_free_rcu); } spin_unlock_bh(&batman_if->neigh_list_lock); } @@ -246,16 +258,17 @@ int ndp_update_neighbor(uint8_t my_tq, uint32_t seqno, struct hlist_node *node; int ret = 1;
- spin_lock_bh(&batman_if->neigh_list_lock); - /* old neighbor? */ - hlist_for_each_entry(tmp_neigh_node, node, &batman_if->neigh_list, + rcu_read_lock(); + hlist_for_each_entry_rcu(tmp_neigh_node, node, &batman_if->neigh_list, list) { if (!compare_orig(tmp_neigh_node->addr, neigh_addr)) continue;
neigh_node = tmp_neigh_node; + kref_get(&neigh_node->refcount); break; } + rcu_read_unlock();
/* new neighbor? */ if (!neigh_node) { @@ -264,15 +277,24 @@ int ndp_update_neighbor(uint8_t my_tq, uint32_t seqno, if (!neigh_node) goto ret;
- hlist_add_head(&neigh_node->list, &batman_if->neigh_list); + ndp_update_neighbor_lq(my_tq, seqno, neigh_node, bat_priv); + + spin_lock_bh(&batman_if->neigh_list_lock); + hlist_add_head_rcu(&neigh_node->list, &batman_if->neigh_list); + spin_unlock_bh(&batman_if->neigh_list_lock); } + /* old neighbor? */ + else { + spin_lock_bh(&neigh_node->update_lock); + ndp_update_neighbor_lq(my_tq, seqno, neigh_node, bat_priv); + spin_unlock_bh(&neigh_node->update_lock);
- ndp_update_neighbor_lq(my_tq, seqno, neigh_node, bat_priv); + kref_put(&neigh_node->refcount, neigh_node_free_ref); + }
ret = 0;
ret: - spin_unlock_bh(&batman_if->neigh_list_lock); return ret; }
@@ -311,9 +333,9 @@ int ndp_seq_print_text(struct seq_file *seq, void *offset) if (batman_if->if_status != IF_ACTIVE) continue;
- spin_lock_bh(&batman_if->neigh_list_lock); - hlist_for_each_entry(neigh_node, node, &batman_if->neigh_list, - list) { + hlist_for_each_entry_rcu(neigh_node, node, + &batman_if->neigh_list, list) { + spin_lock_bh(&neigh_node->update_lock); last_seen_secs = jiffies_to_msecs(jiffies - neigh_node->last_valid) / 1000; last_seen_msecs = jiffies_to_msecs(jiffies - @@ -324,9 +346,9 @@ int ndp_seq_print_text(struct seq_file *seq, void *offset) last_seen_msecs, neigh_node->tq_avg, neigh_node->rq, batman_if->net_dev->name);
+ spin_unlock_bh(&neigh_node->update_lock); batman_count++; } - spin_unlock_bh(&batman_if->neigh_list_lock); } rcu_read_unlock();
diff --git a/originator.c b/originator.c index e98add5..699dbfc 100644 --- a/originator.c +++ b/originator.c @@ -68,7 +68,7 @@ void neigh_node_free_ref(struct kref *refcount) kfree(neigh_node); }
-static void neigh_node_free_rcu(struct rcu_head *rcu) +void neigh_node_free_rcu(struct rcu_head *rcu) { struct neigh_node *neigh_node;
diff --git a/originator.h b/originator.h index f3676fa..2a7d68b 100644 --- a/originator.h +++ b/originator.h @@ -31,6 +31,7 @@ struct neigh_node *create_neighbor(struct orig_node *orig_node, uint8_t *neigh, struct batman_if *if_incoming); void neigh_node_free_ref(struct kref *refcount); +void neigh_node_free_rcu(struct rcu_head *rcu); int orig_seq_print_text(struct seq_file *seq, void *offset); int orig_hash_add_if(struct batman_if *batman_if, int max_if_num); int orig_hash_del_if(struct batman_if *batman_if, int max_if_num); diff --git a/routing.c b/routing.c index 8a3acfa..785ddc2 100644 --- a/routing.c +++ b/routing.c @@ -199,20 +199,24 @@ static int is_bidirectional_neigh(struct orig_node *orig_node, return 0; }
- /* note, bottom halves are already deactivated outside in - * recv_bat_packet() */ - spin_lock(&if_incoming->neigh_list_lock); - hlist_for_each_entry(neigh_node, node, &if_incoming->neigh_list, + rcu_read_lock(); + hlist_for_each_entry_rcu(neigh_node, node, &if_incoming->neigh_list, list) { if (!compare_orig(neigh_node->addr, orig_neigh_node->orig)) continue;
orig_node->last_valid = jiffies; + + /* note, bottom halves are already deactivated outside in + * recv_bat_packet() */ + spin_lock(&neigh_node->update_lock); local_tq = neigh_node->tq_avg; local_rq = neigh_node->rq; + spin_unlock(&neigh_node->update_lock); + break; } - spin_unlock(&if_incoming->neigh_list_lock); + rcu_read_unlock();
if (local_tq == 0) return 0; diff --git a/types.h b/types.h index 43721cf..37c2c58 100644 --- a/types.h +++ b/types.h @@ -129,6 +129,8 @@ struct neigh_node { struct rcu_head rcu; struct orig_node *orig_node; struct batman_if *if_incoming; + spinlock_t update_lock; /* protects last_rq_seqno, ndp_rq_window, rq, + last_valid, tq_avg for NDP */ };
struct neigh_entry {
Hey,
and please let me know if you'd like me to merge this commit into the previous ones or if it might be better to leave it like that for easier debugging of potential rcu-locking/refcounting bugs as the simple spinlocking before should be less bug prone, and leaving patch 10/10 as a separate performance improvement patch.
Cheers, Linus
On Fri, Dec 31, 2010 at 04:46:25PM +0100, Linus Lüssing wrote:
With this commit only spinlocking for reading/writing variables inside a neigh_node for NDP is used. The neigh_list traversal and entry deleting/adding is done with rcu-locking and reference counting instead to greatly reduce the time of (concurrent) spinlocking.
Signed-off-by: Linus Lüssing linus.luessing@ascom.ch
ndp.c | 54 ++++++++++++++++++++++++++++++++++++++---------------- originator.c | 2 +- originator.h | 1 + routing.c | 14 +++++++++----- types.h | 2 ++ 5 files changed, 51 insertions(+), 22 deletions(-)
diff --git a/ndp.c b/ndp.c index 9f498f9..0793564 100644 --- a/ndp.c +++ b/ndp.c @@ -66,19 +66,23 @@ static void ndp_send(struct work_struct *work) ETH_ALEN);
neigh_entry = (struct neigh_entry *)(ndp_packet + 1);
- spin_lock_bh(&batman_if->neigh_list_lock);
- hlist_for_each_entry(neigh_node, node, &batman_if->neigh_list, list) {
rcu_read_lock();
hlist_for_each_entry_rcu(neigh_node, node, &batman_if->neigh_list,
list) {
if (entries_len + sizeof(struct neigh_entry) > skb_tailroom(skb)) break;
spin_lock_bh(&neigh_node->update_lock);
memcpy(neigh_entry->addr, neigh_node->addr, ETH_ALEN); neigh_entry->rq = neigh_node->rq;
spin_unlock_bh(&neigh_node->update_lock);
ndp_packet->num_neighbors++; neigh_entry++; entries_len += sizeof(struct neigh_entry); }
- spin_unlock_bh(&batman_if->neigh_list_lock);
rcu_read_unlock(); skb_put(skb, entries_len);
bat_dbg(DBG_BATMAN, bat_priv,
@@ -205,6 +209,9 @@ static struct neigh_node *ndp_create_neighbor(uint8_t my_tq, uint32_t seqno, return NULL;
INIT_HLIST_NODE(&neigh_node->list);
- spin_lock_init(&neigh_node->update_lock);
- kref_init(&neigh_node->refcount);
- memcpy(neigh_node->addr, neigh_addr, ETH_ALEN); neigh_node->last_rq_seqno = seqno - 1;
@@ -216,6 +223,7 @@ void ndp_purge_neighbors(void) struct neigh_node *neigh_node; struct hlist_node *node, *node_tmp; struct batman_if *batman_if;
unsigned long last_valid;
rcu_read_lock(); list_for_each_entry_rcu(batman_if, &if_list, list) {
@@ -225,13 +233,17 @@ void ndp_purge_neighbors(void) spin_lock_bh(&batman_if->neigh_list_lock); hlist_for_each_entry_safe(neigh_node, node, node_tmp, &batman_if->neigh_list, list) {
if (time_before(jiffies, neigh_node->last_valid +
spin_lock(&neigh_node->update_lock);
last_valid = neigh_node->last_valid;
spin_unlock(&neigh_node->update_lock);
if (time_before(jiffies, last_valid + msecs_to_jiffies(PURGE_TIMEOUT * 1000))) continue;
hlist_del(&neigh_node->list);
kfree(neigh_node);
hlist_del_rcu(&neigh_node->list);
} spin_unlock_bh(&batman_if->neigh_list_lock); }call_rcu(&neigh_node->rcu, neigh_node_free_rcu);
@@ -246,16 +258,17 @@ int ndp_update_neighbor(uint8_t my_tq, uint32_t seqno, struct hlist_node *node; int ret = 1;
- spin_lock_bh(&batman_if->neigh_list_lock);
- /* old neighbor? */
- hlist_for_each_entry(tmp_neigh_node, node, &batman_if->neigh_list,
rcu_read_lock();
hlist_for_each_entry_rcu(tmp_neigh_node, node, &batman_if->neigh_list, list) { if (!compare_orig(tmp_neigh_node->addr, neigh_addr)) continue;
neigh_node = tmp_neigh_node;
kref_get(&neigh_node->refcount);
break; }
rcu_read_unlock();
/* new neighbor? */ if (!neigh_node) {
@@ -264,15 +277,24 @@ int ndp_update_neighbor(uint8_t my_tq, uint32_t seqno, if (!neigh_node) goto ret;
hlist_add_head(&neigh_node->list, &batman_if->neigh_list);
ndp_update_neighbor_lq(my_tq, seqno, neigh_node, bat_priv);
spin_lock_bh(&batman_if->neigh_list_lock);
hlist_add_head_rcu(&neigh_node->list, &batman_if->neigh_list);
}spin_unlock_bh(&batman_if->neigh_list_lock);
- /* old neighbor? */
- else {
spin_lock_bh(&neigh_node->update_lock);
ndp_update_neighbor_lq(my_tq, seqno, neigh_node, bat_priv);
spin_unlock_bh(&neigh_node->update_lock);
- ndp_update_neighbor_lq(my_tq, seqno, neigh_node, bat_priv);
kref_put(&neigh_node->refcount, neigh_node_free_ref);
}
ret = 0;
ret:
- spin_unlock_bh(&batman_if->neigh_list_lock); return ret;
}
@@ -311,9 +333,9 @@ int ndp_seq_print_text(struct seq_file *seq, void *offset) if (batman_if->if_status != IF_ACTIVE) continue;
spin_lock_bh(&batman_if->neigh_list_lock);
hlist_for_each_entry(neigh_node, node, &batman_if->neigh_list,
list) {
hlist_for_each_entry_rcu(neigh_node, node,
&batman_if->neigh_list, list) {
spin_lock_bh(&neigh_node->update_lock); last_seen_secs = jiffies_to_msecs(jiffies - neigh_node->last_valid) / 1000; last_seen_msecs = jiffies_to_msecs(jiffies -
@@ -324,9 +346,9 @@ int ndp_seq_print_text(struct seq_file *seq, void *offset) last_seen_msecs, neigh_node->tq_avg, neigh_node->rq, batman_if->net_dev->name);
}spin_unlock_bh(&neigh_node->update_lock); batman_count++;
} rcu_read_unlock();spin_unlock_bh(&batman_if->neigh_list_lock);
diff --git a/originator.c b/originator.c index e98add5..699dbfc 100644 --- a/originator.c +++ b/originator.c @@ -68,7 +68,7 @@ void neigh_node_free_ref(struct kref *refcount) kfree(neigh_node); }
-static void neigh_node_free_rcu(struct rcu_head *rcu) +void neigh_node_free_rcu(struct rcu_head *rcu) { struct neigh_node *neigh_node;
diff --git a/originator.h b/originator.h index f3676fa..2a7d68b 100644 --- a/originator.h +++ b/originator.h @@ -31,6 +31,7 @@ struct neigh_node *create_neighbor(struct orig_node *orig_node, uint8_t *neigh, struct batman_if *if_incoming); void neigh_node_free_ref(struct kref *refcount); +void neigh_node_free_rcu(struct rcu_head *rcu); int orig_seq_print_text(struct seq_file *seq, void *offset); int orig_hash_add_if(struct batman_if *batman_if, int max_if_num); int orig_hash_del_if(struct batman_if *batman_if, int max_if_num); diff --git a/routing.c b/routing.c index 8a3acfa..785ddc2 100644 --- a/routing.c +++ b/routing.c @@ -199,20 +199,24 @@ static int is_bidirectional_neigh(struct orig_node *orig_node, return 0; }
- /* note, bottom halves are already deactivated outside in
* recv_bat_packet() */
- spin_lock(&if_incoming->neigh_list_lock);
- hlist_for_each_entry(neigh_node, node, &if_incoming->neigh_list,
rcu_read_lock();
hlist_for_each_entry_rcu(neigh_node, node, &if_incoming->neigh_list, list) { if (!compare_orig(neigh_node->addr, orig_neigh_node->orig)) continue;
orig_node->last_valid = jiffies;
/* note, bottom halves are already deactivated outside in
* recv_bat_packet() */
spin_lock(&neigh_node->update_lock);
local_tq = neigh_node->tq_avg; local_rq = neigh_node->rq;
spin_unlock(&neigh_node->update_lock);
break; }
- spin_unlock(&if_incoming->neigh_list_lock);
rcu_read_unlock();
if (local_tq == 0) return 0;
diff --git a/types.h b/types.h index 43721cf..37c2c58 100644 --- a/types.h +++ b/types.h @@ -129,6 +129,8 @@ struct neigh_node { struct rcu_head rcu; struct orig_node *orig_node; struct batman_if *if_incoming;
- spinlock_t update_lock; /* protects last_rq_seqno, ndp_rq_window, rq,
last_valid, tq_avg for NDP */
};
struct neigh_entry {
1.7.1
Hi Linus,
great that you embraced the feedback that quickly. As discussed in Berlin I'll go through your patches once I have a little bit more room to manoeuvre (next week is rather packed).
Would be great if someone could check the usage of rcu-locking + refcounting. I was also a little confused because in "Documentation/RCU/listRCU.txt" list_del_rcu() and list_add_rcu() are not protected with a spinlock for the list here, but in the batman-adv code we are usually having those extra locks. Do I have to leave those spinlocks or can I remove them for adding/deleting entries in the neigh_list?
I don't understand why you think there are no locks. Did you read the text around the examples (Documentation/RCU/listRCU.txt) ? I mean, below the first example (which indeed does not contain spinlocks) it is written:
Normally, the write_lock() and write_unlock() would be replaced by a spin_lock() and a spin_unlock(), but in this case, all callers hold audit_netlink_sem, so no additional locking is required. The auditsc_lock can therefore be eliminated, since use of RCU eliminates the need for writers to exclude readers. Normally, the write_lock() calls would be converted into spin_lock() calls.
If you check the following example you'll find spinlocks or search for list_del_rcu() in the kernel sources to find more usage scenarios.
Regards, Marek
On Wed, Jan 05, 2011 at 01:12:33PM +0100, Marek Lindner wrote:
Hi Linus,
great that you embraced the feedback that quickly. As discussed in Berlin I'll go through your patches once I have a little bit more room to manoeuvre (next week is rather packed).
Would be great if someone could check the usage of rcu-locking + refcounting. I was also a little confused because in "Documentation/RCU/listRCU.txt" list_del_rcu() and list_add_rcu() are not protected with a spinlock for the list here, but in the batman-adv code we are usually having those extra locks. Do I have to leave those spinlocks or can I remove them for adding/deleting entries in the neigh_list?
I don't understand why you think there are no locks. Did you read the text around the examples (Documentation/RCU/listRCU.txt) ? I mean, below the first example (which indeed does not contain spinlocks) it is written:
Normally, the write_lock() and write_unlock() would be replaced by a spin_lock() and a spin_unlock(), but in this case, all callers hold audit_netlink_sem, so no additional locking is required. The auditsc_lock can therefore be eliminated, since use of RCU eliminates the need for writers to exclude readers. Normally, the write_lock() calls would be converted into spin_lock() calls.
If you check the following example you'll find spinlocks or search for list_del_rcu() in the kernel sources to find more usage scenarios.
Regards, Marek
Oki doki, thanks. I was a little confused by the example at that section and couldn't find any other references to "audit_netlink_sem" (though it is/was probably just a common semaphore, I guess). Ok, quick searching of list_del_rcu() in the kernel code (via http://lxr.linux.no/linux) cleared things up.
Cheers, Linus
Oki doki, thanks. I was a little confused by the example at that section and couldn't find any other references to "audit_netlink_sem" (though it is/was probably just a common semaphore, I guess). Ok, quick searching of list_del_rcu() in the kernel code (via http://lxr.linux.no/linux) cleared things up.
You might also find this useful:
http://lwn.net/Articles/421425/
Andrew
b.a.t.m.a.n@lists.open-mesh.org