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@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 33static void print_usage(FILE *f) 34{ 35 fprintf(f, "Usage: ip link { add | set | change | replace | del } NAME\n"); 36 fprintf(f, " type { ip6gre | ip6gretap } [ remote ADDR ] [ local ADDR ]\n"); 37 fprintf(f, " [ [i|o]seq ] [ [i|o]key KEY ] [ [i|o]csum ]\n"); 38 fprintf(f, " [ hoplimit TTL ] [ encaplimit ELIM ]\n"); 39 fprintf(f, " [ tclass TCLASS ] [ flowlabel FLOWLABEL ]\n"); 40 fprintf(f, " [ dscp inherit ] [ dev PHYS_DEV ]\n"); 41 fprintf(f, "\n"); 42 fprintf(f, "Where: NAME := STRING\n"); 43 fprintf(f, " ADDR := IPV6_ADDRESS\n"); 44 fprintf(f, " TTL := { 0..255 } (default=%d)\n", 45 DEFAULT_TNL_HOP_LIMIT); 46 fprintf(f, " KEY := { DOTTED_QUAD | NUMBER }\n"); 47 fprintf(f, " ELIM := { none | 0..255 }(default=%d)\n", 48 IPV6_DEFAULT_TNL_ENCAP_LIMIT); 49 fprintf(f, " TCLASS := { 0x0..0xff | inherit }\n"); 50 fprintf(f, " FLOWLABEL := { 0x0..0xfffff | inherit }\n"); 51} 52 53static void usage(void) __attribute__((noreturn)); 54static void usage(void) 55{ 56 print_usage(stderr); 57 exit(-1); 58} 59 60static int gre_parse_opt(struct link_util *lu, int argc, char **argv, 61 struct nlmsghdr *n) 62{ 63 struct { 64 struct nlmsghdr n; 65 struct ifinfomsg i; 66 char buf[1024]; 67 } req; 68 struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1); 69 struct rtattr *tb[IFLA_MAX + 1]; 70 struct rtattr *linkinfo[IFLA_INFO_MAX+1]; 71 struct rtattr *greinfo[IFLA_GRE_MAX + 1]; 72 __u16 iflags = 0; 73 __u16 oflags = 0; 74 unsigned ikey = 0; 75 unsigned okey = 0; 76 struct in6_addr raddr = IN6ADDR_ANY_INIT; 77 struct in6_addr laddr = IN6ADDR_ANY_INIT; 78 unsigned link = 0; 79 unsigned flowinfo = 0; 80 unsigned flags = 0; 81 __u8 hop_limit = DEFAULT_TNL_HOP_LIMIT; 82 __u8 encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT; 83 int len; 84 85 if (!(n->nlmsg_flags & NLM_F_CREATE)) { 86 memset(&req, 0, sizeof(req)); 87 88 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)); 89 req.n.nlmsg_flags = NLM_F_REQUEST; 90 req.n.nlmsg_type = RTM_GETLINK; 91 req.i.ifi_family = preferred_family; 92 req.i.ifi_index = ifi->ifi_index; 93 94 if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) { 95get_failed: 96 fprintf(stderr, 97 "Failed to get existing tunnel info.\n"); 98 return -1; 99 } 100 101 len = req.n.nlmsg_len; 102 len -= NLMSG_LENGTH(sizeof(*ifi)); 103 if (len < 0) 104 goto get_failed; 105 106 parse_rtattr(tb, IFLA_MAX, IFLA_RTA(&req.i), len); 107 108 if (!tb[IFLA_LINKINFO]) 109 goto get_failed; 110 111 parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]); 112 113 if (!linkinfo[IFLA_INFO_DATA]) 114 goto get_failed; 115 116 parse_rtattr_nested(greinfo, IFLA_GRE_MAX, 117 linkinfo[IFLA_INFO_DATA]); 118 119 if (greinfo[IFLA_GRE_IKEY]) 120 ikey = rta_getattr_u32(greinfo[IFLA_GRE_IKEY]); 121 122 if (greinfo[IFLA_GRE_OKEY]) 123 okey = rta_getattr_u32(greinfo[IFLA_GRE_OKEY]); 124 125 if (greinfo[IFLA_GRE_IFLAGS]) 126 iflags = rta_getattr_u16(greinfo[IFLA_GRE_IFLAGS]); 127 128 if (greinfo[IFLA_GRE_OFLAGS]) 129 oflags = rta_getattr_u16(greinfo[IFLA_GRE_OFLAGS]); 130 131 if (greinfo[IFLA_GRE_LOCAL]) 132 memcpy(&laddr, RTA_DATA(greinfo[IFLA_GRE_LOCAL]), sizeof(laddr)); 133 134 if (greinfo[IFLA_GRE_REMOTE]) 135 memcpy(&raddr, RTA_DATA(greinfo[IFLA_GRE_REMOTE]), sizeof(raddr)); 136 137 if (greinfo[IFLA_GRE_TTL]) 138 hop_limit = rta_getattr_u8(greinfo[IFLA_GRE_TTL]); 139 140 if (greinfo[IFLA_GRE_LINK]) 141 link = rta_getattr_u32(greinfo[IFLA_GRE_LINK]); 142 143 if (greinfo[IFLA_GRE_ENCAP_LIMIT]) 144 encap_limit = rta_getattr_u8(greinfo[IFLA_GRE_ENCAP_LIMIT]); 145 146 if (greinfo[IFLA_GRE_FLOWINFO]) 147 flowinfo = rta_getattr_u32(greinfo[IFLA_GRE_FLOWINFO]); 148 149 if (greinfo[IFLA_GRE_FLAGS]) 150 flags = rta_getattr_u32(greinfo[IFLA_GRE_FLAGS]); 151 } 152 153 while (argc > 0) { 154 if (!matches(*argv, "key")) { 155 unsigned uval; 156 157 NEXT_ARG(); 158 iflags |= GRE_KEY; 159 oflags |= GRE_KEY; 160 if (strchr(*argv, '.')) 161 uval = get_addr32(*argv); 162 else { 163 if (get_unsigned(&uval, *argv, 0) < 0) { 164 fprintf(stderr, 165 "Invalid value for \"key\"\n"); 166 exit(-1); 167 } 168 uval = htonl(uval); 169 } 170 171 ikey = okey = uval; 172 } else if (!matches(*argv, "ikey")) { 173 unsigned uval; 174 175 NEXT_ARG(); 176 iflags |= GRE_KEY; 177 if (strchr(*argv, '.')) 178 uval = get_addr32(*argv); 179 else { 180 if (get_unsigned(&uval, *argv, 0)<0) { 181 fprintf(stderr, "invalid value of \"ikey\"\n"); 182 exit(-1); 183 } 184 uval = htonl(uval); 185 } 186 ikey = uval; 187 } else if (!matches(*argv, "okey")) { 188 unsigned uval; 189 190 NEXT_ARG(); 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, "invalid value of \"okey\"\n"); 197 exit(-1); 198 } 199 uval = htonl(uval); 200 } 201 okey = uval; 202 } else if (!matches(*argv, "seq")) { 203 iflags |= GRE_SEQ; 204 oflags |= GRE_SEQ; 205 } else if (!matches(*argv, "iseq")) { 206 iflags |= GRE_SEQ; 207 } else if (!matches(*argv, "oseq")) { 208 oflags |= GRE_SEQ; 209 } else if (!matches(*argv, "csum")) { 210 iflags |= GRE_CSUM; 211 oflags |= GRE_CSUM; 212 } else if (!matches(*argv, "icsum")) { 213 iflags |= GRE_CSUM; 214 } else if (!matches(*argv, "ocsum")) { 215 oflags |= GRE_CSUM; 216 } else if (!matches(*argv, "remote")) { 217 inet_prefix addr; 218 NEXT_ARG(); 219 get_prefix(&addr, *argv, preferred_family); 220 if (addr.family == AF_UNSPEC) 221 invarg("\"remote\" address family is AF_UNSPEC", *argv); 222 memcpy(&raddr, &addr.data, sizeof(raddr)); 223 } else if (!matches(*argv, "local")) { 224 inet_prefix addr; 225 NEXT_ARG(); 226 get_prefix(&addr, *argv, preferred_family); 227 if (addr.family == AF_UNSPEC) 228 invarg("\"local\" address family is AF_UNSPEC", *argv); 229 memcpy(&laddr, &addr.data, sizeof(laddr)); 230 } else if (!matches(*argv, "dev")) { 231 NEXT_ARG(); 232 link = if_nametoindex(*argv); 233 if (link == 0) { 234 fprintf(stderr, "Cannot find device \"%s\"\n", 235 *argv); 236 exit(-1); 237 } 238 } else if (!matches(*argv, "ttl") || 239 !matches(*argv, "hoplimit")) { 240 __u8 uval; 241 NEXT_ARG(); 242 if (get_u8(&uval, *argv, 0)) 243 invarg("invalid TTL", *argv); 244 hop_limit = uval; 245 } else if (!matches(*argv, "tos") || 246 !matches(*argv, "tclass") || 247 !matches(*argv, "dsfield")) { 248 __u8 uval; 249 NEXT_ARG(); 250 if (strcmp(*argv, "inherit") == 0) 251 flags |= IP6_TNL_F_USE_ORIG_TCLASS; 252 else { 253 if (get_u8(&uval, *argv, 16)) 254 invarg("invalid TClass", *argv); 255 flowinfo |= htonl((__u32)uval << 20) & IP6_FLOWINFO_TCLASS; 256 flags &= ~IP6_TNL_F_USE_ORIG_TCLASS; 257 } 258 } else if (strcmp(*argv, "flowlabel") == 0 || 259 strcmp(*argv, "fl") == 0) { 260 __u32 uval; 261 NEXT_ARG(); 262 if (strcmp(*argv, "inherit") == 0) 263 flags |= IP6_TNL_F_USE_ORIG_FLOWLABEL; 264 else { 265 if (get_u32(&uval, *argv, 16)) 266 invarg("invalid Flowlabel", *argv); 267 if (uval > 0xFFFFF) 268 invarg("invalid Flowlabel", *argv); 269 flowinfo |= htonl(uval) & IP6_FLOWINFO_FLOWLABEL; 270 flags &= ~IP6_TNL_F_USE_ORIG_FLOWLABEL; 271 } 272 } else if (strcmp(*argv, "dscp") == 0) { 273 NEXT_ARG(); 274 if (strcmp(*argv, "inherit") != 0) 275 invarg("not inherit", *argv); 276 flags |= IP6_TNL_F_RCV_DSCP_COPY; 277 } else 278 usage(); 279 argc--; argv++; 280 } 281 282 addattr32(n, 1024, IFLA_GRE_IKEY, ikey); 283 addattr32(n, 1024, IFLA_GRE_OKEY, okey); 284 addattr_l(n, 1024, IFLA_GRE_IFLAGS, &iflags, 2); 285 addattr_l(n, 1024, IFLA_GRE_OFLAGS, &oflags, 2); 286 addattr_l(n, 1024, IFLA_GRE_LOCAL, &laddr, sizeof(laddr)); 287 addattr_l(n, 1024, IFLA_GRE_REMOTE, &raddr, sizeof(raddr)); 288 if (link) 289 addattr32(n, 1024, IFLA_GRE_LINK, link); 290 addattr_l(n, 1024, IFLA_GRE_TTL, &hop_limit, 1); 291 addattr_l(n, 1024, IFLA_GRE_ENCAP_LIMIT, &encap_limit, 1); 292 addattr_l(n, 1024, IFLA_GRE_FLOWINFO, &flowinfo, 4); 293 addattr_l(n, 1024, IFLA_GRE_FLAGS, &flowinfo, 4); 294 295 return 0; 296} 297 298static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) 299{ 300 char s1[1024]; 301 char s2[64]; 302 const char *local = "any"; 303 const char *remote = "any"; 304 unsigned iflags = 0; 305 unsigned oflags = 0; 306 unsigned flags = 0; 307 unsigned flowinfo = 0; 308 struct in6_addr in6_addr_any = IN6ADDR_ANY_INIT; 309 310 if (!tb) 311 return; 312 313 if (tb[IFLA_GRE_FLAGS]) 314 flags = rta_getattr_u32(tb[IFLA_GRE_FLAGS]); 315 316 if (tb[IFLA_GRE_FLOWINFO]) 317 flags = rta_getattr_u32(tb[IFLA_GRE_FLOWINFO]); 318 319 if (tb[IFLA_GRE_REMOTE]) { 320 struct in6_addr addr; 321 memcpy(&addr, RTA_DATA(tb[IFLA_GRE_REMOTE]), sizeof(addr)); 322 323 if (memcmp(&addr, &in6_addr_any, sizeof(addr))) 324 remote = format_host(AF_INET6, sizeof(addr), &addr, s1, sizeof(s1)); 325 } 326 327 fprintf(f, "remote %s ", remote); 328 329 if (tb[IFLA_GRE_LOCAL]) { 330 struct in6_addr addr; 331 memcpy(&addr, RTA_DATA(tb[IFLA_GRE_LOCAL]), sizeof(addr)); 332 333 if (memcmp(&addr, &in6_addr_any, sizeof(addr))) 334 local = format_host(AF_INET6, sizeof(addr), &addr, s1, sizeof(s1)); 335 } 336 337 fprintf(f, "local %s ", local); 338 339 if (tb[IFLA_GRE_LINK] && rta_getattr_u32(tb[IFLA_GRE_LINK])) { 340 unsigned link = rta_getattr_u32(tb[IFLA_GRE_LINK]); 341 const char *n = if_indextoname(link, s2); 342 343 if (n) 344 fprintf(f, "dev %s ", n); 345 else 346 fprintf(f, "dev %u ", link); 347 } 348 349 if (tb[IFLA_GRE_TTL] && rta_getattr_u8(tb[IFLA_GRE_TTL])) 350 fprintf(f, "hoplimit %d ", rta_getattr_u8(tb[IFLA_GRE_TTL])); 351 352 if (flags & IP6_TNL_F_IGN_ENCAP_LIMIT) 353 fprintf(f, "encaplimit none "); 354 else if (tb[IFLA_GRE_ENCAP_LIMIT]) { 355 int encap_limit = rta_getattr_u8(tb[IFLA_GRE_ENCAP_LIMIT]); 356 357 fprintf(f, "encaplimit %d ", encap_limit); 358 } 359 360 if (flags & IP6_TNL_F_USE_ORIG_FLOWLABEL) 361 fprintf(f, "flowlabel inherit "); 362 else 363 fprintf(f, "flowlabel 0x%05x ", ntohl(flowinfo & IP6_FLOWINFO_FLOWLABEL)); 364 365 if (flags & IP6_TNL_F_RCV_DSCP_COPY) 366 fprintf(f, "dscp inherit "); 367 368 if (tb[IFLA_GRE_IFLAGS]) 369 iflags = rta_getattr_u16(tb[IFLA_GRE_IFLAGS]); 370 371 if (tb[IFLA_GRE_OFLAGS]) 372 oflags = rta_getattr_u16(tb[IFLA_GRE_OFLAGS]); 373 374 if ((iflags & GRE_KEY) && tb[IFLA_GRE_IKEY]) { 375 inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_IKEY]), s2, sizeof(s2)); 376 fprintf(f, "ikey %s ", s2); 377 } 378 379 if ((oflags & GRE_KEY) && tb[IFLA_GRE_OKEY]) { 380 inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_OKEY]), s2, sizeof(s2)); 381 fprintf(f, "okey %s ", s2); 382 } 383 384 if (iflags & GRE_SEQ) 385 fputs("iseq ", f); 386 if (oflags & GRE_SEQ) 387 fputs("oseq ", f); 388 if (iflags & GRE_CSUM) 389 fputs("icsum ", f); 390 if (oflags & GRE_CSUM) 391 fputs("ocsum ", f); 392} 393 394static void gre_print_help(struct link_util *lu, int argc, char **argv, 395 FILE *f) 396{ 397 print_usage(f); 398} 399 400struct link_util ip6gre_link_util = { 401 .id = "ip6gre", 402 .maxattr = IFLA_GRE_MAX, 403 .parse_opt = gre_parse_opt, 404 .print_opt = gre_print_opt, 405 .print_help = gre_print_help, 406}; 407 408struct link_util ip6gretap_link_util = { 409 .id = "ip6gretap", 410 .maxattr = IFLA_GRE_MAX, 411 .parse_opt = gre_parse_opt, 412 .print_opt = gre_print_opt, 413 .print_help = gre_print_help, 414}; 415