1/* 2 * iproute_lwtunnel.c 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: Roopa Prabhu, <roopa@cumulusnetworks.com> 10 * Thomas Graf <tgraf@suug.ch> 11 * 12 */ 13 14#include <stdio.h> 15#include <stdlib.h> 16#include <unistd.h> 17#include <fcntl.h> 18#include <string.h> 19#include <linux/ila.h> 20#include <linux/lwtunnel.h> 21#include <linux/mpls_iptunnel.h> 22#include <errno.h> 23 24#include "rt_names.h" 25#include "utils.h" 26#include "iproute_lwtunnel.h" 27 28static int read_encap_type(const char *name) 29{ 30 if (strcmp(name, "mpls") == 0) 31 return LWTUNNEL_ENCAP_MPLS; 32 else if (strcmp(name, "ip") == 0) 33 return LWTUNNEL_ENCAP_IP; 34 else if (strcmp(name, "ip6") == 0) 35 return LWTUNNEL_ENCAP_IP6; 36 else if (strcmp(name, "ila") == 0) 37 return LWTUNNEL_ENCAP_ILA; 38 else 39 return LWTUNNEL_ENCAP_NONE; 40} 41 42static const char *format_encap_type(int type) 43{ 44 switch (type) { 45 case LWTUNNEL_ENCAP_MPLS: 46 return "mpls"; 47 case LWTUNNEL_ENCAP_IP: 48 return "ip"; 49 case LWTUNNEL_ENCAP_IP6: 50 return "ip6"; 51 case LWTUNNEL_ENCAP_ILA: 52 return "ila"; 53 default: 54 return "unknown"; 55 } 56} 57 58static void print_encap_mpls(FILE *fp, struct rtattr *encap) 59{ 60 struct rtattr *tb[MPLS_IPTUNNEL_MAX+1]; 61 char abuf[256]; 62 63 parse_rtattr_nested(tb, MPLS_IPTUNNEL_MAX, encap); 64 65 if (tb[MPLS_IPTUNNEL_DST]) 66 fprintf(fp, " %s ", format_host(AF_MPLS, 67 RTA_PAYLOAD(tb[MPLS_IPTUNNEL_DST]), 68 RTA_DATA(tb[MPLS_IPTUNNEL_DST]), 69 abuf, sizeof(abuf))); 70} 71 72static void print_encap_ip(FILE *fp, struct rtattr *encap) 73{ 74 struct rtattr *tb[LWTUNNEL_IP_MAX+1]; 75 char abuf[256]; 76 77 parse_rtattr_nested(tb, LWTUNNEL_IP_MAX, encap); 78 79 if (tb[LWTUNNEL_IP_ID]) 80 fprintf(fp, "id %llu ", ntohll(rta_getattr_u64(tb[LWTUNNEL_IP_ID]))); 81 82 if (tb[LWTUNNEL_IP_SRC]) 83 fprintf(fp, "src %s ", 84 rt_addr_n2a(AF_INET, 85 RTA_PAYLOAD(tb[LWTUNNEL_IP_SRC]), 86 RTA_DATA(tb[LWTUNNEL_IP_SRC]), 87 abuf, sizeof(abuf))); 88 89 if (tb[LWTUNNEL_IP_DST]) 90 fprintf(fp, "dst %s ", 91 rt_addr_n2a(AF_INET, 92 RTA_PAYLOAD(tb[LWTUNNEL_IP_DST]), 93 RTA_DATA(tb[LWTUNNEL_IP_DST]), 94 abuf, sizeof(abuf))); 95 96 if (tb[LWTUNNEL_IP_TTL]) 97 fprintf(fp, "ttl %d ", rta_getattr_u8(tb[LWTUNNEL_IP_TTL])); 98 99 if (tb[LWTUNNEL_IP_TOS]) 100 fprintf(fp, "tos %d ", rta_getattr_u8(tb[LWTUNNEL_IP_TOS])); 101} 102 103static void print_encap_ila(FILE *fp, struct rtattr *encap) 104{ 105 struct rtattr *tb[ILA_ATTR_MAX+1]; 106 107 parse_rtattr_nested(tb, ILA_ATTR_MAX, encap); 108 109 if (tb[ILA_ATTR_LOCATOR]) { 110 char abuf[ADDR64_BUF_SIZE]; 111 112 addr64_n2a(*(__u64 *)RTA_DATA(tb[ILA_ATTR_LOCATOR]), 113 abuf, sizeof(abuf)); 114 fprintf(fp, " %s ", abuf); 115 } 116} 117 118static void print_encap_ip6(FILE *fp, struct rtattr *encap) 119{ 120 struct rtattr *tb[LWTUNNEL_IP6_MAX+1]; 121 char abuf[256]; 122 123 parse_rtattr_nested(tb, LWTUNNEL_IP6_MAX, encap); 124 125 if (tb[LWTUNNEL_IP6_ID]) 126 fprintf(fp, "id %llu ", ntohll(rta_getattr_u64(tb[LWTUNNEL_IP6_ID]))); 127 128 if (tb[LWTUNNEL_IP6_SRC]) 129 fprintf(fp, "src %s ", 130 rt_addr_n2a(AF_INET6, 131 RTA_PAYLOAD(tb[LWTUNNEL_IP6_SRC]), 132 RTA_DATA(tb[LWTUNNEL_IP6_SRC]), 133 abuf, sizeof(abuf))); 134 135 if (tb[LWTUNNEL_IP6_DST]) 136 fprintf(fp, "dst %s ", 137 rt_addr_n2a(AF_INET6, 138 RTA_PAYLOAD(tb[LWTUNNEL_IP6_DST]), 139 RTA_DATA(tb[LWTUNNEL_IP6_DST]), 140 abuf, sizeof(abuf))); 141 142 if (tb[LWTUNNEL_IP6_HOPLIMIT]) 143 fprintf(fp, "hoplimit %d ", rta_getattr_u8(tb[LWTUNNEL_IP6_HOPLIMIT])); 144 145 if (tb[LWTUNNEL_IP6_TC]) 146 fprintf(fp, "tc %d ", rta_getattr_u8(tb[LWTUNNEL_IP6_TC])); 147} 148 149void lwt_print_encap(FILE *fp, struct rtattr *encap_type, 150 struct rtattr *encap) 151{ 152 int et; 153 154 if (!encap_type) 155 return; 156 157 et = rta_getattr_u16(encap_type); 158 159 fprintf(fp, " encap %s ", format_encap_type(et)); 160 161 switch (et) { 162 case LWTUNNEL_ENCAP_MPLS: 163 print_encap_mpls(fp, encap); 164 break; 165 case LWTUNNEL_ENCAP_IP: 166 print_encap_ip(fp, encap); 167 break; 168 case LWTUNNEL_ENCAP_ILA: 169 print_encap_ila(fp, encap); 170 break; 171 case LWTUNNEL_ENCAP_IP6: 172 print_encap_ip6(fp, encap); 173 break; 174 } 175} 176 177static int parse_encap_mpls(struct rtattr *rta, size_t len, int *argcp, char ***argvp) 178{ 179 inet_prefix addr; 180 int argc = *argcp; 181 char **argv = *argvp; 182 183 if (get_addr(&addr, *argv, AF_MPLS)) { 184 fprintf(stderr, "Error: an inet address is expected rather than \"%s\".\n", *argv); 185 exit(1); 186 } 187 188 rta_addattr_l(rta, len, MPLS_IPTUNNEL_DST, &addr.data, 189 addr.bytelen); 190 191 *argcp = argc; 192 *argvp = argv; 193 194 return 0; 195} 196 197static int parse_encap_ip(struct rtattr *rta, size_t len, int *argcp, char ***argvp) 198{ 199 int id_ok = 0, dst_ok = 0, tos_ok = 0, ttl_ok = 0; 200 char **argv = *argvp; 201 int argc = *argcp; 202 203 while (argc > 0) { 204 if (strcmp(*argv, "id") == 0) { 205 __u64 id; 206 NEXT_ARG(); 207 if (id_ok++) 208 duparg2("id", *argv); 209 if (get_u64(&id, *argv, 0)) 210 invarg("\"id\" value is invalid\n", *argv); 211 rta_addattr64(rta, len, LWTUNNEL_IP_ID, htonll(id)); 212 } else if (strcmp(*argv, "dst") == 0) { 213 inet_prefix addr; 214 NEXT_ARG(); 215 if (dst_ok++) 216 duparg2("dst", *argv); 217 get_addr(&addr, *argv, AF_INET); 218 rta_addattr_l(rta, len, LWTUNNEL_IP_DST, &addr.data, addr.bytelen); 219 } else if (strcmp(*argv, "tos") == 0) { 220 __u32 tos; 221 NEXT_ARG(); 222 if (tos_ok++) 223 duparg2("tos", *argv); 224 if (rtnl_dsfield_a2n(&tos, *argv)) 225 invarg("\"tos\" value is invalid\n", *argv); 226 rta_addattr8(rta, len, LWTUNNEL_IP_TOS, tos); 227 } else if (strcmp(*argv, "ttl") == 0) { 228 __u8 ttl; 229 NEXT_ARG(); 230 if (ttl_ok++) 231 duparg2("ttl", *argv); 232 if (get_u8(&ttl, *argv, 0)) 233 invarg("\"ttl\" value is invalid\n", *argv); 234 rta_addattr8(rta, len, LWTUNNEL_IP_TTL, ttl); 235 } else { 236 break; 237 } 238 argc--; argv++; 239 } 240 241 /* argv is currently the first unparsed argument, 242 * but the lwt_parse_encap() caller will move to the next, 243 * so step back */ 244 *argcp = argc + 1; 245 *argvp = argv - 1; 246 247 return 0; 248} 249 250static int parse_encap_ila(struct rtattr *rta, size_t len, 251 int *argcp, char ***argvp) 252{ 253 __u64 locator; 254 int argc = *argcp; 255 char **argv = *argvp; 256 257 if (get_addr64(&locator, *argv) < 0) { 258 fprintf(stderr, "Bad locator: %s\n", *argv); 259 exit(1); 260 } 261 262 rta_addattr64(rta, 1024, ILA_ATTR_LOCATOR, locator); 263 264 *argcp = argc; 265 *argvp = argv; 266 267 return 0; 268} 269 270static int parse_encap_ip6(struct rtattr *rta, size_t len, int *argcp, char ***argvp) 271{ 272 int id_ok = 0, dst_ok = 0, tos_ok = 0, ttl_ok = 0; 273 char **argv = *argvp; 274 int argc = *argcp; 275 276 while (argc > 0) { 277 if (strcmp(*argv, "id") == 0) { 278 __u64 id; 279 NEXT_ARG(); 280 if (id_ok++) 281 duparg2("id", *argv); 282 if (get_u64(&id, *argv, 0)) 283 invarg("\"id\" value is invalid\n", *argv); 284 rta_addattr64(rta, len, LWTUNNEL_IP6_ID, htonll(id)); 285 } else if (strcmp(*argv, "dst") == 0) { 286 inet_prefix addr; 287 NEXT_ARG(); 288 if (dst_ok++) 289 duparg2("dst", *argv); 290 get_addr(&addr, *argv, AF_INET6); 291 rta_addattr_l(rta, len, LWTUNNEL_IP6_DST, &addr.data, addr.bytelen); 292 } else if (strcmp(*argv, "tc") == 0) { 293 __u32 tc; 294 NEXT_ARG(); 295 if (tos_ok++) 296 duparg2("tc", *argv); 297 if (rtnl_dsfield_a2n(&tc, *argv)) 298 invarg("\"tc\" value is invalid\n", *argv); 299 rta_addattr8(rta, len, LWTUNNEL_IP6_TC, tc); 300 } else if (strcmp(*argv, "hoplimit") == 0) { 301 __u8 hoplimit; 302 NEXT_ARG(); 303 if (ttl_ok++) 304 duparg2("hoplimit", *argv); 305 if (get_u8(&hoplimit, *argv, 0)) 306 invarg("\"hoplimit\" value is invalid\n", *argv); 307 rta_addattr8(rta, len, LWTUNNEL_IP6_HOPLIMIT, hoplimit); 308 } else { 309 break; 310 } 311 argc--; argv++; 312 } 313 314 /* argv is currently the first unparsed argument, 315 * but the lwt_parse_encap() caller will move to the next, 316 * so step back */ 317 *argcp = argc + 1; 318 *argvp = argv - 1; 319 320 return 0; 321} 322 323int lwt_parse_encap(struct rtattr *rta, size_t len, int *argcp, char ***argvp) 324{ 325 struct rtattr *nest; 326 int argc = *argcp; 327 char **argv = *argvp; 328 __u16 type; 329 330 NEXT_ARG(); 331 type = read_encap_type(*argv); 332 if (!type) 333 invarg("\"encap type\" value is invalid\n", *argv); 334 335 NEXT_ARG(); 336 if (argc <= 1) { 337 fprintf(stderr, "Error: unexpected end of line after \"encap\"\n"); 338 exit(-1); 339 } 340 341 nest = rta_nest(rta, 1024, RTA_ENCAP); 342 switch (type) { 343 case LWTUNNEL_ENCAP_MPLS: 344 parse_encap_mpls(rta, len, &argc, &argv); 345 break; 346 case LWTUNNEL_ENCAP_IP: 347 parse_encap_ip(rta, len, &argc, &argv); 348 break; 349 case LWTUNNEL_ENCAP_ILA: 350 parse_encap_ila(rta, len, &argc, &argv); 351 break; 352 case LWTUNNEL_ENCAP_IP6: 353 parse_encap_ip6(rta, len, &argc, &argv); 354 break; 355 default: 356 fprintf(stderr, "Error: unsupported encap type\n"); 357 break; 358 } 359 rta_nest_end(rta, nest); 360 361 rta_addattr16(rta, 1024, RTA_ENCAP_TYPE, type); 362 363 *argcp = argc; 364 *argvp = argv; 365 366 return 0; 367} 368