]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_flowspec_vty.c
staticd: Do not ready prefix for printing till it's decoded
[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"},
53 {0}
54};
55
56static const struct message bgp_flowspec_display_min[] = {
57 {FLOWSPEC_DEST_PREFIX, "to"},
58 {FLOWSPEC_SRC_PREFIX, "from"},
59 {FLOWSPEC_IP_PROTOCOL, "proto"},
60 {FLOWSPEC_PORT, "port"},
61 {FLOWSPEC_DEST_PORT, "dstp"},
62 {FLOWSPEC_SRC_PORT, "srcp"},
63 {FLOWSPEC_ICMP_TYPE, "type"},
64 {FLOWSPEC_ICMP_CODE, "code"},
01ffd28b 65 {FLOWSPEC_TCP_FLAGS, "tcp"},
dba3c1d3
PG
66 {FLOWSPEC_PKT_LEN, "pktlen"},
67 {FLOWSPEC_DSCP, "dscp"},
68 {FLOWSPEC_FRAGMENT, "pktfrag"},
69 {0}
70};
71
362a06e3
PG
72#define FS_STRING_UPDATE(count, ptr, format, remaining_len) do { \
73 int _len_written; \
74 \
75 if (((format) == NLRI_STRING_FORMAT_DEBUG) && (count)) {\
76 _len_written = snprintf((ptr), (remaining_len), \
77 ", "); \
78 (remaining_len) -= _len_written; \
79 (ptr) += _len_written; \
80 } else if (((format) == NLRI_STRING_FORMAT_MIN) \
81 && (count)) { \
82 _len_written = snprintf((ptr), (remaining_len), \
83 " "); \
84 (remaining_len) -= _len_written; \
85 (ptr) += _len_written; \
86 } \
87 count++; \
dba3c1d3
PG
88 } while (0)
89
362a06e3
PG
90/* Parse FLOWSPEC NLRI
91 * passed return_string string has assumed length
92 * BGP_FLOWSPEC_STRING_DISPLAY_MAX
93 */
dba3c1d3 94void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len,
d33fc23b
PG
95 char *return_string, int format,
96 json_object *json_path)
dba3c1d3
PG
97{
98 uint32_t offset = 0;
99 int type;
100 int ret = 0, error = 0;
101 char *ptr = return_string;
102 char local_string[BGP_FLOWSPEC_STRING_DISPLAY_MAX];
103 int count = 0;
104 char extra[2] = "";
105 char pre_extra[2] = "";
106 const struct message *bgp_flowspec_display;
d33fc23b 107 enum bgp_flowspec_util_nlri_t type_util;
362a06e3
PG
108 int len_string = BGP_FLOWSPEC_STRING_DISPLAY_MAX;
109 int len_written;
dba3c1d3
PG
110
111 if (format == NLRI_STRING_FORMAT_LARGE) {
112 snprintf(pre_extra, sizeof(pre_extra), "\t");
113 snprintf(extra, sizeof(extra), "\n");
114 bgp_flowspec_display = bgp_flowspec_display_large;
115 } else
116 bgp_flowspec_display = bgp_flowspec_display_min;
d33fc23b
PG
117 /* if needed. type_util can be set to other values */
118 type_util = BGP_FLOWSPEC_RETURN_STRING;
dba3c1d3
PG
119 error = 0;
120 while (offset < len-1 && error >= 0) {
121 type = nlri_content[offset];
122 offset++;
123 switch (type) {
124 case FLOWSPEC_DEST_PREFIX:
125 case FLOWSPEC_SRC_PREFIX:
126 ret = bgp_flowspec_ip_address(
d33fc23b 127 type_util,
dba3c1d3
PG
128 nlri_content+offset,
129 len - offset,
130 local_string, &error);
131 if (ret <= 0)
132 break;
d33fc23b
PG
133 if (json_path) {
134 json_object_string_add(json_path,
135 lookup_msg(bgp_flowspec_display, type, ""),
136 local_string);
137 break;
138 }
362a06e3
PG
139 FS_STRING_UPDATE(count, ptr, format, len_string);
140 len_written = snprintf(ptr, len_string, "%s%s %s%s",
141 pre_extra,
142 lookup_msg(bgp_flowspec_display,
143 type, ""),
144 local_string, extra);
145 len_string -= len_written;
146 ptr += len_written;
dba3c1d3
PG
147 break;
148 case FLOWSPEC_IP_PROTOCOL:
149 case FLOWSPEC_PORT:
150 case FLOWSPEC_DEST_PORT:
151 case FLOWSPEC_SRC_PORT:
152 case FLOWSPEC_ICMP_TYPE:
153 case FLOWSPEC_ICMP_CODE:
d33fc23b 154 ret = bgp_flowspec_op_decode(type_util,
dba3c1d3
PG
155 nlri_content+offset,
156 len - offset,
157 local_string, &error);
158 if (ret <= 0)
159 break;
d33fc23b
PG
160 if (json_path) {
161 json_object_string_add(json_path,
162 lookup_msg(bgp_flowspec_display, type, ""),
163 local_string);
164 break;
165 }
362a06e3
PG
166 FS_STRING_UPDATE(count, ptr, format, len_string);
167 len_written = snprintf(ptr, len_string, "%s%s %s%s",
168 pre_extra,
169 lookup_msg(bgp_flowspec_display,
170 type, ""),
dba3c1d3 171 local_string, extra);
362a06e3
PG
172 len_string -= len_written;
173 ptr += len_written;
dba3c1d3
PG
174 break;
175 case FLOWSPEC_TCP_FLAGS:
588ec356 176 ret = bgp_flowspec_bitmask_decode(
d33fc23b 177 type_util,
dba3c1d3
PG
178 nlri_content+offset,
179 len - offset,
180 local_string, &error);
181 if (ret <= 0)
182 break;
d33fc23b
PG
183 if (json_path) {
184 json_object_string_add(json_path,
362a06e3
PG
185 lookup_msg(bgp_flowspec_display,
186 type, ""),
d33fc23b
PG
187 local_string);
188 break;
189 }
362a06e3
PG
190 FS_STRING_UPDATE(count, ptr, format, len_string);
191 len_written = snprintf(ptr, len_string, "%s%s %s%s",
192 pre_extra,
193 lookup_msg(bgp_flowspec_display,
194 type, ""),
195 local_string, extra);
196 len_string -= len_written;
197 ptr += len_written;
dba3c1d3
PG
198 break;
199 case FLOWSPEC_PKT_LEN:
200 case FLOWSPEC_DSCP:
201 ret = bgp_flowspec_op_decode(
d33fc23b 202 type_util,
dba3c1d3
PG
203 nlri_content + offset,
204 len - offset, local_string,
205 &error);
206 if (ret <= 0)
207 break;
d33fc23b
PG
208 if (json_path) {
209 json_object_string_add(json_path,
210 lookup_msg(bgp_flowspec_display, type, ""),
211 local_string);
212 break;
213 }
362a06e3
PG
214 FS_STRING_UPDATE(count, ptr, format, len_string);
215 len_written = snprintf(ptr, len_string, "%s%s %s%s",
216 pre_extra,
217 lookup_msg(bgp_flowspec_display,
218 type, ""),
dba3c1d3 219 local_string, extra);
362a06e3
PG
220 len_string -= len_written;
221 ptr += len_written;
dba3c1d3
PG
222 break;
223 case FLOWSPEC_FRAGMENT:
588ec356
PG
224 ret = bgp_flowspec_bitmask_decode(
225 type_util,
226 nlri_content+offset,
227 len - offset,
228 local_string, &error);
dba3c1d3
PG
229 if (ret <= 0)
230 break;
d33fc23b
PG
231 if (json_path) {
232 json_object_string_add(json_path,
233 lookup_msg(bgp_flowspec_display,
234 type, ""),
235 local_string);
236 break;
237 }
362a06e3
PG
238 FS_STRING_UPDATE(count, ptr, format, len_string);
239 len_written = snprintf(ptr, len_string, "%s%s %s%s",
240 pre_extra,
241 lookup_msg(bgp_flowspec_display,
242 type, ""),
243 local_string, extra);
244 len_string -= len_written;
245 ptr += len_written;
dba3c1d3
PG
246 break;
247 default:
248 error = -1;
249 break;
250 }
251 offset += ret;
252 }
253}
254
255void route_vty_out_flowspec(struct vty *vty, struct prefix *p,
9b6d8fcf 256 struct bgp_path_info *path, int display,
4b7e6066 257 json_object *json_paths)
dba3c1d3
PG
258{
259 struct attr *attr;
260 char return_string[BGP_FLOWSPEC_STRING_DISPLAY_MAX];
261 char *s;
d33fc23b
PG
262 json_object *json_nlri_path = NULL;
263 json_object *json_ecom_path = NULL;
264 json_object *json_time_path = NULL;
265 char timebuf[BGP_UPTIME_LEN];
dba3c1d3
PG
266
267 /* Print prefix */
268 if (p != NULL) {
269 if (p->family != AF_FLOWSPEC)
270 return;
d33fc23b
PG
271 if (json_paths) {
272 if (display == NLRI_STRING_FORMAT_JSON)
273 json_nlri_path = json_object_new_object();
274 else
275 json_nlri_path = json_paths;
276 }
9b6d8fcf 277 if (display == NLRI_STRING_FORMAT_LARGE && path)
dba3c1d3 278 vty_out(vty, "BGP flowspec entry: (flags 0x%x)\n",
9b6d8fcf 279 path->flags);
dba3c1d3
PG
280 bgp_fs_nlri_get_string((unsigned char *)
281 p->u.prefix_flowspec.ptr,
282 p->u.prefix_flowspec.prefixlen,
283 return_string,
d33fc23b
PG
284 display,
285 json_nlri_path);
dba3c1d3
PG
286 if (display == NLRI_STRING_FORMAT_LARGE)
287 vty_out(vty, "%s", return_string);
288 else if (display == NLRI_STRING_FORMAT_DEBUG)
289 vty_out(vty, "%s", return_string);
d33fc23b 290 else if (display == NLRI_STRING_FORMAT_MIN)
dba3c1d3 291 vty_out(vty, " %-30s", return_string);
d33fc23b
PG
292 else if (json_paths && display == NLRI_STRING_FORMAT_JSON)
293 json_object_array_add(json_paths, json_nlri_path);
dba3c1d3 294 }
9b6d8fcf 295 if (!path)
dba3c1d3 296 return;
9b6d8fcf 297 if (path->attr && path->attr->ecommunity) {
dba3c1d3 298 /* Print attribute */
9b6d8fcf 299 attr = path->attr;
dba3c1d3
PG
300 s = ecommunity_ecom2str(attr->ecommunity,
301 ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
302 if (!s)
303 return;
304 if (display == NLRI_STRING_FORMAT_LARGE)
305 vty_out(vty, "\t%s\n", s);
d33fc23b 306 else if (display == NLRI_STRING_FORMAT_MIN)
dba3c1d3 307 vty_out(vty, "%s", s);
d33fc23b
PG
308 else if (json_paths) {
309 json_ecom_path = json_object_new_object();
310 json_object_string_add(json_ecom_path,
311 "ecomlist", s);
312 if (display == NLRI_STRING_FORMAT_JSON)
313 json_object_array_add(json_paths,
314 json_ecom_path);
315 }
026b914a
PG
316 if (attr->nexthop.s_addr != 0 &&
317 display == NLRI_STRING_FORMAT_LARGE)
2551b26e
PG
318 vty_out(vty, "\tNLRI NH %-16s\n",
319 inet_ntoa(attr->nexthop));
dba3c1d3
PG
320 XFREE(MTYPE_ECOMMUNITY_STR, s);
321 }
9b6d8fcf 322 peer_uptime(path->uptime, timebuf, BGP_UPTIME_LEN, 0, NULL);
b588b642
PG
323 if (display == NLRI_STRING_FORMAT_LARGE) {
324 vty_out(vty, "\treceived for %8s\n", timebuf);
325 } else if (json_paths) {
d33fc23b
PG
326 json_time_path = json_object_new_object();
327 json_object_string_add(json_time_path,
328 "time", timebuf);
329 if (display == NLRI_STRING_FORMAT_JSON)
330 json_object_array_add(json_paths, json_time_path);
dba3c1d3 331 }
b588b642 332 if (display == NLRI_STRING_FORMAT_LARGE) {
18ee8310 333 struct bgp_path_info_extra *extra =
9b6d8fcf 334 bgp_path_info_extra_get(path);
dba3c1d3 335
b588b642 336 if (extra->bgp_fs_pbr) {
c26edcda 337 struct listnode *node;
b588b642
PG
338 struct bgp_pbr_match_entry *bpme;
339 struct bgp_pbr_match *bpm;
503d1ec6 340 bool list_began = false;
c26edcda 341 struct list *list_bpm;
b588b642 342
c26edcda
PG
343 list_bpm = list_new();
344 if (listcount(extra->bgp_fs_pbr))
345 vty_out(vty, "\tinstalled in PBR");
346 for (ALL_LIST_ELEMENTS_RO(extra->bgp_fs_pbr,
347 node, bpme)) {
348 bpm = bpme->backpointer;
349 if (listnode_lookup(list_bpm, bpm))
350 continue;
351 listnode_add(list_bpm, bpm);
503d1ec6 352 if (!list_began) {
c26edcda 353 vty_out(vty, " (");
503d1ec6
PG
354 list_began = true;
355 } else
c26edcda
PG
356 vty_out(vty, ", ");
357 vty_out(vty, "%s", bpm->ipset_name);
c26edcda 358 }
503d1ec6 359 if (list_began)
c26edcda
PG
360 vty_out(vty, ")");
361 vty_out(vty, "\n");
6a154c88 362 list_delete(&list_bpm);
b588b642
PG
363 } else
364 vty_out(vty, "\tnot installed in PBR\n");
365 }
dba3c1d3
PG
366}
367
368int bgp_show_table_flowspec(struct vty *vty, struct bgp *bgp, afi_t afi,
369 struct bgp_table *table, enum bgp_show_type type,
088f1098
DS
370 void *output_arg, bool use_json, int is_last,
371 unsigned long *output_cum, unsigned long *total_cum)
dba3c1d3 372{
40381db7 373 struct bgp_path_info *pi;
dba3c1d3
PG
374 struct bgp_node *rn;
375 unsigned long total_count = 0;
376 json_object *json_paths = NULL;
d33fc23b 377 int display = NLRI_STRING_FORMAT_LARGE;
dba3c1d3
PG
378
379 if (type != bgp_show_type_detail)
380 return CMD_SUCCESS;
381
dba3c1d3 382 for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
6f94b685
DS
383 pi = bgp_node_get_bgp_path_info(rn);
384 if (pi == NULL)
dba3c1d3 385 continue;
d33fc23b
PG
386 if (use_json) {
387 json_paths = json_object_new_array();
388 display = NLRI_STRING_FORMAT_JSON;
389 }
6f94b685 390 for (; pi; pi = pi->next) {
dba3c1d3 391 total_count++;
40381db7 392 route_vty_out_flowspec(vty, &rn->p, pi, display,
dba3c1d3 393 json_paths);
dba3c1d3 394 }
d33fc23b
PG
395 if (use_json) {
396 vty_out(vty, "%s\n",
397 json_object_to_json_string_ext(
398 json_paths,
399 JSON_C_TO_STRING_PRETTY));
400 json_object_free(json_paths);
401 json_paths = NULL;
402 }
dba3c1d3 403 }
d33fc23b 404 if (total_count && !use_json)
dba3c1d3
PG
405 vty_out(vty,
406 "\nDisplayed %ld flowspec entries\n",
407 total_count);
408 return CMD_SUCCESS;
409}
410
268e1b9b
PG
411DEFUN (debug_bgp_flowspec,
412 debug_bgp_flowspec_cmd,
413 "debug bgp flowspec",
414 DEBUG_STR
415 BGP_STR
416 "BGP allow flowspec debugging entries\n")
417{
418 if (vty->node == CONFIG_NODE)
419 DEBUG_ON(flowspec, FLOWSPEC);
420 else {
421 TERM_DEBUG_ON(flowspec, FLOWSPEC);
422 vty_out(vty, "BGP flowspec debugging is on\n");
423 }
424 return CMD_SUCCESS;
425}
426
427DEFUN (no_debug_bgp_flowspec,
428 no_debug_bgp_flowspec_cmd,
429 "no debug bgp flowspec",
430 NO_STR
431 DEBUG_STR
432 BGP_STR
433 "BGP allow flowspec debugging entries\n")
434{
435 if (vty->node == CONFIG_NODE)
436 DEBUG_OFF(flowspec, FLOWSPEC);
437 else {
438 TERM_DEBUG_OFF(flowspec, FLOWSPEC);
439 vty_out(vty, "BGP flowspec debugging is off\n");
440 }
441 return CMD_SUCCESS;
442}
443
4762c213
PG
444int bgp_fs_config_write_pbr(struct vty *vty, struct bgp *bgp,
445 afi_t afi, safi_t safi)
446{
447 struct bgp_pbr_interface *pbr_if;
448 bool declare_node = false;
449 struct bgp_pbr_config *bgp_pbr_cfg = bgp->bgp_pbr_cfg;
450 struct bgp_pbr_interface_head *head;
451 bool bgp_pbr_interface_any;
452
453 if (!bgp_pbr_cfg || safi != SAFI_FLOWSPEC || afi != AFI_IP)
454 return 0;
455 head = &(bgp_pbr_cfg->ifaces_by_name_ipv4);
456 bgp_pbr_interface_any = bgp_pbr_cfg->pbr_interface_any_ipv4;
457 if (!RB_EMPTY(bgp_pbr_interface_head, head) ||
458 !bgp_pbr_interface_any)
459 declare_node = true;
460 RB_FOREACH (pbr_if, bgp_pbr_interface_head, head) {
461 vty_out(vty, " local-install %s\n", pbr_if->name);
462 }
4762c213
PG
463 return declare_node ? 1 : 0;
464}
465
466static int bgp_fs_local_install_interface(struct bgp *bgp,
467 const char *no, const char *ifname)
468{
469 struct bgp_pbr_interface *pbr_if;
470 struct bgp_pbr_config *bgp_pbr_cfg = bgp->bgp_pbr_cfg;
471 struct bgp_pbr_interface_head *head;
472 bool *bgp_pbr_interface_any;
473
474 if (!bgp_pbr_cfg)
475 return CMD_SUCCESS;
476 head = &(bgp_pbr_cfg->ifaces_by_name_ipv4);
477 bgp_pbr_interface_any = &(bgp_pbr_cfg->pbr_interface_any_ipv4);
478 if (no) {
479 if (!ifname) {
480 if (*bgp_pbr_interface_any) {
481 *bgp_pbr_interface_any = false;
482 /* remove all other interface list */
483 bgp_pbr_reset(bgp, AFI_IP);
484 }
485 return CMD_SUCCESS;
486 }
487 pbr_if = bgp_pbr_interface_lookup(ifname, head);
488 if (!pbr_if)
489 return CMD_SUCCESS;
490 RB_REMOVE(bgp_pbr_interface_head, head, pbr_if);
491 return CMD_SUCCESS;
492 }
493 if (ifname) {
494 pbr_if = bgp_pbr_interface_lookup(ifname, head);
495 if (pbr_if)
496 return CMD_SUCCESS;
497 pbr_if = XCALLOC(MTYPE_TMP,
498 sizeof(struct bgp_pbr_interface));
499 strlcpy(pbr_if->name, ifname, INTERFACE_NAMSIZ);
500 RB_INSERT(bgp_pbr_interface_head, head, pbr_if);
501 *bgp_pbr_interface_any = false;
502 } else {
503 /* set to default */
504 if (!*bgp_pbr_interface_any) {
505 /* remove all other interface list
506 */
507 bgp_pbr_reset(bgp, AFI_IP);
508 *bgp_pbr_interface_any = true;
509 }
510 }
511 return CMD_SUCCESS;
512}
513
514DEFUN (bgp_fs_local_install_ifname,
515 bgp_fs_local_install_ifname_cmd,
516 "[no] local-install INTERFACE",
517 NO_STR
518 "Apply local policy routing\n"
519 "Interface name\n")
520{
521 struct bgp *bgp = VTY_GET_CONTEXT(bgp);
522 int idx = 0;
36de6e0e 523 const char *no = strmatch(argv[0]->text, "no") ? "no" : NULL;
4762c213
PG
524 char *ifname = argv_find(argv, argc, "INTERFACE", &idx) ?
525 argv[idx]->arg : NULL;
526
527 return bgp_fs_local_install_interface(bgp, no, ifname);
528}
529
088f1098
DS
530extern int bgp_flowspec_display_match_per_ip(afi_t afi, struct bgp_table *rib,
531 struct prefix *match,
532 int prefix_check, struct vty *vty,
533 bool use_json,
534 json_object *json_paths)
63a0b7a9
PG
535{
536 struct bgp_node *rn;
537 struct prefix *prefix;
538 int display = 0;
539
540 for (rn = bgp_table_top(rib); rn; rn = bgp_route_next(rn)) {
541 prefix = &rn->p;
542
543 if (prefix->family != AF_FLOWSPEC)
544 continue;
545
546 if (bgp_flowspec_contains_prefix(prefix, match, prefix_check)) {
6f94b685
DS
547 route_vty_out_flowspec(
548 vty, &rn->p, bgp_node_get_bgp_path_info(rn),
549 use_json ? NLRI_STRING_FORMAT_JSON
550 : NLRI_STRING_FORMAT_LARGE,
551 json_paths);
63a0b7a9
PG
552 display++;
553 }
554 }
555 return display;
556}
557
dba3c1d3
PG
558void bgp_flowspec_vty_init(void)
559{
268e1b9b
PG
560 install_element(ENABLE_NODE, &debug_bgp_flowspec_cmd);
561 install_element(CONFIG_NODE, &debug_bgp_flowspec_cmd);
562 install_element(ENABLE_NODE, &no_debug_bgp_flowspec_cmd);
563 install_element(CONFIG_NODE, &no_debug_bgp_flowspec_cmd);
4762c213 564 install_element(BGP_FLOWSPECV4_NODE, &bgp_fs_local_install_ifname_cmd);
dba3c1d3 565}