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