aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Wunderlich <simon@open-mesh.com>2013-11-13 13:14:50 -0500
committerAntonio Quartulli <antonio@meshcoding.com>2014-01-12 08:41:15 -0500
commitf3b3d9018975ffb2680b7c1d37122f9d80301587 (patch)
tree7bba5d71de0bfae806d91653ef8262f396bc08b3
parentef0a937f7a1450d3a133ccd83c9c7d07587e7a00 (diff)
batman-adv: add bonding again
With the new interface alternating, the first hop may send packets in a round robin fashion to it's neighbors because it has multiple valid routes built by the multi interface optimization. This patch enables the feature if bonding is selected. Note that unlike the bonding implemented before, this version is much simpler and may even enable multi path routing to a certain degree. Signed-off-by: Simon Wunderlich <simon@open-mesh.com> Signed-off-by: Marek Lindner <mareklindner@neomailbox.ch> Signed-off-by: Antonio Quartulli <antonio@meshcoding.com>
-rw-r--r--net/batman-adv/originator.c4
-rw-r--r--net/batman-adv/routing.c117
-rw-r--r--net/batman-adv/routing.h2
-rw-r--r--net/batman-adv/types.h2
4 files changed, 121 insertions, 4 deletions
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c
index b8ef41600166..bd887809f08e 100644
--- a/net/batman-adv/originator.c
+++ b/net/batman-adv/originator.c
@@ -701,6 +701,10 @@ batadv_purge_orig_ifinfo(struct batadv_priv *bat_priv,
701 701
702 hlist_del_rcu(&orig_ifinfo->list); 702 hlist_del_rcu(&orig_ifinfo->list);
703 batadv_orig_ifinfo_free_ref(orig_ifinfo); 703 batadv_orig_ifinfo_free_ref(orig_ifinfo);
704 if (orig_node->last_bonding_candidate == orig_ifinfo) {
705 orig_node->last_bonding_candidate = NULL;
706 batadv_orig_ifinfo_free_ref(orig_ifinfo);
707 }
704 } 708 }
705 709
706 spin_unlock_bh(&orig_node->neigh_list_lock); 710 spin_unlock_bh(&orig_node->neigh_list_lock);
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c
index 55e9aebcbc80..153065a8785c 100644
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routing.c
@@ -427,16 +427,127 @@ static int batadv_check_unicast_packet(struct batadv_priv *bat_priv,
427struct batadv_neigh_node * 427struct batadv_neigh_node *
428batadv_find_router(struct batadv_priv *bat_priv, 428batadv_find_router(struct batadv_priv *bat_priv,
429 struct batadv_orig_node *orig_node, 429 struct batadv_orig_node *orig_node,
430 const struct batadv_hard_iface *recv_if) 430 struct batadv_hard_iface *recv_if)
431{ 431{
432 struct batadv_neigh_node *router; 432 struct batadv_algo_ops *bao = bat_priv->bat_algo_ops;
433 struct batadv_neigh_node *first_candidate_router = NULL;
434 struct batadv_neigh_node *next_candidate_router = NULL;
435 struct batadv_neigh_node *router, *cand_router = NULL;
436 struct batadv_neigh_node *last_cand_router = NULL;
437 struct batadv_orig_ifinfo *cand, *first_candidate = NULL;
438 struct batadv_orig_ifinfo *next_candidate = NULL;
439 struct batadv_orig_ifinfo *last_candidate;
440 bool last_candidate_found = false;
433 441
434 if (!orig_node) 442 if (!orig_node)
435 return NULL; 443 return NULL;
436 444
437 router = batadv_orig_router_get(orig_node, recv_if); 445 router = batadv_orig_router_get(orig_node, recv_if);
438 446
439 /* TODO: fill this later with new bonding mechanism */ 447 /* only consider bonding for recv_if == BATADV_IF_DEFAULT (first hop)
448 * and if activated.
449 */
450 if (recv_if == BATADV_IF_DEFAULT || !atomic_read(&bat_priv->bonding) ||
451 !router)
452 return router;
453
454 /* bonding: loop through the list of possible routers found
455 * for the various outgoing interfaces and find a candidate after
456 * the last chosen bonding candidate (next_candidate). If no such
457 * router is found, use the first candidate found (the previously
458 * chosen bonding candidate might have been the last one in the list).
459 * If this can't be found either, return the previously choosen
460 * router - obviously there are no other candidates.
461 */
462 rcu_read_lock();
463 last_candidate = orig_node->last_bonding_candidate;
464 if (last_candidate)
465 last_cand_router = rcu_dereference(last_candidate->router);
466
467 hlist_for_each_entry_rcu(cand, &orig_node->ifinfo_list, list) {
468 /* acquire some structures and references ... */
469 if (!atomic_inc_not_zero(&cand->refcount))
470 continue;
471
472 cand_router = rcu_dereference(cand->router);
473 if (!cand_router)
474 goto next;
475
476 if (!atomic_inc_not_zero(&cand_router->refcount)) {
477 cand_router = NULL;
478 goto next;
479 }
480
481 /* alternative candidate should be good enough to be
482 * considered
483 */
484 if (!bao->bat_neigh_is_equiv_or_better(cand_router,
485 cand->if_outgoing,
486 router, recv_if))
487 goto next;
488
489 /* don't use the same router twice */
490 if (last_cand_router == cand_router)
491 goto next;
492
493 /* mark the first possible candidate */
494 if (!first_candidate) {
495 atomic_inc(&cand_router->refcount);
496 atomic_inc(&cand->refcount);
497 first_candidate = cand;
498 first_candidate_router = cand_router;
499 }
500
501 /* check if the loop has already passed the previously selected
502 * candidate ... this function should select the next candidate
503 * AFTER the previously used bonding candidate.
504 */
505 if (!last_candidate || last_candidate_found) {
506 next_candidate = cand;
507 next_candidate_router = cand_router;
508 break;
509 }
510
511 if (last_candidate == cand)
512 last_candidate_found = true;
513next:
514 /* free references */
515 if (cand_router) {
516 batadv_neigh_node_free_ref(cand_router);
517 cand_router = NULL;
518 }
519 batadv_orig_ifinfo_free_ref(cand);
520 }
521 rcu_read_unlock();
522
523 /* last_bonding_candidate is reset below, remove the old reference. */
524 if (orig_node->last_bonding_candidate)
525 batadv_orig_ifinfo_free_ref(orig_node->last_bonding_candidate);
526
527 /* After finding candidates, handle the three cases:
528 * 1) there is a next candidate, use that
529 * 2) there is no next candidate, use the first of the list
530 * 3) there is no candidate at all, return the default router
531 */
532 if (next_candidate) {
533 batadv_neigh_node_free_ref(router);
534
535 /* remove references to first candidate, we don't need it. */
536 if (first_candidate) {
537 batadv_neigh_node_free_ref(first_candidate_router);
538 batadv_orig_ifinfo_free_ref(first_candidate);
539 }
540 router = next_candidate_router;
541 orig_node->last_bonding_candidate = next_candidate;
542 } else if (first_candidate) {
543 batadv_neigh_node_free_ref(router);
544
545 /* refcounting has already been done in the loop above. */
546 router = first_candidate_router;
547 orig_node->last_bonding_candidate = first_candidate;
548 } else {
549 orig_node->last_bonding_candidate = NULL;
550 }
440 551
441 return router; 552 return router;
442} 553}
diff --git a/net/batman-adv/routing.h b/net/batman-adv/routing.h
index 8920d0b1056c..8fa23fcf25f0 100644
--- a/net/batman-adv/routing.h
+++ b/net/batman-adv/routing.h
@@ -44,7 +44,7 @@ int batadv_recv_unhandled_unicast_packet(struct sk_buff *skb,
44struct batadv_neigh_node * 44struct batadv_neigh_node *
45batadv_find_router(struct batadv_priv *bat_priv, 45batadv_find_router(struct batadv_priv *bat_priv,
46 struct batadv_orig_node *orig_node, 46 struct batadv_orig_node *orig_node,
47 const struct batadv_hard_iface *recv_if); 47 struct batadv_hard_iface *recv_if);
48int batadv_window_protected(struct batadv_priv *bat_priv, int32_t seq_num_diff, 48int batadv_window_protected(struct batadv_priv *bat_priv, int32_t seq_num_diff,
49 unsigned long *last_reset); 49 unsigned long *last_reset);
50 50
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index c317dfc932bf..1409279cb5d2 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -198,6 +198,7 @@ struct batadv_orig_bat_iv {
198 * @orig: originator ethernet address 198 * @orig: originator ethernet address
199 * @primary_addr: hosts primary interface address 199 * @primary_addr: hosts primary interface address
200 * @ifinfo_list: list for routers per outgoing interface 200 * @ifinfo_list: list for routers per outgoing interface
201 * @last_bonding_candidate: pointer to last ifinfo of last used router
201 * @batadv_dat_addr_t: address of the orig node in the distributed hash 202 * @batadv_dat_addr_t: address of the orig node in the distributed hash
202 * @last_seen: time when last packet from this node was received 203 * @last_seen: time when last packet from this node was received
203 * @bcast_seqno_reset: time when the broadcast seqno window was reset 204 * @bcast_seqno_reset: time when the broadcast seqno window was reset
@@ -238,6 +239,7 @@ struct batadv_orig_node {
238 uint8_t orig[ETH_ALEN]; 239 uint8_t orig[ETH_ALEN];
239 uint8_t primary_addr[ETH_ALEN]; 240 uint8_t primary_addr[ETH_ALEN];
240 struct hlist_head ifinfo_list; 241 struct hlist_head ifinfo_list;
242 struct batadv_orig_ifinfo *last_bonding_candidate;
241#ifdef CONFIG_BATMAN_ADV_DAT 243#ifdef CONFIG_BATMAN_ADV_DAT
242 batadv_dat_addr_t dat_addr; 244 batadv_dat_addr_t dat_addr;
243#endif 245#endif