-
Notifications
You must be signed in to change notification settings - Fork 1.5k
zebra: Extend the FPM module to push the missing SRv6 information #12301
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
d15e667
4135eb9
7dfb928
2fbdf88
b1dea24
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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 { | ||
| SRV6_ROUTE_UNSPEC = 0, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 */ | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. | ||
|
|
@@ -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]; | ||
|
|
@@ -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; | ||
|
|
@@ -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)) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 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. 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; | ||
|
|
||
|
|
@@ -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); | ||
| } | ||
|
|
||
|
|
||
|
|
@@ -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; | ||
|
|
@@ -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; | ||
|
|
||
There was a problem hiding this comment.
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?