]> git.proxmox.com Git - mirror_frr.git/blob - bgpd/bgp_flowspec_vty.c
Merge pull request #10492 from ton31337/feature/pmsi_tnl_type_attr_extra
[mirror_frr.git] / bgpd / bgp_flowspec_vty.c
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"
32 #include "bgpd/bgp_debug.h"
33 #include "bgpd/bgp_pbr.h"
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
40 static 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"},
53 {FLOWSPEC_FLOW_LABEL, "Packet Flow Label"},
54 {0}
55 };
56
57 static 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"},
66 {FLOWSPEC_TCP_FLAGS, "tcp"},
67 {FLOWSPEC_PKT_LEN, "pktlen"},
68 {FLOWSPEC_DSCP, "dscp"},
69 {FLOWSPEC_FRAGMENT, "pktfrag"},
70 {FLOWSPEC_FLOW_LABEL, "flwlbl"},
71 {0}
72 };
73
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++; \
90 } while (0)
91
92 /* Parse FLOWSPEC NLRI
93 * passed return_string string has assumed length
94 * BGP_FLOWSPEC_STRING_DISPLAY_MAX
95 */
96 void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len,
97 char *return_string, int format,
98 json_object *json_path,
99 afi_t afi)
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;
110 enum bgp_flowspec_util_nlri_t type_util;
111 int len_string = BGP_FLOWSPEC_STRING_DISPLAY_MAX;
112 int len_written;
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;
120 /* if needed. type_util can be set to other values */
121 type_util = BGP_FLOWSPEC_RETURN_STRING;
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(
130 type_util,
131 nlri_content+offset,
132 len - offset,
133 local_string, &error,
134 afi, NULL);
135 if (ret <= 0)
136 break;
137 if (json_path) {
138 json_object_string_add(json_path,
139 lookup_msg(bgp_flowspec_display, type, ""),
140 local_string);
141 break;
142 }
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;
151 break;
152 case FLOWSPEC_FLOW_LABEL:
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:
159 ret = bgp_flowspec_op_decode(type_util,
160 nlri_content+offset,
161 len - offset,
162 local_string, &error);
163 if (ret <= 0)
164 break;
165 if (json_path) {
166 json_object_string_add(json_path,
167 lookup_msg(bgp_flowspec_display, type, ""),
168 local_string);
169 break;
170 }
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, ""),
176 local_string, extra);
177 len_string -= len_written;
178 ptr += len_written;
179 break;
180 case FLOWSPEC_TCP_FLAGS:
181 ret = bgp_flowspec_bitmask_decode(
182 type_util,
183 nlri_content+offset,
184 len - offset,
185 local_string, &error);
186 if (ret <= 0)
187 break;
188 if (json_path) {
189 json_object_string_add(json_path,
190 lookup_msg(bgp_flowspec_display,
191 type, ""),
192 local_string);
193 break;
194 }
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;
203 break;
204 case FLOWSPEC_PKT_LEN:
205 case FLOWSPEC_DSCP:
206 ret = bgp_flowspec_op_decode(
207 type_util,
208 nlri_content + offset,
209 len - offset, local_string,
210 &error);
211 if (ret <= 0)
212 break;
213 if (json_path) {
214 json_object_string_add(json_path,
215 lookup_msg(bgp_flowspec_display, type, ""),
216 local_string);
217 break;
218 }
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, ""),
224 local_string, extra);
225 len_string -= len_written;
226 ptr += len_written;
227 break;
228 case FLOWSPEC_FRAGMENT:
229 ret = bgp_flowspec_bitmask_decode(
230 type_util,
231 nlri_content+offset,
232 len - offset,
233 local_string, &error);
234 if (ret <= 0)
235 break;
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 }
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;
251 break;
252 default:
253 error = -1;
254 break;
255 }
256 offset += ret;
257 }
258 }
259
260 void route_vty_out_flowspec(struct vty *vty, const struct prefix *p,
261 struct bgp_path_info *path, int display,
262 json_object *json_paths)
263 {
264 struct attr *attr;
265 char return_string[BGP_FLOWSPEC_STRING_DISPLAY_MAX];
266 char *s1 = NULL, *s2 = NULL;
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];
271 struct ecommunity *ipv6_ecomm = NULL;
272
273 if (p == NULL || p->family != AF_FLOWSPEC)
274 return;
275 if (json_paths) {
276 if (display == NLRI_STRING_FORMAT_JSON)
277 json_nlri_path = json_object_new_object();
278 else
279 json_nlri_path = json_paths;
280 }
281 if (display == NLRI_STRING_FORMAT_LARGE && path)
282 vty_out(vty, "BGP flowspec entry: (flags 0x%x)\n",
283 path->flags);
284 bgp_fs_nlri_get_string((unsigned char *)
285 p->u.prefix_flowspec.ptr,
286 p->u.prefix_flowspec.prefixlen,
287 return_string,
288 display,
289 json_nlri_path,
290 family2afi(p->u.prefix_flowspec
291 .family));
292 if (display == NLRI_STRING_FORMAT_LARGE)
293 vty_out(vty, "%s", return_string);
294 else if (display == NLRI_STRING_FORMAT_DEBUG)
295 vty_out(vty, "%s", return_string);
296 else if (display == NLRI_STRING_FORMAT_MIN)
297 vty_out(vty, " %-30s", return_string);
298 else if (json_paths && display == NLRI_STRING_FORMAT_JSON)
299 json_object_array_add(json_paths, json_nlri_path);
300 if (!path)
301 return;
302
303 if (path->attr)
304 ipv6_ecomm = bgp_attr_get_ipv6_ecommunity(path->attr);
305
306 if (path->attr && (bgp_attr_get_ecommunity(path->attr) || ipv6_ecomm)) {
307 /* Print attribute */
308 attr = path->attr;
309 if (bgp_attr_get_ecommunity(attr))
310 s1 = ecommunity_ecom2str(bgp_attr_get_ecommunity(attr),
311 ECOMMUNITY_FORMAT_ROUTE_MAP,
312 0);
313 if (ipv6_ecomm)
314 s2 = ecommunity_ecom2str(
315 ipv6_ecomm, ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
316 if (!s1 && !s2)
317 return;
318 if (display == NLRI_STRING_FORMAT_LARGE)
319 vty_out(vty, "\t%s%s%s\n", s1 ? s1 : "",
320 s2 && s1 ? " " : "", s2 ? s2 : "");
321 else if (display == NLRI_STRING_FORMAT_MIN)
322 vty_out(vty, "%s%s", s1 ? s1 : "", s2 ? s2 : "");
323 else if (json_paths) {
324 json_ecom_path = json_object_new_object();
325 if (s1)
326 json_object_string_add(json_ecom_path,
327 "ecomlist", s1);
328 if (s2)
329 json_object_string_add(json_ecom_path,
330 "ecom6list", s2);
331 if (display == NLRI_STRING_FORMAT_JSON)
332 json_object_array_add(json_paths,
333 json_ecom_path);
334 }
335 if (display == NLRI_STRING_FORMAT_LARGE) {
336 char local_buff[INET6_ADDRSTRLEN];
337
338 local_buff[0] = '\0';
339 if (p->u.prefix_flowspec.family == AF_INET
340 && attr->nexthop.s_addr != INADDR_ANY)
341 inet_ntop(AF_INET,
342 &attr->nexthop.s_addr,
343 local_buff,
344 INET6_ADDRSTRLEN);
345 else if (p->u.prefix_flowspec.family == AF_INET6 &&
346 attr->mp_nexthop_len != 0 &&
347 attr->mp_nexthop_len != BGP_ATTR_NHLEN_IPV4 &&
348 attr->mp_nexthop_len != BGP_ATTR_NHLEN_VPNV4)
349 inet_ntop(AF_INET6,
350 &attr->mp_nexthop_global,
351 local_buff,
352 INET6_ADDRSTRLEN);
353 if (local_buff[0] != '\0')
354 vty_out(vty, "\tNLRI NH %s\n",
355 local_buff);
356 }
357 XFREE(MTYPE_ECOMMUNITY_STR, s1);
358 XFREE(MTYPE_ECOMMUNITY_STR, s2);
359 }
360 peer_uptime(path->uptime, timebuf, BGP_UPTIME_LEN, 0, NULL);
361 if (display == NLRI_STRING_FORMAT_LARGE) {
362 vty_out(vty, "\treceived for %8s\n", timebuf);
363 } else if (json_paths) {
364 json_time_path = json_object_new_object();
365 json_object_string_add(json_time_path,
366 "time", timebuf);
367 if (display == NLRI_STRING_FORMAT_JSON)
368 json_object_array_add(json_paths, json_time_path);
369 }
370 if (display == NLRI_STRING_FORMAT_LARGE) {
371 struct bgp_path_info_extra *extra =
372 bgp_path_info_extra_get(path);
373 bool list_began = false;
374
375 if (extra->bgp_fs_pbr && listcount(extra->bgp_fs_pbr)) {
376 struct listnode *node;
377 struct bgp_pbr_match_entry *bpme;
378 struct bgp_pbr_match *bpm;
379 struct list *list_bpm;
380
381 list_bpm = list_new();
382 vty_out(vty, "\tinstalled in PBR");
383 for (ALL_LIST_ELEMENTS_RO(extra->bgp_fs_pbr,
384 node, bpme)) {
385 bpm = bpme->backpointer;
386 if (listnode_lookup(list_bpm, bpm))
387 continue;
388 listnode_add(list_bpm, bpm);
389 if (!list_began) {
390 vty_out(vty, " (");
391 list_began = true;
392 } else
393 vty_out(vty, ", ");
394 vty_out(vty, "%s", bpm->ipset_name);
395 }
396 list_delete(&list_bpm);
397 }
398 if (extra->bgp_fs_iprule && listcount(extra->bgp_fs_iprule)) {
399 struct listnode *node;
400 struct bgp_pbr_rule *bpr;
401
402 if (!list_began)
403 vty_out(vty, "\tinstalled in PBR");
404 for (ALL_LIST_ELEMENTS_RO(extra->bgp_fs_iprule,
405 node, bpr)) {
406 if (!bpr->action)
407 continue;
408 if (!list_began) {
409 vty_out(vty, " (");
410 list_began = true;
411 } else
412 vty_out(vty, ", ");
413 vty_out(vty, "-ipv4-rule %d action lookup %u-",
414 bpr->priority,
415 bpr->action->table_id);
416 }
417 }
418 if (list_began)
419 vty_out(vty, ")\n");
420 else
421 vty_out(vty, "\tnot installed in PBR\n");
422 }
423 }
424
425 int bgp_show_table_flowspec(struct vty *vty, struct bgp *bgp, afi_t afi,
426 struct bgp_table *table, enum bgp_show_type type,
427 void *output_arg, bool use_json, int is_last,
428 unsigned long *output_cum, unsigned long *total_cum)
429 {
430 struct bgp_path_info *pi;
431 struct bgp_dest *dest;
432 unsigned long total_count = 0;
433 json_object *json_paths = NULL;
434 int display = NLRI_STRING_FORMAT_LARGE;
435
436 if (type != bgp_show_type_detail)
437 return CMD_SUCCESS;
438
439 for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) {
440 pi = bgp_dest_get_bgp_path_info(dest);
441 if (pi == NULL)
442 continue;
443 if (use_json) {
444 json_paths = json_object_new_array();
445 display = NLRI_STRING_FORMAT_JSON;
446 }
447 for (; pi; pi = pi->next) {
448 total_count++;
449 route_vty_out_flowspec(vty, bgp_dest_get_prefix(dest),
450 pi, display, json_paths);
451 }
452 if (use_json) {
453 vty_json(vty, json_paths);
454 json_paths = NULL;
455 }
456 }
457 if (total_count && !use_json)
458 vty_out(vty,
459 "\nDisplayed %ld flowspec entries\n",
460 total_count);
461 return CMD_SUCCESS;
462 }
463
464 DEFUN (debug_bgp_flowspec,
465 debug_bgp_flowspec_cmd,
466 "debug bgp flowspec",
467 DEBUG_STR
468 BGP_STR
469 "BGP allow flowspec debugging entries\n")
470 {
471 if (vty->node == CONFIG_NODE)
472 DEBUG_ON(flowspec, FLOWSPEC);
473 else {
474 TERM_DEBUG_ON(flowspec, FLOWSPEC);
475 vty_out(vty, "BGP flowspec debugging is on\n");
476 }
477 return CMD_SUCCESS;
478 }
479
480 DEFUN (no_debug_bgp_flowspec,
481 no_debug_bgp_flowspec_cmd,
482 "no debug bgp flowspec",
483 NO_STR
484 DEBUG_STR
485 BGP_STR
486 "BGP allow flowspec debugging entries\n")
487 {
488 if (vty->node == CONFIG_NODE)
489 DEBUG_OFF(flowspec, FLOWSPEC);
490 else {
491 TERM_DEBUG_OFF(flowspec, FLOWSPEC);
492 vty_out(vty, "BGP flowspec debugging is off\n");
493 }
494 return CMD_SUCCESS;
495 }
496
497 int bgp_fs_config_write_pbr(struct vty *vty, struct bgp *bgp,
498 afi_t afi, safi_t safi)
499 {
500 struct bgp_pbr_interface *pbr_if;
501 bool declare_node = false;
502 struct bgp_pbr_config *bgp_pbr_cfg = bgp->bgp_pbr_cfg;
503 struct bgp_pbr_interface_head *head;
504 bool bgp_pbr_interface_any;
505
506 if (!bgp_pbr_cfg || safi != SAFI_FLOWSPEC)
507 return 0;
508 if (afi == AFI_IP) {
509 head = &(bgp_pbr_cfg->ifaces_by_name_ipv4);
510 bgp_pbr_interface_any = bgp_pbr_cfg->pbr_interface_any_ipv4;
511 } else if (afi == AFI_IP6) {
512 head = &(bgp_pbr_cfg->ifaces_by_name_ipv6);
513 bgp_pbr_interface_any = bgp_pbr_cfg->pbr_interface_any_ipv6;
514 } else {
515 return 0;
516 }
517 if (!RB_EMPTY(bgp_pbr_interface_head, head) ||
518 !bgp_pbr_interface_any)
519 declare_node = true;
520 RB_FOREACH (pbr_if, bgp_pbr_interface_head, head) {
521 vty_out(vty, " local-install %s\n", pbr_if->name);
522 }
523 return declare_node ? 1 : 0;
524 }
525
526 static int bgp_fs_local_install_interface(struct bgp *bgp,
527 const char *no, const char *ifname,
528 afi_t afi)
529 {
530 struct bgp_pbr_interface *pbr_if;
531 struct bgp_pbr_config *bgp_pbr_cfg = bgp->bgp_pbr_cfg;
532 struct bgp_pbr_interface_head *head;
533 bool *bgp_pbr_interface_any;
534
535 if (!bgp_pbr_cfg)
536 return CMD_SUCCESS;
537 if (afi == AFI_IP) {
538 head = &(bgp_pbr_cfg->ifaces_by_name_ipv4);
539 bgp_pbr_interface_any = &(bgp_pbr_cfg->pbr_interface_any_ipv4);
540 } else {
541 head = &(bgp_pbr_cfg->ifaces_by_name_ipv6);
542 bgp_pbr_interface_any = &(bgp_pbr_cfg->pbr_interface_any_ipv6);
543 }
544 if (no) {
545 if (!ifname) {
546 if (*bgp_pbr_interface_any) {
547 *bgp_pbr_interface_any = false;
548 /* remove all other interface list */
549 bgp_pbr_reset(bgp, afi);
550 }
551 return CMD_SUCCESS;
552 }
553 pbr_if = bgp_pbr_interface_lookup(ifname, head);
554 if (!pbr_if)
555 return CMD_SUCCESS;
556 RB_REMOVE(bgp_pbr_interface_head, head, pbr_if);
557 return CMD_SUCCESS;
558 }
559 if (ifname) {
560 pbr_if = bgp_pbr_interface_lookup(ifname, head);
561 if (pbr_if)
562 return CMD_SUCCESS;
563 pbr_if = XCALLOC(MTYPE_TMP,
564 sizeof(struct bgp_pbr_interface));
565 strlcpy(pbr_if->name, ifname, INTERFACE_NAMSIZ);
566 RB_INSERT(bgp_pbr_interface_head, head, pbr_if);
567 *bgp_pbr_interface_any = false;
568 } else {
569 /* set to default */
570 if (!*bgp_pbr_interface_any) {
571 /* remove all other interface list
572 */
573 bgp_pbr_reset(bgp, afi);
574 *bgp_pbr_interface_any = true;
575 }
576 }
577 return CMD_SUCCESS;
578 }
579
580 DEFUN (bgp_fs_local_install_ifname,
581 bgp_fs_local_install_ifname_cmd,
582 "[no] local-install INTERFACE",
583 NO_STR
584 "Apply local policy routing\n"
585 "Interface name\n")
586 {
587 struct bgp *bgp = VTY_GET_CONTEXT(bgp);
588 int idx = 0;
589 const char *no = strmatch(argv[0]->text, "no") ? "no" : NULL;
590 char *ifname = argv_find(argv, argc, "INTERFACE", &idx) ?
591 argv[idx]->arg : NULL;
592
593 return bgp_fs_local_install_interface(bgp, no, ifname,
594 bgp_node_afi(vty));
595 }
596
597 extern int bgp_flowspec_display_match_per_ip(afi_t afi, struct bgp_table *rib,
598 struct prefix *match,
599 int prefix_check, struct vty *vty,
600 bool use_json,
601 json_object *json_paths)
602 {
603 struct bgp_dest *dest;
604 const struct prefix *prefix;
605 int display = 0;
606
607 for (dest = bgp_table_top(rib); dest; dest = bgp_route_next(dest)) {
608 prefix = bgp_dest_get_prefix(dest);
609
610 if (prefix->family != AF_FLOWSPEC)
611 continue;
612
613 if (bgp_flowspec_contains_prefix(prefix, match, prefix_check)) {
614 route_vty_out_flowspec(
615 vty, prefix, bgp_dest_get_bgp_path_info(dest),
616 use_json ? NLRI_STRING_FORMAT_JSON
617 : NLRI_STRING_FORMAT_LARGE,
618 json_paths);
619 display++;
620 }
621 }
622 return display;
623 }
624
625 void bgp_flowspec_vty_init(void)
626 {
627 install_element(ENABLE_NODE, &debug_bgp_flowspec_cmd);
628 install_element(CONFIG_NODE, &debug_bgp_flowspec_cmd);
629 install_element(ENABLE_NODE, &no_debug_bgp_flowspec_cmd);
630 install_element(CONFIG_NODE, &no_debug_bgp_flowspec_cmd);
631 install_element(BGP_FLOWSPECV4_NODE, &bgp_fs_local_install_ifname_cmd);
632 install_element(BGP_FLOWSPECV6_NODE, &bgp_fs_local_install_ifname_cmd);
633 }