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