• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3  * Copyright (c) 2013 Yasunobu Chiba <yasu@dsl.gr.jp>
4  */
5 
6 /**
7  * @ingroup link
8  * @defgroup vxlan VXLAN
9  * Virtual eXtensible Local Area Network link module
10  *
11  * @details
12  * \b Link Type Name: "vxlan"
13  *
14  * @route_doc{link_vxlan, VXLAN Documentation}
15  *
16  * @{
17  */
18 
19 #include <netlink-private/netlink.h>
20 #include <netlink/netlink.h>
21 #include <netlink/attr.h>
22 #include <netlink/utils.h>
23 #include <netlink/object.h>
24 #include <netlink/route/rtnl.h>
25 #include <netlink-private/route/link/api.h>
26 #include <netlink/route/link/vxlan.h>
27 
28 #include <linux/if_link.h>
29 
30 /** @cond SKIP */
31 #define VXLAN_ATTR_ID                  (1<<0)
32 #define VXLAN_ATTR_GROUP               (1<<1)
33 #define VXLAN_ATTR_LINK                (1<<2)
34 #define VXLAN_ATTR_LOCAL               (1<<3)
35 #define VXLAN_ATTR_TTL                 (1<<4)
36 #define VXLAN_ATTR_TOS                 (1<<5)
37 #define VXLAN_ATTR_LEARNING            (1<<6)
38 #define VXLAN_ATTR_AGEING              (1<<7)
39 #define VXLAN_ATTR_LIMIT               (1<<8)
40 #define VXLAN_ATTR_PORT_RANGE          (1<<9)
41 #define VXLAN_ATTR_PROXY               (1<<10)
42 #define VXLAN_ATTR_RSC                 (1<<11)
43 #define VXLAN_ATTR_L2MISS              (1<<12)
44 #define VXLAN_ATTR_L3MISS              (1<<13)
45 #define VXLAN_ATTR_GROUP6              (1<<14)
46 #define VXLAN_ATTR_LOCAL6              (1<<15)
47 #define VXLAN_ATTR_PORT                (1<<16)
48 #define VXLAN_ATTR_UDP_CSUM            (1<<17)
49 #define VXLAN_ATTR_UDP_ZERO_CSUM6_TX   (1<<18)
50 #define VXLAN_ATTR_UDP_ZERO_CSUM6_RX   (1<<19)
51 #define VXLAN_ATTR_REMCSUM_TX          (1<<20)
52 #define VXLAN_ATTR_REMCSUM_RX          (1<<21)
53 #define VXLAN_ATTR_COLLECT_METADATA    (1<<22)
54 #define VXLAN_ATTR_LABEL               (1<<23)
55 #define VXLAN_ATTR_FLAGS               (1<<24)
56 
57 struct vxlan_info
58 {
59 	uint32_t		vxi_id;
60 	uint32_t		vxi_group;
61 	struct in6_addr		vxi_group6;
62 	uint32_t		vxi_link;
63 	uint32_t		vxi_local;
64 	struct in6_addr		vxi_local6;
65 	uint8_t			vxi_ttl;
66 	uint8_t			vxi_tos;
67 	uint8_t			vxi_learning;
68 	uint8_t			vxi_flags;
69 	uint32_t		vxi_ageing;
70 	uint32_t		vxi_limit;
71 	struct ifla_vxlan_port_range	vxi_port_range;
72 	uint8_t			vxi_proxy;
73 	uint8_t			vxi_rsc;
74 	uint8_t			vxi_l2miss;
75 	uint8_t			vxi_l3miss;
76 	uint16_t		vxi_port;
77 	uint8_t			vxi_udp_csum;
78 	uint8_t			vxi_udp_zero_csum6_tx;
79 	uint8_t			vxi_udp_zero_csum6_rx;
80 	uint8_t			vxi_remcsum_tx;
81 	uint8_t			vxi_remcsum_rx;
82 	uint8_t			vxi_collect_metadata;
83 	uint32_t		vxi_label;
84 	uint32_t		ce_mask;
85 };
86 
87 /** @endcond */
88 
89 static struct nla_policy vxlan_policy[IFLA_VXLAN_MAX+1] = {
90 	[IFLA_VXLAN_ID] = { .type = NLA_U32 },
91 	[IFLA_VXLAN_GROUP] = { .minlen = sizeof(uint32_t) },
92 	[IFLA_VXLAN_GROUP6] = { .minlen = sizeof(struct in6_addr) },
93 	[IFLA_VXLAN_LINK] = { .type = NLA_U32 },
94 	[IFLA_VXLAN_LOCAL] = { .minlen = sizeof(uint32_t) },
95 	[IFLA_VXLAN_LOCAL6] = { .minlen = sizeof(struct in6_addr) },
96 	[IFLA_VXLAN_TTL] = { .type = NLA_U8 },
97 	[IFLA_VXLAN_TOS] = { .type = NLA_U8 },
98 	[IFLA_VXLAN_LABEL] = { .type = NLA_U32 },
99 	[IFLA_VXLAN_LEARNING] = { .type = NLA_U8 },
100 	[IFLA_VXLAN_AGEING] = { .type = NLA_U32 },
101 	[IFLA_VXLAN_LIMIT] = { .type = NLA_U32 },
102 	[IFLA_VXLAN_PORT_RANGE] = { .minlen = sizeof(struct ifla_vxlan_port_range) },
103 	[IFLA_VXLAN_PROXY] = { .type = NLA_U8 },
104 	[IFLA_VXLAN_RSC] = { .type = NLA_U8 },
105 	[IFLA_VXLAN_L2MISS] = { .type = NLA_U8 },
106 	[IFLA_VXLAN_L3MISS] = { .type = NLA_U8 },
107 	[IFLA_VXLAN_COLLECT_METADATA] = { .type = NLA_U8 },
108 	[IFLA_VXLAN_PORT] = { .type = NLA_U16 },
109 	[IFLA_VXLAN_UDP_CSUM] = { .type = NLA_U8 },
110 	[IFLA_VXLAN_UDP_ZERO_CSUM6_TX] = { .type = NLA_U8 },
111 	[IFLA_VXLAN_UDP_ZERO_CSUM6_RX] = { .type = NLA_U8 },
112 	[IFLA_VXLAN_REMCSUM_TX] = { .type = NLA_U8 },
113 	[IFLA_VXLAN_REMCSUM_RX] = { .type = NLA_U8 },
114 	[IFLA_VXLAN_GBP] = { .type = NLA_FLAG, },
115 	[IFLA_VXLAN_GPE] = { .type = NLA_FLAG, },
116 	[IFLA_VXLAN_REMCSUM_NOPARTIAL] = { .type = NLA_FLAG },
117 };
118 
vxlan_alloc(struct rtnl_link * link)119 static int vxlan_alloc(struct rtnl_link *link)
120 {
121 	struct vxlan_info *vxi;
122 
123 	if (link->l_info)
124 		memset(link->l_info, 0, sizeof(*vxi));
125 	else {
126 		if ((vxi = calloc(1, sizeof(*vxi))) == NULL)
127 			return -NLE_NOMEM;
128 
129 		link->l_info = vxi;
130 	}
131 
132 	return 0;
133 }
134 
vxlan_parse(struct rtnl_link * link,struct nlattr * data,struct nlattr * xstats)135 static int vxlan_parse(struct rtnl_link *link, struct nlattr *data,
136 		      struct nlattr *xstats)
137 {
138 	struct nlattr *tb[IFLA_VXLAN_MAX+1];
139 	struct vxlan_info *vxi;
140 	int err;
141 
142 	NL_DBG(3, "Parsing VXLAN link info\n");
143 
144 	if ((err = nla_parse_nested(tb, IFLA_VXLAN_MAX, data, vxlan_policy)) < 0)
145 		goto errout;
146 
147 	if ((err = vxlan_alloc(link)) < 0)
148 		goto errout;
149 
150 	vxi = link->l_info;
151 
152 	if (tb[IFLA_VXLAN_ID]) {
153 		vxi->vxi_id = nla_get_u32(tb[IFLA_VXLAN_ID]);
154 		vxi->ce_mask |= VXLAN_ATTR_ID;
155 	}
156 
157 	if (tb[IFLA_VXLAN_GROUP6]) {
158 		nla_memcpy(&vxi->vxi_group6, tb[IFLA_VXLAN_GROUP6],
159 			   sizeof(vxi->vxi_group6));
160 		vxi->ce_mask |= VXLAN_ATTR_GROUP6;
161 	}
162 
163 	if (tb[IFLA_VXLAN_GROUP]) {
164 		nla_memcpy(&vxi->vxi_group, tb[IFLA_VXLAN_GROUP],
165 				   sizeof(vxi->vxi_group));
166 		vxi->ce_mask |= VXLAN_ATTR_GROUP;
167 		vxi->ce_mask &= ~VXLAN_ATTR_GROUP6;
168 	}
169 
170 	if (tb[IFLA_VXLAN_LINK]) {
171 		vxi->vxi_link = nla_get_u32(tb[IFLA_VXLAN_LINK]);
172 		vxi->ce_mask |= VXLAN_ATTR_LINK;
173 	}
174 
175 	if (tb[IFLA_VXLAN_LOCAL6]) {
176 		nla_memcpy(&vxi->vxi_local6, tb[IFLA_VXLAN_LOCAL6],
177 			   sizeof(vxi->vxi_local6));
178 		vxi->ce_mask |= VXLAN_ATTR_LOCAL6;
179 	}
180 
181 	if (tb[IFLA_VXLAN_LOCAL]) {
182 		nla_memcpy(&vxi->vxi_local, tb[IFLA_VXLAN_LOCAL],
183 				   sizeof(vxi->vxi_local));
184 		vxi->ce_mask |= VXLAN_ATTR_LOCAL;
185 		vxi->ce_mask &= ~VXLAN_ATTR_LOCAL6;
186 	}
187 
188 	if (tb[IFLA_VXLAN_TTL]) {
189 		vxi->vxi_ttl = nla_get_u8(tb[IFLA_VXLAN_TTL]);
190 		vxi->ce_mask |= VXLAN_ATTR_TTL;
191 	}
192 
193 	if (tb[IFLA_VXLAN_TOS]) {
194 		vxi->vxi_tos = nla_get_u8(tb[IFLA_VXLAN_TOS]);
195 		vxi->ce_mask |= VXLAN_ATTR_TOS;
196 	}
197 
198 	if (tb[IFLA_VXLAN_LEARNING]) {
199 		vxi->vxi_learning = nla_get_u8(tb[IFLA_VXLAN_LEARNING]);
200 		vxi->ce_mask |= VXLAN_ATTR_LEARNING;
201 	}
202 
203 	if (tb[IFLA_VXLAN_AGEING]) {
204 		vxi->vxi_ageing = nla_get_u32(tb[IFLA_VXLAN_AGEING]);
205 		vxi->ce_mask |= VXLAN_ATTR_AGEING;
206 	}
207 
208 	if (tb[IFLA_VXLAN_LIMIT]) {
209 		vxi->vxi_limit = nla_get_u32(tb[IFLA_VXLAN_LIMIT]);
210 		vxi->ce_mask |= VXLAN_ATTR_LIMIT;
211 	}
212 
213 	if (tb[IFLA_VXLAN_PORT_RANGE]) {
214 		nla_memcpy(&vxi->vxi_port_range, tb[IFLA_VXLAN_PORT_RANGE],
215 				   sizeof(vxi->vxi_port_range));
216 		vxi->ce_mask |= VXLAN_ATTR_PORT_RANGE;
217 	}
218 
219 	if (tb[IFLA_VXLAN_PROXY]) {
220 		vxi->vxi_proxy = nla_get_u8(tb[IFLA_VXLAN_PROXY]);
221 		vxi->ce_mask |= VXLAN_ATTR_PROXY;
222 	}
223 
224 	if (tb[IFLA_VXLAN_RSC]) {
225 		vxi->vxi_rsc = nla_get_u8(tb[IFLA_VXLAN_RSC]);
226 		vxi->ce_mask |= VXLAN_ATTR_RSC;
227 	}
228 
229 	if (tb[IFLA_VXLAN_L2MISS]) {
230 		vxi->vxi_l2miss = nla_get_u8(tb[IFLA_VXLAN_L2MISS]);
231 		vxi->ce_mask |= VXLAN_ATTR_L2MISS;
232 	}
233 
234 	if (tb[IFLA_VXLAN_L3MISS]) {
235 		vxi->vxi_l3miss = nla_get_u8(tb[IFLA_VXLAN_L3MISS]);
236 		vxi->ce_mask |= VXLAN_ATTR_L3MISS;
237 	}
238 
239 	if (tb[IFLA_VXLAN_PORT]) {
240 		vxi->vxi_port = nla_get_u16(tb[IFLA_VXLAN_PORT]);
241 		vxi->ce_mask |= VXLAN_ATTR_PORT;
242 	}
243 
244 	if (tb[IFLA_VXLAN_UDP_CSUM]) {
245 		vxi->vxi_udp_csum = nla_get_u8(tb[IFLA_VXLAN_UDP_CSUM]);
246 		vxi->ce_mask |= VXLAN_ATTR_UDP_CSUM;
247 	}
248 
249 	if (tb[IFLA_VXLAN_UDP_ZERO_CSUM6_TX]) {
250 		vxi->vxi_udp_zero_csum6_tx = nla_get_u8(tb[IFLA_VXLAN_UDP_ZERO_CSUM6_TX]);
251 		vxi->ce_mask |= VXLAN_ATTR_UDP_ZERO_CSUM6_TX;
252 	}
253 
254 	if (tb[IFLA_VXLAN_UDP_ZERO_CSUM6_RX]) {
255 		vxi->vxi_udp_zero_csum6_rx = nla_get_u8(tb[IFLA_VXLAN_UDP_ZERO_CSUM6_RX]);
256 		vxi->ce_mask |= VXLAN_ATTR_UDP_ZERO_CSUM6_RX;
257 	}
258 
259 	if (tb[IFLA_VXLAN_REMCSUM_TX]) {
260 		vxi->vxi_remcsum_tx = nla_get_u8(tb[IFLA_VXLAN_REMCSUM_TX]);
261 		vxi->ce_mask |= VXLAN_ATTR_REMCSUM_TX;
262 	}
263 
264 	if (tb[IFLA_VXLAN_REMCSUM_RX]) {
265 		vxi->vxi_remcsum_rx = nla_get_u8(tb[IFLA_VXLAN_REMCSUM_RX]);
266 		vxi->ce_mask |= VXLAN_ATTR_REMCSUM_RX;
267 	}
268 
269 	if (tb[IFLA_VXLAN_GBP])
270 		vxi->vxi_flags |= RTNL_LINK_VXLAN_F_GBP;
271 
272 	if (tb[IFLA_VXLAN_REMCSUM_NOPARTIAL])
273 		vxi->vxi_flags |= RTNL_LINK_VXLAN_F_REMCSUM_NOPARTIAL;
274 
275 	if (tb[IFLA_VXLAN_COLLECT_METADATA]) {
276 		vxi->vxi_collect_metadata = nla_get_u8(tb[IFLA_VXLAN_COLLECT_METADATA]);
277 		vxi->ce_mask |= VXLAN_ATTR_COLLECT_METADATA;
278 	}
279 
280 	if (tb[IFLA_VXLAN_LABEL]) {
281 		vxi->vxi_label = nla_get_u32(tb[IFLA_VXLAN_LABEL]);
282 		vxi->ce_mask |= VXLAN_ATTR_LABEL;
283 	}
284 
285 	if (tb[IFLA_VXLAN_GPE])
286 		vxi->vxi_flags |= RTNL_LINK_VXLAN_F_GPE;
287 
288 	err = 0;
289 
290 errout:
291 	return err;
292 }
293 
vxlan_free(struct rtnl_link * link)294 static void vxlan_free(struct rtnl_link *link)
295 {
296 	struct vxlan_info *vxi = link->l_info;
297 
298 	free(vxi);
299 	link->l_info = NULL;
300 }
301 
vxlan_dump_line(struct rtnl_link * link,struct nl_dump_params * p)302 static void vxlan_dump_line(struct rtnl_link *link, struct nl_dump_params *p)
303 {
304 	struct vxlan_info *vxi = link->l_info;
305 
306 	nl_dump(p, "vxlan-id %u", vxi->vxi_id);
307 }
308 
vxlan_dump_details(struct rtnl_link * link,struct nl_dump_params * p)309 static void vxlan_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
310 {
311 	struct vxlan_info *vxi = link->l_info;
312 	char *name, addr[INET6_ADDRSTRLEN];
313 	struct rtnl_link *parent;
314 
315 	nl_dump_line(p, "    vxlan-id %u\n", vxi->vxi_id);
316 
317 	if (vxi->ce_mask & VXLAN_ATTR_GROUP) {
318 		nl_dump(p, "      group ");
319 		nl_dump_line(p, "%s\n",
320 			     _nl_inet_ntop(AF_INET, &vxi->vxi_group, addr));
321 	} else if (vxi->ce_mask & VXLAN_ATTR_GROUP6) {
322 		nl_dump(p, "      group ");
323 		nl_dump_line(p, "%s\n",
324 			     _nl_inet_ntop(AF_INET6, &vxi->vxi_group6, addr));
325 	}
326 
327 	if (vxi->ce_mask & VXLAN_ATTR_LINK) {
328 		nl_dump(p, "      link ");
329 
330 		name = NULL;
331 		parent = link_lookup(link->ce_cache, vxi->vxi_link);
332 		if (parent)
333 			name = rtnl_link_get_name(parent);
334 
335 		if (name)
336 			nl_dump_line(p, "%s\n", name);
337 		else
338 			nl_dump_line(p, "%u\n", vxi->vxi_link);
339 	}
340 
341 	if (vxi->ce_mask & VXLAN_ATTR_LOCAL) {
342 		nl_dump(p, "      local ");
343 		nl_dump_line(p, "%s\n",
344 			     _nl_inet_ntop(AF_INET, &vxi->vxi_local, addr));
345 	} else if (vxi->ce_mask & VXLAN_ATTR_LOCAL6) {
346 		nl_dump(p, "      local ");
347 		nl_dump_line(p, "%s\n",
348 			     _nl_inet_ntop(AF_INET6, &vxi->vxi_local6, addr));
349 	}
350 
351 	if (vxi->ce_mask & VXLAN_ATTR_TTL) {
352 		nl_dump(p, "      ttl ");
353 		if(vxi->vxi_ttl)
354 			nl_dump_line(p, "%u\n", vxi->vxi_ttl);
355 		else
356 			nl_dump_line(p, "inherit\n");
357 	}
358 
359 	if (vxi->ce_mask & VXLAN_ATTR_TOS) {
360 		nl_dump(p, "      tos ");
361 		if (vxi->vxi_tos == 1)
362 			nl_dump_line(p, "inherit\n");
363 		else
364 			nl_dump_line(p, "%#x\n", vxi->vxi_tos);
365 	}
366 
367 	if (vxi->ce_mask & VXLAN_ATTR_LEARNING) {
368 		nl_dump(p, "      learning ");
369 		if (vxi->vxi_learning)
370 			nl_dump_line(p, "enabled (%#x)\n", vxi->vxi_learning);
371 		else
372 			nl_dump_line(p, "disabled\n");
373 	}
374 
375 	if (vxi->ce_mask & VXLAN_ATTR_AGEING) {
376 		nl_dump(p, "      ageing ");
377 		if (vxi->vxi_ageing)
378 			nl_dump_line(p, "%u seconds\n", vxi->vxi_ageing);
379 		else
380 			nl_dump_line(p, "disabled\n");
381 	}
382 
383 	if (vxi->ce_mask & VXLAN_ATTR_LIMIT) {
384 		nl_dump(p, "      limit ");
385 		if (vxi->vxi_limit)
386 			nl_dump_line(p, "%u\n", vxi->vxi_limit);
387 		else
388 			nl_dump_line(p, "unlimited\n");
389 	}
390 
391 	if (vxi->ce_mask & VXLAN_ATTR_PORT_RANGE)
392 		nl_dump_line(p, "      port range %u - %u\n",
393 					 ntohs(vxi->vxi_port_range.low),
394 					 ntohs(vxi->vxi_port_range.high));
395 
396 	if (vxi->ce_mask & VXLAN_ATTR_PROXY) {
397 		nl_dump(p, "      proxy ");
398 		if (vxi->vxi_proxy)
399 			nl_dump_line(p, "enabled (%#x)\n", vxi->vxi_proxy);
400 		else
401 			nl_dump_line(p, "disabled\n");
402 	}
403 
404 	if (vxi->ce_mask & VXLAN_ATTR_RSC) {
405 		nl_dump(p, "      rsc ");
406 		if (vxi->vxi_rsc)
407 			nl_dump_line(p, "enabled (%#x)\n", vxi->vxi_rsc);
408 		else
409 			nl_dump_line(p, "disabled\n");
410 	}
411 
412 	if (vxi->ce_mask & VXLAN_ATTR_L2MISS) {
413 		nl_dump(p, "      l2miss ");
414 		if (vxi->vxi_l2miss)
415 			nl_dump_line(p, "enabled (%#x)\n", vxi->vxi_l2miss);
416 		else
417 			nl_dump_line(p, "disabled\n");
418 	}
419 
420 	if (vxi->ce_mask & VXLAN_ATTR_L3MISS) {
421 		nl_dump(p, "      l3miss ");
422 		if (vxi->vxi_l3miss)
423 			nl_dump_line(p, "enabled (%#x)\n", vxi->vxi_l3miss);
424 		else
425 			nl_dump_line(p, "disabled\n");
426 	}
427 
428 	if (vxi->ce_mask & VXLAN_ATTR_PORT) {
429 		nl_dump(p, "      port ");
430 		nl_dump_line(p, "%u\n", ntohs(vxi->vxi_port));
431 	}
432 
433 	if (vxi->ce_mask & VXLAN_ATTR_UDP_CSUM) {
434 		nl_dump(p, "      UDP checksums ");
435 		if (vxi->vxi_udp_csum)
436 			nl_dump_line(p, "enabled (%#x)\n", vxi->vxi_udp_csum);
437 		else
438 			nl_dump_line(p, "disabled\n");
439 	}
440 
441 	if (vxi->ce_mask & VXLAN_ATTR_UDP_ZERO_CSUM6_TX) {
442 		nl_dump(p, "      udp-zero-csum6-tx ");
443 		if (vxi->vxi_udp_zero_csum6_tx)
444 			nl_dump_line(p, "enabled (%#x)\n", vxi->vxi_udp_zero_csum6_tx);
445 		else
446 			nl_dump_line(p, "disabled\n");
447 	}
448 
449 	if (vxi->ce_mask & VXLAN_ATTR_UDP_ZERO_CSUM6_RX) {
450 		nl_dump(p, "      udp-zero-csum6-rx ");
451 		if (vxi->vxi_udp_zero_csum6_rx)
452 			nl_dump_line(p, "enabled (%#x)\n", vxi->vxi_udp_zero_csum6_rx);
453 		else
454 			nl_dump_line(p, "disabled\n");
455 	}
456 
457 	if (vxi->ce_mask & VXLAN_ATTR_REMCSUM_TX) {
458 		nl_dump(p, "      remcsum-tx ");
459 		if (vxi->vxi_remcsum_tx)
460 			nl_dump_line(p, "enabled (%#x)\n", vxi->vxi_remcsum_tx);
461 		else
462 			nl_dump_line(p, "disabled\n");
463 	}
464 
465 	if (vxi->ce_mask & VXLAN_ATTR_REMCSUM_RX) {
466 		nl_dump(p, "      remcsum-rx ");
467 		if (vxi->vxi_remcsum_rx)
468 			nl_dump_line(p, "enabled (%#x)\n", vxi->vxi_remcsum_rx);
469 		else
470 			nl_dump_line(p, "disabled\n");
471 	}
472 
473 	if (vxi->vxi_flags & RTNL_LINK_VXLAN_F_GBP)
474 		nl_dump(p, "      gbp\n");
475 
476 	if (vxi->vxi_flags & RTNL_LINK_VXLAN_F_REMCSUM_NOPARTIAL)
477 		nl_dump(p, "      rncsum-nopartial\n");
478 
479 	if (vxi->ce_mask & VXLAN_ATTR_COLLECT_METADATA) {
480 		nl_dump(p, "      remcsum-rx ");
481 		if (vxi->vxi_collect_metadata)
482 			nl_dump_line(p, "enabled (%#x)\n", vxi->vxi_collect_metadata);
483 		else
484 			nl_dump_line(p, "disabled\n");
485 	}
486 
487 	if (vxi->ce_mask & VXLAN_ATTR_LABEL) {
488 		nl_dump(p, "      label ");
489 		nl_dump_line(p, "%u\n", ntohl(vxi->vxi_label));
490 	}
491 
492 	if (vxi->vxi_flags & RTNL_LINK_VXLAN_F_GPE)
493 		nl_dump(p, "      gpe\n");
494 }
495 
vxlan_clone(struct rtnl_link * dst,struct rtnl_link * src)496 static int vxlan_clone(struct rtnl_link *dst, struct rtnl_link *src)
497 {
498 	struct vxlan_info *vdst, *vsrc = src->l_info;
499 	int err;
500 
501 	dst->l_info = NULL;
502 	if ((err = rtnl_link_set_type(dst, "vxlan")) < 0)
503 		return err;
504 	vdst = dst->l_info;
505 
506 	if (!vdst || !vsrc)
507 		return -NLE_NOMEM;
508 
509 	memcpy(vdst, vsrc, sizeof(struct vxlan_info));
510 
511 	return 0;
512 }
513 
vxlan_put_attrs(struct nl_msg * msg,struct rtnl_link * link)514 static int vxlan_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
515 {
516 	struct vxlan_info *vxi = link->l_info;
517 	struct nlattr *data;
518 
519 	if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
520 		return -NLE_MSGSIZE;
521 
522 	if (vxi->ce_mask & VXLAN_ATTR_ID)
523 		NLA_PUT_U32(msg, IFLA_VXLAN_ID, vxi->vxi_id);
524 
525 	if (vxi->ce_mask & VXLAN_ATTR_GROUP)
526 		NLA_PUT(msg, IFLA_VXLAN_GROUP, sizeof(vxi->vxi_group), &vxi->vxi_group);
527 
528 	if (vxi->ce_mask & VXLAN_ATTR_GROUP6)
529 		NLA_PUT(msg, IFLA_VXLAN_GROUP6, sizeof(vxi->vxi_group6), &vxi->vxi_group6);
530 
531 	if (vxi->ce_mask & VXLAN_ATTR_LINK)
532 		NLA_PUT_U32(msg, IFLA_VXLAN_LINK, vxi->vxi_link);
533 
534 	if (vxi->ce_mask & VXLAN_ATTR_LOCAL)
535 		NLA_PUT(msg, IFLA_VXLAN_LOCAL, sizeof(vxi->vxi_local), &vxi->vxi_local);
536 
537 	if (vxi->ce_mask & VXLAN_ATTR_LOCAL6)
538 		NLA_PUT(msg, IFLA_VXLAN_LOCAL6, sizeof(vxi->vxi_local6), &vxi->vxi_local6);
539 
540 	if (vxi->ce_mask & VXLAN_ATTR_TTL)
541 		NLA_PUT_U8(msg, IFLA_VXLAN_TTL, vxi->vxi_ttl);
542 
543 	if (vxi->ce_mask & VXLAN_ATTR_TOS)
544 		NLA_PUT_U8(msg, IFLA_VXLAN_TOS, vxi->vxi_tos);
545 
546 	if (vxi->ce_mask & VXLAN_ATTR_LEARNING)
547 		NLA_PUT_U8(msg, IFLA_VXLAN_LEARNING, vxi->vxi_learning);
548 
549 	if (vxi->ce_mask & VXLAN_ATTR_AGEING)
550 		NLA_PUT_U32(msg, IFLA_VXLAN_AGEING, vxi->vxi_ageing);
551 
552 	if (vxi->ce_mask & VXLAN_ATTR_LIMIT)
553 		NLA_PUT_U32(msg, IFLA_VXLAN_LIMIT, vxi->vxi_limit);
554 
555 	if (vxi->ce_mask & VXLAN_ATTR_PORT_RANGE)
556 		NLA_PUT(msg, IFLA_VXLAN_PORT_RANGE, sizeof(vxi->vxi_port_range),
557 				&vxi->vxi_port_range);
558 
559 	if (vxi->ce_mask & VXLAN_ATTR_PROXY)
560 		NLA_PUT_U8(msg, IFLA_VXLAN_PROXY, vxi->vxi_proxy);
561 
562 	if (vxi->ce_mask & VXLAN_ATTR_RSC)
563 		NLA_PUT_U8(msg, IFLA_VXLAN_RSC, vxi->vxi_rsc);
564 
565 	if (vxi->ce_mask & VXLAN_ATTR_L2MISS)
566 		NLA_PUT_U8(msg, IFLA_VXLAN_L2MISS, vxi->vxi_l2miss);
567 
568 	if (vxi->ce_mask & VXLAN_ATTR_L3MISS)
569 		NLA_PUT_U8(msg, IFLA_VXLAN_L3MISS, vxi->vxi_l3miss);
570 
571 	if (vxi->ce_mask & VXLAN_ATTR_PORT)
572 		NLA_PUT_U32(msg, IFLA_VXLAN_PORT, vxi->vxi_port);
573 
574 	if (vxi->ce_mask & VXLAN_ATTR_UDP_CSUM)
575 		NLA_PUT_U8(msg, IFLA_VXLAN_UDP_CSUM, vxi->vxi_udp_csum);
576 
577 	if (vxi->ce_mask & VXLAN_ATTR_UDP_ZERO_CSUM6_TX)
578 		NLA_PUT_U8(msg, IFLA_VXLAN_UDP_ZERO_CSUM6_TX, vxi->vxi_udp_zero_csum6_tx);
579 
580 	if (vxi->ce_mask & VXLAN_ATTR_UDP_ZERO_CSUM6_RX)
581 		NLA_PUT_U8(msg, IFLA_VXLAN_UDP_ZERO_CSUM6_RX, vxi->vxi_udp_zero_csum6_rx);
582 
583 	if (vxi->ce_mask & VXLAN_ATTR_REMCSUM_TX)
584 		NLA_PUT_U8(msg, IFLA_VXLAN_REMCSUM_TX, vxi->vxi_remcsum_tx);
585 
586 	if (vxi->ce_mask & VXLAN_ATTR_REMCSUM_RX)
587 		NLA_PUT_U8(msg, IFLA_VXLAN_REMCSUM_RX, vxi->vxi_remcsum_rx);
588 
589 	if (vxi->vxi_flags & RTNL_LINK_VXLAN_F_GBP)
590 		NLA_PUT_FLAG(msg, IFLA_VXLAN_GBP);
591 
592 	if (vxi->vxi_flags & RTNL_LINK_VXLAN_F_REMCSUM_NOPARTIAL)
593 		NLA_PUT_FLAG(msg, IFLA_VXLAN_REMCSUM_NOPARTIAL);
594 
595 	if (vxi->ce_mask & VXLAN_ATTR_COLLECT_METADATA)
596 		NLA_PUT_U8(msg, IFLA_VXLAN_COLLECT_METADATA, vxi->vxi_collect_metadata);
597 
598 	if (vxi->ce_mask & VXLAN_ATTR_LABEL)
599 		NLA_PUT_U32(msg, IFLA_VXLAN_LABEL, vxi->vxi_label);
600 
601 	if (vxi->vxi_flags & RTNL_LINK_VXLAN_F_GPE)
602 		NLA_PUT_FLAG(msg, IFLA_VXLAN_GPE);
603 
604 	nla_nest_end(msg, data);
605 
606 nla_put_failure:
607 
608 	return 0;
609 }
610 
vxlan_compare(struct rtnl_link * link_a,struct rtnl_link * link_b,int flags)611 static int vxlan_compare(struct rtnl_link *link_a, struct rtnl_link *link_b,
612 			 int flags)
613 {
614 	struct vxlan_info *a = link_a->l_info;
615 	struct vxlan_info *b = link_b->l_info;
616 	int diff = 0;
617 	uint32_t attrs = flags & LOOSE_COMPARISON ? b->ce_mask : ~0;
618 
619 #define VXLAN_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, VXLAN_ATTR_##ATTR, a, b, EXPR)
620 
621 	diff |= VXLAN_DIFF(ID,    a->vxi_id    != b->vxi_id);
622 	diff |= VXLAN_DIFF(GROUP, a->vxi_group != b->vxi_group);
623 	diff |= VXLAN_DIFF(LINK,  a->vxi_link  != b->vxi_link);
624 	diff |= VXLAN_DIFF(LOCAL, a->vxi_local != b->vxi_local);
625 	diff |= VXLAN_DIFF(TOS,   a->vxi_tos   != b->vxi_tos);
626 	diff |= VXLAN_DIFF(TTL,   a->vxi_ttl   != b->vxi_ttl);
627 	diff |= VXLAN_DIFF(LEARNING, a->vxi_learning != b->vxi_learning);
628 	diff |= VXLAN_DIFF(AGEING, a->vxi_ageing != b->vxi_ageing);
629 	diff |= VXLAN_DIFF(LIMIT, a->vxi_limit != b->vxi_limit);
630 	diff |= VXLAN_DIFF(PORT_RANGE,
631 	                   a->vxi_port_range.low != b->vxi_port_range.low);
632 	diff |= VXLAN_DIFF(PORT_RANGE,
633 	                   a->vxi_port_range.high != b->vxi_port_range.high);
634 	diff |= VXLAN_DIFF(PROXY, a->vxi_proxy != b->vxi_proxy);
635 	diff |= VXLAN_DIFF(RSC, a->vxi_proxy != b->vxi_proxy);
636 	diff |= VXLAN_DIFF(L2MISS, a->vxi_proxy != b->vxi_proxy);
637 	diff |= VXLAN_DIFF(L3MISS, a->vxi_proxy != b->vxi_proxy);
638 	diff |= VXLAN_DIFF(PORT, a->vxi_port != b->vxi_port);
639 	diff |= VXLAN_DIFF(GROUP6, memcmp(&a->vxi_group6, &b->vxi_group6, sizeof(a->vxi_group6)) != 0);
640 	diff |= VXLAN_DIFF(LOCAL6,  memcmp(&a->vxi_local6, &b->vxi_local6, sizeof(a->vxi_local6)) != 0);
641 	diff |= VXLAN_DIFF(UDP_CSUM, a->vxi_proxy != b->vxi_proxy);
642 	diff |= VXLAN_DIFF(UDP_ZERO_CSUM6_TX, a->vxi_proxy != b->vxi_proxy);
643 	diff |= VXLAN_DIFF(UDP_ZERO_CSUM6_RX, a->vxi_proxy != b->vxi_proxy);
644 	diff |= VXLAN_DIFF(REMCSUM_TX, a->vxi_proxy != b->vxi_proxy);
645 	diff |= VXLAN_DIFF(REMCSUM_RX, a->vxi_proxy != b->vxi_proxy);
646 	diff |= VXLAN_DIFF(COLLECT_METADATA, a->vxi_collect_metadata != b->vxi_collect_metadata);
647 	diff |= VXLAN_DIFF(LABEL, a->vxi_label != b->vxi_label);
648 	diff |= VXLAN_DIFF(FLAGS, a->vxi_flags != b->vxi_flags);
649 #undef VXLAN_DIFF
650 
651 	return diff;
652 }
653 
654 static struct rtnl_link_info_ops vxlan_info_ops = {
655 	.io_name		= "vxlan",
656 	.io_alloc		= vxlan_alloc,
657 	.io_parse		= vxlan_parse,
658 	.io_dump = {
659 	    [NL_DUMP_LINE]	= vxlan_dump_line,
660 	    [NL_DUMP_DETAILS]	= vxlan_dump_details,
661 	},
662 	.io_clone		= vxlan_clone,
663 	.io_put_attrs		= vxlan_put_attrs,
664 	.io_free		= vxlan_free,
665 	.io_compare             = vxlan_compare,
666 };
667 
668 /** @cond SKIP */
669 #define IS_VXLAN_LINK_ASSERT(link) \
670 	if ((link)->l_info_ops != &vxlan_info_ops) { \
671 		APPBUG("Link is not a vxlan link. set type \"vxlan\" first."); \
672 		return -NLE_OPNOTSUPP; \
673 	}
674 /** @endcond */
675 
676 /**
677  * @name VXLAN Object
678  * @{
679  */
680 
681 /**
682  * Allocate link object of type VXLAN
683  *
684  * @return Allocated link object or NULL.
685  */
rtnl_link_vxlan_alloc(void)686 struct rtnl_link *rtnl_link_vxlan_alloc(void)
687 {
688 	struct rtnl_link *link;
689 
690 	if (!(link = rtnl_link_alloc()))
691 		return NULL;
692 
693 	if (rtnl_link_set_type(link, "vxlan") < 0) {
694 		rtnl_link_put(link);
695 		return NULL;
696 	}
697 
698 	return link;
699 }
700 
701 /**
702  * Check if link is a VXLAN link
703  * @arg link		Link object
704  *
705  * @return True if link is a VXLAN link, otherwise false is returned.
706  */
rtnl_link_is_vxlan(struct rtnl_link * link)707 int rtnl_link_is_vxlan(struct rtnl_link *link)
708 {
709 	return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "vxlan");
710 }
711 
712 /**
713  * Set VXLAN Network Identifier
714  * @arg link		Link object
715  * @arg id		VXLAN network identifier (or VXLAN segment identifier)
716  *
717  * @return 0 on success or a negative error code
718  */
rtnl_link_vxlan_set_id(struct rtnl_link * link,uint32_t id)719 int rtnl_link_vxlan_set_id(struct rtnl_link *link, uint32_t id)
720 {
721 	struct vxlan_info *vxi = link->l_info;
722 
723 	IS_VXLAN_LINK_ASSERT(link);
724 
725 	if (id > VXLAN_ID_MAX)
726 		return -NLE_INVAL;
727 
728 	vxi->vxi_id = id;
729 	vxi->ce_mask |= VXLAN_ATTR_ID;
730 
731 	return 0;
732 }
733 
734 /**
735  * Get VXLAN Network Identifier
736  * @arg link		Link object
737  * @arg id			Pointer to store network identifier
738  *
739  * @return 0 on success or a negative error code
740  */
rtnl_link_vxlan_get_id(struct rtnl_link * link,uint32_t * id)741 int rtnl_link_vxlan_get_id(struct rtnl_link *link, uint32_t *id)
742 {
743 	struct vxlan_info *vxi = link->l_info;
744 
745 	IS_VXLAN_LINK_ASSERT(link);
746 
747 	if(!id)
748 		return -NLE_INVAL;
749 
750 	if (vxi->ce_mask & VXLAN_ATTR_ID)
751 		*id = vxi->vxi_id;
752 	else
753 		return -NLE_AGAIN;
754 
755 	return 0;
756 }
757 
758 /**
759  * Set VXLAN multicast IP address
760  * @arg link		Link object
761  * @arg addr		Multicast IP address to join
762  *
763  * @return 0 on success or a negative error code
764  */
rtnl_link_vxlan_set_group(struct rtnl_link * link,struct nl_addr * addr)765 int rtnl_link_vxlan_set_group(struct rtnl_link *link, struct nl_addr *addr)
766 {
767 	struct vxlan_info *vxi = link->l_info;
768 
769 	IS_VXLAN_LINK_ASSERT(link);
770 
771 	if ((nl_addr_get_family(addr) == AF_INET) &&
772 	    (nl_addr_get_len(addr) == sizeof(vxi->vxi_group))) {
773 		memcpy(&vxi->vxi_group, nl_addr_get_binary_addr(addr),
774 		       sizeof(vxi->vxi_group));
775 		vxi->ce_mask |= VXLAN_ATTR_GROUP;
776 		vxi->ce_mask &= ~VXLAN_ATTR_GROUP6;
777 	} else if ((nl_addr_get_family(addr) == AF_INET6) &&
778 		   (nl_addr_get_len(addr) == sizeof(vxi->vxi_group6))) {
779 		memcpy(&vxi->vxi_group6, nl_addr_get_binary_addr(addr),
780 		       sizeof(vxi->vxi_group6));
781 		vxi->ce_mask |= VXLAN_ATTR_GROUP6;
782 		vxi->ce_mask &= ~VXLAN_ATTR_GROUP;
783 	} else
784 		return -NLE_INVAL;
785 
786 	return 0;
787 }
788 
789 /**
790  * Get VXLAN multicast IP address
791  * @arg link		Link object
792  * @arg addr		Pointer to store multicast IP address
793  *
794  * @return 0 on success or a negative error code
795  */
rtnl_link_vxlan_get_group(struct rtnl_link * link,struct nl_addr ** addr)796 int rtnl_link_vxlan_get_group(struct rtnl_link *link, struct nl_addr **addr)
797 {
798 	struct vxlan_info *vxi = link->l_info;
799 
800 	IS_VXLAN_LINK_ASSERT(link);
801 
802 	if (!addr)
803 		return -NLE_INVAL;
804 
805 	if (vxi->ce_mask & VXLAN_ATTR_GROUP)
806 		*addr = nl_addr_build(AF_INET, &vxi->vxi_group, sizeof(vxi->vxi_group));
807 	else if (vxi->ce_mask & VXLAN_ATTR_GROUP6)
808 		*addr = nl_addr_build(AF_INET6, &vxi->vxi_group6, sizeof(vxi->vxi_group6));
809 	else
810 		return -NLE_AGAIN;
811 
812 	return 0;
813 }
814 
815 /**
816  * Set physical device to use for VXLAN
817  * @arg link		Link object
818  * @arg index		Interface index
819  *
820  * @return 0 on success or a negative error code
821  */
rtnl_link_vxlan_set_link(struct rtnl_link * link,uint32_t index)822 int rtnl_link_vxlan_set_link(struct rtnl_link *link, uint32_t index)
823 {
824 	struct vxlan_info *vxi = link->l_info;
825 
826 	IS_VXLAN_LINK_ASSERT(link);
827 
828 	vxi->vxi_link = index;
829 	vxi->ce_mask |= VXLAN_ATTR_LINK;
830 
831 	return 0;
832 }
833 
834 /**
835  * Get physical device to use for VXLAN
836  * @arg link		Link object
837  * @arg index		Pointer to store interface index
838  *
839  * @return 0 on success or a negative error code
840  */
rtnl_link_vxlan_get_link(struct rtnl_link * link,uint32_t * index)841 int rtnl_link_vxlan_get_link(struct rtnl_link *link, uint32_t *index)
842 {
843 	struct vxlan_info *vxi = link->l_info;
844 
845 	IS_VXLAN_LINK_ASSERT(link);
846 
847 	if (!index)
848 		return -NLE_INVAL;
849 
850 	if (!(vxi->ce_mask & VXLAN_ATTR_LINK))
851 		return -NLE_AGAIN;
852 
853 	*index = vxi->vxi_link;
854 
855 	return 0;
856 }
857 
858 /**
859  * Set source address to use for VXLAN
860  * @arg link		Link object
861  * @arg addr		Local address
862  *
863  * @return 0 on success or a negative error code
864  */
rtnl_link_vxlan_set_local(struct rtnl_link * link,struct nl_addr * addr)865 int rtnl_link_vxlan_set_local(struct rtnl_link *link, struct nl_addr *addr)
866 {
867 	struct vxlan_info *vxi = link->l_info;
868 
869 	IS_VXLAN_LINK_ASSERT(link);
870 
871 	if ((nl_addr_get_family(addr) == AF_INET) &&
872 	    (nl_addr_get_len(addr) == sizeof(vxi->vxi_local))) {
873 		memcpy(&vxi->vxi_local, nl_addr_get_binary_addr(addr),
874 		       sizeof(vxi->vxi_local));
875 		vxi->ce_mask |= VXLAN_ATTR_LOCAL;
876 		vxi->ce_mask &= ~VXLAN_ATTR_LOCAL6;
877 	} else if ((nl_addr_get_family(addr) == AF_INET6) &&
878 		   (nl_addr_get_len(addr) == sizeof(vxi->vxi_local6))) {
879 		memcpy(&vxi->vxi_local6, nl_addr_get_binary_addr(addr),
880 		       sizeof(vxi->vxi_local6));
881 		vxi->ce_mask |= VXLAN_ATTR_LOCAL6;
882 		vxi->ce_mask &= ~VXLAN_ATTR_LOCAL;
883 	} else
884 		return -NLE_INVAL;
885 
886 	return 0;
887 }
888 
889 /**
890  * Get source address to use for VXLAN
891  * @arg link		Link object
892  * @arg addr		Pointer to store local address
893  *
894  * @return 0 on success or a negative error code
895  */
rtnl_link_vxlan_get_local(struct rtnl_link * link,struct nl_addr ** addr)896 int rtnl_link_vxlan_get_local(struct rtnl_link *link, struct nl_addr **addr)
897 {
898 	struct vxlan_info *vxi = link->l_info;
899 
900 	IS_VXLAN_LINK_ASSERT(link);
901 
902 	if (!addr)
903 		return -NLE_INVAL;
904 
905 	if (vxi->ce_mask & VXLAN_ATTR_LOCAL)
906 		*addr = nl_addr_build(AF_INET, &vxi->vxi_local, sizeof(vxi->vxi_local));
907 	else if (vxi->ce_mask & VXLAN_ATTR_LOCAL6)
908 		*addr = nl_addr_build(AF_INET6, &vxi->vxi_local6, sizeof(vxi->vxi_local6));
909 	else
910 		return -NLE_AGAIN;
911 
912 	return 0;
913 }
914 
915 /**
916  * Set IP TTL value to use for VXLAN
917  * @arg link		Link object
918  * @arg ttl			TTL value
919  *
920  * @return 0 on success or a negative error code
921  */
rtnl_link_vxlan_set_ttl(struct rtnl_link * link,uint8_t ttl)922 int rtnl_link_vxlan_set_ttl(struct rtnl_link *link, uint8_t ttl)
923 {
924 	struct vxlan_info *vxi = link->l_info;
925 
926 	IS_VXLAN_LINK_ASSERT(link);
927 
928 	vxi->vxi_ttl = ttl;
929 	vxi->ce_mask |= VXLAN_ATTR_TTL;
930 
931 	return 0;
932 }
933 
934 /**
935  * Get IP TTL value to use for VXLAN
936  * @arg link		Link object
937  *
938  * @return TTL value on success or a negative error code
939  */
rtnl_link_vxlan_get_ttl(struct rtnl_link * link)940 int rtnl_link_vxlan_get_ttl(struct rtnl_link *link)
941 {
942 	struct vxlan_info *vxi = link->l_info;
943 
944 	IS_VXLAN_LINK_ASSERT(link);
945 
946 	if (!(vxi->ce_mask & VXLAN_ATTR_TTL))
947 		return -NLE_AGAIN;
948 
949 	return vxi->vxi_ttl;
950 }
951 
952 /**
953  * Set IP ToS value to use for VXLAN
954  * @arg link		Link object
955  * @arg tos		ToS value
956  *
957  * @return 0 on success or a negative error code
958  */
rtnl_link_vxlan_set_tos(struct rtnl_link * link,uint8_t tos)959 int rtnl_link_vxlan_set_tos(struct rtnl_link *link, uint8_t tos)
960 {
961 	struct vxlan_info *vxi = link->l_info;
962 
963 	IS_VXLAN_LINK_ASSERT(link);
964 
965 	vxi->vxi_tos = tos;
966 	vxi->ce_mask |= VXLAN_ATTR_TOS;
967 
968 	return 0;
969 }
970 
971 /**
972  * Get IP ToS value to use for VXLAN
973  * @arg link		Link object
974  *
975  * @return ToS value on success or a negative error code
976  */
rtnl_link_vxlan_get_tos(struct rtnl_link * link)977 int rtnl_link_vxlan_get_tos(struct rtnl_link *link)
978 {
979 	struct vxlan_info *vxi = link->l_info;
980 
981 	IS_VXLAN_LINK_ASSERT(link);
982 
983 	if (!(vxi->ce_mask & VXLAN_ATTR_TOS))
984 		return -NLE_AGAIN;
985 
986 	return vxi->vxi_tos;
987 }
988 
989 /**
990  * Set VXLAN learning status
991  * @arg link		Link object
992  * @arg learning	Learning status value
993  *
994  * @return 0 on success or a negative error code
995  */
rtnl_link_vxlan_set_learning(struct rtnl_link * link,uint8_t learning)996 int rtnl_link_vxlan_set_learning(struct rtnl_link *link, uint8_t learning)
997 {
998 	struct vxlan_info *vxi = link->l_info;
999 
1000 	IS_VXLAN_LINK_ASSERT(link);
1001 
1002 	vxi->vxi_learning = learning;
1003 	vxi->ce_mask |= VXLAN_ATTR_LEARNING;
1004 
1005 	return 0;
1006 }
1007 
1008 /**
1009  * Get VXLAN learning status
1010  * @arg link		Link object
1011  *
1012  * @return Learning status value on success or a negative error code
1013  */
rtnl_link_vxlan_get_learning(struct rtnl_link * link)1014 int rtnl_link_vxlan_get_learning(struct rtnl_link *link)
1015 {
1016 	struct vxlan_info *vxi = link->l_info;
1017 
1018 	IS_VXLAN_LINK_ASSERT(link);
1019 
1020 	if (!(vxi->ce_mask & VXLAN_ATTR_LEARNING))
1021 		return -NLE_AGAIN;
1022 
1023 	return vxi->vxi_learning;
1024 }
1025 
1026 /**
1027  * Enable VXLAN address learning
1028  * @arg link		Link object
1029  *
1030  * @return 0 on success or a negative error code
1031  */
rtnl_link_vxlan_enable_learning(struct rtnl_link * link)1032 int rtnl_link_vxlan_enable_learning(struct rtnl_link *link)
1033 {
1034 	return rtnl_link_vxlan_set_learning(link, 1);
1035 }
1036 
1037 /**
1038  * Disable VXLAN address learning
1039  * @arg link		Link object
1040  *
1041  * @return 0 on success or a negative error code
1042  */
rtnl_link_vxlan_disable_learning(struct rtnl_link * link)1043 int rtnl_link_vxlan_disable_learning(struct rtnl_link *link)
1044 {
1045 	return rtnl_link_vxlan_set_learning(link, 0);
1046 }
1047 
1048 /**
1049  * Set expiration timer value to use for VXLAN
1050  * @arg link		Link object
1051  * @arg expiry		Expiration timer value
1052  *
1053  * @return 0 on success or a negative error code
1054  */
rtnl_link_vxlan_set_ageing(struct rtnl_link * link,uint32_t expiry)1055 int rtnl_link_vxlan_set_ageing(struct rtnl_link *link, uint32_t expiry)
1056 {
1057 	struct vxlan_info *vxi = link->l_info;
1058 
1059 	IS_VXLAN_LINK_ASSERT(link);
1060 
1061 	vxi->vxi_ageing = expiry;
1062 	vxi->ce_mask |= VXLAN_ATTR_AGEING;
1063 
1064 	return 0;
1065 }
1066 
1067 /**
1068  * Get expiration timer value to use for VXLAN
1069  * @arg link		Link object
1070  * @arg expiry		Pointer to store expiration timer value
1071  *
1072  * @return 0 on success or a negative error code
1073  */
rtnl_link_vxlan_get_ageing(struct rtnl_link * link,uint32_t * expiry)1074 int rtnl_link_vxlan_get_ageing(struct rtnl_link *link, uint32_t *expiry)
1075 {
1076 	struct vxlan_info *vxi = link->l_info;
1077 
1078 	IS_VXLAN_LINK_ASSERT(link);
1079 
1080 	if (!expiry)
1081 		return -NLE_INVAL;
1082 
1083 	if (vxi->ce_mask & VXLAN_ATTR_AGEING)
1084 		*expiry = vxi->vxi_ageing;
1085 	else
1086 		return -NLE_AGAIN;
1087 
1088 	return 0;
1089 }
1090 
1091 /**
1092  * Set maximum number of forwarding database entries to use for VXLAN
1093  * @arg link		Link object
1094  * @arg limit		Maximum number
1095  *
1096  * @return 0 on success or a negative error code
1097  */
rtnl_link_vxlan_set_limit(struct rtnl_link * link,uint32_t limit)1098 int rtnl_link_vxlan_set_limit(struct rtnl_link *link, uint32_t limit)
1099 {
1100 	struct vxlan_info *vxi = link->l_info;
1101 
1102 	IS_VXLAN_LINK_ASSERT(link);
1103 
1104 	vxi->vxi_limit = limit;
1105 	vxi->ce_mask |= VXLAN_ATTR_LIMIT;
1106 
1107 	return 0;
1108 }
1109 
1110 /**
1111  * Get maximum number of forwarding database entries to use for VXLAN
1112  * @arg link		Link object
1113  * @arg limit		Pointer to store maximum number
1114  *
1115  * @return 0 on success or a negative error code
1116  */
rtnl_link_vxlan_get_limit(struct rtnl_link * link,uint32_t * limit)1117 int rtnl_link_vxlan_get_limit(struct rtnl_link *link, uint32_t *limit)
1118 {
1119 	struct vxlan_info *vxi = link->l_info;
1120 
1121 	IS_VXLAN_LINK_ASSERT(link);
1122 
1123 	if (!limit)
1124 		return -NLE_INVAL;
1125 
1126 	if (vxi->ce_mask & VXLAN_ATTR_LIMIT)
1127 		*limit = vxi->vxi_limit;
1128 	else
1129 		return -NLE_AGAIN;
1130 
1131 	return 0;
1132 }
1133 
1134 /**
1135  * Set range of UDP port numbers to use for VXLAN
1136  * @arg link		Link object
1137  * @arg range		Port number range
1138  *
1139  * @return 0 on success or a negative error code
1140  */
rtnl_link_vxlan_set_port_range(struct rtnl_link * link,struct ifla_vxlan_port_range * range)1141 int rtnl_link_vxlan_set_port_range(struct rtnl_link *link,
1142                                    struct ifla_vxlan_port_range *range)
1143 {
1144 	struct vxlan_info *vxi = link->l_info;
1145 
1146 	IS_VXLAN_LINK_ASSERT(link);
1147 
1148 	if (!range)
1149 		return -NLE_INVAL;
1150 
1151 	memcpy(&vxi->vxi_port_range, range, sizeof(vxi->vxi_port_range));
1152 	vxi->ce_mask |= VXLAN_ATTR_PORT_RANGE;
1153 
1154 	return 0;
1155 }
1156 
1157 /**
1158  * Get range of UDP port numbers to use for VXLAN
1159  * @arg link		Link object
1160  * @arg range		Pointer to store port range
1161  *
1162  * @return 0 on success or a negative error code
1163  */
rtnl_link_vxlan_get_port_range(struct rtnl_link * link,struct ifla_vxlan_port_range * range)1164 int rtnl_link_vxlan_get_port_range(struct rtnl_link *link,
1165                                    struct ifla_vxlan_port_range *range)
1166 {
1167 	struct vxlan_info *vxi = link->l_info;
1168 
1169 	IS_VXLAN_LINK_ASSERT(link);
1170 
1171 	if (!range)
1172 		return -NLE_INVAL;
1173 
1174 	if (vxi->ce_mask & VXLAN_ATTR_PORT_RANGE)
1175 		memcpy(range, &vxi->vxi_port_range, sizeof(*range));
1176 	else
1177 		return -NLE_AGAIN;
1178 
1179 	return 0;
1180 }
1181 
1182 /**
1183  * Set ARP proxy status to use for VXLAN
1184  * @arg link		Link object
1185  * @arg proxy		Status value
1186  *
1187  * @return 0 on success or a negative error code
1188  */
rtnl_link_vxlan_set_proxy(struct rtnl_link * link,uint8_t proxy)1189 int rtnl_link_vxlan_set_proxy(struct rtnl_link *link, uint8_t proxy)
1190 {
1191 	struct vxlan_info *vxi = link->l_info;
1192 
1193 	IS_VXLAN_LINK_ASSERT(link);
1194 
1195 	vxi->vxi_proxy = proxy;
1196 	vxi->ce_mask |= VXLAN_ATTR_PROXY;
1197 
1198 	return 0;
1199 }
1200 
1201 /**
1202  * Get ARP proxy status to use for VXLAN
1203  * @arg link		Link object
1204  *
1205  * @return Status value on success or a negative error code
1206  */
rtnl_link_vxlan_get_proxy(struct rtnl_link * link)1207 int rtnl_link_vxlan_get_proxy(struct rtnl_link *link)
1208 {
1209 	struct vxlan_info *vxi = link->l_info;
1210 
1211 	IS_VXLAN_LINK_ASSERT(link);
1212 
1213 	if (!(vxi->ce_mask & VXLAN_ATTR_PROXY))
1214 		return -NLE_AGAIN;
1215 
1216 	return vxi->vxi_proxy;
1217 }
1218 
1219 /**
1220  * Enable ARP proxy
1221  * @arg link		Link object
1222  *
1223  * @return 0 on success or a negative error code
1224  */
rtnl_link_vxlan_enable_proxy(struct rtnl_link * link)1225 int rtnl_link_vxlan_enable_proxy(struct rtnl_link *link)
1226 {
1227 	return rtnl_link_vxlan_set_proxy(link, 1);
1228 }
1229 
1230 /**
1231  * Disable ARP proxy
1232  * @arg link		Link object
1233  *
1234  * @return 0 on success or a negative error code
1235  */
rtnl_link_vxlan_disable_proxy(struct rtnl_link * link)1236 int rtnl_link_vxlan_disable_proxy(struct rtnl_link *link)
1237 {
1238 	return rtnl_link_vxlan_set_proxy(link, 0);
1239 }
1240 
1241 /**
1242  * Set Route Short Circuit status to use for VXLAN
1243  * @arg link		Link object
1244  * @arg rsc			Status value
1245  *
1246  * @return 0 on success or a negative error code
1247  */
rtnl_link_vxlan_set_rsc(struct rtnl_link * link,uint8_t rsc)1248 int rtnl_link_vxlan_set_rsc(struct rtnl_link *link, uint8_t rsc)
1249 {
1250 	struct vxlan_info *vxi = link->l_info;
1251 
1252 	IS_VXLAN_LINK_ASSERT(link);
1253 
1254 	vxi->vxi_rsc = rsc;
1255 	vxi->ce_mask |= VXLAN_ATTR_RSC;
1256 
1257 	return 0;
1258 }
1259 
1260 /**
1261  * Get Route Short Circuit status to use for VXLAN
1262  * @arg link		Link object
1263  *
1264  * @return Status value on success or a negative error code
1265  */
rtnl_link_vxlan_get_rsc(struct rtnl_link * link)1266 int rtnl_link_vxlan_get_rsc(struct rtnl_link *link)
1267 {
1268 	struct vxlan_info *vxi = link->l_info;
1269 
1270 	IS_VXLAN_LINK_ASSERT(link);
1271 
1272 	if (!(vxi->ce_mask & VXLAN_ATTR_RSC))
1273 		return -NLE_AGAIN;
1274 
1275 	return vxi->vxi_rsc;
1276 }
1277 
1278 /**
1279  * Enable Route Short Circuit
1280  * @arg link		Link object
1281  *
1282  * @return 0 on success or a negative error code
1283  */
rtnl_link_vxlan_enable_rsc(struct rtnl_link * link)1284 int rtnl_link_vxlan_enable_rsc(struct rtnl_link *link)
1285 {
1286 	return rtnl_link_vxlan_set_rsc(link, 1);
1287 }
1288 
1289 /**
1290  * Disable Route Short Circuit
1291  * @arg link		Link object
1292  *
1293  * @return 0 on success or a negative error code
1294  */
rtnl_link_vxlan_disable_rsc(struct rtnl_link * link)1295 int rtnl_link_vxlan_disable_rsc(struct rtnl_link *link)
1296 {
1297 	return rtnl_link_vxlan_set_rsc(link, 0);
1298 }
1299 
1300 /**
1301  * Set netlink LLADDR miss notification status to use for VXLAN
1302  * @arg link		Link object
1303  * @arg miss		Status value
1304  *
1305  * @return 0 on success or a negative error code
1306  */
rtnl_link_vxlan_set_l2miss(struct rtnl_link * link,uint8_t miss)1307 int rtnl_link_vxlan_set_l2miss(struct rtnl_link *link, uint8_t miss)
1308 {
1309 	struct vxlan_info *vxi = link->l_info;
1310 
1311 	IS_VXLAN_LINK_ASSERT(link);
1312 
1313 	vxi->vxi_l2miss = miss;
1314 	vxi->ce_mask |= VXLAN_ATTR_L2MISS;
1315 
1316 	return 0;
1317 }
1318 
1319 /**
1320  * Get netlink LLADDR miss notification status to use for VXLAN
1321  * @arg link		Link object
1322  *
1323  * @return Status value on success or a negative error code
1324  */
rtnl_link_vxlan_get_l2miss(struct rtnl_link * link)1325 int rtnl_link_vxlan_get_l2miss(struct rtnl_link *link)
1326 {
1327 	struct vxlan_info *vxi = link->l_info;
1328 
1329 	IS_VXLAN_LINK_ASSERT(link);
1330 
1331 	if (!(vxi->ce_mask & VXLAN_ATTR_L2MISS))
1332 		return -NLE_AGAIN;
1333 
1334 	return vxi->vxi_l2miss;
1335 }
1336 
1337 /**
1338  * Enable netlink LLADDR miss notifications
1339  * @arg link		Link object
1340  *
1341  * @return 0 on success or a negative error code
1342  */
rtnl_link_vxlan_enable_l2miss(struct rtnl_link * link)1343 int rtnl_link_vxlan_enable_l2miss(struct rtnl_link *link)
1344 {
1345 	return rtnl_link_vxlan_set_l2miss(link, 1);
1346 }
1347 
1348 /**
1349  * Disable netlink LLADDR miss notifications
1350  * @arg link		Link object
1351  *
1352  * @return 0 on success or a negative error code
1353  */
rtnl_link_vxlan_disable_l2miss(struct rtnl_link * link)1354 int rtnl_link_vxlan_disable_l2miss(struct rtnl_link *link)
1355 {
1356 	return rtnl_link_vxlan_set_l2miss(link, 0);
1357 }
1358 
1359 /**
1360  * Set netlink IP ADDR miss notification status to use for VXLAN
1361  * @arg link		Link object
1362  * @arg miss		Status value
1363  *
1364  * @return 0 on success or a negative error code
1365  */
rtnl_link_vxlan_set_l3miss(struct rtnl_link * link,uint8_t miss)1366 int rtnl_link_vxlan_set_l3miss(struct rtnl_link *link, uint8_t miss)
1367 {
1368 	struct vxlan_info *vxi = link->l_info;
1369 
1370 	IS_VXLAN_LINK_ASSERT(link);
1371 
1372 	vxi->vxi_l3miss = miss;
1373 	vxi->ce_mask |= VXLAN_ATTR_L3MISS;
1374 
1375 	return 0;
1376 }
1377 
1378 /**
1379  * Get netlink IP ADDR miss notification status to use for VXLAN
1380  * @arg link		Link object
1381  *
1382  * @return Status value on success or a negative error code
1383  */
rtnl_link_vxlan_get_l3miss(struct rtnl_link * link)1384 int rtnl_link_vxlan_get_l3miss(struct rtnl_link *link)
1385 {
1386 	struct vxlan_info *vxi = link->l_info;
1387 
1388 	IS_VXLAN_LINK_ASSERT(link);
1389 
1390 	if (!(vxi->ce_mask & VXLAN_ATTR_L3MISS))
1391 		return -NLE_AGAIN;
1392 
1393 	return vxi->vxi_l3miss;
1394 }
1395 
1396 /**
1397  * Enable netlink IP ADDR miss notifications
1398  * @arg link		Link object
1399  *
1400  * @return 0 on success or a negative error code
1401  */
rtnl_link_vxlan_enable_l3miss(struct rtnl_link * link)1402 int rtnl_link_vxlan_enable_l3miss(struct rtnl_link *link)
1403 {
1404 	return rtnl_link_vxlan_set_l3miss(link, 1);
1405 }
1406 
1407 /**
1408  * Disable netlink IP ADDR miss notifications
1409  * @arg link		Link object
1410  *
1411  * @return 0 on success or a negative error code
1412  */
rtnl_link_vxlan_disable_l3miss(struct rtnl_link * link)1413 int rtnl_link_vxlan_disable_l3miss(struct rtnl_link *link)
1414 {
1415 	return rtnl_link_vxlan_set_l3miss(link, 0);
1416 }
1417 
1418 /**
1419  * Set UDP destination port to use for VXLAN
1420  * @arg link		Link object
1421  * @arg port		Destination port
1422  *
1423  * @return 0 on success or a negative error code
1424  */
rtnl_link_vxlan_set_port(struct rtnl_link * link,uint32_t port)1425 int rtnl_link_vxlan_set_port(struct rtnl_link *link, uint32_t port)
1426 {
1427 	struct vxlan_info *vxi = link->l_info;
1428 
1429 	IS_VXLAN_LINK_ASSERT(link);
1430 
1431 	vxi->vxi_port = htons(port);
1432 	vxi->ce_mask |= VXLAN_ATTR_PORT;
1433 
1434 	return 0;
1435 }
1436 
1437 /**
1438  * Get UDP destination port to use for VXLAN
1439  * @arg link		Link object
1440  * @arg port		Pointer to store destination port
1441  *
1442  * @return 0 on success or a negative error code
1443  */
rtnl_link_vxlan_get_port(struct rtnl_link * link,uint32_t * port)1444 int rtnl_link_vxlan_get_port(struct rtnl_link *link, uint32_t *port)
1445 {
1446 	struct vxlan_info *vxi = link->l_info;
1447 
1448 	IS_VXLAN_LINK_ASSERT(link);
1449 
1450 	if (!port)
1451 		return -NLE_INVAL;
1452 
1453 	if (!(vxi->ce_mask & VXLAN_ATTR_PORT))
1454 		return -NLE_NOATTR;
1455 
1456 	*port = ntohs(vxi->vxi_port);
1457 
1458 	return 0;
1459 }
1460 
1461 /**
1462  * Set UDP checksum status to use for VXLAN
1463  * @arg link		Link object
1464  * @arg csum		Status value
1465  *
1466  * @return 0 on success or a negative error code
1467  */
rtnl_link_vxlan_set_udp_csum(struct rtnl_link * link,uint8_t csum)1468 int rtnl_link_vxlan_set_udp_csum(struct rtnl_link *link, uint8_t csum)
1469 {
1470 	struct vxlan_info *vxi = link->l_info;
1471 
1472 	IS_VXLAN_LINK_ASSERT(link);
1473 
1474 	vxi->vxi_udp_csum = csum;
1475 	vxi->ce_mask |= VXLAN_ATTR_UDP_CSUM;
1476 
1477 	return 0;
1478 }
1479 
1480 /**
1481  * Get UDP checksum status to use for VXLAN
1482  * @arg link		Link object
1483  *
1484  * @return Status value on success or a negative error code
1485  */
rtnl_link_vxlan_get_udp_csum(struct rtnl_link * link)1486 int rtnl_link_vxlan_get_udp_csum(struct rtnl_link *link)
1487 {
1488 	struct vxlan_info *vxi = link->l_info;
1489 
1490 	IS_VXLAN_LINK_ASSERT(link);
1491 
1492 	if (!(vxi->ce_mask & VXLAN_ATTR_UDP_CSUM))
1493 		return -NLE_NOATTR;
1494 
1495 	return vxi->vxi_udp_csum;
1496 }
1497 
1498 /**
1499  * Set skip UDP checksum transmitted over IPv6 status to use for VXLAN
1500  * @arg link		Link object
1501  * @arg csum		Status value
1502  *
1503  * @return 0 on success or a negative error code
1504  */
rtnl_link_vxlan_set_udp_zero_csum6_tx(struct rtnl_link * link,uint8_t csum)1505 int rtnl_link_vxlan_set_udp_zero_csum6_tx(struct rtnl_link *link, uint8_t csum)
1506 {
1507 	struct vxlan_info *vxi = link->l_info;
1508 
1509 	IS_VXLAN_LINK_ASSERT(link);
1510 
1511 	vxi->vxi_udp_zero_csum6_tx = csum;
1512 	vxi->ce_mask |= VXLAN_ATTR_UDP_ZERO_CSUM6_TX;
1513 
1514 	return 0;
1515 }
1516 
1517 /**
1518  * Get skip UDP checksum transmitted over IPv6 status to use for VXLAN
1519  * @arg link		Link object
1520  *
1521  * @return Status value on success or a negative error code
1522  */
rtnl_link_vxlan_get_udp_zero_csum6_tx(struct rtnl_link * link)1523 int rtnl_link_vxlan_get_udp_zero_csum6_tx(struct rtnl_link *link)
1524 {
1525 	struct vxlan_info *vxi = link->l_info;
1526 
1527 	IS_VXLAN_LINK_ASSERT(link);
1528 
1529 	if (!(vxi->ce_mask & VXLAN_ATTR_UDP_ZERO_CSUM6_TX))
1530 		return -NLE_NOATTR;
1531 
1532 	return vxi->vxi_udp_zero_csum6_tx;
1533 }
1534 
1535 /**
1536  * Set skip UDP checksum received over IPv6 status to use for VXLAN
1537  * @arg link		Link object
1538  * @arg csum		Status value
1539  *
1540  * @return 0 on success or a negative error code
1541  */
rtnl_link_vxlan_set_udp_zero_csum6_rx(struct rtnl_link * link,uint8_t csum)1542 int rtnl_link_vxlan_set_udp_zero_csum6_rx(struct rtnl_link *link, uint8_t csum)
1543 {
1544 	struct vxlan_info *vxi = link->l_info;
1545 
1546 	IS_VXLAN_LINK_ASSERT(link);
1547 
1548 	vxi->vxi_udp_zero_csum6_rx = csum;
1549 	vxi->ce_mask |= VXLAN_ATTR_UDP_ZERO_CSUM6_RX;
1550 
1551 	return 0;
1552 }
1553 
1554 /**
1555  * Get skip UDP checksum received over IPv6 status to use for VXLAN
1556  * @arg link		Link object
1557  *
1558  * @return Status value on success or a negative error code
1559  */
rtnl_link_vxlan_get_udp_zero_csum6_rx(struct rtnl_link * link)1560 int rtnl_link_vxlan_get_udp_zero_csum6_rx(struct rtnl_link *link)
1561 {
1562 	struct vxlan_info *vxi = link->l_info;
1563 
1564 	IS_VXLAN_LINK_ASSERT(link);
1565 
1566 	if (!(vxi->ce_mask & VXLAN_ATTR_UDP_ZERO_CSUM6_RX))
1567 		return -NLE_NOATTR;
1568 
1569 	return vxi->vxi_udp_zero_csum6_rx;
1570 }
1571 
1572 /**
1573  * Set remote offload transmit checksum status to use for VXLAN
1574  * @arg link		Link object
1575  * @arg csum		Status value
1576  *
1577  * @return 0 on success or a negative error code
1578  */
rtnl_link_vxlan_set_remcsum_tx(struct rtnl_link * link,uint8_t csum)1579 int rtnl_link_vxlan_set_remcsum_tx(struct rtnl_link *link, uint8_t csum)
1580 {
1581 	struct vxlan_info *vxi = link->l_info;
1582 
1583 	IS_VXLAN_LINK_ASSERT(link);
1584 
1585 	vxi->vxi_remcsum_tx = csum;
1586 	vxi->ce_mask |= VXLAN_ATTR_REMCSUM_TX;
1587 
1588 	return 0;
1589 }
1590 
1591 /**
1592  * Get remote offload transmit checksum status to use for VXLAN
1593  * @arg link		Link object
1594  *
1595  * @return Status value on success or a negative error code
1596  */
rtnl_link_vxlan_get_remcsum_tx(struct rtnl_link * link)1597 int rtnl_link_vxlan_get_remcsum_tx(struct rtnl_link *link)
1598 {
1599 	struct vxlan_info *vxi = link->l_info;
1600 
1601 	IS_VXLAN_LINK_ASSERT(link);
1602 
1603 	if (!(vxi->ce_mask & VXLAN_ATTR_REMCSUM_TX))
1604 		return -NLE_NOATTR;
1605 
1606 	return vxi->vxi_remcsum_tx;
1607 }
1608 
1609 /**
1610  * Set remote offload receive checksum status to use for VXLAN
1611  * @arg link		Link object
1612  * @arg csum		Status value
1613  *
1614  * @return 0 on success or a negative error code
1615  */
rtnl_link_vxlan_set_remcsum_rx(struct rtnl_link * link,uint8_t csum)1616 int rtnl_link_vxlan_set_remcsum_rx(struct rtnl_link *link, uint8_t csum)
1617 {
1618 	struct vxlan_info *vxi = link->l_info;
1619 
1620 	IS_VXLAN_LINK_ASSERT(link);
1621 
1622 	vxi->vxi_remcsum_rx = csum;
1623 	vxi->ce_mask |= VXLAN_ATTR_REMCSUM_RX;
1624 
1625 	return 0;
1626 }
1627 
1628 /**
1629  * Get remote offload receive checksum status to use for VXLAN
1630  * @arg link		Link object
1631  *
1632  * @return Status value on success or a negative error code
1633  */
rtnl_link_vxlan_get_remcsum_rx(struct rtnl_link * link)1634 int rtnl_link_vxlan_get_remcsum_rx(struct rtnl_link *link)
1635 {
1636 	struct vxlan_info *vxi = link->l_info;
1637 
1638 	IS_VXLAN_LINK_ASSERT(link);
1639 
1640 	if (!(vxi->ce_mask & VXLAN_ATTR_REMCSUM_RX))
1641 		return -NLE_NOATTR;
1642 
1643 	return vxi->vxi_remcsum_rx;
1644 }
1645 
1646 /**
1647  * Set collect metadata status to use for VXLAN
1648  * @arg link		Link object
1649  * @arg collect		Status value
1650  *
1651  * @return 0 on success or a negative error code
1652  */
rtnl_link_vxlan_set_collect_metadata(struct rtnl_link * link,uint8_t collect)1653 int rtnl_link_vxlan_set_collect_metadata(struct rtnl_link *link, uint8_t collect)
1654 {
1655 	struct vxlan_info *vxi = link->l_info;
1656 
1657 	IS_VXLAN_LINK_ASSERT(link);
1658 
1659 	vxi->vxi_collect_metadata = collect;
1660 	vxi->ce_mask |= VXLAN_ATTR_COLLECT_METADATA;
1661 
1662 	return 0;
1663 }
1664 
1665 /**
1666  * Get collect metadata status to use for VXLAN
1667  * @arg link		Link object
1668  *
1669  * @return Status value on success or a negative error code
1670  */
rtnl_link_vxlan_get_collect_metadata(struct rtnl_link * link)1671 int rtnl_link_vxlan_get_collect_metadata(struct rtnl_link *link)
1672 {
1673 	struct vxlan_info *vxi = link->l_info;
1674 
1675 	IS_VXLAN_LINK_ASSERT(link);
1676 
1677 	if (!(vxi->ce_mask & VXLAN_ATTR_COLLECT_METADATA))
1678 		return -NLE_NOATTR;
1679 
1680 	return vxi->vxi_collect_metadata;
1681 }
1682 
1683 /**
1684  * Set flow label to use for VXLAN
1685  * @arg link		Link object
1686  * @arg label		Destination label
1687  *
1688  * @return 0 on success or a negative error code
1689  */
rtnl_link_vxlan_set_label(struct rtnl_link * link,uint32_t label)1690 int rtnl_link_vxlan_set_label(struct rtnl_link *link, uint32_t label)
1691 {
1692 	struct vxlan_info *vxi = link->l_info;
1693 
1694 	IS_VXLAN_LINK_ASSERT(link);
1695 
1696 	vxi->vxi_label = htonl(label);
1697 	vxi->ce_mask |= VXLAN_ATTR_LABEL;
1698 
1699 	return 0;
1700 }
1701 
1702 /**
1703  * Get flow label to use for VXLAN
1704  * @arg link		Link object
1705  * @arg label		Pointer to store destination label
1706  *
1707  * @return 0 on success or a negative error code
1708  */
rtnl_link_vxlan_get_label(struct rtnl_link * link,uint32_t * label)1709 int rtnl_link_vxlan_get_label(struct rtnl_link *link, uint32_t *label)
1710 {
1711 	struct vxlan_info *vxi = link->l_info;
1712 
1713 	IS_VXLAN_LINK_ASSERT(link);
1714 
1715 	if (!label)
1716 		return -NLE_INVAL;
1717 
1718 	if (!(vxi->ce_mask & VXLAN_ATTR_LABEL))
1719 		return -NLE_NOATTR;
1720 
1721 	*label = ntohl(vxi->vxi_label);
1722 
1723 	return 0;
1724 }
1725 
1726 /**
1727  * Set VXLAN flags RTNL_LINK_VXLAN_F_*
1728  * @arg link		Link object
1729  * @flags               Which flags to set
1730  * @arg enable		Boolean enabling or disabling flag
1731  *
1732  * @return 0 on success or a negative error code
1733  */
rtnl_link_vxlan_set_flags(struct rtnl_link * link,uint32_t flags,int enable)1734 int rtnl_link_vxlan_set_flags(struct rtnl_link *link, uint32_t flags, int enable)
1735 {
1736 	struct vxlan_info *vxi = link->l_info;
1737 
1738 	IS_VXLAN_LINK_ASSERT(link);
1739 
1740 	if (flags & ~(RTNL_LINK_VXLAN_F_GBP | RTNL_LINK_VXLAN_F_GPE | RTNL_LINK_VXLAN_F_REMCSUM_NOPARTIAL))
1741 		return -NLE_INVAL;
1742 
1743 	if (enable)
1744 		vxi->vxi_flags |= flags;
1745 	else
1746 		vxi->vxi_flags &= ~flags;
1747 
1748 	return 0;
1749 }
1750 
1751 /**
1752  * Get VXLAN flags RTNL_LINK_VXLAN_F_*
1753  * @arg link		Link object
1754  * @arg out_flags       Output value for flags. Must be present.
1755  *
1756  * @return Zero on success or a negative error code
1757  */
rtnl_link_vxlan_get_flags(struct rtnl_link * link,uint32_t * out_flags)1758 int rtnl_link_vxlan_get_flags(struct rtnl_link *link, uint32_t *out_flags)
1759 {
1760 	struct vxlan_info *vxi = link->l_info;
1761 
1762 	IS_VXLAN_LINK_ASSERT(link);
1763 
1764 	*out_flags = vxi->vxi_flags;
1765 	return 0;
1766 }
1767 
1768 /** @} */
1769 
vxlan_init(void)1770 static void __init vxlan_init(void)
1771 {
1772 	rtnl_link_register_info(&vxlan_info_ops);
1773 }
1774 
vxlan_exit(void)1775 static void __exit vxlan_exit(void)
1776 {
1777 	rtnl_link_unregister_info(&vxlan_info_ops);
1778 }
1779 
1780 /** @} */
1781