diff options
author | Simon Wunderlich <siwu@hrz.tu-chemnitz.de> | 2011-10-22 14:12:51 -0400 |
---|---|---|
committer | Antonio Quartulli <ordex@autistici.org> | 2012-04-11 08:28:59 -0400 |
commit | db08e6e557ebc8ffedf6530693937d0e51b8f6b9 (patch) | |
tree | f9f5eb55dd5258e5def03f4e39f2d10145afbaa1 /net/batman-adv | |
parent | 9bf8e4d4254397684250eae29a0dc12d54a00251 (diff) |
batman-adv: allow multiple entries in tt_global_entries
as backbone gateways will all independently announce the same clients,
also the tt global table must be able to hold multiple originators per
client entry.
Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
Signed-off-by: Antonio Quartulli <ordex@autistici.org>
Diffstat (limited to 'net/batman-adv')
-rw-r--r-- | net/batman-adv/translation-table.c | 395 | ||||
-rw-r--r-- | net/batman-adv/types.h | 9 |
2 files changed, 311 insertions, 93 deletions
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index 5f8c540b9f17..9648b0dc57ef 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c | |||
@@ -32,10 +32,8 @@ | |||
32 | 32 | ||
33 | static void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client, | 33 | static void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client, |
34 | struct orig_node *orig_node); | 34 | struct orig_node *orig_node); |
35 | static void _tt_global_del(struct bat_priv *bat_priv, | ||
36 | struct tt_global_entry *tt_global_entry, | ||
37 | const char *message); | ||
38 | static void tt_purge(struct work_struct *work); | 35 | static void tt_purge(struct work_struct *work); |
36 | static void tt_global_del_orig_list(struct tt_global_entry *tt_global_entry); | ||
39 | 37 | ||
40 | /* returns 1 if they are the same mac addr */ | 38 | /* returns 1 if they are the same mac addr */ |
41 | static int compare_tt(const struct hlist_node *node, const void *data2) | 39 | static int compare_tt(const struct hlist_node *node, const void *data2) |
@@ -125,17 +123,31 @@ static void tt_global_entry_free_rcu(struct rcu_head *rcu) | |||
125 | tt_global_entry = container_of(tt_common_entry, struct tt_global_entry, | 123 | tt_global_entry = container_of(tt_common_entry, struct tt_global_entry, |
126 | common); | 124 | common); |
127 | 125 | ||
128 | if (tt_global_entry->orig_node) | ||
129 | orig_node_free_ref(tt_global_entry->orig_node); | ||
130 | |||
131 | kfree(tt_global_entry); | 126 | kfree(tt_global_entry); |
132 | } | 127 | } |
133 | 128 | ||
134 | static void tt_global_entry_free_ref(struct tt_global_entry *tt_global_entry) | 129 | static void tt_global_entry_free_ref(struct tt_global_entry *tt_global_entry) |
135 | { | 130 | { |
136 | if (atomic_dec_and_test(&tt_global_entry->common.refcount)) | 131 | if (atomic_dec_and_test(&tt_global_entry->common.refcount)) { |
132 | tt_global_del_orig_list(tt_global_entry); | ||
137 | call_rcu(&tt_global_entry->common.rcu, | 133 | call_rcu(&tt_global_entry->common.rcu, |
138 | tt_global_entry_free_rcu); | 134 | tt_global_entry_free_rcu); |
135 | } | ||
136 | } | ||
137 | |||
138 | static void tt_orig_list_entry_free_rcu(struct rcu_head *rcu) | ||
139 | { | ||
140 | struct tt_orig_list_entry *orig_entry; | ||
141 | |||
142 | orig_entry = container_of(rcu, struct tt_orig_list_entry, rcu); | ||
143 | atomic_dec(&orig_entry->orig_node->tt_size); | ||
144 | orig_node_free_ref(orig_entry->orig_node); | ||
145 | kfree(orig_entry); | ||
146 | } | ||
147 | |||
148 | static void tt_orig_list_entry_free_ref(struct tt_orig_list_entry *orig_entry) | ||
149 | { | ||
150 | call_rcu(&orig_entry->rcu, tt_orig_list_entry_free_rcu); | ||
139 | } | 151 | } |
140 | 152 | ||
141 | static void tt_local_event(struct bat_priv *bat_priv, const uint8_t *addr, | 153 | static void tt_local_event(struct bat_priv *bat_priv, const uint8_t *addr, |
@@ -184,6 +196,9 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr, | |||
184 | struct bat_priv *bat_priv = netdev_priv(soft_iface); | 196 | struct bat_priv *bat_priv = netdev_priv(soft_iface); |
185 | struct tt_local_entry *tt_local_entry = NULL; | 197 | struct tt_local_entry *tt_local_entry = NULL; |
186 | struct tt_global_entry *tt_global_entry = NULL; | 198 | struct tt_global_entry *tt_global_entry = NULL; |
199 | struct hlist_head *head; | ||
200 | struct hlist_node *node; | ||
201 | struct tt_orig_list_entry *orig_entry; | ||
187 | int hash_added; | 202 | int hash_added; |
188 | 203 | ||
189 | tt_local_entry = tt_local_hash_find(bat_priv, addr); | 204 | tt_local_entry = tt_local_hash_find(bat_priv, addr); |
@@ -234,14 +249,21 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr, | |||
234 | 249 | ||
235 | /* Check whether it is a roaming! */ | 250 | /* Check whether it is a roaming! */ |
236 | if (tt_global_entry) { | 251 | if (tt_global_entry) { |
237 | /* This node is probably going to update its tt table */ | 252 | /* These node are probably going to update their tt table */ |
238 | tt_global_entry->orig_node->tt_poss_change = true; | 253 | head = &tt_global_entry->orig_list; |
239 | /* The global entry has to be marked as ROAMING and has to be | 254 | rcu_read_lock(); |
240 | * kept for consistency purpose */ | 255 | hlist_for_each_entry_rcu(orig_entry, node, head, list) { |
256 | orig_entry->orig_node->tt_poss_change = true; | ||
257 | |||
258 | send_roam_adv(bat_priv, tt_global_entry->common.addr, | ||
259 | orig_entry->orig_node); | ||
260 | } | ||
261 | rcu_read_unlock(); | ||
262 | /* The global entry has to be marked as ROAMING and | ||
263 | * has to be kept for consistency purpose | ||
264 | */ | ||
241 | tt_global_entry->common.flags |= TT_CLIENT_ROAM; | 265 | tt_global_entry->common.flags |= TT_CLIENT_ROAM; |
242 | tt_global_entry->roam_at = jiffies; | 266 | tt_global_entry->roam_at = jiffies; |
243 | send_roam_adv(bat_priv, tt_global_entry->common.addr, | ||
244 | tt_global_entry->orig_node); | ||
245 | } | 267 | } |
246 | out: | 268 | out: |
247 | if (tt_local_entry) | 269 | if (tt_local_entry) |
@@ -492,33 +514,76 @@ static void tt_changes_list_free(struct bat_priv *bat_priv) | |||
492 | spin_unlock_bh(&bat_priv->tt_changes_list_lock); | 514 | spin_unlock_bh(&bat_priv->tt_changes_list_lock); |
493 | } | 515 | } |
494 | 516 | ||
517 | /* find out if an orig_node is already in the list of a tt_global_entry. | ||
518 | * returns 1 if found, 0 otherwise | ||
519 | */ | ||
520 | static bool tt_global_entry_has_orig(const struct tt_global_entry *entry, | ||
521 | const struct orig_node *orig_node) | ||
522 | { | ||
523 | struct tt_orig_list_entry *tmp_orig_entry; | ||
524 | const struct hlist_head *head; | ||
525 | struct hlist_node *node; | ||
526 | bool found = false; | ||
527 | |||
528 | rcu_read_lock(); | ||
529 | head = &entry->orig_list; | ||
530 | hlist_for_each_entry_rcu(tmp_orig_entry, node, head, list) { | ||
531 | if (tmp_orig_entry->orig_node == orig_node) { | ||
532 | found = true; | ||
533 | break; | ||
534 | } | ||
535 | } | ||
536 | rcu_read_unlock(); | ||
537 | return found; | ||
538 | } | ||
539 | |||
540 | static void tt_global_add_orig_entry(struct tt_global_entry *tt_global_entry, | ||
541 | struct orig_node *orig_node, | ||
542 | int ttvn) | ||
543 | { | ||
544 | struct tt_orig_list_entry *orig_entry; | ||
545 | |||
546 | orig_entry = kzalloc(sizeof(*orig_entry), GFP_ATOMIC); | ||
547 | if (!orig_entry) | ||
548 | return; | ||
549 | |||
550 | INIT_HLIST_NODE(&orig_entry->list); | ||
551 | atomic_inc(&orig_node->refcount); | ||
552 | atomic_inc(&orig_node->tt_size); | ||
553 | orig_entry->orig_node = orig_node; | ||
554 | orig_entry->ttvn = ttvn; | ||
555 | |||
556 | spin_lock_bh(&tt_global_entry->list_lock); | ||
557 | hlist_add_head_rcu(&orig_entry->list, | ||
558 | &tt_global_entry->orig_list); | ||
559 | spin_unlock_bh(&tt_global_entry->list_lock); | ||
560 | } | ||
561 | |||
495 | /* caller must hold orig_node refcount */ | 562 | /* caller must hold orig_node refcount */ |
496 | int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node, | 563 | int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node, |
497 | const unsigned char *tt_addr, uint8_t ttvn, bool roaming, | 564 | const unsigned char *tt_addr, uint8_t ttvn, bool roaming, |
498 | bool wifi) | 565 | bool wifi) |
499 | { | 566 | { |
500 | struct tt_global_entry *tt_global_entry; | 567 | struct tt_global_entry *tt_global_entry = NULL; |
501 | struct orig_node *orig_node_tmp; | ||
502 | int ret = 0; | 568 | int ret = 0; |
503 | int hash_added; | 569 | int hash_added; |
504 | 570 | ||
505 | tt_global_entry = tt_global_hash_find(bat_priv, tt_addr); | 571 | tt_global_entry = tt_global_hash_find(bat_priv, tt_addr); |
506 | 572 | ||
507 | if (!tt_global_entry) { | 573 | if (!tt_global_entry) { |
508 | tt_global_entry = | 574 | tt_global_entry = kzalloc(sizeof(*tt_global_entry), |
509 | kmalloc(sizeof(*tt_global_entry), | 575 | GFP_ATOMIC); |
510 | GFP_ATOMIC); | ||
511 | if (!tt_global_entry) | 576 | if (!tt_global_entry) |
512 | goto out; | 577 | goto out; |
513 | 578 | ||
514 | memcpy(tt_global_entry->common.addr, tt_addr, ETH_ALEN); | 579 | memcpy(tt_global_entry->common.addr, tt_addr, ETH_ALEN); |
580 | |||
515 | tt_global_entry->common.flags = NO_FLAGS; | 581 | tt_global_entry->common.flags = NO_FLAGS; |
516 | atomic_set(&tt_global_entry->common.refcount, 2); | ||
517 | /* Assign the new orig_node */ | ||
518 | atomic_inc(&orig_node->refcount); | ||
519 | tt_global_entry->orig_node = orig_node; | ||
520 | tt_global_entry->ttvn = ttvn; | ||
521 | tt_global_entry->roam_at = 0; | 582 | tt_global_entry->roam_at = 0; |
583 | atomic_set(&tt_global_entry->common.refcount, 2); | ||
584 | |||
585 | INIT_HLIST_HEAD(&tt_global_entry->orig_list); | ||
586 | spin_lock_init(&tt_global_entry->list_lock); | ||
522 | 587 | ||
523 | hash_added = hash_add(bat_priv->tt_global_hash, compare_tt, | 588 | hash_added = hash_add(bat_priv->tt_global_hash, compare_tt, |
524 | choose_orig, &tt_global_entry->common, | 589 | choose_orig, &tt_global_entry->common, |
@@ -529,19 +594,27 @@ int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node, | |||
529 | tt_global_entry_free_ref(tt_global_entry); | 594 | tt_global_entry_free_ref(tt_global_entry); |
530 | goto out_remove; | 595 | goto out_remove; |
531 | } | 596 | } |
532 | atomic_inc(&orig_node->tt_size); | 597 | |
598 | tt_global_add_orig_entry(tt_global_entry, orig_node, ttvn); | ||
533 | } else { | 599 | } else { |
534 | if (tt_global_entry->orig_node != orig_node) { | 600 | /* there is already a global entry, use this one. */ |
535 | atomic_dec(&tt_global_entry->orig_node->tt_size); | 601 | |
536 | orig_node_tmp = tt_global_entry->orig_node; | 602 | /* If there is the TT_CLIENT_ROAM flag set, there is only one |
537 | atomic_inc(&orig_node->refcount); | 603 | * originator left in the list and we previously received a |
538 | tt_global_entry->orig_node = orig_node; | 604 | * delete + roaming change for this originator. |
539 | orig_node_free_ref(orig_node_tmp); | 605 | * |
540 | atomic_inc(&orig_node->tt_size); | 606 | * We should first delete the old originator before adding the |
607 | * new one. | ||
608 | */ | ||
609 | if (tt_global_entry->common.flags & TT_CLIENT_ROAM) { | ||
610 | tt_global_del_orig_list(tt_global_entry); | ||
611 | tt_global_entry->common.flags &= ~TT_CLIENT_ROAM; | ||
612 | tt_global_entry->roam_at = 0; | ||
541 | } | 613 | } |
542 | tt_global_entry->common.flags = NO_FLAGS; | 614 | |
543 | tt_global_entry->ttvn = ttvn; | 615 | if (!tt_global_entry_has_orig(tt_global_entry, orig_node)) |
544 | tt_global_entry->roam_at = 0; | 616 | tt_global_add_orig_entry(tt_global_entry, orig_node, |
617 | ttvn); | ||
545 | } | 618 | } |
546 | 619 | ||
547 | if (wifi) | 620 | if (wifi) |
@@ -562,6 +635,34 @@ out: | |||
562 | return ret; | 635 | return ret; |
563 | } | 636 | } |
564 | 637 | ||
638 | /* print all orig nodes who announce the address for this global entry. | ||
639 | * it is assumed that the caller holds rcu_read_lock(); | ||
640 | */ | ||
641 | static void tt_global_print_entry(struct tt_global_entry *tt_global_entry, | ||
642 | struct seq_file *seq) | ||
643 | { | ||
644 | struct hlist_head *head; | ||
645 | struct hlist_node *node; | ||
646 | struct tt_orig_list_entry *orig_entry; | ||
647 | struct tt_common_entry *tt_common_entry; | ||
648 | uint16_t flags; | ||
649 | uint8_t last_ttvn; | ||
650 | |||
651 | tt_common_entry = &tt_global_entry->common; | ||
652 | |||
653 | head = &tt_global_entry->orig_list; | ||
654 | |||
655 | hlist_for_each_entry_rcu(orig_entry, node, head, list) { | ||
656 | flags = tt_common_entry->flags; | ||
657 | last_ttvn = atomic_read(&orig_entry->orig_node->last_ttvn); | ||
658 | seq_printf(seq, " * %pM (%3u) via %pM (%3u) [%c%c]\n", | ||
659 | tt_global_entry->common.addr, orig_entry->ttvn, | ||
660 | orig_entry->orig_node->orig, last_ttvn, | ||
661 | (flags & TT_CLIENT_ROAM ? 'R' : '.'), | ||
662 | (flags & TT_CLIENT_WIFI ? 'W' : '.')); | ||
663 | } | ||
664 | } | ||
665 | |||
565 | int tt_global_seq_print_text(struct seq_file *seq, void *offset) | 666 | int tt_global_seq_print_text(struct seq_file *seq, void *offset) |
566 | { | 667 | { |
567 | struct net_device *net_dev = (struct net_device *)seq->private; | 668 | struct net_device *net_dev = (struct net_device *)seq->private; |
@@ -605,18 +706,7 @@ int tt_global_seq_print_text(struct seq_file *seq, void *offset) | |||
605 | tt_global_entry = container_of(tt_common_entry, | 706 | tt_global_entry = container_of(tt_common_entry, |
606 | struct tt_global_entry, | 707 | struct tt_global_entry, |
607 | common); | 708 | common); |
608 | seq_printf(seq, | 709 | tt_global_print_entry(tt_global_entry, seq); |
609 | " * %pM (%3u) via %pM (%3u) [%c%c]\n", | ||
610 | tt_global_entry->common.addr, | ||
611 | tt_global_entry->ttvn, | ||
612 | tt_global_entry->orig_node->orig, | ||
613 | (uint8_t) atomic_read( | ||
614 | &tt_global_entry->orig_node-> | ||
615 | last_ttvn), | ||
616 | (tt_global_entry->common.flags & | ||
617 | TT_CLIENT_ROAM ? 'R' : '.'), | ||
618 | (tt_global_entry->common.flags & | ||
619 | TT_CLIENT_WIFI ? 'W' : '.')); | ||
620 | } | 710 | } |
621 | rcu_read_unlock(); | 711 | rcu_read_unlock(); |
622 | } | 712 | } |
@@ -626,27 +716,103 @@ out: | |||
626 | return ret; | 716 | return ret; |
627 | } | 717 | } |
628 | 718 | ||
629 | static void _tt_global_del(struct bat_priv *bat_priv, | 719 | /* deletes the orig list of a tt_global_entry */ |
630 | struct tt_global_entry *tt_global_entry, | 720 | static void tt_global_del_orig_list(struct tt_global_entry *tt_global_entry) |
631 | const char *message) | ||
632 | { | 721 | { |
633 | if (!tt_global_entry) | 722 | struct hlist_head *head; |
634 | goto out; | 723 | struct hlist_node *node, *safe; |
724 | struct tt_orig_list_entry *orig_entry; | ||
635 | 725 | ||
636 | bat_dbg(DBG_TT, bat_priv, | 726 | spin_lock_bh(&tt_global_entry->list_lock); |
637 | "Deleting global tt entry %pM (via %pM): %s\n", | 727 | head = &tt_global_entry->orig_list; |
638 | tt_global_entry->common.addr, tt_global_entry->orig_node->orig, | 728 | hlist_for_each_entry_safe(orig_entry, node, safe, head, list) { |
639 | message); | 729 | hlist_del_rcu(node); |
730 | tt_orig_list_entry_free_ref(orig_entry); | ||
731 | } | ||
732 | spin_unlock_bh(&tt_global_entry->list_lock); | ||
640 | 733 | ||
641 | atomic_dec(&tt_global_entry->orig_node->tt_size); | 734 | } |
735 | |||
736 | static void tt_global_del_orig_entry(struct bat_priv *bat_priv, | ||
737 | struct tt_global_entry *tt_global_entry, | ||
738 | struct orig_node *orig_node, | ||
739 | const char *message) | ||
740 | { | ||
741 | struct hlist_head *head; | ||
742 | struct hlist_node *node, *safe; | ||
743 | struct tt_orig_list_entry *orig_entry; | ||
744 | |||
745 | spin_lock_bh(&tt_global_entry->list_lock); | ||
746 | head = &tt_global_entry->orig_list; | ||
747 | hlist_for_each_entry_safe(orig_entry, node, safe, head, list) { | ||
748 | if (orig_entry->orig_node == orig_node) { | ||
749 | bat_dbg(DBG_TT, bat_priv, | ||
750 | "Deleting %pM from global tt entry %pM: %s\n", | ||
751 | orig_node->orig, tt_global_entry->common.addr, | ||
752 | message); | ||
753 | hlist_del_rcu(node); | ||
754 | tt_orig_list_entry_free_ref(orig_entry); | ||
755 | } | ||
756 | } | ||
757 | spin_unlock_bh(&tt_global_entry->list_lock); | ||
758 | } | ||
759 | |||
760 | static void tt_global_del_struct(struct bat_priv *bat_priv, | ||
761 | struct tt_global_entry *tt_global_entry, | ||
762 | const char *message) | ||
763 | { | ||
764 | bat_dbg(DBG_TT, bat_priv, | ||
765 | "Deleting global tt entry %pM: %s\n", | ||
766 | tt_global_entry->common.addr, message); | ||
642 | 767 | ||
643 | hash_remove(bat_priv->tt_global_hash, compare_tt, choose_orig, | 768 | hash_remove(bat_priv->tt_global_hash, compare_tt, choose_orig, |
644 | tt_global_entry->common.addr); | 769 | tt_global_entry->common.addr); |
645 | out: | 770 | tt_global_entry_free_ref(tt_global_entry); |
646 | if (tt_global_entry) | 771 | |
647 | tt_global_entry_free_ref(tt_global_entry); | ||
648 | } | 772 | } |
649 | 773 | ||
774 | /* If the client is to be deleted, we check if it is the last origantor entry | ||
775 | * within tt_global entry. If yes, we set the TT_CLIENT_ROAM flag and the timer, | ||
776 | * otherwise we simply remove the originator scheduled for deletion. | ||
777 | */ | ||
778 | static void tt_global_del_roaming(struct bat_priv *bat_priv, | ||
779 | struct tt_global_entry *tt_global_entry, | ||
780 | struct orig_node *orig_node, | ||
781 | const char *message) | ||
782 | { | ||
783 | bool last_entry = true; | ||
784 | struct hlist_head *head; | ||
785 | struct hlist_node *node; | ||
786 | struct tt_orig_list_entry *orig_entry; | ||
787 | |||
788 | /* no local entry exists, case 1: | ||
789 | * Check if this is the last one or if other entries exist. | ||
790 | */ | ||
791 | |||
792 | rcu_read_lock(); | ||
793 | head = &tt_global_entry->orig_list; | ||
794 | hlist_for_each_entry_rcu(orig_entry, node, head, list) { | ||
795 | if (orig_entry->orig_node != orig_node) { | ||
796 | last_entry = false; | ||
797 | break; | ||
798 | } | ||
799 | } | ||
800 | rcu_read_unlock(); | ||
801 | |||
802 | if (last_entry) { | ||
803 | /* its the last one, mark for roaming. */ | ||
804 | tt_global_entry->common.flags |= TT_CLIENT_ROAM; | ||
805 | tt_global_entry->roam_at = jiffies; | ||
806 | } else | ||
807 | /* there is another entry, we can simply delete this | ||
808 | * one and can still use the other one. | ||
809 | */ | ||
810 | tt_global_del_orig_entry(bat_priv, tt_global_entry, | ||
811 | orig_node, message); | ||
812 | } | ||
813 | |||
814 | |||
815 | |||
650 | static void tt_global_del(struct bat_priv *bat_priv, | 816 | static void tt_global_del(struct bat_priv *bat_priv, |
651 | struct orig_node *orig_node, | 817 | struct orig_node *orig_node, |
652 | const unsigned char *addr, | 818 | const unsigned char *addr, |
@@ -656,30 +822,44 @@ static void tt_global_del(struct bat_priv *bat_priv, | |||
656 | struct tt_local_entry *tt_local_entry = NULL; | 822 | struct tt_local_entry *tt_local_entry = NULL; |
657 | 823 | ||
658 | tt_global_entry = tt_global_hash_find(bat_priv, addr); | 824 | tt_global_entry = tt_global_hash_find(bat_priv, addr); |
659 | if (!tt_global_entry || tt_global_entry->orig_node != orig_node) | 825 | if (!tt_global_entry) |
660 | goto out; | 826 | goto out; |
661 | 827 | ||
662 | if (!roaming) | 828 | if (!roaming) { |
663 | goto out_del; | 829 | tt_global_del_orig_entry(bat_priv, tt_global_entry, orig_node, |
830 | message); | ||
831 | |||
832 | if (hlist_empty(&tt_global_entry->orig_list)) | ||
833 | tt_global_del_struct(bat_priv, tt_global_entry, | ||
834 | message); | ||
835 | |||
836 | goto out; | ||
837 | } | ||
664 | 838 | ||
665 | /* if we are deleting a global entry due to a roam | 839 | /* if we are deleting a global entry due to a roam |
666 | * event, there are two possibilities: | 840 | * event, there are two possibilities: |
667 | * 1) the client roamed from node A to node B => we mark | 841 | * 1) the client roamed from node A to node B => if there |
842 | * is only one originator left for this client, we mark | ||
668 | * it with TT_CLIENT_ROAM, we start a timer and we | 843 | * it with TT_CLIENT_ROAM, we start a timer and we |
669 | * wait for node B to claim it. In case of timeout | 844 | * wait for node B to claim it. In case of timeout |
670 | * the entry is purged. | 845 | * the entry is purged. |
846 | * | ||
847 | * If there are other originators left, we directly delete | ||
848 | * the originator. | ||
671 | * 2) the client roamed to us => we can directly delete | 849 | * 2) the client roamed to us => we can directly delete |
672 | * the global entry, since it is useless now. */ | 850 | * the global entry, since it is useless now. */ |
851 | |||
673 | tt_local_entry = tt_local_hash_find(bat_priv, | 852 | tt_local_entry = tt_local_hash_find(bat_priv, |
674 | tt_global_entry->common.addr); | 853 | tt_global_entry->common.addr); |
675 | if (!tt_local_entry) { | 854 | if (tt_local_entry) { |
676 | tt_global_entry->common.flags |= TT_CLIENT_ROAM; | 855 | /* local entry exists, case 2: client roamed to us. */ |
677 | tt_global_entry->roam_at = jiffies; | 856 | tt_global_del_orig_list(tt_global_entry); |
678 | goto out; | 857 | tt_global_del_struct(bat_priv, tt_global_entry, message); |
679 | } | 858 | } else |
859 | /* no local entry exists, case 1: check for roaming */ | ||
860 | tt_global_del_roaming(bat_priv, tt_global_entry, orig_node, | ||
861 | message); | ||
680 | 862 | ||
681 | out_del: | ||
682 | _tt_global_del(bat_priv, tt_global_entry, message); | ||
683 | 863 | ||
684 | out: | 864 | out: |
685 | if (tt_global_entry) | 865 | if (tt_global_entry) |
@@ -712,11 +892,14 @@ void tt_global_del_orig(struct bat_priv *bat_priv, | |||
712 | tt_global_entry = container_of(tt_common_entry, | 892 | tt_global_entry = container_of(tt_common_entry, |
713 | struct tt_global_entry, | 893 | struct tt_global_entry, |
714 | common); | 894 | common); |
715 | if (tt_global_entry->orig_node == orig_node) { | 895 | |
896 | tt_global_del_orig_entry(bat_priv, tt_global_entry, | ||
897 | orig_node, message); | ||
898 | |||
899 | if (hlist_empty(&tt_global_entry->orig_list)) { | ||
716 | bat_dbg(DBG_TT, bat_priv, | 900 | bat_dbg(DBG_TT, bat_priv, |
717 | "Deleting global tt entry %pM (via %pM): %s\n", | 901 | "Deleting global tt entry %pM: %s\n", |
718 | tt_global_entry->common.addr, | 902 | tt_global_entry->common.addr, |
719 | tt_global_entry->orig_node->orig, | ||
720 | message); | 903 | message); |
721 | hlist_del_rcu(node); | 904 | hlist_del_rcu(node); |
722 | tt_global_entry_free_ref(tt_global_entry); | 905 | tt_global_entry_free_ref(tt_global_entry); |
@@ -757,7 +940,7 @@ static void tt_global_roam_purge(struct bat_priv *bat_priv) | |||
757 | bat_dbg(DBG_TT, bat_priv, | 940 | bat_dbg(DBG_TT, bat_priv, |
758 | "Deleting global tt entry (%pM): Roaming timeout\n", | 941 | "Deleting global tt entry (%pM): Roaming timeout\n", |
759 | tt_global_entry->common.addr); | 942 | tt_global_entry->common.addr); |
760 | atomic_dec(&tt_global_entry->orig_node->tt_size); | 943 | |
761 | hlist_del_rcu(node); | 944 | hlist_del_rcu(node); |
762 | tt_global_entry_free_ref(tt_global_entry); | 945 | tt_global_entry_free_ref(tt_global_entry); |
763 | } | 946 | } |
@@ -820,6 +1003,11 @@ struct orig_node *transtable_search(struct bat_priv *bat_priv, | |||
820 | struct tt_local_entry *tt_local_entry = NULL; | 1003 | struct tt_local_entry *tt_local_entry = NULL; |
821 | struct tt_global_entry *tt_global_entry = NULL; | 1004 | struct tt_global_entry *tt_global_entry = NULL; |
822 | struct orig_node *orig_node = NULL; | 1005 | struct orig_node *orig_node = NULL; |
1006 | struct neigh_node *router = NULL; | ||
1007 | struct hlist_head *head; | ||
1008 | struct hlist_node *node; | ||
1009 | struct tt_orig_list_entry *orig_entry; | ||
1010 | int best_tq; | ||
823 | 1011 | ||
824 | if (src && atomic_read(&bat_priv->ap_isolation)) { | 1012 | if (src && atomic_read(&bat_priv->ap_isolation)) { |
825 | tt_local_entry = tt_local_hash_find(bat_priv, src); | 1013 | tt_local_entry = tt_local_hash_find(bat_priv, src); |
@@ -836,11 +1024,25 @@ struct orig_node *transtable_search(struct bat_priv *bat_priv, | |||
836 | if (tt_local_entry && _is_ap_isolated(tt_local_entry, tt_global_entry)) | 1024 | if (tt_local_entry && _is_ap_isolated(tt_local_entry, tt_global_entry)) |
837 | goto out; | 1025 | goto out; |
838 | 1026 | ||
839 | if (!atomic_inc_not_zero(&tt_global_entry->orig_node->refcount)) | 1027 | best_tq = 0; |
840 | goto out; | ||
841 | 1028 | ||
842 | orig_node = tt_global_entry->orig_node; | 1029 | rcu_read_lock(); |
1030 | head = &tt_global_entry->orig_list; | ||
1031 | hlist_for_each_entry_rcu(orig_entry, node, head, list) { | ||
1032 | router = orig_node_get_router(orig_entry->orig_node); | ||
1033 | if (!router) | ||
1034 | continue; | ||
843 | 1035 | ||
1036 | if (router->tq_avg > best_tq) { | ||
1037 | orig_node = orig_entry->orig_node; | ||
1038 | best_tq = router->tq_avg; | ||
1039 | } | ||
1040 | neigh_node_free_ref(router); | ||
1041 | } | ||
1042 | /* found anything? */ | ||
1043 | if (orig_node && !atomic_inc_not_zero(&orig_node->refcount)) | ||
1044 | orig_node = NULL; | ||
1045 | rcu_read_unlock(); | ||
844 | out: | 1046 | out: |
845 | if (tt_global_entry) | 1047 | if (tt_global_entry) |
846 | tt_global_entry_free_ref(tt_global_entry); | 1048 | tt_global_entry_free_ref(tt_global_entry); |
@@ -872,20 +1074,26 @@ static uint16_t tt_global_crc(struct bat_priv *bat_priv, | |||
872 | tt_global_entry = container_of(tt_common_entry, | 1074 | tt_global_entry = container_of(tt_common_entry, |
873 | struct tt_global_entry, | 1075 | struct tt_global_entry, |
874 | common); | 1076 | common); |
875 | if (compare_eth(tt_global_entry->orig_node, | 1077 | /* Roaming clients are in the global table for |
876 | orig_node)) { | 1078 | * consistency only. They don't have to be |
877 | /* Roaming clients are in the global table for | 1079 | * taken into account while computing the |
878 | * consistency only. They don't have to be | 1080 | * global crc |
879 | * taken into account while computing the | 1081 | */ |
880 | * global crc */ | 1082 | if (tt_global_entry->common.flags & TT_CLIENT_ROAM) |
881 | if (tt_common_entry->flags & TT_CLIENT_ROAM) | 1083 | continue; |
882 | continue; | 1084 | |
883 | total_one = 0; | 1085 | /* find out if this global entry is announced by this |
884 | for (j = 0; j < ETH_ALEN; j++) | 1086 | * originator |
885 | total_one = crc16_byte(total_one, | 1087 | */ |
886 | tt_common_entry->addr[j]); | 1088 | if (!tt_global_entry_has_orig(tt_global_entry, |
887 | total ^= total_one; | 1089 | orig_node)) |
888 | } | 1090 | continue; |
1091 | |||
1092 | total_one = 0; | ||
1093 | for (j = 0; j < ETH_ALEN; j++) | ||
1094 | total_one = crc16_byte(total_one, | ||
1095 | tt_global_entry->common.addr[j]); | ||
1096 | total ^= total_one; | ||
889 | } | 1097 | } |
890 | rcu_read_unlock(); | 1098 | rcu_read_unlock(); |
891 | } | 1099 | } |
@@ -1026,7 +1234,7 @@ static int tt_global_valid_entry(const void *entry_ptr, const void *data_ptr) | |||
1026 | tt_global_entry = container_of(tt_common_entry, struct tt_global_entry, | 1234 | tt_global_entry = container_of(tt_common_entry, struct tt_global_entry, |
1027 | common); | 1235 | common); |
1028 | 1236 | ||
1029 | return (tt_global_entry->orig_node == orig_node); | 1237 | return tt_global_entry_has_orig(tt_global_entry, orig_node); |
1030 | } | 1238 | } |
1031 | 1239 | ||
1032 | static struct sk_buff *tt_response_fill_table(uint16_t tt_len, uint8_t ttvn, | 1240 | static struct sk_buff *tt_response_fill_table(uint16_t tt_len, uint8_t ttvn, |
@@ -1802,6 +2010,8 @@ void tt_commit_changes(struct bat_priv *bat_priv) | |||
1802 | 2010 | ||
1803 | /* Increment the TTVN only once per OGM interval */ | 2011 | /* Increment the TTVN only once per OGM interval */ |
1804 | atomic_inc(&bat_priv->ttvn); | 2012 | atomic_inc(&bat_priv->ttvn); |
2013 | bat_dbg(DBG_TT, bat_priv, "Local changes committed, updating to ttvn %u\n", | ||
2014 | (uint8_t)atomic_read(&bat_priv->ttvn)); | ||
1805 | bat_priv->tt_poss_change = false; | 2015 | bat_priv->tt_poss_change = false; |
1806 | } | 2016 | } |
1807 | 2017 | ||
@@ -1879,6 +2089,7 @@ void tt_update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node, | |||
1879 | } else { | 2089 | } else { |
1880 | /* if we missed more than one change or our tables are not | 2090 | /* if we missed more than one change or our tables are not |
1881 | * in sync anymore -> request fresh tt data */ | 2091 | * in sync anymore -> request fresh tt data */ |
2092 | |||
1882 | if (!orig_node->tt_initialised || ttvn != orig_ttvn || | 2093 | if (!orig_node->tt_initialised || ttvn != orig_ttvn || |
1883 | orig_node->tt_crc != tt_crc) { | 2094 | orig_node->tt_crc != tt_crc) { |
1884 | request_table: | 2095 | request_table: |
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 089dd44a29b1..35cd831508a9 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h | |||
@@ -241,9 +241,16 @@ struct tt_local_entry { | |||
241 | 241 | ||
242 | struct tt_global_entry { | 242 | struct tt_global_entry { |
243 | struct tt_common_entry common; | 243 | struct tt_common_entry common; |
244 | struct hlist_head orig_list; | ||
245 | spinlock_t list_lock; /* protects the list */ | ||
246 | unsigned long roam_at; /* time at which TT_GLOBAL_ROAM was set */ | ||
247 | }; | ||
248 | |||
249 | struct tt_orig_list_entry { | ||
244 | struct orig_node *orig_node; | 250 | struct orig_node *orig_node; |
245 | uint8_t ttvn; | 251 | uint8_t ttvn; |
246 | unsigned long roam_at; /* time at which TT_GLOBAL_ROAM was set */ | 252 | struct rcu_head rcu; |
253 | struct hlist_node list; | ||
247 | }; | 254 | }; |
248 | 255 | ||
249 | struct backbone_gw { | 256 | struct backbone_gw { |