]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_flowspec_vty.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / bgpd / bgp_flowspec_vty.c
CommitLineData
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
27static 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
44static 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 83void 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 247void 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
408int 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
447DEFUN (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
463DEFUN (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
480int 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
509static 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
563DEFUN (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
580extern 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
608void 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}