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