summaryrefslogtreecommitdiffstats
path: root/bgpd
diff options
context:
space:
mode:
authorPhilippe Guibert <philippe.guibert@6wind.com>2018-04-25 18:29:35 +0200
committerPhilippe Guibert <philippe.guibert@6wind.com>2018-05-25 15:49:38 +0200
commit4762c2137de994b5b1054cc43c26efef04b27bbf (patch)
treee645d9a0e0938327506bf7b7bfd507a28329de57 /bgpd
parentbgpd: display if FS entry is installed in PBR or not (diff)
downloadfrr-4762c2137de994b5b1054cc43c26efef04b27bbf.tar.xz
frr-4762c2137de994b5b1054cc43c26efef04b27bbf.zip
bgpd: add vty command to restrict FS policy routing to a defined interface
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>
Diffstat (limited to 'bgpd')
-rw-r--r--bgpd/bgp_flowspec.h3
-rw-r--r--bgpd/bgp_flowspec_vty.c103
-rw-r--r--bgpd/bgp_pbr.c50
-rw-r--r--bgpd/bgp_pbr.h25
-rw-r--r--bgpd/bgp_zebra.c42
-rw-r--r--bgpd/bgpd.c3
-rw-r--r--bgpd/bgpd.h3
7 files changed, 228 insertions, 1 deletions
diff --git a/bgpd/bgp_flowspec.h b/bgpd/bgp_flowspec.h
index 392b32153..5dd2c3931 100644
--- a/bgpd/bgp_flowspec.h
+++ b/bgpd/bgp_flowspec.h
@@ -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 */
diff --git a/bgpd/bgp_flowspec_vty.c b/bgpd/bgp_flowspec_vty.c
index 3ff452889..b21e5ae0d 100644
--- a/bgpd/bgp_flowspec_vty.c
+++ b/bgpd/bgp_flowspec_vty.c
@@ -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);
}
diff --git a/bgpd/bgp_pbr.c b/bgpd/bgp_pbr.c
index 646d58352..343a928ad 100644
--- a/bgpd/bgp_pbr.c
+++ b/bgpd/bgp_pbr.c
@@ -35,6 +35,12 @@
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);
+ }
+}
diff --git a/bgpd/bgp_pbr.h b/bgpd/bgp_pbr.h
index e4117ffd0..20edaf30b 100644
--- a/bgpd/bgp_pbr.h
+++ b/bgpd/bgp_pbr.h
@@ -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__ */
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 84a815580..641861a28 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -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) {
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 71707b6af..ab13a37d9 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -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],
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 340851e8d..f663df162 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -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)