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