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