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