summaryrefslogtreecommitdiff
path: root/zebra/rt_netlink.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/rt_netlink.c')
-rw-r--r--zebra/rt_netlink.c121
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