blob: 7957781ca424caea060a2a8e44380f4694700ee9 [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");
Stephen Hemmingera5494df2012-09-24 12:48:29 -070029 fprintf(stderr, "\n");
30 fprintf(stderr, "Where: VNI := 0-16777215\n");
31 fprintf(stderr, " ADDR := { IP_ADDRESS | any }\n");
32 fprintf(stderr, " TOS := { NUMBER | inherit }\n");
33 fprintf(stderr, " TTL := { 1..255 | inherit }\n");
34}
35
36static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
37 struct nlmsghdr *n)
38{
39 __u32 vni = 0;
40 int vni_set = 0;
41 __u32 saddr = 0;
42 __u32 gaddr = 0;
43 unsigned link = 0;
44 __u8 tos = 0;
45 __u8 ttl = 0;
46 __u8 learning = 1;
47 __u8 noage = 0;
48 __u32 age = 0;
49 __u32 maxaddr = 0;
Stephen Hemminger2d596122012-10-09 23:39:17 -070050 struct ifla_vxlan_port_range range = { 0, 0 };
Stephen Hemmingera5494df2012-09-24 12:48:29 -070051
52 while (argc > 0) {
53 if (!matches(*argv, "id") ||
54 !matches(*argv, "vni")) {
55 NEXT_ARG();
56 if (get_u32(&vni, *argv, 0) ||
57 vni >= 1u << 24)
58 invarg("invalid id", *argv);
59 vni_set = 1;
60 } else if (!matches(*argv, "group")) {
61 NEXT_ARG();
62 gaddr = get_addr32(*argv);
63
64 if (!IN_MULTICAST(ntohl(gaddr)))
65 invarg("invald group address", *argv);
66 } else if (!matches(*argv, "local")) {
67 NEXT_ARG();
68 if (strcmp(*argv, "any"))
69 saddr = get_addr32(*argv);
70 if (IN_MULTICAST(ntohl(saddr)))
71 invarg("invalid local address", *argv);
72 } else if (!matches(*argv, "dev")) {
73 NEXT_ARG();
74 link = if_nametoindex(*argv);
75 if (link == 0)
76 exit(-1);
77 } else if (!matches(*argv, "ttl") ||
78 !matches(*argv, "hoplimit")) {
79 unsigned uval;
80
81 NEXT_ARG();
82 if (strcmp(*argv, "inherit") != 0) {
83 if (get_unsigned(&uval, *argv, 0))
Stephen Hemminger2d596122012-10-09 23:39:17 -070084 invarg("invalid TTL", *argv);
Stephen Hemmingera5494df2012-09-24 12:48:29 -070085 if (uval > 255)
Stephen Hemminger2d596122012-10-09 23:39:17 -070086 invarg("TTL must be <= 255", *argv);
Stephen Hemmingera5494df2012-09-24 12:48:29 -070087 ttl = uval;
88 }
89 } else if (!matches(*argv, "tos") ||
90 !matches(*argv, "dsfield")) {
91 __u32 uval;
92
93 NEXT_ARG();
94 if (strcmp(*argv, "inherit") != 0) {
95 if (rtnl_dsfield_a2n(&uval, *argv))
96 invarg("bad TOS value", *argv);
97 tos = uval;
98 } else
99 tos = 1;
100 } else if (!matches(*argv, "ageing")) {
101 NEXT_ARG();
102 if (strcmp(*argv, "none") == 0)
103 noage = 1;
104 else if (get_u32(&age, *argv, 0))
Stephen Hemminger2d596122012-10-09 23:39:17 -0700105 invarg("ageing timer", *argv);
Stephen Hemmingera5494df2012-09-24 12:48:29 -0700106 } else if (!matches(*argv, "maxaddress")) {
107 NEXT_ARG();
108 if (strcmp(*argv, "unlimited") == 0)
109 maxaddr = 0;
110 else if (get_u32(&maxaddr, *argv, 0))
Stephen Hemminger2d596122012-10-09 23:39:17 -0700111 invarg("max addresses", *argv);
112 } else if (!matches(*argv, "port")) {
113 __u16 minport, maxport;
114 NEXT_ARG();
115 if (get_u16(&minport, *argv, 0))
116 invarg("min port", *argv);
117 NEXT_ARG();
118 if (get_u16(&maxport, *argv, 0))
119 invarg("max port", *argv);
120 range.low = htons(minport);
121 range.high = htons(maxport);
Stephen Hemmingera5494df2012-09-24 12:48:29 -0700122 } else if (!matches(*argv, "nolearning")) {
123 learning = 0;
124 } else if (!matches(*argv, "learning")) {
125 learning = 1;
126 } else if (matches(*argv, "help") == 0) {
127 explain();
128 return -1;
129 } else {
130 fprintf(stderr, "vxlan: what is \"%s\"?\n", *argv);
131 explain();
132 return -1;
133 }
134 argc--, argv++;
135 }
136
137 if (!vni_set) {
138 fprintf(stderr, "vxlan: missing virtual network identifier\n");
139 return -1;
140 }
141 addattr32(n, 1024, IFLA_VXLAN_ID, vni);
142 addattr_l(n, 1024, IFLA_VXLAN_GROUP, &gaddr, 4);
143 addattr_l(n, 1024, IFLA_VXLAN_LOCAL, &saddr, 4);
144 if (link)
145 addattr32(n, 1024, IFLA_VXLAN_LINK, link);
146 addattr8(n, 1024, IFLA_VXLAN_TTL, ttl);
147 addattr8(n, 1024, IFLA_VXLAN_TOS, tos);
148 addattr8(n, 1024, IFLA_VXLAN_LEARNING, learning);
149 if (noage)
150 addattr32(n, 1024, IFLA_VXLAN_AGEING, 0);
151 else if (age)
152 addattr32(n, 1024, IFLA_VXLAN_AGEING, age);
153 if (maxaddr)
154 addattr32(n, 1024, IFLA_VXLAN_LIMIT, maxaddr);
Stephen Hemminger2d596122012-10-09 23:39:17 -0700155 if (range.low || range.high)
156 addattr_l(n, 1024, IFLA_VXLAN_PORT_RANGE,
157 &range, sizeof(range));
Stephen Hemmingera5494df2012-09-24 12:48:29 -0700158
159 return 0;
160}
161
162static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
163{
164 __u32 vni;
165 unsigned link;
Stephen Hemminger2d596122012-10-09 23:39:17 -0700166 __u8 tos;
167 __u32 maxaddr;
Stephen Hemmingera5494df2012-09-24 12:48:29 -0700168 char s1[1024];
169 char s2[64];
170
171 if (!tb)
172 return;
173
174 if (!tb[IFLA_VXLAN_ID] ||
175 RTA_PAYLOAD(tb[IFLA_VXLAN_ID]) < sizeof(__u32))
176 return;
177
178 vni = rta_getattr_u32(tb[IFLA_VXLAN_ID]);
179 fprintf(f, "id %u ", vni);
180
181 if (tb[IFLA_VXLAN_GROUP]) {
182 __u32 addr = rta_getattr_u32(tb[IFLA_VXLAN_GROUP]);
183
184 if (addr)
185 fprintf(f, "group %s ",
186 format_host(AF_INET, 4, &addr, s1, sizeof(s1)));
187 }
188
189 if (tb[IFLA_VXLAN_LOCAL]) {
190 unsigned addr = rta_getattr_u32(tb[IFLA_VXLAN_LOCAL]);
191
192 if (addr)
193 fprintf(f, "local %s ",
194 format_host(AF_INET, 4, &addr, s1, sizeof(s1)));
195 }
196
197 if (tb[IFLA_VXLAN_LINK] &&
198 (link = rta_getattr_u32(tb[IFLA_VXLAN_LINK]))) {
199 const char *n = if_indextoname(link, s2);
200
201 if (n)
202 fprintf(f, "dev %s ", n);
203 else
204 fprintf(f, "dev %u ", link);
205 }
206
Stephen Hemminger2d596122012-10-09 23:39:17 -0700207 if (tb[IFLA_VXLAN_PORT_RANGE]) {
208 const struct ifla_vxlan_port_range *r
209 = RTA_DATA(tb[IFLA_VXLAN_PORT_RANGE]);
210 fprintf(f, "port %u %u ", ntohs(r->low), ntohs(r->high));
211 }
212
Stephen Hemmingera5494df2012-09-24 12:48:29 -0700213 if (tb[IFLA_VXLAN_LEARNING] &&
214 !rta_getattr_u8(tb[IFLA_VXLAN_LEARNING]))
215 fputs("nolearning ", f);
Stephen Hemminger2d596122012-10-09 23:39:17 -0700216
217 if (tb[IFLA_VXLAN_TOS] &&
218 (tos = rta_getattr_u8(tb[IFLA_VXLAN_TOS]))) {
Stephen Hemmingera5494df2012-09-24 12:48:29 -0700219 if (tos == 1)
220 fprintf(f, "tos inherit ");
221 else
222 fprintf(f, "tos %#x ", tos);
223 }
224
225 if (tb[IFLA_VXLAN_TTL]) {
226 __u8 ttl = rta_getattr_u8(tb[IFLA_VXLAN_TTL]);
227 if (ttl)
228 fprintf(f, "ttl %d ", ttl);
229 }
230
231 if (tb[IFLA_VXLAN_AGEING]) {
232 __u32 age = rta_getattr_u32(tb[IFLA_VXLAN_AGEING]);
233 if (age == 0)
234 fprintf(f, "ageing none ");
235 else
236 fprintf(f, "ageing %u ", age);
237 }
Stephen Hemminger2d596122012-10-09 23:39:17 -0700238
239 if (tb[IFLA_VXLAN_LIMIT] &&
240 (maxaddr = rta_getattr_u32(tb[IFLA_VXLAN_LIMIT]) != 0))
241 fprintf(f, "maxaddr %u ", maxaddr);
Stephen Hemmingera5494df2012-09-24 12:48:29 -0700242}
243
244struct link_util vxlan_link_util = {
245 .id = "vxlan",
246 .maxattr = IFLA_VXLAN_MAX,
247 .parse_opt = vxlan_parse_opt,
248 .print_opt = vxlan_print_opt,
249};