blob: b5d8efabf8c66821b2713c4bab006e06a981e0f8 [file] [log] [blame]
Stephen Hemmingera5494df2012-09-24 12:48:29 -07001/*
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");
Stephen Hemminger2d596122012-10-09 23:39:17 -070027 fprintf(stderr, " [ ttl TTL ] [ tos TOS ] [ dev PHYS_DEV ]\n");
Stephen Hemmingerd85e0a52013-05-03 13:18:45 -070028 fprintf(stderr, " [ dstport PORT ] [ srcport MIN MAX ]\n");
29 fprintf(stderr, " [ [no]learning ] [ [no]proxy ] [ [no]rsc ]\n");
David L Stevens1556e292012-12-12 10:02:19 -080030 fprintf(stderr, " [ [no]l2miss ] [ [no]l3miss ]\n");
Stephen Hemmingera5494df2012-09-24 12:48:29 -070031 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;
David L Stevens1556e292012-12-12 10:02:19 -080049 __u8 proxy = 0;
50 __u8 rsc = 0;
51 __u8 l2miss = 0;
52 __u8 l3miss = 0;
Stephen Hemmingera5494df2012-09-24 12:48:29 -070053 __u8 noage = 0;
54 __u32 age = 0;
55 __u32 maxaddr = 0;
Stephen Hemminger2a126a82013-05-15 13:41:49 -070056 __u16 dstport = 0;
57 int dst_port_set = 0;
Stephen Hemminger2d596122012-10-09 23:39:17 -070058 struct ifla_vxlan_port_range range = { 0, 0 };
Stephen Hemmingera5494df2012-09-24 12:48:29 -070059
60 while (argc > 0) {
61 if (!matches(*argv, "id") ||
62 !matches(*argv, "vni")) {
63 NEXT_ARG();
64 if (get_u32(&vni, *argv, 0) ||
65 vni >= 1u << 24)
66 invarg("invalid id", *argv);
67 vni_set = 1;
68 } else if (!matches(*argv, "group")) {
69 NEXT_ARG();
70 gaddr = get_addr32(*argv);
71
72 if (!IN_MULTICAST(ntohl(gaddr)))
73 invarg("invald group address", *argv);
74 } else if (!matches(*argv, "local")) {
75 NEXT_ARG();
76 if (strcmp(*argv, "any"))
77 saddr = get_addr32(*argv);
78 if (IN_MULTICAST(ntohl(saddr)))
79 invarg("invalid local address", *argv);
80 } else if (!matches(*argv, "dev")) {
81 NEXT_ARG();
82 link = if_nametoindex(*argv);
83 if (link == 0)
84 exit(-1);
85 } else if (!matches(*argv, "ttl") ||
86 !matches(*argv, "hoplimit")) {
87 unsigned uval;
88
89 NEXT_ARG();
90 if (strcmp(*argv, "inherit") != 0) {
91 if (get_unsigned(&uval, *argv, 0))
Stephen Hemminger2d596122012-10-09 23:39:17 -070092 invarg("invalid TTL", *argv);
Stephen Hemmingera5494df2012-09-24 12:48:29 -070093 if (uval > 255)
Stephen Hemminger2d596122012-10-09 23:39:17 -070094 invarg("TTL must be <= 255", *argv);
Stephen Hemmingera5494df2012-09-24 12:48:29 -070095 ttl = uval;
96 }
97 } else if (!matches(*argv, "tos") ||
98 !matches(*argv, "dsfield")) {
99 __u32 uval;
100
101 NEXT_ARG();
102 if (strcmp(*argv, "inherit") != 0) {
103 if (rtnl_dsfield_a2n(&uval, *argv))
104 invarg("bad TOS value", *argv);
105 tos = uval;
106 } else
107 tos = 1;
108 } else if (!matches(*argv, "ageing")) {
109 NEXT_ARG();
110 if (strcmp(*argv, "none") == 0)
111 noage = 1;
112 else if (get_u32(&age, *argv, 0))
Stephen Hemminger2d596122012-10-09 23:39:17 -0700113 invarg("ageing timer", *argv);
Stephen Hemmingera5494df2012-09-24 12:48:29 -0700114 } else if (!matches(*argv, "maxaddress")) {
115 NEXT_ARG();
116 if (strcmp(*argv, "unlimited") == 0)
117 maxaddr = 0;
118 else if (get_u32(&maxaddr, *argv, 0))
Stephen Hemminger2d596122012-10-09 23:39:17 -0700119 invarg("max addresses", *argv);
Stephen Hemmingerd85e0a52013-05-03 13:18:45 -0700120 } else if (!matches(*argv, "port") ||
121 !matches(*argv, "srcport")) {
Stephen Hemminger2d596122012-10-09 23:39:17 -0700122 __u16 minport, maxport;
123 NEXT_ARG();
124 if (get_u16(&minport, *argv, 0))
125 invarg("min port", *argv);
126 NEXT_ARG();
127 if (get_u16(&maxport, *argv, 0))
128 invarg("max port", *argv);
129 range.low = htons(minport);
130 range.high = htons(maxport);
Stephen Hemmingerd85e0a52013-05-03 13:18:45 -0700131 } else if (!matches(*argv, "dstport")){
132 NEXT_ARG();
133 if (get_u16(&dstport, *argv, 0))
134 invarg("dst port", *argv);
Stephen Hemminger2a126a82013-05-15 13:41:49 -0700135 dst_port_set = 1;
Stephen Hemmingera5494df2012-09-24 12:48:29 -0700136 } else if (!matches(*argv, "nolearning")) {
137 learning = 0;
138 } else if (!matches(*argv, "learning")) {
139 learning = 1;
David L Stevens1556e292012-12-12 10:02:19 -0800140 } else if (!matches(*argv, "noproxy")) {
141 proxy = 0;
142 } else if (!matches(*argv, "proxy")) {
143 proxy = 1;
144 } else if (!matches(*argv, "norsc")) {
145 rsc = 0;
146 } else if (!matches(*argv, "rsc")) {
147 rsc = 1;
148 } else if (!matches(*argv, "nol2miss")) {
149 l2miss = 0;
150 } else if (!matches(*argv, "l2miss")) {
151 l2miss = 1;
152 } else if (!matches(*argv, "nol3miss")) {
153 l3miss = 0;
154 } else if (!matches(*argv, "l3miss")) {
155 l3miss = 1;
Stephen Hemmingera5494df2012-09-24 12:48:29 -0700156 } else if (matches(*argv, "help") == 0) {
157 explain();
158 return -1;
159 } else {
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +0000160 fprintf(stderr, "vxlan: unknown command \"%s\"?\n", *argv);
Stephen Hemmingera5494df2012-09-24 12:48:29 -0700161 explain();
162 return -1;
163 }
164 argc--, argv++;
165 }
Stephen Hemminger2a126a82013-05-15 13:41:49 -0700166
Stephen Hemmingera5494df2012-09-24 12:48:29 -0700167 if (!vni_set) {
168 fprintf(stderr, "vxlan: missing virtual network identifier\n");
169 return -1;
170 }
Stephen Hemminger2a126a82013-05-15 13:41:49 -0700171
172 if (!dst_port_set) {
173 fprintf(stderr, "vxlan: destination port not specified\n"
174 "Will use Linux kernel default (non-standard value)\n");
175 fprintf(stderr,
176 "Use 'dstport 4789' to get the IANA assigned value\n"
177 "Use 'dstport 0' to get default and quiet this message\n");
178 }
179
Stephen Hemmingera5494df2012-09-24 12:48:29 -0700180 addattr32(n, 1024, IFLA_VXLAN_ID, vni);
Stephen Hemmingerb64da5a2012-10-19 13:25:17 -0700181 if (gaddr)
182 addattr_l(n, 1024, IFLA_VXLAN_GROUP, &gaddr, 4);
183 if (saddr)
184 addattr_l(n, 1024, IFLA_VXLAN_LOCAL, &saddr, 4);
Stephen Hemmingera5494df2012-09-24 12:48:29 -0700185 if (link)
186 addattr32(n, 1024, IFLA_VXLAN_LINK, link);
187 addattr8(n, 1024, IFLA_VXLAN_TTL, ttl);
188 addattr8(n, 1024, IFLA_VXLAN_TOS, tos);
189 addattr8(n, 1024, IFLA_VXLAN_LEARNING, learning);
David L Stevens1556e292012-12-12 10:02:19 -0800190 addattr8(n, 1024, IFLA_VXLAN_PROXY, proxy);
191 addattr8(n, 1024, IFLA_VXLAN_RSC, rsc);
192 addattr8(n, 1024, IFLA_VXLAN_L2MISS, l2miss);
193 addattr8(n, 1024, IFLA_VXLAN_L3MISS, l3miss);
Stephen Hemminger2a126a82013-05-15 13:41:49 -0700194
Stephen Hemmingera5494df2012-09-24 12:48:29 -0700195 if (noage)
196 addattr32(n, 1024, IFLA_VXLAN_AGEING, 0);
197 else if (age)
198 addattr32(n, 1024, IFLA_VXLAN_AGEING, age);
199 if (maxaddr)
200 addattr32(n, 1024, IFLA_VXLAN_LIMIT, maxaddr);
Stephen Hemminger2d596122012-10-09 23:39:17 -0700201 if (range.low || range.high)
202 addattr_l(n, 1024, IFLA_VXLAN_PORT_RANGE,
203 &range, sizeof(range));
Stephen Hemmingerd85e0a52013-05-03 13:18:45 -0700204 if (dstport)
205 addattr16(n, 1024, IFLA_VXLAN_PORT, htons(dstport));
Stephen Hemmingera5494df2012-09-24 12:48:29 -0700206
207 return 0;
208}
209
210static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
211{
212 __u32 vni;
213 unsigned link;
Stephen Hemminger2d596122012-10-09 23:39:17 -0700214 __u8 tos;
215 __u32 maxaddr;
Stephen Hemmingera5494df2012-09-24 12:48:29 -0700216 char s1[1024];
217 char s2[64];
218
219 if (!tb)
220 return;
221
222 if (!tb[IFLA_VXLAN_ID] ||
223 RTA_PAYLOAD(tb[IFLA_VXLAN_ID]) < sizeof(__u32))
224 return;
225
226 vni = rta_getattr_u32(tb[IFLA_VXLAN_ID]);
227 fprintf(f, "id %u ", vni);
228
229 if (tb[IFLA_VXLAN_GROUP]) {
Stephen Hemmingerb64da5a2012-10-19 13:25:17 -0700230 __be32 addr = rta_getattr_u32(tb[IFLA_VXLAN_GROUP]);
Stephen Hemmingera5494df2012-09-24 12:48:29 -0700231 if (addr)
232 fprintf(f, "group %s ",
233 format_host(AF_INET, 4, &addr, s1, sizeof(s1)));
234 }
235
236 if (tb[IFLA_VXLAN_LOCAL]) {
Stephen Hemmingerb64da5a2012-10-19 13:25:17 -0700237 __be32 addr = rta_getattr_u32(tb[IFLA_VXLAN_LOCAL]);
Stephen Hemmingera5494df2012-09-24 12:48:29 -0700238 if (addr)
David L Stevens1556e292012-12-12 10:02:19 -0800239 fprintf(f, "local %s ",
Stephen Hemmingera5494df2012-09-24 12:48:29 -0700240 format_host(AF_INET, 4, &addr, s1, sizeof(s1)));
241 }
242
243 if (tb[IFLA_VXLAN_LINK] &&
244 (link = rta_getattr_u32(tb[IFLA_VXLAN_LINK]))) {
245 const char *n = if_indextoname(link, s2);
246
247 if (n)
248 fprintf(f, "dev %s ", n);
249 else
250 fprintf(f, "dev %u ", link);
251 }
252
Stephen Hemminger2d596122012-10-09 23:39:17 -0700253 if (tb[IFLA_VXLAN_PORT_RANGE]) {
254 const struct ifla_vxlan_port_range *r
255 = RTA_DATA(tb[IFLA_VXLAN_PORT_RANGE]);
Stephen Hemmingerd85e0a52013-05-03 13:18:45 -0700256 fprintf(f, "srcport %u %u ", ntohs(r->low), ntohs(r->high));
David L Stevens1556e292012-12-12 10:02:19 -0800257 }
Stephen Hemminger2d596122012-10-09 23:39:17 -0700258
Stephen Hemmingerd85e0a52013-05-03 13:18:45 -0700259 if (tb[IFLA_VXLAN_PORT])
260 fprintf(f, "dstport %u ",
261 ntohs(rta_getattr_u16(tb[IFLA_VXLAN_PORT])));
262
Stephen Hemmingera5494df2012-09-24 12:48:29 -0700263 if (tb[IFLA_VXLAN_LEARNING] &&
264 !rta_getattr_u8(tb[IFLA_VXLAN_LEARNING]))
265 fputs("nolearning ", f);
David L Stevens1556e292012-12-12 10:02:19 -0800266
267 if (tb[IFLA_VXLAN_PROXY] && rta_getattr_u8(tb[IFLA_VXLAN_PROXY]))
268 fputs("proxy ", f);
269
270 if (tb[IFLA_VXLAN_RSC] && rta_getattr_u8(tb[IFLA_VXLAN_RSC]))
271 fputs("rsc ", f);
272
273 if (tb[IFLA_VXLAN_L2MISS] && rta_getattr_u8(tb[IFLA_VXLAN_L2MISS]))
274 fputs("l2miss ", f);
275
276 if (tb[IFLA_VXLAN_L3MISS] && rta_getattr_u8(tb[IFLA_VXLAN_L3MISS]))
277 fputs("l3miss ", f);
278
Stephen Hemminger2d596122012-10-09 23:39:17 -0700279 if (tb[IFLA_VXLAN_TOS] &&
280 (tos = rta_getattr_u8(tb[IFLA_VXLAN_TOS]))) {
Stephen Hemmingera5494df2012-09-24 12:48:29 -0700281 if (tos == 1)
282 fprintf(f, "tos inherit ");
283 else
284 fprintf(f, "tos %#x ", tos);
285 }
286
287 if (tb[IFLA_VXLAN_TTL]) {
288 __u8 ttl = rta_getattr_u8(tb[IFLA_VXLAN_TTL]);
289 if (ttl)
290 fprintf(f, "ttl %d ", ttl);
291 }
292
293 if (tb[IFLA_VXLAN_AGEING]) {
294 __u32 age = rta_getattr_u32(tb[IFLA_VXLAN_AGEING]);
295 if (age == 0)
296 fprintf(f, "ageing none ");
297 else
298 fprintf(f, "ageing %u ", age);
299 }
Stephen Hemminger2d596122012-10-09 23:39:17 -0700300
301 if (tb[IFLA_VXLAN_LIMIT] &&
302 (maxaddr = rta_getattr_u32(tb[IFLA_VXLAN_LIMIT]) != 0))
303 fprintf(f, "maxaddr %u ", maxaddr);
Stephen Hemmingera5494df2012-09-24 12:48:29 -0700304}
305
306struct link_util vxlan_link_util = {
307 .id = "vxlan",
308 .maxattr = IFLA_VXLAN_MAX,
309 .parse_opt = vxlan_parse_opt,
310 .print_opt = vxlan_print_opt,
311};