| File: | src/usr.sbin/bgpctl/parser.c |
| Warning: | line 1360, column 18 The result of the left shift is undefined because the left operand is negative |
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
| |||
| 1200 | *type = cp->type; | |||
| 1201 | *subtype = cp->subtype; | |||
| 1202 | } | |||
| 1203 | found++; | |||
| 1204 | } | |||
| 1205 | } | |||
| 1206 | if (found
| |||
| 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 == COMMUNITY_ANY1 && type == -1) { | |||
| 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 != NULL((void *)0); cp++) { | |||
| 1371 | if (cp->type == type && cp->subtype == subtype) { | |||
| 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 | } |