Skip to content

Commit

Permalink
pathd: Support srv6 te policy
Browse files Browse the repository at this point in the history
Signed-off-by: guozhongfeng.gzf <[email protected]>
  • Loading branch information
guoguojia2021 committed Nov 26, 2024
1 parent 1dcb4bb commit 13a450e
Show file tree
Hide file tree
Showing 31 changed files with 983 additions and 255 deletions.
1 change: 1 addition & 0 deletions bgpd/bgp_nexthop.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ struct bgp_nexthop_cache {
#define BGP_STATIC_ROUTE_EXACT_MATCH (1 << 5)
#define BGP_NEXTHOP_LABELED_VALID (1 << 6)
#define BGP_NEXTHOP_ULTIMATE (1 << 7)
#define BGP_NEXTHOP_SRV6TE_VALID (1 << 8)

/*
* This flag is added for EVPN gateway IP nexthops.
Expand Down
28 changes: 18 additions & 10 deletions bgpd/bgp_nht.c
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,8 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
}

srte_color = bgp_attr_get_color(pi->attr);
if (srte_color)
p.u.prefix6 = pi->attr->mp_nexthop_global;

} else if (peer) {
/*
Expand Down Expand Up @@ -404,8 +406,8 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
peer);
} else {
if (BGP_DEBUG(nht, NHT))
zlog_debug("Found existing bnc %pFX(%d)(%s) flags 0x%x ifindex %d #paths %d peer %p, resolved prefix %pFX",
&bnc->prefix, bnc->ifindex_ipv6_ll,
zlog_debug("Found existing bnc %pFX(%d)(%u)(%s) flags 0x%x ifindex %d #paths %d peer %p, resolved prefix %pFX",
&bnc->prefix, bnc->ifindex_ipv6_ll, bnc->srte_color,
bnc->bgp->name_pretty, bnc->flags,
bnc->ifindex_ipv6_ll, bnc->path_count,
bnc->nht_info, &bnc->resolved_prefix);
Expand Down Expand Up @@ -636,6 +638,10 @@ static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc,

if (!bnc->is_evpn_gwip_nexthop)
SET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
if (nhr->type == ZEBRA_ROUTE_SRTE)
SET_FLAG(bnc->flags, BGP_NEXTHOP_SRV6TE_VALID);
else
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_SRV6TE_VALID);
bnc->metric = nhr->metric;
bnc->nexthop_num = nhr->nexthop_num;

Expand Down Expand Up @@ -743,6 +749,7 @@ static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc,
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_EVPN_INCOMPLETE);
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID);
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_SRV6TE_VALID);
bnc->nexthop_num = nhr->nexthop_num;

/* notify bgp fsm if nbr ip goes from valid->invalid */
Expand Down Expand Up @@ -1123,9 +1130,8 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p)
*/
static void sendmsg_zebra_rnh(struct bgp_nexthop_cache *bnc, int command)
{
bool exact_match = false;
bool resolve_via_default = false;
int ret;
uint32_t flags = 0;

if (!zclient)
return;
Expand All @@ -1147,19 +1153,21 @@ static void sendmsg_zebra_rnh(struct bgp_nexthop_cache *bnc, int command)
}
if (command == ZEBRA_NEXTHOP_REGISTER) {
if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED))
exact_match = true;
SET_FLAG(flags, NEXTHOP_REGISTER_FLAG_CONNECTED);
if (CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH))
resolve_via_default = true;
SET_FLAG(flags, NEXTHOP_REGISTER_FLAG_RESOLVE_VIA_DEFAULT);
}

if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("%s: sending cmd %s for %pFX (vrf %s)", __func__,
zlog_debug("%s: sending cmd %s for %pFX (vrf %s) color %d", __func__,
zserv_command_string(command), &bnc->prefix,
bnc->bgp->name_pretty);
bnc->bgp->name_pretty, bnc->srte_color);

if (bnc->srte_color)
SET_FLAG(flags, NEXTHOP_REGISTER_FLAG_COLOR);

ret = zclient_send_rnh(zclient, command, &bnc->prefix, SAFI_UNICAST,
exact_match, resolve_via_default,
bnc->bgp->vrf_id);
flags, bnc->bgp->vrf_id, bnc->srte_color);
if (ret == ZCLIENT_SEND_FAILURE) {
flog_warn(EC_BGP_ZEBRA_SEND,
"sendmsg_nexthop: zclient_send_message() failed");
Expand Down
102 changes: 61 additions & 41 deletions bgpd/bgp_zebra.c
Original file line number Diff line number Diff line change
Expand Up @@ -1411,41 +1411,49 @@ static void bgp_zebra_announce_parse_nexthop(
sizeof(struct ethaddr));

api_nh->weight = nh_weight;
if (CHECK_FLAG(mpinfo->nexthop->flags, BGP_NEXTHOP_SRV6TE_VALID)) {
struct nexthop_srv6 *nh_srv6 = mpinfo->nexthop->nexthop->srv6te;
memcpy(&api_nh->seg6_segs[0], &srv6te->seg6_segs[0],
srv6te->seg_num * sizeof(struct in6_addr));
api_nh->seg_num = srv6te->seg_num;
SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_SEG6);
}
else {
if (((mpinfo->attr->srv6_l3vpn &&
!sid_zero_ipv6(&mpinfo->attr->srv6_l3vpn->sid)) ||
(mpinfo->attr->srv6_vpn &&
!sid_zero_ipv6(&mpinfo->attr->srv6_vpn->sid))) &&
!is_evpn && bgp_is_valid_label(&labels[0])) {
struct in6_addr *sid_tmp =
mpinfo->attr->srv6_l3vpn
? (&mpinfo->attr->srv6_l3vpn->sid)
: (&mpinfo->attr->srv6_vpn->sid);

memcpy(&api_nh->seg6_segs[0], sid_tmp,
sizeof(api_nh->seg6_segs[0]));

if (mpinfo->attr->srv6_l3vpn &&
mpinfo->attr->srv6_l3vpn->transposition_len != 0) {
mpls_lse_decode(labels[0], &nh_label, &ttl,
&exp, &bos);

if (nh_label < MPLS_LABEL_UNRESERVED_MIN) {
if (bgp_debug_zebra(&api->prefix))
zlog_debug(
"skip invalid SRv6 routes: transposition scheme is used, but label is too small");
continue;
}

if (((mpinfo->attr->srv6_l3vpn &&
!sid_zero_ipv6(&mpinfo->attr->srv6_l3vpn->sid)) ||
(mpinfo->attr->srv6_vpn &&
!sid_zero_ipv6(&mpinfo->attr->srv6_vpn->sid))) &&
!is_evpn && bgp_is_valid_label(&labels[0])) {
struct in6_addr *sid_tmp =
mpinfo->attr->srv6_l3vpn
? (&mpinfo->attr->srv6_l3vpn->sid)
: (&mpinfo->attr->srv6_vpn->sid);

memcpy(&api_nh->seg6_segs[0], sid_tmp,
sizeof(api_nh->seg6_segs[0]));

if (mpinfo->attr->srv6_l3vpn &&
mpinfo->attr->srv6_l3vpn->transposition_len != 0) {
mpls_lse_decode(labels[0], &nh_label, &ttl,
&exp, &bos);

if (nh_label < MPLS_LABEL_UNRESERVED_MIN) {
if (bgp_debug_zebra(&api->prefix))
zlog_debug(
"skip invalid SRv6 routes: transposition scheme is used, but label is too small");
continue;
transpose_sid(&api_nh->seg6_segs[0], nh_label,
mpinfo->attr->srv6_l3vpn
->transposition_offset,
mpinfo->attr->srv6_l3vpn
->transposition_len);
}

transpose_sid(&api_nh->seg6_segs[0], nh_label,
mpinfo->attr->srv6_l3vpn
->transposition_offset,
mpinfo->attr->srv6_l3vpn
->transposition_len);
api_nh->seg_num = 1;
SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_SEG6);
}

api_nh->seg_num = 1;
SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_SEG6);
}

(*valid_nh_count)++;
Expand All @@ -1460,8 +1468,8 @@ static void bgp_debug_zebra_nh(struct zapi_route *api)
char eth_buf[ETHER_ADDR_STRLEN + 7] = { '\0' };
char buf1[ETHER_ADDR_STRLEN];
char label_buf[20];
char sid_buf[20];
char segs_buf[256];
char sid_buf[INET6_ADDRSTRLEN];
char segs_buf[512];
struct zapi_nexthop *api_nh;
int count;

Expand Down Expand Up @@ -1500,20 +1508,32 @@ static void bgp_debug_zebra_nh(struct zapi_route *api)
!CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN))
snprintf(label_buf, sizeof(label_buf), "label %u",
api_nh->labels[0]);

if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_SEG6) &&
!CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN)) {
inet_ntop(AF_INET6, &api_nh->seg6_segs[0], sid_buf,
sizeof(sid_buf));
snprintf(segs_buf, sizeof(segs_buf), "segs %s", sid_buf);
!CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN)) {

strlcat(segs_buf, "segs ", sizeof(segs_buf));
for (int j = 0; j < api_nh->seg_num; j++) {
memset(sid_buf, 0, sizeof(sid_buf));
inet_ntop(AF_INET6, &api_nh->seg6_segs[j],
sid_buf, sizeof(sid_buf));

if (0 > j && j < api_nh->seg_num - 1)
strlcat(segs_buf, "/", sizeof(segs_buf));

strlcat(segs_buf, sid_buf, sizeof(segs_buf));
}
}

if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN) &&
!is_zero_mac(&api_nh->rmac))
snprintf(eth_buf, sizeof(eth_buf), " RMAC %s",
prefix_mac2str(&api_nh->rmac, buf1,
sizeof(buf1)));
zlog_debug(" nhop [%d]: %s if %u VRF %u wt %" PRIu64

zlog_debug(" nhop [%d][%u]: %s if %u VRF %u wt %" PRIu64
" %s %s %s",
i + 1, nh_buf, api_nh->ifindex, api_nh->vrf_id,
i + 1, api_nh->srte_color, nh_buf, api_nh->ifindex, api_nh->vrf_id,
api_nh->weight, label_buf, segs_buf, eth_buf);
}
}
Expand Down Expand Up @@ -1639,9 +1659,9 @@ bgp_zebra_announce_actual(struct bgp_dest *dest, struct bgp_path_info *info,
}

if (bgp_debug_zebra(p)) {
zlog_debug("Tx route add %s (table id %u) %pFX metric %u tag %" ROUTE_TAG_PRI
zlog_debug("Tx route add %s (table id %u) %pFX color %u metric %u tag %" ROUTE_TAG_PRI
" count %d nhg %d",
bgp->name_pretty, api.tableid, &api.prefix,
bgp->name_pretty, api.tableid, &api.prefix, api.srte_color,
api.metric, api.tag, api.nexthop_num, nhg_id);
bgp_debug_zebra_nh(&api);

Expand Down
4 changes: 3 additions & 1 deletion lib/log.c
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,9 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY(ZEBRA_TC_FILTER_ADD),
DESC_ENTRY(ZEBRA_TC_FILTER_DELETE),
DESC_ENTRY(ZEBRA_OPAQUE_NOTIFY),
DESC_ENTRY(ZEBRA_SRV6_SID_NOTIFY)
DESC_ENTRY(ZEBRA_SRV6_SID_NOTIFY),
DESC_ENTRY(ZEBRA_SRV6_POLICY_SET),
DESC_ENTRY(ZEBRA_SRV6_POLICY_DELETE)
};
#undef DESC_ENTRY

Expand Down
18 changes: 18 additions & 0 deletions lib/prefix.c
Original file line number Diff line number Diff line change
Expand Up @@ -1124,6 +1124,24 @@ const char *prefix2str(union prefixconstptr pu, char *str, int size)
return str;
}

int prefix2ipaddr(union prefixconstptr pu, struct ipaddr *ip)
{
const struct prefix *p = pu.p;
memset(ip, 0, sizeof(struct ipaddr));

if (p->family == AF_INET) {
ip->ipa_type = IPADDR_V4;
memcpy(&(ip->ipaddr_v4), &(p->u.prefix4),
sizeof(struct in_addr));
} else if (p->family == AF_INET6) {
ip->ipa_type = IPADDR_V6;
memcpy(&(ip->ipaddr_v6), &(p->u.prefix6),
sizeof(struct in6_addr));
} else
return -1;
return 0;
}

void prefix_mcast_ip_dump(const char *onfail, const struct ipaddr *addr,
char *buf, int buf_size)
{
Expand Down
1 change: 1 addition & 0 deletions lib/prefix.h
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,7 @@ extern void prefix_mcast_inet4_dump(const char *onfail, struct in_addr addr,
extern const char *prefix_sg2str(const struct prefix_sg *sg, char *str);
extern const char *prefix2str(union prefixconstptr upfx, char *buffer,
int size);
extern int prefix2ipaddr(union prefixconstptr pu, struct ipaddr *ip);
extern int evpn_type5_prefix_match(const struct prefix *evpn_pfx,
const struct prefix *match_pfx);
extern int prefix_match(union prefixconstptr unet, union prefixconstptr upfx);
Expand Down
82 changes: 75 additions & 7 deletions lib/zclient.c
Original file line number Diff line number Diff line change
Expand Up @@ -772,17 +772,15 @@ static void zclient_connect(struct event *t)
}

enum zclient_send_status zclient_send_rnh(struct zclient *zclient, int command,
const struct prefix *p, safi_t safi,
bool connected, bool resolve_via_def,
vrf_id_t vrf_id)
const struct prefix *p, safi_t safi, uint32_t flags,
vrf_id_t vrf_id, uint32_t srte_color)
{
struct stream *s;

s = zclient->obuf;
stream_reset(s);
zclient_create_header(s, command, vrf_id);
stream_putc(s, (connected) ? 1 : 0);
stream_putc(s, (resolve_via_def) ? 1 : 0);
stream_putl(s, flags);
stream_putw(s, safi);
stream_putw(s, PREFIX_FAMILY(p));
stream_putc(s, p->prefixlen);
Expand All @@ -796,6 +794,10 @@ enum zclient_send_status zclient_send_rnh(struct zclient *zclient, int command,
default:
break;
}

if (CHECK_FLAG(flags, NEXTHOP_REGISTER_FLAG_COLOR))
stream_putl(s, srte_color);

stream_putw_at(s, 0, stream_get_endp(s));

return zclient_send_message(zclient);
Expand Down Expand Up @@ -3847,8 +3849,17 @@ int tm_release_table_chunk(struct zclient *zclient, uint32_t start,
enum zclient_send_status zebra_send_sr_policy(struct zclient *zclient, int cmd,
struct zapi_sr_policy *zp)
{
if (zapi_sr_policy_encode(zclient->obuf, cmd, zp) < 0)
return ZCLIENT_SEND_FAILURE;
if (cmd == ZEBRA_SR_POLICY_SET || cmd == ZEBRA_SR_POLICY_DELETE)
{
if (zapi_sr_policy_encode(zclient->obuf, cmd, zp) < 0)
return ZCLIENT_SEND_FAILURE;
}
else if (cmd == ZEBRA_SRV6_POLICY_SET || cmd == ZEBRA_SRV6_POLICY_DELETE)
{
if (zapi_srv6_policy_encode(zclient->obuf, cmd, zp) < 0)
return ZCLIENT_SEND_FAILURE;
}

return zclient_send_message(zclient);
}

Expand Down Expand Up @@ -3914,6 +3925,63 @@ int zapi_sr_policy_decode(struct stream *s, struct zapi_sr_policy *zp)
return -1;
}

int zapi_srv6_policy_encode(struct stream *s, int cmd, struct zapi_sr_policy *zp)
{
struct zapi_srv6te_tunnel *zt = &zp->segment_list_v6;

stream_reset(s);

zclient_create_header(s, cmd, VRF_DEFAULT);
stream_putl(s, zp->color);
stream_put_ipaddr(s, &zp->endpoint);
stream_write(s, &zp->name, SRTE_POLICY_NAME_MAX_LENGTH);

if (zt->seg_num > SRV6_MAX_SEGS) {
flog_err(EC_LIB_ZAPI_ENCODE,
"%s: seg: can't encode %u segs (maximum is %u)",
__func__, zt->seg_num, SRV6_MAX_SEGS);
return -1;
}
stream_putw(s, zt->seg_num);

for (int i = 0; i < zt->seg_num; i++)
stream_write(s, (uint8_t *)&zt->segs[i], IPV6_MAX_BYTELEN);

/* Put length at the first point of the stream. */
stream_putw_at(s, 0, stream_get_endp(s));

return 0;
}

int zapi_srv6_policy_decode(struct stream *s, struct zapi_sr_policy *zp)
{
memset(zp, 0, sizeof(*zp));

struct zapi_srv6te_tunnel *zt = &zp->segment_list_v6;

STREAM_GETL(s, zp->color);
STREAM_GET_IPADDR(s, &zp->endpoint);
STREAM_GET(&zp->name, s, SRTE_POLICY_NAME_MAX_LENGTH);

/* segment list of active candidate path */

STREAM_GETW(s, zt->seg_num);
if (zt->seg_num > SRV6_MAX_SEGS) {
flog_err(EC_LIB_ZAPI_ENCODE,
"%s: seg: can't decode %u segs (maximum is %u)",
__func__, zt->seg_num, SRV6_MAX_SEGS);
return -1;
}
for (int i = 0; i < zt->seg_num; i++)
STREAM_GET(&zt->segs[i], s, IPV6_MAX_BYTELEN);

return 0;

stream_failure:
return -1;
}


int zapi_sr_policy_notify_status_decode(struct stream *s,
struct zapi_sr_policy *zp)
{
Expand Down
Loading

0 comments on commit 13a450e

Please sign in to comment.