]>
Commit | Line | Data |
---|---|---|
acddc0ed | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
dba3c1d3 PG |
2 | /* BGP FlowSpec VTY |
3 | * Copyright (C) 2018 6WIND | |
dba3c1d3 PG |
4 | */ |
5 | ||
6 | #include <zebra.h> | |
7 | #include "command.h" | |
8 | ||
9 | #include "bgpd/bgpd.h" | |
10 | #include "bgpd/bgp_table.h" | |
11 | #include "bgpd/bgp_attr.h" | |
12 | #include "bgpd/bgp_ecommunity.h" | |
13 | #include "bgpd/bgp_vty.h" | |
14 | #include "bgpd/bgp_route.h" | |
15 | #include "bgpd/bgp_aspath.h" | |
16 | #include "bgpd/bgp_flowspec.h" | |
17 | #include "bgpd/bgp_flowspec_util.h" | |
18 | #include "bgpd/bgp_flowspec_private.h" | |
268e1b9b | 19 | #include "bgpd/bgp_debug.h" |
b588b642 | 20 | #include "bgpd/bgp_pbr.h" |
dba3c1d3 PG |
21 | |
22 | /* Local Structures and variables declarations | |
23 | * This code block hosts the struct declared that host the flowspec rules | |
24 | * as well as some structure used to convert to stringx | |
25 | */ | |
26 | ||
27 | static const struct message bgp_flowspec_display_large[] = { | |
28 | {FLOWSPEC_DEST_PREFIX, "Destination Address"}, | |
29 | {FLOWSPEC_SRC_PREFIX, "Source Address"}, | |
30 | {FLOWSPEC_IP_PROTOCOL, "IP Protocol"}, | |
31 | {FLOWSPEC_PORT, "Port"}, | |
32 | {FLOWSPEC_DEST_PORT, "Destination Port"}, | |
33 | {FLOWSPEC_SRC_PORT, "Source Port"}, | |
34 | {FLOWSPEC_ICMP_TYPE, "ICMP Type"}, | |
35 | {FLOWSPEC_ICMP_CODE, "ICMP Code"}, | |
36 | {FLOWSPEC_TCP_FLAGS, "TCP Flags"}, | |
37 | {FLOWSPEC_PKT_LEN, "Packet Length"}, | |
38 | {FLOWSPEC_DSCP, "DSCP field"}, | |
39 | {FLOWSPEC_FRAGMENT, "Packet Fragment"}, | |
40881800 | 40 | {FLOWSPEC_FLOW_LABEL, "Packet Flow Label"}, |
dba3c1d3 PG |
41 | {0} |
42 | }; | |
43 | ||
44 | static const struct message bgp_flowspec_display_min[] = { | |
45 | {FLOWSPEC_DEST_PREFIX, "to"}, | |
46 | {FLOWSPEC_SRC_PREFIX, "from"}, | |
47 | {FLOWSPEC_IP_PROTOCOL, "proto"}, | |
48 | {FLOWSPEC_PORT, "port"}, | |
49 | {FLOWSPEC_DEST_PORT, "dstp"}, | |
50 | {FLOWSPEC_SRC_PORT, "srcp"}, | |
51 | {FLOWSPEC_ICMP_TYPE, "type"}, | |
52 | {FLOWSPEC_ICMP_CODE, "code"}, | |
01ffd28b | 53 | {FLOWSPEC_TCP_FLAGS, "tcp"}, |
dba3c1d3 PG |
54 | {FLOWSPEC_PKT_LEN, "pktlen"}, |
55 | {FLOWSPEC_DSCP, "dscp"}, | |
56 | {FLOWSPEC_FRAGMENT, "pktfrag"}, | |
40881800 | 57 | {FLOWSPEC_FLOW_LABEL, "flwlbl"}, |
dba3c1d3 PG |
58 | {0} |
59 | }; | |
60 | ||
362a06e3 PG |
61 | #define FS_STRING_UPDATE(count, ptr, format, remaining_len) do { \ |
62 | int _len_written; \ | |
63 | \ | |
64 | if (((format) == NLRI_STRING_FORMAT_DEBUG) && (count)) {\ | |
65 | _len_written = snprintf((ptr), (remaining_len), \ | |
66 | ", "); \ | |
67 | (remaining_len) -= _len_written; \ | |
68 | (ptr) += _len_written; \ | |
69 | } else if (((format) == NLRI_STRING_FORMAT_MIN) \ | |
70 | && (count)) { \ | |
71 | _len_written = snprintf((ptr), (remaining_len), \ | |
72 | " "); \ | |
73 | (remaining_len) -= _len_written; \ | |
74 | (ptr) += _len_written; \ | |
75 | } \ | |
76 | count++; \ | |
dba3c1d3 PG |
77 | } while (0) |
78 | ||
362a06e3 PG |
79 | /* Parse FLOWSPEC NLRI |
80 | * passed return_string string has assumed length | |
81 | * BGP_FLOWSPEC_STRING_DISPLAY_MAX | |
82 | */ | |
dba3c1d3 | 83 | void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len, |
d33fc23b | 84 | char *return_string, int format, |
1840384b PG |
85 | json_object *json_path, |
86 | afi_t afi) | |
dba3c1d3 PG |
87 | { |
88 | uint32_t offset = 0; | |
89 | int type; | |
90 | int ret = 0, error = 0; | |
91 | char *ptr = return_string; | |
92 | char local_string[BGP_FLOWSPEC_STRING_DISPLAY_MAX]; | |
93 | int count = 0; | |
94 | char extra[2] = ""; | |
95 | char pre_extra[2] = ""; | |
96 | const struct message *bgp_flowspec_display; | |
d33fc23b | 97 | enum bgp_flowspec_util_nlri_t type_util; |
362a06e3 PG |
98 | int len_string = BGP_FLOWSPEC_STRING_DISPLAY_MAX; |
99 | int len_written; | |
dba3c1d3 PG |
100 | |
101 | if (format == NLRI_STRING_FORMAT_LARGE) { | |
102 | snprintf(pre_extra, sizeof(pre_extra), "\t"); | |
103 | snprintf(extra, sizeof(extra), "\n"); | |
104 | bgp_flowspec_display = bgp_flowspec_display_large; | |
105 | } else | |
106 | bgp_flowspec_display = bgp_flowspec_display_min; | |
d33fc23b PG |
107 | /* if needed. type_util can be set to other values */ |
108 | type_util = BGP_FLOWSPEC_RETURN_STRING; | |
dba3c1d3 PG |
109 | error = 0; |
110 | while (offset < len-1 && error >= 0) { | |
111 | type = nlri_content[offset]; | |
112 | offset++; | |
113 | switch (type) { | |
114 | case FLOWSPEC_DEST_PREFIX: | |
115 | case FLOWSPEC_SRC_PREFIX: | |
116 | ret = bgp_flowspec_ip_address( | |
d33fc23b | 117 | type_util, |
dba3c1d3 PG |
118 | nlri_content+offset, |
119 | len - offset, | |
1840384b | 120 | local_string, &error, |
9cec4121 | 121 | afi, NULL); |
dba3c1d3 PG |
122 | if (ret <= 0) |
123 | break; | |
d33fc23b PG |
124 | if (json_path) { |
125 | json_object_string_add(json_path, | |
126 | lookup_msg(bgp_flowspec_display, type, ""), | |
127 | local_string); | |
128 | break; | |
129 | } | |
362a06e3 PG |
130 | FS_STRING_UPDATE(count, ptr, format, len_string); |
131 | len_written = snprintf(ptr, len_string, "%s%s %s%s", | |
132 | pre_extra, | |
133 | lookup_msg(bgp_flowspec_display, | |
134 | type, ""), | |
135 | local_string, extra); | |
136 | len_string -= len_written; | |
137 | ptr += len_written; | |
dba3c1d3 | 138 | break; |
40881800 | 139 | case FLOWSPEC_FLOW_LABEL: |
dba3c1d3 PG |
140 | case FLOWSPEC_IP_PROTOCOL: |
141 | case FLOWSPEC_PORT: | |
142 | case FLOWSPEC_DEST_PORT: | |
143 | case FLOWSPEC_SRC_PORT: | |
144 | case FLOWSPEC_ICMP_TYPE: | |
145 | case FLOWSPEC_ICMP_CODE: | |
d33fc23b | 146 | ret = bgp_flowspec_op_decode(type_util, |
dba3c1d3 PG |
147 | nlri_content+offset, |
148 | len - offset, | |
149 | local_string, &error); | |
150 | if (ret <= 0) | |
151 | break; | |
d33fc23b PG |
152 | if (json_path) { |
153 | json_object_string_add(json_path, | |
154 | lookup_msg(bgp_flowspec_display, type, ""), | |
155 | local_string); | |
156 | break; | |
157 | } | |
362a06e3 PG |
158 | FS_STRING_UPDATE(count, ptr, format, len_string); |
159 | len_written = snprintf(ptr, len_string, "%s%s %s%s", | |
160 | pre_extra, | |
161 | lookup_msg(bgp_flowspec_display, | |
162 | type, ""), | |
dba3c1d3 | 163 | local_string, extra); |
362a06e3 PG |
164 | len_string -= len_written; |
165 | ptr += len_written; | |
dba3c1d3 PG |
166 | break; |
167 | case FLOWSPEC_TCP_FLAGS: | |
588ec356 | 168 | ret = bgp_flowspec_bitmask_decode( |
d33fc23b | 169 | type_util, |
dba3c1d3 PG |
170 | nlri_content+offset, |
171 | len - offset, | |
172 | local_string, &error); | |
173 | if (ret <= 0) | |
174 | break; | |
d33fc23b PG |
175 | if (json_path) { |
176 | json_object_string_add(json_path, | |
362a06e3 PG |
177 | lookup_msg(bgp_flowspec_display, |
178 | type, ""), | |
d33fc23b PG |
179 | local_string); |
180 | break; | |
181 | } | |
362a06e3 PG |
182 | FS_STRING_UPDATE(count, ptr, format, len_string); |
183 | len_written = snprintf(ptr, len_string, "%s%s %s%s", | |
184 | pre_extra, | |
185 | lookup_msg(bgp_flowspec_display, | |
186 | type, ""), | |
187 | local_string, extra); | |
188 | len_string -= len_written; | |
189 | ptr += len_written; | |
dba3c1d3 PG |
190 | break; |
191 | case FLOWSPEC_PKT_LEN: | |
192 | case FLOWSPEC_DSCP: | |
193 | ret = bgp_flowspec_op_decode( | |
d33fc23b | 194 | type_util, |
dba3c1d3 PG |
195 | nlri_content + offset, |
196 | len - offset, local_string, | |
197 | &error); | |
198 | if (ret <= 0) | |
199 | break; | |
d33fc23b PG |
200 | if (json_path) { |
201 | json_object_string_add(json_path, | |
202 | lookup_msg(bgp_flowspec_display, type, ""), | |
203 | local_string); | |
204 | break; | |
205 | } | |
362a06e3 PG |
206 | FS_STRING_UPDATE(count, ptr, format, len_string); |
207 | len_written = snprintf(ptr, len_string, "%s%s %s%s", | |
208 | pre_extra, | |
209 | lookup_msg(bgp_flowspec_display, | |
210 | type, ""), | |
dba3c1d3 | 211 | local_string, extra); |
362a06e3 PG |
212 | len_string -= len_written; |
213 | ptr += len_written; | |
dba3c1d3 PG |
214 | break; |
215 | case FLOWSPEC_FRAGMENT: | |
588ec356 PG |
216 | ret = bgp_flowspec_bitmask_decode( |
217 | type_util, | |
218 | nlri_content+offset, | |
219 | len - offset, | |
220 | local_string, &error); | |
dba3c1d3 PG |
221 | if (ret <= 0) |
222 | break; | |
d33fc23b PG |
223 | if (json_path) { |
224 | json_object_string_add(json_path, | |
225 | lookup_msg(bgp_flowspec_display, | |
226 | type, ""), | |
227 | local_string); | |
228 | break; | |
229 | } | |
362a06e3 PG |
230 | FS_STRING_UPDATE(count, ptr, format, len_string); |
231 | len_written = snprintf(ptr, len_string, "%s%s %s%s", | |
232 | pre_extra, | |
233 | lookup_msg(bgp_flowspec_display, | |
234 | type, ""), | |
235 | local_string, extra); | |
236 | len_string -= len_written; | |
237 | ptr += len_written; | |
dba3c1d3 PG |
238 | break; |
239 | default: | |
240 | error = -1; | |
241 | break; | |
242 | } | |
243 | offset += ret; | |
244 | } | |
245 | } | |
246 | ||
bd494ec5 | 247 | void route_vty_out_flowspec(struct vty *vty, const struct prefix *p, |
9b6d8fcf | 248 | struct bgp_path_info *path, int display, |
4b7e6066 | 249 | json_object *json_paths) |
dba3c1d3 PG |
250 | { |
251 | struct attr *attr; | |
252 | char return_string[BGP_FLOWSPEC_STRING_DISPLAY_MAX]; | |
c6423c31 | 253 | char *s1 = NULL, *s2 = NULL; |
d33fc23b PG |
254 | json_object *json_nlri_path = NULL; |
255 | json_object *json_ecom_path = NULL; | |
256 | json_object *json_time_path = NULL; | |
257 | char timebuf[BGP_UPTIME_LEN]; | |
7de5a4d9 | 258 | struct ecommunity *ipv6_ecomm = NULL; |
dba3c1d3 | 259 | |
c24ceb89 PG |
260 | if (p == NULL || p->family != AF_FLOWSPEC) |
261 | return; | |
262 | if (json_paths) { | |
263 | if (display == NLRI_STRING_FORMAT_JSON) | |
264 | json_nlri_path = json_object_new_object(); | |
265 | else | |
266 | json_nlri_path = json_paths; | |
dba3c1d3 | 267 | } |
c24ceb89 PG |
268 | if (display == NLRI_STRING_FORMAT_LARGE && path) |
269 | vty_out(vty, "BGP flowspec entry: (flags 0x%x)\n", | |
270 | path->flags); | |
271 | bgp_fs_nlri_get_string((unsigned char *) | |
272 | p->u.prefix_flowspec.ptr, | |
273 | p->u.prefix_flowspec.prefixlen, | |
274 | return_string, | |
275 | display, | |
276 | json_nlri_path, | |
277 | family2afi(p->u.prefix_flowspec | |
278 | .family)); | |
279 | if (display == NLRI_STRING_FORMAT_LARGE) | |
280 | vty_out(vty, "%s", return_string); | |
281 | else if (display == NLRI_STRING_FORMAT_DEBUG) | |
282 | vty_out(vty, "%s", return_string); | |
283 | else if (display == NLRI_STRING_FORMAT_MIN) | |
284 | vty_out(vty, " %-30s", return_string); | |
285 | else if (json_paths && display == NLRI_STRING_FORMAT_JSON) | |
286 | json_object_array_add(json_paths, json_nlri_path); | |
9b6d8fcf | 287 | if (!path) |
dba3c1d3 | 288 | return; |
d04ac434 | 289 | |
7de5a4d9 DA |
290 | if (path->attr) |
291 | ipv6_ecomm = bgp_attr_get_ipv6_ecommunity(path->attr); | |
292 | ||
b53e67a3 | 293 | if (path->attr && (bgp_attr_get_ecommunity(path->attr) || ipv6_ecomm)) { |
dba3c1d3 | 294 | /* Print attribute */ |
9b6d8fcf | 295 | attr = path->attr; |
b53e67a3 DA |
296 | if (bgp_attr_get_ecommunity(attr)) |
297 | s1 = ecommunity_ecom2str(bgp_attr_get_ecommunity(attr), | |
298 | ECOMMUNITY_FORMAT_ROUTE_MAP, | |
299 | 0); | |
d04ac434 DS |
300 | if (ipv6_ecomm) |
301 | s2 = ecommunity_ecom2str( | |
302 | ipv6_ecomm, ECOMMUNITY_FORMAT_ROUTE_MAP, 0); | |
c6423c31 | 303 | if (!s1 && !s2) |
dba3c1d3 PG |
304 | return; |
305 | if (display == NLRI_STRING_FORMAT_LARGE) | |
c6423c31 PG |
306 | vty_out(vty, "\t%s%s%s\n", s1 ? s1 : "", |
307 | s2 && s1 ? " " : "", s2 ? s2 : ""); | |
d33fc23b | 308 | else if (display == NLRI_STRING_FORMAT_MIN) |
c6423c31 | 309 | vty_out(vty, "%s%s", s1 ? s1 : "", s2 ? s2 : ""); |
d33fc23b PG |
310 | else if (json_paths) { |
311 | json_ecom_path = json_object_new_object(); | |
c6423c31 | 312 | if (s1) |
9a659715 | 313 | json_object_string_add(json_ecom_path, |
c6423c31 | 314 | "ecomlist", s1); |
9a659715 PG |
315 | if (s2) |
316 | json_object_string_add(json_ecom_path, | |
317 | "ecom6list", s2); | |
d33fc23b PG |
318 | if (display == NLRI_STRING_FORMAT_JSON) |
319 | json_object_array_add(json_paths, | |
320 | json_ecom_path); | |
321 | } | |
f01e580f PG |
322 | if (display == NLRI_STRING_FORMAT_LARGE) { |
323 | char local_buff[INET6_ADDRSTRLEN]; | |
324 | ||
325 | local_buff[0] = '\0'; | |
3a6290bd DA |
326 | if (p->u.prefix_flowspec.family == AF_INET |
327 | && attr->nexthop.s_addr != INADDR_ANY) | |
07380148 DA |
328 | inet_ntop(AF_INET, &attr->nexthop.s_addr, |
329 | local_buff, sizeof(local_buff)); | |
f01e580f PG |
330 | else if (p->u.prefix_flowspec.family == AF_INET6 && |
331 | attr->mp_nexthop_len != 0 && | |
332 | attr->mp_nexthop_len != BGP_ATTR_NHLEN_IPV4 && | |
333 | attr->mp_nexthop_len != BGP_ATTR_NHLEN_VPNV4) | |
07380148 DA |
334 | inet_ntop(AF_INET6, &attr->mp_nexthop_global, |
335 | local_buff, sizeof(local_buff)); | |
f01e580f PG |
336 | if (local_buff[0] != '\0') |
337 | vty_out(vty, "\tNLRI NH %s\n", | |
338 | local_buff); | |
339 | } | |
c6423c31 PG |
340 | XFREE(MTYPE_ECOMMUNITY_STR, s1); |
341 | XFREE(MTYPE_ECOMMUNITY_STR, s2); | |
dba3c1d3 | 342 | } |
9b6d8fcf | 343 | peer_uptime(path->uptime, timebuf, BGP_UPTIME_LEN, 0, NULL); |
b588b642 PG |
344 | if (display == NLRI_STRING_FORMAT_LARGE) { |
345 | vty_out(vty, "\treceived for %8s\n", timebuf); | |
346 | } else if (json_paths) { | |
d33fc23b PG |
347 | json_time_path = json_object_new_object(); |
348 | json_object_string_add(json_time_path, | |
349 | "time", timebuf); | |
350 | if (display == NLRI_STRING_FORMAT_JSON) | |
351 | json_object_array_add(json_paths, json_time_path); | |
dba3c1d3 | 352 | } |
b588b642 | 353 | if (display == NLRI_STRING_FORMAT_LARGE) { |
18ee8310 | 354 | struct bgp_path_info_extra *extra = |
9b6d8fcf | 355 | bgp_path_info_extra_get(path); |
3e3708cb | 356 | bool list_began = false; |
dba3c1d3 | 357 | |
3e3708cb | 358 | if (extra->bgp_fs_pbr && listcount(extra->bgp_fs_pbr)) { |
c26edcda | 359 | struct listnode *node; |
b588b642 PG |
360 | struct bgp_pbr_match_entry *bpme; |
361 | struct bgp_pbr_match *bpm; | |
c26edcda | 362 | struct list *list_bpm; |
b588b642 | 363 | |
c26edcda | 364 | list_bpm = list_new(); |
ce3c0614 | 365 | vty_out(vty, "\tinstalled in PBR"); |
c26edcda PG |
366 | for (ALL_LIST_ELEMENTS_RO(extra->bgp_fs_pbr, |
367 | node, bpme)) { | |
368 | bpm = bpme->backpointer; | |
369 | if (listnode_lookup(list_bpm, bpm)) | |
370 | continue; | |
371 | listnode_add(list_bpm, bpm); | |
503d1ec6 | 372 | if (!list_began) { |
c26edcda | 373 | vty_out(vty, " ("); |
503d1ec6 PG |
374 | list_began = true; |
375 | } else | |
c26edcda PG |
376 | vty_out(vty, ", "); |
377 | vty_out(vty, "%s", bpm->ipset_name); | |
c26edcda | 378 | } |
3e3708cb PG |
379 | list_delete(&list_bpm); |
380 | } | |
381 | if (extra->bgp_fs_iprule && listcount(extra->bgp_fs_iprule)) { | |
382 | struct listnode *node; | |
383 | struct bgp_pbr_rule *bpr; | |
384 | ||
385 | if (!list_began) | |
386 | vty_out(vty, "\tinstalled in PBR"); | |
ce3c0614 PG |
387 | for (ALL_LIST_ELEMENTS_RO(extra->bgp_fs_iprule, |
388 | node, bpr)) { | |
389 | if (!bpr->action) | |
390 | continue; | |
391 | if (!list_began) { | |
392 | vty_out(vty, " ("); | |
393 | list_began = true; | |
394 | } else | |
395 | vty_out(vty, ", "); | |
396 | vty_out(vty, "-ipv4-rule %d action lookup %u-", | |
397 | bpr->priority, | |
398 | bpr->action->table_id); | |
399 | } | |
3e3708cb | 400 | } |
026b0e3b PG |
401 | if (list_began) |
402 | vty_out(vty, ")\n"); | |
403 | else | |
b588b642 PG |
404 | vty_out(vty, "\tnot installed in PBR\n"); |
405 | } | |
dba3c1d3 PG |
406 | } |
407 | ||
408 | int bgp_show_table_flowspec(struct vty *vty, struct bgp *bgp, afi_t afi, | |
409 | struct bgp_table *table, enum bgp_show_type type, | |
088f1098 DS |
410 | void *output_arg, bool use_json, int is_last, |
411 | unsigned long *output_cum, unsigned long *total_cum) | |
dba3c1d3 | 412 | { |
40381db7 | 413 | struct bgp_path_info *pi; |
9bcb3eef | 414 | struct bgp_dest *dest; |
dba3c1d3 PG |
415 | unsigned long total_count = 0; |
416 | json_object *json_paths = NULL; | |
d33fc23b | 417 | int display = NLRI_STRING_FORMAT_LARGE; |
dba3c1d3 PG |
418 | |
419 | if (type != bgp_show_type_detail) | |
420 | return CMD_SUCCESS; | |
421 | ||
9bcb3eef DS |
422 | for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) { |
423 | pi = bgp_dest_get_bgp_path_info(dest); | |
6f94b685 | 424 | if (pi == NULL) |
dba3c1d3 | 425 | continue; |
d33fc23b PG |
426 | if (use_json) { |
427 | json_paths = json_object_new_array(); | |
428 | display = NLRI_STRING_FORMAT_JSON; | |
429 | } | |
6f94b685 | 430 | for (; pi; pi = pi->next) { |
dba3c1d3 | 431 | total_count++; |
9bcb3eef DS |
432 | route_vty_out_flowspec(vty, bgp_dest_get_prefix(dest), |
433 | pi, display, json_paths); | |
dba3c1d3 | 434 | } |
d33fc23b | 435 | if (use_json) { |
75eeda93 | 436 | vty_json(vty, json_paths); |
d33fc23b PG |
437 | json_paths = NULL; |
438 | } | |
dba3c1d3 | 439 | } |
d33fc23b | 440 | if (total_count && !use_json) |
dba3c1d3 PG |
441 | vty_out(vty, |
442 | "\nDisplayed %ld flowspec entries\n", | |
443 | total_count); | |
444 | return CMD_SUCCESS; | |
445 | } | |
446 | ||
268e1b9b PG |
447 | DEFUN (debug_bgp_flowspec, |
448 | debug_bgp_flowspec_cmd, | |
449 | "debug bgp flowspec", | |
450 | DEBUG_STR | |
451 | BGP_STR | |
452 | "BGP allow flowspec debugging entries\n") | |
453 | { | |
454 | if (vty->node == CONFIG_NODE) | |
455 | DEBUG_ON(flowspec, FLOWSPEC); | |
456 | else { | |
457 | TERM_DEBUG_ON(flowspec, FLOWSPEC); | |
458 | vty_out(vty, "BGP flowspec debugging is on\n"); | |
459 | } | |
460 | return CMD_SUCCESS; | |
461 | } | |
462 | ||
463 | DEFUN (no_debug_bgp_flowspec, | |
464 | no_debug_bgp_flowspec_cmd, | |
465 | "no debug bgp flowspec", | |
466 | NO_STR | |
467 | DEBUG_STR | |
468 | BGP_STR | |
469 | "BGP allow flowspec debugging entries\n") | |
470 | { | |
471 | if (vty->node == CONFIG_NODE) | |
472 | DEBUG_OFF(flowspec, FLOWSPEC); | |
473 | else { | |
474 | TERM_DEBUG_OFF(flowspec, FLOWSPEC); | |
475 | vty_out(vty, "BGP flowspec debugging is off\n"); | |
476 | } | |
477 | return CMD_SUCCESS; | |
478 | } | |
479 | ||
4762c213 PG |
480 | int bgp_fs_config_write_pbr(struct vty *vty, struct bgp *bgp, |
481 | afi_t afi, safi_t safi) | |
482 | { | |
483 | struct bgp_pbr_interface *pbr_if; | |
484 | bool declare_node = false; | |
485 | struct bgp_pbr_config *bgp_pbr_cfg = bgp->bgp_pbr_cfg; | |
486 | struct bgp_pbr_interface_head *head; | |
487 | bool bgp_pbr_interface_any; | |
488 | ||
8f242187 | 489 | if (!bgp_pbr_cfg || safi != SAFI_FLOWSPEC) |
4762c213 | 490 | return 0; |
8f242187 PG |
491 | if (afi == AFI_IP) { |
492 | head = &(bgp_pbr_cfg->ifaces_by_name_ipv4); | |
493 | bgp_pbr_interface_any = bgp_pbr_cfg->pbr_interface_any_ipv4; | |
494 | } else if (afi == AFI_IP6) { | |
495 | head = &(bgp_pbr_cfg->ifaces_by_name_ipv6); | |
496 | bgp_pbr_interface_any = bgp_pbr_cfg->pbr_interface_any_ipv6; | |
497 | } else { | |
498 | return 0; | |
499 | } | |
4762c213 PG |
500 | if (!RB_EMPTY(bgp_pbr_interface_head, head) || |
501 | !bgp_pbr_interface_any) | |
502 | declare_node = true; | |
503 | RB_FOREACH (pbr_if, bgp_pbr_interface_head, head) { | |
504 | vty_out(vty, " local-install %s\n", pbr_if->name); | |
505 | } | |
4762c213 PG |
506 | return declare_node ? 1 : 0; |
507 | } | |
508 | ||
509 | static int bgp_fs_local_install_interface(struct bgp *bgp, | |
8f242187 PG |
510 | const char *no, const char *ifname, |
511 | afi_t afi) | |
4762c213 PG |
512 | { |
513 | struct bgp_pbr_interface *pbr_if; | |
514 | struct bgp_pbr_config *bgp_pbr_cfg = bgp->bgp_pbr_cfg; | |
515 | struct bgp_pbr_interface_head *head; | |
516 | bool *bgp_pbr_interface_any; | |
517 | ||
518 | if (!bgp_pbr_cfg) | |
519 | return CMD_SUCCESS; | |
8f242187 PG |
520 | if (afi == AFI_IP) { |
521 | head = &(bgp_pbr_cfg->ifaces_by_name_ipv4); | |
522 | bgp_pbr_interface_any = &(bgp_pbr_cfg->pbr_interface_any_ipv4); | |
523 | } else { | |
524 | head = &(bgp_pbr_cfg->ifaces_by_name_ipv6); | |
525 | bgp_pbr_interface_any = &(bgp_pbr_cfg->pbr_interface_any_ipv6); | |
526 | } | |
4762c213 PG |
527 | if (no) { |
528 | if (!ifname) { | |
529 | if (*bgp_pbr_interface_any) { | |
530 | *bgp_pbr_interface_any = false; | |
531 | /* remove all other interface list */ | |
8f242187 | 532 | bgp_pbr_reset(bgp, afi); |
4762c213 PG |
533 | } |
534 | return CMD_SUCCESS; | |
535 | } | |
536 | pbr_if = bgp_pbr_interface_lookup(ifname, head); | |
537 | if (!pbr_if) | |
538 | return CMD_SUCCESS; | |
539 | RB_REMOVE(bgp_pbr_interface_head, head, pbr_if); | |
540 | return CMD_SUCCESS; | |
541 | } | |
542 | if (ifname) { | |
543 | pbr_if = bgp_pbr_interface_lookup(ifname, head); | |
544 | if (pbr_if) | |
545 | return CMD_SUCCESS; | |
546 | pbr_if = XCALLOC(MTYPE_TMP, | |
547 | sizeof(struct bgp_pbr_interface)); | |
548 | strlcpy(pbr_if->name, ifname, INTERFACE_NAMSIZ); | |
549 | RB_INSERT(bgp_pbr_interface_head, head, pbr_if); | |
550 | *bgp_pbr_interface_any = false; | |
551 | } else { | |
552 | /* set to default */ | |
553 | if (!*bgp_pbr_interface_any) { | |
554 | /* remove all other interface list | |
555 | */ | |
8f242187 | 556 | bgp_pbr_reset(bgp, afi); |
4762c213 PG |
557 | *bgp_pbr_interface_any = true; |
558 | } | |
559 | } | |
560 | return CMD_SUCCESS; | |
561 | } | |
562 | ||
563 | DEFUN (bgp_fs_local_install_ifname, | |
564 | bgp_fs_local_install_ifname_cmd, | |
565 | "[no] local-install INTERFACE", | |
566 | NO_STR | |
567 | "Apply local policy routing\n" | |
568 | "Interface name\n") | |
569 | { | |
570 | struct bgp *bgp = VTY_GET_CONTEXT(bgp); | |
571 | int idx = 0; | |
36de6e0e | 572 | const char *no = strmatch(argv[0]->text, "no") ? "no" : NULL; |
4762c213 PG |
573 | char *ifname = argv_find(argv, argc, "INTERFACE", &idx) ? |
574 | argv[idx]->arg : NULL; | |
575 | ||
8f242187 PG |
576 | return bgp_fs_local_install_interface(bgp, no, ifname, |
577 | bgp_node_afi(vty)); | |
4762c213 PG |
578 | } |
579 | ||
088f1098 DS |
580 | extern int bgp_flowspec_display_match_per_ip(afi_t afi, struct bgp_table *rib, |
581 | struct prefix *match, | |
582 | int prefix_check, struct vty *vty, | |
583 | bool use_json, | |
584 | json_object *json_paths) | |
63a0b7a9 | 585 | { |
9bcb3eef | 586 | struct bgp_dest *dest; |
b54892e0 | 587 | const struct prefix *prefix; |
63a0b7a9 PG |
588 | int display = 0; |
589 | ||
9bcb3eef DS |
590 | for (dest = bgp_table_top(rib); dest; dest = bgp_route_next(dest)) { |
591 | prefix = bgp_dest_get_prefix(dest); | |
63a0b7a9 PG |
592 | |
593 | if (prefix->family != AF_FLOWSPEC) | |
594 | continue; | |
595 | ||
596 | if (bgp_flowspec_contains_prefix(prefix, match, prefix_check)) { | |
6f94b685 | 597 | route_vty_out_flowspec( |
9bcb3eef | 598 | vty, prefix, bgp_dest_get_bgp_path_info(dest), |
6f94b685 DS |
599 | use_json ? NLRI_STRING_FORMAT_JSON |
600 | : NLRI_STRING_FORMAT_LARGE, | |
601 | json_paths); | |
63a0b7a9 PG |
602 | display++; |
603 | } | |
604 | } | |
605 | return display; | |
606 | } | |
607 | ||
dba3c1d3 PG |
608 | void bgp_flowspec_vty_init(void) |
609 | { | |
268e1b9b PG |
610 | install_element(ENABLE_NODE, &debug_bgp_flowspec_cmd); |
611 | install_element(CONFIG_NODE, &debug_bgp_flowspec_cmd); | |
612 | install_element(ENABLE_NODE, &no_debug_bgp_flowspec_cmd); | |
613 | install_element(CONFIG_NODE, &no_debug_bgp_flowspec_cmd); | |
4762c213 | 614 | install_element(BGP_FLOWSPECV4_NODE, &bgp_fs_local_install_ifname_cmd); |
8f242187 | 615 | install_element(BGP_FLOWSPECV6_NODE, &bgp_fs_local_install_ifname_cmd); |
dba3c1d3 | 616 | } |