1 /* $OpenBSD: parser.c,v 1.107 2021/08/09 08:24:36 claudio Exp $ */ 2 3 /* 4 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 5 * Copyright (c) 2016 Job Snijders <job@instituut.net> 6 * Copyright (c) 2016 Peter Hessler <phessler@openbsd.org> 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21 #include <sys/types.h> 22 23 #include <endian.h> 24 #include <err.h> 25 #include <errno.h> 26 #include <fcntl.h> 27 #include <limits.h> 28 #include <netdb.h> 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <unistd.h> 33 34 #include "parser.h" 35 36 enum token_type { 37 NOTOKEN, 38 ENDTOKEN, 39 KEYWORD, 40 ADDRESS, 41 PEERADDRESS, 42 FLAG, 43 ASNUM, 44 ASTYPE, 45 PREFIX, 46 PEERDESC, 47 GROUPDESC, 48 RIBNAME, 49 COMMUNICATION, 50 COMMUNITY, 51 EXTCOMMUNITY, 52 EXTCOM_SUBTYPE, 53 LARGE_COMMUNITY, 54 LOCALPREF, 55 MED, 56 NEXTHOP, 57 PFTABLE, 58 PREPNBR, 59 PREPSELF, 60 WEIGHT, 61 RD, 62 FAMILY, 63 RTABLE, 64 FILENAME, 65 PATHID, 66 }; 67 68 struct token { 69 enum token_type type; 70 const char *keyword; 71 int value; 72 const struct token *next; 73 }; 74 75 static const struct token t_main[]; 76 static const struct token t_show[]; 77 static const struct token t_show_summary[]; 78 static const struct token t_show_fib[]; 79 static const struct token t_show_rib[]; 80 static const struct token t_show_ovs[]; 81 static const struct token t_show_mrt[]; 82 static const struct token t_show_mrt_file[]; 83 static const struct token t_show_rib_neigh[]; 84 static const struct token t_show_mrt_neigh[]; 85 static const struct token t_show_rib_rib[]; 86 static const struct token t_show_neighbor[]; 87 static const struct token t_show_neighbor_modifiers[]; 88 static const struct token t_fib[]; 89 static const struct token t_neighbor[]; 90 static const struct token t_neighbor_modifiers[]; 91 static const struct token t_show_rib_as[]; 92 static const struct token t_show_mrt_as[]; 93 static const struct token t_show_prefix[]; 94 static const struct token t_show_ip[]; 95 static const struct token t_show_community[]; 96 static const struct token t_show_extcommunity[]; 97 static const struct token t_show_ext_subtype[]; 98 static const struct token t_show_largecommunity[]; 99 static const struct token t_network[]; 100 static const struct token t_network_show[]; 101 static const struct token t_prefix[]; 102 static const struct token t_set[]; 103 static const struct token t_community[]; 104 static const struct token t_extcommunity[]; 105 static const struct token t_ext_subtype[]; 106 static const struct token t_largecommunity[]; 107 static const struct token t_localpref[]; 108 static const struct token t_med[]; 109 static const struct token t_nexthop[]; 110 static const struct token t_pftable[]; 111 static const struct token t_prepnbr[]; 112 static const struct token t_prepself[]; 113 static const struct token t_weight[]; 114 static const struct token t_log[]; 115 static const struct token t_fib_table[]; 116 static const struct token t_show_fib_table[]; 117 static const struct token t_communication[]; 118 static const struct token t_show_rib_path[]; 119 120 static const struct token t_main[] = { 121 { KEYWORD, "reload", RELOAD, t_communication}, 122 { KEYWORD, "show", SHOW, t_show}, 123 { KEYWORD, "fib", FIB, t_fib}, 124 { KEYWORD, "neighbor", NEIGHBOR, t_neighbor}, 125 { KEYWORD, "network", NONE, t_network}, 126 { KEYWORD, "log", NONE, t_log}, 127 { ENDTOKEN, "", NONE, NULL} 128 }; 129 130 static const struct token t_show[] = { 131 { NOTOKEN, "", NONE, NULL}, 132 { KEYWORD, "fib", SHOW_FIB, t_show_fib}, 133 { KEYWORD, "interfaces", SHOW_INTERFACE, NULL}, 134 { KEYWORD, "neighbor", SHOW_NEIGHBOR, t_show_neighbor}, 135 { KEYWORD, "network", NETWORK_SHOW, t_network_show}, 136 { KEYWORD, "nexthop", SHOW_NEXTHOP, NULL}, 137 { KEYWORD, "rib", SHOW_RIB, t_show_rib}, 138 { KEYWORD, "tables", SHOW_FIB_TABLES, NULL}, 139 { KEYWORD, "ip", NONE, t_show_ip}, 140 { KEYWORD, "summary", SHOW_SUMMARY, t_show_summary}, 141 { KEYWORD, "sets", SHOW_SET, NULL}, 142 { KEYWORD, "rtr", SHOW_RTR, NULL}, 143 { KEYWORD, "mrt", SHOW_MRT, t_show_mrt}, 144 { ENDTOKEN, "", NONE, NULL} 145 }; 146 147 static const struct token t_show_summary[] = { 148 { NOTOKEN, "", NONE, NULL}, 149 { KEYWORD, "terse", SHOW_SUMMARY_TERSE, NULL}, 150 { ENDTOKEN, "", NONE, NULL} 151 }; 152 153 static const struct token t_show_fib[] = { 154 { NOTOKEN, "", NONE, NULL}, 155 { FLAG, "connected", F_CONNECTED, t_show_fib}, 156 { FLAG, "static", F_STATIC, t_show_fib}, 157 { FLAG, "bgp", F_BGPD_INSERTED, t_show_fib}, 158 { FLAG, "nexthop", F_NEXTHOP, t_show_fib}, 159 { KEYWORD, "table", NONE, t_show_fib_table}, 160 { FAMILY, "", NONE, t_show_fib}, 161 { ADDRESS, "", NONE, NULL}, 162 { ENDTOKEN, "", NONE, NULL} 163 }; 164 165 static const struct token t_show_rib[] = { 166 { NOTOKEN, "", NONE, NULL}, 167 { ASTYPE, "as", AS_ALL, t_show_rib_as}, 168 { ASTYPE, "source-as", AS_SOURCE, t_show_rib_as}, 169 { ASTYPE, "transit-as", AS_TRANSIT, t_show_rib_as}, 170 { ASTYPE, "peer-as", AS_PEER, t_show_rib_as}, 171 { ASTYPE, "empty-as", AS_EMPTY, t_show_rib}, 172 { KEYWORD, "community", NONE, t_show_community}, 173 { KEYWORD, "ext-community", NONE, t_show_extcommunity}, 174 { KEYWORD, "large-community", NONE, t_show_largecommunity}, 175 { FLAG, "best", F_CTL_ACTIVE, t_show_rib}, 176 { FLAG, "selected", F_CTL_ACTIVE, t_show_rib}, 177 { FLAG, "detail", F_CTL_DETAIL, t_show_rib}, 178 { FLAG, "error", F_CTL_INVALID, t_show_rib}, 179 { FLAG, "ssv" , F_CTL_SSV, t_show_rib}, 180 { FLAG, "in", F_CTL_ADJ_IN, t_show_rib}, 181 { FLAG, "out", F_CTL_ADJ_OUT, t_show_rib}, 182 { KEYWORD, "neighbor", NONE, t_show_rib_neigh}, 183 { KEYWORD, "ovs", NONE, t_show_ovs}, 184 { KEYWORD, "path-id", NONE, t_show_rib_path}, 185 { KEYWORD, "table", NONE, t_show_rib_rib}, 186 { KEYWORD, "summary", SHOW_SUMMARY, t_show_summary}, 187 { KEYWORD, "memory", SHOW_RIB_MEM, NULL}, 188 { FAMILY, "", NONE, t_show_rib}, 189 { PREFIX, "", NONE, t_show_prefix}, 190 { ENDTOKEN, "", NONE, NULL} 191 }; 192 193 static const struct token t_show_ovs[] = { 194 { FLAG, "valid" , F_CTL_OVS_VALID, t_show_rib}, 195 { FLAG, "invalid", F_CTL_OVS_INVALID, t_show_rib}, 196 { FLAG, "not-found", F_CTL_OVS_NOTFOUND, t_show_rib}, 197 { ENDTOKEN, "", NONE, NULL} 198 }; 199 200 static const struct token t_show_mrt[] = { 201 { NOTOKEN, "", NONE, NULL}, 202 { ASTYPE, "as", AS_ALL, t_show_mrt_as}, 203 { ASTYPE, "source-as", AS_SOURCE, t_show_mrt_as}, 204 { ASTYPE, "transit-as", AS_TRANSIT, t_show_mrt_as}, 205 { ASTYPE, "peer-as", AS_PEER, t_show_mrt_as}, 206 { ASTYPE, "empty-as", AS_EMPTY, t_show_mrt}, 207 { FLAG, "detail", F_CTL_DETAIL, t_show_mrt}, 208 { FLAG, "ssv", F_CTL_SSV, t_show_mrt}, 209 { KEYWORD, "neighbor", NONE, t_show_mrt_neigh}, 210 { FLAG, "peers", F_CTL_NEIGHBORS,t_show_mrt}, 211 { KEYWORD, "file", NONE, t_show_mrt_file}, 212 { FAMILY, "", NONE, t_show_mrt}, 213 { PREFIX, "", NONE, t_show_prefix}, 214 { ENDTOKEN, "", NONE, NULL} 215 }; 216 217 static const struct token t_show_mrt_file[] = { 218 { FILENAME, "", NONE, t_show_mrt}, 219 { ENDTOKEN, "", NONE, NULL} 220 }; 221 222 static const struct token t_show_rib_neigh_group[] = { 223 { GROUPDESC, "", NONE, t_show_rib}, 224 { ENDTOKEN, "", NONE, NULL} 225 }; 226 227 static const struct token t_show_rib_neigh[] = { 228 { KEYWORD, "group", NONE, t_show_rib_neigh_group}, 229 { PEERADDRESS, "", NONE, t_show_rib}, 230 { PEERDESC, "", NONE, t_show_rib}, 231 { ENDTOKEN, "", NONE, NULL} 232 }; 233 234 static const struct token t_show_mrt_neigh[] = { 235 { PEERADDRESS, "", NONE, t_show_mrt}, 236 { ENDTOKEN, "", NONE, NULL} 237 }; 238 239 static const struct token t_show_rib_rib[] = { 240 { RIBNAME, "", NONE, t_show_rib}, 241 { ENDTOKEN, "", NONE, NULL} 242 }; 243 244 static const struct token t_show_neighbor_modifiers[] = { 245 { NOTOKEN, "", NONE, NULL}, 246 { KEYWORD, "timers", SHOW_NEIGHBOR_TIMERS, NULL}, 247 { KEYWORD, "messages", SHOW_NEIGHBOR, NULL}, 248 { KEYWORD, "terse", SHOW_NEIGHBOR_TERSE, NULL}, 249 { ENDTOKEN, "", NONE, NULL} 250 }; 251 252 static const struct token t_show_neighbor_group[] = { 253 { GROUPDESC, "", NONE, t_show_neighbor_modifiers}, 254 { ENDTOKEN, "", NONE, NULL} 255 }; 256 257 static const struct token t_show_neighbor[] = { 258 { NOTOKEN, "", NONE, NULL}, 259 { KEYWORD, "group", NONE, t_show_neighbor_group}, 260 { PEERADDRESS, "", NONE, t_show_neighbor_modifiers}, 261 { PEERDESC, "", NONE, t_show_neighbor_modifiers}, 262 { ENDTOKEN, "", NONE, NULL} 263 }; 264 265 static const struct token t_fib[] = { 266 { KEYWORD, "couple", FIB_COUPLE, NULL}, 267 { KEYWORD, "decouple", FIB_DECOUPLE, NULL}, 268 { KEYWORD, "table", NONE, t_fib_table}, 269 { ENDTOKEN, "", NONE, NULL} 270 }; 271 272 static const struct token t_neighbor_group[] = { 273 { GROUPDESC, "", NONE, t_neighbor_modifiers}, 274 { ENDTOKEN, "", NONE, NULL} 275 }; 276 277 static const struct token t_neighbor[] = { 278 { KEYWORD, "group", NONE, t_neighbor_group}, 279 { PEERADDRESS, "", NONE, t_neighbor_modifiers}, 280 { PEERDESC, "", NONE, t_neighbor_modifiers}, 281 { ENDTOKEN, "", NONE, NULL} 282 }; 283 284 static const struct token t_communication[] = { 285 { NOTOKEN, "", NONE, NULL}, 286 { COMMUNICATION, "", NONE, NULL}, 287 { ENDTOKEN, "", NONE, NULL} 288 }; 289 290 static const struct token t_neighbor_modifiers[] = { 291 { KEYWORD, "up", NEIGHBOR_UP, NULL}, 292 { KEYWORD, "down", NEIGHBOR_DOWN, t_communication}, 293 { KEYWORD, "clear", NEIGHBOR_CLEAR, t_communication}, 294 { KEYWORD, "refresh", NEIGHBOR_RREFRESH, NULL}, 295 { KEYWORD, "destroy", NEIGHBOR_DESTROY, NULL}, 296 { ENDTOKEN, "", NONE, NULL} 297 }; 298 299 static const struct token t_show_rib_as[] = { 300 { ASNUM, "", NONE, t_show_rib}, 301 { ENDTOKEN, "", NONE, NULL} 302 }; 303 304 static const struct token t_show_mrt_as[] = { 305 { ASNUM, "", NONE, t_show_mrt}, 306 { ENDTOKEN, "", NONE, NULL} 307 }; 308 309 static const struct token t_show_prefix[] = { 310 { NOTOKEN, "", NONE, NULL}, 311 { FLAG, "all", F_LONGER, NULL}, 312 { FLAG, "longer-prefixes", F_LONGER, NULL}, 313 { FLAG, "or-longer", F_LONGER, NULL}, 314 { FLAG, "or-shorter", F_SHORTER, NULL}, 315 { ENDTOKEN, "", NONE, NULL} 316 }; 317 318 static const struct token t_show_ip[] = { 319 { KEYWORD, "bgp", SHOW_RIB, t_show_rib}, 320 { ENDTOKEN, "", NONE, NULL} 321 }; 322 323 static const struct token t_show_community[] = { 324 { COMMUNITY, "", NONE, t_show_rib}, 325 { ENDTOKEN, "", NONE, NULL} 326 }; 327 328 static const struct token t_show_extcommunity[] = { 329 { EXTCOM_SUBTYPE, "bdc", NONE, t_show_ext_subtype}, 330 { EXTCOM_SUBTYPE, "defgw", NONE, t_show_ext_subtype}, 331 { EXTCOM_SUBTYPE, "esi-lab", NONE, t_show_ext_subtype}, 332 { EXTCOM_SUBTYPE, "esi-rt", NONE, t_show_ext_subtype}, 333 { EXTCOM_SUBTYPE, "l2vid", NONE, t_show_ext_subtype}, 334 { EXTCOM_SUBTYPE, "mac-mob", NONE, t_show_ext_subtype}, 335 { EXTCOM_SUBTYPE, "odi", NONE, t_show_ext_subtype}, 336 { EXTCOM_SUBTYPE, "ort", NONE, t_show_ext_subtype}, 337 { EXTCOM_SUBTYPE, "ori", NONE, t_show_ext_subtype}, 338 { EXTCOM_SUBTYPE, "ovs", NONE, t_show_ext_subtype}, 339 { EXTCOM_SUBTYPE, "rt", NONE, t_show_ext_subtype}, 340 { EXTCOM_SUBTYPE, "soo", NONE, t_show_ext_subtype}, 341 { EXTCOM_SUBTYPE, "srcas", NONE, t_show_ext_subtype}, 342 { EXTCOM_SUBTYPE, "vrfri", NONE, t_show_ext_subtype}, 343 { ENDTOKEN, "", NONE, NULL} 344 }; 345 346 static const struct token t_show_ext_subtype[] = { 347 { EXTCOMMUNITY, "", NONE, t_show_rib}, 348 { ENDTOKEN, "", NONE, NULL} 349 }; 350 351 static const struct token t_show_largecommunity[] = { 352 { LARGE_COMMUNITY, "", NONE, t_show_rib}, 353 { ENDTOKEN, "", NONE, NULL} 354 }; 355 356 static const struct token t_network[] = { 357 { KEYWORD, "add", NETWORK_ADD, t_prefix}, 358 { KEYWORD, "delete", NETWORK_REMOVE, t_prefix}, 359 { KEYWORD, "flush", NETWORK_FLUSH, NULL}, 360 { KEYWORD, "show", NETWORK_SHOW, t_network_show}, 361 { KEYWORD, "mrt", NETWORK_MRT, t_show_mrt}, 362 { KEYWORD, "bulk", NETWORK_BULK_ADD, t_set}, 363 { ENDTOKEN, "", NONE, NULL} 364 }; 365 366 static const struct token t_prefix[] = { 367 { PREFIX, "", NONE, t_set}, 368 { ENDTOKEN, "", NONE, NULL} 369 }; 370 371 static const struct token t_network_show[] = { 372 { NOTOKEN, "", NONE, NULL}, 373 { FAMILY, "", NONE, NULL}, 374 { ENDTOKEN, "", NONE, NULL} 375 }; 376 377 static const struct token t_rd[] = { 378 { RD, "", NONE, t_set}, 379 { ENDTOKEN, "", NONE, NULL} 380 }; 381 382 static const struct token t_set[] = { 383 { NOTOKEN, "", NONE, NULL}, 384 { KEYWORD, "community", NONE, t_community}, 385 { KEYWORD, "ext-community", NONE, t_extcommunity}, 386 { KEYWORD, "large-community", NONE, t_largecommunity}, 387 { KEYWORD, "localpref", NONE, t_localpref}, 388 { KEYWORD, "med", NONE, t_med}, 389 { KEYWORD, "metric", NONE, t_med}, 390 { KEYWORD, "nexthop", NONE, t_nexthop}, 391 { KEYWORD, "pftable", NONE, t_pftable}, 392 { KEYWORD, "prepend-neighbor", NONE, t_prepnbr}, 393 { KEYWORD, "prepend-self", NONE, t_prepself}, 394 { KEYWORD, "rd", NONE, t_rd}, 395 { KEYWORD, "weight", NONE, t_weight}, 396 { KEYWORD, "add", NETWORK_BULK_ADD, NULL}, 397 { KEYWORD, "delete", NETWORK_BULK_REMOVE, NULL}, 398 { ENDTOKEN, "", NONE, NULL} 399 }; 400 401 static const struct token t_community[] = { 402 { COMMUNITY, "", NONE, t_set}, 403 { ENDTOKEN, "", NONE, NULL} 404 }; 405 406 static const struct token t_extcommunity[] = { 407 { EXTCOM_SUBTYPE, "bdc", NONE, t_ext_subtype}, 408 { EXTCOM_SUBTYPE, "defgw", NONE, t_ext_subtype}, 409 { EXTCOM_SUBTYPE, "esi-lab", NONE, t_ext_subtype}, 410 { EXTCOM_SUBTYPE, "esi-rt", NONE, t_ext_subtype}, 411 { EXTCOM_SUBTYPE, "l2vid", NONE, t_ext_subtype}, 412 { EXTCOM_SUBTYPE, "mac-mob", NONE, t_ext_subtype}, 413 { EXTCOM_SUBTYPE, "odi", NONE, t_ext_subtype}, 414 { EXTCOM_SUBTYPE, "ort", NONE, t_ext_subtype}, 415 { EXTCOM_SUBTYPE, "ori", NONE, t_ext_subtype}, 416 { EXTCOM_SUBTYPE, "ovs", NONE, t_ext_subtype}, 417 { EXTCOM_SUBTYPE, "rt", NONE, t_ext_subtype}, 418 { EXTCOM_SUBTYPE, "soo", NONE, t_ext_subtype}, 419 { EXTCOM_SUBTYPE, "srcas", NONE, t_ext_subtype}, 420 { EXTCOM_SUBTYPE, "vrfri", NONE, t_ext_subtype}, 421 { ENDTOKEN, "", NONE, NULL} 422 }; 423 424 static const struct token t_ext_subtype[] = { 425 { EXTCOMMUNITY, "", NONE, t_set}, 426 { ENDTOKEN, "", NONE, NULL} 427 }; 428 429 static const struct token t_largecommunity[] = { 430 { LARGE_COMMUNITY, "", NONE, t_set}, 431 { ENDTOKEN, "", NONE, NULL} 432 }; 433 434 static const struct token t_localpref[] = { 435 { LOCALPREF, "", NONE, t_set}, 436 { ENDTOKEN, "", NONE, NULL} 437 }; 438 439 static const struct token t_med[] = { 440 { MED, "", NONE, t_set}, 441 { ENDTOKEN, "", NONE, NULL} 442 }; 443 444 static const struct token t_nexthop[] = { 445 { NEXTHOP, "", NONE, t_set}, 446 { ENDTOKEN, "", NONE, NULL} 447 }; 448 449 static const struct token t_pftable[] = { 450 { PFTABLE, "", NONE, t_set}, 451 { ENDTOKEN, "", NONE, NULL} 452 }; 453 454 static const struct token t_prepnbr[] = { 455 { PREPNBR, "", NONE, t_set}, 456 { ENDTOKEN, "", NONE, NULL} 457 }; 458 459 static const struct token t_prepself[] = { 460 { PREPSELF, "", NONE, t_set}, 461 { ENDTOKEN, "", NONE, NULL} 462 }; 463 464 static const struct token t_weight[] = { 465 { WEIGHT, "", NONE, t_set}, 466 { ENDTOKEN, "", NONE, NULL} 467 }; 468 469 static const struct token t_log[] = { 470 { KEYWORD, "verbose", LOG_VERBOSE, NULL}, 471 { KEYWORD, "brief", LOG_BRIEF, NULL}, 472 { ENDTOKEN, "", NONE, NULL} 473 }; 474 475 static const struct token t_fib_table[] = { 476 { RTABLE, "", NONE, t_fib}, 477 { ENDTOKEN, "", NONE, NULL} 478 }; 479 480 static const struct token t_show_fib_table[] = { 481 { RTABLE, "", NONE, t_show_fib}, 482 { ENDTOKEN, "", NONE, NULL} 483 }; 484 485 static const struct token t_show_rib_path[] = { 486 { PATHID, "", NONE, t_show_rib}, 487 { ENDTOKEN, "", NONE, NULL} 488 }; 489 490 static struct parse_result res; 491 492 const struct token *match_token(int *argc, char **argv[], 493 const struct token []); 494 void show_valid_args(const struct token []); 495 496 int parse_addr(const char *, struct bgpd_addr *); 497 int parse_asnum(const char *, size_t, u_int32_t *); 498 int parse_number(const char *, struct parse_result *, enum token_type); 499 void parsecommunity(struct community *c, int type, char *s); 500 void parseextcommunity(struct community *c, const char *t, char *s); 501 int parse_nexthop(const char *, struct parse_result *); 502 503 struct parse_result * 504 parse(int argc, char *argv[]) 505 { 506 const struct token *table = t_main; 507 const struct token *match; 508 509 bzero(&res, sizeof(res)); 510 res.rtableid = getrtable(); 511 TAILQ_INIT(&res.set); 512 513 while (argc >= 0) { 514 if ((match = match_token(&argc, &argv, table)) == NULL) { 515 fprintf(stderr, "valid commands/args:\n"); 516 show_valid_args(table); 517 return (NULL); 518 } 519 520 argc--; 521 argv++; 522 523 if (match->type == NOTOKEN || match->next == NULL) 524 break; 525 526 table = match->next; 527 } 528 529 if (argc > 0) { 530 fprintf(stderr, "superfluous argument: %s\n", argv[0]); 531 return (NULL); 532 } 533 534 return (&res); 535 } 536 537 const struct token * 538 match_token(int *argc, char **argv[], const struct token table[]) 539 { 540 u_int i, match; 541 const struct token *t = NULL; 542 struct filter_set *fs; 543 const char *word = *argv[0]; 544 size_t wordlen = 0; 545 546 match = 0; 547 if (word != NULL) 548 wordlen = strlen(word); 549 for (i = 0; table[i].type != ENDTOKEN; i++) { 550 switch (table[i].type) { 551 case NOTOKEN: 552 if (word == NULL || wordlen == 0) { 553 match++; 554 t = &table[i]; 555 } 556 break; 557 case KEYWORD: 558 if (word != NULL && strncmp(word, table[i].keyword, 559 wordlen) == 0) { 560 match++; 561 t = &table[i]; 562 if (t->value) 563 res.action = t->value; 564 } 565 break; 566 case FLAG: 567 if (word != NULL && strncmp(word, table[i].keyword, 568 wordlen) == 0) { 569 match++; 570 t = &table[i]; 571 res.flags |= t->value; 572 } 573 break; 574 case FAMILY: 575 if (word == NULL) 576 break; 577 if (!strcmp(word, "inet") || 578 !strcasecmp(word, "IPv4")) { 579 match++; 580 t = &table[i]; 581 res.aid = AID_INET; 582 } 583 if (!strcmp(word, "inet6") || 584 !strcasecmp(word, "IPv6")) { 585 match++; 586 t = &table[i]; 587 res.aid = AID_INET6; 588 } 589 if (!strcasecmp(word, "VPNv4")) { 590 match++; 591 t = &table[i]; 592 res.aid = AID_VPN_IPv4; 593 } 594 if (!strcasecmp(word, "VPNv6")) { 595 match++; 596 t = &table[i]; 597 res.aid = AID_VPN_IPv6; 598 } 599 break; 600 case ADDRESS: 601 if (parse_addr(word, &res.addr)) { 602 match++; 603 t = &table[i]; 604 } 605 break; 606 case PEERADDRESS: 607 if (parse_addr(word, &res.peeraddr)) { 608 match++; 609 t = &table[i]; 610 } 611 break; 612 case PREFIX: 613 if (parse_prefix(word, wordlen, &res.addr, &res.prefixlen)) { 614 match++; 615 t = &table[i]; 616 } 617 break; 618 case ASTYPE: 619 if (word != NULL && strncmp(word, table[i].keyword, 620 wordlen) == 0) { 621 match++; 622 t = &table[i]; 623 res.as.type = t->value; 624 } 625 break; 626 case ASNUM: 627 if (parse_asnum(word, wordlen, &res.as.as_min)) { 628 res.as.as_max = res.as.as_min; 629 match++; 630 t = &table[i]; 631 } 632 break; 633 case GROUPDESC: 634 res.is_group = 1; 635 /* FALLTHROUGH */ 636 case PEERDESC: 637 if (!match && word != NULL && wordlen > 0) { 638 if (strlcpy(res.peerdesc, word, 639 sizeof(res.peerdesc)) >= 640 sizeof(res.peerdesc)) 641 errx(1, "neighbor description too " 642 "long"); 643 match++; 644 t = &table[i]; 645 } 646 break; 647 case RIBNAME: 648 if (!match && word != NULL && wordlen > 0) { 649 if (strlcpy(res.rib, word, sizeof(res.rib)) >= 650 sizeof(res.rib)) 651 errx(1, "rib name too long"); 652 match++; 653 t = &table[i]; 654 } 655 break; 656 case COMMUNICATION: 657 if (!match && word != NULL && wordlen > 0) { 658 if (strlcpy(res.reason, word, 659 sizeof(res.reason)) >= 660 sizeof(res.reason)) 661 errx(1, "shutdown reason too long"); 662 match++; 663 t = &table[i]; 664 } 665 break; 666 case COMMUNITY: 667 case LARGE_COMMUNITY: 668 if (word != NULL && wordlen > 0) { 669 int type = COMMUNITY_TYPE_BASIC; 670 char *p = strdup(word); 671 672 if (p == NULL) 673 err(1, NULL); 674 if (table[i].type == LARGE_COMMUNITY) 675 type = COMMUNITY_TYPE_LARGE; 676 parsecommunity(&res.community, type, p); 677 free(p); 678 679 if ((fs = calloc(1, sizeof(*fs))) == NULL) 680 err(1, NULL); 681 fs->type = ACTION_SET_COMMUNITY; 682 fs->action.community = res.community; 683 TAILQ_INSERT_TAIL(&res.set, fs, entry); 684 685 match++; 686 t = &table[i]; 687 } 688 break; 689 case EXTCOM_SUBTYPE: 690 if (word != NULL && strncmp(word, table[i].keyword, 691 wordlen) == 0) { 692 res.ext_comm_subtype = table[i].keyword; 693 match++; 694 t = &table[i]; 695 } 696 break; 697 case EXTCOMMUNITY: 698 if (word != NULL && wordlen > 0) { 699 char *p = strdup(word); 700 701 if (p == NULL) 702 err(1, NULL); 703 parseextcommunity(&res.community, 704 res.ext_comm_subtype, p); 705 free(p); 706 707 if ((fs = calloc(1, sizeof(*fs))) == NULL) 708 err(1, NULL); 709 fs->type = ACTION_SET_COMMUNITY; 710 fs->action.community = res.community; 711 TAILQ_INSERT_TAIL(&res.set, fs, entry); 712 713 match++; 714 t = &table[i]; 715 } 716 break; 717 case RD: 718 if (word != NULL && wordlen > 0) { 719 char *p = strdup(word); 720 struct community ext; 721 u_int64_t rd; 722 723 if (p == NULL) 724 err(1, NULL); 725 parseextcommunity(&ext, "rt", p); 726 free(p); 727 728 switch (ext.data3 >> 8) { 729 case EXT_COMMUNITY_TRANS_TWO_AS: 730 rd = (0ULL << 48); 731 rd |= ((u_int64_t)ext.data1 & 0xffff) 732 << 32; 733 rd |= (u_int64_t)ext.data2; 734 break; 735 case EXT_COMMUNITY_TRANS_IPV4: 736 rd = (1ULL << 48); 737 rd |= (u_int64_t)ext.data1 << 16; 738 rd |= (u_int64_t)ext.data2 & 0xffff; 739 break; 740 case EXT_COMMUNITY_TRANS_FOUR_AS: 741 rd = (2ULL << 48); 742 rd |= (u_int64_t)ext.data1 << 16; 743 rd |= (u_int64_t)ext.data2 & 0xffff; 744 break; 745 default: 746 errx(1, "bad encoding of rd"); 747 } 748 res.rd = htobe64(rd); 749 match++; 750 t = &table[i]; 751 } 752 break; 753 case LOCALPREF: 754 case MED: 755 case PREPNBR: 756 case PREPSELF: 757 case WEIGHT: 758 case RTABLE: 759 case PATHID: 760 if (word != NULL && wordlen > 0 && 761 parse_number(word, &res, table[i].type)) { 762 match++; 763 t = &table[i]; 764 } 765 break; 766 case NEXTHOP: 767 if (word != NULL && wordlen > 0 && 768 parse_nexthop(word, &res)) { 769 match++; 770 t = &table[i]; 771 } 772 break; 773 case PFTABLE: 774 if (word != NULL && wordlen > 0) { 775 if ((fs = calloc(1, 776 sizeof(struct filter_set))) == NULL) 777 err(1, NULL); 778 if (strlcpy(fs->action.pftable, word, 779 sizeof(fs->action.pftable)) >= 780 sizeof(fs->action.pftable)) 781 errx(1, "pftable name too long"); 782 TAILQ_INSERT_TAIL(&res.set, fs, entry); 783 match++; 784 t = &table[i]; 785 } 786 break; 787 case FILENAME: 788 if (word != NULL && wordlen > 0) { 789 if ((res.mrtfd = open(word, O_RDONLY)) == -1) { 790 /* 791 * ignore error if path has no / and 792 * does not exist. In hope to print 793 * usage. 794 */ 795 if (errno == ENOENT && 796 !strchr(word, '/')) 797 break; 798 err(1, "mrt open(%s)", word); 799 } 800 match++; 801 t = &table[i]; 802 } 803 break; 804 case ENDTOKEN: 805 break; 806 } 807 } 808 809 if (match != 1) { 810 if (word == NULL) 811 fprintf(stderr, "missing argument:\n"); 812 else if (match > 1) 813 fprintf(stderr, "ambiguous argument: %s\n", word); 814 else if (match < 1) 815 fprintf(stderr, "unknown argument: %s\n", word); 816 return (NULL); 817 } 818 819 return (t); 820 } 821 822 void 823 show_valid_args(const struct token table[]) 824 { 825 int i; 826 827 for (i = 0; table[i].type != ENDTOKEN; i++) { 828 switch (table[i].type) { 829 case NOTOKEN: 830 fprintf(stderr, " <cr>\n"); 831 break; 832 case KEYWORD: 833 case FLAG: 834 case ASTYPE: 835 case EXTCOM_SUBTYPE: 836 fprintf(stderr, " %s\n", table[i].keyword); 837 break; 838 case ADDRESS: 839 case PEERADDRESS: 840 fprintf(stderr, " <address>\n"); 841 break; 842 case PREFIX: 843 fprintf(stderr, " <address>[/<len>]\n"); 844 break; 845 case ASNUM: 846 fprintf(stderr, " <asnum>\n"); 847 break; 848 case GROUPDESC: 849 case PEERDESC: 850 fprintf(stderr, " <neighbor description>\n"); 851 break; 852 case RIBNAME: 853 fprintf(stderr, " <rib name>\n"); 854 break; 855 case COMMUNICATION: 856 fprintf(stderr, " <reason>\n"); 857 break; 858 case COMMUNITY: 859 fprintf(stderr, " <community>\n"); 860 break; 861 case LARGE_COMMUNITY: 862 fprintf(stderr, " <large-community>\n"); 863 break; 864 case EXTCOMMUNITY: 865 fprintf(stderr, " <extended-community>\n"); 866 break; 867 case RD: 868 fprintf(stderr, " <route-distinguisher>\n"); 869 break; 870 case LOCALPREF: 871 case MED: 872 case PREPNBR: 873 case PREPSELF: 874 case WEIGHT: 875 case PATHID: 876 fprintf(stderr, " <number>\n"); 877 break; 878 case RTABLE: 879 fprintf(stderr, " <rtableid>\n"); 880 break; 881 case NEXTHOP: 882 fprintf(stderr, " <address>\n"); 883 break; 884 case PFTABLE: 885 fprintf(stderr, " <pftable>\n"); 886 break; 887 case FAMILY: 888 fprintf(stderr, " [ inet | inet6 | IPv4 | IPv6 | " 889 "VPNv4 | VPNv6 ]\n"); 890 break; 891 case FILENAME: 892 fprintf(stderr, " <filename>\n"); 893 break; 894 case ENDTOKEN: 895 break; 896 } 897 } 898 } 899 900 int 901 parse_addr(const char *word, struct bgpd_addr *addr) 902 { 903 struct in_addr ina; 904 struct addrinfo hints, *r; 905 906 if (word == NULL) 907 return (0); 908 909 bzero(addr, sizeof(struct bgpd_addr)); 910 bzero(&ina, sizeof(ina)); 911 912 if (inet_net_pton(AF_INET, word, &ina, sizeof(ina)) != -1) { 913 addr->aid = AID_INET; 914 addr->v4 = ina; 915 return (1); 916 } 917 918 bzero(&hints, sizeof(hints)); 919 hints.ai_family = AF_INET6; 920 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 921 hints.ai_flags = AI_NUMERICHOST; 922 if (getaddrinfo(word, "0", &hints, &r) == 0) { 923 sa2addr(r->ai_addr, addr, NULL); 924 freeaddrinfo(r); 925 return (1); 926 } 927 928 return (0); 929 } 930 931 int 932 parse_prefix(const char *word, size_t wordlen, struct bgpd_addr *addr, u_int8_t *prefixlen) 933 { 934 char *p, *ps; 935 const char *errstr; 936 int mask = -1; 937 938 if (word == NULL) 939 return (0); 940 941 bzero(addr, sizeof(struct bgpd_addr)); 942 943 if ((p = strrchr(word, '/')) != NULL) { 944 size_t plen = strlen(p); 945 mask = strtonum(p + 1, 0, 128, &errstr); 946 if (errstr) 947 errx(1, "netmask %s", errstr); 948 949 if ((ps = malloc(wordlen - plen + 1)) == NULL) 950 err(1, "parse_prefix: malloc"); 951 strlcpy(ps, word, wordlen - plen + 1); 952 953 if (parse_addr(ps, addr) == 0) { 954 free(ps); 955 return (0); 956 } 957 958 free(ps); 959 } else 960 if (parse_addr(word, addr) == 0) 961 return (0); 962 963 switch (addr->aid) { 964 case AID_INET: 965 if (mask == -1) 966 mask = 32; 967 if (mask > 32) 968 errx(1, "invalid netmask: too large"); 969 addr->v4.s_addr = addr->v4.s_addr & htonl(prefixlen2mask(mask)); 970 break; 971 case AID_INET6: 972 if (mask == -1) 973 mask = 128; 974 inet6applymask(&addr->v6, &addr->v6, mask); 975 break; 976 default: 977 return (0); 978 } 979 980 *prefixlen = mask; 981 return (1); 982 } 983 984 int 985 parse_asnum(const char *word, size_t wordlen, u_int32_t *asnum) 986 { 987 const char *errstr; 988 char *dot, *parseword; 989 u_int32_t uval, uvalh = 0; 990 991 if (word == NULL) 992 return (0); 993 994 if (wordlen < 1 || word[0] < '0' || word[0] > '9') 995 return (0); 996 997 parseword = strdup(word); 998 if ((dot = strchr(parseword, '.')) != NULL) { 999 *dot++ = '\0'; 1000 uvalh = strtonum(parseword, 0, USHRT_MAX, &errstr); 1001 if (errstr) 1002 errx(1, "AS number is %s: %s", errstr, word); 1003 uval = strtonum(dot, 0, USHRT_MAX, &errstr); 1004 if (errstr) 1005 errx(1, "AS number is %s: %s", errstr, word); 1006 } else { 1007 uval = strtonum(parseword, 0, UINT_MAX, &errstr); 1008 if (errstr) 1009 errx(1, "AS number is %s: %s", errstr, word); 1010 } 1011 1012 free(parseword); 1013 *asnum = uval | (uvalh << 16); 1014 return (1); 1015 } 1016 1017 int 1018 parse_number(const char *word, struct parse_result *r, enum token_type type) 1019 { 1020 struct filter_set *fs; 1021 const char *errstr; 1022 u_int uval; 1023 1024 if (word == NULL) 1025 return (0); 1026 1027 uval = strtonum(word, 0, UINT_MAX, &errstr); 1028 if (errstr) 1029 errx(1, "number is %s: %s", errstr, word); 1030 1031 /* number was parseable */ 1032 switch (type) { 1033 case RTABLE: 1034 r->rtableid = uval; 1035 return (1); 1036 case PATHID: 1037 r->pathid = uval; 1038 r->flags |= F_CTL_HAS_PATHID; 1039 return (1); 1040 default: 1041 break; 1042 } 1043 1044 if ((fs = calloc(1, sizeof(struct filter_set))) == NULL) 1045 err(1, NULL); 1046 switch (type) { 1047 case LOCALPREF: 1048 fs->type = ACTION_SET_LOCALPREF; 1049 fs->action.metric = uval; 1050 break; 1051 case MED: 1052 fs->type = ACTION_SET_MED; 1053 fs->action.metric = uval; 1054 break; 1055 case PREPNBR: 1056 if (uval > 128) { 1057 free(fs); 1058 return (0); 1059 } 1060 fs->type = ACTION_SET_PREPEND_PEER; 1061 fs->action.prepend = uval; 1062 break; 1063 case PREPSELF: 1064 if (uval > 128) { 1065 free(fs); 1066 return (0); 1067 } 1068 fs->type = ACTION_SET_PREPEND_SELF; 1069 fs->action.prepend = uval; 1070 break; 1071 case WEIGHT: 1072 fs->type = ACTION_SET_WEIGHT; 1073 fs->action.metric = uval; 1074 break; 1075 default: 1076 errx(1, "king bula sez bad things happen"); 1077 } 1078 1079 TAILQ_INSERT_TAIL(&r->set, fs, entry); 1080 return (1); 1081 } 1082 1083 static void 1084 getcommunity(char *s, int large, u_int32_t *val, u_int32_t *flag) 1085 { 1086 long long max = USHRT_MAX; 1087 const char *errstr; 1088 1089 *flag = 0; 1090 *val = 0; 1091 if (strcmp(s, "*") == 0) { 1092 *flag = COMMUNITY_ANY; 1093 return; 1094 } else if (strcmp(s, "neighbor-as") == 0) { 1095 *flag = COMMUNITY_NEIGHBOR_AS; 1096 return; 1097 } else if (strcmp(s, "local-as") == 0) { 1098 *flag = COMMUNITY_LOCAL_AS; 1099 return; 1100 } 1101 if (large) 1102 max = UINT_MAX; 1103 *val = strtonum(s, 0, max, &errstr); 1104 if (errstr) 1105 errx(1, "Community %s is %s (max: %llu)", s, errstr, max); 1106 } 1107 1108 static void 1109 setcommunity(struct community *c, u_int32_t as, u_int32_t data, 1110 u_int32_t asflag, u_int32_t dataflag) 1111 { 1112 c->flags = COMMUNITY_TYPE_BASIC; 1113 c->flags |= asflag << 8; 1114 c->flags |= dataflag << 16; 1115 c->data1 = as; 1116 c->data2 = data; 1117 c->data3 = 0; 1118 } 1119 1120 static void 1121 parselargecommunity(struct community *c, char *s) 1122 { 1123 char *p, *q; 1124 u_int32_t dflag1, dflag2, dflag3; 1125 1126 if ((p = strchr(s, ':')) == NULL) 1127 errx(1, "Bad community syntax"); 1128 *p++ = 0; 1129 1130 if ((q = strchr(p, ':')) == NULL) 1131 errx(1, "Bad community syntax"); 1132 *q++ = 0; 1133 1134 getcommunity(s, 1, &c->data1, &dflag1); 1135 getcommunity(p, 1, &c->data2, &dflag2); 1136 getcommunity(q, 1, &c->data3, &dflag3); 1137 1138 c->flags = COMMUNITY_TYPE_LARGE; 1139 c->flags |= dflag1 << 8; 1140 c->flags |= dflag2 << 16; 1141 c->flags |= dflag3 << 24; 1142 } 1143 1144 void 1145 parsecommunity(struct community *c, int type, char *s) 1146 { 1147 char *p; 1148 u_int32_t as, data, asflag, dataflag; 1149 1150 if (type == COMMUNITY_TYPE_LARGE) { 1151 parselargecommunity(c, s); 1152 return; 1153 } 1154 1155 /* Well-known communities */ 1156 if (strcasecmp(s, "GRACEFUL_SHUTDOWN") == 0) { 1157 setcommunity(c, COMMUNITY_WELLKNOWN, 1158 COMMUNITY_GRACEFUL_SHUTDOWN, 0, 0); 1159 return; 1160 } else if (strcasecmp(s, "NO_EXPORT") == 0) { 1161 setcommunity(c, COMMUNITY_WELLKNOWN, 1162 COMMUNITY_NO_EXPORT, 0, 0); 1163 return; 1164 } else if (strcasecmp(s, "NO_ADVERTISE") == 0) { 1165 setcommunity(c, COMMUNITY_WELLKNOWN, 1166 COMMUNITY_NO_ADVERTISE, 0, 0); 1167 return; 1168 } else if (strcasecmp(s, "NO_EXPORT_SUBCONFED") == 0) { 1169 setcommunity(c, COMMUNITY_WELLKNOWN, 1170 COMMUNITY_NO_EXPSUBCONFED, 0, 0); 1171 return; 1172 } else if (strcasecmp(s, "NO_PEER") == 0) { 1173 setcommunity(c, COMMUNITY_WELLKNOWN, 1174 COMMUNITY_NO_PEER, 0, 0); 1175 return; 1176 } else if (strcasecmp(s, "BLACKHOLE") == 0) { 1177 setcommunity(c, COMMUNITY_WELLKNOWN, 1178 COMMUNITY_BLACKHOLE, 0, 0); 1179 return; 1180 } 1181 1182 if ((p = strchr(s, ':')) == NULL) 1183 errx(1, "Bad community syntax"); 1184 *p++ = 0; 1185 1186 getcommunity(s, 0, &as, &asflag); 1187 getcommunity(p, 0, &data, &dataflag); 1188 setcommunity(c, as, data, asflag, dataflag); 1189 } 1190 1191 static int 1192 parsesubtype(const char *name, int *type, int *subtype) 1193 { 1194 const struct ext_comm_pairs *cp; 1195 int found = 0; 1196 1197 for (cp = iana_ext_comms; cp->subname != NULL; cp++) { 1198 if (strcmp(name, cp->subname) == 0) { 1199 if (found == 0) { 1200 *type = cp->type; 1201 *subtype = cp->subtype; 1202 } 1203 found++; 1204 } 1205 } 1206 if (found > 1) 1207 *type = -1; 1208 return (found); 1209 } 1210 1211 static int 1212 parseextvalue(int type, char *s, u_int32_t *v, u_int32_t *flag) 1213 { 1214 const char *errstr; 1215 char *p; 1216 struct in_addr ip; 1217 u_int32_t uvalh, uval; 1218 1219 if (type != -1) { 1220 /* nothing */ 1221 } else if (strcmp(s, "neighbor-as") == 0) { 1222 *flag = COMMUNITY_NEIGHBOR_AS; 1223 *v = 0; 1224 return EXT_COMMUNITY_TRANS_FOUR_AS; 1225 } else if (strcmp(s, "local-as") == 0) { 1226 *flag = COMMUNITY_LOCAL_AS; 1227 *v = 0; 1228 return EXT_COMMUNITY_TRANS_FOUR_AS; 1229 } else if ((p = strchr(s, '.')) == NULL) { 1230 /* AS_PLAIN number (4 or 2 byte) */ 1231 strtonum(s, 0, USHRT_MAX, &errstr); 1232 if (errstr == NULL) 1233 type = EXT_COMMUNITY_TRANS_TWO_AS; 1234 else 1235 type = EXT_COMMUNITY_TRANS_FOUR_AS; 1236 } else if (strchr(p + 1, '.') == NULL) { 1237 /* AS_DOT number (4-byte) */ 1238 type = EXT_COMMUNITY_TRANS_FOUR_AS; 1239 } else { 1240 /* more than one dot -> IP address */ 1241 type = EXT_COMMUNITY_TRANS_IPV4; 1242 } 1243 1244 switch (type) { 1245 case EXT_COMMUNITY_TRANS_TWO_AS: 1246 uval = strtonum(s, 0, USHRT_MAX, &errstr); 1247 if (errstr) 1248 errx(1, "Bad ext-community %s is %s", s, errstr); 1249 *v = uval; 1250 break; 1251 case EXT_COMMUNITY_TRANS_FOUR_AS: 1252 if ((p = strchr(s, '.')) == NULL) { 1253 uval = strtonum(s, 0, UINT_MAX, &errstr); 1254 if (errstr) 1255 errx(1, "Bad ext-community %s is %s", s, 1256 errstr); 1257 *v = uval; 1258 break; 1259 } 1260 *p++ = '\0'; 1261 uvalh = strtonum(s, 0, USHRT_MAX, &errstr); 1262 if (errstr) 1263 errx(1, "Bad ext-community %s is %s", s, errstr); 1264 uval = strtonum(p, 0, USHRT_MAX, &errstr); 1265 if (errstr) 1266 errx(1, "Bad ext-community %s is %s", p, errstr); 1267 *v = uval | (uvalh << 16); 1268 break; 1269 case EXT_COMMUNITY_TRANS_IPV4: 1270 if (inet_aton(s, &ip) == 0) 1271 errx(1, "Bad ext-community %s not parseable", s); 1272 *v = ntohl(ip.s_addr); 1273 break; 1274 default: 1275 errx(1, "%s: unexpected type %d", __func__, type); 1276 } 1277 return (type); 1278 } 1279 1280 void 1281 parseextcommunity(struct community *c, const char *t, char *s) 1282 { 1283 const struct ext_comm_pairs *cp; 1284 char *p, *ep; 1285 u_int64_t ullval; 1286 u_int32_t uval, uval2, dflag1 = 0, dflag2 = 0; 1287 int type = 0, subtype = 0; 1288 1289 if (strcmp(t, "*") == 0 && strcmp(s, "*") == 0) { 1290 c->flags = COMMUNITY_TYPE_EXT; 1291 c->flags |= COMMUNITY_ANY << 24; 1292 return; 1293 } 1294 if (parsesubtype(t, &type, &subtype) == 0) 1295 errx(1, "Bad ext-community unknown type"); 1296 1297 switch (type) { 1298 case EXT_COMMUNITY_TRANS_TWO_AS: 1299 case EXT_COMMUNITY_TRANS_FOUR_AS: 1300 case EXT_COMMUNITY_TRANS_IPV4: 1301 case -1: 1302 if (strcmp(s, "*") == 0) { 1303 dflag1 = COMMUNITY_ANY; 1304 break; 1305 } 1306 if ((p = strchr(s, ':')) == NULL) 1307 errx(1, "Bad ext-community %s", s); 1308 *p++ = '\0'; 1309 type = parseextvalue(type, s, &uval, &dflag1); 1310 1311 switch (type) { 1312 case EXT_COMMUNITY_TRANS_TWO_AS: 1313 getcommunity(p, 1, &uval2, &dflag2); 1314 break; 1315 case EXT_COMMUNITY_TRANS_IPV4: 1316 case EXT_COMMUNITY_TRANS_FOUR_AS: 1317 getcommunity(p, 0, &uval2, &dflag2); 1318 break; 1319 default: 1320 errx(1, "parseextcommunity: unexpected result"); 1321 } 1322 1323 c->data1 = uval; 1324 c->data2 = uval2; 1325 break; 1326 case EXT_COMMUNITY_TRANS_OPAQUE: 1327 case EXT_COMMUNITY_TRANS_EVPN: 1328 if (strcmp(s, "*") == 0) { 1329 dflag1 = COMMUNITY_ANY; 1330 break; 1331 } 1332 errno = 0; 1333 ullval = strtoull(s, &ep, 0); 1334 if (s[0] == '\0' || *ep != '\0') 1335 errx(1, "Bad ext-community bad value"); 1336 if (errno == ERANGE && ullval > EXT_COMMUNITY_OPAQUE_MAX) 1337 errx(1, "Bad ext-community value too big"); 1338 c->data1 = ullval >> 32; 1339 c->data2 = ullval; 1340 break; 1341 case EXT_COMMUNITY_NON_TRANS_OPAQUE: 1342 if (subtype == EXT_COMMUNITY_SUBTYPE_OVS) { 1343 if (strcmp(s, "valid") == 0) { 1344 c->data2 = EXT_COMMUNITY_OVS_VALID; 1345 break; 1346 } else if (strcmp(s, "invalid") == 0) { 1347 c->data2 = EXT_COMMUNITY_OVS_INVALID; 1348 break; 1349 } else if (strcmp(s, "not-found") == 0) { 1350 c->data2 = EXT_COMMUNITY_OVS_NOTFOUND; 1351 break; 1352 } else if (strcmp(s, "*") == 0) { 1353 dflag1 = COMMUNITY_ANY; 1354 break; 1355 } 1356 } 1357 errx(1, "Bad ext-community %s", s); 1358 } 1359 1360 c->data3 = type << 8 | subtype; 1361 1362 /* special handling of ext-community rt * since type is not known */ 1363 if (dflag1 == COMMUNITY_ANY && type == -1) { 1364 c->flags = COMMUNITY_TYPE_EXT; 1365 c->flags |= dflag1 << 8; 1366 return; 1367 } 1368 1369 /* verify type/subtype combo */ 1370 for (cp = iana_ext_comms; cp->subname != NULL; cp++) { 1371 if (cp->type == type && cp->subtype == subtype) { 1372 c->flags = COMMUNITY_TYPE_EXT; 1373 c->flags |= dflag1 << 8; 1374 c->flags |= dflag2 << 16; 1375 return; 1376 } 1377 } 1378 1379 errx(1, "Bad ext-community bad format for type"); 1380 } 1381 1382 int 1383 parse_nexthop(const char *word, struct parse_result *r) 1384 { 1385 struct filter_set *fs; 1386 1387 if ((fs = calloc(1, sizeof(struct filter_set))) == NULL) 1388 err(1, NULL); 1389 1390 if (strcmp(word, "blackhole") == 0) 1391 fs->type = ACTION_SET_NEXTHOP_BLACKHOLE; 1392 else if (strcmp(word, "reject") == 0) 1393 fs->type = ACTION_SET_NEXTHOP_REJECT; 1394 else if (strcmp(word, "no-modify") == 0) 1395 fs->type = ACTION_SET_NEXTHOP_NOMODIFY; 1396 else if (parse_addr(word, &fs->action.nexthop)) { 1397 fs->type = ACTION_SET_NEXTHOP; 1398 } else { 1399 free(fs); 1400 return (0); 1401 } 1402 1403 TAILQ_INSERT_TAIL(&r->set, fs, entry); 1404 return (1); 1405 } 1406