blob: f52eb188722779e301c7ab85037d3de007e0955d [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");
27 fprintf(stderr, " [ ttl TTL ] [ tos TOS ] [ [no]learning ] [ dev PHYS_DEV ]\n");
28 fprintf(stderr, "\n");
29 fprintf(stderr, "Where: VNI := 0-16777215\n");
30 fprintf(stderr, " ADDR := { IP_ADDRESS | any }\n");
31 fprintf(stderr, " TOS := { NUMBER | inherit }\n");
32 fprintf(stderr, " TTL := { 1..255 | inherit }\n");
33}
34
35static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
36 struct nlmsghdr *n)
37{
38 __u32 vni = 0;
39 int vni_set = 0;
40 __u32 saddr = 0;
41 __u32 gaddr = 0;
42 unsigned link = 0;
43 __u8 tos = 0;
44 __u8 ttl = 0;
45 __u8 learning = 1;
46 __u8 noage = 0;
47 __u32 age = 0;
48 __u32 maxaddr = 0;
49
50 while (argc > 0) {
51 if (!matches(*argv, "id") ||
52 !matches(*argv, "vni")) {
53 NEXT_ARG();
54 if (get_u32(&vni, *argv, 0) ||
55 vni >= 1u << 24)
56 invarg("invalid id", *argv);
57 vni_set = 1;
58 } else if (!matches(*argv, "group")) {
59 NEXT_ARG();
60 gaddr = get_addr32(*argv);
61
62 if (!IN_MULTICAST(ntohl(gaddr)))
63 invarg("invald group address", *argv);
64 } else if (!matches(*argv, "local")) {
65 NEXT_ARG();
66 if (strcmp(*argv, "any"))
67 saddr = get_addr32(*argv);
68 if (IN_MULTICAST(ntohl(saddr)))
69 invarg("invalid local address", *argv);
70 } else if (!matches(*argv, "dev")) {
71 NEXT_ARG();
72 link = if_nametoindex(*argv);
73 if (link == 0)
74 exit(-1);
75 } else if (!matches(*argv, "ttl") ||
76 !matches(*argv, "hoplimit")) {
77 unsigned uval;
78
79 NEXT_ARG();
80 if (strcmp(*argv, "inherit") != 0) {
81 if (get_unsigned(&uval, *argv, 0))
82 invarg("invalid TTL\n", *argv);
83 if (uval > 255)
84 invarg("TTL must be <= 255\n", *argv);
85 ttl = uval;
86 }
87 } else if (!matches(*argv, "tos") ||
88 !matches(*argv, "dsfield")) {
89 __u32 uval;
90
91 NEXT_ARG();
92 if (strcmp(*argv, "inherit") != 0) {
93 if (rtnl_dsfield_a2n(&uval, *argv))
94 invarg("bad TOS value", *argv);
95 tos = uval;
96 } else
97 tos = 1;
98 } else if (!matches(*argv, "ageing")) {
99 NEXT_ARG();
100 if (strcmp(*argv, "none") == 0)
101 noage = 1;
102 else if (get_u32(&age, *argv, 0))
103 invarg("ageing timer\n", *argv);
104 } else if (!matches(*argv, "maxaddress")) {
105 NEXT_ARG();
106 if (strcmp(*argv, "unlimited") == 0)
107 maxaddr = 0;
108 else if (get_u32(&maxaddr, *argv, 0))
109 invarg("max addresses\n", *argv);
110 } else if (!matches(*argv, "nolearning")) {
111 learning = 0;
112 } else if (!matches(*argv, "learning")) {
113 learning = 1;
114 } else if (matches(*argv, "help") == 0) {
115 explain();
116 return -1;
117 } else {
118 fprintf(stderr, "vxlan: what is \"%s\"?\n", *argv);
119 explain();
120 return -1;
121 }
122 argc--, argv++;
123 }
124
125 if (!vni_set) {
126 fprintf(stderr, "vxlan: missing virtual network identifier\n");
127 return -1;
128 }
129 addattr32(n, 1024, IFLA_VXLAN_ID, vni);
130 addattr_l(n, 1024, IFLA_VXLAN_GROUP, &gaddr, 4);
131 addattr_l(n, 1024, IFLA_VXLAN_LOCAL, &saddr, 4);
132 if (link)
133 addattr32(n, 1024, IFLA_VXLAN_LINK, link);
134 addattr8(n, 1024, IFLA_VXLAN_TTL, ttl);
135 addattr8(n, 1024, IFLA_VXLAN_TOS, tos);
136 addattr8(n, 1024, IFLA_VXLAN_LEARNING, learning);
137 if (noage)
138 addattr32(n, 1024, IFLA_VXLAN_AGEING, 0);
139 else if (age)
140 addattr32(n, 1024, IFLA_VXLAN_AGEING, age);
141 if (maxaddr)
142 addattr32(n, 1024, IFLA_VXLAN_LIMIT, maxaddr);
143
144 return 0;
145}
146
147static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
148{
149 __u32 vni;
150 unsigned link;
151 char s1[1024];
152 char s2[64];
153
154 if (!tb)
155 return;
156
157 if (!tb[IFLA_VXLAN_ID] ||
158 RTA_PAYLOAD(tb[IFLA_VXLAN_ID]) < sizeof(__u32))
159 return;
160
161 vni = rta_getattr_u32(tb[IFLA_VXLAN_ID]);
162 fprintf(f, "id %u ", vni);
163
164 if (tb[IFLA_VXLAN_GROUP]) {
165 __u32 addr = rta_getattr_u32(tb[IFLA_VXLAN_GROUP]);
166
167 if (addr)
168 fprintf(f, "group %s ",
169 format_host(AF_INET, 4, &addr, s1, sizeof(s1)));
170 }
171
172 if (tb[IFLA_VXLAN_LOCAL]) {
173 unsigned addr = rta_getattr_u32(tb[IFLA_VXLAN_LOCAL]);
174
175 if (addr)
176 fprintf(f, "local %s ",
177 format_host(AF_INET, 4, &addr, s1, sizeof(s1)));
178 }
179
180 if (tb[IFLA_VXLAN_LINK] &&
181 (link = rta_getattr_u32(tb[IFLA_VXLAN_LINK]))) {
182 const char *n = if_indextoname(link, s2);
183
184 if (n)
185 fprintf(f, "dev %s ", n);
186 else
187 fprintf(f, "dev %u ", link);
188 }
189
190 if (tb[IFLA_VXLAN_LEARNING] &&
191 !rta_getattr_u8(tb[IFLA_VXLAN_LEARNING]))
192 fputs("nolearning ", f);
193
194 if (tb[IFLA_VXLAN_TOS]) {
195 __u8 tos = rta_getattr_u8(tb[IFLA_VXLAN_TOS]);
196
197 if (tos == 1)
198 fprintf(f, "tos inherit ");
199 else
200 fprintf(f, "tos %#x ", tos);
201 }
202
203 if (tb[IFLA_VXLAN_TTL]) {
204 __u8 ttl = rta_getattr_u8(tb[IFLA_VXLAN_TTL]);
205 if (ttl)
206 fprintf(f, "ttl %d ", ttl);
207 }
208
209 if (tb[IFLA_VXLAN_AGEING]) {
210 __u32 age = rta_getattr_u32(tb[IFLA_VXLAN_AGEING]);
211 if (age == 0)
212 fprintf(f, "ageing none ");
213 else
214 fprintf(f, "ageing %u ", age);
215 }
216 if (tb[IFLA_VXLAN_LIMIT]) {
217 __u32 maxaddr = rta_getattr_u32(tb[IFLA_VXLAN_LIMIT]);
218 if (maxaddr == 0)
219 fprintf(f, "maxaddr unlimited ");
220 else
221 fprintf(f, "maxaddr %u ", maxaddr);
222 }
223}
224
225struct link_util vxlan_link_util = {
226 .id = "vxlan",
227 .maxattr = IFLA_VXLAN_MAX,
228 .parse_opt = vxlan_parse_opt,
229 .print_opt = vxlan_print_opt,
230};