diff options
Diffstat (limited to 'zebra/rt_netlink.c')
| -rw-r--r-- | zebra/rt_netlink.c | 121 |
1 files changed, 114 insertions, 7 deletions
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 2318cd6374..9d8ef00b52 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -407,6 +407,36 @@ static int parse_encap_mpls(struct rtattr *tb, mpls_label_t *labels) return num_labels; } +/** + * @parse_encap_seg6local_flavors() - Parses encapsulated SRv6 flavors + * attributes + * @tb: Pointer to rtattr to look for nested items in. + * @flv: Pointer to store SRv6 flavors info in. + * + * Return: 0 on success, non-zero on error + */ +static int parse_encap_seg6local_flavors(struct rtattr *tb, + struct seg6local_flavors_info *flv) +{ + struct rtattr *tb_encap[SEG6_LOCAL_FLV_MAX + 1] = {}; + + netlink_parse_rtattr_nested(tb_encap, SEG6_LOCAL_FLV_MAX, tb); + + if (tb_encap[SEG6_LOCAL_FLV_OPERATION]) + flv->flv_ops = *(uint32_t *)RTA_DATA( + tb_encap[SEG6_LOCAL_FLV_OPERATION]); + + if (tb_encap[SEG6_LOCAL_FLV_LCBLOCK_BITS]) + flv->lcblock_len = *(uint8_t *)RTA_DATA( + tb_encap[SEG6_LOCAL_FLV_LCBLOCK_BITS]); + + if (tb_encap[SEG6_LOCAL_FLV_LCNODE_FN_BITS]) + flv->lcnode_func_len = *(uint8_t *)RTA_DATA( + tb_encap[SEG6_LOCAL_FLV_LCNODE_FN_BITS]); + + return 0; +} + static enum seg6local_action_t parse_encap_seg6local(struct rtattr *tb, struct seg6local_context *ctx) @@ -434,6 +464,11 @@ parse_encap_seg6local(struct rtattr *tb, ctx->table = *(uint32_t *)RTA_DATA(tb_encap[SEG6_LOCAL_VRFTABLE]); + if (tb_encap[SEG6_LOCAL_FLAVORS]) { + parse_encap_seg6local_flavors(tb_encap[SEG6_LOCAL_FLAVORS], + &ctx->flv); + } + return act; } @@ -532,6 +567,16 @@ parse_nexthop_unicast(ns_id_t ns_id, struct rtmsg *rtm, struct rtattr **tb, if (num_labels) nexthop_add_labels(&nh, ZEBRA_LSP_STATIC, num_labels, labels); + /* Resolve default values for SRv6 flavors */ + if (seg6l_ctx.flv.flv_ops != ZEBRA_SEG6_LOCAL_FLV_OP_UNSPEC) { + if (seg6l_ctx.flv.lcblock_len == 0) + seg6l_ctx.flv.lcblock_len = + ZEBRA_DEFAULT_SEG6_LOCAL_FLV_LCBLOCK_LEN; + if (seg6l_ctx.flv.lcnode_func_len == 0) + seg6l_ctx.flv.lcnode_func_len = + ZEBRA_DEFAULT_SEG6_LOCAL_FLV_LCNODE_FN_LEN; + } + if (seg6l_act != ZEBRA_SEG6_LOCAL_ACTION_UNSPEC) nexthop_add_srv6_seg6local(&nh, seg6l_act, &seg6l_ctx); @@ -639,6 +684,17 @@ static uint8_t parse_multipath_nexthops_unicast(ns_id_t ns_id, nexthop_add_labels(nh, ZEBRA_LSP_STATIC, num_labels, labels); + /* Resolve default values for SRv6 flavors */ + if (seg6l_ctx.flv.flv_ops != + ZEBRA_SEG6_LOCAL_FLV_OP_UNSPEC) { + if (seg6l_ctx.flv.lcblock_len == 0) + seg6l_ctx.flv.lcblock_len = + ZEBRA_DEFAULT_SEG6_LOCAL_FLV_LCBLOCK_LEN; + if (seg6l_ctx.flv.lcnode_func_len == 0) + seg6l_ctx.flv.lcnode_func_len = + ZEBRA_DEFAULT_SEG6_LOCAL_FLV_LCNODE_FN_LEN; + } + if (seg6l_act != ZEBRA_SEG6_LOCAL_ACTION_UNSPEC) nexthop_add_srv6_seg6local(nh, seg6l_act, &seg6l_ctx); @@ -1491,6 +1547,46 @@ static ssize_t fill_seg6ipt_encap(char *buffer, size_t buflen, return srhlen + 4; } +static bool +_netlink_nexthop_encode_seg6local_flavor(const struct nexthop *nexthop, + struct nlmsghdr *nlmsg, size_t buflen) +{ + struct rtattr *nest; + struct seg6local_flavors_info *flv; + + assert(nexthop); + + if (!nexthop->nh_srv6) + return false; + + flv = &nexthop->nh_srv6->seg6local_ctx.flv; + + if (flv->flv_ops == ZEBRA_SEG6_LOCAL_FLV_OP_UNSPEC) + return true; + + nest = nl_attr_nest(nlmsg, buflen, SEG6_LOCAL_FLAVORS); + if (!nest) + return false; + + if (!nl_attr_put32(nlmsg, buflen, SEG6_LOCAL_FLV_OPERATION, + flv->flv_ops)) + return false; + + if (flv->lcblock_len) + if (!nl_attr_put8(nlmsg, buflen, SEG6_LOCAL_FLV_LCBLOCK_BITS, + flv->lcblock_len)) + return false; + + if (flv->lcnode_func_len) + if (!nl_attr_put8(nlmsg, buflen, SEG6_LOCAL_FLV_LCNODE_FN_BITS, + flv->lcnode_func_len)) + return false; + + nl_attr_nest_end(nlmsg, nest); + + return true; +} + /* This function takes a nexthop as argument and adds * the appropriate netlink attributes to an existing * netlink message. @@ -1622,6 +1718,11 @@ static bool _netlink_route_build_singlepath(const struct prefix *p, nexthop->nh_srv6->seg6local_action); return false; } + + if (!_netlink_nexthop_encode_seg6local_flavor( + nexthop, nlmsg, req_size)) + return false; + nl_attr_nest_end(nlmsg, nest); } @@ -2060,10 +2161,10 @@ static int netlink_route_nexthop_encap(struct nlmsghdr *n, size_t nlen, * Returns -1 on failure, 0 when the msg doesn't fit entirely in the buffer * otherwise the number of bytes written to buf. */ -ssize_t netlink_route_multipath_msg_encode(int cmd, - struct zebra_dplane_ctx *ctx, +ssize_t netlink_route_multipath_msg_encode(int cmd, struct zebra_dplane_ctx *ctx, uint8_t *data, size_t datalen, - bool fpm, bool force_nhg) + bool fpm, bool force_nhg, + bool force_rr) { int bytelen; struct nexthop *nexthop = NULL; @@ -2097,8 +2198,9 @@ ssize_t netlink_route_multipath_msg_encode(int cmd, req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; - if ((cmd == RTM_NEWROUTE) && - ((p->family == AF_INET) || v6_rr_semantics)) + if (((cmd == RTM_NEWROUTE) && + ((p->family == AF_INET) || v6_rr_semantics)) || + force_rr) req->n.nlmsg_flags |= NLM_F_REPLACE; req->n.nlmsg_type = cmd; @@ -2861,6 +2963,11 @@ ssize_t netlink_nexthop_msg_encode(uint16_t cmd, __func__, action); return 0; } + + if (!_netlink_nexthop_encode_seg6local_flavor( + nh, &req->n, buflen)) + return false; + nl_attr_nest_end(&req->n, nest); } @@ -2953,14 +3060,14 @@ static ssize_t netlink_newroute_msg_encoder(struct zebra_dplane_ctx *ctx, void *buf, size_t buflen) { return netlink_route_multipath_msg_encode(RTM_NEWROUTE, ctx, buf, - buflen, false, false); + buflen, false, false, false); } static ssize_t netlink_delroute_msg_encoder(struct zebra_dplane_ctx *ctx, void *buf, size_t buflen) { return netlink_route_multipath_msg_encode(RTM_DELROUTE, ctx, buf, - buflen, false, false); + buflen, false, false, false); } enum netlink_msg_status |
