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"
34 /* Local Structures and variables declarations
35 * This code block hosts the struct declared that host the flowspec rules
36 * as well as some structure used to convert to stringx
39 static const struct message bgp_flowspec_display_large
[] = {
40 {FLOWSPEC_DEST_PREFIX
, "Destination Address"},
41 {FLOWSPEC_SRC_PREFIX
, "Source Address"},
42 {FLOWSPEC_IP_PROTOCOL
, "IP Protocol"},
43 {FLOWSPEC_PORT
, "Port"},
44 {FLOWSPEC_DEST_PORT
, "Destination Port"},
45 {FLOWSPEC_SRC_PORT
, "Source Port"},
46 {FLOWSPEC_ICMP_TYPE
, "ICMP Type"},
47 {FLOWSPEC_ICMP_CODE
, "ICMP Code"},
48 {FLOWSPEC_TCP_FLAGS
, "TCP Flags"},
49 {FLOWSPEC_PKT_LEN
, "Packet Length"},
50 {FLOWSPEC_DSCP
, "DSCP field"},
51 {FLOWSPEC_FRAGMENT
, "Packet Fragment"},
55 static const struct message bgp_flowspec_display_min
[] = {
56 {FLOWSPEC_DEST_PREFIX
, "to"},
57 {FLOWSPEC_SRC_PREFIX
, "from"},
58 {FLOWSPEC_IP_PROTOCOL
, "proto"},
59 {FLOWSPEC_PORT
, "port"},
60 {FLOWSPEC_DEST_PORT
, "dstp"},
61 {FLOWSPEC_SRC_PORT
, "srcp"},
62 {FLOWSPEC_ICMP_TYPE
, "type"},
63 {FLOWSPEC_ICMP_CODE
, "code"},
64 {FLOWSPEC_TCP_FLAGS
, "flags"},
65 {FLOWSPEC_PKT_LEN
, "pktlen"},
66 {FLOWSPEC_DSCP
, "dscp"},
67 {FLOWSPEC_FRAGMENT
, "pktfrag"},
71 #define FS_STRING_UPDATE(count, ptr, format, remaining_len) do { \
74 if (((format) == NLRI_STRING_FORMAT_DEBUG) && (count)) {\
75 _len_written = snprintf((ptr), (remaining_len), \
77 (remaining_len) -= _len_written; \
78 (ptr) += _len_written; \
79 } else if (((format) == NLRI_STRING_FORMAT_MIN) \
81 _len_written = snprintf((ptr), (remaining_len), \
83 (remaining_len) -= _len_written; \
84 (ptr) += _len_written; \
89 /* Parse FLOWSPEC NLRI
90 * passed return_string string has assumed length
91 * BGP_FLOWSPEC_STRING_DISPLAY_MAX
93 void bgp_fs_nlri_get_string(unsigned char *nlri_content
, size_t len
,
94 char *return_string
, int format
,
95 json_object
*json_path
)
99 int ret
= 0, error
= 0;
100 char *ptr
= return_string
;
101 char local_string
[BGP_FLOWSPEC_STRING_DISPLAY_MAX
];
104 char pre_extra
[2] = "";
105 const struct message
*bgp_flowspec_display
;
106 enum bgp_flowspec_util_nlri_t type_util
;
107 int len_string
= BGP_FLOWSPEC_STRING_DISPLAY_MAX
;
110 if (format
== NLRI_STRING_FORMAT_LARGE
) {
111 snprintf(pre_extra
, sizeof(pre_extra
), "\t");
112 snprintf(extra
, sizeof(extra
), "\n");
113 bgp_flowspec_display
= bgp_flowspec_display_large
;
115 bgp_flowspec_display
= bgp_flowspec_display_min
;
116 /* if needed. type_util can be set to other values */
117 type_util
= BGP_FLOWSPEC_RETURN_STRING
;
119 while (offset
< len
-1 && error
>= 0) {
120 type
= nlri_content
[offset
];
123 case FLOWSPEC_DEST_PREFIX
:
124 case FLOWSPEC_SRC_PREFIX
:
125 ret
= bgp_flowspec_ip_address(
129 local_string
, &error
);
133 json_object_string_add(json_path
,
134 lookup_msg(bgp_flowspec_display
, type
, ""),
138 FS_STRING_UPDATE(count
, ptr
, format
, len_string
);
139 len_written
= snprintf(ptr
, len_string
, "%s%s %s%s",
141 lookup_msg(bgp_flowspec_display
,
143 local_string
, extra
);
144 len_string
-= len_written
;
147 case FLOWSPEC_IP_PROTOCOL
:
149 case FLOWSPEC_DEST_PORT
:
150 case FLOWSPEC_SRC_PORT
:
151 case FLOWSPEC_ICMP_TYPE
:
152 case FLOWSPEC_ICMP_CODE
:
153 ret
= bgp_flowspec_op_decode(type_util
,
156 local_string
, &error
);
160 json_object_string_add(json_path
,
161 lookup_msg(bgp_flowspec_display
, type
, ""),
165 FS_STRING_UPDATE(count
, ptr
, format
, len_string
);
166 len_written
= snprintf(ptr
, len_string
, "%s%s %s%s",
168 lookup_msg(bgp_flowspec_display
,
170 local_string
, extra
);
171 len_string
-= len_written
;
174 case FLOWSPEC_TCP_FLAGS
:
175 ret
= bgp_flowspec_tcpflags_decode(
179 local_string
, &error
);
183 json_object_string_add(json_path
,
184 lookup_msg(bgp_flowspec_display
,
189 FS_STRING_UPDATE(count
, ptr
, format
, len_string
);
190 len_written
= snprintf(ptr
, len_string
, "%s%s %s%s",
192 lookup_msg(bgp_flowspec_display
,
194 local_string
, extra
);
195 len_string
-= len_written
;
198 case FLOWSPEC_PKT_LEN
:
200 ret
= bgp_flowspec_op_decode(
202 nlri_content
+ offset
,
203 len
- offset
, local_string
,
208 json_object_string_add(json_path
,
209 lookup_msg(bgp_flowspec_display
, type
, ""),
213 FS_STRING_UPDATE(count
, ptr
, format
, len_string
);
214 len_written
= snprintf(ptr
, len_string
, "%s%s %s%s",
216 lookup_msg(bgp_flowspec_display
,
218 local_string
, extra
);
219 len_string
-= len_written
;
222 case FLOWSPEC_FRAGMENT
:
223 ret
= bgp_flowspec_fragment_type_decode(
225 nlri_content
+ offset
,
226 len
- offset
, local_string
,
231 json_object_string_add(json_path
,
232 lookup_msg(bgp_flowspec_display
,
237 FS_STRING_UPDATE(count
, ptr
, format
, len_string
);
238 len_written
= snprintf(ptr
, len_string
, "%s%s %s%s",
240 lookup_msg(bgp_flowspec_display
,
242 local_string
, extra
);
243 len_string
-= len_written
;
254 void route_vty_out_flowspec(struct vty
*vty
, struct prefix
*p
,
255 struct bgp_info
*binfo
,
256 int display
, json_object
*json_paths
)
259 char return_string
[BGP_FLOWSPEC_STRING_DISPLAY_MAX
];
261 json_object
*json_nlri_path
= NULL
;
262 json_object
*json_ecom_path
= NULL
;
263 json_object
*json_time_path
= NULL
;
264 char timebuf
[BGP_UPTIME_LEN
];
268 if (p
->family
!= AF_FLOWSPEC
)
271 if (display
== NLRI_STRING_FORMAT_JSON
)
272 json_nlri_path
= json_object_new_object();
274 json_nlri_path
= json_paths
;
276 if (display
== NLRI_STRING_FORMAT_LARGE
)
277 vty_out(vty
, "BGP flowspec entry: (flags 0x%x)\n",
279 bgp_fs_nlri_get_string((unsigned char *)
280 p
->u
.prefix_flowspec
.ptr
,
281 p
->u
.prefix_flowspec
.prefixlen
,
285 if (display
== NLRI_STRING_FORMAT_LARGE
)
286 vty_out(vty
, "%s", return_string
);
287 else if (display
== NLRI_STRING_FORMAT_DEBUG
)
288 vty_out(vty
, "%s", return_string
);
289 else if (display
== NLRI_STRING_FORMAT_MIN
)
290 vty_out(vty
, " %-30s", return_string
);
291 else if (json_paths
&& display
== NLRI_STRING_FORMAT_JSON
)
292 json_object_array_add(json_paths
, json_nlri_path
);
296 if (binfo
->attr
&& binfo
->attr
->ecommunity
) {
297 /* Print attribute */
299 s
= ecommunity_ecom2str(attr
->ecommunity
,
300 ECOMMUNITY_FORMAT_ROUTE_MAP
, 0);
303 if (display
== NLRI_STRING_FORMAT_LARGE
)
304 vty_out(vty
, "\t%s\n", s
);
305 else if (display
== NLRI_STRING_FORMAT_MIN
)
306 vty_out(vty
, "%s", s
);
307 else if (json_paths
) {
308 json_ecom_path
= json_object_new_object();
309 json_object_string_add(json_ecom_path
,
311 if (display
== NLRI_STRING_FORMAT_JSON
)
312 json_object_array_add(json_paths
,
315 XFREE(MTYPE_ECOMMUNITY_STR
, s
);
317 peer_uptime(binfo
->uptime
, timebuf
, BGP_UPTIME_LEN
, 0, NULL
);
318 if (display
== NLRI_STRING_FORMAT_LARGE
)
319 vty_out(vty
, "\tup for %8s\n", timebuf
);
320 else if (json_paths
) {
321 json_time_path
= json_object_new_object();
322 json_object_string_add(json_time_path
,
324 if (display
== NLRI_STRING_FORMAT_JSON
)
325 json_object_array_add(json_paths
, json_time_path
);
330 int bgp_show_table_flowspec(struct vty
*vty
, struct bgp
*bgp
, afi_t afi
,
331 struct bgp_table
*table
, enum bgp_show_type type
,
332 void *output_arg
, uint8_t use_json
,
333 int is_last
, unsigned long *output_cum
,
334 unsigned long *total_cum
)
338 unsigned long total_count
= 0;
339 json_object
*json_paths
= NULL
;
340 int display
= NLRI_STRING_FORMAT_LARGE
;
342 if (type
!= bgp_show_type_detail
)
345 for (rn
= bgp_table_top(table
); rn
; rn
= bgp_route_next(rn
)) {
346 if (rn
->info
== NULL
)
349 json_paths
= json_object_new_array();
350 display
= NLRI_STRING_FORMAT_JSON
;
352 for (ri
= rn
->info
; ri
; ri
= ri
->next
) {
354 route_vty_out_flowspec(vty
, &rn
->p
,
361 json_object_to_json_string_ext(
363 JSON_C_TO_STRING_PRETTY
));
364 json_object_free(json_paths
);
368 if (total_count
&& !use_json
)
370 "\nDisplayed %ld flowspec entries\n",
375 DEFUN (debug_bgp_flowspec
,
376 debug_bgp_flowspec_cmd
,
377 "debug bgp flowspec",
380 "BGP allow flowspec debugging entries\n")
382 if (vty
->node
== CONFIG_NODE
)
383 DEBUG_ON(flowspec
, FLOWSPEC
);
385 TERM_DEBUG_ON(flowspec
, FLOWSPEC
);
386 vty_out(vty
, "BGP flowspec debugging is on\n");
391 DEFUN (no_debug_bgp_flowspec
,
392 no_debug_bgp_flowspec_cmd
,
393 "no debug bgp flowspec",
397 "BGP allow flowspec debugging entries\n")
399 if (vty
->node
== CONFIG_NODE
)
400 DEBUG_OFF(flowspec
, FLOWSPEC
);
402 TERM_DEBUG_OFF(flowspec
, FLOWSPEC
);
403 vty_out(vty
, "BGP flowspec debugging is off\n");
408 void bgp_flowspec_vty_init(void)
410 install_element(ENABLE_NODE
, &debug_bgp_flowspec_cmd
);
411 install_element(CONFIG_NODE
, &debug_bgp_flowspec_cmd
);
412 install_element(ENABLE_NODE
, &no_debug_bgp_flowspec_cmd
);
413 install_element(CONFIG_NODE
, &no_debug_bgp_flowspec_cmd
);