mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-07 06:03:10 +00:00
Merge pull request #9486 from slankdev/slankdev-srv6-no-cli-1
CLI to delete SRv6 locator
This commit is contained in:
commit
b8c01bba53
@ -714,6 +714,15 @@ static void setsids(struct bgp_path_info *bpi,
|
|||||||
extra->num_sids = num_sids;
|
extra->num_sids = num_sids;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void unsetsids(struct bgp_path_info *bpi)
|
||||||
|
{
|
||||||
|
struct bgp_path_info_extra *extra;
|
||||||
|
|
||||||
|
extra = bgp_path_info_extra_get(bpi);
|
||||||
|
extra->num_sids = 0;
|
||||||
|
memset(extra->sid, 0, sizeof(extra->sid));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* returns pointer to new bgp_path_info upon success
|
* returns pointer to new bgp_path_info upon success
|
||||||
*/
|
*/
|
||||||
@ -821,7 +830,8 @@ leak_update(struct bgp *bgp, /* destination bgp instance */
|
|||||||
else if (new_attr->srv6_vpn)
|
else if (new_attr->srv6_vpn)
|
||||||
setsids(bpi, &new_attr->srv6_vpn->sid,
|
setsids(bpi, &new_attr->srv6_vpn->sid,
|
||||||
num_sids);
|
num_sids);
|
||||||
}
|
} else
|
||||||
|
unsetsids(bpi);
|
||||||
|
|
||||||
if (nexthop_self_flag)
|
if (nexthop_self_flag)
|
||||||
bgp_path_info_set_flag(bn, bpi, BGP_PATH_ANNC_NH_SELF);
|
bgp_path_info_set_flag(bn, bpi, BGP_PATH_ANNC_NH_SELF);
|
||||||
@ -847,6 +857,17 @@ leak_update(struct bgp *bgp, /* destination bgp instance */
|
|||||||
nh_valid = bgp_find_or_add_nexthop(
|
nh_valid = bgp_find_or_add_nexthop(
|
||||||
bgp, bgp_nexthop, afi, safi, bpi, NULL, 0, p);
|
bgp, bgp_nexthop, afi, safi, bpi, NULL, 0, p);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If you are using SRv6 VPN instead of MPLS, it need to check
|
||||||
|
* the SID allocation. If the sid is not allocated, the rib
|
||||||
|
* will be invalid.
|
||||||
|
*/
|
||||||
|
if (bgp->srv6_enabled
|
||||||
|
&& (!new_attr->srv6_l3vpn && !new_attr->srv6_vpn)) {
|
||||||
|
bgp_path_info_unset_flag(bn, bpi, BGP_PATH_VALID);
|
||||||
|
nh_valid = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (debug)
|
if (debug)
|
||||||
zlog_debug("%s: nexthop is %svalid (in vrf %s)",
|
zlog_debug("%s: nexthop is %svalid (in vrf %s)",
|
||||||
__func__, (nh_valid ? "" : "not "),
|
__func__, (nh_valid ? "" : "not "),
|
||||||
@ -893,7 +914,8 @@ leak_update(struct bgp *bgp, /* destination bgp instance */
|
|||||||
setsids(new, &new_attr->srv6_l3vpn->sid, num_sids);
|
setsids(new, &new_attr->srv6_l3vpn->sid, num_sids);
|
||||||
else if (new_attr->srv6_vpn)
|
else if (new_attr->srv6_vpn)
|
||||||
setsids(new, &new_attr->srv6_vpn->sid, num_sids);
|
setsids(new, &new_attr->srv6_vpn->sid, num_sids);
|
||||||
}
|
} else
|
||||||
|
unsetsids(new);
|
||||||
|
|
||||||
if (num_labels)
|
if (num_labels)
|
||||||
setlabels(new, label, num_labels);
|
setlabels(new, label, num_labels);
|
||||||
@ -933,6 +955,17 @@ leak_update(struct bgp *bgp, /* destination bgp instance */
|
|||||||
nh_valid = bgp_find_or_add_nexthop(bgp, bgp_nexthop, afi, safi,
|
nh_valid = bgp_find_or_add_nexthop(bgp, bgp_nexthop, afi, safi,
|
||||||
new, NULL, 0, p);
|
new, NULL, 0, p);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If you are using SRv6 VPN instead of MPLS, it need to check
|
||||||
|
* the SID allocation. If the sid is not allocated, the rib
|
||||||
|
* will be invalid.
|
||||||
|
*/
|
||||||
|
if (bgp->srv6_enabled
|
||||||
|
&& (!new->attr->srv6_l3vpn && !new->attr->srv6_vpn)) {
|
||||||
|
bgp_path_info_unset_flag(bn, new, BGP_PATH_VALID);
|
||||||
|
nh_valid = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (debug)
|
if (debug)
|
||||||
zlog_debug("%s: nexthop is %svalid (in vrf %s)",
|
zlog_debug("%s: nexthop is %svalid (in vrf %s)",
|
||||||
__func__, (nh_valid ? "" : "not "),
|
__func__, (nh_valid ? "" : "not "),
|
||||||
|
@ -243,6 +243,10 @@ static inline void vpn_leak_postchange(vpn_policy_direction_t direction,
|
|||||||
if (!bgp_vrf->vpn_policy[afi].tovpn_sid)
|
if (!bgp_vrf->vpn_policy[afi].tovpn_sid)
|
||||||
ensure_vrf_tovpn_sid(bgp_vpn, bgp_vrf, afi);
|
ensure_vrf_tovpn_sid(bgp_vpn, bgp_vrf, afi);
|
||||||
|
|
||||||
|
if (!bgp_vrf->vpn_policy[afi].tovpn_sid
|
||||||
|
&& bgp_vrf->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent)
|
||||||
|
vpn_leak_zebra_vrf_sid_withdraw(bgp_vrf, afi);
|
||||||
|
|
||||||
if (sid_diff(bgp_vrf->vpn_policy[afi].tovpn_sid,
|
if (sid_diff(bgp_vrf->vpn_policy[afi].tovpn_sid,
|
||||||
bgp_vrf->vpn_policy[afi]
|
bgp_vrf->vpn_policy[afi]
|
||||||
.tovpn_zebra_vrf_sid_last_sent)) {
|
.tovpn_zebra_vrf_sid_last_sent)) {
|
||||||
|
@ -282,6 +282,57 @@ static const char *get_afi_safi_json_str(afi_t afi, safi_t safi)
|
|||||||
return "Unknown";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* unset srv6 locator */
|
||||||
|
static int bgp_srv6_locator_unset(struct bgp *bgp)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct listnode *node, *nnode;
|
||||||
|
struct prefix_ipv6 *chunk;
|
||||||
|
struct bgp_srv6_function *func;
|
||||||
|
struct bgp *bgp_vrf;
|
||||||
|
struct in6_addr *tovpn_sid;
|
||||||
|
|
||||||
|
/* release chunk notification via ZAPI */
|
||||||
|
ret = bgp_zebra_srv6_manager_release_locator_chunk(
|
||||||
|
bgp->srv6_locator_name);
|
||||||
|
if (ret < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* refresh chunks */
|
||||||
|
for (ALL_LIST_ELEMENTS(bgp->srv6_locator_chunks, node, nnode, chunk))
|
||||||
|
listnode_delete(bgp->srv6_locator_chunks, chunk);
|
||||||
|
|
||||||
|
/* refresh functions */
|
||||||
|
for (ALL_LIST_ELEMENTS(bgp->srv6_functions, node, nnode, func))
|
||||||
|
listnode_delete(bgp->srv6_functions, func);
|
||||||
|
|
||||||
|
/* refresh tovpn_sid */
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_vrf)) {
|
||||||
|
if (bgp_vrf->inst_type != BGP_INSTANCE_TYPE_VRF)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* refresh vpnv4 tovpn_sid */
|
||||||
|
tovpn_sid = bgp_vrf->vpn_policy[AFI_IP].tovpn_sid;
|
||||||
|
if (tovpn_sid)
|
||||||
|
XFREE(MTYPE_BGP_SRV6_SID,
|
||||||
|
bgp_vrf->vpn_policy[AFI_IP].tovpn_sid);
|
||||||
|
|
||||||
|
/* refresh vpnv6 tovpn_sid */
|
||||||
|
tovpn_sid = bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid;
|
||||||
|
if (tovpn_sid)
|
||||||
|
XFREE(MTYPE_BGP_SRV6_SID,
|
||||||
|
bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* update vpn bgp processes */
|
||||||
|
vpn_leak_postchange_all();
|
||||||
|
|
||||||
|
/* clear locator name */
|
||||||
|
memset(bgp->srv6_locator_name, 0, sizeof(bgp->srv6_locator_name));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Utility function to get address family from current node. */
|
/* Utility function to get address family from current node. */
|
||||||
afi_t bgp_node_afi(struct vty *vty)
|
afi_t bgp_node_afi(struct vty *vty)
|
||||||
{
|
{
|
||||||
@ -9096,6 +9147,23 @@ DEFUN_NOSH (bgp_segment_routing_srv6,
|
|||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFUN (no_bgp_segment_routing_srv6,
|
||||||
|
no_bgp_segment_routing_srv6_cmd,
|
||||||
|
"no segment-routing srv6",
|
||||||
|
NO_STR
|
||||||
|
"Segment-Routing configuration\n"
|
||||||
|
"Segment-Routing SRv6 configuration\n")
|
||||||
|
{
|
||||||
|
VTY_DECLVAR_CONTEXT(bgp, bgp);
|
||||||
|
|
||||||
|
if (strlen(bgp->srv6_locator_name) > 0)
|
||||||
|
if (bgp_srv6_locator_unset(bgp) < 0)
|
||||||
|
return CMD_WARNING_CONFIG_FAILED;
|
||||||
|
|
||||||
|
bgp->srv6_enabled = false;
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
DEFPY (bgp_srv6_locator,
|
DEFPY (bgp_srv6_locator,
|
||||||
bgp_srv6_locator_cmd,
|
bgp_srv6_locator_cmd,
|
||||||
"locator NAME$name",
|
"locator NAME$name",
|
||||||
@ -9121,6 +9189,32 @@ DEFPY (bgp_srv6_locator,
|
|||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFPY (no_bgp_srv6_locator,
|
||||||
|
no_bgp_srv6_locator_cmd,
|
||||||
|
"no locator NAME$name",
|
||||||
|
NO_STR
|
||||||
|
"Specify SRv6 locator\n"
|
||||||
|
"Specify SRv6 locator\n")
|
||||||
|
{
|
||||||
|
VTY_DECLVAR_CONTEXT(bgp, bgp);
|
||||||
|
|
||||||
|
/* when locator isn't configured, do nothing */
|
||||||
|
if (strlen(bgp->srv6_locator_name) < 1)
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
|
||||||
|
/* name validation */
|
||||||
|
if (strcmp(name, bgp->srv6_locator_name) != 0) {
|
||||||
|
vty_out(vty, "%% No srv6 locator is configured\n");
|
||||||
|
return CMD_WARNING_CONFIG_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* unset locator */
|
||||||
|
if (bgp_srv6_locator_unset(bgp) < 0)
|
||||||
|
return CMD_WARNING_CONFIG_FAILED;
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
DEFPY (show_bgp_srv6,
|
DEFPY (show_bgp_srv6,
|
||||||
show_bgp_srv6_cmd,
|
show_bgp_srv6_cmd,
|
||||||
"show bgp segment-routing srv6",
|
"show bgp segment-routing srv6",
|
||||||
@ -18915,7 +19009,9 @@ void bgp_vty_init(void)
|
|||||||
/* srv6 commands */
|
/* srv6 commands */
|
||||||
install_element(VIEW_NODE, &show_bgp_srv6_cmd);
|
install_element(VIEW_NODE, &show_bgp_srv6_cmd);
|
||||||
install_element(BGP_NODE, &bgp_segment_routing_srv6_cmd);
|
install_element(BGP_NODE, &bgp_segment_routing_srv6_cmd);
|
||||||
|
install_element(BGP_NODE, &no_bgp_segment_routing_srv6_cmd);
|
||||||
install_element(BGP_SRV6_NODE, &bgp_srv6_locator_cmd);
|
install_element(BGP_SRV6_NODE, &bgp_srv6_locator_cmd);
|
||||||
|
install_element(BGP_SRV6_NODE, &no_bgp_srv6_locator_cmd);
|
||||||
install_element(BGP_IPV4_NODE, &af_sid_vpn_export_cmd);
|
install_element(BGP_IPV4_NODE, &af_sid_vpn_export_cmd);
|
||||||
install_element(BGP_IPV6_NODE, &af_sid_vpn_export_cmd);
|
install_element(BGP_IPV6_NODE, &af_sid_vpn_export_cmd);
|
||||||
}
|
}
|
||||||
|
@ -3088,6 +3088,88 @@ static void bgp_zebra_process_srv6_locator_chunk(ZAPI_CALLBACK_ARGS)
|
|||||||
vpn_leak_postchange_all();
|
vpn_leak_postchange_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int bgp_zebra_process_srv6_locator_add(ZAPI_CALLBACK_ARGS)
|
||||||
|
{
|
||||||
|
struct srv6_locator loc = {};
|
||||||
|
struct bgp *bgp = bgp_get_default();
|
||||||
|
const char *loc_name = bgp->srv6_locator_name;
|
||||||
|
|
||||||
|
if (zapi_srv6_locator_decode(zclient->ibuf, &loc) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (!bgp || !bgp->srv6_enabled)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (bgp_zebra_srv6_manager_get_locator_chunk(loc_name) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int bgp_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS)
|
||||||
|
{
|
||||||
|
struct srv6_locator loc = {};
|
||||||
|
struct bgp *bgp = bgp_get_default();
|
||||||
|
struct listnode *node, *nnode;
|
||||||
|
struct prefix_ipv6 *chunk;
|
||||||
|
struct bgp_srv6_function *func;
|
||||||
|
struct bgp *bgp_vrf;
|
||||||
|
struct in6_addr *tovpn_sid;
|
||||||
|
struct prefix_ipv6 tmp_prefi;
|
||||||
|
|
||||||
|
if (zapi_srv6_locator_decode(zclient->ibuf, &loc) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
// refresh chunks
|
||||||
|
for (ALL_LIST_ELEMENTS(bgp->srv6_locator_chunks, node, nnode, chunk))
|
||||||
|
if (prefix_match((struct prefix *)&loc.prefix,
|
||||||
|
(struct prefix *)chunk))
|
||||||
|
listnode_delete(bgp->srv6_locator_chunks, chunk);
|
||||||
|
|
||||||
|
// refresh functions
|
||||||
|
for (ALL_LIST_ELEMENTS(bgp->srv6_functions, node, nnode, func)) {
|
||||||
|
tmp_prefi.family = AF_INET6;
|
||||||
|
tmp_prefi.prefixlen = 128;
|
||||||
|
tmp_prefi.prefix = func->sid;
|
||||||
|
if (prefix_match((struct prefix *)&loc.prefix,
|
||||||
|
(struct prefix *)&tmp_prefi))
|
||||||
|
listnode_delete(bgp->srv6_functions, func);
|
||||||
|
}
|
||||||
|
|
||||||
|
// refresh tovpn_sid
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_vrf)) {
|
||||||
|
if (bgp_vrf->inst_type != BGP_INSTANCE_TYPE_VRF)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// refresh vpnv4 tovpn_sid
|
||||||
|
tovpn_sid = bgp_vrf->vpn_policy[AFI_IP].tovpn_sid;
|
||||||
|
if (tovpn_sid) {
|
||||||
|
tmp_prefi.family = AF_INET6;
|
||||||
|
tmp_prefi.prefixlen = 128;
|
||||||
|
tmp_prefi.prefix = *tovpn_sid;
|
||||||
|
if (prefix_match((struct prefix *)&loc.prefix,
|
||||||
|
(struct prefix *)&tmp_prefi))
|
||||||
|
XFREE(MTYPE_BGP_SRV6_SID,
|
||||||
|
bgp_vrf->vpn_policy[AFI_IP].tovpn_sid);
|
||||||
|
}
|
||||||
|
|
||||||
|
// refresh vpnv6 tovpn_sid
|
||||||
|
tovpn_sid = bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid;
|
||||||
|
if (tovpn_sid) {
|
||||||
|
tmp_prefi.family = AF_INET6;
|
||||||
|
tmp_prefi.prefixlen = 128;
|
||||||
|
tmp_prefi.prefix = *tovpn_sid;
|
||||||
|
if (prefix_match((struct prefix *)&loc.prefix,
|
||||||
|
(struct prefix *)&tmp_prefi))
|
||||||
|
XFREE(MTYPE_BGP_SRV6_SID,
|
||||||
|
bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vpn_leak_postchange_all();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void bgp_zebra_init(struct thread_master *master, unsigned short instance)
|
void bgp_zebra_init(struct thread_master *master, unsigned short instance)
|
||||||
{
|
{
|
||||||
zclient_num_connects = 0;
|
zclient_num_connects = 0;
|
||||||
@ -3130,6 +3212,8 @@ void bgp_zebra_init(struct thread_master *master, unsigned short instance)
|
|||||||
zclient->iptable_notify_owner = iptable_notify_owner;
|
zclient->iptable_notify_owner = iptable_notify_owner;
|
||||||
zclient->route_notify_owner = bgp_zebra_route_notify_owner;
|
zclient->route_notify_owner = bgp_zebra_route_notify_owner;
|
||||||
zclient->instance = instance;
|
zclient->instance = instance;
|
||||||
|
zclient->srv6_locator_add = bgp_zebra_process_srv6_locator_add;
|
||||||
|
zclient->srv6_locator_delete = bgp_zebra_process_srv6_locator_delete;
|
||||||
zclient->process_srv6_locator_chunk =
|
zclient->process_srv6_locator_chunk =
|
||||||
bgp_zebra_process_srv6_locator_chunk;
|
bgp_zebra_process_srv6_locator_chunk;
|
||||||
}
|
}
|
||||||
@ -3541,3 +3625,8 @@ int bgp_zebra_srv6_manager_get_locator_chunk(const char *name)
|
|||||||
{
|
{
|
||||||
return srv6_manager_get_locator_chunk(zclient, name);
|
return srv6_manager_get_locator_chunk(zclient, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int bgp_zebra_srv6_manager_release_locator_chunk(const char *name)
|
||||||
|
{
|
||||||
|
return srv6_manager_release_locator_chunk(zclient, name);
|
||||||
|
}
|
||||||
|
@ -114,4 +114,5 @@ extern int bgp_zebra_send_capabilities(struct bgp *bgp, bool disable);
|
|||||||
extern int bgp_zebra_update(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type);
|
extern int bgp_zebra_update(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type);
|
||||||
extern int bgp_zebra_stale_timer_update(struct bgp *bgp);
|
extern int bgp_zebra_stale_timer_update(struct bgp *bgp);
|
||||||
extern int bgp_zebra_srv6_manager_get_locator_chunk(const char *name);
|
extern int bgp_zebra_srv6_manager_get_locator_chunk(const char *name);
|
||||||
|
extern int bgp_zebra_srv6_manager_release_locator_chunk(const char *name);
|
||||||
#endif /* _QUAGGA_BGP_ZEBRA_H */
|
#endif /* _QUAGGA_BGP_ZEBRA_H */
|
||||||
|
@ -1105,6 +1105,33 @@ stream_failure:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int zapi_srv6_locator_encode(struct stream *s, const struct srv6_locator *l)
|
||||||
|
{
|
||||||
|
stream_putw(s, strlen(l->name));
|
||||||
|
stream_put(s, l->name, strlen(l->name));
|
||||||
|
stream_putw(s, l->prefix.prefixlen);
|
||||||
|
stream_put(s, &l->prefix.prefix, sizeof(l->prefix.prefix));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int zapi_srv6_locator_decode(struct stream *s, struct srv6_locator *l)
|
||||||
|
{
|
||||||
|
uint16_t len = 0;
|
||||||
|
|
||||||
|
STREAM_GETW(s, len);
|
||||||
|
if (len > SRV6_LOCNAME_SIZE)
|
||||||
|
goto stream_failure;
|
||||||
|
|
||||||
|
STREAM_GET(l->name, s, len);
|
||||||
|
STREAM_GETW(s, l->prefix.prefixlen);
|
||||||
|
STREAM_GET(&l->prefix.prefix, s, sizeof(l->prefix.prefix));
|
||||||
|
l->prefix.family = AF_INET6;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
stream_failure:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
static int zapi_nhg_encode(struct stream *s, int cmd, struct zapi_nhg *api_nhg)
|
static int zapi_nhg_encode(struct stream *s, int cmd, struct zapi_nhg *api_nhg)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -1090,6 +1090,9 @@ extern int zapi_labels_encode(struct stream *s, int cmd,
|
|||||||
struct zapi_labels *zl);
|
struct zapi_labels *zl);
|
||||||
extern int zapi_labels_decode(struct stream *s, struct zapi_labels *zl);
|
extern int zapi_labels_decode(struct stream *s, struct zapi_labels *zl);
|
||||||
|
|
||||||
|
extern int zapi_srv6_locator_encode(struct stream *s,
|
||||||
|
const struct srv6_locator *l);
|
||||||
|
extern int zapi_srv6_locator_decode(struct stream *s, struct srv6_locator *l);
|
||||||
extern int zapi_srv6_locator_chunk_encode(struct stream *s,
|
extern int zapi_srv6_locator_chunk_encode(struct stream *s,
|
||||||
const struct srv6_locator_chunk *c);
|
const struct srv6_locator_chunk *c);
|
||||||
extern int zapi_srv6_locator_chunk_decode(struct stream *s,
|
extern int zapi_srv6_locator_chunk_decode(struct stream *s,
|
||||||
|
@ -0,0 +1,160 @@
|
|||||||
|
{
|
||||||
|
"vrfId": 0,
|
||||||
|
"vrfName": "default",
|
||||||
|
"routerId": "1.1.1.1",
|
||||||
|
"defaultLocPrf": 100,
|
||||||
|
"localAS": 1,
|
||||||
|
"routes": {
|
||||||
|
"routeDistinguishers": {
|
||||||
|
"1:10": {
|
||||||
|
"2001:1::/64": [
|
||||||
|
{
|
||||||
|
"pathFrom": "external",
|
||||||
|
"prefix": "2001:1::",
|
||||||
|
"prefixLen": 64,
|
||||||
|
"network": "2001:1::/64",
|
||||||
|
"metric": 0,
|
||||||
|
"weight": 32768,
|
||||||
|
"peerId": "(unspec)",
|
||||||
|
"path": "",
|
||||||
|
"origin": "incomplete",
|
||||||
|
"announceNexthopSelf": true,
|
||||||
|
"nhVrfName": "vrf10",
|
||||||
|
"nexthops": [
|
||||||
|
{
|
||||||
|
"ip": "::",
|
||||||
|
"hostname": "r1",
|
||||||
|
"afi": "ipv6",
|
||||||
|
"used": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"2001:3::/64": [
|
||||||
|
{
|
||||||
|
"pathFrom": "external",
|
||||||
|
"prefix": "2001:3::",
|
||||||
|
"prefixLen": 64,
|
||||||
|
"network": "2001:3::/64",
|
||||||
|
"metric": 0,
|
||||||
|
"weight": 32768,
|
||||||
|
"peerId": "(unspec)",
|
||||||
|
"path": "",
|
||||||
|
"origin": "incomplete",
|
||||||
|
"announceNexthopSelf": true,
|
||||||
|
"nhVrfName": "vrf10",
|
||||||
|
"nexthops": [
|
||||||
|
{
|
||||||
|
"ip": "::",
|
||||||
|
"hostname": "r1",
|
||||||
|
"afi": "ipv6",
|
||||||
|
"used": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"1:20": {
|
||||||
|
"2001:5::/64": [
|
||||||
|
{
|
||||||
|
"pathFrom": "external",
|
||||||
|
"prefix": "2001:5::",
|
||||||
|
"prefixLen": 64,
|
||||||
|
"network": "2001:5::/64",
|
||||||
|
"metric": 0,
|
||||||
|
"weight": 32768,
|
||||||
|
"peerId": "(unspec)",
|
||||||
|
"path": "",
|
||||||
|
"origin": "incomplete",
|
||||||
|
"announceNexthopSelf": true,
|
||||||
|
"nhVrfName": "vrf20",
|
||||||
|
"nexthops": [
|
||||||
|
{
|
||||||
|
"ip": "::",
|
||||||
|
"hostname": "r1",
|
||||||
|
"afi": "ipv6",
|
||||||
|
"used": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"2:10": {
|
||||||
|
"2001:2::/64": [
|
||||||
|
{
|
||||||
|
"valid": true,
|
||||||
|
"bestpath": true,
|
||||||
|
"selectionReason": "First path received",
|
||||||
|
"pathFrom": "external",
|
||||||
|
"prefix": "2001:2::",
|
||||||
|
"prefixLen": 64,
|
||||||
|
"network": "2001:2::/64",
|
||||||
|
"metric": 0,
|
||||||
|
"weight": 0,
|
||||||
|
"peerId": "2001::2",
|
||||||
|
"path": "2",
|
||||||
|
"origin": "incomplete",
|
||||||
|
"nexthops": [
|
||||||
|
{
|
||||||
|
"ip": "2001::2",
|
||||||
|
"hostname": "r2",
|
||||||
|
"afi": "ipv6",
|
||||||
|
"used": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"2:20": {
|
||||||
|
"2001:4::/64": [
|
||||||
|
{
|
||||||
|
"valid": true,
|
||||||
|
"bestpath": true,
|
||||||
|
"selectionReason": "First path received",
|
||||||
|
"pathFrom": "external",
|
||||||
|
"prefix": "2001:4::",
|
||||||
|
"prefixLen": 64,
|
||||||
|
"network": "2001:4::/64",
|
||||||
|
"metric": 0,
|
||||||
|
"weight": 0,
|
||||||
|
"peerId": "2001::2",
|
||||||
|
"path": "2",
|
||||||
|
"origin": "incomplete",
|
||||||
|
"nexthops": [
|
||||||
|
{
|
||||||
|
"ip": "2001::2",
|
||||||
|
"hostname": "r2",
|
||||||
|
"afi": "ipv6",
|
||||||
|
"used": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"2001:6::/64": [
|
||||||
|
{
|
||||||
|
"valid": true,
|
||||||
|
"bestpath": true,
|
||||||
|
"selectionReason": "First path received",
|
||||||
|
"pathFrom": "external",
|
||||||
|
"prefix": "2001:6::",
|
||||||
|
"prefixLen": 64,
|
||||||
|
"network": "2001:6::/64",
|
||||||
|
"metric": 0,
|
||||||
|
"weight": 0,
|
||||||
|
"peerId": "2001::2",
|
||||||
|
"path": "2",
|
||||||
|
"origin": "incomplete",
|
||||||
|
"nexthops": [
|
||||||
|
{
|
||||||
|
"ip": "2001::2",
|
||||||
|
"hostname": "r2",
|
||||||
|
"afi": "ipv6",
|
||||||
|
"used": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,169 @@
|
|||||||
|
{
|
||||||
|
"vrfId": 0,
|
||||||
|
"vrfName": "default",
|
||||||
|
"routerId": "1.1.1.1",
|
||||||
|
"defaultLocPrf": 100,
|
||||||
|
"localAS": 1,
|
||||||
|
"routes": {
|
||||||
|
"routeDistinguishers": {
|
||||||
|
"1:10": {
|
||||||
|
"2001:1::/64": [
|
||||||
|
{
|
||||||
|
"valid": true,
|
||||||
|
"bestpath": true,
|
||||||
|
"selectionReason": "First path received",
|
||||||
|
"pathFrom": "external",
|
||||||
|
"prefix": "2001:1::",
|
||||||
|
"prefixLen": 64,
|
||||||
|
"network": "2001:1::/64",
|
||||||
|
"metric": 0,
|
||||||
|
"weight": 32768,
|
||||||
|
"peerId": "(unspec)",
|
||||||
|
"path": "",
|
||||||
|
"origin": "incomplete",
|
||||||
|
"announceNexthopSelf": true,
|
||||||
|
"nhVrfName": "vrf10",
|
||||||
|
"nexthops": [
|
||||||
|
{
|
||||||
|
"ip": "::",
|
||||||
|
"hostname": "r1",
|
||||||
|
"afi": "ipv6",
|
||||||
|
"used": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"2001:3::/64": [
|
||||||
|
{
|
||||||
|
"valid": true,
|
||||||
|
"bestpath": true,
|
||||||
|
"selectionReason": "First path received",
|
||||||
|
"pathFrom": "external",
|
||||||
|
"prefix": "2001:3::",
|
||||||
|
"prefixLen": 64,
|
||||||
|
"network": "2001:3::/64",
|
||||||
|
"metric": 0,
|
||||||
|
"weight": 32768,
|
||||||
|
"peerId": "(unspec)",
|
||||||
|
"path": "",
|
||||||
|
"origin": "incomplete",
|
||||||
|
"announceNexthopSelf": true,
|
||||||
|
"nhVrfName": "vrf10",
|
||||||
|
"nexthops": [
|
||||||
|
{
|
||||||
|
"ip": "::",
|
||||||
|
"hostname": "r1",
|
||||||
|
"afi": "ipv6",
|
||||||
|
"used": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"1:20": {
|
||||||
|
"2001:5::/64": [
|
||||||
|
{
|
||||||
|
"valid": true,
|
||||||
|
"bestpath": true,
|
||||||
|
"selectionReason": "First path received",
|
||||||
|
"pathFrom": "external",
|
||||||
|
"prefix": "2001:5::",
|
||||||
|
"prefixLen": 64,
|
||||||
|
"network": "2001:5::/64",
|
||||||
|
"metric": 0,
|
||||||
|
"weight": 32768,
|
||||||
|
"peerId": "(unspec)",
|
||||||
|
"path": "",
|
||||||
|
"origin": "incomplete",
|
||||||
|
"announceNexthopSelf": true,
|
||||||
|
"nhVrfName": "vrf20",
|
||||||
|
"nexthops": [
|
||||||
|
{
|
||||||
|
"ip": "::",
|
||||||
|
"hostname": "r1",
|
||||||
|
"afi": "ipv6",
|
||||||
|
"used": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"2:10": {
|
||||||
|
"2001:2::/64": [
|
||||||
|
{
|
||||||
|
"valid": true,
|
||||||
|
"bestpath": true,
|
||||||
|
"selectionReason": "First path received",
|
||||||
|
"pathFrom": "external",
|
||||||
|
"prefix": "2001:2::",
|
||||||
|
"prefixLen": 64,
|
||||||
|
"network": "2001:2::/64",
|
||||||
|
"metric": 0,
|
||||||
|
"weight": 0,
|
||||||
|
"peerId": "2001::2",
|
||||||
|
"path": "2",
|
||||||
|
"origin": "incomplete",
|
||||||
|
"nexthops": [
|
||||||
|
{
|
||||||
|
"ip": "2001::2",
|
||||||
|
"hostname": "r2",
|
||||||
|
"afi": "ipv6",
|
||||||
|
"used": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"2:20": {
|
||||||
|
"2001:4::/64": [
|
||||||
|
{
|
||||||
|
"valid": true,
|
||||||
|
"bestpath": true,
|
||||||
|
"selectionReason": "First path received",
|
||||||
|
"pathFrom": "external",
|
||||||
|
"prefix": "2001:4::",
|
||||||
|
"prefixLen": 64,
|
||||||
|
"network": "2001:4::/64",
|
||||||
|
"metric": 0,
|
||||||
|
"weight": 0,
|
||||||
|
"peerId": "2001::2",
|
||||||
|
"path": "2",
|
||||||
|
"origin": "incomplete",
|
||||||
|
"nexthops": [
|
||||||
|
{
|
||||||
|
"ip": "2001::2",
|
||||||
|
"hostname": "r2",
|
||||||
|
"afi": "ipv6",
|
||||||
|
"used": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"2001:6::/64": [
|
||||||
|
{
|
||||||
|
"valid": true,
|
||||||
|
"bestpath": true,
|
||||||
|
"selectionReason": "First path received",
|
||||||
|
"pathFrom": "external",
|
||||||
|
"prefix": "2001:6::",
|
||||||
|
"prefixLen": 64,
|
||||||
|
"network": "2001:6::/64",
|
||||||
|
"metric": 0,
|
||||||
|
"weight": 0,
|
||||||
|
"peerId": "2001::2",
|
||||||
|
"path": "2",
|
||||||
|
"origin": "incomplete",
|
||||||
|
"nexthops": [
|
||||||
|
{
|
||||||
|
"ip": "2001::2",
|
||||||
|
"hostname": "r2",
|
||||||
|
"afi": "ipv6",
|
||||||
|
"used": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -34,7 +34,9 @@ segment-routing
|
|||||||
ip forwarding
|
ip forwarding
|
||||||
ipv6 forwarding
|
ipv6 forwarding
|
||||||
!
|
!
|
||||||
|
ipv6 route 2001:db8:2:1::/64 2001::2
|
||||||
ipv6 route 2001:db8:2:2::/64 2001::2
|
ipv6 route 2001:db8:2:2::/64 2001::2
|
||||||
|
ipv6 route 2001:db8:2:3::/64 2001::2
|
||||||
!
|
!
|
||||||
line vty
|
line vty
|
||||||
!
|
!
|
||||||
|
@ -0,0 +1,93 @@
|
|||||||
|
{
|
||||||
|
"vrfId": 0,
|
||||||
|
"vrfName": "default",
|
||||||
|
"routerId": "2.2.2.2",
|
||||||
|
"defaultLocPrf": 100,
|
||||||
|
"localAS": 2,
|
||||||
|
"routes": {
|
||||||
|
"routeDistinguishers": {
|
||||||
|
"2:10": {
|
||||||
|
"2001:2::/64": [
|
||||||
|
{
|
||||||
|
"valid": true,
|
||||||
|
"bestpath": true,
|
||||||
|
"selectionReason": "First path received",
|
||||||
|
"pathFrom": "external",
|
||||||
|
"prefix": "2001:2::",
|
||||||
|
"prefixLen": 64,
|
||||||
|
"network": "2001:2::/64",
|
||||||
|
"metric": 0,
|
||||||
|
"weight": 32768,
|
||||||
|
"peerId": "(unspec)",
|
||||||
|
"path": "",
|
||||||
|
"origin": "incomplete",
|
||||||
|
"announceNexthopSelf": true,
|
||||||
|
"nhVrfName": "vrf10",
|
||||||
|
"nexthops": [
|
||||||
|
{
|
||||||
|
"ip": "::",
|
||||||
|
"hostname": "r2",
|
||||||
|
"afi": "ipv6",
|
||||||
|
"used": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"2:20": {
|
||||||
|
"2001:4::/64": [
|
||||||
|
{
|
||||||
|
"valid": true,
|
||||||
|
"bestpath": true,
|
||||||
|
"selectionReason": "First path received",
|
||||||
|
"pathFrom": "external",
|
||||||
|
"prefix": "2001:4::",
|
||||||
|
"prefixLen": 64,
|
||||||
|
"network": "2001:4::/64",
|
||||||
|
"metric": 0,
|
||||||
|
"weight": 32768,
|
||||||
|
"peerId": "(unspec)",
|
||||||
|
"path": "",
|
||||||
|
"origin": "incomplete",
|
||||||
|
"announceNexthopSelf": true,
|
||||||
|
"nhVrfName": "vrf20",
|
||||||
|
"nexthops": [
|
||||||
|
{
|
||||||
|
"ip": "::",
|
||||||
|
"hostname": "r2",
|
||||||
|
"afi": "ipv6",
|
||||||
|
"used": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"2001:6::/64": [
|
||||||
|
{
|
||||||
|
"valid": true,
|
||||||
|
"bestpath": true,
|
||||||
|
"selectionReason": "First path received",
|
||||||
|
"pathFrom": "external",
|
||||||
|
"prefix": "2001:6::",
|
||||||
|
"prefixLen": 64,
|
||||||
|
"network": "2001:6::/64",
|
||||||
|
"metric": 0,
|
||||||
|
"weight": 32768,
|
||||||
|
"peerId": "(unspec)",
|
||||||
|
"path": "",
|
||||||
|
"origin": "incomplete",
|
||||||
|
"announceNexthopSelf": true,
|
||||||
|
"nhVrfName": "vrf20",
|
||||||
|
"nexthops": [
|
||||||
|
{
|
||||||
|
"ip": "::",
|
||||||
|
"hostname": "r2",
|
||||||
|
"afi": "ipv6",
|
||||||
|
"used": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,169 @@
|
|||||||
|
{
|
||||||
|
"vrfId": 0,
|
||||||
|
"vrfName": "default",
|
||||||
|
"routerId": "2.2.2.2",
|
||||||
|
"defaultLocPrf": 100,
|
||||||
|
"localAS": 2,
|
||||||
|
"routes": {
|
||||||
|
"routeDistinguishers": {
|
||||||
|
"1:10": {
|
||||||
|
"2001:1::/64": [
|
||||||
|
{
|
||||||
|
"valid": true,
|
||||||
|
"bestpath": true,
|
||||||
|
"selectionReason": "First path received",
|
||||||
|
"pathFrom": "external",
|
||||||
|
"prefix": "2001:1::",
|
||||||
|
"prefixLen": 64,
|
||||||
|
"network": "2001:1::/64",
|
||||||
|
"metric": 0,
|
||||||
|
"weight": 0,
|
||||||
|
"peerId": "2001::1",
|
||||||
|
"path": "1",
|
||||||
|
"origin": "incomplete",
|
||||||
|
"nexthops": [
|
||||||
|
{
|
||||||
|
"ip": "2001::1",
|
||||||
|
"hostname": "r1",
|
||||||
|
"afi": "ipv6",
|
||||||
|
"used": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"2001:3::/64": [
|
||||||
|
{
|
||||||
|
"valid": true,
|
||||||
|
"bestpath": true,
|
||||||
|
"selectionReason": "First path received",
|
||||||
|
"pathFrom": "external",
|
||||||
|
"prefix": "2001:3::",
|
||||||
|
"prefixLen": 64,
|
||||||
|
"network": "2001:3::/64",
|
||||||
|
"metric": 0,
|
||||||
|
"weight": 0,
|
||||||
|
"peerId": "2001::1",
|
||||||
|
"path": "1",
|
||||||
|
"origin": "incomplete",
|
||||||
|
"nexthops": [
|
||||||
|
{
|
||||||
|
"ip": "2001::1",
|
||||||
|
"hostname": "r1",
|
||||||
|
"afi": "ipv6",
|
||||||
|
"used": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"1:20": {
|
||||||
|
"2001:5::/64": [
|
||||||
|
{
|
||||||
|
"valid": true,
|
||||||
|
"bestpath": true,
|
||||||
|
"selectionReason": "First path received",
|
||||||
|
"pathFrom": "external",
|
||||||
|
"prefix": "2001:5::",
|
||||||
|
"prefixLen": 64,
|
||||||
|
"network": "2001:5::/64",
|
||||||
|
"metric": 0,
|
||||||
|
"weight": 0,
|
||||||
|
"peerId": "2001::1",
|
||||||
|
"path": "1",
|
||||||
|
"origin": "incomplete",
|
||||||
|
"nexthops": [
|
||||||
|
{
|
||||||
|
"ip": "2001::1",
|
||||||
|
"hostname": "r1",
|
||||||
|
"afi": "ipv6",
|
||||||
|
"used": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"2:10": {
|
||||||
|
"2001:2::/64": [
|
||||||
|
{
|
||||||
|
"valid": true,
|
||||||
|
"bestpath": true,
|
||||||
|
"selectionReason": "First path received",
|
||||||
|
"pathFrom": "external",
|
||||||
|
"prefix": "2001:2::",
|
||||||
|
"prefixLen": 64,
|
||||||
|
"network": "2001:2::/64",
|
||||||
|
"metric": 0,
|
||||||
|
"weight": 32768,
|
||||||
|
"peerId": "(unspec)",
|
||||||
|
"path": "",
|
||||||
|
"origin": "incomplete",
|
||||||
|
"announceNexthopSelf": true,
|
||||||
|
"nhVrfName": "vrf10",
|
||||||
|
"nexthops": [
|
||||||
|
{
|
||||||
|
"ip": "::",
|
||||||
|
"hostname": "r2",
|
||||||
|
"afi": "ipv6",
|
||||||
|
"used": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"2:20": {
|
||||||
|
"2001:4::/64": [
|
||||||
|
{
|
||||||
|
"valid": true,
|
||||||
|
"bestpath": true,
|
||||||
|
"selectionReason": "First path received",
|
||||||
|
"pathFrom": "external",
|
||||||
|
"prefix": "2001:4::",
|
||||||
|
"prefixLen": 64,
|
||||||
|
"network": "2001:4::/64",
|
||||||
|
"metric": 0,
|
||||||
|
"weight": 32768,
|
||||||
|
"peerId": "(unspec)",
|
||||||
|
"path": "",
|
||||||
|
"origin": "incomplete",
|
||||||
|
"announceNexthopSelf": true,
|
||||||
|
"nhVrfName": "vrf20",
|
||||||
|
"nexthops": [
|
||||||
|
{
|
||||||
|
"ip": "::",
|
||||||
|
"hostname": "r2",
|
||||||
|
"afi": "ipv6",
|
||||||
|
"used": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"2001:6::/64": [
|
||||||
|
{
|
||||||
|
"valid": true,
|
||||||
|
"bestpath": true,
|
||||||
|
"selectionReason": "First path received",
|
||||||
|
"pathFrom": "external",
|
||||||
|
"prefix": "2001:6::",
|
||||||
|
"prefixLen": 64,
|
||||||
|
"network": "2001:6::/64",
|
||||||
|
"metric": 0,
|
||||||
|
"weight": 32768,
|
||||||
|
"peerId": "(unspec)",
|
||||||
|
"path": "",
|
||||||
|
"origin": "incomplete",
|
||||||
|
"announceNexthopSelf": true,
|
||||||
|
"nhVrfName": "vrf20",
|
||||||
|
"nexthops": [
|
||||||
|
{
|
||||||
|
"ip": "::",
|
||||||
|
"hostname": "r2",
|
||||||
|
"afi": "ipv6",
|
||||||
|
"used": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -35,6 +35,8 @@ ip forwarding
|
|||||||
ipv6 forwarding
|
ipv6 forwarding
|
||||||
!
|
!
|
||||||
ipv6 route 2001:db8:1:1::/64 2001::1
|
ipv6 route 2001:db8:1:1::/64 2001::1
|
||||||
|
ipv6 route 2001:db8:1:2::/64 2001::1
|
||||||
|
ipv6 route 2001:db8:1:3::/64 2001::1
|
||||||
!
|
!
|
||||||
line vty
|
line vty
|
||||||
!
|
!
|
||||||
|
@ -129,6 +129,10 @@ def setup_module(mod):
|
|||||||
tgen.gears["r2"].run("ip link set eth3 master vrf20")
|
tgen.gears["r2"].run("ip link set eth3 master vrf20")
|
||||||
tgen.start_router()
|
tgen.start_router()
|
||||||
|
|
||||||
|
# FOR DEVELOPER:
|
||||||
|
# If you want to stop some specific line and start interactive shell,
|
||||||
|
# please use tgen.mininet_cli() to start it.
|
||||||
|
|
||||||
|
|
||||||
def teardown_module(mod):
|
def teardown_module(mod):
|
||||||
tgen = get_topogen()
|
tgen = get_topogen()
|
||||||
@ -143,7 +147,22 @@ def open_json_file(filename):
|
|||||||
assert False, "Could not read file {}".format(filename)
|
assert False, "Could not read file {}".format(filename)
|
||||||
|
|
||||||
|
|
||||||
def test_rib():
|
def check_ping(name, dest_addr, expect_connected):
|
||||||
|
def _check(name, dest_addr, match):
|
||||||
|
tgen = get_topogen()
|
||||||
|
output = tgen.gears[name].run("ping6 {} -c 1 -w 1".format(dest_addr))
|
||||||
|
logger.info(output)
|
||||||
|
assert match in output, "ping fail"
|
||||||
|
|
||||||
|
match = "{} packet loss".format("0%" if expect_connected else "100%")
|
||||||
|
logger.info("[+] check {} {} {}".format(name, dest_addr, match))
|
||||||
|
tgen = get_topogen()
|
||||||
|
func = functools.partial(_check, name, dest_addr, match)
|
||||||
|
success, result = topotest.run_and_expect(func, None, count=10, wait=0.5)
|
||||||
|
assert result is None, "Failed"
|
||||||
|
|
||||||
|
|
||||||
|
def check_rib(name, cmd, expected_file):
|
||||||
def _check(name, cmd, expected_file):
|
def _check(name, cmd, expected_file):
|
||||||
logger.info("polling")
|
logger.info("polling")
|
||||||
tgen = get_topogen()
|
tgen = get_topogen()
|
||||||
@ -152,51 +171,131 @@ def test_rib():
|
|||||||
expected = open_json_file("{}/{}".format(CWD, expected_file))
|
expected = open_json_file("{}/{}".format(CWD, expected_file))
|
||||||
return topotest.json_cmp(output, expected)
|
return topotest.json_cmp(output, expected)
|
||||||
|
|
||||||
def check(name, cmd, expected_file):
|
logger.info("[+] check {} \"{}\" {}".format(name, cmd, expected_file))
|
||||||
logger.info('[+] check {} "{}" {}'.format(name, cmd, expected_file))
|
tgen = get_topogen()
|
||||||
tgen = get_topogen()
|
func = functools.partial(_check, name, cmd, expected_file)
|
||||||
func = functools.partial(_check, name, cmd, expected_file)
|
success, result = topotest.run_and_expect(func, None, count=10, wait=0.5)
|
||||||
success, result = topotest.run_and_expect(func, None, count=10, wait=0.5)
|
assert result is None, "Failed"
|
||||||
assert result is None, "Failed"
|
|
||||||
|
|
||||||
check("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib.json")
|
|
||||||
check("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib.json")
|
def test_rib():
|
||||||
check("r1", "show ipv6 route vrf vrf10 json", "r1/vrf10_rib.json")
|
check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib.json")
|
||||||
check("r1", "show ipv6 route vrf vrf20 json", "r1/vrf20_rib.json")
|
check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib.json")
|
||||||
check("r2", "show ipv6 route vrf vrf10 json", "r2/vrf10_rib.json")
|
check_rib("r1", "show ipv6 route vrf vrf10 json", "r1/vrf10_rib.json")
|
||||||
check("r2", "show ipv6 route vrf vrf20 json", "r2/vrf20_rib.json")
|
check_rib("r1", "show ipv6 route vrf vrf20 json", "r1/vrf20_rib.json")
|
||||||
check("ce1", "show ipv6 route json", "ce1/ipv6_rib.json")
|
check_rib("r2", "show ipv6 route vrf vrf10 json", "r2/vrf10_rib.json")
|
||||||
check("ce2", "show ipv6 route json", "ce2/ipv6_rib.json")
|
check_rib("r2", "show ipv6 route vrf vrf20 json", "r2/vrf20_rib.json")
|
||||||
check("ce3", "show ipv6 route json", "ce3/ipv6_rib.json")
|
check_rib("ce1", "show ipv6 route json", "ce1/ipv6_rib.json")
|
||||||
check("ce4", "show ipv6 route json", "ce4/ipv6_rib.json")
|
check_rib("ce2", "show ipv6 route json", "ce2/ipv6_rib.json")
|
||||||
check("ce5", "show ipv6 route json", "ce5/ipv6_rib.json")
|
check_rib("ce3", "show ipv6 route json", "ce3/ipv6_rib.json")
|
||||||
check("ce6", "show ipv6 route json", "ce6/ipv6_rib.json")
|
check_rib("ce4", "show ipv6 route json", "ce4/ipv6_rib.json")
|
||||||
|
check_rib("ce5", "show ipv6 route json", "ce5/ipv6_rib.json")
|
||||||
|
check_rib("ce6", "show ipv6 route json", "ce6/ipv6_rib.json")
|
||||||
|
|
||||||
|
|
||||||
def test_ping():
|
def test_ping():
|
||||||
def _check(name, dest_addr, match):
|
check_ping("ce1", "2001:2::2", True)
|
||||||
tgen = get_topogen()
|
check_ping("ce1", "2001:3::2", True)
|
||||||
output = tgen.gears[name].run("ping6 {} -c 1 -w 1".format(dest_addr))
|
check_ping("ce1", "2001:4::2", False)
|
||||||
logger.info(output)
|
check_ping("ce1", "2001:5::2", False)
|
||||||
assert match in output, "ping fail"
|
check_ping("ce1", "2001:6::2", False)
|
||||||
|
check_ping("ce4", "2001:1::2", False)
|
||||||
|
check_ping("ce4", "2001:2::2", False)
|
||||||
|
check_ping("ce4", "2001:3::2", False)
|
||||||
|
check_ping("ce4", "2001:5::2", True)
|
||||||
|
check_ping("ce4", "2001:6::2", True)
|
||||||
|
|
||||||
def check(name, dest_addr, match):
|
|
||||||
logger.info("[+] check {} {} {}".format(name, dest_addr, match))
|
|
||||||
tgen = get_topogen()
|
|
||||||
func = functools.partial(_check, name, dest_addr, match)
|
|
||||||
success, result = topotest.run_and_expect(func, None, count=10, wait=0.5)
|
|
||||||
assert result is None, "Failed"
|
|
||||||
|
|
||||||
check("ce1", "2001:2::2", " 0% packet loss")
|
def test_locator_delete():
|
||||||
check("ce1", "2001:3::2", " 0% packet loss")
|
check_ping("ce1", "2001:2::2", True)
|
||||||
check("ce1", "2001:4::2", " 100% packet loss")
|
get_topogen().gears["r1"].vtysh_cmd(
|
||||||
check("ce1", "2001:5::2", " 100% packet loss")
|
"""
|
||||||
check("ce1", "2001:6::2", " 100% packet loss")
|
configure terminal
|
||||||
check("ce4", "2001:1::2", " 100% packet loss")
|
segment-routing
|
||||||
check("ce4", "2001:2::2", " 100% packet loss")
|
srv6
|
||||||
check("ce4", "2001:3::2", " 100% packet loss")
|
locators
|
||||||
check("ce4", "2001:5::2", " 0% packet loss")
|
no locator loc1
|
||||||
check("ce4", "2001:6::2", " 0% packet loss")
|
"""
|
||||||
|
)
|
||||||
|
check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_locator_deleted.json")
|
||||||
|
check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_locator_deleted.json")
|
||||||
|
check_ping("ce1", "2001:2::2", False)
|
||||||
|
|
||||||
|
|
||||||
|
def test_locator_recreate():
|
||||||
|
check_ping("ce1", "2001:2::2", False)
|
||||||
|
get_topogen().gears["r1"].vtysh_cmd(
|
||||||
|
"""
|
||||||
|
configure terminal
|
||||||
|
segment-routing
|
||||||
|
srv6
|
||||||
|
locators
|
||||||
|
locator loc1
|
||||||
|
prefix 2001:db8:1:1::/64
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_locator_recreated.json")
|
||||||
|
check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_locator_recreated.json")
|
||||||
|
check_ping("ce1", "2001:2::2", True)
|
||||||
|
|
||||||
|
|
||||||
|
def test_bgp_locator_unset():
|
||||||
|
check_ping("ce1", "2001:2::2", True)
|
||||||
|
get_topogen().gears["r1"].vtysh_cmd(
|
||||||
|
"""
|
||||||
|
configure terminal
|
||||||
|
router bgp 1
|
||||||
|
segment-routing srv6
|
||||||
|
no locator loc1
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_locator_deleted.json")
|
||||||
|
check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_locator_deleted.json")
|
||||||
|
check_ping("ce1", "2001:2::2", False)
|
||||||
|
|
||||||
|
|
||||||
|
def test_bgp_locator_reset():
|
||||||
|
check_ping("ce1", "2001:2::2", False)
|
||||||
|
get_topogen().gears["r1"].vtysh_cmd(
|
||||||
|
"""
|
||||||
|
configure terminal
|
||||||
|
router bgp 1
|
||||||
|
segment-routing srv6
|
||||||
|
locator loc1
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_locator_recreated.json")
|
||||||
|
check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_locator_recreated.json")
|
||||||
|
check_ping("ce1", "2001:2::2", True)
|
||||||
|
|
||||||
|
|
||||||
|
def test_bgp_srv6_unset():
|
||||||
|
check_ping("ce1", "2001:2::2", True)
|
||||||
|
get_topogen().gears["r1"].vtysh_cmd(
|
||||||
|
"""
|
||||||
|
configure terminal
|
||||||
|
router bgp 1
|
||||||
|
no segment-routing srv6
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_locator_deleted.json")
|
||||||
|
check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_locator_deleted.json")
|
||||||
|
check_ping("ce1", "2001:2::2", False)
|
||||||
|
|
||||||
|
|
||||||
|
def test_bgp_srv6_reset():
|
||||||
|
check_ping("ce1", "2001:2::2", False)
|
||||||
|
get_topogen().gears["r1"].vtysh_cmd(
|
||||||
|
"""
|
||||||
|
configure terminal
|
||||||
|
router bgp 1
|
||||||
|
segment-routing srv6
|
||||||
|
locator loc1
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_locator_recreated.json")
|
||||||
|
check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_locator_recreated.json")
|
||||||
|
check_ping("ce1", "2001:2::2", True)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
@ -1,6 +1,2 @@
|
|||||||
[
|
[
|
||||||
{
|
|
||||||
"name": "loc3",
|
|
||||||
"chunks": []
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
|
@ -1,8 +1,2 @@
|
|||||||
[
|
[
|
||||||
{
|
|
||||||
"name": "loc3",
|
|
||||||
"chunks": [
|
|
||||||
"2001:db8:3:3::/64"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
|
2
tests/topotests/srv6_locator/expected_chunks6.json
Normal file
2
tests/topotests/srv6_locator/expected_chunks6.json
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[
|
||||||
|
]
|
@ -23,11 +23,13 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name":"loc3",
|
"name": "loc3",
|
||||||
"statusUp":false,
|
"prefix": "2001:db8:3:3::/64",
|
||||||
"chunks":[
|
"statusUp": true,
|
||||||
|
"chunks": [
|
||||||
{
|
{
|
||||||
"proto":"sharp"
|
"prefix": "2001:db8:3:3::/64",
|
||||||
|
"proto": "system"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,5 @@
|
|||||||
{
|
{
|
||||||
"locators":[
|
"locators":[
|
||||||
{
|
|
||||||
"name": "loc1",
|
|
||||||
"prefix": "2001:db8:1:1::/64",
|
|
||||||
"statusUp": true,
|
|
||||||
"chunks": [
|
|
||||||
{
|
|
||||||
"prefix": "2001:db8:1:1::/64",
|
|
||||||
"proto": "system"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "loc2",
|
"name": "loc2",
|
||||||
"prefix": "2001:db8:2:2::/64",
|
"prefix": "2001:db8:2:2::/64",
|
||||||
@ -29,7 +18,7 @@
|
|||||||
"chunks":[
|
"chunks":[
|
||||||
{
|
{
|
||||||
"prefix": "2001:db8:3:3::/64",
|
"prefix": "2001:db8:3:3::/64",
|
||||||
"proto": "sharp"
|
"proto": "system"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
5
tests/topotests/srv6_locator/expected_locators6.json
Normal file
5
tests/topotests/srv6_locator/expected_locators6.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"locators":[
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -102,6 +102,10 @@ def test_srv6():
|
|||||||
success, result = topotest.run_and_expect(func, None, count=5, wait=0.5)
|
success, result = topotest.run_and_expect(func, None, count=5, wait=0.5)
|
||||||
assert result is None, "Failed"
|
assert result is None, "Failed"
|
||||||
|
|
||||||
|
# FOR DEVELOPER:
|
||||||
|
# If you want to stop some specific line and start interactive shell,
|
||||||
|
# please use tgen.mininet_cli() to start it.
|
||||||
|
|
||||||
logger.info("Test1 for Locator Configuration")
|
logger.info("Test1 for Locator Configuration")
|
||||||
check_srv6_locator(router, "expected_locators1.json")
|
check_srv6_locator(router, "expected_locators1.json")
|
||||||
check_sharpd_chunk(router, "expected_chunks1.json")
|
check_sharpd_chunk(router, "expected_chunks1.json")
|
||||||
@ -116,12 +120,7 @@ def test_srv6():
|
|||||||
check_srv6_locator(router, "expected_locators3.json")
|
check_srv6_locator(router, "expected_locators3.json")
|
||||||
check_sharpd_chunk(router, "expected_chunks3.json")
|
check_sharpd_chunk(router, "expected_chunks3.json")
|
||||||
|
|
||||||
logger.info("Test4 get chunk for non-exist locator by zclient")
|
logger.info("Test4 additional locator loc3")
|
||||||
router.vtysh_cmd("sharp srv6-manager get-locator-chunk loc3")
|
|
||||||
check_srv6_locator(router, "expected_locators4.json")
|
|
||||||
check_sharpd_chunk(router, "expected_chunks4.json")
|
|
||||||
|
|
||||||
logger.info("Test5 Test for Zclient. after locator loc3 was configured")
|
|
||||||
router.vtysh_cmd(
|
router.vtysh_cmd(
|
||||||
"""
|
"""
|
||||||
configure terminal
|
configure terminal
|
||||||
@ -132,9 +131,33 @@ def test_srv6():
|
|||||||
prefix 2001:db8:3:3::/64
|
prefix 2001:db8:3:3::/64
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
check_srv6_locator(router, "expected_locators4.json")
|
||||||
|
check_sharpd_chunk(router, "expected_chunks4.json")
|
||||||
|
|
||||||
|
logger.info("Test5 delete locator and chunk is released automatically")
|
||||||
|
router.vtysh_cmd(
|
||||||
|
"""
|
||||||
|
configure terminal
|
||||||
|
segment-routing
|
||||||
|
srv6
|
||||||
|
locators
|
||||||
|
no locator loc1
|
||||||
|
"""
|
||||||
|
)
|
||||||
check_srv6_locator(router, "expected_locators5.json")
|
check_srv6_locator(router, "expected_locators5.json")
|
||||||
check_sharpd_chunk(router, "expected_chunks5.json")
|
check_sharpd_chunk(router, "expected_chunks5.json")
|
||||||
|
|
||||||
|
logger.info("Test6 delete srv6 all configuration")
|
||||||
|
router.vtysh_cmd(
|
||||||
|
"""
|
||||||
|
configure terminal
|
||||||
|
segment-routing
|
||||||
|
no srv6
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
check_srv6_locator(router, "expected_locators6.json")
|
||||||
|
check_sharpd_chunk(router, "expected_chunks6.json")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
args = ["-s"] + sys.argv[1:]
|
args = ["-s"] + sys.argv[1:]
|
||||||
|
@ -1137,6 +1137,31 @@ static int zsend_table_manager_connect_response(struct zserv *client,
|
|||||||
return zserv_send_message(client, s);
|
return zserv_send_message(client, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* SRv6 locator add notification from zebra daemon. */
|
||||||
|
int zsend_zebra_srv6_locator_add(struct zserv *client, struct srv6_locator *loc)
|
||||||
|
{
|
||||||
|
struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ);
|
||||||
|
|
||||||
|
zclient_create_header(s, ZEBRA_SRV6_LOCATOR_ADD, VRF_DEFAULT);
|
||||||
|
zapi_srv6_locator_encode(s, loc);
|
||||||
|
stream_putw_at(s, 0, stream_get_endp(s));
|
||||||
|
|
||||||
|
return zserv_send_message(client, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SRv6 locator delete notification from zebra daemon. */
|
||||||
|
int zsend_zebra_srv6_locator_delete(struct zserv *client,
|
||||||
|
struct srv6_locator *loc)
|
||||||
|
{
|
||||||
|
struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ);
|
||||||
|
|
||||||
|
zclient_create_header(s, ZEBRA_SRV6_LOCATOR_DELETE, VRF_DEFAULT);
|
||||||
|
zapi_srv6_locator_encode(s, loc);
|
||||||
|
stream_putw_at(s, 0, stream_get_endp(s));
|
||||||
|
|
||||||
|
return zserv_send_message(client, s);
|
||||||
|
}
|
||||||
|
|
||||||
/* Inbound message handling ------------------------------------------------ */
|
/* Inbound message handling ------------------------------------------------ */
|
||||||
|
|
||||||
const int cmd2type[] = {
|
const int cmd2type[] = {
|
||||||
|
@ -106,15 +106,60 @@ void zebra_srv6_locator_add(struct srv6_locator *locator)
|
|||||||
{
|
{
|
||||||
struct zebra_srv6 *srv6 = zebra_srv6_get_default();
|
struct zebra_srv6 *srv6 = zebra_srv6_get_default();
|
||||||
struct srv6_locator *tmp;
|
struct srv6_locator *tmp;
|
||||||
|
struct listnode *node;
|
||||||
|
struct zserv *client;
|
||||||
|
|
||||||
tmp = zebra_srv6_locator_lookup(locator->name);
|
tmp = zebra_srv6_locator_lookup(locator->name);
|
||||||
if (!tmp)
|
if (!tmp)
|
||||||
listnode_add(srv6->locators, locator);
|
listnode_add(srv6->locators, locator);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Notify new locator info to zclients.
|
||||||
|
*
|
||||||
|
* The srv6 locators and their prefixes are managed by zserv(zebra).
|
||||||
|
* And an actual configuration the srv6 sid in the srv6 locator is done
|
||||||
|
* by zclient(bgpd, isisd, etc). The configuration of each locator
|
||||||
|
* allocation and specify it by zserv and zclient should be
|
||||||
|
* asynchronous. For that, zclient should be received the event via
|
||||||
|
* ZAPI when a srv6 locator is added on zebra.
|
||||||
|
* Basically, in SRv6, adding/removing SRv6 locators is performed less
|
||||||
|
* frequently than adding rib entries, so a broad to all zclients will
|
||||||
|
* not degrade the overall performance of FRRouting.
|
||||||
|
*/
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client))
|
||||||
|
zsend_zebra_srv6_locator_add(client, locator);
|
||||||
}
|
}
|
||||||
|
|
||||||
void zebra_srv6_locator_delete(struct srv6_locator *locator)
|
void zebra_srv6_locator_delete(struct srv6_locator *locator)
|
||||||
{
|
{
|
||||||
|
struct listnode *n;
|
||||||
|
struct srv6_locator_chunk *c;
|
||||||
struct zebra_srv6 *srv6 = zebra_srv6_get_default();
|
struct zebra_srv6 *srv6 = zebra_srv6_get_default();
|
||||||
|
struct zserv *client;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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((struct list *)locator->chunks, n, c)) {
|
||||||
|
if (c->proto == ZEBRA_ROUTE_SYSTEM)
|
||||||
|
continue;
|
||||||
|
client = zserv_find_client(c->proto, c->instance);
|
||||||
|
if (!client) {
|
||||||
|
zlog_warn(
|
||||||
|
"%s: Not found zclient(proto=%u, instance=%u).",
|
||||||
|
__func__, c->proto, c->instance);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
zsend_zebra_srv6_locator_delete(client, locator);
|
||||||
|
}
|
||||||
|
|
||||||
listnode_delete(srv6->locators, locator);
|
listnode_delete(srv6->locators, locator);
|
||||||
}
|
}
|
||||||
@ -171,19 +216,7 @@ assign_srv6_locator_chunk(uint8_t proto,
|
|||||||
if (!loc) {
|
if (!loc) {
|
||||||
zlog_info("%s: locator %s was not found",
|
zlog_info("%s: locator %s was not found",
|
||||||
__func__, locator_name);
|
__func__, locator_name);
|
||||||
|
return NULL;
|
||||||
loc = srv6_locator_alloc(locator_name);
|
|
||||||
if (!loc) {
|
|
||||||
zlog_info("%s: locator %s can't allocated",
|
|
||||||
__func__, locator_name);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
loc->status_up = false;
|
|
||||||
chunk = srv6_locator_chunk_alloc();
|
|
||||||
chunk->proto = NO_PROTO;
|
|
||||||
listnode_add(loc->chunks, chunk);
|
|
||||||
zebra_srv6_locator_add(loc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (ALL_LIST_ELEMENTS_RO((struct list *)loc->chunks, node, chunk)) {
|
for (ALL_LIST_ELEMENTS_RO((struct list *)loc->chunks, node, chunk)) {
|
||||||
|
@ -197,6 +197,21 @@ DEFUN_NOSH (srv6,
|
|||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFUN (no_srv6,
|
||||||
|
no_srv6_cmd,
|
||||||
|
"no srv6",
|
||||||
|
NO_STR
|
||||||
|
"Segment Routing SRv6\n")
|
||||||
|
{
|
||||||
|
struct zebra_srv6 *srv6 = zebra_srv6_get_default();
|
||||||
|
struct srv6_locator *locator;
|
||||||
|
struct listnode *node, *nnode;
|
||||||
|
|
||||||
|
for (ALL_LIST_ELEMENTS(srv6->locators, node, nnode, locator))
|
||||||
|
zebra_srv6_locator_delete(locator);
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
DEFUN_NOSH (srv6_locators,
|
DEFUN_NOSH (srv6_locators,
|
||||||
srv6_locators_cmd,
|
srv6_locators_cmd,
|
||||||
"locators",
|
"locators",
|
||||||
@ -233,6 +248,23 @@ DEFUN_NOSH (srv6_locator,
|
|||||||
return CMD_SUCCESS;
|
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")
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
zebra_srv6_locator_delete(locator);
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
DEFPY (locator_prefix,
|
DEFPY (locator_prefix,
|
||||||
locator_prefix_cmd,
|
locator_prefix_cmd,
|
||||||
"prefix X:X::X:X/M$prefix [func-bits (16-64)$func_bit_len]",
|
"prefix X:X::X:X/M$prefix [func-bits (16-64)$func_bit_len]",
|
||||||
@ -348,8 +380,10 @@ void zebra_srv6_vty_init(void)
|
|||||||
/* Command for change node */
|
/* Command for change node */
|
||||||
install_element(CONFIG_NODE, &segment_routing_cmd);
|
install_element(CONFIG_NODE, &segment_routing_cmd);
|
||||||
install_element(SEGMENT_ROUTING_NODE, &srv6_cmd);
|
install_element(SEGMENT_ROUTING_NODE, &srv6_cmd);
|
||||||
|
install_element(SEGMENT_ROUTING_NODE, &no_srv6_cmd);
|
||||||
install_element(SRV6_NODE, &srv6_locators_cmd);
|
install_element(SRV6_NODE, &srv6_locators_cmd);
|
||||||
install_element(SRV6_LOCS_NODE, &srv6_locator_cmd);
|
install_element(SRV6_LOCS_NODE, &srv6_locator_cmd);
|
||||||
|
install_element(SRV6_LOCS_NODE, &no_srv6_locator_cmd);
|
||||||
|
|
||||||
/* Command for configuration */
|
/* Command for configuration */
|
||||||
install_element(SRV6_LOC_NODE, &locator_prefix_cmd);
|
install_element(SRV6_LOC_NODE, &locator_prefix_cmd);
|
||||||
|
Loading…
Reference in New Issue
Block a user