]> git.proxmox.com Git - mirror_frr.git/commitdiff
bgpd: support for show bgp ipv4 flowspec
authorPhilippe Guibert <philippe.guibert@6wind.com>
Mon, 19 Feb 2018 16:17:41 +0000 (17:17 +0100)
committerPhilippe Guibert <philippe.guibert@6wind.com>
Fri, 30 Mar 2018 12:01:05 +0000 (14:01 +0200)
The show bgp ipv4 flowspec routine is made available, displays the
flowspec rules contained in the BGP FIB database, as well as the actions
to be done on those rules. Two routines are available:
show bgp ipv4 flowspec
show bgp ipv4 flowspec detail

Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
bgpd/Makefile.am
bgpd/bgp_flowspec.h
bgpd/bgp_flowspec_private.h
bgpd/bgp_flowspec_vty.c [new file with mode: 0644]
bgpd/bgp_route.c
bgpd/bgp_route.h

index a8e50e0ba78de36007bb123c36740f76ade6844f..61d46dfcb96a29c8d422f94342186c50c943e443 100644 (file)
@@ -86,7 +86,8 @@ libbgp_a_SOURCES = \
        bgp_nht.c bgp_updgrp.c bgp_updgrp_packet.c bgp_updgrp_adv.c bgp_bfd.c \
        bgp_encap_tlv.c $(BGP_VNC_RFAPI_SRC) bgp_attr_evpn.c \
        bgp_evpn.c bgp_evpn_vty.c bgp_vpn.c bgp_label.c bgp_rd.c \
-       bgp_keepalives.c bgp_io.c bgp_flowspec.c bgp_flowspec_util.c
+       bgp_keepalives.c bgp_io.c bgp_flowspec.c bgp_flowspec_util.c \
+       bgp_flowspec_vty.c
 
 noinst_HEADERS = \
        bgp_memory.h \
index bf019da3aa4fdf26112d3a000d5b33ec2668c755..791ed2e6932d4744f062479c352968e11c33660d 100644 (file)
 #ifndef _FRR_BGP_FLOWSPEC_H
 #define _FRR_BGP_FLOWSPEC_H
 
+#define NLRI_STRING_FORMAT_LARGE 0
+#define NLRI_STRING_FORMAT_DEBUG 1
+#define NLRI_STRING_FORMAT_MIN   2
+
+#define BGP_FLOWSPEC_NLRI_STRING_MAX 512
+
 extern int bgp_nlri_parse_flowspec(struct peer *peer, struct attr *attr,
                                   struct bgp_nlri *packet, int withdraw);
 
 extern void bgp_flowspec_vty_init(void);
 
+extern int bgp_show_table_flowspec(struct vty *vty, struct bgp *bgp, afi_t afi,
+                                  struct bgp_table *table,
+                                  enum bgp_show_type type,
+                                  void *output_arg, uint8_t use_json,
+                                  int is_last,
+                                  unsigned long *output_cum,
+                                  unsigned long *total_cum);
+
+extern void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len,
+                                   char *return_string, int format);
+
+extern void route_vty_out_flowspec(struct vty *vty, struct prefix *p,
+                                  struct bgp_info *binfo,
+                                  int display, json_object *json_paths);
 #endif /* _FRR_BGP_FLOWSPEC_H */
index 4f086a9f7b02956f00da2d1500128b90804dbe6c..dede4e03d3a4c42aabc66da660486241f0d2d48d 100644 (file)
 #define FLOWSPEC_TRAFFIC_ACTION_SAMPLE         0
 #define FLOWSPEC_TRAFFIC_ACTION_DISTRIBUTE     1
 
+/* Flow Spec Component Types */
+#define NUM_OF_FLOWSPEC_MATCH_TYPES            12
+#define FLOWSPEC_DEST_PREFIX           1
+#define FLOWSPEC_SRC_PREFIX            2
+#define FLOWSPEC_IP_PROTOCOL           3
+#define FLOWSPEC_PORT                  4
+#define FLOWSPEC_DEST_PORT             5
+#define FLOWSPEC_SRC_PORT              6
+#define FLOWSPEC_ICMP_TYPE             7
+#define FLOWSPEC_ICMP_CODE             8
+#define FLOWSPEC_TCP_FLAGS             9
+#define FLOWSPEC_PKT_LEN               10
+#define FLOWSPEC_DSCP                  11
+#define FLOWSPEC_FRAGMENT              12
+
 #endif /* _FRR_BGP_FLOWSPEC_PRIVATE_H */
diff --git a/bgpd/bgp_flowspec_vty.c b/bgpd/bgp_flowspec_vty.c
new file mode 100644 (file)
index 0000000..1006022
--- /dev/null
@@ -0,0 +1,276 @@
+/* BGP FlowSpec VTY
+ * Copyright (C) 2018 6WIND
+ *
+ * FRRouting is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRRouting is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+#include "command.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_table.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_ecommunity.h"
+#include "bgpd/bgp_vty.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_aspath.h"
+#include "bgpd/bgp_flowspec.h"
+#include "bgpd/bgp_flowspec_util.h"
+#include "bgpd/bgp_flowspec_private.h"
+
+/* Local Structures and variables declarations
+ * This code block hosts the struct declared that host the flowspec rules
+ * as well as some structure used to convert to stringx
+ */
+
+static const struct message bgp_flowspec_display_large[] = {
+       {FLOWSPEC_DEST_PREFIX, "Destination Address"},
+       {FLOWSPEC_SRC_PREFIX, "Source Address"},
+       {FLOWSPEC_IP_PROTOCOL, "IP Protocol"},
+       {FLOWSPEC_PORT, "Port"},
+       {FLOWSPEC_DEST_PORT, "Destination Port"},
+       {FLOWSPEC_SRC_PORT, "Source Port"},
+       {FLOWSPEC_ICMP_TYPE, "ICMP Type"},
+       {FLOWSPEC_ICMP_CODE, "ICMP Code"},
+       {FLOWSPEC_TCP_FLAGS, "TCP Flags"},
+       {FLOWSPEC_PKT_LEN, "Packet Length"},
+       {FLOWSPEC_DSCP, "DSCP field"},
+       {FLOWSPEC_FRAGMENT, "Packet Fragment"},
+       {0}
+};
+
+static const struct message bgp_flowspec_display_min[] = {
+       {FLOWSPEC_DEST_PREFIX, "to"},
+       {FLOWSPEC_SRC_PREFIX, "from"},
+       {FLOWSPEC_IP_PROTOCOL, "proto"},
+       {FLOWSPEC_PORT, "port"},
+       {FLOWSPEC_DEST_PORT, "dstp"},
+       {FLOWSPEC_SRC_PORT, "srcp"},
+       {FLOWSPEC_ICMP_TYPE, "type"},
+       {FLOWSPEC_ICMP_CODE, "code"},
+       {FLOWSPEC_TCP_FLAGS, "flags"},
+       {FLOWSPEC_PKT_LEN, "pktlen"},
+       {FLOWSPEC_DSCP, "dscp"},
+       {FLOWSPEC_FRAGMENT, "pktfrag"},
+       {0}
+};
+
+#define        FS_STRING_UPDATE(count, ptr, format) do {                             \
+               if (((format) == NLRI_STRING_FORMAT_DEBUG) && (count)) {      \
+                       (ptr) += sprintf((ptr), ", ");                        \
+               } else if (((format) == NLRI_STRING_FORMAT_MIN) && (count)) { \
+                       (ptr) += sprintf((ptr), " ");                         \
+               }                                                             \
+               count++;                                                      \
+       } while (0)
+
+/* Parse FLOWSPEC NLRI*/
+void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len,
+                           char *return_string, int format)
+{
+       uint32_t offset = 0;
+       int type;
+       int ret = 0, error = 0;
+       char *ptr = return_string;
+       char local_string[BGP_FLOWSPEC_STRING_DISPLAY_MAX];
+       int count = 0;
+       char extra[2] = "";
+       char pre_extra[2] = "";
+       const struct message *bgp_flowspec_display;
+
+       if (format == NLRI_STRING_FORMAT_LARGE) {
+               snprintf(pre_extra, sizeof(pre_extra), "\t");
+               snprintf(extra, sizeof(extra), "\n");
+               bgp_flowspec_display = bgp_flowspec_display_large;
+       } else
+               bgp_flowspec_display = bgp_flowspec_display_min;
+       error = 0;
+       while (offset < len-1 && error >= 0) {
+               type = nlri_content[offset];
+               offset++;
+               switch (type) {
+               case FLOWSPEC_DEST_PREFIX:
+               case FLOWSPEC_SRC_PREFIX:
+                       ret = bgp_flowspec_ip_address(
+                                               BGP_FLOWSPEC_RETURN_STRING,
+                                               nlri_content+offset,
+                                               len - offset,
+                                               local_string, &error);
+                       if (ret <= 0)
+                               break;
+                       FS_STRING_UPDATE(count, ptr, format);
+                       ptr += sprintf(ptr, "%s%s %s%s", pre_extra,
+                                    lookup_msg(bgp_flowspec_display, type, ""),
+                                    local_string, extra);
+                       break;
+               case FLOWSPEC_IP_PROTOCOL:
+               case FLOWSPEC_PORT:
+               case FLOWSPEC_DEST_PORT:
+               case FLOWSPEC_SRC_PORT:
+               case FLOWSPEC_ICMP_TYPE:
+               case FLOWSPEC_ICMP_CODE:
+                       ret = bgp_flowspec_op_decode(BGP_FLOWSPEC_RETURN_STRING,
+                                                    nlri_content+offset,
+                                                    len - offset,
+                                                    local_string, &error);
+                       if (ret <= 0)
+                               break;
+                       FS_STRING_UPDATE(count, ptr, format);
+                       ptr += sprintf(ptr, "%s%s %s%s", pre_extra,
+                                    lookup_msg(bgp_flowspec_display,
+                                               type, ""),
+                                    local_string, extra);
+                       break;
+               case FLOWSPEC_TCP_FLAGS:
+                       ret = bgp_flowspec_tcpflags_decode(
+                                             BGP_FLOWSPEC_RETURN_STRING,
+                                             nlri_content+offset,
+                                             len - offset,
+                                             local_string, &error);
+                       if (ret <= 0)
+                               break;
+                       FS_STRING_UPDATE(count, ptr, format);
+                       ptr += sprintf(ptr, "%s%s %s%s", pre_extra,
+                                    lookup_msg(bgp_flowspec_display, type, ""),
+                                    local_string, extra);
+                       break;
+               case FLOWSPEC_PKT_LEN:
+               case FLOWSPEC_DSCP:
+                       ret = bgp_flowspec_op_decode(
+                                               BGP_FLOWSPEC_RETURN_STRING,
+                                               nlri_content + offset,
+                                               len - offset, local_string,
+                                               &error);
+                       if (ret <= 0)
+                               break;
+                       FS_STRING_UPDATE(count, ptr, format);
+                       ptr += sprintf(ptr, "%s%s %s%s", pre_extra,
+                                    lookup_msg(bgp_flowspec_display,
+                                               type, ""),
+                                    local_string, extra);
+                       break;
+               case FLOWSPEC_FRAGMENT:
+                       ret = bgp_flowspec_fragment_type_decode(
+                                               BGP_FLOWSPEC_RETURN_STRING,
+                                               nlri_content + offset,
+                                               len - offset, local_string,
+                                               &error);
+                       if (ret <= 0)
+                               break;
+                       FS_STRING_UPDATE(count, ptr, format);
+                       ptr += sprintf(ptr, "%s%s %s%s", pre_extra,
+                                    lookup_msg(bgp_flowspec_display,
+                                               type, ""),
+                                    local_string, extra);
+                       break;
+               default:
+                       error = -1;
+                       break;
+               }
+               offset += ret;
+       }
+}
+
+void route_vty_out_flowspec(struct vty *vty, struct prefix *p,
+                           struct bgp_info *binfo,
+                           int display, json_object *json_paths)
+{
+       struct attr *attr;
+       char return_string[BGP_FLOWSPEC_STRING_DISPLAY_MAX];
+       char *s;
+
+       /* Print prefix */
+       if (p != NULL) {
+               if (p->family != AF_FLOWSPEC)
+                       return;
+               if (display == NLRI_STRING_FORMAT_LARGE)
+                       vty_out(vty, "BGP flowspec entry: (flags 0x%x)\n",
+                               binfo->flags);
+               bgp_fs_nlri_get_string((unsigned char *)
+                                      p->u.prefix_flowspec.ptr,
+                                      p->u.prefix_flowspec.prefixlen,
+                                      return_string,
+                                      display);
+               if (display == NLRI_STRING_FORMAT_LARGE)
+                       vty_out(vty, "%s", return_string);
+               else if (display == NLRI_STRING_FORMAT_DEBUG)
+                       vty_out(vty, "%s", return_string);
+               else
+                       vty_out(vty, " %-30s", return_string);
+       }
+       if (!binfo)
+               return;
+       if (binfo->attr && binfo->attr->ecommunity) {
+               /* Print attribute */
+               attr = binfo->attr;
+               s = ecommunity_ecom2str(attr->ecommunity,
+                                       ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
+               if (!s)
+                       return;
+               if (display == NLRI_STRING_FORMAT_LARGE)
+                       vty_out(vty, "\t%s\n", s);
+               else
+                       vty_out(vty, "%s", s);
+               XFREE(MTYPE_ECOMMUNITY_STR, s);
+       }
+       if (display == NLRI_STRING_FORMAT_LARGE) {
+               char timebuf[BGP_UPTIME_LEN];
+
+               vty_out(vty, "\tup for %8s\n",
+                       peer_uptime(binfo->uptime, timebuf, BGP_UPTIME_LEN,
+                                   0, NULL));
+       }
+
+}
+
+int bgp_show_table_flowspec(struct vty *vty, struct bgp *bgp, afi_t afi,
+                           struct bgp_table *table, enum bgp_show_type type,
+                           void *output_arg, uint8_t use_json,
+                           int is_last, unsigned long *output_cum,
+                           unsigned long *total_cum)
+{
+       struct bgp_info *ri;
+       struct bgp_node *rn;
+       unsigned long total_count = 0;
+       json_object *json_paths = NULL;
+       int display;
+
+       if (type != bgp_show_type_detail)
+               return CMD_SUCCESS;
+
+       display = NLRI_STRING_FORMAT_LARGE;
+       if (use_json) /* XXX */
+               return CMD_SUCCESS;
+       for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
+               if (rn->info == NULL)
+                       continue;
+               for (ri = rn->info; ri; ri = ri->next) {
+                       total_count++;
+                       route_vty_out_flowspec(vty, &rn->p,
+                                              ri, display,
+                                              json_paths);
+
+               }
+       }
+       if (total_count)
+               vty_out(vty,
+                       "\nDisplayed  %ld flowspec entries\n",
+                       total_count);
+       return CMD_SUCCESS;
+}
+
+void bgp_flowspec_vty_init(void)
+{
+}
index aef3ad6a7b55183f98f6cde5864b7ff9b8c056af..db82386e72ca1da011e9c60f384af63d64967bf2 100644 (file)
@@ -73,6 +73,7 @@
 #include "bgpd/bgp_encap_tlv.h"
 #include "bgpd/bgp_evpn.h"
 #include "bgpd/bgp_evpn_vty.h"
+#include "bgpd/bgp_flowspec.h"
 
 #ifndef VTYSH_EXTRACT_PL
 #include "bgpd/bgp_route_clippy.c"
@@ -6316,6 +6317,9 @@ static void route_vty_out_route(struct prefix *p, struct vty *vty,
                prefix2str(p, buf, PREFIX_STRLEN);
                len = vty_out(vty, "%s", buf);
 #endif
+       } else if (p->family == AF_FLOWSPEC) {
+               route_vty_out_flowspec(vty, p, NULL,
+                                      NLRI_STRING_FORMAT_MIN, json);
        } else {
                if (!json)
                        len = vty_out(
@@ -8429,6 +8433,12 @@ static int bgp_show(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
                return bgp_show_table_rd(vty, bgp, safi, table, NULL, type,
                                         output_arg, use_json);
        }
+
+       if (safi == SAFI_FLOWSPEC && type == bgp_show_type_detail) {
+               return bgp_show_table_flowspec(vty, bgp, afi, table, type,
+                                              output_arg, use_json,
+                                              1, NULL, NULL);
+       }
        /* labeled-unicast routes live in the unicast table */
        else if (safi == SAFI_LABELED_UNICAST)
                safi = SAFI_UNICAST;
@@ -10425,6 +10435,32 @@ static int bgp_show_neighbor_route(struct vty *vty, struct peer *peer,
        return bgp_show(vty, peer->bgp, afi, safi, type, &peer->su, use_json);
 }
 
+DEFUN (show_ip_bgp_flowspec_routes_detailed,
+       show_ip_bgp_flowspec_routes_detailed_cmd,
+       "show [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" flowspec] detail [json]",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       BGP_INSTANCE_HELP_STR
+       BGP_AFI_HELP_STR
+       "SAFI Flowspec\n"
+       "Detailed information on flowspec entries\n"
+       JSON_STR)
+{
+       afi_t afi = AFI_IP;
+       safi_t safi = SAFI_UNICAST;
+       struct bgp *bgp = NULL;
+       int idx = 0;
+
+       bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi,
+                                           &bgp);
+       if (!idx)
+               return CMD_WARNING;
+
+       return bgp_show(vty, bgp, afi, safi,
+                       bgp_show_type_detail, NULL, use_json(argc, argv));
+}
+
 DEFUN (show_ip_bgp_neighbor_routes,
        show_ip_bgp_neighbor_routes_cmd,
        "show [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]] "
@@ -11439,6 +11475,10 @@ void bgp_route_init(void)
        /* Large Communities */
        install_element(VIEW_NODE, &show_ip_bgp_large_community_list_cmd);
        install_element(VIEW_NODE, &show_ip_bgp_large_community_cmd);
+
+       /* show bgp ipv4 flowspec detailed */
+       install_element(VIEW_NODE, &show_ip_bgp_flowspec_routes_detailed_cmd);
+
 }
 
 void bgp_route_finish(void)
index e1e43bbde3460ea8787cfab600b0f07de87002b3..debd6d1ff315f0491507fe26f69e0dbdeaff1322 100644 (file)
@@ -48,7 +48,8 @@ enum bgp_show_type {
        bgp_show_type_flap_statistics,
        bgp_show_type_flap_neighbor,
        bgp_show_type_dampend_paths,
-       bgp_show_type_damp_neighbor
+       bgp_show_type_damp_neighbor,
+       bgp_show_type_detail,
 };