1 /* 2 * link_vti6.c VTI 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 (at) gondor.apana.org.au> 10 * Saurabh Mohan <saurabh.mohan (at) vyatta.com> Modified link_gre.c for VTI 11 * Steffen Klassert <steffen.klassert (at) secunet.com> Modified link_vti.c for IPv6 12 */ 13 14 #include <string.h> 15 #include <net/if.h> 16 #include <sys/types.h> 17 #include <sys/socket.h> 18 #include <arpa/inet.h> 19 20 #include <linux/ip.h> 21 #include <linux/if_tunnel.h> 22 #include "rt_names.h" 23 #include "utils.h" 24 #include "ip_common.h" 25 #include "tunnel.h" 26 27 28 static void usage(void) __attribute__((noreturn)); 29 static void usage(void) 30 { 31 fprintf(stderr, "Usage: ip link { add | set | change | replace | del } NAME\n"); 32 fprintf(stderr, " type { vti6 } [ remote ADDR ] [ local ADDR ]\n"); 33 fprintf(stderr, " [ [i|o]key KEY ]\n"); 34 fprintf(stderr, " [ dev PHYS_DEV ]\n"); 35 fprintf(stderr, " [ fwmark MARK ]\n"); 36 fprintf(stderr, "\n"); 37 fprintf(stderr, "Where: NAME := STRING\n"); 38 fprintf(stderr, " ADDR := { IPV6_ADDRESS }\n"); 39 fprintf(stderr, " KEY := { DOTTED_QUAD | NUMBER }\n"); 40 fprintf(stderr, " MARK := { 0x0..0xffffffff }\n"); 41 exit(-1); 42 } 43 44 static int vti6_parse_opt(struct link_util *lu, int argc, char **argv, 45 struct nlmsghdr *n) 46 { 47 struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1); 48 struct { 49 struct nlmsghdr n; 50 struct ifinfomsg i; 51 char buf[1024]; 52 } req = { 53 .n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)), 54 .n.nlmsg_flags = NLM_F_REQUEST, 55 .n.nlmsg_type = RTM_GETLINK, 56 .i.ifi_family = preferred_family, 57 .i.ifi_index = ifi->ifi_index, 58 }; 59 struct rtattr *tb[IFLA_MAX + 1]; 60 struct rtattr *linkinfo[IFLA_INFO_MAX+1]; 61 struct rtattr *vtiinfo[IFLA_VTI_MAX + 1]; 62 struct in6_addr saddr = IN6ADDR_ANY_INIT; 63 struct in6_addr daddr = IN6ADDR_ANY_INIT; 64 unsigned int ikey = 0; 65 unsigned int okey = 0; 66 unsigned int link = 0; 67 __u32 fwmark = 0; 68 int len; 69 70 if (!(n->nlmsg_flags & NLM_F_CREATE)) { 71 if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) { 72 get_failed: 73 fprintf(stderr, 74 "Failed to get existing tunnel info.\n"); 75 return -1; 76 } 77 78 len = req.n.nlmsg_len; 79 len -= NLMSG_LENGTH(sizeof(*ifi)); 80 if (len < 0) 81 goto get_failed; 82 83 parse_rtattr(tb, IFLA_MAX, IFLA_RTA(&req.i), len); 84 85 if (!tb[IFLA_LINKINFO]) 86 goto get_failed; 87 88 parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]); 89 90 if (!linkinfo[IFLA_INFO_DATA]) 91 goto get_failed; 92 93 parse_rtattr_nested(vtiinfo, IFLA_VTI_MAX, 94 linkinfo[IFLA_INFO_DATA]); 95 96 if (vtiinfo[IFLA_VTI_IKEY]) 97 ikey = rta_getattr_u32(vtiinfo[IFLA_VTI_IKEY]); 98 99 if (vtiinfo[IFLA_VTI_OKEY]) 100 okey = rta_getattr_u32(vtiinfo[IFLA_VTI_OKEY]); 101 102 if (vtiinfo[IFLA_VTI_LOCAL]) 103 memcpy(&saddr, RTA_DATA(vtiinfo[IFLA_VTI_LOCAL]), sizeof(saddr)); 104 105 if (vtiinfo[IFLA_VTI_REMOTE]) 106 memcpy(&daddr, RTA_DATA(vtiinfo[IFLA_VTI_REMOTE]), sizeof(daddr)); 107 108 if (vtiinfo[IFLA_VTI_LINK]) 109 link = rta_getattr_u8(vtiinfo[IFLA_VTI_LINK]); 110 111 if (vtiinfo[IFLA_VTI_FWMARK]) 112 fwmark = rta_getattr_u32(vtiinfo[IFLA_VTI_FWMARK]); 113 } 114 115 while (argc > 0) { 116 if (!matches(*argv, "key")) { 117 unsigned int uval; 118 119 NEXT_ARG(); 120 if (strchr(*argv, '.')) 121 uval = get_addr32(*argv); 122 else { 123 if (get_unsigned(&uval, *argv, 0) < 0) { 124 fprintf(stderr, 125 "Invalid value for \"key\": \"%s\"; it should be an unsigned integer\n", *argv); 126 exit(-1); 127 } 128 uval = htonl(uval); 129 } 130 131 ikey = okey = uval; 132 } else if (!matches(*argv, "ikey")) { 133 unsigned int uval; 134 135 NEXT_ARG(); 136 if (strchr(*argv, '.')) 137 uval = get_addr32(*argv); 138 else { 139 if (get_unsigned(&uval, *argv, 0) < 0) { 140 fprintf(stderr, "invalid value for \"ikey\": \"%s\"; it should be an unsigned integer\n", *argv); 141 exit(-1); 142 } 143 uval = htonl(uval); 144 } 145 ikey = uval; 146 } else if (!matches(*argv, "okey")) { 147 unsigned int uval; 148 149 NEXT_ARG(); 150 if (strchr(*argv, '.')) 151 uval = get_addr32(*argv); 152 else { 153 if (get_unsigned(&uval, *argv, 0) < 0) { 154 fprintf(stderr, "invalid value for \"okey\": \"%s\"; it should be an unsigned integer\n", *argv); 155 exit(-1); 156 } 157 uval = htonl(uval); 158 } 159 okey = uval; 160 } else if (!matches(*argv, "remote")) { 161 NEXT_ARG(); 162 if (!strcmp(*argv, "any")) { 163 fprintf(stderr, "invalid value for \"remote\": \"%s\"\n", *argv); 164 exit(-1); 165 } else { 166 inet_prefix addr; 167 168 get_prefix(&addr, *argv, AF_INET6); 169 memcpy(&daddr, addr.data, addr.bytelen); 170 } 171 } else if (!matches(*argv, "local")) { 172 NEXT_ARG(); 173 if (!strcmp(*argv, "any")) { 174 fprintf(stderr, "invalid value for \"local\": \"%s\"\n", *argv); 175 exit(-1); 176 } else { 177 inet_prefix addr; 178 179 get_prefix(&addr, *argv, AF_INET6); 180 memcpy(&saddr, addr.data, addr.bytelen); 181 } 182 } else if (!matches(*argv, "dev")) { 183 NEXT_ARG(); 184 link = if_nametoindex(*argv); 185 if (link == 0) 186 exit(-1); 187 } else if (strcmp(*argv, "fwmark") == 0) { 188 NEXT_ARG(); 189 if (get_u32(&fwmark, *argv, 0)) 190 invarg("invalid fwmark\n", *argv); 191 } else 192 usage(); 193 argc--; argv++; 194 } 195 196 addattr32(n, 1024, IFLA_VTI_IKEY, ikey); 197 addattr32(n, 1024, IFLA_VTI_OKEY, okey); 198 199 if (memcmp(&saddr, &in6addr_any, sizeof(in6addr_any))) 200 addattr_l(n, 1024, IFLA_VTI_LOCAL, &saddr, sizeof(saddr)); 201 if (memcmp(&daddr, &in6addr_any, sizeof(in6addr_any))) 202 addattr_l(n, 1024, IFLA_VTI_REMOTE, &daddr, sizeof(daddr)); 203 addattr32(n, 1024, IFLA_VTI_FWMARK, fwmark); 204 if (link) 205 addattr32(n, 1024, IFLA_VTI_LINK, link); 206 207 return 0; 208 } 209 210 static void vti6_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) 211 { 212 const char *local = "any"; 213 const char *remote = "any"; 214 struct in6_addr saddr; 215 struct in6_addr daddr; 216 unsigned int link; 217 char s2[64]; 218 219 if (!tb) 220 return; 221 222 if (tb[IFLA_VTI_REMOTE]) { 223 memcpy(&daddr, RTA_DATA(tb[IFLA_VTI_REMOTE]), sizeof(daddr)); 224 225 remote = format_host(AF_INET6, 16, &daddr); 226 } 227 228 print_string(PRINT_ANY, "remote", "remote %s ", remote); 229 230 if (tb[IFLA_VTI_LOCAL]) { 231 memcpy(&saddr, RTA_DATA(tb[IFLA_VTI_LOCAL]), sizeof(saddr)); 232 233 local = format_host(AF_INET6, 16, &saddr); 234 } 235 236 print_string(PRINT_ANY, "local", "local %s ", local); 237 238 if (tb[IFLA_VTI_LINK] && (link = rta_getattr_u32(tb[IFLA_VTI_LINK]))) { 239 const char *n = if_indextoname(link, s2); 240 241 if (n) 242 print_string(PRINT_ANY, "link", "dev %s ", n); 243 else 244 print_uint(PRINT_ANY, "link_index", "dev %u ", link); 245 } 246 247 if (tb[IFLA_VTI_IKEY]) { 248 inet_ntop(AF_INET, RTA_DATA(tb[IFLA_VTI_IKEY]), s2, sizeof(s2)); 249 print_string(PRINT_ANY, "ikey", "ikey %s ", s2); 250 } 251 252 if (tb[IFLA_VTI_OKEY]) { 253 inet_ntop(AF_INET, RTA_DATA(tb[IFLA_VTI_OKEY]), s2, sizeof(s2)); 254 print_string(PRINT_ANY, "okey", "okey %s ", s2); 255 } 256 257 if (tb[IFLA_VTI_FWMARK]) { 258 __u32 fwmark = rta_getattr_u32(tb[IFLA_VTI_FWMARK]); 259 260 if (fwmark) { 261 snprintf(s2, sizeof(s2), "0x%x", fwmark); 262 263 print_string(PRINT_ANY, "fwmark", "fwmark %s ", s2); 264 } 265 } 266 } 267 268 struct link_util vti6_link_util = { 269 .id = "vti6", 270 .maxattr = IFLA_VTI_MAX, 271 .parse_opt = vti6_parse_opt, 272 .print_opt = vti6_print_opt, 273 }; 274