mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-16 20:59:36 +00:00
Merge pull request #3414 from pguibert6WIND/iprule_any_flowspec_handling_2
Iprule any flowspec handling
This commit is contained in:
commit
2b697c3d47
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
|
361
bgpd/bgp_pbr.c
361
bgpd/bgp_pbr.c
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
133
bgpd/bgp_zebra.c
133
bgpd/bgp_zebra.c
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user