1 /* 2 * link_gre6.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: Dmitry Kozlov <xeb (at) mail.ru> 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 <linux/ip6_tunnel.h> 22 23 #include "rt_names.h" 24 #include "utils.h" 25 #include "ip_common.h" 26 #include "tunnel.h" 27 28 #define IP6_FLOWINFO_TCLASS htonl(0x0FF00000) 29 #define IP6_FLOWINFO_FLOWLABEL htonl(0x000FFFFF) 30 31 #define DEFAULT_TNL_HOP_LIMIT (64) 32 33 static void print_usage(FILE *f) 34 { 35 fprintf(f, 36 "Usage: ... { ip6gre | ip6gretap } [ remote ADDR ]\n" 37 " [ local ADDR ]\n" 38 " [ [i|o]seq ]\n" 39 " [ [i|o]key KEY ]\n" 40 " [ [i|o]csum ]\n" 41 " [ hoplimit TTL ]\n" 42 " [ encaplimit ELIM ]\n" 43 " [ tclass TCLASS ]\n" 44 " [ flowlabel FLOWLABEL ]\n" 45 " [ dscp inherit ]\n" 46 " [ fwmark MARK ]\n" 47 " [ dev PHYS_DEV ]\n" 48 " [ noencap ]\n" 49 " [ encap { fou | gue | none } ]\n" 50 " [ encap-sport PORT ]\n" 51 " [ encap-dport PORT ]\n" 52 " [ [no]encap-csum ]\n" 53 " [ [no]encap-csum6 ]\n" 54 " [ [no]encap-remcsum ]\n" 55 "\n" 56 "Where: ADDR := IPV6_ADDRESS\n" 57 " TTL := { 0..255 } (default=%d)\n" 58 " KEY := { DOTTED_QUAD | NUMBER }\n" 59 " ELIM := { none | 0..255 }(default=%d)\n" 60 " TCLASS := { 0x0..0xff | inherit }\n" 61 " FLOWLABEL := { 0x0..0xfffff | inherit }\n" 62 " MARK := { 0x0..0xffffffff | inherit }\n", 63 DEFAULT_TNL_HOP_LIMIT, IPV6_DEFAULT_TNL_ENCAP_LIMIT 64 ); 65 } 66 67 static void usage(void) __attribute__((noreturn)); 68 static void usage(void) 69 { 70 print_usage(stderr); 71 exit(-1); 72 } 73 74 static int gre_parse_opt(struct link_util *lu, int argc, char **argv, 75 struct nlmsghdr *n) 76 { 77 struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1); 78 struct { 79 struct nlmsghdr n; 80 struct ifinfomsg i; 81 char buf[1024]; 82 } req = { 83 .n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)), 84 .n.nlmsg_flags = NLM_F_REQUEST, 85 .n.nlmsg_type = RTM_GETLINK, 86 .i.ifi_family = preferred_family, 87 .i.ifi_index = ifi->ifi_index, 88 }; 89 struct rtattr *tb[IFLA_MAX + 1]; 90 struct rtattr *linkinfo[IFLA_INFO_MAX+1]; 91 struct rtattr *greinfo[IFLA_GRE_MAX + 1]; 92 __u16 iflags = 0; 93 __u16 oflags = 0; 94 unsigned int ikey = 0; 95 unsigned int okey = 0; 96 struct in6_addr raddr = IN6ADDR_ANY_INIT; 97 struct in6_addr laddr = IN6ADDR_ANY_INIT; 98 unsigned int link = 0; 99 unsigned int flowinfo = 0; 100 unsigned int flags = 0; 101 __u8 hop_limit = DEFAULT_TNL_HOP_LIMIT; 102 __u8 encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT; 103 __u16 encaptype = 0; 104 __u16 encapflags = TUNNEL_ENCAP_FLAG_CSUM6; 105 __u16 encapsport = 0; 106 __u16 encapdport = 0; 107 int len; 108 __u32 fwmark = 0; 109 110 if (!(n->nlmsg_flags & NLM_F_CREATE)) { 111 if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) { 112 get_failed: 113 fprintf(stderr, 114 "Failed to get existing tunnel info.\n"); 115 return -1; 116 } 117 118 len = req.n.nlmsg_len; 119 len -= NLMSG_LENGTH(sizeof(*ifi)); 120 if (len < 0) 121 goto get_failed; 122 123 parse_rtattr(tb, IFLA_MAX, IFLA_RTA(&req.i), len); 124 125 if (!tb[IFLA_LINKINFO]) 126 goto get_failed; 127 128 parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]); 129 130 if (!linkinfo[IFLA_INFO_DATA]) 131 goto get_failed; 132 133 parse_rtattr_nested(greinfo, IFLA_GRE_MAX, 134 linkinfo[IFLA_INFO_DATA]); 135 136 if (greinfo[IFLA_GRE_IKEY]) 137 ikey = rta_getattr_u32(greinfo[IFLA_GRE_IKEY]); 138 139 if (greinfo[IFLA_GRE_OKEY]) 140 okey = rta_getattr_u32(greinfo[IFLA_GRE_OKEY]); 141 142 if (greinfo[IFLA_GRE_IFLAGS]) 143 iflags = rta_getattr_u16(greinfo[IFLA_GRE_IFLAGS]); 144 145 if (greinfo[IFLA_GRE_OFLAGS]) 146 oflags = rta_getattr_u16(greinfo[IFLA_GRE_OFLAGS]); 147 148 if (greinfo[IFLA_GRE_LOCAL]) 149 memcpy(&laddr, RTA_DATA(greinfo[IFLA_GRE_LOCAL]), sizeof(laddr)); 150 151 if (greinfo[IFLA_GRE_REMOTE]) 152 memcpy(&raddr, RTA_DATA(greinfo[IFLA_GRE_REMOTE]), sizeof(raddr)); 153 154 if (greinfo[IFLA_GRE_TTL]) 155 hop_limit = rta_getattr_u8(greinfo[IFLA_GRE_TTL]); 156 157 if (greinfo[IFLA_GRE_LINK]) 158 link = rta_getattr_u32(greinfo[IFLA_GRE_LINK]); 159 160 if (greinfo[IFLA_GRE_ENCAP_LIMIT]) 161 encap_limit = rta_getattr_u8(greinfo[IFLA_GRE_ENCAP_LIMIT]); 162 163 if (greinfo[IFLA_GRE_FLOWINFO]) 164 flowinfo = rta_getattr_u32(greinfo[IFLA_GRE_FLOWINFO]); 165 166 if (greinfo[IFLA_GRE_FLAGS]) 167 flags = rta_getattr_u32(greinfo[IFLA_GRE_FLAGS]); 168 169 if (greinfo[IFLA_GRE_ENCAP_TYPE]) 170 encaptype = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_TYPE]); 171 172 if (greinfo[IFLA_GRE_ENCAP_FLAGS]) 173 encapflags = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_FLAGS]); 174 175 if (greinfo[IFLA_GRE_ENCAP_SPORT]) 176 encapsport = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_SPORT]); 177 178 if (greinfo[IFLA_GRE_ENCAP_DPORT]) 179 encapdport = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_DPORT]); 180 181 if (greinfo[IFLA_GRE_FWMARK]) 182 fwmark = rta_getattr_u32(greinfo[IFLA_GRE_FWMARK]); 183 } 184 185 while (argc > 0) { 186 if (!matches(*argv, "key")) { 187 unsigned int uval; 188 189 NEXT_ARG(); 190 iflags |= GRE_KEY; 191 oflags |= GRE_KEY; 192 if (strchr(*argv, '.')) 193 uval = get_addr32(*argv); 194 else { 195 if (get_unsigned(&uval, *argv, 0) < 0) { 196 fprintf(stderr, 197 "Invalid value for \"key\"\n"); 198 exit(-1); 199 } 200 uval = htonl(uval); 201 } 202 203 ikey = okey = uval; 204 } else if (!matches(*argv, "ikey")) { 205 unsigned int uval; 206 207 NEXT_ARG(); 208 iflags |= GRE_KEY; 209 if (strchr(*argv, '.')) 210 uval = get_addr32(*argv); 211 else { 212 if (get_unsigned(&uval, *argv, 0) < 0) { 213 fprintf(stderr, "invalid value of \"ikey\"\n"); 214 exit(-1); 215 } 216 uval = htonl(uval); 217 } 218 ikey = uval; 219 } else if (!matches(*argv, "okey")) { 220 unsigned int uval; 221 222 NEXT_ARG(); 223 oflags |= GRE_KEY; 224 if (strchr(*argv, '.')) 225 uval = get_addr32(*argv); 226 else { 227 if (get_unsigned(&uval, *argv, 0) < 0) { 228 fprintf(stderr, "invalid value of \"okey\"\n"); 229 exit(-1); 230 } 231 uval = htonl(uval); 232 } 233 okey = uval; 234 } else if (!matches(*argv, "seq")) { 235 iflags |= GRE_SEQ; 236 oflags |= GRE_SEQ; 237 } else if (!matches(*argv, "iseq")) { 238 iflags |= GRE_SEQ; 239 } else if (!matches(*argv, "oseq")) { 240 oflags |= GRE_SEQ; 241 } else if (!matches(*argv, "csum")) { 242 iflags |= GRE_CSUM; 243 oflags |= GRE_CSUM; 244 } else if (!matches(*argv, "icsum")) { 245 iflags |= GRE_CSUM; 246 } else if (!matches(*argv, "ocsum")) { 247 oflags |= GRE_CSUM; 248 } else if (!matches(*argv, "remote")) { 249 inet_prefix addr; 250 251 NEXT_ARG(); 252 get_prefix(&addr, *argv, preferred_family); 253 if (addr.family == AF_UNSPEC) 254 invarg("\"remote\" address family is AF_UNSPEC", *argv); 255 memcpy(&raddr, &addr.data, sizeof(raddr)); 256 } else if (!matches(*argv, "local")) { 257 inet_prefix addr; 258 259 NEXT_ARG(); 260 get_prefix(&addr, *argv, preferred_family); 261 if (addr.family == AF_UNSPEC) 262 invarg("\"local\" address family is AF_UNSPEC", *argv); 263 memcpy(&laddr, &addr.data, sizeof(laddr)); 264 } else if (!matches(*argv, "dev")) { 265 NEXT_ARG(); 266 link = if_nametoindex(*argv); 267 if (link == 0) { 268 fprintf(stderr, "Cannot find device \"%s\"\n", 269 *argv); 270 exit(-1); 271 } 272 } else if (!matches(*argv, "ttl") || 273 !matches(*argv, "hoplimit")) { 274 __u8 uval; 275 276 NEXT_ARG(); 277 if (get_u8(&uval, *argv, 0)) 278 invarg("invalid TTL", *argv); 279 hop_limit = uval; 280 } else if (!matches(*argv, "tos") || 281 !matches(*argv, "tclass") || 282 !matches(*argv, "dsfield")) { 283 __u8 uval; 284 285 NEXT_ARG(); 286 if (strcmp(*argv, "inherit") == 0) 287 flags |= IP6_TNL_F_USE_ORIG_TCLASS; 288 else { 289 if (get_u8(&uval, *argv, 16)) 290 invarg("invalid TClass", *argv); 291 flowinfo &= ~IP6_FLOWINFO_TCLASS; 292 flowinfo |= htonl((__u32)uval << 20) & IP6_FLOWINFO_TCLASS; 293 flags &= ~IP6_TNL_F_USE_ORIG_TCLASS; 294 } 295 } else if (strcmp(*argv, "flowlabel") == 0 || 296 strcmp(*argv, "fl") == 0) { 297 __u32 uval; 298 299 NEXT_ARG(); 300 if (strcmp(*argv, "inherit") == 0) 301 flags |= IP6_TNL_F_USE_ORIG_FLOWLABEL; 302 else { 303 if (get_u32(&uval, *argv, 16)) 304 invarg("invalid Flowlabel", *argv); 305 if (uval > 0xFFFFF) 306 invarg("invalid Flowlabel", *argv); 307 flowinfo &= ~IP6_FLOWINFO_FLOWLABEL; 308 flowinfo |= htonl(uval) & IP6_FLOWINFO_FLOWLABEL; 309 flags &= ~IP6_TNL_F_USE_ORIG_FLOWLABEL; 310 } 311 } else if (strcmp(*argv, "dscp") == 0) { 312 NEXT_ARG(); 313 if (strcmp(*argv, "inherit") != 0) 314 invarg("not inherit", *argv); 315 flags |= IP6_TNL_F_RCV_DSCP_COPY; 316 } else if (strcmp(*argv, "noencap") == 0) { 317 encaptype = TUNNEL_ENCAP_NONE; 318 } else if (strcmp(*argv, "encap") == 0) { 319 NEXT_ARG(); 320 if (strcmp(*argv, "fou") == 0) 321 encaptype = TUNNEL_ENCAP_FOU; 322 else if (strcmp(*argv, "gue") == 0) 323 encaptype = TUNNEL_ENCAP_GUE; 324 else if (strcmp(*argv, "none") == 0) 325 encaptype = TUNNEL_ENCAP_NONE; 326 else 327 invarg("Invalid encap type.", *argv); 328 } else if (strcmp(*argv, "encap-sport") == 0) { 329 NEXT_ARG(); 330 if (strcmp(*argv, "auto") == 0) 331 encapsport = 0; 332 else if (get_u16(&encapsport, *argv, 0)) 333 invarg("Invalid source port.", *argv); 334 } else if (strcmp(*argv, "encap-dport") == 0) { 335 NEXT_ARG(); 336 if (get_u16(&encapdport, *argv, 0)) 337 invarg("Invalid destination port.", *argv); 338 } else if (strcmp(*argv, "encap-csum") == 0) { 339 encapflags |= TUNNEL_ENCAP_FLAG_CSUM; 340 } else if (strcmp(*argv, "noencap-csum") == 0) { 341 encapflags &= ~TUNNEL_ENCAP_FLAG_CSUM; 342 } else if (strcmp(*argv, "encap-udp6-csum") == 0) { 343 encapflags |= TUNNEL_ENCAP_FLAG_CSUM6; 344 } else if (strcmp(*argv, "noencap-udp6-csum") == 0) { 345 encapflags &= ~TUNNEL_ENCAP_FLAG_CSUM6; 346 } else if (strcmp(*argv, "encap-remcsum") == 0) { 347 encapflags |= TUNNEL_ENCAP_FLAG_REMCSUM; 348 } else if (strcmp(*argv, "noencap-remcsum") == 0) { 349 encapflags &= ~TUNNEL_ENCAP_FLAG_REMCSUM; 350 } else if (strcmp(*argv, "fwmark") == 0) { 351 NEXT_ARG(); 352 if (strcmp(*argv, "inherit") == 0) { 353 flags |= IP6_TNL_F_USE_ORIG_FWMARK; 354 fwmark = 0; 355 } else { 356 if (get_u32(&fwmark, *argv, 0)) 357 invarg("invalid fwmark\n", *argv); 358 flags &= ~IP6_TNL_F_USE_ORIG_FWMARK; 359 } 360 } else if (strcmp(*argv, "encaplimit") == 0) { 361 NEXT_ARG(); 362 if (strcmp(*argv, "none") == 0) { 363 flags |= IP6_TNL_F_IGN_ENCAP_LIMIT; 364 } else { 365 __u8 uval; 366 367 if (get_u8(&uval, *argv, 0) < -1) 368 invarg("invalid ELIM", *argv); 369 encap_limit = uval; 370 flags &= ~IP6_TNL_F_IGN_ENCAP_LIMIT; 371 } 372 } else 373 usage(); 374 argc--; argv++; 375 } 376 377 addattr32(n, 1024, IFLA_GRE_IKEY, ikey); 378 addattr32(n, 1024, IFLA_GRE_OKEY, okey); 379 addattr_l(n, 1024, IFLA_GRE_IFLAGS, &iflags, 2); 380 addattr_l(n, 1024, IFLA_GRE_OFLAGS, &oflags, 2); 381 addattr_l(n, 1024, IFLA_GRE_LOCAL, &laddr, sizeof(laddr)); 382 addattr_l(n, 1024, IFLA_GRE_REMOTE, &raddr, sizeof(raddr)); 383 if (link) 384 addattr32(n, 1024, IFLA_GRE_LINK, link); 385 addattr_l(n, 1024, IFLA_GRE_TTL, &hop_limit, 1); 386 addattr_l(n, 1024, IFLA_GRE_ENCAP_LIMIT, &encap_limit, 1); 387 addattr_l(n, 1024, IFLA_GRE_FLOWINFO, &flowinfo, 4); 388 addattr32(n, 1024, IFLA_GRE_FLAGS, flags); 389 addattr32(n, 1024, IFLA_GRE_FWMARK, fwmark); 390 391 addattr16(n, 1024, IFLA_GRE_ENCAP_TYPE, encaptype); 392 addattr16(n, 1024, IFLA_GRE_ENCAP_FLAGS, encapflags); 393 addattr16(n, 1024, IFLA_GRE_ENCAP_SPORT, htons(encapsport)); 394 addattr16(n, 1024, IFLA_GRE_ENCAP_DPORT, htons(encapdport)); 395 396 return 0; 397 } 398 399 static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) 400 { 401 char s2[64]; 402 const char *local = "any"; 403 const char *remote = "any"; 404 unsigned int iflags = 0; 405 unsigned int oflags = 0; 406 unsigned int flags = 0; 407 unsigned int flowinfo = 0; 408 struct in6_addr in6_addr_any = IN6ADDR_ANY_INIT; 409 410 if (!tb) 411 return; 412 413 if (tb[IFLA_GRE_FLAGS]) 414 flags = rta_getattr_u32(tb[IFLA_GRE_FLAGS]); 415 416 if (tb[IFLA_GRE_FLOWINFO]) 417 flowinfo = rta_getattr_u32(tb[IFLA_GRE_FLOWINFO]); 418 419 if (tb[IFLA_GRE_REMOTE]) { 420 struct in6_addr addr; 421 422 memcpy(&addr, RTA_DATA(tb[IFLA_GRE_REMOTE]), sizeof(addr)); 423 424 if (memcmp(&addr, &in6_addr_any, sizeof(addr))) 425 remote = format_host(AF_INET6, sizeof(addr), &addr); 426 } 427 428 print_string(PRINT_ANY, "remote", "remote %s ", remote); 429 430 if (tb[IFLA_GRE_LOCAL]) { 431 struct in6_addr addr; 432 433 memcpy(&addr, RTA_DATA(tb[IFLA_GRE_LOCAL]), sizeof(addr)); 434 435 if (memcmp(&addr, &in6_addr_any, sizeof(addr))) 436 local = format_host(AF_INET6, sizeof(addr), &addr); 437 } 438 439 print_string(PRINT_ANY, "local", "local %s ", local); 440 441 if (tb[IFLA_GRE_LINK] && rta_getattr_u32(tb[IFLA_GRE_LINK])) { 442 unsigned int link = rta_getattr_u32(tb[IFLA_GRE_LINK]); 443 const char *n = if_indextoname(link, s2); 444 445 if (n) 446 print_string(PRINT_ANY, "link", "dev %s ", n); 447 else 448 print_uint(PRINT_ANY, "link_index", "dev %u ", link); 449 } 450 451 if (tb[IFLA_GRE_TTL]) { 452 __u8 ttl = rta_getattr_u8(tb[IFLA_GRE_TTL]); 453 454 if (ttl) 455 print_int(PRINT_ANY, "ttl", "hoplimit %d ", ttl); 456 else 457 print_int(PRINT_JSON, "ttl", NULL, ttl); 458 } 459 460 if (flags & IP6_TNL_F_IGN_ENCAP_LIMIT) 461 print_bool(PRINT_ANY, 462 "ip6_tnl_f_ign_encap_limit", 463 "encaplimit none ", 464 true); 465 else if (tb[IFLA_GRE_ENCAP_LIMIT]) { 466 int encap_limit = rta_getattr_u8(tb[IFLA_GRE_ENCAP_LIMIT]); 467 468 print_int(PRINT_ANY, 469 "encap_limit", 470 "encaplimit %d ", 471 encap_limit); 472 } 473 474 if (flags & IP6_TNL_F_USE_ORIG_FLOWLABEL) { 475 print_bool(PRINT_ANY, 476 "ip6_tnl_f_use_orig_flowlabel", 477 "flowlabel inherit ", 478 true); 479 } else { 480 if (is_json_context()) { 481 SPRINT_BUF(b1); 482 483 snprintf(b1, sizeof(b1), "0x%05x", 484 ntohl(flowinfo & IP6_FLOWINFO_FLOWLABEL)); 485 print_string(PRINT_JSON, "flowlabel", NULL, b1); 486 487 } else { 488 fprintf(f, "flowlabel 0x%05x ", 489 ntohl(flowinfo & IP6_FLOWINFO_FLOWLABEL)); 490 } 491 } 492 493 if (flags & IP6_TNL_F_USE_ORIG_TCLASS) { 494 print_bool(PRINT_ANY, 495 "ip6_tnl_f_use_orig_tclass", 496 "tclass inherit ", 497 true); 498 } else { 499 if (is_json_context()) { 500 SPRINT_BUF(b1); 501 502 snprintf(b1, sizeof(b1), "0x%05x", 503 ntohl(flowinfo & IP6_FLOWINFO_TCLASS) >> 20); 504 print_string(PRINT_JSON, "tclass", NULL, b1); 505 } else { 506 fprintf(f, "tclass 0x%02x ", 507 ntohl(flowinfo & IP6_FLOWINFO_TCLASS) >> 20); 508 } 509 } 510 511 if (flags & IP6_TNL_F_RCV_DSCP_COPY) 512 print_bool(PRINT_ANY, 513 "ip6_tnl_f_rcv_dscp_copy", 514 "dscp inherit ", 515 true); 516 517 if (tb[IFLA_GRE_IFLAGS]) 518 iflags = rta_getattr_u16(tb[IFLA_GRE_IFLAGS]); 519 520 if (tb[IFLA_GRE_OFLAGS]) 521 oflags = rta_getattr_u16(tb[IFLA_GRE_OFLAGS]); 522 523 if ((iflags & GRE_KEY) && tb[IFLA_GRE_IKEY]) { 524 inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_IKEY]), s2, sizeof(s2)); 525 print_string(PRINT_ANY, "ikey", "ikey %s ", s2); 526 } 527 528 if ((oflags & GRE_KEY) && tb[IFLA_GRE_OKEY]) { 529 inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_OKEY]), s2, sizeof(s2)); 530 print_string(PRINT_ANY, "okey", "okey %s ", s2); 531 } 532 533 if (iflags & GRE_SEQ) 534 print_bool(PRINT_ANY, "iseq", "iseq ", true); 535 if (oflags & GRE_SEQ) 536 print_bool(PRINT_ANY, "oseq", "oseq ", true); 537 if (iflags & GRE_CSUM) 538 print_bool(PRINT_ANY, "icsum", "icsum ", true); 539 if (oflags & GRE_CSUM) 540 print_bool(PRINT_ANY, "ocsum", "ocsum ", true); 541 542 if (flags & IP6_TNL_F_USE_ORIG_FWMARK) 543 print_bool(PRINT_ANY, 544 "ip6_tnl_f_use_orig_fwmark", 545 "fwmark inherit ", 546 true); 547 else if (tb[IFLA_GRE_FWMARK]) { 548 __u32 fwmark = rta_getattr_u32(tb[IFLA_GRE_FWMARK]); 549 550 if (fwmark) { 551 snprintf(s2, sizeof(s2), "0x%x", fwmark); 552 553 print_string(PRINT_ANY, "fwmark", "fwmark %s ", s2); 554 } 555 } 556 557 if (tb[IFLA_GRE_ENCAP_TYPE] && 558 rta_getattr_u16(tb[IFLA_GRE_ENCAP_TYPE]) != TUNNEL_ENCAP_NONE) { 559 __u16 type = rta_getattr_u16(tb[IFLA_GRE_ENCAP_TYPE]); 560 __u16 flags = rta_getattr_u16(tb[IFLA_GRE_ENCAP_FLAGS]); 561 __u16 sport = rta_getattr_u16(tb[IFLA_GRE_ENCAP_SPORT]); 562 __u16 dport = rta_getattr_u16(tb[IFLA_GRE_ENCAP_DPORT]); 563 564 open_json_object("encap"); 565 566 print_string(PRINT_FP, NULL, "encap ", NULL); 567 switch (type) { 568 case TUNNEL_ENCAP_FOU: 569 print_string(PRINT_ANY, "type", "%s ", "fou"); 570 break; 571 case TUNNEL_ENCAP_GUE: 572 print_string(PRINT_ANY, "type", "%s ", "gue"); 573 break; 574 default: 575 print_null(PRINT_ANY, "type", "unknown ", NULL); 576 break; 577 } 578 579 if (is_json_context()) { 580 print_uint(PRINT_JSON, 581 "sport", 582 NULL, 583 sport ? ntohs(sport) : 0); 584 print_uint(PRINT_JSON, "dport", NULL, ntohs(dport)); 585 print_bool(PRINT_JSON, "csum", NULL, 586 flags & TUNNEL_ENCAP_FLAG_CSUM); 587 print_bool(PRINT_JSON, "csum6", NULL, 588 flags & TUNNEL_ENCAP_FLAG_CSUM6); 589 print_bool(PRINT_JSON, "remcsum", NULL, 590 flags & TUNNEL_ENCAP_FLAG_REMCSUM); 591 close_json_object(); 592 } else { 593 if (sport == 0) 594 fputs("encap-sport auto ", f); 595 else 596 fprintf(f, "encap-sport %u", ntohs(sport)); 597 598 fprintf(f, "encap-dport %u ", ntohs(dport)); 599 600 if (flags & TUNNEL_ENCAP_FLAG_CSUM) 601 fputs("encap-csum ", f); 602 else 603 fputs("noencap-csum ", f); 604 605 if (flags & TUNNEL_ENCAP_FLAG_CSUM6) 606 fputs("encap-csum6 ", f); 607 else 608 fputs("noencap-csum6 ", f); 609 610 if (flags & TUNNEL_ENCAP_FLAG_REMCSUM) 611 fputs("encap-remcsum ", f); 612 else 613 fputs("noencap-remcsum ", f); 614 } 615 } 616 } 617 618 static void gre_print_help(struct link_util *lu, int argc, char **argv, 619 FILE *f) 620 { 621 print_usage(f); 622 } 623 624 struct link_util ip6gre_link_util = { 625 .id = "ip6gre", 626 .maxattr = IFLA_GRE_MAX, 627 .parse_opt = gre_parse_opt, 628 .print_opt = gre_print_opt, 629 .print_help = gre_print_help, 630 }; 631 632 struct link_util ip6gretap_link_util = { 633 .id = "ip6gretap", 634 .maxattr = IFLA_GRE_MAX, 635 .parse_opt = gre_parse_opt, 636 .print_opt = gre_print_opt, 637 .print_help = gre_print_help, 638 }; 639