mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-08 09:30:30 +00:00
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>
This commit is contained in:
parent
b588b642ce
commit
4762c2137d
@ -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,
|
extern void route_vty_out_flowspec(struct vty *vty, struct prefix *p,
|
||||||
struct bgp_info *binfo,
|
struct bgp_info *binfo,
|
||||||
int display, json_object *json_paths);
|
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 */
|
#endif /* _FRR_BGP_FLOWSPEC_H */
|
||||||
|
@ -425,10 +425,113 @@ DEFUN (no_debug_bgp_flowspec,
|
|||||||
return CMD_SUCCESS;
|
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)
|
void bgp_flowspec_vty_init(void)
|
||||||
{
|
{
|
||||||
install_element(ENABLE_NODE, &debug_bgp_flowspec_cmd);
|
install_element(ENABLE_NODE, &debug_bgp_flowspec_cmd);
|
||||||
install_element(CONFIG_NODE, &debug_bgp_flowspec_cmd);
|
install_element(CONFIG_NODE, &debug_bgp_flowspec_cmd);
|
||||||
install_element(ENABLE_NODE, &no_debug_bgp_flowspec_cmd);
|
install_element(ENABLE_NODE, &no_debug_bgp_flowspec_cmd);
|
||||||
install_element(CONFIG_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);
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,12 @@
|
|||||||
DEFINE_MTYPE_STATIC(BGPD, PBR_MATCH_ENTRY, "PBR match entry")
|
DEFINE_MTYPE_STATIC(BGPD, PBR_MATCH_ENTRY, "PBR match entry")
|
||||||
DEFINE_MTYPE_STATIC(BGPD, PBR_MATCH, "PBR match")
|
DEFINE_MTYPE_STATIC(BGPD, PBR_MATCH, "PBR match")
|
||||||
DEFINE_MTYPE_STATIC(BGPD, PBR_ACTION, "PBR action")
|
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_counter_unique;
|
||||||
static int bgp_pbr_match_entry_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);
|
hash_free(bgp->pbr_action_hash);
|
||||||
bgp->pbr_action_hash = NULL;
|
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)
|
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,
|
hash_create_size(8, bgp_pbr_action_hash_key,
|
||||||
bgp_pbr_action_hash_equal,
|
bgp_pbr_action_hash_equal,
|
||||||
"Match Hash Entry");
|
"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)
|
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);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -150,6 +150,25 @@ struct bgp_pbr_entry_main {
|
|||||||
vrf_id_t vrf_id;
|
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 {
|
struct bgp_pbr_match {
|
||||||
char ipset_name[ZEBRA_IPSET_NAME_SIZE];
|
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,
|
afi_t afi, safi_t safi,
|
||||||
bool nlri_update);
|
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__ */
|
#endif /* __BGP_PBR_H__ */
|
||||||
|
@ -2574,12 +2574,49 @@ void bgp_send_pbr_ipset_entry_match(struct bgp_pbr_match_entry *pbrime,
|
|||||||
pbrime->install_in_progress = true;
|
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,
|
void bgp_send_pbr_iptable(struct bgp_pbr_action *pba,
|
||||||
struct bgp_pbr_match *pbm,
|
struct bgp_pbr_match *pbm,
|
||||||
bool install)
|
bool install)
|
||||||
{
|
{
|
||||||
struct stream *s;
|
struct stream *s;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
int nb_interface;
|
||||||
|
|
||||||
if (pbm->install_iptable_in_progress)
|
if (pbm->install_iptable_in_progress)
|
||||||
return;
|
return;
|
||||||
@ -2594,7 +2631,10 @@ void bgp_send_pbr_iptable(struct bgp_pbr_action *pba,
|
|||||||
VRF_DEFAULT);
|
VRF_DEFAULT);
|
||||||
|
|
||||||
bgp_encode_pbr_iptable_match(s, pba, pbm);
|
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));
|
stream_putw_at(s, 0, stream_get_endp(s));
|
||||||
ret = zclient_send_message(zclient);
|
ret = zclient_send_message(zclient);
|
||||||
if (install) {
|
if (install) {
|
||||||
|
@ -7266,6 +7266,9 @@ static void bgp_config_write_family(struct vty *vty, struct bgp *bgp, afi_t afi,
|
|||||||
if (safi == SAFI_EVPN)
|
if (safi == SAFI_EVPN)
|
||||||
bgp_config_write_evpn_info(vty, bgp, afi, safi);
|
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) {
|
if (safi == SAFI_UNICAST) {
|
||||||
bgp_vpn_policy_config_write_afi(vty, bgp, afi);
|
bgp_vpn_policy_config_write_afi(vty, bgp, afi);
|
||||||
if (CHECK_FLAG(bgp->af_flags[afi][safi],
|
if (CHECK_FLAG(bgp->af_flags[afi][safi],
|
||||||
|
@ -47,6 +47,7 @@
|
|||||||
|
|
||||||
struct update_subgroup;
|
struct update_subgroup;
|
||||||
struct bpacket;
|
struct bpacket;
|
||||||
|
struct bgp_pbr_config;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allow the neighbor XXXX remote-as to take internal or external
|
* 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 vpn_policy vpn_policy[AFI_MAX];
|
||||||
|
|
||||||
|
struct bgp_pbr_config *bgp_pbr_cfg;
|
||||||
|
|
||||||
QOBJ_FIELDS
|
QOBJ_FIELDS
|
||||||
};
|
};
|
||||||
DECLARE_QOBJ_TYPE(bgp)
|
DECLARE_QOBJ_TYPE(bgp)
|
||||||
|
Loading…
Reference in New Issue
Block a user