Commit 068ee6e204e1f48ba24ec91ce40f5ca833a57a81
1 parent
be73b488d1
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>
Showing 1 changed file with 118 additions and 39 deletions Side-by-side Diff
net/batman-adv/translation-table.c
... | ... | @@ -238,6 +238,20 @@ |
238 | 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 | 255 | void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, |
242 | 256 | int ifindex) |
243 | 257 | { |
244 | 258 | |
245 | 259 | |
... | ... | @@ -248,14 +262,38 @@ |
248 | 262 | struct hlist_node *node; |
249 | 263 | struct batadv_tt_orig_list_entry *orig_entry; |
250 | 264 | int hash_added; |
265 | + bool roamed_back = false; | |
251 | 266 | |
252 | 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 | 270 | if (tt_local) { |
255 | 271 | tt_local->last_seen = jiffies; |
256 | - /* possibly unset the BATADV_TT_CLIENT_PENDING flag */ | |
257 | - tt_local->common.flags &= ~BATADV_TT_CLIENT_PENDING; | |
258 | - goto out; | |
272 | + if (tt_local->common.flags & BATADV_TT_CLIENT_PENDING) { | |
273 | + batadv_dbg(BATADV_DBG_TT, bat_priv, | |
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 | 299 | tt_local = kmalloc(sizeof(*tt_local), GFP_ATOMIC); |
262 | 300 | |
... | ... | @@ -294,13 +332,14 @@ |
294 | 332 | goto out; |
295 | 333 | } |
296 | 334 | |
335 | +add_event: | |
297 | 336 | batadv_tt_local_event(bat_priv, addr, tt_local->common.flags); |
298 | 337 | |
299 | - /* remove address from global hash if present */ | |
300 | - tt_global = batadv_tt_global_hash_find(bat_priv, addr); | |
301 | - | |
302 | - /* Check whether it is a roaming! */ | |
303 | - if (tt_global) { | |
338 | +check_roaming: | |
339 | + /* Check whether it is a roaming, but don't do anything if the roaming | |
340 | + * process has already been handled | |
341 | + */ | |
342 | + if (tt_global && !(tt_global->common.flags & BATADV_TT_CLIENT_ROAM)) { | |
304 | 343 | /* These node are probably going to update their tt table */ |
305 | 344 | head = &tt_global->orig_list; |
306 | 345 | rcu_read_lock(); |
307 | 346 | |
... | ... | @@ -309,12 +348,19 @@ |
309 | 348 | orig_entry->orig_node); |
310 | 349 | } |
311 | 350 | rcu_read_unlock(); |
312 | - /* The global entry has to be marked as ROAMING and | |
313 | - * has to be kept for consistency purpose | |
314 | - */ | |
315 | - tt_global->common.flags |= BATADV_TT_CLIENT_ROAM; | |
316 | - tt_global->roam_at = jiffies; | |
351 | + if (roamed_back) { | |
352 | + batadv_tt_global_free(bat_priv, tt_global, | |
353 | + "Roaming canceled"); | |
354 | + tt_global = NULL; | |
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 | 364 | out: |
319 | 365 | if (tt_local) |
320 | 366 | batadv_tt_local_entry_free_ref(tt_local); |
321 | 367 | |
... | ... | @@ -508,13 +554,28 @@ |
508 | 554 | curr_flags = tt_local_entry->common.flags; |
509 | 555 | |
510 | 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 | 561 | if (roaming) { |
512 | 562 | flags |= BATADV_TT_CLIENT_ROAM; |
513 | 563 | /* mark the local client as ROAMed */ |
514 | 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 | 580 | out: |
520 | 581 | if (tt_local_entry) |
521 | 582 | |
522 | 583 | |
... | ... | @@ -724,13 +785,23 @@ |
724 | 785 | uint8_t ttvn) |
725 | 786 | { |
726 | 787 | struct batadv_tt_global_entry *tt_global_entry = NULL; |
788 | + struct batadv_tt_local_entry *tt_local_entry = NULL; | |
727 | 789 | int ret = 0; |
728 | 790 | int hash_added; |
729 | 791 | struct batadv_tt_common_entry *common; |
730 | 792 | uint16_t local_flags; |
731 | 793 | |
732 | 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); | |
733 | 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; | |
804 | + | |
734 | 805 | if (!tt_global_entry) { |
735 | 806 | tt_global_entry = kzalloc(sizeof(*tt_global_entry), GFP_ATOMIC); |
736 | 807 | if (!tt_global_entry) |
737 | 808 | |
738 | 809 | |
739 | 810 | |
... | ... | @@ -764,19 +835,31 @@ |
764 | 835 | goto out_remove; |
765 | 836 | } |
766 | 837 | } else { |
838 | + common = &tt_global_entry->common; | |
767 | 839 | /* If there is already a global entry, we can use this one for |
768 | 840 | * our processing. |
769 | - * But if we are trying to add a temporary client we can exit | |
770 | - * directly because the temporary information should never | |
771 | - * override any already known client state (whatever it is) | |
841 | + * But if we are trying to add a temporary client then here are | |
842 | + * two options at this point: | |
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) | |
774 | - goto out; | |
849 | + if (flags & BATADV_TT_CLIENT_TEMP) { | |
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 | 859 | /* if the client was temporary added before receiving the first |
777 | 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 | 864 | /* If there is the BATADV_TT_CLIENT_ROAM flag set, there is only |
782 | 865 | * one originator left in the list and we previously received a |
783 | 866 | |
784 | 867 | |
785 | 868 | |
... | ... | @@ -785,18 +868,19 @@ |
785 | 868 | * We should first delete the old originator before adding the |
786 | 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 | 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 | 874 | tt_global_entry->roam_at = 0; |
792 | 875 | } |
793 | 876 | } |
877 | +add_orig_entry: | |
794 | 878 | /* add the new orig_entry (if needed) or update it */ |
795 | 879 | batadv_tt_global_orig_entry_add(tt_global_entry, orig_node, ttvn); |
796 | 880 | |
797 | 881 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
798 | 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 | 884 | ret = 1; |
801 | 885 | |
802 | 886 | out_remove: |
803 | 887 | |
804 | 888 | |
... | ... | @@ -804,12 +888,20 @@ |
804 | 888 | /* remove address from local hash if present */ |
805 | 889 | local_flags = batadv_tt_local_remove(bat_priv, tt_addr, |
806 | 890 | "global tt received", |
807 | - flags & BATADV_TT_CLIENT_ROAM); | |
891 | + !!(flags & BATADV_TT_CLIENT_ROAM)); | |
808 | 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 | 900 | out: |
811 | 901 | if (tt_global_entry) |
812 | 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 | 905 | return ret; |
814 | 906 | } |
815 | 907 | |
... | ... | @@ -927,20 +1019,6 @@ |
927 | 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 | 1022 | /* If the client is to be deleted, we check if it is the last origantor entry |
945 | 1023 | * within tt_global entry. If yes, we set the BATADV_TT_CLIENT_ROAM flag and the |
946 | 1024 | * timer, otherwise we simply remove the originator scheduled for deletion. |
... | ... | @@ -1204,7 +1282,8 @@ |
1204 | 1282 | |
1205 | 1283 | if (src && atomic_read(&bat_priv->ap_isolation)) { |
1206 | 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 | 1287 | goto out; |
1209 | 1288 | } |
1210 | 1289 |