diff options
author | Antonio Quartulli <ordex@autistici.org> | 2012-09-23 16:38:37 -0400 |
---|---|---|
committer | Antonio Quartulli <ordex@autistici.org> | 2012-11-14 15:00:37 -0500 |
commit | 068ee6e204e1f48ba24ec91ce40f5ca833a57a81 (patch) | |
tree | 0aa52811822469811fe5f887c9b2ec7823e9359b /net/batman-adv/translation-table.c | |
parent | be73b488d1e2993fe92b5ec02347c3f7c08307b8 (diff) |
batman-adv: roaming handling mechanism redesign
This patch allows clients to roam multiple times within the same
originator-interval.
To enable this new feature two key aspects that have been introduced:
1) packets are always directed to the node that was originally
serving the roamed client which will then re-route the data
to the correct destination at any point in time;
2) the client flags handling mechanism has been properly modified
in order to allow multiple roamings withinin the same orig-int.
Therefore flags are now set properly even in this scenario.
Signed-off-by: Antonio Quartulli <ordex@autistici.org>
Diffstat (limited to 'net/batman-adv/translation-table.c')
-rw-r--r-- | net/batman-adv/translation-table.c | 157 |
1 files changed, 118 insertions, 39 deletions
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index cb8433aceed8..dd2c2545cfef 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c | |||
@@ -238,6 +238,20 @@ static int batadv_tt_local_init(struct batadv_priv *bat_priv) | |||
238 | return 0; | 238 | return 0; |
239 | } | 239 | } |
240 | 240 | ||
241 | static void batadv_tt_global_free(struct batadv_priv *bat_priv, | ||
242 | struct batadv_tt_global_entry *tt_global, | ||
243 | const char *message) | ||
244 | { | ||
245 | batadv_dbg(BATADV_DBG_TT, bat_priv, | ||
246 | "Deleting global tt entry %pM: %s\n", | ||
247 | tt_global->common.addr, message); | ||
248 | |||
249 | batadv_hash_remove(bat_priv->tt.global_hash, batadv_compare_tt, | ||
250 | batadv_choose_orig, tt_global->common.addr); | ||
251 | batadv_tt_global_entry_free_ref(tt_global); | ||
252 | |||
253 | } | ||
254 | |||
241 | void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, | 255 | void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, |
242 | int ifindex) | 256 | int ifindex) |
243 | { | 257 | { |
@@ -248,14 +262,38 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, | |||
248 | struct hlist_node *node; | 262 | struct hlist_node *node; |
249 | struct batadv_tt_orig_list_entry *orig_entry; | 263 | struct batadv_tt_orig_list_entry *orig_entry; |
250 | int hash_added; | 264 | int hash_added; |
265 | bool roamed_back = false; | ||
251 | 266 | ||
252 | tt_local = batadv_tt_local_hash_find(bat_priv, addr); | 267 | tt_local = batadv_tt_local_hash_find(bat_priv, addr); |
268 | tt_global = batadv_tt_global_hash_find(bat_priv, addr); | ||
253 | 269 | ||
254 | if (tt_local) { | 270 | if (tt_local) { |
255 | tt_local->last_seen = jiffies; | 271 | tt_local->last_seen = jiffies; |
256 | /* possibly unset the BATADV_TT_CLIENT_PENDING flag */ | 272 | if (tt_local->common.flags & BATADV_TT_CLIENT_PENDING) { |
257 | tt_local->common.flags &= ~BATADV_TT_CLIENT_PENDING; | 273 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
258 | goto out; | 274 | "Re-adding pending client %pM\n", addr); |
275 | /* whatever the reason why the PENDING flag was set, | ||
276 | * this is a client which was enqueued to be removed in | ||
277 | * this orig_interval. Since it popped up again, the | ||
278 | * flag can be reset like it was never enqueued | ||
279 | */ | ||
280 | tt_local->common.flags &= ~BATADV_TT_CLIENT_PENDING; | ||
281 | goto add_event; | ||
282 | } | ||
283 | |||
284 | if (tt_local->common.flags & BATADV_TT_CLIENT_ROAM) { | ||
285 | batadv_dbg(BATADV_DBG_TT, bat_priv, | ||
286 | "Roaming client %pM came back to its original location\n", | ||
287 | addr); | ||
288 | /* the ROAM flag is set because this client roamed away | ||
289 | * and the node got a roaming_advertisement message. Now | ||
290 | * that the client popped up again at its original | ||
291 | * location such flag can be unset | ||
292 | */ | ||
293 | tt_local->common.flags &= ~BATADV_TT_CLIENT_ROAM; | ||
294 | roamed_back = true; | ||
295 | } | ||
296 | goto check_roaming; | ||
259 | } | 297 | } |
260 | 298 | ||
261 | tt_local = kmalloc(sizeof(*tt_local), GFP_ATOMIC); | 299 | tt_local = kmalloc(sizeof(*tt_local), GFP_ATOMIC); |
@@ -294,13 +332,14 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, | |||
294 | goto out; | 332 | goto out; |
295 | } | 333 | } |
296 | 334 | ||
335 | add_event: | ||
297 | batadv_tt_local_event(bat_priv, addr, tt_local->common.flags); | 336 | batadv_tt_local_event(bat_priv, addr, tt_local->common.flags); |
298 | 337 | ||
299 | /* remove address from global hash if present */ | 338 | check_roaming: |
300 | tt_global = batadv_tt_global_hash_find(bat_priv, addr); | 339 | /* Check whether it is a roaming, but don't do anything if the roaming |
301 | 340 | * process has already been handled | |
302 | /* Check whether it is a roaming! */ | 341 | */ |
303 | if (tt_global) { | 342 | if (tt_global && !(tt_global->common.flags & BATADV_TT_CLIENT_ROAM)) { |
304 | /* These node are probably going to update their tt table */ | 343 | /* These node are probably going to update their tt table */ |
305 | head = &tt_global->orig_list; | 344 | head = &tt_global->orig_list; |
306 | rcu_read_lock(); | 345 | rcu_read_lock(); |
@@ -309,12 +348,19 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, | |||
309 | orig_entry->orig_node); | 348 | orig_entry->orig_node); |
310 | } | 349 | } |
311 | rcu_read_unlock(); | 350 | rcu_read_unlock(); |
312 | /* The global entry has to be marked as ROAMING and | 351 | if (roamed_back) { |
313 | * has to be kept for consistency purpose | 352 | batadv_tt_global_free(bat_priv, tt_global, |
314 | */ | 353 | "Roaming canceled"); |
315 | tt_global->common.flags |= BATADV_TT_CLIENT_ROAM; | 354 | tt_global = NULL; |
316 | tt_global->roam_at = jiffies; | 355 | } else { |
356 | /* The global entry has to be marked as ROAMING and | ||
357 | * has to be kept for consistency purpose | ||
358 | */ | ||
359 | tt_global->common.flags |= BATADV_TT_CLIENT_ROAM; | ||
360 | tt_global->roam_at = jiffies; | ||
361 | } | ||
317 | } | 362 | } |
363 | |||
318 | out: | 364 | out: |
319 | if (tt_local) | 365 | if (tt_local) |
320 | batadv_tt_local_entry_free_ref(tt_local); | 366 | batadv_tt_local_entry_free_ref(tt_local); |
@@ -508,13 +554,28 @@ uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv, | |||
508 | curr_flags = tt_local_entry->common.flags; | 554 | curr_flags = tt_local_entry->common.flags; |
509 | 555 | ||
510 | flags = BATADV_TT_CLIENT_DEL; | 556 | flags = BATADV_TT_CLIENT_DEL; |
557 | /* if this global entry addition is due to a roaming, the node has to | ||
558 | * mark the local entry as "roamed" in order to correctly reroute | ||
559 | * packets later | ||
560 | */ | ||
511 | if (roaming) { | 561 | if (roaming) { |
512 | flags |= BATADV_TT_CLIENT_ROAM; | 562 | flags |= BATADV_TT_CLIENT_ROAM; |
513 | /* mark the local client as ROAMed */ | 563 | /* mark the local client as ROAMed */ |
514 | tt_local_entry->common.flags |= BATADV_TT_CLIENT_ROAM; | 564 | tt_local_entry->common.flags |= BATADV_TT_CLIENT_ROAM; |
515 | } | 565 | } |
516 | 566 | ||
517 | batadv_tt_local_set_pending(bat_priv, tt_local_entry, flags, message); | 567 | if (!(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW)) { |
568 | batadv_tt_local_set_pending(bat_priv, tt_local_entry, flags, | ||
569 | message); | ||
570 | goto out; | ||
571 | } | ||
572 | /* if this client has been added right now, it is possible to | ||
573 | * immediately purge it | ||
574 | */ | ||
575 | batadv_tt_local_event(bat_priv, tt_local_entry->common.addr, | ||
576 | curr_flags | BATADV_TT_CLIENT_DEL); | ||
577 | hlist_del_rcu(&tt_local_entry->common.hash_entry); | ||
578 | batadv_tt_local_entry_free_ref(tt_local_entry); | ||
518 | 579 | ||
519 | out: | 580 | out: |
520 | if (tt_local_entry) | 581 | if (tt_local_entry) |
@@ -724,12 +785,22 @@ int batadv_tt_global_add(struct batadv_priv *bat_priv, | |||
724 | uint8_t ttvn) | 785 | uint8_t ttvn) |
725 | { | 786 | { |
726 | struct batadv_tt_global_entry *tt_global_entry = NULL; | 787 | struct batadv_tt_global_entry *tt_global_entry = NULL; |
788 | struct batadv_tt_local_entry *tt_local_entry = NULL; | ||
727 | int ret = 0; | 789 | int ret = 0; |
728 | int hash_added; | 790 | int hash_added; |
729 | struct batadv_tt_common_entry *common; | 791 | struct batadv_tt_common_entry *common; |
730 | uint16_t local_flags; | 792 | uint16_t local_flags; |
731 | 793 | ||
732 | tt_global_entry = batadv_tt_global_hash_find(bat_priv, tt_addr); | 794 | tt_global_entry = batadv_tt_global_hash_find(bat_priv, tt_addr); |
795 | tt_local_entry = batadv_tt_local_hash_find(bat_priv, tt_addr); | ||
796 | |||
797 | /* if the node already has a local client for this entry, it has to wait | ||
798 | * for a roaming advertisement instead of manually messing up the global | ||
799 | * table | ||
800 | */ | ||
801 | if ((flags & BATADV_TT_CLIENT_TEMP) && tt_local_entry && | ||
802 | !(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW)) | ||
803 | goto out; | ||
733 | 804 | ||
734 | if (!tt_global_entry) { | 805 | if (!tt_global_entry) { |
735 | tt_global_entry = kzalloc(sizeof(*tt_global_entry), GFP_ATOMIC); | 806 | tt_global_entry = kzalloc(sizeof(*tt_global_entry), GFP_ATOMIC); |
@@ -764,19 +835,31 @@ int batadv_tt_global_add(struct batadv_priv *bat_priv, | |||
764 | goto out_remove; | 835 | goto out_remove; |
765 | } | 836 | } |
766 | } else { | 837 | } else { |
838 | common = &tt_global_entry->common; | ||
767 | /* If there is already a global entry, we can use this one for | 839 | /* If there is already a global entry, we can use this one for |
768 | * our processing. | 840 | * our processing. |
769 | * But if we are trying to add a temporary client we can exit | 841 | * But if we are trying to add a temporary client then here are |
770 | * directly because the temporary information should never | 842 | * two options at this point: |
771 | * override any already known client state (whatever it is) | 843 | * 1) the global client is not a temporary client: the global |
844 | * client has to be left as it is, temporary information | ||
845 | * should never override any already known client state | ||
846 | * 2) the global client is a temporary client: purge the | ||
847 | * originator list and add the new one orig_entry | ||
772 | */ | 848 | */ |
773 | if (flags & BATADV_TT_CLIENT_TEMP) | 849 | if (flags & BATADV_TT_CLIENT_TEMP) { |
774 | goto out; | 850 | if (!(common->flags & BATADV_TT_CLIENT_TEMP)) |
851 | goto out; | ||
852 | if (batadv_tt_global_entry_has_orig(tt_global_entry, | ||
853 | orig_node)) | ||
854 | goto out_remove; | ||
855 | batadv_tt_global_del_orig_list(tt_global_entry); | ||
856 | goto add_orig_entry; | ||
857 | } | ||
775 | 858 | ||
776 | /* if the client was temporary added before receiving the first | 859 | /* if the client was temporary added before receiving the first |
777 | * OGM announcing it, we have to clear the TEMP flag | 860 | * OGM announcing it, we have to clear the TEMP flag |
778 | */ | 861 | */ |
779 | tt_global_entry->common.flags &= ~BATADV_TT_CLIENT_TEMP; | 862 | common->flags &= ~BATADV_TT_CLIENT_TEMP; |
780 | 863 | ||
781 | /* If there is the BATADV_TT_CLIENT_ROAM flag set, there is only | 864 | /* If there is the BATADV_TT_CLIENT_ROAM flag set, there is only |
782 | * one originator left in the list and we previously received a | 865 | * one originator left in the list and we previously received a |
@@ -785,18 +868,19 @@ int batadv_tt_global_add(struct batadv_priv *bat_priv, | |||
785 | * We should first delete the old originator before adding the | 868 | * We should first delete the old originator before adding the |
786 | * new one. | 869 | * new one. |
787 | */ | 870 | */ |
788 | if (tt_global_entry->common.flags & BATADV_TT_CLIENT_ROAM) { | 871 | if (common->flags & BATADV_TT_CLIENT_ROAM) { |
789 | batadv_tt_global_del_orig_list(tt_global_entry); | 872 | batadv_tt_global_del_orig_list(tt_global_entry); |
790 | tt_global_entry->common.flags &= ~BATADV_TT_CLIENT_ROAM; | 873 | common->flags &= ~BATADV_TT_CLIENT_ROAM; |
791 | tt_global_entry->roam_at = 0; | 874 | tt_global_entry->roam_at = 0; |
792 | } | 875 | } |
793 | } | 876 | } |
877 | add_orig_entry: | ||
794 | /* add the new orig_entry (if needed) or update it */ | 878 | /* add the new orig_entry (if needed) or update it */ |
795 | batadv_tt_global_orig_entry_add(tt_global_entry, orig_node, ttvn); | 879 | batadv_tt_global_orig_entry_add(tt_global_entry, orig_node, ttvn); |
796 | 880 | ||
797 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 881 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
798 | "Creating new global tt entry: %pM (via %pM)\n", | 882 | "Creating new global tt entry: %pM (via %pM)\n", |
799 | tt_global_entry->common.addr, orig_node->orig); | 883 | common->addr, orig_node->orig); |
800 | ret = 1; | 884 | ret = 1; |
801 | 885 | ||
802 | out_remove: | 886 | out_remove: |
@@ -804,12 +888,20 @@ out_remove: | |||
804 | /* remove address from local hash if present */ | 888 | /* remove address from local hash if present */ |
805 | local_flags = batadv_tt_local_remove(bat_priv, tt_addr, | 889 | local_flags = batadv_tt_local_remove(bat_priv, tt_addr, |
806 | "global tt received", | 890 | "global tt received", |
807 | flags & BATADV_TT_CLIENT_ROAM); | 891 | !!(flags & BATADV_TT_CLIENT_ROAM)); |
808 | tt_global_entry->common.flags |= local_flags & BATADV_TT_CLIENT_WIFI; | 892 | tt_global_entry->common.flags |= local_flags & BATADV_TT_CLIENT_WIFI; |
809 | 893 | ||
894 | if (!(flags & BATADV_TT_CLIENT_ROAM)) | ||
895 | /* this is a normal global add. Therefore the client is not in a | ||
896 | * roaming state anymore. | ||
897 | */ | ||
898 | tt_global_entry->common.flags &= ~BATADV_TT_CLIENT_ROAM; | ||
899 | |||
810 | out: | 900 | out: |
811 | if (tt_global_entry) | 901 | if (tt_global_entry) |
812 | batadv_tt_global_entry_free_ref(tt_global_entry); | 902 | batadv_tt_global_entry_free_ref(tt_global_entry); |
903 | if (tt_local_entry) | ||
904 | batadv_tt_local_entry_free_ref(tt_local_entry); | ||
813 | return ret; | 905 | return ret; |
814 | } | 906 | } |
815 | 907 | ||
@@ -927,20 +1019,6 @@ batadv_tt_global_del_orig_entry(struct batadv_priv *bat_priv, | |||
927 | spin_unlock_bh(&tt_global_entry->list_lock); | 1019 | spin_unlock_bh(&tt_global_entry->list_lock); |
928 | } | 1020 | } |
929 | 1021 | ||
930 | static void batadv_tt_global_free(struct batadv_priv *bat_priv, | ||
931 | struct batadv_tt_global_entry *tt_global, | ||
932 | const char *message) | ||
933 | { | ||
934 | batadv_dbg(BATADV_DBG_TT, bat_priv, | ||
935 | "Deleting global tt entry %pM: %s\n", | ||
936 | tt_global->common.addr, message); | ||
937 | |||
938 | batadv_hash_remove(bat_priv->tt.global_hash, batadv_compare_tt, | ||
939 | batadv_choose_orig, tt_global->common.addr); | ||
940 | batadv_tt_global_entry_free_ref(tt_global); | ||
941 | |||
942 | } | ||
943 | |||
944 | /* If the client is to be deleted, we check if it is the last origantor entry | 1022 | /* If the client is to be deleted, we check if it is the last origantor entry |
945 | * within tt_global entry. If yes, we set the BATADV_TT_CLIENT_ROAM flag and the | 1023 | * within tt_global entry. If yes, we set the BATADV_TT_CLIENT_ROAM flag and the |
946 | * timer, otherwise we simply remove the originator scheduled for deletion. | 1024 | * timer, otherwise we simply remove the originator scheduled for deletion. |
@@ -1204,7 +1282,8 @@ struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv, | |||
1204 | 1282 | ||
1205 | if (src && atomic_read(&bat_priv->ap_isolation)) { | 1283 | if (src && atomic_read(&bat_priv->ap_isolation)) { |
1206 | tt_local_entry = batadv_tt_local_hash_find(bat_priv, src); | 1284 | tt_local_entry = batadv_tt_local_hash_find(bat_priv, src); |
1207 | if (!tt_local_entry) | 1285 | if (!tt_local_entry || |
1286 | (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING)) | ||
1208 | goto out; | 1287 | goto out; |
1209 | } | 1288 | } |
1210 | 1289 | ||