blob: 1e6669d07d60376c5fbfe6ae9208b99f057eb4c0 [file] [log] [blame]
John W. Linville908755d2015-05-08 13:27:08 -04001/*
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
John W. Linvillef4739b22015-06-15 14:37:16 -040014#include "rt_names.h"
John W. Linville908755d2015-05-08 13:27:08 -040015#include "utils.h"
16#include "ip_common.h"
17
18static void print_explain(FILE *f)
19{
20 fprintf(f, "Usage: ... geneve id VNI remote ADDR\n");
Daniel Borkmann29bb2372016-03-24 16:49:56 +010021 fprintf(f, " [ ttl TTL ] [ tos TOS ] [ flowlabel LABEL ]\n");
Paolo Abeni9450c5e2016-01-28 14:48:55 +010022 fprintf(f, " [ dstport PORT ] [ [no]external ]\n");
Jesse Gross325d02b2016-03-18 17:51:09 -070023 fprintf(f, " [ [no]udpcsum ] [ [no]udp6zerocsumtx ] [ [no]udp6zerocsumrx ]\n");
John W. Linville908755d2015-05-08 13:27:08 -040024 fprintf(f, "\n");
Daniel Borkmann29bb2372016-03-24 16:49:56 +010025 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");
John W. Linville908755d2015-05-08 13:27:08 -040030}
31
32static void explain(void)
33{
34 print_explain(stderr);
35}
36
37static 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;
Daniel Borkmann29bb2372016-03-24 16:49:56 +010044 __u32 label = 0;
John W. Linvillef4c05c22015-06-15 14:37:15 -040045 __u8 ttl = 0;
John W. Linvillef4739b22015-06-15 14:37:16 -040046 __u8 tos = 0;
Paolo Abeni9450c5e2016-01-28 14:48:55 +010047 __u16 dstport = 0;
48 bool metadata = 0;
Jesse Gross325d02b2016-03-18 17:51:09 -070049 __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;
John W. Linville908755d2015-05-08 13:27:08 -040055
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 }
John W. Linville906ac542015-09-24 14:39:39 -040070 if (IN6_IS_ADDR_MULTICAST(&daddr6) || IN_MULTICAST(ntohl(daddr)))
John W. Linville908755d2015-05-08 13:27:08 -040071 invarg("invalid remote address", *argv);
John W. Linvillef4c05c22015-06-15 14:37:15 -040072 } else if (!matches(*argv, "ttl") ||
73 !matches(*argv, "hoplimit")) {
Stephen Hemminger56f5daa2016-03-21 11:52:19 -070074 unsigned int uval;
John W. Linvillef4c05c22015-06-15 14:37:15 -040075
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 }
John W. Linvillef4739b22015-06-15 14:37:16 -040084 } 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;
Daniel Borkmann29bb2372016-03-24 16:49:56 +010095 } 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);
Paolo Abeni9450c5e2016-01-28 14:48:55 +0100104 } 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;
Jesse Gross325d02b2016-03-18 17:51:09 -0700112 } 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;
John W. Linville908755d2015-05-08 13:27:08 -0400130 } 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
Paolo Abeni9450c5e2016-01-28 14:48:55 +0100141 if (metadata && vni_set) {
142 fprintf(stderr, "geneve: both 'external' and vni cannot be specified\n");
John W. Linville908755d2015-05-08 13:27:08 -0400143 return -1;
144 }
145
Paolo Abeni9450c5e2016-01-28 14:48:55 +0100146 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
Jiri Benc1f4c51c2016-09-05 11:35:27 +0200153 if (!daddr && IN6_IS_ADDR_UNSPECIFIED(&daddr6)) {
Paolo Abeni9450c5e2016-01-28 14:48:55 +0100154 fprintf(stderr, "geneve: remote link partner not specified\n");
155 return -1;
156 }
John W. Linville908755d2015-05-08 13:27:08 -0400157 }
158
159 addattr32(n, 1024, IFLA_GENEVE_ID, vni);
160 if (daddr)
161 addattr_l(n, 1024, IFLA_GENEVE_REMOTE, &daddr, 4);
Jiri Benc1f4c51c2016-09-05 11:35:27 +0200162 if (!IN6_IS_ADDR_UNSPECIFIED(&daddr6))
John W. Linville906ac542015-09-24 14:39:39 -0400163 addattr_l(n, 1024, IFLA_GENEVE_REMOTE6, &daddr6, sizeof(struct in6_addr));
Daniel Borkmann29bb2372016-03-24 16:49:56 +0100164 addattr32(n, 1024, IFLA_GENEVE_LABEL, label);
John W. Linvillef4c05c22015-06-15 14:37:15 -0400165 addattr8(n, 1024, IFLA_GENEVE_TTL, ttl);
John W. Linvillef4739b22015-06-15 14:37:16 -0400166 addattr8(n, 1024, IFLA_GENEVE_TOS, tos);
Paolo Abeni9450c5e2016-01-28 14:48:55 +0100167 if (dstport)
168 addattr16(n, 1024, IFLA_GENEVE_PORT, htons(dstport));
169 if (metadata)
170 addattr(n, 1024, IFLA_GENEVE_COLLECT_METADATA);
Jesse Gross325d02b2016-03-18 17:51:09 -0700171 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);
John W. Linville908755d2015-05-08 13:27:08 -0400177
178 return 0;
179}
180
181static void geneve_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
182{
183 __u32 vni;
John W. Linvillef4739b22015-06-15 14:37:16 -0400184 __u8 tos;
John W. Linville908755d2015-05-08 13:27:08 -0400185
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]);
Stephen Hemminger56f5daa2016-03-21 11:52:19 -0700198
John W. Linville908755d2015-05-08 13:27:08 -0400199 if (addr)
200 fprintf(f, "remote %s ",
Phil Suttera418e452016-03-22 19:35:15 +0100201 format_host(AF_INET, 4, &addr));
John W. Linville906ac542015-09-24 14:39:39 -0400202 } else if (tb[IFLA_GENEVE_REMOTE6]) {
203 struct in6_addr addr;
Stephen Hemminger56f5daa2016-03-21 11:52:19 -0700204
John W. Linville906ac542015-09-24 14:39:39 -0400205 memcpy(&addr, RTA_DATA(tb[IFLA_GENEVE_REMOTE6]), sizeof(struct in6_addr));
Jiri Benc1f4c51c2016-09-05 11:35:27 +0200206 if (!IN6_IS_ADDR_UNSPECIFIED(&addr)) {
Edward Cree2642b6b2016-05-06 15:28:25 +0100207 if (!IN6_IS_ADDR_MULTICAST(&addr))
John W. Linville906ac542015-09-24 14:39:39 -0400208 fprintf(f, "remote %s ",
Phil Suttera418e452016-03-22 19:35:15 +0100209 format_host(AF_INET6, sizeof(struct in6_addr), &addr));
John W. Linville906ac542015-09-24 14:39:39 -0400210 }
John W. Linville908755d2015-05-08 13:27:08 -0400211 }
John W. Linvillef4c05c22015-06-15 14:37:15 -0400212
213 if (tb[IFLA_GENEVE_TTL]) {
214 __u8 ttl = rta_getattr_u8(tb[IFLA_GENEVE_TTL]);
Stephen Hemminger56f5daa2016-03-21 11:52:19 -0700215
John W. Linvillef4c05c22015-06-15 14:37:15 -0400216 if (ttl)
217 fprintf(f, "ttl %d ", ttl);
218 }
John W. Linvillef4739b22015-06-15 14:37:16 -0400219
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 }
Paolo Abeni9450c5e2016-01-28 14:48:55 +0100227
Daniel Borkmann29bb2372016-03-24 16:49:56 +0100228 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
Paolo Abeni9450c5e2016-01-28 14:48:55 +0100235 if (tb[IFLA_GENEVE_PORT])
236 fprintf(f, "dstport %u ",
Amir Vadaiaab0f612016-12-02 13:25:13 +0200237 rta_getattr_be16(tb[IFLA_GENEVE_PORT]));
Paolo Abeni9450c5e2016-01-28 14:48:55 +0100238
239 if (tb[IFLA_GENEVE_COLLECT_METADATA])
240 fputs("external ", f);
241
Jesse Gross325d02b2016-03-18 17:51:09 -0700242 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 }
John W. Linville908755d2015-05-08 13:27:08 -0400259}
260
261static void geneve_print_help(struct link_util *lu, int argc, char **argv,
262 FILE *f)
263{
264 print_explain(f);
265}
266
267struct 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};