tunnels.c (0ea460474d70d809eac0640c1cf408ec54e23966) tunnels.c (966e50597666d530b69de2abb9c83ff0a9bd3ee6)
1// SPDX-License-Identifier: GPL-2.0-only
2
3#include <linux/ethtool_netlink.h>
4#include <net/udp_tunnel.h>
1// SPDX-License-Identifier: GPL-2.0-only
2
3#include <linux/ethtool_netlink.h>
4#include <net/udp_tunnel.h>
5#include <net/vxlan.h>
5
6#include "bitset.h"
7#include "common.h"
8#include "netlink.h"
9
10static const struct nla_policy
11ethtool_tunnel_info_policy[ETHTOOL_A_TUNNEL_INFO_MAX + 1] = {
12 [ETHTOOL_A_TUNNEL_INFO_UNSPEC] = { .type = NLA_REJECT },
13 [ETHTOOL_A_TUNNEL_INFO_HEADER] = { .type = NLA_NESTED },
14};
15
16static_assert(ETHTOOL_UDP_TUNNEL_TYPE_VXLAN == ilog2(UDP_TUNNEL_TYPE_VXLAN));
17static_assert(ETHTOOL_UDP_TUNNEL_TYPE_GENEVE == ilog2(UDP_TUNNEL_TYPE_GENEVE));
18static_assert(ETHTOOL_UDP_TUNNEL_TYPE_VXLAN_GPE ==
19 ilog2(UDP_TUNNEL_TYPE_VXLAN_GPE));
20
6
7#include "bitset.h"
8#include "common.h"
9#include "netlink.h"
10
11static const struct nla_policy
12ethtool_tunnel_info_policy[ETHTOOL_A_TUNNEL_INFO_MAX + 1] = {
13 [ETHTOOL_A_TUNNEL_INFO_UNSPEC] = { .type = NLA_REJECT },
14 [ETHTOOL_A_TUNNEL_INFO_HEADER] = { .type = NLA_NESTED },
15};
16
17static_assert(ETHTOOL_UDP_TUNNEL_TYPE_VXLAN == ilog2(UDP_TUNNEL_TYPE_VXLAN));
18static_assert(ETHTOOL_UDP_TUNNEL_TYPE_GENEVE == ilog2(UDP_TUNNEL_TYPE_GENEVE));
19static_assert(ETHTOOL_UDP_TUNNEL_TYPE_VXLAN_GPE ==
20 ilog2(UDP_TUNNEL_TYPE_VXLAN_GPE));
21
22static ssize_t ethnl_udp_table_reply_size(unsigned int types, bool compact)
23{
24 ssize_t size;
25
26 size = ethnl_bitset32_size(&types, NULL, __ETHTOOL_UDP_TUNNEL_TYPE_CNT,
27 udp_tunnel_type_names, compact);
28 if (size < 0)
29 return size;
30
31 return size +
32 nla_total_size(0) + /* _UDP_TABLE */
33 nla_total_size(sizeof(u32)); /* _UDP_TABLE_SIZE */
34}
35
21static ssize_t
22ethnl_tunnel_info_reply_size(const struct ethnl_req_info *req_base,
23 struct netlink_ext_ack *extack)
24{
25 bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
26 const struct udp_tunnel_nic_info *info;
27 unsigned int i;
36static ssize_t
37ethnl_tunnel_info_reply_size(const struct ethnl_req_info *req_base,
38 struct netlink_ext_ack *extack)
39{
40 bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
41 const struct udp_tunnel_nic_info *info;
42 unsigned int i;
43 ssize_t ret;
28 size_t size;
44 size_t size;
29 int ret;
30
31 info = req_base->dev->udp_tunnel_nic_info;
32 if (!info) {
33 NL_SET_ERR_MSG(extack,
34 "device does not report tunnel offload info");
35 return -EOPNOTSUPP;
36 }
37
38 size = nla_total_size(0); /* _INFO_UDP_PORTS */
39
40 for (i = 0; i < UDP_TUNNEL_NIC_MAX_TABLES; i++) {
41 if (!info->tables[i].n_entries)
45
46 info = req_base->dev->udp_tunnel_nic_info;
47 if (!info) {
48 NL_SET_ERR_MSG(extack,
49 "device does not report tunnel offload info");
50 return -EOPNOTSUPP;
51 }
52
53 size = nla_total_size(0); /* _INFO_UDP_PORTS */
54
55 for (i = 0; i < UDP_TUNNEL_NIC_MAX_TABLES; i++) {
56 if (!info->tables[i].n_entries)
42 return size;
57 break;
43
58
44 size += nla_total_size(0); /* _UDP_TABLE */
45 size += nla_total_size(sizeof(u32)); /* _UDP_TABLE_SIZE */
46 ret = ethnl_bitset32_size(&info->tables[i].tunnel_types, NULL,
47 __ETHTOOL_UDP_TUNNEL_TYPE_CNT,
48 udp_tunnel_type_names, compact);
59 ret = ethnl_udp_table_reply_size(info->tables[i].tunnel_types,
60 compact);
49 if (ret < 0)
50 return ret;
51 size += ret;
52
53 size += udp_tunnel_nic_dump_size(req_base->dev, i);
54 }
55
61 if (ret < 0)
62 return ret;
63 size += ret;
64
65 size += udp_tunnel_nic_dump_size(req_base->dev, i);
66 }
67
68 if (info->flags & UDP_TUNNEL_NIC_INFO_STATIC_IANA_VXLAN) {
69 ret = ethnl_udp_table_reply_size(0, compact);
70 if (ret < 0)
71 return ret;
72 size += ret;
73
74 size += nla_total_size(0) + /* _TABLE_ENTRY */
75 nla_total_size(sizeof(__be16)) + /* _ENTRY_PORT */
76 nla_total_size(sizeof(u32)); /* _ENTRY_TYPE */
77 }
78
56 return size;
57}
58
59static int
60ethnl_tunnel_info_fill_reply(const struct ethnl_req_info *req_base,
61 struct sk_buff *skb)
62{
63 bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
64 const struct udp_tunnel_nic_info *info;
79 return size;
80}
81
82static int
83ethnl_tunnel_info_fill_reply(const struct ethnl_req_info *req_base,
84 struct sk_buff *skb)
85{
86 bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
87 const struct udp_tunnel_nic_info *info;
65 struct nlattr *ports, *table;
88 struct nlattr *ports, *table, *entry;
66 unsigned int i;
67
68 info = req_base->dev->udp_tunnel_nic_info;
69 if (!info)
70 return -EOPNOTSUPP;
71
72 ports = nla_nest_start(skb, ETHTOOL_A_TUNNEL_INFO_UDP_PORTS);
73 if (!ports)

--- 18 unchanged lines hidden (view full) ---

92 goto err_cancel_table;
93
94 if (udp_tunnel_nic_dump_write(req_base->dev, i, skb))
95 goto err_cancel_table;
96
97 nla_nest_end(skb, table);
98 }
99
89 unsigned int i;
90
91 info = req_base->dev->udp_tunnel_nic_info;
92 if (!info)
93 return -EOPNOTSUPP;
94
95 ports = nla_nest_start(skb, ETHTOOL_A_TUNNEL_INFO_UDP_PORTS);
96 if (!ports)

--- 18 unchanged lines hidden (view full) ---

115 goto err_cancel_table;
116
117 if (udp_tunnel_nic_dump_write(req_base->dev, i, skb))
118 goto err_cancel_table;
119
120 nla_nest_end(skb, table);
121 }
122
123 if (info->flags & UDP_TUNNEL_NIC_INFO_STATIC_IANA_VXLAN) {
124 u32 zero = 0;
125
126 table = nla_nest_start(skb, ETHTOOL_A_TUNNEL_UDP_TABLE);
127 if (!table)
128 goto err_cancel_ports;
129
130 if (nla_put_u32(skb, ETHTOOL_A_TUNNEL_UDP_TABLE_SIZE, 1))
131 goto err_cancel_table;
132
133 if (ethnl_put_bitset32(skb, ETHTOOL_A_TUNNEL_UDP_TABLE_TYPES,
134 &zero, NULL,
135 __ETHTOOL_UDP_TUNNEL_TYPE_CNT,
136 udp_tunnel_type_names, compact))
137 goto err_cancel_table;
138
139 entry = nla_nest_start(skb, ETHTOOL_A_TUNNEL_UDP_TABLE_ENTRY);
140
141 if (nla_put_be16(skb, ETHTOOL_A_TUNNEL_UDP_ENTRY_PORT,
142 htons(IANA_VXLAN_UDP_PORT)) ||
143 nla_put_u32(skb, ETHTOOL_A_TUNNEL_UDP_ENTRY_TYPE,
144 ilog2(UDP_TUNNEL_TYPE_VXLAN)))
145 goto err_cancel_entry;
146
147 nla_nest_end(skb, entry);
148 nla_nest_end(skb, table);
149 }
150
100 nla_nest_end(skb, ports);
101
102 return 0;
103
151 nla_nest_end(skb, ports);
152
153 return 0;
154
155err_cancel_entry:
156 nla_nest_cancel(skb, entry);
104err_cancel_table:
105 nla_nest_cancel(skb, table);
106err_cancel_ports:
107 nla_nest_cancel(skb, ports);
108 return -EMSGSIZE;
109}
110
111static int

--- 148 unchanged lines hidden ---
157err_cancel_table:
158 nla_nest_cancel(skb, table);
159err_cancel_ports:
160 nla_nest_cancel(skb, ports);
161 return -EMSGSIZE;
162}
163
164static int

--- 148 unchanged lines hidden ---