Changeset 1551

Show
Ignore:
Timestamp:
01/17/10 21:33:37 (8 months ago)
Author:
simon
Message:

batman-adv: Add bonding functionality

This patch introduces bonding functionality to batman-advanced, targeted
for the 0.3 release. As we are able to route the payload traffic as we
want, we may use multiple interfaces on multihomed hosts to transfer data
to achieve higher bandwidth. This can be considered as "light Multi Path
Routing" for single hop connections.

To detect which interfaces of a peer node belong to the same host, a
new flag PRIMARIES_FIRST_HOP is introduced. This flag is set on the first hop
of OGMs of the primary (first) interface, which is broadcasted on all
interfaces. When receiving such an OGM, we can learn which interfaces
belong to the same host (by assigning them to the primary originator).

Bonding works by sending packets in a round-robin fashion to the available
interfaces of a neighbor host, if multiple interfaces are available. The
neighbor interfaces should be almost equally good to reach.

To avoid interferences (i.e. sending on the same channel), only neighbor
interfaces with different mac addresses and different outgoing interfaces
are considered as candidates.

Bonding is deactivated by default, and can be activated by

echo 1 > /proc/net/batman-adv/bonding

for each individual node.

Signed-off-by: Simon Wunderlich <siwu@…>

Location:
trunk/batman-adv-kernelland
Files:
12 modified

Legend:

Unmodified
Added
Removed
  • trunk/batman-adv-kernelland/hard-interface.c

    r1529 r1551  
    313313        batman_packet->packet_type = BAT_PACKET; 
    314314        batman_packet->version = COMPAT_VERSION; 
    315         batman_packet->flags = 0x00; 
    316         batman_packet->ttl = (batman_if->if_num > 0 ? 2 : TTL); 
    317         batman_packet->flags = 0; 
     315        batman_packet->flags = batman_if->if_num > 0 ? 
     316                        0x00 : PRIMARIES_FIRST_HOP; 
     317        batman_packet->ttl = batman_if->if_num > 0 ? 2 : TTL; 
    318318        batman_packet->tq = TQ_MAX_VALUE; 
    319319        batman_packet->num_hna = 0; 
  • trunk/batman-adv-kernelland/main.c

    r1540 r1551  
    4848atomic_t vis_interval; 
    4949atomic_t aggregation_enabled; 
     50atomic_t bonding_enabled; 
    5051int16_t num_hna; 
    5152int16_t num_ifs; 
     
    8889                                         * for debugging now. */ 
    8990        atomic_set(&aggregation_enabled, 1); 
     91        atomic_set(&bonding_enabled, 0); 
    9092        atomic_set(&gw_mode, GW_MODE_OFF); 
    9193        atomic_set(&gw_srv_class, 0); 
  • trunk/batman-adv-kernelland/main.h

    r1516 r1551  
    5858#define LOG_BUF_LEN 8192          /* has to be a power of 2 */ 
    5959#define ETH_STR_LEN 20 
     60 
     61/* how much worse secondary interfaces may be to 
     62 * to be considered as bonding candidates */ 
     63 
     64#define BONDING_TQ_THRESHOLD    50 
    6065 
    6166#define MAX_AGGREGATION_BYTES 512 /* should not be bigger than 512 bytes or 
     
    132137extern atomic_t vis_interval; 
    133138extern atomic_t aggregation_enabled; 
     139extern atomic_t bonding_enabled; 
    134140extern int16_t num_hna; 
    135141extern int16_t num_ifs; 
  • trunk/batman-adv-kernelland/originator.c

    r1540 r1551  
    222222                return true; 
    223223        } else { 
    224                 if (purge_orig_neighbors(orig_node, &best_neigh_node)) 
     224                if (purge_orig_neighbors(orig_node, &best_neigh_node)) { 
    225225                        update_routes(orig_node, best_neigh_node, 
    226226                                      orig_node->hna_buff, 
    227227                                      orig_node->hna_buff_len); 
     228                        /* update bonding candidates, we could have lost 
     229                         * some candidates. */ 
     230                        update_bonding_candidates(orig_node); 
     231                } 
    228232        } 
    229233        return false; 
  • trunk/batman-adv-kernelland/packet.h

    r1540 r1551  
    3232#define DIRECTLINK 0x40 
    3333#define VIS_SERVER 0x20 
     34#define PRIMARIES_FIRST_HOP 0x10 
    3435 
    3536/* ICMP message types */ 
  • trunk/batman-adv-kernelland/proc.c

    r1540 r1551  
    3737static struct proc_dir_entry *proc_transt_global_file; 
    3838static struct proc_dir_entry *proc_vis_srv_file, *proc_vis_data_file; 
    39 static struct proc_dir_entry *proc_aggr_file; 
     39static struct proc_dir_entry *proc_aggr_file, *proc_bond_file; 
    4040static struct proc_dir_entry *proc_gw_mode_file, *proc_gw_srv_list_file; 
    4141 
     
    559559 
    560560 
     561static int proc_bond_read(struct seq_file *seq, void *offset) 
     562{ 
     563        seq_printf(seq, "%i\n", atomic_read(&bonding_enabled)); 
     564 
     565        return 0; 
     566} 
     567 
     568static ssize_t proc_bond_write(struct file *file, const char __user *buffer, 
     569                               size_t count, loff_t *ppos) 
     570{ 
     571        char *bond_string; 
     572        int not_copied = 0; 
     573        unsigned long bonding_enabled_tmp; 
     574        int retval; 
     575 
     576        bond_string = kmalloc(count, GFP_KERNEL); 
     577 
     578        if (!bond_string) 
     579                return -ENOMEM; 
     580 
     581        not_copied = copy_from_user(bond_string, buffer, count); 
     582        bond_string[count - not_copied - 1] = 0; 
     583 
     584        retval = strict_strtoul(bond_string, 10, &bonding_enabled_tmp); 
     585 
     586        if (retval || bonding_enabled_tmp > 1) { 
     587                printk(KERN_ERR "batman-adv: Bonding can only be enabled (1) or disabled (0), given value: %li\n", bonding_enabled_tmp); 
     588        } else { 
     589                printk(KERN_INFO "batman-adv:Changing bonding from: %s (%i) to: %s (%li)\n", 
     590                       (atomic_read(&bonding_enabled) == 1 ? 
     591                        "enabled" : "disabled"), 
     592                       atomic_read(&bonding_enabled), 
     593                       (bonding_enabled_tmp == 1 ? "enabled" : "disabled"), 
     594                       bonding_enabled_tmp); 
     595                atomic_set(&bonding_enabled, 
     596                                                (unsigned)bonding_enabled_tmp); 
     597        } 
     598 
     599        kfree(bond_string); 
     600        return count; 
     601} 
     602 
     603static int proc_bond_open(struct inode *inode, struct file *file) 
     604{ 
     605        return single_open(file, proc_bond_read, NULL); 
     606} 
     607 
    561608/* satisfying different prototypes ... */ 
    562609static ssize_t proc_dummy_write(struct file *file, const char __user *buffer, 
     
    593640}; 
    594641 
     642static const struct file_operations proc_bond_fops = { 
     643        .owner          = THIS_MODULE, 
     644        .open           = proc_bond_open, 
     645        .read           = seq_read, 
     646        .write          = proc_bond_write, 
     647        .llseek         = seq_lseek, 
     648        .release        = single_release, 
     649}; 
     650 
    595651static const struct file_operations proc_vis_srv_fops = { 
    596652        .owner          = THIS_MODULE, 
     
    687743        if (proc_gw_srv_list_file) 
    688744                remove_proc_entry(PROC_FILE_GW_SRV_LIST, proc_batman_dir); 
     745 
     746        if (proc_bond_file) 
     747                remove_proc_entry(PROC_FILE_BOND, proc_batman_dir); 
     748 
    689749 
    690750        if (proc_batman_dir) 
     
    816876        } 
    817877 
    818         return 0; 
    819 } 
     878        proc_bond_file = create_proc_entry(PROC_FILE_BOND, S_IWUSR | S_IRUGO, 
     879                                           proc_batman_dir); 
     880        if (proc_bond_file) { 
     881                proc_bond_file->proc_fops = &proc_bond_fops; 
     882        } else { 
     883                printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_BOND); 
     884                cleanup_procfs(); 
     885                return -EFAULT; 
     886        } 
     887 
     888        return 0; 
     889} 
  • trunk/batman-adv-kernelland/proc.h

    r1540 r1551  
    3535#define PROC_FILE_VIS_DATA "vis_data" 
    3636#define PROC_FILE_AGGR "aggregate_ogm" 
     37#define PROC_FILE_BOND "bonding" 
    3738#define PROC_FILE_GW_MODE "gateway_mode" 
    3839#define PROC_FILE_GW_SRV_LIST "gateway_srv_list" 
  • trunk/batman-adv-kernelland/routing.c

    r1550 r1551  
    364364} 
    365365 
     366/* copy primary address for bonding */ 
     367static void mark_bonding_address(struct orig_node *orig_node, 
     368                                struct orig_node *orig_neigh_node, 
     369                                struct batman_packet *batman_packet) 
     370 
     371{ 
     372        /* don't care if bonding is not enabled */ 
     373        if (!atomic_read(&bonding_enabled)) { 
     374                orig_node->bond.candidates = 0; 
     375                return; 
     376        } 
     377 
     378        if (batman_packet->flags & PRIMARIES_FIRST_HOP) 
     379                memcpy(orig_neigh_node->primary_addr, 
     380                                                orig_node->orig, ETH_ALEN); 
     381         else 
     382                return; 
     383} 
     384 
     385/* mark possible bonding candidates in the neighbor list */ 
     386void update_bonding_candidates(struct orig_node *orig_node) 
     387{ 
     388        int candidates; 
     389        int interference_candidate; 
     390        int best_tq; 
     391        struct neigh_node *tmp_neigh_node, *tmp_neigh_node2; 
     392    struct neigh_node *first_candidate, *last_candidate; 
     393 
     394        /* don't care if bonding is not enabled */ 
     395        if (!atomic_read(&bonding_enabled)) { 
     396                orig_node->bond.candidates = 0; 
     397                return; 
     398        } 
     399 
     400        /* update the candidates for this originator */ 
     401        if (!orig_node->router) { 
     402                orig_node->bond.candidates = 0; 
     403                return; 
     404        } 
     405 
     406        best_tq = orig_node->router->tq_avg; 
     407 
     408        /* update bonding candidates */ 
     409 
     410        candidates = 0; 
     411 
     412        /* mark other nodes which also received "PRIMARIES FIRST HOP" packets 
     413         * as "bonding partner" */ 
     414 
     415        /* first, zero the list */ 
     416        list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) { 
     417                tmp_neigh_node->next_bond_candidate = NULL; 
     418        } 
     419 
     420        first_candidate = NULL; 
     421        last_candidate = NULL; 
     422        list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) { 
     423 
     424                /* only consider if it has the same primary address ...  */ 
     425                if (memcmp(orig_node->orig, 
     426                                tmp_neigh_node->orig_node->primary_addr, 
     427                                ETH_ALEN) != 0) 
     428                        continue; 
     429 
     430                /* ... and is good enough to be considered */ 
     431                if (tmp_neigh_node->tq_avg < best_tq - BONDING_TQ_THRESHOLD) 
     432                        continue; 
     433 
     434                /* check if we have another candidate with the same 
     435                 * mac address or interface. If we do, we won't 
     436                 * select this candidate because of possible interference. */ 
     437 
     438                interference_candidate = 0; 
     439                list_for_each_entry(tmp_neigh_node2, 
     440                                &orig_node->neigh_list, list) { 
     441 
     442                        if (tmp_neigh_node2 == tmp_neigh_node) 
     443                                continue; 
     444 
     445                        if ((tmp_neigh_node->if_incoming == 
     446                                tmp_neigh_node2->if_incoming) 
     447                                || (memcmp(tmp_neigh_node->addr, 
     448                                tmp_neigh_node2->addr, ETH_ALEN) == 0)) { 
     449 
     450                                interference_candidate = 1; 
     451                                break; 
     452                        } 
     453                } 
     454                /* don't care further if it is an interference candidate */ 
     455                if (interference_candidate) 
     456                        continue; 
     457 
     458                if (first_candidate == NULL) { 
     459                        first_candidate = tmp_neigh_node; 
     460                        tmp_neigh_node->next_bond_candidate = first_candidate; 
     461                } else 
     462                        tmp_neigh_node->next_bond_candidate = last_candidate; 
     463 
     464                last_candidate = tmp_neigh_node; 
     465 
     466                candidates++; 
     467        } 
     468 
     469        if (candidates > 0) { 
     470                first_candidate->next_bond_candidate = last_candidate; 
     471                orig_node->bond.selected = first_candidate; 
     472        } 
     473 
     474        orig_node->bond.candidates = candidates; 
     475} 
     476 
    366477void receive_bat_packet(struct ethhdr *ethhdr, 
    367478                                struct batman_packet *batman_packet, 
     
    530641                            if_incoming, hna_buff, hna_buff_len, is_duplicate); 
    531642 
     643        mark_bonding_address(orig_node, orig_neigh_node, batman_packet); 
     644        update_bonding_candidates(orig_node); 
     645 
    532646        /* is single hop (direct) neighbor */ 
    533647        if (is_single_hop_neigh) { 
     
    799913} 
    800914 
     915/* find a suitable router for this originator, and use 
     916 * bonding if possible. */ 
     917struct neigh_node *find_router(struct orig_node *orig_node) 
     918{ 
     919        struct orig_node *primary_orig_node; 
     920        struct orig_node *router_orig; 
     921        struct neigh_node *router; 
     922        static uint8_t zero_mac[ETH_ALEN] = {0, 0, 0, 0, 0, 0}; 
     923 
     924        if (!orig_node) 
     925                return NULL; 
     926 
     927        if (!orig_node->router) 
     928                return NULL; 
     929 
     930        /* don't care if bonding is not enabled */ 
     931        if (!atomic_read(&bonding_enabled)) 
     932                return orig_node->router; 
     933 
     934        router_orig = orig_node->router->orig_node; 
     935 
     936        /* if we have something in the primary_addr, we can search 
     937         * for a potential bonding candidate. */ 
     938        if (memcmp(router_orig->primary_addr, zero_mac, ETH_ALEN) == 0) 
     939                return orig_node->router; 
     940 
     941        /* find the orig_node which has the primary interface. might 
     942         * even be the same as our orig_node in many cases */ 
     943 
     944        primary_orig_node = hash_find(orig_hash, router_orig->primary_addr); 
     945        if (!primary_orig_node) 
     946                return orig_node->router; 
     947 
     948        /* with less than 2 candidates, we can't do any 
     949         * bonding and prefer the original router. */ 
     950 
     951        if (primary_orig_node->bond.candidates < 2) 
     952                return orig_node->router; 
     953 
     954        router = primary_orig_node->bond.selected; 
     955 
     956        /* sanity check - this should never happen. */ 
     957        if (!router) 
     958                return orig_node->router; 
     959 
     960        /* select the next bonding partner ... */ 
     961        primary_orig_node->bond.selected = router->next_bond_candidate; 
     962 
     963        return router; 
     964} 
     965 
    801966int recv_unicast_packet(struct sk_buff *skb) 
    802967{ 
    803968        struct unicast_packet *unicast_packet; 
    804969        struct orig_node *orig_node; 
     970        struct neigh_node *router; 
    805971        struct ethhdr *ethhdr; 
    806972        struct batman_if *batman_if; 
     
    808974        uint8_t dstaddr[ETH_ALEN]; 
    809975        int hdr_size = sizeof(struct unicast_packet); 
    810         int ret; 
    811976        unsigned long flags; 
    812977 
     
    8431008        } 
    8441009 
    845         ret = NET_RX_DROP; 
    8461010        /* get routing information */ 
    8471011        spin_lock_irqsave(&orig_hash_lock, flags); 
     
    8491013                     hash_find(orig_hash, unicast_packet->dest)); 
    8501014 
    851         if ((orig_node != NULL) && 
    852             (orig_node->batman_if != NULL) && 
    853             (orig_node->router != NULL)) { 
    854  
    855                 /* don't lock while sending the packets ... we therefore 
    856                  * copy the required data before sending */ 
    857                 batman_if = orig_node->batman_if; 
    858                 memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); 
    859                 spin_unlock_irqrestore(&orig_hash_lock, flags); 
    860  
    861                 /* create a copy of the skb, if needed, to modify it. */ 
    862                 if (!skb_clone_writable(skb, sizeof(struct unicast_packet))) { 
    863                         skb_old = skb; 
    864                         skb = skb_copy(skb, GFP_ATOMIC); 
    865                         if (!skb) 
    866                                 return NET_RX_DROP; 
    867                         unicast_packet = (struct unicast_packet *) skb->data; 
    868                         kfree_skb(skb_old); 
    869                 } 
    870                 /* decrement ttl */ 
    871                 unicast_packet->ttl--; 
    872  
    873                 /* route it */ 
    874                 send_skb_packet(skb, batman_if, dstaddr); 
    875                 ret = NET_RX_SUCCESS; 
    876  
    877         } else 
    878                 spin_unlock_irqrestore(&orig_hash_lock, flags); 
    879  
    880         return ret; 
     1015        router = find_router(orig_node); 
     1016 
     1017        if (!router) { 
     1018                spin_lock_irqsave(&orig_hash_lock, flags); 
     1019                return NET_RX_DROP; 
     1020        } 
     1021 
     1022        /* don't lock while sending the packets ... we therefore 
     1023         * copy the required data before sending */ 
     1024 
     1025        batman_if = router->if_incoming; 
     1026        memcpy(dstaddr, router->addr, ETH_ALEN); 
     1027 
     1028        spin_unlock_irqrestore(&orig_hash_lock, flags); 
     1029 
     1030        /* create a copy of the skb, if needed, to modify it. */ 
     1031        if (!skb_clone_writable(skb, sizeof(struct unicast_packet))) { 
     1032                skb_old = skb; 
     1033                skb = skb_copy(skb, GFP_ATOMIC); 
     1034                if (!skb) 
     1035                        return NET_RX_DROP; 
     1036                unicast_packet = (struct unicast_packet *) skb->data; 
     1037                kfree_skb(skb_old); 
     1038        } 
     1039 
     1040        /* decrement ttl */ 
     1041        unicast_packet->ttl--; 
     1042 
     1043        /* route it */ 
     1044        send_skb_packet(skb, batman_if, dstaddr); 
     1045 
     1046        return NET_RX_SUCCESS; 
    8811047} 
    8821048 
  • trunk/batman-adv-kernelland/routing.h

    r1517 r1551  
    3939int recv_bat_packet(struct sk_buff *skb, 
    4040                                struct batman_if *batman_if); 
     41struct neigh_node *find_router(struct orig_node *orig_node); 
     42void update_bonding_candidates(struct orig_node *orig_node); 
  • trunk/batman-adv-kernelland/send.c

    r1540 r1551  
    277277 
    278278        if (is_vis_server()) 
    279                 batman_packet->flags = VIS_SERVER; 
     279                batman_packet->flags |= VIS_SERVER; 
    280280        else 
    281                 batman_packet->flags = 0; 
     281                batman_packet->flags &= ~VIS_SERVER; 
    282282 
    283283        batman_packet->gw_flags = (uint8_t)atomic_read(&gw_srv_class); 
     
    336336        batman_packet->seqno = htons(batman_packet->seqno); 
    337337 
     338        /* switch of primaries first hop flag when forwarding */ 
     339        batman_packet->flags &= ~PRIMARIES_FIRST_HOP; 
    338340        if (directlink) 
    339341                batman_packet->flags |= DIRECTLINK; 
  • trunk/batman-adv-kernelland/soft-interface.c

    r1542 r1551  
    2323#include "soft-interface.h" 
    2424#include "hard-interface.h" 
     25#include "routing.h" 
    2526#include "send.h" 
    2627#include "translation-table.h" 
     
    172173} 
    173174 
     175 
     176 
    174177int interface_tx(struct sk_buff *skb, struct net_device *dev) 
    175178{ 
     
    177180        struct bcast_packet *bcast_packet; 
    178181        struct orig_node *orig_node; 
     182        struct neigh_node *router; 
    179183        struct ethhdr *ethhdr = (struct ethhdr *)skb->data; 
    180184        struct bat_priv *priv = netdev_priv(dev); 
     
    239243                        orig_node = transtable_search(ethhdr->h_dest); 
    240244 
    241                 if ((orig_node) && 
    242                     (orig_node->batman_if) && 
    243                     (orig_node->router)) { 
    244                         if (my_skb_push(skb, sizeof(struct unicast_packet)) < 0) 
    245                                 goto unlock; 
    246  
    247                         unicast_packet = (struct unicast_packet *)skb->data; 
    248  
    249                         unicast_packet->version = COMPAT_VERSION; 
    250                         /* batman packet type: unicast */ 
    251                         unicast_packet->packet_type = BAT_UNICAST; 
    252                         /* set unicast ttl */ 
    253                         unicast_packet->ttl = TTL; 
    254                         /* copy the destination for faster routing */ 
    255                         memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN); 
    256  
    257                         /* net_dev won't be available when not active */ 
    258                         if (orig_node->batman_if->if_active != IF_ACTIVE) 
    259                                 goto unlock; 
    260  
    261                         /* don't lock while sending the packets ... we therefore 
    262                          * copy the required data before sending */ 
    263  
    264                         batman_if = orig_node->batman_if; 
    265                         memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); 
    266                         spin_unlock_irqrestore(&orig_hash_lock, flags); 
    267  
    268                         send_skb_packet(skb, batman_if, dstaddr); 
    269                 } else { 
     245                router = find_router(orig_node); 
     246 
     247                if (!router) 
    270248                        goto unlock; 
    271                 } 
     249 
     250                /* don't lock while sending the packets ... we therefore 
     251                 * copy the required data before sending */ 
     252 
     253                batman_if = router->if_incoming; 
     254                memcpy(dstaddr, router->addr, ETH_ALEN); 
     255 
     256                spin_unlock_irqrestore(&orig_hash_lock, flags); 
     257 
     258                if (batman_if->if_active != IF_ACTIVE) 
     259                        goto dropped; 
     260 
     261                if (my_skb_push(skb, sizeof(struct unicast_packet)) < 0) 
     262                        goto dropped; 
     263 
     264                unicast_packet = (struct unicast_packet *)skb->data; 
     265 
     266                unicast_packet->version = COMPAT_VERSION; 
     267                /* batman packet type: unicast */ 
     268                unicast_packet->packet_type = BAT_UNICAST; 
     269                /* set unicast ttl */ 
     270                unicast_packet->ttl = TTL; 
     271                /* copy the destination for faster routing */ 
     272                memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN); 
     273 
     274                send_skb_packet(skb, batman_if, dstaddr); 
    272275        } 
    273276 
  • trunk/batman-adv-kernelland/types.h

    r1540 r1551  
    4848struct orig_node {               /* structure for orig_list maintaining nodes of mesh */ 
    4949        uint8_t orig[ETH_ALEN]; 
     50        uint8_t primary_addr[ETH_ALEN]; /* hosts primary interface address */ 
    5051        struct neigh_node *router; 
    5152        struct batman_if *batman_if; 
     
    6465        uint16_t last_bcast_seqno;  /* last broadcast sequence number received by this host */ 
    6566        struct list_head neigh_list; 
     67        struct { 
     68                uint8_t candidates;     /* how many candidates are available */ 
     69                struct neigh_node *selected;    /* next bonding candidate */ 
     70        } bond; 
    6671}; 
    6772 
     
    8186        uint8_t tq_avg; 
    8287        uint8_t last_ttl; 
     88        struct neigh_node *next_bond_candidate; 
    8389        unsigned long last_valid;            /* when last packet via this neighbor was received */ 
    8490        TYPE_OF_WORD real_bits[NUM_WORDS];