From 9b7491e1fc04bf71842865906dbf9a36e62bdb28 Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Thu, 27 Oct 2022 18:32:19 +0200 Subject: [PATCH 01/10] lib: Add support for flags to the SRv6 locator In this commit, we introduce the ability to specify flags for an SRv6 locator. Flags can be used to specify the properties of the locator. Signed-off-by: Carmine Scarpitta --- lib/srv6.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/srv6.h b/lib/srv6.h index 6e0c3ce99d1d..a3575583ae44 100644 --- a/lib/srv6.h +++ b/lib/srv6.h @@ -92,6 +92,8 @@ struct srv6_locator { bool status_up; struct list *chunks; + uint8_t flags; + QOBJ_FIELDS; }; DECLARE_QOBJ_TYPE(srv6_locator); @@ -116,6 +118,8 @@ struct srv6_locator_chunk { uint8_t proto; uint16_t instance; uint32_t session_id; + + uint8_t flags; }; struct nexthop_srv6 { From 02b1544a5c181b8ed24aa084982da1f986325927 Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Thu, 27 Oct 2022 18:41:54 +0200 Subject: [PATCH 02/10] lib: Add `SRV6_LOCATOR_USID` flag to SRv6 locator In this commit, we add support for a new flag called `SRV6_LOCATOR_USID`. When the `SRV6_LOCATOR_USID` flag is set, the routing protocols will install SRv6 behaviors with the uSID in the dataplane. This flag is used to specify a locator as a uSID locator. When a locator is specified as a uSID locator, all the SRv6 SIDs allocated from the locator by the routing protocols (like BGP) are bound to the SRv6 uSID behaviors and use the SRv6 uSID codepoints in the BGP update message. We extend the SRv6 locator implementation to add support for a `usid` flag. When the `usid` flag is set, the bgpd will install SRv6 behaviors with the uSID in the dataplane and use the proper SRv6 Endpoint Behavior codepoint in the BGP advertisement. Signed-off-by: Carmine Scarpitta --- lib/srv6.h | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/srv6.h b/lib/srv6.h index a3575583ae44..c5fd40fa5311 100644 --- a/lib/srv6.h +++ b/lib/srv6.h @@ -93,6 +93,7 @@ struct srv6_locator { struct list *chunks; uint8_t flags; +#define SRV6_LOCATOR_USID (1 << 0) /* The SRv6 Locator is a uSID Locator */ QOBJ_FIELDS; }; From d537287a48a88c1f4ba6c5df59fc701ae3045723 Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Thu, 27 Oct 2022 18:58:39 +0200 Subject: [PATCH 03/10] lib,zebra: Send SRv6 locator flags over the ZAPI In this commit, we extend the ZAPI to support encoding and decoding the locator flags contained in the messages exchanged between zebra and the routing daemons. Signed-off-by: Carmine Scarpitta --- lib/zclient.c | 2 ++ zebra/zapi_msg.c | 1 + 2 files changed, 3 insertions(+) diff --git a/lib/zclient.c b/lib/zclient.c index 8ec82ab7bb91..5f6fcee2e3f9 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -1088,6 +1088,7 @@ int zapi_srv6_locator_chunk_encode(struct stream *s, stream_putc(s, c->node_bits_length); stream_putc(s, c->function_bits_length); stream_putc(s, c->argument_bits_length); + stream_putc(s, c->flags); return 0; } @@ -1109,6 +1110,7 @@ int zapi_srv6_locator_chunk_decode(struct stream *s, STREAM_GETC(s, c->node_bits_length); STREAM_GETC(s, c->function_bits_length); STREAM_GETC(s, c->argument_bits_length); + STREAM_GETC(s, c->flags); return 0; stream_failure: diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 761ba789b87a..583f1b7d54e5 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -2709,6 +2709,7 @@ int zsend_srv6_manager_get_locator_chunk_response(struct zserv *client, chunk.keep = 0; chunk.proto = client->proto; chunk.instance = client->instance; + chunk.flags = loc->flags; zclient_create_header(s, ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK, vrf_id); zapi_srv6_locator_chunk_encode(s, &chunk); From 04947825547f00e5e2f3b894b372b3e4a8201db7 Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Thu, 27 Oct 2022 19:31:34 +0200 Subject: [PATCH 04/10] lib: Add support for SRv6 Behavior codepoints In this commit, we introduce a new enumeration to encode the SRv6 Endpoint Behaviors codepoints defined in the IANA SRv6 Endpoint Behaviors Registry (https://www.iana.org/assignments/segment-routing/segment-routing.xhtml). Signed-off-by: Carmine Scarpitta --- lib/srv6.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lib/srv6.h b/lib/srv6.h index c5fd40fa5311..f128b8b086b9 100644 --- a/lib/srv6.h +++ b/lib/srv6.h @@ -123,6 +123,21 @@ struct srv6_locator_chunk { uint8_t flags; }; +/* + * SRv6 Endpoint Behavior codepoints, as defined by IANA in + * https://www.iana.org/assignments/segment-routing/segment-routing.xhtml + */ +enum srv6_endpoint_behavior_codepoint { + SRV6_ENDPOINT_BEHAVIOR_RESERVED = 0x0000, + SRV6_ENDPOINT_BEHAVIOR_END_DT6 = 0x0012, + SRV6_ENDPOINT_BEHAVIOR_END_DT4 = 0x0013, + SRV6_ENDPOINT_BEHAVIOR_END_DT46 = 0x0014, + SRV6_ENDPOINT_BEHAVIOR_END_DT6_USID = 0x003E, + SRV6_ENDPOINT_BEHAVIOR_END_DT4_USID = 0x003F, + SRV6_ENDPOINT_BEHAVIOR_END_DT46_USID = 0x0040, + SRV6_ENDPOINT_BEHAVIOR_OPAQUE = 0xFFFF, +}; + struct nexthop_srv6 { /* SRv6 localsid info for Endpoint-behaviour */ enum seg6local_action_t seg6local_action; From 05d99980f36769778ebba434b0c101d36bf5fb4f Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Thu, 27 Oct 2022 19:47:11 +0200 Subject: [PATCH 05/10] bgpd: Use SRv6 codepoints in the BGP Advertisement Currently bgpd uses the opaque codepoint (0xFFFF) in the BGP advertisement. In this commit, we update bgpd to use the SRv6 codepoints defined in the IANA SRv6 Endpoint Behaviors Registry (https://www.iana.org/assignments/segment-routing/segment-routing.xhtml) Signed-off-by: Carmine Scarpitta --- bgpd/bgp_attr.c | 4 +++- bgpd/bgp_mplsvpn.c | 18 ++++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index b7d0958bac02..ce50378c8111 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -4355,7 +4355,9 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, stream_put(s, &attr->srv6_l3vpn->sid, sizeof(attr->srv6_l3vpn->sid)); /* sid */ stream_putc(s, 0); /* sid_flags */ - stream_putw(s, 0xffff); /* endpoint */ + stream_putw(s, + attr->srv6_l3vpn + ->endpoint_behavior); /* endpoint */ stream_putc(s, 0); /* reserved */ stream_putc( s, diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index a68167977de8..63f436029396 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -1562,13 +1562,22 @@ void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */ /* Set SID for SRv6 VPN */ if (from_bgp->vpn_policy[afi].tovpn_sid_locator) { + struct srv6_locator_chunk *locator = + from_bgp->vpn_policy[afi].tovpn_sid_locator; encode_label( from_bgp->vpn_policy[afi].tovpn_sid_transpose_label, &label); static_attr.srv6_l3vpn = XCALLOC(MTYPE_BGP_SRV6_L3VPN, sizeof(struct bgp_attr_srv6_l3vpn)); static_attr.srv6_l3vpn->sid_flags = 0x00; - static_attr.srv6_l3vpn->endpoint_behavior = 0xffff; + static_attr.srv6_l3vpn->endpoint_behavior = + afi == AFI_IP + ? (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID) + ? SRV6_ENDPOINT_BEHAVIOR_END_DT4_USID + : SRV6_ENDPOINT_BEHAVIOR_END_DT4) + : (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID) + ? SRV6_ENDPOINT_BEHAVIOR_END_DT6_USID + : SRV6_ENDPOINT_BEHAVIOR_END_DT6); static_attr.srv6_l3vpn->loc_block_len = from_bgp->vpn_policy[afi] .tovpn_sid_locator->block_bits_length; @@ -1595,12 +1604,17 @@ void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */ .tovpn_sid_locator->prefix.prefix, sizeof(struct in6_addr)); } else if (from_bgp->tovpn_sid_locator) { + struct srv6_locator_chunk *locator = + from_bgp->tovpn_sid_locator; encode_label(from_bgp->tovpn_sid_transpose_label, &label); static_attr.srv6_l3vpn = XCALLOC(MTYPE_BGP_SRV6_L3VPN, sizeof(struct bgp_attr_srv6_l3vpn)); static_attr.srv6_l3vpn->sid_flags = 0x00; - static_attr.srv6_l3vpn->endpoint_behavior = 0xffff; + static_attr.srv6_l3vpn->endpoint_behavior = + CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID) + ? SRV6_ENDPOINT_BEHAVIOR_END_DT46_USID + : SRV6_ENDPOINT_BEHAVIOR_END_DT46; static_attr.srv6_l3vpn->loc_block_len = from_bgp->tovpn_sid_locator->block_bits_length; static_attr.srv6_l3vpn->loc_node_len = From a3ff3dff3fcf3e264d4484a1ce5bbe40db3edcb7 Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Thu, 27 Oct 2022 20:01:24 +0200 Subject: [PATCH 06/10] lib,zebra: Add SRv6 uSID info to VTY output In this commit, we extend to print the `SRV6_LOCATOR_USID` flag. The output appears as follows: ``` { "locators":[ { "name":"loc1", "prefix":"fc00:0:1::/48", "blockBitsLength":32, "nodeBitsLength":16, "functionBitsLength":16, "argumentBitsLength":0, "uSID":true, "statusUp":true, "chunks":[ { "prefix":"fc00:0:1::/48", "proto":"bgp" } ] } ] } ``` Signed-off-by: Carmine Scarpitta --- lib/srv6.c | 8 ++++++++ zebra/zebra_srv6_vty.c | 3 +++ 2 files changed, 11 insertions(+) diff --git a/lib/srv6.c b/lib/srv6.c index 306d92ae303b..b7142d618c51 100644 --- a/lib/srv6.c +++ b/lib/srv6.c @@ -245,6 +245,10 @@ json_object *srv6_locator_json(const struct srv6_locator *loc) json_object_int_add(jo_root, "argumentBitsLength", loc->argument_bits_length); + /* set true if the locator is a Micro-segment (uSID) locator */ + if (CHECK_FLAG(loc->flags, SRV6_LOCATOR_USID)) + json_object_string_add(jo_root, "behavior", "usid"); + /* set status_up */ json_object_boolean_add(jo_root, "statusUp", loc->status_up); @@ -290,6 +294,10 @@ json_object *srv6_locator_detailed_json(const struct srv6_locator *loc) json_object_int_add(jo_root, "argumentBitsLength", loc->argument_bits_length); + /* set true if the locator is a Micro-segment (uSID) locator */ + if (CHECK_FLAG(loc->flags, SRV6_LOCATOR_USID)) + json_object_string_add(jo_root, "behavior", "usid"); + /* set algonum */ json_object_int_add(jo_root, "algoNum", loc->algonum); diff --git a/zebra/zebra_srv6_vty.c b/zebra/zebra_srv6_vty.c index 9adfc6550a58..956669af5606 100644 --- a/zebra/zebra_srv6_vty.c +++ b/zebra/zebra_srv6_vty.c @@ -174,6 +174,9 @@ DEFUN (show_srv6_locator_detail, vty_out(vty, "Argument-Bit-Len: %u\n", locator->argument_bits_length); + if (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID)) + vty_out(vty, "Behavior: uSID\n"); + vty_out(vty, "Chunks:\n"); for (ALL_LIST_ELEMENTS_RO((struct list *)locator->chunks, node, chunk)) { From 7e975421bda03fdd34ec81dd17a0c02c36ebb31a Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Sat, 29 Oct 2022 01:28:30 +0200 Subject: [PATCH 07/10] zebra: Add helpers to notify locator add/delete In this commit, we add two helper functions `zebra_notify_srv6_locator_add` and `zebra_notify_srv6_locator_delete`. These functions are used to notify locator additions/deletions to zclients. Signed-off-by: Carmine Scarpitta --- zebra/zebra_srv6.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++ zebra/zebra_srv6.h | 3 +++ 2 files changed, 55 insertions(+) diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c index 36506cacc7b3..d61e4f8045d9 100644 --- a/zebra/zebra_srv6.c +++ b/zebra/zebra_srv6.c @@ -177,6 +177,58 @@ struct srv6_locator *zebra_srv6_locator_lookup(const char *name) return NULL; } +void zebra_notify_srv6_locator_add(struct srv6_locator *locator) +{ + struct listnode *node; + struct zserv *client; + + /* + * Notify new locator info to zclients. + * + * The srv6 locators and their prefixes are managed by zserv(zebra). + * And an actual configuration the srv6 sid in the srv6 locator is done + * by zclient(bgpd, isisd, etc). The configuration of each locator + * allocation and specify it by zserv and zclient should be + * asynchronous. For that, zclient should be received the event via + * ZAPI when a srv6 locator is added on zebra. + * Basically, in SRv6, adding/removing SRv6 locators is performed less + * frequently than adding rib entries, so a broad to all zclients will + * not degrade the overall performance of FRRouting. + */ + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) + zsend_zebra_srv6_locator_add(client, locator); +} + +void zebra_notify_srv6_locator_delete(struct srv6_locator *locator) +{ + struct listnode *n; + struct srv6_locator_chunk *c; + struct zserv *client; + + /* + * Notify deleted locator info to zclients if needed. + * + * zclient(bgpd,isisd,etc) allocates a sid from srv6 locator chunk and + * uses it for its own purpose. For example, in the case of BGP L3VPN, + * the SID assigned to vpn unicast rib will be given. + * And when the locator is deleted by zserv(zebra), those SIDs need to + * be withdrawn. The zclient must initiate the withdrawal of the SIDs + * by ZEBRA_SRV6_LOCATOR_DELETE, and this notification is sent to the + * owner of each chunk. + */ + for (ALL_LIST_ELEMENTS_RO((struct list *)locator->chunks, n, c)) { + if (c->proto == ZEBRA_ROUTE_SYSTEM) + continue; + client = zserv_find_client(c->proto, c->instance); + if (!client) { + zlog_warn("Not found zclient(proto=%u, instance=%u).", + c->proto, c->instance); + continue; + } + zsend_zebra_srv6_locator_delete(client, locator); + } +} + struct zebra_srv6 *zebra_srv6_get_default(void) { static struct zebra_srv6 srv6; diff --git a/zebra/zebra_srv6.h b/zebra/zebra_srv6.h index 84fcc305bc32..f320b9ca0f94 100644 --- a/zebra/zebra_srv6.h +++ b/zebra/zebra_srv6.h @@ -61,6 +61,9 @@ 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); +void zebra_notify_srv6_locator_add(struct srv6_locator *locator); +void zebra_notify_srv6_locator_delete(struct srv6_locator *locator); + extern void zebra_srv6_init(void); extern struct zebra_srv6 *zebra_srv6_get_default(void); extern bool zebra_srv6_is_enable(void); From 3a7e1f656e1888079231b4a18c8dd78a946f5ff1 Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Thu, 27 Oct 2022 20:08:40 +0200 Subject: [PATCH 08/10] zebra: Add `behavior usid` command to VTY Install a new command `behavior usid` into the `SRV6_LOC_NODE` CLI node. This command allows the user to set/unset the `SRV6_LOCATOR_USID` flag for an SRv6 locator. The `SRV6_LOCATOR_USID` flag indicates whether a locator is a uSID locator or not. When the flag is set, the routing daemons (e.g., bgpd) will install SRv6 behaviors with the uSID in the dataplane. Signed-off-by: Carmine Scarpitta --- zebra/zebra_srv6_vty.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/zebra/zebra_srv6_vty.c b/zebra/zebra_srv6_vty.c index 956669af5606..88922607e86e 100644 --- a/zebra/zebra_srv6_vty.c +++ b/zebra/zebra_srv6_vty.c @@ -374,6 +374,38 @@ DEFPY (locator_prefix, return CMD_SUCCESS; } +DEFPY (locator_behavior, + locator_behavior_cmd, + "[no] behavior usid", + NO_STR + "Configure SRv6 behavior\n" + "Specify SRv6 behavior uSID\n") +{ + VTY_DECLVAR_CONTEXT(srv6_locator, locator); + + if (no && !CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID)) + /* SRv6 locator uSID flag already unset, nothing to do */ + return CMD_SUCCESS; + + if (!no && CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID)) + /* SRv6 locator uSID flag already set, nothing to do */ + return CMD_SUCCESS; + + /* Remove old locator from zclients */ + zebra_notify_srv6_locator_delete(locator); + + /* Set/Unset the SRV6_LOCATOR_USID */ + if (no) + UNSET_FLAG(locator->flags, SRV6_LOCATOR_USID); + else + SET_FLAG(locator->flags, SRV6_LOCATOR_USID); + + /* Notify the new locator to zclients */ + zebra_notify_srv6_locator_add(locator); + + return CMD_SUCCESS; +} + static int zebra_sr_config(struct vty *vty) { struct zebra_srv6 *srv6 = zebra_srv6_get_default(); @@ -404,6 +436,8 @@ static int zebra_sr_config(struct vty *vty) if (locator->argument_bits_length) vty_out(vty, " arg-len %u", locator->argument_bits_length); + if (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID)) + vty_out(vty, " behavior usid"); vty_out(vty, "\n"); vty_out(vty, " exit\n"); vty_out(vty, " !\n"); @@ -440,6 +474,7 @@ void zebra_srv6_vty_init(void) /* Command for configuration */ install_element(SRV6_LOC_NODE, &locator_prefix_cmd); + install_element(SRV6_LOC_NODE, &locator_behavior_cmd); /* Command for operation */ install_element(VIEW_NODE, &show_srv6_locator_cmd); From c891f9ce0d281c4d1ed1a2dab1b6e2578509d5a5 Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Thu, 27 Oct 2022 23:40:09 +0200 Subject: [PATCH 09/10] tests: Add topotest for SRv6 uSID Locator This test ensures that the command `behavior usid` works properly. When the `behavior usid` command is set, a flag is added to the locator to indicate that the locator is a uSID locator. This test verifies that the locator works correctly when you set / unset the `behavior usid` command. Signed-off-by: Carmine Scarpitta --- tests/topotests/srv6_locator_usid/__init__.py | 0 .../srv6_locator_usid/expected_chunks_1.json | 1 + .../srv6_locator_usid/expected_chunks_2.json | 8 + .../srv6_locator_usid/expected_chunks_3.json | 1 + .../srv6_locator_usid/expected_chunks_4.json | 1 + .../srv6_locator_usid/expected_chunks_5.json | 2 + .../srv6_locator_usid/expected_chunks_6.json | 2 + .../srv6_locator_usid/expected_chunks_7.json | 2 + .../srv6_locator_usid/expected_chunks_8.json | 2 + .../expected_locators_1.json | 20 ++ .../expected_locators_2.json | 20 ++ .../expected_locators_3.json | 20 ++ .../expected_locators_4.json | 35 +++ .../expected_locators_5.json | 36 +++ .../expected_locators_6.json | 35 +++ .../expected_locators_7.json | 19 ++ .../expected_locators_8.json | 4 + tests/topotests/srv6_locator_usid/r1/setup.sh | 2 + .../srv6_locator_usid/r1/sharpd.conf | 7 + .../topotests/srv6_locator_usid/r1/zebra.conf | 20 ++ .../test_srv6_locator_usid.py | 276 ++++++++++++++++++ 21 files changed, 513 insertions(+) create mode 100644 tests/topotests/srv6_locator_usid/__init__.py create mode 100644 tests/topotests/srv6_locator_usid/expected_chunks_1.json create mode 100644 tests/topotests/srv6_locator_usid/expected_chunks_2.json create mode 100644 tests/topotests/srv6_locator_usid/expected_chunks_3.json create mode 100644 tests/topotests/srv6_locator_usid/expected_chunks_4.json create mode 100644 tests/topotests/srv6_locator_usid/expected_chunks_5.json create mode 100644 tests/topotests/srv6_locator_usid/expected_chunks_6.json create mode 100644 tests/topotests/srv6_locator_usid/expected_chunks_7.json create mode 100644 tests/topotests/srv6_locator_usid/expected_chunks_8.json create mode 100644 tests/topotests/srv6_locator_usid/expected_locators_1.json create mode 100644 tests/topotests/srv6_locator_usid/expected_locators_2.json create mode 100644 tests/topotests/srv6_locator_usid/expected_locators_3.json create mode 100644 tests/topotests/srv6_locator_usid/expected_locators_4.json create mode 100644 tests/topotests/srv6_locator_usid/expected_locators_5.json create mode 100644 tests/topotests/srv6_locator_usid/expected_locators_6.json create mode 100644 tests/topotests/srv6_locator_usid/expected_locators_7.json create mode 100644 tests/topotests/srv6_locator_usid/expected_locators_8.json create mode 100644 tests/topotests/srv6_locator_usid/r1/setup.sh create mode 100644 tests/topotests/srv6_locator_usid/r1/sharpd.conf create mode 100644 tests/topotests/srv6_locator_usid/r1/zebra.conf create mode 100755 tests/topotests/srv6_locator_usid/test_srv6_locator_usid.py diff --git a/tests/topotests/srv6_locator_usid/__init__.py b/tests/topotests/srv6_locator_usid/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/topotests/srv6_locator_usid/expected_chunks_1.json b/tests/topotests/srv6_locator_usid/expected_chunks_1.json new file mode 100644 index 000000000000..fe51488c7066 --- /dev/null +++ b/tests/topotests/srv6_locator_usid/expected_chunks_1.json @@ -0,0 +1 @@ +[] diff --git a/tests/topotests/srv6_locator_usid/expected_chunks_2.json b/tests/topotests/srv6_locator_usid/expected_chunks_2.json new file mode 100644 index 000000000000..304d73807c51 --- /dev/null +++ b/tests/topotests/srv6_locator_usid/expected_chunks_2.json @@ -0,0 +1,8 @@ +[ + { + "name": "loc1", + "chunks": [ + "fc00:0:1::/48" + ] + } +] diff --git a/tests/topotests/srv6_locator_usid/expected_chunks_3.json b/tests/topotests/srv6_locator_usid/expected_chunks_3.json new file mode 100644 index 000000000000..fe51488c7066 --- /dev/null +++ b/tests/topotests/srv6_locator_usid/expected_chunks_3.json @@ -0,0 +1 @@ +[] diff --git a/tests/topotests/srv6_locator_usid/expected_chunks_4.json b/tests/topotests/srv6_locator_usid/expected_chunks_4.json new file mode 100644 index 000000000000..fe51488c7066 --- /dev/null +++ b/tests/topotests/srv6_locator_usid/expected_chunks_4.json @@ -0,0 +1 @@ +[] diff --git a/tests/topotests/srv6_locator_usid/expected_chunks_5.json b/tests/topotests/srv6_locator_usid/expected_chunks_5.json new file mode 100644 index 000000000000..0d4f101c7a37 --- /dev/null +++ b/tests/topotests/srv6_locator_usid/expected_chunks_5.json @@ -0,0 +1,2 @@ +[ +] diff --git a/tests/topotests/srv6_locator_usid/expected_chunks_6.json b/tests/topotests/srv6_locator_usid/expected_chunks_6.json new file mode 100644 index 000000000000..0d4f101c7a37 --- /dev/null +++ b/tests/topotests/srv6_locator_usid/expected_chunks_6.json @@ -0,0 +1,2 @@ +[ +] diff --git a/tests/topotests/srv6_locator_usid/expected_chunks_7.json b/tests/topotests/srv6_locator_usid/expected_chunks_7.json new file mode 100644 index 000000000000..0d4f101c7a37 --- /dev/null +++ b/tests/topotests/srv6_locator_usid/expected_chunks_7.json @@ -0,0 +1,2 @@ +[ +] diff --git a/tests/topotests/srv6_locator_usid/expected_chunks_8.json b/tests/topotests/srv6_locator_usid/expected_chunks_8.json new file mode 100644 index 000000000000..0d4f101c7a37 --- /dev/null +++ b/tests/topotests/srv6_locator_usid/expected_chunks_8.json @@ -0,0 +1,2 @@ +[ +] diff --git a/tests/topotests/srv6_locator_usid/expected_locators_1.json b/tests/topotests/srv6_locator_usid/expected_locators_1.json new file mode 100644 index 000000000000..c0eeacc09a26 --- /dev/null +++ b/tests/topotests/srv6_locator_usid/expected_locators_1.json @@ -0,0 +1,20 @@ +{ + "locators":[ + { + "name": "loc1", + "prefix": "fc00:0:1::/48", + "blockBitsLength": 32, + "nodeBitsLength": 16, + "functionBitsLength": 16, + "argumentBitsLength": 0, + "behavior": "usid", + "statusUp": true, + "chunks": [ + { + "prefix": "fc00:0:1::/48", + "proto": "system" + } + ] + } + ] +} diff --git a/tests/topotests/srv6_locator_usid/expected_locators_2.json b/tests/topotests/srv6_locator_usid/expected_locators_2.json new file mode 100644 index 000000000000..38a6739d64fe --- /dev/null +++ b/tests/topotests/srv6_locator_usid/expected_locators_2.json @@ -0,0 +1,20 @@ +{ + "locators":[ + { + "name": "loc1", + "prefix": "fc00:0:1::/48", + "blockBitsLength": 32, + "nodeBitsLength": 16, + "functionBitsLength": 16, + "argumentBitsLength": 0, + "behavior": "usid", + "statusUp": true, + "chunks": [ + { + "prefix": "fc00:0:1::/48", + "proto": "sharp" + } + ] + } + ] +} diff --git a/tests/topotests/srv6_locator_usid/expected_locators_3.json b/tests/topotests/srv6_locator_usid/expected_locators_3.json new file mode 100644 index 000000000000..c0eeacc09a26 --- /dev/null +++ b/tests/topotests/srv6_locator_usid/expected_locators_3.json @@ -0,0 +1,20 @@ +{ + "locators":[ + { + "name": "loc1", + "prefix": "fc00:0:1::/48", + "blockBitsLength": 32, + "nodeBitsLength": 16, + "functionBitsLength": 16, + "argumentBitsLength": 0, + "behavior": "usid", + "statusUp": true, + "chunks": [ + { + "prefix": "fc00:0:1::/48", + "proto": "system" + } + ] + } + ] +} diff --git a/tests/topotests/srv6_locator_usid/expected_locators_4.json b/tests/topotests/srv6_locator_usid/expected_locators_4.json new file mode 100644 index 000000000000..b1528ff1118a --- /dev/null +++ b/tests/topotests/srv6_locator_usid/expected_locators_4.json @@ -0,0 +1,35 @@ +{ + "locators":[ + { + "name": "loc1", + "prefix": "fc00:0:1::/48", + "blockBitsLength": 32, + "nodeBitsLength": 16, + "functionBitsLength": 16, + "argumentBitsLength": 0, + "behavior": "usid", + "statusUp": true, + "chunks": [ + { + "prefix": "fc00:0:1::/48", + "proto": "system" + } + ] + }, + { + "name": "loc2", + "prefix": "fc00:0:2::/48", + "blockBitsLength": 32, + "nodeBitsLength": 16, + "functionBitsLength": 16, + "argumentBitsLength": 0, + "statusUp": true, + "chunks": [ + { + "prefix": "fc00:0:2::/48", + "proto": "system" + } + ] + } + ] +} diff --git a/tests/topotests/srv6_locator_usid/expected_locators_5.json b/tests/topotests/srv6_locator_usid/expected_locators_5.json new file mode 100644 index 000000000000..b6acc238a795 --- /dev/null +++ b/tests/topotests/srv6_locator_usid/expected_locators_5.json @@ -0,0 +1,36 @@ +{ + "locators":[ + { + "name": "loc1", + "prefix": "fc00:0:1::/48", + "blockBitsLength": 32, + "nodeBitsLength": 16, + "functionBitsLength": 16, + "argumentBitsLength": 0, + "behavior": "usid", + "statusUp": true, + "chunks": [ + { + "prefix": "fc00:0:1::/48", + "proto": "system" + } + ] + }, + { + "name": "loc2", + "prefix": "fc00:0:2::/48", + "blockBitsLength": 32, + "nodeBitsLength": 16, + "functionBitsLength": 16, + "argumentBitsLength": 0, + "behavior": "usid", + "statusUp": true, + "chunks": [ + { + "prefix": "fc00:0:2::/48", + "proto": "system" + } + ] + } + ] +} diff --git a/tests/topotests/srv6_locator_usid/expected_locators_6.json b/tests/topotests/srv6_locator_usid/expected_locators_6.json new file mode 100644 index 000000000000..b1528ff1118a --- /dev/null +++ b/tests/topotests/srv6_locator_usid/expected_locators_6.json @@ -0,0 +1,35 @@ +{ + "locators":[ + { + "name": "loc1", + "prefix": "fc00:0:1::/48", + "blockBitsLength": 32, + "nodeBitsLength": 16, + "functionBitsLength": 16, + "argumentBitsLength": 0, + "behavior": "usid", + "statusUp": true, + "chunks": [ + { + "prefix": "fc00:0:1::/48", + "proto": "system" + } + ] + }, + { + "name": "loc2", + "prefix": "fc00:0:2::/48", + "blockBitsLength": 32, + "nodeBitsLength": 16, + "functionBitsLength": 16, + "argumentBitsLength": 0, + "statusUp": true, + "chunks": [ + { + "prefix": "fc00:0:2::/48", + "proto": "system" + } + ] + } + ] +} diff --git a/tests/topotests/srv6_locator_usid/expected_locators_7.json b/tests/topotests/srv6_locator_usid/expected_locators_7.json new file mode 100644 index 000000000000..e965e0217037 --- /dev/null +++ b/tests/topotests/srv6_locator_usid/expected_locators_7.json @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name": "loc2", + "prefix": "fc00:0:2::/48", + "statusUp": true, + "blockBitsLength": 32, + "nodeBitsLength": 16, + "functionBitsLength": 16, + "argumentBitsLength": 0, + "chunks":[ + { + "prefix": "fc00:0:2::/48", + "proto": "system" + } + ] + } + ] +} diff --git a/tests/topotests/srv6_locator_usid/expected_locators_8.json b/tests/topotests/srv6_locator_usid/expected_locators_8.json new file mode 100644 index 000000000000..6e1b993ca845 --- /dev/null +++ b/tests/topotests/srv6_locator_usid/expected_locators_8.json @@ -0,0 +1,4 @@ +{ + "locators":[ + ] +} diff --git a/tests/topotests/srv6_locator_usid/r1/setup.sh b/tests/topotests/srv6_locator_usid/r1/setup.sh new file mode 100644 index 000000000000..36ed713f2416 --- /dev/null +++ b/tests/topotests/srv6_locator_usid/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_usid/r1/sharpd.conf b/tests/topotests/srv6_locator_usid/r1/sharpd.conf new file mode 100644 index 000000000000..d46085935c80 --- /dev/null +++ b/tests/topotests/srv6_locator_usid/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_usid/r1/zebra.conf b/tests/topotests/srv6_locator_usid/r1/zebra.conf new file mode 100644 index 000000000000..78ef1e9d407a --- /dev/null +++ b/tests/topotests/srv6_locator_usid/r1/zebra.conf @@ -0,0 +1,20 @@ +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 fc00:0:1::/48 func-bits 16 block-len 32 node-len 16 + behavior usid + ! + ! + ! +! diff --git a/tests/topotests/srv6_locator_usid/test_srv6_locator_usid.py b/tests/topotests/srv6_locator_usid/test_srv6_locator_usid.py new file mode 100755 index 000000000000..37fd736d2be5 --- /dev/null +++ b/tests/topotests/srv6_locator_usid/test_srv6_locator_usid.py @@ -0,0 +1,276 @@ +#!/usr/bin/env python + +# Copyright (c) 2022, University of Rome Tor Vergata +# Authored by Carmine Scarpitta +# +# 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_locator_usid.py: +Test for SRv6 Locator uSID on zebra +""" + +import os +import sys +import json +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 + +pytestmark = [pytest.mark.bgpd, pytest.mark.sharpd] + + +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 setup_module(mod): + tgen = Topogen({None: "r1"}, mod.__name__) + tgen.start_topology() + 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_SHARP, os.path.join( + CWD, "{}/sharpd.conf".format(rname)) + ) + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +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 json") + ) + 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=3) + 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=3) + assert result is None, "Failed" + + +def test_srv6_usid_locator_configuration(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + router = tgen.gears["r1"] + + # FOR DEVELOPER: + # If you want to stop some specific line and start interactive shell, + # please use tgen.mininet_cli() to start it. + + logger.info("Verify SRv6 Locators instantiated from config file") + check_srv6_locator(router, "expected_locators_1.json") + check_sharpd_chunk(router, "expected_chunks_1.json") + + +def test_srv6_usid_locator_get_chunk(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + router = tgen.gears["r1"] + + # FOR DEVELOPER: + # If you want to stop some specific line and start interactive shell, + # please use tgen.mininet_cli() to start it. + + logger.info("Get chunk for the locator loc1") + router.vtysh_cmd("sharp srv6-manager get-locator-chunk loc1") + check_srv6_locator(router, "expected_locators_2.json") + check_sharpd_chunk(router, "expected_chunks_2.json") + + +def test_srv6_usid_locator_release_chunk(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + router = tgen.gears["r1"] + + # FOR DEVELOPER: + # If you want to stop some specific line and start interactive shell, + # please use tgen.mininet_cli() to start it. + + logger.info("Release chunk for the locator loc1") + router.vtysh_cmd("sharp srv6-manager release-locator-chunk loc1") + check_srv6_locator(router, "expected_locators_3.json") + check_sharpd_chunk(router, "expected_chunks_3.json") + + +def test_srv6_usid_locator_create_locator(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + router = tgen.gears["r1"] + + # FOR DEVELOPER: + # If you want to stop some specific line and start interactive shell, + # please use tgen.mininet_cli() to start it. + + logger.info("Create an additional SRv6 Locator") + router.vtysh_cmd( + """ + configure terminal + segment-routing + srv6 + locators + locator loc2 + prefix fc00:0:2::/48 func-bits 16 block-len 32 node-len 16 + """ + ) + check_srv6_locator(router, "expected_locators_4.json") + check_sharpd_chunk(router, "expected_chunks_4.json") + + +def test_srv6_usid_locator_set_behavior_usid(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + router = tgen.gears["r1"] + + # FOR DEVELOPER: + # If you want to stop some specific line and start interactive shell, + # please use tgen.mininet_cli() to start it. + + logger.info( + "Specify the SRv6 Locator loc2 as a Micro-segment (uSID) Locator" + ) + router.vtysh_cmd( + """ + configure terminal + segment-routing + srv6 + locators + locator loc2 + behavior usid + """ + ) + check_srv6_locator(router, "expected_locators_5.json") + check_sharpd_chunk(router, "expected_chunks_5.json") + + +def test_srv6_usid_locator_unset_behavior_usid(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + router = tgen.gears["r1"] + + # FOR DEVELOPER: + # If you want to stop some specific line and start interactive shell, + # please use tgen.mininet_cli() to start it. + + logger.info("Clear Micro-segment (uSID) Locator flag for loc2") + router.vtysh_cmd( + """ + configure terminal + segment-routing + srv6 + locators + locator loc2 + no behavior usid + """ + ) + check_srv6_locator(router, "expected_locators_6.json") + check_sharpd_chunk(router, "expected_chunks_6.json") + + +def test_srv6_usid_locator_delete(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + router = tgen.gears["r1"] + + # FOR DEVELOPER: + # If you want to stop some specific line and start interactive shell, + # please use tgen.mininet_cli() to start it. + + logger.info( + "Delete locator loc1 and verify that the chunk is released automatically" + ) + router.vtysh_cmd( + """ + configure terminal + segment-routing + srv6 + locators + no locator loc1 + """ + ) + check_srv6_locator(router, "expected_locators_7.json") + check_sharpd_chunk(router, "expected_chunks_7.json") + + +def test_srv6_usid_locator_delete_all(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + router = tgen.gears["r1"] + + # FOR DEVELOPER: + # If you want to stop some specific line and start interactive shell, + # please use tgen.mininet_cli() to start it. + + logger.info("Delete all the SRv6 configuration") + router.vtysh_cmd( + """ + configure terminal + segment-routing + no srv6 + """ + ) + check_srv6_locator(router, "expected_locators_8.json") + check_sharpd_chunk(router, "expected_chunks_8.json") + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) From 439d4c9b03f37522376e2466c67540f63d40891b Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Fri, 28 Oct 2022 00:11:02 +0200 Subject: [PATCH 10/10] doc: Add documentation for behavior usid command Add the documentation for the `behavior usid` command to zebra. When the `behavior usid` command is set, a flag is added to the locator to indicate that the locator is a uSID locator. When a locator is specified as a uSID locator, the bgpd will install SRv6 behaviors with the uSID in the dataplane and use the SRv6 uSID codepoints in the BGP update message. Signed-off-by: Carmine Scarpitta --- doc/user/zebra.rst | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index bfe11a19a13f..9001e2c6251c 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -810,6 +810,36 @@ and this section also helps that case. ! ... +.. clicmd:: behavior usid + + Specify the SRv6 locator as a Micro-segment (uSID) locator. When a locator is + specified as a uSID locator, all the SRv6 SIDs allocated from the locator by the routing + protocols are bound to the SRv6 uSID behaviors. For example, if you configure BGP to use + a locator specified as a uSID locator, BGP instantiates and advertises SRv6 uSID behaviors + (e.g., ``uDT4`` / ``uDT6`` / ``uDT46``) instead of classic SRv6 behaviors + (e.g., ``End.DT4`` / ``End.DT6`` / ``End.DT46``). + +:: + + router# configure terminal + router(config)# segment-routinig + router(config-sr)# srv6 + router(config-srv6)# locators + router(config-srv6-locators)# locator loc1 + router(config-srv6-locator)# prefix fc00:0:1::/48 block-len 32 node-len 16 func-bits 16 + router(config-srv6-locator)# behavior usid + + router(config-srv6-locator)# show run + ... + segment-routing + srv6 + locators + locator loc1 + prefix fc00:0:1::/48 + behavior usid + ! + ... + .. _multicast-rib-commands: Multicast RIB Commands