From 113f49bc4ec080c9785fc2158214dc032723158b Mon Sep 17 00:00:00 2001 From: ysj17861081006 <1686637505@qq.com> Date: Fri, 13 Sep 2024 03:48:30 +0000 Subject: [PATCH] add CLI about locator, related funcs and KERNELBYPASS flag on dplane_ctx Signed-off-by: ysj17861081006 <1686637505@qq.com> --- lib/command.h | 57 ++--- lib/nexthop.h | 3 + lib/srv6.c | 65 ++++- lib/srv6.h | 36 +++ lib/zclient.c | 28 +++ lib/zclient.h | 9 + lib/zebra.h | 4 + vtysh/vtysh.c | 41 +++- zebra/rt_netlink.c | 16 ++ zebra/rt_socket.c | 15 ++ zebra/zapi_msg.c | 66 +++++ zebra/zapi_msg.h | 8 + zebra/zebra_dplane.c | 48 +++- zebra/zebra_dplane.h | 2 + zebra/zebra_fpm_netlink.c | 2 + zebra/zebra_srv6.c | 466 ++++++++++++++++++++++++++++++++++- zebra/zebra_srv6.h | 27 +++ zebra/zebra_srv6_vty.c | 499 +++++++++++++++++++++++++++++--------- zebra/zebra_vrf.c | 1 + 19 files changed, 1228 insertions(+), 165 deletions(-) diff --git a/lib/command.h b/lib/command.h index 61d09973fd9e..a0ccc02b2775 100644 --- a/lib/command.h +++ b/lib/command.h @@ -77,8 +77,8 @@ struct host { /* List of CLI nodes. Please remember to update the name array in command.c. */ /* clang-format off */ enum node_type { - AUTH_NODE, /* Authentication mode of vty interface. */ - VIEW_NODE, /* View node. Default mode of vty interface. */ + AUTH_NODE, /* Authentication mode of vty interface. */ + VIEW_NODE, /* View node. Default mode of vty interface. */ AUTH_ENABLE_NODE, /* Authentication mode for change enable. */ ENABLE_NODE, /* Enable node. */ CONFIG_NODE, /* Config node. Default mode of config file. */ @@ -134,36 +134,37 @@ enum node_type { ISIS_FLEX_ALGO_NODE, /* ISIS Flex Algo mode */ ACCESS_NODE, /* Access list node. */ ACCESS_IPV6_NODE, /* Access list node. */ - ACCESS_MAC_NODE, /* MAC access list node*/ - AS_LIST_NODE, /* AS list node. */ - COMMUNITY_LIST_NODE, /* Community list node. */ - COMMUNITY_ALIAS_NODE, /* Community alias node. */ - RMAP_NODE, /* Route map node. */ - PBRMAP_NODE, /* PBR map node. */ - SMUX_NODE, /* SNMP configuration node. */ - DUMP_NODE, /* Packet dump node. */ - FORWARDING_NODE, /* IP forwarding node. */ - PROTOCOL_NODE, /* protocol filtering node */ - MPLS_NODE, /* MPLS config node */ - PW_NODE, /* Pseudowire config node */ - SEGMENT_ROUTING_NODE, /* Segment routing root node */ - SR_TRAFFIC_ENG_NODE, /* SR Traffic Engineering node */ - SR_SEGMENT_LIST_NODE, /* SR segment list config node */ - SR_POLICY_NODE, /* SR policy config node */ - SR_CANDIDATE_DYN_NODE, /* SR dynamic candidate path config node */ - PCEP_NODE, /* PCEP node */ - PCEP_PCE_CONFIG_NODE, /* PCE shared configuration node */ - PCEP_PCE_NODE, /* PCE configuration node */ - PCEP_PCC_NODE, /* PCC configuration node */ - SRV6_NODE, /* SRv6 node */ - SRV6_LOCS_NODE, /* SRv6 locators node */ - SRV6_LOC_NODE, /* SRv6 locator node */ + ACCESS_MAC_NODE, /* MAC access list node*/ + AS_LIST_NODE, /* AS list node. */ + COMMUNITY_LIST_NODE, /* Community list node. */ + COMMUNITY_ALIAS_NODE, /* Community alias node. */ + RMAP_NODE, /* Route map node. */ + PBRMAP_NODE, /* PBR map node. */ + SMUX_NODE, /* SNMP configuration node. */ + DUMP_NODE, /* Packet dump node. */ + FORWARDING_NODE, /* IP forwarding node. */ + PROTOCOL_NODE, /* protocol filtering node */ + MPLS_NODE, /* MPLS config node */ + PW_NODE, /* Pseudowire config node */ + SEGMENT_ROUTING_NODE, /* Segment routing root node */ + SR_TRAFFIC_ENG_NODE, /* SR Traffic Engineering node */ + SR_SEGMENT_LIST_NODE, /* SR segment list config node */ + SR_POLICY_NODE, /* SR policy config node */ + SR_CANDIDATE_DYN_NODE, /* SR dynamic candidate path config node */ + PCEP_NODE, /* PCEP node */ + PCEP_PCE_CONFIG_NODE, /* PCE shared configuration node */ + PCEP_PCE_NODE, /* PCE configuration node */ + PCEP_PCC_NODE, /* PCC configuration node */ + SRV6_NODE, /* SRv6 node */ + SRV6_LOCS_NODE, /* SRv6 locators node */ + SRV6_LOC_NODE, /* SRv6 locator node */ + SRV6_PREFIX_NODE, /* SRv6 locator prefix node */ SRV6_ENCAP_NODE, /* SRv6 encapsulation node */ SRV6_SID_FORMATS_NODE, /* SRv6 SID formats config node */ SRV6_SID_FORMAT_USID_F3216_NODE, /* SRv6 uSID f3216 format config node */ SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, /* SRv6 uncompressed f4024 format config node */ - VTY_NODE, /* Vty node. */ - FPM_NODE, /* Dataplane FPM node. */ + VTY_NODE, /* Vty node. */ + FPM_NODE, /* Dataplane FPM node. */ LINK_PARAMS_NODE, /* Link-parameters node */ BGP_EVPN_VNI_NODE, /* BGP EVPN VNI */ RPKI_NODE, /* RPKI node for configuration of RPKI cache server diff --git a/lib/nexthop.h b/lib/nexthop.h index 15cfb26d8206..bbe89d69c6f2 100644 --- a/lib/nexthop.h +++ b/lib/nexthop.h @@ -86,6 +86,9 @@ struct nexthop { (CHECK_FLAG(flags, NEXTHOP_FLAG_ACTIVE) \ && !CHECK_FLAG(flags, NEXTHOP_FLAG_DUPLICATE)) + uint8_t nh_flags; +#define NEXTHOP_FLAG_EVPN_RVTEP (1 << 0) /* EVPN remote vtep nexthop */ + /* Nexthop address */ union { union g_addr gate; diff --git a/lib/srv6.c b/lib/srv6.c index e6fc375fbb11..d57b52ddb509 100644 --- a/lib/srv6.c +++ b/lib/srv6.c @@ -158,14 +158,23 @@ void srv6_locator_chunk_list_free(void *data) srv6_locator_chunk_free(&chunk); } +struct srv6_locator *srv6_locator_new() +{ + struct srv6_locator *locator = NULL; + locator = XCALLOC(MTYPE_SRV6_LOCATOR, sizeof(struct srv6_locator)); + return locator; +} + struct srv6_locator *srv6_locator_alloc(const char *name) { struct srv6_locator *locator = NULL; - locator = XCALLOC(MTYPE_SRV6_LOCATOR, sizeof(struct srv6_locator)); + locator = srv6_locator_new(); strlcpy(locator->name, name, sizeof(locator->name)); locator->chunks = list_new(); - locator->chunks->del = srv6_locator_chunk_list_free; + locator->chunks->del = (void (*)(void *))srv6_locator_chunk_free; + + locator->sids = list_new(); QOBJ_REG(locator, srv6_locator); return locator; @@ -179,6 +188,15 @@ struct srv6_locator_chunk *srv6_locator_chunk_alloc(void) sizeof(struct srv6_locator_chunk)); return chunk; } +void srv6_locator_del(struct srv6_locator *locator) +{ + if (locator->chunks) + list_delete(&locator->chunks); + if (locator->sids) + list_delete(&locator->sids); + XFREE(MTYPE_SRV6_LOCATOR, locator); + return; +} void srv6_locator_copy(struct srv6_locator *copy, const struct srv6_locator *locator) @@ -205,6 +223,49 @@ void srv6_locator_free(struct srv6_locator *locator) } } +struct seg6_sid *srv6_locator_sid_alloc(void) +{ + struct seg6_sid *sid = NULL; + + sid = XCALLOC(MTYPE_SRV6_LOCATOR_CHUNK, sizeof(struct seg6_sid)); + strlcpy(sid->vrfName, "Default", sizeof(sid->vrfName)); + return sid; +} +void srv6_locator_sid_free(struct seg6_sid *sid) +{ + XFREE(MTYPE_SRV6_LOCATOR_CHUNK, sid); + return; +} + +void combine_sid(struct srv6_locator *locator, struct in6_addr *sid_addr, + struct in6_addr *result_addr) +{ + uint8_t idx = 0; + uint8_t funcid = 0; + uint8_t locatorbit = 0; + /* uint8_t sidbit = 0;*/ + uint8_t totalbit = 0; + uint8_t funbit = 0; + locatorbit = + (locator->block_bits_length + locator->node_bits_length) / 8; + /* sidbit = 16 - locatorbit; */ + totalbit = (locator->block_bits_length + locator->node_bits_length + + locator->function_bits_length + + locator->argument_bits_length) / + 8; + funbit = (locator->function_bits_length + + locator->argument_bits_length) / + 8; + for (idx = 0; idx < locatorbit; idx++) { + result_addr->s6_addr[idx] = locator->prefix.prefix.s6_addr[idx]; + } + for (; idx < totalbit; idx++) { + result_addr->s6_addr[idx] = + sid_addr->s6_addr[16 - funbit + funcid]; + funcid++; + } +} + void srv6_locator_chunk_free(struct srv6_locator_chunk **chunk) { XFREE(MTYPE_SRV6_LOCATOR_CHUNK, *chunk); diff --git a/lib/srv6.h b/lib/srv6.h index f25c5cfcaa5c..b344e2de45c3 100644 --- a/lib/srv6.h +++ b/lib/srv6.h @@ -10,6 +10,7 @@ #include #include "prefix.h" #include "json.h" +#include "vrf.h" #include #include @@ -106,6 +107,17 @@ struct seg6local_context { struct in6_addr nh6; uint32_t table; struct seg6local_flavors_info flv; + uint8_t block_bits_length; + uint8_t node_bits_length; + uint8_t function_bits_length; + uint8_t argument_bits_length; + char vrfName[VRF_NAMSIZ + 1]; +}; + +enum srv6_format { + SRV6_FORMAT_F1 = 0, ///< Format 1. + SRV6_FORMAT_USID_3216, ///< uSID 32/16 Format. + SRV6_FORMAT_MAX, }; struct srv6_locator { @@ -125,8 +137,10 @@ struct srv6_locator { uint64_t current; bool status_up; struct list *chunks; + struct list *sids; uint8_t flags; + enum srv6_format format; #define SRV6_LOCATOR_USID (1 << 0) /* The SRv6 Locator is a uSID Locator */ /* Pointer to the SID format. */ @@ -163,6 +177,21 @@ struct srv6_locator_chunk { uint8_t flags; }; +struct seg6_sid { + enum seg6local_action_t sidaction; + char vrfName[VRF_NAMSIZ + 1]; + struct prefix_ipv6 ipv6Addr; + char sidstr[PREFIX_STRLEN]; + char ifname[INTERFACE_NAMSIZ]; + struct in6_addr nexthop; +}; +struct seg6_sid_msg { + char locator_name[SRV6_LOCNAME_SIZE]; + enum seg6local_action_t sidaction; + char vrfName[VRF_NAMSIZ + 1]; + struct prefix_ipv6 ipv6Addr; +}; + /* * SRv6 Endpoint Behavior codepoints, as defined by IANA in * https://www.iana.org/assignments/segment-routing/segment-routing.xhtml @@ -372,8 +401,15 @@ static inline const char *srv6_sid_ctx2str(char *str, size_t size, int snprintf_seg6_segs(char *str, size_t size, const struct seg6_segs *segs); +extern void combine_sid(struct srv6_locator *locator, struct in6_addr *sid_addr, + struct in6_addr *result_addr); +extern void srv6_locator_del(struct srv6_locator *locator); +extern struct srv6_locator *srv6_locator_new(); + extern struct srv6_locator *srv6_locator_alloc(const char *name); extern struct srv6_locator_chunk *srv6_locator_chunk_alloc(void); +extern struct seg6_sid *srv6_locator_sid_alloc(void); +extern void srv6_locator_sid_free(struct seg6_sid *sid); extern void srv6_locator_free(struct srv6_locator *locator); extern void srv6_locator_chunk_list_free(void *data); extern void srv6_locator_chunk_free(struct srv6_locator_chunk **chunk); diff --git a/lib/zclient.c b/lib/zclient.c index 0e832f0d8fe5..92b859235c95 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -1156,6 +1156,34 @@ int zapi_srv6_locator_decode(struct stream *s, struct srv6_locator *l) return -1; } +int zapi_srv6_locator_sid_encode(struct stream *s, struct srv6_locator *loc) +{ + struct seg6_sid *sidtmp = NULL; + struct listnode *node = NULL; + + stream_putw(s, strlen(loc->name)); + stream_put(s, loc->name, strlen(loc->name)); + + stream_putw(s, loc->prefix.prefixlen); + stream_put(s, &loc->prefix.prefix, sizeof(loc->prefix.prefix)); + stream_putc(s, loc->block_bits_length); + stream_putc(s, loc->node_bits_length); + stream_putc(s, loc->function_bits_length); + stream_putc(s, loc->argument_bits_length); + + stream_putl(s, loc->sids->count); + for (ALL_LIST_ELEMENTS_RO(loc->sids, node, sidtmp)) { + stream_putw(s, sidtmp->ipv6Addr.prefixlen); + stream_put(s, &sidtmp->ipv6Addr.prefix, + sizeof(sidtmp->ipv6Addr.prefix)); + stream_putl(s, sidtmp->sidaction); + stream_putw(s, strlen(sidtmp->vrfName)); + stream_put(s, sidtmp->vrfName, strlen(sidtmp->vrfName)); + } + + return 0; +} + static int zapi_nhg_encode(struct stream *s, int cmd, struct zapi_nhg *api_nhg) { int i; diff --git a/lib/zclient.h b/lib/zclient.h index 2877b347d8d0..7f09b474e8fb 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -570,6 +570,12 @@ struct zapi_route { */ #define ZEBRA_FLAG_OUTOFSYNC 0x400 +/* + * This flag lets us know that the route entry is set to bypass + * kernel for some reason (e.g. route-map, etc) + */ +#define ZEBRA_FLAG_KERNEL_BYPASS 0x800 + /* The older XXX_MESSAGE flags live here */ uint32_t message; @@ -1088,6 +1094,9 @@ extern struct interface *zebra_interface_link_params_read(struct stream *s, bool *changed); extern size_t zebra_interface_link_params_write(struct stream *, struct interface *); + +extern int zapi_srv6_locator_sid_encode(struct stream *s, + struct srv6_locator *loc); extern enum zclient_send_status zclient_send_get_label_chunk(struct zclient *zclient, uint8_t keep, uint32_t chunk_size, uint32_t base); diff --git a/lib/zebra.h b/lib/zebra.h index 15a54f6cdf61..87fcd9e0c083 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -226,6 +226,10 @@ struct in_pktinfo { #define strmatch(a,b) (!strcmp((a), (b))) +/* Zebra message flags */ + +#define ZEBRA_FLAG_LOCAL_SID_ROUTE 0x01 + #if BYTE_ORDER == LITTLE_ENDIAN #define htonll(x) (((uint64_t)htonl((x)&0xFFFFFFFF) << 32) | htonl((x) >> 32)) #define ntohll(x) (((uint64_t)ntohl((x)&0xFFFFFFFF) << 32) | ntohl((x) >> 32)) diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 2d80feef6c97..8bce8fc980d0 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -1329,6 +1329,12 @@ static struct cmd_node srv6_loc_node = { .prompt = "%s(config-srv6-locator)# ", }; +static struct cmd_node srv6_prefix_node = { + .name = "srv6-locator-prefix", + .node = SRV6_PREFIX_NODE, + .parent_node = SRV6_LOC_NODE, + .prompt = "%s(config-srv6-locator-prefix)# "}; + static struct cmd_node srv6_encap_node = { .name = "srv6-encap", .node = SRV6_ENCAP_NODE, @@ -1704,15 +1710,30 @@ DEFUNSH(VTYSH_ZEBRA, srv6_locators, srv6_locators_cmd, return CMD_SUCCESS; } -DEFUNSH(VTYSH_ZEBRA, srv6_locator, srv6_locator_cmd, - "locator WORD", - "Segment Routing SRv6 locator\n" +DEFUNSH(VTYSH_ZEBRA, srv6_locator_sid, srv6_locator_cmd, "locator WORD", + "Segment Routing SRv6 locators locator\n" "Specify locator-name\n") { vty->node = SRV6_LOC_NODE; return CMD_SUCCESS; } +DEFUNSH(VTYSH_ZEBRA, srv6_prefix_sid, srv6_prefix_cmd, + "prefix X:X::X:X/M$prefix \ + [block-len (16-64)$block_bit_len] [node-len (16-64)$node_bit_len] [func-bits (16-80)$func_bit_len]", + "Configure SRv6 locator prefix\n" + "Specify SRv6 locator prefix\n" + "Configure SRv6 locator block length in bits\n" + "Specify SRv6 locator block length in bits\n" + "Configure SRv6 locator node length in bits\n" + "Specify SRv6 locator node length in bits\n" + "Configure SRv6 locator function length in bits\n" + "Specify SRv6 locator function length in bits\n") +{ + vty->node = SRV6_PREFIX_NODE; + return CMD_SUCCESS; +} + DEFUNSH(VTYSH_ZEBRA, srv6_encap, srv6_encap_cmd, "encapsulation", "Segment Routing SRv6 encapsulation\n") @@ -2562,6 +2583,14 @@ DEFUNSH(VTYSH_ZEBRA, exit_srv6_loc_config, exit_srv6_loc_config_cmd, "exit", return CMD_SUCCESS; } +DEFUNSH(VTYSH_ZEBRA, exit_srv6_prefix_config, exit_srv6_prefix_config_cmd, + "exit", "Exit from SRv6-locators prefix configuration mode\n") +{ + if (vty->node == SRV6_PREFIX_NODE) + vty->node = SRV6_LOC_NODE; + return CMD_SUCCESS; +} + DEFUNSH(VTYSH_ZEBRA, exit_srv6_encap, exit_srv6_encap_cmd, "exit", "Exit from SRv6-encapsulation configuration mode\n") { @@ -5451,9 +5480,15 @@ void vtysh_init_vty(void) install_element(SRV6_LOCS_NODE, &exit_srv6_locs_config_cmd); install_element(SRV6_LOCS_NODE, &vtysh_end_all_cmd); + install_node(&srv6_loc_node); + install_element(SRV6_LOC_NODE, &srv6_prefix_cmd); install_element(SRV6_LOC_NODE, &exit_srv6_loc_config_cmd); install_element(SRV6_LOC_NODE, &vtysh_end_all_cmd); + install_node(&srv6_prefix_node); + install_element(SRV6_PREFIX_NODE, &exit_srv6_prefix_config_cmd); + install_element(SRV6_PREFIX_NODE, &vtysh_end_all_cmd); + install_element(SRV6_ENCAP_NODE, &exit_srv6_encap_cmd); install_element(SRV6_ENCAP_NODE, &vtysh_end_all_cmd); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index ddcb83cd8ce7..91fdf2d1b663 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -3137,6 +3137,22 @@ netlink_put_route_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx) { int cmd; const struct prefix *p = dplane_ctx_get_dest(ctx); + uint32_t flag, old_flag; + + flag = dplane_ctx_get_flags(ctx); + old_flag = dplane_ctx_get_old_flags(ctx); + + /* If new route is set kernel-bypass,we just return success + * unless old route is not kernel-bypass when update operation . + */ + if (CHECK_FLAG(flag, ZEBRA_FLAG_KERNEL_BYPASS)) { + if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_UPDATE && + !CHECK_FLAG(old_flag, ZEBRA_FLAG_KERNEL_BYPASS) && + !RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx))) + netlink_batch_add_msg( + bth, ctx, netlink_delroute_msg_encoder, true); + return FRR_NETLINK_SUCCESS; + } if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_DELETE) { cmd = RTM_DELROUTE; diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index 0bfcd518cade..c33f17247a56 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -305,6 +305,7 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx) { enum zebra_dplane_result res = ZEBRA_DPLANE_REQUEST_SUCCESS; uint32_t type, old_type; + uint32_t flag, old_flag; if (dplane_ctx_get_src(ctx) != NULL) { zlog_err("route add: IPv6 sourcedest routes unsupported!"); @@ -313,8 +314,22 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx) type = dplane_ctx_get_type(ctx); old_type = dplane_ctx_get_old_type(ctx); + flag = dplane_ctx_get_flags(ctx); + old_flag = dplane_ctx_get_old_flags(ctx); frr_with_privs(&zserv_privs) { + /* If new route is set kernel-bypass,we just return success + * unless old route is not kernel-bypass when update operation. + */ + if (!CHECK_FLAG(flag, ZEBRA_FLAG_KERNEL_BYPASS)) { + if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_UPDATE && + !CHECK_FLAG(old_flag, ZEBRA_FLAG_KERNEL_BYPASS) && + !RSYSTEM_ROUTE(old_type)) + kernel_rtm(RTM_DELETE, dplane_ctx_get_dest(ctx), + dplane_ctx_get_old_ng(ctx), + dplane_ctx_get_old_metric(ctx)); + continue; + } if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_DELETE) { if (!RSYSTEM_ROUTE(type)) diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index aecbba2ebc5f..57554e8d0eb5 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -2774,6 +2774,42 @@ int zsend_client_close_notify(struct zserv *client, struct zserv *closed_client) return zserv_send_message(client, s); } +int zsend_srv6_manager_get_locator_sid_response(struct zserv *client, + vrf_id_t vrf_id, + struct srv6_locator *loc, + struct seg6_sid *sid) +{ + + struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); + + zclient_create_header(s, ZEBRA_SRV6_MANAGER_GET_LOCATOR_SID, vrf_id); + zapi_srv6_locator_sid_encode(s, loc); + stream_putw_at(s, 0, stream_get_endp(s)); + return zserv_send_message(client, s); +} + +int zsend_srv6_manager_del_sid(struct zserv *client, vrf_id_t vrf_id, + struct srv6_locator *loc, struct seg6_sid *sid) +{ + + struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); + + zclient_create_header(s, ZEBRA_SRV6_MANAGER_RELEASE_LOCATOR_SID, + vrf_id); + + stream_putw(s, strlen(loc->name)); + stream_put(s, loc->name, strlen(loc->name)); + + stream_putl(s, 1); + stream_putw(s, sid->ipv6Addr.prefixlen); + stream_put(s, &sid->ipv6Addr.prefix, sizeof(sid->ipv6Addr.prefix)); + stream_putl(s, sid->sidaction); + stream_putw(s, strlen(sid->vrfName)); + stream_put(s, sid->vrfName, strlen(sid->vrfName)); + stream_putw_at(s, 0, stream_get_endp(s)); + return zserv_send_message(client, s); +} + int zsend_srv6_manager_get_locator_chunk_response(struct zserv *client, vrf_id_t vrf_id, struct srv6_locator *loc) @@ -3137,6 +3173,36 @@ static void zread_srv6_manager_get_locator(struct zserv *client, return; } +static void zread_srv6_manager_get_locator_sid(struct zserv *client, + struct stream *msg, + vrf_id_t vrf_id) +{ + struct stream *s = msg; + uint16_t len; + char locator_name[SRV6_LOCNAME_SIZE] = {0}; + + /* Get data. */ + STREAM_GETW(s, len); + STREAM_GET(locator_name, s, len); + + /* call hook to get a chunk using wrapper */ + struct srv6_locator *loc = NULL; + srv6_manager_get_locator_sid_call(&loc, client, locator_name, vrf_id); + +stream_failure: + return; +} + +static void zread_srv6_manager_get_locator_all(struct zserv *client, + struct stream *msg, + vrf_id_t vrf_id) +{ + /* call hook to get a chunk using wrapper */ + srv6_manager_get_locator_all_call(client, vrf_id); + + return; +} + static void zread_srv6_manager_request(ZAPI_HANDLER_ARGS) { switch (hdr->command) { diff --git a/zebra/zapi_msg.h b/zebra/zapi_msg.h index a59ccc838b97..ee4a9bb456d5 100644 --- a/zebra/zapi_msg.h +++ b/zebra/zapi_msg.h @@ -118,6 +118,14 @@ extern int zsend_srv6_manager_get_locator_chunk_response(struct zserv *client, extern int zsend_srv6_manager_get_locator_response(struct zserv *client, struct srv6_locator *locator); +extern int zsend_srv6_manager_get_locator_sid_response(struct zserv *client, + vrf_id_t vrf_id, + struct srv6_locator *loc, + struct seg6_sid *sid); +extern int zsend_srv6_manager_del_sid(struct zserv *client, vrf_id_t vrf_id, + struct srv6_locator *loc, + struct seg6_sid *sid); + #ifdef __cplusplus } #endif diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 75147e713649..ce23d268ec6e 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -116,6 +116,8 @@ struct dplane_route_info { int zd_type; int zd_old_type; + int zd_old_flag; + route_tag_t zd_tag; route_tag_t zd_old_tag; uint32_t zd_metric; @@ -1849,6 +1851,18 @@ int dplane_ctx_get_old_type(const struct zebra_dplane_ctx *ctx) return ctx->u.rinfo.zd_old_type; } +int dplane_ctx_get_old_flags(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.rinfo.zd_old_flag; +} +void dplane_ctx_set_old_flags(struct zebra_dplane_ctx *ctx, uint32_t flags) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.rinfo.zd_old_flag = flags; +} void dplane_ctx_set_afi(struct zebra_dplane_ctx *ctx, afi_t afi) { DPLANE_CTX_VALID(ctx); @@ -1946,7 +1960,6 @@ void dplane_ctx_set_flags(struct zebra_dplane_ctx *ctx, uint32_t flags) ctx->u.rinfo.zd_flags = flags; } - uint32_t dplane_ctx_get_metric(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); @@ -2484,6 +2497,13 @@ int dplane_ctx_get_pw_status(const struct zebra_dplane_ctx *ctx) return ctx->u.pw.status; } +int dplane_ctx_get_old_flag(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.rinfo.zd_old_flag; +} + void dplane_ctx_set_pw_status(struct zebra_dplane_ctx *ctx, int status) { DPLANE_CTX_VALID(ctx); @@ -4244,6 +4264,9 @@ dplane_route_update_internal(struct route_node *rn, enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE; int ret = EINVAL; struct zebra_dplane_ctx *ctx = NULL; + struct nexthop *nexthop, *old_nexthop; + uint32_t flags = 0; + uint32_t old_flags = 0; /* Obtain context block */ ctx = dplane_ctx_alloc(); @@ -4251,11 +4274,34 @@ dplane_route_update_internal(struct route_node *rn, /* Init context with info from zebra data structs */ ret = dplane_ctx_route_init(ctx, op, rn, re); if (ret == AOK) { + nexthop = re->nhe->nhg.nexthop; + flags = re->flags; + if (CHECK_FLAG(re->flags, ZEBRA_FLAG_LOCAL_SID_ROUTE)) { + SET_FLAG(flags, ZEBRA_FLAG_KERNEL_BYPASS); + } + dplane_ctx_set_flags(ctx, flags); + nexthop = re->nhe->nhg.nexthop; + flags = re->flags; + if (nexthop && nexthop->nh_srv6) { + SET_FLAG(flags, ZEBRA_FLAG_KERNEL_BYPASS); + } + dplane_ctx_set_flags(ctx, flags); /* Capture some extra info for update case * where there's a different 'old' route. */ if ((op == DPLANE_OP_ROUTE_UPDATE) && old_re && (old_re != re)) { + old_nexthop = old_re->nhe->nhg.nexthop; + old_flags = old_re->flags; + /* Assign ZEBRA_FLAG_KERNEL_BYPASS to dplane route info + */ + if (CHECK_FLAG(old_re->flags, + ZEBRA_FLAG_LOCAL_SID_ROUTE)) { + SET_FLAG(old_flags, ZEBRA_FLAG_KERNEL_BYPASS); + } + dplane_ctx_set_old_flags(ctx, old_flags); + ctx->zd_is_update = true; + old_re->dplane_sequence = zebra_router_get_next_sequence(); diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index 0e9a8bfb99f5..ff6fcc4d87b7 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -510,6 +510,8 @@ void dplane_ctx_set_instance(struct zebra_dplane_ctx *ctx, uint16_t instance); uint16_t dplane_ctx_get_old_instance(const struct zebra_dplane_ctx *ctx); uint32_t dplane_ctx_get_flags(const struct zebra_dplane_ctx *ctx); void dplane_ctx_set_flags(struct zebra_dplane_ctx *ctx, uint32_t flags); +int dplane_ctx_get_old_flags(const struct zebra_dplane_ctx *ctx); +void dplane_ctx_set_old_flags(struct zebra_dplane_ctx *ctx, uint32_t flags); uint32_t dplane_ctx_get_metric(const struct zebra_dplane_ctx *ctx); uint32_t dplane_ctx_get_old_metric(const struct zebra_dplane_ctx *ctx); uint32_t dplane_ctx_get_mtu(const struct zebra_dplane_ctx *ctx); diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c index 95207ce75cb2..cc478a505a92 100644 --- a/zebra/zebra_fpm_netlink.c +++ b/zebra/zebra_fpm_netlink.c @@ -264,6 +264,8 @@ static int netlink_route_info_fill(struct netlink_route_info *ri, int cmd, ri->nlmsg_pid = pid; ri->nlmsg_type = cmd; + // ri->rtm_table = table_info->table_id; + ri->rtm_table = zvrf_id(rib_dest_vrf(dest)); ri->rtm_protocol = RTPROT_UNSPEC; /* diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c index 082d4609aacd..68db2f25b162 100644 --- a/zebra/zebra_srv6.c +++ b/zebra/zebra_srv6.c @@ -96,6 +96,19 @@ void srv6_manager_release_locator_chunk_call(struct zserv *client, hook_call(srv6_manager_release_chunk, client, locator_name, vrf_id); } +void srv6_manager_get_locator_sid_call(struct srv6_locator **loc, + struct zserv *client, + const char *locator_name, + vrf_id_t vrf_id) +{ + hook_call(srv6_manager_get_sid, loc, client, locator_name, vrf_id); +} + +void srv6_manager_get_locator_all_call(struct zserv *client, vrf_id_t vrf_id) +{ + hook_call(srv6_manager_get_locator_sid_all, client, vrf_id); +} + int srv6_manager_client_disconnect_cb(struct zserv *client) { hook_call(srv6_manager_client_disconnect, client); @@ -626,30 +639,133 @@ void zebra_srv6_locator_add(struct srv6_locator *locator) zsend_zebra_srv6_locator_add(client, locator); } +void zebra_srv6_prefix_delete(struct srv6_locator *locator) +{ + struct listnode *n, *nnode; + struct srv6_locator_chunk *c; + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct seg6_sid *sid = NULL; + struct zserv *client; + struct listnode *client_node; + + for (ALL_LIST_ELEMENTS(locator->sids, n, nnode, sid)) { + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, client_node, + client)) { + + zsend_srv6_manager_del_sid(client, VRF_DEFAULT, locator, + sid); + } + zebra_srv6_local_sid_del(locator, sid); + listnode_delete(locator->sids, sid); + srv6_locator_sid_free(sid); + } + + memset(&locator->prefix, 0, sizeof(struct prefix_ipv6)); + locator->block_bits_length = 0; + locator->node_bits_length = 0; + locator->function_bits_length = 0; + locator->argument_bits_length = 0; + + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, client_node, client)) + zsend_zebra_srv6_locator_delete(client, locator); + + locator->status_up = false; +} + void zebra_srv6_locator_delete(struct srv6_locator *locator) { - struct listnode *n; + struct listnode *n, *nnode; + struct srv6_locator_chunk *c; struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct seg6_sid *sid = NULL; struct zserv *client; + struct listnode *client_node; - /* - * Notify deleted locator info to zclients if needed. - * - * zclient(bgpd,isisd,etc) allocates a sid from srv6 locator chunk and - * uses it for its own purpose. For example, in the case of BGP L3VPN, - * the SID assigned to vpn unicast rib will be given. - * And when the locator is deleted by zserv(zebra), those SIDs need to - * be withdrawn. The zclient must initiate the withdrawal of the SIDs - * by ZEBRA_SRV6_LOCATOR_DELETE, and this notification is sent to the - * owner of each chunk. - */ - for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, n, client)) + for (ALL_LIST_ELEMENTS(locator->sids, n, nnode, sid)) { + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, client_node, + client)) { + + zsend_srv6_manager_del_sid(client, VRF_DEFAULT, locator, + sid); + } + zebra_srv6_local_sid_del(locator, sid); + listnode_delete(locator->sids, sid); + srv6_locator_sid_free(sid); + } + + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, client_node, client)) zsend_zebra_srv6_locator_delete(client, locator); listnode_delete(srv6->locators, locator); srv6_locator_free(locator); } + +extern bool zebra_srv6_local_sid_format_valid(struct srv6_locator *locator, + struct seg6_sid *sid) +{ + struct in6_addr result_sid = {0}; + uint16_t sid_masklen = 0; + combine_sid(locator, &sid->ipv6Addr.prefix, &result_sid); + + sid_masklen = locator->block_bits_length + locator->node_bits_length + + locator->function_bits_length; + // Logic is the same as la_vrf_impl::verify_srv6_endpoint + // addr_msb + // uint32_t addr_0 = result_sid.s6_addr32[0]; + uint32_t addr_1 = result_sid.s6_addr32[1]; + + // addr_lsb + uint32_t addr_2 = result_sid.s6_addr32[2]; + uint32_t addr_3 = result_sid.s6_addr32[3]; + + if (locator->format == SRV6_FORMAT_F1) { + if (sid_masklen == 128) { + // Verify that bits [39:0] are zero + if ((addr_2 & 0xff000000) == 0 && + (addr_3 & 0xffffffff) == 0) { + return true; + } + } + return false; + } + + if (locator->format != SRV6_FORMAT_USID_3216) { + return false; + } + + // Check for valid prefix lengths. /48, /64, /80. + if (sid_masklen == 48) { + // Make sure that bits [95:80] are not zero. + if ((addr_1 & 0xffff) != 0) { + return true; + } + return false; + } + + if (sid_masklen == 64) { + // Make sure that bits [79:64] are not zero. + if ((addr_1 & 0xffff0000) != 0) { + return true; + } + return false; + } + + if (sid_masklen == 80) { + // WLIB format + // Make sure that [79:64] == 0xfff_0xxx + if ((addr_1 & 0xf8ff0000) != 0xf0ff0000) { + return false; + } + // Make sure that bits [63:48] are not zero. + if ((addr_2 & 0xffff) != 0) { + return true; + } + } + + return false; +} + struct srv6_locator *zebra_srv6_locator_lookup(const char *name) { struct zebra_srv6 *srv6 = zebra_srv6_get_default(); @@ -788,6 +904,232 @@ assign_srv6_locator_chunk(uint8_t proto, return loc; } +extern bool zebra_srv6_local_sid_get_format(struct srv6_locator *locator) +{ + // Logic is the same as sai_srv6_handler::get_la_sid_format + if (locator->block_bits_length == 32 && + locator->node_bits_length == 16 && + locator->function_bits_length == 0) { + // prefix len = 48 + locator->format = SRV6_FORMAT_USID_3216; + return true; + } else if (locator->block_bits_length == 32 && + locator->node_bits_length == 0 && + locator->function_bits_length == 16) { + // prefix len = 48 + locator->format = SRV6_FORMAT_USID_3216; + return true; + } else if (locator->block_bits_length == 32 && + locator->node_bits_length == 16 && + locator->function_bits_length == 16) { + // prefix len = 64 + locator->format = SRV6_FORMAT_USID_3216; + return true; + } else if (locator->block_bits_length == 32 && + locator->node_bits_length == 16 && + locator->function_bits_length == 32) { + // prefix len = 80 + locator->format = SRV6_FORMAT_USID_3216; + return true; + } else if (locator->block_bits_length == 40 && + locator->node_bits_length == 24 && + locator->function_bits_length == 16 && + locator->argument_bits_length == 8) { + locator->format = SRV6_FORMAT_F1; + return true; + } + + return false; +} + +void zebra_srv6_local_sid_add(struct srv6_locator *locator, + struct seg6_sid *sid) +{ + enum seg6local_action_t act; + struct seg6local_context ctx = {}; + struct in6_addr result_sid = {0}; + struct vrf *vrf; + struct zebra_vrf *zvrf; + + combine_sid(locator, &sid->ipv6Addr.prefix, &result_sid); + + vrf = vrf_lookup_by_name(sid->vrfName); + if (!vrf) + return; + + zvrf = vrf->info; + ctx.table = zvrf->table_id; + act = sid->sidaction; + ctx.block_bits_length = locator->block_bits_length; + ctx.node_bits_length = locator->node_bits_length; + ctx.function_bits_length = locator->function_bits_length; + ctx.argument_bits_length = locator->argument_bits_length; + strncpy(ctx.vrfName, sid->vrfName, VRF_NAMSIZ + 1); + + if (CHECK_FLAG(vrf->status, VRF_ACTIVE)) { + zebra_route_add(&result_sid, vrf, act, &ctx); + } +} + +void zebra_srv6_local_sid_del(struct srv6_locator *locator, + struct seg6_sid *sid) +{ + enum seg6local_action_t act; + struct seg6local_context ctx = {}; + struct in6_addr result_sid = {0}; + struct vrf *vrf; + struct zebra_vrf *zvrf; + + combine_sid(locator, &sid->ipv6Addr.prefix, &result_sid); + + vrf = vrf_lookup_by_name(sid->vrfName); + if (!vrf) + return; + + zvrf = vrf->info; + ctx.table = zvrf->table_id; + ctx.block_bits_length = locator->block_bits_length; + ctx.node_bits_length = locator->node_bits_length; + ctx.function_bits_length = locator->function_bits_length; + ctx.argument_bits_length = locator->argument_bits_length; + act = sid->sidaction; + + zebra_route_del(&result_sid, vrf, act, &ctx); +} + +int zebra_route_add(struct in6_addr *result_sid, struct vrf *vrf, + enum seg6local_action_t act, struct seg6local_context *ctx) +{ + afi_t afi; + struct prefix_ipv6 *src_p = NULL; + struct route_entry *re; + struct nexthop_group *ng = NULL; + int ret = 0; + struct nhg_hash_entry nhe, *n; + struct zebra_vrf *zvrf; + struct vrf *def_vrf = NULL; + struct prefix p = {}; + struct nexthop *nexthop; + + p.family = AF_INET6; + p.prefixlen = ctx->block_bits_length + ctx->node_bits_length + + ctx->function_bits_length; + p.u.prefix6 = *result_sid; + + def_vrf = vrf_lookup_by_name(VRF_DEFAULT_NAME); + zvrf = zebra_vrf_lookup_by_id(def_vrf->vrf_id); + if (!zvrf) { + return ret; + } + + /* Allocate new route. */ + re = XCALLOC(MTYPE_RE, sizeof(struct route_entry)); + re->type = ZEBRA_ROUTE_STATIC; + re->instance = 0; + SET_FLAG(re->flags, ZEBRA_FLAG_ALLOW_RECURSION); + SET_FLAG(re->flags, ZEBRA_FLAG_LOCAL_SID_ROUTE); + SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); + re->uptime = monotime(NULL); + re->vrf_id = VRF_DEFAULT; + + re->table = zvrf->table_id; + + ng = nexthop_group_new(); + /* + * TBD should _all_ of the nexthop add operations use + * api_nh->vrf_id instead of re->vrf_id ? I only changed + * for cases NEXTHOP_TYPE_IPV4 and NEXTHOP_TYPE_IPV6. + */ + + /* Convert zapi nexthop */ + nexthop = nexthop_from_ifindex(vrf->vrf_id, 0); + + if (!nexthop) { + if (ng) + nexthop_group_delete(&ng); + return ret; + } + + zlog_debug("%s: adding seg6local action %s", __func__, + seg6local_action2str(act)); + + nexthop_add_srv6_seg6local(nexthop, act, ctx); + + if (ng) { + /* Add new nexthop to temporary list. This list is + * canonicalized - sorted - so that it can be hashed + * later in route processing. We expect that the sender + * has sent the list sorted, and the zapi client api + * attempts to enforce that, so this should be + * inexpensive - but it is necessary to support shared + * nexthop-groups. + */ + nexthop_group_add_sorted(ng, nexthop); + } + + afi = family2afi(AF_INET6); + + /* + * If we have an ID, this proto owns the NHG it sent along with the + * route, so we just send the ID into rib code with it. + * + * Havent figured out how to handle backup NHs with this yet, so lets + * keep that separate. + * Include backup info with the route. We use a temporary nhe here; + * if this is a new/unknown nhe, a new copy will be allocated + * and stored. + */ + if (!re->nhe_id) { + zebra_nhe_init(&nhe, afi, ng->nexthop); + nhe.nhg.nexthop = ng->nexthop; + } + + n = zebra_nhe_copy(&nhe, 0); + ret = rib_add_multipath_nhe(afi, SAFI_UNICAST, &p, src_p, re, n, false); + + /* At this point, these allocations are not needed: 're' has been + * retained or freed, and if 're' still exists, it is using + * a reference to a shared group object. + */ + nexthop_group_delete(&ng); + return ret; +} + +int zebra_route_del(struct in6_addr *result_sid, struct vrf *vrf, + enum seg6local_action_t act, struct seg6local_context *ctx) +{ + afi_t afi; + struct prefix_ipv6 *src_p = NULL; + uint32_t table_id; + struct zebra_vrf *zvrf; + struct vrf *def_vrf = NULL; + int ret = 0; + uint32_t flags = 0; + + struct prefix p = {}; + + p.family = AF_INET6; + p.prefixlen = ctx->block_bits_length + ctx->node_bits_length + + ctx->function_bits_length; + p.u.prefix6 = *result_sid; + + def_vrf = vrf_lookup_by_name(VRF_DEFAULT_NAME); + zvrf = zebra_vrf_lookup_by_id(def_vrf->vrf_id); + if (!zvrf) { + return ret; + } + + afi = family2afi(AF_INET6); + + table_id = zvrf->table_id; + SET_FLAG(flags, ZEBRA_FLAG_ALLOW_RECURSION); + SET_FLAG(flags, ZEBRA_FLAG_LOCAL_SID_ROUTE); + + rib_delete(afi, SAFI_UNICAST, zvrf_id(zvrf), ZEBRA_ROUTE_STATIC, 0, + flags, &p, src_p, NULL, 0, table_id, 0, 0, false); + return 0; +} + static int zebra_srv6_manager_get_locator_chunk(struct srv6_locator **loc, struct zserv *client, const char *locator_name, @@ -813,6 +1155,59 @@ static int zebra_srv6_manager_get_locator_chunk(struct srv6_locator **loc, return ret; } +/** + * Core function, assigns srv6-locator chunks + * + * It first searches through the list to check if there's one available + * (previously released). Otherwise it creates and assigns a new one + * + * @param proto Daemon protocol of client, to identify the owner + * @param instance Instance, to identify the owner + * @param session_id SessionID of client + * @param name Name of SRv6-locator + * @return Pointer to the assigned srv6-locator chunk, + * or NULL if the request could not be satisfied + */ +static int zebra_srv6_manager_get_locator_sid(struct srv6_locator **loc, + struct zserv *client, + const char *locator_name, + vrf_id_t vrf_id) +{ + int ret = 0; + + *loc = zebra_srv6_locator_lookup(locator_name); + + if (!*loc) + zlog_err("Unable to assign locator chunk to %s instance %u", + zebra_route_string(client->proto), client->instance); + else if (IS_ZEBRA_DEBUG_PACKET) + zlog_info("Assigned locator chunk %s to %s instance %u", + (*loc)->name, zebra_route_string(client->proto), + client->instance); + + if (*loc && (*loc)->status_up) + ret = zsend_srv6_manager_get_locator_sid_response( + client, vrf_id, *loc, NULL); + return ret; +} + +static int zebra_srv6_manager_get_locator_all(struct zserv *client, + vrf_id_t vrf_id) +{ + int ret = 0; + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct srv6_locator *locator; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO(srv6->locators, node, locator)) { + if (locator->status_up) + ret = zsend_srv6_manager_get_locator_sid_response( + client, vrf_id, locator, NULL); + } + + return ret; +} + /** * Core function, release no longer used srv6-locator chunks * @@ -872,6 +1267,28 @@ static int zebra_srv6_manager_release_locator_chunk(struct zserv *client, client->session_id, locator_name); } +/** + * Core function, release no longer used srv6-locator chunks + * + * @param proto Daemon protocol of client, to identify the owner + * @param instance Instance, to identify the owner + * @param session_id Zclient session ID, to identify the zclient session + * @param locator_name SRv6-locator name, to identify the actual locator + * @return 0 on success, -1 otherwise + */ +static int zebra_srv6_manager_release_locator_sid(struct zserv *client, + const char *locator_name, + vrf_id_t vrf_id) +{ + if (vrf_id != VRF_DEFAULT) { + zlog_err("SRv6 locator doesn't support vrf"); + return -1; + } + + return release_srv6_locator_chunk(client->proto, client->instance, + client->session_id, locator_name); +} + /** * Release srv6-locator chunks from a client. * @@ -2460,3 +2877,26 @@ bool zebra_srv6_is_enable(void) return listcount(srv6->locators); } + +int zebra_srv6_vrf_enable(struct zebra_vrf *zvrf) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct listnode *node, *opcodenode; + struct srv6_locator *locator; + struct seg6_sid *sid; + struct vrf *vrf; + + for (ALL_LIST_ELEMENTS_RO(srv6->locators, node, locator)) { + for (ALL_LIST_ELEMENTS_RO(locator->sids, opcodenode, sid)) { + if (sid->vrfName == NULL) + continue; + vrf = vrf_lookup_by_name(sid->vrfName); + if (zvrf->vrf != vrf) + continue; + if (CHECK_FLAG(vrf->status, VRF_ACTIVE)) { + zebra_srv6_local_sid_add(locator, sid); + } + } + } + return 0; +} \ No newline at end of file diff --git a/zebra/zebra_srv6.h b/zebra/zebra_srv6.h index 1599fd7adfbd..f8404b3afbf1 100644 --- a/zebra/zebra_srv6.h +++ b/zebra/zebra_srv6.h @@ -245,10 +245,22 @@ DECLARE_HOOK(srv6_manager_get_locator, extern void zebra_srv6_locator_add(struct srv6_locator *locator); extern void zebra_srv6_locator_delete(struct srv6_locator *locator); +extern void zebra_srv6_prefix_delete(struct srv6_locator *locator); extern struct srv6_locator *zebra_srv6_locator_lookup(const char *name); +extern int zebra_route_add(struct in6_addr *result_sid, struct vrf *vrf, + enum seg6local_action_t act, + struct seg6local_context *ctx); +extern int zebra_route_del(struct in6_addr *result_sid, struct vrf *vrf, + enum seg6local_action_t act, + struct seg6local_context *ctx); + void zebra_notify_srv6_locator_add(struct srv6_locator *locator); void zebra_notify_srv6_locator_delete(struct srv6_locator *locator); +extern void zebra_srv6_local_sid_add(struct srv6_locator *locator, + struct seg6_sid *sid); +extern void zebra_srv6_local_sid_del(struct srv6_locator *locator, + struct seg6_sid *sid); extern void zebra_srv6_init(void); extern void zebra_srv6_terminate(void); @@ -264,8 +276,23 @@ extern void srv6_manager_get_locator_chunk_call(struct srv6_locator **loc, extern void srv6_manager_release_locator_chunk_call(struct zserv *client, const char *locator_name, vrf_id_t vrf_id); + +extern void srv6_manager_release_locator_sid_call(struct zserv *client, + const char *locator_name, + vrf_id_t vrf_id); +extern void srv6_manager_get_locator_sid_call(struct srv6_locator **loc, + struct zserv *client, + const char *locator_name, + vrf_id_t vrf_id); +extern void srv6_manager_get_locator_all_call(struct zserv *client, + vrf_id_t vrf_id); + extern int srv6_manager_client_disconnect_cb(struct zserv *client); +extern bool zebra_srv6_local_sid_format_valid(struct srv6_locator *locator, + struct seg6_sid *sid); extern int release_daemon_srv6_locator_chunks(struct zserv *client); +extern bool zebra_srv6_local_sid_get_format(struct srv6_locator *locator); +extern int zebra_srv6_vrf_enable(struct zebra_vrf *zvrf); extern void zebra_srv6_encap_src_addr_set(struct in6_addr *src_addr); extern void zebra_srv6_encap_src_addr_unset(void); diff --git a/zebra/zebra_srv6_vty.c b/zebra/zebra_srv6_vty.c index 5a8052414902..563b44654457 100644 --- a/zebra/zebra_srv6_vty.c +++ b/zebra/zebra_srv6_vty.c @@ -26,6 +26,7 @@ #include "zebra/redistribute.h" #include "zebra/zebra_routemap.h" #include "zebra/zebra_dplane.h" +#include "zebra/zapi_msg.h" #include "zebra/zebra_srv6_vty_clippy.c" @@ -61,6 +62,70 @@ static struct cmd_node srv6_loc_node = { .prompt = "%s(config-srv6-locator)# " }; +static struct cmd_node srv6_prefix_node = { + .name = "srv6-locator-prefix", + .node = SRV6_PREFIX_NODE, + .parent_node = SRV6_LOC_NODE, + .prompt = "%s(config-srv6-locator-prefix)# "}; + +static bool seg6local_act_contain_sidact(enum seg6local_action_t action, + enum seg6local_action_t sidaction) +{ + switch (action) { + case ZEBRA_SEG6_LOCAL_ACTION_END: + case ZEBRA_SEG6_LOCAL_ACTION_END_T: + case ZEBRA_SEG6_LOCAL_ACTION_END_DX2: + case ZEBRA_SEG6_LOCAL_ACTION_END_DX6: + case ZEBRA_SEG6_LOCAL_ACTION_END_DX4: + case ZEBRA_SEG6_LOCAL_ACTION_END_B6: + case ZEBRA_SEG6_LOCAL_ACTION_END_B6_ENCAP: + case ZEBRA_SEG6_LOCAL_ACTION_END_BM: + case ZEBRA_SEG6_LOCAL_ACTION_END_S: + case ZEBRA_SEG6_LOCAL_ACTION_END_AS: + case ZEBRA_SEG6_LOCAL_ACTION_END_AM: + if (action == sidaction) + return true; + break; + case ZEBRA_SEG6_LOCAL_ACTION_END_DT46: + if (sidaction == ZEBRA_SEG6_LOCAL_ACTION_END_DT4 || + sidaction == ZEBRA_SEG6_LOCAL_ACTION_END_DT6 || + sidaction == ZEBRA_SEG6_LOCAL_ACTION_END_DT46) + return true; + break; + case ZEBRA_SEG6_LOCAL_ACTION_END_DT4: + if (sidaction == ZEBRA_SEG6_LOCAL_ACTION_END_DT4 || + sidaction == ZEBRA_SEG6_LOCAL_ACTION_END_DT46) + return true; + break; + case ZEBRA_SEG6_LOCAL_ACTION_END_DT6: + if (sidaction == ZEBRA_SEG6_LOCAL_ACTION_END_DT46 || + sidaction == ZEBRA_SEG6_LOCAL_ACTION_END_DT6) + return true; + break; + default: + return false; + } + return false; +} + +static struct seg6_sid * +sid_lookup_by_vrf_action(struct srv6_locator *loc, const char *vrfname, + enum seg6local_action_t sidaction) +{ + struct seg6_sid *sid = NULL; + struct listnode *node, *nnode; + + if (!vrfname) + return NULL; + + for (ALL_LIST_ELEMENTS(loc->sids, node, nnode, sid)) { + if (strcmp(sid->vrfName, vrfname) == 0 && + seg6local_act_contain_sidact(sid->sidaction, sidaction)) + return sid; + } + return NULL; +} + static struct cmd_node srv6_encap_node = { .name = "srv6-encap", .node = SRV6_ENCAP_NODE, @@ -195,7 +260,10 @@ DEFUN (show_srv6_locator_detail, struct zebra_srv6 *srv6 = zebra_srv6_get_default(); struct srv6_locator *locator; struct listnode *node; + struct listnode *sidnode; + struct seg6_sid *sid = NULL; char str[256]; + char buf[256]; const char *locator_name = argv[4]->arg; json_object *json_locator = NULL; @@ -253,6 +321,14 @@ DEFUN (show_srv6_locator_detail, vty_out(vty, "- prefix: %s, owner: %s\n", str, zebra_route_string(chunk->proto)); } + vty_out(vty, " sids:\n"); + for (ALL_LIST_ELEMENTS_RO(locator->sids, sidnode, sid)) { + prefix2str(&sid->ipv6Addr, buf, sizeof(buf)); + vty_out(vty, " -opcode %s\n", buf); + vty_out(vty, " sidaction %s\n", + seg6local_action2str(sid->sidaction)); + vty_out(vty, " vrf %s\n", sid->vrfName); + } } @@ -322,18 +398,17 @@ DEFUN_NOSH (srv6_locators, return CMD_SUCCESS; } -DEFUN_NOSH (srv6_locator, - srv6_locator_cmd, - "locator WORD", - "Segment Routing SRv6 locator\n" - "Specify locator-name\n") +DEFUN_NOSH(srv6_locator_sid, + srv6_locator_cmd, + "locator WORD", + "Segment Routing SRv6 locators locator\n" + "Specify locator-name\n") { - struct srv6_locator *locator = NULL; - - locator = zebra_srv6_locator_lookup(argv[1]->arg); + struct srv6_locator *locator = zebra_srv6_locator_lookup(argv[1]->arg); if (locator) { VTY_PUSH_CONTEXT(SRV6_LOC_NODE, locator); - locator->status_up = true; + + vty->node = SRV6_LOC_NODE; return CMD_SUCCESS; } @@ -342,123 +417,71 @@ DEFUN_NOSH (srv6_locator, vty_out(vty, "%% Alloc failed\n"); return CMD_WARNING_CONFIG_FAILED; } - locator->status_up = true; + zebra_srv6_locator_add(locator); VTY_PUSH_CONTEXT(SRV6_LOC_NODE, locator); vty->node = SRV6_LOC_NODE; return CMD_SUCCESS; } -DEFUN (no_srv6_locator, - no_srv6_locator_cmd, - "no locator WORD", - NO_STR - "Segment Routing SRv6 locator\n" - "Specify locator-name\n") +DEFUN_NOSH(srv6_prefix_sid, srv6_prefix_cmd, + "prefix X:X::X:X/M$prefix \ + [block-len (16-64)$block_bit_len] [node-len (16-64)$node_bit_len] [func-bits (16-80)$func_bit_len]", + "Configure SRv6 locator prefix\n" + "Specify SRv6 locator prefix\n" + "Configure SRv6 locator block length in bits\n" + "Specify SRv6 locator block length in bits\n" + "Configure SRv6 locator node length in bits\n" + "Specify SRv6 locator node length in bits\n" + "Configure SRv6 locator function length in bits\n" + "Specify SRv6 locator function length in bits\n") { - struct zebra_srv6 *srv6 = zebra_srv6_get_default(); - struct zebra_srv6_sid_block *block; - struct listnode *node, *nnode; - struct zebra_srv6_sid_ctx *ctx; - struct srv6_locator *locator = zebra_srv6_locator_lookup(argv[2]->arg); - if (!locator) { - vty_out(vty, "%% Can't find SRv6 locator\n"); + VTY_DECLVAR_CONTEXT(srv6_locator, locator_sid); + char *prefix = NULL; + int ret = 0; + int idx = 0; + int block_bit_len = 0; + int node_bit_len = 0; + int func_bit_len = 0; + int args_bit_len = 0; + + prefix = argv[1]->arg; + ret = str2prefix_ipv6(prefix, &locator_sid->prefix); + apply_mask_ipv6(&locator_sid->prefix); + if (!ret) { + vty_out(vty, "Malformed IPv6 prefix\n"); return CMD_WARNING_CONFIG_FAILED; } - for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, ctx)) { - if (!ctx->sid || ctx->sid->locator != locator) - continue; - - if (ctx->sid) - zebra_srv6_sid_free(ctx->sid); - - listnode_delete(srv6->sids, ctx); - zebra_srv6_sid_ctx_free(ctx); + if (argv_find(argv, argc, "block-len", &idx)) { + block_bit_len = strtoul(argv[idx + 1]->arg, NULL, 10); } - - block = locator->sid_block; - if (block) { - block->refcnt--; - if (block->refcnt == 0) { - listnode_delete(srv6->sid_blocks, block); - zebra_srv6_sid_block_free(block); - } - locator->sid_block = NULL; + if (argv_find(argv, argc, "node-len", &idx)) { + node_bit_len = strtoul(argv[idx + 1]->arg, NULL, 10); } - - zebra_srv6_locator_delete(locator); - return CMD_SUCCESS; -} - -DEFPY (locator_prefix, - locator_prefix_cmd, - "prefix X:X::X:X/M$prefix [block-len (16-64)$block_bit_len] \ - [node-len (16-64)$node_bit_len] [func-bits (0-64)$func_bit_len]", - "Configure SRv6 locator prefix\n" - "Specify SRv6 locator prefix\n" - "Configure SRv6 locator block length in bits\n" - "Specify SRv6 locator block length in bits\n" - "Configure SRv6 locator node length in bits\n" - "Specify SRv6 locator node length in bits\n" - "Configure SRv6 locator function length in bits\n" - "Specify SRv6 locator function length in bits\n") -{ - VTY_DECLVAR_CONTEXT(srv6_locator, locator); - struct srv6_locator_chunk *chunk = NULL; - struct listnode *node = NULL; - uint8_t expected_prefixlen; - struct srv6_sid_format *format; - - locator->prefix = *prefix; - func_bit_len = func_bit_len ?: ZEBRA_SRV6_FUNCTION_LENGTH; - - expected_prefixlen = prefix->prefixlen; - format = locator->sid_format; - if (format) { - if (strmatch(format->name, SRV6_SID_FORMAT_USID_F3216_NAME)) - expected_prefixlen = - SRV6_SID_FORMAT_USID_F3216_BLOCK_LEN + - SRV6_SID_FORMAT_USID_F3216_NODE_LEN; - else if (strmatch(format->name, - SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME)) - expected_prefixlen = - SRV6_SID_FORMAT_UNCOMPRESSED_F4024_BLOCK_LEN + - SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE_LEN; + if (argv_find(argv, argc, "func-bits", &idx)) { + func_bit_len = strtoul(argv[idx + 1]->arg, NULL, 10); } + args_bit_len = 128 - (block_bit_len + node_bit_len + func_bit_len); - if (prefix->prefixlen != expected_prefixlen) { - vty_out(vty, - "%% Locator prefix length '%u' inconsistent with configured format '%s'. Please either use a prefix length that is consistent with the format or change the format.\n", - prefix->prefixlen, format->name); - return CMD_WARNING_CONFIG_FAILED; - } - /* Resolve optional arguments */ if (block_bit_len == 0 && node_bit_len == 0) { - block_bit_len = prefix->prefixlen - - ZEBRA_SRV6_LOCATOR_NODE_LENGTH; - node_bit_len = ZEBRA_SRV6_LOCATOR_NODE_LENGTH; + block_bit_len = block_bit_len + ? block_bit_len + : locator_sid->prefix.prefixlen - 24; + node_bit_len = node_bit_len ? node_bit_len : 24; } else if (block_bit_len == 0) { - block_bit_len = prefix->prefixlen - node_bit_len; + block_bit_len = locator_sid->prefix.prefixlen - node_bit_len; } else if (node_bit_len == 0) { - node_bit_len = prefix->prefixlen - block_bit_len; + node_bit_len = locator_sid->prefix.prefixlen - block_bit_len; } else { - if (block_bit_len + node_bit_len != prefix->prefixlen) { + if (block_bit_len + node_bit_len != + locator_sid->prefix.prefixlen) { vty_out(vty, - "%% block-len + node-len must be equal to the selected prefix length %d\n", - prefix->prefixlen); + "%% block-bits + node-bits must be equal to the prefix length\n"); return CMD_WARNING_CONFIG_FAILED; } } - - if (prefix->prefixlen + func_bit_len + 0 > 128) { - vty_out(vty, - "%% prefix-len + function-len + arg-len (%ld) cannot be greater than 128\n", - prefix->prefixlen + func_bit_len + 0); - return CMD_WARNING_CONFIG_FAILED; - } - /* * Currently, the SID transposition algorithm implemented in bgpd * handles incorrectly the SRv6 locators with function length greater @@ -472,11 +495,30 @@ DEFPY (locator_prefix, return CMD_WARNING_CONFIG_FAILED; } - locator->block_bits_length = block_bit_len; - locator->node_bits_length = node_bit_len; - locator->function_bits_length = func_bit_len; - locator->argument_bits_length = 0; + /* + * TODO(slankdev): please support variable node-bit-length. + * In draft-ietf-bess-srv6-services-05#section-3.2.1. + * Locator block length and Locator node length are defined. + * Which are defined as "locator-len == block-len + node-len". + * In current implementation, node bits length is hardcoded as 24. + * It should be supported various val. + * + * Cisco IOS-XR support only following pattern. + * (1) Teh locator length should be 64-bits long. + * (2) The SID block portion (MSBs) cannot exceed 40 bits. + * If this value is less than 40 bits, + * user should use a pattern of zeros as a filler. + * (3) The Node Id portion (LSBs) cannot exceed 24 bits. + */ + locator_sid->block_bits_length = block_bit_len; + locator_sid->node_bits_length = node_bit_len; + locator_sid->function_bits_length = func_bit_len; + locator_sid->argument_bits_length = args_bit_len; + if (!zebra_srv6_local_sid_get_format(locator_sid)) { + vty_out(vty, "%% Malformed locator sid format\n"); + return CMD_WARNING_CONFIG_FAILED; + } if (list_isempty(locator->chunks)) { chunk = srv6_locator_chunk_alloc(); chunk->prefix = *prefix; @@ -510,9 +552,12 @@ DEFPY (locator_prefix, zebra_srv6_locator_format_set(locator, locator->sid_format); + locator_sid->status_up = true; + VTY_PUSH_CONTEXT(SRV6_PREFIX_NODE, locator_sid); + vty->node = SRV6_PREFIX_NODE; + return CMD_SUCCESS; } - DEFPY (locator_behavior, locator_behavior_cmd, "[no] behavior usid", @@ -546,7 +591,6 @@ DEFPY (locator_behavior, return CMD_SUCCESS; } - DEFPY(locator_sid_format, locator_sid_format_cmd, "format $format", @@ -945,13 +989,207 @@ DEFPY(no_srv6_sid_format_explicit, return CMD_SUCCESS; } +DEFUN(no_srv6_prefix_sid, + no_srv6_prefix_cmd, + "no prefix", + NO_STR + "Segment Routing SRv6 locator prefix\n") +{ + VTY_DECLVAR_CONTEXT(srv6_locator, locator); + + zebra_srv6_prefix_delete(locator); + return CMD_SUCCESS; +} + +DEFUN(no_srv6_locator_sid, + no_srv6_locator_cmd, + "no locator WORD", + NO_STR + "Segment Routing SRv6 locator\n" + "Specify locator-name\n") +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct zebra_srv6_sid_block *block; + struct listnode *node, *nnode; + struct zebra_srv6_sid_ctx *ctx; + struct srv6_locator *locator = zebra_srv6_locator_lookup(argv[2]->arg); + if (!locator) { + vty_out(vty, "%% Can't find SRv6 locator\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, ctx)) { + if (!ctx->sid || ctx->sid->locator != locator) + continue; + + if (ctx->sid) + zebra_srv6_sid_free(ctx->sid); + + listnode_delete(srv6->sids, ctx); + zebra_srv6_sid_ctx_free(ctx); + } + + block = locator->sid_block; + if (block) { + block->refcnt--; + if (block->refcnt == 0) { + listnode_delete(srv6->sid_blocks, block); + zebra_srv6_sid_block_free(block); + } + locator->sid_block = NULL; + } + + zebra_srv6_locator_delete(locator); + return CMD_SUCCESS; +} + +DEFPY(locator_prefix, locator_prefix_cmd, + "opcode WORD ", + "Configure SRv6 locator prefix\n" + "Specify SRv6 locator hex opcode\n" + "Apply the code to an End SID\n" + "Apply the code to an End.DT46 SID\n" + "vrf\n" + "vrf\n" + "Apply the code to an End.DT4 SID\n" + "vrf\n" + "vrf\n" + "Apply the code to an End.DT6 SID\n" + "vrf\n" + "vrf\n") +{ + VTY_DECLVAR_CONTEXT(srv6_locator, locator); + struct seg6_sid *sid = NULL; + struct listnode *node = NULL; + enum seg6local_action_t sidaction = ZEBRA_SEG6_LOCAL_ACTION_UNSPEC; + int idx = 0; + char *vrfName = VRF_DEFAULT_NAME; + char *prefix = NULL; + int ret = 0; + struct prefix_ipv6 ipv6prefix = {0}; + struct in6_addr nexthop = {}; + struct zserv *client; + struct listnode *client_node; + struct vrf *vrf = NULL; + + if (!locator->status_up) { + vty_out(vty, "Missing valid prefix.\n"); + return CMD_WARNING; + } + if (argv_find(argv, argc, "end", &idx)) + sidaction = ZEBRA_SEG6_LOCAL_ACTION_END; + else if (argv_find(argv, argc, "end-dt46", &idx)) { + sidaction = ZEBRA_SEG6_LOCAL_ACTION_END_DT46; + vrfName = argv[idx + 2]->arg; + } else if (argv_find(argv, argc, "end-dt4", &idx)) { + sidaction = ZEBRA_SEG6_LOCAL_ACTION_END_DT4; + vrfName = argv[idx + 2]->arg; + } else if (argv_find(argv, argc, "end-dt6", &idx)) { + sidaction = ZEBRA_SEG6_LOCAL_ACTION_END_DT6; + vrfName = argv[idx + 2]->arg; + } + prefix = argv[1]->arg; + ret = str2prefix_ipv6(prefix, &ipv6prefix); + apply_mask_ipv6(&ipv6prefix); + if (!ret) { + vty_out(vty, "Malformed IPv6 prefix\n"); + return CMD_WARNING_CONFIG_FAILED; + } + for (ALL_LIST_ELEMENTS_RO(locator->sids, node, sid)) { + if (IPV6_ADDR_SAME(&sid->ipv6Addr.prefix, &ipv6prefix.prefix)) { + vty_out(vty, + "Prefix %s is already exist,please delete it first. \n", + argv[1]->arg); + return CMD_WARNING; + } + } + + sid = sid_lookup_by_vrf_action(locator, vrfName, sidaction); + if (sid) { + vty_out(vty, + "VRF %s is already exist,please delete it first. \n", + vrfName); + return CMD_WARNING; + } + + sid = srv6_locator_sid_alloc(); + sid->sidaction = sidaction; + + if (vrfName != NULL) + strlcpy(sid->vrfName, vrfName, VRF_NAMSIZ); + + sid->ipv6Addr = ipv6prefix; + strncpy(sid->sidstr, prefix, PREFIX_STRLEN); + + sid->ifname[0] = '\0'; + memcpy(&sid->nexthop, &nexthop, sizeof(struct in6_addr)); + if (!zebra_srv6_local_sid_format_valid(locator, sid)) { + vty_out(vty, "%% Malformed locator sid opcode format\n"); + srv6_locator_sid_free(sid); + return CMD_WARNING_CONFIG_FAILED; + } + + listnode_add(locator->sids, sid); + zebra_srv6_local_sid_add(locator, sid); + + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, client_node, client)) { + + zsend_srv6_manager_get_locator_sid_response(client, VRF_DEFAULT, + locator, sid); + } + return CMD_SUCCESS; +} + +DEFPY(no_locator_prefix, + no_locator_prefix_cmd, + "no opcode WORD", + NO_STR + "Configure SRv6 locator prefix\n" + "Specify SRv6 locator hex opcode\n") +{ + VTY_DECLVAR_CONTEXT(srv6_locator, locator); + struct seg6_sid *sid = NULL; + struct listnode *node, *next; + char *prefix = NULL; + int ret = 0; + struct prefix_ipv6 ipv6prefix = {0}; + struct zserv *client; + struct listnode *client_node; + + prefix = argv[2]->arg; + ret = str2prefix_ipv6(prefix, &ipv6prefix); + if (!ret) { + vty_out(vty, "Malformed IPv6 prefix\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + for (ALL_LIST_ELEMENTS(locator->sids, node, next, sid)) { + if (IPV6_ADDR_SAME(&sid->ipv6Addr.prefix, &ipv6prefix.prefix)) { + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, + client_node, client)) { + + zsend_srv6_manager_del_sid(client, VRF_DEFAULT, + locator, sid); + } + zebra_srv6_local_sid_del(locator, sid); + + listnode_delete(locator->sids, sid); + srv6_locator_sid_free(sid); + return CMD_SUCCESS; + } + } + return CMD_SUCCESS; +} + static int zebra_sr_config(struct vty *vty) { struct zebra_srv6 *srv6 = zebra_srv6_get_default(); - struct listnode *node; + struct listnode *node, *opcodenode; struct srv6_locator *locator; + struct seg6_sid *sid; struct srv6_sid_format *format; char str[256]; + char buf[INET6_ADDRSTRLEN]; bool display_source_srv6 = false; if (srv6 && !IPV6_ADDR_SAME(&srv6->encap_src_addr, &in6addr_any)) @@ -977,21 +1215,42 @@ static int zebra_sr_config(struct vty *vty) vty_out(vty, " locator %s\n", locator->name); vty_out(vty, " prefix %s/%u", str, locator->prefix.prefixlen); - if (locator->block_bits_length) + if (locator->node_bits_length) vty_out(vty, " block-len %u", locator->block_bits_length); - if (locator->node_bits_length) + if (locator->function_bits_length) vty_out(vty, " node-len %u", locator->node_bits_length); - if (locator->function_bits_length) + if (locator->block_bits_length) vty_out(vty, " func-bits %u", locator->function_bits_length); - if (locator->argument_bits_length) - vty_out(vty, " arg-len %u", - locator->argument_bits_length); vty_out(vty, "\n"); if (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID)) vty_out(vty, " behavior usid\n"); + for (ALL_LIST_ELEMENTS_RO(locator->sids, opcodenode, + sid)) { + vty_out(vty, " opcode %s", sid->sidstr); + if (sid->sidaction == + ZEBRA_SEG6_LOCAL_ACTION_END) + vty_out(vty, " end"); + else if (sid->sidaction == + ZEBRA_SEG6_LOCAL_ACTION_END_DT4) { + vty_out(vty, " end-dt4"); + vty_out(vty, " vrf %s", sid->vrfName); + } else if (sid->sidaction == + ZEBRA_SEG6_LOCAL_ACTION_END_DT6) { + vty_out(vty, " end-dt6"); + vty_out(vty, " vrf %s", sid->vrfName); + } else if (sid->sidaction == + ZEBRA_SEG6_LOCAL_ACTION_END_DT46) { + vty_out(vty, " end-dt46"); + vty_out(vty, " vrf %s", sid->vrfName); + } + vty_out(vty, "\n"); + } + vty_out(vty, "\n"); + vty_out(vty, " exit\n"); + vty_out(vty, " !\n"); if (locator->sid_format) { format = locator->sid_format; vty_out(vty, " format %s\n", format->name); @@ -1045,7 +1304,6 @@ static int zebra_sr_config(struct vty *vty) } vty_out(vty, " exit\n"); vty_out(vty, " !\n"); - vty_out(vty, " exit\n"); vty_out(vty, " !\n"); } if (display_source_srv6 || zebra_srv6_is_enable()) { @@ -1062,6 +1320,7 @@ void zebra_srv6_vty_init(void) install_node(&srv6_node); install_node(&srv6_locs_node); install_node(&srv6_loc_node); + install_node(&srv6_prefix_node); install_node(&srv6_encap_node); install_node(&srv6_sid_formats_node); install_node(&srv6_sid_format_usid_f3216_node); @@ -1070,6 +1329,7 @@ void zebra_srv6_vty_init(void) install_default(SRV6_NODE); install_default(SRV6_LOCS_NODE); install_default(SRV6_LOC_NODE); + install_default(SRV6_PREFIX_NODE); install_default(SRV6_ENCAP_NODE); install_default(SRV6_SID_FORMATS_NODE); install_default(SRV6_SID_FORMAT_USID_F3216_NODE); @@ -1093,7 +1353,10 @@ void zebra_srv6_vty_init(void) &no_srv6_sid_format_f4024_uncompressed_cmd); /* Command for configuration */ - install_element(SRV6_LOC_NODE, &locator_prefix_cmd); + install_element(SRV6_LOC_NODE, &srv6_prefix_cmd); + install_element(SRV6_LOC_NODE, &no_srv6_prefix_cmd); + install_element(SRV6_PREFIX_NODE, &locator_prefix_cmd); + install_element(SRV6_PREFIX_NODE, &no_locator_prefix_cmd); install_element(SRV6_LOC_NODE, &locator_behavior_cmd); install_element(SRV6_LOC_NODE, &locator_sid_format_cmd); install_element(SRV6_LOC_NODE, &no_locator_sid_format_cmd); diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index e464e47b1f0c..3ce048406167 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -150,6 +150,7 @@ static int zebra_vrf_enable(struct vrf *vrf) /* Kick off any VxLAN-EVPN processing. */ zebra_vxlan_vrf_enable(zvrf); + zebra_srv6_vrf_enable(zvrf); return 0; }