2 * Copyright (C) 2018 6WIND
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
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.
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
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"
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
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"},
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"},
74 #define FS_STRING_UPDATE(count, ptr, format, remaining_len) do { \
77 if (((format) == NLRI_STRING_FORMAT_DEBUG) && (count)) {\
78 _len_written = snprintf((ptr), (remaining_len), \
80 (remaining_len) -= _len_written; \
81 (ptr) += _len_written; \
82 } else if (((format) == NLRI_STRING_FORMAT_MIN) \
84 _len_written = snprintf((ptr), (remaining_len), \
86 (remaining_len) -= _len_written; \
87 (ptr) += _len_written; \
92 /* Parse FLOWSPEC NLRI
93 * passed return_string string has assumed length
94 * BGP_FLOWSPEC_STRING_DISPLAY_MAX
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
,
103 int ret
= 0, error
= 0;
104 char *ptr
= return_string
;
105 char local_string
[BGP_FLOWSPEC_STRING_DISPLAY_MAX
];
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
;
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
;
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
;
123 while (offset
< len
-1 && error
>= 0) {
124 type
= nlri_content
[offset
];
127 case FLOWSPEC_DEST_PREFIX
:
128 case FLOWSPEC_SRC_PREFIX
:
129 ret
= bgp_flowspec_ip_address(
133 local_string
, &error
,
138 json_object_string_add(json_path
,
139 lookup_msg(bgp_flowspec_display
, type
, ""),
143 FS_STRING_UPDATE(count
, ptr
, format
, len_string
);
144 len_written
= snprintf(ptr
, len_string
, "%s%s %s%s",
146 lookup_msg(bgp_flowspec_display
,
148 local_string
, extra
);
149 len_string
-= len_written
;
152 case FLOWSPEC_FLOW_LABEL
:
153 case FLOWSPEC_IP_PROTOCOL
:
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
,
162 local_string
, &error
);
166 json_object_string_add(json_path
,
167 lookup_msg(bgp_flowspec_display
, type
, ""),
171 FS_STRING_UPDATE(count
, ptr
, format
, len_string
);
172 len_written
= snprintf(ptr
, len_string
, "%s%s %s%s",
174 lookup_msg(bgp_flowspec_display
,
176 local_string
, extra
);
177 len_string
-= len_written
;
180 case FLOWSPEC_TCP_FLAGS
:
181 ret
= bgp_flowspec_bitmask_decode(
185 local_string
, &error
);
189 json_object_string_add(json_path
,
190 lookup_msg(bgp_flowspec_display
,
195 FS_STRING_UPDATE(count
, ptr
, format
, len_string
);
196 len_written
= snprintf(ptr
, len_string
, "%s%s %s%s",
198 lookup_msg(bgp_flowspec_display
,
200 local_string
, extra
);
201 len_string
-= len_written
;
204 case FLOWSPEC_PKT_LEN
:
206 ret
= bgp_flowspec_op_decode(
208 nlri_content
+ offset
,
209 len
- offset
, local_string
,
214 json_object_string_add(json_path
,
215 lookup_msg(bgp_flowspec_display
, type
, ""),
219 FS_STRING_UPDATE(count
, ptr
, format
, len_string
);
220 len_written
= snprintf(ptr
, len_string
, "%s%s %s%s",
222 lookup_msg(bgp_flowspec_display
,
224 local_string
, extra
);
225 len_string
-= len_written
;
228 case FLOWSPEC_FRAGMENT
:
229 ret
= bgp_flowspec_bitmask_decode(
233 local_string
, &error
);
237 json_object_string_add(json_path
,
238 lookup_msg(bgp_flowspec_display
,
243 FS_STRING_UPDATE(count
, ptr
, format
, len_string
);
244 len_written
= snprintf(ptr
, len_string
, "%s%s %s%s",
246 lookup_msg(bgp_flowspec_display
,
248 local_string
, extra
);
249 len_string
-= len_written
;
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
)
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 bgp_dest
*dest
= NULL
;
276 bgp_dest_get_bgp_table_info(dest
);
277 if (p
== NULL
|| p
->family
!= AF_FLOWSPEC
)
280 if (display
== NLRI_STRING_FORMAT_JSON
)
281 json_nlri_path
= json_object_new_object();
283 json_nlri_path
= json_paths
;
285 if (display
== NLRI_STRING_FORMAT_LARGE
&& path
)
286 vty_out(vty
, "BGP flowspec entry: (flags 0x%x)\n",
288 bgp_fs_nlri_get_string((unsigned char *)
289 p
->u
.prefix_flowspec
.ptr
,
290 p
->u
.prefix_flowspec
.prefixlen
,
294 family2afi(p
->u
.prefix_flowspec
296 if (display
== NLRI_STRING_FORMAT_LARGE
)
297 vty_out(vty
, "%s", return_string
);
298 else if (display
== NLRI_STRING_FORMAT_DEBUG
)
299 vty_out(vty
, "%s", return_string
);
300 else if (display
== NLRI_STRING_FORMAT_MIN
)
301 vty_out(vty
, " %-30s", return_string
);
302 else if (json_paths
&& display
== NLRI_STRING_FORMAT_JSON
)
303 json_object_array_add(json_paths
, json_nlri_path
);
307 (path
->attr
->ecommunity
|| path
->attr
->ipv6_ecommunity
)) {
308 /* Print attribute */
310 if (attr
->ecommunity
)
311 s1
= ecommunity_ecom2str(attr
->ecommunity
,
312 ECOMMUNITY_FORMAT_ROUTE_MAP
, 0);
313 if (attr
->ipv6_ecommunity
)
314 s2
= ecommunity_ecom2str(attr
->ipv6_ecommunity
,
315 ECOMMUNITY_FORMAT_ROUTE_MAP
, 0);
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();
326 json_object_string_add(json_ecom_path
,
329 json_object_string_add(json_ecom_path
,
331 if (display
== NLRI_STRING_FORMAT_JSON
)
332 json_object_array_add(json_paths
,
335 if (display
== NLRI_STRING_FORMAT_LARGE
) {
336 char local_buff
[INET6_ADDRSTRLEN
];
338 local_buff
[0] = '\0';
339 if (p
->u
.prefix_flowspec
.family
== AF_INET
&&
340 attr
->nexthop
.s_addr
!= 0)
342 &attr
->nexthop
.s_addr
,
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
)
350 &attr
->mp_nexthop_global
,
353 if (local_buff
[0] != '\0')
354 vty_out(vty
, "\tNLRI NH %s\n",
357 XFREE(MTYPE_ECOMMUNITY_STR
, s1
);
358 XFREE(MTYPE_ECOMMUNITY_STR
, s2
);
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
,
367 if (display
== NLRI_STRING_FORMAT_JSON
)
368 json_object_array_add(json_paths
, json_time_path
);
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;
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
;
381 list_bpm
= list_new();
382 vty_out(vty
, "\tinstalled in PBR");
383 for (ALL_LIST_ELEMENTS_RO(extra
->bgp_fs_pbr
,
385 bpm
= bpme
->backpointer
;
386 if (listnode_lookup(list_bpm
, bpm
))
388 listnode_add(list_bpm
, bpm
);
394 vty_out(vty
, "%s", bpm
->ipset_name
);
396 list_delete(&list_bpm
);
398 if (extra
->bgp_fs_iprule
&& listcount(extra
->bgp_fs_iprule
)) {
399 struct listnode
*node
;
400 struct bgp_pbr_rule
*bpr
;
403 vty_out(vty
, "\tinstalled in PBR");
404 for (ALL_LIST_ELEMENTS_RO(extra
->bgp_fs_iprule
,
413 vty_out(vty
, "-ipv4-rule %d action lookup %u-",
415 bpr
->action
->table_id
);
421 vty_out(vty
, "\tnot installed in PBR\n");
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
)
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
;
436 if (type
!= bgp_show_type_detail
)
439 for (dest
= bgp_table_top(table
); dest
; dest
= bgp_route_next(dest
)) {
440 pi
= bgp_dest_get_bgp_path_info(dest
);
444 json_paths
= json_object_new_array();
445 display
= NLRI_STRING_FORMAT_JSON
;
447 for (; pi
; pi
= pi
->next
) {
449 route_vty_out_flowspec(vty
, bgp_dest_get_prefix(dest
),
450 pi
, display
, json_paths
);
454 json_object_to_json_string_ext(
456 JSON_C_TO_STRING_PRETTY
));
457 json_object_free(json_paths
);
461 if (total_count
&& !use_json
)
463 "\nDisplayed %ld flowspec entries\n",
468 DEFUN (debug_bgp_flowspec
,
469 debug_bgp_flowspec_cmd
,
470 "debug bgp flowspec",
473 "BGP allow flowspec debugging entries\n")
475 if (vty
->node
== CONFIG_NODE
)
476 DEBUG_ON(flowspec
, FLOWSPEC
);
478 TERM_DEBUG_ON(flowspec
, FLOWSPEC
);
479 vty_out(vty
, "BGP flowspec debugging is on\n");
484 DEFUN (no_debug_bgp_flowspec
,
485 no_debug_bgp_flowspec_cmd
,
486 "no debug bgp flowspec",
490 "BGP allow flowspec debugging entries\n")
492 if (vty
->node
== CONFIG_NODE
)
493 DEBUG_OFF(flowspec
, FLOWSPEC
);
495 TERM_DEBUG_OFF(flowspec
, FLOWSPEC
);
496 vty_out(vty
, "BGP flowspec debugging is off\n");
501 int bgp_fs_config_write_pbr(struct vty
*vty
, struct bgp
*bgp
,
502 afi_t afi
, safi_t safi
)
504 struct bgp_pbr_interface
*pbr_if
;
505 bool declare_node
= false;
506 struct bgp_pbr_config
*bgp_pbr_cfg
= bgp
->bgp_pbr_cfg
;
507 struct bgp_pbr_interface_head
*head
;
508 bool bgp_pbr_interface_any
;
510 if (!bgp_pbr_cfg
|| safi
!= SAFI_FLOWSPEC
)
513 head
= &(bgp_pbr_cfg
->ifaces_by_name_ipv4
);
514 bgp_pbr_interface_any
= bgp_pbr_cfg
->pbr_interface_any_ipv4
;
515 } else if (afi
== AFI_IP6
) {
516 head
= &(bgp_pbr_cfg
->ifaces_by_name_ipv6
);
517 bgp_pbr_interface_any
= bgp_pbr_cfg
->pbr_interface_any_ipv6
;
521 if (!RB_EMPTY(bgp_pbr_interface_head
, head
) ||
522 !bgp_pbr_interface_any
)
524 RB_FOREACH (pbr_if
, bgp_pbr_interface_head
, head
) {
525 vty_out(vty
, " local-install %s\n", pbr_if
->name
);
527 return declare_node
? 1 : 0;
530 static int bgp_fs_local_install_interface(struct bgp
*bgp
,
531 const char *no
, const char *ifname
,
534 struct bgp_pbr_interface
*pbr_if
;
535 struct bgp_pbr_config
*bgp_pbr_cfg
= bgp
->bgp_pbr_cfg
;
536 struct bgp_pbr_interface_head
*head
;
537 bool *bgp_pbr_interface_any
;
542 head
= &(bgp_pbr_cfg
->ifaces_by_name_ipv4
);
543 bgp_pbr_interface_any
= &(bgp_pbr_cfg
->pbr_interface_any_ipv4
);
545 head
= &(bgp_pbr_cfg
->ifaces_by_name_ipv6
);
546 bgp_pbr_interface_any
= &(bgp_pbr_cfg
->pbr_interface_any_ipv6
);
550 if (*bgp_pbr_interface_any
) {
551 *bgp_pbr_interface_any
= false;
552 /* remove all other interface list */
553 bgp_pbr_reset(bgp
, afi
);
557 pbr_if
= bgp_pbr_interface_lookup(ifname
, head
);
560 RB_REMOVE(bgp_pbr_interface_head
, head
, pbr_if
);
564 pbr_if
= bgp_pbr_interface_lookup(ifname
, head
);
567 pbr_if
= XCALLOC(MTYPE_TMP
,
568 sizeof(struct bgp_pbr_interface
));
569 strlcpy(pbr_if
->name
, ifname
, INTERFACE_NAMSIZ
);
570 RB_INSERT(bgp_pbr_interface_head
, head
, pbr_if
);
571 *bgp_pbr_interface_any
= false;
574 if (!*bgp_pbr_interface_any
) {
575 /* remove all other interface list
577 bgp_pbr_reset(bgp
, afi
);
578 *bgp_pbr_interface_any
= true;
584 DEFUN (bgp_fs_local_install_ifname
,
585 bgp_fs_local_install_ifname_cmd
,
586 "[no] local-install INTERFACE",
588 "Apply local policy routing\n"
591 struct bgp
*bgp
= VTY_GET_CONTEXT(bgp
);
593 const char *no
= strmatch(argv
[0]->text
, "no") ? "no" : NULL
;
594 char *ifname
= argv_find(argv
, argc
, "INTERFACE", &idx
) ?
595 argv
[idx
]->arg
: NULL
;
597 return bgp_fs_local_install_interface(bgp
, no
, ifname
,
601 extern int bgp_flowspec_display_match_per_ip(afi_t afi
, struct bgp_table
*rib
,
602 struct prefix
*match
,
603 int prefix_check
, struct vty
*vty
,
605 json_object
*json_paths
)
607 struct bgp_dest
*dest
;
608 const struct prefix
*prefix
;
611 for (dest
= bgp_table_top(rib
); dest
; dest
= bgp_route_next(dest
)) {
612 prefix
= bgp_dest_get_prefix(dest
);
614 if (prefix
->family
!= AF_FLOWSPEC
)
617 if (bgp_flowspec_contains_prefix(prefix
, match
, prefix_check
)) {
618 route_vty_out_flowspec(
619 vty
, prefix
, bgp_dest_get_bgp_path_info(dest
),
620 use_json
? NLRI_STRING_FORMAT_JSON
621 : NLRI_STRING_FORMAT_LARGE
,
629 void bgp_flowspec_vty_init(void)
631 install_element(ENABLE_NODE
, &debug_bgp_flowspec_cmd
);
632 install_element(CONFIG_NODE
, &debug_bgp_flowspec_cmd
);
633 install_element(ENABLE_NODE
, &no_debug_bgp_flowspec_cmd
);
634 install_element(CONFIG_NODE
, &no_debug_bgp_flowspec_cmd
);
635 install_element(BGP_FLOWSPECV4_NODE
, &bgp_fs_local_install_ifname_cmd
);
636 install_element(BGP_FLOWSPECV6_NODE
, &bgp_fs_local_install_ifname_cmd
);