Hi everyone,
The following patches add a redundancy bonding mode to batman-adv: In case of multiple interfaces available towards a next hop node, instead of sending packets in interface alternating or round robin bonding fashion, packets get send redundantly on all available interfaces available for bonding.
This mode increases the packet delivery ratio of unicast data transfers for the cost of throughput in multi interface mesh networks and is therefore aimed at high reliability mesh networks.
It is especially useful if the main source of packet loss is not always reliably detectable by batman-adv's broadcast PDR measurements (i.e. bursty periods of interference on a single channel, which gets averaged out due to the windowing; different unicast bitrate; ...). Or if a fault tolerant packet forwarding scheme which is able to tolerate a sudden link failure with no impact on the user experience is required.
The first eight patches are mainly some restructuring of the unicast sending code paths. Patches nine to 13 add the actual redandancy bonding mode.
Please note, that this redundancy bonding mode is not yet compatible with batman-adv's link layer fragmentation feature.
Cheers, Linus
Signed-off-by: Linus Lüssing linus.luessing@ascom.ch --- routing.c | 7 +++---- routing.h | 3 +-- soft-interface.c | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-)
diff --git a/batman-adv/routing.c b/batman-adv/routing.c index a2b770a..ec14a59 100644 --- a/batman-adv/routing.c +++ b/batman-adv/routing.c @@ -1280,8 +1280,7 @@ static int check_unicast_packet(struct sk_buff *skb, int hdr_size) return 0; }
-int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, - int hdr_size) +int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if) { struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface); struct orig_node *orig_node = NULL; @@ -1385,7 +1384,7 @@ int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if) return NET_RX_SUCCESS; }
- return route_unicast_packet(skb, recv_if, hdr_size); + return route_unicast_packet(skb, recv_if); }
int recv_ucast_frag_packet(struct sk_buff *skb, struct batman_if *recv_if) @@ -1418,7 +1417,7 @@ int recv_ucast_frag_packet(struct sk_buff *skb, struct batman_if *recv_if) return NET_RX_SUCCESS; }
- return route_unicast_packet(skb, recv_if, hdr_size); + return route_unicast_packet(skb, recv_if); }
diff --git a/batman-adv/routing.h b/batman-adv/routing.h index e2a9872..d302bd7 100644 --- a/batman-adv/routing.h +++ b/batman-adv/routing.h @@ -30,8 +30,7 @@ void receive_bat_packet(struct ethhdr *ethhdr, void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node, struct neigh_node *neigh_node, unsigned char *hna_buff, int hna_buff_len); -int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, - int hdr_size); +int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if); int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if); 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); diff --git a/batman-adv/soft-interface.c b/batman-adv/soft-interface.c index 152beaa..eccced9 100644 --- a/batman-adv/soft-interface.c +++ b/batman-adv/soft-interface.c @@ -482,7 +482,7 @@ void interface_rx(struct net_device *soft_iface,
memcpy(unicast_packet->dest, bat_priv->softif_neigh->addr, ETH_ALEN); - ret = route_unicast_packet(skb, recv_if, hdr_size); + ret = route_unicast_packet(skb, recv_if); if (ret == NET_RX_DROP) goto dropped;
Just a minor style adjustment, to give people a hint which fields should not be reordered and need to be at the beginning of each packet with batman-adv's frame type.
Signed-off-by: Linus Lüssing linus.luessing@ascom.ch --- aggregation.c | 4 ++-- hard-interface.c | 18 +++++++++--------- icmp_socket.c | 6 +++--- packet.h | 52 ++++++++++++++++++++++------------------------------ routing.c | 34 +++++++++++++++++----------------- send.c | 20 ++++++++++---------- soft-interface.c | 14 +++++++------- unicast.c | 16 ++++++++-------- vis.c | 14 +++++++------- 9 files changed, 85 insertions(+), 93 deletions(-)
diff --git a/batman-adv/aggregation.c b/batman-adv/aggregation.c index 1997725..ad3c91b 100644 --- a/batman-adv/aggregation.c +++ b/batman-adv/aggregation.c @@ -69,7 +69,7 @@ static bool can_aggregate_with(struct batman_packet *new_batman_packet, * are flooded through the net */ if ((!directlink) && (!(batman_packet->flags & DIRECTLINK)) && - (batman_packet->ttl != 1) && + (batman_packet->header.ttl != 1) &&
/* own packets originating non-primary * interfaces leave only that interface */ @@ -80,7 +80,7 @@ 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_batman_packet->header.ttl == 1) && (forw_packet->if_incoming == if_incoming) &&
/* packets from direct neighbors or diff --git a/batman-adv/hard-interface.c b/batman-adv/hard-interface.c index 8982485..8d523cc 100644 --- a/batman-adv/hard-interface.c +++ b/batman-adv/hard-interface.c @@ -146,8 +146,8 @@ static void set_primary_if(struct bat_priv *bat_priv, return;
batman_packet = (struct batman_packet *)(batman_if->packet_buff); + batman_packet->header.ttl = TTL; batman_packet->flags = PRIMARIES_FIRST_HOP; - batman_packet->ttl = TTL;
update_primary_addr(bat_priv);
@@ -312,10 +312,10 @@ int hardif_enable_interface(struct batman_if *batman_if, char *iface_name) }
batman_packet = (struct batman_packet *)(batman_if->packet_buff); - batman_packet->packet_type = BAT_PACKET; - batman_packet->version = COMPAT_VERSION; + batman_packet->header.packet_type = BAT_PACKET; + batman_packet->header.version = COMPAT_VERSION; + batman_packet->header.ttl = 2; batman_packet->flags = 0; - batman_packet->ttl = 2; batman_packet->tq = TQ_MAX_VALUE; batman_packet->num_hna = 0;
@@ -558,7 +558,7 @@ static int batman_skb_recv(struct sk_buff *skb, struct net_device *dev, struct net_device *orig_dev) { struct bat_priv *bat_priv; - struct batman_packet *batman_packet; + struct batman_header *batman_header; struct batman_if *batman_if; int ret;
@@ -590,19 +590,19 @@ static 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; + batman_header = (struct batman_header *)skb->data;
- if (batman_packet->version != COMPAT_VERSION) { + if (batman_header->version != COMPAT_VERSION) { bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: incompatible batman version (%i)\n", - batman_packet->version); + batman_header->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 (batman_header->packet_type) { /* batman originator packet */ case BAT_PACKET: ret = recv_bat_packet(skb, batman_if); diff --git a/batman-adv/icmp_socket.c b/batman-adv/icmp_socket.c index 9f150bf..869c9aa 100644 --- a/batman-adv/icmp_socket.c +++ b/batman-adv/icmp_socket.c @@ -190,7 +190,7 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, goto free_skb; }
- if (icmp_packet->packet_type != BAT_ICMP) { + if (icmp_packet->header.packet_type != BAT_ICMP) { bat_dbg(DBG_BATMAN, bat_priv, "Error - can't send packet from char device: " "got bogus packet type (expected: BAT_ICMP)\n"); @@ -208,9 +208,9 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff,
icmp_packet->uid = socket_client->index;
- if (icmp_packet->version != COMPAT_VERSION) { + if (icmp_packet->header.version != COMPAT_VERSION) { + icmp_packet->header.ttl = COMPAT_VERSION; icmp_packet->msg_type = PARAMETER_PROBLEM; - icmp_packet->ttl = COMPAT_VERSION; bat_socket_add_packet(socket_client, icmp_packet, packet_len); goto free_skb; } diff --git a/batman-adv/packet.h b/batman-adv/packet.h index e757187..ae7a0ce 100644 --- a/batman-adv/packet.h +++ b/batman-adv/packet.h @@ -52,31 +52,33 @@ #define UNI_FRAG_HEAD 0x01 #define UNI_FRAG_LARGETAIL 0x02
+struct batman_header { + uint8_t packet_type; + uint8_t version; /* batman version field */ + uint8_t ttl; + uint8_t align; +} __packed; + struct batman_packet { - uint8_t packet_type; - uint8_t version; /* batman version field */ + struct batman_header header; + uint32_t seqno; uint8_t flags; /* 0x40: DIRECTLINK flag, 0x20 VIS_SERVER flag... */ uint8_t tq; - uint32_t seqno; uint8_t orig[6]; uint8_t prev_sender[6]; - uint8_t ttl; uint8_t num_hna; uint8_t gw_flags; /* flags related to gateway class */ - uint8_t align; } __packed;
#define BAT_PACKET_LEN sizeof(struct batman_packet)
struct icmp_packet { - uint8_t packet_type; - uint8_t version; /* batman version field */ + struct batman_header header; + uint16_t seqno; uint8_t msg_type; /* see ICMP message types above */ - uint8_t ttl; + uint8_t uid; uint8_t dst[6]; uint8_t orig[6]; - uint16_t seqno; - uint8_t uid; } __packed;
#define BAT_RR_LEN 16 @@ -84,50 +86,40 @@ struct icmp_packet { /* icmp_packet_rr must start with all fields from imcp_packet * as this is assumed by code that handles ICMP packets */ struct icmp_packet_rr { - uint8_t packet_type; - uint8_t version; /* batman version field */ + struct batman_header header; + uint16_t seqno; uint8_t msg_type; /* see ICMP message types above */ - uint8_t ttl; + uint8_t uid; uint8_t dst[6]; uint8_t orig[6]; - uint16_t seqno; - uint8_t uid; uint8_t rr_cur; uint8_t rr[BAT_RR_LEN][ETH_ALEN]; } __packed;
struct unicast_packet { - uint8_t packet_type; - uint8_t version; /* batman version field */ + struct batman_header header; uint8_t dest[6]; - uint8_t ttl; } __packed;
struct unicast_frag_packet { - uint8_t packet_type; - uint8_t version; /* batman version field */ + struct batman_header header; uint8_t dest[6]; - uint8_t ttl; + uint8_t orig[6]; uint8_t flags; - uint8_t orig[6]; uint16_t seqno; } __packed;
struct bcast_packet { - uint8_t packet_type; - uint8_t version; /* batman version field */ - uint8_t orig[6]; - uint8_t ttl; + struct batman_header header; uint32_t seqno; + uint8_t orig[6]; } __packed;
struct vis_packet { - uint8_t packet_type; - uint8_t version; /* batman version field */ + struct batman_header header; + uint32_t seqno; /* sequence number */ uint8_t vis_type; /* which type of vis-participant sent this? */ uint8_t entries; /* number of entries behind this struct */ - uint32_t seqno; /* sequence number */ - uint8_t ttl; /* TTL */ uint8_t vis_orig[6]; /* originator that informs about its * neighbors */ uint8_t target_orig[6]; /* who should receive this packet */ diff --git a/batman-adv/routing.c b/batman-adv/routing.c index ec14a59..89e765f 100644 --- a/batman-adv/routing.c +++ b/batman-adv/routing.c @@ -441,8 +441,8 @@ static void update_orig(struct bat_priv *bat_priv, 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 = batman_packet->header.ttl; + neigh_node->last_ttl = batman_packet->header.ttl; }
bonding_candidate_add(orig_node, neigh_node); @@ -632,7 +632,7 @@ void receive_bat_packet(struct ethhdr *ethhdr, * packet in an aggregation. Here we expect that the padding * is always zero (or not 0x01) */ - if (batman_packet->packet_type != BAT_PACKET) + if (batman_packet->header.packet_type != BAT_PACKET) return;
/* could be changed by schedule_own_packet() */ @@ -650,8 +650,8 @@ void receive_bat_packet(struct ethhdr *ethhdr, 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); + batman_packet->tq, batman_packet->header.ttl, + batman_packet->header.version, has_directlink_flag);
rcu_read_lock(); list_for_each_entry_rcu(batman_if, &if_list, list) { @@ -678,10 +678,10 @@ void receive_bat_packet(struct ethhdr *ethhdr, } rcu_read_unlock();
- if (batman_packet->version != COMPAT_VERSION) { + if (batman_packet->header.version != COMPAT_VERSION) { bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: incompatible batman version (%i)\n", - batman_packet->version); + batman_packet->header.version); return; }
@@ -798,7 +798,7 @@ void receive_bat_packet(struct ethhdr *ethhdr, if (is_bidirectional && (!is_duplicate || ((orig_node->last_real_seqno == batman_packet->seqno) && - (orig_node->last_ttl - 3 <= batman_packet->ttl)))) + (orig_node->last_ttl - 3 <= batman_packet->header.ttl)))) update_orig(bat_priv, orig_node, ethhdr, batman_packet, if_incoming, hna_buff, hna_buff_len, is_duplicate);
@@ -927,7 +927,7 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv, memcpy(icmp_packet->orig, bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); icmp_packet->msg_type = ECHO_REPLY; - icmp_packet->ttl = TTL; + icmp_packet->header.ttl = TTL;
send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); ret = NET_RX_SUCCESS; @@ -995,7 +995,7 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, memcpy(icmp_packet->orig, bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); icmp_packet->msg_type = TTL_EXCEEDED; - icmp_packet->ttl = TTL; + icmp_packet->header.ttl = TTL;
send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); ret = NET_RX_SUCCESS; @@ -1061,7 +1061,7 @@ int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if) return recv_my_icmp_packet(bat_priv, skb, hdr_size);
/* TTL exceeded */ - if (icmp_packet->ttl < 2) + if (icmp_packet->header.ttl < 2) return recv_icmp_ttl_exceeded(bat_priv, skb);
/* get routing information */ @@ -1092,7 +1092,7 @@ int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if) icmp_packet = (struct icmp_packet_rr *)skb->data;
/* decrement ttl */ - icmp_packet->ttl--; + icmp_packet->header.ttl--;
/* route it */ send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); @@ -1293,7 +1293,7 @@ int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if) unicast_packet = (struct unicast_packet *)skb->data;
/* TTL exceeded */ - if (unicast_packet->ttl < 2) { + if (unicast_packet->header.ttl < 2) { pr_debug("Warning - can't forward unicast packet from %pM to " "%pM: ttl exceeded\n", ethhdr->h_source, unicast_packet->dest); @@ -1324,7 +1324,7 @@ int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if)
unicast_packet = (struct unicast_packet *)skb->data;
- if (unicast_packet->packet_type == BAT_UNICAST && + if (unicast_packet->header.packet_type == BAT_UNICAST && atomic_read(&bat_priv->fragmentation) && skb->len > neigh_node->if_incoming->net_dev->mtu) { ret = frag_send_skb(skb, bat_priv, @@ -1332,7 +1332,7 @@ int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if) goto out; }
- if (unicast_packet->packet_type == BAT_UNICAST_FRAG && + if (unicast_packet->header.packet_type == BAT_UNICAST_FRAG && frag_can_reassemble(skb, neigh_node->if_incoming->net_dev->mtu)) {
ret = frag_reassemble_skb(skb, bat_priv, &new_skb); @@ -1351,7 +1351,7 @@ int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if) }
/* decrement ttl */ - unicast_packet->ttl--; + unicast_packet->header.ttl--;
/* route it */ send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); @@ -1455,7 +1455,7 @@ int recv_bcast_packet(struct sk_buff *skb, struct batman_if *recv_if) if (is_my_mac(bcast_packet->orig)) goto out;
- if (bcast_packet->ttl < 2) + if (bcast_packet->header.ttl < 2) goto out;
rcu_read_lock(); diff --git a/batman-adv/send.c b/batman-adv/send.c index 8314276..b6a9a3b 100644 --- a/batman-adv/send.c +++ b/batman-adv/send.c @@ -139,7 +139,7 @@ static void send_packet_to_if(struct forw_packet *forw_packet, " 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->tq, batman_packet->header.ttl, (batman_packet->flags & DIRECTLINK ? "on" : "off"), batman_if->net_dev->name, batman_if->net_dev->dev_addr); @@ -181,7 +181,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 && (batman_packet->header.ttl == 1)) || (forw_packet->own && (forw_packet->if_incoming->if_num > 0))) {
/* FIXME: what about aggregated packets ? */ @@ -190,7 +190,7 @@ static void send_packet(struct forw_packet *forw_packet) "on interface %s [%pM]\n", (forw_packet->own ? "Sending own" : "Forwarding"), batman_packet->orig, ntohl(batman_packet->seqno), - batman_packet->ttl, + batman_packet->header.ttl, forw_packet->if_incoming->net_dev->name, forw_packet->if_incoming->net_dev->dev_addr);
@@ -310,15 +310,15 @@ 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 (batman_packet->header.ttl <= 1) { bat_dbg(DBG_BATMAN, bat_priv, "ttl exceeded\n"); return; }
in_tq = batman_packet->tq; - in_ttl = batman_packet->ttl; + in_ttl = batman_packet->header.ttl;
- batman_packet->ttl--; + batman_packet->header.ttl--; memcpy(batman_packet->prev_sender, ethhdr->h_source, ETH_ALEN);
/* rebroadcast tq of our best ranking neighbor to ensure the rebroadcast @@ -330,8 +330,8 @@ void schedule_forward_packet(struct orig_node *orig_node, batman_packet->tq = orig_node->router->tq_avg;
if (orig_node->router->last_ttl) - batman_packet->ttl = orig_node->router->last_ttl - - 1; + batman_packet->header.ttl = + orig_node->router->last_ttl - 1; }
tq_avg = orig_node->router->tq_avg; @@ -344,7 +344,7 @@ void schedule_forward_packet(struct orig_node *orig_node, "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); + batman_packet->header.ttl);
batman_packet->seqno = htonl(batman_packet->seqno);
@@ -420,7 +420,7 @@ int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb)
/* as we have a copy now, it is safe to decrease the TTL */ bcast_packet = (struct bcast_packet *)skb->data; - bcast_packet->ttl--; + bcast_packet->header.ttl--;
skb_reset_mac_header(skb);
diff --git a/batman-adv/soft-interface.c b/batman-adv/soft-interface.c index eccced9..55edebb 100644 --- a/batman-adv/soft-interface.c +++ b/batman-adv/soft-interface.c @@ -226,10 +226,10 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, else batman_packet = (struct batman_packet *)(skb->data + ETH_HLEN);
- if (batman_packet->version != COMPAT_VERSION) + if (batman_packet->header.version != COMPAT_VERSION) goto err;
- if (batman_packet->packet_type != BAT_PACKET) + if (batman_packet->header.packet_type != BAT_PACKET) goto err;
if (!(batman_packet->flags & PRIMARIES_FIRST_HOP)) @@ -393,11 +393,11 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) goto dropped;
bcast_packet = (struct bcast_packet *)skb->data; - bcast_packet->version = COMPAT_VERSION; - bcast_packet->ttl = TTL; + bcast_packet->header.version = COMPAT_VERSION; + bcast_packet->header.ttl = TTL;
/* batman packet type: broadcast */ - bcast_packet->packet_type = BAT_BCAST; + bcast_packet->header.packet_type = BAT_BCAST;
/* hw address of first interface is the orig mac because only * this mac is known throughout the mesh */ @@ -474,8 +474,8 @@ void interface_rx(struct net_device *soft_iface, skb_push(skb, hdr_size); unicast_packet = (struct unicast_packet *)skb->data;
- if ((unicast_packet->packet_type != BAT_UNICAST) && - (unicast_packet->packet_type != BAT_UNICAST_FRAG)) + if ((unicast_packet->header.packet_type != BAT_UNICAST) && + (unicast_packet->header.packet_type != BAT_UNICAST_FRAG)) goto dropped;
skb_reset_mac_header(skb); diff --git a/batman-adv/unicast.c b/batman-adv/unicast.c index a7aacad..62e6c64 100644 --- a/batman-adv/unicast.c +++ b/batman-adv/unicast.c @@ -67,7 +67,7 @@ static struct sk_buff *frag_merge_packet(struct list_head *head,
memmove(skb->data + uni_diff, skb->data, hdr_len); unicast_packet = (struct unicast_packet *) skb_pull(skb, uni_diff); - unicast_packet->packet_type = BAT_UNICAST; + unicast_packet->header.packet_type = BAT_UNICAST;
return skb;
@@ -260,9 +260,9 @@ int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
memcpy(frag1, &tmp_uc, sizeof(struct unicast_packet));
- frag1->ttl--; - frag1->version = COMPAT_VERSION; - frag1->packet_type = BAT_UNICAST_FRAG; + frag1->header.ttl--; + frag1->header.version = COMPAT_VERSION; + frag1->header.packet_type = BAT_UNICAST_FRAG;
memcpy(frag1->orig, bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); memcpy(frag2, frag1, sizeof(struct unicast_frag_packet)); @@ -326,11 +326,11 @@ find_router:
unicast_packet = (struct unicast_packet *)skb->data;
- unicast_packet->version = COMPAT_VERSION; + unicast_packet->header.version = COMPAT_VERSION; /* batman packet type: unicast */ - unicast_packet->packet_type = BAT_UNICAST; + unicast_packet->header.packet_type = BAT_UNICAST; /* set unicast ttl */ - unicast_packet->ttl = TTL; + unicast_packet->header.ttl = TTL; /* copy the destination for faster routing */ memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN);
@@ -338,7 +338,7 @@ find_router: data_len + sizeof(struct unicast_packet) > neigh_node->if_incoming->net_dev->mtu) { /* send frag skb decreases ttl */ - unicast_packet->ttl++; + unicast_packet->header.ttl++; ret = frag_send_skb(skb, bat_priv, neigh_node->if_incoming, neigh_node->addr); goto out; diff --git a/batman-adv/vis.c b/batman-adv/vis.c index c1c3258..3551f06 100644 --- a/batman-adv/vis.c +++ b/batman-adv/vis.c @@ -592,7 +592,7 @@ static int generate_vis_packet(struct bat_priv *bat_priv) packet->vis_type = atomic_read(&bat_priv->vis_mode);
memcpy(packet->target_orig, broadcast_addr, ETH_ALEN); - packet->ttl = TTL; + packet->header.ttl = TTL; packet->seqno = htonl(ntohl(packet->seqno) + 1); packet->entries = 0; skb_trim(info->skb_packet, sizeof(struct vis_packet)); @@ -806,20 +806,20 @@ static void send_vis_packet(struct bat_priv *bat_priv, struct vis_info *info) struct vis_packet *packet;
packet = (struct vis_packet *)info->skb_packet->data; - if (packet->ttl < 2) { + if (packet->header.ttl < 2) { pr_debug("Error - can't send vis packet: ttl exceeded\n"); return; }
memcpy(packet->sender_orig, bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); - packet->ttl--; + packet->header.ttl--;
if (is_broadcast_ether_addr(packet->target_orig)) broadcast_vis_packet(bat_priv, info); else unicast_vis_packet(bat_priv, info); - packet->ttl++; /* restore TTL */ + packet->header.ttl++; /* restore TTL */ }
/* called from timer; send (and maybe generate) vis packet. */ @@ -900,9 +900,9 @@ int vis_init(struct bat_priv *bat_priv) INIT_LIST_HEAD(&bat_priv->my_vis_info->send_list); kref_init(&bat_priv->my_vis_info->refcount); bat_priv->my_vis_info->bat_priv = bat_priv; - packet->version = COMPAT_VERSION; - packet->packet_type = BAT_VIS; - packet->ttl = TTL; + packet->header.version = COMPAT_VERSION; + packet->header.packet_type = BAT_VIS; + packet->header.ttl = TTL; packet->seqno = 0; packet->entries = 0;
On Tue, Feb 15, 2011 at 06:12:17PM +0100, Linus L??ssing wrote:
Just a minor style adjustment, to give people a hint which fields should not be reordered and need to be at the beginning of each packet with batman-adv's frame type.
Hi Linus
+struct batman_header {
- uint8_t packet_type;
- uint8_t version; /* batman version field */
- uint8_t ttl;
- uint8_t align;
+} __packed;
struct batman_packet {
- uint8_t packet_type;
- uint8_t version; /* batman version field */
- struct batman_header header;
- uint32_t seqno; uint8_t flags; /* 0x40: DIRECTLINK flag, 0x20 VIS_SERVER flag... */ uint8_t tq;
- uint32_t seqno; uint8_t orig[6]; uint8_t prev_sender[6];
- uint8_t ttl; uint8_t num_hna; uint8_t gw_flags; /* flags related to gateway class */
- uint8_t align;
} __packed;
Two different ideas, both triggered by the align byte in header. This byte is a waste of space, it is not used, and it is probably not easy to find something which all packet types are going to need in the future.
1) Did you try not having it. So long header is __packed, and all the structures it is used in are __packed, i think the compiler will do the right thing. The downside is that alignment is not obvious. Most people will assume header is 4 bytes, not 3, and think the alignment of the packets is wrong.
2) Did you consider using a union? It is a more invasive patch, but the alignment is then clear. The downside is sizeof() no longer gives you the per packet type size, rather it gives you the size of the biggest member of the union. So this makes the change even more invasive and bug prone.
I think i prefer 1), with appropriate comments to explain the alignment issue.
Andrew
Andrew Lunn andrew@lunn.ch schrieb am 16.02.2011 07:08:11:
[Bild entfernt]
Re: [B.A.T.M.A.N.] [PATCH 02/13] batman-adv: Add explicit batman header structure
Andrew Lunn
an:
The list for a Better Approach To Mobile Ad-hoc Networking
16.02.2011 07:08
Kopie:
Linus L??ssing
On Tue, Feb 15, 2011 at 06:12:17PM +0100, Linus L??ssing wrote:
Just a minor style adjustment, to give people a hint which fields
should
not be reordered and need to be at the beginning of each packet with batman-adv's frame type.
Hi Linus
+struct batman_header {
- uint8_t packet_type;
- uint8_t version; /* batman version field */
- uint8_t ttl;
- uint8_t align;
+} __packed;
struct batman_packet {
- uint8_t packet_type;
- uint8_t version; /* batman version field */
- struct batman_header header;
- uint32_t seqno; uint8_t flags; /* 0x40: DIRECTLINK flag, 0x20 VIS_SERVER
flag... */
uint8_t tq;
- uint32_t seqno; uint8_t orig[6]; uint8_t prev_sender[6];
- uint8_t ttl; uint8_t num_hna; uint8_t gw_flags; /* flags related to gateway class */
- uint8_t align;
} __packed;
Two different ideas, both triggered by the align byte in header. This byte is a waste of space, it is not used, and it is probably not easy to find something which all packet types are going to need in the future.
Sure, anything that not all packet types have in common can't go inside of the batman_header. But are those three variables something we could agree on, being something that all packet types will need today and in the future? version + packet_type is something we'll always need I think, the TTL might be something to argue about, as packets that do not get routed would not necessarily need them (though it could be a "safety belt" in case of bugs, to really make sure packets only intended for one hop will not be routed).
- Did you try not having it. So long header is __packed, and all the
structures it is used in are __packed, i think the compiler will do the right thing. The downside is that alignment is not obvious. Most people will assume header is 4 bytes, not 3, and think the alignment of the packets is wrong.
- Did you consider using a union? It is a more invasive patch, but
the alignment is then clear. The downside is sizeof() no longer gives you the per packet type size, rather it gives you the size of the biggest member of the union. So this makes the change even more invasive and bug prone.
Hmm, no, actually haven't thought about that. So we'd actually put the batman packet types as a union inside of the batman-header structure, instead of putting the header structure at the front of each packet type. Don't know if I'd like that either, due to the reason you've mentioned.
I think i prefer 1), with appropriate comments to explain the alignment issue.
So I think I'd prefer the first option, that should work too :). Just didn't think that an extra Byte would matter that much, and had the readability / making the alignment a little more obvious in mind. (And who knows when we might need to increase the version number size already ;) )
Andrew
Cheers, Linus
All our packets have a TTL and with the last batman header patch also at the same place in a batman encapsulated packet. We can therefore savely do one single TTL check before sending any batman packet type.
This commit also modifies the TTL handling to be more consistent with how it is done in other network protocols (like IPv6): The TTL is always decreased before transmitting a packet and not on receiption for one thing. And packets with a TTL of zero will never be be sent out on a network interface for another. Compare with: RFC1812; RFC2460,4.4; RFC3443,2.3
Signed-off-by: Linus Lüssing linus.luessing@ascom.ch --- aggregation.c | 2 +- hard-interface.c | 2 +- routing.c | 92 --------------------------------------- send.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++------- unicast.c | 3 - vis.c | 6 --- 6 files changed, 111 insertions(+), 119 deletions(-)
diff --git a/batman-adv/aggregation.c b/batman-adv/aggregation.c index ad3c91b..550317e 100644 --- a/batman-adv/aggregation.c +++ b/batman-adv/aggregation.c @@ -69,7 +69,7 @@ static bool can_aggregate_with(struct batman_packet *new_batman_packet, * are flooded through the net */ if ((!directlink) && (!(batman_packet->flags & DIRECTLINK)) && - (batman_packet->header.ttl != 1) && + (batman_packet->header.ttl != 2) &&
/* own packets originating non-primary * interfaces leave only that interface */ diff --git a/batman-adv/hard-interface.c b/batman-adv/hard-interface.c index 8d523cc..52d32f2 100644 --- a/batman-adv/hard-interface.c +++ b/batman-adv/hard-interface.c @@ -314,7 +314,7 @@ int hardif_enable_interface(struct batman_if *batman_if, char *iface_name) batman_packet = (struct batman_packet *)(batman_if->packet_buff); batman_packet->header.packet_type = BAT_PACKET; batman_packet->header.version = COMPAT_VERSION; - batman_packet->header.ttl = 2; + batman_packet->header.ttl = 3; batman_packet->flags = 0; batman_packet->tq = TQ_MAX_VALUE; batman_packet->num_hna = 0; diff --git a/batman-adv/routing.c b/batman-adv/routing.c index 89e765f..293bb32 100644 --- a/batman-adv/routing.c +++ b/batman-adv/routing.c @@ -943,75 +943,6 @@ out: return ret; }
-static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, - struct sk_buff *skb) -{ - struct orig_node *orig_node = NULL; - struct neigh_node *neigh_node = NULL; - struct icmp_packet *icmp_packet; - int ret = NET_RX_DROP; - - icmp_packet = (struct icmp_packet *)skb->data; - - /* send TTL exceeded if packet is an echo request (traceroute) */ - if (icmp_packet->msg_type != ECHO_REQUEST) { - pr_debug("Warning - can't forward icmp packet from %pM to " - "%pM: ttl exceeded\n", icmp_packet->orig, - icmp_packet->dst); - goto out; - } - - if (!bat_priv->primary_if) - goto out; - - /* get routing information */ - rcu_read_lock(); - orig_node = ((struct orig_node *) - hash_find(bat_priv->orig_hash, compare_orig, choose_orig, - icmp_packet->orig)); - if (!orig_node) - goto unlock; - - kref_get(&orig_node->refcount); - neigh_node = orig_node->router; - - if (!neigh_node) - goto unlock; - - if (!atomic_inc_not_zero(&neigh_node->refcount)) { - neigh_node = NULL; - goto unlock; - } - - rcu_read_unlock(); - - /* create a copy of the skb, if needed, to modify it. */ - if (skb_cow(skb, sizeof(struct ethhdr)) < 0) - goto out; - - icmp_packet = (struct icmp_packet *)skb->data; - - memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); - memcpy(icmp_packet->orig, - bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); - icmp_packet->msg_type = TTL_EXCEEDED; - icmp_packet->header.ttl = TTL; - - send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); - ret = NET_RX_SUCCESS; - goto out; - -unlock: - rcu_read_unlock(); -out: - if (neigh_node) - neigh_node_free_ref(neigh_node); - if (orig_node) - kref_put(&orig_node->refcount, orig_node_free_ref); - return ret; -} - - int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if) { struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface); @@ -1060,10 +991,6 @@ int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if) if (is_my_mac(icmp_packet->dst)) return recv_my_icmp_packet(bat_priv, skb, hdr_size);
- /* TTL exceeded */ - if (icmp_packet->header.ttl < 2) - return recv_icmp_ttl_exceeded(bat_priv, skb); - /* get routing information */ rcu_read_lock(); orig_node = ((struct orig_node *) @@ -1091,9 +1018,6 @@ int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if)
icmp_packet = (struct icmp_packet_rr *)skb->data;
- /* decrement ttl */ - icmp_packet->header.ttl--; - /* route it */ send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); ret = NET_RX_SUCCESS; @@ -1286,20 +1210,11 @@ int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if) struct orig_node *orig_node = NULL; struct neigh_node *neigh_node = NULL; struct unicast_packet *unicast_packet; - struct ethhdr *ethhdr = (struct ethhdr *)skb_mac_header(skb); int ret = NET_RX_DROP; struct sk_buff *new_skb;
unicast_packet = (struct unicast_packet *)skb->data;
- /* TTL exceeded */ - if (unicast_packet->header.ttl < 2) { - pr_debug("Warning - can't forward unicast packet from %pM to " - "%pM: ttl exceeded\n", ethhdr->h_source, - unicast_packet->dest); - goto out; - } - /* get routing information */ rcu_read_lock(); orig_node = ((struct orig_node *) @@ -1347,12 +1262,8 @@ int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if) }
skb = new_skb; - unicast_packet = (struct unicast_packet *)skb->data; }
- /* decrement ttl */ - unicast_packet->header.ttl--; - /* route it */ send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); ret = NET_RX_SUCCESS; @@ -1455,9 +1366,6 @@ int recv_bcast_packet(struct sk_buff *skb, struct batman_if *recv_if) if (is_my_mac(bcast_packet->orig)) goto out;
- if (bcast_packet->header.ttl < 2) - goto out; - rcu_read_lock(); orig_node = ((struct orig_node *) hash_find(bat_priv->orig_hash, compare_orig, choose_orig, diff --git a/batman-adv/send.c b/batman-adv/send.c index b6a9a3b..f3e8895 100644 --- a/batman-adv/send.c +++ b/batman-adv/send.c @@ -22,6 +22,7 @@ #include "main.h" #include "send.h" #include "routing.h" +#include "hash.h" #include "translation-table.h" #include "soft-interface.h" #include "hard-interface.h" @@ -53,13 +54,107 @@ static unsigned long forward_send_time(void) return jiffies + msecs_to_jiffies(random32() % (JITTER/2)); }
+static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, + struct sk_buff *skb) +{ + struct orig_node *orig_node = NULL; + struct neigh_node *neigh_node = NULL; + struct icmp_packet *icmp_packet; + int ret = NET_RX_DROP; + + icmp_packet = (struct icmp_packet *)skb->data; + + /* send TTL exceeded if packet is an echo request (traceroute) */ + if (icmp_packet->msg_type != ECHO_REQUEST) { + pr_debug("Warning - can't forward icmp packet from %pM to " + "%pM: ttl exceeded\n", icmp_packet->orig, + icmp_packet->dst); + goto out; + } + + if (!bat_priv->primary_if) + goto out; + + /* get routing information */ + rcu_read_lock(); + orig_node = ((struct orig_node *) + hash_find(bat_priv->orig_hash, compare_orig, choose_orig, + icmp_packet->orig)); + if (!orig_node) + goto unlock; + + kref_get(&orig_node->refcount); + neigh_node = orig_node->router; + + if (!neigh_node) + goto unlock; + + if (!atomic_inc_not_zero(&neigh_node->refcount)) { + neigh_node = NULL; + goto unlock; + } + + rcu_read_unlock(); + + /* create a copy of the skb, if needed, to modify it. */ + if (skb_cow(skb, sizeof(struct ethhdr)) < 0) + goto out; + + icmp_packet = (struct icmp_packet *)skb->data; + + memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); + memcpy(icmp_packet->orig, + bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); + icmp_packet->msg_type = TTL_EXCEEDED; + icmp_packet->header.ttl = TTL; + + send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); + ret = NET_RX_SUCCESS; + goto out; + +unlock: + rcu_read_unlock(); +out: + if (neigh_node) + neigh_node_free_ref(neigh_node); + if (orig_node) + kref_put(&orig_node->refcount, orig_node_free_ref); + return ret; +} + +static void print_ttl_exceeded(struct sk_buff *skb, int packet_type, + struct bat_priv *bat_priv) { + switch (packet_type) { + case BAT_PACKET: + bat_dbg(DBG_BATMAN, bat_priv, "ttl exceeded\n"); + break; + case BAT_ICMP: + recv_icmp_ttl_exceeded(bat_priv, skb); + break; + case BAT_VIS: + pr_debug("Error - can't send vis packet: ttl exceeded\n"); + break; + case BAT_UNICAST: + pr_debug("Warning - can't forward unicast packet from %pM to " + "%pM: ttl exceeded\n", + ((struct ethhdr *)skb->data)->h_source, + ((struct unicast_packet *)skb->data)->dest); + break; + default: + break; + } +} + /* send out an already prepared packet to the given address via the - * specified batman interface */ + * specified batman interface; drops it if the current TTL is 1 or less + * or else reduces the TTL by one */ int send_skb_packet(struct sk_buff *skb, struct batman_if *batman_if, uint8_t *dst_addr) { struct ethhdr *ethhdr; + struct batman_header *batman_header; + struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface);
if (batman_if->if_status != IF_ACTIVE) goto send_skb_err; @@ -73,6 +168,15 @@ int send_skb_packet(struct sk_buff *skb, goto send_skb_err; }
+ if (unlikely(!pskb_may_pull(skb, sizeof(struct batman_packet)))) + goto send_skb_err; + batman_header = (struct batman_header *) skb->data; + if (batman_header->ttl <= 1) { + print_ttl_exceeded(skb, batman_header->packet_type, bat_priv); + goto send_skb_err; + } + batman_header->ttl--; + /* push to the ethernet header. */ if (my_skb_head_push(skb, sizeof(struct ethhdr)) < 0) goto send_skb_err; @@ -181,7 +285,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->header.ttl == 1)) || + if ((directlink && (batman_packet->header.ttl == 2)) || (forw_packet->own && (forw_packet->if_incoming->if_num > 0))) {
/* FIXME: what about aggregated packets ? */ @@ -310,15 +414,9 @@ 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->header.ttl <= 1) { - bat_dbg(DBG_BATMAN, bat_priv, "ttl exceeded\n"); - return; - } - in_tq = batman_packet->tq; in_ttl = batman_packet->header.ttl;
- batman_packet->header.ttl--; memcpy(batman_packet->prev_sender, ethhdr->h_source, ETH_ALEN);
/* rebroadcast tq of our best ranking neighbor to ensure the rebroadcast @@ -331,7 +429,7 @@ void schedule_forward_packet(struct orig_node *orig_node,
if (orig_node->router->last_ttl) batman_packet->header.ttl = - orig_node->router->last_ttl - 1; + orig_node->router->last_ttl; }
tq_avg = orig_node->router->tq_avg; @@ -343,8 +441,8 @@ void schedule_forward_packet(struct orig_node *orig_node, 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->header.ttl); + in_tq, tq_avg, batman_packet->tq, in_ttl, + batman_packet->header.ttl - 1);
batman_packet->seqno = htonl(batman_packet->seqno);
@@ -399,7 +497,6 @@ static void _add_bcast_packet_to_list(struct bat_priv *bat_priv, int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb) { struct forw_packet *forw_packet; - struct bcast_packet *bcast_packet;
if (!atomic_dec_not_zero(&bat_priv->bcast_queue_left)) { bat_dbg(DBG_BATMAN, bat_priv, "bcast packet queue full\n"); @@ -418,10 +515,6 @@ int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb) if (!skb) goto packet_free;
- /* as we have a copy now, it is safe to decrease the TTL */ - bcast_packet = (struct bcast_packet *)skb->data; - bcast_packet->header.ttl--; - skb_reset_mac_header(skb);
forw_packet->skb = skb; diff --git a/batman-adv/unicast.c b/batman-adv/unicast.c index 62e6c64..4cbc011 100644 --- a/batman-adv/unicast.c +++ b/batman-adv/unicast.c @@ -260,7 +260,6 @@ int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
memcpy(frag1, &tmp_uc, sizeof(struct unicast_packet));
- frag1->header.ttl--; frag1->header.version = COMPAT_VERSION; frag1->header.packet_type = BAT_UNICAST_FRAG;
@@ -337,8 +336,6 @@ find_router: if (atomic_read(&bat_priv->fragmentation) && data_len + sizeof(struct unicast_packet) > neigh_node->if_incoming->net_dev->mtu) { - /* send frag skb decreases ttl */ - unicast_packet->header.ttl++; ret = frag_send_skb(skb, bat_priv, neigh_node->if_incoming, neigh_node->addr); goto out; diff --git a/batman-adv/vis.c b/batman-adv/vis.c index 3551f06..926b328 100644 --- a/batman-adv/vis.c +++ b/batman-adv/vis.c @@ -806,20 +806,14 @@ static void send_vis_packet(struct bat_priv *bat_priv, struct vis_info *info) struct vis_packet *packet;
packet = (struct vis_packet *)info->skb_packet->data; - if (packet->header.ttl < 2) { - pr_debug("Error - can't send vis packet: ttl exceeded\n"); - return; - }
memcpy(packet->sender_orig, bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); - packet->header.ttl--;
if (is_broadcast_ether_addr(packet->target_orig)) broadcast_vis_packet(bat_priv, info); else unicast_vis_packet(bat_priv, info); - packet->header.ttl++; /* restore TTL */ }
/* called from timer; send (and maybe generate) vis packet. */
On Tue, Feb 15, 2011 at 06:12:18PM +0100, Linus L??ssing wrote:
All our packets have a TTL and with the last batman header patch also at the same place in a batman encapsulated packet. We can therefore savely do one single TTL check before sending any batman packet type.
+static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv,
struct sk_buff *skb)
+{
- struct orig_node *orig_node = NULL;
- struct neigh_node *neigh_node = NULL;
- struct icmp_packet *icmp_packet;
- int ret = NET_RX_DROP;
This is in the middle of the send path, so calling it recv_icmp_ttl_exceeded() seems a bit strange. I would say either send_icmp_ttl_exceeded() or recvd_icmp_ttl_exceeded() are better.
Andrew
Andrew Lunn andrew@lunn.ch schrieb am 16.02.2011 07:16:49:
[Bild entfernt]
Re: [B.A.T.M.A.N.] [PATCH 03/13] batman-adv: Unify TTL handling
Andrew Lunn
an:
The list for a Better Approach To Mobile Ad-hoc Networking
16.02.2011 07:17
Kopie:
Linus L??ssing
On Tue, Feb 15, 2011 at 06:12:18PM +0100, Linus L??ssing wrote:
All our packets have a TTL and with the last batman header patch also
at
the same place in a batman encapsulated packet. We can therefore
savely
do one single TTL check before sending any batman packet type.
+static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv,
struct sk_buff *skb)
+{
- struct orig_node *orig_node = NULL;
- struct neigh_node *neigh_node = NULL;
- struct icmp_packet *icmp_packet;
- int ret = NET_RX_DROP;
This is in the middle of the send path, so calling it recv_icmp_ttl_exceeded() seems a bit strange. I would say either send_icmp_ttl_exceeded() or recvd_icmp_ttl_exceeded() are better.
Andrew
Ah, yes, you're right, I missed that when I just moved the function. the recv_ naming does not make sense here anymore, correct, I'll change that.
Signed-off-by: Linus Lüssing linus.luessing@ascom.ch --- routing.c | 20 +++++++++----------- routing.h | 3 ++- soft-interface.c | 3 ++- 3 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/batman-adv/routing.c b/batman-adv/routing.c index 293bb32..e53f6f5 100644 --- a/batman-adv/routing.c +++ b/batman-adv/routing.c @@ -1204,22 +1204,20 @@ static int check_unicast_packet(struct sk_buff *skb, int hdr_size) return 0; }
-int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if) +int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, + uint8_t *dest, uint8_t packet_type) { struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface); struct orig_node *orig_node = NULL; struct neigh_node *neigh_node = NULL; - struct unicast_packet *unicast_packet; int ret = NET_RX_DROP; struct sk_buff *new_skb;
- unicast_packet = (struct unicast_packet *)skb->data; - /* get routing information */ rcu_read_lock(); orig_node = ((struct orig_node *) hash_find(bat_priv->orig_hash, compare_orig, choose_orig, - unicast_packet->dest)); + dest));
if (!orig_node) goto unlock; @@ -1237,9 +1235,7 @@ int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if) if (skb_cow(skb, sizeof(struct ethhdr)) < 0) goto out;
- unicast_packet = (struct unicast_packet *)skb->data; - - if (unicast_packet->header.packet_type == BAT_UNICAST && + if (packet_type == BAT_UNICAST && atomic_read(&bat_priv->fragmentation) && skb->len > neigh_node->if_incoming->net_dev->mtu) { ret = frag_send_skb(skb, bat_priv, @@ -1247,7 +1243,7 @@ int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if) goto out; }
- if (unicast_packet->header.packet_type == BAT_UNICAST_FRAG && + if (packet_type == BAT_UNICAST_FRAG && frag_can_reassemble(skb, neigh_node->if_incoming->net_dev->mtu)) {
ret = frag_reassemble_skb(skb, bat_priv, &new_skb); @@ -1295,7 +1291,8 @@ int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if) return NET_RX_SUCCESS; }
- return route_unicast_packet(skb, recv_if); + return route_unicast_packet(skb, recv_if, unicast_packet->dest, + unicast_packet->header.packet_type); }
int recv_ucast_frag_packet(struct sk_buff *skb, struct batman_if *recv_if) @@ -1328,7 +1325,8 @@ int recv_ucast_frag_packet(struct sk_buff *skb, struct batman_if *recv_if) return NET_RX_SUCCESS; }
- return route_unicast_packet(skb, recv_if); + return route_unicast_packet(skb, recv_if, unicast_packet->dest, + unicast_packet->header.packet_type); }
diff --git a/batman-adv/routing.h b/batman-adv/routing.h index d302bd7..c6b2ad3 100644 --- a/batman-adv/routing.h +++ b/batman-adv/routing.h @@ -30,7 +30,8 @@ void receive_bat_packet(struct ethhdr *ethhdr, void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node, struct neigh_node *neigh_node, unsigned char *hna_buff, int hna_buff_len); -int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if); +int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, + uint8_t *dest, uint8_t packet_type); int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if); 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); diff --git a/batman-adv/soft-interface.c b/batman-adv/soft-interface.c index 55edebb..0b48bf1 100644 --- a/batman-adv/soft-interface.c +++ b/batman-adv/soft-interface.c @@ -482,7 +482,8 @@ void interface_rx(struct net_device *soft_iface,
memcpy(unicast_packet->dest, bat_priv->softif_neigh->addr, ETH_ALEN); - ret = route_unicast_packet(skb, recv_if); + ret = route_unicast_packet(skb, recv_if, unicast_packet->dest, + unicast_packet->header.packet_type); if (ret == NET_RX_DROP) goto dropped;
This structure is being used in several places - removing some redundancy.
Signed-off-by: Linus Lüssing linus.luessing@ascom.ch --- hash.h | 18 +++++++++++++++ icmp_socket.c | 21 +++++------------ originator.c | 11 +------- routing.c | 67 +++++++++++++------------------------------------------- send.c | 20 +++++------------ unicast.c | 14 +---------- 6 files changed, 50 insertions(+), 101 deletions(-)
diff --git a/batman-adv/hash.h b/batman-adv/hash.h index 3c48c6b..2b6a8ae 100644 --- a/batman-adv/hash.h +++ b/batman-adv/hash.h @@ -23,6 +23,7 @@ #define _NET_BATMAN_ADV_HASH_H_
#include <linux/list.h> +#include "originator.h"
/* callback to a compare function. should * compare 2 element datas for their keys, @@ -193,4 +194,21 @@ static inline void *hash_find(struct hashtable_t *hash, return bucket_data; }
+/* increases the orig_node's refcount, if found */ +static inline struct orig_node *hash_find_orig(struct bat_priv *bat_priv, + uint8_t *dest) +{ + struct hashtable_t *hash = bat_priv->orig_hash; + struct orig_node *orig_node; + + rcu_read_lock(); + + orig_node = hash_find(hash, compare_orig, choose_orig, dest); + if (orig_node) + kref_get(&orig_node->refcount); + + rcu_read_unlock(); + return orig_node; +} + #endif /* _NET_BATMAN_ADV_HASH_H_ */ diff --git a/batman-adv/icmp_socket.c b/batman-adv/icmp_socket.c index 869c9aa..90fb0b7 100644 --- a/batman-adv/icmp_socket.c +++ b/batman-adv/icmp_socket.c @@ -218,23 +218,16 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE) goto dst_unreach;
- rcu_read_lock(); - orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, - compare_orig, choose_orig, - icmp_packet->dst)); - + orig_node = hash_find_orig(bat_priv, icmp_packet->dst); if (!orig_node) - goto unlock; + goto dst_unreach;
- kref_get(&orig_node->refcount); + rcu_read_lock(); neigh_node = orig_node->router; - - if (!neigh_node) - goto unlock; - - if (!atomic_inc_not_zero(&neigh_node->refcount)) { + if (!neigh_node || !atomic_inc_not_zero(&neigh_node->refcount)) { neigh_node = NULL; - goto unlock; + rcu_read_unlock(); + goto dst_unreach; }
rcu_read_unlock(); @@ -255,8 +248,6 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); goto out;
-unlock: - rcu_read_unlock(); dst_unreach: icmp_packet->msg_type = DESTINATION_UNREACHABLE; bat_socket_add_packet(socket_client, icmp_packet, packet_len); diff --git a/batman-adv/originator.c b/batman-adv/originator.c index bde9778..af3f338 100644 --- a/batman-adv/originator.c +++ b/batman-adv/originator.c @@ -189,16 +189,9 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr) int size; int hash_added;
- rcu_read_lock(); - orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, - compare_orig, choose_orig, - addr)); - rcu_read_unlock(); - - if (orig_node) { - kref_get(&orig_node->refcount); + orig_node = hash_find_orig(bat_priv, addr); + if (orig_node) return orig_node; - }
bat_dbg(DBG_BATMAN, bat_priv, "Creating new originator: %pM\n", addr); diff --git a/batman-adv/routing.c b/batman-adv/routing.c index e53f6f5..081c461 100644 --- a/batman-adv/routing.c +++ b/batman-adv/routing.c @@ -897,22 +897,16 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv,
/* answer echo request (ping) */ /* get routing information */ - rcu_read_lock(); - orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, - compare_orig, choose_orig, - icmp_packet->orig)); + orig_node = hash_find_orig(bat_priv, icmp_packet->orig); if (!orig_node) - goto unlock; + goto out;
- kref_get(&orig_node->refcount); + rcu_read_lock(); neigh_node = orig_node->router; - - if (!neigh_node) - goto unlock; - - if (!atomic_inc_not_zero(&neigh_node->refcount)) { + if (!neigh_node || !atomic_inc_not_zero(&neigh_node->refcount)) { neigh_node = NULL; - goto unlock; + rcu_read_unlock(); + goto out; }
rcu_read_unlock(); @@ -933,8 +927,6 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv, ret = NET_RX_SUCCESS; goto out;
-unlock: - rcu_read_unlock(); out: if (neigh_node) neigh_node_free_ref(neigh_node); @@ -992,22 +984,16 @@ int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if) return recv_my_icmp_packet(bat_priv, skb, hdr_size);
/* get routing information */ - rcu_read_lock(); - orig_node = ((struct orig_node *) - hash_find(bat_priv->orig_hash, compare_orig, choose_orig, - icmp_packet->dst)); + orig_node = hash_find_orig(bat_priv, icmp_packet->dst); if (!orig_node) - goto unlock; + goto out;
- kref_get(&orig_node->refcount); + rcu_read_lock(); neigh_node = orig_node->router; - - if (!neigh_node) - goto unlock; - - if (!atomic_inc_not_zero(&neigh_node->refcount)) { + if (!neigh_node || !atomic_inc_not_zero(&neigh_node->refcount)) { neigh_node = NULL; - goto unlock; + rcu_read_unlock(); + goto out; }
rcu_read_unlock(); @@ -1023,8 +1009,6 @@ int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if) ret = NET_RX_SUCCESS; goto out;
-unlock: - rcu_read_unlock(); out: if (neigh_node) neigh_node_free_ref(neigh_node); @@ -1214,16 +1198,9 @@ int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, struct sk_buff *new_skb;
/* get routing information */ - rcu_read_lock(); - orig_node = ((struct orig_node *) - hash_find(bat_priv->orig_hash, compare_orig, choose_orig, - dest)); - + orig_node = hash_find_orig(bat_priv, dest); if (!orig_node) - goto unlock; - - kref_get(&orig_node->refcount); - rcu_read_unlock(); + goto out;
/* find_router() increases neigh_nodes refcount if found. */ neigh_node = find_router(bat_priv, orig_node, recv_if); @@ -1265,8 +1242,6 @@ int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, ret = NET_RX_SUCCESS; goto out;
-unlock: - rcu_read_unlock(); out: if (neigh_node) neigh_node_free_ref(neigh_node); @@ -1364,16 +1339,9 @@ int recv_bcast_packet(struct sk_buff *skb, struct batman_if *recv_if) if (is_my_mac(bcast_packet->orig)) goto out;
- rcu_read_lock(); - orig_node = ((struct orig_node *) - hash_find(bat_priv->orig_hash, compare_orig, choose_orig, - bcast_packet->orig)); - + orig_node = hash_find_orig(bat_priv, bcast_packet->orig); if (!orig_node) - goto rcu_unlock; - - kref_get(&orig_node->refcount); - rcu_read_unlock(); + goto out;
spin_lock_bh(&orig_node->bcast_seqno_lock);
@@ -1404,9 +1372,6 @@ int recv_bcast_packet(struct sk_buff *skb, struct batman_if *recv_if) ret = NET_RX_SUCCESS; goto out;
-rcu_unlock: - rcu_read_unlock(); - goto out; spin_unlock: spin_unlock_bh(&orig_node->bcast_seqno_lock); out: diff --git a/batman-adv/send.c b/batman-adv/send.c index f3e8895..df4cd34 100644 --- a/batman-adv/send.c +++ b/batman-adv/send.c @@ -76,22 +76,16 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, goto out;
/* get routing information */ - rcu_read_lock(); - orig_node = ((struct orig_node *) - hash_find(bat_priv->orig_hash, compare_orig, choose_orig, - icmp_packet->orig)); + orig_node = hash_find_orig(bat_priv, icmp_packet->orig); if (!orig_node) - goto unlock; + goto out;
- kref_get(&orig_node->refcount); + rcu_read_lock(); neigh_node = orig_node->router; - - if (!neigh_node) - goto unlock; - - if (!atomic_inc_not_zero(&neigh_node->refcount)) { + if (!neigh_node || !atomic_inc_not_zero(&neigh_node->refcount)) { neigh_node = NULL; - goto unlock; + rcu_read_unlock(); + goto out; }
rcu_read_unlock(); @@ -112,8 +106,6 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, ret = NET_RX_SUCCESS; goto out;
-unlock: - rcu_read_unlock(); out: if (neigh_node) neigh_node_free_ref(neigh_node); diff --git a/batman-adv/unicast.c b/batman-adv/unicast.c index 4cbc011..4d794cb 100644 --- a/batman-adv/unicast.c +++ b/batman-adv/unicast.c @@ -184,15 +184,9 @@ int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
*new_skb = NULL;
- rcu_read_lock(); - orig_node = ((struct orig_node *) - hash_find(bat_priv->orig_hash, compare_orig, choose_orig, - unicast_packet->orig)); + orig_node = hash_find_orig(bat_priv, unicast_packet->orig); if (!orig_node) - goto unlock; - - kref_get(&orig_node->refcount); - rcu_read_unlock(); + goto out;
orig_node->last_frag_packet = jiffies;
@@ -217,10 +211,6 @@ int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv, if (*new_skb) ret = NET_RX_SUCCESS;
- goto out; - -unlock: - rcu_read_unlock(); out: if (orig_node) kref_put(&orig_node->refcount, orig_node_free_ref);
This removes some redundancy present in unicast_send_skb(). It now invokes route_unicast_packet() for the next hop decision and sending.
Signed-off-by: Linus Lüssing linus.luessing@ascom.ch --- routing.c | 15 ++++++++------- routing.h | 5 +++-- soft-interface.c | 3 ++- unicast.c | 41 +++++++---------------------------------- 4 files changed, 20 insertions(+), 44 deletions(-)
diff --git a/batman-adv/routing.c b/batman-adv/routing.c index 081c461..f8fb709 100644 --- a/batman-adv/routing.c +++ b/batman-adv/routing.c @@ -1188,10 +1188,10 @@ static int check_unicast_packet(struct sk_buff *skb, int hdr_size) return 0; }
-int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, - uint8_t *dest, uint8_t packet_type) +int route_unicast_packet(struct bat_priv *bat_priv, struct sk_buff *skb, + struct batman_if *recv_if, uint8_t *dest, + uint8_t packet_type) { - struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface); struct orig_node *orig_node = NULL; struct neigh_node *neigh_node = NULL; int ret = NET_RX_DROP; @@ -1252,6 +1252,7 @@ out:
int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if) { + struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface); struct unicast_packet *unicast_packet; int hdr_size = sizeof(struct unicast_packet);
@@ -1266,8 +1267,8 @@ int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if) return NET_RX_SUCCESS; }
- return route_unicast_packet(skb, recv_if, unicast_packet->dest, - unicast_packet->header.packet_type); + return route_unicast_packet(bat_priv, skb, recv_if, + unicast_packet->dest, unicast_packet->header.packet_type); }
int recv_ucast_frag_packet(struct sk_buff *skb, struct batman_if *recv_if) @@ -1300,8 +1301,8 @@ int recv_ucast_frag_packet(struct sk_buff *skb, struct batman_if *recv_if) return NET_RX_SUCCESS; }
- return route_unicast_packet(skb, recv_if, unicast_packet->dest, - unicast_packet->header.packet_type); + return route_unicast_packet(bat_priv, skb, recv_if, + unicast_packet->dest, unicast_packet->header.packet_type); }
diff --git a/batman-adv/routing.h b/batman-adv/routing.h index c6b2ad3..406f396 100644 --- a/batman-adv/routing.h +++ b/batman-adv/routing.h @@ -30,8 +30,9 @@ void receive_bat_packet(struct ethhdr *ethhdr, void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node, struct neigh_node *neigh_node, unsigned char *hna_buff, int hna_buff_len); -int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, - uint8_t *dest, uint8_t packet_type); +int route_unicast_packet(struct bat_priv *bat_priv, struct sk_buff *skb, + struct batman_if *recv_if, uint8_t *dest, + uint8_t packet_type); int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if); 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); diff --git a/batman-adv/soft-interface.c b/batman-adv/soft-interface.c index 0b48bf1..23f374a 100644 --- a/batman-adv/soft-interface.c +++ b/batman-adv/soft-interface.c @@ -482,7 +482,8 @@ void interface_rx(struct net_device *soft_iface,
memcpy(unicast_packet->dest, bat_priv->softif_neigh->addr, ETH_ALEN); - ret = route_unicast_packet(skb, recv_if, unicast_packet->dest, + ret = route_unicast_packet(bat_priv, skb, recv_if, + unicast_packet->dest, unicast_packet->header.packet_type); if (ret == NET_RX_DROP) goto dropped; diff --git a/batman-adv/unicast.c b/batman-adv/unicast.c index 4d794cb..df69514 100644 --- a/batman-adv/unicast.c +++ b/batman-adv/unicast.c @@ -282,34 +282,19 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv) struct ethhdr *ethhdr = (struct ethhdr *)skb->data; struct unicast_packet *unicast_packet; struct orig_node *orig_node; - struct neigh_node *neigh_node; - int data_len = skb->len; - int ret = 1; + int ret = NET_RX_DROP;
/* get routing information */ if (is_multicast_ether_addr(ethhdr->h_dest)) { orig_node = (struct orig_node *)gw_get_selected(bat_priv); if (orig_node) - goto find_router; + goto route; }
/* check for hna host - increases orig_node refcount */ orig_node = transtable_search(bat_priv, ethhdr->h_dest);
-find_router: - /** - * find_router(): - * - if orig_node is NULL it returns NULL - * - increases neigh_nodes refcount if found. - */ - neigh_node = find_router(bat_priv, orig_node, NULL); - - if (!neigh_node) - goto out; - - if (neigh_node->if_incoming->if_status != IF_ACTIVE) - goto out; - +route: if (my_skb_head_push(skb, sizeof(struct unicast_packet)) < 0) goto out;
@@ -323,24 +308,12 @@ find_router: /* copy the destination for faster routing */ memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN);
- if (atomic_read(&bat_priv->fragmentation) && - data_len + sizeof(struct unicast_packet) > - neigh_node->if_incoming->net_dev->mtu) { - ret = frag_send_skb(skb, bat_priv, - neigh_node->if_incoming, neigh_node->addr); - goto out; - } - - send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); - ret = 0; - goto out; + ret = route_unicast_packet(orig_node->bat_priv, skb, NULL, + unicast_packet->dest, unicast_packet->header.packet_type);
out: - if (neigh_node) - neigh_node_free_ref(neigh_node); - if (orig_node) - kref_put(&orig_node->refcount, orig_node_free_ref); - if (ret == 1) + if (ret == NET_RX_DROP) kfree_skb(skb); + return ret; }
Signed-off-by: Linus Lüssing linus.luessing@ascom.ch --- routing.c | 37 ++++++++++++++++++------------------- routing.h | 8 +++----- soft-interface.c | 6 ++++-- unicast.c | 4 ++-- 4 files changed, 27 insertions(+), 28 deletions(-)
diff --git a/batman-adv/routing.c b/batman-adv/routing.c index f8fb709..4899649 100644 --- a/batman-adv/routing.c +++ b/batman-adv/routing.c @@ -1020,10 +1020,10 @@ out: /* find a suitable router for this originator, and use * bonding if possible. increases the found neighbors * refcount.*/ -struct neigh_node *find_router(struct bat_priv *bat_priv, - struct orig_node *orig_node, +struct neigh_node *find_router(struct orig_node *orig_node, struct batman_if *recv_if) { + struct bat_priv *bat_priv; struct orig_node *primary_orig_node; struct orig_node *router_orig; struct neigh_node *router, *first_candidate, *tmp_neigh_node; @@ -1036,6 +1036,8 @@ struct neigh_node *find_router(struct bat_priv *bat_priv, if (!orig_node->router) return NULL;
+ bat_priv = orig_node->bat_priv; + /* without bonding, the first node should * always choose the default router. */ bonding_enabled = atomic_read(&bat_priv->bonding); @@ -1188,22 +1190,15 @@ static int check_unicast_packet(struct sk_buff *skb, int hdr_size) return 0; }
-int route_unicast_packet(struct bat_priv *bat_priv, struct sk_buff *skb, - struct batman_if *recv_if, uint8_t *dest, - uint8_t packet_type) +int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, + struct orig_node *orig_node, uint8_t packet_type) { - struct orig_node *orig_node = NULL; struct neigh_node *neigh_node = NULL; int ret = NET_RX_DROP; struct sk_buff *new_skb;
- /* get routing information */ - orig_node = hash_find_orig(bat_priv, dest); - if (!orig_node) - goto out; - /* find_router() increases neigh_nodes refcount if found. */ - neigh_node = find_router(bat_priv, orig_node, recv_if); + neigh_node = find_router(orig_node, recv_if);
if (!neigh_node) goto out; @@ -1213,9 +1208,9 @@ int route_unicast_packet(struct bat_priv *bat_priv, struct sk_buff *skb, goto out;
if (packet_type == BAT_UNICAST && - atomic_read(&bat_priv->fragmentation) && + atomic_read(&orig_node->bat_priv->fragmentation) && skb->len > neigh_node->if_incoming->net_dev->mtu) { - ret = frag_send_skb(skb, bat_priv, + ret = frag_send_skb(skb, orig_node->bat_priv, neigh_node->if_incoming, neigh_node->addr); goto out; } @@ -1223,7 +1218,7 @@ int route_unicast_packet(struct bat_priv *bat_priv, struct sk_buff *skb, if (packet_type == BAT_UNICAST_FRAG && frag_can_reassemble(skb, neigh_node->if_incoming->net_dev->mtu)) {
- ret = frag_reassemble_skb(skb, bat_priv, &new_skb); + ret = frag_reassemble_skb(skb, orig_node->bat_priv, &new_skb);
if (ret == NET_RX_DROP) goto out; @@ -1254,6 +1249,7 @@ int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if) { struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface); struct unicast_packet *unicast_packet; + struct orig_node *orig_node; int hdr_size = sizeof(struct unicast_packet);
if (check_unicast_packet(skb, hdr_size) < 0) @@ -1267,14 +1263,16 @@ int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if) return NET_RX_SUCCESS; }
- return route_unicast_packet(bat_priv, skb, recv_if, - unicast_packet->dest, unicast_packet->header.packet_type); + orig_node = hash_find_orig(bat_priv, unicast_packet->dest); + return route_unicast_packet(skb, recv_if, orig_node, + unicast_packet->header.packet_type); }
int recv_ucast_frag_packet(struct sk_buff *skb, struct batman_if *recv_if) { struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface); struct unicast_frag_packet *unicast_packet; + struct orig_node *orig_node; int hdr_size = sizeof(struct unicast_frag_packet); struct sk_buff *new_skb = NULL; int ret; @@ -1301,8 +1299,9 @@ int recv_ucast_frag_packet(struct sk_buff *skb, struct batman_if *recv_if) return NET_RX_SUCCESS; }
- return route_unicast_packet(bat_priv, skb, recv_if, - unicast_packet->dest, unicast_packet->header.packet_type); + orig_node = hash_find_orig(bat_priv, unicast_packet->dest); + return route_unicast_packet(skb, recv_if, orig_node, + unicast_packet->header.packet_type); }
diff --git a/batman-adv/routing.h b/batman-adv/routing.h index 406f396..3c04bb0 100644 --- a/batman-adv/routing.h +++ b/batman-adv/routing.h @@ -30,17 +30,15 @@ void receive_bat_packet(struct ethhdr *ethhdr, void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node, struct neigh_node *neigh_node, unsigned char *hna_buff, int hna_buff_len); -int route_unicast_packet(struct bat_priv *bat_priv, struct sk_buff *skb, - struct batman_if *recv_if, uint8_t *dest, - uint8_t packet_type); +int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, + struct orig_node *orig_node, uint8_t packet_type); int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if); 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_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 neigh_node *find_router(struct orig_node *orig_node, struct batman_if *recv_if); void bonding_candidate_del(struct orig_node *orig_node, struct neigh_node *neigh_node); diff --git a/batman-adv/soft-interface.c b/batman-adv/soft-interface.c index 23f374a..7225764 100644 --- a/batman-adv/soft-interface.c +++ b/batman-adv/soft-interface.c @@ -439,6 +439,7 @@ void interface_rx(struct net_device *soft_iface, { struct bat_priv *bat_priv = netdev_priv(soft_iface); struct unicast_packet *unicast_packet; + struct orig_node *orig_node; struct ethhdr *ethhdr; struct vlan_ethhdr *vhdr; short vid = -1; @@ -482,8 +483,9 @@ void interface_rx(struct net_device *soft_iface,
memcpy(unicast_packet->dest, bat_priv->softif_neigh->addr, ETH_ALEN); - ret = route_unicast_packet(bat_priv, skb, recv_if, - unicast_packet->dest, + + orig_node = hash_find_orig(bat_priv, unicast_packet->dest); + ret = route_unicast_packet(skb, recv_if, orig_node, unicast_packet->header.packet_type); if (ret == NET_RX_DROP) goto dropped; diff --git a/batman-adv/unicast.c b/batman-adv/unicast.c index df69514..7262a22 100644 --- a/batman-adv/unicast.c +++ b/batman-adv/unicast.c @@ -308,8 +308,8 @@ route: /* copy the destination for faster routing */ memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN);
- ret = route_unicast_packet(orig_node->bat_priv, skb, NULL, - unicast_packet->dest, unicast_packet->header.packet_type); + ret = route_unicast_packet(skb, NULL, orig_node, + unicast_packet->header.packet_type);
out: if (ret == NET_RX_DROP)
Instead of branching the code paths and having several possible methods doing the final preparation and sending of an skb, depending on whether a packet needs to be fragmented or not, this commit now decouples the sending procedure from the fragmentation methods: The fragmentation methods are only manipulating a packet_list and packet_list_entries now so that the fragmentation process becomes transparent for route_unicast_packet().
This further allows easier integration of future extensions that send copies of multiple (modified) unicast packets to several next hop neighbours.
Signed-off-by: Linus Lüssing linus.luessing@ascom.ch --- routing.c | 76 +++++++++++++++----------------------- routing.h | 4 +-- send.c | 14 +++++++ send.h | 7 ++++ soft-interface.c | 3 +- unicast.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++----- unicast.h | 25 +------------ 7 files changed, 153 insertions(+), 83 deletions(-)
diff --git a/batman-adv/routing.c b/batman-adv/routing.c index 4899649..3fceca0 100644 --- a/batman-adv/routing.c +++ b/batman-adv/routing.c @@ -1020,21 +1020,24 @@ out: /* find a suitable router for this originator, and use * bonding if possible. increases the found neighbors * refcount.*/ -struct neigh_node *find_router(struct orig_node *orig_node, - struct batman_if *recv_if) +static void find_router(struct orig_node *orig_node, + struct batman_if *recv_if, + struct sk_buff *skb, + struct hlist_head *packet_list) { struct bat_priv *bat_priv; struct orig_node *primary_orig_node; struct orig_node *router_orig; struct neigh_node *router, *first_candidate, *tmp_neigh_node; + struct packet_list_entry *entry; static uint8_t zero_mac[ETH_ALEN] = {0, 0, 0, 0, 0, 0}; int bonding_enabled;
if (!orig_node) - return NULL; + return;
if (!orig_node->router) - return NULL; + return;
bat_priv = orig_node->bat_priv;
@@ -1048,7 +1051,7 @@ struct neigh_node *find_router(struct orig_node *orig_node, router_orig = orig_node->router->orig_node; if (!router_orig || !atomic_inc_not_zero(&router->refcount)) { rcu_read_unlock(); - return NULL; + return; }
if ((!recv_if) && (!bonding_enabled)) @@ -1110,7 +1113,7 @@ struct neigh_node *find_router(struct orig_node *orig_node,
if (!router) { rcu_read_unlock(); - return NULL; + return; }
/* selected should point to the next element @@ -1162,7 +1165,16 @@ struct neigh_node *find_router(struct orig_node *orig_node, } return_router: rcu_read_unlock(); - return router; + + entry = kmalloc(sizeof(struct packet_list_entry), GFP_ATOMIC); + if (!entry) { + kfree_skb(skb); + return; + } + + entry->skb = skb; + entry->neigh_node = router; + hlist_add_head(&entry->list, packet_list); }
static int check_unicast_packet(struct sk_buff *skb, int hdr_size) @@ -1191,55 +1203,29 @@ static int check_unicast_packet(struct sk_buff *skb, int hdr_size) }
int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, - struct orig_node *orig_node, uint8_t packet_type) + struct orig_node *orig_node) { - struct neigh_node *neigh_node = NULL; int ret = NET_RX_DROP; - struct sk_buff *new_skb; + struct hlist_head packet_list;
- /* find_router() increases neigh_nodes refcount if found. */ - neigh_node = find_router(orig_node, recv_if); - - if (!neigh_node) - goto out; + INIT_HLIST_HEAD(&packet_list);
/* create a copy of the skb, if needed, to modify it. */ if (skb_cow(skb, sizeof(struct ethhdr)) < 0) goto out;
- if (packet_type == BAT_UNICAST && - atomic_read(&orig_node->bat_priv->fragmentation) && - skb->len > neigh_node->if_incoming->net_dev->mtu) { - ret = frag_send_skb(skb, orig_node->bat_priv, - neigh_node->if_incoming, neigh_node->addr); - goto out; - } + /* creates the (initial) packet list */ + find_router(orig_node, recv_if, skb, &packet_list);
- if (packet_type == BAT_UNICAST_FRAG && - frag_can_reassemble(skb, neigh_node->if_incoming->net_dev->mtu)) { + /* split packets that won't fit or maybe buffer fragments */ + frag_packet_list(orig_node->bat_priv, &packet_list);
- ret = frag_reassemble_skb(skb, orig_node->bat_priv, &new_skb); - - if (ret == NET_RX_DROP) - goto out; - - /* packet was buffered for late merge */ - if (!new_skb) { - ret = NET_RX_SUCCESS; - goto out; - } - - skb = new_skb; - } - - /* route it */ - send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); + /* route them */ + send_packet_list(&packet_list); ret = NET_RX_SUCCESS; goto out;
out: - if (neigh_node) - neigh_node_free_ref(neigh_node); if (orig_node) kref_put(&orig_node->refcount, orig_node_free_ref); return ret; @@ -1264,8 +1250,7 @@ int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if) }
orig_node = hash_find_orig(bat_priv, unicast_packet->dest); - return route_unicast_packet(skb, recv_if, orig_node, - unicast_packet->header.packet_type); + return route_unicast_packet(skb, recv_if, orig_node); }
int recv_ucast_frag_packet(struct sk_buff *skb, struct batman_if *recv_if) @@ -1300,8 +1285,7 @@ int recv_ucast_frag_packet(struct sk_buff *skb, struct batman_if *recv_if) }
orig_node = hash_find_orig(bat_priv, unicast_packet->dest); - return route_unicast_packet(skb, recv_if, orig_node, - unicast_packet->header.packet_type); + return route_unicast_packet(skb, recv_if, orig_node); }
diff --git a/batman-adv/routing.h b/batman-adv/routing.h index 3c04bb0..43a2609 100644 --- a/batman-adv/routing.h +++ b/batman-adv/routing.h @@ -31,15 +31,13 @@ void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node, struct neigh_node *neigh_node, unsigned char *hna_buff, int hna_buff_len); int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, - struct orig_node *orig_node, uint8_t packet_type); + struct orig_node *orig_node); int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if); 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_bat_packet(struct sk_buff *skb, struct batman_if *recv_if); -struct neigh_node *find_router(struct orig_node *orig_node, - struct batman_if *recv_if); void bonding_candidate_del(struct orig_node *orig_node, struct neigh_node *neigh_node);
diff --git a/batman-adv/send.c b/batman-adv/send.c index df4cd34..20476b0 100644 --- a/batman-adv/send.c +++ b/batman-adv/send.c @@ -196,6 +196,20 @@ send_skb_err: return NET_XMIT_DROP; }
+void send_packet_list(struct hlist_head *packet_list) +{ + struct packet_list_entry *entry; + struct hlist_node *pos, *tmp; + + hlist_for_each_entry_safe(entry, pos, tmp, packet_list, list) { + send_skb_packet(entry->skb, entry->neigh_node->if_incoming, + entry->neigh_node->addr); + neigh_node_free_ref(entry->neigh_node); + hlist_del(&entry->list); + kfree(entry); + } +} + /* Send a packet to a given interface */ static void send_packet_to_if(struct forw_packet *forw_packet, struct batman_if *batman_if) diff --git a/batman-adv/send.h b/batman-adv/send.h index b68c272..fc7780f 100644 --- a/batman-adv/send.h +++ b/batman-adv/send.h @@ -22,9 +22,16 @@ #ifndef _NET_BATMAN_ADV_SEND_H_ #define _NET_BATMAN_ADV_SEND_H_
+struct packet_list_entry { + struct hlist_node list; + struct sk_buff *skb; + struct neigh_node *neigh_node; +}; + int send_skb_packet(struct sk_buff *skb, struct batman_if *batman_if, uint8_t *dst_addr); +void send_packet_list(struct hlist_head *packet_list); void schedule_own_packet(struct batman_if *batman_if); void schedule_forward_packet(struct orig_node *orig_node, struct ethhdr *ethhdr, diff --git a/batman-adv/soft-interface.c b/batman-adv/soft-interface.c index 7225764..f3c7141 100644 --- a/batman-adv/soft-interface.c +++ b/batman-adv/soft-interface.c @@ -485,8 +485,7 @@ void interface_rx(struct net_device *soft_iface, bat_priv->softif_neigh->addr, ETH_ALEN);
orig_node = hash_find_orig(bat_priv, unicast_packet->dest); - ret = route_unicast_packet(skb, recv_if, orig_node, - unicast_packet->header.packet_type); + ret = route_unicast_packet(skb, recv_if, orig_node); if (ret == NET_RX_DROP) goto dropped;
diff --git a/batman-adv/unicast.c b/batman-adv/unicast.c index 7262a22..b824315 100644 --- a/batman-adv/unicast.c +++ b/batman-adv/unicast.c @@ -217,17 +217,43 @@ out: return ret; }
-int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv, - struct batman_if *batman_if, uint8_t dstaddr[]) +static void frag_reassemble_packet(struct packet_list_entry *entry, + struct bat_priv *bat_priv) +{ + struct sk_buff *new_skb = NULL; + int ret; + + ret = frag_reassemble_skb(entry->skb, bat_priv, &new_skb); + + /* Could reassemble packet, leave this new one in list */ + if (new_skb) { + entry->skb = new_skb; + return; + } + + /* merge failed */ + if (ret == NET_RX_DROP) + kfree_skb(entry->skb); + + /* merge failed or skb is buffered, remove from send list */ + neigh_node_free_ref(entry->neigh_node); + hlist_del(&entry->list); + kfree(entry); +} + +static void frag_skb(struct packet_list_entry *entry, struct bat_priv *bat_priv) { struct unicast_packet tmp_uc, *unicast_packet; struct sk_buff *frag_skb; struct unicast_frag_packet *frag1, *frag2; + struct packet_list_entry *frag_entry; int uc_hdr_len = sizeof(struct unicast_packet); int ucf_hdr_len = sizeof(struct unicast_frag_packet); - int data_len = skb->len - uc_hdr_len; + int data_len = entry->skb->len - uc_hdr_len; int large_tail = 0; uint16_t seqno; + struct sk_buff *skb = entry->skb; + struct batman_if *batman_if = entry->neigh_node->if_incoming;
if (!bat_priv->primary_if) goto dropped; @@ -266,15 +292,79 @@ int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv, frag1->seqno = htons(seqno - 1); frag2->seqno = htons(seqno);
- send_skb_packet(skb, batman_if, dstaddr); - send_skb_packet(frag_skb, batman_if, dstaddr); - return NET_RX_SUCCESS; + frag_entry = kmalloc(sizeof(struct packet_list_entry), GFP_ATOMIC); + if (!frag_entry) + goto drop_frag; + + if (!atomic_inc_not_zero(&entry->neigh_node->refcount)) + goto drop_frag; + + frag_entry->skb = frag_skb; + frag_entry->neigh_node = entry->neigh_node; + hlist_add_before(&frag_entry->list, &entry->list);
drop_frag: kfree_skb(frag_skb); dropped: kfree_skb(skb); - return NET_RX_DROP; + neigh_node_free_ref(entry->neigh_node); + hlist_del(&entry->list); + kfree(entry); +} + +static inline int frag_can_reassemble(struct sk_buff *skb, int mtu) +{ + struct unicast_frag_packet *unicast_packet; + int uneven_correction = 0; + unsigned int merged_size; + + unicast_packet = (struct unicast_frag_packet *)skb->data; + + if (unicast_packet->flags & UNI_FRAG_LARGETAIL) { + if (unicast_packet->flags & UNI_FRAG_HEAD) + uneven_correction = 1; + else + uneven_correction = -1; + } + + merged_size = (skb->len - 2 * sizeof(struct unicast_frag_packet)); + merged_size += sizeof(struct unicast_packet) + uneven_correction; + + return merged_size <= mtu; +} + +void frag_packet_list(struct bat_priv *bat_priv, + struct hlist_head *packet_list) +{ + struct packet_list_entry *entry; + struct hlist_node *pos, *tmp; + uint8_t packet_type; + + hlist_for_each_entry_safe(entry, pos, tmp, packet_list, list) { + packet_type = ((struct batman_header *) + entry->skb->data)->packet_type; + + switch (packet_type) { + case BAT_UNICAST: + if (!atomic_read(&bat_priv->fragmentation) || + entry->skb->len <= + entry->neigh_node->if_incoming->net_dev->mtu) + break; + + frag_skb(entry, bat_priv); + break; + case BAT_UNICAST_FRAG: + if (!frag_can_reassemble(entry->skb, + entry->neigh_node->if_incoming->net_dev->mtu)) + break; + + frag_reassemble_packet(entry, bat_priv); + break; + default: + /* We should never be here... */ + break; + } + } }
int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv) @@ -308,8 +398,7 @@ route: /* copy the destination for faster routing */ memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN);
- ret = route_unicast_packet(skb, NULL, orig_node, - unicast_packet->header.packet_type); + ret = route_unicast_packet(skb, NULL, orig_node);
out: if (ret == NET_RX_DROP) diff --git a/batman-adv/unicast.h b/batman-adv/unicast.h index 8897308..1b4dbb0 100644 --- a/batman-adv/unicast.h +++ b/batman-adv/unicast.h @@ -30,29 +30,8 @@ int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv, struct sk_buff **new_skb); void frag_list_free(struct list_head *head); +void frag_packet_list(struct bat_priv *bat_priv, + struct hlist_head *packet_list); int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv); -int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv, - struct batman_if *batman_if, uint8_t dstaddr[]); - -static inline int frag_can_reassemble(struct sk_buff *skb, int mtu) -{ - struct unicast_frag_packet *unicast_packet; - int uneven_correction = 0; - unsigned int merged_size; - - unicast_packet = (struct unicast_frag_packet *)skb->data; - - if (unicast_packet->flags & UNI_FRAG_LARGETAIL) { - if (unicast_packet->flags & UNI_FRAG_HEAD) - uneven_correction = 1; - else - uneven_correction = -1; - } - - merged_size = (skb->len - sizeof(struct unicast_frag_packet)) * 2; - merged_size += sizeof(struct unicast_packet) + uneven_correction; - - return merged_size <= mtu; -}
#endif /* _NET_BATMAN_ADV_UNICAST_H_ */
When bonding is enabled, then enabling red_bonding too changes the behavior from throughput bonding (round robin sending on interfaces) to redundant bonding (sending every packet on all interfaces available for bonding).
Signed-off-by: Linus Lüssing linus.luessing@ascom.ch --- bat_sysfs.c | 10 ++++++++++ soft-interface.c | 1 + types.h | 1 + 3 files changed, 12 insertions(+), 0 deletions(-)
diff --git a/batman-adv/bat_sysfs.c b/batman-adv/bat_sysfs.c index 93ae20a..fb9f3e9 100644 --- a/batman-adv/bat_sysfs.c +++ b/batman-adv/bat_sysfs.c @@ -356,8 +356,17 @@ static ssize_t store_gw_bwidth(struct kobject *kobj, struct attribute *attr, return gw_bandwidth_set(net_dev, buff, count); }
+static void print_bonding_notice(struct net_device *net_dev) +{ + bat_info(net_dev, "Redundant Bonding mode is currently not compatible " + "with batman-adv's link layer fragmentation and will " + "be ignored. Also make sure to activate general " + "bonding for redundant bonding to take effect.\n"); +} + BAT_ATTR_BOOL(aggregated_ogms, S_IRUGO | S_IWUSR, NULL); BAT_ATTR_BOOL(bonding, S_IRUGO | S_IWUSR, NULL); +BAT_ATTR_BOOL(red_bonding, S_IRUGO | S_IWUSR, print_bonding_notice); BAT_ATTR_BOOL(fragmentation, S_IRUGO | S_IWUSR, update_min_mtu); static BAT_ATTR(vis_mode, S_IRUGO | S_IWUSR, show_vis_mode, store_vis_mode); static BAT_ATTR(gw_mode, S_IRUGO | S_IWUSR, show_gw_mode, store_gw_mode); @@ -374,6 +383,7 @@ BAT_ATTR_UINT(log_level, S_IRUGO | S_IWUSR, 0, 3, NULL); static struct bat_attribute *mesh_attrs[] = { &bat_attr_aggregated_ogms, &bat_attr_bonding, + &bat_attr_red_bonding, &bat_attr_fragmentation, &bat_attr_vis_mode, &bat_attr_gw_mode, diff --git a/batman-adv/soft-interface.c b/batman-adv/soft-interface.c index f3c7141..25db300 100644 --- a/batman-adv/soft-interface.c +++ b/batman-adv/soft-interface.c @@ -590,6 +590,7 @@ struct net_device *softif_create(char *name)
atomic_set(&bat_priv->aggregated_ogms, 1); atomic_set(&bat_priv->bonding, 0); + atomic_set(&bat_priv->red_bonding, 0); atomic_set(&bat_priv->vis_mode, VIS_TYPE_CLIENT_UPDATE); atomic_set(&bat_priv->gw_mode, GW_MODE_OFF); atomic_set(&bat_priv->gw_sel_class, 20); diff --git a/batman-adv/types.h b/batman-adv/types.h index b6acb12..c2ddd0a 100644 --- a/batman-adv/types.h +++ b/batman-adv/types.h @@ -131,6 +131,7 @@ struct bat_priv { struct net_device_stats stats; atomic_t aggregated_ogms; /* boolean */ atomic_t bonding; /* boolean */ + atomic_t red_bonding; /* boolean */ atomic_t fragmentation; /* boolean */ atomic_t vis_mode; /* VIS_TYPE_* */ atomic_t gw_mode; /* GW_MODE_* */
With this feature unicast packets can be send in a redundancy bonding instead of throughput bonding mode on all interfaces available towards a common node. This shall increase the robustness of unicast data transfer / decrease packet loss in cases where bursty packet loss on only one channel, which batman-adv's link quality measurements cannot detect, is to be expected or where batman-adv's metric adaptation is expected to be too slow for certain scenarios.
Signed-off-by: Linus Lüssing linus.luessing@ascom.ch --- main.h | 5 ++ packet.h | 8 ++++ routing.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++++----- routing.h | 3 +- soft-interface.c | 8 +++- types.h | 1 + unicast.c | 10 +++-- unicast.h | 2 +- 8 files changed, 135 insertions(+), 19 deletions(-)
diff --git a/batman-adv/main.h b/batman-adv/main.h index bd8470d..862643a 100644 --- a/batman-adv/main.h +++ b/batman-adv/main.h @@ -97,6 +97,11 @@ * Vis */
+/* Bonding modes */ +#define THROUGHPUT_BONDING 1 +#define REDUNDANT_BONDING 2 + + /* * Kernel headers */ diff --git a/batman-adv/packet.h b/batman-adv/packet.h index ae7a0ce..e5a897c 100644 --- a/batman-adv/packet.h +++ b/batman-adv/packet.h @@ -30,6 +30,7 @@ #define BAT_BCAST 0x04 #define BAT_VIS 0x05 #define BAT_UNICAST_FRAG 0x06 +#define BAT_UNICAST_SAFE 0x07
/* this file is included by batctl which needs these defines */ #define COMPAT_VERSION 12 @@ -101,6 +102,13 @@ struct unicast_packet { uint8_t dest[6]; } __packed;
+struct unicast_packet_safe { + struct batman_header header; + uint8_t dest[6]; + uint8_t orig[6]; + uint32_t seqno; +} __packed; + struct unicast_frag_packet { struct batman_header header; uint8_t dest[6]; diff --git a/batman-adv/routing.c b/batman-adv/routing.c index 3fceca0..0797ab5 100644 --- a/batman-adv/routing.c +++ b/batman-adv/routing.c @@ -1017,10 +1017,77 @@ out: return ret; }
+static int unicast_to_unicast_safe(struct sk_buff *skb, + struct bat_priv *bat_priv) +{ + struct unicast_packet unicast_packet; + struct unicast_packet_safe *unicast_packet_safe; + + memcpy(&unicast_packet, skb->data, sizeof(unicast_packet)); + if (my_skb_head_push(skb, sizeof(struct unicast_packet_safe) - + sizeof(struct unicast_packet)) < 0) + return -1; + + unicast_packet_safe = (struct unicast_packet_safe *) skb->data; + unicast_packet_safe->header = unicast_packet.header; + memcpy(unicast_packet_safe->dest, unicast_packet.dest, ETH_ALEN); + unicast_packet_safe->header.packet_type = BAT_UNICAST_SAFE; + memcpy(unicast_packet_safe->orig, + bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); + unicast_packet_safe->seqno = + htonl(atomic_inc_return(&bat_priv->dup_seqno)); + + return 0; +} + +static void red_bonding_copy(struct sk_buff *skb, struct list_head *bond_list, + struct hlist_head *packet_list, + struct bat_priv *bat_priv) +{ + struct neigh_node *neigh_node; + struct packet_list_entry *entry; + int num_entries = 0; + int packet_type = ((struct batman_header *) skb->data)->packet_type; + + /* We only expect either BAT_UNICAST or BAT_UNICAST_SAFE here */ + if (packet_type == BAT_UNICAST) { + if (unicast_to_unicast_safe(skb, bat_priv) < 0) { + kfree_skb(skb); + return; + } + } + + list_for_each_entry_rcu(neigh_node, bond_list, bonding_list) { + entry = kmalloc(sizeof(struct packet_list_entry), GFP_ATOMIC); + if (!entry) { + kfree_skb(skb); + return; + } + if (!num_entries) + entry->skb = skb; + else { + entry->skb = skb_copy(skb, GFP_ATOMIC); + if (!entry->skb) { + kfree_skb(skb); + kfree(entry); + return; + } + } + entry->neigh_node = neigh_node; + if (!atomic_inc_not_zero(&neigh_node->refcount)) { + kfree_skb(entry->skb); + kfree(entry); + continue; + } + hlist_add_head(&entry->list, packet_list); + num_entries++; + } +} + /* find a suitable router for this originator, and use * bonding if possible. increases the found neighbors * refcount.*/ -static void find_router(struct orig_node *orig_node, +static void find_router(int bonding_mode, struct orig_node *orig_node, struct batman_if *recv_if, struct sk_buff *skb, struct hlist_head *packet_list) @@ -1031,7 +1098,6 @@ static void find_router(struct orig_node *orig_node, struct neigh_node *router, *first_candidate, *tmp_neigh_node; struct packet_list_entry *entry; static uint8_t zero_mac[ETH_ALEN] = {0, 0, 0, 0, 0, 0}; - int bonding_enabled;
if (!orig_node) return; @@ -1043,7 +1109,6 @@ static void find_router(struct orig_node *orig_node,
/* without bonding, the first node should * always choose the default router. */ - bonding_enabled = atomic_read(&bat_priv->bonding);
rcu_read_lock(); /* select default router to output */ @@ -1054,7 +1119,7 @@ static void find_router(struct orig_node *orig_node, return; }
- if ((!recv_if) && (!bonding_enabled)) + if ((!recv_if) && (!bonding_mode)) goto return_router;
/* if we have something in the primary_addr, we can search @@ -1090,7 +1155,7 @@ static void find_router(struct orig_node *orig_node, first_candidate = NULL; router = NULL;
- if (bonding_enabled) { + if (bonding_mode == THROUGHPUT_BONDING) { /* in the bonding case, send the packets in a round * robin fashion over the remaining interfaces. */
@@ -1126,6 +1191,11 @@ static void find_router(struct orig_node *orig_node, &router->bonding_list); spin_unlock_bh(&primary_orig_node->neigh_list_lock);
+ } else if (bonding_mode == REDUNDANT_BONDING) { + red_bonding_copy(skb, &primary_orig_node->bond_list, + packet_list, bat_priv); + rcu_read_unlock(); + return; } else { /* if bonding is disabled, use the best of the * remaining candidates which are not using @@ -1202,12 +1272,16 @@ static int check_unicast_packet(struct sk_buff *skb, int hdr_size) return 0; }
-int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, +int route_unicast_packet(int bonding_mode, struct sk_buff *skb, + struct batman_if *recv_if, struct orig_node *orig_node) { int ret = NET_RX_DROP; struct hlist_head packet_list;
+ if (!orig_node) + goto out; + INIT_HLIST_HEAD(&packet_list);
/* create a copy of the skb, if needed, to modify it. */ @@ -1215,10 +1289,10 @@ int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, goto out;
/* creates the (initial) packet list */ - find_router(orig_node, recv_if, skb, &packet_list); + find_router(bonding_mode, orig_node, recv_if, skb, &packet_list);
/* split packets that won't fit or maybe buffer fragments */ - frag_packet_list(orig_node->bat_priv, &packet_list); + frag_packet_list(bonding_mode, orig_node->bat_priv, &packet_list);
/* route them */ send_packet_list(&packet_list); @@ -1237,6 +1311,7 @@ int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if) struct unicast_packet *unicast_packet; struct orig_node *orig_node; int hdr_size = sizeof(struct unicast_packet); + int bonding_mode;
if (check_unicast_packet(skb, hdr_size) < 0) return NET_RX_DROP; @@ -1249,8 +1324,10 @@ int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if) return NET_RX_SUCCESS; }
+ bonding_mode = atomic_read(&bat_priv->bonding) << + atomic_read(&bat_priv->red_bonding); orig_node = hash_find_orig(bat_priv, unicast_packet->dest); - return route_unicast_packet(skb, recv_if, orig_node); + return route_unicast_packet(bonding_mode, skb, recv_if, orig_node); }
int recv_ucast_frag_packet(struct sk_buff *skb, struct batman_if *recv_if) @@ -1260,7 +1337,7 @@ int recv_ucast_frag_packet(struct sk_buff *skb, struct batman_if *recv_if) struct orig_node *orig_node; int hdr_size = sizeof(struct unicast_frag_packet); struct sk_buff *new_skb = NULL; - int ret; + int ret, bonding_mode;
if (check_unicast_packet(skb, hdr_size) < 0) return NET_RX_DROP; @@ -1284,8 +1361,26 @@ int recv_ucast_frag_packet(struct sk_buff *skb, struct batman_if *recv_if) return NET_RX_SUCCESS; }
+ /* The redundant bonding mode currently cannot handle fragmented + * packets, therefore need to defrag them first */ + bonding_mode = atomic_read(&bat_priv->bonding) << + atomic_read(&bat_priv->red_bonding); + + if (bonding_mode == REDUNDANT_BONDING) { + ret = frag_reassemble_skb(skb, bat_priv, &new_skb); + + if (ret == NET_RX_DROP) + return NET_RX_DROP; + + /* packet was buffered for late merge */ + if (!new_skb) + return NET_RX_SUCCESS; + + skb = new_skb; + } + orig_node = hash_find_orig(bat_priv, unicast_packet->dest); - return route_unicast_packet(skb, recv_if, orig_node); + return route_unicast_packet(bonding_mode, skb, recv_if, orig_node); }
diff --git a/batman-adv/routing.h b/batman-adv/routing.h index 43a2609..01fab8d 100644 --- a/batman-adv/routing.h +++ b/batman-adv/routing.h @@ -30,7 +30,8 @@ void receive_bat_packet(struct ethhdr *ethhdr, void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node, struct neigh_node *neigh_node, unsigned char *hna_buff, int hna_buff_len); -int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, +int route_unicast_packet(int bonding_mode, struct sk_buff *skb, + struct batman_if *recv_if, struct orig_node *orig_node); int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if); int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if); diff --git a/batman-adv/soft-interface.c b/batman-adv/soft-interface.c index 25db300..c6035fe 100644 --- a/batman-adv/soft-interface.c +++ b/batman-adv/soft-interface.c @@ -443,7 +443,7 @@ void interface_rx(struct net_device *soft_iface, struct ethhdr *ethhdr; struct vlan_ethhdr *vhdr; short vid = -1; - int ret; + int ret, bonding_mode;
/* check if enough space is available for pulling, and pull */ if (!pskb_may_pull(skb, hdr_size)) @@ -484,8 +484,11 @@ void interface_rx(struct net_device *soft_iface, memcpy(unicast_packet->dest, bat_priv->softif_neigh->addr, ETH_ALEN);
+ bonding_mode = atomic_read(&bat_priv->bonding) << + atomic_read(&bat_priv->red_bonding); orig_node = hash_find_orig(bat_priv, unicast_packet->dest); - ret = route_unicast_packet(skb, recv_if, orig_node); + ret = route_unicast_packet(bonding_mode, skb, recv_if, + orig_node); if (ret == NET_RX_DROP) goto dropped;
@@ -604,6 +607,7 @@ struct net_device *softif_create(char *name)
atomic_set(&bat_priv->mesh_state, MESH_INACTIVE); atomic_set(&bat_priv->bcast_seqno, 1); + atomic_set(&bat_priv->dup_seqno, 1); atomic_set(&bat_priv->hna_local_changed, 0);
bat_priv->primary_if = NULL; diff --git a/batman-adv/types.h b/batman-adv/types.h index c2ddd0a..5401498 100644 --- a/batman-adv/types.h +++ b/batman-adv/types.h @@ -141,6 +141,7 @@ struct bat_priv { atomic_t hop_penalty; /* uint */ atomic_t log_level; /* uint */ atomic_t bcast_seqno; + atomic_t dup_seqno; atomic_t bcast_queue_left; atomic_t batman_queue_left; char num_ifaces; diff --git a/batman-adv/unicast.c b/batman-adv/unicast.c index b824315..aa46103 100644 --- a/batman-adv/unicast.c +++ b/batman-adv/unicast.c @@ -30,7 +30,6 @@ #include "routing.h" #include "hard-interface.h"
- static struct sk_buff *frag_merge_packet(struct list_head *head, struct frag_packet_list_entry *tfp, struct sk_buff *skb) @@ -333,7 +332,7 @@ static inline int frag_can_reassemble(struct sk_buff *skb, int mtu) return merged_size <= mtu; }
-void frag_packet_list(struct bat_priv *bat_priv, +void frag_packet_list(int bonding, struct bat_priv *bat_priv, struct hlist_head *packet_list) { struct packet_list_entry *entry; @@ -347,6 +346,7 @@ void frag_packet_list(struct bat_priv *bat_priv, switch (packet_type) { case BAT_UNICAST: if (!atomic_read(&bat_priv->fragmentation) || + bonding == REDUNDANT_BONDING || entry->skb->len <= entry->neigh_node->if_incoming->net_dev->mtu) break; @@ -372,7 +372,7 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv) struct ethhdr *ethhdr = (struct ethhdr *)skb->data; struct unicast_packet *unicast_packet; struct orig_node *orig_node; - int ret = NET_RX_DROP; + int ret = NET_RX_DROP, bonding_mode;
/* get routing information */ if (is_multicast_ether_addr(ethhdr->h_dest)) { @@ -398,7 +398,9 @@ route: /* copy the destination for faster routing */ memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN);
- ret = route_unicast_packet(skb, NULL, orig_node); + bonding_mode = atomic_read(&bat_priv->bonding) << + atomic_read(&bat_priv->red_bonding); + ret = route_unicast_packet(bonding_mode, skb, NULL, orig_node);
out: if (ret == NET_RX_DROP) diff --git a/batman-adv/unicast.h b/batman-adv/unicast.h index 1b4dbb0..e87597b 100644 --- a/batman-adv/unicast.h +++ b/batman-adv/unicast.h @@ -30,7 +30,7 @@ int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv, struct sk_buff **new_skb); void frag_list_free(struct list_head *head); -void frag_packet_list(struct bat_priv *bat_priv, +void frag_packet_list(int bonding, struct bat_priv *bat_priv, struct hlist_head *packet_list); int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv);
With this commit unicast_safe packets generated by a node in redundant bonding mode will be processed on reception. It is being transformed back to a normal unicast packet if the packet is for the node itself or if redundant bonding mode is deactivated on this node. Otherwise it is being passed on as is to the routing functions.
Signed-off-by: Linus Lüssing linus.luessing@ascom.ch --- hard-interface.c | 5 ++++ routing.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++--- routing.h | 1 + 3 files changed, 62 insertions(+), 4 deletions(-)
diff --git a/batman-adv/hard-interface.c b/batman-adv/hard-interface.c index 52d32f2..fa12a4e 100644 --- a/batman-adv/hard-interface.c +++ b/batman-adv/hard-interface.c @@ -623,6 +623,11 @@ static int batman_skb_recv(struct sk_buff *skb, struct net_device *dev, ret = recv_ucast_frag_packet(skb, batman_if); break;
+ /* fragmented unicast packet */ + case BAT_UNICAST_SAFE: + ret = recv_ucast_safe_packet(skb, batman_if); + break; + /* broadcast packet */ case BAT_BCAST: ret = recv_bcast_packet(skb, batman_if); diff --git a/batman-adv/routing.c b/batman-adv/routing.c index 0797ab5..4aa7fb5 100644 --- a/batman-adv/routing.c +++ b/batman-adv/routing.c @@ -1017,6 +1017,29 @@ out: return ret; }
+static void unicast_safe_to_unicast(struct sk_buff *skb) +{ + struct unicast_packet_safe unicast_packet_safe; + struct unicast_packet *unicast_packet; + + unicast_packet_safe = *((struct unicast_packet_safe *)skb->data); + unicast_packet = (struct unicast_packet *) skb_pull(skb, + sizeof(struct unicast_packet_safe) - + sizeof(struct unicast_packet)); + + unicast_packet->header = unicast_packet_safe.header; + unicast_packet->header.packet_type = BAT_UNICAST; + memcpy(unicast_packet->dest, unicast_packet_safe.dest, ETH_ALEN); +} + +static void set_unicast_safe_options(struct bat_priv *bat_priv, + struct unicast_packet_safe *unicast_packet) +{ + memcpy(unicast_packet->orig, bat_priv->primary_if->net_dev->dev_addr, + ETH_ALEN); + unicast_packet->seqno = htonl(atomic_inc_return(&bat_priv->dup_seqno)); +} + static int unicast_to_unicast_safe(struct sk_buff *skb, struct bat_priv *bat_priv) { @@ -1032,10 +1055,7 @@ static int unicast_to_unicast_safe(struct sk_buff *skb, unicast_packet_safe->header = unicast_packet.header; memcpy(unicast_packet_safe->dest, unicast_packet.dest, ETH_ALEN); unicast_packet_safe->header.packet_type = BAT_UNICAST_SAFE; - memcpy(unicast_packet_safe->orig, - bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); - unicast_packet_safe->seqno = - htonl(atomic_inc_return(&bat_priv->dup_seqno)); + set_unicast_safe_options(bat_priv, unicast_packet_safe);
return 0; } @@ -1383,6 +1403,38 @@ int recv_ucast_frag_packet(struct sk_buff *skb, struct batman_if *recv_if) return route_unicast_packet(bonding_mode, skb, recv_if, orig_node); }
+int recv_ucast_safe_packet(struct sk_buff *skb, struct batman_if *recv_if) +{ + struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface); + struct unicast_packet_safe *unicast_packet; + struct orig_node *orig_node; + int hdr_size = sizeof(struct unicast_packet); + int bonding_mode; + + if (check_unicast_packet(skb, hdr_size) < 0) + return NET_RX_DROP; + + unicast_packet = (struct unicast_packet_safe *)skb->data; + + /* packet for me */ + if (is_my_mac(unicast_packet->dest)) { + unicast_safe_to_unicast(skb); + + interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size); + return NET_RX_SUCCESS; + } + + bonding_mode = atomic_read(&bat_priv->bonding) << + atomic_read(&bat_priv->red_bonding); + + if (bonding_mode != REDUNDANT_BONDING) + unicast_safe_to_unicast(skb); + else + set_unicast_safe_options(bat_priv, unicast_packet); + + orig_node = hash_find_orig(bat_priv, unicast_packet->dest); + return route_unicast_packet(bonding_mode, skb, recv_if, orig_node); +}
int recv_bcast_packet(struct sk_buff *skb, struct batman_if *recv_if) { diff --git a/batman-adv/routing.h b/batman-adv/routing.h index 01fab8d..146b290 100644 --- a/batman-adv/routing.h +++ b/batman-adv/routing.h @@ -36,6 +36,7 @@ int route_unicast_packet(int bonding_mode, struct sk_buff *skb, int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if); 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_ucast_safe_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_bat_packet(struct sk_buff *skb, struct batman_if *recv_if);
This reduces the size of recv_bcast_packet, increasing its readability. It further introduces a generic function for duplicate checking for data packets (which might later be used for multicast or promiscous unicast packet handling or other packets).
Signed-off-by: Linus Lüssing linus.luessing@ascom.ch --- originator.c | 2 +- routing.c | 60 ++++++++++++++++++++++++++++++++++----------------------- types.h | 10 ++++++-- 3 files changed, 44 insertions(+), 28 deletions(-)
diff --git a/batman-adv/originator.c b/batman-adv/originator.c index af3f338..4845421 100644 --- a/batman-adv/originator.c +++ b/batman-adv/originator.c @@ -211,7 +211,7 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr) memcpy(orig_node->orig, addr, ETH_ALEN); orig_node->router = NULL; orig_node->hna_buff = NULL; - orig_node->bcast_seqno_reset = jiffies - 1 + orig_node->bcast_seqno_state.seqno_reset = jiffies - 1 - msecs_to_jiffies(RESET_PROTECTION_MS); orig_node->batman_seqno_reset = jiffies - 1 - msecs_to_jiffies(RESET_PROTECTION_MS); diff --git a/batman-adv/routing.c b/batman-adv/routing.c index 4aa7fb5..afbeef8 100644 --- a/batman-adv/routing.c +++ b/batman-adv/routing.c @@ -1292,6 +1292,36 @@ static int check_unicast_packet(struct sk_buff *skb, int hdr_size) return 0; }
+static inline int check_duplicate(struct bat_priv *bat_priv, uint32_t seqno, + struct seqno_state *seqno_state, + spinlock_t *seqno_lock) +{ + int32_t seq_diff; + int ret = NET_RX_DROP; + + spin_lock_bh(seqno_lock); + + /* check whether the packet is a duplicate */ + if (get_bit_status(seqno_state->bits, seqno_state->last_seqno, seqno)) + goto spin_unlock; + + seq_diff = seqno - seqno_state->last_seqno; + + /* check whether the packet is old and the host just restarted. */ + if (window_protected(bat_priv, seq_diff, &seqno_state->seqno_reset)) + goto spin_unlock; + + /* mark broadcast in flood history, update window position + * if required. */ + if (bit_get_packet(bat_priv, seqno_state->bits, seq_diff, 1)) + seqno_state->last_seqno = seqno; + + ret = NET_RX_SUCCESS; +spin_unlock: + spin_unlock_bh(seqno_lock); + return ret; +} + int route_unicast_packet(int bonding_mode, struct sk_buff *skb, struct batman_if *recv_if, struct orig_node *orig_node) @@ -1444,7 +1474,6 @@ int recv_bcast_packet(struct sk_buff *skb, struct batman_if *recv_if) struct ethhdr *ethhdr; int hdr_size = sizeof(struct bcast_packet); int ret = NET_RX_DROP; - int32_t seq_diff;
/* drop packet if it has not necessary minimum size */ if (unlikely(!pskb_may_pull(skb, hdr_size))) @@ -1474,26 +1503,13 @@ int recv_bcast_packet(struct sk_buff *skb, struct batman_if *recv_if) if (!orig_node) goto out;
- spin_lock_bh(&orig_node->bcast_seqno_lock); + ret = check_duplicate(bat_priv, ntohl(bcast_packet->seqno), + &orig_node->bcast_seqno_state, + &orig_node->bcast_seqno_lock);
- /* check whether the packet is a duplicate */ - if (get_bit_status(orig_node->bcast_bits, orig_node->last_bcast_seqno, - ntohl(bcast_packet->seqno))) - goto spin_unlock; - - seq_diff = ntohl(bcast_packet->seqno) - orig_node->last_bcast_seqno; - - /* check whether the packet is old and the host just restarted. */ - if (window_protected(bat_priv, seq_diff, - &orig_node->bcast_seqno_reset)) - goto spin_unlock; - - /* mark broadcast in flood history, update window position - * if required. */ - if (bit_get_packet(bat_priv, orig_node->bcast_bits, seq_diff, 1)) - orig_node->last_bcast_seqno = ntohl(bcast_packet->seqno); - - spin_unlock_bh(&orig_node->bcast_seqno_lock); + kref_put(&orig_node->refcount, orig_node_free_ref); + if (ret == NET_RX_DROP) + goto out;
/* rebroadcast packet */ add_bcast_packet_to_list(bat_priv, skb); @@ -1503,11 +1519,7 @@ int recv_bcast_packet(struct sk_buff *skb, struct batman_if *recv_if) ret = NET_RX_SUCCESS; goto out;
-spin_unlock: - spin_unlock_bh(&orig_node->bcast_seqno_lock); out: - if (orig_node) - kref_put(&orig_node->refcount, orig_node_free_ref); return ret; }
diff --git a/batman-adv/types.h b/batman-adv/types.h index 5401498..5a2035a 100644 --- a/batman-adv/types.h +++ b/batman-adv/types.h @@ -49,6 +49,12 @@ struct batman_if { struct rcu_head rcu; };
+struct seqno_state { + unsigned long seqno_reset; + uint32_t last_seqno; + unsigned long bits[NUM_WORDS]; +}; + /** * orig_node - structure for orig_list maintaining nodes of mesh * @primary_addr: hosts primary interface address @@ -71,7 +77,6 @@ struct orig_node { unsigned long *bcast_own; uint8_t *bcast_own_sum; unsigned long last_valid; - unsigned long bcast_seqno_reset; unsigned long batman_seqno_reset; uint8_t gw_flags; uint8_t flags; @@ -79,14 +84,13 @@ struct orig_node { int16_t hna_buff_len; uint32_t last_real_seqno; uint8_t last_ttl; - unsigned long bcast_bits[NUM_WORDS]; - uint32_t last_bcast_seqno; struct hlist_head neigh_list; struct list_head frag_list; spinlock_t neigh_list_lock; /* protects neighbor list */ struct kref refcount; struct bat_priv *bat_priv; unsigned long last_frag_packet; + struct seqno_state bcast_seqno_state; spinlock_t ogm_cnt_lock; /* protects: bcast_own, bcast_own_sum, * neigh_node->real_bits, * neigh_node->real_packet_count */
With the new redundant bonding mode a node might receive a unicast_safe packet more than once. Therefore duplicate checks on any unicast_safe packet need to be performed before further processing.
Signed-off-by: Linus Lüssing linus.luessing@ascom.ch --- originator.c | 3 +++ routing.c | 14 +++++++++++++- types.h | 2 ++ 3 files changed, 18 insertions(+), 1 deletions(-)
diff --git a/batman-adv/originator.c b/batman-adv/originator.c index 4845421..7dc090c 100644 --- a/batman-adv/originator.c +++ b/batman-adv/originator.c @@ -204,6 +204,7 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr) INIT_LIST_HEAD(&orig_node->bond_list); spin_lock_init(&orig_node->ogm_cnt_lock); spin_lock_init(&orig_node->bcast_seqno_lock); + spin_lock_init(&orig_node->ucast_safe_seqno_lock); spin_lock_init(&orig_node->neigh_list_lock); kref_init(&orig_node->refcount);
@@ -213,6 +214,8 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr) orig_node->hna_buff = NULL; orig_node->bcast_seqno_state.seqno_reset = jiffies - 1 - msecs_to_jiffies(RESET_PROTECTION_MS); + orig_node->ucast_safe_seqno_state.seqno_reset = jiffies - 1 + - msecs_to_jiffies(RESET_PROTECTION_MS); orig_node->batman_seqno_reset = jiffies - 1 - msecs_to_jiffies(RESET_PROTECTION_MS);
diff --git a/batman-adv/routing.c b/batman-adv/routing.c index afbeef8..f92e5d3 100644 --- a/batman-adv/routing.c +++ b/batman-adv/routing.c @@ -1439,13 +1439,25 @@ int recv_ucast_safe_packet(struct sk_buff *skb, struct batman_if *recv_if) struct unicast_packet_safe *unicast_packet; struct orig_node *orig_node; int hdr_size = sizeof(struct unicast_packet); - int bonding_mode; + int ret, bonding_mode;
if (check_unicast_packet(skb, hdr_size) < 0) return NET_RX_DROP;
unicast_packet = (struct unicast_packet_safe *)skb->data;
+ orig_node = hash_find_orig(bat_priv, unicast_packet->orig); + if (!orig_node) + return NET_RX_DROP; + + ret = check_duplicate(bat_priv, ntohl(unicast_packet->seqno), + &orig_node->ucast_safe_seqno_state, + &orig_node->ucast_safe_seqno_lock); + + kref_put(&orig_node->refcount, orig_node_free_ref); + if (ret == NET_RX_DROP) + return NET_RX_DROP; + /* packet for me */ if (is_my_mac(unicast_packet->dest)) { unicast_safe_to_unicast(skb); diff --git a/batman-adv/types.h b/batman-adv/types.h index 5a2035a..d0ab22f 100644 --- a/batman-adv/types.h +++ b/batman-adv/types.h @@ -91,11 +91,13 @@ struct orig_node { struct bat_priv *bat_priv; unsigned long last_frag_packet; struct seqno_state bcast_seqno_state; + struct seqno_state ucast_safe_seqno_state; spinlock_t ogm_cnt_lock; /* protects: bcast_own, bcast_own_sum, * neigh_node->real_bits, * neigh_node->real_packet_count */ spinlock_t bcast_seqno_lock; /* protects bcast_bits, * last_bcast_seqno */ + spinlock_t ucast_safe_seqno_lock; /* protects ucast_safe_seqno_state */ atomic_t bond_candidates; struct list_head bond_list; };
b.a.t.m.a.n@lists.open-mesh.org