Commit 068ee6e204e1f48ba24ec91ce40f5ca833a57a81

Authored by Antonio Quartulli
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