Hi everyone,
Here are some smaller modifications of the redundancy bonding mode patches. I haven't modified the batman_header yet, as there seem to be some other opinions about this, too and might be easier to discuss at the WBMv4.
As always, everything is available here as well: http://git.open-mesh.org/?p=t_x/batman-adv.git;a=shortlog;h=refs/heads/rbond...
Cheers, Linus
rbonding changelog v2: * Fix (interim) refcounting bug / memory leak in unicast_send_skb() [5/12] * change recv_icmp_ttl_exceeded() to change_icmp_ttl_exceeded(), as it is in the sending code path now (thanks Andrew!) [3/12] * Add missing ttl modification in aggregation.c [3/12] * rebased to f39fe6f230e4cbf2b04e659b056ea62a652578a0
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/routing.c b/routing.c index 42cb6e2..c172f5d 100644 --- a/routing.c +++ b/routing.c @@ -1263,8 +1263,7 @@ static int check_unicast_packet(struct sk_buff *skb, int hdr_size) return 0; }
-int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if, - int hdr_size) +int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if) { struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface); struct orig_node *orig_node = NULL; @@ -1365,7 +1364,7 @@ int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *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 hard_iface *recv_if) @@ -1398,7 +1397,7 @@ int recv_ucast_frag_packet(struct sk_buff *skb, struct hard_iface *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/routing.h b/routing.h index 5efceaf..b5a064c 100644 --- a/routing.h +++ b/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 hard_iface *recv_if, - int hdr_size); +int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if); int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if); int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if); int recv_ucast_frag_packet(struct sk_buff *skb, struct hard_iface *recv_if); diff --git a/soft-interface.c b/soft-interface.c index 95d1c3f..6b514ec 100644 --- a/soft-interface.c +++ b/soft-interface.c @@ -462,7 +462,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;
On Wednesday 02 March 2011 18:18:30 Linus Lüssing wrote:
@@ -1263,8 +1263,7 @@ static int check_unicast_packet(struct sk_buff *skb, int hdr_size) return 0; }
-int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if,
int hdr_size)
+int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if) { struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface); struct orig_node *orig_node = NULL;
Applied in revision 1953.
Thanks, Marek
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 | 50 +++++++++++++++++++++----------------------------- routing.c | 34 +++++++++++++++++----------------- send.c | 20 ++++++++++---------- soft-interface.c | 14 +++++++------- unicast.c | 16 ++++++++-------- vis.c | 14 +++++++------- 9 files changed, 84 insertions(+), 92 deletions(-)
diff --git a/aggregation.c b/aggregation.c index af45d6b..5bd74e1 100644 --- a/aggregation.c +++ b/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/hard-interface.c b/hard-interface.c index 95a35b6..3637602 100644 --- a/hard-interface.c +++ b/hard-interface.c @@ -146,8 +146,8 @@ static void set_primary_if(struct bat_priv *bat_priv, return;
batman_packet = (struct batman_packet *)(hard_iface->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 hard_iface *hard_iface, char *iface_name) }
batman_packet = (struct batman_packet *)(hard_iface->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;
@@ -559,7 +559,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 hard_iface *hard_iface; int ret;
@@ -591,19 +591,19 @@ static int batman_skb_recv(struct sk_buff *skb, struct net_device *dev, if (hard_iface->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, hard_iface); diff --git a/icmp_socket.c b/icmp_socket.c index 34ce56c..2b9ea74 100644 --- a/icmp_socket.c +++ b/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/packet.h b/packet.h index e757187..ae7a0ce 100644 --- a/packet.h +++ b/packet.h @@ -52,31 +52,33 @@ #define UNI_FRAG_HEAD 0x01 #define UNI_FRAG_LARGETAIL 0x02
-struct batman_packet { +struct batman_header { uint8_t packet_type; uint8_t version; /* batman version field */ + uint8_t ttl; + uint8_t align; +} __packed; + +struct batman_packet { + 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 flags; uint8_t orig[6]; + uint8_t flags; 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/routing.c b/routing.c index c172f5d..115a8de 100644 --- a/routing.c +++ b/routing.c @@ -430,8 +430,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); @@ -621,7 +621,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() */ @@ -639,8 +639,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(hard_iface, &hardif_list, list) { @@ -667,10 +667,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; }
@@ -787,7 +787,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);
@@ -914,7 +914,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; @@ -980,7 +980,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; @@ -1046,7 +1046,7 @@ int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *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 */ @@ -1075,7 +1075,7 @@ int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *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); @@ -1276,7 +1276,7 @@ int route_unicast_packet(struct sk_buff *skb, struct hard_iface *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); @@ -1304,7 +1304,7 @@ int route_unicast_packet(struct sk_buff *skb, struct hard_iface *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, @@ -1312,7 +1312,7 @@ int route_unicast_packet(struct sk_buff *skb, struct hard_iface *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); @@ -1331,7 +1331,7 @@ int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if) }
/* decrement ttl */ - unicast_packet->ttl--; + unicast_packet->header.ttl--;
/* route it */ send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); @@ -1435,7 +1435,7 @@ int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *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/send.c b/send.c index d49e54d..93e4f8f 100644 --- a/send.c +++ b/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"), hard_iface->net_dev->name, @@ -182,7 +182,7 @@ static void send_packet(struct forw_packet *forw_packet)
/* multihomed peer assumed */ /* non-primary OGMs are only broadcasted on their interface */ - if ((directlink && (batman_packet->ttl == 1)) || + if ((directlink && (batman_packet->header.ttl == 1)) || (forw_packet->own && (forw_packet->if_incoming->if_num > 0))) {
/* FIXME: what about aggregated packets ? */ @@ -191,7 +191,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);
@@ -311,15 +311,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 @@ -331,8 +331,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; @@ -345,7 +345,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);
@@ -421,7 +421,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/soft-interface.c b/soft-interface.c index 6b514ec..b0c023d 100644 --- a/soft-interface.c +++ b/soft-interface.c @@ -206,10 +206,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)) @@ -373,11 +373,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 */ @@ -454,8 +454,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/unicast.c b/unicast.c index 19f84bd..a57033a 100644 --- a/unicast.c +++ b/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;
@@ -250,9 +250,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)); @@ -316,11 +316,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);
@@ -328,7 +328,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/vis.c b/vis.c index f90212f..491430c 100644 --- a/vis.c +++ b/vis.c @@ -616,7 +616,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)); @@ -819,20 +819,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. */ @@ -913,9 +913,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;
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 | 4 +- hard-interface.c | 2 +- routing.c | 90 --------------------------------------- send.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++------- unicast.c | 3 - vis.c | 6 --- 6 files changed, 110 insertions(+), 118 deletions(-)
diff --git a/aggregation.c b/aggregation.c index 5bd74e1..d9ca9ae 100644 --- a/aggregation.c +++ b/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 */ @@ -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->header.ttl == 1) && + (new_batman_packet->header.ttl == 2) && (forw_packet->if_incoming == if_incoming) &&
/* packets from direct neighbors or diff --git a/hard-interface.c b/hard-interface.c index 3637602..b0105e9 100644 --- a/hard-interface.c +++ b/hard-interface.c @@ -314,7 +314,7 @@ int hardif_enable_interface(struct hard_iface *hard_iface, char *iface_name) batman_packet = (struct batman_packet *)(hard_iface->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/routing.c b/routing.c index 115a8de..c60296c 100644 --- a/routing.c +++ b/routing.c @@ -930,73 +930,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 = orig_hash_find(bat_priv, icmp_packet->orig); - - if (!orig_node) - goto unlock; - - 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) - orig_node_free_ref(orig_node); - return ret; -} - - int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if) { struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface); @@ -1045,10 +978,6 @@ int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *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 = orig_hash_find(bat_priv, icmp_packet->dst); @@ -1074,9 +1003,6 @@ int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *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; @@ -1269,20 +1195,11 @@ int route_unicast_packet(struct sk_buff *skb, struct hard_iface *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 = orig_hash_find(bat_priv, unicast_packet->dest); @@ -1327,12 +1244,8 @@ int route_unicast_packet(struct sk_buff *skb, struct hard_iface *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; @@ -1435,9 +1348,6 @@ int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if) if (is_my_mac(bcast_packet->orig)) goto out;
- if (bcast_packet->header.ttl < 2) - goto out; - rcu_read_lock(); orig_node = orig_hash_find(bat_priv, bcast_packet->orig);
diff --git a/send.c b/send.c index 93e4f8f..1f1afce 100644 --- a/send.c +++ b/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,105 @@ static unsigned long forward_send_time(void) return jiffies + msecs_to_jiffies(random32() % (JITTER/2)); }
+static int send_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 = orig_hash_find(bat_priv, icmp_packet->orig); + + if (!orig_node) + goto unlock; + + 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) + orig_node_free_ref(orig_node); + 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: + send_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 hard_iface *hard_iface, uint8_t *dst_addr) { struct ethhdr *ethhdr; + struct batman_header *batman_header; + struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
if (hard_iface->if_status != IF_ACTIVE) goto send_skb_err; @@ -73,6 +166,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; @@ -182,7 +284,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 ? */ @@ -311,15 +413,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 @@ -332,7 +428,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; @@ -344,8 +440,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);
@@ -400,7 +496,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"); @@ -419,10 +514,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/unicast.c b/unicast.c index a57033a..2677c06 100644 --- a/unicast.c +++ b/unicast.c @@ -250,7 +250,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;
@@ -327,8 +326,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/vis.c b/vis.c index 491430c..cde91f4 100644 --- a/vis.c +++ b/vis.c @@ -819,20 +819,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. */
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/routing.c b/routing.c index c60296c..118b841 100644 --- a/routing.c +++ b/routing.c @@ -1189,20 +1189,18 @@ static int check_unicast_packet(struct sk_buff *skb, int hdr_size) return 0; }
-int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if) +int route_unicast_packet(struct sk_buff *skb, struct hard_iface *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 = orig_hash_find(bat_priv, unicast_packet->dest); + orig_node = orig_hash_find(bat_priv, dest);
if (!orig_node) goto unlock; @@ -1219,9 +1217,7 @@ int route_unicast_packet(struct sk_buff *skb, struct hard_iface *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, @@ -1229,7 +1225,7 @@ int route_unicast_packet(struct sk_buff *skb, struct hard_iface *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); @@ -1277,7 +1273,8 @@ int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *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 hard_iface *recv_if) @@ -1310,7 +1307,8 @@ int recv_ucast_frag_packet(struct sk_buff *skb, struct hard_iface *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/routing.h b/routing.h index b5a064c..88e8ef5 100644 --- a/routing.h +++ b/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 hard_iface *recv_if); +int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if, + uint8_t *dest, uint8_t packet_type); int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if); int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if); int recv_ucast_frag_packet(struct sk_buff *skb, struct hard_iface *recv_if); diff --git a/soft-interface.c b/soft-interface.c index b0c023d..fdb3586 100644 --- a/soft-interface.c +++ b/soft-interface.c @@ -462,7 +462,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 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 | 39 +++++++-------------------------------- 4 files changed, 20 insertions(+), 42 deletions(-)
diff --git a/routing.c b/routing.c index 118b841..97e99ce 100644 --- a/routing.c +++ b/routing.c @@ -1189,10 +1189,10 @@ static int check_unicast_packet(struct sk_buff *skb, int hdr_size) return 0; }
-int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if, - uint8_t *dest, uint8_t packet_type) +int route_unicast_packet(struct bat_priv *bat_priv, struct sk_buff *skb, + struct hard_iface *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; @@ -1259,6 +1259,7 @@ out:
int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *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);
@@ -1273,8 +1274,8 @@ int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *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 hard_iface *recv_if) @@ -1307,8 +1308,8 @@ int recv_ucast_frag_packet(struct sk_buff *skb, struct hard_iface *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/routing.h b/routing.h index 88e8ef5..5972bf3 100644 --- a/routing.h +++ b/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 hard_iface *recv_if, - uint8_t *dest, uint8_t packet_type); +int route_unicast_packet(struct bat_priv *bat_priv, struct sk_buff *skb, + struct hard_iface *recv_if, uint8_t *dest, + uint8_t packet_type); int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if); int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if); int recv_ucast_frag_packet(struct sk_buff *skb, struct hard_iface *recv_if); diff --git a/soft-interface.c b/soft-interface.c index fdb3586..bd460b3 100644 --- a/soft-interface.c +++ b/soft-interface.c @@ -462,7 +462,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/unicast.c b/unicast.c index 2677c06..c6c465c 100644 --- a/unicast.c +++ b/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,14 @@ 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) orig_node_free_ref(orig_node); - 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 | 43 ++++++++++++++++++------------------------- routing.h | 8 +++----- soft-interface.c | 7 +++++-- unicast.c | 6 ++---- 4 files changed, 28 insertions(+), 36 deletions(-)
diff --git a/routing.c b/routing.c index 97e99ce..60579fc 100644 --- a/routing.c +++ b/routing.c @@ -1021,10 +1021,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 hard_iface *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; @@ -1037,6 +1037,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); @@ -1189,26 +1191,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 hard_iface *recv_if, uint8_t *dest, - uint8_t packet_type) +int route_unicast_packet(struct sk_buff *skb, struct hard_iface *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 */ - rcu_read_lock(); - orig_node = orig_hash_find(bat_priv, dest); - - if (!orig_node) - goto unlock; - - rcu_read_unlock(); - /* 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; @@ -1218,9 +1209,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; } @@ -1228,7 +1219,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; @@ -1247,8 +1238,6 @@ int route_unicast_packet(struct bat_priv *bat_priv, struct sk_buff *skb, ret = NET_RX_SUCCESS; goto out;
-unlock: - rcu_read_unlock(); out: if (neigh_node) neigh_node_free_ref(neigh_node); @@ -1261,6 +1250,7 @@ int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *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) @@ -1274,14 +1264,16 @@ int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *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 = orig_hash_find(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 hard_iface *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; @@ -1308,8 +1300,9 @@ int recv_ucast_frag_packet(struct sk_buff *skb, struct hard_iface *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 = orig_hash_find(bat_priv, unicast_packet->dest); + return route_unicast_packet(skb, recv_if, orig_node, + unicast_packet->header.packet_type); }
diff --git a/routing.h b/routing.h index 5972bf3..d97f720 100644 --- a/routing.h +++ b/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 hard_iface *recv_if, uint8_t *dest, - uint8_t packet_type); +int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if, + struct orig_node *orig_node, uint8_t packet_type); int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if); int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if); int recv_ucast_frag_packet(struct sk_buff *skb, struct hard_iface *recv_if); int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if); int recv_vis_packet(struct sk_buff *skb, struct hard_iface *recv_if); int recv_bat_packet(struct sk_buff *skb, struct hard_iface *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 hard_iface *recv_if); void bonding_candidate_del(struct orig_node *orig_node, struct neigh_node *neigh_node); diff --git a/soft-interface.c b/soft-interface.c index bd460b3..07fe7c8 100644 --- a/soft-interface.c +++ b/soft-interface.c @@ -20,6 +20,7 @@ */
#include "main.h" +#include "originator.h" #include "soft-interface.h" #include "hard-interface.h" #include "routing.h" @@ -419,6 +420,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; @@ -462,8 +464,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 = orig_hash_find(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/unicast.c b/unicast.c index c6c465c..54e956b 100644 --- a/unicast.c +++ b/unicast.c @@ -308,12 +308,10 @@ 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 (orig_node) - orig_node_free_ref(orig_node); if (ret == NET_RX_DROP) kfree_skb(skb);
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/routing.c b/routing.c index 60579fc..ba4756c 100644 --- a/routing.c +++ b/routing.c @@ -1021,21 +1021,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 hard_iface *recv_if) +static void find_router(struct orig_node *orig_node, + struct hard_iface *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;
@@ -1049,7 +1052,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)) @@ -1111,7 +1114,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 @@ -1163,7 +1166,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) @@ -1192,55 +1204,29 @@ static int check_unicast_packet(struct sk_buff *skb, int hdr_size) }
int route_unicast_packet(struct sk_buff *skb, struct hard_iface *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; - } - - if (packet_type == BAT_UNICAST_FRAG && - frag_can_reassemble(skb, neigh_node->if_incoming->net_dev->mtu)) { - - 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; - } + /* creates the (initial) packet list */ + find_router(orig_node, recv_if, skb, &packet_list);
- skb = new_skb; - } + /* split packets that won't fit or maybe buffer fragments */ + frag_packet_list(orig_node->bat_priv, &packet_list);
- /* 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) orig_node_free_ref(orig_node); return ret; @@ -1265,8 +1251,7 @@ int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if) }
orig_node = orig_hash_find(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 hard_iface *recv_if) @@ -1301,8 +1286,7 @@ int recv_ucast_frag_packet(struct sk_buff *skb, struct hard_iface *recv_if) }
orig_node = orig_hash_find(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/routing.h b/routing.h index d97f720..681512b 100644 --- a/routing.h +++ b/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 hard_iface *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 hard_iface *recv_if); int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if); int recv_ucast_frag_packet(struct sk_buff *skb, struct hard_iface *recv_if); int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if); int recv_vis_packet(struct sk_buff *skb, struct hard_iface *recv_if); int recv_bat_packet(struct sk_buff *skb, struct hard_iface *recv_if); -struct neigh_node *find_router(struct orig_node *orig_node, - struct hard_iface *recv_if); void bonding_candidate_del(struct orig_node *orig_node, struct neigh_node *neigh_node);
diff --git a/send.c b/send.c index 1f1afce..862ce79 100644 --- a/send.c +++ b/send.c @@ -202,6 +202,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 hard_iface *hard_iface) diff --git a/send.h b/send.h index 7b2ff19..290195e 100644 --- a/send.h +++ b/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 hard_iface *hard_iface, uint8_t *dst_addr); +void send_packet_list(struct hlist_head *packet_list); void schedule_own_packet(struct hard_iface *hard_iface); void schedule_forward_packet(struct orig_node *orig_node, struct ethhdr *ethhdr, diff --git a/soft-interface.c b/soft-interface.c index 07fe7c8..8224fdc 100644 --- a/soft-interface.c +++ b/soft-interface.c @@ -466,8 +466,7 @@ void interface_rx(struct net_device *soft_iface, bat_priv->softif_neigh->addr, ETH_ALEN);
orig_node = orig_hash_find(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/unicast.c b/unicast.c index 54e956b..07ef785 100644 --- a/unicast.c +++ b/unicast.c @@ -217,17 +217,43 @@ out: return ret; }
-int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv, - struct hard_iface *hard_iface, 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 hard_iface *hard_iface = 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, hard_iface, dstaddr); - send_skb_packet(frag_skb, hard_iface, 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/unicast.h b/unicast.h index 16ad7a9..1b4dbb0 100644 --- a/unicast.h +++ b/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 hard_iface *hard_iface, 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_ */
On Wednesday 02 March 2011 18:18:36 Linus Lüssing wrote:
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);
In the past weeks we worked very hard to reduce the batman-adv overhead to a bare minimum (see the hash restructuring patches and the orig_hash spinlock removal) and now you want to add a malloc() for each forwarded packet ?? Can't we find a less bloated way to achieve the same thing ?
Regards, Marek
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/bat_sysfs.c b/bat_sysfs.c index e449bf6..3b8cf26 100644 --- a/bat_sysfs.c +++ b/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/soft-interface.c b/soft-interface.c index 8224fdc..7f0e768 100644 --- a/soft-interface.c +++ b/soft-interface.c @@ -571,6 +571,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/types.h b/types.h index 83445cf..0ce4b99 100644 --- a/types.h +++ b/types.h @@ -133,6 +133,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_* */
On Wednesday 02 March 2011 18:18:37 Linus Lüssing wrote:
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).
Why not making redundant bonding a sysfs variant of bonding ? You wrote yourself: "Also make sure to activate general bonding for redundant bonding to take effect". Having an extra option does not seem to make much sense ?!
Cheers, Marek
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/main.h b/main.h index a0059dd..c6d4848 100644 --- a/main.h +++ b/main.h @@ -97,6 +97,11 @@ * Vis */
+/* Bonding modes */ +#define THROUGHPUT_BONDING 1 +#define REDUNDANT_BONDING 2 + + /* * Kernel headers */ diff --git a/packet.h b/packet.h index ae7a0ce..e5a897c 100644 --- a/packet.h +++ b/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/routing.c b/routing.c index ba4756c..f17834a 100644 --- a/routing.c +++ b/routing.c @@ -1018,10 +1018,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 hard_iface *recv_if, struct sk_buff *skb, struct hlist_head *packet_list) @@ -1032,7 +1099,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; @@ -1044,7 +1110,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 */ @@ -1055,7 +1120,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 @@ -1091,7 +1156,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. */
@@ -1127,6 +1192,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 @@ -1203,12 +1273,16 @@ static int check_unicast_packet(struct sk_buff *skb, int hdr_size) return 0; }
-int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if, +int route_unicast_packet(int bonding_mode, struct sk_buff *skb, + struct hard_iface *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. */ @@ -1216,10 +1290,10 @@ int route_unicast_packet(struct sk_buff *skb, struct hard_iface *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); @@ -1238,6 +1312,7 @@ int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *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; @@ -1250,8 +1325,10 @@ int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if) return NET_RX_SUCCESS; }
+ bonding_mode = atomic_read(&bat_priv->bonding) << + atomic_read(&bat_priv->red_bonding); orig_node = orig_hash_find(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 hard_iface *recv_if) @@ -1261,7 +1338,7 @@ int recv_ucast_frag_packet(struct sk_buff *skb, struct hard_iface *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; @@ -1285,8 +1362,26 @@ int recv_ucast_frag_packet(struct sk_buff *skb, struct hard_iface *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 = orig_hash_find(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/routing.h b/routing.h index 681512b..1530c6d 100644 --- a/routing.h +++ b/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 hard_iface *recv_if, +int route_unicast_packet(int bonding_mode, struct sk_buff *skb, + struct hard_iface *recv_if, struct orig_node *orig_node); int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if); int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if); diff --git a/soft-interface.c b/soft-interface.c index 7f0e768..15e08cf 100644 --- a/soft-interface.c +++ b/soft-interface.c @@ -424,7 +424,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)) @@ -465,8 +465,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 = orig_hash_find(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;
@@ -585,6 +588,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/types.h b/types.h index 0ce4b99..3f625aa 100644 --- a/types.h +++ b/types.h @@ -143,6 +143,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/unicast.c b/unicast.c index 07ef785..9261607 100644 --- a/unicast.c +++ b/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/unicast.h b/unicast.h index 1b4dbb0..e87597b 100644 --- a/unicast.h +++ b/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);
On Wednesday 02 March 2011 18:18:38 Linus Lüssing wrote:
diff --git a/main.h b/main.h index a0059dd..c6d4848 100644 --- a/main.h +++ b/main.h @@ -97,6 +97,11 @@
- Vis
*/
+/* Bonding modes */ +#define THROUGHPUT_BONDING 1 +#define REDUNDANT_BONDING 2
Here you go into the right direction but ...
@@ -347,6 +346,7 @@ void frag_packet_list(struct bat_priv *bat_priv,
bonding_mode = atomic_read(&bat_priv->bonding) <<
atomic_read(&bat_priv->red_bonding);
here you resort to some magic. I believe that can be simplified (see my sysfs reply).
+static int unicast_to_unicast_safe(struct sk_buff *skb,
struct bat_priv *bat_priv)
[..]
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;
I don't think "unicast_packet_safe->header = unicast_packet.header;" does what you want it to do.
+static void red_bonding_copy(struct sk_buff *skb, struct list_head [..]
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;
}
}
Yet another malloc() followed by an skb_copy() ? Seems to be unnecessary ballast.
Cheers, Marek
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/hard-interface.c b/hard-interface.c index b0105e9..7164b1f 100644 --- a/hard-interface.c +++ b/hard-interface.c @@ -624,6 +624,11 @@ static int batman_skb_recv(struct sk_buff *skb, struct net_device *dev, ret = recv_ucast_frag_packet(skb, hard_iface); break;
+ /* fragmented unicast packet */ + case BAT_UNICAST_SAFE: + ret = recv_ucast_safe_packet(skb, hard_iface); + break; + /* broadcast packet */ case BAT_BCAST: ret = recv_bcast_packet(skb, hard_iface); diff --git a/routing.c b/routing.c index f17834a..d31a7ad 100644 --- a/routing.c +++ b/routing.c @@ -1018,6 +1018,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) { @@ -1033,10 +1056,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; } @@ -1384,6 +1404,38 @@ int recv_ucast_frag_packet(struct sk_buff *skb, struct hard_iface *recv_if) return route_unicast_packet(bonding_mode, skb, recv_if, orig_node); }
+int recv_ucast_safe_packet(struct sk_buff *skb, struct hard_iface *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 hard_iface *recv_if) { diff --git a/routing.h b/routing.h index 1530c6d..8608ac3 100644 --- a/routing.h +++ b/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 hard_iface *recv_if); int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if); int recv_ucast_frag_packet(struct sk_buff *skb, struct hard_iface *recv_if); +int recv_ucast_safe_packet(struct sk_buff *skb, struct hard_iface *recv_if); int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if); int recv_vis_packet(struct sk_buff *skb, struct hard_iface *recv_if); int recv_bat_packet(struct sk_buff *skb, struct hard_iface *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 | 63 ++++++++++++++++++++++++++++++++++----------------------- types.h | 10 ++++++-- 3 files changed, 45 insertions(+), 30 deletions(-)
diff --git a/originator.c b/originator.c index 53753d3..57cb5c9 100644 --- a/originator.c +++ b/originator.c @@ -207,7 +207,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/routing.c b/routing.c index d31a7ad..a2c55fd 100644 --- a/routing.c +++ b/routing.c @@ -1293,6 +1293,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 hard_iface *recv_if, struct orig_node *orig_node) @@ -1433,7 +1463,7 @@ int recv_ucast_safe_packet(struct sk_buff *skb, struct hard_iface *recv_if) else set_unicast_safe_options(bat_priv, unicast_packet);
- orig_node = hash_find_orig(bat_priv, unicast_packet->dest); + orig_node = orig_hash_find(bat_priv, unicast_packet->dest); return route_unicast_packet(bonding_mode, skb, recv_if, orig_node); }
@@ -1445,7 +1475,6 @@ int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *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))) @@ -1479,26 +1508,13 @@ int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
rcu_read_unlock();
- spin_lock_bh(&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; + ret = check_duplicate(bat_priv, ntohl(bcast_packet->seqno), + &orig_node->bcast_seqno_state, + &orig_node->bcast_seqno_lock);
- /* 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); + orig_node_free_ref(orig_node); + if (ret == NET_RX_DROP) + goto out;
/* rebroadcast packet */ add_bcast_packet_to_list(bat_priv, skb); @@ -1510,12 +1526,7 @@ int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
rcu_unlock: rcu_read_unlock(); - goto out; -spin_unlock: - spin_unlock_bh(&orig_node->bcast_seqno_lock); out: - if (orig_node) - orig_node_free_ref(orig_node); return ret; }
diff --git a/types.h b/types.h index 3f625aa..cceff07 100644 --- a/types.h +++ b/types.h @@ -49,6 +49,12 @@ struct hard_iface { 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,8 +84,6 @@ 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 */ @@ -89,6 +92,7 @@ struct orig_node { struct hlist_node hash_entry; 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/originator.c b/originator.c index 57cb5c9..3be8460 100644 --- a/originator.c +++ b/originator.c @@ -198,6 +198,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);
/* extra reference for return */ @@ -209,6 +210,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/routing.c b/routing.c index a2c55fd..d19eb77 100644 --- a/routing.c +++ b/routing.c @@ -1440,13 +1440,25 @@ int recv_ucast_safe_packet(struct sk_buff *skb, struct hard_iface *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 = orig_hash_find(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); + + orig_node_free_ref(orig_node); + 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/types.h b/types.h index cceff07..bfab0c7 100644 --- a/types.h +++ b/types.h @@ -93,11 +93,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