Commit 89652331c00f43574515059ecbf262d26d885717
batman-adv: split tq information in neigh_node struct
For the network wide multi interface optimization it is required to save metrics per outgoing interface in one neighbor. Therefore a new type is introduced to keep interface-specific information. This also requires some changes in access and list management. The compare and equiv_or_better API calls are changed to take the outgoing interface into consideration. Signed-off-by: Simon Wunderlich <simon@open-mesh.com> Signed-off-by: Marek Lindner <mareklindner@neomailbox.ch> Signed-off-by: Antonio Quartulli <antonio@meshcoding.com>
Showing 9 changed files with 588 additions and 114 deletions Side-by-side Diff
... | ... | @@ -272,8 +272,15 @@ |
272 | 272 | if (!neigh_node) |
273 | 273 | goto out; |
274 | 274 | |
275 | - spin_lock_init(&neigh_node->bat_iv.lq_update_lock); | |
275 | + if (!atomic_inc_not_zero(&hard_iface->refcount)) { | |
276 | + kfree(neigh_node); | |
277 | + neigh_node = NULL; | |
278 | + goto out; | |
279 | + } | |
276 | 280 | |
281 | + neigh_node->orig_node = orig_neigh; | |
282 | + neigh_node->if_incoming = hard_iface; | |
283 | + | |
277 | 284 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, |
278 | 285 | "Creating new neighbor %pM for orig_node %pM on interface %s\n", |
279 | 286 | neigh_addr, orig_node->orig, hard_iface->net_dev->name); |
280 | 287 | |
281 | 288 | |
... | ... | @@ -895,15 +902,30 @@ |
895 | 902 | batadv_hardif_free_ref(primary_if); |
896 | 903 | } |
897 | 904 | |
905 | +/** | |
906 | + * batadv_iv_ogm_orig_update - use OGM to update corresponding data in an | |
907 | + * originator | |
908 | + * @bat_priv: the bat priv with all the soft interface information | |
909 | + * @orig_node: the orig node who originally emitted the ogm packet | |
910 | + * @ethhdr: Ethernet header of the OGM | |
911 | + * @batadv_ogm_packet: the ogm packet | |
912 | + * @if_incoming: interface where the packet was received | |
913 | + * @if_outgoing: interface for which the retransmission should be considered | |
914 | + * @tt_buff: pointer to the tt buffer | |
915 | + * @dup_status: the duplicate status of this ogm packet. | |
916 | + */ | |
898 | 917 | static void |
899 | 918 | batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, |
900 | 919 | struct batadv_orig_node *orig_node, |
901 | 920 | const struct ethhdr *ethhdr, |
902 | 921 | const struct batadv_ogm_packet *batadv_ogm_packet, |
903 | 922 | struct batadv_hard_iface *if_incoming, |
923 | + struct batadv_hard_iface *if_outgoing, | |
904 | 924 | const unsigned char *tt_buff, |
905 | 925 | enum batadv_dup_status dup_status) |
906 | 926 | { |
927 | + struct batadv_neigh_ifinfo *neigh_ifinfo = NULL; | |
928 | + struct batadv_neigh_ifinfo *router_ifinfo = NULL; | |
907 | 929 | struct batadv_neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL; |
908 | 930 | struct batadv_neigh_node *router = NULL; |
909 | 931 | struct batadv_orig_node *orig_node_tmp; |
... | ... | @@ -931,12 +953,21 @@ |
931 | 953 | if (dup_status != BATADV_NO_DUP) |
932 | 954 | continue; |
933 | 955 | |
934 | - spin_lock_bh(&tmp_neigh_node->bat_iv.lq_update_lock); | |
935 | - batadv_ring_buffer_set(tmp_neigh_node->bat_iv.tq_recv, | |
936 | - &tmp_neigh_node->bat_iv.tq_index, 0); | |
937 | - tq_avg = batadv_ring_buffer_avg(tmp_neigh_node->bat_iv.tq_recv); | |
938 | - tmp_neigh_node->bat_iv.tq_avg = tq_avg; | |
939 | - spin_unlock_bh(&tmp_neigh_node->bat_iv.lq_update_lock); | |
956 | + /* only update the entry for this outgoing interface */ | |
957 | + neigh_ifinfo = batadv_neigh_ifinfo_get(tmp_neigh_node, | |
958 | + if_outgoing); | |
959 | + if (!neigh_ifinfo) | |
960 | + continue; | |
961 | + | |
962 | + spin_lock_bh(&tmp_neigh_node->ifinfo_lock); | |
963 | + batadv_ring_buffer_set(neigh_ifinfo->bat_iv.tq_recv, | |
964 | + &neigh_ifinfo->bat_iv.tq_index, 0); | |
965 | + tq_avg = batadv_ring_buffer_avg(neigh_ifinfo->bat_iv.tq_recv); | |
966 | + neigh_ifinfo->bat_iv.tq_avg = tq_avg; | |
967 | + spin_unlock_bh(&tmp_neigh_node->ifinfo_lock); | |
968 | + | |
969 | + batadv_neigh_ifinfo_free_ref(neigh_ifinfo); | |
970 | + neigh_ifinfo = NULL; | |
940 | 971 | } |
941 | 972 | |
942 | 973 | if (!neigh_node) { |
943 | 974 | |
944 | 975 | |
945 | 976 | |
... | ... | @@ -958,20 +989,23 @@ |
958 | 989 | "Updating existing last-hop neighbor of originator\n"); |
959 | 990 | |
960 | 991 | rcu_read_unlock(); |
992 | + neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node, if_outgoing); | |
993 | + if (!neigh_ifinfo) | |
994 | + goto out; | |
961 | 995 | |
962 | 996 | neigh_node->last_seen = jiffies; |
963 | 997 | |
964 | - spin_lock_bh(&neigh_node->bat_iv.lq_update_lock); | |
965 | - batadv_ring_buffer_set(neigh_node->bat_iv.tq_recv, | |
966 | - &neigh_node->bat_iv.tq_index, | |
998 | + spin_lock_bh(&neigh_node->ifinfo_lock); | |
999 | + batadv_ring_buffer_set(neigh_ifinfo->bat_iv.tq_recv, | |
1000 | + &neigh_ifinfo->bat_iv.tq_index, | |
967 | 1001 | batadv_ogm_packet->tq); |
968 | - tq_avg = batadv_ring_buffer_avg(neigh_node->bat_iv.tq_recv); | |
969 | - neigh_node->bat_iv.tq_avg = tq_avg; | |
970 | - spin_unlock_bh(&neigh_node->bat_iv.lq_update_lock); | |
1002 | + tq_avg = batadv_ring_buffer_avg(neigh_ifinfo->bat_iv.tq_recv); | |
1003 | + neigh_ifinfo->bat_iv.tq_avg = tq_avg; | |
1004 | + spin_unlock_bh(&neigh_node->ifinfo_lock); | |
971 | 1005 | |
972 | 1006 | if (dup_status == BATADV_NO_DUP) { |
973 | 1007 | orig_node->last_ttl = batadv_ogm_packet->ttl; |
974 | - neigh_node->last_ttl = batadv_ogm_packet->ttl; | |
1008 | + neigh_ifinfo->last_ttl = batadv_ogm_packet->ttl; | |
975 | 1009 | } |
976 | 1010 | |
977 | 1011 | /* if this neighbor already is our next hop there is nothing |
978 | 1012 | |
979 | 1013 | |
... | ... | @@ -981,14 +1015,23 @@ |
981 | 1015 | if (router == neigh_node) |
982 | 1016 | goto out; |
983 | 1017 | |
984 | - /* if this neighbor does not offer a better TQ we won't consider it */ | |
985 | - if (router && (router->bat_iv.tq_avg > neigh_node->bat_iv.tq_avg)) | |
986 | - goto out; | |
1018 | + if (router) { | |
1019 | + router_ifinfo = batadv_neigh_ifinfo_get(router, if_outgoing); | |
1020 | + if (!router_ifinfo) | |
1021 | + goto out; | |
987 | 1022 | |
1023 | + /* if this neighbor does not offer a better TQ we won't | |
1024 | + * consider it | |
1025 | + */ | |
1026 | + if (router_ifinfo->bat_iv.tq_avg > neigh_ifinfo->bat_iv.tq_avg) | |
1027 | + goto out; | |
1028 | + } | |
1029 | + | |
988 | 1030 | /* if the TQ is the same and the link not more symmetric we |
989 | 1031 | * won't consider it either |
990 | 1032 | */ |
991 | - if (router && (neigh_node->bat_iv.tq_avg == router->bat_iv.tq_avg)) { | |
1033 | + if (router_ifinfo && | |
1034 | + (neigh_ifinfo->bat_iv.tq_avg == router_ifinfo->bat_iv.tq_avg)) { | |
992 | 1035 | orig_node_tmp = router->orig_node; |
993 | 1036 | spin_lock_bh(&orig_node_tmp->bat_iv.ogm_cnt_lock); |
994 | 1037 | if_num = router->if_incoming->if_num; |
995 | 1038 | |
996 | 1039 | |
997 | 1040 | |
... | ... | @@ -1015,15 +1058,31 @@ |
1015 | 1058 | batadv_neigh_node_free_ref(neigh_node); |
1016 | 1059 | if (router) |
1017 | 1060 | batadv_neigh_node_free_ref(router); |
1061 | + if (neigh_ifinfo) | |
1062 | + batadv_neigh_ifinfo_free_ref(neigh_ifinfo); | |
1063 | + if (router_ifinfo) | |
1064 | + batadv_neigh_ifinfo_free_ref(router_ifinfo); | |
1018 | 1065 | } |
1019 | 1066 | |
1067 | +/** | |
1068 | + * batadv_iv_ogm_calc_tq - calculate tq for current received ogm packet | |
1069 | + * @orig_node: the orig node who originally emitted the ogm packet | |
1070 | + * @orig_neigh_node: the orig node struct of the neighbor who sent the packet | |
1071 | + * @batadv_ogm_packet: the ogm packet | |
1072 | + * @if_incoming: interface where the packet was received | |
1073 | + * @if_outgoing: interface for which the retransmission should be considered | |
1074 | + * | |
1075 | + * Returns 1 if the link can be considered bidirectional, 0 otherwise | |
1076 | + */ | |
1020 | 1077 | static int batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node, |
1021 | 1078 | struct batadv_orig_node *orig_neigh_node, |
1022 | 1079 | struct batadv_ogm_packet *batadv_ogm_packet, |
1023 | - struct batadv_hard_iface *if_incoming) | |
1080 | + struct batadv_hard_iface *if_incoming, | |
1081 | + struct batadv_hard_iface *if_outgoing) | |
1024 | 1082 | { |
1025 | 1083 | struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); |
1026 | 1084 | struct batadv_neigh_node *neigh_node = NULL, *tmp_neigh_node; |
1085 | + struct batadv_neigh_ifinfo *neigh_ifinfo; | |
1027 | 1086 | uint8_t total_count; |
1028 | 1087 | uint8_t orig_eq_count, neigh_rq_count, neigh_rq_inv, tq_own; |
1029 | 1088 | unsigned int neigh_rq_inv_cube, neigh_rq_max_cube; |
... | ... | @@ -1068,7 +1127,13 @@ |
1068 | 1127 | spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock); |
1069 | 1128 | if_num = if_incoming->if_num; |
1070 | 1129 | orig_eq_count = orig_neigh_node->bat_iv.bcast_own_sum[if_num]; |
1071 | - neigh_rq_count = neigh_node->bat_iv.real_packet_count; | |
1130 | + neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node, if_outgoing); | |
1131 | + if (neigh_ifinfo) { | |
1132 | + neigh_rq_count = neigh_ifinfo->bat_iv.real_packet_count; | |
1133 | + batadv_neigh_ifinfo_free_ref(neigh_ifinfo); | |
1134 | + } else { | |
1135 | + neigh_rq_count = 0; | |
1136 | + } | |
1072 | 1137 | spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock); |
1073 | 1138 | |
1074 | 1139 | /* pay attention to not get a value bigger than 100 % */ |
1075 | 1140 | |
1076 | 1141 | |
... | ... | @@ -1132,17 +1197,20 @@ |
1132 | 1197 | * @ethhdr: ethernet header of the packet |
1133 | 1198 | * @batadv_ogm_packet: OGM packet to be considered |
1134 | 1199 | * @if_incoming: interface on which the OGM packet was received |
1200 | + * @if_outgoing: interface for which the retransmission should be considered | |
1135 | 1201 | * |
1136 | 1202 | * Returns duplicate status as enum batadv_dup_status |
1137 | 1203 | */ |
1138 | 1204 | static enum batadv_dup_status |
1139 | 1205 | batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr, |
1140 | 1206 | const struct batadv_ogm_packet *batadv_ogm_packet, |
1141 | - const struct batadv_hard_iface *if_incoming) | |
1207 | + const struct batadv_hard_iface *if_incoming, | |
1208 | + struct batadv_hard_iface *if_outgoing) | |
1142 | 1209 | { |
1143 | 1210 | struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); |
1144 | 1211 | struct batadv_orig_node *orig_node; |
1145 | - struct batadv_neigh_node *tmp_neigh_node; | |
1212 | + struct batadv_neigh_node *neigh_node; | |
1213 | + struct batadv_neigh_ifinfo *neigh_ifinfo; | |
1146 | 1214 | int is_dup; |
1147 | 1215 | int32_t seq_diff; |
1148 | 1216 | int need_update = 0; |
1149 | 1217 | |
... | ... | @@ -1169,15 +1237,19 @@ |
1169 | 1237 | } |
1170 | 1238 | |
1171 | 1239 | rcu_read_lock(); |
1172 | - hlist_for_each_entry_rcu(tmp_neigh_node, | |
1173 | - &orig_node->neigh_list, list) { | |
1174 | - neigh_addr = tmp_neigh_node->addr; | |
1175 | - is_dup = batadv_test_bit(tmp_neigh_node->bat_iv.real_bits, | |
1240 | + hlist_for_each_entry_rcu(neigh_node, &orig_node->neigh_list, list) { | |
1241 | + neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node, | |
1242 | + if_outgoing); | |
1243 | + if (!neigh_ifinfo) | |
1244 | + continue; | |
1245 | + | |
1246 | + neigh_addr = neigh_node->addr; | |
1247 | + is_dup = batadv_test_bit(neigh_ifinfo->bat_iv.real_bits, | |
1176 | 1248 | orig_node->last_real_seqno, |
1177 | 1249 | seqno); |
1178 | 1250 | |
1179 | 1251 | if (batadv_compare_eth(neigh_addr, ethhdr->h_source) && |
1180 | - tmp_neigh_node->if_incoming == if_incoming) { | |
1252 | + neigh_node->if_incoming == if_incoming) { | |
1181 | 1253 | set_mark = 1; |
1182 | 1254 | if (is_dup) |
1183 | 1255 | ret = BATADV_NEIGH_DUP; |
1184 | 1256 | |
1185 | 1257 | |
... | ... | @@ -1188,13 +1260,14 @@ |
1188 | 1260 | } |
1189 | 1261 | |
1190 | 1262 | /* if the window moved, set the update flag. */ |
1191 | - bitmap = tmp_neigh_node->bat_iv.real_bits; | |
1263 | + bitmap = neigh_ifinfo->bat_iv.real_bits; | |
1192 | 1264 | need_update |= batadv_bit_get_packet(bat_priv, bitmap, |
1193 | 1265 | seq_diff, set_mark); |
1194 | 1266 | |
1195 | - packet_count = bitmap_weight(tmp_neigh_node->bat_iv.real_bits, | |
1267 | + packet_count = bitmap_weight(bitmap, | |
1196 | 1268 | BATADV_TQ_LOCAL_WINDOW_SIZE); |
1197 | - tmp_neigh_node->bat_iv.real_packet_count = packet_count; | |
1269 | + neigh_ifinfo->bat_iv.real_packet_count = packet_count; | |
1270 | + batadv_neigh_ifinfo_free_ref(neigh_ifinfo); | |
1198 | 1271 | } |
1199 | 1272 | rcu_read_unlock(); |
1200 | 1273 | |
... | ... | @@ -1221,6 +1294,7 @@ |
1221 | 1294 | struct batadv_orig_node *orig_neigh_node, *orig_node, *orig_node_tmp; |
1222 | 1295 | struct batadv_neigh_node *router = NULL, *router_router = NULL; |
1223 | 1296 | struct batadv_neigh_node *orig_neigh_router = NULL; |
1297 | + struct batadv_neigh_ifinfo *router_ifinfo = NULL; | |
1224 | 1298 | int has_directlink_flag; |
1225 | 1299 | int is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0; |
1226 | 1300 | int is_bidirect; |
... | ... | @@ -1353,7 +1427,8 @@ |
1353 | 1427 | return; |
1354 | 1428 | |
1355 | 1429 | dup_status = batadv_iv_ogm_update_seqnos(ethhdr, batadv_ogm_packet, |
1356 | - if_incoming); | |
1430 | + if_incoming, | |
1431 | + BATADV_IF_DEFAULT); | |
1357 | 1432 | |
1358 | 1433 | if (dup_status == BATADV_PROTECTED) { |
1359 | 1434 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, |
1360 | 1435 | |
... | ... | @@ -1372,9 +1447,11 @@ |
1372 | 1447 | if (router) { |
1373 | 1448 | orig_node_tmp = router->orig_node; |
1374 | 1449 | router_router = batadv_orig_node_get_router(orig_node_tmp); |
1450 | + router_ifinfo = batadv_neigh_ifinfo_get(router, | |
1451 | + BATADV_IF_DEFAULT); | |
1375 | 1452 | } |
1376 | 1453 | |
1377 | - if ((router && router->bat_iv.tq_avg != 0) && | |
1454 | + if ((router && router_ifinfo->bat_iv.tq_avg != 0) && | |
1378 | 1455 | (batadv_compare_eth(router->addr, ethhdr->h_source))) |
1379 | 1456 | is_from_best_next_hop = true; |
1380 | 1457 | |
... | ... | @@ -1420,7 +1497,8 @@ |
1420 | 1497 | } |
1421 | 1498 | |
1422 | 1499 | is_bidirect = batadv_iv_ogm_calc_tq(orig_node, orig_neigh_node, |
1423 | - batadv_ogm_packet, if_incoming); | |
1500 | + batadv_ogm_packet, if_incoming, | |
1501 | + BATADV_IF_DEFAULT); | |
1424 | 1502 | |
1425 | 1503 | /* update ranking if it is not a duplicate or has the same |
1426 | 1504 | * seqno and similar ttl as the non-duplicate |
... | ... | @@ -1431,7 +1509,8 @@ |
1431 | 1509 | (sameseq && similar_ttl))) |
1432 | 1510 | batadv_iv_ogm_orig_update(bat_priv, orig_node, ethhdr, |
1433 | 1511 | batadv_ogm_packet, if_incoming, |
1434 | - tt_buff, dup_status); | |
1512 | + BATADV_IF_DEFAULT, tt_buff, | |
1513 | + dup_status); | |
1435 | 1514 | |
1436 | 1515 | /* is single hop (direct) neighbor */ |
1437 | 1516 | if (is_single_hop_neigh) { |
... | ... | @@ -1527,6 +1606,34 @@ |
1527 | 1606 | return NET_RX_SUCCESS; |
1528 | 1607 | } |
1529 | 1608 | |
1609 | +/* batadv_iv_ogm_orig_print_neigh - print neighbors for the originator table | |
1610 | + * @orig_node: the orig_node for which the neighbors are printed | |
1611 | + * @if_outgoing: outgoing interface for these entries | |
1612 | + * @seq: debugfs table seq_file struct | |
1613 | + * | |
1614 | + * Must be called while holding an rcu lock. | |
1615 | + */ | |
1616 | +static void | |
1617 | +batadv_iv_ogm_orig_print_neigh(struct batadv_orig_node *orig_node, | |
1618 | + struct batadv_hard_iface *if_outgoing, | |
1619 | + struct seq_file *seq) | |
1620 | +{ | |
1621 | + struct batadv_neigh_node *neigh_node; | |
1622 | + struct batadv_neigh_ifinfo *n_ifinfo; | |
1623 | + | |
1624 | + hlist_for_each_entry_rcu(neigh_node, &orig_node->neigh_list, list) { | |
1625 | + n_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing); | |
1626 | + if (!n_ifinfo) | |
1627 | + continue; | |
1628 | + | |
1629 | + seq_printf(seq, " %pM (%3i)", | |
1630 | + neigh_node->addr, | |
1631 | + n_ifinfo->bat_iv.tq_avg); | |
1632 | + | |
1633 | + batadv_neigh_ifinfo_free_ref(n_ifinfo); | |
1634 | + } | |
1635 | +} | |
1636 | + | |
1530 | 1637 | /** |
1531 | 1638 | * batadv_iv_ogm_orig_print - print the originator table |
1532 | 1639 | * @bat_priv: the bat priv with all the soft interface information |
1533 | 1640 | |
... | ... | @@ -1535,10 +1642,11 @@ |
1535 | 1642 | static void batadv_iv_ogm_orig_print(struct batadv_priv *bat_priv, |
1536 | 1643 | struct seq_file *seq) |
1537 | 1644 | { |
1538 | - struct batadv_neigh_node *neigh_node, *neigh_node_tmp; | |
1645 | + struct batadv_neigh_node *neigh_node; | |
1539 | 1646 | struct batadv_hashtable *hash = bat_priv->orig_hash; |
1540 | 1647 | int last_seen_msecs, last_seen_secs; |
1541 | 1648 | struct batadv_orig_node *orig_node; |
1649 | + struct batadv_neigh_ifinfo *n_ifinfo; | |
1542 | 1650 | unsigned long last_seen_jiffies; |
1543 | 1651 | struct hlist_head *head; |
1544 | 1652 | int batman_count = 0; |
1545 | 1653 | |
... | ... | @@ -1557,9 +1665,14 @@ |
1557 | 1665 | if (!neigh_node) |
1558 | 1666 | continue; |
1559 | 1667 | |
1560 | - if (neigh_node->bat_iv.tq_avg == 0) | |
1668 | + n_ifinfo = batadv_neigh_ifinfo_get(neigh_node, | |
1669 | + BATADV_IF_DEFAULT); | |
1670 | + if (!n_ifinfo) | |
1561 | 1671 | goto next; |
1562 | 1672 | |
1673 | + if (n_ifinfo->bat_iv.tq_avg == 0) | |
1674 | + goto next; | |
1675 | + | |
1563 | 1676 | last_seen_jiffies = jiffies - orig_node->last_seen; |
1564 | 1677 | last_seen_msecs = jiffies_to_msecs(last_seen_jiffies); |
1565 | 1678 | last_seen_secs = last_seen_msecs / 1000; |
1566 | 1679 | |
1567 | 1680 | |
... | ... | @@ -1567,22 +1680,19 @@ |
1567 | 1680 | |
1568 | 1681 | seq_printf(seq, "%pM %4i.%03is (%3i) %pM [%10s]:", |
1569 | 1682 | orig_node->orig, last_seen_secs, |
1570 | - last_seen_msecs, neigh_node->bat_iv.tq_avg, | |
1683 | + last_seen_msecs, n_ifinfo->bat_iv.tq_avg, | |
1571 | 1684 | neigh_node->addr, |
1572 | 1685 | neigh_node->if_incoming->net_dev->name); |
1573 | 1686 | |
1574 | - hlist_for_each_entry_rcu(neigh_node_tmp, | |
1575 | - &orig_node->neigh_list, list) { | |
1576 | - seq_printf(seq, " %pM (%3i)", | |
1577 | - neigh_node_tmp->addr, | |
1578 | - neigh_node_tmp->bat_iv.tq_avg); | |
1579 | - } | |
1580 | - | |
1687 | + batadv_iv_ogm_orig_print_neigh(orig_node, | |
1688 | + BATADV_IF_DEFAULT, seq); | |
1581 | 1689 | seq_puts(seq, "\n"); |
1582 | 1690 | batman_count++; |
1583 | 1691 | |
1584 | 1692 | next: |
1585 | 1693 | batadv_neigh_node_free_ref(neigh_node); |
1694 | + if (n_ifinfo) | |
1695 | + batadv_neigh_ifinfo_free_ref(n_ifinfo); | |
1586 | 1696 | } |
1587 | 1697 | rcu_read_unlock(); |
1588 | 1698 | } |
1589 | 1699 | |
1590 | 1700 | |
1591 | 1701 | |
1592 | 1702 | |
1593 | 1703 | |
1594 | 1704 | |
1595 | 1705 | |
1596 | 1706 | |
1597 | 1707 | |
1598 | 1708 | |
1599 | 1709 | |
... | ... | @@ -1594,37 +1704,84 @@ |
1594 | 1704 | /** |
1595 | 1705 | * batadv_iv_ogm_neigh_cmp - compare the metrics of two neighbors |
1596 | 1706 | * @neigh1: the first neighbor object of the comparison |
1707 | + * @if_outgoing1: outgoing interface for the first neighbor | |
1597 | 1708 | * @neigh2: the second neighbor object of the comparison |
1709 | + * @if_outgoing2: outgoing interface for the second neighbor | |
1598 | 1710 | * |
1599 | 1711 | * Returns a value less, equal to or greater than 0 if the metric via neigh1 is |
1600 | 1712 | * lower, the same as or higher than the metric via neigh2 |
1601 | 1713 | */ |
1602 | 1714 | static int batadv_iv_ogm_neigh_cmp(struct batadv_neigh_node *neigh1, |
1603 | - struct batadv_neigh_node *neigh2) | |
1715 | + struct batadv_hard_iface *if_outgoing1, | |
1716 | + struct batadv_neigh_node *neigh2, | |
1717 | + struct batadv_hard_iface *if_outgoing2) | |
1604 | 1718 | { |
1719 | + struct batadv_neigh_ifinfo *neigh1_ifinfo, *neigh2_ifinfo; | |
1605 | 1720 | uint8_t tq1, tq2; |
1721 | + int diff; | |
1606 | 1722 | |
1607 | - tq1 = neigh1->bat_iv.tq_avg; | |
1608 | - tq2 = neigh2->bat_iv.tq_avg; | |
1723 | + neigh1_ifinfo = batadv_neigh_ifinfo_get(neigh1, if_outgoing1); | |
1724 | + neigh2_ifinfo = batadv_neigh_ifinfo_get(neigh2, if_outgoing2); | |
1609 | 1725 | |
1610 | - return tq1 - tq2; | |
1726 | + if (!neigh1_ifinfo || !neigh2_ifinfo) { | |
1727 | + diff = 0; | |
1728 | + goto out; | |
1729 | + } | |
1730 | + | |
1731 | + tq1 = neigh1_ifinfo->bat_iv.tq_avg; | |
1732 | + tq2 = neigh2_ifinfo->bat_iv.tq_avg; | |
1733 | + diff = tq1 - tq2; | |
1734 | + | |
1735 | +out: | |
1736 | + if (neigh1_ifinfo) | |
1737 | + batadv_neigh_ifinfo_free_ref(neigh1_ifinfo); | |
1738 | + if (neigh2_ifinfo) | |
1739 | + batadv_neigh_ifinfo_free_ref(neigh2_ifinfo); | |
1740 | + | |
1741 | + return diff; | |
1611 | 1742 | } |
1612 | 1743 | |
1613 | 1744 | /** |
1614 | 1745 | * batadv_iv_ogm_neigh_is_eob - check if neigh1 is equally good or better than |
1615 | 1746 | * neigh2 from the metric prospective |
1616 | 1747 | * @neigh1: the first neighbor object of the comparison |
1748 | + * @if_outgoing: outgoing interface for the first neighbor | |
1617 | 1749 | * @neigh2: the second neighbor object of the comparison |
1618 | - * | |
1619 | - * Returns true if the metric via neigh1 is equally good or better than the | |
1620 | - * metric via neigh2, false otherwise. | |
1750 | + * @if_outgoing2: outgoing interface for the second neighbor | |
1751 | + | |
1752 | + * Returns true if the metric via neigh1 is equally good or better than | |
1753 | + * the metric via neigh2, false otherwise. | |
1621 | 1754 | */ |
1622 | -static bool batadv_iv_ogm_neigh_is_eob(struct batadv_neigh_node *neigh1, | |
1623 | - struct batadv_neigh_node *neigh2) | |
1755 | +static bool | |
1756 | +batadv_iv_ogm_neigh_is_eob(struct batadv_neigh_node *neigh1, | |
1757 | + struct batadv_hard_iface *if_outgoing1, | |
1758 | + struct batadv_neigh_node *neigh2, | |
1759 | + struct batadv_hard_iface *if_outgoing2) | |
1624 | 1760 | { |
1625 | - int diff = batadv_iv_ogm_neigh_cmp(neigh1, neigh2); | |
1761 | + struct batadv_neigh_ifinfo *neigh1_ifinfo, *neigh2_ifinfo; | |
1762 | + uint8_t tq1, tq2; | |
1763 | + bool ret; | |
1626 | 1764 | |
1627 | - return diff > -BATADV_TQ_SIMILARITY_THRESHOLD; | |
1765 | + neigh1_ifinfo = batadv_neigh_ifinfo_get(neigh1, if_outgoing1); | |
1766 | + neigh2_ifinfo = batadv_neigh_ifinfo_get(neigh2, if_outgoing2); | |
1767 | + | |
1768 | + /* we can't say that the metric is better */ | |
1769 | + if (!neigh1_ifinfo || !neigh2_ifinfo) { | |
1770 | + ret = false; | |
1771 | + goto out; | |
1772 | + } | |
1773 | + | |
1774 | + tq1 = neigh1_ifinfo->bat_iv.tq_avg; | |
1775 | + tq2 = neigh2_ifinfo->bat_iv.tq_avg; | |
1776 | + ret = (tq1 - tq2) > -BATADV_TQ_SIMILARITY_THRESHOLD; | |
1777 | + | |
1778 | +out: | |
1779 | + if (neigh1_ifinfo) | |
1780 | + batadv_neigh_ifinfo_free_ref(neigh1_ifinfo); | |
1781 | + if (neigh2_ifinfo) | |
1782 | + batadv_neigh_ifinfo_free_ref(neigh2_ifinfo); | |
1783 | + | |
1784 | + return ret; | |
1628 | 1785 | } |
1629 | 1786 | |
1630 | 1787 | static struct batadv_algo_ops batadv_batman_iv __read_mostly = { |
... | ... | @@ -129,6 +129,7 @@ |
129 | 129 | batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv) |
130 | 130 | { |
131 | 131 | struct batadv_neigh_node *router; |
132 | + struct batadv_neigh_ifinfo *router_ifinfo; | |
132 | 133 | struct batadv_gw_node *gw_node, *curr_gw = NULL; |
133 | 134 | uint32_t max_gw_factor = 0, tmp_gw_factor = 0; |
134 | 135 | uint32_t gw_divisor; |
135 | 136 | |
... | ... | @@ -149,10 +150,15 @@ |
149 | 150 | if (!router) |
150 | 151 | continue; |
151 | 152 | |
153 | + router_ifinfo = batadv_neigh_ifinfo_get(router, | |
154 | + BATADV_IF_DEFAULT); | |
155 | + if (!router_ifinfo) | |
156 | + goto next; | |
157 | + | |
152 | 158 | if (!atomic_inc_not_zero(&gw_node->refcount)) |
153 | 159 | goto next; |
154 | 160 | |
155 | - tq_avg = router->bat_iv.tq_avg; | |
161 | + tq_avg = router_ifinfo->bat_iv.tq_avg; | |
156 | 162 | |
157 | 163 | switch (atomic_read(&bat_priv->gw_sel_class)) { |
158 | 164 | case 1: /* fast connection */ |
... | ... | @@ -197,6 +203,8 @@ |
197 | 203 | |
198 | 204 | next: |
199 | 205 | batadv_neigh_node_free_ref(router); |
206 | + if (router_ifinfo) | |
207 | + batadv_neigh_ifinfo_free_ref(router_ifinfo); | |
200 | 208 | } |
201 | 209 | rcu_read_unlock(); |
202 | 210 | |
... | ... | @@ -239,6 +247,7 @@ |
239 | 247 | { |
240 | 248 | struct batadv_gw_node *curr_gw = NULL, *next_gw = NULL; |
241 | 249 | struct batadv_neigh_node *router = NULL; |
250 | + struct batadv_neigh_ifinfo *router_ifinfo = NULL; | |
242 | 251 | char gw_addr[18] = { '\0' }; |
243 | 252 | |
244 | 253 | if (atomic_read(&bat_priv->gw_mode) != BATADV_GW_MODE_CLIENT) |
... | ... | @@ -262,6 +271,13 @@ |
262 | 271 | batadv_gw_reselect(bat_priv); |
263 | 272 | goto out; |
264 | 273 | } |
274 | + | |
275 | + router_ifinfo = batadv_neigh_ifinfo_get(router, | |
276 | + BATADV_IF_DEFAULT); | |
277 | + if (!router_ifinfo) { | |
278 | + batadv_gw_reselect(bat_priv); | |
279 | + goto out; | |
280 | + } | |
265 | 281 | } |
266 | 282 | |
267 | 283 | if ((curr_gw) && (!next_gw)) { |
... | ... | @@ -276,7 +292,8 @@ |
276 | 292 | next_gw->bandwidth_down / 10, |
277 | 293 | next_gw->bandwidth_down % 10, |
278 | 294 | next_gw->bandwidth_up / 10, |
279 | - next_gw->bandwidth_up % 10, router->bat_iv.tq_avg); | |
295 | + next_gw->bandwidth_up % 10, | |
296 | + router_ifinfo->bat_iv.tq_avg); | |
280 | 297 | batadv_throw_uevent(bat_priv, BATADV_UEV_GW, BATADV_UEV_ADD, |
281 | 298 | gw_addr); |
282 | 299 | } else { |
... | ... | @@ -286,7 +303,8 @@ |
286 | 303 | next_gw->bandwidth_down / 10, |
287 | 304 | next_gw->bandwidth_down % 10, |
288 | 305 | next_gw->bandwidth_up / 10, |
289 | - next_gw->bandwidth_up % 10, router->bat_iv.tq_avg); | |
306 | + next_gw->bandwidth_up % 10, | |
307 | + router_ifinfo->bat_iv.tq_avg); | |
290 | 308 | batadv_throw_uevent(bat_priv, BATADV_UEV_GW, BATADV_UEV_CHANGE, |
291 | 309 | gw_addr); |
292 | 310 | } |
293 | 311 | |
... | ... | @@ -300,11 +318,15 @@ |
300 | 318 | batadv_gw_node_free_ref(next_gw); |
301 | 319 | if (router) |
302 | 320 | batadv_neigh_node_free_ref(router); |
321 | + if (router_ifinfo) | |
322 | + batadv_neigh_ifinfo_free_ref(router_ifinfo); | |
303 | 323 | } |
304 | 324 | |
305 | 325 | void batadv_gw_check_election(struct batadv_priv *bat_priv, |
306 | 326 | struct batadv_orig_node *orig_node) |
307 | 327 | { |
328 | + struct batadv_neigh_ifinfo *router_orig_tq = NULL; | |
329 | + struct batadv_neigh_ifinfo *router_gw_tq = NULL; | |
308 | 330 | struct batadv_orig_node *curr_gw_orig; |
309 | 331 | struct batadv_neigh_node *router_gw = NULL, *router_orig = NULL; |
310 | 332 | uint8_t gw_tq_avg, orig_tq_avg; |
... | ... | @@ -317,6 +339,11 @@ |
317 | 339 | if (!router_gw) |
318 | 340 | goto reselect; |
319 | 341 | |
342 | + router_gw_tq = batadv_neigh_ifinfo_get(router_gw, | |
343 | + BATADV_IF_DEFAULT); | |
344 | + if (!router_gw_tq) | |
345 | + goto reselect; | |
346 | + | |
320 | 347 | /* this node already is the gateway */ |
321 | 348 | if (curr_gw_orig == orig_node) |
322 | 349 | goto out; |
323 | 350 | |
... | ... | @@ -325,9 +352,14 @@ |
325 | 352 | if (!router_orig) |
326 | 353 | goto out; |
327 | 354 | |
328 | - gw_tq_avg = router_gw->bat_iv.tq_avg; | |
329 | - orig_tq_avg = router_orig->bat_iv.tq_avg; | |
355 | + router_orig_tq = batadv_neigh_ifinfo_get(router_orig, | |
356 | + BATADV_IF_DEFAULT); | |
357 | + if (!router_orig_tq) | |
358 | + goto out; | |
330 | 359 | |
360 | + gw_tq_avg = router_gw_tq->bat_iv.tq_avg; | |
361 | + orig_tq_avg = router_orig_tq->bat_iv.tq_avg; | |
362 | + | |
331 | 363 | /* the TQ value has to be better */ |
332 | 364 | if (orig_tq_avg < gw_tq_avg) |
333 | 365 | goto out; |
... | ... | @@ -352,6 +384,10 @@ |
352 | 384 | batadv_neigh_node_free_ref(router_gw); |
353 | 385 | if (router_orig) |
354 | 386 | batadv_neigh_node_free_ref(router_orig); |
387 | + if (router_gw_tq) | |
388 | + batadv_neigh_ifinfo_free_ref(router_gw_tq); | |
389 | + if (router_orig_tq) | |
390 | + batadv_neigh_ifinfo_free_ref(router_orig_tq); | |
355 | 391 | |
356 | 392 | return; |
357 | 393 | } |
358 | 394 | |
359 | 395 | |
360 | 396 | |
361 | 397 | |
... | ... | @@ -537,28 +573,36 @@ |
537 | 573 | { |
538 | 574 | struct batadv_gw_node *curr_gw; |
539 | 575 | struct batadv_neigh_node *router; |
576 | + struct batadv_neigh_ifinfo *router_ifinfo = NULL; | |
540 | 577 | int ret = -1; |
541 | 578 | |
542 | 579 | router = batadv_orig_node_get_router(gw_node->orig_node); |
543 | 580 | if (!router) |
544 | 581 | goto out; |
545 | 582 | |
583 | + router_ifinfo = batadv_neigh_ifinfo_get(router, BATADV_IF_DEFAULT); | |
584 | + if (!router_ifinfo) | |
585 | + goto out; | |
586 | + | |
546 | 587 | curr_gw = batadv_gw_get_selected_gw_node(bat_priv); |
547 | 588 | |
548 | 589 | ret = seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %u.%u/%u.%u MBit\n", |
549 | 590 | (curr_gw == gw_node ? "=>" : " "), |
550 | 591 | gw_node->orig_node->orig, |
551 | - router->bat_iv.tq_avg, router->addr, | |
592 | + router_ifinfo->bat_iv.tq_avg, router->addr, | |
552 | 593 | router->if_incoming->net_dev->name, |
553 | 594 | gw_node->bandwidth_down / 10, |
554 | 595 | gw_node->bandwidth_down % 10, |
555 | 596 | gw_node->bandwidth_up / 10, |
556 | 597 | gw_node->bandwidth_up % 10); |
557 | 598 | |
558 | - batadv_neigh_node_free_ref(router); | |
559 | 599 | if (curr_gw) |
560 | 600 | batadv_gw_node_free_ref(curr_gw); |
561 | 601 | out: |
602 | + if (router_ifinfo) | |
603 | + batadv_neigh_ifinfo_free_ref(router_ifinfo); | |
604 | + if (router) | |
605 | + batadv_neigh_node_free_ref(router); | |
562 | 606 | return ret; |
563 | 607 | } |
564 | 608 | |
... | ... | @@ -746,6 +790,7 @@ |
746 | 790 | struct batadv_neigh_node *neigh_curr = NULL, *neigh_old = NULL; |
747 | 791 | struct batadv_orig_node *orig_dst_node = NULL; |
748 | 792 | struct batadv_gw_node *gw_node = NULL, *curr_gw = NULL; |
793 | + struct batadv_neigh_ifinfo *curr_ifinfo, *old_ifinfo; | |
749 | 794 | struct ethhdr *ethhdr = (struct ethhdr *)skb->data; |
750 | 795 | bool out_of_range = false; |
751 | 796 | uint8_t curr_tq_avg; |
... | ... | @@ -787,7 +832,14 @@ |
787 | 832 | if (!neigh_curr) |
788 | 833 | goto out; |
789 | 834 | |
790 | - curr_tq_avg = neigh_curr->bat_iv.tq_avg; | |
835 | + curr_ifinfo = batadv_neigh_ifinfo_get(neigh_curr, | |
836 | + BATADV_IF_DEFAULT); | |
837 | + if (!curr_ifinfo) | |
838 | + goto out; | |
839 | + | |
840 | + curr_tq_avg = curr_ifinfo->bat_iv.tq_avg; | |
841 | + batadv_neigh_ifinfo_free_ref(curr_ifinfo); | |
842 | + | |
791 | 843 | break; |
792 | 844 | case BATADV_GW_MODE_OFF: |
793 | 845 | default: |
794 | 846 | |
... | ... | @@ -798,8 +850,13 @@ |
798 | 850 | if (!neigh_old) |
799 | 851 | goto out; |
800 | 852 | |
801 | - if (curr_tq_avg - neigh_old->bat_iv.tq_avg > BATADV_GW_THRESHOLD) | |
853 | + old_ifinfo = batadv_neigh_ifinfo_get(neigh_old, BATADV_IF_DEFAULT); | |
854 | + if (!old_ifinfo) | |
855 | + goto out; | |
856 | + | |
857 | + if ((curr_tq_avg - old_ifinfo->bat_iv.tq_avg) > BATADV_GW_THRESHOLD) | |
802 | 858 | out_of_range = true; |
859 | + batadv_neigh_ifinfo_free_ref(old_ifinfo); | |
803 | 860 | |
804 | 861 | out: |
805 | 862 | if (orig_dst_node) |
... | ... | @@ -51,11 +51,28 @@ |
51 | 51 | void batadv_update_min_mtu(struct net_device *soft_iface); |
52 | 52 | void batadv_hardif_free_rcu(struct rcu_head *rcu); |
53 | 53 | |
54 | +/** | |
55 | + * batadv_hardif_free_ref - decrement the hard interface refcounter and | |
56 | + * possibly free it | |
57 | + * @hard_iface: the hard interface to free | |
58 | + */ | |
54 | 59 | static inline void |
55 | 60 | batadv_hardif_free_ref(struct batadv_hard_iface *hard_iface) |
56 | 61 | { |
57 | 62 | if (atomic_dec_and_test(&hard_iface->refcount)) |
58 | 63 | call_rcu(&hard_iface->rcu, batadv_hardif_free_rcu); |
64 | +} | |
65 | + | |
66 | +/** | |
67 | + * batadv_hardif_free_ref_now - decrement the hard interface refcounter and | |
68 | + * possibly free it (without rcu callback) | |
69 | + * @hard_iface: the hard interface to free | |
70 | + */ | |
71 | +static inline void | |
72 | +batadv_hardif_free_ref_now(struct batadv_hard_iface *hard_iface) | |
73 | +{ | |
74 | + if (atomic_dec_and_test(&hard_iface->refcount)) | |
75 | + batadv_hardif_free_rcu(&hard_iface->rcu); | |
59 | 76 | } |
60 | 77 | |
61 | 78 | static inline struct batadv_hard_iface * |
... | ... | @@ -72,6 +72,12 @@ |
72 | 72 | |
73 | 73 | #define BATADV_NO_MARK 0 |
74 | 74 | |
75 | +/* default interface for multi interface operation. The default interface is | |
76 | + * used for communication which originated locally (i.e. is not forwarded) | |
77 | + * or where special forwarding is not desired/necessary. | |
78 | + */ | |
79 | +#define BATADV_IF_DEFAULT ((struct batadv_hard_iface *)NULL) | |
80 | + | |
75 | 81 | #define BATADV_NUM_WORDS BITS_TO_LONGS(BATADV_TQ_LOCAL_WINDOW_SIZE) |
76 | 82 | |
77 | 83 | #define BATADV_LOG_BUF_LEN 8192 /* has to be a power of 2 */ |
... | ... | @@ -1008,6 +1008,8 @@ |
1008 | 1008 | struct batadv_coded_packet *coded_packet; |
1009 | 1009 | struct batadv_neigh_node *neigh_tmp, *router_neigh; |
1010 | 1010 | struct batadv_neigh_node *router_coding = NULL; |
1011 | + struct batadv_neigh_ifinfo *router_neigh_ifinfo = NULL; | |
1012 | + struct batadv_neigh_ifinfo *router_coding_ifinfo = NULL; | |
1011 | 1013 | uint8_t *first_source, *first_dest, *second_source, *second_dest; |
1012 | 1014 | __be32 packet_id1, packet_id2; |
1013 | 1015 | size_t count; |
1014 | 1016 | |
1015 | 1017 | |
... | ... | @@ -1021,16 +1023,26 @@ |
1021 | 1023 | if (!router_neigh) |
1022 | 1024 | goto out; |
1023 | 1025 | |
1026 | + router_neigh_ifinfo = batadv_neigh_ifinfo_get(router_neigh, | |
1027 | + BATADV_IF_DEFAULT); | |
1028 | + if (!router_neigh_ifinfo) | |
1029 | + goto out; | |
1030 | + | |
1024 | 1031 | neigh_tmp = nc_packet->neigh_node; |
1025 | 1032 | router_coding = batadv_orig_node_get_router(neigh_tmp->orig_node); |
1026 | 1033 | if (!router_coding) |
1027 | 1034 | goto out; |
1028 | 1035 | |
1029 | - tq_tmp = batadv_nc_random_weight_tq(router_neigh->bat_iv.tq_avg); | |
1030 | - tq_weighted_neigh = tq_tmp; | |
1031 | - tq_tmp = batadv_nc_random_weight_tq(router_coding->bat_iv.tq_avg); | |
1032 | - tq_weighted_coding = tq_tmp; | |
1036 | + router_coding_ifinfo = batadv_neigh_ifinfo_get(router_coding, | |
1037 | + BATADV_IF_DEFAULT); | |
1038 | + if (!router_coding_ifinfo) | |
1039 | + goto out; | |
1033 | 1040 | |
1041 | + tq_tmp = router_neigh_ifinfo->bat_iv.tq_avg; | |
1042 | + tq_weighted_neigh = batadv_nc_random_weight_tq(tq_tmp); | |
1043 | + tq_tmp = router_coding_ifinfo->bat_iv.tq_avg; | |
1044 | + tq_weighted_coding = batadv_nc_random_weight_tq(tq_tmp); | |
1045 | + | |
1034 | 1046 | /* Select one destination for the MAC-header dst-field based on |
1035 | 1047 | * weighted TQ-values. |
1036 | 1048 | */ |
... | ... | @@ -1153,6 +1165,10 @@ |
1153 | 1165 | batadv_neigh_node_free_ref(router_neigh); |
1154 | 1166 | if (router_coding) |
1155 | 1167 | batadv_neigh_node_free_ref(router_coding); |
1168 | + if (router_neigh_ifinfo) | |
1169 | + batadv_neigh_ifinfo_free_ref(router_neigh_ifinfo); | |
1170 | + if (router_coding_ifinfo) | |
1171 | + batadv_neigh_ifinfo_free_ref(router_coding_ifinfo); | |
1156 | 1172 | return res; |
1157 | 1173 | } |
1158 | 1174 |
... | ... | @@ -148,10 +148,87 @@ |
148 | 148 | return -ENOMEM; |
149 | 149 | } |
150 | 150 | |
151 | +/** | |
152 | + * batadv_neigh_ifinfo_free_rcu - free the neigh_ifinfo object | |
153 | + * @rcu: rcu pointer of the neigh_ifinfo object | |
154 | + */ | |
155 | +static void batadv_neigh_ifinfo_free_rcu(struct rcu_head *rcu) | |
156 | +{ | |
157 | + struct batadv_neigh_ifinfo *neigh_ifinfo; | |
158 | + | |
159 | + neigh_ifinfo = container_of(rcu, struct batadv_neigh_ifinfo, rcu); | |
160 | + | |
161 | + if (neigh_ifinfo->if_outgoing != BATADV_IF_DEFAULT) | |
162 | + batadv_hardif_free_ref_now(neigh_ifinfo->if_outgoing); | |
163 | + | |
164 | + kfree(neigh_ifinfo); | |
165 | +} | |
166 | + | |
167 | +/** | |
168 | + * batadv_neigh_ifinfo_free_now - decrement the refcounter and possibly free | |
169 | + * the neigh_ifinfo (without rcu callback) | |
170 | + * @neigh_ifinfo: the neigh_ifinfo object to release | |
171 | + */ | |
172 | +static void | |
173 | +batadv_neigh_ifinfo_free_ref_now(struct batadv_neigh_ifinfo *neigh_ifinfo) | |
174 | +{ | |
175 | + if (atomic_dec_and_test(&neigh_ifinfo->refcount)) | |
176 | + batadv_neigh_ifinfo_free_rcu(&neigh_ifinfo->rcu); | |
177 | +} | |
178 | + | |
179 | +/** | |
180 | + * batadv_neigh_ifinfo_free_ref - decrement the refcounter and possibly free | |
181 | + * the neigh_ifinfo | |
182 | + * @neigh_ifinfo: the neigh_ifinfo object to release | |
183 | + */ | |
184 | +void batadv_neigh_ifinfo_free_ref(struct batadv_neigh_ifinfo *neigh_ifinfo) | |
185 | +{ | |
186 | + if (atomic_dec_and_test(&neigh_ifinfo->refcount)) | |
187 | + call_rcu(&neigh_ifinfo->rcu, batadv_neigh_ifinfo_free_rcu); | |
188 | +} | |
189 | + | |
190 | +/** | |
191 | + * batadv_neigh_node_free_rcu - free the neigh_node | |
192 | + * @rcu: rcu pointer of the neigh_node | |
193 | + */ | |
194 | +static void batadv_neigh_node_free_rcu(struct rcu_head *rcu) | |
195 | +{ | |
196 | + struct hlist_node *node_tmp; | |
197 | + struct batadv_neigh_node *neigh_node; | |
198 | + struct batadv_neigh_ifinfo *neigh_ifinfo; | |
199 | + | |
200 | + neigh_node = container_of(rcu, struct batadv_neigh_node, rcu); | |
201 | + | |
202 | + hlist_for_each_entry_safe(neigh_ifinfo, node_tmp, | |
203 | + &neigh_node->ifinfo_list, list) { | |
204 | + batadv_neigh_ifinfo_free_ref_now(neigh_ifinfo); | |
205 | + } | |
206 | + batadv_hardif_free_ref_now(neigh_node->if_incoming); | |
207 | + | |
208 | + kfree(neigh_node); | |
209 | +} | |
210 | + | |
211 | +/** | |
212 | + * batadv_neigh_node_free_ref_now - decrement the neighbors refcounter | |
213 | + * and possibly free it (without rcu callback) | |
214 | + * @neigh_node: neigh neighbor to free | |
215 | + */ | |
216 | +static void | |
217 | +batadv_neigh_node_free_ref_now(struct batadv_neigh_node *neigh_node) | |
218 | +{ | |
219 | + if (atomic_dec_and_test(&neigh_node->refcount)) | |
220 | + batadv_neigh_node_free_rcu(&neigh_node->rcu); | |
221 | +} | |
222 | + | |
223 | +/** | |
224 | + * batadv_neigh_node_free_ref - decrement the neighbors refcounter | |
225 | + * and possibly free it | |
226 | + * @neigh_node: neigh neighbor to free | |
227 | + */ | |
151 | 228 | void batadv_neigh_node_free_ref(struct batadv_neigh_node *neigh_node) |
152 | 229 | { |
153 | 230 | if (atomic_dec_and_test(&neigh_node->refcount)) |
154 | - kfree_rcu(neigh_node, rcu); | |
231 | + call_rcu(&neigh_node->rcu, batadv_neigh_node_free_rcu); | |
155 | 232 | } |
156 | 233 | |
157 | 234 | /* increases the refcounter of a found router */ |
... | ... | @@ -171,6 +248,84 @@ |
171 | 248 | } |
172 | 249 | |
173 | 250 | /** |
251 | + * batadv_neigh_ifinfo_get - find the ifinfo from an neigh_node | |
252 | + * @neigh_node: the neigh node to be queried | |
253 | + * @if_outgoing: the interface for which the ifinfo should be acquired | |
254 | + * | |
255 | + * The object is returned with refcounter increased by 1. | |
256 | + * | |
257 | + * Returns the requested neigh_ifinfo or NULL if not found | |
258 | + */ | |
259 | +struct batadv_neigh_ifinfo * | |
260 | +batadv_neigh_ifinfo_get(struct batadv_neigh_node *neigh, | |
261 | + struct batadv_hard_iface *if_outgoing) | |
262 | +{ | |
263 | + struct batadv_neigh_ifinfo *neigh_ifinfo = NULL, | |
264 | + *tmp_neigh_ifinfo; | |
265 | + | |
266 | + rcu_read_lock(); | |
267 | + hlist_for_each_entry_rcu(tmp_neigh_ifinfo, &neigh->ifinfo_list, | |
268 | + list) { | |
269 | + if (tmp_neigh_ifinfo->if_outgoing != if_outgoing) | |
270 | + continue; | |
271 | + | |
272 | + if (!atomic_inc_not_zero(&tmp_neigh_ifinfo->refcount)) | |
273 | + continue; | |
274 | + | |
275 | + neigh_ifinfo = tmp_neigh_ifinfo; | |
276 | + break; | |
277 | + } | |
278 | + rcu_read_unlock(); | |
279 | + | |
280 | + return neigh_ifinfo; | |
281 | +} | |
282 | + | |
283 | +/** | |
284 | + * batadv_neigh_ifinfo_new - search and possibly create an neigh_ifinfo object | |
285 | + * @neigh_node: the neigh node to be queried | |
286 | + * @if_outgoing: the interface for which the ifinfo should be acquired | |
287 | + * | |
288 | + * Returns NULL in case of failure or the neigh_ifinfo object for the | |
289 | + * if_outgoing interface otherwise. The object is created and added to the list | |
290 | + * if it does not exist. | |
291 | + * | |
292 | + * The object is returned with refcounter increased by 1. | |
293 | + */ | |
294 | +struct batadv_neigh_ifinfo * | |
295 | +batadv_neigh_ifinfo_new(struct batadv_neigh_node *neigh, | |
296 | + struct batadv_hard_iface *if_outgoing) | |
297 | +{ | |
298 | + struct batadv_neigh_ifinfo *neigh_ifinfo; | |
299 | + | |
300 | + spin_lock_bh(&neigh->ifinfo_lock); | |
301 | + | |
302 | + neigh_ifinfo = batadv_neigh_ifinfo_get(neigh, if_outgoing); | |
303 | + if (neigh_ifinfo) | |
304 | + goto out; | |
305 | + | |
306 | + neigh_ifinfo = kzalloc(sizeof(*neigh_ifinfo), GFP_ATOMIC); | |
307 | + if (!neigh_ifinfo) | |
308 | + goto out; | |
309 | + | |
310 | + if (if_outgoing && !atomic_inc_not_zero(&if_outgoing->refcount)) { | |
311 | + kfree(neigh_ifinfo); | |
312 | + neigh_ifinfo = NULL; | |
313 | + goto out; | |
314 | + } | |
315 | + | |
316 | + INIT_HLIST_NODE(&neigh_ifinfo->list); | |
317 | + atomic_set(&neigh_ifinfo->refcount, 2); | |
318 | + neigh_ifinfo->if_outgoing = if_outgoing; | |
319 | + | |
320 | + hlist_add_head_rcu(&neigh_ifinfo->list, &neigh->ifinfo_list); | |
321 | + | |
322 | +out: | |
323 | + spin_unlock_bh(&neigh->ifinfo_lock); | |
324 | + | |
325 | + return neigh_ifinfo; | |
326 | +} | |
327 | + | |
328 | +/** | |
174 | 329 | * batadv_neigh_node_new - create and init a new neigh_node object |
175 | 330 | * @hard_iface: the interface where the neighbour is connected to |
176 | 331 | * @neigh_addr: the mac address of the neighbour interface |
... | ... | @@ -191,6 +346,8 @@ |
191 | 346 | goto out; |
192 | 347 | |
193 | 348 | INIT_HLIST_NODE(&neigh_node->list); |
349 | + INIT_HLIST_HEAD(&neigh_node->ifinfo_list); | |
350 | + spin_lock_init(&neigh_node->ifinfo_lock); | |
194 | 351 | |
195 | 352 | memcpy(neigh_node->addr, neigh_addr, ETH_ALEN); |
196 | 353 | neigh_node->if_incoming = hard_iface; |
... | ... | @@ -217,7 +374,7 @@ |
217 | 374 | hlist_for_each_entry_safe(neigh_node, node_tmp, |
218 | 375 | &orig_node->neigh_list, list) { |
219 | 376 | hlist_del_rcu(&neigh_node->list); |
220 | - batadv_neigh_node_free_ref(neigh_node); | |
377 | + batadv_neigh_node_free_ref_now(neigh_node); | |
221 | 378 | } |
222 | 379 | |
223 | 380 | spin_unlock_bh(&orig_node->neigh_list_lock); |
224 | 381 | |
225 | 382 | |
226 | 383 | |
... | ... | @@ -362,20 +519,23 @@ |
362 | 519 | return NULL; |
363 | 520 | } |
364 | 521 | |
522 | +/** | |
523 | + * batadv_purge_orig_neighbors - purges neighbors from originator | |
524 | + * @bat_priv: the bat priv with all the soft interface information | |
525 | + * @orig_node: orig node which is to be checked | |
526 | + * | |
527 | + * Returns true if any neighbor was purged, false otherwise | |
528 | + */ | |
365 | 529 | static bool |
366 | 530 | batadv_purge_orig_neighbors(struct batadv_priv *bat_priv, |
367 | - struct batadv_orig_node *orig_node, | |
368 | - struct batadv_neigh_node **best_neigh) | |
531 | + struct batadv_orig_node *orig_node) | |
369 | 532 | { |
370 | - struct batadv_algo_ops *bao = bat_priv->bat_algo_ops; | |
371 | 533 | struct hlist_node *node_tmp; |
372 | 534 | struct batadv_neigh_node *neigh_node; |
373 | 535 | bool neigh_purged = false; |
374 | 536 | unsigned long last_seen; |
375 | 537 | struct batadv_hard_iface *if_incoming; |
376 | 538 | |
377 | - *best_neigh = NULL; | |
378 | - | |
379 | 539 | spin_lock_bh(&orig_node->neigh_list_lock); |
380 | 540 | |
381 | 541 | /* for all neighbors towards this originator ... */ |
... | ... | @@ -405,13 +565,6 @@ |
405 | 565 | |
406 | 566 | hlist_del_rcu(&neigh_node->list); |
407 | 567 | batadv_neigh_node_free_ref(neigh_node); |
408 | - } else { | |
409 | - /* store the best_neighbour if this is the first | |
410 | - * iteration or if a better neighbor has been found | |
411 | - */ | |
412 | - if (!*best_neigh || | |
413 | - bao->bat_neigh_cmp(neigh_node, *best_neigh) > 0) | |
414 | - *best_neigh = neigh_node; | |
415 | 568 | } |
416 | 569 | } |
417 | 570 | |
... | ... | @@ -419,6 +572,41 @@ |
419 | 572 | return neigh_purged; |
420 | 573 | } |
421 | 574 | |
575 | +/** | |
576 | + * batadv_find_best_neighbor - finds the best neighbor after purging | |
577 | + * @bat_priv: the bat priv with all the soft interface information | |
578 | + * @orig_node: orig node which is to be checked | |
579 | + * @if_outgoing: the interface for which the metric should be compared | |
580 | + * | |
581 | + * Returns the current best neighbor, with refcount increased. | |
582 | + */ | |
583 | +static struct batadv_neigh_node * | |
584 | +batadv_find_best_neighbor(struct batadv_priv *bat_priv, | |
585 | + struct batadv_orig_node *orig_node, | |
586 | + struct batadv_hard_iface *if_outgoing) | |
587 | +{ | |
588 | + struct batadv_neigh_node *best = NULL, *neigh; | |
589 | + struct batadv_algo_ops *bao = bat_priv->bat_algo_ops; | |
590 | + | |
591 | + rcu_read_lock(); | |
592 | + hlist_for_each_entry_rcu(neigh, &orig_node->neigh_list, list) { | |
593 | + if (best && (bao->bat_neigh_cmp(neigh, if_outgoing, | |
594 | + best, if_outgoing) <= 0)) | |
595 | + continue; | |
596 | + | |
597 | + if (!atomic_inc_not_zero(&neigh->refcount)) | |
598 | + continue; | |
599 | + | |
600 | + if (best) | |
601 | + batadv_neigh_node_free_ref(best); | |
602 | + | |
603 | + best = neigh; | |
604 | + } | |
605 | + rcu_read_unlock(); | |
606 | + | |
607 | + return best; | |
608 | +} | |
609 | + | |
422 | 610 | static bool batadv_purge_orig_node(struct batadv_priv *bat_priv, |
423 | 611 | struct batadv_orig_node *orig_node) |
424 | 612 | { |
425 | 613 | |
... | ... | @@ -431,12 +619,15 @@ |
431 | 619 | orig_node->orig, |
432 | 620 | jiffies_to_msecs(orig_node->last_seen)); |
433 | 621 | return true; |
434 | - } else { | |
435 | - if (batadv_purge_orig_neighbors(bat_priv, orig_node, | |
436 | - &best_neigh_node)) | |
437 | - batadv_update_route(bat_priv, orig_node, | |
438 | - best_neigh_node); | |
439 | 622 | } |
623 | + if (!batadv_purge_orig_neighbors(bat_priv, orig_node)) | |
624 | + return false; | |
625 | + | |
626 | + best_neigh_node = batadv_find_best_neighbor(bat_priv, orig_node, | |
627 | + BATADV_IF_DEFAULT); | |
628 | + batadv_update_route(bat_priv, orig_node, best_neigh_node); | |
629 | + if (best_neigh_node) | |
630 | + batadv_neigh_node_free_ref(best_neigh_node); | |
440 | 631 | |
441 | 632 | return false; |
442 | 633 | } |
... | ... | @@ -35,6 +35,13 @@ |
35 | 35 | void batadv_neigh_node_free_ref(struct batadv_neigh_node *neigh_node); |
36 | 36 | struct batadv_neigh_node * |
37 | 37 | batadv_orig_node_get_router(struct batadv_orig_node *orig_node); |
38 | +struct batadv_neigh_ifinfo * | |
39 | +batadv_neigh_ifinfo_new(struct batadv_neigh_node *neigh, | |
40 | + struct batadv_hard_iface *if_outgoing); | |
41 | +struct batadv_neigh_ifinfo * | |
42 | +batadv_neigh_ifinfo_get(struct batadv_neigh_node *neigh, | |
43 | + struct batadv_hard_iface *if_outgoing); | |
44 | +void batadv_neigh_ifinfo_free_ref(struct batadv_neigh_ifinfo *neigh_ifinfo); | |
38 | 45 | int batadv_orig_seq_print_text(struct seq_file *seq, void *offset); |
39 | 46 | int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface, |
40 | 47 | int max_if_num); |
... | ... | @@ -1405,7 +1405,8 @@ |
1405 | 1405 | continue; |
1406 | 1406 | |
1407 | 1407 | if (best_router && |
1408 | - bao->bat_neigh_cmp(router, best_router) <= 0) { | |
1408 | + bao->bat_neigh_cmp(router, BATADV_IF_DEFAULT, | |
1409 | + best_router, BATADV_IF_DEFAULT) <= 0) { | |
1409 | 1410 | batadv_neigh_node_free_ref(router); |
1410 | 1411 | continue; |
1411 | 1412 | } |
... | ... | @@ -289,47 +289,62 @@ |
289 | 289 | }; |
290 | 290 | |
291 | 291 | /** |
292 | - * struct batadv_neigh_bat_iv - B.A.T.M.A.N. IV specific structure for single | |
293 | - * hop neighbors | |
292 | + * struct batadv_neigh_node - structure for single hops neighbors | |
293 | + * @list: list node for batadv_orig_node::neigh_list | |
294 | + * @orig_node: pointer to corresponding orig_node | |
295 | + * @addr: the MAC address of the neighboring interface | |
296 | + * @ifinfo_list: list for routing metrics per outgoing interface | |
297 | + * @ifinfo_lock: lock protecting private ifinfo members and list | |
298 | + * @if_incoming: pointer to incoming hard interface | |
299 | + * @last_seen: when last packet via this neighbor was received | |
300 | + * @last_ttl: last received ttl from this neigh node | |
301 | + * @rcu: struct used for freeing in an RCU-safe manner | |
302 | + * @bat_iv: B.A.T.M.A.N. IV private structure | |
303 | + */ | |
304 | +struct batadv_neigh_node { | |
305 | + struct hlist_node list; | |
306 | + struct batadv_orig_node *orig_node; | |
307 | + uint8_t addr[ETH_ALEN]; | |
308 | + struct hlist_head ifinfo_list; | |
309 | + spinlock_t ifinfo_lock; /* protects ifinfo_list and its members */ | |
310 | + struct batadv_hard_iface *if_incoming; | |
311 | + unsigned long last_seen; | |
312 | + atomic_t refcount; | |
313 | + struct rcu_head rcu; | |
314 | +}; | |
315 | + | |
316 | +/* struct batadv_neigh_node_bat_iv - neighbor information per outgoing | |
317 | + * interface for BATMAN IV | |
294 | 318 | * @tq_recv: ring buffer of received TQ values from this neigh node |
295 | 319 | * @tq_index: ring buffer index |
296 | 320 | * @tq_avg: averaged tq of all tq values in the ring buffer (tq_recv) |
297 | 321 | * @real_bits: bitfield containing the number of OGMs received from this neigh |
298 | 322 | * node (relative to orig_node->last_real_seqno) |
299 | 323 | * @real_packet_count: counted result of real_bits |
300 | - * @lq_update_lock: lock protecting tq_recv & tq_index | |
301 | 324 | */ |
302 | -struct batadv_neigh_bat_iv { | |
325 | +struct batadv_neigh_ifinfo_bat_iv { | |
303 | 326 | uint8_t tq_recv[BATADV_TQ_GLOBAL_WINDOW_SIZE]; |
304 | 327 | uint8_t tq_index; |
305 | 328 | uint8_t tq_avg; |
306 | 329 | DECLARE_BITMAP(real_bits, BATADV_TQ_LOCAL_WINDOW_SIZE); |
307 | 330 | uint8_t real_packet_count; |
308 | - spinlock_t lq_update_lock; /* protects tq_recv & tq_index */ | |
309 | 331 | }; |
310 | 332 | |
311 | -/** | |
312 | - * struct batadv_neigh_node - structure for single hops neighbors | |
313 | - * @list: list node for batadv_orig_node::neigh_list | |
314 | - * @orig_node: pointer to corresponding orig_node | |
315 | - * @addr: the MAC address of the neighboring interface | |
316 | - * @if_incoming: pointer to incoming hard interface | |
317 | - * @last_seen: when last packet via this neighbor was received | |
333 | +/* struct batadv_neigh_ifinfo - neighbor information per outgoing interface | |
334 | + * @list: list node for batadv_neigh_node::ifinfo_list | |
335 | + * @if_outgoing: pointer to outgoing hard interface | |
336 | + * @bat_iv: B.A.T.M.A.N. IV private structure | |
318 | 337 | * @last_ttl: last received ttl from this neigh node |
319 | 338 | * @refcount: number of contexts the object is used |
320 | - * @rcu: struct used for freeing in an RCU-safe manner | |
321 | - * @bat_iv: B.A.T.M.A.N. IV private structure | |
339 | + * @rcu: struct used for freeing in a RCU-safe manner | |
322 | 340 | */ |
323 | -struct batadv_neigh_node { | |
341 | +struct batadv_neigh_ifinfo { | |
324 | 342 | struct hlist_node list; |
325 | - struct batadv_orig_node *orig_node; | |
326 | - uint8_t addr[ETH_ALEN]; | |
327 | - struct batadv_hard_iface *if_incoming; | |
328 | - unsigned long last_seen; | |
343 | + struct batadv_hard_iface *if_outgoing; | |
344 | + struct batadv_neigh_ifinfo_bat_iv bat_iv; | |
329 | 345 | uint8_t last_ttl; |
330 | 346 | atomic_t refcount; |
331 | 347 | struct rcu_head rcu; |
332 | - struct batadv_neigh_bat_iv bat_iv; | |
333 | 348 | }; |
334 | 349 | |
335 | 350 | /** |
... | ... | @@ -1013,9 +1028,11 @@ |
1013 | 1028 | * @bat_primary_iface_set: called when primary interface is selected / changed |
1014 | 1029 | * @bat_ogm_schedule: prepare a new outgoing OGM for the send queue |
1015 | 1030 | * @bat_ogm_emit: send scheduled OGM |
1016 | - * @bat_neigh_cmp: compare the metrics of two neighbors | |
1017 | - * @bat_neigh_is_equiv_or_better: check if neigh1 is equally good or | |
1018 | - * better than neigh2 from the metric prospective | |
1031 | + * @bat_neigh_cmp: compare the metrics of two neighbors for their respective | |
1032 | + * outgoing interfaces | |
1033 | + * @bat_neigh_is_equiv_or_better: check if neigh1 is equally good or better | |
1034 | + * than neigh2 for their respective outgoing interface from the metric | |
1035 | + * prospective | |
1019 | 1036 | * @bat_orig_print: print the originator table (optional) |
1020 | 1037 | * @bat_orig_free: free the resources allocated by the routing algorithm for an |
1021 | 1038 | * orig_node object |
... | ... | @@ -1034,9 +1051,14 @@ |
1034 | 1051 | void (*bat_ogm_schedule)(struct batadv_hard_iface *hard_iface); |
1035 | 1052 | void (*bat_ogm_emit)(struct batadv_forw_packet *forw_packet); |
1036 | 1053 | int (*bat_neigh_cmp)(struct batadv_neigh_node *neigh1, |
1037 | - struct batadv_neigh_node *neigh2); | |
1038 | - bool (*bat_neigh_is_equiv_or_better)(struct batadv_neigh_node *neigh1, | |
1039 | - struct batadv_neigh_node *neigh2); | |
1054 | + struct batadv_hard_iface *if_outgoing1, | |
1055 | + struct batadv_neigh_node *neigh2, | |
1056 | + struct batadv_hard_iface *if_outgoing2); | |
1057 | + bool (*bat_neigh_is_equiv_or_better) | |
1058 | + (struct batadv_neigh_node *neigh1, | |
1059 | + struct batadv_hard_iface *if_outgoing1, | |
1060 | + struct batadv_neigh_node *neigh2, | |
1061 | + struct batadv_hard_iface *if_outgoing2); | |
1040 | 1062 | /* orig_node handling API */ |
1041 | 1063 | void (*bat_orig_print)(struct batadv_priv *priv, struct seq_file *seq); |
1042 | 1064 | void (*bat_orig_free)(struct batadv_orig_node *orig_node); |
-
mentioned in commit c1e517
-
mentioned in commit 709de1
-
mentioned in commit 1adf64
-
mentioned in commit cd70e6
-
mentioned in commit 1adf64
-
mentioned in commit cd70e6
-
mentioned in commit 1adf64
-
mentioned in commit cd70e6
-
mentioned in commit 1adf64
-
mentioned in commit cd70e6
-
mentioned in commit 1adf64
-
mentioned in commit cd70e6
-
mentioned in commit 31459b
-
mentioned in commit 568f95
-
mentioned in commit 11ed67
-
mentioned in commit 31459b
-
mentioned in commit 568f95
-
mentioned in commit 11ed67
-
mentioned in commit 31459b
-
mentioned in commit 568f95
-
mentioned in commit 11ed67
-
mentioned in commit 2baa75
-
mentioned in commit ae3e1e
-
mentioned in commit b4d922
-
mentioned in commit 2baa75
-
mentioned in commit ae3e1e
-
mentioned in commit b4d922