]> git.proxmox.com Git - mirror_frr.git/commitdiff
bgpd: add vty command to restrict FS policy routing to a defined interface
authorPhilippe Guibert <philippe.guibert@6wind.com>
Wed, 25 Apr 2018 16:29:35 +0000 (18:29 +0200)
committerPhilippe Guibert <philippe.guibert@6wind.com>
Fri, 25 May 2018 13:49:38 +0000 (15:49 +0200)
policy routing is configurable via address-family ipv4 flowspec
subfamily node. This is then possible to restrict flowspec operation
through the BGP instance, to a single or some interfaces, but not all.

Two commands available:
[no] local-install [IFNAME]

Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
bgpd/bgp_flowspec.h
bgpd/bgp_flowspec_vty.c
bgpd/bgp_pbr.c
bgpd/bgp_pbr.h
bgpd/bgp_zebra.c
bgpd/bgpd.c
bgpd/bgpd.h

index 392b32153036dd82f412ddb85e508900375a3dcb..5dd2c3931ac7a78c1150aded46b125d375c3fd86 100644 (file)
@@ -47,4 +47,7 @@ extern void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len,
 extern void route_vty_out_flowspec(struct vty *vty, struct prefix *p,
                                   struct bgp_info *binfo,
                                   int display, json_object *json_paths);
+extern int bgp_fs_config_write_pbr(struct vty *vty, struct bgp *bgp,
+                                  afi_t afi, safi_t safi);
+
 #endif /* _FRR_BGP_FLOWSPEC_H */
index 3ff45288953dc59df04ffbb8b9e13e24fb8641eb..b21e5ae0dcc4b2284c510c91dee3af34868d0d1c 100644 (file)
@@ -425,10 +425,113 @@ 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);
+       }
+       if (!bgp_pbr_interface_any)
+               vty_out(vty, "  no local-install any\n");
+       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);
+}
+
+DEFUN (bgp_fs_local_install_any,
+       bgp_fs_local_install_any_cmd,
+       "[no] local-install any",
+       NO_STR
+       "Apply local policy routing\n"
+       "Any Interface\n")
+{
+       struct bgp *bgp = VTY_GET_CONTEXT(bgp);
+       const char *no = strmatch(argv[0]->text, (char *)"no") ? "no" : NULL;
+
+       return bgp_fs_local_install_interface(bgp, no, NULL);
+}
+
 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_any_cmd);
+       install_element(BGP_FLOWSPECV4_NODE, &bgp_fs_local_install_ifname_cmd);
 }
index 646d58352e590c6be1b337d95a18e1f298db16c1..343a928ad80bb577842944fa657d03040c2b3efe 100644 (file)
 DEFINE_MTYPE_STATIC(BGPD, PBR_MATCH_ENTRY, "PBR match entry")
 DEFINE_MTYPE_STATIC(BGPD, PBR_MATCH, "PBR match")
 DEFINE_MTYPE_STATIC(BGPD, PBR_ACTION, "PBR action")
+DEFINE_MTYPE_STATIC(BGPD, PBR, "BGP PBR Context")
+
+RB_GENERATE(bgp_pbr_interface_head, bgp_pbr_interface,
+           id_entry, bgp_pbr_interface_compare);
+struct bgp_pbr_interface_head ifaces_by_name_ipv4 =
+       RB_INITIALIZER(&ifaces_by_name_ipv4);
 
 static int bgp_pbr_match_counter_unique;
 static int bgp_pbr_match_entry_counter_unique;
@@ -705,6 +711,11 @@ void bgp_pbr_cleanup(struct bgp *bgp)
                hash_free(bgp->pbr_action_hash);
                bgp->pbr_action_hash = NULL;
        }
+       if (bgp->bgp_pbr_cfg == NULL)
+               return;
+       bgp_pbr_reset(bgp, AFI_IP);
+       XFREE(MTYPE_PBR, bgp->bgp_pbr_cfg);
+       bgp->bgp_pbr_cfg = NULL;
 }
 
 void bgp_pbr_init(struct bgp *bgp)
@@ -717,6 +728,9 @@ void bgp_pbr_init(struct bgp *bgp)
                hash_create_size(8, bgp_pbr_action_hash_key,
                                 bgp_pbr_action_hash_equal,
                                 "Match Hash Entry");
+
+       bgp->bgp_pbr_cfg = XCALLOC(MTYPE_PBR, sizeof(struct bgp_pbr_config));
+       bgp->bgp_pbr_cfg->pbr_interface_any_ipv4 = true;
 }
 
 void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main *api)
@@ -1350,3 +1364,39 @@ void bgp_pbr_update_entry(struct bgp *bgp, struct prefix *p,
        }
        bgp_pbr_handle_entry(bgp, info, &api, nlri_update);
 }
+
+int bgp_pbr_interface_compare(const struct bgp_pbr_interface *a,
+                         const struct bgp_pbr_interface *b)
+{
+       return strcmp(a->name, b->name);
+}
+
+struct bgp_pbr_interface *bgp_pbr_interface_lookup(const char *name,
+                                          struct bgp_pbr_interface_head *head)
+{
+       struct bgp_pbr_interface pbr_if;
+
+       strlcpy(pbr_if.name, name, sizeof(pbr_if.name));
+       return (RB_FIND(bgp_pbr_interface_head,
+                       head, &pbr_if));
+}
+
+/* this function resets to the default policy routing
+ * go back to default status
+ */
+void bgp_pbr_reset(struct bgp *bgp, afi_t afi)
+{
+       struct bgp_pbr_config *bgp_pbr_cfg = bgp->bgp_pbr_cfg;
+       struct bgp_pbr_interface_head *head;
+       struct bgp_pbr_interface *pbr_if;
+
+       if (!bgp_pbr_cfg || afi != AFI_IP)
+               return;
+       head = &(bgp_pbr_cfg->ifaces_by_name_ipv4);
+
+       while (!RB_EMPTY(bgp_pbr_interface_head, head)) {
+               pbr_if = RB_ROOT(bgp_pbr_interface_head, head);
+               RB_REMOVE(bgp_pbr_interface_head, head, pbr_if);
+               XFREE(MTYPE_TMP, pbr_if);
+       }
+}
index e4117ffd05e0822ce0dda8a61768acb79192ba8a..20edaf30b8a567fa5bf70a6f73e73375ef6cb276 100644 (file)
@@ -150,6 +150,25 @@ struct bgp_pbr_entry_main {
        vrf_id_t vrf_id;
 };
 
+struct bgp_pbr_interface {
+       RB_ENTRY(bgp_pbr_interface) id_entry;
+       char name[INTERFACE_NAMSIZ];
+};
+
+RB_HEAD(bgp_pbr_interface_head, bgp_pbr_interface);
+RB_PROTOTYPE(bgp_pbr_interface_head, bgp_pbr_interface, id_entry,
+            bgp_pbr_interface_compare);
+
+extern int bgp_pbr_interface_compare(const struct bgp_pbr_interface *a,
+                                    const struct bgp_pbr_interface *b);
+
+struct bgp_pbr_config {
+       struct bgp_pbr_interface_head ifaces_by_name_ipv4;
+       bool pbr_interface_any_ipv4;
+};
+
+extern struct bgp_pbr_config *bgp_pbr_cfg;
+
 struct bgp_pbr_match {
        char ipset_name[ZEBRA_IPSET_NAME_SIZE];
 
@@ -267,4 +286,10 @@ extern void bgp_pbr_update_entry(struct bgp *bgp, struct prefix *p,
                                afi_t afi, safi_t safi,
                                bool nlri_update);
 
+/* bgp pbr utilities */
+extern struct bgp_pbr_interface *pbr_interface_lookup(const char *name);
+extern void bgp_pbr_reset(struct bgp *bgp, afi_t afi);
+extern struct bgp_pbr_interface *bgp_pbr_interface_lookup(const char *name,
+                                  struct bgp_pbr_interface_head *head);
+
 #endif /* __BGP_PBR_H__ */
index 84a8155808f1df193220ff7ba7015f4f1ea2f069..641861a28f37ad4444a904c234b2cd7dbddfe178 100644 (file)
@@ -2574,12 +2574,49 @@ void bgp_send_pbr_ipset_entry_match(struct bgp_pbr_match_entry *pbrime,
                pbrime->install_in_progress = true;
 }
 
+static void bgp_encode_pbr_interface_list(struct bgp *bgp, struct stream *s)
+{
+       struct bgp_pbr_config *bgp_pbr_cfg = bgp->bgp_pbr_cfg;
+       struct bgp_pbr_interface_head *head;
+       struct bgp_pbr_interface *pbr_if;
+       struct interface *ifp;
+
+       if (!bgp_pbr_cfg)
+               return;
+       head = &(bgp_pbr_cfg->ifaces_by_name_ipv4);
+
+       RB_FOREACH (pbr_if, bgp_pbr_interface_head, head) {
+               ifp = if_lookup_by_name(pbr_if->name, bgp->vrf_id);
+               if (ifp)
+                       stream_putl(s, ifp->ifindex);
+       }
+}
+
+static int bgp_pbr_get_ifnumber(struct bgp *bgp)
+{
+       struct bgp_pbr_config *bgp_pbr_cfg = bgp->bgp_pbr_cfg;
+       struct bgp_pbr_interface_head *head;
+       struct bgp_pbr_interface *pbr_if;
+       int cnt = 0;
+
+       if (!bgp_pbr_cfg)
+               return 0;
+       head = &(bgp_pbr_cfg->ifaces_by_name_ipv4);
+
+       RB_FOREACH (pbr_if, bgp_pbr_interface_head, head) {
+               if (if_lookup_by_name(pbr_if->name, bgp->vrf_id))
+                       cnt++;
+       }
+       return cnt;
+}
+
 void bgp_send_pbr_iptable(struct bgp_pbr_action *pba,
                          struct bgp_pbr_match *pbm,
                          bool install)
 {
        struct stream *s;
        int ret = 0;
+       int nb_interface;
 
        if (pbm->install_iptable_in_progress)
                return;
@@ -2594,7 +2631,10 @@ void bgp_send_pbr_iptable(struct bgp_pbr_action *pba,
                              VRF_DEFAULT);
 
        bgp_encode_pbr_iptable_match(s, pba, pbm);
-
+       nb_interface = bgp_pbr_get_ifnumber(pba->bgp);
+       stream_putl(s, nb_interface);
+       if (nb_interface)
+               bgp_encode_pbr_interface_list(pba->bgp, s);
        stream_putw_at(s, 0, stream_get_endp(s));
        ret = zclient_send_message(zclient);
        if (install) {
index 71707b6afa8ebae15eddf9651686d73451e496d5..ab13a37d9d1fd5cb09a57490c9366f833158eba2 100644 (file)
@@ -7266,6 +7266,9 @@ static void bgp_config_write_family(struct vty *vty, struct bgp *bgp, afi_t afi,
        if (safi == SAFI_EVPN)
                bgp_config_write_evpn_info(vty, bgp, afi, safi);
 
+       if (safi == SAFI_FLOWSPEC)
+               bgp_fs_config_write_pbr(vty, bgp, afi, safi);
+
        if (safi == SAFI_UNICAST) {
                bgp_vpn_policy_config_write_afi(vty, bgp, afi);
                if (CHECK_FLAG(bgp->af_flags[afi][safi],
index 340851e8d90ce1c3544ed556ecd23860eb47d9df..f663df162f7b37667c63f5f84dbfce6212b19d2b 100644 (file)
@@ -47,6 +47,7 @@
 
 struct update_subgroup;
 struct bpacket;
+struct bgp_pbr_config;
 
 /*
  * Allow the neighbor XXXX remote-as to take internal or external
@@ -531,6 +532,8 @@ struct bgp {
 
        struct vpn_policy vpn_policy[AFI_MAX];
 
+       struct bgp_pbr_config *bgp_pbr_cfg;
+
        QOBJ_FIELDS
 };
 DECLARE_QOBJ_TYPE(bgp)