aboutsummaryrefslogtreecommitdiffstats
path: root/net/batman-adv/routing.c
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 /net/batman-adv/routing.c
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>
Diffstat (limited to 'net/batman-adv/routing.c')
-rw-r--r--net/batman-adv/routing.c117
1 files changed, 114 insertions, 3 deletions
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}