]> git.proxmox.com Git - mirror_iproute2.git/blob - ip/link_gre.c
ip/tunnel: Document "external" parameter
[mirror_iproute2.git] / ip / link_gre.c
1 /*
2 * link_gre.c gre driver module
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: Herbert Xu <herbert@gondor.apana.org.au>
10 *
11 */
12
13 #include <string.h>
14 #include <net/if.h>
15 #include <sys/types.h>
16 #include <sys/socket.h>
17 #include <arpa/inet.h>
18
19 #include <linux/ip.h>
20 #include <linux/if_tunnel.h>
21 #include "rt_names.h"
22 #include "utils.h"
23 #include "ip_common.h"
24 #include "tunnel.h"
25
26 static void print_usage(FILE *f)
27 {
28 fprintf(f,
29 "Usage: ... { gre | gretap | erspan } [ remote ADDR ]\n"
30 " [ local ADDR ]\n"
31 " [ [i|o]seq ]\n"
32 " [ [i|o]key KEY ]\n"
33 " [ [i|o]csum ]\n"
34 " [ ttl TTL ]\n"
35 " [ tos TOS ]\n"
36 " [ [no]pmtudisc ]\n"
37 " [ [no]ignore-df ]\n"
38 " [ dev PHYS_DEV ]\n"
39 " [ noencap ]\n"
40 " [ encap { fou | gue | none } ]\n"
41 " [ encap-sport PORT ]\n"
42 " [ encap-dport PORT ]\n"
43 " [ [no]encap-csum ]\n"
44 " [ [no]encap-csum6 ]\n"
45 " [ [no]encap-remcsum ]\n"
46 " [ external ]\n"
47 " [ fwmark MARK ]\n"
48 " [ erspan IDX ]\n"
49 "\n"
50 "Where: ADDR := { IP_ADDRESS | any }\n"
51 " TOS := { NUMBER | inherit }\n"
52 " TTL := { 1..255 | inherit }\n"
53 " KEY := { DOTTED_QUAD | NUMBER }\n"
54 " MARK := { 0x0..0xffffffff }\n"
55 );
56 }
57
58 static void usage(void) __attribute__((noreturn));
59 static void usage(void)
60 {
61 print_usage(stderr);
62 exit(-1);
63 }
64
65 static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
66 struct nlmsghdr *n)
67 {
68 struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1);
69 struct {
70 struct nlmsghdr n;
71 struct ifinfomsg i;
72 } req = {
73 .n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)),
74 .n.nlmsg_flags = NLM_F_REQUEST,
75 .n.nlmsg_type = RTM_GETLINK,
76 .i.ifi_family = preferred_family,
77 .i.ifi_index = ifi->ifi_index,
78 };
79 struct nlmsghdr *answer;
80 struct rtattr *tb[IFLA_MAX + 1];
81 struct rtattr *linkinfo[IFLA_INFO_MAX+1];
82 struct rtattr *greinfo[IFLA_GRE_MAX + 1];
83 __u16 iflags = 0;
84 __u16 oflags = 0;
85 __be32 ikey = 0;
86 __be32 okey = 0;
87 unsigned int saddr = 0;
88 unsigned int daddr = 0;
89 unsigned int link = 0;
90 __u8 pmtudisc = 1;
91 __u8 ttl = 0;
92 __u8 tos = 0;
93 int len;
94 __u16 encaptype = 0;
95 __u16 encapflags = 0;
96 __u16 encapsport = 0;
97 __u16 encapdport = 0;
98 __u8 metadata = 0;
99 __u8 ignore_df = 0;
100 __u32 fwmark = 0;
101 __u32 erspan_idx = 0;
102
103 if (!(n->nlmsg_flags & NLM_F_CREATE)) {
104 if (rtnl_talk(&rth, &req.n, &answer) < 0) {
105 get_failed:
106 fprintf(stderr,
107 "Failed to get existing tunnel info.\n");
108 return -1;
109 }
110
111 len = answer->nlmsg_len;
112 len -= NLMSG_LENGTH(sizeof(*ifi));
113 if (len < 0)
114 goto get_failed;
115
116 parse_rtattr(tb, IFLA_MAX, IFLA_RTA(NLMSG_DATA(answer)), len);
117
118 if (!tb[IFLA_LINKINFO])
119 goto get_failed;
120
121 parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
122
123 if (!linkinfo[IFLA_INFO_DATA])
124 goto get_failed;
125
126 parse_rtattr_nested(greinfo, IFLA_GRE_MAX,
127 linkinfo[IFLA_INFO_DATA]);
128
129 if (greinfo[IFLA_GRE_IKEY])
130 ikey = rta_getattr_u32(greinfo[IFLA_GRE_IKEY]);
131
132 if (greinfo[IFLA_GRE_OKEY])
133 okey = rta_getattr_u32(greinfo[IFLA_GRE_OKEY]);
134
135 if (greinfo[IFLA_GRE_IFLAGS])
136 iflags = rta_getattr_u16(greinfo[IFLA_GRE_IFLAGS]);
137
138 if (greinfo[IFLA_GRE_OFLAGS])
139 oflags = rta_getattr_u16(greinfo[IFLA_GRE_OFLAGS]);
140
141 if (greinfo[IFLA_GRE_LOCAL])
142 saddr = rta_getattr_u32(greinfo[IFLA_GRE_LOCAL]);
143
144 if (greinfo[IFLA_GRE_REMOTE])
145 daddr = rta_getattr_u32(greinfo[IFLA_GRE_REMOTE]);
146
147 if (greinfo[IFLA_GRE_PMTUDISC])
148 pmtudisc = rta_getattr_u8(
149 greinfo[IFLA_GRE_PMTUDISC]);
150
151 if (greinfo[IFLA_GRE_TTL])
152 ttl = rta_getattr_u8(greinfo[IFLA_GRE_TTL]);
153
154 if (greinfo[IFLA_GRE_TOS])
155 tos = rta_getattr_u8(greinfo[IFLA_GRE_TOS]);
156
157 if (greinfo[IFLA_GRE_LINK])
158 link = rta_getattr_u32(greinfo[IFLA_GRE_LINK]);
159
160 if (greinfo[IFLA_GRE_ENCAP_TYPE])
161 encaptype = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_TYPE]);
162 if (greinfo[IFLA_GRE_ENCAP_FLAGS])
163 encapflags = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_FLAGS]);
164 if (greinfo[IFLA_GRE_ENCAP_SPORT])
165 encapsport = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_SPORT]);
166 if (greinfo[IFLA_GRE_ENCAP_DPORT])
167 encapdport = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_DPORT]);
168
169 if (greinfo[IFLA_GRE_COLLECT_METADATA])
170 metadata = 1;
171
172 if (greinfo[IFLA_GRE_IGNORE_DF])
173 ignore_df =
174 !!rta_getattr_u8(greinfo[IFLA_GRE_IGNORE_DF]);
175
176 if (greinfo[IFLA_GRE_FWMARK])
177 fwmark = rta_getattr_u32(greinfo[IFLA_GRE_FWMARK]);
178
179 if (greinfo[IFLA_GRE_ERSPAN_INDEX])
180 erspan_idx = rta_getattr_u32(greinfo[IFLA_GRE_ERSPAN_INDEX]);
181
182 free(answer);
183 }
184
185 while (argc > 0) {
186 if (!matches(*argv, "key")) {
187 NEXT_ARG();
188 iflags |= GRE_KEY;
189 oflags |= GRE_KEY;
190 ikey = okey = tnl_parse_key("key", *argv);
191 } else if (!matches(*argv, "ikey")) {
192 NEXT_ARG();
193 iflags |= GRE_KEY;
194 ikey = tnl_parse_key("ikey", *argv);
195 } else if (!matches(*argv, "okey")) {
196 NEXT_ARG();
197 oflags |= GRE_KEY;
198 okey = tnl_parse_key("okey", *argv);
199 } else if (!matches(*argv, "seq")) {
200 iflags |= GRE_SEQ;
201 oflags |= GRE_SEQ;
202 } else if (!matches(*argv, "iseq")) {
203 iflags |= GRE_SEQ;
204 } else if (!matches(*argv, "oseq")) {
205 oflags |= GRE_SEQ;
206 } else if (!matches(*argv, "csum")) {
207 iflags |= GRE_CSUM;
208 oflags |= GRE_CSUM;
209 } else if (!matches(*argv, "icsum")) {
210 iflags |= GRE_CSUM;
211 } else if (!matches(*argv, "ocsum")) {
212 oflags |= GRE_CSUM;
213 } else if (!matches(*argv, "nopmtudisc")) {
214 pmtudisc = 0;
215 } else if (!matches(*argv, "pmtudisc")) {
216 pmtudisc = 1;
217 } else if (!matches(*argv, "remote")) {
218 NEXT_ARG();
219 daddr = get_addr32(*argv);
220 } else if (!matches(*argv, "local")) {
221 NEXT_ARG();
222 saddr = get_addr32(*argv);
223 } else if (!matches(*argv, "dev")) {
224 NEXT_ARG();
225 link = if_nametoindex(*argv);
226 if (link == 0) {
227 fprintf(stderr, "Cannot find device \"%s\"\n",
228 *argv);
229 exit(-1);
230 }
231 } else if (!matches(*argv, "ttl") ||
232 !matches(*argv, "hoplimit")) {
233 unsigned int uval;
234
235 NEXT_ARG();
236 if (strcmp(*argv, "inherit") != 0) {
237 if (get_unsigned(&uval, *argv, 0))
238 invarg("invalid TTL\n", *argv);
239 if (uval > 255)
240 invarg("TTL must be <= 255\n", *argv);
241 ttl = uval;
242 } else
243 ttl = 0;
244 } else if (!matches(*argv, "tos") ||
245 !matches(*argv, "tclass") ||
246 !matches(*argv, "dsfield")) {
247 __u32 uval;
248
249 NEXT_ARG();
250 if (strcmp(*argv, "inherit") != 0) {
251 if (rtnl_dsfield_a2n(&uval, *argv))
252 invarg("bad TOS value", *argv);
253 tos = uval;
254 } else
255 tos = 1;
256 } else if (strcmp(*argv, "noencap") == 0) {
257 encaptype = TUNNEL_ENCAP_NONE;
258 } else if (strcmp(*argv, "encap") == 0) {
259 NEXT_ARG();
260 if (strcmp(*argv, "fou") == 0)
261 encaptype = TUNNEL_ENCAP_FOU;
262 else if (strcmp(*argv, "gue") == 0)
263 encaptype = TUNNEL_ENCAP_GUE;
264 else if (strcmp(*argv, "none") == 0)
265 encaptype = TUNNEL_ENCAP_NONE;
266 else
267 invarg("Invalid encap type.", *argv);
268 } else if (strcmp(*argv, "encap-sport") == 0) {
269 NEXT_ARG();
270 if (strcmp(*argv, "auto") == 0)
271 encapsport = 0;
272 else if (get_u16(&encapsport, *argv, 0))
273 invarg("Invalid source port.", *argv);
274 } else if (strcmp(*argv, "encap-dport") == 0) {
275 NEXT_ARG();
276 if (get_u16(&encapdport, *argv, 0))
277 invarg("Invalid destination port.", *argv);
278 } else if (strcmp(*argv, "encap-csum") == 0) {
279 encapflags |= TUNNEL_ENCAP_FLAG_CSUM;
280 } else if (strcmp(*argv, "noencap-csum") == 0) {
281 encapflags &= ~TUNNEL_ENCAP_FLAG_CSUM;
282 } else if (strcmp(*argv, "encap-udp6-csum") == 0) {
283 encapflags |= TUNNEL_ENCAP_FLAG_CSUM6;
284 } else if (strcmp(*argv, "noencap-udp6-csum") == 0) {
285 encapflags &= ~TUNNEL_ENCAP_FLAG_CSUM6;
286 } else if (strcmp(*argv, "encap-remcsum") == 0) {
287 encapflags |= TUNNEL_ENCAP_FLAG_REMCSUM;
288 } else if (strcmp(*argv, "noencap-remcsum") == 0) {
289 encapflags &= ~TUNNEL_ENCAP_FLAG_REMCSUM;
290 } else if (strcmp(*argv, "external") == 0) {
291 metadata = 1;
292 } else if (strcmp(*argv, "ignore-df") == 0) {
293 ignore_df = 1;
294 } else if (strcmp(*argv, "noignore-df") == 0) {
295 /*
296 *only the lsb is significant, use 2 for presence
297 */
298 ignore_df = 2;
299 } else if (strcmp(*argv, "fwmark") == 0) {
300 NEXT_ARG();
301 if (get_u32(&fwmark, *argv, 0))
302 invarg("invalid fwmark\n", *argv);
303 } else if (strcmp(*argv, "erspan") == 0) {
304 NEXT_ARG();
305 if (get_u32(&erspan_idx, *argv, 0))
306 invarg("invalid erspan index\n", *argv);
307 if (erspan_idx & ~((1<<20) - 1) || erspan_idx == 0)
308 invarg("erspan index must be > 0 and <= 20-bit\n", *argv);
309 } else
310 usage();
311 argc--; argv++;
312 }
313
314 if (!ikey && IN_MULTICAST(ntohl(daddr))) {
315 ikey = daddr;
316 iflags |= GRE_KEY;
317 }
318 if (!okey && IN_MULTICAST(ntohl(daddr))) {
319 okey = daddr;
320 oflags |= GRE_KEY;
321 }
322 if (IN_MULTICAST(ntohl(daddr)) && !saddr) {
323 fprintf(stderr, "A broadcast tunnel requires a source address.\n");
324 return -1;
325 }
326
327 if (!metadata) {
328 addattr32(n, 1024, IFLA_GRE_IKEY, ikey);
329 addattr32(n, 1024, IFLA_GRE_OKEY, okey);
330 addattr_l(n, 1024, IFLA_GRE_IFLAGS, &iflags, 2);
331 addattr_l(n, 1024, IFLA_GRE_OFLAGS, &oflags, 2);
332 addattr_l(n, 1024, IFLA_GRE_LOCAL, &saddr, 4);
333 addattr_l(n, 1024, IFLA_GRE_REMOTE, &daddr, 4);
334 addattr_l(n, 1024, IFLA_GRE_PMTUDISC, &pmtudisc, 1);
335 if (link)
336 addattr32(n, 1024, IFLA_GRE_LINK, link);
337 addattr_l(n, 1024, IFLA_GRE_TTL, &ttl, 1);
338 addattr_l(n, 1024, IFLA_GRE_TOS, &tos, 1);
339 addattr32(n, 1024, IFLA_GRE_FWMARK, fwmark);
340 if (erspan_idx != 0)
341 addattr32(n, 1024, IFLA_GRE_ERSPAN_INDEX, erspan_idx);
342 } else {
343 addattr_l(n, 1024, IFLA_GRE_COLLECT_METADATA, NULL, 0);
344 }
345
346 addattr16(n, 1024, IFLA_GRE_ENCAP_TYPE, encaptype);
347 addattr16(n, 1024, IFLA_GRE_ENCAP_FLAGS, encapflags);
348 addattr16(n, 1024, IFLA_GRE_ENCAP_SPORT, htons(encapsport));
349 addattr16(n, 1024, IFLA_GRE_ENCAP_DPORT, htons(encapdport));
350
351 if (ignore_df)
352 addattr8(n, 1024, IFLA_GRE_IGNORE_DF, ignore_df & 1);
353
354 return 0;
355 }
356
357 static void gre_print_direct_opt(FILE *f, struct rtattr *tb[])
358 {
359 char s2[64];
360 const char *local = "any";
361 const char *remote = "any";
362 unsigned int iflags = 0;
363 unsigned int oflags = 0;
364
365 if (tb[IFLA_GRE_REMOTE]) {
366 unsigned int addr = rta_getattr_u32(tb[IFLA_GRE_REMOTE]);
367
368 if (addr)
369 remote = format_host(AF_INET, 4, &addr);
370 }
371
372 print_string(PRINT_ANY, "remote", "remote %s ", remote);
373
374 if (tb[IFLA_GRE_LOCAL]) {
375 unsigned int addr = rta_getattr_u32(tb[IFLA_GRE_LOCAL]);
376
377 if (addr)
378 local = format_host(AF_INET, 4, &addr);
379 }
380
381 print_string(PRINT_ANY, "local", "local %s ", local);
382
383 if (tb[IFLA_GRE_LINK] && rta_getattr_u32(tb[IFLA_GRE_LINK])) {
384 unsigned int link = rta_getattr_u32(tb[IFLA_GRE_LINK]);
385 const char *n = if_indextoname(link, s2);
386
387 if (n)
388 print_string(PRINT_ANY, "link", "dev %s ", n);
389 else
390 print_uint(PRINT_ANY, "link_index", "dev %u ", link);
391 }
392
393 if (tb[IFLA_GRE_TTL]) {
394 __u8 ttl = rta_getattr_u8(tb[IFLA_GRE_TTL]);
395
396 if (ttl)
397 print_int(PRINT_ANY, "ttl", "ttl %d ", ttl);
398 else
399 print_int(PRINT_JSON, "ttl", NULL, ttl);
400 } else {
401 print_string(PRINT_FP, NULL, "ttl %s ", "inherit");
402 }
403
404 if (tb[IFLA_GRE_TOS] && rta_getattr_u8(tb[IFLA_GRE_TOS])) {
405 int tos = rta_getattr_u8(tb[IFLA_GRE_TOS]);
406
407 if (is_json_context()) {
408 SPRINT_BUF(b1);
409
410 snprintf(b1, sizeof(b1), "0x%x", tos);
411 print_string(PRINT_JSON, "tos", NULL, b1);
412 } else {
413 fputs("tos ", f);
414 if (tos == 1)
415 fputs("inherit ", f);
416 else
417 fprintf(f, "0x%x ", tos);
418 }
419 }
420
421 if (tb[IFLA_GRE_PMTUDISC]) {
422 if (!rta_getattr_u8(tb[IFLA_GRE_PMTUDISC]))
423 print_bool(PRINT_ANY, "pmtudisc", "nopmtudisc ", false);
424 else
425 print_bool(PRINT_JSON, "pmtudisc", NULL, true);
426 }
427
428 if (tb[IFLA_GRE_IFLAGS])
429 iflags = rta_getattr_u16(tb[IFLA_GRE_IFLAGS]);
430
431 if (tb[IFLA_GRE_OFLAGS])
432 oflags = rta_getattr_u16(tb[IFLA_GRE_OFLAGS]);
433
434 if ((iflags & GRE_KEY) && tb[IFLA_GRE_IKEY]) {
435 inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_IKEY]), s2, sizeof(s2));
436 print_string(PRINT_ANY, "ikey", "ikey %s ", s2);
437 }
438
439 if ((oflags & GRE_KEY) && tb[IFLA_GRE_OKEY]) {
440 inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_OKEY]), s2, sizeof(s2));
441 print_string(PRINT_ANY, "okey", "okey %s ", s2);
442 }
443
444 if (iflags & GRE_SEQ)
445 print_bool(PRINT_ANY, "iseq", "iseq ", true);
446 if (oflags & GRE_SEQ)
447 print_bool(PRINT_ANY, "oseq", "oseq ", true);
448 if (iflags & GRE_CSUM)
449 print_bool(PRINT_ANY, "icsum", "icsum ", true);
450 if (oflags & GRE_CSUM)
451 print_bool(PRINT_ANY, "ocsum", "ocsum ", true);
452
453 if (tb[IFLA_GRE_FWMARK]) {
454 __u32 fwmark = rta_getattr_u32(tb[IFLA_GRE_FWMARK]);
455
456 if (fwmark) {
457 snprintf(s2, sizeof(s2), "0x%x", fwmark);
458
459 print_string(PRINT_ANY, "fwmark", "fwmark %s ", s2);
460 }
461 }
462 }
463
464 static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
465 {
466 if (!tb)
467 return;
468
469 if (!tb[IFLA_GRE_COLLECT_METADATA])
470 gre_print_direct_opt(f, tb);
471 else
472 print_bool(PRINT_ANY, "external", "external ", true);
473
474 if (tb[IFLA_GRE_IGNORE_DF] && rta_getattr_u8(tb[IFLA_GRE_IGNORE_DF]))
475 print_bool(PRINT_ANY, "ignore_df", "ignore-df ", true);
476
477 if (tb[IFLA_GRE_ERSPAN_INDEX]) {
478 __u32 erspan_idx = rta_getattr_u32(tb[IFLA_GRE_ERSPAN_INDEX]);
479
480 fprintf(f, "erspan_index %u ", erspan_idx);
481 }
482
483 if (tb[IFLA_GRE_ENCAP_TYPE] &&
484 rta_getattr_u16(tb[IFLA_GRE_ENCAP_TYPE]) != TUNNEL_ENCAP_NONE) {
485 __u16 type = rta_getattr_u16(tb[IFLA_GRE_ENCAP_TYPE]);
486 __u16 flags = rta_getattr_u16(tb[IFLA_GRE_ENCAP_FLAGS]);
487 __u16 sport = rta_getattr_u16(tb[IFLA_GRE_ENCAP_SPORT]);
488 __u16 dport = rta_getattr_u16(tb[IFLA_GRE_ENCAP_DPORT]);
489
490
491 open_json_object("encap");
492 print_string(PRINT_FP, NULL, "encap ", NULL);
493
494 switch (type) {
495 case TUNNEL_ENCAP_FOU:
496 print_string(PRINT_ANY, "type", "%s ", "fou");
497 break;
498 case TUNNEL_ENCAP_GUE:
499 print_string(PRINT_ANY, "type", "%s ", "gue");
500 break;
501 default:
502 print_null(PRINT_ANY, "type", "%s ", "unknown");
503 break;
504 }
505
506 if (is_json_context()) {
507 print_uint(PRINT_JSON,
508 "sport",
509 NULL,
510 sport ? ntohs(sport) : 0);
511 print_uint(PRINT_JSON, "dport", NULL, ntohs(dport));
512
513 print_bool(PRINT_JSON,
514 "csum",
515 NULL,
516 flags & TUNNEL_ENCAP_FLAG_CSUM);
517
518 print_bool(PRINT_JSON,
519 "csum6",
520 NULL,
521 flags & TUNNEL_ENCAP_FLAG_CSUM6);
522
523 print_bool(PRINT_JSON,
524 "remcsum",
525 NULL,
526 flags & TUNNEL_ENCAP_FLAG_REMCSUM);
527
528 close_json_object();
529 } else {
530 if (sport == 0)
531 fputs("encap-sport auto ", f);
532 else
533 fprintf(f, "encap-sport %u", ntohs(sport));
534
535 fprintf(f, "encap-dport %u ", ntohs(dport));
536
537 if (flags & TUNNEL_ENCAP_FLAG_CSUM)
538 fputs("encap-csum ", f);
539 else
540 fputs("noencap-csum ", f);
541
542 if (flags & TUNNEL_ENCAP_FLAG_CSUM6)
543 fputs("encap-csum6 ", f);
544 else
545 fputs("noencap-csum6 ", f);
546
547 if (flags & TUNNEL_ENCAP_FLAG_REMCSUM)
548 fputs("encap-remcsum ", f);
549 else
550 fputs("noencap-remcsum ", f);
551 }
552 }
553 }
554
555 static void gre_print_help(struct link_util *lu, int argc, char **argv,
556 FILE *f)
557 {
558 print_usage(f);
559 }
560
561 struct link_util gre_link_util = {
562 .id = "gre",
563 .maxattr = IFLA_GRE_MAX,
564 .parse_opt = gre_parse_opt,
565 .print_opt = gre_print_opt,
566 .print_help = gre_print_help,
567 };
568
569 struct link_util gretap_link_util = {
570 .id = "gretap",
571 .maxattr = IFLA_GRE_MAX,
572 .parse_opt = gre_parse_opt,
573 .print_opt = gre_print_opt,
574 .print_help = gre_print_help,
575 };
576
577 struct link_util erspan_link_util = {
578 .id = "erspan",
579 .maxattr = IFLA_GRE_MAX,
580 .parse_opt = gre_parse_opt,
581 .print_opt = gre_print_opt,
582 .print_help = gre_print_help,
583 };