1 /* 2 * link_vti.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 */ 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 27 static void print_usage(FILE *f) 28 { 29 fprintf(f, "Usage: ip link { add | set | change | replace | del } NAME\n"); 30 fprintf(f, " type { vti } [ remote ADDR ] [ local ADDR ]\n"); 31 fprintf(f, " [ [i|o]key KEY ]\n"); 32 fprintf(f, " [ dev PHYS_DEV ]\n"); 33 fprintf(f, "\n"); 34 fprintf(f, "Where: NAME := STRING\n"); 35 fprintf(f, " ADDR := { IP_ADDRESS }\n"); 36 fprintf(f, " KEY := { DOTTED_QUAD | NUMBER }\n"); 37 } 38 39 static void usage(void) __attribute__((noreturn)); 40 static void usage(void) 41 { 42 print_usage(stderr); 43 exit(-1); 44 } 45 46 static int vti_parse_opt(struct link_util *lu, int argc, char **argv, 47 struct nlmsghdr *n) 48 { 49 struct { 50 struct nlmsghdr n; 51 struct ifinfomsg i; 52 char buf[1024]; 53 } req; 54 struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1); 55 struct rtattr *tb[IFLA_MAX + 1]; 56 struct rtattr *linkinfo[IFLA_INFO_MAX+1]; 57 struct rtattr *vtiinfo[IFLA_VTI_MAX + 1]; 58 unsigned ikey = 0; 59 unsigned okey = 0; 60 unsigned saddr = 0; 61 unsigned daddr = 0; 62 unsigned link = 0; 63 int len; 64 65 if (!(n->nlmsg_flags & NLM_F_CREATE)) { 66 memset(&req, 0, sizeof(req)); 67 68 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)); 69 req.n.nlmsg_flags = NLM_F_REQUEST; 70 req.n.nlmsg_type = RTM_GETLINK; 71 req.i.ifi_family = preferred_family; 72 req.i.ifi_index = ifi->ifi_index; 73 74 if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) { 75 get_failed: 76 fprintf(stderr, 77 "Failed to get existing tunnel info.\n"); 78 return -1; 79 } 80 81 len = req.n.nlmsg_len; 82 len -= NLMSG_LENGTH(sizeof(*ifi)); 83 if (len < 0) 84 goto get_failed; 85 86 parse_rtattr(tb, IFLA_MAX, IFLA_RTA(&req.i), len); 87 88 if (!tb[IFLA_LINKINFO]) 89 goto get_failed; 90 91 parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]); 92 93 if (!linkinfo[IFLA_INFO_DATA]) 94 goto get_failed; 95 96 parse_rtattr_nested(vtiinfo, IFLA_VTI_MAX, 97 linkinfo[IFLA_INFO_DATA]); 98 99 if (vtiinfo[IFLA_VTI_IKEY]) 100 ikey = *(__u32 *)RTA_DATA(vtiinfo[IFLA_VTI_IKEY]); 101 102 if (vtiinfo[IFLA_VTI_OKEY]) 103 okey = *(__u32 *)RTA_DATA(vtiinfo[IFLA_VTI_OKEY]); 104 105 if (vtiinfo[IFLA_VTI_LOCAL]) 106 saddr = *(__u32 *)RTA_DATA(vtiinfo[IFLA_VTI_LOCAL]); 107 108 if (vtiinfo[IFLA_VTI_REMOTE]) 109 daddr = *(__u32 *)RTA_DATA(vtiinfo[IFLA_VTI_REMOTE]); 110 111 if (vtiinfo[IFLA_VTI_LINK]) 112 link = *(__u8 *)RTA_DATA(vtiinfo[IFLA_VTI_LINK]); 113 } 114 115 while (argc > 0) { 116 if (!matches(*argv, "key")) { 117 unsigned 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 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 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 daddr = get_addr32(*argv); 167 } 168 } else if (!matches(*argv, "local")) { 169 NEXT_ARG(); 170 if (!strcmp(*argv, "any")) { 171 fprintf(stderr, "invalid value for \"local\": \"%s\"\n", *argv); 172 exit(-1); 173 } else { 174 saddr = get_addr32(*argv); 175 } 176 } else if (!matches(*argv, "dev")) { 177 NEXT_ARG(); 178 link = if_nametoindex(*argv); 179 if (link == 0) { 180 fprintf(stderr, "Cannot find device \"%s\"\n", 181 *argv); 182 exit(-1); 183 } 184 } else 185 usage(); 186 argc--; argv++; 187 } 188 189 addattr32(n, 1024, IFLA_VTI_IKEY, ikey); 190 addattr32(n, 1024, IFLA_VTI_OKEY, okey); 191 addattr_l(n, 1024, IFLA_VTI_LOCAL, &saddr, 4); 192 addattr_l(n, 1024, IFLA_VTI_REMOTE, &daddr, 4); 193 if (link) 194 addattr32(n, 1024, IFLA_VTI_LINK, link); 195 196 return 0; 197 } 198 199 static void vti_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) 200 { 201 char s1[1024]; 202 char s2[64]; 203 const char *local = "any"; 204 const char *remote = "any"; 205 206 if (!tb) 207 return; 208 209 if (tb[IFLA_VTI_REMOTE]) { 210 unsigned addr = *(__u32 *)RTA_DATA(tb[IFLA_VTI_REMOTE]); 211 212 if (addr) 213 remote = format_host(AF_INET, 4, &addr, s1, sizeof(s1)); 214 } 215 216 fprintf(f, "remote %s ", remote); 217 218 if (tb[IFLA_VTI_LOCAL]) { 219 unsigned addr = *(__u32 *)RTA_DATA(tb[IFLA_VTI_LOCAL]); 220 221 if (addr) 222 local = format_host(AF_INET, 4, &addr, s1, sizeof(s1)); 223 } 224 225 fprintf(f, "local %s ", local); 226 227 if (tb[IFLA_VTI_LINK] && *(__u32 *)RTA_DATA(tb[IFLA_VTI_LINK])) { 228 unsigned link = *(__u32 *)RTA_DATA(tb[IFLA_VTI_LINK]); 229 const char *n = if_indextoname(link, s2); 230 231 if (n) 232 fprintf(f, "dev %s ", n); 233 else 234 fprintf(f, "dev %u ", link); 235 } 236 237 if (tb[IFLA_VTI_IKEY]) { 238 inet_ntop(AF_INET, RTA_DATA(tb[IFLA_VTI_IKEY]), s2, sizeof(s2)); 239 fprintf(f, "ikey %s ", s2); 240 } 241 242 if (tb[IFLA_VTI_OKEY]) { 243 inet_ntop(AF_INET, RTA_DATA(tb[IFLA_VTI_OKEY]), s2, sizeof(s2)); 244 fprintf(f, "okey %s ", s2); 245 } 246 } 247 248 static void vti_print_help(struct link_util *lu, int argc, char **argv, 249 FILE *f) 250 { 251 print_usage(f); 252 } 253 254 struct link_util vti_link_util = { 255 .id = "vti", 256 .maxattr = IFLA_VTI_MAX, 257 .parse_opt = vti_parse_opt, 258 .print_opt = vti_print_opt, 259 .print_help = vti_print_help, 260 }; 261