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, "\n"); 36 fprintf(stderr, "Where: NAME := STRING\n"); 37 fprintf(stderr, " ADDR := { IPV6_ADDRESS }\n"); 38 fprintf(stderr, " KEY := { DOTTED_QUAD | NUMBER }\n"); 39 exit(-1); 40 } 41 42 static int vti6_parse_opt(struct link_util *lu, int argc, char **argv, 43 struct nlmsghdr *n) 44 { 45 struct { 46 struct nlmsghdr n; 47 struct ifinfomsg i; 48 char buf[1024]; 49 } req; 50 struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1); 51 struct rtattr *tb[IFLA_MAX + 1]; 52 struct rtattr *linkinfo[IFLA_INFO_MAX+1]; 53 struct rtattr *vtiinfo[IFLA_VTI_MAX + 1]; 54 struct in6_addr saddr; 55 struct in6_addr daddr; 56 unsigned ikey = 0; 57 unsigned okey = 0; 58 unsigned link = 0; 59 int len; 60 61 if (!(n->nlmsg_flags & NLM_F_CREATE)) { 62 memset(&req, 0, sizeof(req)); 63 64 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)); 65 req.n.nlmsg_flags = NLM_F_REQUEST; 66 req.n.nlmsg_type = RTM_GETLINK; 67 req.i.ifi_family = preferred_family; 68 req.i.ifi_index = ifi->ifi_index; 69 70 if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) { 71 get_failed: 72 fprintf(stderr, 73 "Failed to get existing tunnel info.\n"); 74 return -1; 75 } 76 77 len = req.n.nlmsg_len; 78 len -= NLMSG_LENGTH(sizeof(*ifi)); 79 if (len < 0) 80 goto get_failed; 81 82 parse_rtattr(tb, IFLA_MAX, IFLA_RTA(&req.i), len); 83 84 if (!tb[IFLA_LINKINFO]) 85 goto get_failed; 86 87 parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]); 88 89 if (!linkinfo[IFLA_INFO_DATA]) 90 goto get_failed; 91 92 parse_rtattr_nested(vtiinfo, IFLA_VTI_MAX, 93 linkinfo[IFLA_INFO_DATA]); 94 95 if (vtiinfo[IFLA_VTI_IKEY]) 96 ikey = rta_getattr_u32(vtiinfo[IFLA_VTI_IKEY]); 97 98 if (vtiinfo[IFLA_VTI_OKEY]) 99 okey = rta_getattr_u32(vtiinfo[IFLA_VTI_OKEY]); 100 101 if (vtiinfo[IFLA_VTI_LOCAL]) 102 memcpy(&saddr, RTA_DATA(vtiinfo[IFLA_VTI_LOCAL]), sizeof(saddr)); 103 104 if (vtiinfo[IFLA_VTI_REMOTE]) 105 memcpy(&daddr, RTA_DATA(vtiinfo[IFLA_VTI_REMOTE]), sizeof(daddr)); 106 107 if (vtiinfo[IFLA_VTI_LINK]) 108 link = rta_getattr_u8(vtiinfo[IFLA_VTI_LINK]); 109 } 110 111 while (argc > 0) { 112 if (!matches(*argv, "key")) { 113 unsigned uval; 114 115 NEXT_ARG(); 116 if (strchr(*argv, '.')) 117 uval = get_addr32(*argv); 118 else { 119 if (get_unsigned(&uval, *argv, 0) < 0) { 120 fprintf(stderr, 121 "Invalid value for \"key\": \"%s\"; it should be an unsigned integer\n", *argv); 122 exit(-1); 123 } 124 uval = htonl(uval); 125 } 126 127 ikey = okey = uval; 128 } else if (!matches(*argv, "ikey")) { 129 unsigned uval; 130 131 NEXT_ARG(); 132 if (strchr(*argv, '.')) 133 uval = get_addr32(*argv); 134 else { 135 if (get_unsigned(&uval, *argv, 0) < 0) { 136 fprintf(stderr, "invalid value for \"ikey\": \"%s\"; it should be an unsigned integer\n", *argv); 137 exit(-1); 138 } 139 uval = htonl(uval); 140 } 141 ikey = uval; 142 } else if (!matches(*argv, "okey")) { 143 unsigned uval; 144 145 NEXT_ARG(); 146 if (strchr(*argv, '.')) 147 uval = get_addr32(*argv); 148 else { 149 if (get_unsigned(&uval, *argv, 0) < 0) { 150 fprintf(stderr, "invalid value for \"okey\": \"%s\"; it should be an unsigned integer\n", *argv); 151 exit(-1); 152 } 153 uval = htonl(uval); 154 } 155 okey = uval; 156 } else if (!matches(*argv, "remote")) { 157 NEXT_ARG(); 158 if (!strcmp(*argv, "any")) { 159 fprintf(stderr, "invalid value for \"remote\": \"%s\"\n", *argv); 160 exit(-1); 161 } else { 162 inet_prefix addr; 163 get_prefix(&addr, *argv, AF_INET6); 164 memcpy(&daddr, addr.data, addr.bytelen); 165 } 166 } else if (!matches(*argv, "local")) { 167 NEXT_ARG(); 168 if (!strcmp(*argv, "any")) { 169 fprintf(stderr, "invalid value for \"local\": \"%s\"\n", *argv); 170 exit(-1); 171 } else { 172 inet_prefix addr; 173 get_prefix(&addr, *argv, AF_INET6); 174 memcpy(&saddr, addr.data, addr.bytelen); 175 } 176 } else if (!matches(*argv, "dev")) { 177 NEXT_ARG(); 178 link = if_nametoindex(*argv); 179 if (link == 0) 180 exit(-1); 181 } else 182 usage(); 183 argc--; argv++; 184 } 185 186 addattr32(n, 1024, IFLA_VTI_IKEY, ikey); 187 addattr32(n, 1024, IFLA_VTI_OKEY, okey); 188 addattr_l(n, 1024, IFLA_VTI_LOCAL, &saddr, sizeof(saddr)); 189 addattr_l(n, 1024, IFLA_VTI_REMOTE, &daddr, sizeof(daddr)); 190 if (link) 191 addattr32(n, 1024, IFLA_VTI_LINK, link); 192 193 return 0; 194 } 195 196 static void vti6_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) 197 { 198 char s1[1024]; 199 char s2[64]; 200 const char *local = "any"; 201 const char *remote = "any"; 202 struct in6_addr saddr; 203 struct in6_addr daddr; 204 205 if (!tb) 206 return; 207 208 if (tb[IFLA_VTI_REMOTE]) { 209 memcpy(&daddr, RTA_DATA(tb[IFLA_VTI_REMOTE]), sizeof(daddr)); 210 211 remote = format_host(AF_INET6, 16, &daddr, s1, sizeof(s1)); 212 } 213 214 fprintf(f, "remote %s ", remote); 215 216 if (tb[IFLA_VTI_LOCAL]) { 217 memcpy(&saddr, RTA_DATA(tb[IFLA_VTI_LOCAL]), sizeof(saddr)); 218 219 local = format_host(AF_INET6, 16, &saddr, s1, sizeof(s1)); 220 } 221 222 fprintf(f, "local %s ", local); 223 224 if (tb[IFLA_VTI_LINK] && *(__u32 *)RTA_DATA(tb[IFLA_VTI_LINK])) { 225 unsigned link = *(__u32 *)RTA_DATA(tb[IFLA_VTI_LINK]); 226 const char *n = if_indextoname(link, s2); 227 228 if (n) 229 fprintf(f, "dev %s ", n); 230 else 231 fprintf(f, "dev %u ", link); 232 } 233 234 if (tb[IFLA_VTI_IKEY]) { 235 inet_ntop(AF_INET, RTA_DATA(tb[IFLA_VTI_IKEY]), s2, sizeof(s2)); 236 fprintf(f, "ikey %s ", s2); 237 } 238 239 if (tb[IFLA_VTI_OKEY]) { 240 inet_ntop(AF_INET, RTA_DATA(tb[IFLA_VTI_OKEY]), s2, sizeof(s2)); 241 fprintf(f, "okey %s ", s2); 242 } 243 } 244 245 struct link_util vti6_link_util = { 246 .id = "vti6", 247 .maxattr = IFLA_VTI_MAX, 248 .parse_opt = vti6_parse_opt, 249 .print_opt = vti6_print_opt, 250 }; 251