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"},
56 static 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"},
65 {FLOWSPEC_TCP_FLAGS
, "tcp"},
66 {FLOWSPEC_PKT_LEN
, "pktlen"},
67 {FLOWSPEC_DSCP
, "dscp"},
68 {FLOWSPEC_FRAGMENT
, "pktfrag"},
72 #define FS_STRING_UPDATE(count, ptr, format, remaining_len) do { \
75 if (((format) == NLRI_STRING_FORMAT_DEBUG) && (count)) {\
76 _len_written = snprintf((ptr), (remaining_len), \
78 (remaining_len) -= _len_written; \
79 (ptr) += _len_written; \
80 } else if (((format) == NLRI_STRING_FORMAT_MIN) \
82 _len_written = snprintf((ptr), (remaining_len), \
84 (remaining_len) -= _len_written; \
85 (ptr) += _len_written; \
90 /* Parse FLOWSPEC NLRI
91 * passed return_string string has assumed length
92 * BGP_FLOWSPEC_STRING_DISPLAY_MAX
94 void bgp_fs_nlri_get_string(unsigned char *nlri_content
, size_t len
,
95 char *return_string
, int format
,
96 json_object
*json_path
)
100 int ret
= 0, error
= 0;
101 char *ptr
= return_string
;
102 char local_string
[BGP_FLOWSPEC_STRING_DISPLAY_MAX
];
105 char pre_extra
[2] = "";
106 const struct message
*bgp_flowspec_display
;
107 enum bgp_flowspec_util_nlri_t type_util
;
108 int len_string
= BGP_FLOWSPEC_STRING_DISPLAY_MAX
;
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
;
116 bgp_flowspec_display
= bgp_flowspec_display_min
;
117 /* if needed. type_util can be set to other values */
118 type_util
= BGP_FLOWSPEC_RETURN_STRING
;
120 while (offset
< len
-1 && error
>= 0) {
121 type
= nlri_content
[offset
];
124 case FLOWSPEC_DEST_PREFIX
:
125 case FLOWSPEC_SRC_PREFIX
:
126 ret
= bgp_flowspec_ip_address(
130 local_string
, &error
);
134 json_object_string_add(json_path
,
135 lookup_msg(bgp_flowspec_display
, type
, ""),
139 FS_STRING_UPDATE(count
, ptr
, format
, len_string
);
140 len_written
= snprintf(ptr
, len_string
, "%s%s %s%s",
142 lookup_msg(bgp_flowspec_display
,
144 local_string
, extra
);
145 len_string
-= len_written
;
148 case FLOWSPEC_IP_PROTOCOL
:
150 case FLOWSPEC_DEST_PORT
:
151 case FLOWSPEC_SRC_PORT
:
152 case FLOWSPEC_ICMP_TYPE
:
153 case FLOWSPEC_ICMP_CODE
:
154 ret
= bgp_flowspec_op_decode(type_util
,
157 local_string
, &error
);
161 json_object_string_add(json_path
,
162 lookup_msg(bgp_flowspec_display
, type
, ""),
166 FS_STRING_UPDATE(count
, ptr
, format
, len_string
);
167 len_written
= snprintf(ptr
, len_string
, "%s%s %s%s",
169 lookup_msg(bgp_flowspec_display
,
171 local_string
, extra
);
172 len_string
-= len_written
;
175 case FLOWSPEC_TCP_FLAGS
:
176 ret
= bgp_flowspec_bitmask_decode(
180 local_string
, &error
);
184 json_object_string_add(json_path
,
185 lookup_msg(bgp_flowspec_display
,
190 FS_STRING_UPDATE(count
, ptr
, format
, len_string
);
191 len_written
= snprintf(ptr
, len_string
, "%s%s %s%s",
193 lookup_msg(bgp_flowspec_display
,
195 local_string
, extra
);
196 len_string
-= len_written
;
199 case FLOWSPEC_PKT_LEN
:
201 ret
= bgp_flowspec_op_decode(
203 nlri_content
+ offset
,
204 len
- offset
, local_string
,
209 json_object_string_add(json_path
,
210 lookup_msg(bgp_flowspec_display
, type
, ""),
214 FS_STRING_UPDATE(count
, ptr
, format
, len_string
);
215 len_written
= snprintf(ptr
, len_string
, "%s%s %s%s",
217 lookup_msg(bgp_flowspec_display
,
219 local_string
, extra
);
220 len_string
-= len_written
;
223 case FLOWSPEC_FRAGMENT
:
224 ret
= bgp_flowspec_bitmask_decode(
228 local_string
, &error
);
232 json_object_string_add(json_path
,
233 lookup_msg(bgp_flowspec_display
,
238 FS_STRING_UPDATE(count
, ptr
, format
, len_string
);
239 len_written
= snprintf(ptr
, len_string
, "%s%s %s%s",
241 lookup_msg(bgp_flowspec_display
,
243 local_string
, extra
);
244 len_string
-= len_written
;
255 void route_vty_out_flowspec(struct vty
*vty
, struct prefix
*p
,
256 struct bgp_info
*binfo
,
257 int display
, json_object
*json_paths
)
260 char return_string
[BGP_FLOWSPEC_STRING_DISPLAY_MAX
];
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
];
269 if (p
->family
!= AF_FLOWSPEC
)
272 if (display
== NLRI_STRING_FORMAT_JSON
)
273 json_nlri_path
= json_object_new_object();
275 json_nlri_path
= json_paths
;
277 if (display
== NLRI_STRING_FORMAT_LARGE
&& binfo
)
278 vty_out(vty
, "BGP flowspec entry: (flags 0x%x)\n",
280 bgp_fs_nlri_get_string((unsigned char *)
281 p
->u
.prefix_flowspec
.ptr
,
282 p
->u
.prefix_flowspec
.prefixlen
,
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
);
290 else if (display
== NLRI_STRING_FORMAT_MIN
)
291 vty_out(vty
, " %-30s", return_string
);
292 else if (json_paths
&& display
== NLRI_STRING_FORMAT_JSON
)
293 json_object_array_add(json_paths
, json_nlri_path
);
297 if (binfo
->attr
&& binfo
->attr
->ecommunity
) {
298 /* Print attribute */
300 s
= ecommunity_ecom2str(attr
->ecommunity
,
301 ECOMMUNITY_FORMAT_ROUTE_MAP
, 0);
304 if (display
== NLRI_STRING_FORMAT_LARGE
)
305 vty_out(vty
, "\t%s\n", s
);
306 else if (display
== NLRI_STRING_FORMAT_MIN
)
307 vty_out(vty
, "%s", s
);
308 else if (json_paths
) {
309 json_ecom_path
= json_object_new_object();
310 json_object_string_add(json_ecom_path
,
312 if (display
== NLRI_STRING_FORMAT_JSON
)
313 json_object_array_add(json_paths
,
316 if (attr
->nexthop
.s_addr
!= 0 &&
317 display
== NLRI_STRING_FORMAT_LARGE
)
318 vty_out(vty
, "\tNH %-16s\n", inet_ntoa(attr
->nexthop
));
319 XFREE(MTYPE_ECOMMUNITY_STR
, s
);
321 peer_uptime(binfo
->uptime
, timebuf
, BGP_UPTIME_LEN
, 0, NULL
);
322 if (display
== NLRI_STRING_FORMAT_LARGE
) {
323 vty_out(vty
, "\treceived for %8s\n", timebuf
);
324 } else if (json_paths
) {
325 json_time_path
= json_object_new_object();
326 json_object_string_add(json_time_path
,
328 if (display
== NLRI_STRING_FORMAT_JSON
)
329 json_object_array_add(json_paths
, json_time_path
);
331 if (display
== NLRI_STRING_FORMAT_LARGE
) {
332 struct bgp_info_extra
*extra
= bgp_info_extra_get(binfo
);
334 if (extra
->bgp_fs_pbr
) {
335 struct listnode
*node
;
336 struct bgp_pbr_match_entry
*bpme
;
337 struct bgp_pbr_match
*bpm
;
338 bool list_began
= false;
339 struct list
*list_bpm
;
341 list_bpm
= list_new();
342 if (listcount(extra
->bgp_fs_pbr
))
343 vty_out(vty
, "\tinstalled in PBR");
344 for (ALL_LIST_ELEMENTS_RO(extra
->bgp_fs_pbr
,
346 bpm
= bpme
->backpointer
;
347 if (listnode_lookup(list_bpm
, bpm
))
349 listnode_add(list_bpm
, bpm
);
355 vty_out(vty
, "%s", bpm
->ipset_name
);
360 list_delete_and_null(&list_bpm
);
362 vty_out(vty
, "\tnot installed in PBR\n");
366 int bgp_show_table_flowspec(struct vty
*vty
, struct bgp
*bgp
, afi_t afi
,
367 struct bgp_table
*table
, enum bgp_show_type type
,
368 void *output_arg
, bool use_json
, int is_last
,
369 unsigned long *output_cum
, unsigned long *total_cum
)
373 unsigned long total_count
= 0;
374 json_object
*json_paths
= NULL
;
375 int display
= NLRI_STRING_FORMAT_LARGE
;
377 if (type
!= bgp_show_type_detail
)
380 for (rn
= bgp_table_top(table
); rn
; rn
= bgp_route_next(rn
)) {
381 if (rn
->info
== NULL
)
384 json_paths
= json_object_new_array();
385 display
= NLRI_STRING_FORMAT_JSON
;
387 for (ri
= rn
->info
; ri
; ri
= ri
->next
) {
389 route_vty_out_flowspec(vty
, &rn
->p
,
396 json_object_to_json_string_ext(
398 JSON_C_TO_STRING_PRETTY
));
399 json_object_free(json_paths
);
403 if (total_count
&& !use_json
)
405 "\nDisplayed %ld flowspec entries\n",
410 DEFUN (debug_bgp_flowspec
,
411 debug_bgp_flowspec_cmd
,
412 "debug bgp flowspec",
415 "BGP allow flowspec debugging entries\n")
417 if (vty
->node
== CONFIG_NODE
)
418 DEBUG_ON(flowspec
, FLOWSPEC
);
420 TERM_DEBUG_ON(flowspec
, FLOWSPEC
);
421 vty_out(vty
, "BGP flowspec debugging is on\n");
426 DEFUN (no_debug_bgp_flowspec
,
427 no_debug_bgp_flowspec_cmd
,
428 "no debug bgp flowspec",
432 "BGP allow flowspec debugging entries\n")
434 if (vty
->node
== CONFIG_NODE
)
435 DEBUG_OFF(flowspec
, FLOWSPEC
);
437 TERM_DEBUG_OFF(flowspec
, FLOWSPEC
);
438 vty_out(vty
, "BGP flowspec debugging is off\n");
443 int bgp_fs_config_write_pbr(struct vty
*vty
, struct bgp
*bgp
,
444 afi_t afi
, safi_t safi
)
446 struct bgp_pbr_interface
*pbr_if
;
447 bool declare_node
= false;
448 struct bgp_pbr_config
*bgp_pbr_cfg
= bgp
->bgp_pbr_cfg
;
449 struct bgp_pbr_interface_head
*head
;
450 bool bgp_pbr_interface_any
;
452 if (!bgp_pbr_cfg
|| safi
!= SAFI_FLOWSPEC
|| afi
!= AFI_IP
)
454 head
= &(bgp_pbr_cfg
->ifaces_by_name_ipv4
);
455 bgp_pbr_interface_any
= bgp_pbr_cfg
->pbr_interface_any_ipv4
;
456 if (!RB_EMPTY(bgp_pbr_interface_head
, head
) ||
457 !bgp_pbr_interface_any
)
459 RB_FOREACH (pbr_if
, bgp_pbr_interface_head
, head
) {
460 vty_out(vty
, " local-install %s\n", pbr_if
->name
);
462 return declare_node
? 1 : 0;
465 static int bgp_fs_local_install_interface(struct bgp
*bgp
,
466 const char *no
, const char *ifname
)
468 struct bgp_pbr_interface
*pbr_if
;
469 struct bgp_pbr_config
*bgp_pbr_cfg
= bgp
->bgp_pbr_cfg
;
470 struct bgp_pbr_interface_head
*head
;
471 bool *bgp_pbr_interface_any
;
475 head
= &(bgp_pbr_cfg
->ifaces_by_name_ipv4
);
476 bgp_pbr_interface_any
= &(bgp_pbr_cfg
->pbr_interface_any_ipv4
);
479 if (*bgp_pbr_interface_any
) {
480 *bgp_pbr_interface_any
= false;
481 /* remove all other interface list */
482 bgp_pbr_reset(bgp
, AFI_IP
);
486 pbr_if
= bgp_pbr_interface_lookup(ifname
, head
);
489 RB_REMOVE(bgp_pbr_interface_head
, head
, pbr_if
);
493 pbr_if
= bgp_pbr_interface_lookup(ifname
, head
);
496 pbr_if
= XCALLOC(MTYPE_TMP
,
497 sizeof(struct bgp_pbr_interface
));
498 strlcpy(pbr_if
->name
, ifname
, INTERFACE_NAMSIZ
);
499 RB_INSERT(bgp_pbr_interface_head
, head
, pbr_if
);
500 *bgp_pbr_interface_any
= false;
503 if (!*bgp_pbr_interface_any
) {
504 /* remove all other interface list
506 bgp_pbr_reset(bgp
, AFI_IP
);
507 *bgp_pbr_interface_any
= true;
513 DEFUN (bgp_fs_local_install_ifname
,
514 bgp_fs_local_install_ifname_cmd
,
515 "[no] local-install INTERFACE",
517 "Apply local policy routing\n"
520 struct bgp
*bgp
= VTY_GET_CONTEXT(bgp
);
522 const char *no
= strmatch(argv
[0]->text
, "no") ? "no" : NULL
;
523 char *ifname
= argv_find(argv
, argc
, "INTERFACE", &idx
) ?
524 argv
[idx
]->arg
: NULL
;
526 return bgp_fs_local_install_interface(bgp
, no
, ifname
);
529 extern int bgp_flowspec_display_match_per_ip(afi_t afi
, struct bgp_table
*rib
,
530 struct prefix
*match
,
531 int prefix_check
, struct vty
*vty
,
533 json_object
*json_paths
)
536 struct prefix
*prefix
;
539 for (rn
= bgp_table_top(rib
); rn
; rn
= bgp_route_next(rn
)) {
542 if (prefix
->family
!= AF_FLOWSPEC
)
545 if (bgp_flowspec_contains_prefix(prefix
, match
, prefix_check
)) {
546 route_vty_out_flowspec(vty
, &rn
->p
,
548 NLRI_STRING_FORMAT_JSON
:
549 NLRI_STRING_FORMAT_LARGE
,
557 void bgp_flowspec_vty_init(void)
559 install_element(ENABLE_NODE
, &debug_bgp_flowspec_cmd
);
560 install_element(CONFIG_NODE
, &debug_bgp_flowspec_cmd
);
561 install_element(ENABLE_NODE
, &no_debug_bgp_flowspec_cmd
);
562 install_element(CONFIG_NODE
, &no_debug_bgp_flowspec_cmd
);
563 install_element(BGP_FLOWSPECV4_NODE
, &bgp_fs_local_install_ifname_cmd
);