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, 30 "Usage: ... vti [ remote ADDR ]\n" 31 " [ local ADDR ]\n" 32 " [ [i|o]key KEY ]\n" 33 " [ dev PHYS_DEV ]\n" 34 " [ fwmark MARK ]\n" 35 "\n" 36 "Where: ADDR := { IP_ADDRESS }\n" 37 " KEY := { DOTTED_QUAD | NUMBER }\n" 38 " MARK := { 0x0..0xffffffff }\n" 39 ); 40 } 41 42 static void usage(void) __attribute__((noreturn)); 43 static void usage(void) 44 { 45 print_usage(stderr); 46 exit(-1); 47 } 48 49 static int vti_parse_opt(struct link_util *lu, int argc, char **argv, 50 struct nlmsghdr *n) 51 { 52 struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1); 53 struct { 54 struct nlmsghdr n; 55 struct ifinfomsg i; 56 char buf[1024]; 57 } req = { 58 .n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)), 59 .n.nlmsg_flags = NLM_F_REQUEST, 60 .n.nlmsg_type = RTM_GETLINK, 61 .i.ifi_family = preferred_family, 62 .i.ifi_index = ifi->ifi_index, 63 }; 64 struct rtattr *tb[IFLA_MAX + 1]; 65 struct rtattr *linkinfo[IFLA_INFO_MAX+1]; 66 struct rtattr *vtiinfo[IFLA_VTI_MAX + 1]; 67 unsigned int ikey = 0; 68 unsigned int okey = 0; 69 unsigned int saddr = 0; 70 unsigned int daddr = 0; 71 unsigned int link = 0; 72 unsigned int fwmark = 0; 73 int len; 74 75 if (!(n->nlmsg_flags & NLM_F_CREATE)) { 76 if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) { 77 get_failed: 78 fprintf(stderr, 79 "Failed to get existing tunnel info.\n"); 80 return -1; 81 } 82 83 len = req.n.nlmsg_len; 84 len -= NLMSG_LENGTH(sizeof(*ifi)); 85 if (len < 0) 86 goto get_failed; 87 88 parse_rtattr(tb, IFLA_MAX, IFLA_RTA(&req.i), len); 89 90 if (!tb[IFLA_LINKINFO]) 91 goto get_failed; 92 93 parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]); 94 95 if (!linkinfo[IFLA_INFO_DATA]) 96 goto get_failed; 97 98 parse_rtattr_nested(vtiinfo, IFLA_VTI_MAX, 99 linkinfo[IFLA_INFO_DATA]); 100 101 if (vtiinfo[IFLA_VTI_IKEY]) 102 ikey = rta_getattr_u32(vtiinfo[IFLA_VTI_IKEY]); 103 104 if (vtiinfo[IFLA_VTI_OKEY]) 105 okey = rta_getattr_u32(vtiinfo[IFLA_VTI_OKEY]); 106 107 if (vtiinfo[IFLA_VTI_LOCAL]) 108 saddr = rta_getattr_u32(vtiinfo[IFLA_VTI_LOCAL]); 109 110 if (vtiinfo[IFLA_VTI_REMOTE]) 111 daddr = rta_getattr_u32(vtiinfo[IFLA_VTI_REMOTE]); 112 113 if (vtiinfo[IFLA_VTI_LINK]) 114 link = rta_getattr_u8(vtiinfo[IFLA_VTI_LINK]); 115 116 if (vtiinfo[IFLA_VTI_FWMARK]) 117 fwmark = rta_getattr_u32(vtiinfo[IFLA_VTI_FWMARK]); 118 } 119 120 while (argc > 0) { 121 if (!matches(*argv, "key")) { 122 unsigned int uval; 123 124 NEXT_ARG(); 125 if (strchr(*argv, '.')) 126 uval = get_addr32(*argv); 127 else { 128 if (get_unsigned(&uval, *argv, 0) < 0) { 129 fprintf(stderr, 130 "Invalid value for \"key\": \"%s\"; it should be an unsigned integer\n", *argv); 131 exit(-1); 132 } 133 uval = htonl(uval); 134 } 135 136 ikey = okey = uval; 137 } else if (!matches(*argv, "ikey")) { 138 unsigned int uval; 139 140 NEXT_ARG(); 141 if (strchr(*argv, '.')) 142 uval = get_addr32(*argv); 143 else { 144 if (get_unsigned(&uval, *argv, 0) < 0) { 145 fprintf(stderr, "invalid value for \"ikey\": \"%s\"; it should be an unsigned integer\n", *argv); 146 exit(-1); 147 } 148 uval = htonl(uval); 149 } 150 ikey = uval; 151 } else if (!matches(*argv, "okey")) { 152 unsigned int uval; 153 154 NEXT_ARG(); 155 if (strchr(*argv, '.')) 156 uval = get_addr32(*argv); 157 else { 158 if (get_unsigned(&uval, *argv, 0) < 0) { 159 fprintf(stderr, "invalid value for \"okey\": \"%s\"; it should be an unsigned integer\n", *argv); 160 exit(-1); 161 } 162 uval = htonl(uval); 163 } 164 okey = uval; 165 } else if (!matches(*argv, "remote")) { 166 NEXT_ARG(); 167 if (!strcmp(*argv, "any")) { 168 fprintf(stderr, "invalid value for \"remote\": \"%s\"\n", *argv); 169 exit(-1); 170 } else { 171 daddr = get_addr32(*argv); 172 } 173 } else if (!matches(*argv, "local")) { 174 NEXT_ARG(); 175 if (!strcmp(*argv, "any")) { 176 fprintf(stderr, "invalid value for \"local\": \"%s\"\n", *argv); 177 exit(-1); 178 } else { 179 saddr = get_addr32(*argv); 180 } 181 } else if (!matches(*argv, "dev")) { 182 NEXT_ARG(); 183 link = if_nametoindex(*argv); 184 if (link == 0) { 185 fprintf(stderr, "Cannot find device \"%s\"\n", 186 *argv); 187 exit(-1); 188 } 189 } else if (strcmp(*argv, "fwmark") == 0) { 190 NEXT_ARG(); 191 if (get_u32(&fwmark, *argv, 0)) 192 invarg("invalid fwmark\n", *argv); 193 } else 194 usage(); 195 argc--; argv++; 196 } 197 198 addattr32(n, 1024, IFLA_VTI_IKEY, ikey); 199 addattr32(n, 1024, IFLA_VTI_OKEY, okey); 200 addattr_l(n, 1024, IFLA_VTI_LOCAL, &saddr, 4); 201 addattr_l(n, 1024, IFLA_VTI_REMOTE, &daddr, 4); 202 addattr32(n, 1024, IFLA_VTI_FWMARK, fwmark); 203 if (link) 204 addattr32(n, 1024, IFLA_VTI_LINK, link); 205 206 return 0; 207 } 208 209 static void vti_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) 210 { 211 const char *local = "any"; 212 const char *remote = "any"; 213 __u32 key; 214 unsigned int link; 215 char s2[IFNAMSIZ]; 216 217 if (!tb) 218 return; 219 220 if (tb[IFLA_VTI_REMOTE]) { 221 unsigned int addr = rta_getattr_u32(tb[IFLA_VTI_REMOTE]); 222 223 if (addr) 224 remote = format_host(AF_INET, 4, &addr); 225 } 226 227 print_string(PRINT_ANY, "remote", "remote %s ", remote); 228 229 if (tb[IFLA_VTI_LOCAL]) { 230 unsigned int addr = rta_getattr_u32(tb[IFLA_VTI_LOCAL]); 231 232 if (addr) 233 local = format_host(AF_INET, 4, &addr); 234 } 235 236 print_string(PRINT_ANY, "local", "local %s ", local); 237 238 if (tb[IFLA_VTI_LINK] && 239 (link = rta_getattr_u32(tb[IFLA_VTI_LINK]))) { 240 const char *n = if_indextoname(link, s2); 241 242 if (n) 243 print_string(PRINT_ANY, "link", "dev %s ", n); 244 else 245 print_uint(PRINT_ANY, "link_index", "dev %u ", link); 246 } 247 248 if (tb[IFLA_VTI_IKEY] && 249 (key = rta_getattr_u32(tb[IFLA_VTI_IKEY]))) 250 print_0xhex(PRINT_ANY, "ikey", "ikey %#x ", ntohl(key)); 251 252 253 if (tb[IFLA_VTI_OKEY] && 254 (key = rta_getattr_u32(tb[IFLA_VTI_OKEY]))) 255 print_0xhex(PRINT_ANY, "okey", "okey %#x ", ntohl(key)); 256 257 if (tb[IFLA_VTI_FWMARK]) { 258 __u32 fwmark = rta_getattr_u32(tb[IFLA_VTI_FWMARK]); 259 260 if (fwmark) { 261 SPRINT_BUF(b1); 262 263 snprintf(b1, sizeof(b1), "0x%x", fwmark); 264 print_string(PRINT_ANY, "fwmark", "fwmark %s ", s2); 265 } 266 } 267 } 268 269 static void vti_print_help(struct link_util *lu, int argc, char **argv, 270 FILE *f) 271 { 272 print_usage(f); 273 } 274 275 struct link_util vti_link_util = { 276 .id = "vti", 277 .maxattr = IFLA_VTI_MAX, 278 .parse_opt = vti_parse_opt, 279 .print_opt = vti_print_opt, 280 .print_help = vti_print_help, 281 }; 282