]> git.proxmox.com Git - mirror_frr.git/blobdiff - bgpd/bgp_flowspec_vty.c
Merge pull request #2677 from rtrlib/2018-07-18-master-bugfix
[mirror_frr.git] / bgpd / bgp_flowspec_vty.c
index eae9bedcbd3c83c0d556c649c21ee4c7b22db502..31d2c540fa524e2d044a299daad914ea6457cfef 100644 (file)
@@ -30,6 +30,7 @@
 #include "bgpd/bgp_flowspec_util.h"
 #include "bgpd/bgp_flowspec_private.h"
 #include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_pbr.h"
 
 /* Local Structures and variables declarations
  * This code block hosts the struct declared that host the flowspec rules
@@ -61,23 +62,35 @@ static const struct message bgp_flowspec_display_min[] = {
        {FLOWSPEC_SRC_PORT, "srcp"},
        {FLOWSPEC_ICMP_TYPE, "type"},
        {FLOWSPEC_ICMP_CODE, "code"},
-       {FLOWSPEC_TCP_FLAGS, "flags"},
+       {FLOWSPEC_TCP_FLAGS, "tcp"},
        {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++;                                                      \
+#define        FS_STRING_UPDATE(count, ptr, format, remaining_len) do {        \
+               int _len_written;                                       \
+                                                                       \
+               if (((format) == NLRI_STRING_FORMAT_DEBUG) && (count)) {\
+                       _len_written = snprintf((ptr), (remaining_len), \
+                                               ", ");                  \
+                       (remaining_len) -= _len_written;                \
+                       (ptr) += _len_written;                          \
+               } else if (((format) == NLRI_STRING_FORMAT_MIN)         \
+                          && (count)) {                                \
+                       _len_written = snprintf((ptr), (remaining_len), \
+                                               " ");                   \
+                       (remaining_len) -= _len_written;                \
+                       (ptr) += _len_written;                          \
+               }                                                       \
+               count++;                                                \
        } while (0)
 
-/* Parse FLOWSPEC NLRI*/
+/* Parse FLOWSPEC NLRI
+ * passed return_string string has assumed length
+ * BGP_FLOWSPEC_STRING_DISPLAY_MAX
+ */
 void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len,
                            char *return_string, int format,
                            json_object *json_path)
@@ -92,6 +105,8 @@ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len,
        char pre_extra[2] = "";
        const struct message *bgp_flowspec_display;
        enum bgp_flowspec_util_nlri_t type_util;
+       int len_string = BGP_FLOWSPEC_STRING_DISPLAY_MAX;
+       int len_written;
 
        if (format == NLRI_STRING_FORMAT_LARGE) {
                snprintf(pre_extra, sizeof(pre_extra), "\t");
@@ -121,10 +136,14 @@ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len,
                                     local_string);
                                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);
+                       FS_STRING_UPDATE(count, ptr, format, len_string);
+                       len_written = snprintf(ptr, len_string, "%s%s %s%s",
+                                       pre_extra,
+                                       lookup_msg(bgp_flowspec_display,
+                                                  type, ""),
+                                       local_string, extra);
+                       len_string -= len_written;
+                       ptr += len_written;
                        break;
                case FLOWSPEC_IP_PROTOCOL:
                case FLOWSPEC_PORT:
@@ -144,14 +163,17 @@ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len,
                                     local_string);
                                break;
                        }
-                       FS_STRING_UPDATE(count, ptr, format);
-                       ptr += sprintf(ptr, "%s%s %s%s", pre_extra,
-                                    lookup_msg(bgp_flowspec_display,
-                                               type, ""),
+                       FS_STRING_UPDATE(count, ptr, format, len_string);
+                       len_written = snprintf(ptr, len_string, "%s%s %s%s",
+                                       pre_extra,
+                                       lookup_msg(bgp_flowspec_display,
+                                       type, ""),
                                     local_string, extra);
+                       len_string -= len_written;
+                       ptr += len_written;
                        break;
                case FLOWSPEC_TCP_FLAGS:
-                       ret = bgp_flowspec_tcpflags_decode(
+                       ret = bgp_flowspec_bitmask_decode(
                                              type_util,
                                              nlri_content+offset,
                                              len - offset,
@@ -160,14 +182,19 @@ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len,
                                break;
                        if (json_path) {
                                json_object_string_add(json_path,
-                                    lookup_msg(bgp_flowspec_display, type, ""),
+                                    lookup_msg(bgp_flowspec_display,
+                                               type, ""),
                                     local_string);
                                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);
+                       FS_STRING_UPDATE(count, ptr, format, len_string);
+                       len_written = snprintf(ptr, len_string, "%s%s %s%s",
+                                       pre_extra,
+                                       lookup_msg(bgp_flowspec_display,
+                                                  type, ""),
+                                       local_string, extra);
+                       len_string -= len_written;
+                       ptr += len_written;
                        break;
                case FLOWSPEC_PKT_LEN:
                case FLOWSPEC_DSCP:
@@ -184,18 +211,21 @@ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len,
                                    local_string);
                                break;
                        }
-                       FS_STRING_UPDATE(count, ptr, format);
-                       ptr += sprintf(ptr, "%s%s %s%s", pre_extra,
-                                    lookup_msg(bgp_flowspec_display,
-                                               type, ""),
+                       FS_STRING_UPDATE(count, ptr, format, len_string);
+                       len_written = snprintf(ptr, len_string, "%s%s %s%s",
+                                       pre_extra,
+                                       lookup_msg(bgp_flowspec_display,
+                                       type, ""),
                                     local_string, extra);
+                       len_string -= len_written;
+                       ptr += len_written;
                        break;
                case FLOWSPEC_FRAGMENT:
-                       ret = bgp_flowspec_fragment_type_decode(
-                                               type_util,
-                                               nlri_content + offset,
-                                               len - offset, local_string,
-                                               &error);
+                       ret = bgp_flowspec_bitmask_decode(
+                                             type_util,
+                                             nlri_content+offset,
+                                             len - offset,
+                                             local_string, &error);
                        if (ret <= 0)
                                break;
                        if (json_path) {
@@ -205,11 +235,14 @@ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len,
                                    local_string);
                                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);
+                       FS_STRING_UPDATE(count, ptr, format, len_string);
+                       len_written = snprintf(ptr, len_string, "%s%s %s%s",
+                                       pre_extra,
+                                       lookup_msg(bgp_flowspec_display,
+                                       type, ""),
+                                       local_string, extra);
+                       len_string -= len_written;
+                       ptr += len_written;
                        break;
                default:
                        error = -1;
@@ -241,7 +274,7 @@ void route_vty_out_flowspec(struct vty *vty, struct prefix *p,
                        else
                                json_nlri_path = json_paths;
                }
-               if (display == NLRI_STRING_FORMAT_LARGE)
+               if (display == NLRI_STRING_FORMAT_LARGE && binfo)
                        vty_out(vty, "BGP flowspec entry: (flags 0x%x)\n",
                                binfo->flags);
                bgp_fs_nlri_get_string((unsigned char *)
@@ -280,19 +313,54 @@ void route_vty_out_flowspec(struct vty *vty, struct prefix *p,
                                json_object_array_add(json_paths,
                                                      json_ecom_path);
                }
+               if (attr->nexthop.s_addr != 0 &&
+                   display == NLRI_STRING_FORMAT_LARGE)
+                       vty_out(vty, "\tNH %-16s\n", inet_ntoa(attr->nexthop));
                XFREE(MTYPE_ECOMMUNITY_STR, s);
        }
        peer_uptime(binfo->uptime, timebuf, BGP_UPTIME_LEN, 0, NULL);
-       if (display == NLRI_STRING_FORMAT_LARGE)
-               vty_out(vty, "\tup for %8s\n", timebuf);
-       else if (json_paths) {
+       if (display == NLRI_STRING_FORMAT_LARGE) {
+               vty_out(vty, "\treceived for %8s\n", timebuf);
+       else if (json_paths) {
                json_time_path = json_object_new_object();
                json_object_string_add(json_time_path,
                                       "time", timebuf);
                if (display == NLRI_STRING_FORMAT_JSON)
                        json_object_array_add(json_paths, json_time_path);
        }
+       if (display == NLRI_STRING_FORMAT_LARGE) {
+               struct bgp_info_extra *extra = bgp_info_extra_get(binfo);
+
+               if (extra->bgp_fs_pbr) {
+                       struct listnode *node;
+                       struct bgp_pbr_match_entry *bpme;
+                       struct bgp_pbr_match *bpm;
+                       bool list_began = false;
+                       struct list *list_bpm;
 
+                       list_bpm = list_new();
+                       if (listcount(extra->bgp_fs_pbr))
+                               vty_out(vty, "\tinstalled in PBR");
+                       for (ALL_LIST_ELEMENTS_RO(extra->bgp_fs_pbr,
+                                                 node, bpme)) {
+                               bpm = bpme->backpointer;
+                               if (listnode_lookup(list_bpm, bpm))
+                                       continue;
+                               listnode_add(list_bpm, bpm);
+                               if (!list_began) {
+                                       vty_out(vty, " (");
+                                       list_began = true;
+                               } else
+                                       vty_out(vty, ", ");
+                               vty_out(vty, "%s", bpm->ipset_name);
+                       }
+                       if (list_began)
+                               vty_out(vty, ")");
+                       vty_out(vty, "\n");
+                       list_delete_and_null(&list_bpm);
+               } else
+                       vty_out(vty, "\tnot installed in PBR\n");
+       }
 }
 
 int bgp_show_table_flowspec(struct vty *vty, struct bgp *bgp, afi_t afi,
@@ -373,10 +441,127 @@ DEFUN (no_debug_bgp_flowspec,
        return CMD_SUCCESS;
 }
 
+int bgp_fs_config_write_pbr(struct vty *vty, struct bgp *bgp,
+                           afi_t afi, safi_t safi)
+{
+       struct bgp_pbr_interface *pbr_if;
+       bool declare_node = false;
+       struct bgp_pbr_config *bgp_pbr_cfg = bgp->bgp_pbr_cfg;
+       struct bgp_pbr_interface_head *head;
+       bool bgp_pbr_interface_any;
+
+       if (!bgp_pbr_cfg || safi != SAFI_FLOWSPEC || afi != AFI_IP)
+               return 0;
+       head = &(bgp_pbr_cfg->ifaces_by_name_ipv4);
+       bgp_pbr_interface_any = bgp_pbr_cfg->pbr_interface_any_ipv4;
+       if (!RB_EMPTY(bgp_pbr_interface_head, head) ||
+            !bgp_pbr_interface_any)
+               declare_node = true;
+       RB_FOREACH (pbr_if, bgp_pbr_interface_head, head) {
+               vty_out(vty, "  local-install %s\n", pbr_if->name);
+       }
+       return declare_node ? 1 : 0;
+}
+
+static int bgp_fs_local_install_interface(struct bgp *bgp,
+                                         const char *no, const char *ifname)
+{
+       struct bgp_pbr_interface *pbr_if;
+       struct bgp_pbr_config *bgp_pbr_cfg = bgp->bgp_pbr_cfg;
+       struct bgp_pbr_interface_head *head;
+       bool *bgp_pbr_interface_any;
+
+       if (!bgp_pbr_cfg)
+               return CMD_SUCCESS;
+       head = &(bgp_pbr_cfg->ifaces_by_name_ipv4);
+       bgp_pbr_interface_any = &(bgp_pbr_cfg->pbr_interface_any_ipv4);
+       if (no) {
+               if (!ifname) {
+                       if (*bgp_pbr_interface_any) {
+                               *bgp_pbr_interface_any = false;
+                               /* remove all other interface list */
+                               bgp_pbr_reset(bgp, AFI_IP);
+                       }
+                       return CMD_SUCCESS;
+               }
+               pbr_if = bgp_pbr_interface_lookup(ifname, head);
+               if (!pbr_if)
+                       return CMD_SUCCESS;
+               RB_REMOVE(bgp_pbr_interface_head, head, pbr_if);
+               return CMD_SUCCESS;
+       }
+       if (ifname) {
+               pbr_if = bgp_pbr_interface_lookup(ifname, head);
+               if (pbr_if)
+                       return CMD_SUCCESS;
+               pbr_if = XCALLOC(MTYPE_TMP,
+                                sizeof(struct bgp_pbr_interface));
+               strlcpy(pbr_if->name, ifname, INTERFACE_NAMSIZ);
+               RB_INSERT(bgp_pbr_interface_head, head, pbr_if);
+               *bgp_pbr_interface_any = false;
+       } else {
+               /* set to default */
+               if (!*bgp_pbr_interface_any) {
+                       /* remove all other interface list
+                        */
+                       bgp_pbr_reset(bgp, AFI_IP);
+                       *bgp_pbr_interface_any = true;
+               }
+       }
+       return CMD_SUCCESS;
+}
+
+DEFUN (bgp_fs_local_install_ifname,
+       bgp_fs_local_install_ifname_cmd,
+       "[no] local-install INTERFACE",
+       NO_STR
+       "Apply local policy routing\n"
+       "Interface name\n")
+{
+       struct bgp *bgp = VTY_GET_CONTEXT(bgp);
+       int idx = 0;
+       const char *no = strmatch(argv[0]->text, (char *)"no") ? "no" : NULL;
+       char *ifname = argv_find(argv, argc, "INTERFACE", &idx) ?
+               argv[idx]->arg : NULL;
+
+       return bgp_fs_local_install_interface(bgp, no, ifname);
+}
+
+extern int bgp_flowspec_display_match_per_ip(afi_t afi,
+                       struct bgp_table *rib,
+                       struct prefix *match,
+                       int prefix_check,
+                       struct vty *vty,
+                       uint8_t use_json,
+                       json_object *json_paths)
+{
+       struct bgp_node *rn;
+       struct prefix *prefix;
+       int display = 0;
+
+       for (rn = bgp_table_top(rib); rn; rn = bgp_route_next(rn)) {
+               prefix = &rn->p;
+
+               if (prefix->family != AF_FLOWSPEC)
+                       continue;
+
+               if (bgp_flowspec_contains_prefix(prefix, match, prefix_check)) {
+                       route_vty_out_flowspec(vty, &rn->p,
+                                              rn->info, use_json ?
+                                              NLRI_STRING_FORMAT_JSON :
+                                              NLRI_STRING_FORMAT_LARGE,
+                                              json_paths);
+                       display++;
+               }
+       }
+       return display;
+}
+
 void bgp_flowspec_vty_init(void)
 {
        install_element(ENABLE_NODE, &debug_bgp_flowspec_cmd);
        install_element(CONFIG_NODE, &debug_bgp_flowspec_cmd);
        install_element(ENABLE_NODE, &no_debug_bgp_flowspec_cmd);
        install_element(CONFIG_NODE, &no_debug_bgp_flowspec_cmd);
+       install_element(BGP_FLOWSPECV4_NODE, &bgp_fs_local_install_ifname_cmd);
 }