blob: 4b72361e3b6c945f55c5aef15721c173568f7d54 [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");
28 fprintf(stderr, " [ port MIN MAX ] [ [no]learning ]\n");
David L Stevens1556e292012-12-12 10:02:19 -080029 fprintf(stderr, " [ [no]proxy ] [ [no]rsc ]\n");
30 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 Hemminger2d596122012-10-09 23:39:17 -070056 struct ifla_vxlan_port_range range = { 0, 0 };
Stephen Hemmingera5494df2012-09-24 12:48:29 -070057
58 while (argc > 0) {
59 if (!matches(*argv, "id") ||
60 !matches(*argv, "vni")) {
61 NEXT_ARG();
62 if (get_u32(&vni, *argv, 0) ||
63 vni >= 1u << 24)
64 invarg("invalid id", *argv);
65 vni_set = 1;
66 } else if (!matches(*argv, "group")) {
67 NEXT_ARG();
68 gaddr = get_addr32(*argv);
69
70 if (!IN_MULTICAST(ntohl(gaddr)))
71 invarg("invald group address", *argv);
72 } else if (!matches(*argv, "local")) {
73 NEXT_ARG();
74 if (strcmp(*argv, "any"))
75 saddr = get_addr32(*argv);
76 if (IN_MULTICAST(ntohl(saddr)))
77 invarg("invalid local address", *argv);
78 } else if (!matches(*argv, "dev")) {
79 NEXT_ARG();
80 link = if_nametoindex(*argv);
81 if (link == 0)
82 exit(-1);
83 } else if (!matches(*argv, "ttl") ||
84 !matches(*argv, "hoplimit")) {
85 unsigned uval;
86
87 NEXT_ARG();
88 if (strcmp(*argv, "inherit") != 0) {
89 if (get_unsigned(&uval, *argv, 0))
Stephen Hemminger2d596122012-10-09 23:39:17 -070090 invarg("invalid TTL", *argv);
Stephen Hemmingera5494df2012-09-24 12:48:29 -070091 if (uval > 255)
Stephen Hemminger2d596122012-10-09 23:39:17 -070092 invarg("TTL must be <= 255", *argv);
Stephen Hemmingera5494df2012-09-24 12:48:29 -070093 ttl = uval;
94 }
95 } else if (!matches(*argv, "tos") ||
96 !matches(*argv, "dsfield")) {
97 __u32 uval;
98
99 NEXT_ARG();
100 if (strcmp(*argv, "inherit") != 0) {
101 if (rtnl_dsfield_a2n(&uval, *argv))
102 invarg("bad TOS value", *argv);
103 tos = uval;
104 } else
105 tos = 1;
106 } else if (!matches(*argv, "ageing")) {
107 NEXT_ARG();
108 if (strcmp(*argv, "none") == 0)
109 noage = 1;
110 else if (get_u32(&age, *argv, 0))
Stephen Hemminger2d596122012-10-09 23:39:17 -0700111 invarg("ageing timer", *argv);
Stephen Hemmingera5494df2012-09-24 12:48:29 -0700112 } else if (!matches(*argv, "maxaddress")) {
113 NEXT_ARG();
114 if (strcmp(*argv, "unlimited") == 0)
115 maxaddr = 0;
116 else if (get_u32(&maxaddr, *argv, 0))
Stephen Hemminger2d596122012-10-09 23:39:17 -0700117 invarg("max addresses", *argv);
118 } else if (!matches(*argv, "port")) {
119 __u16 minport, maxport;
120 NEXT_ARG();
121 if (get_u16(&minport, *argv, 0))
122 invarg("min port", *argv);
123 NEXT_ARG();
124 if (get_u16(&maxport, *argv, 0))
125 invarg("max port", *argv);
126 range.low = htons(minport);
127 range.high = htons(maxport);
Stephen Hemmingera5494df2012-09-24 12:48:29 -0700128 } else if (!matches(*argv, "nolearning")) {
129 learning = 0;
130 } else if (!matches(*argv, "learning")) {
131 learning = 1;
David L Stevens1556e292012-12-12 10:02:19 -0800132 } else if (!matches(*argv, "noproxy")) {
133 proxy = 0;
134 } else if (!matches(*argv, "proxy")) {
135 proxy = 1;
136 } else if (!matches(*argv, "norsc")) {
137 rsc = 0;
138 } else if (!matches(*argv, "rsc")) {
139 rsc = 1;
140 } else if (!matches(*argv, "nol2miss")) {
141 l2miss = 0;
142 } else if (!matches(*argv, "l2miss")) {
143 l2miss = 1;
144 } else if (!matches(*argv, "nol3miss")) {
145 l3miss = 0;
146 } else if (!matches(*argv, "l3miss")) {
147 l3miss = 1;
Stephen Hemmingera5494df2012-09-24 12:48:29 -0700148 } else if (matches(*argv, "help") == 0) {
149 explain();
150 return -1;
151 } else {
152 fprintf(stderr, "vxlan: what is \"%s\"?\n", *argv);
153 explain();
154 return -1;
155 }
156 argc--, argv++;
157 }
158
159 if (!vni_set) {
160 fprintf(stderr, "vxlan: missing virtual network identifier\n");
161 return -1;
162 }
163 addattr32(n, 1024, IFLA_VXLAN_ID, vni);
Stephen Hemmingerb64da5a2012-10-19 13:25:17 -0700164 if (gaddr)
165 addattr_l(n, 1024, IFLA_VXLAN_GROUP, &gaddr, 4);
166 if (saddr)
167 addattr_l(n, 1024, IFLA_VXLAN_LOCAL, &saddr, 4);
Stephen Hemmingera5494df2012-09-24 12:48:29 -0700168 if (link)
169 addattr32(n, 1024, IFLA_VXLAN_LINK, link);
170 addattr8(n, 1024, IFLA_VXLAN_TTL, ttl);
171 addattr8(n, 1024, IFLA_VXLAN_TOS, tos);
172 addattr8(n, 1024, IFLA_VXLAN_LEARNING, learning);
David L Stevens1556e292012-12-12 10:02:19 -0800173 addattr8(n, 1024, IFLA_VXLAN_PROXY, proxy);
174 addattr8(n, 1024, IFLA_VXLAN_RSC, rsc);
175 addattr8(n, 1024, IFLA_VXLAN_L2MISS, l2miss);
176 addattr8(n, 1024, IFLA_VXLAN_L3MISS, l3miss);
Stephen Hemmingera5494df2012-09-24 12:48:29 -0700177 if (noage)
178 addattr32(n, 1024, IFLA_VXLAN_AGEING, 0);
179 else if (age)
180 addattr32(n, 1024, IFLA_VXLAN_AGEING, age);
181 if (maxaddr)
182 addattr32(n, 1024, IFLA_VXLAN_LIMIT, maxaddr);
Stephen Hemminger2d596122012-10-09 23:39:17 -0700183 if (range.low || range.high)
184 addattr_l(n, 1024, IFLA_VXLAN_PORT_RANGE,
185 &range, sizeof(range));
Stephen Hemmingera5494df2012-09-24 12:48:29 -0700186
187 return 0;
188}
189
190static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
191{
192 __u32 vni;
193 unsigned link;
Stephen Hemminger2d596122012-10-09 23:39:17 -0700194 __u8 tos;
195 __u32 maxaddr;
Stephen Hemmingera5494df2012-09-24 12:48:29 -0700196 char s1[1024];
197 char s2[64];
198
199 if (!tb)
200 return;
201
202 if (!tb[IFLA_VXLAN_ID] ||
203 RTA_PAYLOAD(tb[IFLA_VXLAN_ID]) < sizeof(__u32))
204 return;
205
206 vni = rta_getattr_u32(tb[IFLA_VXLAN_ID]);
207 fprintf(f, "id %u ", vni);
208
209 if (tb[IFLA_VXLAN_GROUP]) {
Stephen Hemmingerb64da5a2012-10-19 13:25:17 -0700210 __be32 addr = rta_getattr_u32(tb[IFLA_VXLAN_GROUP]);
Stephen Hemmingera5494df2012-09-24 12:48:29 -0700211 if (addr)
212 fprintf(f, "group %s ",
213 format_host(AF_INET, 4, &addr, s1, sizeof(s1)));
214 }
215
216 if (tb[IFLA_VXLAN_LOCAL]) {
Stephen Hemmingerb64da5a2012-10-19 13:25:17 -0700217 __be32 addr = rta_getattr_u32(tb[IFLA_VXLAN_LOCAL]);
Stephen Hemmingera5494df2012-09-24 12:48:29 -0700218 if (addr)
David L Stevens1556e292012-12-12 10:02:19 -0800219 fprintf(f, "local %s ",
Stephen Hemmingera5494df2012-09-24 12:48:29 -0700220 format_host(AF_INET, 4, &addr, s1, sizeof(s1)));
221 }
222
223 if (tb[IFLA_VXLAN_LINK] &&
224 (link = rta_getattr_u32(tb[IFLA_VXLAN_LINK]))) {
225 const char *n = if_indextoname(link, s2);
226
227 if (n)
228 fprintf(f, "dev %s ", n);
229 else
230 fprintf(f, "dev %u ", link);
231 }
232
Stephen Hemminger2d596122012-10-09 23:39:17 -0700233 if (tb[IFLA_VXLAN_PORT_RANGE]) {
234 const struct ifla_vxlan_port_range *r
235 = RTA_DATA(tb[IFLA_VXLAN_PORT_RANGE]);
236 fprintf(f, "port %u %u ", ntohs(r->low), ntohs(r->high));
David L Stevens1556e292012-12-12 10:02:19 -0800237 }
Stephen Hemminger2d596122012-10-09 23:39:17 -0700238
Stephen Hemmingera5494df2012-09-24 12:48:29 -0700239 if (tb[IFLA_VXLAN_LEARNING] &&
240 !rta_getattr_u8(tb[IFLA_VXLAN_LEARNING]))
241 fputs("nolearning ", f);
David L Stevens1556e292012-12-12 10:02:19 -0800242
243 if (tb[IFLA_VXLAN_PROXY] && rta_getattr_u8(tb[IFLA_VXLAN_PROXY]))
244 fputs("proxy ", f);
245
246 if (tb[IFLA_VXLAN_RSC] && rta_getattr_u8(tb[IFLA_VXLAN_RSC]))
247 fputs("rsc ", f);
248
249 if (tb[IFLA_VXLAN_L2MISS] && rta_getattr_u8(tb[IFLA_VXLAN_L2MISS]))
250 fputs("l2miss ", f);
251
252 if (tb[IFLA_VXLAN_L3MISS] && rta_getattr_u8(tb[IFLA_VXLAN_L3MISS]))
253 fputs("l3miss ", f);
254
Stephen Hemminger2d596122012-10-09 23:39:17 -0700255 if (tb[IFLA_VXLAN_TOS] &&
256 (tos = rta_getattr_u8(tb[IFLA_VXLAN_TOS]))) {
Stephen Hemmingera5494df2012-09-24 12:48:29 -0700257 if (tos == 1)
258 fprintf(f, "tos inherit ");
259 else
260 fprintf(f, "tos %#x ", tos);
261 }
262
263 if (tb[IFLA_VXLAN_TTL]) {
264 __u8 ttl = rta_getattr_u8(tb[IFLA_VXLAN_TTL]);
265 if (ttl)
266 fprintf(f, "ttl %d ", ttl);
267 }
268
269 if (tb[IFLA_VXLAN_AGEING]) {
270 __u32 age = rta_getattr_u32(tb[IFLA_VXLAN_AGEING]);
271 if (age == 0)
272 fprintf(f, "ageing none ");
273 else
274 fprintf(f, "ageing %u ", age);
275 }
Stephen Hemminger2d596122012-10-09 23:39:17 -0700276
277 if (tb[IFLA_VXLAN_LIMIT] &&
278 (maxaddr = rta_getattr_u32(tb[IFLA_VXLAN_LIMIT]) != 0))
279 fprintf(f, "maxaddr %u ", maxaddr);
Stephen Hemmingera5494df2012-09-24 12:48:29 -0700280}
281
282struct link_util vxlan_link_util = {
283 .id = "vxlan",
284 .maxattr = IFLA_VXLAN_MAX,
285 .parse_opt = vxlan_parse_opt,
286 .print_opt = vxlan_print_opt,
287};