diff --git a/lib/command.h b/lib/command.h index c60751789f66..c97739f935dd 100644 --- a/lib/command.h +++ b/lib/command.h @@ -156,6 +156,7 @@ enum node_type { 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 */ diff --git a/lib/srv6.c b/lib/srv6.c index 969dc613f62a..e46056ee5a1b 100644 --- a/lib/srv6.c +++ b/lib/srv6.c @@ -167,9 +167,19 @@ struct srv6_locator *srv6_locator_alloc(const char *name) locator->chunks = list_new(); locator->chunks->del = srv6_locator_chunk_list_free; + locator->sids = list_new(); + QOBJ_REG(locator, srv6_locator); return locator; } +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); +} struct srv6_locator_chunk *srv6_locator_chunk_alloc(void) { @@ -205,6 +215,43 @@ 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); +} + +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); @@ -485,7 +532,6 @@ json_object *srv6_locator_detailed_json(const struct srv6_locator *loc) jo_chunk = srv6_locator_chunk_detailed_json(chunk); json_object_array_add(jo_chunks, jo_chunk); } - /* set sids */ jo_sids = json_object_new_array(); json_object_object_add(jo_root, "sids", jo_sids); diff --git a/lib/srv6.h b/lib/srv6.h index 12393a73d6e7..94636402bd78 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 @@ -129,6 +130,7 @@ struct srv6_locator { uint64_t current; bool status_up; struct list *chunks; + struct list *sids; uint8_t flags; #define SRV6_LOCATOR_USID (1 << 0) /* The SRv6 Locator is a uSID Locator */ @@ -167,6 +169,12 @@ 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]; +}; /* * SRv6 Endpoint Behavior codepoints, as defined by IANA in * https://www.iana.org/assignments/segment-routing/segment-routing.xhtml @@ -376,8 +384,14 @@ 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_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 557d9c3eb9b4..85d0ba90d28c 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -1156,6 +1156,33 @@ 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 6da9558aa560..88e0ae769298 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -211,6 +211,9 @@ typedef enum { ZEBRA_SRV6_MANAGER_GET_LOCATOR, ZEBRA_SRV6_MANAGER_GET_SRV6_SID, ZEBRA_SRV6_MANAGER_RELEASE_SRV6_SID, + ZEBRA_SRV6_MANAGER_GET_LOCATOR_SID, + ZEBRA_SRV6_MANAGER_RELEASE_LOCATOR_SID, + ZEBRA_SRV6_MANAGER_GET_LOCATOR_ALL, ZEBRA_ERROR, ZEBRA_CLIENT_CAPABILITIES, ZEBRA_OPAQUE_MESSAGE, @@ -1064,6 +1067,8 @@ 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/vtysh/vtysh.c b/vtysh/vtysh.c index 5a54c60c6b11..d88099bf6916 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -1325,6 +1325,13 @@ 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, @@ -1709,6 +1716,22 @@ DEFUNSH(VTYSH_ZEBRA, srv6_locator, srv6_locator_cmd, return CMD_SUCCESS; } +DEFUNSH(VTYSH_ZEBRA, srv6_prefix, 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") @@ -2558,6 +2581,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") { @@ -5001,6 +5032,7 @@ void vtysh_init_vty(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); @@ -5447,9 +5479,13 @@ 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_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_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/zapi_msg.c b/zebra/zapi_msg.c index 10acee9be435..24801c3e4437 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -2760,6 +2760,37 @@ 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 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) diff --git a/zebra/zapi_msg.h b/zebra/zapi_msg.h index a59ccc838b97..a9caf9023712 100644 --- a/zebra/zapi_msg.h +++ b/zebra/zapi_msg.h @@ -118,6 +118,11 @@ 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); +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_srv6.c b/zebra/zebra_srv6.c index 624f60e815af..49a37808a938 100644 --- a/zebra/zebra_srv6.c +++ b/zebra/zebra_srv6.c @@ -628,10 +628,16 @@ void zebra_srv6_locator_add(struct srv6_locator *locator) void zebra_srv6_locator_delete(struct srv6_locator *locator) { - struct listnode *n; + struct listnode *n, *nnode; 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)) { + listnode_delete(locator->sids, sid); + srv6_locator_sid_free(sid); + } /* * Notify deleted locator info to zclients if needed. * @@ -643,7 +649,8 @@ void zebra_srv6_locator_delete(struct srv6_locator *locator) * 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_RO(zrouter.client_list, client_node, client)) zsend_zebra_srv6_locator_delete(client, locator); listnode_delete(srv6->locators, locator); diff --git a/zebra/zebra_srv6.h b/zebra/zebra_srv6.h index 1599fd7adfbd..3479bb2b8e07 100644 --- a/zebra/zebra_srv6.h +++ b/zebra/zebra_srv6.h @@ -245,6 +245,7 @@ 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); void zebra_notify_srv6_locator_add(struct srv6_locator *locator); diff --git a/zebra/zebra_srv6_vty.c b/zebra/zebra_srv6_vty.c index 5a8052414902..cf529c67d8d4 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,28 @@ 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 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 && (sid->sidaction == sidaction)) + return sid; + } + return NULL; +} + static struct cmd_node srv6_encap_node = { .name = "srv6-encap", .node = SRV6_ENCAP_NODE, @@ -195,7 +218,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 +279,13 @@ 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); + } } @@ -334,6 +367,7 @@ DEFUN_NOSH (srv6_locator, if (locator) { VTY_PUSH_CONTEXT(SRV6_LOC_NODE, locator); locator->status_up = true; + vty->node = SRV6_LOC_NODE; return CMD_SUCCESS; } @@ -391,7 +425,7 @@ DEFUN (no_srv6_locator, return CMD_SUCCESS; } -DEFPY (locator_prefix, +DEFUN_NOSH (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]", @@ -409,11 +443,33 @@ DEFPY (locator_prefix, struct listnode *node = NULL; uint8_t expected_prefixlen; struct srv6_sid_format *format; + char *prefixstr = NULL; + struct prefix_ipv6 prefix; + int ret = 0; + int idx = 0; + int block_bit_len = 0; + int node_bit_len = 0; + int func_bit_len = 0; + + prefixstr = argv[1]->arg; + ret = str2prefix_ipv6(prefixstr, &prefix); + apply_mask_ipv6(&prefix); + if (!ret) { + vty_out(vty, "Malformed IPv6 prefix\n"); + return CMD_WARNING_CONFIG_FAILED; + } - locator->prefix = *prefix; + if (argv_find(argv, argc, "block-len", &idx)) + block_bit_len = strtoul(argv[idx + 1]->arg, NULL, 10); + if (argv_find(argv, argc, "node-len", &idx)) + node_bit_len = strtoul(argv[idx + 1]->arg, NULL, 10); + if (argv_find(argv, argc, "func-bits", &idx)) + func_bit_len = strtoul(argv[idx + 1]->arg, NULL, 10); + + locator->prefix = prefix; func_bit_len = func_bit_len ?: ZEBRA_SRV6_FUNCTION_LENGTH; - expected_prefixlen = prefix->prefixlen; + expected_prefixlen = prefix.prefixlen; format = locator->sid_format; if (format) { if (strmatch(format->name, SRV6_SID_FORMAT_USID_F3216_NAME)) @@ -427,35 +483,34 @@ DEFPY (locator_prefix, SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE_LEN; } - if (prefix->prefixlen != expected_prefixlen) { + 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); + 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; + block_bit_len = prefix.prefixlen - ZEBRA_SRV6_LOCATOR_NODE_LENGTH; node_bit_len = ZEBRA_SRV6_LOCATOR_NODE_LENGTH; } else if (block_bit_len == 0) { - block_bit_len = prefix->prefixlen - node_bit_len; + block_bit_len = prefix.prefixlen - node_bit_len; } else if (node_bit_len == 0) { - node_bit_len = prefix->prefixlen - block_bit_len; + node_bit_len = prefix.prefixlen - block_bit_len; } else { - if (block_bit_len + node_bit_len != prefix->prefixlen) { + if (block_bit_len + node_bit_len != prefix.prefixlen) { vty_out(vty, "%% block-len + node-len must be equal to the selected prefix length %d\n", - prefix->prefixlen); + prefix.prefixlen); return CMD_WARNING_CONFIG_FAILED; } } - if (prefix->prefixlen + func_bit_len + 0 > 128) { + 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); + "%% prefix-len + function-len + arg-len (%d) cannot be greater than 128\n", + prefix.prefixlen + func_bit_len + 0); return CMD_WARNING_CONFIG_FAILED; } @@ -479,7 +534,7 @@ DEFPY (locator_prefix, if (list_isempty(locator->chunks)) { chunk = srv6_locator_chunk_alloc(); - chunk->prefix = *prefix; + chunk->prefix = prefix; chunk->proto = 0; listnode_add(locator->chunks, chunk); } else { @@ -490,7 +545,7 @@ DEFPY (locator_prefix, struct zserv *client; struct listnode *client_node; - chunk->prefix = *prefix; + chunk->prefix = prefix; for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, client_node, client)) { @@ -510,6 +565,8 @@ DEFPY (locator_prefix, zebra_srv6_locator_format_set(locator, locator->sid_format); + vty->node = SRV6_PREFIX_NODE; + return CMD_SUCCESS; } @@ -945,11 +1002,127 @@ DEFPY(no_srv6_sid_format_explicit, return CMD_SUCCESS; } + +DEFPY(locator_opcode, locator_opcode_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 = NULL; + char *prefix = NULL; + int ret = 0; + struct prefix_ipv6 ipv6prefix = { 0 }; + struct zserv *client; + struct listnode *client_node; + + 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); + else + strlcpy(sid->vrfName, VRF_DEFAULT_NAME, VRF_NAMSIZ); + + sid->ipv6Addr = ipv6prefix; + strlcpy(sid->sidstr, prefix, PREFIX_STRLEN); + + listnode_add(locator->sids, sid); + + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, client_node, client)) + zsend_srv6_manager_get_locator_sid_response(client, VRF_DEFAULT, locator); + return CMD_SUCCESS; +} + +DEFPY(no_locator_opcode, + no_locator_opcode_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); + 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]; bool display_source_srv6 = false; @@ -992,6 +1165,25 @@ static int zebra_sr_config(struct vty *vty) 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); @@ -1062,6 +1254,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 +1263,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); @@ -1094,6 +1288,9 @@ void zebra_srv6_vty_init(void) /* Command for configuration */ install_element(SRV6_LOC_NODE, &locator_prefix_cmd); + //install_element(SRV6_LOC_NODE, &no_srv6_prefix_cmd); + install_element(SRV6_PREFIX_NODE, &locator_opcode_cmd); + install_element(SRV6_PREFIX_NODE, &no_locator_opcode_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);