]> git.proxmox.com Git - mirror_frr.git/blob - bgpd/bgp_flowspec_vty.c
Merge pull request #1984 from donaldsharp/conf_date_master
[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
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
37 */
38
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"},
52 {0}
53 };
54
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"},
68 {0}
69 };
70
71 #define FS_STRING_UPDATE(count, ptr, format, remaining_len) do { \
72 int _len_written; \
73 \
74 if (((format) == NLRI_STRING_FORMAT_DEBUG) && (count)) {\
75 _len_written = snprintf((ptr), (remaining_len), \
76 ", "); \
77 (remaining_len) -= _len_written; \
78 (ptr) += _len_written; \
79 } else if (((format) == NLRI_STRING_FORMAT_MIN) \
80 && (count)) { \
81 _len_written = snprintf((ptr), (remaining_len), \
82 " "); \
83 (remaining_len) -= _len_written; \
84 (ptr) += _len_written; \
85 } \
86 count++; \
87 } while (0)
88
89 /* Parse FLOWSPEC NLRI
90 * passed return_string string has assumed length
91 * BGP_FLOWSPEC_STRING_DISPLAY_MAX
92 */
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)
96 {
97 uint32_t offset = 0;
98 int type;
99 int ret = 0, error = 0;
100 char *ptr = return_string;
101 char local_string[BGP_FLOWSPEC_STRING_DISPLAY_MAX];
102 int count = 0;
103 char extra[2] = "";
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;
108 int len_written;
109
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;
114 } else
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;
118 error = 0;
119 while (offset < len-1 && error >= 0) {
120 type = nlri_content[offset];
121 offset++;
122 switch (type) {
123 case FLOWSPEC_DEST_PREFIX:
124 case FLOWSPEC_SRC_PREFIX:
125 ret = bgp_flowspec_ip_address(
126 type_util,
127 nlri_content+offset,
128 len - offset,
129 local_string, &error);
130 if (ret <= 0)
131 break;
132 if (json_path) {
133 json_object_string_add(json_path,
134 lookup_msg(bgp_flowspec_display, type, ""),
135 local_string);
136 break;
137 }
138 FS_STRING_UPDATE(count, ptr, format, len_string);
139 len_written = snprintf(ptr, len_string, "%s%s %s%s",
140 pre_extra,
141 lookup_msg(bgp_flowspec_display,
142 type, ""),
143 local_string, extra);
144 len_string -= len_written;
145 ptr += len_written;
146 break;
147 case FLOWSPEC_IP_PROTOCOL:
148 case FLOWSPEC_PORT:
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,
154 nlri_content+offset,
155 len - offset,
156 local_string, &error);
157 if (ret <= 0)
158 break;
159 if (json_path) {
160 json_object_string_add(json_path,
161 lookup_msg(bgp_flowspec_display, type, ""),
162 local_string);
163 break;
164 }
165 FS_STRING_UPDATE(count, ptr, format, len_string);
166 len_written = snprintf(ptr, len_string, "%s%s %s%s",
167 pre_extra,
168 lookup_msg(bgp_flowspec_display,
169 type, ""),
170 local_string, extra);
171 len_string -= len_written;
172 ptr += len_written;
173 break;
174 case FLOWSPEC_TCP_FLAGS:
175 ret = bgp_flowspec_tcpflags_decode(
176 type_util,
177 nlri_content+offset,
178 len - offset,
179 local_string, &error);
180 if (ret <= 0)
181 break;
182 if (json_path) {
183 json_object_string_add(json_path,
184 lookup_msg(bgp_flowspec_display,
185 type, ""),
186 local_string);
187 break;
188 }
189 FS_STRING_UPDATE(count, ptr, format, len_string);
190 len_written = snprintf(ptr, len_string, "%s%s %s%s",
191 pre_extra,
192 lookup_msg(bgp_flowspec_display,
193 type, ""),
194 local_string, extra);
195 len_string -= len_written;
196 ptr += len_written;
197 break;
198 case FLOWSPEC_PKT_LEN:
199 case FLOWSPEC_DSCP:
200 ret = bgp_flowspec_op_decode(
201 type_util,
202 nlri_content + offset,
203 len - offset, local_string,
204 &error);
205 if (ret <= 0)
206 break;
207 if (json_path) {
208 json_object_string_add(json_path,
209 lookup_msg(bgp_flowspec_display, type, ""),
210 local_string);
211 break;
212 }
213 FS_STRING_UPDATE(count, ptr, format, len_string);
214 len_written = snprintf(ptr, len_string, "%s%s %s%s",
215 pre_extra,
216 lookup_msg(bgp_flowspec_display,
217 type, ""),
218 local_string, extra);
219 len_string -= len_written;
220 ptr += len_written;
221 break;
222 case FLOWSPEC_FRAGMENT:
223 ret = bgp_flowspec_fragment_type_decode(
224 type_util,
225 nlri_content + offset,
226 len - offset, local_string,
227 &error);
228 if (ret <= 0)
229 break;
230 if (json_path) {
231 json_object_string_add(json_path,
232 lookup_msg(bgp_flowspec_display,
233 type, ""),
234 local_string);
235 break;
236 }
237 FS_STRING_UPDATE(count, ptr, format, len_string);
238 len_written = snprintf(ptr, len_string, "%s%s %s%s",
239 pre_extra,
240 lookup_msg(bgp_flowspec_display,
241 type, ""),
242 local_string, extra);
243 len_string -= len_written;
244 ptr += len_written;
245 break;
246 default:
247 error = -1;
248 break;
249 }
250 offset += ret;
251 }
252 }
253
254 void route_vty_out_flowspec(struct vty *vty, struct prefix *p,
255 struct bgp_info *binfo,
256 int display, json_object *json_paths)
257 {
258 struct attr *attr;
259 char return_string[BGP_FLOWSPEC_STRING_DISPLAY_MAX];
260 char *s;
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];
265
266 /* Print prefix */
267 if (p != NULL) {
268 if (p->family != AF_FLOWSPEC)
269 return;
270 if (json_paths) {
271 if (display == NLRI_STRING_FORMAT_JSON)
272 json_nlri_path = json_object_new_object();
273 else
274 json_nlri_path = json_paths;
275 }
276 if (display == NLRI_STRING_FORMAT_LARGE)
277 vty_out(vty, "BGP flowspec entry: (flags 0x%x)\n",
278 binfo->flags);
279 bgp_fs_nlri_get_string((unsigned char *)
280 p->u.prefix_flowspec.ptr,
281 p->u.prefix_flowspec.prefixlen,
282 return_string,
283 display,
284 json_nlri_path);
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);
293 }
294 if (!binfo)
295 return;
296 if (binfo->attr && binfo->attr->ecommunity) {
297 /* Print attribute */
298 attr = binfo->attr;
299 s = ecommunity_ecom2str(attr->ecommunity,
300 ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
301 if (!s)
302 return;
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,
310 "ecomlist", s);
311 if (display == NLRI_STRING_FORMAT_JSON)
312 json_object_array_add(json_paths,
313 json_ecom_path);
314 }
315 XFREE(MTYPE_ECOMMUNITY_STR, s);
316 }
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,
323 "time", timebuf);
324 if (display == NLRI_STRING_FORMAT_JSON)
325 json_object_array_add(json_paths, json_time_path);
326 }
327
328 }
329
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)
335 {
336 struct bgp_info *ri;
337 struct bgp_node *rn;
338 unsigned long total_count = 0;
339 json_object *json_paths = NULL;
340 int display = NLRI_STRING_FORMAT_LARGE;
341
342 if (type != bgp_show_type_detail)
343 return CMD_SUCCESS;
344
345 for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
346 if (rn->info == NULL)
347 continue;
348 if (use_json) {
349 json_paths = json_object_new_array();
350 display = NLRI_STRING_FORMAT_JSON;
351 }
352 for (ri = rn->info; ri; ri = ri->next) {
353 total_count++;
354 route_vty_out_flowspec(vty, &rn->p,
355 ri, display,
356 json_paths);
357
358 }
359 if (use_json) {
360 vty_out(vty, "%s\n",
361 json_object_to_json_string_ext(
362 json_paths,
363 JSON_C_TO_STRING_PRETTY));
364 json_object_free(json_paths);
365 json_paths = NULL;
366 }
367 }
368 if (total_count && !use_json)
369 vty_out(vty,
370 "\nDisplayed %ld flowspec entries\n",
371 total_count);
372 return CMD_SUCCESS;
373 }
374
375 DEFUN (debug_bgp_flowspec,
376 debug_bgp_flowspec_cmd,
377 "debug bgp flowspec",
378 DEBUG_STR
379 BGP_STR
380 "BGP allow flowspec debugging entries\n")
381 {
382 if (vty->node == CONFIG_NODE)
383 DEBUG_ON(flowspec, FLOWSPEC);
384 else {
385 TERM_DEBUG_ON(flowspec, FLOWSPEC);
386 vty_out(vty, "BGP flowspec debugging is on\n");
387 }
388 return CMD_SUCCESS;
389 }
390
391 DEFUN (no_debug_bgp_flowspec,
392 no_debug_bgp_flowspec_cmd,
393 "no debug bgp flowspec",
394 NO_STR
395 DEBUG_STR
396 BGP_STR
397 "BGP allow flowspec debugging entries\n")
398 {
399 if (vty->node == CONFIG_NODE)
400 DEBUG_OFF(flowspec, FLOWSPEC);
401 else {
402 TERM_DEBUG_OFF(flowspec, FLOWSPEC);
403 vty_out(vty, "BGP flowspec debugging is off\n");
404 }
405 return CMD_SUCCESS;
406 }
407
408 void bgp_flowspec_vty_init(void)
409 {
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);
414 }