bgpd: support for redirect ipv6 simpson method

this commit supports [0] where ipv6 address is encoded in nexthop
attribute of nlri, and not in bgp redirect ip extended community. the
community contains only duplicate information or not.
Adding to this, because an action or a rule needs to apply to either
ipv4 or ipv6 flow, modify some internal structures so as to be aware of
which flow needs to be filtered. This work is needed when an ipv6
flowspec rule without ip addresses is mentioned, we need to know which
afi is served. Also, this work will be useful when doing redirect VRF.

[0] draft-simpson-idr-flowspec-redirect-02.txt

Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
This commit is contained in:
Philippe Guibert 2019-10-16 10:05:36 +02:00
parent 4088180002
commit f01e580fc0
6 changed files with 132 additions and 35 deletions

View File

@ -1052,7 +1052,8 @@ bool ecommunity_del_val(struct ecommunity *ecom, struct ecommunity_val *eval)
}
int ecommunity_fill_pbr_action(struct ecommunity_val *ecom_eval,
struct bgp_pbr_entry_action *api)
struct bgp_pbr_entry_action *api,
afi_t afi)
{
if (ecom_eval->val[1] == ECOMMUNITY_TRAFFIC_RATE) {
api->action = ACTION_TRAFFICRATE;
@ -1076,7 +1077,8 @@ int ecommunity_fill_pbr_action(struct ecommunity_val *ecom_eval,
} else if (ecom_eval->val[1] == ECOMMUNITY_REDIRECT_VRF) {
/* must use external function */
return 0;
} else if (ecom_eval->val[1] == ECOMMUNITY_REDIRECT_IP_NH) {
} else if (ecom_eval->val[1] == ECOMMUNITY_REDIRECT_IP_NH &&
afi == AFI_IP) {
/* see draft-ietf-idr-flowspec-redirect-ip-02
* Q1: how come a ext. community can host ipv6 address
* Q2 : from cisco documentation:

View File

@ -222,7 +222,8 @@ extern bool ecommunity_del_val(struct ecommunity *ecom,
struct ecommunity_val *eval);
struct bgp_pbr_entry_action;
extern int ecommunity_fill_pbr_action(struct ecommunity_val *ecom_eval,
struct bgp_pbr_entry_action *api);
struct bgp_pbr_entry_action *api,
afi_t afi);
extern void bgp_compute_aggregate_ecommunity(
struct bgp_aggregate *aggregate,

View File

@ -325,10 +325,28 @@ void route_vty_out_flowspec(struct vty *vty, const struct prefix *p,
json_object_array_add(json_paths,
json_ecom_path);
}
if (attr->nexthop.s_addr != 0 &&
display == NLRI_STRING_FORMAT_LARGE)
vty_out(vty, "\tNLRI NH %-16s\n",
inet_ntoa(attr->nexthop));
if (display == NLRI_STRING_FORMAT_LARGE) {
char local_buff[INET6_ADDRSTRLEN];
local_buff[0] = '\0';
if (p->u.prefix_flowspec.family == AF_INET &&
attr->nexthop.s_addr != 0)
inet_ntop(AF_INET,
&attr->nexthop.s_addr,
local_buff,
INET6_ADDRSTRLEN);
else if (p->u.prefix_flowspec.family == AF_INET6 &&
attr->mp_nexthop_len != 0 &&
attr->mp_nexthop_len != BGP_ATTR_NHLEN_IPV4 &&
attr->mp_nexthop_len != BGP_ATTR_NHLEN_VPNV4)
inet_ntop(AF_INET6,
&attr->mp_nexthop_global,
local_buff,
INET6_ADDRSTRLEN);
if (local_buff[0] != '\0')
vty_out(vty, "\tNLRI NH %s\n",
local_buff);
}
XFREE(MTYPE_ECOMMUNITY_STR, s);
}
peer_uptime(path->uptime, timebuf, BGP_UPTIME_LEN, 0, NULL);

View File

@ -248,6 +248,7 @@ struct bgp_pbr_val_mask {
struct bgp_pbr_filter {
uint8_t type;
vrf_id_t vrf_id;
uint8_t family;
struct prefix *src;
struct prefix *dst;
uint8_t bitmask_iprule;
@ -793,9 +794,10 @@ int bgp_pbr_build_and_validate_entry(const struct prefix *p,
* do not overwrite
* draft-ietf-idr-flowspec-redirect
*/
if (api_action_redirect_ip) {
if (api_action_redirect_ip->u.zr
.redirect_ip_v4.s_addr
if (api_action_redirect_ip &&
p->u.prefix_flowspec.family == AF_INET) {
if (api_action_redirect_ip->u
.zr.redirect_ip_v4.s_addr
!= INADDR_ANY)
continue;
if (path->attr->nexthop.s_addr
@ -807,13 +809,42 @@ int bgp_pbr_build_and_validate_entry(const struct prefix *p,
api_action_redirect_ip->u.zr.duplicate
= ecom_eval->val[7];
continue;
} else {
} else if (api_action_redirect_ip &&
p->u.prefix_flowspec.family == AF_INET6) {
if (memcmp(&api_action_redirect_ip->u
.zr.redirect_ip_v6,
&in6addr_any,
sizeof(struct in6_addr)))
continue;
if (path->attr->mp_nexthop_len == 0 ||
path->attr->mp_nexthop_len ==
BGP_ATTR_NHLEN_IPV4 ||
path->attr->mp_nexthop_len ==
BGP_ATTR_NHLEN_VPNV4)
continue;
memcpy(&api_action_redirect_ip->u
.zr.redirect_ip_v6,
&path->attr->mp_nexthop_global,
sizeof(struct in6_addr));
api_action_redirect_ip->u.zr.duplicate
= ecom_eval->val[7];
continue;
} else if (p->u.prefix_flowspec.family == AF_INET) {
api_action->action = ACTION_REDIRECT_IP;
api_action->u.zr.redirect_ip_v4.s_addr =
path->attr->nexthop.s_addr;
api_action->u.zr.duplicate =
ecom_eval->val[7];
api_action_redirect_ip = api_action;
} else if (p->u.prefix_flowspec.family == AF_INET6) {
api_action->action = ACTION_REDIRECT_IP;
memcpy(&api_action->u
.zr.redirect_ip_v6,
&path->attr->mp_nexthop_global,
sizeof(struct in6_addr));
api_action->u.zr.duplicate
= ecom_eval->val[7];
api_action_redirect_ip = api_action;
}
} else if ((ecom_eval->val[0] ==
(char)ECOMMUNITY_ENCODE_IP) &&
@ -845,7 +876,8 @@ int bgp_pbr_build_and_validate_entry(const struct prefix *p,
(char)ECOMMUNITY_ENCODE_TRANS_EXP)
continue;
ret = ecommunity_fill_pbr_action(ecom_eval,
api_action);
api_action,
afi);
if (ret != 0)
continue;
if ((api_action->action == ACTION_TRAFFICRATE) &&
@ -1181,6 +1213,7 @@ uint32_t bgp_pbr_action_hash_key(const void *arg)
pbra = arg;
key = jhash_1word(pbra->table_id, 0x4312abde);
key = jhash_1word(pbra->fwmark, key);
key = jhash_1word(pbra->afi, key);
return key;
}
@ -1198,6 +1231,9 @@ bool bgp_pbr_action_hash_equal(const void *arg1, const void *arg2)
if (r1->vrf_id != r2->vrf_id)
return false;
if (r1->afi != r2->afi)
return false;
if (memcmp(&r1->nh, &r2->nh, sizeof(struct nexthop)))
return false;
@ -1515,18 +1551,25 @@ void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main *api)
ptr += delta;
}
break;
case ACTION_REDIRECT_IP:
char local_buff[INET_ADDRSTRLEN];
case ACTION_REDIRECT_IP: {
char local_buff[INET6_ADDRSTRLEN];
void *ptr_ip;
INCREMENT_DISPLAY(ptr, nb_items, len);
if (inet_ntop(AF_INET,
&api->actions[i].u.zr.redirect_ip_v4,
local_buff, INET_ADDRSTRLEN) != NULL)
if (api->afi == AF_INET)
ptr_ip = &api->actions[i].u.zr.redirect_ip_v4;
else
ptr_ip = &api->actions[i].u.zr.redirect_ip_v6;
if (inet_ntop(afi2family(api->afi),
ptr_ip, local_buff,
INET6_ADDRSTRLEN) != NULL) {
delta = snprintf(ptr, len,
"@redirect ip nh %s", local_buff);
len -= delta;
ptr += delta;
}
break;
}
case ACTION_REDIRECT: {
struct vrf *vrf;
@ -1639,7 +1682,7 @@ static void bgp_pbr_flush_entry(struct bgp *bgp, struct bgp_pbr_action *bpa,
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->afi,
bpa->table_id,
false);
bpa->installed = false;
@ -1794,12 +1837,12 @@ static void bgp_pbr_policyroute_remove_from_zebra_unit(
temp.flags |= MATCH_IP_SRC_SET;
prefix_copy(&temp2.src, bpf->src);
} else
temp2.src.family = AF_INET;
temp2.src.family = bpf->family;
if (bpf->dst) {
temp.flags |= MATCH_IP_DST_SET;
prefix_copy(&temp2.dst, bpf->dst);
} else
temp2.dst.family = AF_INET;
temp2.dst.family = bpf->family;
if (src_port && (src_port->min_port || bpf->protocol == IPPROTO_ICMP)) {
if (bpf->protocol == IPPROTO_ICMP)
temp.flags |= MATCH_ICMP_SET;
@ -2200,6 +2243,7 @@ static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp,
if (nh)
memcpy(&temp3.nh, nh, sizeof(struct nexthop));
temp3.vrf_id = bpf->vrf_id;
temp3.afi = family2afi(bpf->family);
bpa = hash_get(bgp->pbr_action_hash, &temp3,
bgp_pbr_action_alloc_intern);
@ -2258,7 +2302,8 @@ static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp,
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);
bpa->afi,
bpa->table_id, true);
}
/* ip rule add */
if (bpr && !bpr->installed)
@ -2377,11 +2422,11 @@ static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp,
if (bpf->src)
prefix_copy(&temp2.src, bpf->src);
else
temp2.src.family = AF_INET;
temp2.src.family = bpf->family;
if (bpf->dst)
prefix_copy(&temp2.dst, bpf->dst);
else
temp2.dst.family = AF_INET;
temp2.dst.family = bpf->family;
temp2.src_port_min = src_port ? src_port->min_port : 0;
temp2.dst_port_min = dst_port ? dst_port->min_port : 0;
temp2.src_port_max = src_port ? src_port->max_port : 0;
@ -2428,7 +2473,7 @@ static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp,
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);
bpa->afi, bpa->table_id, true);
}
/* ipset create */
@ -2690,6 +2735,7 @@ static void bgp_pbr_handle_entry(struct bgp *bgp, struct bgp_path_info *path,
bpf.protocol = proto;
bpf.src_port = srcp;
bpf.dst_port = dstp;
bpf.family = afi2family(api->afi);
if (!add) {
bgp_pbr_policyroute_remove_from_zebra(bgp, path, &bpf, &bpof);
return;
@ -2739,10 +2785,18 @@ static void bgp_pbr_handle_entry(struct bgp *bgp, struct bgp_path_info *path,
*/
break;
case ACTION_REDIRECT_IP:
nh.type = NEXTHOP_TYPE_IPV4;
nh.gate.ipv4.s_addr =
api->actions[i].u.zr.redirect_ip_v4.s_addr;
nh.vrf_id = api->vrf_id;
if (api->afi == AFI_IP) {
nh.type = NEXTHOP_TYPE_IPV4;
nh.gate.ipv4.s_addr =
api->actions[i].u.zr.
redirect_ip_v4.s_addr;
} else {
nh.type = NEXTHOP_TYPE_IPV6;
memcpy(&nh.gate.ipv6,
&api->actions[i].u.zr.redirect_ip_v6,
sizeof(struct in6_addr));
}
bgp_pbr_policyroute_add_to_zebra(bgp, path, &bpf, &bpof,
&nh, &rate);
/* XXX combination with REDIRECT_VRF

View File

@ -260,6 +260,7 @@ struct bgp_pbr_action {
bool install_in_progress;
uint32_t refcnt;
struct bgp *bgp;
afi_t afi;
};
extern struct bgp_pbr_rule *bgp_pbr_rule_lookup(vrf_id_t vrf_id,

View File

@ -2356,7 +2356,10 @@ static void bgp_encode_pbr_rule_action(struct stream *s,
struct bgp_pbr_rule *pbr)
{
struct prefix pfx;
uint8_t fam = AF_INET;
if (pbra && pbra->nh.type == NEXTHOP_TYPE_IPV6)
fam = AF_INET6;
stream_putl(s, 0); /* seqno unused */
if (pbr)
stream_putl(s, pbr->priority);
@ -2376,7 +2379,7 @@ static void bgp_encode_pbr_rule_action(struct stream *s,
memcpy(&pfx, &(pbr->src), sizeof(struct prefix));
else {
memset(&pfx, 0, sizeof(pfx));
pfx.family = AF_INET;
pfx.family = fam;
}
stream_putc(s, pfx.family);
stream_putc(s, pfx.prefixlen);
@ -2388,7 +2391,7 @@ static void bgp_encode_pbr_rule_action(struct stream *s,
memcpy(&pfx, &(pbr->dst), sizeof(struct prefix));
else {
memset(&pfx, 0, sizeof(pfx));
pfx.family = AF_INET;
pfx.family = fam;
}
stream_putc(s, pfx.family);
stream_putc(s, pfx.prefixlen);
@ -3063,14 +3066,14 @@ void bgp_zebra_announce_default(struct bgp *bgp, struct nexthop *nh,
struct zapi_route api;
struct prefix p;
if (!nh || nh->type != NEXTHOP_TYPE_IPV4
if (!nh || (nh->type != NEXTHOP_TYPE_IPV4
&& nh->type != NEXTHOP_TYPE_IPV6)
|| nh->vrf_id == VRF_UNKNOWN)
return;
memset(&p, 0, sizeof(struct prefix));
/* default route */
if (afi != AFI_IP)
if (afi != AFI_IP && afi != AFI_IP6)
return;
p.family = AF_INET;
p.family = afi2family(afi);
memset(&api, 0, sizeof(api));
api.vrf_id = bgp->vrf_id;
api.type = ZEBRA_ROUTE_BGP;
@ -3086,7 +3089,7 @@ void bgp_zebra_announce_default(struct bgp *bgp, struct nexthop *nh,
SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE);
/* redirect IP */
if (nh->gate.ipv4.s_addr != INADDR_ANY) {
if (afi == AFI_IP && nh->gate.ipv4.s_addr != INADDR_ANY) {
char buff[PREFIX_STRLEN];
api_nh->vrf_id = nh->vrf_id;
@ -3095,7 +3098,25 @@ void bgp_zebra_announce_default(struct bgp *bgp, struct nexthop *nh,
inet_ntop(AF_INET, &(nh->gate.ipv4), buff, INET_ADDRSTRLEN);
if (BGP_DEBUG(zebra, ZEBRA))
zlog_info("BGP: %s default route to %s table %d (redirect IP)",
zlog_debug("BGP: %s default route to %s table %d (redirect IP)",
announce ? "adding" : "withdrawing",
buff, table_id);
zclient_route_send(announce ? ZEBRA_ROUTE_ADD
: ZEBRA_ROUTE_DELETE,
zclient, &api);
} else if (afi == AFI_IP6 &&
memcmp(&nh->gate.ipv6,
&in6addr_any, sizeof(struct in6_addr))) {
char buff[PREFIX_STRLEN];
api_nh->vrf_id = nh->vrf_id;
memcpy(&api_nh->gate.ipv6, &nh->gate.ipv6,
sizeof(struct in6_addr));
api_nh->type = NEXTHOP_TYPE_IPV6;
inet_ntop(AF_INET6, &(nh->gate.ipv6), buff, INET_ADDRSTRLEN);
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("BGP: %s default route to %s table %d (redirect IP)",
announce ? "adding" : "withdrawing",
buff, table_id);
zclient_route_send(announce ? ZEBRA_ROUTE_ADD