aboutsummaryrefslogtreecommitdiffstats
path: root/net/batman-adv/translation-table.c
diff options
context:
space:
mode:
authorMarek Lindner <lindner_marek@yahoo.de>2013-05-27 03:33:25 -0400
committerAntonio Quartulli <antonio@meshcoding.com>2013-10-23 11:03:43 -0400
commita19d3d85e1b854e4a483a55d740a42458085560d (patch)
treea289948258c78d0ea968059ab432046ac2938d56 /net/batman-adv/translation-table.c
parent4627456a77782026ab60c4a16435b089bb444fce (diff)
batman-adv: limit local translation table max size
The local translation table size is limited by what can be transferred from one node to another via a full table request. The number of entries fitting into a full table request depend on whether the fragmentation is enabled or not. Therefore this patch introduces a max table size check and refuses to add more local clients when that size is reached. Moreover, if the max full table packet size changes (MTU change or fragmentation is disabled) the local table is downsized instantaneously. Signed-off-by: Marek Lindner <lindner_marek@yahoo.de> Acked-by: Antonio Quartulli <ordex@autistici.org>
Diffstat (limited to 'net/batman-adv/translation-table.c')
-rw-r--r--net/batman-adv/translation-table.c150
1 files changed, 134 insertions, 16 deletions
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 4c28251dd8e6..a3c965dd1d96 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -401,6 +401,35 @@ static uint16_t batadv_tt_entries(uint16_t tt_len)
401 return tt_len / batadv_tt_len(1); 401 return tt_len / batadv_tt_len(1);
402} 402}
403 403
404/**
405 * batadv_tt_local_table_transmit_size - calculates the local translation table
406 * size when transmitted over the air
407 * @bat_priv: the bat priv with all the soft interface information
408 *
409 * Returns local translation table size in bytes.
410 */
411static int batadv_tt_local_table_transmit_size(struct batadv_priv *bat_priv)
412{
413 uint16_t num_vlan = 0, tt_local_entries = 0;
414 struct batadv_softif_vlan *vlan;
415 int hdr_size;
416
417 rcu_read_lock();
418 hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) {
419 num_vlan++;
420 tt_local_entries += atomic_read(&vlan->tt.num_entries);
421 }
422 rcu_read_unlock();
423
424 /* header size of tvlv encapsulated tt response payload */
425 hdr_size = sizeof(struct batadv_unicast_tvlv_packet);
426 hdr_size += sizeof(struct batadv_tvlv_hdr);
427 hdr_size += sizeof(struct batadv_tvlv_tt_data);
428 hdr_size += num_vlan * sizeof(struct batadv_tvlv_tt_vlan_data);
429
430 return hdr_size + batadv_tt_len(tt_local_entries);
431}
432
404static int batadv_tt_local_init(struct batadv_priv *bat_priv) 433static int batadv_tt_local_init(struct batadv_priv *bat_priv)
405{ 434{
406 if (bat_priv->tt.local_hash) 435 if (bat_priv->tt.local_hash)
@@ -439,8 +468,10 @@ static void batadv_tt_global_free(struct batadv_priv *bat_priv,
439 * @vid: VLAN identifier 468 * @vid: VLAN identifier
440 * @ifindex: index of the interface where the client is connected to (useful to 469 * @ifindex: index of the interface where the client is connected to (useful to
441 * identify wireless clients) 470 * identify wireless clients)
471 *
472 * Returns true if the client was successfully added, false otherwise.
442 */ 473 */
443void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, 474bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
444 unsigned short vid, int ifindex) 475 unsigned short vid, int ifindex)
445{ 476{
446 struct batadv_priv *bat_priv = netdev_priv(soft_iface); 477 struct batadv_priv *bat_priv = netdev_priv(soft_iface);
@@ -448,8 +479,8 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
448 struct batadv_tt_global_entry *tt_global; 479 struct batadv_tt_global_entry *tt_global;
449 struct hlist_head *head; 480 struct hlist_head *head;
450 struct batadv_tt_orig_list_entry *orig_entry; 481 struct batadv_tt_orig_list_entry *orig_entry;
451 int hash_added; 482 int hash_added, table_size, packet_size_max;
452 bool roamed_back = false; 483 bool ret = false, roamed_back = false;
453 484
454 tt_local = batadv_tt_local_hash_find(bat_priv, addr, vid); 485 tt_local = batadv_tt_local_hash_find(bat_priv, addr, vid);
455 tt_global = batadv_tt_global_hash_find(bat_priv, addr, vid); 486 tt_global = batadv_tt_global_hash_find(bat_priv, addr, vid);
@@ -484,6 +515,17 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
484 goto check_roaming; 515 goto check_roaming;
485 } 516 }
486 517
518 /* Ignore the client if we cannot send it in a full table response. */
519 table_size = batadv_tt_local_table_transmit_size(bat_priv);
520 table_size += batadv_tt_len(1);
521 packet_size_max = atomic_read(&bat_priv->packet_size_max);
522 if (table_size > packet_size_max) {
523 net_ratelimited_function(batadv_info, soft_iface,
524 "Local translation table size (%i) exceeds maximum packet size (%i); Ignoring new local tt entry: %pM\n",
525 table_size, packet_size_max, addr);
526 goto out;
527 }
528
487 tt_local = kmalloc(sizeof(*tt_local), GFP_ATOMIC); 529 tt_local = kmalloc(sizeof(*tt_local), GFP_ATOMIC);
488 if (!tt_local) 530 if (!tt_local)
489 goto out; 531 goto out;
@@ -550,11 +592,14 @@ check_roaming:
550 } 592 }
551 } 593 }
552 594
595 ret = true;
596
553out: 597out:
554 if (tt_local) 598 if (tt_local)
555 batadv_tt_local_entry_free_ref(tt_local); 599 batadv_tt_local_entry_free_ref(tt_local);
556 if (tt_global) 600 if (tt_global)
557 batadv_tt_global_entry_free_ref(tt_global); 601 batadv_tt_global_entry_free_ref(tt_global);
602 return ret;
558} 603}
559 604
560/** 605/**
@@ -926,8 +971,16 @@ out:
926 return curr_flags; 971 return curr_flags;
927} 972}
928 973
974/**
975 * batadv_tt_local_purge_list - purge inactive tt local entries
976 * @bat_priv: the bat priv with all the soft interface information
977 * @head: pointer to the list containing the local tt entries
978 * @timeout: parameter deciding whether a given tt local entry is considered
979 * inactive or not
980 */
929static void batadv_tt_local_purge_list(struct batadv_priv *bat_priv, 981static void batadv_tt_local_purge_list(struct batadv_priv *bat_priv,
930 struct hlist_head *head) 982 struct hlist_head *head,
983 int timeout)
931{ 984{
932 struct batadv_tt_local_entry *tt_local_entry; 985 struct batadv_tt_local_entry *tt_local_entry;
933 struct batadv_tt_common_entry *tt_common_entry; 986 struct batadv_tt_common_entry *tt_common_entry;
@@ -945,8 +998,7 @@ static void batadv_tt_local_purge_list(struct batadv_priv *bat_priv,
945 if (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING) 998 if (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING)
946 continue; 999 continue;
947 1000
948 if (!batadv_has_timed_out(tt_local_entry->last_seen, 1001 if (!batadv_has_timed_out(tt_local_entry->last_seen, timeout))
949 BATADV_TT_LOCAL_TIMEOUT))
950 continue; 1002 continue;
951 1003
952 batadv_tt_local_set_pending(bat_priv, tt_local_entry, 1004 batadv_tt_local_set_pending(bat_priv, tt_local_entry,
@@ -954,7 +1006,14 @@ static void batadv_tt_local_purge_list(struct batadv_priv *bat_priv,
954 } 1006 }
955} 1007}
956 1008
957static void batadv_tt_local_purge(struct batadv_priv *bat_priv) 1009/**
1010 * batadv_tt_local_purge - purge inactive tt local entries
1011 * @bat_priv: the bat priv with all the soft interface information
1012 * @timeout: parameter deciding whether a given tt local entry is considered
1013 * inactive or not
1014 */
1015static void batadv_tt_local_purge(struct batadv_priv *bat_priv,
1016 int timeout)
958{ 1017{
959 struct batadv_hashtable *hash = bat_priv->tt.local_hash; 1018 struct batadv_hashtable *hash = bat_priv->tt.local_hash;
960 struct hlist_head *head; 1019 struct hlist_head *head;
@@ -966,7 +1025,7 @@ static void batadv_tt_local_purge(struct batadv_priv *bat_priv)
966 list_lock = &hash->list_locks[i]; 1025 list_lock = &hash->list_locks[i];
967 1026
968 spin_lock_bh(list_lock); 1027 spin_lock_bh(list_lock);
969 batadv_tt_local_purge_list(bat_priv, head); 1028 batadv_tt_local_purge_list(bat_priv, head, timeout);
970 spin_unlock_bh(list_lock); 1029 spin_unlock_bh(list_lock);
971 } 1030 }
972} 1031}
@@ -2383,6 +2442,15 @@ static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv,
2383 req_dst_orig_node); 2442 req_dst_orig_node);
2384 } 2443 }
2385 2444
2445 /* Don't send the response, if larger than fragmented packet. */
2446 tt_len = sizeof(struct batadv_unicast_tvlv_packet) + tvlv_len;
2447 if (tt_len > atomic_read(&bat_priv->packet_size_max)) {
2448 net_ratelimited_function(batadv_info, bat_priv->soft_iface,
2449 "Ignoring TT_REQUEST from %pM; Response size exceeds max packet size.\n",
2450 res_dst_orig_node->orig);
2451 goto out;
2452 }
2453
2386 tvlv_tt_data->flags = BATADV_TT_RESPONSE; 2454 tvlv_tt_data->flags = BATADV_TT_RESPONSE;
2387 tvlv_tt_data->ttvn = req_ttvn; 2455 tvlv_tt_data->ttvn = req_ttvn;
2388 2456
@@ -2859,7 +2927,7 @@ static void batadv_tt_purge(struct work_struct *work)
2859 priv_tt = container_of(delayed_work, struct batadv_priv_tt, work); 2927 priv_tt = container_of(delayed_work, struct batadv_priv_tt, work);
2860 bat_priv = container_of(priv_tt, struct batadv_priv, tt); 2928 bat_priv = container_of(priv_tt, struct batadv_priv, tt);
2861 2929
2862 batadv_tt_local_purge(bat_priv); 2930 batadv_tt_local_purge(bat_priv, BATADV_TT_LOCAL_TIMEOUT);
2863 batadv_tt_global_purge(bat_priv); 2931 batadv_tt_global_purge(bat_priv);
2864 batadv_tt_req_purge(bat_priv); 2932 batadv_tt_req_purge(bat_priv);
2865 batadv_tt_roam_purge(bat_priv); 2933 batadv_tt_roam_purge(bat_priv);
@@ -2972,18 +3040,18 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv)
2972} 3040}
2973 3041
2974/** 3042/**
2975 * batadv_tt_local_commit_changes - commit all pending local tt changes which 3043 * batadv_tt_local_commit_changes_nolock - commit all pending local tt changes
2976 * have been queued in the time since the last commit 3044 * which have been queued in the time since the last commit
2977 * @bat_priv: the bat priv with all the soft interface information 3045 * @bat_priv: the bat priv with all the soft interface information
3046 *
3047 * Caller must hold tt->commit_lock.
2978 */ 3048 */
2979void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv) 3049static void batadv_tt_local_commit_changes_nolock(struct batadv_priv *bat_priv)
2980{ 3050{
2981 spin_lock_bh(&bat_priv->tt.commit_lock);
2982
2983 if (atomic_read(&bat_priv->tt.local_changes) < 1) { 3051 if (atomic_read(&bat_priv->tt.local_changes) < 1) {
2984 if (!batadv_atomic_dec_not_zero(&bat_priv->tt.ogm_append_cnt)) 3052 if (!batadv_atomic_dec_not_zero(&bat_priv->tt.ogm_append_cnt))
2985 batadv_tt_tvlv_container_update(bat_priv); 3053 batadv_tt_tvlv_container_update(bat_priv);
2986 goto out; 3054 return;
2987 } 3055 }
2988 3056
2989 batadv_tt_local_set_flags(bat_priv, BATADV_TT_CLIENT_NEW, false, true); 3057 batadv_tt_local_set_flags(bat_priv, BATADV_TT_CLIENT_NEW, false, true);
@@ -3000,8 +3068,17 @@ void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv)
3000 /* reset the sending counter */ 3068 /* reset the sending counter */
3001 atomic_set(&bat_priv->tt.ogm_append_cnt, BATADV_TT_OGM_APPEND_MAX); 3069 atomic_set(&bat_priv->tt.ogm_append_cnt, BATADV_TT_OGM_APPEND_MAX);
3002 batadv_tt_tvlv_container_update(bat_priv); 3070 batadv_tt_tvlv_container_update(bat_priv);
3071}
3003 3072
3004out: 3073/**
3074 * batadv_tt_local_commit_changes - commit all pending local tt changes which
3075 * have been queued in the time since the last commit
3076 * @bat_priv: the bat priv with all the soft interface information
3077 */
3078void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv)
3079{
3080 spin_lock_bh(&bat_priv->tt.commit_lock);
3081 batadv_tt_local_commit_changes_nolock(bat_priv);
3005 spin_unlock_bh(&bat_priv->tt.commit_lock); 3082 spin_unlock_bh(&bat_priv->tt.commit_lock);
3006} 3083}
3007 3084
@@ -3197,6 +3274,47 @@ out:
3197} 3274}
3198 3275
3199/** 3276/**
3277 * batadv_tt_local_resize_to_mtu - resize the local translation table fit the
3278 * maximum packet size that can be transported through the mesh
3279 * @soft_iface: netdev struct of the mesh interface
3280 *
3281 * Remove entries older than 'timeout' and half timeout if more entries need
3282 * to be removed.
3283 */
3284void batadv_tt_local_resize_to_mtu(struct net_device *soft_iface)
3285{
3286 struct batadv_priv *bat_priv = netdev_priv(soft_iface);
3287 int packet_size_max = atomic_read(&bat_priv->packet_size_max);
3288 int table_size, timeout = BATADV_TT_LOCAL_TIMEOUT / 2;
3289 bool reduced = false;
3290
3291 spin_lock_bh(&bat_priv->tt.commit_lock);
3292
3293 while (true) {
3294 table_size = batadv_tt_local_table_transmit_size(bat_priv);
3295 if (packet_size_max >= table_size)
3296 break;
3297
3298 batadv_tt_local_purge(bat_priv, timeout);
3299 batadv_tt_local_purge_pending_clients(bat_priv);
3300
3301 timeout /= 2;
3302 reduced = true;
3303 net_ratelimited_function(batadv_info, soft_iface,
3304 "Forced to purge local tt entries to fit new maximum fragment MTU (%i)\n",
3305 packet_size_max);
3306 }
3307
3308 /* commit these changes immediately, to avoid synchronization problem
3309 * with the TTVN
3310 */
3311 if (reduced)
3312 batadv_tt_local_commit_changes_nolock(bat_priv);
3313
3314 spin_unlock_bh(&bat_priv->tt.commit_lock);
3315}
3316
3317/**
3200 * batadv_tt_tvlv_ogm_handler_v1 - process incoming tt tvlv container 3318 * batadv_tt_tvlv_ogm_handler_v1 - process incoming tt tvlv container
3201 * @bat_priv: the bat priv with all the soft interface information 3319 * @bat_priv: the bat priv with all the soft interface information
3202 * @orig: the orig_node of the ogm 3320 * @orig: the orig_node of the ogm