Commit 89652331c00f43574515059ecbf262d26d885717

Authored by Simon Wunderlich
Committed by Antonio Quartulli
1 parent f6c8b71173

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

net/batman-adv/bat_iv_ogm.c
... ... @@ -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 = {
net/batman-adv/gateway_client.c
... ... @@ -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)
net/batman-adv/hard-interface.h
... ... @@ -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 *
net/batman-adv/main.h
... ... @@ -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 */
net/batman-adv/network-coding.c
... ... @@ -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  
net/batman-adv/originator.c
... ... @@ -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 }
net/batman-adv/originator.h
... ... @@ -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);
net/batman-adv/translation-table.c
... ... @@ -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 }
net/batman-adv/types.h
... ... @@ -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);