]> git.proxmox.com Git - mirror_iproute2.git/blob - ip/iplink_geneve.c
Merge branch 'master' into net-next
[mirror_iproute2.git] / ip / iplink_geneve.c
1 /*
2 * iplink_geneve.c GENEVE 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: John W. Linville <linville@tuxdriver.com>
10 */
11
12 #include <stdio.h>
13
14 #include "rt_names.h"
15 #include "utils.h"
16 #include "ip_common.h"
17
18 static void print_explain(FILE *f)
19 {
20 fprintf(f, "Usage: ... geneve id VNI remote ADDR\n");
21 fprintf(f, " [ ttl TTL ] [ tos TOS ] [ flowlabel LABEL ]\n");
22 fprintf(f, " [ dstport PORT ] [ [no]external ]\n");
23 fprintf(f, " [ [no]udpcsum ] [ [no]udp6zerocsumtx ] [ [no]udp6zerocsumrx ]\n");
24 fprintf(f, "\n");
25 fprintf(f, "Where: VNI := 0-16777215\n");
26 fprintf(f, " ADDR := IP_ADDRESS\n");
27 fprintf(f, " TOS := { NUMBER | inherit }\n");
28 fprintf(f, " TTL := { 1..255 | inherit }\n");
29 fprintf(f, " LABEL := 0-1048575\n");
30 }
31
32 static void explain(void)
33 {
34 print_explain(stderr);
35 }
36
37 static int geneve_parse_opt(struct link_util *lu, int argc, char **argv,
38 struct nlmsghdr *n)
39 {
40 __u32 vni = 0;
41 int vni_set = 0;
42 __u32 daddr = 0;
43 struct in6_addr daddr6 = IN6ADDR_ANY_INIT;
44 __u32 label = 0;
45 __u8 ttl = 0;
46 __u8 tos = 0;
47 __u16 dstport = 0;
48 bool metadata = 0;
49 __u8 udpcsum = 0;
50 bool udpcsum_set = false;
51 __u8 udp6zerocsumtx = 0;
52 bool udp6zerocsumtx_set = false;
53 __u8 udp6zerocsumrx = 0;
54 bool udp6zerocsumrx_set = false;
55
56 while (argc > 0) {
57 if (!matches(*argv, "id") ||
58 !matches(*argv, "vni")) {
59 NEXT_ARG();
60 if (get_u32(&vni, *argv, 0) ||
61 vni >= 1u << 24)
62 invarg("invalid id", *argv);
63 vni_set = 1;
64 } else if (!matches(*argv, "remote")) {
65 NEXT_ARG();
66 if (!inet_get_addr(*argv, &daddr, &daddr6)) {
67 fprintf(stderr, "Invalid address \"%s\"\n", *argv);
68 return -1;
69 }
70 if (IN6_IS_ADDR_MULTICAST(&daddr6) || IN_MULTICAST(ntohl(daddr)))
71 invarg("invalid remote address", *argv);
72 } else if (!matches(*argv, "ttl") ||
73 !matches(*argv, "hoplimit")) {
74 unsigned int uval;
75
76 NEXT_ARG();
77 if (strcmp(*argv, "inherit") != 0) {
78 if (get_unsigned(&uval, *argv, 0))
79 invarg("invalid TTL", *argv);
80 if (uval > 255)
81 invarg("TTL must be <= 255", *argv);
82 ttl = uval;
83 }
84 } else if (!matches(*argv, "tos") ||
85 !matches(*argv, "dsfield")) {
86 __u32 uval;
87
88 NEXT_ARG();
89 if (strcmp(*argv, "inherit") != 0) {
90 if (rtnl_dsfield_a2n(&uval, *argv))
91 invarg("bad TOS value", *argv);
92 tos = uval;
93 } else
94 tos = 1;
95 } else if (!matches(*argv, "label") ||
96 !matches(*argv, "flowlabel")) {
97 __u32 uval;
98
99 NEXT_ARG();
100 if (get_u32(&uval, *argv, 0) ||
101 (uval & ~LABEL_MAX_MASK))
102 invarg("invalid flowlabel", *argv);
103 label = htonl(uval);
104 } else if (!matches(*argv, "dstport")) {
105 NEXT_ARG();
106 if (get_u16(&dstport, *argv, 0))
107 invarg("dstport", *argv);
108 } else if (!matches(*argv, "external")) {
109 metadata = true;
110 } else if (!matches(*argv, "noexternal")) {
111 metadata = false;
112 } else if (!matches(*argv, "udpcsum")) {
113 udpcsum = 1;
114 udpcsum_set = true;
115 } else if (!matches(*argv, "noudpcsum")) {
116 udpcsum = 0;
117 udpcsum_set = true;
118 } else if (!matches(*argv, "udp6zerocsumtx")) {
119 udp6zerocsumtx = 1;
120 udp6zerocsumtx_set = true;
121 } else if (!matches(*argv, "noudp6zerocsumtx")) {
122 udp6zerocsumtx = 0;
123 udp6zerocsumtx_set = true;
124 } else if (!matches(*argv, "udp6zerocsumrx")) {
125 udp6zerocsumrx = 1;
126 udp6zerocsumrx_set = true;
127 } else if (!matches(*argv, "noudp6zerocsumrx")) {
128 udp6zerocsumrx = 0;
129 udp6zerocsumrx_set = true;
130 } else if (matches(*argv, "help") == 0) {
131 explain();
132 return -1;
133 } else {
134 fprintf(stderr, "geneve: unknown command \"%s\"?\n", *argv);
135 explain();
136 return -1;
137 }
138 argc--, argv++;
139 }
140
141 if (metadata && vni_set) {
142 fprintf(stderr, "geneve: both 'external' and vni cannot be specified\n");
143 return -1;
144 }
145
146 if (!metadata) {
147 /* parameter checking make sense only for full geneve tunnels */
148 if (!vni_set) {
149 fprintf(stderr, "geneve: missing virtual network identifier\n");
150 return -1;
151 }
152
153 if (!daddr && memcmp(&daddr6, &in6addr_any, sizeof(daddr6)) == 0) {
154 fprintf(stderr, "geneve: remote link partner not specified\n");
155 return -1;
156 }
157 }
158
159 addattr32(n, 1024, IFLA_GENEVE_ID, vni);
160 if (daddr)
161 addattr_l(n, 1024, IFLA_GENEVE_REMOTE, &daddr, 4);
162 if (memcmp(&daddr6, &in6addr_any, sizeof(daddr6)) != 0)
163 addattr_l(n, 1024, IFLA_GENEVE_REMOTE6, &daddr6, sizeof(struct in6_addr));
164 addattr32(n, 1024, IFLA_GENEVE_LABEL, label);
165 addattr8(n, 1024, IFLA_GENEVE_TTL, ttl);
166 addattr8(n, 1024, IFLA_GENEVE_TOS, tos);
167 if (dstport)
168 addattr16(n, 1024, IFLA_GENEVE_PORT, htons(dstport));
169 if (metadata)
170 addattr(n, 1024, IFLA_GENEVE_COLLECT_METADATA);
171 if (udpcsum_set)
172 addattr8(n, 1024, IFLA_GENEVE_UDP_CSUM, udpcsum);
173 if (udp6zerocsumtx_set)
174 addattr8(n, 1024, IFLA_GENEVE_UDP_ZERO_CSUM6_TX, udp6zerocsumtx);
175 if (udp6zerocsumrx_set)
176 addattr8(n, 1024, IFLA_GENEVE_UDP_ZERO_CSUM6_RX, udp6zerocsumrx);
177
178 return 0;
179 }
180
181 static void geneve_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
182 {
183 __u32 vni;
184 __u8 tos;
185
186 if (!tb)
187 return;
188
189 if (!tb[IFLA_GENEVE_ID] ||
190 RTA_PAYLOAD(tb[IFLA_GENEVE_ID]) < sizeof(__u32))
191 return;
192
193 vni = rta_getattr_u32(tb[IFLA_GENEVE_ID]);
194 fprintf(f, "id %u ", vni);
195
196 if (tb[IFLA_GENEVE_REMOTE]) {
197 __be32 addr = rta_getattr_u32(tb[IFLA_GENEVE_REMOTE]);
198
199 if (addr)
200 fprintf(f, "remote %s ",
201 format_host(AF_INET, 4, &addr));
202 } else if (tb[IFLA_GENEVE_REMOTE6]) {
203 struct in6_addr addr;
204
205 memcpy(&addr, RTA_DATA(tb[IFLA_GENEVE_REMOTE6]), sizeof(struct in6_addr));
206 if (memcmp(&addr, &in6addr_any, sizeof(addr)) != 0) {
207 if (!IN6_IS_ADDR_MULTICAST(&addr))
208 fprintf(f, "remote %s ",
209 format_host(AF_INET6, sizeof(struct in6_addr), &addr));
210 }
211 }
212
213 if (tb[IFLA_GENEVE_TTL]) {
214 __u8 ttl = rta_getattr_u8(tb[IFLA_GENEVE_TTL]);
215
216 if (ttl)
217 fprintf(f, "ttl %d ", ttl);
218 }
219
220 if (tb[IFLA_GENEVE_TOS] &&
221 (tos = rta_getattr_u8(tb[IFLA_GENEVE_TOS]))) {
222 if (tos == 1)
223 fprintf(f, "tos inherit ");
224 else
225 fprintf(f, "tos %#x ", tos);
226 }
227
228 if (tb[IFLA_GENEVE_LABEL]) {
229 __u32 label = rta_getattr_u32(tb[IFLA_GENEVE_LABEL]);
230
231 if (label)
232 fprintf(f, "flowlabel %#x ", ntohl(label));
233 }
234
235 if (tb[IFLA_GENEVE_PORT])
236 fprintf(f, "dstport %u ",
237 ntohs(rta_getattr_u16(tb[IFLA_GENEVE_PORT])));
238
239 if (tb[IFLA_GENEVE_COLLECT_METADATA])
240 fputs("external ", f);
241
242 if (tb[IFLA_GENEVE_UDP_CSUM]) {
243 if (!rta_getattr_u8(tb[IFLA_GENEVE_UDP_CSUM]))
244 fputs("no", f);
245 fputs("udpcsum ", f);
246 }
247
248 if (tb[IFLA_GENEVE_UDP_ZERO_CSUM6_TX]) {
249 if (!rta_getattr_u8(tb[IFLA_GENEVE_UDP_ZERO_CSUM6_TX]))
250 fputs("no", f);
251 fputs("udp6zerocsumtx ", f);
252 }
253
254 if (tb[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]) {
255 if (!rta_getattr_u8(tb[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]))
256 fputs("no", f);
257 fputs("udp6zerocsumrx ", f);
258 }
259 }
260
261 static void geneve_print_help(struct link_util *lu, int argc, char **argv,
262 FILE *f)
263 {
264 print_explain(f);
265 }
266
267 struct link_util geneve_link_util = {
268 .id = "geneve",
269 .maxattr = IFLA_GENEVE_MAX,
270 .parse_opt = geneve_parse_opt,
271 .print_opt = geneve_print_opt,
272 .print_help = geneve_print_help,
273 };