diff options
author | Antonio Quartulli <a@unstable.cc> | 2016-07-03 06:46:34 -0400 |
---|---|---|
committer | Simon Wunderlich <sw@simonwunderlich.de> | 2016-08-09 01:54:30 -0400 |
commit | 50164d8f500f1cd211178f7b3d062987d68fe013 (patch) | |
tree | 68adc6e26dd6a457161bdab8d9a06a18aaf15bea | |
parent | 34d99cfefaac596adfe9b69f5e7c2cd291af2334 (diff) |
batman-adv: B.A.T.M.A.N. V - implement GW selection logic
Since the GW selection logic has been made routing protocol specific
it is now possible for B.A.T.M.A.N V to have its own mechanism by
providing the API implementation.
Implement the GW specific API in the B.A.T.M.A.N. V protocol in
order to provide a working GW selection mechanism.
Signed-off-by: Antonio Quartulli <a@unstable.cc>
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Marek Lindner <mareklindner@neomailbox.ch>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
-rw-r--r-- | net/batman-adv/bat_v.c | 223 | ||||
-rw-r--r-- | net/batman-adv/gateway_client.c | 5 | ||||
-rw-r--r-- | net/batman-adv/gateway_client.h | 2 |
3 files changed, 226 insertions, 4 deletions
diff --git a/net/batman-adv/bat_v.c b/net/batman-adv/bat_v.c index 90fd5ee877d1..1d777b171366 100644 --- a/net/batman-adv/bat_v.c +++ b/net/batman-adv/bat_v.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/init.h> | 25 | #include <linux/init.h> |
26 | #include <linux/jiffies.h> | 26 | #include <linux/jiffies.h> |
27 | #include <linux/kernel.h> | 27 | #include <linux/kernel.h> |
28 | #include <linux/kref.h> | ||
28 | #include <linux/netdevice.h> | 29 | #include <linux/netdevice.h> |
29 | #include <linux/rculist.h> | 30 | #include <linux/rculist.h> |
30 | #include <linux/rcupdate.h> | 31 | #include <linux/rcupdate.h> |
@@ -40,6 +41,7 @@ | |||
40 | #include "gateway_common.h" | 41 | #include "gateway_common.h" |
41 | #include "hard-interface.h" | 42 | #include "hard-interface.h" |
42 | #include "hash.h" | 43 | #include "hash.h" |
44 | #include "log.h" | ||
43 | #include "originator.h" | 45 | #include "originator.h" |
44 | #include "packet.h" | 46 | #include "packet.h" |
45 | 47 | ||
@@ -350,6 +352,213 @@ static ssize_t batadv_v_show_sel_class(struct batadv_priv *bat_priv, char *buff) | |||
350 | return sprintf(buff, "%u.%u MBit\n", class / 10, class % 10); | 352 | return sprintf(buff, "%u.%u MBit\n", class / 10, class % 10); |
351 | } | 353 | } |
352 | 354 | ||
355 | /** | ||
356 | * batadv_v_gw_throughput_get - retrieve the GW-bandwidth for a given GW | ||
357 | * @gw_node: the GW to retrieve the metric for | ||
358 | * @bw: the pointer where the metric will be stored. The metric is computed as | ||
359 | * the minimum between the GW advertised throughput and the path throughput to | ||
360 | * it in the mesh | ||
361 | * | ||
362 | * Return: 0 on success, -1 on failure | ||
363 | */ | ||
364 | static int batadv_v_gw_throughput_get(struct batadv_gw_node *gw_node, u32 *bw) | ||
365 | { | ||
366 | struct batadv_neigh_ifinfo *router_ifinfo = NULL; | ||
367 | struct batadv_orig_node *orig_node; | ||
368 | struct batadv_neigh_node *router; | ||
369 | int ret = -1; | ||
370 | |||
371 | orig_node = gw_node->orig_node; | ||
372 | router = batadv_orig_router_get(orig_node, BATADV_IF_DEFAULT); | ||
373 | if (!router) | ||
374 | goto out; | ||
375 | |||
376 | router_ifinfo = batadv_neigh_ifinfo_get(router, BATADV_IF_DEFAULT); | ||
377 | if (!router_ifinfo) | ||
378 | goto out; | ||
379 | |||
380 | /* the GW metric is computed as the minimum between the path throughput | ||
381 | * to reach the GW itself and the advertised bandwidth. | ||
382 | * This gives us an approximation of the effective throughput that the | ||
383 | * client can expect via this particular GW node | ||
384 | */ | ||
385 | *bw = router_ifinfo->bat_v.throughput; | ||
386 | *bw = min_t(u32, *bw, gw_node->bandwidth_down); | ||
387 | |||
388 | ret = 0; | ||
389 | out: | ||
390 | if (router) | ||
391 | batadv_neigh_node_put(router); | ||
392 | if (router_ifinfo) | ||
393 | batadv_neigh_ifinfo_put(router_ifinfo); | ||
394 | |||
395 | return ret; | ||
396 | } | ||
397 | |||
398 | /** | ||
399 | * batadv_v_gw_get_best_gw_node - retrieve the best GW node | ||
400 | * @bat_priv: the bat priv with all the soft interface information | ||
401 | * | ||
402 | * Return: the GW node having the best GW-metric, NULL if no GW is known | ||
403 | */ | ||
404 | static struct batadv_gw_node * | ||
405 | batadv_v_gw_get_best_gw_node(struct batadv_priv *bat_priv) | ||
406 | { | ||
407 | struct batadv_gw_node *gw_node, *curr_gw = NULL; | ||
408 | u32 max_bw = 0, bw; | ||
409 | |||
410 | rcu_read_lock(); | ||
411 | hlist_for_each_entry_rcu(gw_node, &bat_priv->gw.list, list) { | ||
412 | if (!kref_get_unless_zero(&gw_node->refcount)) | ||
413 | continue; | ||
414 | |||
415 | if (batadv_v_gw_throughput_get(gw_node, &bw) < 0) | ||
416 | goto next; | ||
417 | |||
418 | if (curr_gw && (bw <= max_bw)) | ||
419 | goto next; | ||
420 | |||
421 | if (curr_gw) | ||
422 | batadv_gw_node_put(curr_gw); | ||
423 | |||
424 | curr_gw = gw_node; | ||
425 | kref_get(&curr_gw->refcount); | ||
426 | max_bw = bw; | ||
427 | |||
428 | next: | ||
429 | batadv_gw_node_put(gw_node); | ||
430 | } | ||
431 | rcu_read_unlock(); | ||
432 | |||
433 | return curr_gw; | ||
434 | } | ||
435 | |||
436 | /** | ||
437 | * batadv_v_gw_is_eligible - check if a originator would be selected as GW | ||
438 | * @bat_priv: the bat priv with all the soft interface information | ||
439 | * @curr_gw_orig: originator representing the currently selected GW | ||
440 | * @orig_node: the originator representing the new candidate | ||
441 | * | ||
442 | * Return: true if orig_node can be selected as current GW, false otherwise | ||
443 | */ | ||
444 | static bool batadv_v_gw_is_eligible(struct batadv_priv *bat_priv, | ||
445 | struct batadv_orig_node *curr_gw_orig, | ||
446 | struct batadv_orig_node *orig_node) | ||
447 | { | ||
448 | struct batadv_gw_node *curr_gw = NULL, *orig_gw = NULL; | ||
449 | u32 gw_throughput, orig_throughput, threshold; | ||
450 | bool ret = false; | ||
451 | |||
452 | threshold = atomic_read(&bat_priv->gw.sel_class); | ||
453 | |||
454 | curr_gw = batadv_gw_node_get(bat_priv, curr_gw_orig); | ||
455 | if (!curr_gw) { | ||
456 | ret = true; | ||
457 | goto out; | ||
458 | } | ||
459 | |||
460 | if (batadv_v_gw_throughput_get(curr_gw, &gw_throughput) < 0) { | ||
461 | ret = true; | ||
462 | goto out; | ||
463 | } | ||
464 | |||
465 | orig_gw = batadv_gw_node_get(bat_priv, orig_node); | ||
466 | if (!orig_node) | ||
467 | goto out; | ||
468 | |||
469 | if (batadv_v_gw_throughput_get(orig_gw, &orig_throughput) < 0) | ||
470 | goto out; | ||
471 | |||
472 | if (orig_throughput < gw_throughput) | ||
473 | goto out; | ||
474 | |||
475 | if ((orig_throughput - gw_throughput) < threshold) | ||
476 | goto out; | ||
477 | |||
478 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | ||
479 | "Restarting gateway selection: better gateway found (throughput curr: %u, throughput new: %u)\n", | ||
480 | gw_throughput, orig_throughput); | ||
481 | |||
482 | ret = true; | ||
483 | out: | ||
484 | if (curr_gw) | ||
485 | batadv_gw_node_put(curr_gw); | ||
486 | if (orig_gw) | ||
487 | batadv_gw_node_put(orig_gw); | ||
488 | |||
489 | return ret; | ||
490 | } | ||
491 | |||
492 | /* fails if orig_node has no router */ | ||
493 | static int batadv_v_gw_write_buffer_text(struct batadv_priv *bat_priv, | ||
494 | struct seq_file *seq, | ||
495 | const struct batadv_gw_node *gw_node) | ||
496 | { | ||
497 | struct batadv_gw_node *curr_gw; | ||
498 | struct batadv_neigh_node *router; | ||
499 | struct batadv_neigh_ifinfo *router_ifinfo = NULL; | ||
500 | int ret = -1; | ||
501 | |||
502 | router = batadv_orig_router_get(gw_node->orig_node, BATADV_IF_DEFAULT); | ||
503 | if (!router) | ||
504 | goto out; | ||
505 | |||
506 | router_ifinfo = batadv_neigh_ifinfo_get(router, BATADV_IF_DEFAULT); | ||
507 | if (!router_ifinfo) | ||
508 | goto out; | ||
509 | |||
510 | curr_gw = batadv_gw_get_selected_gw_node(bat_priv); | ||
511 | |||
512 | seq_printf(seq, "%s %pM (%9u.%1u) %pM [%10s]: %u.%u/%u.%u MBit\n", | ||
513 | (curr_gw == gw_node ? "=>" : " "), | ||
514 | gw_node->orig_node->orig, | ||
515 | router_ifinfo->bat_v.throughput / 10, | ||
516 | router_ifinfo->bat_v.throughput % 10, router->addr, | ||
517 | router->if_incoming->net_dev->name, | ||
518 | gw_node->bandwidth_down / 10, | ||
519 | gw_node->bandwidth_down % 10, | ||
520 | gw_node->bandwidth_up / 10, | ||
521 | gw_node->bandwidth_up % 10); | ||
522 | ret = seq_has_overflowed(seq) ? -1 : 0; | ||
523 | |||
524 | if (curr_gw) | ||
525 | batadv_gw_node_put(curr_gw); | ||
526 | out: | ||
527 | if (router_ifinfo) | ||
528 | batadv_neigh_ifinfo_put(router_ifinfo); | ||
529 | if (router) | ||
530 | batadv_neigh_node_put(router); | ||
531 | return ret; | ||
532 | } | ||
533 | |||
534 | /** | ||
535 | * batadv_v_gw_print - print the gateway list | ||
536 | * @bat_priv: the bat priv with all the soft interface information | ||
537 | * @seq: gateway table seq_file struct | ||
538 | */ | ||
539 | static void batadv_v_gw_print(struct batadv_priv *bat_priv, | ||
540 | struct seq_file *seq) | ||
541 | { | ||
542 | struct batadv_gw_node *gw_node; | ||
543 | int gw_count = 0; | ||
544 | |||
545 | seq_puts(seq, | ||
546 | " Gateway ( throughput) Nexthop [outgoingIF]: advertised uplink bandwidth\n"); | ||
547 | |||
548 | rcu_read_lock(); | ||
549 | hlist_for_each_entry_rcu(gw_node, &bat_priv->gw.list, list) { | ||
550 | /* fails if orig_node has no router */ | ||
551 | if (batadv_v_gw_write_buffer_text(bat_priv, seq, gw_node) < 0) | ||
552 | continue; | ||
553 | |||
554 | gw_count++; | ||
555 | } | ||
556 | rcu_read_unlock(); | ||
557 | |||
558 | if (gw_count == 0) | ||
559 | seq_puts(seq, "No gateways in range ...\n"); | ||
560 | } | ||
561 | |||
353 | static struct batadv_algo_ops batadv_batman_v __read_mostly = { | 562 | static struct batadv_algo_ops batadv_batman_v __read_mostly = { |
354 | .name = "BATMAN_V", | 563 | .name = "BATMAN_V", |
355 | .iface = { | 564 | .iface = { |
@@ -371,6 +580,9 @@ static struct batadv_algo_ops batadv_batman_v __read_mostly = { | |||
371 | .gw = { | 580 | .gw = { |
372 | .store_sel_class = batadv_v_store_sel_class, | 581 | .store_sel_class = batadv_v_store_sel_class, |
373 | .show_sel_class = batadv_v_show_sel_class, | 582 | .show_sel_class = batadv_v_show_sel_class, |
583 | .get_best_gw_node = batadv_v_gw_get_best_gw_node, | ||
584 | .is_eligible = batadv_v_gw_is_eligible, | ||
585 | .print = batadv_v_gw_print, | ||
374 | }, | 586 | }, |
375 | }; | 587 | }; |
376 | 588 | ||
@@ -397,7 +609,16 @@ void batadv_v_hardif_init(struct batadv_hard_iface *hard_iface) | |||
397 | */ | 609 | */ |
398 | int batadv_v_mesh_init(struct batadv_priv *bat_priv) | 610 | int batadv_v_mesh_init(struct batadv_priv *bat_priv) |
399 | { | 611 | { |
400 | return batadv_v_ogm_init(bat_priv); | 612 | int ret = 0; |
613 | |||
614 | ret = batadv_v_ogm_init(bat_priv); | ||
615 | if (ret < 0) | ||
616 | return ret; | ||
617 | |||
618 | /* set default throughput difference threshold to 5Mbps */ | ||
619 | atomic_set(&bat_priv->gw.sel_class, 50); | ||
620 | |||
621 | return 0; | ||
401 | } | 622 | } |
402 | 623 | ||
403 | /** | 624 | /** |
diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index ec363f39b6a9..a77a17939f1e 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c | |||
@@ -360,9 +360,8 @@ static void batadv_gw_node_add(struct batadv_priv *bat_priv, | |||
360 | * | 360 | * |
361 | * Return: gateway node if found or NULL otherwise. | 361 | * Return: gateway node if found or NULL otherwise. |
362 | */ | 362 | */ |
363 | static struct batadv_gw_node * | 363 | struct batadv_gw_node *batadv_gw_node_get(struct batadv_priv *bat_priv, |
364 | batadv_gw_node_get(struct batadv_priv *bat_priv, | 364 | struct batadv_orig_node *orig_node) |
365 | struct batadv_orig_node *orig_node) | ||
366 | { | 365 | { |
367 | struct batadv_gw_node *gw_node_tmp, *gw_node = NULL; | 366 | struct batadv_gw_node *gw_node_tmp, *gw_node = NULL; |
368 | 367 | ||
diff --git a/net/batman-adv/gateway_client.h b/net/batman-adv/gateway_client.h index 4c9edde48914..6b40432aa1ed 100644 --- a/net/batman-adv/gateway_client.h +++ b/net/batman-adv/gateway_client.h | |||
@@ -47,5 +47,7 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, struct sk_buff *skb); | |||
47 | enum batadv_dhcp_recipient | 47 | enum batadv_dhcp_recipient |
48 | batadv_gw_dhcp_recipient_get(struct sk_buff *skb, unsigned int *header_len, | 48 | batadv_gw_dhcp_recipient_get(struct sk_buff *skb, unsigned int *header_len, |
49 | u8 *chaddr); | 49 | u8 *chaddr); |
50 | struct batadv_gw_node *batadv_gw_node_get(struct batadv_priv *bat_priv, | ||
51 | struct batadv_orig_node *orig_node); | ||
50 | 52 | ||
51 | #endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */ | 53 | #endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */ |