From 7a4b49bdd1ce453cb50a84167fb9f3e2f8e58630 Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Wed, 19 Feb 2020 21:46:24 +0900 Subject: [PATCH 01/66] lib: refactor func prototype seg6local_context2str (step1) Make seg6local_context2str function's prototype better. This function is added on commit e496b4203, and function interface's considering wasn't enough. Signed-off-by: Hiroki Shirokura --- lib/srv6.c | 3 ++- lib/srv6.h | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/srv6.c b/lib/srv6.c index 287bf56089..9b9f402987 100644 --- a/lib/srv6.c +++ b/lib/srv6.c @@ -76,7 +76,8 @@ int snprintf_seg6_segs(char *str, } const char *seg6local_context2str(char *str, size_t size, - struct seg6local_context *ctx, uint32_t action) + const struct seg6local_context *ctx, + uint32_t action) { char b0[128]; diff --git a/lib/srv6.h b/lib/srv6.h index 24c7ffc3a2..b72b098c78 100644 --- a/lib/srv6.h +++ b/lib/srv6.h @@ -119,9 +119,9 @@ static inline void *sid_copy(struct in6_addr *dst, const char * seg6local_action2str(uint32_t action); -const char * -seg6local_context2str(char *str, size_t size, - struct seg6local_context *ctx, uint32_t action); +const char *seg6local_context2str(char *str, size_t size, + const struct seg6local_context *ctx, + uint32_t action); int snprintf_seg6_segs(char *str, size_t size, const struct seg6_segs *segs); From cb7775a9740d78ba81b5126fcb637102e4bad1d6 Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Wed, 19 Aug 2020 09:46:33 +0900 Subject: [PATCH 02/66] lib: add new nexthop's attributes seg6local (step1) This commit is a part of #5853 works that add new nexthop's addional object for SRv6 routing about seg6local route. Before this commit, we can add MPLS info as additional object on nexthop. This commit make it add more support about seg6local routes. seg6local routes are ones of the LWT routing mechanism, so configuration of seg6local routes is performed by ZEBRA_ROUTE_SEND, it's same as MPLS configuration. Real configuration implementation isn't implemented at this commit. later commit add that. This commit add only nexthop additional object and some misc functions. Signed-off-by: Hiroki Shirokura --- lib/nexthop.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++ lib/nexthop.h | 8 +++++++ lib/zclient.c | 39 ++++++++++++++++++++++++++++++++++ lib/zclient.h | 14 ++++++++++++ 4 files changed, 120 insertions(+) diff --git a/lib/nexthop.c b/lib/nexthop.c index 0ac6c0ae1b..3c36dbf69a 100644 --- a/lib/nexthop.c +++ b/lib/nexthop.c @@ -36,6 +36,7 @@ DEFINE_MTYPE_STATIC(LIB, NEXTHOP, "Nexthop"); DEFINE_MTYPE_STATIC(LIB, NH_LABEL, "Nexthop label"); +DEFINE_MTYPE_STATIC(LIB, NH_SEG6LOCAL, "Nexthop seg6local"); static int _nexthop_labels_cmp(const struct nexthop *nh1, const struct nexthop *nh2) @@ -66,6 +67,28 @@ static int _nexthop_labels_cmp(const struct nexthop *nh1, (nhl1->num_labels * sizeof(mpls_label_t))); } +static int _nexthop_seg6local_cmp(const struct nexthop *nh1, + const struct nexthop *nh2) +{ + if (nh1->nh_seg6local_action > nh2->nh_seg6local_action) + return 1; + + if (nh2->nh_seg6local_action < nh1->nh_seg6local_action) + return -1; + + if (!nh1->nh_seg6local_ctx && !nh2->nh_seg6local_ctx) + return 0; + + if (nh1->nh_seg6local_ctx && !nh2->nh_seg6local_ctx) + return 1; + + if (!nh1->nh_seg6local_ctx && nh2->nh_seg6local_ctx) + return -1; + + return memcmp(nh1->nh_seg6local_ctx, nh2->nh_seg6local_ctx, + sizeof(struct seg6local_context)); +} + int nexthop_g_addr_cmp(enum nexthop_types_t type, const union g_addr *addr1, const union g_addr *addr2) { @@ -199,6 +222,10 @@ int nexthop_cmp(const struct nexthop *next1, const struct nexthop *next2) return ret; ret = _nexthop_labels_cmp(next1, next2); + if (ret != 0) + return ret; + + ret = _nexthop_seg6local_cmp(next1, next2); return ret; } @@ -353,6 +380,7 @@ struct nexthop *nexthop_new(void) void nexthop_free(struct nexthop *nexthop) { nexthop_del_labels(nexthop); + nexthop_del_seg6local(nexthop); if (nexthop->resolved) nexthops_free(nexthop->resolved); XFREE(MTYPE_NEXTHOP, nexthop); @@ -523,6 +551,27 @@ void nexthop_del_labels(struct nexthop *nexthop) nexthop->nh_label_type = ZEBRA_LSP_NONE; } +void nexthop_add_seg6local(struct nexthop *nexthop, uint32_t action, + const struct seg6local_context *ctx) +{ + struct seg6local_context *nh_ctx; + + if (action == ZEBRA_SEG6_LOCAL_ACTION_UNSPEC) + return; + + nh_ctx = XCALLOC(MTYPE_NH_SEG6LOCAL, sizeof(struct seg6local_context)); + if (ctx) + *nh_ctx = *ctx; + nexthop->nh_seg6local_action = action; + nexthop->nh_seg6local_ctx = nh_ctx; +} + +void nexthop_del_seg6local(struct nexthop *nexthop) +{ + XFREE(MTYPE_NH_SEG6LOCAL, nexthop->nh_seg6local_ctx); + nexthop->nh_seg6local_action = ZEBRA_SEG6_LOCAL_ACTION_UNSPEC; +} + const char *nexthop2str(const struct nexthop *nexthop, char *str, int size) { switch (nexthop->type) { @@ -668,6 +717,12 @@ uint32_t nexthop_hash_quick(const struct nexthop *nexthop) key = jhash_1word(nexthop->backup_idx[i], key); } + if (nexthop->nh_seg6local_ctx) { + key = jhash_1word(nexthop->nh_seg6local_action, key); + key = jhash(nexthop->nh_seg6local_ctx, + sizeof(nexthop->nh_seg6local_ctx), key); + } + return key; } @@ -720,6 +775,10 @@ void nexthop_copy_no_recurse(struct nexthop *copy, nexthop_add_labels(copy, nexthop->nh_label_type, nexthop->nh_label->num_labels, &nexthop->nh_label->label[0]); + + if (nexthop->nh_seg6local_ctx) + nexthop_add_seg6local(copy, nexthop->nh_seg6local_action, + nexthop->nh_seg6local_ctx); } void nexthop_copy(struct nexthop *copy, const struct nexthop *nexthop, diff --git a/lib/nexthop.h b/lib/nexthop.h index d6ea83cf06..7bddee8713 100644 --- a/lib/nexthop.h +++ b/lib/nexthop.h @@ -26,6 +26,7 @@ #include "prefix.h" #include "mpls.h" #include "vxlan.h" +#include "srv6.h" #ifdef __cplusplus extern "C" { @@ -139,6 +140,10 @@ struct nexthop { /* SR-TE color used for matching SR-TE policies */ uint32_t srte_color; + + /* SRv6 localsid info for Endpoint-behaviour */ + enum seg6local_action_t nh_seg6local_action; + struct seg6local_context *nh_seg6local_ctx; }; /* Utility to append one nexthop to another. */ @@ -157,6 +162,9 @@ void nexthops_free(struct nexthop *nexthop); void nexthop_add_labels(struct nexthop *nexthop, enum lsp_types_t ltype, uint8_t num_labels, const mpls_label_t *labels); void nexthop_del_labels(struct nexthop *); +void nexthop_add_seg6local(struct nexthop *nexthop, uint32_t action, + const struct seg6local_context *ctx); +void nexthop_del_seg6local(struct nexthop *nexthop); /* * Allocate a new nexthop object and initialize it from various args. diff --git a/lib/zclient.c b/lib/zclient.c index 3ea1789441..bf67392cbe 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -796,6 +796,19 @@ static int zapi_nexthop_labels_cmp(const struct zapi_nexthop *next1, return memcmp(next1->labels, next2->labels, next1->label_num); } +static int zapi_nexthop_seg6local_cmp(const struct zapi_nexthop *next1, + const struct zapi_nexthop *next2) +{ + if (next1->seg6local_action > next2->seg6local_action) + return 1; + + if (next1->seg6local_action < next2->seg6local_action) + return -1; + + return memcmp(&next1->seg6local_ctx, &next2->seg6local_ctx, + sizeof(struct seg6local_context)); +} + static int zapi_nexthop_cmp_no_labels(const struct zapi_nexthop *next1, const struct zapi_nexthop *next2) { @@ -896,6 +909,10 @@ static int zapi_nexthop_cmp(const void *item1, const void *item2) return ret; ret = zapi_nexthop_labels_cmp(next1, next2); + if (ret != 0) + return ret; + + ret = zapi_nexthop_seg6local_cmp(next1, next2); return ret; } @@ -992,6 +1009,12 @@ int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh, stream_putc(s, api_nh->backup_idx[i]); } + if (CHECK_FLAG(api_flags, ZEBRA_FLAG_SEG6LOCAL_ROUTE)) { + stream_putl(s, api_nh->seg6local_action); + stream_write(s, &api_nh->seg6local_ctx, + sizeof(struct seg6local_context)); + } + done: return ret; } @@ -1273,6 +1296,12 @@ int zapi_nexthop_decode(struct stream *s, struct zapi_nexthop *api_nh, STREAM_GETC(s, api_nh->backup_idx[i]); } + if (CHECK_FLAG(api_flags, ZEBRA_FLAG_SEG6LOCAL_ROUTE)) { + STREAM_GETL(s, api_nh->seg6local_action); + STREAM_GET(&api_nh->seg6local_ctx, s, + sizeof(struct seg6local_context)); + } + /* Success */ ret = 0; @@ -1637,6 +1666,10 @@ struct nexthop *nexthop_from_zapi_nexthop(const struct zapi_nexthop *znh) memcpy(n->backup_idx, znh->backup_idx, n->backup_num); } + if (znh->seg6local_action != 0) + nexthop_add_seg6local(n, znh->seg6local_action, + &znh->seg6local_ctx); + return n; } @@ -1681,6 +1714,12 @@ int zapi_nexthop_from_nexthop(struct zapi_nexthop *znh, memcpy(znh->backup_idx, nh->backup_idx, znh->backup_num); } + if (nh->nh_seg6local_action != 0 && nh->nh_seg6local_ctx != NULL) { + znh->seg6local_action = nh->nh_seg6local_action; + memcpy(&znh->seg6local_ctx, nh->nh_seg6local_ctx, + sizeof(struct seg6local_context)); + } + return 0; } diff --git a/lib/zclient.h b/lib/zclient.h index 8c27916542..3f5225f097 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -459,6 +459,10 @@ struct zapi_nexthop { /* SR-TE color. */ uint32_t srte_color; + + /* SRv6 localsid info for Endpoint-behaviour */ + uint32_t seg6local_action; + struct seg6local_context seg6local_ctx; }; /* @@ -555,6 +559,16 @@ struct zapi_route { * offload situation. */ #define ZEBRA_FLAG_OFFLOAD_FAILED 0x200 +/* + * This flag tells Zebra that the route is a seg6 route and should + * be treated specially. + */ +#define ZEBRA_FLAG_SEG6_ROUTE 0x400 +/* + * This flag tells Zebra that the route is a seg6local route and + * should be treated specially. + */ +#define ZEBRA_FLAG_SEG6LOCAL_ROUTE 0x800 /* The older XXX_MESSAGE flags live here */ uint32_t message; From 8689b25a08134924d8d8c5f009fd4081d11049f2 Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Sun, 6 Dec 2020 08:01:39 +0900 Subject: [PATCH 03/66] zebra: ZEBRA_ROUTE_ADD supports seg6local route (step1) With this patch, zclient can intall seg6local rotues whem they set properties nh_seg6local_{action,ctx} on struct nexthop and set ZEBRA_FLAG_SEG6LOCAL_ROUTE on zapi_route's flag. Signed-off-by: Hiroki Shirokura --- zebra/rt_netlink.c | 118 +++++++++++++++++++++++++++++++++++++++++++++ zebra/zapi_msg.c | 12 +++++ zebra/zebra_nhg.c | 2 + zebra/zebra_vty.c | 19 ++++++++ 4 files changed, 151 insertions(+) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index fbf37230c7..54dee7d911 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -22,9 +22,18 @@ #ifdef HAVE_NETLINK +/* The following definition is to workaround an issue in the Linux kernel + * header files with redefinition of 'struct in6_addr' in both + * netinet/in.h and linux/in6.h. + * Reference - https://sourceware.org/ml/libc-alpha/2013-01/msg00599.html + */ +#define _LINUX_IN6_H + #include #include #include +#include +#include #include #include #include @@ -38,6 +47,8 @@ #include "if.h" #include "log.h" #include "prefix.h" +#include "plist.h" +#include "plist_int.h" #include "connected.h" #include "table.h" #include "memory.h" @@ -1262,6 +1273,52 @@ static bool _netlink_route_build_singlepath(const struct prefix *p, sizeof(label_buf))) return false; + if (nexthop->nh_seg6local_ctx) { + struct rtattr *nest; + const struct seg6local_context *ctx; + + ctx = nexthop->nh_seg6local_ctx; + nl_attr_put16(nlmsg, req_size, RTA_ENCAP_TYPE, + LWTUNNEL_ENCAP_SEG6_LOCAL); + + nest = nl_attr_nest(nlmsg, req_size, RTA_ENCAP); + switch (nexthop->nh_seg6local_action) { + case ZEBRA_SEG6_LOCAL_ACTION_END: + nl_attr_put32(nlmsg, req_size, SEG6_LOCAL_ACTION, + SEG6_LOCAL_ACTION_END); + break; + case ZEBRA_SEG6_LOCAL_ACTION_END_X: + nl_attr_put32(nlmsg, req_size, SEG6_LOCAL_ACTION, + SEG6_LOCAL_ACTION_END_X); + nl_attr_put(nlmsg, req_size, SEG6_LOCAL_NH6, &ctx->nh6, + sizeof(struct in6_addr)); + break; + case ZEBRA_SEG6_LOCAL_ACTION_END_T: + nl_attr_put32(nlmsg, req_size, SEG6_LOCAL_ACTION, + SEG6_LOCAL_ACTION_END_T); + nl_attr_put32(nlmsg, req_size, SEG6_LOCAL_TABLE, + ctx->table); + break; + case ZEBRA_SEG6_LOCAL_ACTION_END_DX4: + nl_attr_put32(nlmsg, req_size, SEG6_LOCAL_ACTION, + SEG6_LOCAL_ACTION_END_DX4); + nl_attr_put(nlmsg, req_size, SEG6_LOCAL_NH4, &ctx->nh4, + sizeof(struct in_addr)); + break; + case ZEBRA_SEG6_LOCAL_ACTION_END_DT6: + nl_attr_put32(nlmsg, req_size, SEG6_LOCAL_ACTION, + SEG6_LOCAL_ACTION_END_DT6); + nl_attr_put32(nlmsg, req_size, SEG6_LOCAL_TABLE, + ctx->table); + break; + default: + zlog_err("%s: unsupport seg6local behaviour action=%u", + __func__, nexthop->nh_seg6local_action); + break; + } + nl_attr_nest_end(nlmsg, nest); + } + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) rtmsg->rtm_flags |= RTNH_F_ONLINK; @@ -2256,6 +2313,67 @@ ssize_t netlink_nexthop_msg_encode(uint16_t cmd, nl_attr_nest_end(&req->n, nest); } + if (nh->nh_seg6local_ctx) { + uint32_t action; + uint16_t encap; + struct rtattr *nest; + const struct seg6local_context *ctx; + + req->nhm.nh_family = AF_INET6; + action = nh->nh_seg6local_action; + ctx = nh->nh_seg6local_ctx; + encap = LWTUNNEL_ENCAP_SEG6_LOCAL; + nl_attr_put(&req->n, buflen, NHA_ENCAP_TYPE, + &encap, sizeof(uint16_t)); + + nest = nl_attr_nest(&req->n, buflen, + NHA_ENCAP | NLA_F_NESTED); + switch (action) { + case SEG6_LOCAL_ACTION_END: + nl_attr_put32(&req->n, buflen, + SEG6_LOCAL_ACTION, + SEG6_LOCAL_ACTION_END); + break; + case SEG6_LOCAL_ACTION_END_X: + nl_attr_put32(&req->n, buflen, + SEG6_LOCAL_ACTION, + SEG6_LOCAL_ACTION_END_X); + nl_attr_put(&req->n, buflen, + SEG6_LOCAL_NH6, &ctx->nh6, + sizeof(struct in6_addr)); + break; + case SEG6_LOCAL_ACTION_END_T: + nl_attr_put32(&req->n, buflen, + SEG6_LOCAL_ACTION, + SEG6_LOCAL_ACTION_END_T); + nl_attr_put32(&req->n, buflen, + SEG6_LOCAL_TABLE, + ctx->table); + break; + case SEG6_LOCAL_ACTION_END_DX4: + nl_attr_put32(&req->n, buflen, + SEG6_LOCAL_ACTION, + SEG6_LOCAL_ACTION_END_DX4); + nl_attr_put(&req->n, buflen, + SEG6_LOCAL_NH4, &ctx->nh4, + sizeof(struct in_addr)); + break; + case SEG6_LOCAL_ACTION_END_DT6: + nl_attr_put32(&req->n, buflen, + SEG6_LOCAL_ACTION, + SEG6_LOCAL_ACTION_END_DT6); + nl_attr_put32(&req->n, buflen, + SEG6_LOCAL_TABLE, + ctx->table); + break; + default: + zlog_err("%s: unsupport seg6local behaviour action=%u", + __func__, action); + break; + } + nl_attr_nest_end(&req->n, nest); + } + nexthop_done: if (IS_ZEBRA_DEBUG_KERNEL) diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 544bb07fbe..752738b214 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -1747,6 +1747,18 @@ static bool zapi_read_nexthops(struct zserv *client, struct prefix *p, &api_nh->labels[0]); } + if (CHECK_FLAG(flags, ZEBRA_FLAG_SEG6LOCAL_ROUTE) + && api_nh->type != NEXTHOP_TYPE_BLACKHOLE) { + if (IS_ZEBRA_DEBUG_RECV) + zlog_debug("%s: adding seg6local action %s", + __func__, + seg6local_action2str( + api_nh->seg6local_action)); + + nexthop_add_seg6local(nexthop, api_nh->seg6local_action, + &api_nh->seg6local_ctx); + } + if (IS_ZEBRA_DEBUG_RECV) { labelbuf[0] = '\0'; nhbuf[0] = '\0'; diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 6b40eae5b7..ddd37b4df7 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -1007,6 +1007,7 @@ void nhg_ctx_free(struct nhg_ctx **ctx) nh = nhg_ctx_get_nh(*ctx); nexthop_del_labels(nh); + nexthop_del_seg6local(nh); done: XFREE(MTYPE_NHG_CTX, *ctx); @@ -1377,6 +1378,7 @@ static struct nhg_hash_entry *depends_find_singleton(const struct nexthop *nh, /* The copy may have allocated labels; free them if necessary. */ nexthop_del_labels(&lookup); + nexthop_del_seg6local(&lookup); if (IS_ZEBRA_DEBUG_NHG_DETAIL) zlog_debug("%s: nh %pNHv => %p (%u)", diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 2c2c75c419..c178ce075c 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -653,6 +653,15 @@ static void show_route_nexthop_helper(struct vty *vty, sizeof(buf), 1)); } + if (nexthop->nh_seg6local_ctx) { + seg6local_context2str(buf, sizeof(buf), + nexthop->nh_seg6local_ctx, + nexthop->nh_seg6local_action); + vty_out(vty, ", seg6local %s %s", + seg6local_action2str(nexthop->nh_seg6local_action), + buf); + } + if (nexthop->weight) vty_out(vty, ", weight %u", nexthop->weight); @@ -675,6 +684,7 @@ static void show_nexthop_json_helper(json_object *json_nexthop, char buf[SRCDEST2STR_BUFFER]; json_object *json_labels = NULL; json_object *json_backups = NULL; + json_object *json_seg6local = NULL; int i; json_object_int_add(json_nexthop, "flags", @@ -852,6 +862,15 @@ static void show_nexthop_json_helper(json_object *json_nexthop, if (nexthop->srte_color) json_object_int_add(json_nexthop, "srteColor", nexthop->srte_color); + + if (nexthop->nh_seg6local_ctx) { + json_seg6local = json_object_new_object(); + json_object_string_add( + json_seg6local, "action", + seg6local_action2str(nexthop->nh_seg6local_action)); + json_object_object_add(json_nexthop, "seg6local", + json_seg6local); + } } static void vty_show_ip_route(struct vty *vty, struct route_node *rn, From d49e6c4afd864653e6d384d314872c0ae95f1963 Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Fri, 18 Dec 2020 22:39:25 +0900 Subject: [PATCH 04/66] zebra: parse non-zebra seg6local configuration via netlink (step1) FRRouting operator can install seg6local route via ZAPI, But linux kernel operator also can install seg6local route via Netlink directry (i.e. iproute2) This commit make zebra to parse non-frr seg6local route configuration via netlink and audit Zebra's RIB. Signed-off-by: Hiroki Shirokura --- zebra/rt_netlink.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 54dee7d911..2ddda7449c 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -415,6 +415,32 @@ static int parse_encap_mpls(struct rtattr *tb, mpls_label_t *labels) return num_labels; } +static enum seg6local_action_t +parse_encap_seg6local(struct rtattr *tb, + struct seg6local_context *ctx) +{ + struct rtattr *tb_encap[256] = {0}; + enum seg6local_action_t act = ZEBRA_SEG6_LOCAL_ACTION_UNSPEC; + + netlink_parse_rtattr_nested(tb_encap, 256, tb); + + if (tb_encap[SEG6_LOCAL_ACTION]) + act = *(uint32_t *)RTA_DATA(tb_encap[SEG6_LOCAL_ACTION]); + + if (tb_encap[SEG6_LOCAL_NH4]) + ctx->nh4 = *(struct in_addr *)RTA_DATA( + tb_encap[SEG6_LOCAL_NH4]); + + if (tb_encap[SEG6_LOCAL_NH6]) + ctx->nh6 = *(struct in6_addr *)RTA_DATA( + tb_encap[SEG6_LOCAL_NH6]); + + if (tb_encap[SEG6_LOCAL_TABLE]) + ctx->table = *(uint32_t *)RTA_DATA(tb_encap[SEG6_LOCAL_TABLE]); + + return act; +} + static struct nexthop parse_nexthop_unicast(ns_id_t ns_id, struct rtmsg *rtm, struct rtattr **tb, enum blackhole_type bh_type, int index, void *prefsrc, @@ -424,6 +450,8 @@ parse_nexthop_unicast(ns_id_t ns_id, struct rtmsg *rtm, struct rtattr **tb, struct nexthop nh = {0}; mpls_label_t labels[MPLS_MAX_LABELS] = {0}; int num_labels = 0; + enum seg6local_action_t seg6l_act = SEG6_LOCAL_ACTION_UNSPEC; + struct seg6local_context seg6l_ctx = {{0}}; vrf_id_t nh_vrf_id = vrf_id; size_t sz = (afi == AFI_IP) ? 4 : 16; @@ -463,6 +491,11 @@ parse_nexthop_unicast(ns_id_t ns_id, struct rtmsg *rtm, struct rtattr **tb, == LWTUNNEL_ENCAP_MPLS) { num_labels = parse_encap_mpls(tb[RTA_ENCAP], labels); } + if (tb[RTA_ENCAP] && tb[RTA_ENCAP_TYPE] + && *(uint16_t *)RTA_DATA(tb[RTA_ENCAP_TYPE]) + == LWTUNNEL_ENCAP_SEG6_LOCAL) { + seg6l_act = parse_encap_seg6local(tb[RTA_ENCAP], &seg6l_ctx); + } if (rtm->rtm_flags & RTNH_F_ONLINK) SET_FLAG(nh.flags, NEXTHOP_FLAG_ONLINK); @@ -470,6 +503,9 @@ parse_nexthop_unicast(ns_id_t ns_id, struct rtmsg *rtm, struct rtattr **tb, if (num_labels) nexthop_add_labels(&nh, ZEBRA_LSP_STATIC, num_labels, labels); + if (seg6l_act != ZEBRA_SEG6_LOCAL_ACTION_UNSPEC) + nexthop_add_seg6local(&nh, seg6l_act, &seg6l_ctx); + return nh; } @@ -486,6 +522,8 @@ static uint8_t parse_multipath_nexthops_unicast(ns_id_t ns_id, /* MPLS labels */ mpls_label_t labels[MPLS_MAX_LABELS] = {0}; int num_labels = 0; + enum seg6local_action_t seg6l_act = SEG6_LOCAL_ACTION_UNSPEC; + struct seg6local_context seg6l_ctx = {{0}}; struct rtattr *rtnh_tb[RTA_MAX + 1] = {}; int len = RTA_PAYLOAD(tb[RTA_MULTIPATH]); @@ -530,6 +568,12 @@ static uint8_t parse_multipath_nexthops_unicast(ns_id_t ns_id, num_labels = parse_encap_mpls( rtnh_tb[RTA_ENCAP], labels); } + if (rtnh_tb[RTA_ENCAP] && rtnh_tb[RTA_ENCAP_TYPE] + && *(uint16_t *)RTA_DATA(rtnh_tb[RTA_ENCAP_TYPE]) + == LWTUNNEL_ENCAP_SEG6_LOCAL) { + seg6l_act = parse_encap_seg6local( + rtnh_tb[RTA_ENCAP], &seg6l_ctx); + } } if (gate && rtm->rtm_family == AF_INET) { @@ -555,6 +599,10 @@ static uint8_t parse_multipath_nexthops_unicast(ns_id_t ns_id, nexthop_add_labels(nh, ZEBRA_LSP_STATIC, num_labels, labels); + if (seg6l_act != ZEBRA_SEG6_LOCAL_ACTION_UNSPEC) + nexthop_add_seg6local(nh, seg6l_act, + &seg6l_ctx); + if (rtnh->rtnh_flags & RTNH_F_ONLINK) SET_FLAG(nh->flags, NEXTHOP_FLAG_ONLINK); From c27b47d7916d0abd558fed46ba2c6e11d2573b3f Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Sun, 6 Dec 2020 17:13:19 +0900 Subject: [PATCH 05/66] sharpd: install_routes_helper support ZAPI_ROUTE flags (step1) current route addition mechanism on shaprd support only ipv4/v6 nexthop routes simply. so It doesn't need to ensure flags of zapi_routes. Then when we want to configure more complicated routing feature (like a srv6), we will want to control flags of zapi_route. In this patch, it will supports to configure flags of zapi_route when sharpd calls ZEBRA_ROUTE_ADD. Signed-off-by: Hiroki Shirokura --- sharpd/sharp_globals.h | 3 +++ sharpd/sharp_vty.c | 3 ++- sharpd/sharp_zebra.c | 20 +++++++++++++------- sharpd/sharp_zebra.h | 2 +- 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/sharpd/sharp_globals.h b/sharpd/sharp_globals.h index 0b3776cd90..b050ba85ca 100644 --- a/sharpd/sharp_globals.h +++ b/sharpd/sharp_globals.h @@ -40,6 +40,9 @@ struct sharp_routes { uint32_t removed_routes; int32_t repeat; + /* ZAPI_ROUTE's flag */ + uint32_t flags; + uint8_t inst; vrf_id_t vrf_id; diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index 1ff0591d5e..de2d092c36 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -219,6 +219,7 @@ DEFPY (install_routes, struct prefix prefix; uint32_t rts; uint32_t nhgid = 0; + uint32_t route_flags = 0; sg.r.total_routes = routes; sg.r.installed_routes = 0; @@ -332,7 +333,7 @@ DEFPY (install_routes, rts = routes; sharp_install_routes_helper(&prefix, sg.r.vrf_id, sg.r.inst, nhgid, &sg.r.nhop_group, &sg.r.backup_nhop_group, - rts, sg.r.opaque); + rts, route_flags, sg.r.opaque); return CMD_SUCCESS; } diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c index 128cfe2de6..da056160bf 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -230,6 +230,7 @@ struct buffer_delay { vrf_id_t vrf_id; uint8_t instance; uint32_t nhgid; + uint32_t flags; const struct nexthop_group *nhg; const struct nexthop_group *backup_nhg; enum where_to_restart restart; @@ -244,7 +245,8 @@ struct buffer_delay { */ static bool route_add(const struct prefix *p, vrf_id_t vrf_id, uint8_t instance, uint32_t nhgid, const struct nexthop_group *nhg, - const struct nexthop_group *backup_nhg, char *opaque) + const struct nexthop_group *backup_nhg, uint32_t flags, + char *opaque) { struct zapi_route api; struct zapi_nexthop *api_nh; @@ -258,6 +260,7 @@ static bool route_add(const struct prefix *p, vrf_id_t vrf_id, uint8_t instance, api.safi = SAFI_UNICAST; memcpy(&api.prefix, p, sizeof(*p)); + api.flags = flags; SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION); SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); @@ -335,7 +338,7 @@ static void sharp_install_routes_restart(struct prefix *p, uint32_t count, uint32_t nhgid, const struct nexthop_group *nhg, const struct nexthop_group *backup_nhg, - uint32_t routes, char *opaque) + uint32_t routes, uint32_t flags, char *opaque) { uint32_t temp, i; bool v4 = false; @@ -348,7 +351,7 @@ static void sharp_install_routes_restart(struct prefix *p, uint32_t count, for (i = count; i < routes; i++) { bool buffered = route_add(p, vrf_id, (uint8_t)instance, nhgid, - nhg, backup_nhg, opaque); + nhg, backup_nhg, flags, opaque); if (v4) p->u.prefix4.s_addr = htonl(++temp); else @@ -362,6 +365,7 @@ static void sharp_install_routes_restart(struct prefix *p, uint32_t count, wb.instance = instance; wb.nhgid = nhgid; wb.nhg = nhg; + wb.flags = flags; wb.backup_nhg = backup_nhg; wb.opaque = opaque; wb.restart = SHARP_INSTALL_ROUTES_RESTART; @@ -375,7 +379,7 @@ void sharp_install_routes_helper(struct prefix *p, vrf_id_t vrf_id, uint8_t instance, uint32_t nhgid, const struct nexthop_group *nhg, const struct nexthop_group *backup_nhg, - uint32_t routes, char *opaque) + uint32_t routes, uint32_t flags, char *opaque) { zlog_debug("Inserting %u routes", routes); @@ -385,7 +389,7 @@ void sharp_install_routes_helper(struct prefix *p, vrf_id_t vrf_id, monotime(&sg.r.t_start); sharp_install_routes_restart(p, 0, vrf_id, instance, nhgid, nhg, - backup_nhg, routes, opaque); + backup_nhg, routes, flags, opaque); } static void sharp_remove_routes_restart(struct prefix *p, uint32_t count, @@ -451,7 +455,8 @@ static void handle_repeated(bool installed) sharp_install_routes_helper(&p, sg.r.vrf_id, sg.r.inst, sg.r.nhgid, &sg.r.nhop_group, &sg.r.backup_nhop_group, - sg.r.total_routes, sg.r.opaque); + sg.r.total_routes, sg.r.flags, + sg.r.opaque); } } @@ -461,7 +466,8 @@ static void sharp_zclient_buffer_ready(void) case SHARP_INSTALL_ROUTES_RESTART: sharp_install_routes_restart( &wb.p, wb.count, wb.vrf_id, wb.instance, wb.nhgid, - wb.nhg, wb.backup_nhg, wb.routes, wb.opaque); + wb.nhg, wb.backup_nhg, wb.routes, wb.flags, + wb.opaque); return; case SHARP_DELETE_ROUTES_RESTART: sharp_remove_routes_restart(&wb.p, wb.count, wb.vrf_id, diff --git a/sharpd/sharp_zebra.h b/sharpd/sharp_zebra.h index 4355f49a2f..495ce6ec58 100644 --- a/sharpd/sharp_zebra.h +++ b/sharpd/sharp_zebra.h @@ -39,7 +39,7 @@ extern void sharp_install_routes_helper(struct prefix *p, vrf_id_t vrf_id, uint8_t instance, uint32_t nhgid, const struct nexthop_group *nhg, const struct nexthop_group *backup_nhg, - uint32_t routes, char *opaque); + uint32_t routes, uint32_t flags, char *opaque); extern void sharp_remove_routes_helper(struct prefix *p, vrf_id_t vrf_id, uint8_t instance, uint32_t routes); From dc3883cffef8b995ee3f36f52cd75673304e2cf9 Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Sun, 6 Dec 2020 09:10:33 +0900 Subject: [PATCH 06/66] shaprd: install route supports nexthop-seg6local (step1) In this patch, we can install seg6local routes from shapd cli. New sub command "sharp install route $PREFIX nexthop-seg6local" is added to install seg6local routes via ZEBRA_ROUTE_ADD. This is for the behaviour test(topotest) to ensure SRv6 ZAPI is working fine. NEW-CLI: sharp install routes 1::1 nexthop-seg6local dum0 End 1 sharp install routes 2::1 nexthop-seg6local dum0 End_X 2001::1 1 sharp install routes 3::1 nexthop-seg6local dum0 End_T 10 1 sharp install routes 4::1 nexthop-seg6local dum0 End_DX4 10.0.0.1 1 SRv6 routes are installed as NEXTHOP_IFINDEX routes because of seg6local specification. seg6local routes depends the output device status instead of routing-nexthop. FYI: In seg6local implementation, kernel don't care RTA_OIF on the nexthop deeply but some requirement are exist as follow. (a) DEV isn't loopback interface (b) DEV's ipv6 status is enabled (c) DEV's enslaving status is the same with target-route Signed-off-by: Hiroki Shirokura --- sharpd/sharp_vty.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index de2d092c36..253d1943b3 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -189,7 +189,13 @@ DEFPY (install_routes, "sharp install routes [vrf NAME$vrf_name]\ \ |\ - nexthop-group NHGNAME$nexthop_group>\ + nexthop-group NHGNAME$nexthop_group|\ + nexthop-seg6local NAME$seg6l_oif\ + >\ [backup$backup ] \ (1-1000000)$routes [instance (0-255)$instance] [repeat (2-1000)$rpt] [opaque WORD]", "Sharp routing Protocol\n" @@ -204,6 +210,17 @@ DEFPY (install_routes, "V6 Nexthop address to use\n" "Nexthop-Group to use\n" "The Name of the nexthop-group\n" + "Nexthop-seg6local to use\n" + "Output device to use\n" + "SRv6 End function to use\n" + "SRv6 End.X function to use\n" + "V6 Nexthop address to use\n" + "SRv6 End.T function to use\n" + "Redirect table id to use\n" + "SRv6 End.DX4 function to use\n" + "V4 Nexthop address to use\n" + "SRv6 End.DT6 function to use\n" + "Redirect table id to use\n" "Backup nexthop to use(Can be an IPv4 or IPv6 address)\n" "Backup V4 Nexthop address to use\n" "Backup V6 Nexthop address to use\n" @@ -291,6 +308,32 @@ DEFPY (install_routes, sg.r.backup_nhop.vrf_id = vrf->vrf_id; sg.r.backup_nhop_group.nexthop = bnhgc->nhg.nexthop; } + } else if (seg6l_oif) { + struct seg6local_context ctx; + enum seg6local_action_t action; + memset(&ctx, 0, sizeof(struct seg6local_context)); + if (seg6l_enddx4) { + action = ZEBRA_SEG6_LOCAL_ACTION_END_DX4; + ctx.nh4 = seg6l_enddx4_nh4; + } else if (seg6l_endx) { + action = ZEBRA_SEG6_LOCAL_ACTION_END_X; + ctx.nh6 = seg6l_endx_nh6; + } else if (seg6l_endt) { + action = ZEBRA_SEG6_LOCAL_ACTION_END_T; + ctx.table = seg6l_endt_table; + } else if (seg6l_enddt6) { + action = ZEBRA_SEG6_LOCAL_ACTION_END_DT6; + ctx.table = seg6l_enddt6_table; + } else { + action = ZEBRA_SEG6_LOCAL_ACTION_END; + } + + sg.r.nhop.type = NEXTHOP_TYPE_IFINDEX; + sg.r.nhop.ifindex = ifname2ifindex(seg6l_oif, vrf->vrf_id); + sg.r.nhop.vrf_id = vrf->vrf_id; + sg.r.nhop_group.nexthop = &sg.r.nhop; + nexthop_add_seg6local(&sg.r.nhop, action, &ctx); + SET_FLAG(route_flags, ZEBRA_FLAG_SEG6LOCAL_ROUTE); } else { if (nexthop4.s_addr != INADDR_ANY) { sg.r.nhop.gate.ipv4 = nexthop4; From 0adde13a58a4556d930cb2e9611a801cf09d5fc4 Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Sun, 6 Dec 2020 12:37:24 +0900 Subject: [PATCH 07/66] topotests: for zapi's seg6local route configuration (step1) This commit checks seg6local route configuration via ZAPI is working fine. SRv6 feature is little young feature as kernel feature so netlink interface may be changed/updated in the future. And this ZAPI extention is something to support new routing paradigm, so it should be checked by topotests until srv6 feature of linux kernel will be well stable. Signed-off-by: Hiroki Shirokura --- .../zebra_seg6local_route/r1/routes.json | 98 ++++++++++++++++ .../zebra_seg6local_route/r1/setup.sh | 3 + .../zebra_seg6local_route/r1/sharpd.conf | 0 .../zebra_seg6local_route/r1/zebra.conf | 9 ++ .../test_zebra_seg6local_route.py | 107 ++++++++++++++++++ 5 files changed, 217 insertions(+) create mode 100644 tests/topotests/zebra_seg6local_route/r1/routes.json create mode 100644 tests/topotests/zebra_seg6local_route/r1/setup.sh create mode 100644 tests/topotests/zebra_seg6local_route/r1/sharpd.conf create mode 100644 tests/topotests/zebra_seg6local_route/r1/zebra.conf create mode 100755 tests/topotests/zebra_seg6local_route/test_zebra_seg6local_route.py diff --git a/tests/topotests/zebra_seg6local_route/r1/routes.json b/tests/topotests/zebra_seg6local_route/r1/routes.json new file mode 100644 index 0000000000..4cb1c4ae13 --- /dev/null +++ b/tests/topotests/zebra_seg6local_route/r1/routes.json @@ -0,0 +1,98 @@ +[ + { + "in": { + "dest": "1::1", + "context": "End" + }, + "out":[{ + "prefix":"1::1/128", + "protocol":"sharp", + "selected":true, + "destSelected":true, + "distance":150, + "metric":0, + "installed":true, + "table":254, + "nexthops":[{ + "flags":3, + "fib":true, + "active":true, + "directlyConnected":true, + "interfaceName": "dum0", + "seg6local": { "action": "End" } + }] + }] + }, + { + "in": { + "dest": "2::1", + "context": "End_X 2001::1" + }, + "out":[{ + "prefix":"2::1/128", + "protocol":"sharp", + "selected":true, + "destSelected":true, + "distance":150, + "metric":0, + "installed":true, + "table":254, + "nexthops":[{ + "flags":3, + "fib":true, + "active":true, + "directlyConnected":true, + "interfaceName": "dum0", + "seg6local": { "action": "End.X" } + }] + }] + }, + { + "in": { + "dest": "3::1", + "context": "End_T 10" + }, + "out":[{ + "prefix":"3::1/128", + "protocol":"sharp", + "selected":true, + "destSelected":true, + "distance":150, + "metric":0, + "installed":true, + "table":254, + "nexthops":[{ + "flags":3, + "fib":true, + "active":true, + "directlyConnected":true, + "interfaceName": "dum0", + "seg6local": { "action": "End.T" } + }] + }] + }, + { + "in": { + "dest": "4::1", + "context": "End_DX4 10.0.0.1" + }, + "out":[{ + "prefix":"4::1/128", + "protocol":"sharp", + "selected":true, + "destSelected":true, + "distance":150, + "metric":0, + "installed":true, + "table":254, + "nexthops":[{ + "flags":3, + "fib":true, + "active":true, + "directlyConnected":true, + "interfaceName": "dum0", + "seg6local": { "action": "End.DX4" } + }] + }] + } +] diff --git a/tests/topotests/zebra_seg6local_route/r1/setup.sh b/tests/topotests/zebra_seg6local_route/r1/setup.sh new file mode 100644 index 0000000000..691adb0a19 --- /dev/null +++ b/tests/topotests/zebra_seg6local_route/r1/setup.sh @@ -0,0 +1,3 @@ +ip link add dum0 type dummy +ip link set dum0 up +sysctl -w net.ipv6.conf.dum0.disable_ipv6=0 diff --git a/tests/topotests/zebra_seg6local_route/r1/sharpd.conf b/tests/topotests/zebra_seg6local_route/r1/sharpd.conf new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/topotests/zebra_seg6local_route/r1/zebra.conf b/tests/topotests/zebra_seg6local_route/r1/zebra.conf new file mode 100644 index 0000000000..22eb88098b --- /dev/null +++ b/tests/topotests/zebra_seg6local_route/r1/zebra.conf @@ -0,0 +1,9 @@ +log file zebra.log +! +log stdout notifications +log monitor notifications +log commands +! +debug zebra packet +debug zebra dplane +debug zebra kernel msgdump diff --git a/tests/topotests/zebra_seg6local_route/test_zebra_seg6local_route.py b/tests/topotests/zebra_seg6local_route/test_zebra_seg6local_route.py new file mode 100755 index 0000000000..66c6ac6dd2 --- /dev/null +++ b/tests/topotests/zebra_seg6local_route/test_zebra_seg6local_route.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python + +# +# test_zebra_seg6local_route.py +# +# Copyright (c) 2020 by +# LINE Corporation, Hiroki Shirokura +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +test_zebra_seg6local_route.py: Test seg6local route addition with zapi. +""" + +import os +import re +import sys +import pytest +import json +import platform +from functools import partial + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger +from lib.common_config import shutdown_bringup_interface +from mininet.topo import Topo + + +def open_json_file(filename): + try: + with open(filename, "r") as f: + return json.load(f) + except IOError: + assert False, "Could not read file {}".format(filename) + + +class TemplateTopo(Topo): + def build(self, **_opts): + tgen = get_topogen(self) + tgen.add_router("r1") + + +def setup_module(mod): + tgen = Topogen(TemplateTopo, mod.__name__) + tgen.start_topology() + router_list = tgen.routers() + for rname, router in tgen.routers().items(): + router.run("/bin/bash {}".format(os.path.join(CWD, "{}/setup.sh".format(rname)))) + router.load_config(TopoRouter.RD_ZEBRA, os.path.join(CWD, '{}/zebra.conf'.format(rname))) + router.load_config(TopoRouter.RD_SHARP, os.path.join(CWD, "{}/sharpd.conf".format(rname))) + tgen.start_router() + + +def teardown_module(_mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_zebra_seg6local_routes(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + logger.info("Test for seg6local route install via ZAPI was start.") + r1 = tgen.gears["r1"] + + def check(router, dest, context, expected): + router.vtysh_cmd("sharp install routes {} "\ + "nexthop-seg6local dum0 {} 1".format(dest, context)) + output = json.loads(router.vtysh_cmd("show ipv6 route {} json".format(dest))) + output = output.get('{}/128'.format(dest)) + if output is None: + return False + return topotest.json_cmp(output, expected) + + manifests = open_json_file(os.path.join(CWD, "{}/routes.json".format("r1"))) + for manifest in manifests: + logger.info("CHECK {} {}".format(manifest['in']['dest'], + manifest['in']['context'])) + test_func = partial(check, r1, + manifest['in']['dest'], + manifest['in']['context'], + manifest['out']) + success, result = topotest.run_and_expect(test_func, None, count=5, wait=1) + assert result is None, 'Failed' + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) From 6c0a7c094111b11b7f8c298b71c60e08b82d8e15 Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Wed, 30 Sep 2020 12:59:19 +0900 Subject: [PATCH 08/66] *: new cli-nodes for SRv6 manager (step2) This commit is a part of #5853 that add new cmd-node for SRv6 configuration. This commit just add cmd-node and moving node cli only, acutual SRv6 config command isn't added. (that is added later commit. of this branch) new cli nodes: * SRv6 * SRv6-locators * SRv6-locator Signed-off-by: Hiroki Shirokura --- lib/command.c | 9 +++ lib/command.h | 3 + vtysh/vtysh.c | 88 ++++++++++++++++++++++++++- vtysh/vtysh.h | 1 + vtysh/vtysh_config.c | 4 ++ zebra/main.c | 2 + zebra/subdir.am | 3 + zebra/zebra_srv6_vty.c | 132 +++++++++++++++++++++++++++++++++++++++++ zebra/zebra_srv6_vty.h | 25 ++++++++ 9 files changed, 266 insertions(+), 1 deletion(-) create mode 100644 zebra/zebra_srv6_vty.c create mode 100644 zebra/zebra_srv6_vty.h diff --git a/lib/command.c b/lib/command.c index 7fb405bdfb..805dd9abe2 100644 --- a/lib/command.c +++ b/lib/command.c @@ -889,6 +889,15 @@ enum node_type node_parent(enum node_type node) case PCEP_PCC_NODE: ret = PCEP_NODE; break; + case SRV6_NODE: + ret = SEGMENT_ROUTING_NODE; + break; + case SRV6_LOCS_NODE: + ret = SRV6_NODE; + break; + case SRV6_LOC_NODE: + ret = SRV6_LOCS_NODE; + break; default: ret = CONFIG_NODE; break; diff --git a/lib/command.h b/lib/command.h index 51da4c52e6..846434066d 100644 --- a/lib/command.h +++ b/lib/command.h @@ -155,6 +155,9 @@ enum node_type { 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 */ VTY_NODE, /* Vty node. */ FPM_NODE, /* Dataplane FPM node. */ LINK_PARAMS_NODE, /* Link-parameters node */ diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 111c2dbc03..e55a8cfb1a 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -1349,6 +1349,27 @@ static struct cmd_node rmap_node = { .prompt = "%s(config-route-map)# ", }; +static struct cmd_node srv6_node = { + .name = "srv6", + .node = SRV6_NODE, + .parent_node = SEGMENT_ROUTING_NODE, + .prompt = "%s(config-srv6)# ", +}; + +static struct cmd_node srv6_locs_node = { + .name = "srv6-locators", + .node = SRV6_LOCS_NODE, + .parent_node = SRV6_NODE, + .prompt = "%s(config-srv6-locators)# ", +}; + +static struct cmd_node srv6_loc_node = { + .name = "srv6-locator", + .node = SRV6_LOC_NODE, + .parent_node = SRV6_LOCS_NODE, + .prompt = "%s(config-srv6-locator)# ", +}; + #ifdef HAVE_PBRD static struct cmd_node pbr_map_node = { .name = "pbr-map", @@ -1659,6 +1680,31 @@ DEFUNSH(VTYSH_REALLYALL, vtysh_end_all, vtysh_end_all_cmd, "end", return vtysh_end(); } +DEFUNSH(VTYSH_SR, srv6, srv6_cmd, + "srv6", + "Segment-Routing SRv6 configration\n") +{ + vty->node = SRV6_NODE; + return CMD_SUCCESS; +} + +DEFUNSH(VTYSH_SR, srv6_locators, srv6_locators_cmd, + "locators", + "Segment-Routing SRv6 locators configration\n") +{ + vty->node = SRV6_LOCS_NODE; + return CMD_SUCCESS; +} + +DEFUNSH(VTYSH_SR, srv6_locator, srv6_locator_cmd, + "locator WORD", + "Segment Routing SRv6 locator\n" + "Specify locator-name\n") +{ + vty->node = SRV6_LOC_NODE; + return CMD_SUCCESS; +} + #ifdef HAVE_BGPD DEFUNSH(VTYSH_BGPD, router_bgp, router_bgp_cmd, "router bgp [(1-4294967295) [ WORD]]", @@ -2084,7 +2130,7 @@ DEFUNSH(VTYSH_FABRICD, router_openfabric, router_openfabric_cmd, "router openfab #endif /* HAVE_FABRICD */ #if defined(HAVE_PATHD) -DEFUNSH(VTYSH_PATHD, segment_routing, segment_routing_cmd, +DEFUNSH(VTYSH_SR, segment_routing, segment_routing_cmd, "segment-routing", "Configure segment routing\n") { @@ -2366,6 +2412,30 @@ DEFUNSH(VTYSH_VRF, exit_vrf_config, exit_vrf_config_cmd, "exit-vrf", return CMD_SUCCESS; } +DEFUNSH(VTYSH_SR, exit_srv6_config, exit_srv6_config_cmd, "exit", + "Exit from SRv6 configuration mode\n") +{ + if (vty->node == SRV6_NODE) + vty->node = SEGMENT_ROUTING_NODE; + return CMD_SUCCESS; +} + +DEFUNSH(VTYSH_SR, exit_srv6_locs_config, exit_srv6_locs_config_cmd, "exit", + "Exit from SRv6-locator configuration mode\n") +{ + if (vty->node == SRV6_LOCS_NODE) + vty->node = SRV6_NODE; + return CMD_SUCCESS; +} + +DEFUNSH(VTYSH_SR, exit_srv6_loc_config, exit_srv6_loc_config_cmd, "exit", + "Exit from SRv6-locators configuration mode\n") +{ + if (vty->node == SRV6_LOC_NODE) + vty->node = SRV6_LOCS_NODE; + return CMD_SUCCESS; +} + #ifdef HAVE_RIPD DEFUNSH(VTYSH_RIPD, vtysh_exit_ripd, vtysh_exit_ripd_cmd, "exit", "Exit current mode and down to previous mode\n") @@ -4431,6 +4501,22 @@ void vtysh_init_vty(void) install_element(CONFIG_NODE, &vtysh_end_all_cmd); install_element(ENABLE_NODE, &vtysh_end_all_cmd); + /* SRv6 Data-plane */ + install_node(&srv6_node); + install_element(SEGMENT_ROUTING_NODE, &srv6_cmd); + install_element(SRV6_NODE, &srv6_locators_cmd); + install_element(SRV6_NODE, &exit_srv6_config_cmd); + install_element(SRV6_NODE, &vtysh_end_all_cmd); + + install_node(&srv6_locs_node); + install_element(SRV6_LOCS_NODE, &srv6_locator_cmd); + 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, &exit_srv6_loc_config_cmd); + install_element(SRV6_LOC_NODE, &vtysh_end_all_cmd); + install_element(ENABLE_NODE, &vtysh_show_running_config_cmd); install_element(ENABLE_NODE, &vtysh_copy_running_config_cmd); install_element(ENABLE_NODE, &vtysh_copy_to_running_cmd); diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h index 7c8d9315e1..87f1f67443 100644 --- a/vtysh/vtysh.h +++ b/vtysh/vtysh.h @@ -60,6 +60,7 @@ DECLARE_MGROUP(MVTYSH); #define VTYSH_KEYS VTYSH_RIPD|VTYSH_EIGRPD /* Daemons who can process nexthop-group configs */ #define VTYSH_NH_GROUP VTYSH_PBRD|VTYSH_SHARPD +#define VTYSH_SR VTYSH_ZEBRA|VTYSH_PATHD enum vtysh_write_integrated { WRITE_INTEGRATED_UNSPECIFIED, diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index f92b0e920b..6d80cf9d96 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -430,6 +430,10 @@ void vtysh_config_parse_line(void *arg, const char *line) config = config_get(PROTOCOL_NODE, line); else if (strncmp(line, "mpls", strlen("mpls")) == 0) config = config_get(MPLS_NODE, line); + else if (strncmp(line, "segment-routing", + strlen("segment-routing")) + == 0) + config = config_get(SEGMENT_ROUTING_NODE, line); else if (strncmp(line, "bfd", strlen("bfd")) == 0) config = config_get(BFD_NODE, line); else { diff --git a/zebra/main.c b/zebra/main.c index 3f75b222ba..259c70d0df 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -57,6 +57,7 @@ #include "zebra/zebra_nb.h" #include "zebra/zebra_opaque.h" #include "zebra/zebra_srte.h" +#include "zebra/zebra_srv6_vty.h" #define ZEBRA_PTM_SUPPORT @@ -418,6 +419,7 @@ int main(int argc, char **argv) zebra_pbr_init(); zebra_opaque_init(); zebra_srte_init(); + zebra_srv6_vty_init(); /* For debug purpose. */ /* SET_FLAG (zebra_debug_event, ZEBRA_DEBUG_EVENT); */ diff --git a/zebra/subdir.am b/zebra/subdir.am index 6fc8ef0df5..ca77502ba3 100644 --- a/zebra/subdir.am +++ b/zebra/subdir.am @@ -13,6 +13,7 @@ vtysh_scan += \ zebra/zebra_mlag_vty.c \ zebra/zebra_evpn_mh.c \ zebra/zebra_mpls_vty.c \ + zebra/zebra_srv6_vty.c \ zebra/zebra_ptm.c \ zebra/zebra_pw.c \ zebra/zebra_routemap.c \ @@ -92,6 +93,7 @@ zebra_zebra_SOURCES = \ zebra/zebra_mpls_openbsd.c \ zebra/zebra_mpls_null.c \ zebra/zebra_mpls_vty.c \ + zebra/zebra_srv6_vty.c \ zebra/zebra_mroute.c \ zebra/zebra_nb.c \ zebra/zebra_nb_config.c \ @@ -161,6 +163,7 @@ noinst_HEADERS += \ zebra/zebra_mlag.h \ zebra/zebra_mlag_vty.h \ zebra/zebra_mpls.h \ + zebra/zebra_srv6_vty.h \ zebra/zebra_mroute.h \ zebra/zebra_nb.h \ zebra/zebra_netns_id.h \ diff --git a/zebra/zebra_srv6_vty.c b/zebra/zebra_srv6_vty.c new file mode 100644 index 0000000000..f8eff70c2d --- /dev/null +++ b/zebra/zebra_srv6_vty.c @@ -0,0 +1,132 @@ +/* + * Zebra SRv6 VTY functions + * Copyright (C) 2020 Hiroki Shirokura, LINE Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "memory.h" +#include "if.h" +#include "prefix.h" +#include "command.h" +#include "table.h" +#include "rib.h" +#include "nexthop.h" +#include "vrf.h" +#include "srv6.h" +#include "lib/json.h" + +#include "zebra/zserv.h" +#include "zebra/zebra_vrf.h" +#include "zebra/zebra_srv6_vty.h" +#include "zebra/zebra_rnh.h" +#include "zebra/redistribute.h" +#include "zebra/zebra_routemap.h" +#include "zebra/zebra_dplane.h" + +static int zebra_sr_config(struct vty *vty); + +static struct cmd_node sr_node = { + .name = "sr", + .node = SEGMENT_ROUTING_NODE, + .parent_node = CONFIG_NODE, + .prompt = "%s(config-sr)# ", + .config_write = zebra_sr_config, +}; + +static struct cmd_node srv6_node = { + .name = "srv6", + .node = SRV6_NODE, + .parent_node = SEGMENT_ROUTING_NODE, + .prompt = "%s(config-srv6)# ", + +}; + +static struct cmd_node srv6_locs_node = { + .name = "srv6-locators", + .node = SRV6_LOCS_NODE, + .parent_node = SRV6_NODE, + .prompt = "%s(config-srv6-locators)# ", +}; + +static struct cmd_node srv6_loc_node = { + .name = "srv6-locator", + .node = SRV6_LOC_NODE, + .parent_node = SRV6_LOCS_NODE, + .prompt = "%s(config-srv6-locator)# " +}; + +DEFUN_NOSH (segment_routing, + segment_routing_cmd, + "segment-routing", + "Segment Routing\n") +{ + vty->node = SEGMENT_ROUTING_NODE; + return CMD_SUCCESS; +} + +DEFUN_NOSH (srv6, + srv6_cmd, + "srv6", + "Segment Routing SRv6\n") +{ + vty->node = SRV6_NODE; + return CMD_SUCCESS; +} + +DEFUN_NOSH (srv6_locators, + srv6_locators_cmd, + "locators", + "Segment Routing SRv6 locators\n") +{ + vty->node = SRV6_LOCS_NODE; + return CMD_SUCCESS; +} + +DEFUN_NOSH (srv6_locator, + srv6_locator_cmd, + "locator WORD", + "Segment Routing SRv6 locator\n" + "Specify locator-name\n") +{ + vty->node = SRV6_LOC_NODE; + return CMD_SUCCESS; +} + +static int zebra_sr_config(struct vty *vty) +{ + return 0; +} + +void zebra_srv6_vty_init(void) +{ + /* Install nodes and its default commands */ + install_node(&sr_node); + install_node(&srv6_node); + install_node(&srv6_locs_node); + install_node(&srv6_loc_node); + install_default(SEGMENT_ROUTING_NODE); + install_default(SRV6_NODE); + install_default(SRV6_LOCS_NODE); + install_default(SRV6_LOC_NODE); + + /* Command for change node */ + install_element(CONFIG_NODE, &segment_routing_cmd); + install_element(SEGMENT_ROUTING_NODE, &srv6_cmd); + install_element(SRV6_NODE, &srv6_locators_cmd); + install_element(SRV6_LOCS_NODE, &srv6_locator_cmd); +} diff --git a/zebra/zebra_srv6_vty.h b/zebra/zebra_srv6_vty.h new file mode 100644 index 0000000000..42d6aefa9a --- /dev/null +++ b/zebra/zebra_srv6_vty.h @@ -0,0 +1,25 @@ +/* + * Zebra SRv6 VTY functions + * Copyright (C) 2020 Hiroki Shirokura, LINE Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _ZEBRA_SRV6_VTY_H +#define _ZEBRA_SRV6_VTY_H + +extern void zebra_srv6_vty_init(void); + +#endif /* _ZEBRA_SRV6_VTY_H */ From f2867068e679900582aeb263d1723f8d7c3aa0ed Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Sun, 23 Feb 2020 11:27:15 +0000 Subject: [PATCH 09/66] lib: add new structures for srv6-locator (step2) This commit is a part of #5853 works that add new structures for SRv6-locator. This structure will be used by zebra and another routing daemon and its ZAPI messaging to manage SRv6-locator. Encoder/decoder for ZAPI stream is also added by this commit. Real configuration mechanism isn't implemented at this commit. later commit add real configure implementation. This commit add only SRv6-locator's structures and misc functions. Signed-off-by: Hiroki Shirokura --- lib/srv6.c | 85 +++++++++++++++++++++++ lib/srv6.h | 32 +++++++++ lib/zclient.c | 184 ++++++++++++++++++++++++++++++++++++++++++++++++++ lib/zclient.h | 16 +++++ 4 files changed, 317 insertions(+) diff --git a/lib/srv6.c b/lib/srv6.c index 9b9f402987..d59d2d75b0 100644 --- a/lib/srv6.c +++ b/lib/srv6.c @@ -22,6 +22,10 @@ #include "srv6.h" #include "log.h" +DEFINE_QOBJ_TYPE(srv6_locator); +DEFINE_MTYPE_STATIC(LIB, SRV6_LOCATOR, "SRV6 locator"); +DEFINE_MTYPE_STATIC(LIB, SRV6_LOCATOR_CHUNK, "SRV6 locator chunk"); + const char *seg6local_action2str(uint32_t action) { switch (action) { @@ -117,3 +121,84 @@ const char *seg6local_context2str(char *str, size_t size, return str; } } + +struct srv6_locator *srv6_locator_alloc(const char *name) +{ + struct srv6_locator *locator = NULL; + + locator = XCALLOC(MTYPE_SRV6_LOCATOR, sizeof(struct srv6_locator)); + strlcpy(locator->name, name, sizeof(locator->name)); + locator->chunks = list_new(); + QOBJ_REG(locator, srv6_locator); + return locator; +} + +struct srv6_locator_chunk *srv6_locator_chunk_alloc(void) +{ + struct srv6_locator_chunk *chunk = NULL; + + chunk = XCALLOC(MTYPE_SRV6_LOCATOR_CHUNK, + sizeof(struct srv6_locator_chunk)); + return chunk; +} + +void srv6_locator_free(struct srv6_locator *locator) +{ + XFREE(MTYPE_SRV6_LOCATOR, locator); +} + +void srv6_locator_chunk_free(struct srv6_locator_chunk *chunk) +{ + XFREE(MTYPE_SRV6_LOCATOR_CHUNK, chunk); +} + +json_object *srv6_locator_chunk_json(const struct srv6_locator_chunk *chunk) +{ + char str[256]; + json_object *jo_root = NULL; + + jo_root = json_object_new_object(); + prefix2str(&chunk->prefix, str, sizeof(str)); + json_object_string_add(jo_root, "prefix", str); + json_object_string_add(jo_root, "proto", + zebra_route_string(chunk->proto)); + + return jo_root; +} + +json_object *srv6_locator_json(const struct srv6_locator *loc) +{ + char str[256]; + struct listnode *node; + struct srv6_locator_chunk *chunk; + json_object *jo_root = NULL; + json_object *jo_chunk = NULL; + json_object *jo_chunks = NULL; + + jo_root = json_object_new_object(); + + /* set name */ + json_object_string_add(jo_root, "name", loc->name); + + /* set prefix */ + prefix2str(&loc->prefix, str, sizeof(str)); + json_object_string_add(jo_root, "prefix", str); + + /* set function_bits_length */ + json_object_int_add(jo_root, "function_bits_length", + loc->function_bits_length); + + /* set status_up */ + json_object_boolean_add(jo_root, "status_up", + loc->status_up); + + /* set chunks */ + jo_chunks = json_object_new_array(); + json_object_object_add(jo_root, "chunks", jo_chunks); + for (ALL_LIST_ELEMENTS_RO((struct list *)loc->chunks, node, chunk)) { + jo_chunk = srv6_locator_chunk_json(chunk); + json_object_array_add(jo_chunks, jo_chunk); + } + + return jo_root; +} diff --git a/lib/srv6.h b/lib/srv6.h index b72b098c78..46ff830e7f 100644 --- a/lib/srv6.h +++ b/lib/srv6.h @@ -21,10 +21,14 @@ #define _FRR_SRV6_H #include +#include "prefix.h" +#include "json.h" + #include #include #define SRV6_MAX_SIDS 16 +#define SRV6_LOCNAME_SIZE 256 #ifdef __cplusplus extern "C" { @@ -69,6 +73,27 @@ struct seg6local_context { uint32_t table; }; +struct srv6_locator { + char name[SRV6_LOCNAME_SIZE]; + struct prefix_ipv6 prefix; + uint8_t function_bits_length; + int algonum; + uint64_t current; + bool status_up; + struct list *chunks; + + QOBJ_FIELDS; +}; +DECLARE_QOBJ_TYPE(srv6_locator); + +struct srv6_locator_chunk { + uint8_t keep; + uint8_t proto; + uint16_t instance; + uint32_t session_id; + struct prefix_ipv6 prefix; +}; + static inline const char *seg6_mode2str(enum seg6_mode_t mode) { switch (mode) { @@ -126,6 +151,13 @@ const char *seg6local_context2str(char *str, size_t size, int snprintf_seg6_segs(char *str, size_t size, const struct seg6_segs *segs); +extern struct srv6_locator *srv6_locator_alloc(const char *name); +extern struct srv6_locator_chunk *srv6_locator_chunk_alloc(void); +extern void srv6_locator_free(struct srv6_locator *locator); +extern void srv6_locator_chunk_free(struct srv6_locator_chunk *chunk); +json_object *srv6_locator_chunk_json(const struct srv6_locator_chunk *chunk); +json_object *srv6_locator_json(const struct srv6_locator *loc); + #ifdef __cplusplus } #endif diff --git a/lib/zclient.c b/lib/zclient.c index bf67392cbe..c8bb720591 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -41,6 +41,7 @@ #include "lib_errors.h" #include "srte.h" #include "printfrr.h" +#include "srv6.h" DEFINE_MTYPE_STATIC(LIB, ZCLIENT, "Zclient"); DEFINE_MTYPE_STATIC(LIB, REDIST_INST, "Redistribution instance IDs"); @@ -2637,6 +2638,174 @@ stream_failure: return -1; } +/** + * Connect to srv6 manager in a syncronous way + * + * It first writes the request to zcient output buffer and then + * immediately reads the answer from the input buffer. + * + * @param zclient Zclient used to connect to srv6 manager (zebra) + * @result Result of response + */ +int srv6_manager_connect(struct zclient *zclient) +{ + struct stream *s; + int ret, result = 0; + uint16_t cmd = ZEBRA_SRV6_MANAGER_CONNECT; + + if (zclient_debug) + zlog_debug("Connecting to SRv6 Manager"); + + if (zclient->sock < 0) { + zlog_debug("%s: invalid zclient socket", __func__); + return -1; + } + + /* send request */ + s = zclient->obuf; + stream_reset(s); + zclient_create_header(s, cmd, VRF_DEFAULT); + + stream_putc(s, zclient->redist_default); /* proto */ + stream_putw(s, zclient->instance); /* instance */ + stream_putw_at(s, 0, stream_get_endp(s)); + ret = writen(zclient->sock, s->data, stream_get_endp(s)); + if (ret < 0) { + flog_err(EC_LIB_ZAPI_SOCKET, "Can't write to zclient sock"); + close(zclient->sock); + zclient->sock = -1; + return -1; + } + if (ret == 0) { + flog_err(EC_LIB_ZAPI_SOCKET, "Zclient sock closed"); + close(zclient->sock); + zclient->sock = -1; + return -1; + } + if (zclient_debug) + zlog_debug("SRv6 Manager connect request sent (%d bytes)", ret); + + /* read response */ + if (zclient_read_sync_response(zclient, cmd) + != 0) + return -1; + + s = zclient->ibuf; + + /* read instance and proto */ + uint8_t proto; + uint16_t instance; + + STREAM_GETC(s, proto); + STREAM_GETW(s, instance); + + /* sanity */ + if (proto != zclient->redist_default) + flog_err( + EC_LIB_ZAPI_ENCODE, + "Wrong proto (%u) in SRv6 Manager connect response. Should be %u", + proto, zclient->redist_default); + if (instance != zclient->instance) + flog_err( + EC_LIB_ZAPI_ENCODE, + "Wrong instId (%u) in SRv6 Manager connect response. Should be %u", + instance, zclient->instance); + + /* result code */ + STREAM_GETC(s, result); + if (zclient_debug) + zlog_debug("SRv6 Manager connect-response received, result %u", result); + + return (int)result; + +stream_failure: + return -1; +} + +/** + * Function to request a srv6-locator chunk in an Asyncronous way + * + * It first writes the request to zclient output buffer and then + * immediately reads the answer from the input buffer. + * + * @param zclient Zclient used to connect to table manager (zebra) + * @param locator_name Name of SRv6-locator + * @result 0 on success, -1 otherwise + */ +int srv6_manager_get_locator_chunk(struct zclient *zclient, + const char *locator_name) +{ + struct stream *s; + const size_t len = strlen(locator_name); + + if (zclient_debug) + zlog_debug("Getting SRv6-Locator Chunk %s", locator_name); + + if (zclient->sock < 0) + return -1; + + /* send request */ + s = zclient->obuf; + stream_reset(s); + zclient_create_header(s, ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK, VRF_DEFAULT); + + /* proto */ + stream_putc(s, zclient->redist_default); + + /* instance */ + stream_putw(s, zclient->instance); + + /* locator_name */ + stream_putw(s, len); + stream_put(s, locator_name, len); + + /* Put length at the first point of the stream. */ + stream_putw_at(s, 0, stream_get_endp(s)); + + return zclient_send_message(zclient); +} + +/** + * Function to release a srv6-locator chunk + * + * @param zclient Zclient used to connect to table manager (zebra) + * @param locator_name Name of SRv6-locator + * @result 0 on success, -1 otherwise + */ +int srv6_manager_release_locator_chunk(struct zclient *zclient, + const char *locator_name) +{ + struct stream *s; + const size_t len = strlen(locator_name); + + if (zclient_debug) + zlog_debug("Releasing SRv6-Locator Chunk %s", locator_name); + + if (zclient->sock < 0) + return -1; + + /* send request */ + s = zclient->obuf; + stream_reset(s); + zclient_create_header(s, ZEBRA_SRV6_MANAGER_RELEASE_LOCATOR_CHUNK, + VRF_DEFAULT); + + /* proto */ + stream_putc(s, zclient->redist_default); + + /* instance */ + stream_putw(s, zclient->instance); + + /* locator_name */ + stream_putw(s, len); + stream_put(s, locator_name, len); + + /* Put length at the first point of the stream. */ + stream_putw_at(s, 0, stream_get_endp(s)); + + return zclient_send_message(zclient); +} + /* * Asynchronous label chunk request * @@ -3927,6 +4096,21 @@ static int zclient_read(struct thread *thread) case ZEBRA_MLAG_FORWARD_MSG: zclient_mlag_handle_msg(command, zclient, length, vrf_id); break; + case ZEBRA_SRV6_LOCATOR_ADD: + if (zclient->srv6_locator_add) + (*zclient->srv6_locator_add)(command, zclient, length, + vrf_id); + break; + case ZEBRA_SRV6_LOCATOR_DELETE: + if (zclient->srv6_locator_delete) + (*zclient->srv6_locator_delete)(command, zclient, + length, vrf_id); + break; + case ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK: + if (zclient->process_srv6_locator_chunk) + (*zclient->process_srv6_locator_chunk)(command, zclient, + length, vrf_id); + break; case ZEBRA_ERROR: zclient_handle_error(command, zclient, length, vrf_id); break; diff --git a/lib/zclient.h b/lib/zclient.h index 3f5225f097..6496e79c89 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -39,6 +39,7 @@ #include "mlag.h" #include "srte.h" +#include "srv6.h" #ifdef __cplusplus extern "C" { @@ -216,6 +217,11 @@ typedef enum { ZEBRA_NHG_NOTIFY_OWNER, ZEBRA_EVPN_REMOTE_NH_ADD, ZEBRA_EVPN_REMOTE_NH_DEL, + ZEBRA_SRV6_LOCATOR_ADD, + ZEBRA_SRV6_LOCATOR_DELETE, + ZEBRA_SRV6_MANAGER_CONNECT, + ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK, + ZEBRA_SRV6_MANAGER_RELEASE_LOCATOR_CHUNK, ZEBRA_ERROR, ZEBRA_CLIENT_CAPABILITIES, ZEBRA_OPAQUE_MESSAGE, @@ -387,6 +393,11 @@ struct zclient { int (*mlag_process_down)(void); int (*mlag_handle_msg)(struct stream *msg, int len); int (*nhg_notify_owner)(ZAPI_CALLBACK_ARGS); + int (*srv6_locator_add)(ZAPI_CALLBACK_ARGS); + int (*srv6_locator_delete)(ZAPI_CALLBACK_ARGS); + int (*srv6_function_add)(ZAPI_CALLBACK_ARGS); + int (*srv6_function_delete)(ZAPI_CALLBACK_ARGS); + void (*process_srv6_locator_chunk)(ZAPI_CALLBACK_ARGS); int (*handle_error)(enum zebra_error_types error); int (*opaque_msg_handler)(ZAPI_CALLBACK_ARGS); int (*opaque_register_handler)(ZAPI_CALLBACK_ARGS); @@ -1051,6 +1062,11 @@ extern int tm_get_table_chunk(struct zclient *zclient, uint32_t chunk_size, uint32_t *start, uint32_t *end); extern int tm_release_table_chunk(struct zclient *zclient, uint32_t start, uint32_t end); +extern int srv6_manager_connect(struct zclient *zclient); +extern int srv6_manager_get_locator_chunk(struct zclient *zclient, + const char *locator_name); +extern int srv6_manager_release_locator_chunk(struct zclient *zclient, + const char *locator_name); extern enum zclient_send_status zebra_send_sr_policy(struct zclient *zclient, int cmd, From 6e68a08484bf8f5c79f041ce8c103ce42abc2e7f Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Wed, 9 Dec 2020 18:52:17 +0900 Subject: [PATCH 10/66] zebra: ZAPI add new api to manipulate srv6-locator (step2) This commit is a part of #5853 works that add new ZAPI to configure SRv6 locator which manages chunk prefix for SRv6 SID IPv6 address for each routing protocol daemons. NEW-ZAPIs: * ZEBRA_SRV6_LOCATOR_ADD * ZEBRA_SRV6_LOCATOR_DELETE * ZEBRA_SRV6_MANAGER_CONNECT * ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK * ZEBRA_SRV6_MANAGER_RELEASE_LOCATOR_CHUNK Zclient can connect to zebra's srv6-manager with ZEBRA_SRV6_MANAGER_CONNECT api like a label-manager. Then zclient uses ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK to allocated dedicated locator chunk for it's routing protocol. Zebra works for only prefix reservation and distribute the ownership of the locator chunks for zcliens. Then, zclient installs SRv6 function with ZEBRA_ROUTE_ADD api with nh_seg6local_* fields. This feature is already implemented by another PR(#7680). Signed-off-by: Hiroki Shirokura --- zebra/main.c | 2 + zebra/subdir.am | 2 + zebra/zapi_msg.c | 166 ++++++++++++++++++++ zebra/zapi_msg.h | 9 ++ zebra/zebra_errors.c | 6 + zebra/zebra_errors.h | 1 + zebra/zebra_srv6.c | 349 +++++++++++++++++++++++++++++++++++++++++++ zebra/zebra_srv6.h | 79 ++++++++++ 8 files changed, 614 insertions(+) create mode 100644 zebra/zebra_srv6.c create mode 100644 zebra/zebra_srv6.h diff --git a/zebra/main.c b/zebra/main.c index 259c70d0df..e36af51005 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -57,6 +57,7 @@ #include "zebra/zebra_nb.h" #include "zebra/zebra_opaque.h" #include "zebra/zebra_srte.h" +#include "zebra/zebra_srv6.h" #include "zebra/zebra_srv6_vty.h" #define ZEBRA_PTM_SUPPORT @@ -419,6 +420,7 @@ int main(int argc, char **argv) zebra_pbr_init(); zebra_opaque_init(); zebra_srte_init(); + zebra_srv6_init(); zebra_srv6_vty_init(); /* For debug purpose. */ diff --git a/zebra/subdir.am b/zebra/subdir.am index ca77502ba3..4d8115597b 100644 --- a/zebra/subdir.am +++ b/zebra/subdir.am @@ -93,6 +93,7 @@ zebra_zebra_SOURCES = \ zebra/zebra_mpls_openbsd.c \ zebra/zebra_mpls_null.c \ zebra/zebra_mpls_vty.c \ + zebra/zebra_srv6.c \ zebra/zebra_srv6_vty.c \ zebra/zebra_mroute.c \ zebra/zebra_nb.c \ @@ -163,6 +164,7 @@ noinst_HEADERS += \ zebra/zebra_mlag.h \ zebra/zebra_mlag_vty.h \ zebra/zebra_mpls.h \ + zebra/zebra_srv6.h \ zebra/zebra_srv6_vty.h \ zebra/zebra_mroute.h \ zebra/zebra_nb.h \ diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 752738b214..fa6a4cfca7 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -60,6 +60,7 @@ #include "zebra/connected.h" #include "zebra/zebra_opaque.h" #include "zebra/zebra_srte.h" +#include "zebra/zebra_srv6.h" DEFINE_MTYPE_STATIC(ZEBRA, OPAQUE, "Opaque Data"); @@ -1136,6 +1137,29 @@ static int zsend_table_manager_connect_response(struct zserv *client, return zserv_send_message(client, s); } +static int zsend_srv6_manager_connect_response(struct zserv *client, + vrf_id_t vrf_id, + uint16_t result) +{ + struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); + + zclient_create_header(s, ZEBRA_SRV6_MANAGER_CONNECT, vrf_id); + + /* proto */ + stream_putc(s, client->proto); + + /* instance */ + stream_putw(s, client->instance); + + /* result */ + stream_putc(s, result); + + /* Write packet size. */ + stream_putw_at(s, 0, stream_get_endp(s)); + + return zserv_send_message(client, s); +} + /* Inbound message handling ------------------------------------------------ */ const int cmd2type[] = { @@ -2624,6 +2648,74 @@ int zsend_client_close_notify(struct zserv *client, struct zserv *closed_client) return zserv_send_message(client, s); } +/* Send response to a srv6 manager connect request to client */ +static void zread_srv6_manager_connect(struct zserv *client, + struct stream *msg, vrf_id_t vrf_id) +{ + struct stream *s; + uint8_t proto; + uint16_t instance; + struct vrf *vrf = vrf_lookup_by_id(vrf_id); + + s = msg; + + /* Get data. */ + STREAM_GETC(s, proto); + STREAM_GETW(s, instance); + + /* accept only dynamic routing protocols */ + if ((proto >= ZEBRA_ROUTE_MAX) || (proto <= ZEBRA_ROUTE_STATIC)) { + flog_err(EC_ZEBRA_TM_WRONG_PROTO, + "client %d has wrong protocol %s", client->sock, + zebra_route_string(proto)); + zsend_srv6_manager_connect_response(client, vrf_id, 1); + return; + } + zlog_notice("client %d with vrf %s(%u) instance %u connected as %s", + client->sock, VRF_LOGNAME(vrf), vrf_id, instance, + zebra_route_string(proto)); + client->proto = proto; + client->instance = instance; + + /* + * Release previous locators of same protocol and instance. + * This is done in case it restarted from an unexpected shutdown. + */ + release_daemon_srv6_locator_chunks(client); + + zsend_srv6_manager_connect_response(client, vrf_id, 0); + +stream_failure: + return; +} + +int zsend_srv6_manager_get_locator_chunk_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_CHUNK, vrf_id); + + /* proto */ + stream_putc(s, client->proto); + + /* instance */ + stream_putw(s, client->instance); + + if (loc) { + 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, 16); + } + + /* Write packet size. */ + stream_putw_at(s, 0, stream_get_endp(s)); + + return zserv_send_message(client, s); +} + /* Send response to a table manager connect request to client */ static void zread_table_manager_connect(struct zserv *client, struct stream *msg, vrf_id_t vrf_id) @@ -2833,6 +2925,77 @@ static void zread_table_manager_request(ZAPI_HANDLER_ARGS) } } +static void zread_srv6_manager_get_locator_chunk(struct zserv *client, + struct stream *msg, + vrf_id_t vrf_id) +{ + struct stream *s = msg; + uint8_t proto; + uint16_t instance; + uint16_t len; + char locator_name[SRV6_LOCNAME_SIZE] = {0}; + + /* Get data. */ + STREAM_GETC(s, proto); + STREAM_GETW(s, instance); + STREAM_GETW(s, len); + STREAM_GET(locator_name, s, len); + + assert(proto == client->proto && instance == client->instance); + + /* call hook to get a chunk using wrapper */ + struct srv6_locator *loc = NULL; + srv6_manager_get_locator_chunk_call(&loc, client, locator_name, vrf_id); + +stream_failure: + return; +} + +static void zread_srv6_manager_release_locator_chunk(struct zserv *client, + struct stream *msg, + vrf_id_t vrf_id) +{ + struct stream *s = msg; + uint8_t proto; + uint16_t instance; + uint16_t len; + char locator_name[SRV6_LOCNAME_SIZE] = {0}; + + /* Get data. */ + STREAM_GETC(s, proto); + STREAM_GETW(s, instance); + STREAM_GETW(s, len); + STREAM_GET(locator_name, s, len); + + assert(proto == client->proto && instance == client->instance); + + /* call hook to release a chunk using wrapper */ + srv6_manager_release_locator_chunk_call(client, locator_name, vrf_id); + +stream_failure: + return; +} + +static void zread_srv6_manager_request(ZAPI_HANDLER_ARGS) +{ + switch (hdr->command) { + case ZEBRA_SRV6_MANAGER_CONNECT: + zread_srv6_manager_connect(client, msg, zvrf_id(zvrf)); + break; + case ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK: + zread_srv6_manager_get_locator_chunk(client, msg, + zvrf_id(zvrf)); + break; + case ZEBRA_SRV6_MANAGER_RELEASE_LOCATOR_CHUNK: + zread_srv6_manager_release_locator_chunk(client, msg, + zvrf_id(zvrf)); + break; + default: + zlog_err("%s: unknown SRv6 Mamanger command", __func__); + break; + } +} + static void zread_pseudowire(ZAPI_HANDLER_ARGS) { struct stream *s; @@ -3592,6 +3755,9 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = { [ZEBRA_MLAG_CLIENT_REGISTER] = zebra_mlag_client_register, [ZEBRA_MLAG_CLIENT_UNREGISTER] = zebra_mlag_client_unregister, [ZEBRA_MLAG_FORWARD_MSG] = zebra_mlag_forward_client_msg, + [ZEBRA_SRV6_MANAGER_CONNECT] = zread_srv6_manager_request, + [ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK] = zread_srv6_manager_request, + [ZEBRA_SRV6_MANAGER_RELEASE_LOCATOR_CHUNK] = zread_srv6_manager_request, [ZEBRA_CLIENT_CAPABILITIES] = zread_client_capabilities, [ZEBRA_NEIGH_DISCOVER] = zread_neigh_discover, [ZEBRA_NHG_ADD] = zread_nhg_add, diff --git a/zebra/zapi_msg.h b/zebra/zapi_msg.h index 0beb3cc100..35bb554121 100644 --- a/zebra/zapi_msg.h +++ b/zebra/zapi_msg.h @@ -30,6 +30,7 @@ #include "zebra/zebra_pbr.h" #include "zebra/zebra_errors.h" #include "zebra/label_manager.h" +#include "zebra/zebra_srv6.h" #ifdef __cplusplus @@ -116,6 +117,14 @@ int zsend_nhg_notify(uint16_t type, uint16_t instance, uint32_t session_id, extern void zapi_opaque_free(struct opaque *opaque); +extern int zsend_zebra_srv6_locator_add(struct zserv *client, + struct srv6_locator *loc); +extern int zsend_zebra_srv6_locator_delete(struct zserv *client, + struct srv6_locator *loc); +extern int zsend_srv6_manager_get_locator_chunk_response(struct zserv *client, + vrf_id_t vrf_id, + struct srv6_locator *loc); + #ifdef __cplusplus } #endif diff --git a/zebra/zebra_errors.c b/zebra/zebra_errors.c index 29b271425d..c3890f7220 100644 --- a/zebra/zebra_errors.c +++ b/zebra/zebra_errors.c @@ -785,6 +785,12 @@ static struct log_ref ferr_zebra_err[] = { .description = "Zebra has detected a situation where there are two vrf devices with the exact same tableid. This is considered a complete misconfiguration of VRF devices and breaks a fundamental assumption in FRR about how VRF's work", .suggestion = "Use different table id's for the VRF's in question" }, + { + .code = EC_ZEBRA_SRV6M_UNRELEASED_LOCATOR_CHUNK, + .title = "Zebra did not free any srv6 locator chunks", + .description = "Zebra's srv6-locator chunk cleanup procedure ran, but no srv6 locator chunks were released.", + .suggestion = "Ignore this error.", + }, { .code = END_FERR, } diff --git a/zebra/zebra_errors.h b/zebra/zebra_errors.h index 200a977a69..540c6dd7d0 100644 --- a/zebra/zebra_errors.h +++ b/zebra/zebra_errors.h @@ -135,6 +135,7 @@ enum zebra_log_refs { EC_ZEBRA_VRF_MISCONFIGURED, EC_ZEBRA_ES_CREATE, EC_ZEBRA_GRE_SET_UPDATE, + EC_ZEBRA_SRV6M_UNRELEASED_LOCATOR_CHUNK, }; void zebra_error_init(void); diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c new file mode 100644 index 0000000000..b4b691e8e0 --- /dev/null +++ b/zebra/zebra_srv6.c @@ -0,0 +1,349 @@ +/* + * Zebra SRv6 definitions + * Copyright (C) 2020 Hiroki Shirokura, LINE Corporation + * Copyright (C) 2020 Masakazu Asama + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "network.h" +#include "prefix.h" +#include "stream.h" +#include "srv6.h" +#include "zebra/debug.h" +#include "zebra/zapi_msg.h" +#include "zebra/zserv.h" +#include "zebra/zebra_router.h" +#include "zebra/zebra_srv6.h" +#include "zebra/zebra_errors.h" +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +DEFINE_MGROUP(SRV6_MGR, "SRv6 Manager"); +DEFINE_MTYPE_STATIC(SRV6_MGR, SRV6M_CHUNK, "SRv6 Manager Chunk"); + +/* define hooks for the basic API, so that it can be specialized or served + * externally + */ + +DEFINE_HOOK(srv6_manager_client_connect, + (struct zserv *client, vrf_id_t vrf_id), + (client, vrf_id)); +DEFINE_HOOK(srv6_manager_client_disconnect, + (struct zserv *client), (client)); +DEFINE_HOOK(srv6_manager_get_chunk, + (struct srv6_locator **loc, + struct zserv *client, + const char *locator_name, + vrf_id_t vrf_id), + (loc, client, locator_name, vrf_id)); +DEFINE_HOOK(srv6_manager_release_chunk, + (struct zserv *client, + const char *locator_name, + vrf_id_t vrf_id), + (client, locator_name, vrf_id)); + +/* define wrappers to be called in zapi_msg.c (as hooks must be called in + * source file where they were defined) + */ + +void srv6_manager_client_connect_call(struct zserv *client, vrf_id_t vrf_id) +{ + hook_call(srv6_manager_client_connect, client, vrf_id); +} + +void srv6_manager_get_locator_chunk_call(struct srv6_locator **loc, + struct zserv *client, + const char *locator_name, + vrf_id_t vrf_id) +{ + hook_call(srv6_manager_get_chunk, loc, client, locator_name, vrf_id); +} + +void srv6_manager_release_locator_chunk_call(struct zserv *client, + const char *locator_name, + vrf_id_t vrf_id) +{ + hook_call(srv6_manager_release_chunk, client, locator_name, vrf_id); +} + +int srv6_manager_client_disconnect_cb(struct zserv *client) +{ + hook_call(srv6_manager_client_disconnect, client); + return 0; +} + +static int zebra_srv6_cleanup(struct zserv *client) +{ + return 0; +} + +void zebra_srv6_locator_add(struct srv6_locator *locator) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct srv6_locator *tmp; + + tmp = zebra_srv6_locator_lookup(locator->name); + if (!tmp) + listnode_add(srv6->locators, locator); +} + +void zebra_srv6_locator_delete(struct srv6_locator *locator) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + listnode_delete(srv6->locators, locator); +} + +struct srv6_locator *zebra_srv6_locator_lookup(const char *name) +{ + 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 (!strncmp(name, locator->name, SRV6_LOCNAME_SIZE)) + return locator; + return NULL; +} + +struct zebra_srv6 *zebra_srv6_get_default(void) +{ + static struct zebra_srv6 srv6; + static bool first_execution = true; + + if (first_execution) { + first_execution = false; + srv6.locators = list_new(); + } + return &srv6; +} + +/** + * 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 struct srv6_locator * +assign_srv6_locator_chunk(uint8_t proto, + uint16_t instance, + uint32_t session_id, + const char *locator_name) +{ + bool chunk_found = false; + struct listnode *node = NULL; + struct srv6_locator *loc = NULL; + struct srv6_locator_chunk *chunk = NULL; + + loc = zebra_srv6_locator_lookup(locator_name); + if (!loc) { + zlog_info("%s: locator %s was not found", + __func__, locator_name); + + 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 = 0; + listnode_add(loc->chunks, chunk); + zebra_srv6_locator_add(loc); + } + + for (ALL_LIST_ELEMENTS_RO((struct list *)loc->chunks, node, chunk)) { + if (chunk->proto != 0 && chunk->proto != proto) + continue; + chunk_found = true; + break; + } + + if (!chunk_found) { + zlog_info("%s: locator is already owned", __func__); + return NULL; + } + + chunk->proto = proto; + return loc; +} + +static int zebra_srv6_manager_get_locator_chunk(struct srv6_locator **loc, + struct zserv *client, + const char *locator_name, + vrf_id_t vrf_id) +{ + *loc = assign_srv6_locator_chunk(client->proto, client->instance, + client->session_id, 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); + + int ret = 0; + if ((*loc)->status_up) + ret = zsend_srv6_manager_get_locator_chunk_response(client, + vrf_id, + *loc); + return ret; +} + +/** + * 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 release_srv6_locator_chunk(uint8_t proto, uint16_t instance, + uint32_t session_id, + const char *locator_name) +{ + int ret = -1; + struct listnode *node; + struct srv6_locator_chunk *chunk; + struct srv6_locator *loc = NULL; + + loc = zebra_srv6_locator_lookup(locator_name); + if (!loc) { + return -1; + } + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: Releasing srv6-locator on %s", __func__, + locator_name); + + for (ALL_LIST_ELEMENTS_RO((struct list *)loc->chunks, node, chunk)) { + if (chunk->proto != proto || + chunk->instance != instance || + chunk->session_id != session_id) + continue; + chunk->proto = NO_PROTO; + chunk->instance = 0; + chunk->session_id = 0; + chunk->keep = 0; + ret = 0; + break; + } + + if (ret != 0) + flog_err(EC_ZEBRA_SRV6M_UNRELEASED_LOCATOR_CHUNK, + "%s: SRv6 locator chunk not released", __func__); + + return ret; +} + +static int zebra_srv6_manager_release_locator_chunk(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. + * + * Called on client disconnection or reconnection. It only releases chunks + * with empty keep value. + * + * @param proto Daemon protocol of client, to identify the owner + * @param instance Instance, to identify the owner + * @return Number of chunks released + */ +int release_daemon_srv6_locator_chunks(struct zserv *client) +{ + int ret; + int count = 0; + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct listnode *loc_node; + struct listnode *chunk_node; + struct srv6_locator *loc; + struct srv6_locator_chunk *chunk; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: Releasing chunks for client proto %s, instance %d, session %u", + __func__, zebra_route_string(client->proto), + client->instance, client->session_id); + + for (ALL_LIST_ELEMENTS_RO(srv6->locators, loc_node, loc)) { + for (ALL_LIST_ELEMENTS_RO(loc->chunks, chunk_node, chunk)) { + if (chunk->proto == client->proto && + chunk->instance == client->instance && + chunk->session_id == client->session_id && + chunk->keep == 0) { + ret = release_srv6_locator_chunk( + chunk->proto, chunk->instance, + chunk->session_id, loc->name); + if (ret == 0) + count++; + } + } + } + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: Released %d srv6-locator chunks", + __func__, count); + + return count; +} + +void zebra_srv6_init(void) +{ + hook_register(zserv_client_close, zebra_srv6_cleanup); + hook_register(srv6_manager_get_chunk, + zebra_srv6_manager_get_locator_chunk); + hook_register(srv6_manager_release_chunk, + zebra_srv6_manager_release_locator_chunk); +} + +bool zebra_srv6_is_enable(void) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + + return listcount(srv6->locators); +} diff --git a/zebra/zebra_srv6.h b/zebra/zebra_srv6.h new file mode 100644 index 0000000000..751cee6e70 --- /dev/null +++ b/zebra/zebra_srv6.h @@ -0,0 +1,79 @@ +/* + * Zebra SRv6 definitions + * Copyright (C) 2020 Hiroki Shirokura, LINE Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _ZEBRA_SRV6_H +#define _ZEBRA_SRV6_H + +#include +#include +#include + +#include "qobj.h" +#include "prefix.h" +#include +#include + +/* SRv6 instance structure. */ +struct zebra_srv6 { + struct list *locators; +}; + +/* declare hooks for the basic API, so that it can be specialized or served + * externally. Also declare a hook when those functions have been registered, + * so that any external module wanting to replace those can react + */ + +DECLARE_HOOK(srv6_manager_client_connect, + (struct zserv *client, vrf_id_t vrf_id), + (client, vrf_id)); +DECLARE_HOOK(srv6_manager_client_disconnect, + (struct zserv *client), (client)); +DECLARE_HOOK(srv6_manager_get_chunk, + (struct srv6_locator **loc, + struct zserv *client, + const char *locator_name, + vrf_id_t vrf_id), + (mc, client, keep, size, base, vrf_id)); +DECLARE_HOOK(srv6_manager_release_chunk, + (struct zserv *client, + const char *locator_name, + vrf_id_t vrf_id), + (client, locator_name, vrf_id)); + + +extern void zebra_srv6_locator_add(struct srv6_locator *locator); +extern void zebra_srv6_locator_delete(struct srv6_locator *locator); +extern struct srv6_locator *zebra_srv6_locator_lookup(const char *name); + +extern void zebra_srv6_init(void); +extern struct zebra_srv6 *zebra_srv6_get_default(void); +extern bool zebra_srv6_is_enable(void); + +extern void srv6_manager_client_connect_call(struct zserv *client, vrf_id_t vrf_id); +extern void srv6_manager_get_locator_chunk_call(struct srv6_locator **loc, + struct zserv *client, + const char *locator_name, + vrf_id_t vrf_id); +extern void srv6_manager_release_locator_chunk_call(struct zserv *client, + const char *locator_name, + vrf_id_t vrf_id); +extern int srv6_manager_client_disconnect_cb(struct zserv *client); +extern int release_daemon_srv6_locator_chunks(struct zserv *client); + +#endif /* _ZEBRA_SRV6_H */ From 0097897734b08194d0c6acae1d759e2001cd9026 Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Sun, 23 Feb 2020 11:38:26 +0000 Subject: [PATCH 11/66] zebra: add new CLI to manipulate srv6-locator (step2) This commit is a part of #5853 works that add new clis to configure SRv6 locator and its show commands. Following clis are added on this commit. vtysh -c 'conf te' \ -c 'segment-routing' \ -c ' srv6' \ -c ' locators' \ -c ' locator LOC1' \ -c ' prefix A::/64' - "show segment-routing srv6 sid [json]" - "show segment-routing srv6 locator [json]" - "show segment-routing srv6 locator NAME detail [json]" - "show runnning-config" (make it to print srv6 configuration) Signed-off-by: Hiroki Shirokura --- zebra/zebra_srv6_vty.c | 205 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) diff --git a/zebra/zebra_srv6_vty.c b/zebra/zebra_srv6_vty.c index f8eff70c2d..73038fad73 100644 --- a/zebra/zebra_srv6_vty.c +++ b/zebra/zebra_srv6_vty.c @@ -31,7 +31,9 @@ #include "lib/json.h" #include "zebra/zserv.h" +#include "zebra/zebra_router.h" #include "zebra/zebra_vrf.h" +#include "zebra/zebra_srv6.h" #include "zebra/zebra_srv6_vty.h" #include "zebra/zebra_rnh.h" #include "zebra/redistribute.h" @@ -70,6 +72,108 @@ static struct cmd_node srv6_loc_node = { .prompt = "%s(config-srv6-locator)# " }; +DEFUN (show_srv6_locator, + show_srv6_locator_cmd, + "show segment-routing srv6 locator [json]", + SHOW_STR + "Segment Routing\n" + "Segment Routing SRv6\n" + "Locator Information\n" + JSON_STR) +{ + const bool uj = use_json(argc, argv); + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct srv6_locator *locator; + struct listnode *node; + char str[256]; + int id; + json_object *json = NULL; + json_object *json_locators = NULL; + json_object *json_locator = NULL; + + if (uj) { + json = json_object_new_object(); + json_locators = json_object_new_array(); + json_object_object_add(json, "locators", json_locators); + + for (ALL_LIST_ELEMENTS_RO(srv6->locators, node, locator)) { + json_locator = srv6_locator_json(locator); + if (!json_locator) + continue; + json_object_array_add(json_locators, json_locator); + + } + + vty_out(vty, "%s\n", json_object_to_json_string_ext(json, + JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } else { + vty_out(vty, "Locator:\n"); + vty_out(vty, "Name ID Prefix Status\n"); + vty_out(vty, "-------------------- ------- ------------------------ -------\n"); + + id = 1; + for (ALL_LIST_ELEMENTS_RO(srv6->locators, node, locator)) { + prefix2str(&locator->prefix, str, sizeof(str)); + vty_out(vty, "%-20s %7d %-24s %s\n", + locator->name, id, str, + locator->status_up ? "Up" : "Down"); + ++id; + } + vty_out(vty, "\n"); + } + + return CMD_SUCCESS; +} + +DEFUN (show_srv6_locator_detail, + show_srv6_locator_detail_cmd, + "show segment-routing srv6 locator NAME detail [json]", + SHOW_STR + "Segment Routing\n" + "Segment Routing SRv6\n" + "Locator Information\n" + "Locator Name\n" + "Detailed information\n" + JSON_STR) +{ + const bool uj = use_json(argc, argv); + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct srv6_locator *locator; + struct listnode *node; + char str[256]; + const char *locator_name = argv[4]->arg; + + if (uj) { + vty_out(vty, "JSON format isn't supported\n"); + return CMD_WARNING; + } else { + for (ALL_LIST_ELEMENTS_RO(srv6->locators, node, locator)) { + if (strcmp(locator->name, locator_name) != 0) { + continue; + } + + prefix2str(&locator->prefix, str, sizeof(str)); + vty_out(vty, "Name: %s\n", locator->name); + vty_out(vty, "Prefix: %s\n", str); + vty_out(vty, "Function-Bit-Len: %u\n", + locator->function_bits_length); + + vty_out(vty, "Chunks:\n"); + struct listnode *node; + struct srv6_locator_chunk *chunk; + for (ALL_LIST_ELEMENTS_RO((struct list *)locator->chunks, node, chunk)) { + prefix2str(&chunk->prefix, str, sizeof(str)); + vty_out(vty, "- prefix: %s, owner: %s\n", str, + zebra_route_string(chunk->proto)); + } + } + + } + + return CMD_SUCCESS; +} + DEFUN_NOSH (segment_routing, segment_routing_cmd, "segment-routing", @@ -103,12 +207,106 @@ DEFUN_NOSH (srv6_locator, "Segment Routing SRv6 locator\n" "Specify locator-name\n") { + struct srv6_locator *locator = NULL; + + locator = zebra_srv6_locator_lookup(argv[1]->arg); + if (locator) { + VTY_PUSH_CONTEXT(SRV6_LOC_NODE, locator); + locator->status_up = true; + return CMD_SUCCESS; + } + + locator = srv6_locator_alloc(argv[1]->arg); + if (!locator) { + vty_out(vty, "%% Alloc failed\n"); + return CMD_WARNING_CONFIG_FAILED; + } + locator->status_up = true; + + VTY_PUSH_CONTEXT(SRV6_LOC_NODE, locator); vty->node = SRV6_LOC_NODE; return CMD_SUCCESS; } +DEFUN (locator_prefix, + locator_prefix_cmd, + "prefix X:X::X:X/M [func-bits (8-64)]", + "Configure SRv6 locator prefix\n" + "Specify SRv6 locator prefix\n" + "Configure SRv6 locator function length in bits\n" + "Specify SRv6 locator function length in bits\n") +{ + VTY_DECLVAR_CONTEXT(srv6_locator, locator); + struct prefix_ipv6 prefix; + struct srv6_locator_chunk *chunk = NULL; + struct listnode *node = NULL; + uint8_t function_bits_length = 16; + int ret; + + ret = str2prefix_ipv6(argv[1]->arg, &prefix); + if (ret <= 0) { + vty_out(vty, "%% Malformed address\n"); + return CMD_WARNING_CONFIG_FAILED; + } + apply_mask_ipv6(&prefix); + + if (argc >= 3) + function_bits_length = strtoul(argv[3]->arg, NULL, 10); + + locator->prefix = prefix; + locator->function_bits_length = function_bits_length; + + if (list_isempty(locator->chunks)) { + chunk = srv6_locator_chunk_alloc(); + chunk->prefix = prefix; + chunk->proto = 0; + listnode_add(locator->chunks, chunk); + } else { + for (ALL_LIST_ELEMENTS_RO(locator->chunks, node, chunk)) { + uint8_t zero[16] = {0}; + if (memcmp(&chunk->prefix.prefix, zero, 16) == 0) { + struct zserv *client; + struct listnode *client_node; + chunk->prefix = prefix; + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, client_node, client)) { + if (client->proto != chunk->proto) + continue; + struct srv6_locator *tmp; + srv6_manager_get_locator_chunk_call( + &tmp, client, locator->name, VRF_DEFAULT); + } + } + } + } + + zebra_srv6_locator_add(locator); + return CMD_SUCCESS; +} + static int zebra_sr_config(struct vty *vty) { + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct listnode *node; + struct srv6_locator *locator; + char str[256]; + + vty_out(vty, "!\n"); + if (zebra_srv6_is_enable()) { + vty_out(vty, "segment-routing\n"); + vty_out(vty, " srv6\n"); + vty_out(vty, " locators\n"); + for (ALL_LIST_ELEMENTS_RO(srv6->locators, node, locator)) { + inet_ntop(AF_INET6, &locator->prefix.prefix, + str, sizeof(str)); + vty_out(vty, " locator %s\n", locator->name); + vty_out(vty, " prefix %s/%u\n", str, + locator->prefix.prefixlen); + vty_out(vty, " !\n"); + } + vty_out(vty, " !\n"); + vty_out(vty, " !\n"); + vty_out(vty, "!\n"); + } return 0; } @@ -129,4 +327,11 @@ void zebra_srv6_vty_init(void) install_element(SEGMENT_ROUTING_NODE, &srv6_cmd); install_element(SRV6_NODE, &srv6_locators_cmd); install_element(SRV6_LOCS_NODE, &srv6_locator_cmd); + + /* Command for configuration */ + install_element(SRV6_LOC_NODE, &locator_prefix_cmd); + + /* Command for operation */ + install_element(VIEW_NODE, &show_srv6_locator_cmd); + install_element(VIEW_NODE, &show_srv6_locator_detail_cmd); } From ade3eebc6a54a84e6949b86e5e391824f1b172ca Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Sun, 11 Oct 2020 17:27:40 +0900 Subject: [PATCH 12/66] sharpd: support create/delete srv6-locator (step2) Signed-off-by: Hiroki Shirokura --- sharpd/sharp_globals.h | 13 +++++ sharpd/sharp_main.c | 1 + sharpd/sharp_vty.c | 105 +++++++++++++++++++++++++++++++++++++++++ sharpd/sharp_zebra.c | 63 +++++++++++++++++++++++++ sharpd/sharp_zebra.h | 7 +++ 5 files changed, 189 insertions(+) diff --git a/sharpd/sharp_globals.h b/sharpd/sharp_globals.h index b050ba85ca..46096f4aa7 100644 --- a/sharpd/sharp_globals.h +++ b/sharpd/sharp_globals.h @@ -22,6 +22,8 @@ #ifndef __SHARP_GLOBAL_H__ #define __SHARP_GLOBAL_H__ +#include "lib/srv6.h" + DECLARE_MGROUP(SHARPD); struct sharp_routes { @@ -52,6 +54,14 @@ struct sharp_routes { char opaque[ZAPI_MESSAGE_OPAQUE_LENGTH]; }; +struct sharp_srv6_locator { + /* name of locator */ + char name[SRV6_LOCNAME_SIZE]; + + /* list of struct prefix_ipv6 */ + struct list *chunks; +}; + struct sharp_global { /* Global data about route install/deletions */ struct sharp_routes r; @@ -61,6 +71,9 @@ struct sharp_global { /* Traffic Engineering Database */ struct ls_ted *ted; + + /* list of sharp_srv6_locator */ + struct list *srv6_locators; }; extern struct sharp_global sg; diff --git a/sharpd/sharp_main.c b/sharpd/sharp_main.c index e93db34ffa..75cf145385 100644 --- a/sharpd/sharp_main.c +++ b/sharpd/sharp_main.c @@ -140,6 +140,7 @@ static void sharp_global_init(void) memset(&sg, 0, sizeof(sg)); sg.nhs = list_new(); sg.ted = NULL; + sg.srv6_locators = list_new(); } static void sharp_start_configuration(void) diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index 253d1943b3..c580338f33 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -39,6 +39,8 @@ #include "sharpd/sharp_vty_clippy.c" #endif +DEFINE_MTYPE_STATIC(SHARPD, SRV6_LOCATOR, "SRv6 Locator"); + DEFPY(watch_redistribute, watch_redistribute_cmd, "sharp watch [vrf NAME$vrf_name] redistribute " FRR_REDIST_STR_SHARPD, "Sharp routing Protocol\n" @@ -784,6 +786,40 @@ DEFPY (import_te, return CMD_SUCCESS; } +DEFPY (sharp_srv6_manager_get_locator_chunk, + sharp_srv6_manager_get_locator_chunk_cmd, + "sharp srv6-manager get-locator-chunk NAME$locator_name", + SHARP_STR + "Segment-Routing IPv6\n" + "Get SRv6 locator-chunk\n" + "SRv6 Locator name\n") +{ + int ret; + struct listnode *node; + struct sharp_srv6_locator *loc; + struct sharp_srv6_locator *loc_found = NULL; + + for (ALL_LIST_ELEMENTS_RO(sg.srv6_locators, node, loc)) { + if (strcmp(loc->name, locator_name)) + continue; + loc_found = loc; + break; + } + if (!loc_found) { + loc = XCALLOC(MTYPE_SRV6_LOCATOR, + sizeof(struct sharp_srv6_locator)); + loc->chunks = list_new(); + snprintf(loc->name, SRV6_LOCNAME_SIZE, "%s", locator_name); + listnode_add(sg.srv6_locators, loc); + } + + ret = sharp_zebra_srv6_manager_get_locator_chunk(locator_name); + if (ret < 0) + return CMD_WARNING_CONFIG_FAILED; + + return CMD_SUCCESS; +} + DEFUN (show_sharp_ted, show_sharp_ted_cmd, "show sharp ted [] [verbose|json]", @@ -905,6 +941,71 @@ DEFUN (show_sharp_ted, json, JSON_C_TO_STRING_PRETTY)); json_object_free(json); } + + return CMD_SUCCESS; +} + +DEFPY (sharp_srv6_manager_release_locator_chunk, + sharp_srv6_manager_release_locator_chunk_cmd, + "sharp srv6-manager release-locator-chunk NAME$locator_name", + SHARP_STR + "Segment-Routing IPv6\n" + "Release SRv6 locator-chunk\n" + "SRv6 Locator name\n") +{ + int ret; + struct listnode *loc_node; + struct sharp_srv6_locator *loc; + + for (ALL_LIST_ELEMENTS_RO(sg.srv6_locators, loc_node, loc)) { + if (!strcmp(loc->name, locator_name)) { + list_delete_all_node(loc->chunks); + list_delete(&loc->chunks); + listnode_delete(sg.srv6_locators, loc); + break; + } + } + + ret = sharp_zebra_srv6_manager_release_locator_chunk(locator_name); + if (ret < 0) + return CMD_WARNING_CONFIG_FAILED; + + return CMD_SUCCESS; +} + +DEFPY (show_sharp_segment_routing_srv6, + show_sharp_segment_routing_srv6_cmd, + "show sharp segment-routing srv6", + SHOW_STR + SHARP_STR + "Segment-Routing\n" + "Segment-Routing IPv6\n") +{ + char str[256]; + struct listnode *loc_node; + struct listnode *chunk_node; + struct sharp_srv6_locator *loc; + struct prefix_ipv6 *chunk; + json_object *jo_locs = NULL; + json_object *jo_loc = NULL; + json_object *jo_chunks = NULL; + + jo_locs = json_object_new_array(); + for (ALL_LIST_ELEMENTS_RO(sg.srv6_locators, loc_node, loc)) { + jo_loc = json_object_new_object(); + json_object_array_add(jo_locs, jo_loc); + json_object_string_add(jo_loc, "name", loc->name); + jo_chunks = json_object_new_array(); + json_object_object_add(jo_loc, "chunks", jo_chunks); + for (ALL_LIST_ELEMENTS_RO(loc->chunks, chunk_node, chunk)) { + prefix2str(chunk, str, sizeof(str)); + json_array_string_add(jo_chunks, str); + } + } + + vty_out(vty, "%s\n", json_object_to_json_string_ext( + jo_locs, JSON_C_TO_STRING_PRETTY)); + json_object_free(jo_locs); return CMD_SUCCESS; } @@ -932,5 +1033,9 @@ void sharp_vty_init(void) install_element(ENABLE_NODE, &show_debugging_sharpd_cmd); install_element(ENABLE_NODE, &show_sharp_ted_cmd); + install_element(ENABLE_NODE, &sharp_srv6_manager_get_locator_chunk_cmd); + install_element(ENABLE_NODE, &sharp_srv6_manager_release_locator_chunk_cmd); + install_element(ENABLE_NODE, &show_sharp_segment_routing_srv6_cmd); + return; } diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c index da056160bf..7c24ae380f 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -924,6 +924,68 @@ static int nhg_notify_owner(ZAPI_CALLBACK_ARGS) return 0; } +int sharp_zebra_srv6_manager_get_locator_chunk(const char* locator_name) +{ + return srv6_manager_get_locator_chunk(zclient, locator_name); +} + +int sharp_zebra_srv6_manager_release_locator_chunk(const char *locator_name) +{ + return srv6_manager_release_locator_chunk(zclient, locator_name); +} + +static void sharp_zebra_process_srv6_locator_chunk(ZAPI_CALLBACK_ARGS) +{ + struct stream *s = NULL; + uint8_t proto; + uint16_t instance; + uint16_t len; + char name[256] = {0}; + struct prefix_ipv6 *chunk = NULL; + chunk = prefix_ipv6_new(); + + s = zclient->ibuf; + STREAM_GETC(s, proto); + STREAM_GETW(s, instance); + + STREAM_GETW(s, len); + STREAM_GET(name, s, len); + + STREAM_GETW(s, chunk->prefixlen); + STREAM_GET(&chunk->prefix, s, 16); + + if (zclient->redist_default != proto) { + zlog_err("Got SRv6 Manager msg with wrong proto %u", proto); + return; + } + if (zclient->instance != instance) { + zlog_err("Got SRv6 Manager msg with wrong instance %u", proto); + return; + } + + struct listnode *loc_node; + struct sharp_srv6_locator *loc; + for (ALL_LIST_ELEMENTS_RO(sg.srv6_locators, loc_node, loc)) { + if (strcmp(loc->name, name)) + continue; + + struct listnode *chunk_node; + struct prefix_ipv6 *c; + for (ALL_LIST_ELEMENTS_RO(loc->chunks, chunk_node, c)) { + if (!prefix_cmp(c, chunk)) + return; + } + listnode_add(loc->chunks, chunk); + } + return; + +stream_failure: + free(chunk); + + zlog_err("%s: can't get locator_chunk!!", __func__); + return; +} + void sharp_zebra_init(void) { struct zclient_options opt = {.receive_notify = true}; @@ -945,4 +1007,5 @@ void sharp_zebra_init(void) zclient->redistribute_route_add = sharp_redistribute_route; zclient->redistribute_route_del = sharp_redistribute_route; zclient->opaque_msg_handler = sharp_opaque_handler; + zclient->process_srv6_locator_chunk = sharp_zebra_process_srv6_locator_chunk; } diff --git a/sharpd/sharp_zebra.h b/sharpd/sharp_zebra.h index 495ce6ec58..043a7405c2 100644 --- a/sharpd/sharp_zebra.h +++ b/sharpd/sharp_zebra.h @@ -65,4 +65,11 @@ extern void sharp_zebra_register_te(void); extern void sharp_redistribute_vrf(struct vrf *vrf, int source); +extern int sharp_zebra_srv6_manager_get_locator_chunk(const char* locator_name); +extern int sharp_zebra_srv6_manager_release_locator_chunk(const char *locator_name); +extern void sharp_install_seg6local_route_helper(struct prefix *p, + uint8_t instance, + enum seg6local_action_t act, + struct seg6local_context *ctx); + #endif From 96d423f7c92eb45c1a9a5c5e7d1736e1b75f1159 Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Sun, 23 Feb 2020 05:37:24 +0000 Subject: [PATCH 13/66] topotests: keep srv6-locator feature fine (step2) This commit is a part of #5853 works. This commit add new topotest to verify SRv6-manager's functionality. Following tests are performed on this topotest. - check that SRv6-locator is set correctly - check that default SRv6-function locator is set correctly - check that SRv6-function is installed as ipv6 route correctly Signed-off-by: Hiroki Shirokura --- tests/topotests/srv6_locator/__init__.py | 0 .../srv6_locator/expected_chunks1.json | 1 + .../srv6_locator/expected_chunks2.json | 8 + .../srv6_locator/expected_chunks3.json | 1 + .../srv6_locator/expected_chunks4.json | 6 + .../srv6_locator/expected_chunks5.json | 8 + .../srv6_locator/expected_ipv6_routes.json | 29 ++++ .../srv6_locator/expected_locators1.json | 26 ++++ .../srv6_locator/expected_locators2.json | 26 ++++ .../srv6_locator/expected_locators3.json | 26 ++++ .../srv6_locator/expected_locators4.json | 36 +++++ .../srv6_locator/expected_locators5.json | 38 +++++ tests/topotests/srv6_locator/r1/setup.sh | 2 + tests/topotests/srv6_locator/r1/sharpd.conf | 7 + tests/topotests/srv6_locator/r1/zebra.conf | 22 +++ .../srv6_locator/test_srv6_locator.py | 142 ++++++++++++++++++ 16 files changed, 378 insertions(+) create mode 100644 tests/topotests/srv6_locator/__init__.py create mode 100644 tests/topotests/srv6_locator/expected_chunks1.json create mode 100644 tests/topotests/srv6_locator/expected_chunks2.json create mode 100644 tests/topotests/srv6_locator/expected_chunks3.json create mode 100644 tests/topotests/srv6_locator/expected_chunks4.json create mode 100644 tests/topotests/srv6_locator/expected_chunks5.json create mode 100644 tests/topotests/srv6_locator/expected_ipv6_routes.json create mode 100644 tests/topotests/srv6_locator/expected_locators1.json create mode 100644 tests/topotests/srv6_locator/expected_locators2.json create mode 100644 tests/topotests/srv6_locator/expected_locators3.json create mode 100644 tests/topotests/srv6_locator/expected_locators4.json create mode 100644 tests/topotests/srv6_locator/expected_locators5.json create mode 100644 tests/topotests/srv6_locator/r1/setup.sh create mode 100644 tests/topotests/srv6_locator/r1/sharpd.conf create mode 100644 tests/topotests/srv6_locator/r1/zebra.conf create mode 100755 tests/topotests/srv6_locator/test_srv6_locator.py diff --git a/tests/topotests/srv6_locator/__init__.py b/tests/topotests/srv6_locator/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/topotests/srv6_locator/expected_chunks1.json b/tests/topotests/srv6_locator/expected_chunks1.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/tests/topotests/srv6_locator/expected_chunks1.json @@ -0,0 +1 @@ +[] diff --git a/tests/topotests/srv6_locator/expected_chunks2.json b/tests/topotests/srv6_locator/expected_chunks2.json new file mode 100644 index 0000000000..8707384777 --- /dev/null +++ b/tests/topotests/srv6_locator/expected_chunks2.json @@ -0,0 +1,8 @@ +[ + { + "name": "loc1", + "chunks": [ + "2001:db8:1:1::/64" + ] + } +] diff --git a/tests/topotests/srv6_locator/expected_chunks3.json b/tests/topotests/srv6_locator/expected_chunks3.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/tests/topotests/srv6_locator/expected_chunks3.json @@ -0,0 +1 @@ +[] diff --git a/tests/topotests/srv6_locator/expected_chunks4.json b/tests/topotests/srv6_locator/expected_chunks4.json new file mode 100644 index 0000000000..6e49738f37 --- /dev/null +++ b/tests/topotests/srv6_locator/expected_chunks4.json @@ -0,0 +1,6 @@ +[ + { + "name": "loc3", + "chunks": [] + } +] diff --git a/tests/topotests/srv6_locator/expected_chunks5.json b/tests/topotests/srv6_locator/expected_chunks5.json new file mode 100644 index 0000000000..a18221859e --- /dev/null +++ b/tests/topotests/srv6_locator/expected_chunks5.json @@ -0,0 +1,8 @@ +[ + { + "name": "loc3", + "chunks": [ + "2001:db8:3:3::/64" + ] + } +] diff --git a/tests/topotests/srv6_locator/expected_ipv6_routes.json b/tests/topotests/srv6_locator/expected_ipv6_routes.json new file mode 100644 index 0000000000..fb92f25b73 --- /dev/null +++ b/tests/topotests/srv6_locator/expected_ipv6_routes.json @@ -0,0 +1,29 @@ +{ + "2001:db8:1:1:1::/80":[ + { + "prefix":"2001:db8:1:1:1::/80", + "protocol":"static", + "selected":true, + "installed":true, + "nexthops":[{ + "fib":true, + "active":true, + "seg6local":{ "action":"End" } + }] + } + ], + "2001:db8:2:2:1::/80":[ + { + "prefix":"2001:db8:2:2:1::/80", + "protocol":"static", + "selected":true, + "installed":true, + "nexthops":[{ + "fib":true, + "active":true, + "seg6local":{ "action":"End" } + + }] + } + ] +} diff --git a/tests/topotests/srv6_locator/expected_locators1.json b/tests/topotests/srv6_locator/expected_locators1.json new file mode 100644 index 0000000000..39f35fadd4 --- /dev/null +++ b/tests/topotests/srv6_locator/expected_locators1.json @@ -0,0 +1,26 @@ +{ + "locators":[ + { + "name": "loc1", + "prefix": "2001:db8:1:1::/64", + "status_up": true, + "chunks": [ + { + "prefix": "2001:db8:1:1::/64", + "proto": "system" + } + ] + }, + { + "name": "loc2", + "prefix": "2001:db8:2:2::/64", + "status_up": true, + "chunks": [ + { + "prefix": "2001:db8:2:2::/64", + "proto": "system" + } + ] + } + ] +} diff --git a/tests/topotests/srv6_locator/expected_locators2.json b/tests/topotests/srv6_locator/expected_locators2.json new file mode 100644 index 0000000000..03ccb87ffe --- /dev/null +++ b/tests/topotests/srv6_locator/expected_locators2.json @@ -0,0 +1,26 @@ +{ + "locators":[ + { + "name": "loc1", + "prefix": "2001:db8:1:1::/64", + "status_up": true, + "chunks": [ + { + "prefix": "2001:db8:1:1::/64", + "proto": "sharp" + } + ] + }, + { + "name": "loc2", + "prefix": "2001:db8:2:2::/64", + "status_up": true, + "chunks": [ + { + "prefix": "2001:db8:2:2::/64", + "proto": "system" + } + ] + } + ] +} diff --git a/tests/topotests/srv6_locator/expected_locators3.json b/tests/topotests/srv6_locator/expected_locators3.json new file mode 100644 index 0000000000..39f35fadd4 --- /dev/null +++ b/tests/topotests/srv6_locator/expected_locators3.json @@ -0,0 +1,26 @@ +{ + "locators":[ + { + "name": "loc1", + "prefix": "2001:db8:1:1::/64", + "status_up": true, + "chunks": [ + { + "prefix": "2001:db8:1:1::/64", + "proto": "system" + } + ] + }, + { + "name": "loc2", + "prefix": "2001:db8:2:2::/64", + "status_up": true, + "chunks": [ + { + "prefix": "2001:db8:2:2::/64", + "proto": "system" + } + ] + } + ] +} diff --git a/tests/topotests/srv6_locator/expected_locators4.json b/tests/topotests/srv6_locator/expected_locators4.json new file mode 100644 index 0000000000..4def3c000c --- /dev/null +++ b/tests/topotests/srv6_locator/expected_locators4.json @@ -0,0 +1,36 @@ +{ + "locators":[ + { + "name": "loc1", + "prefix": "2001:db8:1:1::/64", + "status_up": true, + "chunks": [ + { + "prefix": "2001:db8:1:1::/64", + "proto": "system" + } + ] + }, + { + "name": "loc2", + "prefix": "2001:db8:2:2::/64", + "status_up": true, + "chunks": [ + { + "prefix": "2001:db8:2:2::/64", + "proto": "system" + } + ] + }, + { + "name":"loc3", + "status_up":false, + "chunks":[ + { + "proto":"sharp" + } + ] + } + ] +} + diff --git a/tests/topotests/srv6_locator/expected_locators5.json b/tests/topotests/srv6_locator/expected_locators5.json new file mode 100644 index 0000000000..526cd2f154 --- /dev/null +++ b/tests/topotests/srv6_locator/expected_locators5.json @@ -0,0 +1,38 @@ +{ + "locators":[ + { + "name": "loc1", + "prefix": "2001:db8:1:1::/64", + "status_up": true, + "chunks": [ + { + "prefix": "2001:db8:1:1::/64", + "proto": "system" + } + ] + }, + { + "name": "loc2", + "prefix": "2001:db8:2:2::/64", + "status_up": true, + "chunks": [ + { + "prefix": "2001:db8:2:2::/64", + "proto": "system" + } + ] + }, + { + "name": "loc3", + "prefix": "2001:db8:3:3::/64", + "status_up": true, + "chunks":[ + { + "prefix": "2001:db8:3:3::/64", + "proto": "sharp" + } + ] + } + ] +} + diff --git a/tests/topotests/srv6_locator/r1/setup.sh b/tests/topotests/srv6_locator/r1/setup.sh new file mode 100644 index 0000000000..36ed713f24 --- /dev/null +++ b/tests/topotests/srv6_locator/r1/setup.sh @@ -0,0 +1,2 @@ +ip link add dummy0 type dummy +ip link set dummy0 up diff --git a/tests/topotests/srv6_locator/r1/sharpd.conf b/tests/topotests/srv6_locator/r1/sharpd.conf new file mode 100644 index 0000000000..d46085935c --- /dev/null +++ b/tests/topotests/srv6_locator/r1/sharpd.conf @@ -0,0 +1,7 @@ +hostname r1 +! +log stdout notifications +log monitor notifications +log commands +log file sharpd.log debugging +! diff --git a/tests/topotests/srv6_locator/r1/zebra.conf b/tests/topotests/srv6_locator/r1/zebra.conf new file mode 100644 index 0000000000..d0c0232073 --- /dev/null +++ b/tests/topotests/srv6_locator/r1/zebra.conf @@ -0,0 +1,22 @@ +hostname r1 +! +debug zebra events +debug zebra rib detailed +! +log stdout notifications +log monitor notifications +log commands +log file zebra.log debugging +! +segment-routing + srv6 + locators + locator loc1 + prefix 2001:db8:1:1::/64 + ! + locator loc2 + prefix 2001:db8:2:2::/64 + ! + ! + ! +! diff --git a/tests/topotests/srv6_locator/test_srv6_locator.py b/tests/topotests/srv6_locator/test_srv6_locator.py new file mode 100755 index 0000000000..91850b5045 --- /dev/null +++ b/tests/topotests/srv6_locator/test_srv6_locator.py @@ -0,0 +1,142 @@ +#!/usr/bin/env python + +# +# test_srv6_manager.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2020 by +# LINE Corporation, Hiroki Shirokura +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +test_srv6_manager.py: +Test for SRv6 manager on zebra +""" + +import os +import sys +import json +import time +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, '../')) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger +from mininet.topo import Topo + + +def open_json_file(filename): + try: + with open(filename, "r") as f: + return json.load(f) + except IOError: + assert False, "Could not read file {}".format(filename) + + +class TemplateTopo(Topo): + def build(self, *_args, **_opts): + tgen = get_topogen(self) + tgen.add_router('r1') + + +def setup_module(mod): + tgen = Topogen(TemplateTopo, mod.__name__) + tgen.start_topology() + router_list = tgen.routers() + for rname, router in tgen.routers().items(): + router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname)) + router.load_config(TopoRouter.RD_ZEBRA, os.path.join(CWD, '{}/zebra.conf'.format(rname))) + router.load_config(TopoRouter.RD_BGP, os.path.join(CWD, '{}/bgpd.conf'.format(rname))) + router.load_config(TopoRouter.RD_SHARP, os.path.join(CWD, '{}/sharpd.conf'.format(rname))) + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_srv6(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + router = tgen.gears['r1'] + + def _check_srv6_locator(router, expected_locator_file): + logger.info("checking zebra locator status") + output = json.loads(router.vtysh_cmd("show segment-routing srv6 locator json")) + expected = open_json_file("{}/{}".format(CWD, expected_locator_file)) + return topotest.json_cmp(output, expected) + + def _check_sharpd_chunk(router, expected_chunk_file): + logger.info("checking sharpd locator chunk status") + output = json.loads(router.vtysh_cmd("show sharp segment-routing srv6")) + expected = open_json_file("{}/{}".format(CWD, expected_chunk_file)) + return topotest.json_cmp(output, expected) + + def check_srv6_locator(router, expected_file): + func = functools.partial(_check_srv6_locator, router, expected_file) + success, result = topotest.run_and_expect(func, None, count=5, wait=0.5) + assert result is None, 'Failed' + + def check_sharpd_chunk(router, expected_file): + func = functools.partial(_check_sharpd_chunk, router, expected_file) + success, result = topotest.run_and_expect(func, None, count=5, wait=0.5) + assert result is None, 'Failed' + + logger.info("Test1 for Locator Configuration") + check_srv6_locator(router, "expected_locators1.json") + check_sharpd_chunk(router, "expected_chunks1.json") + + logger.info("Test2 get chunk for locator loc1") + router.vtysh_cmd("sharp srv6-manager get-locator-chunk loc1") + check_srv6_locator(router, "expected_locators2.json") + check_sharpd_chunk(router, "expected_chunks2.json") + + logger.info("Test3 release chunk for locator loc1") + router.vtysh_cmd("sharp srv6-manager release-locator-chunk loc1") + check_srv6_locator(router, "expected_locators3.json") + check_sharpd_chunk(router, "expected_chunks3.json") + + logger.info("Test4 get chunk for non-exist locator by zclient") + 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( + """ + configure terminal + segment-routing + srv6 + locators + locator loc3 + prefix 2001:db8:3:3::/64 + """ + ) + check_srv6_locator(router, "expected_locators5.json") + check_sharpd_chunk(router, "expected_chunks5.json") + + +if __name__ == '__main__': + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) From 4c6f9934e4d0cb824e0383e9435bd957ea54bcb0 Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Sun, 23 Feb 2020 16:58:09 +0000 Subject: [PATCH 14/66] doc: add new section for srv6 configuration (step2) Signed-off-by: Hiroki Shirokura --- doc/user/zebra.rst | 98 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index 1539f9a9d1..02999a7006 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -620,6 +620,104 @@ presence of the entry. 21 Static 10.125.0.2 IPv4 Explicit Null +.. _zebra-srv6: + +Segment-Routing SRv6 +==================== + +Segment-Routing is source routing paradigm that allows +network operator to encode network intent into the packets. +SRv6 is an implementation of Segment-Routing +with application of IPv6 and segment-routing-header. + +All routing daemon can use the Segment-Routing base +framework implemented on zebra to use SRv6 routing mechanism. +In that case, user must configure initial srv6 setting on +FRR's cli or frr.conf or zebra.conf. This section shows how +to configure SRv6 on FRR. Of course SRv6 can be used as standalone, +and this section also helps that case. + +.. index:: show segment-routing srv6 locator [json] +.. clicmd:: show segment-routing srv6 locator [json] + + This command dump SRv6-locator configured on zebra. + SRv6-locator is used to route to the node before performing + the SRv6-function. and that works as aggregation of + SRv6-function's IDs. + Following console log shows two SRv6-locators LOC1 and LOC2. + All locators are identified by unique IPv6 prefix. + User can get that information as JSON string when ``json`` + key word at the end of cli is presented. + +:: + + router# sh segment-routing srv6 locator + Locator: + Name ID Prefix Status + -------------------- ------- ------------------------ ------- + hoge 1 1::/64 Up + fuga 2 2::/64 Up + +.. index:: segment-routing +.. clicmd:: segment-routing +.. index:: srv6 +.. clicmd:: srv6 +.. index:: locators +.. clicmd:: locators + + User can enter the SRv6 configuration node with ``segment-routing`` and + ``srv6`` commands in configure mode. If there is some SRv6-locator exist, + SRv6 feature is looked enabled and this affects running-config. + + User can enter the Locators node with ``locators`` command. + in srv6 configure mode. + After entering locators node, user can configure one or multi SRv6-locators. + +.. index:: locator NAME +.. clicmd:: locator NAME +.. index:: prefix X:X::X:X/M [function-bits-length 32] +.. clicmd:: prefix X:X::X:X/M [function-bits-length 32] + + Following example console log shows the typical configuration of + SRv6 data-plane. After a new SRv6 locator, named LOC1, is created, + LOC1's prefix is configured as ``2001:db8:a:a::/64``. + + If user or some routing daemon allocates new SID on this locator, + new SID will allocated in range of this prefix. + + For example, if some routing daemon creates new SID on locator + (``2001:db8:a:a::/64``), Then new SID will be + ``2001:db8:a:a:7::/80``, ``2001:db8:a:a:8::/80``, and so on. + + Each locator has default SID that is SRv6 local function "End". + Usually default SID is allocated as ``PREFIX:1::``. + (``PREFIX`` is locator's prefix) + For example, if user configure the locator's prefix as + `2001:db8:a:a::/64`, then default SID will be `2001:db8:a:a:1::`) + + The function bits range is 16bits by default. + If operator want to change function bits range, they can configure + with ``function-bits-length`` option. + +:: + + router# configure terminal + router(config)# segment-routinig + router(config-sr)# srv6 + router(config-srv6)# locators + router(config-srv6-locs)# locator LOC1 + router(config-srv6-loc)# prefix 2001:db8:a:a::/64 + + router(config-srv6-loc)# show run + ... + segment-routing + srv6 + locators + locator LOC1 + prefix 2001:db8:a:a::/64 + ! + ... + .. _multicast-rib-commands: Multicast RIB Commands From 2aa01034f3c437e076cf12f1ea4e4b7b5b6b9075 Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Thu, 17 Dec 2020 22:45:58 +0900 Subject: [PATCH 15/66] lib: add new nexthop's attributes seg6 (step3) This commit add new nexthop's addional object for SRv6 routing about seg6 route. Before this commit, we can add MPLS info as additional object on nexthop. This commit make it add more support about seg6 routes. seg6 routes are ones of the LWT routing mechanism, so configuration of seg6local routes is performed by ZEBRA_ROUTE_SEND, it's same as MPLS configuration. Real configuration implementation isn't implemented at this commit. later commit add that. This commit add only nexthop additional object and some misc functions. Signed-off-by: Hiroki Shirokura --- lib/nexthop.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ lib/nexthop.h | 5 +++++ lib/zclient.c | 27 +++++++++++++++++++++++++++ lib/zclient.h | 3 +++ 4 files changed, 79 insertions(+) diff --git a/lib/nexthop.c b/lib/nexthop.c index 3c36dbf69a..d0cc5dc258 100644 --- a/lib/nexthop.c +++ b/lib/nexthop.c @@ -37,6 +37,7 @@ DEFINE_MTYPE_STATIC(LIB, NEXTHOP, "Nexthop"); DEFINE_MTYPE_STATIC(LIB, NH_LABEL, "Nexthop label"); DEFINE_MTYPE_STATIC(LIB, NH_SEG6LOCAL, "Nexthop seg6local"); +DEFINE_MTYPE_STATIC(LIB, NH_SEG6, "Nexthop seg6"); static int _nexthop_labels_cmp(const struct nexthop *nh1, const struct nexthop *nh2) @@ -89,6 +90,22 @@ static int _nexthop_seg6local_cmp(const struct nexthop *nh1, sizeof(struct seg6local_context)); } +static int _nexthop_seg6_cmp(const struct nexthop *nh1, + const struct nexthop *nh2) +{ + if (!nh1->nh_seg6_segs && !nh2->nh_seg6_segs) + return 0; + + if (nh1->nh_seg6_segs && !nh2->nh_seg6_segs) + return 1; + + if (!nh1->nh_seg6_segs && nh2->nh_seg6_segs) + return -1; + + return memcmp(nh1->nh_seg6_segs, nh2->nh_seg6_segs, + sizeof(struct in6_addr)); +} + int nexthop_g_addr_cmp(enum nexthop_types_t type, const union g_addr *addr1, const union g_addr *addr2) { @@ -226,6 +243,10 @@ int nexthop_cmp(const struct nexthop *next1, const struct nexthop *next2) return ret; ret = _nexthop_seg6local_cmp(next1, next2); + if (ret != 0) + return ret; + + ret = _nexthop_seg6_cmp(next1, next2); return ret; } @@ -381,6 +402,7 @@ void nexthop_free(struct nexthop *nexthop) { nexthop_del_labels(nexthop); nexthop_del_seg6local(nexthop); + nexthop_del_seg6(nexthop); if (nexthop->resolved) nexthops_free(nexthop->resolved); XFREE(MTYPE_NEXTHOP, nexthop); @@ -572,6 +594,21 @@ void nexthop_del_seg6local(struct nexthop *nexthop) nexthop->nh_seg6local_action = ZEBRA_SEG6_LOCAL_ACTION_UNSPEC; } +void nexthop_add_seg6(struct nexthop *nexthop, const struct in6_addr *segs) +{ + struct in6_addr *nh_segs; + + nh_segs = XCALLOC(MTYPE_NH_SEG6, sizeof(struct in6_addr)); + if (segs) + *nh_segs = *segs; + nexthop->nh_seg6_segs = nh_segs; +} + +void nexthop_del_seg6(struct nexthop *nexthop) +{ + XFREE(MTYPE_NH_SEG6, nexthop->nh_seg6_segs); +} + const char *nexthop2str(const struct nexthop *nexthop, char *str, int size) { switch (nexthop->type) { @@ -723,6 +760,10 @@ uint32_t nexthop_hash_quick(const struct nexthop *nexthop) sizeof(nexthop->nh_seg6local_ctx), key); } + if (nexthop->nh_seg6_segs) + key = jhash(nexthop->nh_seg6_segs, + sizeof(nexthop->nh_seg6_segs), key); + return key; } @@ -779,6 +820,9 @@ void nexthop_copy_no_recurse(struct nexthop *copy, if (nexthop->nh_seg6local_ctx) nexthop_add_seg6local(copy, nexthop->nh_seg6local_action, nexthop->nh_seg6local_ctx); + + if (nexthop->nh_seg6_segs) + nexthop_add_seg6(copy, nexthop->nh_seg6_segs); } void nexthop_copy(struct nexthop *copy, const struct nexthop *nexthop, diff --git a/lib/nexthop.h b/lib/nexthop.h index 7bddee8713..8c52631af1 100644 --- a/lib/nexthop.h +++ b/lib/nexthop.h @@ -144,6 +144,9 @@ struct nexthop { /* SRv6 localsid info for Endpoint-behaviour */ enum seg6local_action_t nh_seg6local_action; struct seg6local_context *nh_seg6local_ctx; + + /* SRv6 Headend-behaviour */ + struct in6_addr *nh_seg6_segs; }; /* Utility to append one nexthop to another. */ @@ -165,6 +168,8 @@ void nexthop_del_labels(struct nexthop *); void nexthop_add_seg6local(struct nexthop *nexthop, uint32_t action, const struct seg6local_context *ctx); void nexthop_del_seg6local(struct nexthop *nexthop); +void nexthop_add_seg6(struct nexthop *nexthop, const struct in6_addr* segs); +void nexthop_del_seg6(struct nexthop *nexthop); /* * Allocate a new nexthop object and initialize it from various args. diff --git a/lib/zclient.c b/lib/zclient.c index c8bb720591..8520fd769d 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -810,6 +810,13 @@ static int zapi_nexthop_seg6local_cmp(const struct zapi_nexthop *next1, sizeof(struct seg6local_context)); } +static int zapi_nexthop_seg6_cmp(const struct zapi_nexthop *next1, + const struct zapi_nexthop *next2) +{ + return memcmp(&next1->seg6_segs, &next2->seg6_segs, + sizeof(struct in6_addr)); +} + static int zapi_nexthop_cmp_no_labels(const struct zapi_nexthop *next1, const struct zapi_nexthop *next2) { @@ -914,6 +921,10 @@ static int zapi_nexthop_cmp(const void *item1, const void *item2) return ret; ret = zapi_nexthop_seg6local_cmp(next1, next2); + if (ret != 0) + return ret; + + ret = zapi_nexthop_seg6_cmp(next1, next2); return ret; } @@ -1016,6 +1027,10 @@ int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh, sizeof(struct seg6local_context)); } + if (CHECK_FLAG(api_flags, ZEBRA_FLAG_SEG6_ROUTE)) + stream_write(s, &api_nh->seg6_segs, + sizeof(struct in6_addr)); + done: return ret; } @@ -1303,6 +1318,10 @@ int zapi_nexthop_decode(struct stream *s, struct zapi_nexthop *api_nh, sizeof(struct seg6local_context)); } + if (CHECK_FLAG(api_flags, ZEBRA_FLAG_SEG6_ROUTE)) + STREAM_GET(&api_nh->seg6_segs, s, + sizeof(struct in6_addr)); + /* Success */ ret = 0; @@ -1645,6 +1664,7 @@ stream_failure: struct nexthop *nexthop_from_zapi_nexthop(const struct zapi_nexthop *znh) { + uint8_t zero[16] = {0}; struct nexthop *n = nexthop_new(); n->type = znh->type; @@ -1671,6 +1691,9 @@ struct nexthop *nexthop_from_zapi_nexthop(const struct zapi_nexthop *znh) nexthop_add_seg6local(n, znh->seg6local_action, &znh->seg6local_ctx); + if (memcmp(&znh->seg6_segs, zero, sizeof(struct in6_addr)) != 0) + nexthop_add_seg6(n, &znh->seg6_segs); + return n; } @@ -1721,6 +1744,10 @@ int zapi_nexthop_from_nexthop(struct zapi_nexthop *znh, sizeof(struct seg6local_context)); } + if (nh->nh_seg6_segs != NULL) + memcpy(&znh->seg6_segs, nh->nh_seg6_segs, + sizeof(struct in6_addr)); + return 0; } diff --git a/lib/zclient.h b/lib/zclient.h index 6496e79c89..95f3775d5b 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -474,6 +474,9 @@ struct zapi_nexthop { /* SRv6 localsid info for Endpoint-behaviour */ uint32_t seg6local_action; struct seg6local_context seg6local_ctx; + + /* SRv6 Headend-behaviour */ + struct in6_addr seg6_segs; }; /* From 76fb7ae4dea7604afe1185df91de941d9e3ce58f Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Thu, 17 Dec 2020 23:43:01 +0900 Subject: [PATCH 16/66] zebra: ZEBRA_ROUTE_ADD supports seg6 route (step3) With this patch, zclient can intall seg6 rotues when they set properties "nh_seg6_segs" on struct nexthop and set ZEBRA_FLAG_SEG6_ROUTE on zapi_route's flag. Signed-off-by: Hiroki Shirokura --- zebra/rt_netlink.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++ zebra/zapi_msg.c | 8 +++++++ zebra/zebra_nhg.c | 2 ++ zebra/zebra_vty.c | 13 ++++++++++++ 4 files changed, 75 insertions(+) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 2ddda7449c..00eb0b6644 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1286,6 +1286,26 @@ static bool _netlink_route_encode_nexthop_src(const struct nexthop *nexthop, return true; } +static size_t fill_seg6ipt_encap(char *buffer, size_t buflen, + struct in6_addr *seg) +{ + struct seg6_iptunnel_encap *ipt; + struct ipv6_sr_hdr *srh; + const size_t srhlen = 24; + memset(buffer, 0, buflen); + + ipt = (struct seg6_iptunnel_encap *)buffer; + ipt->mode = SEG6_IPTUN_MODE_ENCAP; + srh = ipt->srh; + srh->hdrlen = (srhlen >> 3) - 1; + srh->type = 4; + srh->segments_left = 0; + srh->first_segment = 0; + memcpy(&srh->segments[0], seg, sizeof(struct in6_addr)); + + return srhlen + 4; +} + /* This function takes a nexthop as argument and adds * the appropriate netlink attributes to an existing * netlink message. @@ -1367,6 +1387,21 @@ static bool _netlink_route_build_singlepath(const struct prefix *p, nl_attr_nest_end(nlmsg, nest); } + if (nexthop->nh_seg6_segs) { + char tun_buf[4096]; + size_t tun_len; + struct rtattr *nest; + + nl_attr_put16(nlmsg, req_size, RTA_ENCAP_TYPE, + LWTUNNEL_ENCAP_SEG6); + nest = nl_attr_nest(nlmsg, req_size, RTA_ENCAP); + tun_len = fill_seg6ipt_encap(tun_buf, sizeof(tun_buf), + nexthop->nh_seg6_segs); + nl_attr_put(nlmsg, req_size, SEG6_IPTUNNEL_SRH, + tun_buf, tun_len); + nl_attr_nest_end(nlmsg, nest); + } + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) rtmsg->rtm_flags |= RTNH_F_ONLINK; @@ -2422,6 +2457,23 @@ ssize_t netlink_nexthop_msg_encode(uint16_t cmd, nl_attr_nest_end(&req->n, nest); } + if (nh->nh_seg6_segs) { + char tun_buf[4096]; + size_t tun_len; + struct rtattr *nest; + + nl_attr_put16(&req->n, buflen, NHA_ENCAP_TYPE, + LWTUNNEL_ENCAP_SEG6); + nest = nl_attr_nest(&req->n, buflen, + NHA_ENCAP | NLA_F_NESTED); + tun_len = fill_seg6ipt_encap(tun_buf, + sizeof(tun_buf), + nh->nh_seg6_segs); + nl_attr_put(&req->n, buflen, SEG6_IPTUNNEL_SRH, + tun_buf, tun_len); + nl_attr_nest_end(&req->n, nest); + } + nexthop_done: if (IS_ZEBRA_DEBUG_KERNEL) diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index fa6a4cfca7..25c51e2227 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -1783,6 +1783,14 @@ static bool zapi_read_nexthops(struct zserv *client, struct prefix *p, &api_nh->seg6local_ctx); } + if (CHECK_FLAG(flags, ZEBRA_FLAG_SEG6_ROUTE) + && api_nh->type != NEXTHOP_TYPE_BLACKHOLE) { + if (IS_ZEBRA_DEBUG_RECV) + zlog_debug("%s: adding seg6", __func__); + + nexthop_add_seg6(nexthop, &api_nh->seg6_segs); + } + if (IS_ZEBRA_DEBUG_RECV) { labelbuf[0] = '\0'; nhbuf[0] = '\0'; diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index ddd37b4df7..84ce97b008 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -1008,6 +1008,7 @@ void nhg_ctx_free(struct nhg_ctx **ctx) nexthop_del_labels(nh); nexthop_del_seg6local(nh); + nexthop_del_seg6(nh); done: XFREE(MTYPE_NHG_CTX, *ctx); @@ -1379,6 +1380,7 @@ static struct nhg_hash_entry *depends_find_singleton(const struct nexthop *nh, /* The copy may have allocated labels; free them if necessary. */ nexthop_del_labels(&lookup); nexthop_del_seg6local(&lookup); + nexthop_del_seg6(&lookup); if (IS_ZEBRA_DEBUG_NHG_DETAIL) zlog_debug("%s: nh %pNHv => %p (%u)", diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index c178ce075c..fae443ca2e 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -662,6 +662,11 @@ static void show_route_nexthop_helper(struct vty *vty, buf); } + if (nexthop->nh_seg6_segs) { + inet_ntop(AF_INET6, nexthop->nh_seg6_segs, buf, sizeof(buf)); + vty_out(vty, ", seg6 %s", buf); + } + if (nexthop->weight) vty_out(vty, ", weight %u", nexthop->weight); @@ -685,6 +690,7 @@ static void show_nexthop_json_helper(json_object *json_nexthop, json_object *json_labels = NULL; json_object *json_backups = NULL; json_object *json_seg6local = NULL; + json_object *json_seg6 = NULL; int i; json_object_int_add(json_nexthop, "flags", @@ -871,6 +877,13 @@ static void show_nexthop_json_helper(json_object *json_nexthop, json_object_object_add(json_nexthop, "seg6local", json_seg6local); } + + if (nexthop->nh_seg6_segs) { + json_seg6 = json_object_new_object(); + inet_ntop(AF_INET6, nexthop->nh_seg6_segs, buf, sizeof(buf)); + json_object_string_add(json_seg6, "segs", buf); + json_object_object_add(json_nexthop, "seg6", json_seg6); + } } static void vty_show_ip_route(struct vty *vty, struct route_node *rn, From f16de90b8c4d29f28cf9829389325a5e9bb09293 Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Fri, 18 Dec 2020 21:41:19 +0900 Subject: [PATCH 17/66] zebra: parse non-zebra seg6 configuration via netlink (step3) FRRouting operator can install seg6 route via ZAPI, But linux kernel operator also can install seg6 route via Netlink directry (i.e. iproute2) This commit make zebra to parse non-frr seg6 route configuration via netlink and audit Zebra's RIB. Signed-off-by: Hiroki Shirokura --- zebra/rt_netlink.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 00eb0b6644..705a035de5 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -441,6 +441,29 @@ parse_encap_seg6local(struct rtattr *tb, return act; } +static int parse_encap_seg6(struct rtattr *tb, struct in6_addr *segs) +{ + struct rtattr *tb_encap[256] = {0}; + struct seg6_iptunnel_encap *ipt = NULL; + struct in6_addr *segments = NULL; + + netlink_parse_rtattr_nested(tb_encap, 256, tb); + + /* + * TODO: It's not support multiple SID list. + */ + if (tb_encap[SEG6_IPTUNNEL_SRH]) { + ipt = (struct seg6_iptunnel_encap *) + RTA_DATA(tb_encap[SEG6_IPTUNNEL_SRH]); + segments = ipt->srh[0].segments; + *segs = segments[0]; + return 1; + } + + return 0; +} + + static struct nexthop parse_nexthop_unicast(ns_id_t ns_id, struct rtmsg *rtm, struct rtattr **tb, enum blackhole_type bh_type, int index, void *prefsrc, @@ -452,6 +475,8 @@ parse_nexthop_unicast(ns_id_t ns_id, struct rtmsg *rtm, struct rtattr **tb, int num_labels = 0; enum seg6local_action_t seg6l_act = SEG6_LOCAL_ACTION_UNSPEC; struct seg6local_context seg6l_ctx = {{0}}; + struct in6_addr seg6_segs = {0}; + int num_segs = 0; vrf_id_t nh_vrf_id = vrf_id; size_t sz = (afi == AFI_IP) ? 4 : 16; @@ -496,6 +521,11 @@ parse_nexthop_unicast(ns_id_t ns_id, struct rtmsg *rtm, struct rtattr **tb, == LWTUNNEL_ENCAP_SEG6_LOCAL) { seg6l_act = parse_encap_seg6local(tb[RTA_ENCAP], &seg6l_ctx); } + if (tb[RTA_ENCAP] && tb[RTA_ENCAP_TYPE] + && *(uint16_t *)RTA_DATA(tb[RTA_ENCAP_TYPE]) + == LWTUNNEL_ENCAP_SEG6) { + num_segs = parse_encap_seg6(tb[RTA_ENCAP], &seg6_segs); + } if (rtm->rtm_flags & RTNH_F_ONLINK) SET_FLAG(nh.flags, NEXTHOP_FLAG_ONLINK); @@ -506,6 +536,9 @@ parse_nexthop_unicast(ns_id_t ns_id, struct rtmsg *rtm, struct rtattr **tb, if (seg6l_act != ZEBRA_SEG6_LOCAL_ACTION_UNSPEC) nexthop_add_seg6local(&nh, seg6l_act, &seg6l_ctx); + if (num_segs) + nexthop_add_seg6(&nh, &seg6_segs); + return nh; } @@ -524,6 +557,8 @@ static uint8_t parse_multipath_nexthops_unicast(ns_id_t ns_id, int num_labels = 0; enum seg6local_action_t seg6l_act = SEG6_LOCAL_ACTION_UNSPEC; struct seg6local_context seg6l_ctx = {{0}}; + struct in6_addr seg6_segs = {0}; + int num_segs = 0; struct rtattr *rtnh_tb[RTA_MAX + 1] = {}; int len = RTA_PAYLOAD(tb[RTA_MULTIPATH]); @@ -574,6 +609,12 @@ static uint8_t parse_multipath_nexthops_unicast(ns_id_t ns_id, seg6l_act = parse_encap_seg6local( rtnh_tb[RTA_ENCAP], &seg6l_ctx); } + if (rtnh_tb[RTA_ENCAP] && rtnh_tb[RTA_ENCAP_TYPE] + && *(uint16_t *)RTA_DATA(rtnh_tb[RTA_ENCAP_TYPE]) + == LWTUNNEL_ENCAP_SEG6) { + num_segs = parse_encap_seg6(rtnh_tb[RTA_ENCAP], + &seg6_segs); + } } if (gate && rtm->rtm_family == AF_INET) { @@ -603,6 +644,9 @@ static uint8_t parse_multipath_nexthops_unicast(ns_id_t ns_id, nexthop_add_seg6local(nh, seg6l_act, &seg6l_ctx); + if (num_segs) + nexthop_add_seg6(nh, &seg6_segs); + if (rtnh->rtnh_flags & RTNH_F_ONLINK) SET_FLAG(nh->flags, NEXTHOP_FLAG_ONLINK); From af31f6c05c26192d4e2ea18845bef2617b919631 Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Fri, 18 Dec 2020 21:18:12 +0900 Subject: [PATCH 18/66] sharpd: install route supports nexthop-seg6 (step3) We can install seg6 routes from shapd cli. This is for the behaviour test(topotest) to ensure SRv6 ZAPI is working fine. NEW-CLI: sharp install routes 1::1 nexthop-seg6 2001::1 encap a:: Signed-off-by: Hiroki Shirokura --- sharpd/sharp_vty.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index c580338f33..5997e5e312 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -197,7 +197,8 @@ DEFPY (install_routes, End_X$seg6l_endx X:X::X:X$seg6l_endx_nh6|\ End_T$seg6l_endt (1-4294967295)$seg6l_endt_table|\ End_DX4$seg6l_enddx4 A.B.C.D$seg6l_enddx4_nh4|\ - End_DT6$seg6l_enddt6 (1-4294967295)$seg6l_enddt6_table>>\ + End_DT6$seg6l_enddt6 (1-4294967295)$seg6l_enddt6_table>|\ + nexthop-seg6$nh_seg6 X:X::X:X$seg6_nh6 encap X:X::X:X$seg6_seg>\ [backup$backup ] \ (1-1000000)$routes [instance (0-255)$instance] [repeat (2-1000)$rpt] [opaque WORD]", "Sharp routing Protocol\n" @@ -223,6 +224,10 @@ DEFPY (install_routes, "V4 Nexthop address to use\n" "SRv6 End.DT6 function to use\n" "Redirect table id to use\n" + "Nexthop-seg6 to use\n" + "V6 Nexthop address to use\n" + "Encap mode\n" + "Segment List to use\n" "Backup nexthop to use(Can be an IPv4 or IPv6 address)\n" "Backup V4 Nexthop address to use\n" "Backup V6 Nexthop address to use\n" @@ -336,6 +341,14 @@ DEFPY (install_routes, sg.r.nhop_group.nexthop = &sg.r.nhop; nexthop_add_seg6local(&sg.r.nhop, action, &ctx); SET_FLAG(route_flags, ZEBRA_FLAG_SEG6LOCAL_ROUTE); + } else if (nh_seg6) { + sg.r.nhop.type = NEXTHOP_TYPE_IPV6; + sg.r.nhop.gate.ipv6 = seg6_nh6; + sg.r.nhop.vrf_id = vrf->vrf_id; + sg.r.nhop_group.nexthop = &sg.r.nhop; + + nexthop_add_seg6(&sg.r.nhop, &seg6_seg); + SET_FLAG(route_flags, ZEBRA_FLAG_SEG6_ROUTE); } else { if (nexthop4.s_addr != INADDR_ANY) { sg.r.nhop.gate.ipv4 = nexthop4; From c5a044e0551fc607fdfe950ddefcc351d8a4f15d Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Fri, 18 Dec 2020 22:11:19 +0900 Subject: [PATCH 19/66] topotests: for zapi's seg6 route configuration (step3) This commit checks seg6 route configuration via ZAPI is working fine. Signed-off-by: Hiroki Shirokura --- .../topotests/zebra_seg6_route/r1/routes.json | 25 ++++ tests/topotests/zebra_seg6_route/r1/setup.sh | 5 + .../topotests/zebra_seg6_route/r1/sharpd.conf | 0 .../topotests/zebra_seg6_route/r1/zebra.conf | 13 +++ .../zebra_seg6_route/test_zebra_seg6_route.py | 109 ++++++++++++++++++ 5 files changed, 152 insertions(+) create mode 100644 tests/topotests/zebra_seg6_route/r1/routes.json create mode 100644 tests/topotests/zebra_seg6_route/r1/setup.sh create mode 100644 tests/topotests/zebra_seg6_route/r1/sharpd.conf create mode 100644 tests/topotests/zebra_seg6_route/r1/zebra.conf create mode 100755 tests/topotests/zebra_seg6_route/test_zebra_seg6_route.py diff --git a/tests/topotests/zebra_seg6_route/r1/routes.json b/tests/topotests/zebra_seg6_route/r1/routes.json new file mode 100644 index 0000000000..a0c15b8fe4 --- /dev/null +++ b/tests/topotests/zebra_seg6_route/r1/routes.json @@ -0,0 +1,25 @@ +[ + { + "in": { + "dest": "1::1", + "nh": "2001::1", + "sid": "a::" + }, + "out":[{ + "prefix":"1::1/128", + "protocol":"sharp", + "selected":true, + "destSelected":true, + "distance":150, + "metric":0, + "installed":true, + "table":254, + "nexthops":[{ + "flags":3, + "fib":true, + "active":true, + "seg6": { "segs": "a::" } + }] + }] + } +] diff --git a/tests/topotests/zebra_seg6_route/r1/setup.sh b/tests/topotests/zebra_seg6_route/r1/setup.sh new file mode 100644 index 0000000000..2cb5c4a4ec --- /dev/null +++ b/tests/topotests/zebra_seg6_route/r1/setup.sh @@ -0,0 +1,5 @@ +ip link add vrf10 type vrf table 10 +ip link set vrf10 up +ip link add dum0 type dummy +ip link set dum0 up +sysctl -w net.ipv6.conf.dum0.disable_ipv6=0 diff --git a/tests/topotests/zebra_seg6_route/r1/sharpd.conf b/tests/topotests/zebra_seg6_route/r1/sharpd.conf new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/topotests/zebra_seg6_route/r1/zebra.conf b/tests/topotests/zebra_seg6_route/r1/zebra.conf new file mode 100644 index 0000000000..ad661e116b --- /dev/null +++ b/tests/topotests/zebra_seg6_route/r1/zebra.conf @@ -0,0 +1,13 @@ +log file zebra.log +! +log stdout notifications +log monitor notifications +log commands +! +debug zebra packet +debug zebra dplane +debug zebra kernel msgdump +! +interface dum0 + ipv6 address 2001::1/64 +! diff --git a/tests/topotests/zebra_seg6_route/test_zebra_seg6_route.py b/tests/topotests/zebra_seg6_route/test_zebra_seg6_route.py new file mode 100755 index 0000000000..e14d9690c1 --- /dev/null +++ b/tests/topotests/zebra_seg6_route/test_zebra_seg6_route.py @@ -0,0 +1,109 @@ +#!/usr/bin/env python + +# +# test_zebra_seg6_route.py +# +# Copyright (c) 2020 by +# LINE Corporation, Hiroki Shirokura +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +test_zebra_seg6_route.py: Test seg6 route addition with zapi. +""" + +import os +import re +import sys +import pytest +import json +import platform +from functools import partial + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger +from lib.common_config import shutdown_bringup_interface +from mininet.topo import Topo + + +def open_json_file(filename): + try: + with open(filename, "r") as f: + return json.load(f) + except IOError: + assert False, "Could not read file {}".format(filename) + + +class TemplateTopo(Topo): + def build(self, **_opts): + tgen = get_topogen(self) + tgen.add_router("r1") + + +def setup_module(mod): + tgen = Topogen(TemplateTopo, mod.__name__) + tgen.start_topology() + router_list = tgen.routers() + for rname, router in tgen.routers().items(): + router.run("/bin/bash {}".format(os.path.join(CWD, "{}/setup.sh".format(rname)))) + router.load_config(TopoRouter.RD_ZEBRA, os.path.join(CWD, '{}/zebra.conf'.format(rname))) + router.load_config(TopoRouter.RD_SHARP, os.path.join(CWD, "{}/sharpd.conf".format(rname))) + tgen.start_router() + + +def teardown_module(_mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_zebra_seg6local_routes(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + logger.info("Test for seg6local route install via ZAPI was start.") + r1 = tgen.gears["r1"] + + def check(router, dest, nh, sid, expected): + router.vtysh_cmd("sharp install routes {} "\ + "nexthop-seg6 {} encap {} 1".format(dest, nh, sid)) + output = json.loads(router.vtysh_cmd("show ipv6 route {} json".format(dest))) + output = output.get('{}/128'.format(dest)) + if output is None: + return False + return topotest.json_cmp(output, expected) + + manifests = open_json_file(os.path.join(CWD, "{}/routes.json".format("r1"))) + for manifest in manifests: + logger.info("CHECK {} {} {}".format(manifest['in']['dest'], + manifest['in']['nh'], + manifest['in']['sid'])) + test_func = partial(check, r1, + manifest['in']['dest'], + manifest['in']['nh'], + manifest['in']['sid'], + manifest['out']) + success, result = topotest.run_and_expect(test_func, None, count=5, wait=1) + assert result is None, 'Failed' + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) From 4df9d8592b1631e6cb50e291cab1ff7486467a3d Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Wed, 24 Feb 2021 10:47:05 +0000 Subject: [PATCH 20/66] *: fix code format accourding to checkpatch Signed-off-by: Hiroki Shirokura --- lib/nexthop.h | 2 +- lib/zclient.c | 6 +++-- sharpd/sharp_vty.c | 4 ++- sharpd/sharp_zebra.c | 19 ++++++++------ sharpd/sharp_zebra.h | 6 ++++- zebra/rt_netlink.c | 13 +++++----- zebra/zapi_msg.h | 3 +-- zebra/zebra_srv6.c | 7 ++--- zebra/zebra_srv6.h | 3 ++- zebra/zebra_srv6_vty.c | 58 ++++++++++++++++++++++++------------------ 10 files changed, 71 insertions(+), 50 deletions(-) diff --git a/lib/nexthop.h b/lib/nexthop.h index 8c52631af1..c9af1ff478 100644 --- a/lib/nexthop.h +++ b/lib/nexthop.h @@ -168,7 +168,7 @@ void nexthop_del_labels(struct nexthop *); void nexthop_add_seg6local(struct nexthop *nexthop, uint32_t action, const struct seg6local_context *ctx); void nexthop_del_seg6local(struct nexthop *nexthop); -void nexthop_add_seg6(struct nexthop *nexthop, const struct in6_addr* segs); +void nexthop_add_seg6(struct nexthop *nexthop, const struct in6_addr *segs); void nexthop_del_seg6(struct nexthop *nexthop); /* diff --git a/lib/zclient.c b/lib/zclient.c index 8520fd769d..7eb365c305 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -2774,7 +2774,8 @@ int srv6_manager_get_locator_chunk(struct zclient *zclient, /* send request */ s = zclient->obuf; stream_reset(s); - zclient_create_header(s, ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK, VRF_DEFAULT); + zclient_create_header(s, ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK, + VRF_DEFAULT); /* proto */ stream_putc(s, zclient->redist_default); @@ -3580,7 +3581,8 @@ enum zclient_send_status zclient_send_mlag_register(struct zclient *client, enum zclient_send_status zclient_send_mlag_deregister(struct zclient *client) { - return zebra_message_send(client, ZEBRA_MLAG_CLIENT_UNREGISTER, VRF_DEFAULT); + return zebra_message_send(client, ZEBRA_MLAG_CLIENT_UNREGISTER, + VRF_DEFAULT); } enum zclient_send_status zclient_send_mlag_data(struct zclient *client, diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index 5997e5e312..58f6e3fe95 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -318,6 +318,7 @@ DEFPY (install_routes, } else if (seg6l_oif) { struct seg6local_context ctx; enum seg6local_action_t action; + memset(&ctx, 0, sizeof(struct seg6local_context)); if (seg6l_enddx4) { action = ZEBRA_SEG6_LOCAL_ACTION_END_DX4; @@ -1047,7 +1048,8 @@ void sharp_vty_init(void) install_element(ENABLE_NODE, &show_sharp_ted_cmd); install_element(ENABLE_NODE, &sharp_srv6_manager_get_locator_chunk_cmd); - install_element(ENABLE_NODE, &sharp_srv6_manager_release_locator_chunk_cmd); + install_element(ENABLE_NODE, + &sharp_srv6_manager_release_locator_chunk_cmd); install_element(ENABLE_NODE, &show_sharp_segment_routing_srv6_cmd); return; diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c index 7c24ae380f..ae4add6a60 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -338,7 +338,8 @@ static void sharp_install_routes_restart(struct prefix *p, uint32_t count, uint32_t nhgid, const struct nexthop_group *nhg, const struct nexthop_group *backup_nhg, - uint32_t routes, uint32_t flags, char *opaque) + uint32_t routes, uint32_t flags, + char *opaque) { uint32_t temp, i; bool v4 = false; @@ -924,7 +925,7 @@ static int nhg_notify_owner(ZAPI_CALLBACK_ARGS) return 0; } -int sharp_zebra_srv6_manager_get_locator_chunk(const char* locator_name) +int sharp_zebra_srv6_manager_get_locator_chunk(const char *locator_name) { return srv6_manager_get_locator_chunk(zclient, locator_name); } @@ -942,6 +943,7 @@ static void sharp_zebra_process_srv6_locator_chunk(ZAPI_CALLBACK_ARGS) uint16_t len; char name[256] = {0}; struct prefix_ipv6 *chunk = NULL; + chunk = prefix_ipv6_new(); s = zclient->ibuf; @@ -965,16 +967,17 @@ static void sharp_zebra_process_srv6_locator_chunk(ZAPI_CALLBACK_ARGS) struct listnode *loc_node; struct sharp_srv6_locator *loc; + for (ALL_LIST_ELEMENTS_RO(sg.srv6_locators, loc_node, loc)) { + struct listnode *chunk_node; + struct prefix_ipv6 *c; + if (strcmp(loc->name, name)) continue; - struct listnode *chunk_node; - struct prefix_ipv6 *c; - for (ALL_LIST_ELEMENTS_RO(loc->chunks, chunk_node, c)) { + for (ALL_LIST_ELEMENTS_RO(loc->chunks, chunk_node, c)) if (!prefix_cmp(c, chunk)) return; - } listnode_add(loc->chunks, chunk); } return; @@ -983,7 +986,6 @@ stream_failure: free(chunk); zlog_err("%s: can't get locator_chunk!!", __func__); - return; } void sharp_zebra_init(void) @@ -1007,5 +1009,6 @@ void sharp_zebra_init(void) zclient->redistribute_route_add = sharp_redistribute_route; zclient->redistribute_route_del = sharp_redistribute_route; zclient->opaque_msg_handler = sharp_opaque_handler; - zclient->process_srv6_locator_chunk = sharp_zebra_process_srv6_locator_chunk; + zclient->process_srv6_locator_chunk = + sharp_zebra_process_srv6_locator_chunk; } diff --git a/sharpd/sharp_zebra.h b/sharpd/sharp_zebra.h index 043a7405c2..45e26a9b3d 100644 --- a/sharpd/sharp_zebra.h +++ b/sharpd/sharp_zebra.h @@ -39,7 +39,8 @@ extern void sharp_install_routes_helper(struct prefix *p, vrf_id_t vrf_id, uint8_t instance, uint32_t nhgid, const struct nexthop_group *nhg, const struct nexthop_group *backup_nhg, - uint32_t routes, uint32_t flags, char *opaque); + uint32_t routes, uint32_t flags, + char *opaque); extern void sharp_remove_routes_helper(struct prefix *p, vrf_id_t vrf_id, uint8_t instance, uint32_t routes); @@ -67,6 +68,9 @@ extern void sharp_redistribute_vrf(struct vrf *vrf, int source); extern int sharp_zebra_srv6_manager_get_locator_chunk(const char* locator_name); extern int sharp_zebra_srv6_manager_release_locator_chunk(const char *locator_name); +extern int sharp_zebra_srv6_manager_get_locator_chunk(const char *locator_name); +extern int sharp_zebra_srv6_manager_release_locator_chunk( + const char *locator_name); extern void sharp_install_seg6local_route_helper(struct prefix *p, uint8_t instance, enum seg6local_action_t act, diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 705a035de5..f5ce4e795b 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -474,7 +474,7 @@ parse_nexthop_unicast(ns_id_t ns_id, struct rtmsg *rtm, struct rtattr **tb, mpls_label_t labels[MPLS_MAX_LABELS] = {0}; int num_labels = 0; enum seg6local_action_t seg6l_act = SEG6_LOCAL_ACTION_UNSPEC; - struct seg6local_context seg6l_ctx = {{0}}; + struct seg6local_context seg6l_ctx = { {0} }; struct in6_addr seg6_segs = {0}; int num_segs = 0; @@ -556,7 +556,7 @@ static uint8_t parse_multipath_nexthops_unicast(ns_id_t ns_id, mpls_label_t labels[MPLS_MAX_LABELS] = {0}; int num_labels = 0; enum seg6local_action_t seg6l_act = SEG6_LOCAL_ACTION_UNSPEC; - struct seg6local_context seg6l_ctx = {{0}}; + struct seg6local_context seg6l_ctx = { {0} }; struct in6_addr seg6_segs = {0}; int num_segs = 0; struct rtattr *rtnh_tb[RTA_MAX + 1] = {}; @@ -1336,6 +1336,7 @@ static size_t fill_seg6ipt_encap(char *buffer, size_t buflen, struct seg6_iptunnel_encap *ipt; struct ipv6_sr_hdr *srh; const size_t srhlen = 24; + memset(buffer, 0, buflen); ipt = (struct seg6_iptunnel_encap *)buffer; @@ -2479,16 +2480,16 @@ ssize_t netlink_nexthop_msg_encode(uint16_t cmd, break; case SEG6_LOCAL_ACTION_END_DX4: nl_attr_put32(&req->n, buflen, - SEG6_LOCAL_ACTION, - SEG6_LOCAL_ACTION_END_DX4); + SEG6_LOCAL_ACTION, + SEG6_LOCAL_ACTION_END_DX4); nl_attr_put(&req->n, buflen, SEG6_LOCAL_NH4, &ctx->nh4, sizeof(struct in_addr)); break; case SEG6_LOCAL_ACTION_END_DT6: nl_attr_put32(&req->n, buflen, - SEG6_LOCAL_ACTION, - SEG6_LOCAL_ACTION_END_DT6); + SEG6_LOCAL_ACTION, + SEG6_LOCAL_ACTION_END_DT6); nl_attr_put32(&req->n, buflen, SEG6_LOCAL_TABLE, ctx->table); diff --git a/zebra/zapi_msg.h b/zebra/zapi_msg.h index 35bb554121..e991dca4f3 100644 --- a/zebra/zapi_msg.h +++ b/zebra/zapi_msg.h @@ -122,8 +122,7 @@ extern int zsend_zebra_srv6_locator_add(struct zserv *client, extern int zsend_zebra_srv6_locator_delete(struct zserv *client, struct srv6_locator *loc); extern int zsend_srv6_manager_get_locator_chunk_response(struct zserv *client, - vrf_id_t vrf_id, - struct srv6_locator *loc); + vrf_id_t vrf_id, struct srv6_locator *loc); #ifdef __cplusplus } diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c index b4b691e8e0..1e12117ac4 100644 --- a/zebra/zebra_srv6.c +++ b/zebra/zebra_srv6.c @@ -115,6 +115,7 @@ void zebra_srv6_locator_add(struct srv6_locator *locator) void zebra_srv6_locator_delete(struct srv6_locator *locator) { struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + listnode_delete(srv6->locators, locator); } @@ -206,6 +207,8 @@ static int zebra_srv6_manager_get_locator_chunk(struct srv6_locator **loc, const char *locator_name, vrf_id_t vrf_id) { + int ret = 0; + *loc = assign_srv6_locator_chunk(client->proto, client->instance, client->session_id, locator_name); @@ -217,7 +220,6 @@ static int zebra_srv6_manager_get_locator_chunk(struct srv6_locator **loc, (*loc)->name, zebra_route_string(client->proto), client->instance); - int ret = 0; if ((*loc)->status_up) ret = zsend_srv6_manager_get_locator_chunk_response(client, vrf_id, @@ -244,9 +246,8 @@ static int release_srv6_locator_chunk(uint8_t proto, uint16_t instance, struct srv6_locator *loc = NULL; loc = zebra_srv6_locator_lookup(locator_name); - if (!loc) { + if (!loc) return -1; - } if (IS_ZEBRA_DEBUG_PACKET) zlog_debug("%s: Releasing srv6-locator on %s", __func__, diff --git a/zebra/zebra_srv6.h b/zebra/zebra_srv6.h index 751cee6e70..84fcc305bc 100644 --- a/zebra/zebra_srv6.h +++ b/zebra/zebra_srv6.h @@ -65,7 +65,8 @@ extern void zebra_srv6_init(void); extern struct zebra_srv6 *zebra_srv6_get_default(void); extern bool zebra_srv6_is_enable(void); -extern void srv6_manager_client_connect_call(struct zserv *client, vrf_id_t vrf_id); +extern void srv6_manager_client_connect_call(struct zserv *client, + vrf_id_t vrf_id); extern void srv6_manager_get_locator_chunk_call(struct srv6_locator **loc, struct zserv *client, const char *locator_name, diff --git a/zebra/zebra_srv6_vty.c b/zebra/zebra_srv6_vty.c index 73038fad73..e2685141bb 100644 --- a/zebra/zebra_srv6_vty.c +++ b/zebra/zebra_srv6_vty.c @@ -147,30 +147,31 @@ DEFUN (show_srv6_locator_detail, if (uj) { vty_out(vty, "JSON format isn't supported\n"); return CMD_WARNING; - } else { - for (ALL_LIST_ELEMENTS_RO(srv6->locators, node, locator)) { - if (strcmp(locator->name, locator_name) != 0) { - continue; - } - - prefix2str(&locator->prefix, str, sizeof(str)); - vty_out(vty, "Name: %s\n", locator->name); - vty_out(vty, "Prefix: %s\n", str); - vty_out(vty, "Function-Bit-Len: %u\n", - locator->function_bits_length); - - vty_out(vty, "Chunks:\n"); - struct listnode *node; - struct srv6_locator_chunk *chunk; - for (ALL_LIST_ELEMENTS_RO((struct list *)locator->chunks, node, chunk)) { - prefix2str(&chunk->prefix, str, sizeof(str)); - vty_out(vty, "- prefix: %s, owner: %s\n", str, - zebra_route_string(chunk->proto)); - } - } - } + for (ALL_LIST_ELEMENTS_RO(srv6->locators, node, locator)) { + struct listnode *node; + struct srv6_locator_chunk *chunk; + + if (strcmp(locator->name, locator_name) != 0) + continue; + + prefix2str(&locator->prefix, str, sizeof(str)); + vty_out(vty, "Name: %s\n", locator->name); + vty_out(vty, "Prefix: %s\n", str); + vty_out(vty, "Function-Bit-Len: %u\n", + locator->function_bits_length); + + vty_out(vty, "Chunks:\n"); + for (ALL_LIST_ELEMENTS_RO((struct list *)locator->chunks, node, + chunk)) { + prefix2str(&chunk->prefix, str, sizeof(str)); + vty_out(vty, "- prefix: %s, owner: %s\n", str, + zebra_route_string(chunk->proto)); + } + } + + return CMD_SUCCESS; } @@ -264,16 +265,23 @@ DEFUN (locator_prefix, } else { for (ALL_LIST_ELEMENTS_RO(locator->chunks, node, chunk)) { uint8_t zero[16] = {0}; + if (memcmp(&chunk->prefix.prefix, zero, 16) == 0) { struct zserv *client; struct listnode *client_node; + chunk->prefix = prefix; - for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, client_node, client)) { + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, + client_node, + client)) { + struct srv6_locator *tmp; + if (client->proto != chunk->proto) continue; - struct srv6_locator *tmp; srv6_manager_get_locator_chunk_call( - &tmp, client, locator->name, VRF_DEFAULT); + &tmp, client, + locator->name, + VRF_DEFAULT); } } } From b83127e1568bc22fd8011b535eb2cf95de1dac59 Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Thu, 24 Dec 2020 04:07:39 +0000 Subject: [PATCH 21/66] bgpd: fix prefix-sid crash bug and add topotest (step4) This commit fix bgpd's prefix-sid type4,5 feature which has miss implementation from https://github.com/FRRouting/frr/pull/5653 was merged. Due to some nessesary lines are not presented. When bgpd receives multi update message with same service-sid on prefix-sid type-5 attribute, bgpd will crash arround path-attribute's values object reference count. And also, this commit add a topotest to check that feature work fine. Signed-off-by: Hiroki Shirokura --- bgpd/bgp_attr.c | 24 ++++ .../bgp_prefix_sid2/peer1/exabgp.cfg | 29 +++++ .../bgp_prefix_sid2/peer1/exabgp.env | 53 ++++++++ tests/topotests/bgp_prefix_sid2/r1/bgpd.conf | 26 ++++ .../bgp_prefix_sid2/r1/vpnv6_rib_entry1.json | 50 ++++++++ .../bgp_prefix_sid2/r1/vpnv6_rib_entry2.json | 50 ++++++++ tests/topotests/bgp_prefix_sid2/r1/zebra.conf | 7 + .../bgp_prefix_sid2/test_bgp_prefix_sid2.py | 121 ++++++++++++++++++ 8 files changed, 360 insertions(+) create mode 100644 tests/topotests/bgp_prefix_sid2/peer1/exabgp.cfg create mode 100644 tests/topotests/bgp_prefix_sid2/peer1/exabgp.env create mode 100644 tests/topotests/bgp_prefix_sid2/r1/bgpd.conf create mode 100644 tests/topotests/bgp_prefix_sid2/r1/vpnv6_rib_entry1.json create mode 100644 tests/topotests/bgp_prefix_sid2/r1/vpnv6_rib_entry2.json create mode 100644 tests/topotests/bgp_prefix_sid2/r1/zebra.conf create mode 100755 tests/topotests/bgp_prefix_sid2/test_bgp_prefix_sid2.py diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 71e4b56a00..c20c435003 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -676,6 +676,10 @@ unsigned int attrhash_key_make(const void *p) MIX(transit_hash_key_make(bgp_attr_get_transit(attr))); if (attr->encap_subtlvs) MIX(encap_hash_key_make(attr->encap_subtlvs)); + if (attr->srv6_l3vpn) + MIX(srv6_l3vpn_hash_key_make(attr->srv6_l3vpn)); + if (attr->srv6_vpn) + MIX(srv6_vpn_hash_key_make(attr->srv6_vpn)); #ifdef ENABLE_BGP_VNC struct bgp_attr_encap_subtlv *vnc_subtlvs = bgp_attr_get_vnc_subtlvs(attr); @@ -1141,6 +1145,16 @@ void bgp_attr_undup(struct attr *new, struct attr *old) if (new->lcommunity != old->lcommunity) lcommunity_free(&new->lcommunity); + + if (new->srv6_l3vpn != old->srv6_l3vpn) { + srv6_l3vpn_free(new->srv6_l3vpn); + new->srv6_l3vpn = NULL; + } + + if (new->srv6_vpn != old->srv6_vpn) { + srv6_vpn_free(new->srv6_vpn); + new->srv6_vpn = NULL; + } } /* Free bgp attribute and aspath. */ @@ -1202,6 +1216,14 @@ void bgp_attr_flush(struct attr *attr) encap_free(attr->encap_subtlvs); attr->encap_subtlvs = NULL; } + if (attr->srv6_l3vpn && !attr->srv6_l3vpn->refcnt) { + srv6_l3vpn_free(attr->srv6_l3vpn); + attr->srv6_l3vpn = NULL; + } + if (attr->srv6_vpn && !attr->srv6_vpn->refcnt) { + srv6_vpn_free(attr->srv6_vpn); + attr->srv6_vpn = NULL; + } #ifdef ENABLE_BGP_VNC struct bgp_attr_encap_subtlv *vnc_subtlvs = bgp_attr_get_vnc_subtlvs(attr); @@ -2676,6 +2698,7 @@ static bgp_attr_parse_ret_t bgp_attr_psid_sub(uint8_t type, uint16_t length, sizeof(struct bgp_attr_srv6_vpn)); attr->srv6_vpn->sid_flags = sid_flags; sid_copy(&attr->srv6_vpn->sid, &ipv6_sid); + attr->srv6_vpn = srv6_vpn_intern(attr->srv6_vpn); } /* Placeholder code for the SRv6 L3 Service type */ @@ -2718,6 +2741,7 @@ static bgp_attr_parse_ret_t bgp_attr_psid_sub(uint8_t type, uint16_t length, attr->srv6_l3vpn->sid_flags = sid_flags; attr->srv6_l3vpn->endpoint_behavior = endpoint_behavior; sid_copy(&attr->srv6_l3vpn->sid, &ipv6_sid); + attr->srv6_l3vpn = srv6_l3vpn_intern(attr->srv6_l3vpn); } /* Placeholder code for Unsupported TLV */ diff --git a/tests/topotests/bgp_prefix_sid2/peer1/exabgp.cfg b/tests/topotests/bgp_prefix_sid2/peer1/exabgp.cfg new file mode 100644 index 0000000000..ad1b15a26c --- /dev/null +++ b/tests/topotests/bgp_prefix_sid2/peer1/exabgp.cfg @@ -0,0 +1,29 @@ +group controller { + neighbor 10.0.0.1 { + router-id 10.0.0.101; + local-address 10.0.0.101; + local-as 2; + peer-as 1; + + family { + ipv6 mpls-vpn; + } + + static { + route 2001:1::/64 { + rd 2:10; + next-hop 2001::2; + extended-community [ target:2:10 ]; + label 3; + attribute [0x28 0xc0 0x0500150020010db800010001000000000000000100ffff00 ]; + } + route 2001:2::/64 { + rd 2:10; + next-hop 2001::2; + extended-community [ target:2:10 ]; + label 3; + attribute [0x28 0xc0 0x0500150020010db800010001000000000000000100ffff00 ]; + } + } + } +} diff --git a/tests/topotests/bgp_prefix_sid2/peer1/exabgp.env b/tests/topotests/bgp_prefix_sid2/peer1/exabgp.env new file mode 100644 index 0000000000..6c554f5fa8 --- /dev/null +++ b/tests/topotests/bgp_prefix_sid2/peer1/exabgp.env @@ -0,0 +1,53 @@ + +[exabgp.api] +encoder = text +highres = false +respawn = false +socket = '' + +[exabgp.bgp] +openwait = 60 + +[exabgp.cache] +attributes = true +nexthops = true + +[exabgp.daemon] +daemonize = true +pid = '/var/run/exabgp/exabgp.pid' +user = 'exabgp' + +[exabgp.log] +all = false +configuration = true +daemon = true +destination = '/var/log/exabgp.log' +enable = true +level = INFO +message = false +network = true +packets = false +parser = false +processes = true +reactor = true +rib = false +routes = false +short = false +timers = false + +[exabgp.pdb] +enable = false + +[exabgp.profile] +enable = false +file = '' + +[exabgp.reactor] +speed = 1.0 + +[exabgp.tcp] +acl = false +bind = '' +delay = 0 +once = false +port = 179 diff --git a/tests/topotests/bgp_prefix_sid2/r1/bgpd.conf b/tests/topotests/bgp_prefix_sid2/r1/bgpd.conf new file mode 100644 index 0000000000..ddc1f07e42 --- /dev/null +++ b/tests/topotests/bgp_prefix_sid2/r1/bgpd.conf @@ -0,0 +1,26 @@ +log stdout notifications +log monitor notifications +!log commands +! +!debug bgp zebra +!debug bgp neighbor-events +!debug bgp vnc verbose +!debug bgp update-groups +!debug bgp updates in +!debug bgp updates out +!debug bgp vpn label +!debug bgp vpn leak-from-vrf +!debug bgp vpn leak-to-vrf +!debug bgp vpn rmap-event +! +router bgp 1 + bgp router-id 10.0.0.1 + no bgp default ipv4-unicast + no bgp ebgp-requires-policy + neighbor 10.0.0.101 remote-as 2 + neighbor 10.0.0.101 timers 3 10 + ! + address-family ipv6 vpn + neighbor 10.0.0.101 activate + exit-address-family +! diff --git a/tests/topotests/bgp_prefix_sid2/r1/vpnv6_rib_entry1.json b/tests/topotests/bgp_prefix_sid2/r1/vpnv6_rib_entry1.json new file mode 100644 index 0000000000..42293b1fc7 --- /dev/null +++ b/tests/topotests/bgp_prefix_sid2/r1/vpnv6_rib_entry1.json @@ -0,0 +1,50 @@ +{ + "2:10":{ + "prefix":"2001:1::\/64", + "advertisedTo":{ + "10.0.0.101":{ + } + }, + "paths":[ + { + "aspath":{ + "string":"2", + "segments":[ + { + "type":"as-sequence", + "list":[ + 2 + ] + } + ], + "length":1 + }, + "origin":"IGP", + "valid":true, + "bestpath":{ + "overall":true + }, + "extendedCommunity":{ + "string":"RT:2:10" + }, + "remoteLabel":3, + "remoteSid":"2001:db8:1:1::1", + "nexthops":[ + { + "ip":"2001::2", + "afi":"ipv6", + "scope":"global", + "metric":0, + "accessible":true, + "used":true + } + ], + "peer":{ + "peerId":"10.0.0.101", + "routerId":"10.0.0.101", + "type":"external" + } + } + ] + } +} diff --git a/tests/topotests/bgp_prefix_sid2/r1/vpnv6_rib_entry2.json b/tests/topotests/bgp_prefix_sid2/r1/vpnv6_rib_entry2.json new file mode 100644 index 0000000000..c9ad8714c1 --- /dev/null +++ b/tests/topotests/bgp_prefix_sid2/r1/vpnv6_rib_entry2.json @@ -0,0 +1,50 @@ +{ + "2:10":{ + "prefix":"2001:2::\/64", + "advertisedTo":{ + "10.0.0.101":{ + } + }, + "paths":[ + { + "aspath":{ + "string":"2", + "segments":[ + { + "type":"as-sequence", + "list":[ + 2 + ] + } + ], + "length":1 + }, + "origin":"IGP", + "valid":true, + "bestpath":{ + "overall":true + }, + "extendedCommunity":{ + "string":"RT:2:10" + }, + "remoteLabel":3, + "remoteSid":"2001:db8:1:1::1", + "nexthops":[ + { + "ip":"2001::2", + "afi":"ipv6", + "scope":"global", + "metric":0, + "accessible":true, + "used":true + } + ], + "peer":{ + "peerId":"10.0.0.101", + "routerId":"10.0.0.101", + "type":"external" + } + } + ] + } +} diff --git a/tests/topotests/bgp_prefix_sid2/r1/zebra.conf b/tests/topotests/bgp_prefix_sid2/r1/zebra.conf new file mode 100644 index 0000000000..0cd26052f2 --- /dev/null +++ b/tests/topotests/bgp_prefix_sid2/r1/zebra.conf @@ -0,0 +1,7 @@ +hostname r1 +! +interface r1-eth0 + ip address 10.0.0.1/24 + no shutdown +! +line vty diff --git a/tests/topotests/bgp_prefix_sid2/test_bgp_prefix_sid2.py b/tests/topotests/bgp_prefix_sid2/test_bgp_prefix_sid2.py new file mode 100755 index 0000000000..25362530d4 --- /dev/null +++ b/tests/topotests/bgp_prefix_sid2/test_bgp_prefix_sid2.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python + +# +# test_bgp_prefix_sid2.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2020 by LINE Corporation +# Copyright (c) 2020 by Hiroki Shirokura +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +test_bgp_prefix_sid2.py: Test BGP topology with EBGP on prefix-sid +""" + +import json +import os +import sys +import functools +import pytest + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger +from mininet.topo import Topo + + +class TemplateTopo(Topo): + def build(self, **_opts): + tgen = get_topogen(self) + router = tgen.add_router("r1") + switch = tgen.add_switch("s1") + switch.add_link(router) + + switch = tgen.gears["s1"] + peer1 = tgen.add_exabgp_peer( + "peer1", ip="10.0.0.101", defaultRoute="via 10.0.0.1" + ) + switch.add_link(peer1) + + +def setup_module(module): + tgen = Topogen(TemplateTopo, module.__name__) + tgen.start_topology() + + router = tgen.gears["r1"] + router.load_config( + TopoRouter.RD_ZEBRA, + os.path.join(CWD, "{}/zebra.conf".format("r1")) + ) + router.load_config( + TopoRouter.RD_BGP, + os.path.join(CWD, "{}/bgpd.conf".format("r1")) + ) + router.start() + + logger.info("starting exaBGP") + peer_list = tgen.exabgp_peers() + for pname, peer in peer_list.items(): + logger.info("starting exaBGP on {}".format(pname)) + peer_dir = os.path.join(CWD, pname) + env_file = os.path.join(CWD, pname, "exabgp.env") + logger.info("Running ExaBGP peer on {}".format(pname)) + peer.start(peer_dir, env_file) + logger.info(pname) + + +def teardown_module(module): + tgen = get_topogen() + tgen.stop_topology() + + +def open_json_file(filename): + try: + with open(filename, "r") as f: + return json.load(f) + except IOError: + assert False, "Could not read file {}".format(filename) + + +def test_r1_rib(): + def _check(name, cmd, expected_file): + logger.info("polling") + tgen = get_topogen() + router = tgen.gears[name] + output = json.loads(router.vtysh_cmd(cmd)) + expected = open_json_file("{}/{}".format(CWD, expected_file)) + return topotest.json_cmp(output, expected) + + def check(name, cmd, expected_file): + logger.info("[+] check {} \"{}\" {}".format(name, cmd, expected_file)) + tgen = get_topogen() + func = functools.partial(_check, name, cmd, expected_file) + success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) + assert result is None, 'Failed' + + check("r1", "show bgp ipv6 vpn 2001:1::/64 json", "r1/vpnv6_rib_entry1.json") + check("r1", "show bgp ipv6 vpn 2001:2::/64 json", "r1/vpnv6_rib_entry2.json") + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + ret = pytest.main(args) + sys.exit(ret) From bfaab44d1e6ffa23cfc983ccd72d98e6082e38df Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Sat, 19 Dec 2020 08:47:11 +0900 Subject: [PATCH 22/66] *: new cli-nodes for BGP SRv6 VPNv4 (step4) This commit add just CLI-nodes for MP-BGP VPN configuration with SRv6 backend rather than MPLS. Actual configuration cli will be implemented after this commit. Example Configuration follow. This cli design is based on Cisco IOS-XR but actual cli tree design is defferent between FRR and Cisco. It's just based on cisco. ref: https://www.cisco.com/c/en/us/td/docs/routers/asr9000/software/asr9k-r6-6/segment-routing/configuration/guide/b-segment-routing-cg-asr9000-66x/b-segment-routing-cg-asr9000-66x_chapter_011.html#concept_hwj_trf_dlb router bgp 1 bgp router-id 1.1.1.1 ! segment-routing srv6 ! new cli-node locator LOC1 ! this cli will be added after this commit. ! ! Signed-off-by: Hiroki Shirokura --- bgpd/bgp_vty.c | 23 +++++++++++++++++++++++ lib/command.h | 1 + vtysh/vtysh.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index b2769e21d9..b8dad338b2 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -9858,6 +9858,17 @@ DEFUN_NOSH (address_family_evpn, return CMD_SUCCESS; } +DEFUN_NOSH (bgp_segment_routing_srv6, + bgp_segment_routing_srv6_cmd, + "segment-routing srv6", + "Segment-Routing configuration\n" + "Segment-Routing SRv6 configuration\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + vty->node = BGP_SRV6_NODE; + return CMD_SUCCESS; +} + DEFUN_NOSH (exit_address_family, exit_address_family_cmd, "exit-address-family", @@ -18020,6 +18031,13 @@ static struct cmd_node bgp_flowspecv6_node = { .prompt = "%s(config-router-af-vpnv6)# ", }; +static struct cmd_node bgp_srv6_node = { + .name = "bgp srv6", + .node = BGP_SRV6_NODE, + .parent_node = BGP_NODE, + .prompt = "%s(config-router-srv6)# ", +}; + static void community_list_vty(void); static void bgp_ac_neighbor(vector comps, struct cmd_token *token) @@ -18094,6 +18112,7 @@ void bgp_vty_init(void) install_node(&bgp_evpn_vni_node); install_node(&bgp_flowspecv4_node); install_node(&bgp_flowspecv6_node); + install_node(&bgp_srv6_node); /* Install default VTY commands to new nodes. */ install_default(BGP_NODE); @@ -18109,6 +18128,7 @@ void bgp_vty_init(void) install_default(BGP_FLOWSPECV6_NODE); install_default(BGP_EVPN_NODE); install_default(BGP_EVPN_VNI_NODE); + install_default(BGP_SRV6_NODE); /* "bgp local-mac" hidden commands. */ install_element(CONFIG_NODE, &bgp_local_mac_cmd); @@ -19437,6 +19457,9 @@ void bgp_vty_init(void) /* tcp-mss command */ install_element(BGP_NODE, &neighbor_tcp_mss_cmd); install_element(BGP_NODE, &no_neighbor_tcp_mss_cmd); + + /* srv6 commands */ + install_element(BGP_NODE, &bgp_segment_routing_srv6_cmd); } #include "memory.h" diff --git a/lib/command.h b/lib/command.h index 846434066d..c36797d125 100644 --- a/lib/command.h +++ b/lib/command.h @@ -120,6 +120,7 @@ enum node_type { BGP_VNC_L2_GROUP_NODE, /* BGP VNC L2 group */ RFP_DEFAULTS_NODE, /* RFP defaults node */ BGP_EVPN_NODE, /* BGP EVPN node. */ + BGP_SRV6_NODE, /* BGP SRv6 node. */ OSPF_NODE, /* OSPF protocol mode */ OSPF6_NODE, /* OSPF protocol for IPv6 mode */ LDP_NODE, /* LDP protocol mode */ diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index e55a8cfb1a..e8184c2dc8 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -1507,6 +1507,13 @@ static struct cmd_node bmp_node = { .parent_node = BGP_NODE, .prompt = "%s(config-bgp-bmp)# " }; + +static struct cmd_node bgp_srv6_node = { + .name = "bgp srv6", + .node = BGP_SRV6_NODE, + .parent_node = BGP_NODE, + .prompt = "%s(config-router-srv6)# ", +}; #endif /* HAVE_BGPD */ #ifdef HAVE_OSPFD @@ -1862,6 +1869,39 @@ DEFUNSH(VTYSH_BGPD, return CMD_SUCCESS; } +DEFUNSH(VTYSH_BGPD, + bgp_srv6, + bgp_srv6_cmd, + "segment-routing srv6", + "Segment-Routing configuration\n" + "Segment-Routing SRv6 configuration\n") +{ + vty->node = BGP_SRV6_NODE; + return CMD_SUCCESS; +} + +DEFUNSH(VTYSH_BGPD, + exit_bgp_srv6, + exit_bgp_srv6_cmd, + "exit", + "exit Segment-Routing SRv6 configuration\n") +{ + if (vty->node == BGP_SRV6_NODE) + vty->node = BGP_NODE; + return CMD_SUCCESS; +} + +DEFUNSH(VTYSH_BGPD, + quit_bgp_srv6, + quit_bgp_srv6_cmd, + "quit", + "quit Segment-Routing SRv6 configuration\n") +{ + if (vty->node == BGP_SRV6_NODE) + vty->node = BGP_NODE; + return CMD_SUCCESS; +} + DEFUNSH(VTYSH_BGPD, address_family_evpn, address_family_evpn_cmd, "address-family ", "Enter Address Family command mode\n" @@ -4201,6 +4241,12 @@ void vtysh_init_vty(void) install_element(BMP_NODE, &bmp_exit_cmd); install_element(BMP_NODE, &bmp_quit_cmd); install_element(BMP_NODE, &vtysh_end_all_cmd); + + install_node(&bgp_srv6_node); + install_element(BGP_NODE, &bgp_srv6_cmd); + install_element(BGP_SRV6_NODE, &exit_bgp_srv6_cmd); + install_element(BGP_SRV6_NODE, &quit_bgp_srv6_cmd); + install_element(BGP_SRV6_NODE, &vtysh_end_all_cmd); #endif /* HAVE_BGPD */ /* ripd */ From 618538f8ab65eeee12323a460336dffb08cd36e8 Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Sat, 19 Dec 2020 09:28:38 +0900 Subject: [PATCH 23/66] lib: add usual func to install SRv6 localsid (step4) This commit add usuful function to configure SRv6 localsid which is represented with seg6local lwt route. Now, it can support only NEXTHOP_TYPE_IFINDEX route. Actual configurationof SRv6 localsid is performed with ZEBRA_ROUTE_ADD. So this is just a wrapper function for route-install. Signed-off-by: Hiroki Shirokura --- lib/zclient.c | 39 +++++++++++++++++++++++++++++++++++++++ lib/zclient.h | 5 +++++ 2 files changed, 44 insertions(+) diff --git a/lib/zclient.c b/lib/zclient.c index 7eb365c305..1acf7f20d5 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -436,6 +436,45 @@ enum zclient_send_status zclient_send_vrf_label(struct zclient *zclient, return zclient_send_message(zclient); } +enum zclient_send_status zclient_send_localsid(struct zclient *zclient, + const struct in6_addr *sid, ifindex_t oif, + enum seg6local_action_t action, + const struct seg6local_context *context) +{ + struct prefix_ipv6 p; + struct zapi_route api; + struct nexthop nh; + + memset(&p, 0, sizeof(p)); + p.family = AF_INET6; + p.prefixlen = 128; + p.prefix = *sid; + + memset(&api, 0, sizeof(api)); + api.vrf_id = VRF_DEFAULT; + api.type = ZEBRA_ROUTE_BGP; + api.instance = 0; + api.safi = SAFI_UNICAST; + memcpy(&api.prefix, &p, sizeof(p)); + + if (action == ZEBRA_SEG6_LOCAL_ACTION_UNSPEC) + return zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api); + + SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION); + SET_FLAG(api.flags, ZEBRA_FLAG_SEG6LOCAL_ROUTE); + SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); + + memset(&nh, 0, sizeof(nh)); + nh.type = NEXTHOP_TYPE_IFINDEX; + nh.ifindex = oif; + nexthop_add_seg6local(&nh, action, context); + + zapi_nexthop_from_nexthop(&api.nexthops[0], &nh); + api.nexthop_num = 1; + + return zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api); +} + /* Send register requests to zebra daemon for the information in a VRF. */ void zclient_send_reg_requests(struct zclient *zclient, vrf_id_t vrf_id) { diff --git a/lib/zclient.h b/lib/zclient.h index 95f3775d5b..e06079673a 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -933,6 +933,11 @@ extern enum zclient_send_status zclient_send_vrf_label(struct zclient *zclient, vrf_id_t vrf_id, afi_t afi, mpls_label_t label, enum lsp_types_t ltype); +extern enum zclient_send_status +zclient_send_localsid(struct zclient *zclient, const struct in6_addr *sid, + ifindex_t oif, enum seg6local_action_t action, + const struct seg6local_context *context); + extern void zclient_send_reg_requests(struct zclient *, vrf_id_t); extern void zclient_send_dereg_requests(struct zclient *, vrf_id_t); extern enum zclient_send_status From bc65dfafbcea33eeb7497cab0477b5bdc6458d3b Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Sat, 19 Dec 2020 10:42:44 +0900 Subject: [PATCH 24/66] bgpd: implement nb-func to im/ex-port vrf-rib to vpn-rib (step4) This commit implement the contents of following 2 functions. - bgp_global_afi_safis_afi_safi_ipv6_unicast_vpn_config_import_vpn_modify - bgp_global_afi_safis_afi_safi_ipv6_unicast_vpn_config_export_vpn_modify This implementation is based on already implemented function for ipv4. Signed-off-by: Hiroki Shirokura --- bgpd/bgp_nb_config.c | 45 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_nb_config.c b/bgpd/bgp_nb_config.c index 3b7d95c0f3..e83b9e20a8 100644 --- a/bgpd/bgp_nb_config.c +++ b/bgpd/bgp_nb_config.c @@ -11442,12 +11442,33 @@ int bgp_global_afi_safis_afi_safi_ipv6_unicast_vpn_config_nexthop_destroy( int bgp_global_afi_safis_afi_safi_ipv6_unicast_vpn_config_import_vpn_modify( struct nb_cb_modify_args *args) { + bool is_enable = false; + struct bgp *bgp; + switch (args->event) { case NB_EV_VALIDATE: + bgp = nb_running_get_entry(args->dnode, NULL, false); + if (!bgp) + return NB_OK; + + if (BGP_INSTANCE_TYPE_VRF != bgp->inst_type + && BGP_INSTANCE_TYPE_DEFAULT != bgp->inst_type) { + snprintf( + args->errmsg, args->errmsg_len, + "import|export vpn valid only for bgp vrf or default instance"); + return NB_ERR_VALIDATION; + } + + break; case NB_EV_PREPARE: case NB_EV_ABORT: + return NB_OK; case NB_EV_APPLY: - /* TODO: implement me. */ + if (yang_dnode_get_bool(args->dnode, NULL)) + is_enable = true; + + return bgp_global_afi_safi_ip_unicast_vpn_config_import_export_vpn_modify( + args, "import", is_enable); break; } @@ -11461,12 +11482,32 @@ int bgp_global_afi_safis_afi_safi_ipv6_unicast_vpn_config_import_vpn_modify( int bgp_global_afi_safis_afi_safi_ipv6_unicast_vpn_config_export_vpn_modify( struct nb_cb_modify_args *args) { + bool is_enable = false; + struct bgp *bgp; + switch (args->event) { case NB_EV_VALIDATE: + bgp = nb_running_get_entry(args->dnode, NULL, false); + if (!bgp) + return NB_OK; + + if (BGP_INSTANCE_TYPE_VRF != bgp->inst_type + && BGP_INSTANCE_TYPE_DEFAULT != bgp->inst_type) { + snprintf( + args->errmsg, args->errmsg_len, + "import|export vpn valid only for bgp vrf or default instance"); + return NB_ERR_VALIDATION; + } + break; case NB_EV_PREPARE: case NB_EV_ABORT: + return NB_OK; case NB_EV_APPLY: - /* TODO: implement me. */ + if (yang_dnode_get_bool(args->dnode, NULL)) + is_enable = true; + + return bgp_global_afi_safi_ip_unicast_vpn_config_import_export_vpn_modify( + args, "export", is_enable); break; } From 92a9e6f296a4b3a2d23db14b22b62ebf6cf007cf Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Sat, 19 Dec 2020 17:45:26 +0900 Subject: [PATCH 25/66] bgpd: add srv6 vpn base code (step4) This commit add base-lines for BGP SRv6 VPN support. srv6_locator_chunks property of struct bgp is used to store BGPd's own SRv6 locator chunk getting with ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK api. And srv6_functions is used to store BGP's srv6 localsids. It's mainly used when new SID reservation from locator chunks. Signed-off-by: Hiroki Shirokura base --- bgpd/bgp_memory.c | 2 ++ bgpd/bgp_memory.h | 2 ++ bgpd/bgp_vty.c | 1 + bgpd/bgpd.c | 16 ++++++++++++++++ bgpd/bgpd.h | 20 ++++++++++++++++++++ 5 files changed, 41 insertions(+) diff --git a/bgpd/bgp_memory.c b/bgpd/bgp_memory.c index fc508496cc..eb85936f0f 100644 --- a/bgpd/bgp_memory.c +++ b/bgpd/bgp_memory.c @@ -142,3 +142,5 @@ DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_INDEX, "BGP flowspec index"); DEFINE_MTYPE(BGPD, BGP_SRV6_L3VPN, "BGP prefix-sid srv6 l3vpn servcie"); DEFINE_MTYPE(BGPD, BGP_SRV6_VPN, "BGP prefix-sid srv6 vpn service"); +DEFINE_MTYPE(BGPD, BGP_SRV6_SID, "BGP srv6 segment-id"); +DEFINE_MTYPE(BGPD, BGP_SRV6_FUNCTION, "BGP srv6 function"); diff --git a/bgpd/bgp_memory.h b/bgpd/bgp_memory.h index 4080248038..c5ba371498 100644 --- a/bgpd/bgp_memory.h +++ b/bgpd/bgp_memory.h @@ -139,5 +139,7 @@ DECLARE_MTYPE(BGP_FLOWSPEC_INDEX); DECLARE_MTYPE(BGP_SRV6_L3VPN); DECLARE_MTYPE(BGP_SRV6_VPN); +DECLARE_MTYPE(BGP_SRV6_SID); +DECLARE_MTYPE(BGP_SRV6_FUNCTION); #endif /* _QUAGGA_BGP_MEMORY_H */ diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index b8dad338b2..8067c33884 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -9865,6 +9865,7 @@ DEFUN_NOSH (bgp_segment_routing_srv6, "Segment-Routing SRv6 configuration\n") { VTY_DECLVAR_CONTEXT(bgp, bgp); + bgp->srv6_enabled = true; vty->node = BGP_SRV6_NODE; return CMD_SUCCESS; } diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 6f2f2c9f34..1b78be354b 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1327,6 +1327,20 @@ int bgp_peer_gr_init(struct peer *peer) return BGP_GR_SUCCESS; } +static void bgp_srv6_init(struct bgp *bgp) +{ + bgp->srv6_enabled = false; + memset(bgp->srv6_locator_name, 0, sizeof(bgp->srv6_locator_name)); + bgp->srv6_locator_chunks = list_new(); + bgp->srv6_functions = list_new(); +} + +static void bgp_srv6_cleanup(struct bgp *bgp) +{ + list_delete(&bgp->srv6_locator_chunks); + list_delete(&bgp->srv6_functions); +} + /* Allocate new peer object, implicitely locked. */ struct peer *peer_new(struct bgp *bgp) { @@ -3238,6 +3252,7 @@ static struct bgp *bgp_create(as_t *as, const char *name, bgp_evpn_init(bgp); bgp_evpn_vrf_es_init(bgp); bgp_pbr_init(bgp); + bgp_srv6_init(bgp); /*initilize global GR FSM */ bgp_global_gr_init(bgp); @@ -3754,6 +3769,7 @@ void bgp_free(struct bgp *bgp) bgp_evpn_cleanup(bgp); bgp_pbr_cleanup(bgp); + bgp_srv6_cleanup(bgp); XFREE(MTYPE_BGP_EVPN_INFO, bgp->evpn_info); for (afi = AFI_IP; afi < AFI_MAX; afi++) { diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 4a17b72b7f..ffac20c218 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -29,6 +29,7 @@ #include "lib/json.h" #include "vrf.h" #include "vty.h" +#include "srv6.h" #include "iana_afi.h" /* For union sockunion. */ @@ -222,6 +223,7 @@ struct vpn_policy { #define BGP_VPN_POLICY_TOVPN_LABEL_AUTO (1 << 0) #define BGP_VPN_POLICY_TOVPN_RD_SET (1 << 1) #define BGP_VPN_POLICY_TOVPN_NEXTHOP_SET (1 << 2) +#define BGP_VPN_POLICY_TOVPN_SID_AUTO (1 << 3) /* * If we are importing another vrf into us keep a list of @@ -234,6 +236,13 @@ struct vpn_policy { * vrf names that we are being exported to. */ struct list *export_vrf; + + /* + * Segment-Routing SRv6 Mode + */ + uint32_t tovpn_sid_index; /* unset => set to 0 */ + struct in6_addr *tovpn_sid; + struct in6_addr *tovpn_zebra_vrf_sid_last_sent; }; /* @@ -322,6 +331,11 @@ struct bgp_snmp_stats { uint32_t routes_deleted; }; +struct bgp_srv6_function { + struct in6_addr sid; + char locator_name[SRV6_LOCNAME_SIZE]; +}; + /* BGP instance structure. */ struct bgp { /* AS number of this BGP instance. */ @@ -718,6 +732,12 @@ struct bgp { /* BGP route flap dampening configuration */ struct bgp_damp_config damp[AFI_MAX][SAFI_MAX]; + /* BGP VPN SRv6 backend */ + bool srv6_enabled; + char srv6_locator_name[SRV6_LOCNAME_SIZE]; + struct list *srv6_locator_chunks; + struct list *srv6_functions; + QOBJ_FIELDS; }; DECLARE_QOBJ_TYPE(bgp); From a0281b2eab10a2053cd4f143c02bfd8cc8a12f24 Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Sat, 19 Dec 2020 10:50:18 +0900 Subject: [PATCH 26/66] bgpd: cli for srv6-locator assignment (step4) This commit add command to speficy SRv6 locator for BGP SRv6-VPN. CLI example is follow. CLI block of "segment-routing" is already implemented by previous commits and it's managed by zebra. Zebra manage just the ownership of locator's prefix. Zlient can request to get srv6-locator's prefix chunk using srv6_manager_get_locator_chunk() which is usuful func to execute ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK api. This request is wokring as async, And zebra calls same api to Zclients when zebra allocate locator prefix chunk. And then, finally zclient(bgpd) catch the information via process_srv6_lcoator_chunk callback function. router bgp 1 segment-routing srv6 locator loc1 ! ! segment-routing srv6 locators locator loc1 prefix 2001:db8:1:1::/64 ! ! ! ! [POINT_OF_REVIEW] In current implementation, user can just configure srv6 locator but user can't de-configure srv6 locator. Signed-off-by: Hiroki Shirokura --- bgpd/bgp_vty.c | 32 ++++++++++++++++++++++++++ bgpd/bgp_zebra.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++ bgpd/bgp_zebra.h | 1 + 3 files changed, 93 insertions(+) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 8067c33884..a236d4e30c 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -9870,6 +9870,29 @@ DEFUN_NOSH (bgp_segment_routing_srv6, return CMD_SUCCESS; } +DEFPY (bgp_srv6_locator, + bgp_srv6_locator_cmd, + "locator NAME$name", + "Specify SRv6 locator\n" + "Specify SRv6 locator\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + + if (strlen(bgp->srv6_locator_name) > 0 + && strcmp(name, bgp->srv6_locator_name) != 0) { + vty_out(vty, "srv6 locator is already configured\n"); + return CMD_WARNING_CONFIG_FAILED; + } else + snprintf(bgp->srv6_locator_name, + sizeof(bgp->srv6_locator_name), "%s", name); + + int ret = bgp_zebra_srv6_manager_get_locator_chunk(name); + if (ret < 0) + return CMD_WARNING_CONFIG_FAILED; + + return CMD_SUCCESS; +} + DEFUN_NOSH (exit_address_family, exit_address_family_cmd, "exit-address-family", @@ -17887,6 +17910,14 @@ int bgp_config_write(struct vty *vty) if (CHECK_FLAG(bgp->flags, BGP_FLAG_SHUTDOWN)) vty_out(vty, " bgp shutdown\n"); + if (bgp->srv6_enabled) { + vty_frame(vty, " !\n segment-routing srv6\n"); + if (bgp->srv6_locator_name) + vty_out(vty, " locator %s\n", + bgp->srv6_locator_name); + } + + /* IPv4 unicast configuration. */ bgp_config_write_family(vty, bgp, AFI_IP, SAFI_UNICAST); @@ -19461,6 +19492,7 @@ void bgp_vty_init(void) /* srv6 commands */ install_element(BGP_NODE, &bgp_segment_routing_srv6_cmd); + install_element(BGP_SRV6_NODE, &bgp_srv6_locator_cmd); } #include "memory.h" diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 97f781b2bf..c66348691b 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -2976,6 +2976,60 @@ static int bgp_ifp_create(struct interface *ifp) return 0; } +static void bgp_zebra_process_srv6_locator_chunk(ZAPI_CALLBACK_ARGS) +{ + struct stream *s = NULL; + uint8_t proto; + uint16_t instance; + uint16_t len; + char name[256] = {0}; + struct prefix_ipv6 *chunk = NULL; + chunk = prefix_ipv6_new(); + + s = zclient->ibuf; + STREAM_GETC(s, proto); + STREAM_GETW(s, instance); + + STREAM_GETW(s, len); + STREAM_GET(name, s, len); + + STREAM_GETW(s, chunk->prefixlen); + STREAM_GET(&chunk->prefix, s, 16); + + if (zclient->redist_default != proto) { + zlog_err("Got SRv6 Manager msg with wrong proto %u", proto); + return; + } + if (zclient->instance != instance) { + zlog_err("Got SRv6 Manager msg with wrong instance %u", proto); + return; + } + + struct bgp *bgp = bgp_get_default(); + if (strcmp(bgp->srv6_locator_name, name) != 0) { + zlog_info("name unmatch %s:%s", + bgp->srv6_locator_name, name); + return; + } + + struct listnode *node; + struct prefix_ipv6 *c; + for (ALL_LIST_ELEMENTS_RO(bgp->srv6_locator_chunks, node, c)) { + if (!prefix_cmp(c, chunk)) + return; + } + + listnode_add(bgp->srv6_locator_chunks, chunk); + vpn_leak_postchange_all(); + return; + +stream_failure: + free(chunk); + + zlog_err("%s: can't get locator_chunk!!", __func__); + return; +} + void bgp_zebra_init(struct thread_master *master, unsigned short instance) { zclient_num_connects = 0; @@ -3018,6 +3072,7 @@ void bgp_zebra_init(struct thread_master *master, unsigned short instance) zclient->iptable_notify_owner = iptable_notify_owner; zclient->route_notify_owner = bgp_zebra_route_notify_owner; zclient->instance = instance; + zclient->process_srv6_locator_chunk = bgp_zebra_process_srv6_locator_chunk; } void bgp_zebra_destroy(void) @@ -3415,3 +3470,8 @@ int bgp_zebra_stale_timer_update(struct bgp *bgp) zlog_debug("send capabilty success"); return BGP_GR_SUCCESS; } + +int bgp_zebra_srv6_manager_get_locator_chunk(const char *name) +{ + return srv6_manager_get_locator_chunk(zclient, name); +} diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index 4b357c380a..02b6484943 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -113,4 +113,5 @@ extern void bgp_zebra_announce_default(struct bgp *bgp, struct nexthop *nh, 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_stale_timer_update(struct bgp *bgp); +extern int bgp_zebra_srv6_manager_get_locator_chunk(const char *name); #endif /* _QUAGGA_BGP_ZEBRA_H */ From b72c9e14756feba0af0ebff2159069c5b55224fc Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Sat, 19 Dec 2020 11:04:40 +0900 Subject: [PATCH 27/66] bgpd: cli for SRv6 SID alloc to redirect to vrf (step4) This commit add cil to configure BGP SRv6-VPN sid allocation. Almost mechanism are based on BGP MPLS-VPN. User can allocate and export sid with using following config. Then bgpd try to allocate new SID to redirect vpn to vrf using SRv6 localsid End.DT4/DT6. Currently linux kernel will regect End.DT4 route install due to no-implementation. (at-least today's FRR's ci kernel.) So now we only supports BGP SRv6-VPNv6. router bgp 1 segment-routing srv6 locator loc1 ! address-family ipv6 vpn exit-address-family ! router bgp 1 vrf vrf10 address-family ipv6 unicast sid vpn export 1 !!(option1)!! sid vpn export auto !!(option2)!! exit-address-family ! Signed-off-by: Hiroki Shirokura --- bgpd/bgp_main.c | 2 + bgpd/bgp_mplsvpn.c | 197 +++++++++++++++++++++++++++++++++++++++++++++ bgpd/bgp_mplsvpn.h | 12 +++ bgpd/bgp_vty.c | 73 +++++++++++++++++ 4 files changed, 284 insertions(+) diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index d545becded..6736671f37 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -317,6 +317,8 @@ static int bgp_vrf_enable(struct vrf *vrf) bgp_instance_up(bgp); vpn_leak_zebra_vrf_label_update(bgp, AFI_IP); vpn_leak_zebra_vrf_label_update(bgp, AFI_IP6); + vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP); + vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP6); vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, AFI_IP, bgp_get_default(), bgp); vpn_leak_postchange(BGP_VPN_POLICY_DIR_FROMVPN, AFI_IP, diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index eb68d84c06..c16edc20f5 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -47,6 +47,7 @@ #include "bgpd/bgp_nexthop.h" #include "bgpd/bgp_nht.h" #include "bgpd/bgp_evpn.h" +#include "bgpd/bgp_memory.h" #ifdef ENABLE_BGP_VNC #include "bgpd/rfapi/rfapi_backend.h" @@ -356,6 +357,85 @@ void vpn_leak_zebra_vrf_label_withdraw(struct bgp *bgp, afi_t afi) bgp->vpn_policy[afi].tovpn_zebra_vrf_label_last_sent = label; } +/* + * This function informs zebra of the srv6-function this vrf sets on routes + * leaked to VPN. Zebra should install this srv6-function in the kernel with + * an action of "End.DT4/6's IP FIB to route the PDU." + */ +void vpn_leak_zebra_vrf_sid_update(struct bgp *bgp, afi_t afi) +{ + int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL); + enum seg6local_action_t act; + struct seg6local_context ctx = {{0}}; + struct in6_addr *tovpn_sid = NULL; + struct in6_addr *tovpn_sid_ls = NULL; + struct vrf *vrf; + char buf[256] = {0}; + + if (bgp->vrf_id == VRF_UNKNOWN) { + if (debug) + zlog_debug("%s: vrf %s: afi %s: vrf_id not set, " + "can't set zebra vrf label", + __func__, bgp->name_pretty, afi2str(afi)); + return; + } + + tovpn_sid = bgp->vpn_policy[afi].tovpn_sid; + if (!tovpn_sid) { + if (debug) + zlog_debug("%s: vrf %s: afi %s: sid not set", __func__, + bgp->name_pretty, afi2str(afi)); + return; + } + + if (debug) { + inet_ntop(AF_INET6, tovpn_sid, buf, sizeof(buf)); + zlog_debug("%s: vrf %s: afi %s: setting sid %s for vrf id %d", + __func__, bgp->name_pretty, afi2str(afi), buf, + bgp->vrf_id); + } + + vrf = vrf_lookup_by_id(bgp->vrf_id); + if (!vrf) + return; + + ctx.table = vrf->data.l.table_id; + act = afi == AFI_IP ? ZEBRA_SEG6_LOCAL_ACTION_END_DT4 + : ZEBRA_SEG6_LOCAL_ACTION_END_DT6; + zclient_send_localsid(zclient, tovpn_sid, bgp->vrf_id, act, &ctx); + + tovpn_sid_ls = XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr)); + *tovpn_sid_ls = *tovpn_sid; + bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent = tovpn_sid_ls; +} + +/* + * If zebra tells us vrf has become unconfigured, tell zebra not to + * use this srv6-function to forward to the vrf anymore + */ +void vpn_leak_zebra_vrf_sid_withdraw(struct bgp *bgp, afi_t afi) +{ + int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL); + + if (bgp->vrf_id == VRF_UNKNOWN) { + if (debug) + zlog_debug("%s: vrf %s: afi %s: vrf_id not set, " + "can't set zebra vrf label", + __func__, bgp->name_pretty, afi2str(afi)); + return; + } + + if (debug) + zlog_debug("%s: deleting sid for vrf %s afi (id=%d)", __func__, + bgp->name_pretty, bgp->vrf_id); + + zclient_send_localsid(zclient, + bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent, + bgp->vrf_id, ZEBRA_SEG6_LOCAL_ACTION_UNSPEC, NULL); + XFREE(MTYPE_BGP_SRV6_SID, + bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent); +} + int vpn_leak_label_callback( mpls_label_t label, void *labelid, @@ -417,6 +497,123 @@ int vpn_leak_label_callback( return 0; } +static void sid_register(struct bgp *bgp, const struct in6_addr *sid, + const char *locator_name) +{ + struct bgp_srv6_function *func; + func = XCALLOC(MTYPE_BGP_SRV6_FUNCTION, + sizeof(struct bgp_srv6_function)); + func->sid = *sid; + snprintf(func->locator_name, sizeof(func->locator_name), + "%s", locator_name); + listnode_add(bgp->srv6_functions, func); +} + +static bool sid_exist(struct bgp *bgp, const struct in6_addr *sid) +{ + struct listnode *node; + struct bgp_srv6_function *func; + for (ALL_LIST_ELEMENTS_RO(bgp->srv6_functions, node, func)) + if (sid_same(&func->sid, sid)) + return true; + return false; +} + +/* if index != 0: try to allocate as index-mode + * else: try to allocate as auto-mode */ +static bool alloc_new_sid(struct bgp *bgp, uint32_t index, + struct in6_addr *sid) +{ + struct listnode *node; + struct prefix_ipv6 *chunk; + struct in6_addr sid_buf; + bool alloced = false; + + if (!bgp || !sid) + return false; + + for (ALL_LIST_ELEMENTS_RO(bgp->srv6_locator_chunks, node, chunk)) { + sid_buf = chunk->prefix; + if (index != 0) { + sid_buf.s6_addr[15] = index; + if (sid_exist(bgp, &sid_buf)) + return false; + alloced = true; + break; + } else { + for (size_t i=1; i<255; i++) { + sid_buf.s6_addr16[7] = i; + if (sid_exist(bgp, &sid_buf)) + continue; + alloced = true; + break; + } + } + } + + if (!alloced) + return false; + + sid_register(bgp, &sid_buf, bgp->srv6_locator_name); + *sid = sid_buf; + return true; +} + +void ensure_vrf_tovpn_sid(struct bgp *bgp_vpn, struct bgp *bgp_vrf, afi_t afi) +{ + int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF); + bool alloced = false; + char buf[256]; + struct in6_addr *sid; + uint32_t tovpn_sid_index = 0; + bool tovpn_sid_auto = false; + + if (debug) + zlog_debug("%s: try to allocate new SID for vrf %s: afi %s", + __func__, bgp_vrf->name_pretty, afi2str(afi)); + + /* skip when tovpn sid is already allocated on vrf instance */ + if (bgp_vrf->vpn_policy[afi].tovpn_sid) + return; + + /* skip when bgp vpn instance ins't allocated + * or srv6 locator chunk isn't allocated */ + if (!bgp_vpn || !bgp_vpn->srv6_locator_chunks || !bgp_vrf) + return; + + tovpn_sid_index = bgp_vrf->vpn_policy[afi].tovpn_sid_index; + tovpn_sid_auto = CHECK_FLAG(bgp_vrf->vpn_policy[afi].flags, + BGP_VPN_POLICY_TOVPN_SID_AUTO); + + /* skip when VPN isn't configured on vrf-instance */ + if (tovpn_sid_index == 0 && !tovpn_sid_auto) + return; + + /* check invalid case both configured index and auto */ + if (tovpn_sid_index != 0 && tovpn_sid_index) { + zlog_err("%s: index-mode and auto-mode both selected. ignored.", + __func__); + return; + } + + sid = XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr)); + alloced = alloc_new_sid(bgp_vpn, tovpn_sid_index, sid); + if (!alloced) { + zlog_debug("%s: not allocated new sid for vrf %s: afi %s", + __func__, bgp_vrf->name_pretty, afi2str(afi)); + return; + } + + if (debug) { + inet_ntop(AF_INET6, sid, buf, sizeof(buf)); + zlog_debug("%s: new sid %s allocated for vrf %s: afi %s", + __func__, buf, bgp_vrf->name_pretty, + afi2str(afi)); + } + bgp_vrf->vpn_policy[afi].tovpn_sid = sid; + return; +} + static bool ecom_intersect(struct ecommunity *e1, struct ecommunity *e2) { uint32_t i, j; diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h index 91a073d5d7..172372bdf0 100644 --- a/bgpd/bgp_mplsvpn.h +++ b/bgpd/bgp_mplsvpn.h @@ -77,7 +77,10 @@ extern void vpn_leak_to_vrf_withdraw(struct bgp *bgp_vpn, extern void vpn_leak_zebra_vrf_label_update(struct bgp *bgp, afi_t afi); extern void vpn_leak_zebra_vrf_label_withdraw(struct bgp *bgp, afi_t afi); +extern void vpn_leak_zebra_vrf_sid_update(struct bgp *bgp, afi_t afi); +extern void vpn_leak_zebra_vrf_sid_withdraw(struct bgp *bgp, afi_t afi); extern int vpn_leak_label_callback(mpls_label_t label, void *lblid, bool alloc); +extern void ensure_vrf_tovpn_sid(struct bgp *vpn, struct bgp *vrf, afi_t afi); extern void vrf_import_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp, afi_t afi, safi_t safi); void vrf_unimport_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp, @@ -237,6 +240,15 @@ static inline void vpn_leak_postchange(vpn_policy_direction_t direction, vpn_leak_zebra_vrf_label_update(bgp_vrf, afi); } + if (!bgp_vrf->vpn_policy[afi].tovpn_sid) + ensure_vrf_tovpn_sid(bgp_vpn, bgp_vrf, afi); + + if (sid_diff(bgp_vrf->vpn_policy[afi].tovpn_sid, + bgp_vrf->vpn_policy[afi]. + tovpn_zebra_vrf_sid_last_sent)) { + vpn_leak_zebra_vrf_sid_update(bgp_vrf, afi); + } + vpn_leak_from_vrf_update_all(bgp_vpn, bgp_vrf, afi); } } diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index a236d4e30c..fb181eab3d 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -9232,6 +9232,77 @@ DEFPY (af_label_vpn_export, return CMD_SUCCESS; } +DEFPY (af_sid_vpn_export, + af_sid_vpn_export_cmd, + "[no] sid vpn export <(1-255)$sid_idx|auto$sid_auto>", + NO_STR + "sid value for VRF\n" + "Between current address-family and vpn\n" + "For routes leaked from current address-family to vpn\n" + "Sid allocation index\n" + "Automatically assign a label\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + afi_t afi; + int debug = 0; + int idx = 0; + bool yes = true; + + if (argv_find(argv, argc, "no", &idx)) + yes = false; + debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF) | + BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF)); + + afi = vpn_policy_getafi(vty, bgp, false); + if (afi == AFI_MAX) + return CMD_WARNING_CONFIG_FAILED; + + if (!yes) { + /* implement me */ + vty_out(vty, "It's not implemented"); + return CMD_WARNING_CONFIG_FAILED; + } + + /* skip when it's already configured */ + if ((sid_idx != 0 && bgp->vpn_policy[afi].tovpn_sid_index != 0) + || (sid_auto && CHECK_FLAG(bgp->vpn_policy[afi].flags, + BGP_VPN_POLICY_TOVPN_SID_AUTO))) + return CMD_SUCCESS; + + /* mode change between sid_idx and sid_auto isn't supported. + * user must negate sid vpn export when they want to change + * the mode */ + if ((sid_auto && bgp->vpn_policy[afi].tovpn_sid_index != 0) + || (sid_idx != 0 && CHECK_FLAG(bgp->vpn_policy[afi].flags, + BGP_VPN_POLICY_TOVPN_SID_AUTO))) { + vty_out(vty, "it's already configured as %s.\n", + sid_auto ? "auto-mode" : "idx-mode"); + return CMD_WARNING_CONFIG_FAILED; + } + + /* pre-change */ + vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, afi, + bgp_get_default(), bgp); + + if (sid_auto) { + /* SID allocation auto-mode */ + if (debug) + zlog_debug("%s: auto sid alloc.", __func__); + SET_FLAG(bgp->vpn_policy[afi].flags, + BGP_VPN_POLICY_TOVPN_SID_AUTO); + } else { + /* SID allocation index-mode */ + if (debug) + zlog_debug("%s: idx %ld sid alloc.", __func__, sid_idx); + bgp->vpn_policy[afi].tovpn_sid_index = sid_idx; + } + + /* post-change */ + vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, afi, + bgp_get_default(), bgp); + return CMD_SUCCESS; +} + ALIAS (af_label_vpn_export, af_no_label_vpn_export_cmd, "no label vpn export", @@ -19493,6 +19564,8 @@ void bgp_vty_init(void) /* srv6 commands */ install_element(BGP_NODE, &bgp_segment_routing_srv6_cmd); install_element(BGP_SRV6_NODE, &bgp_srv6_locator_cmd); + install_element(BGP_IPV4_NODE, &af_sid_vpn_export_cmd); + install_element(BGP_IPV6_NODE, &af_sid_vpn_export_cmd); } #include "memory.h" From ea372e81b057ea85eb9192e87c82b4002e7e32a5 Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Sat, 19 Dec 2020 10:14:08 +0900 Subject: [PATCH 28/66] bgpd: cli for checking srv6 information (step4) This commit add cli to check bgp's srv6 status which is srv6-locator name and its locator-chunks for bgpd. And this command also can be used to check tovpn_sid for each bgp instances. Signed-off-by: Hiroki Shirokura --- bgpd/bgp_vty.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index fb181eab3d..03c4e69591 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -9964,6 +9964,65 @@ DEFPY (bgp_srv6_locator, return CMD_SUCCESS; } +DEFPY (show_bgp_srv6, + show_bgp_srv6_cmd, + "show bgp segment-routing srv6", + SHOW_STR + BGP_STR + "BGP Segment Routing\n" + "BGP Segment Routing SRv6\n") +{ + struct bgp *bgp; + struct listnode *node; + struct prefix_ipv6 *chunk; + struct bgp_srv6_function *func; + struct in6_addr *tovpn4_sid; + struct in6_addr *tovpn6_sid; + char buf[256]; + char buf_tovpn4_sid[256]; + char buf_tovpn6_sid[256]; + + bgp = bgp_get_default(); + if (!bgp || !bgp->srv6_locator_name) + return CMD_SUCCESS; + + vty_out(vty, "locator_name: %s\n", bgp->srv6_locator_name); + vty_out(vty, "locator_chunks:\n"); + for (ALL_LIST_ELEMENTS_RO(bgp->srv6_locator_chunks, node, chunk)) { + prefix2str(chunk, buf, sizeof(buf)); + vty_out(vty, "- %s\n", buf); + } + + vty_out(vty, "functions:\n"); + for (ALL_LIST_ELEMENTS_RO(bgp->srv6_functions, node, func)) { + inet_ntop(AF_INET6, &func->sid, buf, sizeof(buf)); + vty_out(vty, "- sid: %s\n", buf); + vty_out(vty, " locator: %s\n", func->locator_name); + } + + vty_out(vty, "bgps:\n"); + for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp)) { + vty_out(vty, "- name: %s\n", + bgp->name ? bgp->name : "default"); + + tovpn4_sid = bgp->vpn_policy[AFI_IP].tovpn_sid; + tovpn6_sid = bgp->vpn_policy[AFI_IP6].tovpn_sid; + if (tovpn4_sid) + inet_ntop(AF_INET6, tovpn4_sid, buf_tovpn4_sid, + sizeof(buf_tovpn4_sid)); + if (tovpn6_sid) + inet_ntop(AF_INET6, tovpn6_sid, buf_tovpn6_sid, + sizeof(buf_tovpn6_sid)); + + vty_out(vty, " vpn_policy[AFI_IP].tovpn_sid: %s\n", + tovpn4_sid ? buf_tovpn4_sid : "none"); + vty_out(vty, " vpn_policy[AFI_IP6].tovpn_sid: %s\n", + tovpn6_sid ? buf_tovpn6_sid : "none"); + } + + return CMD_SUCCESS; +} + DEFUN_NOSH (exit_address_family, exit_address_family_cmd, "exit-address-family", @@ -19562,6 +19621,7 @@ void bgp_vty_init(void) install_element(BGP_NODE, &no_neighbor_tcp_mss_cmd); /* srv6 commands */ + install_element(VIEW_NODE, &show_bgp_srv6_cmd); install_element(BGP_NODE, &bgp_segment_routing_srv6_cmd); install_element(BGP_SRV6_NODE, &bgp_srv6_locator_cmd); install_element(BGP_IPV4_NODE, &af_sid_vpn_export_cmd); From dbcf19b88dda9e94e270bc4dcb70764320f9e0ce Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Sat, 19 Dec 2020 11:07:16 +0900 Subject: [PATCH 29/66] bgpd: advertising vpn-rib include SRv6-SID (step4) This commit make bgpd to support VPN SID advertisement as BGP Prefix-SID when route-leaking from BGP-vrf instance to BGP-vpn instance. Signed-off-by: Hiroki Shirokura --- bgpd/bgp_attr.c | 2 +- bgpd/bgp_mplsvpn.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index c20c435003..2f0751a5f0 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -4122,7 +4122,7 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, } /* SRv6 Service Information Attribute. */ - if (afi == AFI_IP && safi == SAFI_MPLS_VPN) { + if ((afi == AFI_IP || afi == AFI_IP6) && safi == SAFI_MPLS_VPN) { if (attr->srv6_l3vpn) { stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS); diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index c16edc20f5..2d0c9ec017 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -684,6 +684,33 @@ static void setlabels(struct bgp_path_info *bpi, extra->num_labels = num_labels; } +/* + * make encoded route SIDs match specified encoded sid set + */ +static void setsids(struct bgp_path_info *bpi, + struct in6_addr *sid, + uint32_t num_sids) +{ + uint32_t i; + struct bgp_path_info_extra *extra; + + if (num_sids) + assert(sid); + assert(num_sids <= BGP_MAX_SIDS); + + if (!num_sids) { + if (bpi->extra) + bpi->extra->num_sids = 0; + return; + } + + extra = bgp_path_info_extra_get(bpi); + for (i = 0; i < num_sids; i++) { + memcpy(&extra->sid[i], &sid[i], sizeof(struct in6_addr)); + } + extra->num_sids = num_sids; +} + /* * returns pointer to new bgp_path_info upon success */ @@ -700,6 +727,10 @@ leak_update(struct bgp *bgp, /* destination bgp instance */ struct bgp_path_info *bpi_ultimate; struct bgp_path_info *new; + uint32_t num_sids = 0; + if (new_attr->srv6_l3vpn || new_attr->srv6_vpn) + num_sids = 1; + if (debug) zlog_debug( "%s: entry: leak-to=%s, p=%pBD, type=%d, sub_type=%d", @@ -777,6 +808,16 @@ leak_update(struct bgp *bgp, /* destination bgp instance */ if (!labelssame) setlabels(bpi, label, num_labels); + /* + * rewrite sid + */ + if (num_sids) { + if (new_attr->srv6_l3vpn) + setsids(bpi, &new_attr->srv6_l3vpn->sid, num_sids); + else if (new_attr->srv6_vpn) + setsids(bpi, &new_attr->srv6_vpn->sid, num_sids); + } + if (nexthop_self_flag) bgp_path_info_set_flag(bn, bpi, BGP_PATH_ANNC_NH_SELF); @@ -839,6 +880,16 @@ leak_update(struct bgp *bgp, /* destination bgp instance */ bgp_path_info_extra_get(new); + /* + * rewrite sid + */ + if (num_sids) { + if (new_attr->srv6_l3vpn) + setsids(new, &new_attr->srv6_l3vpn->sid, num_sids); + else if (new_attr->srv6_vpn) + setsids(new, &new_attr->srv6_vpn->sid, num_sids); + } + if (num_labels) setlabels(new, label, num_labels); @@ -1095,6 +1146,17 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */ SET_FLAG(static_attr.flag, ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)); static_attr.originator_id = bgp_vpn->router_id; + /* Set SID for SRv6 VPN */ + if (!sid_zero(bgp_vrf->vpn_policy[afi].tovpn_sid)) { + static_attr.srv6_l3vpn = XCALLOC(MTYPE_BGP_SRV6_L3VPN, + sizeof(struct bgp_attr_srv6_l3vpn)* 100); + static_attr.srv6_l3vpn->sid_flags = 0x00; + static_attr.srv6_l3vpn->endpoint_behavior = 0xffff; + memcpy(&static_attr.srv6_l3vpn->sid, + bgp_vrf->vpn_policy[afi].tovpn_sid, + sizeof(static_attr.srv6_l3vpn->sid)); + } + new_attr = bgp_attr_intern( &static_attr); /* hashed refcounted everything */ From 53a4de82ec6548f3652f553787df71d25ad9448b Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Sat, 19 Dec 2020 07:53:03 +0900 Subject: [PATCH 30/66] bgpd: install vpn's transit route using H.Encaps (step4) This commit make bgpd to support install H.Encaps(seg6 mode segs) routes when VPN-prefix has Prefix-sid. Signed-off-by: Hiroki Shirokura --- bgpd/bgp_zebra.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index c66348691b..8349358da4 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1171,6 +1171,7 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, unsigned int valid_nh_count = 0; int has_valid_label = 0; bool allow_recursion = false; + int has_valid_sid = 0; uint8_t distance; struct peer *peer; struct bgp_path_info *mpinfo; @@ -1395,9 +1396,20 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, sizeof(struct ethaddr)); api_nh->weight = nh_weight; + if (mpinfo->extra + && !sid_zero(&mpinfo->extra->sid[0]) + && !CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) { + has_valid_sid = 1; + memcpy(&api_nh->seg6_segs, &mpinfo->extra->sid[0], + sizeof(api_nh->seg6_segs)); + } + valid_nh_count++; } + if (has_valid_sid && !(CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE))) + SET_FLAG(api.flags, ZEBRA_FLAG_SEG6_ROUTE); + is_add = (valid_nh_count || nhg_id) ? true : false; if (is_add && CHECK_FLAG(bm->flags, BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA)) { @@ -1453,6 +1465,8 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, char eth_buf[ETHER_ADDR_STRLEN + 7] = {'\0'}; char buf1[ETHER_ADDR_STRLEN]; char label_buf[20]; + char sid_buf[20]; + char segs_buf[256]; int i; zlog_debug( @@ -1495,15 +1509,22 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, && !CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) snprintf(label_buf, sizeof(label_buf), "label %u", api_nh->labels[0]); + if (has_valid_sid + && !CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) { + inet_ntop(AF_INET6, &api_nh->seg6_segs, + sid_buf, sizeof(sid_buf)); + snprintf(segs_buf, sizeof(segs_buf), "segs %s", + sid_buf); + } if (CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE) && !is_zero_mac(&api_nh->rmac)) snprintf(eth_buf, sizeof(eth_buf), " RMAC %s", prefix_mac2str(&api_nh->rmac, buf1, sizeof(buf1))); - zlog_debug(" nhop [%d]: %s if %u VRF %u wt %u %s %s", + zlog_debug(" nhop [%d]: %s if %u VRF %u wt %u %s %s %s", i + 1, nh_buf, api_nh->ifindex, api_nh->vrf_id, api_nh->weight, - label_buf, eth_buf); + label_buf, segs_buf, eth_buf); } int recursion_flag = 0; From 7c653fc53e2a1715229d0d5f114ec08c2bc74080 Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Sat, 19 Dec 2020 08:40:22 +0900 Subject: [PATCH 31/66] topotests: bgp_srv6l3vpn_to_bgp_vrf (step4) Signed-off-by: Hiroki Shirokura --- .../bgp_srv6l3vpn_to_bgp_vrf/ce1/bgpd.conf | 8 + .../ce1/ipv6_rib.json | 58 +++++ .../bgp_srv6l3vpn_to_bgp_vrf/ce1/zebra.conf | 14 ++ .../bgp_srv6l3vpn_to_bgp_vrf/ce2/bgpd.conf | 8 + .../ce2/ipv6_rib.json | 58 +++++ .../bgp_srv6l3vpn_to_bgp_vrf/ce2/zebra.conf | 14 ++ .../bgp_srv6l3vpn_to_bgp_vrf/ce3/bgpd.conf | 8 + .../ce3/ipv6_rib.json | 58 +++++ .../bgp_srv6l3vpn_to_bgp_vrf/ce3/zebra.conf | 14 ++ .../bgp_srv6l3vpn_to_bgp_vrf/ce4/bgpd.conf | 8 + .../ce4/ipv6_rib.json | 58 +++++ .../bgp_srv6l3vpn_to_bgp_vrf/ce4/zebra.conf | 14 ++ .../bgp_srv6l3vpn_to_bgp_vrf/ce5/bgpd.conf | 8 + .../ce5/ipv6_rib.json | 58 +++++ .../bgp_srv6l3vpn_to_bgp_vrf/ce5/zebra.conf | 14 ++ .../bgp_srv6l3vpn_to_bgp_vrf/ce6/bgpd.conf | 8 + .../ce6/ipv6_rib.json | 58 +++++ .../bgp_srv6l3vpn_to_bgp_vrf/ce6/zebra.conf | 14 ++ .../bgp_srv6l3vpn_to_bgp_vrf/r1/bgpd.conf | 64 ++++++ .../r1/vpnv6_rib.json | 170 +++++++++++++++ .../r1/vrf10_rib.json | 89 ++++++++ .../r1/vrf20_rib.json | 98 +++++++++ .../bgp_srv6l3vpn_to_bgp_vrf/r1/zebra.conf | 40 ++++ .../bgp_srv6l3vpn_to_bgp_vrf/r2/bgpd.conf | 65 ++++++ .../r2/vpnv6_rib.json | 170 +++++++++++++++ .../r2/vrf10_rib.json | 98 +++++++++ .../r2/vrf20_rib.json | 89 ++++++++ .../bgp_srv6l3vpn_to_bgp_vrf/r2/zebra.conf | 40 ++++ .../test_bgp_srv6l3vpn_to_bgp_vrf.py | 204 ++++++++++++++++++ 29 files changed, 1607 insertions(+) create mode 100644 tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce1/bgpd.conf create mode 100644 tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce1/ipv6_rib.json create mode 100644 tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce1/zebra.conf create mode 100644 tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce2/bgpd.conf create mode 100644 tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce2/ipv6_rib.json create mode 100644 tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce2/zebra.conf create mode 100644 tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce3/bgpd.conf create mode 100644 tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce3/ipv6_rib.json create mode 100644 tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce3/zebra.conf create mode 100644 tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce4/bgpd.conf create mode 100644 tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce4/ipv6_rib.json create mode 100644 tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce4/zebra.conf create mode 100644 tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce5/bgpd.conf create mode 100644 tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce5/ipv6_rib.json create mode 100644 tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce5/zebra.conf create mode 100644 tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce6/bgpd.conf create mode 100644 tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce6/ipv6_rib.json create mode 100644 tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce6/zebra.conf create mode 100644 tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/bgpd.conf create mode 100644 tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/vpnv6_rib.json create mode 100644 tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/vrf10_rib.json create mode 100644 tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/vrf20_rib.json create mode 100644 tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/zebra.conf create mode 100644 tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/bgpd.conf create mode 100644 tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/vpnv6_rib.json create mode 100644 tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/vrf10_rib.json create mode 100644 tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/vrf20_rib.json create mode 100644 tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/zebra.conf create mode 100755 tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/test_bgp_srv6l3vpn_to_bgp_vrf.py diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce1/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce1/bgpd.conf new file mode 100644 index 0000000000..3459796629 --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce1/bgpd.conf @@ -0,0 +1,8 @@ +frr defaults traditional +! +hostname ce1 +password zebra +! +log stdout notifications +log commands +log file bgpd.log diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce1/ipv6_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce1/ipv6_rib.json new file mode 100644 index 0000000000..d19e315772 --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce1/ipv6_rib.json @@ -0,0 +1,58 @@ +{ + "::/0": [ + { + "prefix": "::/0", + "protocol": "static", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 1, + "metric": 0, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 73, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "ip": "2001:1::1", + "afi": "ipv6", + "interfaceName": "eth0", + "active": true, + "weight": 1 + } + ] + } + ], + "2001:1::/64": [ + { + "prefix": "2001:1::/64", + "protocol": "connected", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 0, + "metric": 0, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "directlyConnected": true, + "interfaceName": "eth0", + "active": true + } + ] + } + ] +} diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce1/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce1/zebra.conf new file mode 100644 index 0000000000..665808a0e7 --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce1/zebra.conf @@ -0,0 +1,14 @@ +log file zebra.log +! +hostname ce1 +! +interface eth0 + ipv6 address 2001:1::2/64 +! +ip forwarding +ipv6 forwarding +! +ipv6 route ::/0 2001:1::1 +! +line vty +! diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce2/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce2/bgpd.conf new file mode 100644 index 0000000000..8ed9978749 --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce2/bgpd.conf @@ -0,0 +1,8 @@ +frr defaults traditional +! +hostname ce2 +password zebra +! +log stdout notifications +log commands +log file bgpd.log diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce2/ipv6_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce2/ipv6_rib.json new file mode 100644 index 0000000000..35ff14efad --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce2/ipv6_rib.json @@ -0,0 +1,58 @@ +{ + "::/0": [ + { + "prefix": "::/0", + "protocol": "static", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 1, + "metric": 0, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 73, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "ip": "2001:2::1", + "afi": "ipv6", + "interfaceName": "eth0", + "active": true, + "weight": 1 + } + ] + } + ], + "2001:2::/64": [ + { + "prefix": "2001:2::/64", + "protocol": "connected", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 0, + "metric": 0, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "directlyConnected": true, + "interfaceName": "eth0", + "active": true + } + ] + } + ] +} diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce2/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce2/zebra.conf new file mode 100644 index 0000000000..cc9b90a3b0 --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce2/zebra.conf @@ -0,0 +1,14 @@ +log file zebra.log +! +hostname ce2 +! +interface eth0 + ipv6 address 2001:2::2/64 +! +ip forwarding +ipv6 forwarding +! +ipv6 route ::/0 2001:2::1 +! +line vty +! diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce3/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce3/bgpd.conf new file mode 100644 index 0000000000..a85d9701c7 --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce3/bgpd.conf @@ -0,0 +1,8 @@ +frr defaults traditional +! +hostname ce3 +password zebra +! +log stdout notifications +log commands +log file bgpd.log diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce3/ipv6_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce3/ipv6_rib.json new file mode 100644 index 0000000000..2f2931f80f --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce3/ipv6_rib.json @@ -0,0 +1,58 @@ +{ + "::/0": [ + { + "prefix": "::/0", + "protocol": "static", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 1, + "metric": 0, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 73, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "ip": "2001:3::1", + "afi": "ipv6", + "interfaceName": "eth0", + "active": true, + "weight": 1 + } + ] + } + ], + "2001:3::/64": [ + { + "prefix": "2001:3::/64", + "protocol": "connected", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 0, + "metric": 0, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "directlyConnected": true, + "interfaceName": "eth0", + "active": true + } + ] + } + ] +} diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce3/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce3/zebra.conf new file mode 100644 index 0000000000..beca0b1211 --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce3/zebra.conf @@ -0,0 +1,14 @@ +log file zebra.log +! +hostname ce3 +! +interface eth0 + ipv6 address 2001:3::2/64 +! +ip forwarding +ipv6 forwarding +! +ipv6 route ::/0 2001:3::1 +! +line vty +! diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce4/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce4/bgpd.conf new file mode 100644 index 0000000000..93fb32fd1b --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce4/bgpd.conf @@ -0,0 +1,8 @@ +frr defaults traditional +! +hostname ce4 +password zebra +! +log stdout notifications +log commands +log file bgpd.log diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce4/ipv6_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce4/ipv6_rib.json new file mode 100644 index 0000000000..8a98768e0d --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce4/ipv6_rib.json @@ -0,0 +1,58 @@ +{ + "::/0": [ + { + "prefix": "::/0", + "protocol": "static", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 1, + "metric": 0, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 73, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "ip": "2001:4::1", + "afi": "ipv6", + "interfaceName": "eth0", + "active": true, + "weight": 1 + } + ] + } + ], + "2001:4::/64": [ + { + "prefix": "2001:4::/64", + "protocol": "connected", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 0, + "metric": 0, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "directlyConnected": true, + "interfaceName": "eth0", + "active": true + } + ] + } + ] +} diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce4/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce4/zebra.conf new file mode 100644 index 0000000000..7b21074df0 --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce4/zebra.conf @@ -0,0 +1,14 @@ +log file zebra.log +! +hostname ce4 +! +interface eth0 + ipv6 address 2001:4::2/64 +! +ip forwarding +ipv6 forwarding +! +ipv6 route ::/0 2001:4::1 +! +line vty +! diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce5/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce5/bgpd.conf new file mode 100644 index 0000000000..2ab6f2d2a7 --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce5/bgpd.conf @@ -0,0 +1,8 @@ +frr defaults traditional +! +hostname ce5 +password zebra +! +log stdout notifications +log commands +log file bgpd.log diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce5/ipv6_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce5/ipv6_rib.json new file mode 100644 index 0000000000..80ff52ad6e --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce5/ipv6_rib.json @@ -0,0 +1,58 @@ +{ + "::/0": [ + { + "prefix": "::/0", + "protocol": "static", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 1, + "metric": 0, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 73, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "ip": "2001:5::1", + "afi": "ipv6", + "interfaceName": "eth0", + "active": true, + "weight": 1 + } + ] + } + ], + "2001:5::/64": [ + { + "prefix": "2001:5::/64", + "protocol": "connected", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 0, + "metric": 0, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "directlyConnected": true, + "interfaceName": "eth0", + "active": true + } + ] + } + ] +} diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce5/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce5/zebra.conf new file mode 100644 index 0000000000..b5ad48e709 --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce5/zebra.conf @@ -0,0 +1,14 @@ +log file zebra.log +! +hostname ce5 +! +interface eth0 + ipv6 address 2001:5::2/64 +! +ip forwarding +ipv6 forwarding +! +ipv6 route ::/0 2001:5::1 +! +line vty +! diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce6/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce6/bgpd.conf new file mode 100644 index 0000000000..e0b6540514 --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce6/bgpd.conf @@ -0,0 +1,8 @@ +frr defaults traditional +! +hostname ce6 +password zebra +! +log stdout notifications +log commands +log file bgpd.log diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce6/ipv6_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce6/ipv6_rib.json new file mode 100644 index 0000000000..ace6136f06 --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce6/ipv6_rib.json @@ -0,0 +1,58 @@ +{ + "::/0": [ + { + "prefix": "::/0", + "protocol": "static", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 1, + "metric": 0, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 73, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "ip": "2001:6::1", + "afi": "ipv6", + "interfaceName": "eth0", + "active": true, + "weight": 1 + } + ] + } + ], + "2001:6::/64": [ + { + "prefix": "2001:6::/64", + "protocol": "connected", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 0, + "metric": 0, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "directlyConnected": true, + "interfaceName": "eth0", + "active": true + } + ] + } + ] +} diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce6/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce6/zebra.conf new file mode 100644 index 0000000000..7d19d9880b --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce6/zebra.conf @@ -0,0 +1,14 @@ +log file zebra.log +! +hostname ce6 +! +interface eth0 + ipv6 address 2001:6::2/64 +! +ip forwarding +ipv6 forwarding +! +ipv6 route ::/0 2001:6::1 +! +line vty +! diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/bgpd.conf new file mode 100644 index 0000000000..d07d0532e3 --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/bgpd.conf @@ -0,0 +1,64 @@ +frr defaults traditional +! +hostname r1 +password zebra +! +log stdout notifications +log monitor notifications +log commands +! +!debug bgp neighbor-events +!debug bgp zebra +!debug bgp vnc verbose +!debug bgp update-groups +!debug bgp updates in +!debug bgp updates out +!debug bgp vpn label +!debug bgp vpn leak-from-vrf +!debug bgp vpn leak-to-vrf +!debug bgp vpn rmap-event +! +router bgp 1 + bgp router-id 1.1.1.1 + no bgp ebgp-requires-policy + no bgp default ipv4-unicast + neighbor 2001::2 remote-as 2 + neighbor 2001::2 timers 3 10 + neighbor 2001::2 timers connect 1 + ! + address-family ipv6 vpn + neighbor 2001::2 activate + exit-address-family + ! + segment-routing srv6 + locator loc1 + ! +! +router bgp 1 vrf vrf10 + bgp router-id 1.1.1.1 + no bgp ebgp-requires-policy + no bgp default ipv4-unicast + ! + address-family ipv6 unicast + sid vpn export auto + rd vpn export 1:10 + rt vpn both 99:99 + import vpn + export vpn + redistribute connected + exit-address-family +! +router bgp 1 vrf vrf20 + bgp router-id 1.1.1.1 + no bgp ebgp-requires-policy + no bgp default ipv4-unicast + ! + address-family ipv6 unicast + sid vpn export auto + rd vpn export 1:20 + rt vpn both 88:88 + import vpn + export vpn + redistribute connected + exit-address-family +! diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/vpnv6_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/vpnv6_rib.json new file mode 100644 index 0000000000..25b7a8616f --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/vpnv6_rib.json @@ -0,0 +1,170 @@ +{ + "vrfId": 0, + "vrfName": "default", + "tableVersion": 2, + "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 + } + ] + } + ] + } + } + } +} diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/vrf10_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/vrf10_rib.json new file mode 100644 index 0000000000..9219d9ad38 --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/vrf10_rib.json @@ -0,0 +1,89 @@ +{ + "2001:1::/64": [ + { + "prefix": "2001:1::/64", + "protocol": "connected", + "vrfName": "vrf10", + "selected": true, + "destSelected": true, + "distance": 0, + "metric": 0, + "installed": true, + "table": 10, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "directlyConnected": true, + "interfaceName": "eth1", + "active": true + } + ] + } + ], + "2001:2::/64": [ + { + "prefix": "2001:2::/64", + "protocol": "bgp", + "vrfName": "vrf10", + "selected": true, + "destSelected": true, + "distance": 20, + "metric": 0, + "installed": true, + "table": 10, + "internalStatus": 16, + "internalFlags": 1032, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "afi": "ipv6", + "interfaceName": "eth0", + "vrf": "default", + "active": true, + "labels": [ + 3 + ], + "weight": 1, + "seg6": { + "segs": "2001:db8:2:2::100" + } + } + ], + "asPath": "2" + } + ], + "2001:3::/64": [ + { + "prefix": "2001:3::/64", + "protocol": "connected", + "vrfName": "vrf10", + "selected": true, + "destSelected": true, + "distance": 0, + "metric": 0, + "installed": true, + "table": 10, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "directlyConnected": true, + "interfaceName": "eth2", + "active": true + } + ] + } + ] +} diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/vrf20_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/vrf20_rib.json new file mode 100644 index 0000000000..cd4c7d5039 --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/vrf20_rib.json @@ -0,0 +1,98 @@ +{ + "2001:4::/64": [ + { + "prefix": "2001:4::/64", + "protocol": "bgp", + "vrfName": "vrf20", + "selected": true, + "destSelected": true, + "distance": 20, + "metric": 0, + "installed": true, + "table": 20, + "internalStatus": 16, + "internalFlags": 1032, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "afi": "ipv6", + "interfaceName": "eth0", + "vrf": "default", + "active": true, + "labels": [ + 3 + ], + "weight": 1, + "seg6": { + "segs": "2001:db8:2:2::200" + } + } + ], + "asPath": "2" + } + ], + "2001:5::/64": [ + { + "prefix": "2001:5::/64", + "protocol": "connected", + "vrfName": "vrf20", + "selected": true, + "destSelected": true, + "distance": 0, + "metric": 0, + "installed": true, + "table": 20, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "directlyConnected": true, + "interfaceName": "eth3", + "active": true + } + ] + } + ], + "2001:6::/64": [ + { + "prefix": "2001:6::/64", + "protocol": "bgp", + "vrfName": "vrf20", + "selected": true, + "destSelected": true, + "distance": 20, + "metric": 0, + "installed": true, + "table": 20, + "internalStatus": 16, + "internalFlags": 1032, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "afi": "ipv6", + "interfaceName": "eth0", + "vrf": "default", + "active": true, + "labels": [ + 3 + ], + "weight": 1, + "seg6": { + "segs": "2001:db8:2:2::200" + } + } + ], + "asPath": "2" + } + ] +} diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/zebra.conf new file mode 100644 index 0000000000..ec36870369 --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/zebra.conf @@ -0,0 +1,40 @@ +log file zebra.log +! +hostname r1 +password zebra +! +log stdout notifications +log monitor notifications +log commands +! +debug zebra packet +debug zebra dplane +debug zebra kernel +! +interface eth0 + ipv6 address 2001::1/64 +! +interface eth1 vrf vrf10 + ipv6 address 2001:1::1/64 +! +interface eth2 vrf vrf10 + ipv6 address 2001:3::1/64 +! +interface eth3 vrf vrf20 + ipv6 address 2001:5::1/64 +! +segment-routing + srv6 + locators + locator loc1 + prefix 2001:db8:1:1::/64 + ! + ! +! +ip forwarding +ipv6 forwarding +! +ipv6 route 2001:db8:2:2::/64 2001::2 +! +line vty +! diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/bgpd.conf new file mode 100644 index 0000000000..d0b3ea8ada --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/bgpd.conf @@ -0,0 +1,65 @@ +frr defaults traditional +! +hostname r2 +password zebra +! +log stdout notifications +log monitor notifications +log commands +! +!debug bgp neighbor-events +!debug bgp zebra +!debug bgp vnc verbose +!debug bgp update-groups +!debug bgp updates in +!debug bgp updates out +!debug bgp updates +!debug bgp vpn label +!debug bgp vpn leak-from-vrf +!debug bgp vpn leak-to-vrf +!debug bgp vpn rmap-event +! +router bgp 2 + bgp router-id 2.2.2.2 + no bgp ebgp-requires-policy + no bgp default ipv4-unicast + neighbor 2001::1 remote-as 1 + neighbor 2001::1 timers 3 10 + neighbor 2001::1 timers connect 1 + ! + address-family ipv6 vpn + neighbor 2001::1 activate + exit-address-family + ! + segment-routing srv6 + locator loc1 + ! +! +router bgp 2 vrf vrf10 + bgp router-id 2.2.2.2 + no bgp ebgp-requires-policy + no bgp default ipv4-unicast + ! + address-family ipv6 unicast + sid vpn export auto + rd vpn export 2:10 + rt vpn both 99:99 + import vpn + export vpn + redistribute connected + exit-address-family +! +router bgp 2 vrf vrf20 + bgp router-id 2.2.2.2 + no bgp ebgp-requires-policy + no bgp default ipv4-unicast + ! + address-family ipv6 unicast + sid vpn export auto + rd vpn export 2:20 + rt vpn both 88:88 + import vpn + export vpn + redistribute connected + exit-address-family +! diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/vpnv6_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/vpnv6_rib.json new file mode 100644 index 0000000000..2cd47b9ce5 --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/vpnv6_rib.json @@ -0,0 +1,170 @@ +{ + "vrfId": 0, + "vrfName": "default", + "tableVersion": 2, + "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 + } + ] + } + ] + } + } + } +} diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/vrf10_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/vrf10_rib.json new file mode 100644 index 0000000000..5ae377c399 --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/vrf10_rib.json @@ -0,0 +1,98 @@ +{ + "2001:1::/64": [ + { + "prefix": "2001:1::/64", + "protocol": "bgp", + "vrfName": "vrf10", + "selected": true, + "destSelected": true, + "distance": 20, + "metric": 0, + "installed": true, + "table": 10, + "internalStatus": 16, + "internalFlags": 1032, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "afi": "ipv6", + "interfaceName": "eth0", + "vrf": "default", + "active": true, + "labels": [ + 3 + ], + "weight": 1, + "seg6": { + "segs": "2001:db8:1:1::100" + } + } + ], + "asPath": "1" + } + ], + "2001:2::/64": [ + { + "prefix": "2001:2::/64", + "protocol": "connected", + "vrfName": "vrf10", + "selected": true, + "destSelected": true, + "distance": 0, + "metric": 0, + "installed": true, + "table": 10, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "directlyConnected": true, + "interfaceName": "eth1", + "active": true + } + ] + } + ], + "2001:3::/64": [ + { + "prefix": "2001:3::/64", + "protocol": "bgp", + "vrfName": "vrf10", + "selected": true, + "destSelected": true, + "distance": 20, + "metric": 0, + "installed": true, + "table": 10, + "internalStatus": 16, + "internalFlags": 1032, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "afi": "ipv6", + "interfaceName": "eth0", + "vrf": "default", + "active": true, + "labels": [ + 3 + ], + "weight": 1, + "seg6": { + "segs": "2001:db8:1:1::100" + } + } + ], + "asPath": "1" + } + ] +} diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/vrf20_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/vrf20_rib.json new file mode 100644 index 0000000000..ea1fe4c2a9 --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/vrf20_rib.json @@ -0,0 +1,89 @@ +{ + "2001:4::/64": [ + { + "prefix": "2001:4::/64", + "protocol": "connected", + "vrfName": "vrf20", + "selected": true, + "destSelected": true, + "distance": 0, + "metric": 0, + "installed": true, + "table": 20, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "directlyConnected": true, + "interfaceName": "eth2", + "active": true + } + ] + } + ], + "2001:5::/64": [ + { + "prefix": "2001:5::/64", + "protocol": "bgp", + "vrfName": "vrf20", + "selected": true, + "destSelected": true, + "distance": 20, + "metric": 0, + "installed": true, + "table": 20, + "internalStatus": 16, + "internalFlags": 1032, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "afi": "ipv6", + "interfaceName": "eth0", + "vrf": "default", + "active": true, + "labels": [ + 3 + ], + "weight": 1, + "seg6": { + "segs": "2001:db8:1:1::200" + } + } + ], + "asPath": "1" + } + ], + "2001:6::/64": [ + { + "prefix": "2001:6::/64", + "protocol": "connected", + "vrfName": "vrf20", + "selected": true, + "destSelected": true, + "distance": 0, + "metric": 0, + "installed": true, + "table": 20, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "directlyConnected": true, + "interfaceName": "eth3", + "active": true + } + ] + } + ] +} diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/zebra.conf new file mode 100644 index 0000000000..f3e025d23a --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/zebra.conf @@ -0,0 +1,40 @@ +log file zebra.log +! +hostname r2 +password zebra +! +log stdout notifications +log monitor notifications +log commands +! +debug zebra packet +debug zebra dplane +debug zebra kernel +! +interface eth0 + ipv6 address 2001::2/64 +! +interface eth1 vrf vrf10 + ipv6 address 2001:2::1/64 +! +interface eth2 vrf vrf20 + ipv6 address 2001:4::1/64 +! +interface eth3 vrf vrf20 + ipv6 address 2001:6::1/64 +! +segment-routing + srv6 + locators + locator loc1 + prefix 2001:db8:2:2::/64 + ! + ! +! +ip forwarding +ipv6 forwarding +! +ipv6 route 2001:db8:1:1::/64 2001::1 +! +line vty +! diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/test_bgp_srv6l3vpn_to_bgp_vrf.py b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/test_bgp_srv6l3vpn_to_bgp_vrf.py new file mode 100755 index 0000000000..2d80c66b0b --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/test_bgp_srv6l3vpn_to_bgp_vrf.py @@ -0,0 +1,204 @@ +#!/usr/bin/env python + +# +# Part of NetDEF Topology Tests +# +# Copyright (c) 2018, LabN Consulting, L.L.C. +# Authored by Lou Berger +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +import os +import re +import sys +import json +import functools +import pytest + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger +from lib.common_config import required_linux_kernel_version +from mininet.topo import Topo + + +class Topology(Topo): + """ + CE1 CE3 CE5 + (eth0) (eth0) (eth0) + :2 :2 :2 + | | | + 2001: 2001: 2001: + 1::/64 3::/64 5::/64 + | | | + :1 :1 :1 + +-(eth1)--(eth2)---(eth3)-+ + | \ / | | + | (vrf10) (vrf20) | + | R1 | + +----------(eth0)---------+ + :1 + | + 2001::/64 + | + :2 + (eth0) + +----------(eth0)--------------+ + | R2 | + | (vrf10) (vrf20) | + | / / \ | + +-(eth1)-----(eth2)-----(eth3)-+ + :1 :1 :1 + | | | + +------+ +------+ +------+ + / 2001: \ / 2001: \ / 2001: \ + \ 2::/64 / \ 4::/64 / \ 6::/64 / + +------+ +------+ +------+ + | | | + :2 :2 :2 + (eth0) (eth0) (eth0) + CE2 CE4 CE6 + """ + def build(self, *_args, **_opts): + tgen = get_topogen(self) + tgen.add_router("r1") + tgen.add_router("r2") + tgen.add_router("ce1") + tgen.add_router("ce2") + tgen.add_router("ce3") + tgen.add_router("ce4") + tgen.add_router("ce5") + tgen.add_router("ce6") + + tgen.add_link(tgen.gears["r1"], tgen.gears["r2"], "eth0", "eth0") + tgen.add_link(tgen.gears["ce1"], tgen.gears["r1"], "eth0", "eth1") + tgen.add_link(tgen.gears["ce2"], tgen.gears["r2"], "eth0", "eth1") + tgen.add_link(tgen.gears["ce3"], tgen.gears["r1"], "eth0", "eth2") + tgen.add_link(tgen.gears["ce4"], tgen.gears["r2"], "eth0", "eth2") + tgen.add_link(tgen.gears["ce5"], tgen.gears["r1"], "eth0", "eth3") + tgen.add_link(tgen.gears["ce6"], tgen.gears["r2"], "eth0", "eth3") + + +def setup_module(mod): + result = required_linux_kernel_version("4.15") + if result is not True: + pytest.skip("Kernel requirements are not met") + + tgen = Topogen(Topology, mod.__name__) + tgen.start_topology() + router_list = tgen.routers() + for rname, router in tgen.routers().items(): + router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname)) + router.load_config(TopoRouter.RD_ZEBRA, + os.path.join(CWD, '{}/zebra.conf'.format(rname))) + router.load_config(TopoRouter.RD_BGP, + os.path.join(CWD, '{}/bgpd.conf'.format(rname))) + + tgen.gears["r1"].run("ip link add vrf10 type vrf table 10") + tgen.gears["r1"].run("ip link set vrf10 up") + tgen.gears["r1"].run("ip link add vrf20 type vrf table 20") + tgen.gears["r1"].run("ip link set vrf20 up") + tgen.gears["r1"].run("ip link set eth1 master vrf10") + tgen.gears["r1"].run("ip link set eth2 master vrf10") + tgen.gears["r1"].run("ip link set eth3 master vrf20") + + tgen.gears["r2"].run("ip link add vrf10 type vrf table 10") + tgen.gears["r2"].run("ip link set vrf10 up") + tgen.gears["r2"].run("ip link add vrf20 type vrf table 20") + tgen.gears["r2"].run("ip link set vrf20 up") + tgen.gears["r2"].run("ip link set eth1 master vrf10") + tgen.gears["r2"].run("ip link set eth2 master vrf20") + tgen.gears["r2"].run("ip link set eth3 master vrf20") + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def open_json_file(filename): + try: + with open(filename, "r") as f: + return json.load(f) + except IOError: + assert False, "Could not read file {}".format(filename) + + +def test_rib(): + def _check(name, cmd, expected_file): + logger.info("polling") + tgen = get_topogen() + router = tgen.gears[name] + output = json.loads(router.vtysh_cmd(cmd)) + expected = open_json_file("{}/{}".format(CWD, expected_file)) + return topotest.json_cmp(output, expected) + + def check(name, cmd, expected_file): + logger.info("[+] check {} \"{}\" {}".format(name, cmd, expected_file)) + tgen = get_topogen() + func = functools.partial(_check, name, cmd, expected_file) + success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) + 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") + check("r1", "show ipv6 route vrf vrf10 json", "r1/vrf10_rib.json") + check("r1", "show ipv6 route vrf vrf20 json", "r1/vrf20_rib.json") + check("r2", "show ipv6 route vrf vrf10 json", "r2/vrf10_rib.json") + check("r2", "show ipv6 route vrf vrf20 json", "r2/vrf20_rib.json") + check("ce1", "show ipv6 route json", "ce1/ipv6_rib.json") + check("ce2", "show ipv6 route json", "ce2/ipv6_rib.json") + check("ce3", "show ipv6 route json", "ce3/ipv6_rib.json") + check("ce4", "show ipv6 route json", "ce4/ipv6_rib.json") + check("ce5", "show ipv6 route json", "ce5/ipv6_rib.json") + check("ce6", "show ipv6 route json", "ce6/ipv6_rib.json") + + +def test_ping(): + 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" + + 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") + check("ce1", "2001:3::2", " 0% packet loss") + check("ce1", "2001:4::2", " 100% packet loss") + check("ce1", "2001:5::2", " 100% packet loss") + check("ce1", "2001:6::2", " 100% packet loss") + check("ce4", "2001:1::2", " 100% packet loss") + check("ce4", "2001:2::2", " 100% packet loss") + check("ce4", "2001:3::2", " 100% packet loss") + check("ce4", "2001:5::2", " 0% packet loss") + check("ce4", "2001:6::2", " 0% packet loss") + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) From 7de4c88525f9f234fbf68f7fdbd7fcdf4fc2aacd Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Wed, 24 Feb 2021 10:10:06 +0000 Subject: [PATCH 32/66] *: fix code format accourding to checkpatch Signed-off-by: Hiroki Shirokura --- bgpd/bgp_mplsvpn.c | 51 +++++++++++++++++++++++--------------------- bgpd/bgp_mplsvpn.h | 4 ++-- bgpd/bgp_nb_config.c | 8 +++---- bgpd/bgp_vty.c | 17 +++++++++------ bgpd/bgp_zebra.c | 13 ++++++----- 5 files changed, 49 insertions(+), 44 deletions(-) diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 2d0c9ec017..33266ef511 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -366,7 +366,7 @@ void vpn_leak_zebra_vrf_sid_update(struct bgp *bgp, afi_t afi) { int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL); enum seg6local_action_t act; - struct seg6local_context ctx = {{0}}; + struct seg6local_context ctx = { {0} }; struct in6_addr *tovpn_sid = NULL; struct in6_addr *tovpn_sid_ls = NULL; struct vrf *vrf; @@ -374,8 +374,7 @@ void vpn_leak_zebra_vrf_sid_update(struct bgp *bgp, afi_t afi) if (bgp->vrf_id == VRF_UNKNOWN) { if (debug) - zlog_debug("%s: vrf %s: afi %s: vrf_id not set, " - "can't set zebra vrf label", + zlog_debug("%s: vrf %s: afi %s: vrf_id not set, can't set zebra vrf label", __func__, bgp->name_pretty, afi2str(afi)); return; } @@ -419,8 +418,7 @@ void vpn_leak_zebra_vrf_sid_withdraw(struct bgp *bgp, afi_t afi) if (bgp->vrf_id == VRF_UNKNOWN) { if (debug) - zlog_debug("%s: vrf %s: afi %s: vrf_id not set, " - "can't set zebra vrf label", + zlog_debug("%s: vrf %s: afi %s: vrf_id not set, can't set zebra vrf label", __func__, bgp->name_pretty, afi2str(afi)); return; } @@ -513,14 +511,17 @@ static bool sid_exist(struct bgp *bgp, const struct in6_addr *sid) { struct listnode *node; struct bgp_srv6_function *func; + for (ALL_LIST_ELEMENTS_RO(bgp->srv6_functions, node, func)) if (sid_same(&func->sid, sid)) return true; return false; } -/* if index != 0: try to allocate as index-mode - * else: try to allocate as auto-mode */ +/* + * if index != 0: try to allocate as index-mode + * else: try to allocate as auto-mode + */ static bool alloc_new_sid(struct bgp *bgp, uint32_t index, struct in6_addr *sid) { @@ -540,14 +541,14 @@ static bool alloc_new_sid(struct bgp *bgp, uint32_t index, return false; alloced = true; break; - } else { - for (size_t i=1; i<255; i++) { - sid_buf.s6_addr16[7] = i; - if (sid_exist(bgp, &sid_buf)) - continue; - alloced = true; - break; - } + } + + for (size_t i = 1; i < 255; i++) { + sid_buf.s6_addr16[7] = i; + if (sid_exist(bgp, &sid_buf)) + continue; + alloced = true; + break; } } @@ -576,8 +577,10 @@ void ensure_vrf_tovpn_sid(struct bgp *bgp_vpn, struct bgp *bgp_vrf, afi_t afi) if (bgp_vrf->vpn_policy[afi].tovpn_sid) return; - /* skip when bgp vpn instance ins't allocated - * or srv6 locator chunk isn't allocated */ + /* + * skip when bgp vpn instance ins't allocated + * or srv6 locator chunk isn't allocated + */ if (!bgp_vpn || !bgp_vpn->srv6_locator_chunks || !bgp_vrf) return; @@ -611,7 +614,6 @@ void ensure_vrf_tovpn_sid(struct bgp *bgp_vpn, struct bgp *bgp_vrf, afi_t afi) afi2str(afi)); } bgp_vrf->vpn_policy[afi].tovpn_sid = sid; - return; } static bool ecom_intersect(struct ecommunity *e1, struct ecommunity *e2) @@ -705,9 +707,8 @@ static void setsids(struct bgp_path_info *bpi, } extra = bgp_path_info_extra_get(bpi); - for (i = 0; i < num_sids; i++) { + for (i = 0; i < num_sids; i++) memcpy(&extra->sid[i], &sid[i], sizeof(struct in6_addr)); - } extra->num_sids = num_sids; } @@ -726,8 +727,8 @@ leak_update(struct bgp *bgp, /* destination bgp instance */ struct bgp_path_info *bpi; struct bgp_path_info *bpi_ultimate; struct bgp_path_info *new; - uint32_t num_sids = 0; + if (new_attr->srv6_l3vpn || new_attr->srv6_vpn) num_sids = 1; @@ -813,9 +814,11 @@ leak_update(struct bgp *bgp, /* destination bgp instance */ */ if (num_sids) { if (new_attr->srv6_l3vpn) - setsids(bpi, &new_attr->srv6_l3vpn->sid, num_sids); + setsids(bpi, &new_attr->srv6_l3vpn->sid, + num_sids); else if (new_attr->srv6_vpn) - setsids(bpi, &new_attr->srv6_vpn->sid, num_sids); + setsids(bpi, &new_attr->srv6_vpn->sid, + num_sids); } if (nexthop_self_flag) @@ -1149,7 +1152,7 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */ /* Set SID for SRv6 VPN */ if (!sid_zero(bgp_vrf->vpn_policy[afi].tovpn_sid)) { static_attr.srv6_l3vpn = XCALLOC(MTYPE_BGP_SRV6_L3VPN, - sizeof(struct bgp_attr_srv6_l3vpn)* 100); + sizeof(struct bgp_attr_srv6_l3vpn) * 100); static_attr.srv6_l3vpn->sid_flags = 0x00; static_attr.srv6_l3vpn->endpoint_behavior = 0xffff; memcpy(&static_attr.srv6_l3vpn->sid, diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h index 172372bdf0..38193721b3 100644 --- a/bgpd/bgp_mplsvpn.h +++ b/bgpd/bgp_mplsvpn.h @@ -244,8 +244,8 @@ static inline void vpn_leak_postchange(vpn_policy_direction_t direction, ensure_vrf_tovpn_sid(bgp_vpn, bgp_vrf, afi); if (sid_diff(bgp_vrf->vpn_policy[afi].tovpn_sid, - bgp_vrf->vpn_policy[afi]. - tovpn_zebra_vrf_sid_last_sent)) { + bgp_vrf->vpn_policy[afi] + .tovpn_zebra_vrf_sid_last_sent)) { vpn_leak_zebra_vrf_sid_update(bgp_vrf, afi); } diff --git a/bgpd/bgp_nb_config.c b/bgpd/bgp_nb_config.c index e83b9e20a8..5189d7ba8f 100644 --- a/bgpd/bgp_nb_config.c +++ b/bgpd/bgp_nb_config.c @@ -11451,8 +11451,8 @@ int bgp_global_afi_safis_afi_safi_ipv6_unicast_vpn_config_import_vpn_modify( if (!bgp) return NB_OK; - if (BGP_INSTANCE_TYPE_VRF != bgp->inst_type - && BGP_INSTANCE_TYPE_DEFAULT != bgp->inst_type) { + if (bgp->inst_type != BGP_INSTANCE_TYPE_VRF + && bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT) { snprintf( args->errmsg, args->errmsg_len, "import|export vpn valid only for bgp vrf or default instance"); @@ -11491,8 +11491,8 @@ int bgp_global_afi_safis_afi_safi_ipv6_unicast_vpn_config_export_vpn_modify( if (!bgp) return NB_OK; - if (BGP_INSTANCE_TYPE_VRF != bgp->inst_type - && BGP_INSTANCE_TYPE_DEFAULT != bgp->inst_type) { + if (bgp->inst_type != BGP_INSTANCE_TYPE_VRF + && bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT) { snprintf( args->errmsg, args->errmsg_len, "import|export vpn valid only for bgp vrf or default instance"); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 03c4e69591..db3a15d481 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -9269,9 +9269,10 @@ DEFPY (af_sid_vpn_export, BGP_VPN_POLICY_TOVPN_SID_AUTO))) return CMD_SUCCESS; - /* mode change between sid_idx and sid_auto isn't supported. - * user must negate sid vpn export when they want to change - * the mode */ + /* + * mode change between sid_idx and sid_auto isn't supported. + * user must negate sid vpn export when they want to change the mode + */ if ((sid_auto && bgp->vpn_policy[afi].tovpn_sid_index != 0) || (sid_idx != 0 && CHECK_FLAG(bgp->vpn_policy[afi].flags, BGP_VPN_POLICY_TOVPN_SID_AUTO))) { @@ -9948,16 +9949,18 @@ DEFPY (bgp_srv6_locator, "Specify SRv6 locator\n") { VTY_DECLVAR_CONTEXT(bgp, bgp); + int ret; if (strlen(bgp->srv6_locator_name) > 0 && strcmp(name, bgp->srv6_locator_name) != 0) { vty_out(vty, "srv6 locator is already configured\n"); return CMD_WARNING_CONFIG_FAILED; - } else - snprintf(bgp->srv6_locator_name, - sizeof(bgp->srv6_locator_name), "%s", name); + } - int ret = bgp_zebra_srv6_manager_get_locator_chunk(name); + snprintf(bgp->srv6_locator_name, + sizeof(bgp->srv6_locator_name), "%s", name); + + ret = bgp_zebra_srv6_manager_get_locator_chunk(name); if (ret < 0) return CMD_WARNING_CONFIG_FAILED; diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 8349358da4..7e2dfed64d 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -3004,8 +3004,10 @@ static void bgp_zebra_process_srv6_locator_chunk(ZAPI_CALLBACK_ARGS) uint16_t instance; uint16_t len; char name[256] = {0}; - struct prefix_ipv6 *chunk = NULL; - chunk = prefix_ipv6_new(); + struct bgp *bgp = bgp_get_default(); + struct listnode *node; + struct prefix_ipv6 *c; + struct prefix_ipv6 *chunk = prefix_ipv6_new(); s = zclient->ibuf; STREAM_GETC(s, proto); @@ -3026,15 +3028,12 @@ static void bgp_zebra_process_srv6_locator_chunk(ZAPI_CALLBACK_ARGS) return; } - struct bgp *bgp = bgp_get_default(); if (strcmp(bgp->srv6_locator_name, name) != 0) { zlog_info("name unmatch %s:%s", bgp->srv6_locator_name, name); return; } - struct listnode *node; - struct prefix_ipv6 *c; for (ALL_LIST_ELEMENTS_RO(bgp->srv6_locator_chunks, node, c)) { if (!prefix_cmp(c, chunk)) return; @@ -3048,7 +3047,6 @@ stream_failure: free(chunk); zlog_err("%s: can't get locator_chunk!!", __func__); - return; } void bgp_zebra_init(struct thread_master *master, unsigned short instance) @@ -3093,7 +3091,8 @@ void bgp_zebra_init(struct thread_master *master, unsigned short instance) zclient->iptable_notify_owner = iptable_notify_owner; zclient->route_notify_owner = bgp_zebra_route_notify_owner; zclient->instance = instance; - zclient->process_srv6_locator_chunk = bgp_zebra_process_srv6_locator_chunk; + zclient->process_srv6_locator_chunk = + bgp_zebra_process_srv6_locator_chunk; } void bgp_zebra_destroy(void) From daedb8b3cfee5639d9997b1a0c3193b31bfbb5ad Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Tue, 29 Dec 2020 07:30:47 +0000 Subject: [PATCH 33/66] zebra: rewrite locator_prefix_cmd with DEFPY Signed-off-by: Hiroki Shirokura --- zebra/subdir.am | 1 + zebra/zebra_srv6_vty.c | 29 ++++++++++------------------- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/zebra/subdir.am b/zebra/subdir.am index 4d8115597b..70d8c4005d 100644 --- a/zebra/subdir.am +++ b/zebra/subdir.am @@ -131,6 +131,7 @@ clippy_scan += \ zebra/zebra_mlag_vty.c \ zebra/zebra_routemap.c \ zebra/zebra_vty.c \ + zebra/zebra_srv6_vty.c \ # end noinst_HEADERS += \ diff --git a/zebra/zebra_srv6_vty.c b/zebra/zebra_srv6_vty.c index e2685141bb..0bc48f6339 100644 --- a/zebra/zebra_srv6_vty.c +++ b/zebra/zebra_srv6_vty.c @@ -40,6 +40,10 @@ #include "zebra/zebra_routemap.h" #include "zebra/zebra_dplane.h" +#ifndef VTYSH_EXTRACT_PL +#include "zebra/zebra_srv6_vty_clippy.c" +#endif + static int zebra_sr_config(struct vty *vty); static struct cmd_node sr_node = { @@ -229,37 +233,24 @@ DEFUN_NOSH (srv6_locator, return CMD_SUCCESS; } -DEFUN (locator_prefix, +DEFPY (locator_prefix, locator_prefix_cmd, - "prefix X:X::X:X/M [func-bits (8-64)]", + "prefix X:X::X:X/M$prefix [func-bits (16-64)$func_bit_len]", "Configure SRv6 locator prefix\n" "Specify SRv6 locator prefix\n" "Configure SRv6 locator function length in bits\n" "Specify SRv6 locator function length in bits\n") { VTY_DECLVAR_CONTEXT(srv6_locator, locator); - struct prefix_ipv6 prefix; struct srv6_locator_chunk *chunk = NULL; struct listnode *node = NULL; - uint8_t function_bits_length = 16; - int ret; - ret = str2prefix_ipv6(argv[1]->arg, &prefix); - if (ret <= 0) { - vty_out(vty, "%% Malformed address\n"); - return CMD_WARNING_CONFIG_FAILED; - } - apply_mask_ipv6(&prefix); - - if (argc >= 3) - function_bits_length = strtoul(argv[3]->arg, NULL, 10); - - locator->prefix = prefix; - locator->function_bits_length = function_bits_length; + locator->prefix = *prefix; + locator->function_bits_length = func_bit_len; 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 { @@ -270,7 +261,7 @@ DEFUN (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)) { From 124f7236fb77bf34185e461fc029d304f9ba4b37 Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Tue, 29 Dec 2020 08:23:34 +0000 Subject: [PATCH 34/66] bgpd: fix crash when bgp_delete found by unit-test Signed-off-by: Hiroki Shirokura --- bgpd/bgpd.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 1b78be354b..33429d1d78 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1337,8 +1337,10 @@ static void bgp_srv6_init(struct bgp *bgp) static void bgp_srv6_cleanup(struct bgp *bgp) { - list_delete(&bgp->srv6_locator_chunks); - list_delete(&bgp->srv6_functions); + if (bgp->srv6_locator_chunks) + list_delete(&bgp->srv6_locator_chunks); + if (bgp->srv6_functions) + list_delete(&bgp->srv6_functions); } /* Allocate new peer object, implicitely locked. */ From 361a62ac9d2226269ecebd66de7c4c7e824917da Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Tue, 29 Dec 2020 10:55:50 +0000 Subject: [PATCH 35/66] zebra: fix compile error of missing-braces Signed-off-by: Hiroki Shirokura --- zebra/rt_netlink.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index f5ce4e795b..a84c3da6ad 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -475,7 +475,7 @@ parse_nexthop_unicast(ns_id_t ns_id, struct rtmsg *rtm, struct rtattr **tb, int num_labels = 0; enum seg6local_action_t seg6l_act = SEG6_LOCAL_ACTION_UNSPEC; struct seg6local_context seg6l_ctx = { {0} }; - struct in6_addr seg6_segs = {0}; + struct in6_addr seg6_segs = { .s6_addr = {0} }; int num_segs = 0; vrf_id_t nh_vrf_id = vrf_id; @@ -557,7 +557,7 @@ static uint8_t parse_multipath_nexthops_unicast(ns_id_t ns_id, int num_labels = 0; enum seg6local_action_t seg6l_act = SEG6_LOCAL_ACTION_UNSPEC; struct seg6local_context seg6l_ctx = { {0} }; - struct in6_addr seg6_segs = {0}; + struct in6_addr seg6_segs = { .s6_addr = {0} }; int num_segs = 0; struct rtattr *rtnh_tb[RTA_MAX + 1] = {}; From 96db4340b71d5c593e674dda6aff9ab47d971dea Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Tue, 29 Dec 2020 10:56:38 +0000 Subject: [PATCH 36/66] bgpd: fix compile error for BSD platforms Signed-off-by: Hiroki Shirokura --- bgpd/bgp_vty.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index db3a15d481..2d8099a8e2 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -9986,7 +9986,7 @@ DEFPY (show_bgp_srv6, char buf_tovpn6_sid[256]; bgp = bgp_get_default(); - if (!bgp || !bgp->srv6_locator_name) + if (!bgp) return CMD_SUCCESS; vty_out(vty, "locator_name: %s\n", bgp->srv6_locator_name); @@ -18045,7 +18045,7 @@ int bgp_config_write(struct vty *vty) if (bgp->srv6_enabled) { vty_frame(vty, " !\n segment-routing srv6\n"); - if (bgp->srv6_locator_name) + if (strlen(bgp->srv6_locator_name)) vty_out(vty, " locator %s\n", bgp->srv6_locator_name); } From 537b608a3db0af5ba97268dbc4366b8d3ad085e2 Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Wed, 30 Dec 2020 01:19:20 +0000 Subject: [PATCH 37/66] bgpd: fix vrf route-leaking crash around srv6 Signed-off-by: Hiroki Shirokura --- bgpd/bgp_mplsvpn.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 33266ef511..332504db84 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -1150,9 +1150,9 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */ static_attr.originator_id = bgp_vpn->router_id; /* Set SID for SRv6 VPN */ - if (!sid_zero(bgp_vrf->vpn_policy[afi].tovpn_sid)) { + if (bgp_vrf->vpn_policy[afi].tovpn_sid) { static_attr.srv6_l3vpn = XCALLOC(MTYPE_BGP_SRV6_L3VPN, - sizeof(struct bgp_attr_srv6_l3vpn) * 100); + sizeof(struct bgp_attr_srv6_l3vpn)); static_attr.srv6_l3vpn->sid_flags = 0x00; static_attr.srv6_l3vpn->endpoint_behavior = 0xffff; memcpy(&static_attr.srv6_l3vpn->sid, From 6e9e2233270ea4176f6851472947f2c03329a662 Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Wed, 30 Dec 2020 02:16:44 +0000 Subject: [PATCH 38/66] doc: fix srv6 section according to review Signed-off-by: Hiroki Shirokura --- doc/user/zebra.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index 02999a7006..2522ec6771 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -669,7 +669,7 @@ and this section also helps that case. ``srv6`` commands in configure mode. If there is some SRv6-locator exist, SRv6 feature is looked enabled and this affects running-config. - User can enter the Locators node with ``locators`` command. + User can enter the Locators node with ``locators`` command in srv6 configure mode. After entering locators node, user can configure one or multi SRv6-locators. @@ -693,7 +693,7 @@ and this section also helps that case. Usually default SID is allocated as ``PREFIX:1::``. (``PREFIX`` is locator's prefix) For example, if user configure the locator's prefix as - `2001:db8:a:a::/64`, then default SID will be `2001:db8:a:a:1::`) + ``2001:db8:a:a::/64``, then default SID will be ``2001:db8:a:a:1::``) The function bits range is 16bits by default. If operator want to change function bits range, they can configure From ac6a9479af182fad4810fe6d21abc73f39c751f9 Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Thu, 31 Dec 2020 11:56:32 +0000 Subject: [PATCH 39/66] zebra: add zapi_srv6_locator_chunk_{en,de}code Signed-off-by: Hiroki Shirokura --- lib/srv6.h | 25 ++++++++++++++++++++++++- lib/zclient.c | 40 ++++++++++++++++++++++++++++++++++++++++ lib/zclient.h | 5 +++++ zebra/zapi_msg.c | 29 +++++++++++++---------------- zebra/zebra_srv6_vty.c | 19 +++++++++++++++++++ 5 files changed, 101 insertions(+), 17 deletions(-) diff --git a/lib/srv6.h b/lib/srv6.h index 46ff830e7f..9ac89125ce 100644 --- a/lib/srv6.h +++ b/lib/srv6.h @@ -76,7 +76,16 @@ struct seg6local_context { struct srv6_locator { char name[SRV6_LOCNAME_SIZE]; struct prefix_ipv6 prefix; + + /* + * Bit length of SRv6 locator described in + * draft-ietf-bess-srv6-services-05#section-3.2.1 + */ + uint8_t block_bits_length; + uint8_t node_bits_length; uint8_t function_bits_length; + uint8_t argument_bits_length; + int algonum; uint64_t current; bool status_up; @@ -87,11 +96,25 @@ struct srv6_locator { DECLARE_QOBJ_TYPE(srv6_locator); struct srv6_locator_chunk { + char locator_name[SRV6_LOCNAME_SIZE]; + struct prefix_ipv6 prefix; + + /* + * Bit length of SRv6 locator described in + * draft-ietf-bess-srv6-services-05#section-3.2.1 + */ + uint8_t block_bits_length; + uint8_t node_bits_length; + uint8_t function_bits_length; + uint8_t argument_bits_length; + + /* + * For Zclient communication values + */ uint8_t keep; uint8_t proto; uint16_t instance; uint32_t session_id; - struct prefix_ipv6 prefix; }; static inline const char *seg6_mode2str(enum seg6_mode_t mode) diff --git a/lib/zclient.c b/lib/zclient.c index 1acf7f20d5..f6b97a768f 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -1074,6 +1074,46 @@ done: return ret; } +int zapi_srv6_locator_chunk_encode(struct stream *s, + const struct srv6_locator_chunk *c) +{ + stream_putc(s, c->proto); + stream_putw(s, c->instance); + stream_putw(s, strlen(c->locator_name)); + stream_put(s, c->locator_name, strlen(c->locator_name)); + stream_putw(s, c->prefix.prefixlen); + stream_put(s, &c->prefix.prefix, sizeof(c->prefix.prefix)); + stream_putc(s, c->block_bits_length); + stream_putc(s, c->node_bits_length); + stream_putc(s, c->function_bits_length); + stream_putc(s, c->argument_bits_length); + return 0; +} + +int zapi_srv6_locator_chunk_decode(struct stream *s, + struct srv6_locator_chunk *c) +{ + uint16_t len = 0; + + STREAM_GETC(s, c->proto); + STREAM_GETW(s, c->instance); + STREAM_GETW(s, len); + if (len > SRV6_LOCNAME_SIZE) + goto stream_failure; + + STREAM_GET(c->locator_name, s, len); + STREAM_GETW(s, c->prefix.prefixlen); + STREAM_GET(&c->prefix.prefix, s, sizeof(c->prefix.prefix)); + STREAM_GETC(s, c->block_bits_length); + STREAM_GETC(s, c->node_bits_length); + STREAM_GETC(s, c->function_bits_length); + STREAM_GETC(s, c->argument_bits_length); + return 0; + +stream_failure: + return -1; +} + 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 e06079673a..d9ca6a859d 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -1092,6 +1092,11 @@ extern int zapi_labels_encode(struct stream *s, int cmd, struct zapi_labels *zl); extern int zapi_labels_decode(struct stream *s, struct zapi_labels *zl); +extern int zapi_srv6_locator_chunk_encode(struct stream *s, + const struct srv6_locator_chunk *c); +extern int zapi_srv6_locator_chunk_decode(struct stream *s, + struct srv6_locator_chunk *c); + extern enum zclient_send_status zebra_send_pw(struct zclient *zclient, int command, struct zapi_pw *pw); extern int zebra_read_pw_status_update(ZAPI_CALLBACK_ARGS, diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 25c51e2227..46bd9d9959 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -2701,26 +2701,23 @@ int zsend_srv6_manager_get_locator_chunk_response(struct zserv *client, vrf_id_t vrf_id, struct srv6_locator *loc) { + struct srv6_locator_chunk chunk; struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); + memset(&chunk, 0, sizeof(chunk)); + strlcpy(chunk.locator_name, loc->name, sizeof(chunk.locator_name)); + chunk.prefix = loc->prefix; + chunk.block_bits_length = loc->block_bits_length; + chunk.node_bits_length = loc->node_bits_length; + chunk.function_bits_length = loc->function_bits_length; + chunk.argument_bits_length = loc->argument_bits_length; + chunk.keep = 0; + chunk.proto = client->proto; + chunk.instance = client->instance; + zclient_create_header(s, ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK, vrf_id); - - /* proto */ - stream_putc(s, client->proto); - - /* instance */ - stream_putw(s, client->instance); - - if (loc) { - 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, 16); - } - - /* Write packet size. */ + zapi_srv6_locator_chunk_encode(s, &chunk); stream_putw_at(s, 0, stream_get_endp(s)); - return zserv_send_message(client, s); } diff --git a/zebra/zebra_srv6_vty.c b/zebra/zebra_srv6_vty.c index 0bc48f6339..803e9f1196 100644 --- a/zebra/zebra_srv6_vty.c +++ b/zebra/zebra_srv6_vty.c @@ -246,7 +246,26 @@ DEFPY (locator_prefix, struct listnode *node = NULL; locator->prefix = *prefix; + + /* + * 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->block_bits_length = prefix->prefixlen - 24; + locator->node_bits_length = 24; locator->function_bits_length = func_bit_len; + locator->argument_bits_length = 0; if (list_isempty(locator->chunks)) { chunk = srv6_locator_chunk_alloc(); From 3a0220e46a8ed0e0cbf80c42cbff7ede6846df9d Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Thu, 31 Dec 2020 11:57:03 +0000 Subject: [PATCH 40/66] bgpd: use zapi_srv6_locator_chunk_decode Signed-off-by: Hiroki Shirokura --- bgpd/bgp_zebra.c | 43 ++++++++++++++++--------------------------- 1 file changed, 16 insertions(+), 27 deletions(-) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 7e2dfed64d..df6f383fb7 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -3000,53 +3000,42 @@ static int bgp_ifp_create(struct interface *ifp) static void bgp_zebra_process_srv6_locator_chunk(ZAPI_CALLBACK_ARGS) { struct stream *s = NULL; - uint8_t proto; - uint16_t instance; - uint16_t len; - char name[256] = {0}; struct bgp *bgp = bgp_get_default(); struct listnode *node; struct prefix_ipv6 *c; - struct prefix_ipv6 *chunk = prefix_ipv6_new(); + struct srv6_locator_chunk s6c; + struct prefix_ipv6 *chunk = NULL; s = zclient->ibuf; - STREAM_GETC(s, proto); - STREAM_GETW(s, instance); + memset(&s6c, 0, sizeof(s6c)); + zapi_srv6_locator_chunk_decode(s, &s6c); - STREAM_GETW(s, len); - STREAM_GET(name, s, len); - - STREAM_GETW(s, chunk->prefixlen); - STREAM_GET(&chunk->prefix, s, 16); - - if (zclient->redist_default != proto) { - zlog_err("Got SRv6 Manager msg with wrong proto %u", proto); + if (zclient->redist_default != s6c.proto) { + zlog_err("%s: Got SRv6 Manager msg with wrong proto %u", + __func__, s6c.proto); return; } - if (zclient->instance != instance) { - zlog_err("Got SRv6 Manager msg with wrong instance %u", proto); + if (zclient->instance != s6c.instance) { + zlog_err("%s: Got SRv6 Manager msg with wrong instance %u", + __func__, s6c.instance); return; } - if (strcmp(bgp->srv6_locator_name, name) != 0) { - zlog_info("name unmatch %s:%s", - bgp->srv6_locator_name, name); + if (strcmp(bgp->srv6_locator_name, s6c.locator_name) != 0) { + zlog_err("%s: Locator name unmatch %s:%s", __func__, + bgp->srv6_locator_name, s6c.locator_name); return; } for (ALL_LIST_ELEMENTS_RO(bgp->srv6_locator_chunks, node, c)) { - if (!prefix_cmp(c, chunk)) + if (!prefix_cmp(c, &s6c.prefix)) return; } + chunk = prefix_ipv6_new(); + *chunk = s6c.prefix; listnode_add(bgp->srv6_locator_chunks, chunk); vpn_leak_postchange_all(); - return; - -stream_failure: - free(chunk); - - zlog_err("%s: can't get locator_chunk!!", __func__); } void bgp_zebra_init(struct thread_master *master, unsigned short instance) From 7f8c7d9166317e4e65f359d72b044a9d6dfd062c Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Tue, 9 Feb 2021 05:26:22 +0000 Subject: [PATCH 41/66] bgpd: ignore nexthop validation for srv6-vpn Signed-off-by: Hiroki Shirokura --- bgpd/bgp_nht.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index e94f63541d..f046235610 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -66,9 +66,20 @@ static int bgp_isvalid_nexthop(struct bgp_nexthop_cache *bnc) static int bgp_isvalid_labeled_nexthop(struct bgp_nexthop_cache *bnc) { + /* + * In the case of MPLS-VPN, the label is learned from LDP or other + * protocols, and nexthop tracking is enabled for the label. + * The value is recorded as BGP_NEXTHOP_LABELED_VALID. + * In the case of SRv6-VPN, we need to track the reachability to the + * SID (in other words, IPv6 address). As in MPLS, we need to record + * the value as BGP_NEXTHOP_SID_VALID. However, this function is + * currently not implemented, and this function assumes that all + * Transit routes for SRv6-VPN are valid. + */ return (bgp_zebra_num_connects() == 0 - || (bnc && CHECK_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID) - && bnc->nexthop_num > 0)); + || (bnc && bnc->nexthop_num > 0 + && (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID) + || bnc->bgp->srv6_enabled))); } static void bgp_unlink_nexthop_check(struct bgp_nexthop_cache *bnc) From f29aed7480294e9551389cf652390a6e807ae05b Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Wed, 24 Feb 2021 09:36:09 +0000 Subject: [PATCH 42/66] *: fix code format accourding to checkpatch Signed-off-by: Hiroki Shirokura --- zebra/zebra_srv6_vty.c | 1 + 1 file changed, 1 insertion(+) diff --git a/zebra/zebra_srv6_vty.c b/zebra/zebra_srv6_vty.c index 803e9f1196..97935f126e 100644 --- a/zebra/zebra_srv6_vty.c +++ b/zebra/zebra_srv6_vty.c @@ -288,6 +288,7 @@ DEFPY (locator_prefix, if (client->proto != chunk->proto) continue; + srv6_manager_get_locator_chunk_call( &tmp, client, locator->name, From 1d5f59a2353c9537193527ca0ffaf58a2e56d30e Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Wed, 24 Feb 2021 11:28:59 +0000 Subject: [PATCH 43/66] zebra: fix Dereference of null pointer Signed-off-by: Hiroki Shirokura --- zebra/zebra_srv6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c index 1e12117ac4..5664a29682 100644 --- a/zebra/zebra_srv6.c +++ b/zebra/zebra_srv6.c @@ -220,7 +220,7 @@ static int zebra_srv6_manager_get_locator_chunk(struct srv6_locator **loc, (*loc)->name, zebra_route_string(client->proto), client->instance); - if ((*loc)->status_up) + if (*loc && (*loc)->status_up) ret = zsend_srv6_manager_get_locator_chunk_response(client, vrf_id, *loc); From 90dbd3b85cba4f1476847f9143af1f5030554aea Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Wed, 24 Feb 2021 11:52:30 +0000 Subject: [PATCH 44/66] bgpd: fix build error for NetBSD8 Signed-off-by: Hiroki Shirokura --- bgpd/bgp_mplsvpn.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 332504db84..6162ec42a6 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -544,7 +544,9 @@ static bool alloc_new_sid(struct bgp *bgp, uint32_t index, } for (size_t i = 1; i < 255; i++) { - sid_buf.s6_addr16[7] = i; + sid_buf.s6_addr[15] = (i & 0xff00) >> 8; + sid_buf.s6_addr[14] = (i & 0x00ff); + if (sid_exist(bgp, &sid_buf)) continue; alloced = true; From 9f900cda302f6b9030f21d64a0f04fce16a06379 Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Mon, 8 Mar 2021 15:05:49 +0000 Subject: [PATCH 45/66] zebra: fix typo Signed-off-by: Hiroki Shirokura --- zebra/zapi_msg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 46bd9d9959..235c06f177 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -2996,7 +2996,7 @@ static void zread_srv6_manager_request(ZAPI_HANDLER_ARGS) zvrf_id(zvrf)); break; default: - zlog_err("%s: unknown SRv6 Mamanger command", __func__); + zlog_err("%s: unknown SRv6 Manager command", __func__); break; } } From 326591dcdbaf892b5f5e57d5a5d5d80d2e8937ab Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Mon, 22 Mar 2021 00:04:06 +0000 Subject: [PATCH 46/66] lib: fix json style to camel-case instead of underscores Signed-off-by: Hiroki Shirokura --- lib/srv6.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/srv6.c b/lib/srv6.c index d59d2d75b0..ceb769ef76 100644 --- a/lib/srv6.c +++ b/lib/srv6.c @@ -185,11 +185,11 @@ json_object *srv6_locator_json(const struct srv6_locator *loc) json_object_string_add(jo_root, "prefix", str); /* set function_bits_length */ - json_object_int_add(jo_root, "function_bits_length", + json_object_int_add(jo_root, "functionBitsLength", loc->function_bits_length); /* set status_up */ - json_object_boolean_add(jo_root, "status_up", + json_object_boolean_add(jo_root, "statusUp", loc->status_up); /* set chunks */ From 1bda3e627de060ece571012041965faa389c33c5 Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Mon, 22 Mar 2021 00:31:56 +0000 Subject: [PATCH 47/66] *: use one line init instead of memset and format it Signed-off-by: Hiroki Shirokura --- bgpd/bgp_mplsvpn.c | 2 +- bgpd/bgp_zebra.c | 3 +-- lib/zclient.c | 9 +++------ sharpd/sharp_vty.c | 3 +-- zebra/rt_netlink.c | 12 ++++++------ zebra/zapi_msg.c | 3 +-- 6 files changed, 13 insertions(+), 19 deletions(-) diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 6162ec42a6..f99d672c8a 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -366,7 +366,7 @@ void vpn_leak_zebra_vrf_sid_update(struct bgp *bgp, afi_t afi) { int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL); enum seg6local_action_t act; - struct seg6local_context ctx = { {0} }; + struct seg6local_context ctx = {}; struct in6_addr *tovpn_sid = NULL; struct in6_addr *tovpn_sid_ls = NULL; struct vrf *vrf; diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index df6f383fb7..a10c6fd245 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -3003,11 +3003,10 @@ static void bgp_zebra_process_srv6_locator_chunk(ZAPI_CALLBACK_ARGS) struct bgp *bgp = bgp_get_default(); struct listnode *node; struct prefix_ipv6 *c; - struct srv6_locator_chunk s6c; + struct srv6_locator_chunk s6c = {}; struct prefix_ipv6 *chunk = NULL; s = zclient->ibuf; - memset(&s6c, 0, sizeof(s6c)); zapi_srv6_locator_chunk_decode(s, &s6c); if (zclient->redist_default != s6c.proto) { diff --git a/lib/zclient.c b/lib/zclient.c index f6b97a768f..158a20eb58 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -441,16 +441,14 @@ enum zclient_send_status zclient_send_localsid(struct zclient *zclient, enum seg6local_action_t action, const struct seg6local_context *context) { - struct prefix_ipv6 p; - struct zapi_route api; - struct nexthop nh; + struct prefix_ipv6 p = {}; + struct zapi_route api = {}; + struct nexthop nh = {}; - memset(&p, 0, sizeof(p)); p.family = AF_INET6; p.prefixlen = 128; p.prefix = *sid; - memset(&api, 0, sizeof(api)); api.vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_BGP; api.instance = 0; @@ -464,7 +462,6 @@ enum zclient_send_status zclient_send_localsid(struct zclient *zclient, SET_FLAG(api.flags, ZEBRA_FLAG_SEG6LOCAL_ROUTE); SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); - memset(&nh, 0, sizeof(nh)); nh.type = NEXTHOP_TYPE_IFINDEX; nh.ifindex = oif; nexthop_add_seg6local(&nh, action, context); diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index 58f6e3fe95..72bc7d16b9 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -316,10 +316,9 @@ DEFPY (install_routes, sg.r.backup_nhop_group.nexthop = bnhgc->nhg.nexthop; } } else if (seg6l_oif) { - struct seg6local_context ctx; + struct seg6local_context ctx = {}; enum seg6local_action_t action; - memset(&ctx, 0, sizeof(struct seg6local_context)); if (seg6l_enddx4) { action = ZEBRA_SEG6_LOCAL_ACTION_END_DX4; ctx.nh4 = seg6l_enddx4_nh4; diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index a84c3da6ad..70db6234bb 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -419,7 +419,7 @@ static enum seg6local_action_t parse_encap_seg6local(struct rtattr *tb, struct seg6local_context *ctx) { - struct rtattr *tb_encap[256] = {0}; + struct rtattr *tb_encap[256] = {}; enum seg6local_action_t act = ZEBRA_SEG6_LOCAL_ACTION_UNSPEC; netlink_parse_rtattr_nested(tb_encap, 256, tb); @@ -443,7 +443,7 @@ parse_encap_seg6local(struct rtattr *tb, static int parse_encap_seg6(struct rtattr *tb, struct in6_addr *segs) { - struct rtattr *tb_encap[256] = {0}; + struct rtattr *tb_encap[256] = {}; struct seg6_iptunnel_encap *ipt = NULL; struct in6_addr *segments = NULL; @@ -474,8 +474,8 @@ parse_nexthop_unicast(ns_id_t ns_id, struct rtmsg *rtm, struct rtattr **tb, mpls_label_t labels[MPLS_MAX_LABELS] = {0}; int num_labels = 0; enum seg6local_action_t seg6l_act = SEG6_LOCAL_ACTION_UNSPEC; - struct seg6local_context seg6l_ctx = { {0} }; - struct in6_addr seg6_segs = { .s6_addr = {0} }; + struct seg6local_context seg6l_ctx = {}; + struct in6_addr seg6_segs = {}; int num_segs = 0; vrf_id_t nh_vrf_id = vrf_id; @@ -556,8 +556,8 @@ static uint8_t parse_multipath_nexthops_unicast(ns_id_t ns_id, mpls_label_t labels[MPLS_MAX_LABELS] = {0}; int num_labels = 0; enum seg6local_action_t seg6l_act = SEG6_LOCAL_ACTION_UNSPEC; - struct seg6local_context seg6l_ctx = { {0} }; - struct in6_addr seg6_segs = { .s6_addr = {0} }; + struct seg6local_context seg6l_ctx = {}; + struct in6_addr seg6_segs = {}; int num_segs = 0; struct rtattr *rtnh_tb[RTA_MAX + 1] = {}; diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 235c06f177..4331487b8b 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -2701,10 +2701,9 @@ int zsend_srv6_manager_get_locator_chunk_response(struct zserv *client, vrf_id_t vrf_id, struct srv6_locator *loc) { - struct srv6_locator_chunk chunk; + struct srv6_locator_chunk chunk = {}; struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); - memset(&chunk, 0, sizeof(chunk)); strlcpy(chunk.locator_name, loc->name, sizeof(chunk.locator_name)); chunk.prefix = loc->prefix; chunk.block_bits_length = loc->block_bits_length; From fbaa42f744b8bcf30f50a5442ecbe8028ea47d2a Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Mon, 22 Mar 2021 00:52:11 +0000 Subject: [PATCH 48/66] lib: integrate srv6-nexthop-cmp functions I agree with the PR review from mstap and merged the following two functions into one. - zapi_nexthop_seg6_cmp - zapi_nexthop_seg6local_cmp [note] If both of them have more complex extensions in the future, I think it will be less confusing to remove the integration of these functions and make them as separate functions as before. Signed-off-by: Hiroki Shirokura --- lib/zclient.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/lib/zclient.c b/lib/zclient.c index 158a20eb58..27cc095f12 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -833,9 +833,16 @@ static int zapi_nexthop_labels_cmp(const struct zapi_nexthop *next1, return memcmp(next1->labels, next2->labels, next1->label_num); } -static int zapi_nexthop_seg6local_cmp(const struct zapi_nexthop *next1, - const struct zapi_nexthop *next2) +static int zapi_nexthop_srv6_cmp(const struct zapi_nexthop *next1, + const struct zapi_nexthop *next2) { + int ret = 0; + + ret = memcmp(&next1->seg6_segs, &next2->seg6_segs, + sizeof(struct in6_addr)); + if (ret != 0) + return ret; + if (next1->seg6local_action > next2->seg6local_action) return 1; @@ -846,13 +853,6 @@ static int zapi_nexthop_seg6local_cmp(const struct zapi_nexthop *next1, sizeof(struct seg6local_context)); } -static int zapi_nexthop_seg6_cmp(const struct zapi_nexthop *next1, - const struct zapi_nexthop *next2) -{ - return memcmp(&next1->seg6_segs, &next2->seg6_segs, - sizeof(struct in6_addr)); -} - static int zapi_nexthop_cmp_no_labels(const struct zapi_nexthop *next1, const struct zapi_nexthop *next2) { @@ -956,11 +956,7 @@ static int zapi_nexthop_cmp(const void *item1, const void *item2) if (ret != 0) return ret; - ret = zapi_nexthop_seg6local_cmp(next1, next2); - if (ret != 0) - return ret; - - ret = zapi_nexthop_seg6_cmp(next1, next2); + ret = zapi_nexthop_srv6_cmp(next1, next2); return ret; } From 8dcb27e6d908dc6f95b6ce2b119102bb084563c5 Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Mon, 22 Mar 2021 00:57:03 +0000 Subject: [PATCH 49/66] lib: eliminate odd line-break Signed-off-by: Hiroki Shirokura --- lib/zclient.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/zclient.c b/lib/zclient.c index 27cc095f12..32414f34d1 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -2785,8 +2785,7 @@ int srv6_manager_connect(struct zclient *zclient) zlog_debug("SRv6 Manager connect request sent (%d bytes)", ret); /* read response */ - if (zclient_read_sync_response(zclient, cmd) - != 0) + if (zclient_read_sync_response(zclient, cmd) != 0) return -1; s = zclient->ibuf; From 4c6a567d724170e742730d56daf15a49db37d714 Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Mon, 22 Mar 2021 01:09:16 +0000 Subject: [PATCH 50/66] lib: erase wrong comments by copy-paste Signed-off-by: Hiroki Shirokura --- lib/zclient.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/zclient.c b/lib/zclient.c index 32414f34d1..270f780ed0 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -2823,9 +2823,6 @@ stream_failure: /** * Function to request a srv6-locator chunk in an Asyncronous way * - * It first writes the request to zclient output buffer and then - * immediately reads the answer from the input buffer. - * * @param zclient Zclient used to connect to table manager (zebra) * @param locator_name Name of SRv6-locator * @result 0 on success, -1 otherwise From a9510347aa9126fbbca09679a170b10c63ef851c Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Mon, 22 Mar 2021 01:45:33 +0000 Subject: [PATCH 51/66] zebra: delete unneeded zebra_srv6_manager_connect Signed-off-by: Hiroki Shirokura --- lib/zclient.c | 83 ------------------------------------------------ lib/zclient.h | 2 -- zebra/zapi_msg.c | 68 --------------------------------------- 3 files changed, 153 deletions(-) diff --git a/lib/zclient.c b/lib/zclient.c index 270f780ed0..de3aed46e9 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -2737,89 +2737,6 @@ stream_failure: return -1; } -/** - * Connect to srv6 manager in a syncronous way - * - * It first writes the request to zcient output buffer and then - * immediately reads the answer from the input buffer. - * - * @param zclient Zclient used to connect to srv6 manager (zebra) - * @result Result of response - */ -int srv6_manager_connect(struct zclient *zclient) -{ - struct stream *s; - int ret, result = 0; - uint16_t cmd = ZEBRA_SRV6_MANAGER_CONNECT; - - if (zclient_debug) - zlog_debug("Connecting to SRv6 Manager"); - - if (zclient->sock < 0) { - zlog_debug("%s: invalid zclient socket", __func__); - return -1; - } - - /* send request */ - s = zclient->obuf; - stream_reset(s); - zclient_create_header(s, cmd, VRF_DEFAULT); - - stream_putc(s, zclient->redist_default); /* proto */ - stream_putw(s, zclient->instance); /* instance */ - stream_putw_at(s, 0, stream_get_endp(s)); - ret = writen(zclient->sock, s->data, stream_get_endp(s)); - if (ret < 0) { - flog_err(EC_LIB_ZAPI_SOCKET, "Can't write to zclient sock"); - close(zclient->sock); - zclient->sock = -1; - return -1; - } - if (ret == 0) { - flog_err(EC_LIB_ZAPI_SOCKET, "Zclient sock closed"); - close(zclient->sock); - zclient->sock = -1; - return -1; - } - if (zclient_debug) - zlog_debug("SRv6 Manager connect request sent (%d bytes)", ret); - - /* read response */ - if (zclient_read_sync_response(zclient, cmd) != 0) - return -1; - - s = zclient->ibuf; - - /* read instance and proto */ - uint8_t proto; - uint16_t instance; - - STREAM_GETC(s, proto); - STREAM_GETW(s, instance); - - /* sanity */ - if (proto != zclient->redist_default) - flog_err( - EC_LIB_ZAPI_ENCODE, - "Wrong proto (%u) in SRv6 Manager connect response. Should be %u", - proto, zclient->redist_default); - if (instance != zclient->instance) - flog_err( - EC_LIB_ZAPI_ENCODE, - "Wrong instId (%u) in SRv6 Manager connect response. Should be %u", - instance, zclient->instance); - - /* result code */ - STREAM_GETC(s, result); - if (zclient_debug) - zlog_debug("SRv6 Manager connect-response received, result %u", result); - - return (int)result; - -stream_failure: - return -1; -} - /** * Function to request a srv6-locator chunk in an Asyncronous way * diff --git a/lib/zclient.h b/lib/zclient.h index d9ca6a859d..c41d25133d 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -219,7 +219,6 @@ typedef enum { ZEBRA_EVPN_REMOTE_NH_DEL, ZEBRA_SRV6_LOCATOR_ADD, ZEBRA_SRV6_LOCATOR_DELETE, - ZEBRA_SRV6_MANAGER_CONNECT, ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK, ZEBRA_SRV6_MANAGER_RELEASE_LOCATOR_CHUNK, ZEBRA_ERROR, @@ -1070,7 +1069,6 @@ extern int tm_get_table_chunk(struct zclient *zclient, uint32_t chunk_size, uint32_t *start, uint32_t *end); extern int tm_release_table_chunk(struct zclient *zclient, uint32_t start, uint32_t end); -extern int srv6_manager_connect(struct zclient *zclient); extern int srv6_manager_get_locator_chunk(struct zclient *zclient, const char *locator_name); extern int srv6_manager_release_locator_chunk(struct zclient *zclient, diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 4331487b8b..4f6663fe2b 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -1137,29 +1137,6 @@ static int zsend_table_manager_connect_response(struct zserv *client, return zserv_send_message(client, s); } -static int zsend_srv6_manager_connect_response(struct zserv *client, - vrf_id_t vrf_id, - uint16_t result) -{ - struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); - - zclient_create_header(s, ZEBRA_SRV6_MANAGER_CONNECT, vrf_id); - - /* proto */ - stream_putc(s, client->proto); - - /* instance */ - stream_putw(s, client->instance); - - /* result */ - stream_putc(s, result); - - /* Write packet size. */ - stream_putw_at(s, 0, stream_get_endp(s)); - - return zserv_send_message(client, s); -} - /* Inbound message handling ------------------------------------------------ */ const int cmd2type[] = { @@ -2656,47 +2633,6 @@ int zsend_client_close_notify(struct zserv *client, struct zserv *closed_client) return zserv_send_message(client, s); } -/* Send response to a srv6 manager connect request to client */ -static void zread_srv6_manager_connect(struct zserv *client, - struct stream *msg, vrf_id_t vrf_id) -{ - struct stream *s; - uint8_t proto; - uint16_t instance; - struct vrf *vrf = vrf_lookup_by_id(vrf_id); - - s = msg; - - /* Get data. */ - STREAM_GETC(s, proto); - STREAM_GETW(s, instance); - - /* accept only dynamic routing protocols */ - if ((proto >= ZEBRA_ROUTE_MAX) || (proto <= ZEBRA_ROUTE_STATIC)) { - flog_err(EC_ZEBRA_TM_WRONG_PROTO, - "client %d has wrong protocol %s", client->sock, - zebra_route_string(proto)); - zsend_srv6_manager_connect_response(client, vrf_id, 1); - return; - } - zlog_notice("client %d with vrf %s(%u) instance %u connected as %s", - client->sock, VRF_LOGNAME(vrf), vrf_id, instance, - zebra_route_string(proto)); - client->proto = proto; - client->instance = instance; - - /* - * Release previous locators of same protocol and instance. - * This is done in case it restarted from an unexpected shutdown. - */ - release_daemon_srv6_locator_chunks(client); - - zsend_srv6_manager_connect_response(client, vrf_id, 0); - -stream_failure: - return; -} - int zsend_srv6_manager_get_locator_chunk_response(struct zserv *client, vrf_id_t vrf_id, struct srv6_locator *loc) @@ -2983,9 +2919,6 @@ stream_failure: static void zread_srv6_manager_request(ZAPI_HANDLER_ARGS) { switch (hdr->command) { - case ZEBRA_SRV6_MANAGER_CONNECT: - zread_srv6_manager_connect(client, msg, zvrf_id(zvrf)); - break; case ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK: zread_srv6_manager_get_locator_chunk(client, msg, zvrf_id(zvrf)); @@ -3759,7 +3692,6 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = { [ZEBRA_MLAG_CLIENT_REGISTER] = zebra_mlag_client_register, [ZEBRA_MLAG_CLIENT_UNREGISTER] = zebra_mlag_client_unregister, [ZEBRA_MLAG_FORWARD_MSG] = zebra_mlag_forward_client_msg, - [ZEBRA_SRV6_MANAGER_CONNECT] = zread_srv6_manager_request, [ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK] = zread_srv6_manager_request, [ZEBRA_SRV6_MANAGER_RELEASE_LOCATOR_CHUNK] = zread_srv6_manager_request, [ZEBRA_CLIENT_CAPABILITIES] = zread_client_capabilities, From 7b778857f8340df730b1b26844a11c09eb7dc451 Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Mon, 22 Mar 2021 02:24:06 +0000 Subject: [PATCH 52/66] zebra: drop un-needed info in locator-zapi Signed-off-by: Hiroki Shirokura --- lib/zclient.c | 12 ------------ zebra/zapi_msg.c | 12 ------------ 2 files changed, 24 deletions(-) diff --git a/lib/zclient.c b/lib/zclient.c index de3aed46e9..4d8fbdf157 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -2762,12 +2762,6 @@ int srv6_manager_get_locator_chunk(struct zclient *zclient, zclient_create_header(s, ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK, VRF_DEFAULT); - /* proto */ - stream_putc(s, zclient->redist_default); - - /* instance */ - stream_putw(s, zclient->instance); - /* locator_name */ stream_putw(s, len); stream_put(s, locator_name, len); @@ -2803,12 +2797,6 @@ int srv6_manager_release_locator_chunk(struct zclient *zclient, zclient_create_header(s, ZEBRA_SRV6_MANAGER_RELEASE_LOCATOR_CHUNK, VRF_DEFAULT); - /* proto */ - stream_putc(s, zclient->redist_default); - - /* instance */ - stream_putw(s, zclient->instance); - /* locator_name */ stream_putw(s, len); stream_put(s, locator_name, len); diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 4f6663fe2b..d97d876cf5 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -2870,19 +2870,13 @@ static void zread_srv6_manager_get_locator_chunk(struct zserv *client, vrf_id_t vrf_id) { struct stream *s = msg; - uint8_t proto; - uint16_t instance; uint16_t len; char locator_name[SRV6_LOCNAME_SIZE] = {0}; /* Get data. */ - STREAM_GETC(s, proto); - STREAM_GETW(s, instance); STREAM_GETW(s, len); STREAM_GET(locator_name, s, len); - assert(proto == client->proto && instance == client->instance); - /* call hook to get a chunk using wrapper */ struct srv6_locator *loc = NULL; srv6_manager_get_locator_chunk_call(&loc, client, locator_name, vrf_id); @@ -2896,19 +2890,13 @@ static void zread_srv6_manager_release_locator_chunk(struct zserv *client, vrf_id_t vrf_id) { struct stream *s = msg; - uint8_t proto; - uint16_t instance; uint16_t len; char locator_name[SRV6_LOCNAME_SIZE] = {0}; /* Get data. */ - STREAM_GETC(s, proto); - STREAM_GETW(s, instance); STREAM_GETW(s, len); STREAM_GET(locator_name, s, len); - assert(proto == client->proto && instance == client->instance); - /* call hook to release a chunk using wrapper */ srv6_manager_release_locator_chunk_call(client, locator_name, vrf_id); From 04d43dbd0255f5bf89f3c3c1e62a9d5d97643846 Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Mon, 22 Mar 2021 08:23:08 +0000 Subject: [PATCH 53/66] tests: fix json style on srv6_locator test Signed-off-by: Hiroki Shirokura --- tests/topotests/srv6_locator/expected_locators1.json | 4 ++-- tests/topotests/srv6_locator/expected_locators2.json | 4 ++-- tests/topotests/srv6_locator/expected_locators3.json | 4 ++-- tests/topotests/srv6_locator/expected_locators4.json | 6 +++--- tests/topotests/srv6_locator/expected_locators5.json | 6 +++--- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/topotests/srv6_locator/expected_locators1.json b/tests/topotests/srv6_locator/expected_locators1.json index 39f35fadd4..3953bb0723 100644 --- a/tests/topotests/srv6_locator/expected_locators1.json +++ b/tests/topotests/srv6_locator/expected_locators1.json @@ -3,7 +3,7 @@ { "name": "loc1", "prefix": "2001:db8:1:1::/64", - "status_up": true, + "statusUp": true, "chunks": [ { "prefix": "2001:db8:1:1::/64", @@ -14,7 +14,7 @@ { "name": "loc2", "prefix": "2001:db8:2:2::/64", - "status_up": true, + "statusUp": true, "chunks": [ { "prefix": "2001:db8:2:2::/64", diff --git a/tests/topotests/srv6_locator/expected_locators2.json b/tests/topotests/srv6_locator/expected_locators2.json index 03ccb87ffe..ce3a4045d7 100644 --- a/tests/topotests/srv6_locator/expected_locators2.json +++ b/tests/topotests/srv6_locator/expected_locators2.json @@ -3,7 +3,7 @@ { "name": "loc1", "prefix": "2001:db8:1:1::/64", - "status_up": true, + "statusUp": true, "chunks": [ { "prefix": "2001:db8:1:1::/64", @@ -14,7 +14,7 @@ { "name": "loc2", "prefix": "2001:db8:2:2::/64", - "status_up": true, + "statusUp": true, "chunks": [ { "prefix": "2001:db8:2:2::/64", diff --git a/tests/topotests/srv6_locator/expected_locators3.json b/tests/topotests/srv6_locator/expected_locators3.json index 39f35fadd4..3953bb0723 100644 --- a/tests/topotests/srv6_locator/expected_locators3.json +++ b/tests/topotests/srv6_locator/expected_locators3.json @@ -3,7 +3,7 @@ { "name": "loc1", "prefix": "2001:db8:1:1::/64", - "status_up": true, + "statusUp": true, "chunks": [ { "prefix": "2001:db8:1:1::/64", @@ -14,7 +14,7 @@ { "name": "loc2", "prefix": "2001:db8:2:2::/64", - "status_up": true, + "statusUp": true, "chunks": [ { "prefix": "2001:db8:2:2::/64", diff --git a/tests/topotests/srv6_locator/expected_locators4.json b/tests/topotests/srv6_locator/expected_locators4.json index 4def3c000c..7989f9021b 100644 --- a/tests/topotests/srv6_locator/expected_locators4.json +++ b/tests/topotests/srv6_locator/expected_locators4.json @@ -3,7 +3,7 @@ { "name": "loc1", "prefix": "2001:db8:1:1::/64", - "status_up": true, + "statusUp": true, "chunks": [ { "prefix": "2001:db8:1:1::/64", @@ -14,7 +14,7 @@ { "name": "loc2", "prefix": "2001:db8:2:2::/64", - "status_up": true, + "statusUp": true, "chunks": [ { "prefix": "2001:db8:2:2::/64", @@ -24,7 +24,7 @@ }, { "name":"loc3", - "status_up":false, + "statusUp":false, "chunks":[ { "proto":"sharp" diff --git a/tests/topotests/srv6_locator/expected_locators5.json b/tests/topotests/srv6_locator/expected_locators5.json index 526cd2f154..8c512ebc46 100644 --- a/tests/topotests/srv6_locator/expected_locators5.json +++ b/tests/topotests/srv6_locator/expected_locators5.json @@ -3,7 +3,7 @@ { "name": "loc1", "prefix": "2001:db8:1:1::/64", - "status_up": true, + "statusUp": true, "chunks": [ { "prefix": "2001:db8:1:1::/64", @@ -14,7 +14,7 @@ { "name": "loc2", "prefix": "2001:db8:2:2::/64", - "status_up": true, + "statusUp": true, "chunks": [ { "prefix": "2001:db8:2:2::/64", @@ -25,7 +25,7 @@ { "name": "loc3", "prefix": "2001:db8:3:3::/64", - "status_up": true, + "statusUp": true, "chunks":[ { "prefix": "2001:db8:3:3::/64", From 054859269166720f36fe34096c904a7390f85f9e Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Mon, 22 Mar 2021 09:07:18 +0000 Subject: [PATCH 54/66] *: eliminate redundant info from srv6 locator zapi Signed-off-by: Hiroki Shirokura --- bgpd/bgp_zebra.c | 11 --------- lib/zclient.c | 6 ++--- sharpd/sharp_zebra.c | 53 ++++++++++++++------------------------------ 3 files changed, 19 insertions(+), 51 deletions(-) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index a10c6fd245..d4a4ed2305 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -3009,17 +3009,6 @@ static void bgp_zebra_process_srv6_locator_chunk(ZAPI_CALLBACK_ARGS) s = zclient->ibuf; zapi_srv6_locator_chunk_decode(s, &s6c); - if (zclient->redist_default != s6c.proto) { - zlog_err("%s: Got SRv6 Manager msg with wrong proto %u", - __func__, s6c.proto); - return; - } - if (zclient->instance != s6c.instance) { - zlog_err("%s: Got SRv6 Manager msg with wrong instance %u", - __func__, s6c.instance); - return; - } - if (strcmp(bgp->srv6_locator_name, s6c.locator_name) != 0) { zlog_err("%s: Locator name unmatch %s:%s", __func__, bgp->srv6_locator_name, s6c.locator_name); diff --git a/lib/zclient.c b/lib/zclient.c index 4d8fbdf157..5395d4799d 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -1070,8 +1070,6 @@ done: int zapi_srv6_locator_chunk_encode(struct stream *s, const struct srv6_locator_chunk *c) { - stream_putc(s, c->proto); - stream_putw(s, c->instance); stream_putw(s, strlen(c->locator_name)); stream_put(s, c->locator_name, strlen(c->locator_name)); stream_putw(s, c->prefix.prefixlen); @@ -1088,8 +1086,8 @@ int zapi_srv6_locator_chunk_decode(struct stream *s, { uint16_t len = 0; - STREAM_GETC(s, c->proto); - STREAM_GETW(s, c->instance); + c->prefix.family = AF_INET6; + STREAM_GETW(s, len); if (len > SRV6_LOCNAME_SIZE) goto stream_failure; diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c index ae4add6a60..2575475dd2 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -938,52 +938,33 @@ int sharp_zebra_srv6_manager_release_locator_chunk(const char *locator_name) static void sharp_zebra_process_srv6_locator_chunk(ZAPI_CALLBACK_ARGS) { struct stream *s = NULL; - uint8_t proto; - uint16_t instance; - uint16_t len; - char name[256] = {0}; - struct prefix_ipv6 *chunk = NULL; - - chunk = prefix_ipv6_new(); - - s = zclient->ibuf; - STREAM_GETC(s, proto); - STREAM_GETW(s, instance); - - STREAM_GETW(s, len); - STREAM_GET(name, s, len); - - STREAM_GETW(s, chunk->prefixlen); - STREAM_GET(&chunk->prefix, s, 16); - - if (zclient->redist_default != proto) { - zlog_err("Got SRv6 Manager msg with wrong proto %u", proto); - return; - } - if (zclient->instance != instance) { - zlog_err("Got SRv6 Manager msg with wrong instance %u", proto); - return; - } - - struct listnode *loc_node; + struct srv6_locator_chunk s6c = {}; + struct listnode *node, *nnode; struct sharp_srv6_locator *loc; - for (ALL_LIST_ELEMENTS_RO(sg.srv6_locators, loc_node, loc)) { + s = zclient->ibuf; + zapi_srv6_locator_chunk_decode(s, &s6c); + + for (ALL_LIST_ELEMENTS(sg.srv6_locators, node, nnode, loc)) { + struct prefix_ipv6 *chunk = NULL; struct listnode *chunk_node; struct prefix_ipv6 *c; - if (strcmp(loc->name, name)) + if (strcmp(loc->name, s6c.locator_name) != 0) { + zlog_err("%s: Locator name unmatch %s:%s", __func__, + loc->name, s6c.locator_name); continue; + } for (ALL_LIST_ELEMENTS_RO(loc->chunks, chunk_node, c)) - if (!prefix_cmp(c, chunk)) + if (!prefix_cmp(c, &s6c.prefix)) return; - listnode_add(loc->chunks, chunk); - } - return; -stream_failure: - free(chunk); + chunk = prefix_ipv6_new(); + *chunk = s6c.prefix; + listnode_add(loc->chunks, chunk); + return; + } zlog_err("%s: can't get locator_chunk!!", __func__); } From b9596f139b73929a57c796681f450dfbb7621947 Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Mon, 22 Mar 2021 09:28:32 +0000 Subject: [PATCH 55/66] zebra: fix implicit conversion Signed-off-by: Hiroki Shirokura --- zebra/rt_netlink.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 70db6234bb..acd545a565 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -473,7 +473,7 @@ parse_nexthop_unicast(ns_id_t ns_id, struct rtmsg *rtm, struct rtattr **tb, struct nexthop nh = {0}; mpls_label_t labels[MPLS_MAX_LABELS] = {0}; int num_labels = 0; - enum seg6local_action_t seg6l_act = SEG6_LOCAL_ACTION_UNSPEC; + enum seg6local_action_t seg6l_act = ZEBRA_SEG6_LOCAL_ACTION_UNSPEC; struct seg6local_context seg6l_ctx = {}; struct in6_addr seg6_segs = {}; int num_segs = 0; @@ -555,7 +555,7 @@ static uint8_t parse_multipath_nexthops_unicast(ns_id_t ns_id, /* MPLS labels */ mpls_label_t labels[MPLS_MAX_LABELS] = {0}; int num_labels = 0; - enum seg6local_action_t seg6l_act = SEG6_LOCAL_ACTION_UNSPEC; + enum seg6local_action_t seg6l_act = ZEBRA_SEG6_LOCAL_ACTION_UNSPEC; struct seg6local_context seg6l_ctx = {}; struct in6_addr seg6_segs = {}; int num_segs = 0; From 8a18a7c0c976993604dbf3b061c0e5ea0ec5f0d4 Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Mon, 22 Mar 2021 09:48:04 +0000 Subject: [PATCH 56/66] zebra: use const on fill_seg6ipt_encap func Signed-off-by: Hiroki Shirokura --- zebra/rt_netlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index acd545a565..535547a8a2 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1331,7 +1331,7 @@ static bool _netlink_route_encode_nexthop_src(const struct nexthop *nexthop, } static size_t fill_seg6ipt_encap(char *buffer, size_t buflen, - struct in6_addr *seg) + const struct in6_addr *seg) { struct seg6_iptunnel_encap *ipt; struct ipv6_sr_hdr *srh; From 52026569ca4f06dd4efe4c51994c2cf1a21d0618 Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Mon, 22 Mar 2021 10:36:17 +0000 Subject: [PATCH 57/66] zebra: error check for nl_attr_xxx Signed-off-by: Hiroki Shirokura --- zebra/rt_netlink.c | 147 ++++++++++++++++++++++++++++----------------- 1 file changed, 92 insertions(+), 55 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 535547a8a2..77c22bff9f 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1391,38 +1391,51 @@ static bool _netlink_route_build_singlepath(const struct prefix *p, const struct seg6local_context *ctx; ctx = nexthop->nh_seg6local_ctx; - nl_attr_put16(nlmsg, req_size, RTA_ENCAP_TYPE, - LWTUNNEL_ENCAP_SEG6_LOCAL); + if (!nl_attr_put16(nlmsg, req_size, RTA_ENCAP_TYPE, + LWTUNNEL_ENCAP_SEG6_LOCAL)) + return false; nest = nl_attr_nest(nlmsg, req_size, RTA_ENCAP); + if (!nest) + return false; + switch (nexthop->nh_seg6local_action) { case ZEBRA_SEG6_LOCAL_ACTION_END: - nl_attr_put32(nlmsg, req_size, SEG6_LOCAL_ACTION, - SEG6_LOCAL_ACTION_END); + if (!nl_attr_put32(nlmsg, req_size, SEG6_LOCAL_ACTION, + SEG6_LOCAL_ACTION_END)) + return false; break; case ZEBRA_SEG6_LOCAL_ACTION_END_X: - nl_attr_put32(nlmsg, req_size, SEG6_LOCAL_ACTION, - SEG6_LOCAL_ACTION_END_X); - nl_attr_put(nlmsg, req_size, SEG6_LOCAL_NH6, &ctx->nh6, - sizeof(struct in6_addr)); + if (!nl_attr_put32(nlmsg, req_size, SEG6_LOCAL_ACTION, + SEG6_LOCAL_ACTION_END_X)) + return false; + if (!nl_attr_put(nlmsg, req_size, SEG6_LOCAL_NH6, + &ctx->nh6, sizeof(struct in6_addr))) + return false; break; case ZEBRA_SEG6_LOCAL_ACTION_END_T: - nl_attr_put32(nlmsg, req_size, SEG6_LOCAL_ACTION, - SEG6_LOCAL_ACTION_END_T); - nl_attr_put32(nlmsg, req_size, SEG6_LOCAL_TABLE, - ctx->table); + if (!nl_attr_put32(nlmsg, req_size, SEG6_LOCAL_ACTION, + SEG6_LOCAL_ACTION_END_T)) + return false; + if (!nl_attr_put32(nlmsg, req_size, SEG6_LOCAL_TABLE, + ctx->table)) + return false; break; case ZEBRA_SEG6_LOCAL_ACTION_END_DX4: - nl_attr_put32(nlmsg, req_size, SEG6_LOCAL_ACTION, - SEG6_LOCAL_ACTION_END_DX4); - nl_attr_put(nlmsg, req_size, SEG6_LOCAL_NH4, &ctx->nh4, - sizeof(struct in_addr)); + if (!nl_attr_put32(nlmsg, req_size, SEG6_LOCAL_ACTION, + SEG6_LOCAL_ACTION_END_DX4)) + return false; + if (!nl_attr_put(nlmsg, req_size, SEG6_LOCAL_NH4, + &ctx->nh4, sizeof(struct in_addr))) + return false; break; case ZEBRA_SEG6_LOCAL_ACTION_END_DT6: - nl_attr_put32(nlmsg, req_size, SEG6_LOCAL_ACTION, - SEG6_LOCAL_ACTION_END_DT6); - nl_attr_put32(nlmsg, req_size, SEG6_LOCAL_TABLE, - ctx->table); + if (!nl_attr_put32(nlmsg, req_size, SEG6_LOCAL_ACTION, + SEG6_LOCAL_ACTION_END_DT6)) + return false; + if (!nl_attr_put32(nlmsg, req_size, SEG6_LOCAL_TABLE, + ctx->table)) + return false; break; default: zlog_err("%s: unsupport seg6local behaviour action=%u", @@ -1437,13 +1450,17 @@ static bool _netlink_route_build_singlepath(const struct prefix *p, size_t tun_len; struct rtattr *nest; - nl_attr_put16(nlmsg, req_size, RTA_ENCAP_TYPE, - LWTUNNEL_ENCAP_SEG6); + if (!nl_attr_put16(nlmsg, req_size, RTA_ENCAP_TYPE, + LWTUNNEL_ENCAP_SEG6)) + return false; nest = nl_attr_nest(nlmsg, req_size, RTA_ENCAP); + if (!nest) + return false; tun_len = fill_seg6ipt_encap(tun_buf, sizeof(tun_buf), nexthop->nh_seg6_segs); - nl_attr_put(nlmsg, req_size, SEG6_IPTUNNEL_SRH, - tun_buf, tun_len); + if (!nl_attr_put(nlmsg, req_size, SEG6_IPTUNNEL_SRH, tun_buf, + tun_len)) + return false; nl_attr_nest_end(nlmsg, nest); } @@ -2451,48 +2468,62 @@ ssize_t netlink_nexthop_msg_encode(uint16_t cmd, action = nh->nh_seg6local_action; ctx = nh->nh_seg6local_ctx; encap = LWTUNNEL_ENCAP_SEG6_LOCAL; - nl_attr_put(&req->n, buflen, NHA_ENCAP_TYPE, - &encap, sizeof(uint16_t)); + if (!nl_attr_put(&req->n, buflen, + NHA_ENCAP_TYPE, &encap, + sizeof(uint16_t))) + return 0; nest = nl_attr_nest(&req->n, buflen, NHA_ENCAP | NLA_F_NESTED); + if (!nest) + return 0; + switch (action) { case SEG6_LOCAL_ACTION_END: - nl_attr_put32(&req->n, buflen, - SEG6_LOCAL_ACTION, - SEG6_LOCAL_ACTION_END); + if (!nl_attr_put32(&req->n, buflen, + SEG6_LOCAL_ACTION, + SEG6_LOCAL_ACTION_END)) + return 0; break; case SEG6_LOCAL_ACTION_END_X: - nl_attr_put32(&req->n, buflen, - SEG6_LOCAL_ACTION, - SEG6_LOCAL_ACTION_END_X); - nl_attr_put(&req->n, buflen, + if (!nl_attr_put32(&req->n, buflen, + SEG6_LOCAL_ACTION, + SEG6_LOCAL_ACTION_END_X)) + return 0; + if (!nl_attr_put(&req->n, buflen, SEG6_LOCAL_NH6, &ctx->nh6, - sizeof(struct in6_addr)); + sizeof(struct in6_addr))) + return 0; break; case SEG6_LOCAL_ACTION_END_T: - nl_attr_put32(&req->n, buflen, - SEG6_LOCAL_ACTION, - SEG6_LOCAL_ACTION_END_T); - nl_attr_put32(&req->n, buflen, - SEG6_LOCAL_TABLE, - ctx->table); + if (!nl_attr_put32(&req->n, buflen, + SEG6_LOCAL_ACTION, + SEG6_LOCAL_ACTION_END_T)) + return 0; + if (!nl_attr_put32(&req->n, buflen, + SEG6_LOCAL_TABLE, + ctx->table)) + return 0; break; case SEG6_LOCAL_ACTION_END_DX4: - nl_attr_put32(&req->n, buflen, - SEG6_LOCAL_ACTION, - SEG6_LOCAL_ACTION_END_DX4); - nl_attr_put(&req->n, buflen, + if (!nl_attr_put32(&req->n, buflen, + SEG6_LOCAL_ACTION, + SEG6_LOCAL_ACTION_END_DX4)) + return 0; + if (!nl_attr_put(&req->n, buflen, SEG6_LOCAL_NH4, &ctx->nh4, - sizeof(struct in_addr)); + sizeof(struct in_addr))) + return 0; break; case SEG6_LOCAL_ACTION_END_DT6: - nl_attr_put32(&req->n, buflen, - SEG6_LOCAL_ACTION, - SEG6_LOCAL_ACTION_END_DT6); - nl_attr_put32(&req->n, buflen, - SEG6_LOCAL_TABLE, - ctx->table); + if (!nl_attr_put32(&req->n, buflen, + SEG6_LOCAL_ACTION, + SEG6_LOCAL_ACTION_END_DT6)) + return 0; + if (!nl_attr_put32(&req->n, buflen, + SEG6_LOCAL_TABLE, + ctx->table)) + return 0; break; default: zlog_err("%s: unsupport seg6local behaviour action=%u", @@ -2507,15 +2538,21 @@ ssize_t netlink_nexthop_msg_encode(uint16_t cmd, size_t tun_len; struct rtattr *nest; - nl_attr_put16(&req->n, buflen, NHA_ENCAP_TYPE, - LWTUNNEL_ENCAP_SEG6); + if (!nl_attr_put16(&req->n, buflen, + NHA_ENCAP_TYPE, + LWTUNNEL_ENCAP_SEG6)) + return 0; nest = nl_attr_nest(&req->n, buflen, NHA_ENCAP | NLA_F_NESTED); + if (!nest) + return 0; tun_len = fill_seg6ipt_encap(tun_buf, sizeof(tun_buf), nh->nh_seg6_segs); - nl_attr_put(&req->n, buflen, SEG6_IPTUNNEL_SRH, - tun_buf, tun_len); + if (!nl_attr_put(&req->n, buflen, + SEG6_IPTUNNEL_SRH, + tun_buf, tun_len)) + return 0; nl_attr_nest_end(&req->n, nest); } From a2df1e4f9a6b9f2f8cc0e9242b351dec1b88f1ae Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Mon, 22 Mar 2021 11:32:09 +0000 Subject: [PATCH 58/66] sharpd: follow the practice on cli design for json output The "show sharp segment-routing srv6" command was a json output command, but it did not follow the common practice of the other commands. It follows the review and outputs the json format by using the json keyword. Otherwise, it produces human readable output. Signed-off-by: Hiroki Shirokura --- sharpd/sharp_vty.c | 47 +++++++++++++------ .../srv6_locator/test_srv6_locator.py | 2 +- 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index 72bc7d16b9..a6fcb8d58c 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -988,37 +988,54 @@ DEFPY (sharp_srv6_manager_release_locator_chunk, DEFPY (show_sharp_segment_routing_srv6, show_sharp_segment_routing_srv6_cmd, - "show sharp segment-routing srv6", + "show sharp segment-routing srv6 [json]", SHOW_STR SHARP_STR "Segment-Routing\n" - "Segment-Routing IPv6\n") + "Segment-Routing IPv6\n" + JSON_STR) { char str[256]; struct listnode *loc_node; struct listnode *chunk_node; struct sharp_srv6_locator *loc; struct prefix_ipv6 *chunk; + bool uj = use_json(argc, argv); json_object *jo_locs = NULL; json_object *jo_loc = NULL; json_object *jo_chunks = NULL; - jo_locs = json_object_new_array(); - for (ALL_LIST_ELEMENTS_RO(sg.srv6_locators, loc_node, loc)) { - jo_loc = json_object_new_object(); - json_object_array_add(jo_locs, jo_loc); - json_object_string_add(jo_loc, "name", loc->name); - jo_chunks = json_object_new_array(); - json_object_object_add(jo_loc, "chunks", jo_chunks); - for (ALL_LIST_ELEMENTS_RO(loc->chunks, chunk_node, chunk)) { - prefix2str(chunk, str, sizeof(str)); - json_array_string_add(jo_chunks, str); + if (uj) { + jo_locs = json_object_new_array(); + for (ALL_LIST_ELEMENTS_RO(sg.srv6_locators, loc_node, loc)) { + jo_loc = json_object_new_object(); + json_object_array_add(jo_locs, jo_loc); + json_object_string_add(jo_loc, "name", loc->name); + jo_chunks = json_object_new_array(); + json_object_object_add(jo_loc, "chunks", jo_chunks); + for (ALL_LIST_ELEMENTS_RO(loc->chunks, chunk_node, + chunk)) { + prefix2str(chunk, str, sizeof(str)); + json_array_string_add(jo_chunks, str); + } + } + + vty_out(vty, "%s\n", json_object_to_json_string_ext( + jo_locs, JSON_C_TO_STRING_PRETTY)); + json_object_free(jo_locs); + } else { + for (ALL_LIST_ELEMENTS_RO(sg.srv6_locators, loc_node, loc)) { + vty_out(vty, "Locator %s has %d prefix chunks\n", + loc->name, listcount(loc->chunks)); + for (ALL_LIST_ELEMENTS_RO(loc->chunks, chunk_node, + chunk)) { + prefix2str(chunk, str, sizeof(str)); + vty_out(vty, " %s\n", str); + } + vty_out(vty, "\n"); } } - vty_out(vty, "%s\n", json_object_to_json_string_ext( - jo_locs, JSON_C_TO_STRING_PRETTY)); - json_object_free(jo_locs); return CMD_SUCCESS; } diff --git a/tests/topotests/srv6_locator/test_srv6_locator.py b/tests/topotests/srv6_locator/test_srv6_locator.py index 91850b5045..a7416ce085 100755 --- a/tests/topotests/srv6_locator/test_srv6_locator.py +++ b/tests/topotests/srv6_locator/test_srv6_locator.py @@ -89,7 +89,7 @@ def test_srv6(): def _check_sharpd_chunk(router, expected_chunk_file): logger.info("checking sharpd locator chunk status") - output = json.loads(router.vtysh_cmd("show sharp segment-routing srv6")) + output = json.loads(router.vtysh_cmd("show sharp segment-routing srv6 json")) expected = open_json_file("{}/{}".format(CWD, expected_chunk_file)) return topotest.json_cmp(output, expected) From f463eac7687e9c7a1fac87a5e4563580dc8ec4c9 Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Mon, 22 Mar 2021 13:58:20 +0000 Subject: [PATCH 59/66] zebra: fill_seg6ipt_encap func with boundary check Signed-off-by: Hiroki Shirokura --- zebra/rt_netlink.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 77c22bff9f..d40c717018 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1330,13 +1330,26 @@ static bool _netlink_route_encode_nexthop_src(const struct nexthop *nexthop, return true; } -static size_t fill_seg6ipt_encap(char *buffer, size_t buflen, - const struct in6_addr *seg) +static ssize_t fill_seg6ipt_encap(char *buffer, size_t buflen, + const struct in6_addr *seg) { struct seg6_iptunnel_encap *ipt; struct ipv6_sr_hdr *srh; const size_t srhlen = 24; + /* + * Caution: Support only SINGLE-SID, not MULTI-SID + * This function only supports the case where segs represents + * a single SID. If you want to extend the SRv6 functionality, + * you should improve the Boundary Check. + * Ex. In case of set a SID-List include multiple-SIDs as an + * argument of the Transit Behavior, we must support variable + * boundary check for buflen. + */ + if (buflen < (sizeof(struct seg6_iptunnel_encap) + + sizeof(struct ipv6_sr_hdr) + 16)) + return -1; + memset(buffer, 0, buflen); ipt = (struct seg6_iptunnel_encap *)buffer; @@ -1447,7 +1460,7 @@ static bool _netlink_route_build_singlepath(const struct prefix *p, if (nexthop->nh_seg6_segs) { char tun_buf[4096]; - size_t tun_len; + ssize_t tun_len; struct rtattr *nest; if (!nl_attr_put16(nlmsg, req_size, RTA_ENCAP_TYPE, @@ -1458,6 +1471,8 @@ static bool _netlink_route_build_singlepath(const struct prefix *p, return false; tun_len = fill_seg6ipt_encap(tun_buf, sizeof(tun_buf), nexthop->nh_seg6_segs); + if (tun_len < 0) + return false; if (!nl_attr_put(nlmsg, req_size, SEG6_IPTUNNEL_SRH, tun_buf, tun_len)) return false; @@ -2535,7 +2550,7 @@ ssize_t netlink_nexthop_msg_encode(uint16_t cmd, if (nh->nh_seg6_segs) { char tun_buf[4096]; - size_t tun_len; + ssize_t tun_len; struct rtattr *nest; if (!nl_attr_put16(&req->n, buflen, @@ -2549,6 +2564,8 @@ ssize_t netlink_nexthop_msg_encode(uint16_t cmd, tun_len = fill_seg6ipt_encap(tun_buf, sizeof(tun_buf), nh->nh_seg6_segs); + if (tun_len < 0) + return 0; if (!nl_attr_put(&req->n, buflen, SEG6_IPTUNNEL_SRH, tun_buf, tun_len)) From 1cb131eec38c168f8d5ff8bd1cb95fc0d0cc2df6 Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Fri, 2 Apr 2021 12:12:20 +0000 Subject: [PATCH 60/66] sharpd: split srv6 route install command Signed-off-by: Hiroki Shirokura --- sharpd/sharp_vty.c | 239 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 180 insertions(+), 59 deletions(-) diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index a6fcb8d58c..7cd9b959f8 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -191,14 +191,7 @@ DEFPY (install_routes, "sharp install routes [vrf NAME$vrf_name]\ \ |\ - nexthop-group NHGNAME$nexthop_group|\ - nexthop-seg6local NAME$seg6l_oif\ - |\ - nexthop-seg6$nh_seg6 X:X::X:X$seg6_nh6 encap X:X::X:X$seg6_seg>\ + nexthop-group NHGNAME$nexthop_group>\ [backup$backup ] \ (1-1000000)$routes [instance (0-255)$instance] [repeat (2-1000)$rpt] [opaque WORD]", "Sharp routing Protocol\n" @@ -213,21 +206,6 @@ DEFPY (install_routes, "V6 Nexthop address to use\n" "Nexthop-Group to use\n" "The Name of the nexthop-group\n" - "Nexthop-seg6local to use\n" - "Output device to use\n" - "SRv6 End function to use\n" - "SRv6 End.X function to use\n" - "V6 Nexthop address to use\n" - "SRv6 End.T function to use\n" - "Redirect table id to use\n" - "SRv6 End.DX4 function to use\n" - "V4 Nexthop address to use\n" - "SRv6 End.DT6 function to use\n" - "Redirect table id to use\n" - "Nexthop-seg6 to use\n" - "V6 Nexthop address to use\n" - "Encap mode\n" - "Segment List to use\n" "Backup nexthop to use(Can be an IPv4 or IPv6 address)\n" "Backup V4 Nexthop address to use\n" "Backup V6 Nexthop address to use\n" @@ -243,7 +221,6 @@ DEFPY (install_routes, struct prefix prefix; uint32_t rts; uint32_t nhgid = 0; - uint32_t route_flags = 0; sg.r.total_routes = routes; sg.r.installed_routes = 0; @@ -315,40 +292,6 @@ DEFPY (install_routes, sg.r.backup_nhop.vrf_id = vrf->vrf_id; sg.r.backup_nhop_group.nexthop = bnhgc->nhg.nexthop; } - } else if (seg6l_oif) { - struct seg6local_context ctx = {}; - enum seg6local_action_t action; - - if (seg6l_enddx4) { - action = ZEBRA_SEG6_LOCAL_ACTION_END_DX4; - ctx.nh4 = seg6l_enddx4_nh4; - } else if (seg6l_endx) { - action = ZEBRA_SEG6_LOCAL_ACTION_END_X; - ctx.nh6 = seg6l_endx_nh6; - } else if (seg6l_endt) { - action = ZEBRA_SEG6_LOCAL_ACTION_END_T; - ctx.table = seg6l_endt_table; - } else if (seg6l_enddt6) { - action = ZEBRA_SEG6_LOCAL_ACTION_END_DT6; - ctx.table = seg6l_enddt6_table; - } else { - action = ZEBRA_SEG6_LOCAL_ACTION_END; - } - - sg.r.nhop.type = NEXTHOP_TYPE_IFINDEX; - sg.r.nhop.ifindex = ifname2ifindex(seg6l_oif, vrf->vrf_id); - sg.r.nhop.vrf_id = vrf->vrf_id; - sg.r.nhop_group.nexthop = &sg.r.nhop; - nexthop_add_seg6local(&sg.r.nhop, action, &ctx); - SET_FLAG(route_flags, ZEBRA_FLAG_SEG6LOCAL_ROUTE); - } else if (nh_seg6) { - sg.r.nhop.type = NEXTHOP_TYPE_IPV6; - sg.r.nhop.gate.ipv6 = seg6_nh6; - sg.r.nhop.vrf_id = vrf->vrf_id; - sg.r.nhop_group.nexthop = &sg.r.nhop; - - nexthop_add_seg6(&sg.r.nhop, &seg6_seg); - SET_FLAG(route_flags, ZEBRA_FLAG_SEG6_ROUTE); } else { if (nexthop4.s_addr != INADDR_ANY) { sg.r.nhop.gate.ipv4 = nexthop4; @@ -391,7 +334,183 @@ DEFPY (install_routes, rts = routes; sharp_install_routes_helper(&prefix, sg.r.vrf_id, sg.r.inst, nhgid, &sg.r.nhop_group, &sg.r.backup_nhop_group, - rts, route_flags, sg.r.opaque); + rts, 0, sg.r.opaque); + + return CMD_SUCCESS; +} + +DEFPY (install_seg6_routes, + install_seg6_routes_cmd, + "sharp install seg6-routes [vrf NAME$vrf_name]\ + \ + nexthop-seg6 X:X::X:X$seg6_nh6 encap X:X::X:X$seg6_seg\ + (1-1000000)$routes [repeat (2-1000)$rpt]", + "Sharp routing Protocol\n" + "install some routes\n" + "Routes to install\n" + "The vrf we would like to install into if non-default\n" + "The NAME of the vrf\n" + "v4 Address to start /32 generation at\n" + "v6 Address to start /32 generation at\n" + "Nexthop-seg6 to use\n" + "V6 Nexthop address to use\n" + "Encap mode\n" + "Segment List to use\n" + "How many to create\n" + "Should we repeat this command\n" + "How many times to repeat this command\n") +{ + struct vrf *vrf; + struct prefix prefix; + uint32_t route_flags = 0; + + sg.r.total_routes = routes; + sg.r.installed_routes = 0; + + if (rpt >= 2) + sg.r.repeat = rpt * 2; + else + sg.r.repeat = 0; + + memset(&prefix, 0, sizeof(prefix)); + memset(&sg.r.orig_prefix, 0, sizeof(sg.r.orig_prefix)); + memset(&sg.r.nhop, 0, sizeof(sg.r.nhop)); + memset(&sg.r.nhop_group, 0, sizeof(sg.r.nhop_group)); + memset(&sg.r.backup_nhop, 0, sizeof(sg.r.nhop)); + memset(&sg.r.backup_nhop_group, 0, sizeof(sg.r.nhop_group)); + sg.r.opaque[0] = '\0'; + sg.r.inst = 0; + + if (start4.s_addr != INADDR_ANY) { + prefix.family = AF_INET; + prefix.prefixlen = 32; + prefix.u.prefix4 = start4; + } else { + prefix.family = AF_INET6; + prefix.prefixlen = 128; + prefix.u.prefix6 = start6; + } + sg.r.orig_prefix = prefix; + + if (!vrf_name) + vrf_name = VRF_DEFAULT_NAME; + + vrf = vrf_lookup_by_name(vrf_name); + if (!vrf) { + vty_out(vty, "The vrf NAME specified: %s does not exist\n", + vrf_name); + return CMD_WARNING; + } + + sg.r.nhop.type = NEXTHOP_TYPE_IPV6; + sg.r.nhop.gate.ipv6 = seg6_nh6; + sg.r.nhop.vrf_id = vrf->vrf_id; + sg.r.nhop_group.nexthop = &sg.r.nhop; + + nexthop_add_seg6(&sg.r.nhop, &seg6_seg); + SET_FLAG(route_flags, ZEBRA_FLAG_SEG6_ROUTE); + + sg.r.vrf_id = vrf->vrf_id; + sharp_install_routes_helper(&prefix, sg.r.vrf_id, sg.r.inst, 0, + &sg.r.nhop_group, &sg.r.backup_nhop_group, + routes, route_flags, sg.r.opaque); + + return CMD_SUCCESS; +} + +DEFPY (install_seg6local_routes, + install_seg6local_routes_cmd, + "sharp install seg6local-routes [vrf NAME$vrf_name]\ + X:X::X:X$start6\ + nexthop-seg6local NAME$seg6l_oif\ + \ + (1-1000000)$routes [repeat (2-1000)$rpt]", + "Sharp routing Protocol\n" + "install some routes\n" + "Routes to install\n" + "The vrf we would like to install into if non-default\n" + "The NAME of the vrf\n" + "v6 Address to start /32 generation at\n" + "Nexthop-seg6local to use\n" + "Output device to use\n" + "SRv6 End function to use\n" + "SRv6 End.X function to use\n" + "V6 Nexthop address to use\n" + "SRv6 End.T function to use\n" + "Redirect table id to use\n" + "SRv6 End.DX4 function to use\n" + "V4 Nexthop address to use\n" + "SRv6 End.DT6 function to use\n" + "Redirect table id to use\n" + "How many to create\n" + "Should we repeat this command\n" + "How many times to repeat this command\n") +{ + struct vrf *vrf; + uint32_t route_flags = 0; + struct seg6local_context ctx = {}; + enum seg6local_action_t action; + + sg.r.total_routes = routes; + sg.r.installed_routes = 0; + + if (rpt >= 2) + sg.r.repeat = rpt * 2; + else + sg.r.repeat = 0; + + memset(&sg.r.orig_prefix, 0, sizeof(sg.r.orig_prefix)); + memset(&sg.r.nhop, 0, sizeof(sg.r.nhop)); + memset(&sg.r.nhop_group, 0, sizeof(sg.r.nhop_group)); + memset(&sg.r.backup_nhop, 0, sizeof(sg.r.nhop)); + memset(&sg.r.backup_nhop_group, 0, sizeof(sg.r.nhop_group)); + sg.r.opaque[0] = '\0'; + sg.r.inst = 0; + sg.r.orig_prefix.family = AF_INET6; + sg.r.orig_prefix.prefixlen = 128; + sg.r.orig_prefix.u.prefix6 = start6; + + if (!vrf_name) + vrf_name = VRF_DEFAULT_NAME; + + vrf = vrf_lookup_by_name(vrf_name); + if (!vrf) { + vty_out(vty, "The vrf NAME specified: %s does not exist\n", + vrf_name); + return CMD_WARNING; + } + + if (seg6l_enddx4) { + action = ZEBRA_SEG6_LOCAL_ACTION_END_DX4; + ctx.nh4 = seg6l_enddx4_nh4; + } else if (seg6l_endx) { + action = ZEBRA_SEG6_LOCAL_ACTION_END_X; + ctx.nh6 = seg6l_endx_nh6; + } else if (seg6l_endt) { + action = ZEBRA_SEG6_LOCAL_ACTION_END_T; + ctx.table = seg6l_endt_table; + } else if (seg6l_enddt6) { + action = ZEBRA_SEG6_LOCAL_ACTION_END_DT6; + ctx.table = seg6l_enddt6_table; + } else { + action = ZEBRA_SEG6_LOCAL_ACTION_END; + } + + sg.r.nhop.type = NEXTHOP_TYPE_IFINDEX; + sg.r.nhop.ifindex = ifname2ifindex(seg6l_oif, vrf->vrf_id); + sg.r.nhop.vrf_id = vrf->vrf_id; + sg.r.nhop_group.nexthop = &sg.r.nhop; + nexthop_add_seg6local(&sg.r.nhop, action, &ctx); + SET_FLAG(route_flags, ZEBRA_FLAG_SEG6LOCAL_ROUTE); + + sg.r.vrf_id = vrf->vrf_id; + sharp_install_routes_helper(&sg.r.orig_prefix, sg.r.vrf_id, sg.r.inst, 0, + &sg.r.nhop_group, &sg.r.backup_nhop_group, + routes, route_flags, sg.r.opaque); return CMD_SUCCESS; } @@ -1043,6 +1162,8 @@ void sharp_vty_init(void) { install_element(ENABLE_NODE, &install_routes_data_dump_cmd); install_element(ENABLE_NODE, &install_routes_cmd); + install_element(ENABLE_NODE, &install_seg6_routes_cmd); + install_element(ENABLE_NODE, &install_seg6local_routes_cmd); install_element(ENABLE_NODE, &remove_routes_cmd); install_element(ENABLE_NODE, &vrf_label_cmd); install_element(ENABLE_NODE, &sharp_nht_data_dump_cmd); From e2a5888d7c9e6fc2f0bfa040670161c63209b00f Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Fri, 2 Apr 2021 12:12:46 +0000 Subject: [PATCH 61/66] tests: update sharpd srv6 route command Signed-off-by: Hiroki Shirokura --- tests/topotests/zebra_seg6_route/test_zebra_seg6_route.py | 2 +- .../zebra_seg6local_route/test_zebra_seg6local_route.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/topotests/zebra_seg6_route/test_zebra_seg6_route.py b/tests/topotests/zebra_seg6_route/test_zebra_seg6_route.py index e14d9690c1..e83b2c1007 100755 --- a/tests/topotests/zebra_seg6_route/test_zebra_seg6_route.py +++ b/tests/topotests/zebra_seg6_route/test_zebra_seg6_route.py @@ -82,7 +82,7 @@ def test_zebra_seg6local_routes(): r1 = tgen.gears["r1"] def check(router, dest, nh, sid, expected): - router.vtysh_cmd("sharp install routes {} "\ + router.vtysh_cmd("sharp install seg6-routes {} "\ "nexthop-seg6 {} encap {} 1".format(dest, nh, sid)) output = json.loads(router.vtysh_cmd("show ipv6 route {} json".format(dest))) output = output.get('{}/128'.format(dest)) diff --git a/tests/topotests/zebra_seg6local_route/test_zebra_seg6local_route.py b/tests/topotests/zebra_seg6local_route/test_zebra_seg6local_route.py index 66c6ac6dd2..1c9d208fef 100755 --- a/tests/topotests/zebra_seg6local_route/test_zebra_seg6local_route.py +++ b/tests/topotests/zebra_seg6local_route/test_zebra_seg6local_route.py @@ -82,7 +82,7 @@ def test_zebra_seg6local_routes(): r1 = tgen.gears["r1"] def check(router, dest, context, expected): - router.vtysh_cmd("sharp install routes {} "\ + router.vtysh_cmd("sharp install seg6local-routes {} "\ "nexthop-seg6local dum0 {} 1".format(dest, context)) output = json.loads(router.vtysh_cmd("show ipv6 route {} json".format(dest))) output = output.get('{}/128'.format(dest)) From 4ccd40339c232aa87f180c9893b5b929ea8713d8 Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Sat, 3 Apr 2021 17:33:06 +0000 Subject: [PATCH 62/66] doc: update srv6 cli guide Signed-off-by: Hiroki Shirokura --- doc/user/bgp.rst | 47 +++++++++++++++ doc/user/sharp.rst | 139 +++++++++++++++++++++++++++++++++++++++++++++ doc/user/zebra.rst | 113 +++++++++++++++++++++++------------- 3 files changed, 259 insertions(+), 40 deletions(-) diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index dd042e2584..0e01b8c3e4 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -2597,6 +2597,19 @@ address-family: The CLI will disallow attempts to configure incompatible leaking modes. +.. _bgp-l3vpn-srv6: + +L3VPN SRv6 +---------- + +.. clicmd:: segment-routing srv6 + + Use SRv6 backend with BGP L3VPN, and go to its configuration node. + +.. clicmd:: locator NAME + + Specify the SRv6 locator to be used for SRv6 L3VPN. The Locator name must + be set in zebra, but user can set it in any order. .. _bgp-evpn: @@ -3528,6 +3541,40 @@ Displaying Update Group Information Display Information about update-group events in FRR. +Segment-Routing IPv6 +-------------------- + +.. clicmd:: show bgp segment-routing srv6 + + This command displays information about SRv6 L3VPN in bgpd. Specifically, + what kind of Locator is being used, and its Locator chunk information. + And the SID of the SRv6 Function that is actually managed on bgpd. + In the following example, bgpd is using a Locator named loc1, and two SRv6 + Functions are managed to perform VPNv6 VRF redirect for vrf10 and vrf20. + +:: + + router# show bgp segment-routing srv6 + locator_name: loc1 + locator_chunks: + - 2001:db8:1:1::/64 + functions: + - sid: 2001:db8:1:1::100 + locator: loc1 + - sid: 2001:db8:1:1::200 + locator: loc1 + bgps: + - name: default + vpn_policy[AFI_IP].tovpn_sid: none + vpn_policy[AFI_IP6].tovpn_sid: none + - name: vrf10 + vpn_policy[AFI_IP].tovpn_sid: none + vpn_policy[AFI_IP6].tovpn_sid: 2001:db8:1:1::100 + - name: vrf20 + vpn_policy[AFI_IP].tovpn_sid: none + vpn_policy[AFI_IP6].tovpn_sid: 2001:db8:1:1::200 + + .. _bgp-route-reflector: Route Reflector diff --git a/doc/user/sharp.rst b/doc/user/sharp.rst index 0542a593ae..49aa6a08ef 100644 --- a/doc/user/sharp.rst +++ b/doc/user/sharp.rst @@ -147,4 +147,143 @@ keyword. At present, no sharp commands will be preserved in the config. Show imported Traffic Engineering Data Base +.. clicmd:: sharp install seg6-routes [vrf NAME] nexthop-seg6 X:X::X:X encap X:X::X:X (1-1000000) + This command installs a route for SRv6 Transit behavior (on Linux it is + known as seg6 route). The count, destination, vrf, etc. have the same + meaning as in the ``sharp install routes`` command. With this command, + sharpd will request zebra to configure seg6 route via ZEBRA_ROUTE_ADD + ZAPI. As in the following example. + +:: + + router# sharp install seg6-routes 1::A nexthop-seg6 2001::2 encap A:: 1 + router# sharp install seg6-routes 1::B nexthop-seg6 2001::2 encap B:: 1 + + router# show ipv6 route + D>* 1::A/128 [150/0] via 2001::2, dum0, seg6 a::, weight 1, 00:00:01 + D>* 1::B/128 [150/0] via 2001::2, dum0, seg6 b::, weight 1, 00:00:01 + + bash# ip -6 route list + 1::A encap seg6 mode encap segs 1 [ a:: ] via 2001::2 dev dum0 proto 194 metric 20 pref medium + 1::B encap seg6 mode encap segs 1 [ b:: ] via 2001::2 dev dum0 proto 194 metric 20 pref medium + +.. clicmd:: sharp install seg6local-routes [vrf NAME] X:X::X:X nexthop-seg6local NAME ACTION ARGS.. (1-1000000) + + This command installs a route for SRv6 Endpoint behavior (on Linux it is + known as seg6local route). The count, destination, vrf, etc. have the same + meaning as in the ``sharp install routes`` command. With this command, + sharpd will request zebra to configure seg6local route via ZEBRA_ROUTE_ADD + ZAPI. As in the following example. + + There are many End Functions defined in SRv6, which have been standardized + in RFC 8986. The current implementation supports End, End.X, End.T, End.DX4, + and End.DT6, which can be configured as follows. + +:: + + router# sharp install seg6local-routes 1::1 nexthop-seg6local dum0 End 1 + router# sharp install seg6local-routes 1::2 nexthop-seg6local dum0 End_X 2001::1 1 + router# sharp install seg6local-routes 1::3 nexthop-seg6local dum0 End_T 10 1 + router# sharp install seg6local-routes 1::4 nexthop-seg6local dum0 End_DX4 10.0.0.1 1 + router# sharp install seg6local-routes 1::5 nexthop-seg6local dum0 End_DT6 10 1 + + router# show ipv6 route + D>* 1::1/128 [150/0] is directly connected, dum0, seg6local End USP, weight 1, 00:00:05 + D>* 1::2/128 [150/0] is directly connected, dum0, seg6local End.X nh6 2001::1, weight 1, 00:00:05 + D>* 1::3/128 [150/0] is directly connected, dum0, seg6local End.T table 10, weight 1, 00:00:05 + D>* 1::4/128 [150/0] is directly connected, dum0, seg6local End.DX4 nh4 10.0.0.1, weight 1, 00:00:05 + D>* 1::5/128 [150/0] is directly connected, dum0, seg6local End.DT6 table 10, weight 1, 00:00:05 + + bash# ip -6 route + 1::1 encap seg6local action End dev dum0 proto 194 metric 20 pref medium + 1::2 encap seg6local action End.X nh6 2001::1 dev dum0 proto 194 metric 20 pref medium + 1::3 encap seg6local action End.T table 10 dev dum0 proto 194 metric 20 pref medium + 1::4 encap seg6local action End.DX4 nh4 10.0.0.1 dev dum0 proto 194 metric 20 pref medium + 1::5 encap seg6local action End.DT6 table 10 dev dum0 proto 194 metric 20 pref medium + +.. clicmd:: show sharp segment-routing srv6 + + This command shows us what SRv6 locator chunk, sharp is holding as zclient. + An SRv6 locator is defined for each SRv6 router, and a single locator may + be shared by multiple protocols. + + In the FRRouting implementation, the Locator chunk get request is executed + by a routing protocol daemon such as sharpd or bgpd, And then Zebra + allocates a Locator Chunk, which is a subset of the Locator Prefix, and + notifies the requesting protocol daemon of this information. + + This command example shows how the locator chunk of sharpd itself is + allocated. + +:: + + router# show segment-routing srv6 locator + Locator: + Name ID 2 2001:db8:2:2::/64 Up + + router# show sharp segment-routing srv6 + Locator loc1 has 1 prefix chunks + 2001:db8:1:1::/64 + +.. clicmd:: sharp srv6-manager get-locator-chunk + + This command requests the SRv6 locator to allocate a locator chunk via ZAPI. + This chunk can be owned by the protocol daemon, and the chunk obtained by + sharpd will not be used by the SRv6 mechanism of another routing protocol. + + Since this request is made asynchronously, it can be issued before the SRv6 + locator is configured on the zebra side, and as soon as it is ready on the + zebra side, sharpd can check the allocated locator chunk via zapi. + +:: + + router# show segment-routing srv6 locator loc1 detail + Name: loc1 + Prefix: 2001:db8:1:1::/64 + Chunks: + - prefix: 2001:db8:1:1::/64, owner: system + + router# show sharp segment-routing srv6 + (nothing) + + router# sharp srv6-manager get-locator-chunk loc1 + + router# show segment-routing srv6 locator loc1 detail + Name: loc1 + Prefix: 2001:db8:1:1::/64 + Chunks: + - prefix: 2001:db8:1:1::/64, owner: sharp + + router# show sharp segment-routing srv6 + Locator loc1 has 1 prefix chunks + 2001:db8:1:1::/64 + +.. clicmd:: sharp srv6-manager release-locator-chunk + + This command releases a locator chunk that has already been allocated by + ZAPI. The freed chunk will have its owner returned to the system and will + be available to another protocol daemon. + +:: + + router# show segment-routing srv6 locator loc1 detail + Name: loc1 + Prefix: 2001:db8:1:1::/64 + Chunks: + - prefix: 2001:db8:1:1::/64, owner: sharp + + router# show sharp segment-routing srv6 + Locator loc1 has 1 prefix chunks + 2001:db8:1:1::/64 + + router# sharp srv6-manager release-locator-chunk loc1 + + router# show segment-routing srv6 locator loc1 detail + Name: loc1 + Prefix: 2001:db8:1:1::/64 + Chunks: + - prefix: 2001:db8:1:1::/64, owner: system + + router# show sharp segment-routing srv6 + (nothing) diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index 2522ec6771..34e1028833 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -622,7 +622,7 @@ presence of the entry. .. _zebra-srv6: -Segment-Routing SRv6 +Segment-Routing IPv6 ==================== Segment-Routing is source routing paradigm that allows @@ -640,14 +640,12 @@ and this section also helps that case. .. index:: show segment-routing srv6 locator [json] .. clicmd:: show segment-routing srv6 locator [json] - This command dump SRv6-locator configured on zebra. - SRv6-locator is used to route to the node before performing - the SRv6-function. and that works as aggregation of - SRv6-function's IDs. - Following console log shows two SRv6-locators LOC1 and LOC2. - All locators are identified by unique IPv6 prefix. - User can get that information as JSON string when ``json`` - key word at the end of cli is presented. + This command dump SRv6-locator configured on zebra. SRv6-locator is used + to route to the node before performing the SRv6-function. and that works as + aggregation of SRv6-function's IDs. Following console log shows two + SRv6-locators loc1 and loc2. All locators are identified by unique IPv6 + prefix. User can get that information as JSON string when ``json`` key word + at the end of cli is presented. :: @@ -655,49 +653,84 @@ and this section also helps that case. Locator: Name ID Prefix Status -------------------- ------- ------------------------ ------- - hoge 1 1::/64 Up - fuga 2 2::/64 Up + loc1 1 2001:db8:1:1::/64 Up + loc2 2 2001:db8:2:2::/64 Up + +.. index:: show segment-routing srv6 locator NAME detail [json] +.. clicmd:: show segment-routing srv6 locator NAME detail [json] + + As shown in the example, by specifying the name of the locator, you + can see the detailed information for each locator. Locator can be + represented by a single IPv6 prefix, but SRv6 is designed to share this + Locator among multiple Routing Protocols. For this purpose, zebra divides + the IPv6 prefix block that makes the Locator unique into multiple chunks, + and manages the ownership of each chunk. + + For example, loc1 has system as its owner. For example, loc1 is owned by + system, which means that it is not yet proprietary to any routing protocol. + For example, loc2 has sharp as its owner. This means that the shaprd for + function development holds the owner of the chunk of this locator, and no + other routing protocol will use this area. + +:: + + router# show segment-routing srv6 locator loc1 detail + Name: loc1 + Prefix: 2001:db8:1:1::/64 + Chunks: + - prefix: 2001:db8:1:1::/64, owner: system + + router# show segment-routing srv6 locator loc2 detail + Name: loc2 + Prefix: 2001:db8:2:2::/64 + Chunks: + - prefix: 2001:db8:2:2::/64, owner: sharp .. index:: segment-routing .. clicmd:: segment-routing + + Move from configure mode to segment-routing node. + .. index:: srv6 .. clicmd:: srv6 + + Move from segment-routing node to srv6 node. + .. index:: locators .. clicmd:: locators - User can enter the SRv6 configuration node with ``segment-routing`` and - ``srv6`` commands in configure mode. If there is some SRv6-locator exist, - SRv6 feature is looked enabled and this affects running-config. - - User can enter the Locators node with ``locators`` command - in srv6 configure mode. - After entering locators node, user can configure one or multi SRv6-locators. + Move from srv6 node to locator node. In this locator node, user can + configure detailed settings such as the actual srv6 locator. .. index:: locator NAME .. clicmd:: locator NAME + + Create a new locator. If the name of an existing locator is specified, + move to specified locator's configuration node to change the settings it. + .. index:: prefix X:X::X:X/M [function-bits-length 32] .. clicmd:: prefix X:X::X:X/M [function-bits-length 32] - Following example console log shows the typical configuration of - SRv6 data-plane. After a new SRv6 locator, named LOC1, is created, - LOC1's prefix is configured as ``2001:db8:a:a::/64``. + Set the ipv6 prefix block of the locator. SRv6 locator is defined by + RFC8986. The actual routing protocol specifies the locator and allocates a + SID to be used by each routing protocol. This SID is included in the locator + as an IPv6 prefix. - If user or some routing daemon allocates new SID on this locator, - new SID will allocated in range of this prefix. + Following example console log shows the typical configuration of SRv6 + data-plane. After a new SRv6 locator, named loc1, is created, loc1's prefix + is configured as ``2001:db8:1:1::/64``. If user or some routing daemon + allocates new SID on this locator, new SID will allocated in range of this + prefix. For example, if some routing daemon creates new SID on locator + (``2001:db8:1:1::/64``), Then new SID will be ``2001:db8:1:1:7::/80``, + ``2001:db8:1:1:8::/80``, and so on. Each locator has default SID that is + SRv6 local function "End". Usually default SID is allocated as + ``PREFIX:1::``. (``PREFIX`` is locator's prefix) For example, if user + configure the locator's prefix as ``2001:db8:1:1::/64``, then default SID + will be ``2001:db8:1:1:1::``) - For example, if some routing daemon creates new SID on locator - (``2001:db8:a:a::/64``), Then new SID will be - ``2001:db8:a:a:7::/80``, ``2001:db8:a:a:8::/80``, and so on. - - Each locator has default SID that is SRv6 local function "End". - Usually default SID is allocated as ``PREFIX:1::``. - (``PREFIX`` is locator's prefix) - For example, if user configure the locator's prefix as - ``2001:db8:a:a::/64``, then default SID will be ``2001:db8:a:a:1::``) - - The function bits range is 16bits by default. - If operator want to change function bits range, they can configure - with ``function-bits-length`` option. + The function bits range is 16bits by default. If operator want to change + function bits range, they can configure with ``function-bits-length`` + option. :: @@ -705,16 +738,16 @@ and this section also helps that case. router(config)# segment-routinig router(config-sr)# srv6 router(config-srv6)# locators - router(config-srv6-locs)# locator LOC1 - router(config-srv6-loc)# prefix 2001:db8:a:a::/64 + router(config-srv6-locs)# locator loc1 + router(config-srv6-loc)# prefix 2001:db8:1:1::/64 router(config-srv6-loc)# show run ... segment-routing srv6 locators - locator LOC1 - prefix 2001:db8:a:a::/64 + locator loc1 + prefix 2001:db8:1:1::/64 ! ... From eab0f8f0a202201fcc9757c6097f5c913456ff4d Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Mon, 5 Apr 2021 13:29:12 +0000 Subject: [PATCH 63/66] lib,sharpd,zebra: update nexthop object with nh_srv6 Signed-off-by: Hiroki Shirokura --- lib/nexthop.c | 149 ++++++++++---------- lib/nexthop.h | 19 ++- lib/srv6.h | 9 ++ lib/zclient.c | 33 ++--- sharpd/sharp_vty.c | 4 +- zebra/rt_netlink.c | 328 ++++++++++++++++++++++++--------------------- zebra/zapi_msg.c | 7 +- zebra/zebra_nhg.c | 8 +- zebra/zebra_vty.c | 20 ++- 9 files changed, 308 insertions(+), 269 deletions(-) diff --git a/lib/nexthop.c b/lib/nexthop.c index d0cc5dc258..23e3a2b733 100644 --- a/lib/nexthop.c +++ b/lib/nexthop.c @@ -36,8 +36,7 @@ DEFINE_MTYPE_STATIC(LIB, NEXTHOP, "Nexthop"); DEFINE_MTYPE_STATIC(LIB, NH_LABEL, "Nexthop label"); -DEFINE_MTYPE_STATIC(LIB, NH_SEG6LOCAL, "Nexthop seg6local"); -DEFINE_MTYPE_STATIC(LIB, NH_SEG6, "Nexthop seg6"); +DEFINE_MTYPE_STATIC(LIB, NH_SRV6, "Nexthop srv6"); static int _nexthop_labels_cmp(const struct nexthop *nh1, const struct nexthop *nh2) @@ -68,42 +67,37 @@ static int _nexthop_labels_cmp(const struct nexthop *nh1, (nhl1->num_labels * sizeof(mpls_label_t))); } -static int _nexthop_seg6local_cmp(const struct nexthop *nh1, - const struct nexthop *nh2) -{ - if (nh1->nh_seg6local_action > nh2->nh_seg6local_action) - return 1; - - if (nh2->nh_seg6local_action < nh1->nh_seg6local_action) - return -1; - - if (!nh1->nh_seg6local_ctx && !nh2->nh_seg6local_ctx) - return 0; - - if (nh1->nh_seg6local_ctx && !nh2->nh_seg6local_ctx) - return 1; - - if (!nh1->nh_seg6local_ctx && nh2->nh_seg6local_ctx) - return -1; - - return memcmp(nh1->nh_seg6local_ctx, nh2->nh_seg6local_ctx, - sizeof(struct seg6local_context)); -} - -static int _nexthop_seg6_cmp(const struct nexthop *nh1, +static int _nexthop_srv6_cmp(const struct nexthop *nh1, const struct nexthop *nh2) { - if (!nh1->nh_seg6_segs && !nh2->nh_seg6_segs) + int ret = 0; + + if (!nh1->nh_srv6 && !nh2->nh_srv6) return 0; - if (nh1->nh_seg6_segs && !nh2->nh_seg6_segs) + if (nh1->nh_srv6 && !nh2->nh_srv6) return 1; - if (!nh1->nh_seg6_segs && nh2->nh_seg6_segs) + if (!nh1->nh_srv6 && nh2->nh_srv6) return -1; - return memcmp(nh1->nh_seg6_segs, nh2->nh_seg6_segs, - sizeof(struct in6_addr)); + if (nh1->nh_srv6->seg6local_action > nh2->nh_srv6->seg6local_action) + return 1; + + if (nh2->nh_srv6->seg6local_action < nh1->nh_srv6->seg6local_action) + return -1; + + ret = memcmp(&nh1->nh_srv6->seg6local_ctx, + &nh2->nh_srv6->seg6local_ctx, + sizeof(struct seg6local_context)); + if (ret != 0) + return ret; + + ret = memcmp(&nh1->nh_srv6->seg6_segs, + &nh2->nh_srv6->seg6_segs, + sizeof(struct in6_addr)); + + return ret; } int nexthop_g_addr_cmp(enum nexthop_types_t type, const union g_addr *addr1, @@ -242,11 +236,7 @@ int nexthop_cmp(const struct nexthop *next1, const struct nexthop *next2) if (ret != 0) return ret; - ret = _nexthop_seg6local_cmp(next1, next2); - if (ret != 0) - return ret; - - ret = _nexthop_seg6_cmp(next1, next2); + ret = _nexthop_srv6_cmp(next1, next2); return ret; } @@ -401,8 +391,8 @@ struct nexthop *nexthop_new(void) void nexthop_free(struct nexthop *nexthop) { nexthop_del_labels(nexthop); - nexthop_del_seg6local(nexthop); - nexthop_del_seg6(nexthop); + nexthop_del_srv6_seg6local(nexthop); + nexthop_del_srv6_seg6(nexthop); if (nexthop->resolved) nexthops_free(nexthop->resolved); XFREE(MTYPE_NEXTHOP, nexthop); @@ -573,40 +563,55 @@ void nexthop_del_labels(struct nexthop *nexthop) nexthop->nh_label_type = ZEBRA_LSP_NONE; } -void nexthop_add_seg6local(struct nexthop *nexthop, uint32_t action, - const struct seg6local_context *ctx) +void nexthop_add_srv6_seg6local(struct nexthop *nexthop, uint32_t action, + const struct seg6local_context *ctx) { - struct seg6local_context *nh_ctx; - if (action == ZEBRA_SEG6_LOCAL_ACTION_UNSPEC) return; - nh_ctx = XCALLOC(MTYPE_NH_SEG6LOCAL, sizeof(struct seg6local_context)); - if (ctx) - *nh_ctx = *ctx; - nexthop->nh_seg6local_action = action; - nexthop->nh_seg6local_ctx = nh_ctx; + if (!nexthop->nh_srv6) + nexthop->nh_srv6 = XCALLOC(MTYPE_NH_SRV6, + sizeof(struct nexthop_srv6)); + + nexthop->nh_srv6->seg6local_action = action; + nexthop->nh_srv6->seg6local_ctx = *ctx; } -void nexthop_del_seg6local(struct nexthop *nexthop) +void nexthop_del_srv6_seg6local(struct nexthop *nexthop) { - XFREE(MTYPE_NH_SEG6LOCAL, nexthop->nh_seg6local_ctx); - nexthop->nh_seg6local_action = ZEBRA_SEG6_LOCAL_ACTION_UNSPEC; + if (!nexthop->nh_srv6) + return; + + nexthop->nh_srv6->seg6local_action = ZEBRA_SEG6_LOCAL_ACTION_UNSPEC; + + if (sid_zero(&nexthop->nh_srv6->seg6_segs)) + XFREE(MTYPE_NH_SRV6, nexthop->nh_srv6); } -void nexthop_add_seg6(struct nexthop *nexthop, const struct in6_addr *segs) +void nexthop_add_srv6_seg6(struct nexthop *nexthop, + const struct in6_addr *segs) { - struct in6_addr *nh_segs; + if (!segs) + return; - nh_segs = XCALLOC(MTYPE_NH_SEG6, sizeof(struct in6_addr)); - if (segs) - *nh_segs = *segs; - nexthop->nh_seg6_segs = nh_segs; + if (!nexthop->nh_srv6) + nexthop->nh_srv6 = XCALLOC(MTYPE_NH_SRV6, + sizeof(struct nexthop_srv6)); + + nexthop->nh_srv6->seg6_segs = *segs; } -void nexthop_del_seg6(struct nexthop *nexthop) +void nexthop_del_srv6_seg6(struct nexthop *nexthop) { - XFREE(MTYPE_NH_SEG6, nexthop->nh_seg6_segs); + if (!nexthop->nh_srv6) + return; + + memset(&nexthop->nh_srv6->seg6_segs, 0, + sizeof(nexthop->nh_srv6->seg6_segs)); + + if (nexthop->nh_srv6->seg6local_action == + ZEBRA_SEG6_LOCAL_ACTION_UNSPEC) + XFREE(MTYPE_NH_SRV6, nexthop->nh_srv6); } const char *nexthop2str(const struct nexthop *nexthop, char *str, int size) @@ -754,16 +759,14 @@ uint32_t nexthop_hash_quick(const struct nexthop *nexthop) key = jhash_1word(nexthop->backup_idx[i], key); } - if (nexthop->nh_seg6local_ctx) { - key = jhash_1word(nexthop->nh_seg6local_action, key); - key = jhash(nexthop->nh_seg6local_ctx, - sizeof(nexthop->nh_seg6local_ctx), key); + if (nexthop->nh_srv6) { + key = jhash_1word(nexthop->nh_srv6->seg6local_action, key); + key = jhash(&nexthop->nh_srv6->seg6local_ctx, + sizeof(nexthop->nh_srv6->seg6local_ctx), key); + key = jhash(&nexthop->nh_srv6->seg6_segs, + sizeof(nexthop->nh_srv6->seg6_segs), key); } - if (nexthop->nh_seg6_segs) - key = jhash(nexthop->nh_seg6_segs, - sizeof(nexthop->nh_seg6_segs), key); - return key; } @@ -817,12 +820,16 @@ void nexthop_copy_no_recurse(struct nexthop *copy, nexthop->nh_label->num_labels, &nexthop->nh_label->label[0]); - if (nexthop->nh_seg6local_ctx) - nexthop_add_seg6local(copy, nexthop->nh_seg6local_action, - nexthop->nh_seg6local_ctx); - - if (nexthop->nh_seg6_segs) - nexthop_add_seg6(copy, nexthop->nh_seg6_segs); + if (nexthop->nh_srv6) { + if (nexthop->nh_srv6->seg6local_action != + ZEBRA_SEG6_LOCAL_ACTION_UNSPEC) + nexthop_add_srv6_seg6local(copy, + nexthop->nh_srv6->seg6local_action, + &nexthop->nh_srv6->seg6local_ctx); + if (!sid_zero(&nexthop->nh_srv6->seg6_segs)) + nexthop_add_srv6_seg6(copy, + &nexthop->nh_srv6->seg6_segs); + } } void nexthop_copy(struct nexthop *copy, const struct nexthop *nexthop, diff --git a/lib/nexthop.h b/lib/nexthop.h index c9af1ff478..dd65509aec 100644 --- a/lib/nexthop.h +++ b/lib/nexthop.h @@ -141,12 +141,8 @@ struct nexthop { /* SR-TE color used for matching SR-TE policies */ uint32_t srte_color; - /* SRv6 localsid info for Endpoint-behaviour */ - enum seg6local_action_t nh_seg6local_action; - struct seg6local_context *nh_seg6local_ctx; - - /* SRv6 Headend-behaviour */ - struct in6_addr *nh_seg6_segs; + /* SRv6 information */ + struct nexthop_srv6 *nh_srv6; }; /* Utility to append one nexthop to another. */ @@ -165,11 +161,12 @@ void nexthops_free(struct nexthop *nexthop); void nexthop_add_labels(struct nexthop *nexthop, enum lsp_types_t ltype, uint8_t num_labels, const mpls_label_t *labels); void nexthop_del_labels(struct nexthop *); -void nexthop_add_seg6local(struct nexthop *nexthop, uint32_t action, - const struct seg6local_context *ctx); -void nexthop_del_seg6local(struct nexthop *nexthop); -void nexthop_add_seg6(struct nexthop *nexthop, const struct in6_addr *segs); -void nexthop_del_seg6(struct nexthop *nexthop); +void nexthop_add_srv6_seg6local(struct nexthop *nexthop, uint32_t action, + const struct seg6local_context *ctx); +void nexthop_del_srv6_seg6local(struct nexthop *nexthop); +void nexthop_add_srv6_seg6(struct nexthop *nexthop, + const struct in6_addr *segs); +void nexthop_del_srv6_seg6(struct nexthop *nexthop); /* * Allocate a new nexthop object and initialize it from various args. diff --git a/lib/srv6.h b/lib/srv6.h index 9ac89125ce..715fc3723b 100644 --- a/lib/srv6.h +++ b/lib/srv6.h @@ -117,6 +117,15 @@ struct srv6_locator_chunk { uint32_t session_id; }; +struct nexthop_srv6 { + /* SRv6 localsid info for Endpoint-behaviour */ + enum seg6local_action_t seg6local_action; + struct seg6local_context seg6local_ctx; + + /* SRv6 Headend-behaviour */ + struct in6_addr seg6_segs; +}; + static inline const char *seg6_mode2str(enum seg6_mode_t mode) { switch (mode) { diff --git a/lib/zclient.c b/lib/zclient.c index 5395d4799d..4eef55e469 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -464,7 +464,7 @@ enum zclient_send_status zclient_send_localsid(struct zclient *zclient, nh.type = NEXTHOP_TYPE_IFINDEX; nh.ifindex = oif; - nexthop_add_seg6local(&nh, action, context); + nexthop_add_srv6_seg6local(&nh, action, context); zapi_nexthop_from_nexthop(&api.nexthops[0], &nh); api.nexthop_num = 1; @@ -1734,7 +1734,6 @@ stream_failure: struct nexthop *nexthop_from_zapi_nexthop(const struct zapi_nexthop *znh) { - uint8_t zero[16] = {0}; struct nexthop *n = nexthop_new(); n->type = znh->type; @@ -1757,12 +1756,12 @@ struct nexthop *nexthop_from_zapi_nexthop(const struct zapi_nexthop *znh) memcpy(n->backup_idx, znh->backup_idx, n->backup_num); } - if (znh->seg6local_action != 0) - nexthop_add_seg6local(n, znh->seg6local_action, - &znh->seg6local_ctx); + if (znh->seg6local_action != ZEBRA_SEG6_LOCAL_ACTION_UNSPEC) + nexthop_add_srv6_seg6local(n, znh->seg6local_action, + &znh->seg6local_ctx); - if (memcmp(&znh->seg6_segs, zero, sizeof(struct in6_addr)) != 0) - nexthop_add_seg6(n, &znh->seg6_segs); + if (!sid_zero(&znh->seg6_segs)) + nexthop_add_srv6_seg6(n, &znh->seg6_segs); return n; } @@ -1808,15 +1807,19 @@ int zapi_nexthop_from_nexthop(struct zapi_nexthop *znh, memcpy(znh->backup_idx, nh->backup_idx, znh->backup_num); } - if (nh->nh_seg6local_action != 0 && nh->nh_seg6local_ctx != NULL) { - znh->seg6local_action = nh->nh_seg6local_action; - memcpy(&znh->seg6local_ctx, nh->nh_seg6local_ctx, - sizeof(struct seg6local_context)); - } + if (nh->nh_srv6) { + if (nh->nh_srv6->seg6local_action != + ZEBRA_SEG6_LOCAL_ACTION_UNSPEC) { + znh->seg6local_action = nh->nh_srv6->seg6local_action; + memcpy(&znh->seg6local_ctx, + &nh->nh_srv6->seg6local_ctx, + sizeof(struct seg6local_context)); + } - if (nh->nh_seg6_segs != NULL) - memcpy(&znh->seg6_segs, nh->nh_seg6_segs, - sizeof(struct in6_addr)); + if (!sid_zero(&nh->nh_srv6->seg6_segs)) + memcpy(&znh->seg6_segs, &nh->nh_srv6->seg6_segs, + sizeof(struct in6_addr)); + } return 0; } diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index 7cd9b959f8..7482a6da68 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -407,7 +407,7 @@ DEFPY (install_seg6_routes, sg.r.nhop.vrf_id = vrf->vrf_id; sg.r.nhop_group.nexthop = &sg.r.nhop; - nexthop_add_seg6(&sg.r.nhop, &seg6_seg); + nexthop_add_srv6_seg6(&sg.r.nhop, &seg6_seg); SET_FLAG(route_flags, ZEBRA_FLAG_SEG6_ROUTE); sg.r.vrf_id = vrf->vrf_id; @@ -504,7 +504,7 @@ DEFPY (install_seg6local_routes, sg.r.nhop.ifindex = ifname2ifindex(seg6l_oif, vrf->vrf_id); sg.r.nhop.vrf_id = vrf->vrf_id; sg.r.nhop_group.nexthop = &sg.r.nhop; - nexthop_add_seg6local(&sg.r.nhop, action, &ctx); + nexthop_add_srv6_seg6local(&sg.r.nhop, action, &ctx); SET_FLAG(route_flags, ZEBRA_FLAG_SEG6LOCAL_ROUTE); sg.r.vrf_id = vrf->vrf_id; diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index d40c717018..4479c434eb 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -534,10 +534,10 @@ parse_nexthop_unicast(ns_id_t ns_id, struct rtmsg *rtm, struct rtattr **tb, nexthop_add_labels(&nh, ZEBRA_LSP_STATIC, num_labels, labels); if (seg6l_act != ZEBRA_SEG6_LOCAL_ACTION_UNSPEC) - nexthop_add_seg6local(&nh, seg6l_act, &seg6l_ctx); + nexthop_add_srv6_seg6local(&nh, seg6l_act, &seg6l_ctx); if (num_segs) - nexthop_add_seg6(&nh, &seg6_segs); + nexthop_add_srv6_seg6(&nh, &seg6_segs); return nh; } @@ -641,11 +641,11 @@ static uint8_t parse_multipath_nexthops_unicast(ns_id_t ns_id, num_labels, labels); if (seg6l_act != ZEBRA_SEG6_LOCAL_ACTION_UNSPEC) - nexthop_add_seg6local(nh, seg6l_act, - &seg6l_ctx); + nexthop_add_srv6_seg6local(nh, seg6l_act, + &seg6l_ctx); if (num_segs) - nexthop_add_seg6(nh, &seg6_segs); + nexthop_add_srv6_seg6(nh, &seg6_segs); if (rtnh->rtnh_flags & RTNH_F_ONLINK) SET_FLAG(nh->flags, NEXTHOP_FLAG_ONLINK); @@ -1399,84 +1399,97 @@ static bool _netlink_route_build_singlepath(const struct prefix *p, sizeof(label_buf))) return false; - if (nexthop->nh_seg6local_ctx) { - struct rtattr *nest; - const struct seg6local_context *ctx; + if (nexthop->nh_srv6) { + if (nexthop->nh_srv6->seg6local_action != + ZEBRA_SEG6_LOCAL_ACTION_UNSPEC) { + struct rtattr *nest; + const struct seg6local_context *ctx; - ctx = nexthop->nh_seg6local_ctx; - if (!nl_attr_put16(nlmsg, req_size, RTA_ENCAP_TYPE, - LWTUNNEL_ENCAP_SEG6_LOCAL)) - return false; + ctx = &nexthop->nh_srv6->seg6local_ctx; + if (!nl_attr_put16(nlmsg, req_size, RTA_ENCAP_TYPE, + LWTUNNEL_ENCAP_SEG6_LOCAL)) + return false; - nest = nl_attr_nest(nlmsg, req_size, RTA_ENCAP); - if (!nest) - return false; + nest = nl_attr_nest(nlmsg, req_size, RTA_ENCAP); + if (!nest) + return false; - switch (nexthop->nh_seg6local_action) { - case ZEBRA_SEG6_LOCAL_ACTION_END: - if (!nl_attr_put32(nlmsg, req_size, SEG6_LOCAL_ACTION, - SEG6_LOCAL_ACTION_END)) - return false; - break; - case ZEBRA_SEG6_LOCAL_ACTION_END_X: - if (!nl_attr_put32(nlmsg, req_size, SEG6_LOCAL_ACTION, - SEG6_LOCAL_ACTION_END_X)) - return false; - if (!nl_attr_put(nlmsg, req_size, SEG6_LOCAL_NH6, - &ctx->nh6, sizeof(struct in6_addr))) - return false; - break; - case ZEBRA_SEG6_LOCAL_ACTION_END_T: - if (!nl_attr_put32(nlmsg, req_size, SEG6_LOCAL_ACTION, - SEG6_LOCAL_ACTION_END_T)) - return false; - if (!nl_attr_put32(nlmsg, req_size, SEG6_LOCAL_TABLE, - ctx->table)) - return false; - break; - case ZEBRA_SEG6_LOCAL_ACTION_END_DX4: - if (!nl_attr_put32(nlmsg, req_size, SEG6_LOCAL_ACTION, - SEG6_LOCAL_ACTION_END_DX4)) - return false; - if (!nl_attr_put(nlmsg, req_size, SEG6_LOCAL_NH4, - &ctx->nh4, sizeof(struct in_addr))) - return false; - break; - case ZEBRA_SEG6_LOCAL_ACTION_END_DT6: - if (!nl_attr_put32(nlmsg, req_size, SEG6_LOCAL_ACTION, - SEG6_LOCAL_ACTION_END_DT6)) - return false; - if (!nl_attr_put32(nlmsg, req_size, SEG6_LOCAL_TABLE, - ctx->table)) - return false; - break; - default: - zlog_err("%s: unsupport seg6local behaviour action=%u", - __func__, nexthop->nh_seg6local_action); - break; + switch (nexthop->nh_srv6->seg6local_action) { + case ZEBRA_SEG6_LOCAL_ACTION_END: + if (!nl_attr_put32(nlmsg, req_size, + SEG6_LOCAL_ACTION, + SEG6_LOCAL_ACTION_END)) + return false; + break; + case ZEBRA_SEG6_LOCAL_ACTION_END_X: + if (!nl_attr_put32(nlmsg, req_size, + SEG6_LOCAL_ACTION, + SEG6_LOCAL_ACTION_END_X)) + return false; + if (!nl_attr_put(nlmsg, req_size, + SEG6_LOCAL_NH6, &ctx->nh6, + sizeof(struct in6_addr))) + return false; + break; + case ZEBRA_SEG6_LOCAL_ACTION_END_T: + if (!nl_attr_put32(nlmsg, req_size, + SEG6_LOCAL_ACTION, + SEG6_LOCAL_ACTION_END_T)) + return false; + if (!nl_attr_put32(nlmsg, req_size, + SEG6_LOCAL_TABLE, + ctx->table)) + return false; + break; + case ZEBRA_SEG6_LOCAL_ACTION_END_DX4: + if (!nl_attr_put32(nlmsg, req_size, + SEG6_LOCAL_ACTION, + SEG6_LOCAL_ACTION_END_DX4)) + return false; + if (!nl_attr_put(nlmsg, req_size, + SEG6_LOCAL_NH4, &ctx->nh4, + sizeof(struct in_addr))) + return false; + break; + case ZEBRA_SEG6_LOCAL_ACTION_END_DT6: + if (!nl_attr_put32(nlmsg, req_size, + SEG6_LOCAL_ACTION, + SEG6_LOCAL_ACTION_END_DT6)) + return false; + if (!nl_attr_put32(nlmsg, req_size, + SEG6_LOCAL_TABLE, + ctx->table)) + return false; + break; + default: + zlog_err("%s: unsupport seg6local behaviour action=%u", + __func__, + nexthop->nh_srv6->seg6local_action); + break; + } + nl_attr_nest_end(nlmsg, nest); } - nl_attr_nest_end(nlmsg, nest); - } - if (nexthop->nh_seg6_segs) { - char tun_buf[4096]; - ssize_t tun_len; - struct rtattr *nest; + if (!sid_zero(&nexthop->nh_srv6->seg6_segs)) { + char tun_buf[4096]; + ssize_t tun_len; + struct rtattr *nest; - if (!nl_attr_put16(nlmsg, req_size, RTA_ENCAP_TYPE, - LWTUNNEL_ENCAP_SEG6)) - return false; - nest = nl_attr_nest(nlmsg, req_size, RTA_ENCAP); - if (!nest) - return false; - tun_len = fill_seg6ipt_encap(tun_buf, sizeof(tun_buf), - nexthop->nh_seg6_segs); - if (tun_len < 0) - return false; - if (!nl_attr_put(nlmsg, req_size, SEG6_IPTUNNEL_SRH, tun_buf, - tun_len)) - return false; - nl_attr_nest_end(nlmsg, nest); + if (!nl_attr_put16(nlmsg, req_size, RTA_ENCAP_TYPE, + LWTUNNEL_ENCAP_SEG6)) + return false; + nest = nl_attr_nest(nlmsg, req_size, RTA_ENCAP); + if (!nest) + return false; + tun_len = fill_seg6ipt_encap(tun_buf, sizeof(tun_buf), + &nexthop->nh_srv6->seg6_segs); + if (tun_len < 0) + return false; + if (!nl_attr_put(nlmsg, req_size, SEG6_IPTUNNEL_SRH, + tun_buf, tun_len)) + return false; + nl_attr_nest_end(nlmsg, nest); + } } if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) @@ -2473,104 +2486,117 @@ ssize_t netlink_nexthop_msg_encode(uint16_t cmd, nl_attr_nest_end(&req->n, nest); } - if (nh->nh_seg6local_ctx) { - uint32_t action; - uint16_t encap; - struct rtattr *nest; - const struct seg6local_context *ctx; + if (nh->nh_srv6) { + if (nh->nh_srv6->seg6local_action != + ZEBRA_SEG6_LOCAL_ACTION_UNSPEC) { + uint32_t action; + uint16_t encap; + struct rtattr *nest; + const struct seg6local_context *ctx; - req->nhm.nh_family = AF_INET6; - action = nh->nh_seg6local_action; - ctx = nh->nh_seg6local_ctx; - encap = LWTUNNEL_ENCAP_SEG6_LOCAL; - if (!nl_attr_put(&req->n, buflen, - NHA_ENCAP_TYPE, &encap, - sizeof(uint16_t))) - return 0; + req->nhm.nh_family = AF_INET6; + action = nh->nh_srv6->seg6local_action; + ctx = &nh->nh_srv6->seg6local_ctx; + encap = LWTUNNEL_ENCAP_SEG6_LOCAL; + if (!nl_attr_put(&req->n, buflen, + NHA_ENCAP_TYPE, + &encap, + sizeof(uint16_t))) + return 0; - nest = nl_attr_nest(&req->n, buflen, - NHA_ENCAP | NLA_F_NESTED); - if (!nest) - return 0; + nest = nl_attr_nest(&req->n, buflen, + NHA_ENCAP | NLA_F_NESTED); + if (!nest) + return 0; - switch (action) { - case SEG6_LOCAL_ACTION_END: - if (!nl_attr_put32(&req->n, buflen, + switch (action) { + case SEG6_LOCAL_ACTION_END: + if (!nl_attr_put32( + &req->n, buflen, SEG6_LOCAL_ACTION, SEG6_LOCAL_ACTION_END)) - return 0; - break; - case SEG6_LOCAL_ACTION_END_X: - if (!nl_attr_put32(&req->n, buflen, + return 0; + break; + case SEG6_LOCAL_ACTION_END_X: + if (!nl_attr_put32( + &req->n, buflen, SEG6_LOCAL_ACTION, SEG6_LOCAL_ACTION_END_X)) - return 0; - if (!nl_attr_put(&req->n, buflen, + return 0; + if (!nl_attr_put( + &req->n, buflen, SEG6_LOCAL_NH6, &ctx->nh6, sizeof(struct in6_addr))) - return 0; - break; - case SEG6_LOCAL_ACTION_END_T: - if (!nl_attr_put32(&req->n, buflen, + return 0; + break; + case SEG6_LOCAL_ACTION_END_T: + if (!nl_attr_put32( + &req->n, buflen, SEG6_LOCAL_ACTION, SEG6_LOCAL_ACTION_END_T)) - return 0; - if (!nl_attr_put32(&req->n, buflen, + return 0; + if (!nl_attr_put32( + &req->n, buflen, SEG6_LOCAL_TABLE, ctx->table)) - return 0; - break; - case SEG6_LOCAL_ACTION_END_DX4: - if (!nl_attr_put32(&req->n, buflen, + return 0; + break; + case SEG6_LOCAL_ACTION_END_DX4: + if (!nl_attr_put32( + &req->n, buflen, SEG6_LOCAL_ACTION, SEG6_LOCAL_ACTION_END_DX4)) - return 0; - if (!nl_attr_put(&req->n, buflen, + return 0; + if (!nl_attr_put( + &req->n, buflen, SEG6_LOCAL_NH4, &ctx->nh4, sizeof(struct in_addr))) - return 0; - break; - case SEG6_LOCAL_ACTION_END_DT6: - if (!nl_attr_put32(&req->n, buflen, + return 0; + break; + case SEG6_LOCAL_ACTION_END_DT6: + if (!nl_attr_put32( + &req->n, buflen, SEG6_LOCAL_ACTION, SEG6_LOCAL_ACTION_END_DT6)) - return 0; - if (!nl_attr_put32(&req->n, buflen, + return 0; + if (!nl_attr_put32( + &req->n, buflen, SEG6_LOCAL_TABLE, ctx->table)) - return 0; - break; - default: - zlog_err("%s: unsupport seg6local behaviour action=%u", - __func__, action); - break; + return 0; + break; + default: + zlog_err("%s: unsupport seg6local behaviour action=%u", + __func__, action); + break; + } + nl_attr_nest_end(&req->n, nest); } - nl_attr_nest_end(&req->n, nest); - } - if (nh->nh_seg6_segs) { - char tun_buf[4096]; - ssize_t tun_len; - struct rtattr *nest; + if (!sid_zero(&nh->nh_srv6->seg6_segs)) { + char tun_buf[4096]; + ssize_t tun_len; + struct rtattr *nest; - if (!nl_attr_put16(&req->n, buflen, - NHA_ENCAP_TYPE, - LWTUNNEL_ENCAP_SEG6)) - return 0; - nest = nl_attr_nest(&req->n, buflen, - NHA_ENCAP | NLA_F_NESTED); - if (!nest) - return 0; - tun_len = fill_seg6ipt_encap(tun_buf, - sizeof(tun_buf), - nh->nh_seg6_segs); - if (tun_len < 0) - return 0; - if (!nl_attr_put(&req->n, buflen, - SEG6_IPTUNNEL_SRH, - tun_buf, tun_len)) - return 0; - nl_attr_nest_end(&req->n, nest); + if (!nl_attr_put16(&req->n, buflen, + NHA_ENCAP_TYPE, + LWTUNNEL_ENCAP_SEG6)) + return 0; + nest = nl_attr_nest(&req->n, buflen, + NHA_ENCAP | NLA_F_NESTED); + if (!nest) + return 0; + tun_len = fill_seg6ipt_encap(tun_buf, + sizeof(tun_buf), + &nh->nh_srv6->seg6_segs); + if (tun_len < 0) + return 0; + if (!nl_attr_put(&req->n, buflen, + SEG6_IPTUNNEL_SRH, + tun_buf, tun_len)) + return 0; + nl_attr_nest_end(&req->n, nest); + } } nexthop_done: diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index d97d876cf5..f6151463ce 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -1756,8 +1756,9 @@ static bool zapi_read_nexthops(struct zserv *client, struct prefix *p, seg6local_action2str( api_nh->seg6local_action)); - nexthop_add_seg6local(nexthop, api_nh->seg6local_action, - &api_nh->seg6local_ctx); + nexthop_add_srv6_seg6local(nexthop, + api_nh->seg6local_action, + &api_nh->seg6local_ctx); } if (CHECK_FLAG(flags, ZEBRA_FLAG_SEG6_ROUTE) @@ -1765,7 +1766,7 @@ static bool zapi_read_nexthops(struct zserv *client, struct prefix *p, if (IS_ZEBRA_DEBUG_RECV) zlog_debug("%s: adding seg6", __func__); - nexthop_add_seg6(nexthop, &api_nh->seg6_segs); + nexthop_add_srv6_seg6(nexthop, &api_nh->seg6_segs); } if (IS_ZEBRA_DEBUG_RECV) { diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 84ce97b008..face0ef3bc 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -1007,8 +1007,8 @@ void nhg_ctx_free(struct nhg_ctx **ctx) nh = nhg_ctx_get_nh(*ctx); nexthop_del_labels(nh); - nexthop_del_seg6local(nh); - nexthop_del_seg6(nh); + nexthop_del_srv6_seg6local(nh); + nexthop_del_srv6_seg6(nh); done: XFREE(MTYPE_NHG_CTX, *ctx); @@ -1379,8 +1379,8 @@ static struct nhg_hash_entry *depends_find_singleton(const struct nexthop *nh, /* The copy may have allocated labels; free them if necessary. */ nexthop_del_labels(&lookup); - nexthop_del_seg6local(&lookup); - nexthop_del_seg6(&lookup); + nexthop_del_srv6_seg6local(&lookup); + nexthop_del_srv6_seg6(&lookup); if (IS_ZEBRA_DEBUG_NHG_DETAIL) zlog_debug("%s: nh %pNHv => %p (%u)", diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index fae443ca2e..2bc25f6f7d 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -653,17 +653,15 @@ static void show_route_nexthop_helper(struct vty *vty, sizeof(buf), 1)); } - if (nexthop->nh_seg6local_ctx) { + if (nexthop->nh_srv6) { seg6local_context2str(buf, sizeof(buf), - nexthop->nh_seg6local_ctx, - nexthop->nh_seg6local_action); + &nexthop->nh_srv6->seg6local_ctx, + nexthop->nh_srv6->seg6local_action); vty_out(vty, ", seg6local %s %s", - seg6local_action2str(nexthop->nh_seg6local_action), + seg6local_action2str(nexthop->nh_srv6->seg6local_action), buf); - } - if (nexthop->nh_seg6_segs) { - inet_ntop(AF_INET6, nexthop->nh_seg6_segs, buf, sizeof(buf)); + inet_ntop(AF_INET6, &nexthop->nh_srv6->seg6_segs, buf, sizeof(buf)); vty_out(vty, ", seg6 %s", buf); } @@ -869,18 +867,16 @@ static void show_nexthop_json_helper(json_object *json_nexthop, json_object_int_add(json_nexthop, "srteColor", nexthop->srte_color); - if (nexthop->nh_seg6local_ctx) { + if (nexthop->nh_srv6) { json_seg6local = json_object_new_object(); json_object_string_add( json_seg6local, "action", - seg6local_action2str(nexthop->nh_seg6local_action)); + seg6local_action2str(nexthop->nh_srv6->seg6local_action)); json_object_object_add(json_nexthop, "seg6local", json_seg6local); - } - if (nexthop->nh_seg6_segs) { json_seg6 = json_object_new_object(); - inet_ntop(AF_INET6, nexthop->nh_seg6_segs, buf, sizeof(buf)); + inet_ntop(AF_INET6, &nexthop->nh_srv6->seg6_segs, buf, sizeof(buf)); json_object_string_add(json_seg6, "segs", buf); json_object_object_add(json_nexthop, "seg6", json_seg6); } From 0a543b792920312f1035d0590b7bad44dd480ddc Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Fri, 23 Apr 2021 11:27:41 +0000 Subject: [PATCH 64/66] zebra: early return on seg6local nlmsg crafting Signed-off-by: Hiroki Shirokura --- zebra/rt_netlink.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 4479c434eb..38f8140db2 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1465,7 +1465,7 @@ static bool _netlink_route_build_singlepath(const struct prefix *p, zlog_err("%s: unsupport seg6local behaviour action=%u", __func__, nexthop->nh_srv6->seg6local_action); - break; + return false; } nl_attr_nest_end(nlmsg, nest); } @@ -2568,7 +2568,7 @@ ssize_t netlink_nexthop_msg_encode(uint16_t cmd, default: zlog_err("%s: unsupport seg6local behaviour action=%u", __func__, action); - break; + return 0; } nl_attr_nest_end(&req->n, nest); } From c60c1ade86c1c999f5219c0ebc35374acddb661c Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Fri, 23 Apr 2021 12:46:07 +0000 Subject: [PATCH 65/66] *: delete ZEBRA_FLAG_SEG6*_ROUTE and add ZAPI_NEXTHOP_FLAG_SEG6* https://github.com/FRRouting/frr/pull/5865#discussion_r597670225 As this comment says. ZEBRA_FLAG_XXX should not have been used. To communicate SRv6 Route Information. A simple Nexthop Flag would have been sufficient for SRv6 information. And I fixed the whole thing that way. Signed-off-by: Hiroki Shirokura --- bgpd/bgp_zebra.c | 2 +- lib/zclient.c | 15 +++++++++------ lib/zclient.h | 12 ++---------- sharpd/sharp_vty.c | 3 --- .../bgp_srv6l3vpn_to_bgp_vrf/r1/vrf10_rib.json | 2 +- .../bgp_srv6l3vpn_to_bgp_vrf/r1/vrf20_rib.json | 4 ++-- .../bgp_srv6l3vpn_to_bgp_vrf/r2/vrf10_rib.json | 4 ++-- .../bgp_srv6l3vpn_to_bgp_vrf/r2/vrf20_rib.json | 2 +- zebra/zapi_msg.c | 4 ++-- 9 files changed, 20 insertions(+), 28 deletions(-) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index d4a4ed2305..e3a795c6f1 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1408,7 +1408,7 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, } if (has_valid_sid && !(CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE))) - SET_FLAG(api.flags, ZEBRA_FLAG_SEG6_ROUTE); + SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_SEG6); is_add = (valid_nh_count || nhg_id) ? true : false; diff --git a/lib/zclient.c b/lib/zclient.c index 4eef55e469..10dda5ba0e 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -459,11 +459,11 @@ enum zclient_send_status zclient_send_localsid(struct zclient *zclient, return zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api); SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION); - SET_FLAG(api.flags, ZEBRA_FLAG_SEG6LOCAL_ROUTE); SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); nh.type = NEXTHOP_TYPE_IFINDEX; nh.ifindex = oif; + SET_FLAG(nh.flags, ZAPI_NEXTHOP_FLAG_SEG6LOCAL); nexthop_add_srv6_seg6local(&nh, action, context); zapi_nexthop_from_nexthop(&api.nexthops[0], &nh); @@ -1053,13 +1053,13 @@ int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh, stream_putc(s, api_nh->backup_idx[i]); } - if (CHECK_FLAG(api_flags, ZEBRA_FLAG_SEG6LOCAL_ROUTE)) { + if (CHECK_FLAG(nh_flags, ZAPI_NEXTHOP_FLAG_SEG6LOCAL)) { stream_putl(s, api_nh->seg6local_action); stream_write(s, &api_nh->seg6local_ctx, sizeof(struct seg6local_context)); } - if (CHECK_FLAG(api_flags, ZEBRA_FLAG_SEG6_ROUTE)) + if (CHECK_FLAG(nh_flags, ZAPI_NEXTHOP_FLAG_SEG6)) stream_write(s, &api_nh->seg6_segs, sizeof(struct in6_addr)); @@ -1382,13 +1382,13 @@ int zapi_nexthop_decode(struct stream *s, struct zapi_nexthop *api_nh, STREAM_GETC(s, api_nh->backup_idx[i]); } - if (CHECK_FLAG(api_flags, ZEBRA_FLAG_SEG6LOCAL_ROUTE)) { + if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_SEG6LOCAL)) { STREAM_GETL(s, api_nh->seg6local_action); STREAM_GET(&api_nh->seg6local_ctx, s, sizeof(struct seg6local_context)); } - if (CHECK_FLAG(api_flags, ZEBRA_FLAG_SEG6_ROUTE)) + if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_SEG6)) STREAM_GET(&api_nh->seg6_segs, s, sizeof(struct in6_addr)); @@ -1810,15 +1810,18 @@ int zapi_nexthop_from_nexthop(struct zapi_nexthop *znh, if (nh->nh_srv6) { if (nh->nh_srv6->seg6local_action != ZEBRA_SEG6_LOCAL_ACTION_UNSPEC) { + SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_SEG6LOCAL); znh->seg6local_action = nh->nh_srv6->seg6local_action; memcpy(&znh->seg6local_ctx, &nh->nh_srv6->seg6local_ctx, sizeof(struct seg6local_context)); } - if (!sid_zero(&nh->nh_srv6->seg6_segs)) + if (!sid_zero(&nh->nh_srv6->seg6_segs)) { + SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_SEG6); memcpy(&znh->seg6_segs, &nh->nh_srv6->seg6_segs, sizeof(struct in6_addr)); + } } return 0; diff --git a/lib/zclient.h b/lib/zclient.h index c41d25133d..48de3425be 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -488,6 +488,8 @@ struct zapi_nexthop { #define ZAPI_NEXTHOP_FLAG_LABEL 0x02 #define ZAPI_NEXTHOP_FLAG_WEIGHT 0x04 #define ZAPI_NEXTHOP_FLAG_HAS_BACKUP 0x08 /* Nexthop has a backup */ +#define ZAPI_NEXTHOP_FLAG_SEG6 0x10 +#define ZAPI_NEXTHOP_FLAG_SEG6LOCAL 0x20 /* * ZAPI Nexthop Group. For use with protocol creation of nexthop groups. @@ -572,16 +574,6 @@ struct zapi_route { * offload situation. */ #define ZEBRA_FLAG_OFFLOAD_FAILED 0x200 -/* - * This flag tells Zebra that the route is a seg6 route and should - * be treated specially. - */ -#define ZEBRA_FLAG_SEG6_ROUTE 0x400 -/* - * This flag tells Zebra that the route is a seg6local route and - * should be treated specially. - */ -#define ZEBRA_FLAG_SEG6LOCAL_ROUTE 0x800 /* The older XXX_MESSAGE flags live here */ uint32_t message; diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index 7482a6da68..1a3c5f4502 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -406,9 +406,7 @@ DEFPY (install_seg6_routes, sg.r.nhop.gate.ipv6 = seg6_nh6; sg.r.nhop.vrf_id = vrf->vrf_id; sg.r.nhop_group.nexthop = &sg.r.nhop; - nexthop_add_srv6_seg6(&sg.r.nhop, &seg6_seg); - SET_FLAG(route_flags, ZEBRA_FLAG_SEG6_ROUTE); sg.r.vrf_id = vrf->vrf_id; sharp_install_routes_helper(&prefix, sg.r.vrf_id, sg.r.inst, 0, @@ -505,7 +503,6 @@ DEFPY (install_seg6local_routes, sg.r.nhop.vrf_id = vrf->vrf_id; sg.r.nhop_group.nexthop = &sg.r.nhop; nexthop_add_srv6_seg6local(&sg.r.nhop, action, &ctx); - SET_FLAG(route_flags, ZEBRA_FLAG_SEG6LOCAL_ROUTE); sg.r.vrf_id = vrf->vrf_id; sharp_install_routes_helper(&sg.r.orig_prefix, sg.r.vrf_id, sg.r.inst, 0, diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/vrf10_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/vrf10_rib.json index 9219d9ad38..fa05972a35 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/vrf10_rib.json +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/vrf10_rib.json @@ -37,7 +37,7 @@ "installed": true, "table": 10, "internalStatus": 16, - "internalFlags": 1032, + "internalFlags": 8, "internalNextHopNum": 1, "internalNextHopActiveNum": 1, "nexthops": [ diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/vrf20_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/vrf20_rib.json index cd4c7d5039..0155557242 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/vrf20_rib.json +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/vrf20_rib.json @@ -11,7 +11,7 @@ "installed": true, "table": 20, "internalStatus": 16, - "internalFlags": 1032, + "internalFlags": 8, "internalNextHopNum": 1, "internalNextHopActiveNum": 1, "nexthops": [ @@ -72,7 +72,7 @@ "installed": true, "table": 20, "internalStatus": 16, - "internalFlags": 1032, + "internalFlags": 8, "internalNextHopNum": 1, "internalNextHopActiveNum": 1, "nexthops": [ diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/vrf10_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/vrf10_rib.json index 5ae377c399..887eb24386 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/vrf10_rib.json +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/vrf10_rib.json @@ -11,7 +11,7 @@ "installed": true, "table": 10, "internalStatus": 16, - "internalFlags": 1032, + "internalFlags": 8, "internalNextHopNum": 1, "internalNextHopActiveNum": 1, "nexthops": [ @@ -72,7 +72,7 @@ "installed": true, "table": 10, "internalStatus": 16, - "internalFlags": 1032, + "internalFlags": 8, "internalNextHopNum": 1, "internalNextHopActiveNum": 1, "nexthops": [ diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/vrf20_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/vrf20_rib.json index ea1fe4c2a9..c118518423 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/vrf20_rib.json +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/vrf20_rib.json @@ -37,7 +37,7 @@ "installed": true, "table": 20, "internalStatus": 16, - "internalFlags": 1032, + "internalFlags": 8, "internalNextHopNum": 1, "internalNextHopActiveNum": 1, "nexthops": [ diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index f6151463ce..06aaa706dc 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -1748,7 +1748,7 @@ static bool zapi_read_nexthops(struct zserv *client, struct prefix *p, &api_nh->labels[0]); } - if (CHECK_FLAG(flags, ZEBRA_FLAG_SEG6LOCAL_ROUTE) + if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_SEG6LOCAL) && api_nh->type != NEXTHOP_TYPE_BLACKHOLE) { if (IS_ZEBRA_DEBUG_RECV) zlog_debug("%s: adding seg6local action %s", @@ -1761,7 +1761,7 @@ static bool zapi_read_nexthops(struct zserv *client, struct prefix *p, &api_nh->seg6local_ctx); } - if (CHECK_FLAG(flags, ZEBRA_FLAG_SEG6_ROUTE) + if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_SEG6) && api_nh->type != NEXTHOP_TYPE_BLACKHOLE) { if (IS_ZEBRA_DEBUG_RECV) zlog_debug("%s: adding seg6", __func__); From 2ba6be5b24c9c572d167248004fb1e3c4b57e0a2 Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Wed, 5 May 2021 10:37:55 +0000 Subject: [PATCH 66/66] bgpd,sharpd,zebra: fix code style Signed-off-by: Hiroki Shirokura --- bgpd/bgp_nht.c | 2 +- sharpd/sharp_vty.c | 7 ++++--- sharpd/sharp_zebra.h | 7 ++----- zebra/zebra_vty.c | 15 ++++++++------- 4 files changed, 15 insertions(+), 16 deletions(-) diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index f046235610..4b4a3716e6 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -79,7 +79,7 @@ static int bgp_isvalid_labeled_nexthop(struct bgp_nexthop_cache *bnc) return (bgp_zebra_num_connects() == 0 || (bnc && bnc->nexthop_num > 0 && (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID) - || bnc->bgp->srv6_enabled))); + || bnc->bgp->srv6_enabled))); } static void bgp_unlink_nexthop_check(struct bgp_nexthop_cache *bnc) diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index 1a3c5f4502..250151b1fa 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -505,9 +505,10 @@ DEFPY (install_seg6local_routes, nexthop_add_srv6_seg6local(&sg.r.nhop, action, &ctx); sg.r.vrf_id = vrf->vrf_id; - sharp_install_routes_helper(&sg.r.orig_prefix, sg.r.vrf_id, sg.r.inst, 0, - &sg.r.nhop_group, &sg.r.backup_nhop_group, - routes, route_flags, sg.r.opaque); + sharp_install_routes_helper(&sg.r.orig_prefix, sg.r.vrf_id, sg.r.inst, + 0, &sg.r.nhop_group, + &sg.r.backup_nhop_group, routes, + route_flags, sg.r.opaque); return CMD_SUCCESS; } diff --git a/sharpd/sharp_zebra.h b/sharpd/sharp_zebra.h index 45e26a9b3d..49f11a67e8 100644 --- a/sharpd/sharp_zebra.h +++ b/sharpd/sharp_zebra.h @@ -66,11 +66,8 @@ extern void sharp_zebra_register_te(void); extern void sharp_redistribute_vrf(struct vrf *vrf, int source); -extern int sharp_zebra_srv6_manager_get_locator_chunk(const char* locator_name); -extern int sharp_zebra_srv6_manager_release_locator_chunk(const char *locator_name); -extern int sharp_zebra_srv6_manager_get_locator_chunk(const char *locator_name); -extern int sharp_zebra_srv6_manager_release_locator_chunk( - const char *locator_name); +extern int sharp_zebra_srv6_manager_get_locator_chunk(const char *lname); +extern int sharp_zebra_srv6_manager_release_locator_chunk(const char *lname); extern void sharp_install_seg6local_route_helper(struct prefix *p, uint8_t instance, enum seg6local_action_t act, diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 2bc25f6f7d..51f19a3c03 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -657,11 +657,11 @@ static void show_route_nexthop_helper(struct vty *vty, seg6local_context2str(buf, sizeof(buf), &nexthop->nh_srv6->seg6local_ctx, nexthop->nh_srv6->seg6local_action); - vty_out(vty, ", seg6local %s %s", - seg6local_action2str(nexthop->nh_srv6->seg6local_action), - buf); + vty_out(vty, ", seg6local %s %s", seg6local_action2str( + nexthop->nh_srv6->seg6local_action), buf); - inet_ntop(AF_INET6, &nexthop->nh_srv6->seg6_segs, buf, sizeof(buf)); + inet_ntop(AF_INET6, &nexthop->nh_srv6->seg6_segs, buf, + sizeof(buf)); vty_out(vty, ", seg6 %s", buf); } @@ -870,13 +870,14 @@ static void show_nexthop_json_helper(json_object *json_nexthop, if (nexthop->nh_srv6) { json_seg6local = json_object_new_object(); json_object_string_add( - json_seg6local, "action", - seg6local_action2str(nexthop->nh_srv6->seg6local_action)); + json_seg6local, "action", seg6local_action2str( + nexthop->nh_srv6->seg6local_action)); json_object_object_add(json_nexthop, "seg6local", json_seg6local); json_seg6 = json_object_new_object(); - inet_ntop(AF_INET6, &nexthop->nh_srv6->seg6_segs, buf, sizeof(buf)); + inet_ntop(AF_INET6, &nexthop->nh_srv6->seg6_segs, buf, + sizeof(buf)); json_object_string_add(json_seg6, "segs", buf); json_object_object_add(json_nexthop, "seg6", json_seg6); }