Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

batman-adv: add multicast flags netlink support

Dump the list of multicast flags entries via the netlink socket.

Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>

authored by

Linus Lüssing and committed by
Simon Wunderlich
53dd9a68 41aeefcc

+329
+62
include/uapi/linux/batman_adv.h
··· 92 92 }; 93 93 94 94 /** 95 + * enum batadv_mcast_flags_priv - Private, own multicast flags 96 + * 97 + * These are internal, multicast related flags. Currently they describe certain 98 + * multicast related attributes of the segment this originator bridges into the 99 + * mesh. 100 + * 101 + * Those attributes are used to determine the public multicast flags this 102 + * originator is going to announce via TT. 103 + * 104 + * For netlink, if BATADV_MCAST_FLAGS_BRIDGED is unset then all querier 105 + * related flags are undefined. 106 + */ 107 + enum batadv_mcast_flags_priv { 108 + /** 109 + * @BATADV_MCAST_FLAGS_BRIDGED: There is a bridge on top of the mesh 110 + * interface. 111 + */ 112 + BATADV_MCAST_FLAGS_BRIDGED = (1 << 0), 113 + 114 + /** 115 + * @BATADV_MCAST_FLAGS_QUERIER_IPV4_EXISTS: Whether an IGMP querier 116 + * exists in the mesh 117 + */ 118 + BATADV_MCAST_FLAGS_QUERIER_IPV4_EXISTS = (1 << 1), 119 + 120 + /** 121 + * @BATADV_MCAST_FLAGS_QUERIER_IPV6_EXISTS: Whether an MLD querier 122 + * exists in the mesh 123 + */ 124 + BATADV_MCAST_FLAGS_QUERIER_IPV6_EXISTS = (1 << 2), 125 + 126 + /** 127 + * @BATADV_MCAST_FLAGS_QUERIER_IPV4_SHADOWING: If an IGMP querier 128 + * exists, whether it is potentially shadowing multicast listeners 129 + * (i.e. querier is behind our own bridge segment) 130 + */ 131 + BATADV_MCAST_FLAGS_QUERIER_IPV4_SHADOWING = (1 << 3), 132 + 133 + /** 134 + * @BATADV_MCAST_FLAGS_QUERIER_IPV6_SHADOWING: If an MLD querier 135 + * exists, whether it is potentially shadowing multicast listeners 136 + * (i.e. querier is behind our own bridge segment) 137 + */ 138 + BATADV_MCAST_FLAGS_QUERIER_IPV6_SHADOWING = (1 << 4), 139 + }; 140 + 141 + /** 95 142 * enum batadv_nl_attrs - batman-adv netlink attributes 96 143 */ 97 144 enum batadv_nl_attrs { ··· 334 287 */ 335 288 BATADV_ATTR_DAT_CACHE_VID, 336 289 290 + /** 291 + * @BATADV_ATTR_MCAST_FLAGS: Per originator multicast flags 292 + */ 293 + BATADV_ATTR_MCAST_FLAGS, 294 + 295 + /** 296 + * @BATADV_ATTR_MCAST_FLAGS_PRIV: Private, own multicast flags 297 + */ 298 + BATADV_ATTR_MCAST_FLAGS_PRIV, 299 + 337 300 /* add attributes above here, update the policy in netlink.c */ 338 301 339 302 /** ··· 437 380 * @BATADV_CMD_GET_DAT_CACHE: Query list of DAT cache entries 438 381 */ 439 382 BATADV_CMD_GET_DAT_CACHE, 383 + 384 + /** 385 + * @BATADV_CMD_GET_MCAST_FLAGS: Query list of multicast flags 386 + */ 387 + BATADV_CMD_GET_MCAST_FLAGS, 440 388 441 389 /* add new commands above here */ 442 390
+237
net/batman-adv/multicast.c
··· 40 40 #include <linux/list.h> 41 41 #include <linux/lockdep.h> 42 42 #include <linux/netdevice.h> 43 + #include <linux/netlink.h> 43 44 #include <linux/printk.h> 44 45 #include <linux/rculist.h> 45 46 #include <linux/rcupdate.h> ··· 53 52 #include <linux/types.h> 54 53 #include <linux/workqueue.h> 55 54 #include <net/addrconf.h> 55 + #include <net/genetlink.h> 56 56 #include <net/if_inet6.h> 57 57 #include <net/ip.h> 58 58 #include <net/ipv6.h> 59 + #include <net/netlink.h> 60 + #include <net/sock.h> 59 61 #include <uapi/linux/batadv_packet.h> 62 + #include <uapi/linux/batman_adv.h> 60 63 61 64 #include "hard-interface.h" 62 65 #include "hash.h" 63 66 #include "log.h" 67 + #include "netlink.h" 68 + #include "soft-interface.h" 64 69 #include "translation-table.h" 65 70 #include "tvlv.h" 66 71 ··· 1339 1332 return 0; 1340 1333 } 1341 1334 #endif 1335 + 1336 + /** 1337 + * batadv_mcast_mesh_info_put() - put multicast info into a netlink message 1338 + * @msg: buffer for the message 1339 + * @bat_priv: the bat priv with all the soft interface information 1340 + * 1341 + * Return: 0 or error code. 1342 + */ 1343 + int batadv_mcast_mesh_info_put(struct sk_buff *msg, 1344 + struct batadv_priv *bat_priv) 1345 + { 1346 + u32 flags = bat_priv->mcast.flags; 1347 + u32 flags_priv = BATADV_NO_FLAGS; 1348 + 1349 + if (bat_priv->mcast.bridged) { 1350 + flags_priv |= BATADV_MCAST_FLAGS_BRIDGED; 1351 + 1352 + if (bat_priv->mcast.querier_ipv4.exists) 1353 + flags_priv |= BATADV_MCAST_FLAGS_QUERIER_IPV4_EXISTS; 1354 + if (bat_priv->mcast.querier_ipv6.exists) 1355 + flags_priv |= BATADV_MCAST_FLAGS_QUERIER_IPV6_EXISTS; 1356 + if (bat_priv->mcast.querier_ipv4.shadowing) 1357 + flags_priv |= BATADV_MCAST_FLAGS_QUERIER_IPV4_SHADOWING; 1358 + if (bat_priv->mcast.querier_ipv6.shadowing) 1359 + flags_priv |= BATADV_MCAST_FLAGS_QUERIER_IPV6_SHADOWING; 1360 + } 1361 + 1362 + if (nla_put_u32(msg, BATADV_ATTR_MCAST_FLAGS, flags) || 1363 + nla_put_u32(msg, BATADV_ATTR_MCAST_FLAGS_PRIV, flags_priv)) 1364 + return -EMSGSIZE; 1365 + 1366 + return 0; 1367 + } 1368 + 1369 + /** 1370 + * batadv_mcast_flags_dump_entry() - dump one entry of the multicast flags table 1371 + * to a netlink socket 1372 + * @msg: buffer for the message 1373 + * @portid: netlink port 1374 + * @seq: Sequence number of netlink message 1375 + * @orig_node: originator to dump the multicast flags of 1376 + * 1377 + * Return: 0 or error code. 1378 + */ 1379 + static int 1380 + batadv_mcast_flags_dump_entry(struct sk_buff *msg, u32 portid, u32 seq, 1381 + struct batadv_orig_node *orig_node) 1382 + { 1383 + void *hdr; 1384 + 1385 + hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, 1386 + NLM_F_MULTI, BATADV_CMD_GET_MCAST_FLAGS); 1387 + if (!hdr) 1388 + return -ENOBUFS; 1389 + 1390 + if (nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN, 1391 + orig_node->orig)) { 1392 + genlmsg_cancel(msg, hdr); 1393 + return -EMSGSIZE; 1394 + } 1395 + 1396 + if (test_bit(BATADV_ORIG_CAPA_HAS_MCAST, 1397 + &orig_node->capabilities)) { 1398 + if (nla_put_u32(msg, BATADV_ATTR_MCAST_FLAGS, 1399 + orig_node->mcast_flags)) { 1400 + genlmsg_cancel(msg, hdr); 1401 + return -EMSGSIZE; 1402 + } 1403 + } 1404 + 1405 + genlmsg_end(msg, hdr); 1406 + return 0; 1407 + } 1408 + 1409 + /** 1410 + * batadv_mcast_flags_dump_bucket() - dump one bucket of the multicast flags 1411 + * table to a netlink socket 1412 + * @msg: buffer for the message 1413 + * @portid: netlink port 1414 + * @seq: Sequence number of netlink message 1415 + * @head: bucket to dump 1416 + * @idx_skip: How many entries to skip 1417 + * 1418 + * Return: 0 or error code. 1419 + */ 1420 + static int 1421 + batadv_mcast_flags_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq, 1422 + struct hlist_head *head, long *idx_skip) 1423 + { 1424 + struct batadv_orig_node *orig_node; 1425 + long idx = 0; 1426 + 1427 + rcu_read_lock(); 1428 + hlist_for_each_entry_rcu(orig_node, head, hash_entry) { 1429 + if (!test_bit(BATADV_ORIG_CAPA_HAS_MCAST, 1430 + &orig_node->capa_initialized)) 1431 + continue; 1432 + 1433 + if (idx < *idx_skip) 1434 + goto skip; 1435 + 1436 + if (batadv_mcast_flags_dump_entry(msg, portid, seq, 1437 + orig_node)) { 1438 + rcu_read_unlock(); 1439 + *idx_skip = idx; 1440 + 1441 + return -EMSGSIZE; 1442 + } 1443 + 1444 + skip: 1445 + idx++; 1446 + } 1447 + rcu_read_unlock(); 1448 + 1449 + return 0; 1450 + } 1451 + 1452 + /** 1453 + * __batadv_mcast_flags_dump() - dump multicast flags table to a netlink socket 1454 + * @msg: buffer for the message 1455 + * @portid: netlink port 1456 + * @seq: Sequence number of netlink message 1457 + * @bat_priv: the bat priv with all the soft interface information 1458 + * @bucket: current bucket to dump 1459 + * @idx: index in current bucket to the next entry to dump 1460 + * 1461 + * Return: 0 or error code. 1462 + */ 1463 + static int 1464 + __batadv_mcast_flags_dump(struct sk_buff *msg, u32 portid, u32 seq, 1465 + struct batadv_priv *bat_priv, long *bucket, long *idx) 1466 + { 1467 + struct batadv_hashtable *hash = bat_priv->orig_hash; 1468 + long bucket_tmp = *bucket; 1469 + struct hlist_head *head; 1470 + long idx_tmp = *idx; 1471 + 1472 + while (bucket_tmp < hash->size) { 1473 + head = &hash->table[bucket_tmp]; 1474 + 1475 + if (batadv_mcast_flags_dump_bucket(msg, portid, seq, head, 1476 + &idx_tmp)) 1477 + break; 1478 + 1479 + bucket_tmp++; 1480 + idx_tmp = 0; 1481 + } 1482 + 1483 + *bucket = bucket_tmp; 1484 + *idx = idx_tmp; 1485 + 1486 + return msg->len; 1487 + } 1488 + 1489 + /** 1490 + * batadv_mcast_netlink_get_primary() - get primary interface from netlink 1491 + * callback 1492 + * @cb: netlink callback structure 1493 + * @primary_if: the primary interface pointer to return the result in 1494 + * 1495 + * Return: 0 or error code. 1496 + */ 1497 + static int 1498 + batadv_mcast_netlink_get_primary(struct netlink_callback *cb, 1499 + struct batadv_hard_iface **primary_if) 1500 + { 1501 + struct batadv_hard_iface *hard_iface = NULL; 1502 + struct net *net = sock_net(cb->skb->sk); 1503 + struct net_device *soft_iface; 1504 + struct batadv_priv *bat_priv; 1505 + int ifindex; 1506 + int ret = 0; 1507 + 1508 + ifindex = batadv_netlink_get_ifindex(cb->nlh, BATADV_ATTR_MESH_IFINDEX); 1509 + if (!ifindex) 1510 + return -EINVAL; 1511 + 1512 + soft_iface = dev_get_by_index(net, ifindex); 1513 + if (!soft_iface || !batadv_softif_is_valid(soft_iface)) { 1514 + ret = -ENODEV; 1515 + goto out; 1516 + } 1517 + 1518 + bat_priv = netdev_priv(soft_iface); 1519 + 1520 + hard_iface = batadv_primary_if_get_selected(bat_priv); 1521 + if (!hard_iface || hard_iface->if_status != BATADV_IF_ACTIVE) { 1522 + ret = -ENOENT; 1523 + goto out; 1524 + } 1525 + 1526 + out: 1527 + if (soft_iface) 1528 + dev_put(soft_iface); 1529 + 1530 + if (!ret && primary_if) 1531 + *primary_if = hard_iface; 1532 + else 1533 + batadv_hardif_put(hard_iface); 1534 + 1535 + return ret; 1536 + } 1537 + 1538 + /** 1539 + * batadv_mcast_flags_dump() - dump multicast flags table to a netlink socket 1540 + * @msg: buffer for the message 1541 + * @cb: callback structure containing arguments 1542 + * 1543 + * Return: message length. 1544 + */ 1545 + int batadv_mcast_flags_dump(struct sk_buff *msg, struct netlink_callback *cb) 1546 + { 1547 + struct batadv_hard_iface *primary_if = NULL; 1548 + int portid = NETLINK_CB(cb->skb).portid; 1549 + struct batadv_priv *bat_priv; 1550 + long *bucket = &cb->args[0]; 1551 + long *idx = &cb->args[1]; 1552 + int ret; 1553 + 1554 + ret = batadv_mcast_netlink_get_primary(cb, &primary_if); 1555 + if (ret) 1556 + return ret; 1557 + 1558 + bat_priv = netdev_priv(primary_if->soft_iface); 1559 + ret = __batadv_mcast_flags_dump(msg, portid, cb->nlh->nlmsg_seq, 1560 + bat_priv, bucket, idx); 1561 + 1562 + batadv_hardif_put(primary_if); 1563 + return ret; 1564 + } 1342 1565 1343 1566 /** 1344 1567 * batadv_mcast_free() - free the multicast optimizations structures
+18
net/batman-adv/multicast.h
··· 21 21 22 22 #include "main.h" 23 23 24 + struct netlink_callback; 24 25 struct seq_file; 25 26 struct sk_buff; 26 27 ··· 55 54 56 55 int batadv_mcast_flags_seq_print_text(struct seq_file *seq, void *offset); 57 56 57 + int batadv_mcast_mesh_info_put(struct sk_buff *msg, 58 + struct batadv_priv *bat_priv); 59 + 60 + int batadv_mcast_flags_dump(struct sk_buff *msg, struct netlink_callback *cb); 61 + 58 62 void batadv_mcast_free(struct batadv_priv *bat_priv); 59 63 60 64 void batadv_mcast_purge_orig(struct batadv_orig_node *orig_node); ··· 76 70 static inline int batadv_mcast_init(struct batadv_priv *bat_priv) 77 71 { 78 72 return 0; 73 + } 74 + 75 + static inline int 76 + batadv_mcast_mesh_info_put(struct sk_buff *msg, struct batadv_priv *bat_priv) 77 + { 78 + return 0; 79 + } 80 + 81 + static inline int batadv_mcast_flags_dump(struct sk_buff *msg, 82 + struct netlink_callback *cb) 83 + { 84 + return -EOPNOTSUPP; 79 85 } 80 86 81 87 static inline void batadv_mcast_free(struct batadv_priv *bat_priv)
+12
net/batman-adv/netlink.c
··· 48 48 #include "distributed-arp-table.h" 49 49 #include "gateway_client.h" 50 50 #include "hard-interface.h" 51 + #include "multicast.h" 51 52 #include "originator.h" 52 53 #include "soft-interface.h" 53 54 #include "tp_meter.h" ··· 102 101 [BATADV_ATTR_DAT_CACHE_IP4ADDRESS] = { .type = NLA_U32 }, 103 102 [BATADV_ATTR_DAT_CACHE_HWADDRESS] = { .len = ETH_ALEN }, 104 103 [BATADV_ATTR_DAT_CACHE_VID] = { .type = NLA_U16 }, 104 + [BATADV_ATTR_MCAST_FLAGS] = { .type = NLA_U32 }, 105 + [BATADV_ATTR_MCAST_FLAGS_PRIV] = { .type = NLA_U32 }, 105 106 }; 106 107 107 108 /** ··· 153 150 ntohs(bat_priv->bla.claim_dest.group))) 154 151 goto out; 155 152 #endif 153 + 154 + if (batadv_mcast_mesh_info_put(msg, bat_priv)) 155 + goto out; 156 156 157 157 primary_if = batadv_primary_if_get_selected(bat_priv); 158 158 if (primary_if && primary_if->if_status == BATADV_IF_ACTIVE) { ··· 619 613 .flags = GENL_ADMIN_PERM, 620 614 .policy = batadv_netlink_policy, 621 615 .dumpit = batadv_dat_cache_dump, 616 + }, 617 + { 618 + .cmd = BATADV_CMD_GET_MCAST_FLAGS, 619 + .flags = GENL_ADMIN_PERM, 620 + .policy = batadv_netlink_policy, 621 + .dumpit = batadv_mcast_flags_dump, 622 622 }, 623 623 624 624 };