| File: | src/usr.bin/bgplg/bgpctl/../../../usr.sbin/bgpctl/parser.c |
| Warning: | line 731, column 34 The left operand of '&' is a garbage value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 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(*__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((void *)0)} | ||||
| 128 | }; | ||||
| 129 | |||||
| 130 | static const struct token t_show[] = { | ||||
| 131 | { NOTOKEN, "", NONE, NULL((void *)0)}, | ||||
| 132 | { KEYWORD, "fib", SHOW_FIB, t_show_fib}, | ||||
| 133 | { KEYWORD, "interfaces", SHOW_INTERFACE, NULL((void *)0)}, | ||||
| 134 | { KEYWORD, "neighbor", SHOW_NEIGHBOR, t_show_neighbor}, | ||||
| 135 | { KEYWORD, "network", NETWORK_SHOW, t_network_show}, | ||||
| 136 | { KEYWORD, "nexthop", SHOW_NEXTHOP, NULL((void *)0)}, | ||||
| 137 | { KEYWORD, "rib", SHOW_RIB, t_show_rib}, | ||||
| 138 | { KEYWORD, "tables", SHOW_FIB_TABLES, NULL((void *)0)}, | ||||
| 139 | { KEYWORD, "ip", NONE, t_show_ip}, | ||||
| 140 | { KEYWORD, "summary", SHOW_SUMMARY, t_show_summary}, | ||||
| 141 | { KEYWORD, "sets", SHOW_SET, NULL((void *)0)}, | ||||
| 142 | { KEYWORD, "rtr", SHOW_RTR, NULL((void *)0)}, | ||||
| 143 | { KEYWORD, "mrt", SHOW_MRT, t_show_mrt}, | ||||
| 144 | { ENDTOKEN, "", NONE, NULL((void *)0)} | ||||
| 145 | }; | ||||
| 146 | |||||
| 147 | static const struct token t_show_summary[] = { | ||||
| 148 | { NOTOKEN, "", NONE, NULL((void *)0)}, | ||||
| 149 | { KEYWORD, "terse", SHOW_SUMMARY_TERSE, NULL((void *)0)}, | ||||
| 150 | { ENDTOKEN, "", NONE, NULL((void *)0)} | ||||
| 151 | }; | ||||
| 152 | |||||
| 153 | static const struct token t_show_fib[] = { | ||||
| 154 | { NOTOKEN, "", NONE, NULL((void *)0)}, | ||||
| 155 | { FLAG, "connected", F_CONNECTED0x0004, t_show_fib}, | ||||
| 156 | { FLAG, "static", F_STATIC0x0020, t_show_fib}, | ||||
| 157 | { FLAG, "bgp", F_BGPD_INSERTED0x0001, t_show_fib}, | ||||
| 158 | { FLAG, "nexthop", F_NEXTHOP0x0008, t_show_fib}, | ||||
| 159 | { KEYWORD, "table", NONE, t_show_fib_table}, | ||||
| 160 | { FAMILY, "", NONE, t_show_fib}, | ||||
| 161 | { ADDRESS, "", NONE, NULL((void *)0)}, | ||||
| 162 | { ENDTOKEN, "", NONE, NULL((void *)0)} | ||||
| 163 | }; | ||||
| 164 | |||||
| 165 | static const struct token t_show_rib[] = { | ||||
| 166 | { NOTOKEN, "", NONE, NULL((void *)0)}, | ||||
| 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_ACTIVE0x8000, t_show_rib}, | ||||
| 176 | { FLAG, "selected", F_CTL_ACTIVE0x8000, t_show_rib}, | ||||
| 177 | { FLAG, "detail", F_CTL_DETAIL0x1000, t_show_rib}, | ||||
| 178 | { FLAG, "error", F_CTL_INVALID0x40000, t_show_rib}, | ||||
| 179 | { FLAG, "ssv" , F_CTL_SSV0x20000, t_show_rib}, | ||||
| 180 | { FLAG, "in", F_CTL_ADJ_IN0x2000, t_show_rib}, | ||||
| 181 | { FLAG, "out", F_CTL_ADJ_OUT0x4000, 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((void *)0)}, | ||||
| 188 | { FAMILY, "", NONE, t_show_rib}, | ||||
| 189 | { PREFIX, "", NONE, t_show_prefix}, | ||||
| 190 | { ENDTOKEN, "", NONE, NULL((void *)0)} | ||||
| 191 | }; | ||||
| 192 | |||||
| 193 | static const struct token t_show_ovs[] = { | ||||
| 194 | { FLAG, "valid" , F_CTL_OVS_VALID0x80000, t_show_rib}, | ||||
| 195 | { FLAG, "invalid", F_CTL_OVS_INVALID0x100000, t_show_rib}, | ||||
| 196 | { FLAG, "not-found", F_CTL_OVS_NOTFOUND0x200000, t_show_rib}, | ||||
| 197 | { ENDTOKEN, "", NONE, NULL((void *)0)} | ||||
| 198 | }; | ||||
| 199 | |||||
| 200 | static const struct token t_show_mrt[] = { | ||||
| 201 | { NOTOKEN, "", NONE, NULL((void *)0)}, | ||||
| 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_DETAIL0x1000, t_show_mrt}, | ||||
| 208 | { FLAG, "ssv", F_CTL_SSV0x20000, t_show_mrt}, | ||||
| 209 | { KEYWORD, "neighbor", NONE, t_show_mrt_neigh}, | ||||
| 210 | { FLAG, "peers", F_CTL_NEIGHBORS0x400000,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((void *)0)} | ||||
| 215 | }; | ||||
| 216 | |||||
| 217 | static const struct token t_show_mrt_file[] = { | ||||
| 218 | { FILENAME, "", NONE, t_show_mrt}, | ||||
| 219 | { ENDTOKEN, "", NONE, NULL((void *)0)} | ||||
| 220 | }; | ||||
| 221 | |||||
| 222 | static const struct token t_show_rib_neigh_group[] = { | ||||
| 223 | { GROUPDESC, "", NONE, t_show_rib}, | ||||
| 224 | { ENDTOKEN, "", NONE, NULL((void *)0)} | ||||
| 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((void *)0)} | ||||
| 232 | }; | ||||
| 233 | |||||
| 234 | static const struct token t_show_mrt_neigh[] = { | ||||
| 235 | { PEERADDRESS, "", NONE, t_show_mrt}, | ||||
| 236 | { ENDTOKEN, "", NONE, NULL((void *)0)} | ||||
| 237 | }; | ||||
| 238 | |||||
| 239 | static const struct token t_show_rib_rib[] = { | ||||
| 240 | { RIBNAME, "", NONE, t_show_rib}, | ||||
| 241 | { ENDTOKEN, "", NONE, NULL((void *)0)} | ||||
| 242 | }; | ||||
| 243 | |||||
| 244 | static const struct token t_show_neighbor_modifiers[] = { | ||||
| 245 | { NOTOKEN, "", NONE, NULL((void *)0)}, | ||||
| 246 | { KEYWORD, "timers", SHOW_NEIGHBOR_TIMERS, NULL((void *)0)}, | ||||
| 247 | { KEYWORD, "messages", SHOW_NEIGHBOR, NULL((void *)0)}, | ||||
| 248 | { KEYWORD, "terse", SHOW_NEIGHBOR_TERSE, NULL((void *)0)}, | ||||
| 249 | { ENDTOKEN, "", NONE, NULL((void *)0)} | ||||
| 250 | }; | ||||
| 251 | |||||
| 252 | static const struct token t_show_neighbor_group[] = { | ||||
| 253 | { GROUPDESC, "", NONE, t_show_neighbor_modifiers}, | ||||
| 254 | { ENDTOKEN, "", NONE, NULL((void *)0)} | ||||
| 255 | }; | ||||
| 256 | |||||
| 257 | static const struct token t_show_neighbor[] = { | ||||
| 258 | { NOTOKEN, "", NONE, NULL((void *)0)}, | ||||
| 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((void *)0)} | ||||
| 263 | }; | ||||
| 264 | |||||
| 265 | static const struct token t_fib[] = { | ||||
| 266 | { KEYWORD, "couple", FIB_COUPLE, NULL((void *)0)}, | ||||
| 267 | { KEYWORD, "decouple", FIB_DECOUPLE, NULL((void *)0)}, | ||||
| 268 | { KEYWORD, "table", NONE, t_fib_table}, | ||||
| 269 | { ENDTOKEN, "", NONE, NULL((void *)0)} | ||||
| 270 | }; | ||||
| 271 | |||||
| 272 | static const struct token t_neighbor_group[] = { | ||||
| 273 | { GROUPDESC, "", NONE, t_neighbor_modifiers}, | ||||
| 274 | { ENDTOKEN, "", NONE, NULL((void *)0)} | ||||
| 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((void *)0)} | ||||
| 282 | }; | ||||
| 283 | |||||
| 284 | static const struct token t_communication[] = { | ||||
| 285 | { NOTOKEN, "", NONE, NULL((void *)0)}, | ||||
| 286 | { COMMUNICATION, "", NONE, NULL((void *)0)}, | ||||
| 287 | { ENDTOKEN, "", NONE, NULL((void *)0)} | ||||
| 288 | }; | ||||
| 289 | |||||
| 290 | static const struct token t_neighbor_modifiers[] = { | ||||
| 291 | { KEYWORD, "up", NEIGHBOR_UP, NULL((void *)0)}, | ||||
| 292 | { KEYWORD, "down", NEIGHBOR_DOWN, t_communication}, | ||||
| 293 | { KEYWORD, "clear", NEIGHBOR_CLEAR, t_communication}, | ||||
| 294 | { KEYWORD, "refresh", NEIGHBOR_RREFRESH, NULL((void *)0)}, | ||||
| 295 | { KEYWORD, "destroy", NEIGHBOR_DESTROY, NULL((void *)0)}, | ||||
| 296 | { ENDTOKEN, "", NONE, NULL((void *)0)} | ||||
| 297 | }; | ||||
| 298 | |||||
| 299 | static const struct token t_show_rib_as[] = { | ||||
| 300 | { ASNUM, "", NONE, t_show_rib}, | ||||
| 301 | { ENDTOKEN, "", NONE, NULL((void *)0)} | ||||
| 302 | }; | ||||
| 303 | |||||
| 304 | static const struct token t_show_mrt_as[] = { | ||||
| 305 | { ASNUM, "", NONE, t_show_mrt}, | ||||
| 306 | { ENDTOKEN, "", NONE, NULL((void *)0)} | ||||
| 307 | }; | ||||
| 308 | |||||
| 309 | static const struct token t_show_prefix[] = { | ||||
| 310 | { NOTOKEN, "", NONE, NULL((void *)0)}, | ||||
| 311 | { FLAG, "all", F_LONGER0x0200, NULL((void *)0)}, | ||||
| 312 | { FLAG, "longer-prefixes", F_LONGER0x0200, NULL((void *)0)}, | ||||
| 313 | { FLAG, "or-longer", F_LONGER0x0200, NULL((void *)0)}, | ||||
| 314 | { FLAG, "or-shorter", F_SHORTER0x0400, NULL((void *)0)}, | ||||
| 315 | { ENDTOKEN, "", NONE, NULL((void *)0)} | ||||
| 316 | }; | ||||
| 317 | |||||
| 318 | static const struct token t_show_ip[] = { | ||||
| 319 | { KEYWORD, "bgp", SHOW_RIB, t_show_rib}, | ||||
| 320 | { ENDTOKEN, "", NONE, NULL((void *)0)} | ||||
| 321 | }; | ||||
| 322 | |||||
| 323 | static const struct token t_show_community[] = { | ||||
| 324 | { COMMUNITY, "", NONE, t_show_rib}, | ||||
| 325 | { ENDTOKEN, "", NONE, NULL((void *)0)} | ||||
| 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((void *)0)} | ||||
| 344 | }; | ||||
| 345 | |||||
| 346 | static const struct token t_show_ext_subtype[] = { | ||||
| 347 | { EXTCOMMUNITY, "", NONE, t_show_rib}, | ||||
| 348 | { ENDTOKEN, "", NONE, NULL((void *)0)} | ||||
| 349 | }; | ||||
| 350 | |||||
| 351 | static const struct token t_show_largecommunity[] = { | ||||
| 352 | { LARGE_COMMUNITY, "", NONE, t_show_rib}, | ||||
| 353 | { ENDTOKEN, "", NONE, NULL((void *)0)} | ||||
| 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((void *)0)}, | ||||
| 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((void *)0)} | ||||
| 364 | }; | ||||
| 365 | |||||
| 366 | static const struct token t_prefix[] = { | ||||
| 367 | { PREFIX, "", NONE, t_set}, | ||||
| 368 | { ENDTOKEN, "", NONE, NULL((void *)0)} | ||||
| 369 | }; | ||||
| 370 | |||||
| 371 | static const struct token t_network_show[] = { | ||||
| 372 | { NOTOKEN, "", NONE, NULL((void *)0)}, | ||||
| 373 | { FAMILY, "", NONE, NULL((void *)0)}, | ||||
| 374 | { ENDTOKEN, "", NONE, NULL((void *)0)} | ||||
| 375 | }; | ||||
| 376 | |||||
| 377 | static const struct token t_rd[] = { | ||||
| 378 | { RD, "", NONE, t_set}, | ||||
| 379 | { ENDTOKEN, "", NONE, NULL((void *)0)} | ||||
| 380 | }; | ||||
| 381 | |||||
| 382 | static const struct token t_set[] = { | ||||
| 383 | { NOTOKEN, "", NONE, NULL((void *)0)}, | ||||
| 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((void *)0)}, | ||||
| 397 | { KEYWORD, "delete", NETWORK_BULK_REMOVE, NULL((void *)0)}, | ||||
| 398 | { ENDTOKEN, "", NONE, NULL((void *)0)} | ||||
| 399 | }; | ||||
| 400 | |||||
| 401 | static const struct token t_community[] = { | ||||
| 402 | { COMMUNITY, "", NONE, t_set}, | ||||
| 403 | { ENDTOKEN, "", NONE, NULL((void *)0)} | ||||
| 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((void *)0)} | ||||
| 422 | }; | ||||
| 423 | |||||
| 424 | static const struct token t_ext_subtype[] = { | ||||
| 425 | { EXTCOMMUNITY, "", NONE, t_set}, | ||||
| 426 | { ENDTOKEN, "", NONE, NULL((void *)0)} | ||||
| 427 | }; | ||||
| 428 | |||||
| 429 | static const struct token t_largecommunity[] = { | ||||
| 430 | { LARGE_COMMUNITY, "", NONE, t_set}, | ||||
| 431 | { ENDTOKEN, "", NONE, NULL((void *)0)} | ||||
| 432 | }; | ||||
| 433 | |||||
| 434 | static const struct token t_localpref[] = { | ||||
| 435 | { LOCALPREF, "", NONE, t_set}, | ||||
| 436 | { ENDTOKEN, "", NONE, NULL((void *)0)} | ||||
| 437 | }; | ||||
| 438 | |||||
| 439 | static const struct token t_med[] = { | ||||
| 440 | { MED, "", NONE, t_set}, | ||||
| 441 | { ENDTOKEN, "", NONE, NULL((void *)0)} | ||||
| 442 | }; | ||||
| 443 | |||||
| 444 | static const struct token t_nexthop[] = { | ||||
| 445 | { NEXTHOP, "", NONE, t_set}, | ||||
| 446 | { ENDTOKEN, "", NONE, NULL((void *)0)} | ||||
| 447 | }; | ||||
| 448 | |||||
| 449 | static const struct token t_pftable[] = { | ||||
| 450 | { PFTABLE, "", NONE, t_set}, | ||||
| 451 | { ENDTOKEN, "", NONE, NULL((void *)0)} | ||||
| 452 | }; | ||||
| 453 | |||||
| 454 | static const struct token t_prepnbr[] = { | ||||
| 455 | { PREPNBR, "", NONE, t_set}, | ||||
| 456 | { ENDTOKEN, "", NONE, NULL((void *)0)} | ||||
| 457 | }; | ||||
| 458 | |||||
| 459 | static const struct token t_prepself[] = { | ||||
| 460 | { PREPSELF, "", NONE, t_set}, | ||||
| 461 | { ENDTOKEN, "", NONE, NULL((void *)0)} | ||||
| 462 | }; | ||||
| 463 | |||||
| 464 | static const struct token t_weight[] = { | ||||
| 465 | { WEIGHT, "", NONE, t_set}, | ||||
| 466 | { ENDTOKEN, "", NONE, NULL((void *)0)} | ||||
| 467 | }; | ||||
| 468 | |||||
| 469 | static const struct token t_log[] = { | ||||
| 470 | { KEYWORD, "verbose", LOG_VERBOSE, NULL((void *)0)}, | ||||
| 471 | { KEYWORD, "brief", LOG_BRIEF, NULL((void *)0)}, | ||||
| 472 | { ENDTOKEN, "", NONE, NULL((void *)0)} | ||||
| 473 | }; | ||||
| 474 | |||||
| 475 | static const struct token t_fib_table[] = { | ||||
| 476 | { RTABLE, "", NONE, t_fib}, | ||||
| 477 | { ENDTOKEN, "", NONE, NULL((void *)0)} | ||||
| 478 | }; | ||||
| 479 | |||||
| 480 | static const struct token t_show_fib_table[] = { | ||||
| 481 | { RTABLE, "", NONE, t_show_fib}, | ||||
| 482 | { ENDTOKEN, "", NONE, NULL((void *)0)} | ||||
| 483 | }; | ||||
| 484 | |||||
| 485 | static const struct token t_show_rib_path[] = { | ||||
| 486 | { PATHID, "", NONE, t_show_rib}, | ||||
| 487 | { ENDTOKEN, "", NONE, NULL((void *)0)} | ||||
| 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)do { (&res.set)->tqh_first = ((void *)0); (&res.set )->tqh_last = &(&res.set)->tqh_first; } while ( 0); | ||||
| 512 | |||||
| 513 | while (argc >= 0) { | ||||
| 514 | if ((match = match_token(&argc, &argv, table)) == NULL((void *)0)) { | ||||
| 515 | fprintf(stderr(&__sF[2]), "valid commands/args:\n"); | ||||
| 516 | show_valid_args(table); | ||||
| 517 | return (NULL((void *)0)); | ||||
| 518 | } | ||||
| 519 | |||||
| 520 | argc--; | ||||
| 521 | argv++; | ||||
| 522 | |||||
| 523 | if (match->type == NOTOKEN || match->next == NULL((void *)0)) | ||||
| 524 | break; | ||||
| 525 | |||||
| 526 | table = match->next; | ||||
| 527 | } | ||||
| 528 | |||||
| 529 | if (argc > 0) { | ||||
| 530 | fprintf(stderr(&__sF[2]), "superfluous argument: %s\n", argv[0]); | ||||
| 531 | return (NULL((void *)0)); | ||||
| 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((void *)0); | ||||
| 542 | struct filter_set *fs; | ||||
| 543 | const char *word = *argv[0]; | ||||
| 544 | size_t wordlen = 0; | ||||
| 545 | |||||
| 546 | match = 0; | ||||
| 547 | if (word != NULL((void *)0)) | ||||
| |||||
| 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((void *)0) || wordlen == 0) { | ||||
| 553 | match++; | ||||
| 554 | t = &table[i]; | ||||
| 555 | } | ||||
| 556 | break; | ||||
| 557 | case KEYWORD: | ||||
| 558 | if (word != NULL((void *)0) && 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((void *)0) && 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((void *)0)) | ||||
| 576 | break; | ||||
| 577 | if (!strcmp(word, "inet") || | ||||
| 578 | !strcasecmp(word, "IPv4")) { | ||||
| 579 | match++; | ||||
| 580 | t = &table[i]; | ||||
| 581 | res.aid = AID_INET1; | ||||
| 582 | } | ||||
| 583 | if (!strcmp(word, "inet6") || | ||||
| 584 | !strcasecmp(word, "IPv6")) { | ||||
| 585 | match++; | ||||
| 586 | t = &table[i]; | ||||
| 587 | res.aid = AID_INET62; | ||||
| 588 | } | ||||
| 589 | if (!strcasecmp(word, "VPNv4")) { | ||||
| 590 | match++; | ||||
| 591 | t = &table[i]; | ||||
| 592 | res.aid = AID_VPN_IPv43; | ||||
| 593 | } | ||||
| 594 | if (!strcasecmp(word, "VPNv6")) { | ||||
| 595 | match++; | ||||
| 596 | t = &table[i]; | ||||
| 597 | res.aid = AID_VPN_IPv64; | ||||
| 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((void *)0) && 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((void *)0) && 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((void *)0) && 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((void *)0) && 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((void *)0) && wordlen > 0) { | ||||
| 669 | int type = COMMUNITY_TYPE_BASIC8; | ||||
| 670 | char *p = strdup(word); | ||||
| 671 | |||||
| 672 | if (p == NULL((void *)0)) | ||||
| 673 | err(1, NULL((void *)0)); | ||||
| 674 | if (table[i].type == LARGE_COMMUNITY) | ||||
| 675 | type = COMMUNITY_TYPE_LARGE32; | ||||
| 676 | parsecommunity(&res.community, type, p); | ||||
| 677 | free(p); | ||||
| 678 | |||||
| 679 | if ((fs = calloc(1, sizeof(*fs))) == NULL((void *)0)) | ||||
| 680 | err(1, NULL((void *)0)); | ||||
| 681 | fs->type = ACTION_SET_COMMUNITY; | ||||
| 682 | fs->action.community = res.community; | ||||
| 683 | TAILQ_INSERT_TAIL(&res.set, fs, entry)do { (fs)->entry.tqe_next = ((void *)0); (fs)->entry.tqe_prev = (&res.set)->tqh_last; *(&res.set)->tqh_last = (fs); (&res.set)->tqh_last = &(fs)->entry.tqe_next ; } while (0); | ||||
| 684 | |||||
| 685 | match++; | ||||
| 686 | t = &table[i]; | ||||
| 687 | } | ||||
| 688 | break; | ||||
| 689 | case EXTCOM_SUBTYPE: | ||||
| 690 | if (word != NULL((void *)0) && 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((void *)0) && wordlen > 0) { | ||||
| 699 | char *p = strdup(word); | ||||
| 700 | |||||
| 701 | if (p == NULL((void *)0)) | ||||
| 702 | err(1, NULL((void *)0)); | ||||
| 703 | parseextcommunity(&res.community, | ||||
| 704 | res.ext_comm_subtype, p); | ||||
| 705 | free(p); | ||||
| 706 | |||||
| 707 | if ((fs = calloc(1, sizeof(*fs))) == NULL((void *)0)) | ||||
| 708 | err(1, NULL((void *)0)); | ||||
| 709 | fs->type = ACTION_SET_COMMUNITY; | ||||
| 710 | fs->action.community = res.community; | ||||
| 711 | TAILQ_INSERT_TAIL(&res.set, fs, entry)do { (fs)->entry.tqe_next = ((void *)0); (fs)->entry.tqe_prev = (&res.set)->tqh_last; *(&res.set)->tqh_last = (fs); (&res.set)->tqh_last = &(fs)->entry.tqe_next ; } while (0); | ||||
| 712 | |||||
| 713 | match++; | ||||
| 714 | t = &table[i]; | ||||
| 715 | } | ||||
| 716 | break; | ||||
| 717 | case RD: | ||||
| 718 | if (word
| ||||
| 719 | char *p = strdup(word); | ||||
| 720 | struct community ext; | ||||
| 721 | u_int64_t rd; | ||||
| 722 | |||||
| 723 | if (p == NULL((void *)0)) | ||||
| 724 | err(1, NULL((void *)0)); | ||||
| 725 | parseextcommunity(&ext, "rt", p); | ||||
| 726 | free(p); | ||||
| 727 | |||||
| 728 | switch (ext.data3 >> 8) { | ||||
| 729 | case EXT_COMMUNITY_TRANS_TWO_AS0x00: | ||||
| 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_IPV40x01: | ||||
| 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_AS0x02: | ||||
| 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)(__uint64_t)(__builtin_constant_p(rd) ? (__uint64_t)((((__uint64_t )(rd) & 0xff) << 56) | ((__uint64_t)(rd) & 0xff00ULL ) << 40 | ((__uint64_t)(rd) & 0xff0000ULL) << 24 | ((__uint64_t)(rd) & 0xff000000ULL) << 8 | ((__uint64_t )(rd) & 0xff00000000ULL) >> 8 | ((__uint64_t)(rd) & 0xff0000000000ULL) >> 24 | ((__uint64_t)(rd) & 0xff000000000000ULL ) >> 40 | ((__uint64_t)(rd) & 0xff00000000000000ULL ) >> 56) : __swap64md(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((void *)0) && 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((void *)0) && wordlen > 0 && | ||||
| 768 | parse_nexthop(word, &res)) { | ||||
| 769 | match++; | ||||
| 770 | t = &table[i]; | ||||
| 771 | } | ||||
| 772 | break; | ||||
| 773 | case PFTABLE: | ||||
| 774 | if (word != NULL((void *)0) && wordlen > 0) { | ||||
| 775 | if ((fs = calloc(1, | ||||
| 776 | sizeof(struct filter_set))) == NULL((void *)0)) | ||||
| 777 | err(1, NULL((void *)0)); | ||||
| 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)do { (fs)->entry.tqe_next = ((void *)0); (fs)->entry.tqe_prev = (&res.set)->tqh_last; *(&res.set)->tqh_last = (fs); (&res.set)->tqh_last = &(fs)->entry.tqe_next ; } while (0); | ||||
| 783 | match++; | ||||
| 784 | t = &table[i]; | ||||
| 785 | } | ||||
| 786 | break; | ||||
| 787 | case FILENAME: | ||||
| 788 | if (word != NULL((void *)0) && wordlen > 0) { | ||||
| 789 | if ((res.mrtfd = open(word, O_RDONLY0x0000)) == -1) { | ||||
| 790 | /* | ||||
| 791 | * ignore error if path has no / and | ||||
| 792 | * does not exist. In hope to print | ||||
| 793 | * usage. | ||||
| 794 | */ | ||||
| 795 | if (errno(*__errno()) == ENOENT2 && | ||||
| 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((void *)0)) | ||||
| 811 | fprintf(stderr(&__sF[2]), "missing argument:\n"); | ||||
| 812 | else if (match > 1) | ||||
| 813 | fprintf(stderr(&__sF[2]), "ambiguous argument: %s\n", word); | ||||
| 814 | else if (match < 1) | ||||
| 815 | fprintf(stderr(&__sF[2]), "unknown argument: %s\n", word); | ||||
| 816 | return (NULL((void *)0)); | ||||
| 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(&__sF[2]), " <cr>\n"); | ||||
| 831 | break; | ||||
| 832 | case KEYWORD: | ||||
| 833 | case FLAG: | ||||
| 834 | case ASTYPE: | ||||
| 835 | case EXTCOM_SUBTYPE: | ||||
| 836 | fprintf(stderr(&__sF[2]), " %s\n", table[i].keyword); | ||||
| 837 | break; | ||||
| 838 | case ADDRESS: | ||||
| 839 | case PEERADDRESS: | ||||
| 840 | fprintf(stderr(&__sF[2]), " <address>\n"); | ||||
| 841 | break; | ||||
| 842 | case PREFIX: | ||||
| 843 | fprintf(stderr(&__sF[2]), " <address>[/<len>]\n"); | ||||
| 844 | break; | ||||
| 845 | case ASNUM: | ||||
| 846 | fprintf(stderr(&__sF[2]), " <asnum>\n"); | ||||
| 847 | break; | ||||
| 848 | case GROUPDESC: | ||||
| 849 | case PEERDESC: | ||||
| 850 | fprintf(stderr(&__sF[2]), " <neighbor description>\n"); | ||||
| 851 | break; | ||||
| 852 | case RIBNAME: | ||||
| 853 | fprintf(stderr(&__sF[2]), " <rib name>\n"); | ||||
| 854 | break; | ||||
| 855 | case COMMUNICATION: | ||||
| 856 | fprintf(stderr(&__sF[2]), " <reason>\n"); | ||||
| 857 | break; | ||||
| 858 | case COMMUNITY: | ||||
| 859 | fprintf(stderr(&__sF[2]), " <community>\n"); | ||||
| 860 | break; | ||||
| 861 | case LARGE_COMMUNITY: | ||||
| 862 | fprintf(stderr(&__sF[2]), " <large-community>\n"); | ||||
| 863 | break; | ||||
| 864 | case EXTCOMMUNITY: | ||||
| 865 | fprintf(stderr(&__sF[2]), " <extended-community>\n"); | ||||
| 866 | break; | ||||
| 867 | case RD: | ||||
| 868 | fprintf(stderr(&__sF[2]), " <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(&__sF[2]), " <number>\n"); | ||||
| 877 | break; | ||||
| 878 | case RTABLE: | ||||
| 879 | fprintf(stderr(&__sF[2]), " <rtableid>\n"); | ||||
| 880 | break; | ||||
| 881 | case NEXTHOP: | ||||
| 882 | fprintf(stderr(&__sF[2]), " <address>\n"); | ||||
| 883 | break; | ||||
| 884 | case PFTABLE: | ||||
| 885 | fprintf(stderr(&__sF[2]), " <pftable>\n"); | ||||
| 886 | break; | ||||
| 887 | case FAMILY: | ||||
| 888 | fprintf(stderr(&__sF[2]), " [ inet | inet6 | IPv4 | IPv6 | " | ||||
| 889 | "VPNv4 | VPNv6 ]\n"); | ||||
| 890 | break; | ||||
| 891 | case FILENAME: | ||||
| 892 | fprintf(stderr(&__sF[2]), " <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((void *)0)) | ||||
| 907 | return (0); | ||||
| 908 | |||||
| 909 | bzero(addr, sizeof(struct bgpd_addr)); | ||||
| 910 | bzero(&ina, sizeof(ina)); | ||||
| 911 | |||||
| 912 | if (inet_net_pton(AF_INET2, word, &ina, sizeof(ina)) != -1) { | ||||
| 913 | addr->aid = AID_INET1; | ||||
| 914 | addr->v4ba.v4 = ina; | ||||
| 915 | return (1); | ||||
| 916 | } | ||||
| 917 | |||||
| 918 | bzero(&hints, sizeof(hints)); | ||||
| 919 | hints.ai_family = AF_INET624; | ||||
| 920 | hints.ai_socktype = SOCK_DGRAM2; /*dummy*/ | ||||
| 921 | hints.ai_flags = AI_NUMERICHOST4; | ||||
| 922 | if (getaddrinfo(word, "0", &hints, &r) == 0) { | ||||
| 923 | sa2addr(r->ai_addr, addr, NULL((void *)0)); | ||||
| 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((void *)0)) | ||||
| 939 | return (0); | ||||
| 940 | |||||
| 941 | bzero(addr, sizeof(struct bgpd_addr)); | ||||
| 942 | |||||
| 943 | if ((p = strrchr(word, '/')) != NULL((void *)0)) { | ||||
| 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((void *)0)) | ||||
| 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_INET1: | ||||
| 965 | if (mask == -1) | ||||
| 966 | mask = 32; | ||||
| 967 | if (mask > 32) | ||||
| 968 | errx(1, "invalid netmask: too large"); | ||||
| 969 | addr->v4ba.v4.s_addr = addr->v4ba.v4.s_addr & htonl(prefixlen2mask(mask))(__uint32_t)(__builtin_constant_p(prefixlen2mask(mask)) ? (__uint32_t )(((__uint32_t)(prefixlen2mask(mask)) & 0xff) << 24 | ((__uint32_t)(prefixlen2mask(mask)) & 0xff00) << 8 | ((__uint32_t)(prefixlen2mask(mask)) & 0xff0000) >> 8 | ((__uint32_t)(prefixlen2mask(mask)) & 0xff000000) >> 24) : __swap32md(prefixlen2mask(mask))); | ||||
| 970 | break; | ||||
| 971 | case AID_INET62: | ||||
| 972 | if (mask == -1) | ||||
| 973 | mask = 128; | ||||
| 974 | inet6applymask(&addr->v6ba.v6, &addr->v6ba.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((void *)0)) | ||||
| 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((void *)0)) { | ||||
| 999 | *dot++ = '\0'; | ||||
| 1000 | uvalh = strtonum(parseword, 0, USHRT_MAX(32767 *2 +1), &errstr); | ||||
| 1001 | if (errstr) | ||||
| 1002 | errx(1, "AS number is %s: %s", errstr, word); | ||||
| 1003 | uval = strtonum(dot, 0, USHRT_MAX(32767 *2 +1), &errstr); | ||||
| 1004 | if (errstr) | ||||
| 1005 | errx(1, "AS number is %s: %s", errstr, word); | ||||
| 1006 | } else { | ||||
| 1007 | uval = strtonum(parseword, 0, UINT_MAX(2147483647 *2U +1U), &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((void *)0)) | ||||
| 1025 | return (0); | ||||
| 1026 | |||||
| 1027 | uval = strtonum(word, 0, UINT_MAX(2147483647 *2U +1U), &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_PATHID0x800000; | ||||
| 1039 | return (1); | ||||
| 1040 | default: | ||||
| 1041 | break; | ||||
| 1042 | } | ||||
| 1043 | |||||
| 1044 | if ((fs = calloc(1, sizeof(struct filter_set))) == NULL((void *)0)) | ||||
| 1045 | err(1, NULL((void *)0)); | ||||
| 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)do { (fs)->entry.tqe_next = ((void *)0); (fs)->entry.tqe_prev = (&r->set)->tqh_last; *(&r->set)->tqh_last = (fs); (&r->set)->tqh_last = &(fs)->entry. tqe_next; } while (0); | ||||
| 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(32767 *2 +1); | ||||
| 1087 | const char *errstr; | ||||
| 1088 | |||||
| 1089 | *flag = 0; | ||||
| 1090 | *val = 0; | ||||
| 1091 | if (strcmp(s, "*") == 0) { | ||||
| 1092 | *flag = COMMUNITY_ANY1; | ||||
| 1093 | return; | ||||
| 1094 | } else if (strcmp(s, "neighbor-as") == 0) { | ||||
| 1095 | *flag = COMMUNITY_NEIGHBOR_AS2; | ||||
| 1096 | return; | ||||
| 1097 | } else if (strcmp(s, "local-as") == 0) { | ||||
| 1098 | *flag = COMMUNITY_LOCAL_AS3; | ||||
| 1099 | return; | ||||
| 1100 | } | ||||
| 1101 | if (large) | ||||
| 1102 | max = UINT_MAX(2147483647 *2U +1U); | ||||
| 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_BASIC8; | ||||
| 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((void *)0)) | ||||
| 1127 | errx(1, "Bad community syntax"); | ||||
| 1128 | *p++ = 0; | ||||
| 1129 | |||||
| 1130 | if ((q = strchr(p, ':')) == NULL((void *)0)) | ||||
| 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_LARGE32; | ||||
| 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_LARGE32) { | ||||
| 1151 | parselargecommunity(c, s); | ||||
| 1152 | return; | ||||
| 1153 | } | ||||
| 1154 | |||||
| 1155 | /* Well-known communities */ | ||||
| 1156 | if (strcasecmp(s, "GRACEFUL_SHUTDOWN") == 0) { | ||||
| 1157 | setcommunity(c, COMMUNITY_WELLKNOWN0xffff, | ||||
| 1158 | COMMUNITY_GRACEFUL_SHUTDOWN0x0000, 0, 0); | ||||
| 1159 | return; | ||||
| 1160 | } else if (strcasecmp(s, "NO_EXPORT") == 0) { | ||||
| 1161 | setcommunity(c, COMMUNITY_WELLKNOWN0xffff, | ||||
| 1162 | COMMUNITY_NO_EXPORT0xff01, 0, 0); | ||||
| 1163 | return; | ||||
| 1164 | } else if (strcasecmp(s, "NO_ADVERTISE") == 0) { | ||||
| 1165 | setcommunity(c, COMMUNITY_WELLKNOWN0xffff, | ||||
| 1166 | COMMUNITY_NO_ADVERTISE0xff02, 0, 0); | ||||
| 1167 | return; | ||||
| 1168 | } else if (strcasecmp(s, "NO_EXPORT_SUBCONFED") == 0) { | ||||
| 1169 | setcommunity(c, COMMUNITY_WELLKNOWN0xffff, | ||||
| 1170 | COMMUNITY_NO_EXPSUBCONFED0xff03, 0, 0); | ||||
| 1171 | return; | ||||
| 1172 | } else if (strcasecmp(s, "NO_PEER") == 0) { | ||||
| 1173 | setcommunity(c, COMMUNITY_WELLKNOWN0xffff, | ||||
| 1174 | COMMUNITY_NO_PEER0xff04, 0, 0); | ||||
| 1175 | return; | ||||
| 1176 | } else if (strcasecmp(s, "BLACKHOLE") == 0) { | ||||
| 1177 | setcommunity(c, COMMUNITY_WELLKNOWN0xffff, | ||||
| 1178 | COMMUNITY_BLACKHOLE0x029A, 0, 0); | ||||
| 1179 | return; | ||||
| 1180 | } | ||||
| 1181 | |||||
| 1182 | if ((p = strchr(s, ':')) == NULL((void *)0)) | ||||
| 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((void *)0); 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_AS2; | ||||
| 1223 | *v = 0; | ||||
| 1224 | return EXT_COMMUNITY_TRANS_FOUR_AS0x02; | ||||
| 1225 | } else if (strcmp(s, "local-as") == 0) { | ||||
| 1226 | *flag = COMMUNITY_LOCAL_AS3; | ||||
| 1227 | *v = 0; | ||||
| 1228 | return EXT_COMMUNITY_TRANS_FOUR_AS0x02; | ||||
| 1229 | } else if ((p = strchr(s, '.')) == NULL((void *)0)) { | ||||
| 1230 | /* AS_PLAIN number (4 or 2 byte) */ | ||||
| 1231 | strtonum(s, 0, USHRT_MAX(32767 *2 +1), &errstr); | ||||
| 1232 | if (errstr == NULL((void *)0)) | ||||
| 1233 | type = EXT_COMMUNITY_TRANS_TWO_AS0x00; | ||||
| 1234 | else | ||||
| 1235 | type = EXT_COMMUNITY_TRANS_FOUR_AS0x02; | ||||
| 1236 | } else if (strchr(p + 1, '.') == NULL((void *)0)) { | ||||
| 1237 | /* AS_DOT number (4-byte) */ | ||||
| 1238 | type = EXT_COMMUNITY_TRANS_FOUR_AS0x02; | ||||
| 1239 | } else { | ||||
| 1240 | /* more than one dot -> IP address */ | ||||
| 1241 | type = EXT_COMMUNITY_TRANS_IPV40x01; | ||||
| 1242 | } | ||||
| 1243 | |||||
| 1244 | switch (type) { | ||||
| 1245 | case EXT_COMMUNITY_TRANS_TWO_AS0x00: | ||||
| 1246 | uval = strtonum(s, 0, USHRT_MAX(32767 *2 +1), &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_AS0x02: | ||||
| 1252 | if ((p = strchr(s, '.')) == NULL((void *)0)) { | ||||
| 1253 | uval = strtonum(s, 0, UINT_MAX(2147483647 *2U +1U), &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(32767 *2 +1), &errstr); | ||||
| 1262 | if (errstr) | ||||
| 1263 | errx(1, "Bad ext-community %s is %s", s, errstr); | ||||
| 1264 | uval = strtonum(p, 0, USHRT_MAX(32767 *2 +1), &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_IPV40x01: | ||||
| 1270 | if (inet_aton(s, &ip) == 0) | ||||
| 1271 | errx(1, "Bad ext-community %s not parseable", s); | ||||
| 1272 | *v = ntohl(ip.s_addr)(__uint32_t)(__builtin_constant_p(ip.s_addr) ? (__uint32_t)(( (__uint32_t)(ip.s_addr) & 0xff) << 24 | ((__uint32_t )(ip.s_addr) & 0xff00) << 8 | ((__uint32_t)(ip.s_addr ) & 0xff0000) >> 8 | ((__uint32_t)(ip.s_addr) & 0xff000000) >> 24) : __swap32md(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_EXT16; | ||||
| 1291 | c->flags |= COMMUNITY_ANY1 << 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_AS0x00: | ||||
| 1299 | case EXT_COMMUNITY_TRANS_FOUR_AS0x02: | ||||
| 1300 | case EXT_COMMUNITY_TRANS_IPV40x01: | ||||
| 1301 | case -1: | ||||
| 1302 | if (strcmp(s, "*") == 0) { | ||||
| 1303 | dflag1 = COMMUNITY_ANY1; | ||||
| 1304 | break; | ||||
| 1305 | } | ||||
| 1306 | if ((p = strchr(s, ':')) == NULL((void *)0)) | ||||
| 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_AS0x00: | ||||
| 1313 | getcommunity(p, 1, &uval2, &dflag2); | ||||
| 1314 | break; | ||||
| 1315 | case EXT_COMMUNITY_TRANS_IPV40x01: | ||||
| 1316 | case EXT_COMMUNITY_TRANS_FOUR_AS0x02: | ||||
| 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_OPAQUE0x03: | ||||
| 1327 | case EXT_COMMUNITY_TRANS_EVPN0x06: | ||||
| 1328 | if (strcmp(s, "*") == 0) { | ||||
| 1329 | dflag1 = COMMUNITY_ANY1; | ||||
| 1330 | break; | ||||
| 1331 | } | ||||
| 1332 | errno(*__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(*__errno()) == ERANGE34 && ullval > EXT_COMMUNITY_OPAQUE_MAX0xffffffffffffULL) | ||||
| 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_OPAQUE0x43: | ||||
| 1342 | if (subtype == EXT_COMMUNITY_SUBTYPE_OVS0) { | ||||
| 1343 | if (strcmp(s, "valid") == 0) { | ||||
| 1344 | c->data2 = EXT_COMMUNITY_OVS_VALID0; | ||||
| 1345 | break; | ||||
| 1346 | } else if (strcmp(s, "invalid") == 0) { | ||||
| 1347 | c->data2 = EXT_COMMUNITY_OVS_INVALID2; | ||||
| 1348 | break; | ||||
| 1349 | } else if (strcmp(s, "not-found") == 0) { | ||||
| 1350 | c->data2 = EXT_COMMUNITY_OVS_NOTFOUND1; | ||||
| 1351 | break; | ||||
| 1352 | } else if (strcmp(s, "*") == 0) { | ||||
| 1353 | dflag1 = COMMUNITY_ANY1; | ||||
| 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
| ||||
| 1364 | c->flags = COMMUNITY_TYPE_EXT16; | ||||
| 1365 | c->flags |= dflag1 << 8; | ||||
| 1366 | return; | ||||
| 1367 | } | ||||
| 1368 | |||||
| 1369 | /* verify type/subtype combo */ | ||||
| 1370 | for (cp = iana_ext_comms; cp->subname
| ||||
| 1371 | if (cp->type == type
| ||||
| 1372 | c->flags = COMMUNITY_TYPE_EXT16; | ||||
| 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((void *)0)) | ||||
| 1388 | err(1, NULL((void *)0)); | ||||
| 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)do { (fs)->entry.tqe_next = ((void *)0); (fs)->entry.tqe_prev = (&r->set)->tqh_last; *(&r->set)->tqh_last = (fs); (&r->set)->tqh_last = &(fs)->entry. tqe_next; } while (0); | ||||
| 1404 | return (1); | ||||
| 1405 | } |