Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions lib/nexthop.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,62 @@ enum blackhole_type {

enum nh_encap_type {
NET_VXLAN = 100, /* value copied from FPM_NH_ENCAP_VXLAN. */
FPM_NH_ENCAP_SRV6_ROUTE = 101,
FPM_NH_ENCAP_SRV6_LOCAL_SID = 102,
};

enum {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not crazy about these anonymous enums - do we have guidance about that in the dev docs?

SRV6_ROUTE_UNSPEC = 0,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why put these SRV6 items here - why not in one of the srv6-specific headers?

SRV6_ROUTE_VPN_SID = 1,
SRV6_ROUTE_ENCAP_SRC_ADDR = 2,
};

enum srv6_localsid_action {
FPM_SRV6_LOCALSID_ACTION_UNSPEC = 0,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FPM-specific items - is this the right header for FPM?

FPM_SRV6_LOCALSID_ACTION_END = 1,
FPM_SRV6_LOCALSID_ACTION_END_X = 2,
FPM_SRV6_LOCALSID_ACTION_END_T = 3,
FPM_SRV6_LOCALSID_ACTION_END_DX2 = 4,
FPM_SRV6_LOCALSID_ACTION_END_DX6 = 5,
FPM_SRV6_LOCALSID_ACTION_END_DX4 = 6,
FPM_SRV6_LOCALSID_ACTION_END_DT6 = 7,
FPM_SRV6_LOCALSID_ACTION_END_DT4 = 8,
FPM_SRV6_LOCALSID_ACTION_END_B6 = 9,
FPM_SRV6_LOCALSID_ACTION_END_B6_ENCAP = 10,
FPM_SRV6_LOCALSID_ACTION_END_BM = 11,
FPM_SRV6_LOCALSID_ACTION_END_S = 12,
FPM_SRV6_LOCALSID_ACTION_END_AS = 13,
FPM_SRV6_LOCALSID_ACTION_END_AM = 14,
FPM_SRV6_LOCALSID_ACTION_END_BPF = 15,
FPM_SRV6_LOCALSID_ACTION_END_DT46 = 16,
FPM_SRV6_LOCALSID_ACTION_UDT4 = 100,
FPM_SRV6_LOCALSID_ACTION_UDT6 = 101,
FPM_SRV6_LOCALSID_ACTION_UDT46 = 102,
FPM_SRV6_LOCALSID_ACTION_MAX,
};

enum {
FPM_SRV6_LOCALSID_UNSPEC = 0,
FPM_SRV6_LOCALSID_ACTION = 1,
FPM_SRV6_LOCALSID_SRH = 2,
FPM_SRV6_LOCALSID_TABLE = 3,
FPM_SRV6_LOCALSID_NH4 = 4,
FPM_SRV6_LOCALSID_NH6 = 5,
FPM_SRV6_LOCALSID_IIF = 6,
FPM_SRV6_LOCALSID_OIF = 7,
FPM_SRV6_LOCALSID_BPF = 8,
FPM_SRV6_LOCALSID_VRFTABLE = 9,
FPM_SRV6_LOCALSID_COUNTERS = 10,
FPM_SRV6_LOCALSID_VRFNAME = 100,
FPM_SRV6_LOCALSID_FORMAT = 101,
};

enum {
FPM_SRV6_LOCALSID_FORMAT_UNSPEC = 0,
FPM_SRV6_LOCALSID_FORMAT_BLOCK_LEN = 1,
FPM_SRV6_LOCALSID_FORMAT_NODE_LEN = 2,
FPM_SRV6_LOCALSID_FORMAT_FUNC_LEN = 3,
FPM_SRV6_LOCALSID_FORMAT_ARG_LEN = 4,
};

/* Fixed limit on the number of backup nexthops per primary nexthop */
Expand Down
267 changes: 263 additions & 4 deletions zebra/rt_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,29 @@ vrf_id_t vrf_lookup_by_table(uint32_t table_id, ns_id_t ns_id)
return VRF_DEFAULT;
}

static struct zebra_vrf *vrf_lookup_by_table_id(uint32_t table_id)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't really care for the copy-paste of the existing function logic. can't we have one version of the logic that knows the rules for iterating through the vrfs, and then use that to return the different pieces of info? and really, that should be in the zebra_vrf module, shouldn't it?

{
struct vrf *vrf;
struct zebra_vrf *zvrf;

RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
zvrf = vrf->info;
if (zvrf == NULL)
continue;
/* case vrf with netns : match the netnsid */
if (vrf_is_backend_netns()) {
return NULL;
} else {
/* VRF is VRF_BACKEND_VRF_LITE */
if (zvrf->table_id != table_id)
continue;
return zvrf;
}
}

return NULL;
}

/**
* @parse_encap_mpls() - Parses encapsulated mpls attributes
* @tb: Pointer to rtattr to look for nested items in.
Expand Down Expand Up @@ -1537,7 +1560,7 @@ static bool _netlink_route_build_singlepath(const struct prefix *p,
const struct nexthop *nexthop,
struct nlmsghdr *nlmsg,
struct rtmsg *rtmsg,
size_t req_size, int cmd)
size_t req_size, int cmd, bool fpm)
{

char label_buf[256];
Expand All @@ -1552,7 +1575,7 @@ static bool _netlink_route_build_singlepath(const struct prefix *p,
label_buf, sizeof(label_buf)))
return false;

if (nexthop->nh_srv6) {
if (!fpm && nexthop->nh_srv6) {
if (nexthop->nh_srv6->seg6local_action !=
ZEBRA_SEG6_LOCAL_ACTION_UNSPEC) {
struct rtattr *nest;
Expand Down Expand Up @@ -1674,6 +1697,239 @@ static bool _netlink_route_build_singlepath(const struct prefix *p,
}
}

if (fpm && nexthop->nh_srv6) {
if (nexthop->nh_srv6->seg6local_action !=
ZEBRA_SEG6_LOCAL_ACTION_UNSPEC) {
struct zebra_srv6 *srv6 = zebra_srv6_get_default();
struct zebra_vrf *zvrf;
bool locator_found = false;
struct srv6_locator *locator;
struct listnode *node;
struct rtattr *nest, *inner_nest;
const struct seg6local_context *ctx;

ctx = &nexthop->nh_srv6->seg6local_ctx;

if (!nl_attr_put16(nlmsg, req_size, RTA_ENCAP_TYPE,
FPM_NH_ENCAP_SRV6_LOCAL_SID))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so the design here is "pick a new encap number, and use that to contain the various tlvs with srv6 info", is that right?
is that a robust choice - will the OS-based netlink messaging never support this information? the original goal of the netlink encoded FPM messaging was to be able to use a single encoding or marshalling code-base consistently, but this sort of pushes that aside and introduces a different approach.

Copy link
Contributor Author

@cscarpitta cscarpitta Nov 18, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mjstapp Thanks for your review.

Yes, we pick a new encap number and we use that to contain the TLVs with SRv6 information.

I know dplane_fpm_nl is designed to share zebra's Netlink encoding functions but unfortunately we can't reuse the existing encoding functions in this case.

The reason is that the SRv6 kernel's data model is very different from the SRv6 SONiC's data model.


Let's make an example.

When we encapsulate a packet using SRv6, we add an outer IPv6 header and we need to choose an IPv6 address to use as source address in the outer IPv6 header.

This is implemented differently in the Linux kernel and in SONiC.
In the Linux kernel, we have a source address configured globally in the system and we use that address for all the SRv6 encapsulated packets. For this reason, the Netlink message used to install a route in the kernel does not contain the source address.

Instead, in SONiC each SRv6 route has its own IPv6 source address. Therefore, the Netlink message used to install an SRv6 route in SONiC must contain the source address.


This is why we need to pick a new encap number to send the SRv6 information to SONiC.

return false;

for (ALL_LIST_ELEMENTS_RO(srv6->locators, node,
locator)) {
if (prefix_match(&locator->prefix, p)) {
locator_found = true;
break;
}
}

nest = nl_attr_nest(nlmsg, req_size, RTA_ENCAP);

/* Process Local SID format */
if (locator_found) {
inner_nest =
nl_attr_nest(nlmsg, req_size,
FPM_SRV6_LOCALSID_FORMAT);

if (locator->block_bits_length)
if (!nl_attr_put8(
nlmsg, req_size,
FPM_SRV6_LOCALSID_FORMAT_BLOCK_LEN,
locator->block_bits_length))
return false;

if (locator->node_bits_length)
if (!nl_attr_put8(
nlmsg, req_size,
FPM_SRV6_LOCALSID_FORMAT_NODE_LEN,
locator->node_bits_length))
return false;

if (locator->function_bits_length)
if (!nl_attr_put8(
nlmsg, req_size,
FPM_SRV6_LOCALSID_FORMAT_FUNC_LEN,
locator->function_bits_length))
return false;

if (locator->argument_bits_length)
if (!nl_attr_put8(
nlmsg, req_size,
FPM_SRV6_LOCALSID_FORMAT_ARG_LEN,
locator->argument_bits_length))
return false;

nl_attr_nest_end(nlmsg, inner_nest);
}

switch (nexthop->nh_srv6->seg6local_action) {
case ZEBRA_SEG6_LOCAL_ACTION_END:
if (!nl_attr_put32(
nlmsg, req_size,
FPM_SRV6_LOCALSID_ACTION,
FPM_SRV6_LOCALSID_ACTION_END))
return false;

break;
case ZEBRA_SEG6_LOCAL_ACTION_END_X:
if (!nl_attr_put32(
nlmsg, req_size,
FPM_SRV6_LOCALSID_ACTION,
FPM_SRV6_LOCALSID_ACTION_END_X))
return false;

if (!nl_attr_put(nlmsg, req_size,
FPM_SRV6_LOCALSID_NH6,
&ctx->nh6,
sizeof(struct in6_addr)))
return false;
break;
case ZEBRA_SEG6_LOCAL_ACTION_END_T:
zvrf = vrf_lookup_by_table_id(ctx->table);
if (!zvrf)
return false;

if (!nl_attr_put32(
nlmsg, req_size,
FPM_SRV6_LOCALSID_ACTION,
FPM_SRV6_LOCALSID_ACTION_END_T))
return false;

if (!nl_attr_put(nlmsg, req_size,
FPM_SRV6_LOCALSID_VRFNAME,
zvrf->vrf->name,
strlen(zvrf->vrf->name) + 1))
return false;

break;
case ZEBRA_SEG6_LOCAL_ACTION_END_DX4:
if (!nl_attr_put32(
nlmsg, req_size,
FPM_SRV6_LOCALSID_ACTION,
FPM_SRV6_LOCALSID_ACTION_END_DX4))
return false;

if (!nl_attr_put(nlmsg, req_size,
FPM_SRV6_LOCALSID_NH4,
&ctx->nh4,
sizeof(struct in_addr)))
return false;

break;
case ZEBRA_SEG6_LOCAL_ACTION_END_DT6:
zvrf = vrf_lookup_by_table_id(ctx->table);
if (!zvrf)
return false;

if (locator_found &&
CHECK_FLAG(locator->flags,
SRV6_LOCATOR_USID)) {
if (!nl_attr_put32(
nlmsg, req_size,
FPM_SRV6_LOCALSID_ACTION,
FPM_SRV6_LOCALSID_ACTION_UDT6))
return false;
} else {
if (!nl_attr_put32(
nlmsg, req_size,
FPM_SRV6_LOCALSID_ACTION,
FPM_SRV6_LOCALSID_ACTION_END_DT6))
return false;
}

if (!nl_attr_put(nlmsg, req_size,
FPM_SRV6_LOCALSID_VRFNAME,
zvrf->vrf->name,
strlen(zvrf->vrf->name) + 1))
return false;

break;
case ZEBRA_SEG6_LOCAL_ACTION_END_DT4:
zvrf = vrf_lookup_by_table_id(ctx->table);
if (!zvrf)
return false;

if (locator_found &&
CHECK_FLAG(locator->flags,
SRV6_LOCATOR_USID)) {
if (!nl_attr_put32(
nlmsg, req_size,
FPM_SRV6_LOCALSID_ACTION,
FPM_SRV6_LOCALSID_ACTION_UDT4))
return false;
} else {
if (!nl_attr_put32(
nlmsg, req_size,
FPM_SRV6_LOCALSID_ACTION,
FPM_SRV6_LOCALSID_ACTION_END_DT4))
return false;
}

if (!nl_attr_put(nlmsg, req_size,
FPM_SRV6_LOCALSID_VRFNAME,
zvrf->vrf->name,
strlen(zvrf->vrf->name) + 1))
return false;

break;
case ZEBRA_SEG6_LOCAL_ACTION_END_DT46:
zvrf = vrf_lookup_by_table_id(ctx->table);
if (!zvrf)
return false;

if (locator_found &&
CHECK_FLAG(locator->flags,
SRV6_LOCATOR_USID)) {
if (!nl_attr_put32(
nlmsg, req_size,
FPM_SRV6_LOCALSID_ACTION,
FPM_SRV6_LOCALSID_ACTION_UDT46))
return false;
} else {
if (!nl_attr_put32(
nlmsg, req_size,
FPM_SRV6_LOCALSID_ACTION,
FPM_SRV6_LOCALSID_ACTION_END_DT46))
return false;
}

if (!nl_attr_put(nlmsg, req_size,
FPM_SRV6_LOCALSID_VRFNAME,
zvrf->vrf->name,
strlen(zvrf->vrf->name) + 1))
return false;

break;
default:
zlog_err(
"Unsupported seg6local behaviour action=%u",
nexthop->nh_srv6->seg6local_action);
return false;
}
nl_attr_nest_end(nlmsg, nest);
}

if (!sid_zero(&nexthop->nh_srv6->seg6_segs)) {
struct zebra_srv6 *srv6 = zebra_srv6_get_default();
struct rtattr *nest;

if (!nl_attr_put16(nlmsg, req_size, RTA_ENCAP_TYPE,
FPM_NH_ENCAP_SRV6_ROUTE))
return false;
nest = nl_attr_nest(nlmsg, req_size, RTA_ENCAP);
if (!nest)
return false;
if (!nl_attr_put(
nlmsg, req_size, SRV6_ROUTE_ENCAP_SRC_ADDR,
&srv6->encap_src_addr, IPV6_MAX_BYTELEN))
return false;
if (!nl_attr_put(nlmsg, req_size, SRV6_ROUTE_VPN_SID,
&nexthop->nh_srv6->seg6_segs,
IPV6_MAX_BYTELEN))
return false;
nl_attr_nest_end(nlmsg, nest);
}
}

if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK))
rtmsg->rtm_flags |= RTNH_F_ONLINK;

Expand Down Expand Up @@ -1941,7 +2197,7 @@ _netlink_mpls_build_singlepath(const struct prefix *p, const char *routedesc,
bytelen = (family == AF_INET ? 4 : 16);
return _netlink_route_build_singlepath(p, routedesc, bytelen,
nhlfe->nexthop, nlmsg, rtmsg,
req_size, cmd);
req_size, cmd, false);
}


Expand Down Expand Up @@ -2076,6 +2332,8 @@ static int netlink_route_nexthop_encap(struct nlmsghdr *n, size_t nlen,
return false;
nl_attr_nest_end(n, nest);
break;
default:
zlog_err("Unsupported encap type %d", nh->nh_encap_type);
}

return true;
Expand Down Expand Up @@ -2326,7 +2584,8 @@ ssize_t netlink_route_multipath_msg_encode(int cmd,

if (!_netlink_route_build_singlepath(
p, routedesc, bytelen, nexthop,
&req->n, &req->r, datalen, cmd))
&req->n, &req->r, datalen, cmd,
fpm))
return 0;
nexthop_num++;
break;
Expand Down
3 changes: 3 additions & 0 deletions zebra/zebra_srv6.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
/* SRv6 instance structure. */
struct zebra_srv6 {
struct list *locators;

/* Source address for SRv6 encapsulation */
struct in6_addr encap_src_addr;
};

/* declare hooks for the basic API, so that it can be specialized or served
Expand Down