^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #include <linux/ethtool_netlink.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #include <net/udp_tunnel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <net/vxlan.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include "bitset.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include "common.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include "netlink.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) const struct nla_policy ethnl_tunnel_info_get_policy[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) [ETHTOOL_A_TUNNEL_INFO_HEADER] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) NLA_POLICY_NESTED(ethnl_header_policy),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) static_assert(ETHTOOL_UDP_TUNNEL_TYPE_VXLAN == ilog2(UDP_TUNNEL_TYPE_VXLAN));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) static_assert(ETHTOOL_UDP_TUNNEL_TYPE_GENEVE == ilog2(UDP_TUNNEL_TYPE_GENEVE));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) static_assert(ETHTOOL_UDP_TUNNEL_TYPE_VXLAN_GPE ==
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) ilog2(UDP_TUNNEL_TYPE_VXLAN_GPE));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) static ssize_t ethnl_udp_table_reply_size(unsigned int types, bool compact)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) ssize_t size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) size = ethnl_bitset32_size(&types, NULL, __ETHTOOL_UDP_TUNNEL_TYPE_CNT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) udp_tunnel_type_names, compact);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) if (size < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) return size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) return size +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) nla_total_size(0) + /* _UDP_TABLE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) nla_total_size(sizeof(u32)); /* _UDP_TABLE_SIZE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) static ssize_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) ethnl_tunnel_info_reply_size(const struct ethnl_req_info *req_base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) struct netlink_ext_ack *extack)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) const struct udp_tunnel_nic_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) ssize_t ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) size_t size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) info = req_base->dev->udp_tunnel_nic_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) if (!info) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) NL_SET_ERR_MSG(extack,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) "device does not report tunnel offload info");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) size = nla_total_size(0); /* _INFO_UDP_PORTS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) for (i = 0; i < UDP_TUNNEL_NIC_MAX_TABLES; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) if (!info->tables[i].n_entries)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) ret = ethnl_udp_table_reply_size(info->tables[i].tunnel_types,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) compact);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) size += ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) size += udp_tunnel_nic_dump_size(req_base->dev, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) if (info->flags & UDP_TUNNEL_NIC_INFO_STATIC_IANA_VXLAN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) ret = ethnl_udp_table_reply_size(0, compact);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) size += ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) size += nla_total_size(0) + /* _TABLE_ENTRY */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) nla_total_size(sizeof(__be16)) + /* _ENTRY_PORT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) nla_total_size(sizeof(u32)); /* _ENTRY_TYPE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) return size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) ethnl_tunnel_info_fill_reply(const struct ethnl_req_info *req_base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) struct sk_buff *skb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) const struct udp_tunnel_nic_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) struct nlattr *ports, *table, *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) info = req_base->dev->udp_tunnel_nic_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) if (!info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) ports = nla_nest_start(skb, ETHTOOL_A_TUNNEL_INFO_UDP_PORTS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) if (!ports)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) return -EMSGSIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) for (i = 0; i < UDP_TUNNEL_NIC_MAX_TABLES; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) if (!info->tables[i].n_entries)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) table = nla_nest_start(skb, ETHTOOL_A_TUNNEL_UDP_TABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) if (!table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) goto err_cancel_ports;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) if (nla_put_u32(skb, ETHTOOL_A_TUNNEL_UDP_TABLE_SIZE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) info->tables[i].n_entries))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) goto err_cancel_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) if (ethnl_put_bitset32(skb, ETHTOOL_A_TUNNEL_UDP_TABLE_TYPES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) &info->tables[i].tunnel_types, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) __ETHTOOL_UDP_TUNNEL_TYPE_CNT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) udp_tunnel_type_names, compact))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) goto err_cancel_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) if (udp_tunnel_nic_dump_write(req_base->dev, i, skb))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) goto err_cancel_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) nla_nest_end(skb, table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) if (info->flags & UDP_TUNNEL_NIC_INFO_STATIC_IANA_VXLAN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) u32 zero = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) table = nla_nest_start(skb, ETHTOOL_A_TUNNEL_UDP_TABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) if (!table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) goto err_cancel_ports;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) if (nla_put_u32(skb, ETHTOOL_A_TUNNEL_UDP_TABLE_SIZE, 1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) goto err_cancel_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) if (ethnl_put_bitset32(skb, ETHTOOL_A_TUNNEL_UDP_TABLE_TYPES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) &zero, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) __ETHTOOL_UDP_TUNNEL_TYPE_CNT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) udp_tunnel_type_names, compact))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) goto err_cancel_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) entry = nla_nest_start(skb, ETHTOOL_A_TUNNEL_UDP_TABLE_ENTRY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) if (nla_put_be16(skb, ETHTOOL_A_TUNNEL_UDP_ENTRY_PORT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) htons(IANA_VXLAN_UDP_PORT)) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) nla_put_u32(skb, ETHTOOL_A_TUNNEL_UDP_ENTRY_TYPE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) ilog2(UDP_TUNNEL_TYPE_VXLAN)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) goto err_cancel_entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) nla_nest_end(skb, entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) nla_nest_end(skb, table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) nla_nest_end(skb, ports);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) err_cancel_entry:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) nla_nest_cancel(skb, entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) err_cancel_table:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) nla_nest_cancel(skb, table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) err_cancel_ports:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) nla_nest_cancel(skb, ports);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) return -EMSGSIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) int ethnl_tunnel_info_doit(struct sk_buff *skb, struct genl_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) struct ethnl_req_info req_info = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) struct nlattr **tb = info->attrs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) struct sk_buff *rskb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) void *reply_payload;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) int reply_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) ret = ethnl_parse_header_dev_get(&req_info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) tb[ETHTOOL_A_TUNNEL_INFO_HEADER],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) genl_info_net(info), info->extack,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) rtnl_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) ret = ethnl_tunnel_info_reply_size(&req_info, info->extack);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) goto err_unlock_rtnl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) reply_len = ret + ethnl_reply_header_size();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) rskb = ethnl_reply_init(reply_len, req_info.dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) ETHTOOL_MSG_TUNNEL_INFO_GET_REPLY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) ETHTOOL_A_TUNNEL_INFO_HEADER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) info, &reply_payload);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) if (!rskb) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) goto err_unlock_rtnl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) ret = ethnl_tunnel_info_fill_reply(&req_info, rskb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) goto err_free_msg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) rtnl_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) dev_put(req_info.dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) genlmsg_end(rskb, reply_payload);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) return genlmsg_reply(rskb, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) err_free_msg:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) nlmsg_free(rskb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) err_unlock_rtnl:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) rtnl_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) dev_put(req_info.dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) struct ethnl_tunnel_info_dump_ctx {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) struct ethnl_req_info req_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) int pos_hash;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) int pos_idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) int ethnl_tunnel_info_start(struct netlink_callback *cb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) const struct genl_dumpit_info *info = genl_dumpit_info(cb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) struct ethnl_tunnel_info_dump_ctx *ctx = (void *)cb->ctx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) struct nlattr **tb = info->attrs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) BUILD_BUG_ON(sizeof(*ctx) > sizeof(cb->ctx));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) memset(ctx, 0, sizeof(*ctx));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) ret = ethnl_parse_header_dev_get(&ctx->req_info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) tb[ETHTOOL_A_TUNNEL_INFO_HEADER],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) sock_net(cb->skb->sk), cb->extack,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) if (ctx->req_info.dev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) dev_put(ctx->req_info.dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) ctx->req_info.dev = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) int ethnl_tunnel_info_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) struct ethnl_tunnel_info_dump_ctx *ctx = (void *)cb->ctx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) struct net *net = sock_net(skb->sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) int s_idx = ctx->pos_idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) int h, idx = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) void *ehdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) rtnl_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) cb->seq = net->dev_base_seq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) for (h = ctx->pos_hash; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) struct hlist_head *head;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) struct net_device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) head = &net->dev_index_head[h];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) idx = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) hlist_for_each_entry(dev, head, index_hlist) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) if (idx < s_idx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) goto cont;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) ehdr = ethnl_dump_put(skb, cb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) ETHTOOL_MSG_TUNNEL_INFO_GET_REPLY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) if (!ehdr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) ret = -EMSGSIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) ret = ethnl_fill_reply_header(skb, dev, ETHTOOL_A_TUNNEL_INFO_HEADER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) genlmsg_cancel(skb, ehdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) ctx->req_info.dev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) ret = ethnl_tunnel_info_fill_reply(&ctx->req_info, skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) ctx->req_info.dev = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) genlmsg_cancel(skb, ehdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) if (ret == -EOPNOTSUPP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) goto cont;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) genlmsg_end(skb, ehdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) cont:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) idx++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) rtnl_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) ctx->pos_hash = h;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) ctx->pos_idx = idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) nl_dump_check_consistent(cb, nlmsg_hdr(skb));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) if (ret == -EMSGSIZE && skb->len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) return skb->len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) }