]> git.proxmox.com Git - mirror_iproute2.git/blame - ip/iplink_vxlan.c
iproute2: support NTF_ROUTER flag in VXLAN fdb entries
[mirror_iproute2.git] / ip / iplink_vxlan.c
CommitLineData
a5494df2
SH
1/*
2 * iplink_vxlan.c VXLAN device support
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * Authors: Stephen Hemminger <shemminger@vyatta.com
10 */
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <net/if.h>
16#include <linux/ip.h>
17#include <linux/if_link.h>
18#include <arpa/inet.h>
19
20#include "rt_names.h"
21#include "utils.h"
22#include "ip_common.h"
23
24static void explain(void)
25{
26 fprintf(stderr, "Usage: ... vxlan id VNI [ group ADDR ] [ local ADDR ]\n");
2d596120 27 fprintf(stderr, " [ ttl TTL ] [ tos TOS ] [ dev PHYS_DEV ]\n");
d85e0a59
SH
28 fprintf(stderr, " [ dstport PORT ] [ srcport MIN MAX ]\n");
29 fprintf(stderr, " [ [no]learning ] [ [no]proxy ] [ [no]rsc ]\n");
1556e29d 30 fprintf(stderr, " [ [no]l2miss ] [ [no]l3miss ]\n");
a5494df2
SH
31 fprintf(stderr, "\n");
32 fprintf(stderr, "Where: VNI := 0-16777215\n");
33 fprintf(stderr, " ADDR := { IP_ADDRESS | any }\n");
34 fprintf(stderr, " TOS := { NUMBER | inherit }\n");
35 fprintf(stderr, " TTL := { 1..255 | inherit }\n");
36}
37
38static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
39 struct nlmsghdr *n)
40{
41 __u32 vni = 0;
42 int vni_set = 0;
43 __u32 saddr = 0;
44 __u32 gaddr = 0;
45 unsigned link = 0;
46 __u8 tos = 0;
47 __u8 ttl = 0;
48 __u8 learning = 1;
1556e29d
DS
49 __u8 proxy = 0;
50 __u8 rsc = 0;
51 __u8 l2miss = 0;
52 __u8 l3miss = 0;
a5494df2
SH
53 __u8 noage = 0;
54 __u32 age = 0;
55 __u32 maxaddr = 0;
d85e0a59 56 __u16 dstport = 4789;
2d596120 57 struct ifla_vxlan_port_range range = { 0, 0 };
a5494df2
SH
58
59 while (argc > 0) {
60 if (!matches(*argv, "id") ||
61 !matches(*argv, "vni")) {
62 NEXT_ARG();
63 if (get_u32(&vni, *argv, 0) ||
64 vni >= 1u << 24)
65 invarg("invalid id", *argv);
66 vni_set = 1;
67 } else if (!matches(*argv, "group")) {
68 NEXT_ARG();
69 gaddr = get_addr32(*argv);
70
71 if (!IN_MULTICAST(ntohl(gaddr)))
72 invarg("invald group address", *argv);
73 } else if (!matches(*argv, "local")) {
74 NEXT_ARG();
75 if (strcmp(*argv, "any"))
76 saddr = get_addr32(*argv);
77 if (IN_MULTICAST(ntohl(saddr)))
78 invarg("invalid local address", *argv);
79 } else if (!matches(*argv, "dev")) {
80 NEXT_ARG();
81 link = if_nametoindex(*argv);
82 if (link == 0)
83 exit(-1);
84 } else if (!matches(*argv, "ttl") ||
85 !matches(*argv, "hoplimit")) {
86 unsigned uval;
87
88 NEXT_ARG();
89 if (strcmp(*argv, "inherit") != 0) {
90 if (get_unsigned(&uval, *argv, 0))
2d596120 91 invarg("invalid TTL", *argv);
a5494df2 92 if (uval > 255)
2d596120 93 invarg("TTL must be <= 255", *argv);
a5494df2
SH
94 ttl = uval;
95 }
96 } else if (!matches(*argv, "tos") ||
97 !matches(*argv, "dsfield")) {
98 __u32 uval;
99
100 NEXT_ARG();
101 if (strcmp(*argv, "inherit") != 0) {
102 if (rtnl_dsfield_a2n(&uval, *argv))
103 invarg("bad TOS value", *argv);
104 tos = uval;
105 } else
106 tos = 1;
107 } else if (!matches(*argv, "ageing")) {
108 NEXT_ARG();
109 if (strcmp(*argv, "none") == 0)
110 noage = 1;
111 else if (get_u32(&age, *argv, 0))
2d596120 112 invarg("ageing timer", *argv);
a5494df2
SH
113 } else if (!matches(*argv, "maxaddress")) {
114 NEXT_ARG();
115 if (strcmp(*argv, "unlimited") == 0)
116 maxaddr = 0;
117 else if (get_u32(&maxaddr, *argv, 0))
2d596120 118 invarg("max addresses", *argv);
d85e0a59
SH
119 } else if (!matches(*argv, "port") ||
120 !matches(*argv, "srcport")) {
2d596120
SH
121 __u16 minport, maxport;
122 NEXT_ARG();
123 if (get_u16(&minport, *argv, 0))
124 invarg("min port", *argv);
125 NEXT_ARG();
126 if (get_u16(&maxport, *argv, 0))
127 invarg("max port", *argv);
128 range.low = htons(minport);
129 range.high = htons(maxport);
d85e0a59
SH
130 } else if (!matches(*argv, "dstport")){
131 NEXT_ARG();
132 if (get_u16(&dstport, *argv, 0))
133 invarg("dst port", *argv);
a5494df2
SH
134 } else if (!matches(*argv, "nolearning")) {
135 learning = 0;
136 } else if (!matches(*argv, "learning")) {
137 learning = 1;
1556e29d
DS
138 } else if (!matches(*argv, "noproxy")) {
139 proxy = 0;
140 } else if (!matches(*argv, "proxy")) {
141 proxy = 1;
142 } else if (!matches(*argv, "norsc")) {
143 rsc = 0;
144 } else if (!matches(*argv, "rsc")) {
145 rsc = 1;
146 } else if (!matches(*argv, "nol2miss")) {
147 l2miss = 0;
148 } else if (!matches(*argv, "l2miss")) {
149 l2miss = 1;
150 } else if (!matches(*argv, "nol3miss")) {
151 l3miss = 0;
152 } else if (!matches(*argv, "l3miss")) {
153 l3miss = 1;
a5494df2
SH
154 } else if (matches(*argv, "help") == 0) {
155 explain();
156 return -1;
157 } else {
14645ec2 158 fprintf(stderr, "vxlan: unknown command \"%s\"?\n", *argv);
a5494df2
SH
159 explain();
160 return -1;
161 }
162 argc--, argv++;
163 }
a5494df2
SH
164 if (!vni_set) {
165 fprintf(stderr, "vxlan: missing virtual network identifier\n");
166 return -1;
167 }
168 addattr32(n, 1024, IFLA_VXLAN_ID, vni);
b64da5a5
SH
169 if (gaddr)
170 addattr_l(n, 1024, IFLA_VXLAN_GROUP, &gaddr, 4);
171 if (saddr)
172 addattr_l(n, 1024, IFLA_VXLAN_LOCAL, &saddr, 4);
a5494df2
SH
173 if (link)
174 addattr32(n, 1024, IFLA_VXLAN_LINK, link);
175 addattr8(n, 1024, IFLA_VXLAN_TTL, ttl);
176 addattr8(n, 1024, IFLA_VXLAN_TOS, tos);
177 addattr8(n, 1024, IFLA_VXLAN_LEARNING, learning);
1556e29d
DS
178 addattr8(n, 1024, IFLA_VXLAN_PROXY, proxy);
179 addattr8(n, 1024, IFLA_VXLAN_RSC, rsc);
180 addattr8(n, 1024, IFLA_VXLAN_L2MISS, l2miss);
181 addattr8(n, 1024, IFLA_VXLAN_L3MISS, l3miss);
a5494df2
SH
182 if (noage)
183 addattr32(n, 1024, IFLA_VXLAN_AGEING, 0);
184 else if (age)
185 addattr32(n, 1024, IFLA_VXLAN_AGEING, age);
186 if (maxaddr)
187 addattr32(n, 1024, IFLA_VXLAN_LIMIT, maxaddr);
2d596120
SH
188 if (range.low || range.high)
189 addattr_l(n, 1024, IFLA_VXLAN_PORT_RANGE,
190 &range, sizeof(range));
d85e0a59
SH
191 if (dstport)
192 addattr16(n, 1024, IFLA_VXLAN_PORT, htons(dstport));
a5494df2
SH
193
194 return 0;
195}
196
197static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
198{
199 __u32 vni;
200 unsigned link;
2d596120
SH
201 __u8 tos;
202 __u32 maxaddr;
a5494df2
SH
203 char s1[1024];
204 char s2[64];
205
206 if (!tb)
207 return;
208
209 if (!tb[IFLA_VXLAN_ID] ||
210 RTA_PAYLOAD(tb[IFLA_VXLAN_ID]) < sizeof(__u32))
211 return;
212
213 vni = rta_getattr_u32(tb[IFLA_VXLAN_ID]);
214 fprintf(f, "id %u ", vni);
215
216 if (tb[IFLA_VXLAN_GROUP]) {
b64da5a5 217 __be32 addr = rta_getattr_u32(tb[IFLA_VXLAN_GROUP]);
a5494df2
SH
218 if (addr)
219 fprintf(f, "group %s ",
220 format_host(AF_INET, 4, &addr, s1, sizeof(s1)));
221 }
222
223 if (tb[IFLA_VXLAN_LOCAL]) {
b64da5a5 224 __be32 addr = rta_getattr_u32(tb[IFLA_VXLAN_LOCAL]);
a5494df2 225 if (addr)
1556e29d 226 fprintf(f, "local %s ",
a5494df2
SH
227 format_host(AF_INET, 4, &addr, s1, sizeof(s1)));
228 }
229
230 if (tb[IFLA_VXLAN_LINK] &&
231 (link = rta_getattr_u32(tb[IFLA_VXLAN_LINK]))) {
232 const char *n = if_indextoname(link, s2);
233
234 if (n)
235 fprintf(f, "dev %s ", n);
236 else
237 fprintf(f, "dev %u ", link);
238 }
239
2d596120
SH
240 if (tb[IFLA_VXLAN_PORT_RANGE]) {
241 const struct ifla_vxlan_port_range *r
242 = RTA_DATA(tb[IFLA_VXLAN_PORT_RANGE]);
d85e0a59 243 fprintf(f, "srcport %u %u ", ntohs(r->low), ntohs(r->high));
1556e29d 244 }
2d596120 245
d85e0a59
SH
246 if (tb[IFLA_VXLAN_PORT])
247 fprintf(f, "dstport %u ",
248 ntohs(rta_getattr_u16(tb[IFLA_VXLAN_PORT])));
249
a5494df2
SH
250 if (tb[IFLA_VXLAN_LEARNING] &&
251 !rta_getattr_u8(tb[IFLA_VXLAN_LEARNING]))
252 fputs("nolearning ", f);
1556e29d
DS
253
254 if (tb[IFLA_VXLAN_PROXY] && rta_getattr_u8(tb[IFLA_VXLAN_PROXY]))
255 fputs("proxy ", f);
256
257 if (tb[IFLA_VXLAN_RSC] && rta_getattr_u8(tb[IFLA_VXLAN_RSC]))
258 fputs("rsc ", f);
259
260 if (tb[IFLA_VXLAN_L2MISS] && rta_getattr_u8(tb[IFLA_VXLAN_L2MISS]))
261 fputs("l2miss ", f);
262
263 if (tb[IFLA_VXLAN_L3MISS] && rta_getattr_u8(tb[IFLA_VXLAN_L3MISS]))
264 fputs("l3miss ", f);
265
2d596120
SH
266 if (tb[IFLA_VXLAN_TOS] &&
267 (tos = rta_getattr_u8(tb[IFLA_VXLAN_TOS]))) {
a5494df2
SH
268 if (tos == 1)
269 fprintf(f, "tos inherit ");
270 else
271 fprintf(f, "tos %#x ", tos);
272 }
273
274 if (tb[IFLA_VXLAN_TTL]) {
275 __u8 ttl = rta_getattr_u8(tb[IFLA_VXLAN_TTL]);
276 if (ttl)
277 fprintf(f, "ttl %d ", ttl);
278 }
279
280 if (tb[IFLA_VXLAN_AGEING]) {
281 __u32 age = rta_getattr_u32(tb[IFLA_VXLAN_AGEING]);
282 if (age == 0)
283 fprintf(f, "ageing none ");
284 else
285 fprintf(f, "ageing %u ", age);
286 }
2d596120
SH
287
288 if (tb[IFLA_VXLAN_LIMIT] &&
289 (maxaddr = rta_getattr_u32(tb[IFLA_VXLAN_LIMIT]) != 0))
290 fprintf(f, "maxaddr %u ", maxaddr);
a5494df2
SH
291}
292
293struct link_util vxlan_link_util = {
294 .id = "vxlan",
295 .maxattr = IFLA_VXLAN_MAX,
296 .parse_opt = vxlan_parse_opt,
297 .print_opt = vxlan_print_opt,
298};