Merge pull request #3414 from pguibert6WIND/iprule_any_flowspec_handling_2

Iprule any flowspec handling
This commit is contained in:
Donald Sharp 2019-01-29 14:01:38 -05:00 committed by GitHub
commit 2b697c3d47
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 515 additions and 68 deletions

View File

@ -456,8 +456,7 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
*/
if (prefix->family == AF_INET
&& prefix->u.prefix4.s_addr == 0)
memset(prefix, 0,
sizeof(struct prefix));
bpem->match_bitmask_iprule |= bitmask;
else
bpem->match_bitmask |= bitmask;
}
@ -580,6 +579,22 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
__func__, type);
}
}
if (bpem->match_packet_length_num || bpem->match_fragment_num ||
bpem->match_tcpflags_num || bpem->match_dscp_num ||
bpem->match_packet_length_num || bpem->match_icmp_code_num ||
bpem->match_icmp_type_num || bpem->match_port_num ||
bpem->match_src_port_num || bpem->match_dst_port_num ||
bpem->match_protocol_num || bpem->match_bitmask)
bpem->type = BGP_PBR_IPSET;
else if ((bpem->match_bitmask_iprule & PREFIX_SRC_PRESENT) ||
(bpem->match_bitmask_iprule & PREFIX_DST_PRESENT))
/* the extracted policy rule may not need an
* iptables/ipset filtering. check this may not be
* a standard ip rule : permit any to any ( eg)
*/
bpem->type = BGP_PBR_IPRULE;
else
bpem->type = BGP_PBR_UNDEFINED;
return error;
}

View File

@ -333,16 +333,17 @@ void route_vty_out_flowspec(struct vty *vty, struct prefix *p,
struct bgp_path_info_extra *extra =
bgp_path_info_extra_get(path);
if (extra->bgp_fs_pbr) {
if (listcount(extra->bgp_fs_pbr) ||
listcount(extra->bgp_fs_iprule)) {
struct listnode *node;
struct bgp_pbr_match_entry *bpme;
struct bgp_pbr_rule *bpr;
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");
vty_out(vty, "\tinstalled in PBR");
for (ALL_LIST_ELEMENTS_RO(extra->bgp_fs_pbr,
node, bpme)) {
bpm = bpme->backpointer;
@ -356,6 +357,19 @@ void route_vty_out_flowspec(struct vty *vty, struct prefix *p,
vty_out(vty, ", ");
vty_out(vty, "%s", bpm->ipset_name);
}
for (ALL_LIST_ELEMENTS_RO(extra->bgp_fs_iprule,
node, bpr)) {
if (!bpr->action)
continue;
if (!list_began) {
vty_out(vty, " (");
list_began = true;
} else
vty_out(vty, ", ");
vty_out(vty, "-ipv4-rule %d action lookup %u-",
bpr->priority,
bpr->action->table_id);
}
if (list_began)
vty_out(vty, ")");
vty_out(vty, "\n");

View File

@ -38,6 +38,7 @@
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_RULE, "PBR rule")
DEFINE_MTYPE_STATIC(BGPD, PBR, "BGP PBR Context")
DEFINE_MTYPE_STATIC(BGPD, PBR_VALMASK, "BGP PBR Val Mask Value")
@ -66,6 +67,25 @@ struct bgp_pbr_action_unique {
struct bgp_pbr_action *bpa_found;
};
struct bgp_pbr_rule_unique {
uint32_t unique;
struct bgp_pbr_rule *bpr_found;
};
static int bgp_pbr_rule_walkcb(struct hash_backet *backet, void *arg)
{
struct bgp_pbr_rule *bpr = (struct bgp_pbr_rule *)backet->data;
struct bgp_pbr_rule_unique *bpru = (struct bgp_pbr_rule_unique *)
arg;
uint32_t unique = bpru->unique;
if (bpr->unique == unique) {
bpru->bpr_found = bpr;
return HASHWALK_ABORT;
}
return HASHWALK_CONTINUE;
}
static int bgp_pbr_action_walkcb(struct hash_backet *backet, void *arg)
{
struct bgp_pbr_action *bpa = (struct bgp_pbr_action *)backet->data;
@ -200,9 +220,11 @@ struct bgp_pbr_val_mask {
* so that BGP can create pbr instructions to ZEBRA
*/
struct bgp_pbr_filter {
uint8_t type;
vrf_id_t vrf_id;
struct prefix *src;
struct prefix *dst;
uint8_t bitmask_iprule;
uint8_t protocol;
struct bgp_pbr_range_port *pkt_len;
struct bgp_pbr_range_port *src_port;
@ -448,6 +470,11 @@ static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main *api)
{
bool enumerate_icmp = false;
if (api->type == BGP_PBR_UNDEFINED) {
if (BGP_DEBUG(pbr, PBR))
zlog_debug("BGP: pbr entry undefined. cancel.");
return 0;
}
/* because bgp pbr entry may contain unsupported
* combinations, a message will be displayed here if
* not supported.
@ -612,13 +639,45 @@ static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main *api)
" too complex. ignoring.");
return 0;
}
if (!(api->match_bitmask & PREFIX_SRC_PRESENT) &&
!(api->match_bitmask & PREFIX_DST_PRESENT)) {
/* iprule only supports redirect IP */
if (api->type == BGP_PBR_IPRULE) {
int i;
for (i = 0; i < api->action_num; i++) {
if (api->actions[i].action == ACTION_TRAFFICRATE &&
api->actions[i].u.r.rate == 0) {
if (BGP_DEBUG(pbr, PBR)) {
bgp_pbr_print_policy_route(api);
zlog_debug("BGP: iprule match actions"
" drop not supported");
}
return 0;
}
if (api->actions[i].action == ACTION_MARKING) {
if (BGP_DEBUG(pbr, PBR)) {
bgp_pbr_print_policy_route(api);
zlog_warn("PBR: iprule set DSCP %u"
" not supported",
api->actions[i].u.marking_dscp);
}
}
if (api->actions[i].action == ACTION_REDIRECT) {
if (BGP_DEBUG(pbr, PBR)) {
bgp_pbr_print_policy_route(api);
zlog_warn("PBR: iprule redirect VRF %u"
" not supported",
api->actions[i].u.redirect_vrf);
}
}
}
} else if (!(api->match_bitmask & PREFIX_SRC_PRESENT) &&
!(api->match_bitmask & PREFIX_DST_PRESENT)) {
if (BGP_DEBUG(pbr, PBR)) {
bgp_pbr_print_policy_route(api);
zlog_debug("BGP: match actions without src"
" or dst address can not operate."
" ignoring.");
" or dst address can not operate."
" ignoring.");
}
return 0;
}
@ -832,6 +891,34 @@ static void *bgp_pbr_match_alloc_intern(void *arg)
return new;
}
static void bgp_pbr_rule_free(void *arg)
{
struct bgp_pbr_rule *bpr;
bpr = (struct bgp_pbr_rule *)arg;
/* delete iprule */
if (bpr->installed) {
bgp_send_pbr_rule_action(bpr->action, bpr, false);
bpr->installed = false;
bpr->action->refcnt--;
bpr->action = NULL;
}
XFREE(MTYPE_PBR_RULE, bpr);
}
static void *bgp_pbr_rule_alloc_intern(void *arg)
{
struct bgp_pbr_rule *bpr, *new;
bpr = (struct bgp_pbr_rule *)arg;
new = XCALLOC(MTYPE_PBR_RULE, sizeof(*new));
memcpy(new, bpr, sizeof(*bpr));
return new;
}
static void bgp_pbr_action_free(void *arg)
{
struct bgp_pbr_action *bpa;
@ -840,7 +927,7 @@ static void bgp_pbr_action_free(void *arg)
if (bpa->refcnt == 0) {
if (bpa->installed && bpa->table_id != 0) {
bgp_send_pbr_rule_action(bpa, false);
bgp_send_pbr_rule_action(bpa, NULL, false);
bgp_zebra_announce_default(bpa->bgp, &(bpa->nh),
AFI_IP,
bpa->table_id,
@ -932,6 +1019,44 @@ bool bgp_pbr_match_hash_equal(const void *arg1, const void *arg2)
return true;
}
uint32_t bgp_pbr_rule_hash_key(void *arg)
{
struct bgp_pbr_rule *pbr = (struct bgp_pbr_rule *)arg;
uint32_t key;
key = prefix_hash_key(&pbr->src);
key = jhash_1word(pbr->vrf_id, key);
key = jhash_1word(pbr->flags, key);
return jhash_1word(prefix_hash_key(&pbr->dst), key);
}
bool bgp_pbr_rule_hash_equal(const void *arg1, const void *arg2)
{
const struct bgp_pbr_rule *r1, *r2;
r1 = (const struct bgp_pbr_rule *)arg1;
r2 = (const struct bgp_pbr_rule *)arg2;
if (r1->vrf_id != r2->vrf_id)
return false;
if (r1->flags != r2->flags)
return false;
if (r1->action != r2->action)
return false;
if ((r1->flags & MATCH_IP_SRC_SET) &&
!prefix_same(&r1->src, &r2->src))
return false;
if ((r1->flags & MATCH_IP_DST_SET) &&
!prefix_same(&r1->dst, &r2->dst))
return false;
return true;
}
uint32_t bgp_pbr_match_entry_hash_key(void *arg)
{
struct bgp_pbr_match_entry *pbme;
@ -1017,6 +1142,20 @@ bool bgp_pbr_action_hash_equal(const void *arg1, const void *arg2)
return true;
}
struct bgp_pbr_rule *bgp_pbr_rule_lookup(vrf_id_t vrf_id,
uint32_t unique)
{
struct bgp *bgp = bgp_lookup_by_vrf_id(vrf_id);
struct bgp_pbr_rule_unique bpru;
if (!bgp || unique == 0)
return NULL;
bpru.unique = unique;
bpru.bpr_found = NULL;
hash_walk(bgp->pbr_rule_hash, bgp_pbr_rule_walkcb, &bpru);
return bpru.bpr_found;
}
struct bgp_pbr_action *bgp_pbr_action_rule_lookup(vrf_id_t vrf_id,
uint32_t unique)
{
@ -1090,6 +1229,11 @@ void bgp_pbr_cleanup(struct bgp *bgp)
hash_free(bgp->pbr_match_hash);
bgp->pbr_match_hash = NULL;
}
if (bgp->pbr_rule_hash) {
hash_clean(bgp->pbr_rule_hash, bgp_pbr_rule_free);
hash_free(bgp->pbr_rule_hash);
bgp->pbr_rule_hash = NULL;
}
if (bgp->pbr_action_hash) {
hash_clean(bgp->pbr_action_hash, bgp_pbr_action_free);
hash_free(bgp->pbr_action_hash);
@ -1113,6 +1257,11 @@ void bgp_pbr_init(struct bgp *bgp)
bgp_pbr_action_hash_equal,
"Match Hash Entry");
bgp->pbr_rule_hash =
hash_create_size(8, bgp_pbr_rule_hash_key,
bgp_pbr_rule_hash_equal,
"Match Rule");
bgp->bgp_pbr_cfg = XCALLOC(MTYPE_PBR, sizeof(struct bgp_pbr_config));
bgp->bgp_pbr_cfg->pbr_interface_any_ipv4 = true;
}
@ -1253,6 +1402,42 @@ void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main *api)
zlog_info("%s", return_string);
}
static void bgp_pbr_flush_iprule(struct bgp *bgp, struct bgp_pbr_action *bpa,
struct bgp_pbr_rule *bpr)
{
/* if bpr is null, do nothing
*/
if (bpr == NULL)
return;
if (bpr->installed) {
bgp_send_pbr_rule_action(bpa, bpr, false);
bpr->installed = false;
bpr->action->refcnt--;
bpr->action = NULL;
if (bpr->path) {
struct bgp_path_info *path;
struct bgp_path_info_extra *extra;
/* unlink path to bpme */
path = (struct bgp_path_info *)bpr->path;
extra = bgp_path_info_extra_get(path);
listnode_delete(extra->bgp_fs_iprule, bpr);
bpr->path = NULL;
}
}
hash_release(bgp->pbr_rule_hash, bpr);
if (bpa->refcnt == 0) {
if (bpa->installed && bpa->table_id != 0) {
bgp_send_pbr_rule_action(bpa, NULL, false);
bgp_zebra_announce_default(bpa->bgp, &(bpa->nh),
AFI_IP,
bpa->table_id,
false);
bpa->installed = false;
}
}
}
static void bgp_pbr_flush_entry(struct bgp *bgp, struct bgp_pbr_action *bpa,
struct bgp_pbr_match *bpm,
struct bgp_pbr_match_entry *bpme)
@ -1270,11 +1455,10 @@ static void bgp_pbr_flush_entry(struct bgp *bgp, struct bgp_pbr_action *bpa,
struct bgp_path_info *path;
struct bgp_path_info_extra *extra;
/* unlink bgp_path_info to bpme */
/* unlink path to bpme */
path = (struct bgp_path_info *)bpme->path;
extra = bgp_path_info_extra_get(path);
if (extra->bgp_fs_pbr)
listnode_delete(extra->bgp_fs_pbr, bpme);
listnode_delete(extra->bgp_fs_pbr, bpme);
bpme->path = NULL;
}
}
@ -1300,7 +1484,7 @@ static void bgp_pbr_flush_entry(struct bgp *bgp, struct bgp_pbr_action *bpa,
}
if (bpa->refcnt == 0) {
if (bpa->installed && bpa->table_id != 0) {
bgp_send_pbr_rule_action(bpa, false);
bgp_send_pbr_rule_action(bpa, NULL, false);
bgp_zebra_announce_default(bpa->bgp, &(bpa->nh),
AFI_IP,
bpa->table_id,
@ -1315,6 +1499,50 @@ struct bgp_pbr_match_entry_remain {
struct bgp_pbr_match_entry *bpme_found;
};
struct bgp_pbr_rule_remain {
struct bgp_pbr_rule *bpr_to_match;
struct bgp_pbr_rule *bpr_found;
};
static int bgp_pbr_get_same_rule(struct hash_backet *backet, void *arg)
{
struct bgp_pbr_rule *r1 = (struct bgp_pbr_rule *)backet->data;
struct bgp_pbr_rule_remain *ctxt =
(struct bgp_pbr_rule_remain *)arg;
struct bgp_pbr_rule *r2;
r2 = ctxt->bpr_to_match;
if (r1->vrf_id != r2->vrf_id)
return HASHWALK_CONTINUE;
if (r1->flags != r2->flags)
return HASHWALK_CONTINUE;
if ((r1->flags & MATCH_IP_SRC_SET) &&
!prefix_same(&r1->src, &r2->src))
return HASHWALK_CONTINUE;
if ((r1->flags & MATCH_IP_DST_SET) &&
!prefix_same(&r1->dst, &r2->dst))
return HASHWALK_CONTINUE;
/* this function is used for two cases:
* - remove an entry upon withdraw request
* (case r2->action is null)
* - replace an old iprule with different action
* (case r2->action is != null)
* the old one is removed after the new one
* this is to avoid disruption in traffic
*/
if (r2->action == NULL ||
r1->action != r2->action) {
ctxt->bpr_found = r1;
return HASHWALK_ABORT;
}
return HASHWALK_CONTINUE;
}
static int bgp_pbr_get_remaining_entry(struct hash_backet *backet, void *arg)
{
struct bgp_pbr_match *bpm = (struct bgp_pbr_match *)backet->data;
@ -1352,12 +1580,15 @@ static void bgp_pbr_policyroute_remove_from_zebra_unit(
{
struct bgp_pbr_match temp;
struct bgp_pbr_match_entry temp2;
struct bgp_pbr_rule pbr_rule;
struct bgp_pbr_rule *bpr;
struct bgp_pbr_match *bpm;
struct bgp_pbr_match_entry *bpme;
struct bgp_pbr_match_entry_remain bpmer;
struct bgp_pbr_range_port *src_port;
struct bgp_pbr_range_port *dst_port;
struct bgp_pbr_range_port *pkt_len;
struct bgp_pbr_rule_remain bprr;
if (!bpf)
return;
@ -1374,6 +1605,37 @@ static void bgp_pbr_policyroute_remove_from_zebra_unit(
*/
memset(&temp2, 0, sizeof(temp2));
memset(&temp, 0, sizeof(temp));
if (bpf->type == BGP_PBR_IPRULE) {
memset(&pbr_rule, 0, sizeof(pbr_rule));
pbr_rule.vrf_id = bpf->vrf_id;
if (bpf->src) {
prefix_copy(&pbr_rule.src, bpf->src);
pbr_rule.flags |= MATCH_IP_SRC_SET;
}
if (bpf->dst) {
prefix_copy(&pbr_rule.dst, bpf->dst);
pbr_rule.flags |= MATCH_IP_DST_SET;
}
bpr = &pbr_rule;
/* A previous entry may already exist
* flush previous entry if necessary
*/
bprr.bpr_to_match = bpr;
bprr.bpr_found = NULL;
hash_walk(bgp->pbr_rule_hash, bgp_pbr_get_same_rule, &bprr);
if (bprr.bpr_found) {
static struct bgp_pbr_rule *local_bpr;
static struct bgp_pbr_action *local_bpa;
local_bpr = bprr.bpr_found;
local_bpa = local_bpr->action;
bgp_pbr_flush_iprule(bgp, local_bpa,
local_bpr);
}
return;
}
if (bpf->src) {
temp.flags |= MATCH_IP_SRC_SET;
prefix_copy(&temp2.src, bpf->src);
@ -1732,9 +1994,13 @@ static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp,
struct bgp_pbr_action temp3;
struct bgp_pbr_action *bpa = NULL;
struct bgp_pbr_match_entry_remain bpmer;
struct bgp_pbr_rule_remain bprr;
struct bgp_pbr_range_port *src_port;
struct bgp_pbr_range_port *dst_port;
struct bgp_pbr_range_port *pkt_len;
struct bgp_pbr_rule pbr_rule;
struct bgp_pbr_rule *bpr;
bool bpr_found = false;
bool bpme_found = false;
if (!bpf)
@ -1771,7 +2037,69 @@ static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp,
/* 0 value is forbidden */
bpa->install_in_progress = false;
}
if (bpf->type == BGP_PBR_IPRULE) {
memset(&pbr_rule, 0, sizeof(pbr_rule));
pbr_rule.vrf_id = bpf->vrf_id;
pbr_rule.priority = 20;
if (bpf->src) {
pbr_rule.flags |= MATCH_IP_SRC_SET;
prefix_copy(&pbr_rule.src, bpf->src);
}
if (bpf->dst) {
pbr_rule.flags |= MATCH_IP_DST_SET;
prefix_copy(&pbr_rule.dst, bpf->dst);
}
pbr_rule.action = bpa;
bpr = hash_get(bgp->pbr_rule_hash, &pbr_rule,
bgp_pbr_rule_alloc_intern);
if (bpr && bpr->unique == 0) {
bpr->unique = ++bgp_pbr_action_counter_unique;
bpr->installed = false;
bpr->install_in_progress = false;
/* link bgp info to bpr */
bpr->path = (void *)path;
} else
bpr_found = true;
/* already installed */
if (bpr_found && bpr) {
struct bgp_path_info_extra *extra =
bgp_path_info_extra_get(path);
if (extra && listnode_lookup(extra->bgp_fs_iprule,
bpr)) {
if (BGP_DEBUG(pbr, PBR_ERROR))
zlog_err("%s: entry %p/%p already "
"installed in bgp pbr iprule",
__func__, path, bpr);
return;
}
}
if (!bpa->installed && !bpa->install_in_progress) {
bgp_send_pbr_rule_action(bpa, NULL, true);
bgp_zebra_announce_default(bgp, nh,
AFI_IP, bpa->table_id, true);
}
/* ip rule add */
if (bpr && !bpr->installed)
bgp_send_pbr_rule_action(bpa, bpr, true);
/* A previous entry may already exist
* flush previous entry if necessary
*/
bprr.bpr_to_match = bpr;
bprr.bpr_found = NULL;
hash_walk(bgp->pbr_rule_hash, bgp_pbr_get_same_rule, &bprr);
if (bprr.bpr_found) {
static struct bgp_pbr_rule *local_bpr;
static struct bgp_pbr_action *local_bpa;
local_bpr = bprr.bpr_found;
local_bpa = local_bpr->action;
bgp_pbr_flush_iprule(bgp, local_bpa,
local_bpr);
}
return;
}
/* then look for bpm */
memset(&temp, 0, sizeof(temp));
temp.vrf_id = bpf->vrf_id;
@ -1885,8 +2213,7 @@ static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp,
struct bgp_path_info_extra *extra =
bgp_path_info_extra_get(path);
if (extra && extra->bgp_fs_pbr &&
listnode_lookup(extra->bgp_fs_pbr, bpme)) {
if (extra && listnode_lookup(extra->bgp_fs_pbr, bpme)) {
if (BGP_DEBUG(pbr, PBR_ERROR))
zlog_err(
"%s: entry %p/%p already installed in bgp pbr",
@ -1906,7 +2233,7 @@ static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp,
*/
/* ip rule add */
if (!bpa->installed && !bpa->install_in_progress) {
bgp_send_pbr_rule_action(bpa, true);
bgp_send_pbr_rule_action(bpa, NULL, true);
bgp_zebra_announce_default(bgp, nh,
AFI_IP, bpa->table_id, true);
}
@ -2048,10 +2375,16 @@ static void bgp_pbr_handle_entry(struct bgp *bgp, struct bgp_path_info *path,
memset(&nh, 0, sizeof(struct nexthop));
memset(&bpf, 0, sizeof(struct bgp_pbr_filter));
memset(&bpof, 0, sizeof(struct bgp_pbr_or_filter));
if (api->match_bitmask & PREFIX_SRC_PRESENT)
if (api->match_bitmask & PREFIX_SRC_PRESENT ||
(api->type == BGP_PBR_IPRULE &&
api->match_bitmask_iprule & PREFIX_SRC_PRESENT))
src = &api->src_prefix;
if (api->match_bitmask & PREFIX_DST_PRESENT)
if (api->match_bitmask & PREFIX_DST_PRESENT ||
(api->type == BGP_PBR_IPRULE &&
api->match_bitmask_iprule & PREFIX_DST_PRESENT))
dst = &api->dst_prefix;
if (api->type == BGP_PBR_IPRULE)
bpf.type = api->type;
memset(&nh, 0, sizeof(struct nexthop));
nh.vrf_id = VRF_UNKNOWN;
if (api->match_protocol_num)

View File

@ -87,12 +87,10 @@ struct bgp_pbr_entry_action {
/* BGP Policy Route structure */
struct bgp_pbr_entry_main {
#define BGP_PBR_UNDEFINED 0
#define BGP_PBR_IPSET 1
#define BGP_PBR_IPRULE 2
uint8_t type;
uint16_t instance;
uint32_t flags;
uint8_t message;
/*
* This is an enum but we are going to treat it as a uint8_t
@ -103,6 +101,7 @@ struct bgp_pbr_entry_main {
#define PREFIX_SRC_PRESENT (1 << 0)
#define PREFIX_DST_PRESENT (1 << 1)
uint8_t match_bitmask_iprule;
uint8_t match_bitmask;
uint8_t match_src_port_num;
@ -137,14 +136,6 @@ struct bgp_pbr_entry_main {
uint16_t action_num;
struct bgp_pbr_entry_action actions[ACTIONS_MAX_NUM];
uint8_t distance;
uint32_t metric;
route_tag_t tag;
uint32_t mtu;
vrf_id_t vrf_id;
};
@ -167,6 +158,19 @@ struct bgp_pbr_config {
extern struct bgp_pbr_config *bgp_pbr_cfg;
struct bgp_pbr_rule {
uint32_t flags;
struct prefix src;
struct prefix dst;
struct bgp_pbr_action *action;
vrf_id_t vrf_id;
uint32_t unique;
uint32_t priority;
bool installed;
bool install_in_progress;
void *path;
};
struct bgp_pbr_match {
char ipset_name[ZEBRA_IPSET_NAME_SIZE];
@ -251,6 +255,9 @@ struct bgp_pbr_action {
struct bgp *bgp;
};
extern struct bgp_pbr_rule *bgp_pbr_rule_lookup(vrf_id_t vrf_id,
uint32_t unique);
extern struct bgp_pbr_action *bgp_pbr_action_rule_lookup(vrf_id_t vrf_id,
uint32_t unique);
@ -266,6 +273,9 @@ extern struct bgp_pbr_match *bgp_pbr_match_iptable_lookup(vrf_id_t vrf_id,
extern void bgp_pbr_cleanup(struct bgp *bgp);
extern void bgp_pbr_init(struct bgp *bgp);
extern uint32_t bgp_pbr_rule_hash_key(void *arg);
extern bool bgp_pbr_rule_hash_equal(const void *arg1,
const void *arg2);
extern uint32_t bgp_pbr_action_hash_key(void *arg);
extern bool bgp_pbr_action_hash_equal(const void *arg1,
const void *arg2);

View File

@ -175,6 +175,8 @@ static struct bgp_path_info_extra *bgp_path_info_extra_new(void)
sizeof(struct bgp_path_info_extra));
new->label[0] = MPLS_INVALID_LABEL;
new->num_labels = 0;
new->bgp_fs_pbr = list_new();
new->bgp_fs_iprule = list_new();
return new;
}
@ -218,6 +220,8 @@ void bgp_path_info_extra_free(struct bgp_path_info_extra **extra)
if (e->bgp_orig)
bgp_unlock(e->bgp_orig);
if ((*extra)->bgp_fs_iprule)
list_delete(&((*extra)->bgp_fs_iprule));
if ((*extra)->bgp_fs_pbr)
list_delete(&((*extra)->bgp_fs_pbr));
XFREE(MTYPE_BGP_ROUTE_EXTRA, *extra);

View File

@ -147,8 +147,10 @@ struct bgp_path_info_extra {
* Set nexthop_orig.family to 0 if not valid.
*/
struct prefix nexthop_orig;
/* presence of FS pbr entry */
/* presence of FS pbr firewall based entry */
struct list *bgp_fs_pbr;
/* presence of FS pbr iprule based entry */
struct list *bgp_fs_iprule;
};
struct bgp_path_info {

View File

@ -36,6 +36,7 @@
#include "filter.h"
#include "mpls.h"
#include "vxlan.h"
#include "pbr.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_route.h"
@ -2051,6 +2052,7 @@ static int rule_notify_owner(int command, struct zclient *zclient,
uint32_t seqno, priority, unique;
enum zapi_rule_notify_owner note;
struct bgp_pbr_action *bgp_pbra;
struct bgp_pbr_rule *bgp_pbr = NULL;
ifindex_t ifi;
if (!zapi_rule_notify_decode(zclient->ibuf, &seqno, &priority, &unique,
@ -2059,10 +2061,14 @@ static int rule_notify_owner(int command, struct zclient *zclient,
bgp_pbra = bgp_pbr_action_rule_lookup(vrf_id, unique);
if (!bgp_pbra) {
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("%s: Fail to look BGP rule (%u)",
__PRETTY_FUNCTION__, unique);
return 0;
/* look in bgp pbr rule */
bgp_pbr = bgp_pbr_rule_lookup(vrf_id, unique);
if (!bgp_pbr && note != ZAPI_RULE_REMOVED) {
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("%s: Fail to look BGP rule (%u)",
__PRETTY_FUNCTION__, unique);
return 0;
}
}
switch (note) {
@ -2070,12 +2076,30 @@ static int rule_notify_owner(int command, struct zclient *zclient,
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("%s: Received RULE_FAIL_INSTALL",
__PRETTY_FUNCTION__);
bgp_pbra->installed = false;
bgp_pbra->install_in_progress = false;
if (bgp_pbra) {
bgp_pbra->installed = false;
bgp_pbra->install_in_progress = false;
} else {
bgp_pbr->installed = false;
bgp_pbr->install_in_progress = false;
}
break;
case ZAPI_RULE_INSTALLED:
bgp_pbra->installed = true;
bgp_pbra->install_in_progress = false;
if (bgp_pbra) {
bgp_pbra->installed = true;
bgp_pbra->install_in_progress = false;
} else {
struct bgp_path_info *path;
struct bgp_path_info_extra *extra;
bgp_pbr->installed = true;
bgp_pbr->install_in_progress = false;
bgp_pbr->action->refcnt++;
/* link bgp_info to bgp_pbr */
path = (struct bgp_path_info *)bgp_pbr->path;
extra = bgp_path_info_extra_get(path);
listnode_add(extra->bgp_fs_iprule, bgp_pbr);
}
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("%s: Received RULE_INSTALLED",
__PRETTY_FUNCTION__);
@ -2182,8 +2206,6 @@ static int ipset_entry_notify_owner(int command, struct zclient *zclient,
/* link bgp_path_info to bpme */
path = (struct bgp_path_info *)bgp_pbime->path;
extra = bgp_path_info_extra_get(path);
if (extra->bgp_fs_pbr == NULL)
extra->bgp_fs_pbr = list_new();
listnode_add(extra->bgp_fs_pbr, bgp_pbime);
}
break;
@ -2242,31 +2264,60 @@ static int iptable_notify_owner(int command, struct zclient *zclient,
return 0;
}
/* this function is used to forge ip rule,
* - either for iptable/ipset using fwmark id
* - or for sample ip rule command
*/
static void bgp_encode_pbr_rule_action(struct stream *s,
struct bgp_pbr_action *pbra)
struct bgp_pbr_action *pbra,
struct bgp_pbr_rule *pbr)
{
struct prefix any;
struct prefix pfx;
stream_putl(s, 0); /* seqno unused */
stream_putl(s, 0); /* ruleno unused */
stream_putl(s, pbra->unique);
memset(&any, 0, sizeof(any));
any.family = AF_INET;
stream_putc(s, any.family);
stream_putc(s, any.prefixlen);
stream_put(s, &any.u.prefix, prefix_blen(&any));
if (pbr)
stream_putl(s, pbr->priority);
else
stream_putl(s, 0);
/* ruleno unused - priority change
* ruleno permits distinguishing various FS PBR entries
* - FS PBR entries based on ipset/iptables
* - FS PBR entries based on iprule
* the latter may contain default routing information injected by FS
*/
if (pbr)
stream_putl(s, pbr->unique);
else
stream_putl(s, pbra->unique);
if (pbr && pbr->flags & MATCH_IP_SRC_SET)
memcpy(&pfx, &(pbr->src), sizeof(struct prefix));
else {
memset(&pfx, 0, sizeof(pfx));
pfx.family = AF_INET;
}
stream_putc(s, pfx.family);
stream_putc(s, pfx.prefixlen);
stream_put(s, &pfx.u.prefix, prefix_blen(&pfx));
stream_putw(s, 0); /* src port */
stream_putc(s, any.family);
stream_putc(s, any.prefixlen);
stream_put(s, &any.u.prefix, prefix_blen(&any));
if (pbr && pbr->flags & MATCH_IP_DST_SET)
memcpy(&pfx, &(pbr->dst), sizeof(struct prefix));
else {
memset(&pfx, 0, sizeof(pfx));
pfx.family = AF_INET;
}
stream_putc(s, pfx.family);
stream_putc(s, pfx.prefixlen);
stream_put(s, &pfx.u.prefix, prefix_blen(&pfx));
stream_putw(s, 0); /* dst port */
stream_putl(s, pbra->fwmark); /* fwmark */
/* if pbr present, fwmark is not used */
if (pbr)
stream_putl(s, 0);
else
stream_putl(s, pbra->fwmark); /* fwmark */
stream_putl(s, pbra->table_id);
@ -2676,16 +2727,26 @@ int bgp_zebra_num_connects(void)
return zclient_num_connects;
}
void bgp_send_pbr_rule_action(struct bgp_pbr_action *pbra, bool install)
void bgp_send_pbr_rule_action(struct bgp_pbr_action *pbra,
struct bgp_pbr_rule *pbr,
bool install)
{
struct stream *s;
if (pbra->install_in_progress)
if (pbra->install_in_progress && !pbr)
return;
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("%s: table %d fwmark %d %d",
__PRETTY_FUNCTION__,
pbra->table_id, pbra->fwmark, install);
if (pbr && pbr->install_in_progress)
return;
if (BGP_DEBUG(zebra, ZEBRA)) {
if (pbr)
zlog_debug("%s: table %d (ip rule) %d",
__PRETTY_FUNCTION__,
pbra->table_id, install);
else
zlog_debug("%s: table %d fwmark %d %d",
__PRETTY_FUNCTION__,
pbra->table_id, pbra->fwmark, install);
}
s = zclient->obuf;
stream_reset(s);
@ -2694,11 +2755,15 @@ void bgp_send_pbr_rule_action(struct bgp_pbr_action *pbra, bool install)
VRF_DEFAULT);
stream_putl(s, 1); /* send one pbr action */
bgp_encode_pbr_rule_action(s, pbra);
bgp_encode_pbr_rule_action(s, pbra, pbr);
stream_putw_at(s, 0, stream_get_endp(s));
if (!zclient_send_message(zclient) && install)
pbra->install_in_progress = true;
if (!zclient_send_message(zclient) && install) {
if (!pbr)
pbra->install_in_progress = true;
else
pbr->install_in_progress = true;
}
}
void bgp_send_pbr_ipset_match(struct bgp_pbr_match *pbrim, bool install)

View File

@ -84,9 +84,11 @@ extern bool bgp_zebra_nexthop_set(union sockunion *, union sockunion *,
struct bgp_pbr_action;
struct bgp_pbr_match;
struct bgp_pbr_rule;
struct bgp_pbr_match_entry;
extern void bgp_send_pbr_rule_action(struct bgp_pbr_action *pbra,
bool install);
struct bgp_pbr_rule *pbr,
bool install);
extern void bgp_send_pbr_ipset_match(struct bgp_pbr_match *pbrim,
bool install);
extern void bgp_send_pbr_ipset_entry_match(struct bgp_pbr_match_entry *pbrime,

View File

@ -414,6 +414,7 @@ struct bgp {
*
* pbr_action a <----- pbr_match i <--- pbr_match_entry 1..n
* <----- pbr_match j <--- pbr_match_entry 1..m
* <----- pbr_rule k
*
* - here in BGP structure, the list of match and actions will
* stand for the list of ipset sets, and table_ids in the kernel
@ -423,6 +424,7 @@ struct bgp {
* contained in match, that lists the whole set of entries
*/
struct hash *pbr_match_hash;
struct hash *pbr_rule_hash;
struct hash *pbr_action_hash;
/* timer to re-evaluate neighbor default-originate route-maps */