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 | } |