diff --git a/doc/user/sharp.rst b/doc/user/sharp.rst index 2be38a31df..9afb1a2173 100644 --- a/doc/user/sharp.rst +++ b/doc/user/sharp.rst @@ -198,14 +198,24 @@ keyword. At present, no sharp commands will be preserved in the config. router# sharp install seg6local-routes 1::4 nexthop-seg6local dum0 End_DX4 10.0.0.1 1 router# sharp install seg6local-routes 1::5 nexthop-seg6local dum0 End_DT6 10 1 router# sharp install seg6local-routes 1::6 nexthop-seg6local dum0 End_DT46 10 1 + router# sharp install seg6local-routes 1::7 nexthop-seg6local dum0 uN 1 + router# sharp install seg6local-routes 1::8 nexthop-seg6local dum0 uA 2001::1 1 + router# sharp install seg6local-routes 1::9 nexthop-seg6local dum0 uN usid-block-length 40 usid-function-length 8 1 + router# sharp install seg6local-routes 1::10 nexthop-seg6local dum0 uA 2001::1 usid-block-length 40 usid-function-length 8 1 + router# sharp install seg6local-routes 1::11 nexthop-seg6local dum0 End_B6_Encap nexthop-seg6 2001::5 encap 2001:a::b:c 2001:a::d:e 1 router# show ipv6 route - D>* 1::1/128 [150/0] is directly connected, dum0, seg6local End USP, weight 1, 00:00:05 + D>* 1::1/128 [150/0] is directly connected, dum0, seg6local End -, weight 1, 00:00:05 D>* 1::2/128 [150/0] is directly connected, dum0, seg6local End.X nh6 2001::1, weight 1, 00:00:05 D>* 1::3/128 [150/0] is directly connected, dum0, seg6local End.T table 10, weight 1, 00:00:05 D>* 1::4/128 [150/0] is directly connected, dum0, seg6local End.DX4 nh4 10.0.0.1, weight 1, 00:00:05 D>* 1::5/128 [150/0] is directly connected, dum0, seg6local End.DT6 table 10, weight 1, 00:00:05 D>* 1::6/128 [150/0] is directly connected, dum0, seg6local End.DT46 table 10, weight 1, 00:00:05 + D>* 1::7/128 [150/0] is directly connected, dum0, seg6local End -, weight 1, 00:00:05 + D>* 1::8/128 [150/0] is directly connected, dum0, seg6local End.X nh6 2001::1, weight 1, 00:01:17 + D>* 1::9/128 [150/0] is directly connected, dum0, seg6local End -, weight 1, 00:00:12 + D>* 1::10/128 [150/0] is directly connected, dum0, seg6local End.X nh6 2001::1, weight 1, 00:00:05 + D>* 1::11/128 [150/0] is directly connected, dum0, seg6local End.B6.Encap nh6 2001::5, seg6 2001:a::b:c,2001:a::d:e, weight 1, 00:00:04 bash# ip -6 route 1::1 encap seg6local action End dev dum0 proto 194 metric 20 pref medium @@ -214,6 +224,12 @@ keyword. At present, no sharp commands will be preserved in the config. 1::4 encap seg6local action End.DX4 nh4 10.0.0.1 dev dum0 proto 194 metric 20 pref medium 1::5 encap seg6local action End.DT6 table 10 dev dum0 proto 194 metric 20 pref medium 1::6 encap seg6local action End.DT46 table 10 dev dum0 proto 194 metric 20 pref medium + 1::7 encap seg6local action End flavors next-csid lblen 32 nflen 16 dev dum0 proto 194 metric 20 pref medium + 1::8 encap seg6local action End.X nh6 2001::1 flavors next-csid lblen 32 nflen 16 dev dum0 proto 194 metric 20 pref medium + 1::9 encap seg6local action End flavors next-csid lblen 40 nflen 8 dev dum0 proto 194 metric 20 pref medium + 1::10 encap seg6local action End.X nh6 2001::1 flavors next-csid lblen 40 nflen 8 dev dum0 proto 194 metric 20 pref medium + 1::11 encap seg6local action End.B6.Encaps segs 2 [ 2001:a::b:c 2001:a::d:e ] via 2001::5 dev dum0 proto 194 metric 20 pref medium + .. clicmd:: show sharp segment-routing srv6 diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index 17e6d04430..fd36e8898e 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -439,19 +439,125 @@ DEFPY (install_seg6_routes, return CMD_SUCCESS; } +DEFPY(install_seg6local_segs_routes, install_seg6local_segs_routes_cmd, + "sharp install seg6local-routes [vrf NAME$vrf_name]\ + X:X::X:X$start6\ + nexthop-seg6local NAME$seg6l_oif\ + \ + nexthop-seg6 X:X::X:X$seg6_nh6\ + encap X:X::X:X$seg6_seg1 X:X::X:X$seg6_seg2\ + [usid-block-length (1-128)$lcblen] [usid-function-length (1-128)$lcfunclen] \ + (1-1000000)$routes [repeat (2-1000)$rpt]", + "Sharp routing Protocol\n" + "install some routes\n" + "Routes to install\n" + "The vrf we would like to install into if non-default\n" + "The NAME of the vrf\n" + "v6 Address to start /32 generation at\n" + "Nexthop-seg6local to use\n" + "Output device to use\n" + "SRv6 End.B6.Encap function to use\n" + "SRv6 uB6.Encap function to use\n" + "Nexthop-seg6 to use\n" + "V6 Nexthop address to use\n" + "Encap mode\n" + "Segment List, 1st SID to use\n" + "Segment List, 2nd SID to use\n" + "uSID locator block length\n" + "Value in bits\n" + "uSID node Function length\n" + "Value in bits\n" + "How many to create\n" + "Should we repeat this command\n" + "How many times to repeat this command\n") +{ + struct vrf *vrf; + uint32_t route_flags = 0; + struct seg6local_context ctx = {}; + enum seg6local_action_t action; + struct in6_addr seg_list[2]; + struct in6_addr *p_seg_list = &seg_list[0]; + + sg.r.total_routes = routes; + sg.r.installed_routes = 0; + + if (rpt >= 2) + sg.r.repeat = rpt * 2; + else + sg.r.repeat = 0; + + memset(&sg.r.orig_prefix, 0, sizeof(sg.r.orig_prefix)); + nexthop_del_srv6_seg6local(&sg.r.nhop); + nexthop_del_srv6_seg6(&sg.r.nhop); + memset(&sg.r.nhop, 0, sizeof(sg.r.nhop)); + memset(&sg.r.nhop_group, 0, sizeof(sg.r.nhop_group)); + memset(&sg.r.backup_nhop, 0, sizeof(sg.r.nhop)); + memset(&sg.r.backup_nhop_group, 0, sizeof(sg.r.nhop_group)); + sg.r.opaque[0] = '\0'; + sg.r.inst = 0; + sg.r.orig_prefix.family = AF_INET6; + sg.r.orig_prefix.prefixlen = 128; + sg.r.orig_prefix.u.prefix6 = start6; + + if (!vrf_name) + vrf_name = VRF_DEFAULT_NAME; + + vrf = vrf_lookup_by_name(vrf_name); + if (!vrf) { + vty_out(vty, "The vrf NAME specified: %s does not exist\n", vrf_name); + return CMD_WARNING; + } + + ctx.nh6 = seg6_nh6; + action = ZEBRA_SEG6_LOCAL_ACTION_END_B6_ENCAP; + if (ub6_encap) { + SET_SRV6_FLV_OP(ctx.flv.flv_ops, ZEBRA_SEG6_LOCAL_FLV_OP_NEXT_CSID); + if (lcblen) + ctx.flv.lcblock_len = lcblen; + if (lcfunclen) + ctx.flv.lcnode_func_len = lcfunclen; + } + + sg.r.nhop.type = NEXTHOP_TYPE_IPV6_IFINDEX; + sg.r.nhop.gate.ipv6 = seg6_nh6; + sg.r.nhop.ifindex = ifname2ifindex(seg6l_oif, vrf->vrf_id); + sg.r.nhop.vrf_id = vrf->vrf_id; + sg.r.nhop_group.nexthop = &sg.r.nhop; + nexthop_add_srv6_seg6local(&sg.r.nhop, action, &ctx); + sg.r.nhop_group.nexthop = &sg.r.nhop; + seg_list[0] = seg6_seg1; + seg_list[1] = seg6_seg2; + nexthop_add_srv6_seg6(&sg.r.nhop, p_seg_list, 2); + + sg.r.vrf_id = vrf->vrf_id; + sharp_install_routes_helper(&sg.r.orig_prefix, sg.r.vrf_id, sg.r.inst, 0, &sg.r.nhop_group, + &sg.r.backup_nhop_group, routes, route_flags, sg.r.opaque); + + return CMD_SUCCESS; +} + DEFPY (install_seg6local_routes, install_seg6local_routes_cmd, "sharp install seg6local-routes [vrf NAME$vrf_name]\ X:X::X:X$start6\ nexthop-seg6local NAME$seg6l_oif\ \ + uDT4$seg6l_micro_enddt4 (1-4294967295)$seg6l_micro_enddt4_table|\ + End_DT46$seg6l_enddt46 (1-4294967295)$seg6l_enddt46_table|\ + uDT46$seg6l_micro_enddt46 (1-4294967295)$seg6l_micro_enddt46_table>\ + [usid-block-length (1-128)$lcblen] [usid-function-length (1-128)$lcfunclen] \ (1-1000000)$routes [repeat (2-1000)$rpt]", "Sharp routing Protocol\n" "install some routes\n" @@ -462,20 +568,39 @@ DEFPY (install_seg6local_routes, "Nexthop-seg6local to use\n" "Output device to use\n" "SRv6 End function to use\n" + "SRv6 uN function to use\n" "SRv6 End.X function to use\n" "V6 Nexthop address to use\n" + "SRv6 uA function to use\n" + "V6 Nexthop address to use\n" "SRv6 End.T function to use\n" "Redirect table id to use\n" + "SRv6 uDT function to use\n" + "Redirect table id to use\n" "SRv6 End.DX4 function to use\n" "V4 Nexthop address to use\n" + "SRv6 uDX4 function to use\n" + "V4 Nexthop address to use\n" "SRv6 End.DX6 function to use\n" "V6 Nexthop address to use\n" + "SRv6 uDX6 function to use\n" + "V6 Nexthop address to use\n" "SRv6 End.DT6 function to use\n" "Redirect table id to use\n" + "SRv6 uDT6 function to use\n" + "Redirect table id to use\n" "SRv6 End.DT4 function to use\n" "Redirect table id to use\n" + "SRv6 uDT4 function to use\n" + "Redirect table id to use\n" "SRv6 End.DT46 function to use\n" "Redirect table id to use\n" + "SRv6 uDT46 function to use\n" + "Redirect table id to use\n" + "uSID locator block length\n" + "Value in bits\n" + "uSID node Function length\n" + "Value in bits\n" "How many to create\n" "Should we repeat this command\n" "How many times to repeat this command\n") @@ -519,28 +644,64 @@ DEFPY (install_seg6local_routes, if (seg6l_enddx4) { action = ZEBRA_SEG6_LOCAL_ACTION_END_DX4; ctx.nh4 = seg6l_enddx4_nh4; + } else if (seg6l_micro_enddx4) { + action = ZEBRA_SEG6_LOCAL_ACTION_END_DX4; + ctx.nh4 = seg6l_micro_enddx4_nh4; + SET_SRV6_FLV_OP(ctx.flv.flv_ops, ZEBRA_SEG6_LOCAL_FLV_OP_NEXT_CSID); } else if (seg6l_enddx6) { action = ZEBRA_SEG6_LOCAL_ACTION_END_DX6; ctx.nh6 = seg6l_enddx6_nh6; + } else if (seg6l_micro_enddx6) { + action = ZEBRA_SEG6_LOCAL_ACTION_END_DX6; + ctx.nh6 = seg6l_enddx6_nh6; + SET_SRV6_FLV_OP(ctx.flv.flv_ops, ZEBRA_SEG6_LOCAL_FLV_OP_NEXT_CSID); } else if (seg6l_endx) { action = ZEBRA_SEG6_LOCAL_ACTION_END_X; ctx.nh6 = seg6l_endx_nh6; + } else if (seg6l_micro_endx) { + action = ZEBRA_SEG6_LOCAL_ACTION_END_X; + ctx.nh6 = seg6l_micro_endx_nh6; + SET_SRV6_FLV_OP(ctx.flv.flv_ops, ZEBRA_SEG6_LOCAL_FLV_OP_NEXT_CSID); } else if (seg6l_endt) { action = ZEBRA_SEG6_LOCAL_ACTION_END_T; ctx.table = seg6l_endt_table; + } else if (seg6l_micro_endt) { + action = ZEBRA_SEG6_LOCAL_ACTION_END_T; + ctx.table = seg6l_micro_endt_table; + SET_SRV6_FLV_OP(ctx.flv.flv_ops, ZEBRA_SEG6_LOCAL_FLV_OP_NEXT_CSID); } else if (seg6l_enddt6) { action = ZEBRA_SEG6_LOCAL_ACTION_END_DT6; ctx.table = seg6l_enddt6_table; + } else if (seg6l_micro_enddt6) { + action = ZEBRA_SEG6_LOCAL_ACTION_END_DT6; + ctx.table = seg6l_micro_enddt6_table; + SET_SRV6_FLV_OP(ctx.flv.flv_ops, ZEBRA_SEG6_LOCAL_FLV_OP_NEXT_CSID); } else if (seg6l_enddt4) { action = ZEBRA_SEG6_LOCAL_ACTION_END_DT4; ctx.table = seg6l_enddt4_table; + } else if (seg6l_micro_enddt4) { + action = ZEBRA_SEG6_LOCAL_ACTION_END_DT4; + ctx.table = seg6l_micro_enddt4_table; + SET_SRV6_FLV_OP(ctx.flv.flv_ops, ZEBRA_SEG6_LOCAL_FLV_OP_NEXT_CSID); } else if (seg6l_enddt46) { action = ZEBRA_SEG6_LOCAL_ACTION_END_DT46; ctx.table = seg6l_enddt46_table; - } else { + } else if (seg6l_micro_enddt46) { + action = ZEBRA_SEG6_LOCAL_ACTION_END_DT46; + ctx.table = seg6l_micro_enddt46_table; + SET_SRV6_FLV_OP(ctx.flv.flv_ops, ZEBRA_SEG6_LOCAL_FLV_OP_NEXT_CSID); + } else if (seg6l_micro_end) { + action = ZEBRA_SEG6_LOCAL_ACTION_END; + SET_SRV6_FLV_OP(ctx.flv.flv_ops, ZEBRA_SEG6_LOCAL_FLV_OP_NEXT_CSID); + } else action = ZEBRA_SEG6_LOCAL_ACTION_END; - } + if (CHECK_SRV6_FLV_OP(ctx.flv.flv_ops, ZEBRA_SEG6_LOCAL_FLV_OP_NEXT_CSID)) { + if (lcblen) + ctx.flv.lcblock_len = lcblen; + if (lcfunclen) + ctx.flv.lcnode_func_len = lcfunclen; + } sg.r.nhop.type = NEXTHOP_TYPE_IFINDEX; sg.r.nhop.ifindex = ifname2ifindex(seg6l_oif, vrf->vrf_id); sg.r.nhop.vrf_id = vrf->vrf_id; @@ -1491,6 +1652,7 @@ void sharp_vty_init(void) install_element(ENABLE_NODE, &install_routes_cmd); install_element(ENABLE_NODE, &install_seg6_routes_cmd); install_element(ENABLE_NODE, &install_seg6local_routes_cmd); + install_element(ENABLE_NODE, &install_seg6local_segs_routes_cmd); install_element(ENABLE_NODE, &remove_routes_cmd); install_element(ENABLE_NODE, &vrf_label_cmd); install_element(ENABLE_NODE, &sharp_nht_data_dump_cmd); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index a2e7997ab4..477fbc455f 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -94,6 +94,12 @@ struct gw_family_t { union g_addr gate; }; +struct buf_req { + struct nlmsghdr n; + struct nhmsg nhm; + char buf[]; +}; + static const char ipv4_ll_buf[16] = "169.254.0.1"; static struct in_addr ipv4_ll; @@ -2936,6 +2942,54 @@ static bool _netlink_nexthop_build_group(struct nlmsghdr *n, size_t req_size, ui return true; } +static ssize_t fill_srh_end_b6_encaps(char *buffer, size_t buflen, struct seg6_seg_stack *segs) +{ + struct ipv6_sr_hdr *srh; + size_t srhlen; + int i; + + if (!segs || segs->num_segs > SRV6_MAX_SEGS) { + /* Exceeding maximum supported SIDs */ + return -1; + } + + srhlen = SRH_BASE_HEADER_LENGTH + SRH_SEGMENT_LENGTH * segs->num_segs; + + if (buflen < srhlen) + return -1; + + memset(buffer, 0, buflen); + + srh = (struct ipv6_sr_hdr *)buffer; + srh->hdrlen = (srhlen >> 3) - 1; + srh->type = 4; + srh->segments_left = segs->num_segs - 1; + srh->first_segment = segs->num_segs - 1; + + for (i = 0; i < segs->num_segs; i++) { + memcpy(&srh->segments[segs->num_segs - i - 1], &segs->seg[i], + sizeof(struct in6_addr)); + } + + return srhlen; +} + +static int netlink_nexthop_msg_encode_end_b6_encaps(struct buf_req *req, const struct nexthop *nh, + size_t buflen) +{ + int srh_len; + char srh_buf[4096]; + + if (!nl_attr_put32(&req->n, buflen, SEG6_LOCAL_ACTION, SEG6_LOCAL_ACTION_END_B6_ENCAP)) + return 0; + srh_len = fill_srh_end_b6_encaps(srh_buf, sizeof(srh_buf), nh->nh_srv6->seg6_segs); + if (srh_len < 0) + return 0; + if (!nl_attr_put(&req->n, buflen, SEG6_LOCAL_SRH, srh_buf, srh_len)) + return 0; + return 1; +} + /** * Next hop packet encoding helper function. * @@ -3248,6 +3302,12 @@ ssize_t netlink_nexthop_msg_encode(uint16_t cmd, ctx6->table)) return 0; break; + case ZEBRA_SEG6_LOCAL_ACTION_END_B6_ENCAP: + netlink_nexthop_msg_encode_end_b6_encaps((struct buf_req + *) + req, + nh, buflen); + break; default: zlog_err("%s: unsupport seg6local behaviour action=%u", __func__, action); @@ -3261,9 +3321,9 @@ ssize_t netlink_nexthop_msg_encode(uint16_t cmd, nl_attr_nest_end(&req->n, nest); } - if (nh->nh_srv6->seg6_segs && - nh->nh_srv6->seg6_segs->num_segs && - !sid_zero(nh->nh_srv6->seg6_segs)) { + if (nh->nh_srv6->seg6_segs && nh->nh_srv6->seg6_segs->num_segs && + !sid_zero(nh->nh_srv6->seg6_segs) && + nh->nh_srv6->seg6local_action == ZEBRA_SEG6_LOCAL_ACTION_UNSPEC) { char tun_buf[4096]; ssize_t tun_len;