From c4c205b091934d96a173f4c0d75ef7e888298ac7 Mon Sep 17 00:00:00 2001 From: Takeru Hayasaka Date: Fri, 30 Dec 2022 16:41:44 +0900 Subject: [PATCH] sr: support define src ipv6 per encap policy Can to define src ip of outer IPv6 Hdr for each encap policy. Along with that, I decided to develop it as API version V2. This is useful in the SRv6 MUP case. For example, it will be possible to handle multiple UPF destinations. Type: feature Change-Id: I44ff7b54e8868619069621ab53e194e2c7a17435 Signed-off-by: Takeru Hayasaka --- src/vnet/srv6/sr.api | 84 +++++++++++++++++- src/vnet/srv6/sr.h | 13 +-- src/vnet/srv6/sr_api.c | 179 +++++++++++++++++++++++++++++++++----- src/vnet/srv6/sr_policy_rewrite.c | 62 ++++++++----- src/vnet/srv6/sr_test.c | 23 +++++ test/test_srv6.py | 116 ++++++++++++++++++++++++ test/vpp_srv6.py | 79 ++++++++++++++++- 7 files changed, 506 insertions(+), 50 deletions(-) diff --git a/src/vnet/srv6/sr.api b/src/vnet/srv6/sr.api index 08ae9fa2300..8bebcd1b894 100644 --- a/src/vnet/srv6/sr.api +++ b/src/vnet/srv6/sr.api @@ -14,7 +14,7 @@ * limitations under the License. */ -option version = "2.0.0"; +option version = "2.1.0"; import "vnet/interface_types.api"; import "vnet/ip/ip_types.api"; @@ -109,6 +109,65 @@ autoreply define sr_policy_mod vl_api_srv6_sid_list_t sids; }; +enum sr_policy_type : u8 +{ + SR_API_POLICY_TYPE_DEFAULT = 0, + SR_API_POLICY_TYPE_SPRAY = 1, + SR_API_POLICY_TYPE_TEF = 2, +}; + +/** \brief IPv6 SR policy add + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param bsid is the bindingSID of the SR Policy + @param weight is the weight of the sid list. optional. + @param is_encap is the behavior of the SR policy. (0.SRH insert // 1.Encapsulation) + @param type is the SR policy param. (0.Default // 1.Spray // 2.Tef) + @param fib_table is the VRF where to install the FIB entry for the BSID + @param sids is a srv6_sid_list object + @param encap_src is a encaps IPv6 source addr. optional. +*/ +autoreply define sr_policy_add_v2 +{ + u32 client_index; + u32 context; + vl_api_ip6_address_t bsid_addr; + u32 weight; + bool is_encap; + vl_api_sr_policy_type_t type [default=0x0]; + u32 fib_table; + vl_api_srv6_sid_list_t sids; + vl_api_ip6_address_t encap_src; + option status="in_progress"; +}; + +/** \brief IPv6 SR policy modification + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param bsid is the bindingSID of the SR Policy + @param sr_policy_index is the index of the SR policy + @param fib_table is the VRF where to install the FIB entry for the BSID + @param operation is the operation to perform (among the top ones) + @param sl_index is the index of the Segment List to modify/delete + @param weight is the weight of the sid list. optional. + @param sids is a srv6_sid_list object + @param encap_src is a encaps IPv6 source addr. optional. +*/ +autoreply define sr_policy_mod_v2 +{ + u32 client_index; + u32 context; + vl_api_ip6_address_t bsid_addr; + u32 sr_policy_index; + u32 fib_table; + vl_api_sr_policy_op_t operation; + u32 sl_index; + u32 weight; + vl_api_srv6_sid_list_t sids; + vl_api_ip6_address_t encap_src; + option status="in_progress"; +}; + /** \brief IPv6 SR policy deletion @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -248,6 +307,29 @@ define sr_policies_details vl_api_srv6_sid_list_t sid_lists[num_sid_lists]; }; +/** \brief Dump the list of SR policies v2 + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request +*/ +define sr_policies_v2_dump +{ + u32 client_index; + u32 context; +}; + +define sr_policies_v2_details +{ + u32 context; + vl_api_ip6_address_t bsid; + vl_api_ip6_address_t encap_src; + vl_api_sr_policy_type_t type; + bool is_encap; + u32 fib_table; + u8 num_sid_lists; + vl_api_srv6_sid_list_t sid_lists[num_sid_lists]; + option in_progress; +}; + /** \brief Dump the list of SR policies along with actual segment list index on VPP @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request diff --git a/src/vnet/srv6/sr.h b/src/vnet/srv6/sr.h index 02cceade682..7d8aa732a65 100644 --- a/src/vnet/srv6/sr.h +++ b/src/vnet/srv6/sr.h @@ -112,6 +112,8 @@ typedef struct u8 is_encap; /**< Mode (0 is SRH insert, 1 Encaps) */ + ip6_address_t encap_src; + u16 plugin; void *plugin_mem; } ip6_sr_policy_t; @@ -345,11 +347,12 @@ sr_policy_register_function (vlib_main_t * vm, u8 * fn_name, sr_p_plugin_callback_t * removal_fn); extern int sr_policy_add (ip6_address_t *bsid, ip6_address_t *segments, - u32 weight, u8 type, u32 fib_table, u8 is_encap, - u16 plugin, void *plugin_mem); -extern int sr_policy_mod (ip6_address_t * bsid, u32 index, u32 fib_table, - u8 operation, ip6_address_t * segments, - u32 sl_index, u32 weight); + ip6_address_t *encap_src, u32 weight, u8 type, + u32 fib_table, u8 is_encap, u16 plugin, + void *plugin_mem); +extern int sr_policy_mod (ip6_address_t *bsid, u32 index, u32 fib_table, + u8 operation, ip6_address_t *segments, + ip6_address_t *encap_src, u32 sl_index, u32 weight); extern int sr_policy_del (ip6_address_t * bsid, u32 index); extern int diff --git a/src/vnet/srv6/sr_api.c b/src/vnet/srv6/sr_api.c index 1b95125bc90..5594fed44f6 100644 --- a/src/vnet/srv6/sr_api.c +++ b/src/vnet/srv6/sr_api.c @@ -82,17 +82,16 @@ vl_api_sr_policy_add_t_handler (vl_api_sr_policy_add_t * mp) ip6_address_decode (mp->bsid_addr, &bsid_addr); -/* - * sr_policy_add (ip6_address_t *bsid, ip6_address_t *segments, - * u32 weight, u8 behavior, u32 fib_table, u8 is_encap, - * u16 behavior, void *plugin_mem) - */ + /* + * sr_policy_add (ip6_address_t *bsid, ip6_address_t *segments, + * ip6_address_t *encap_src, + * u32 weight, u8 behavior, u32 fib_table, u8 is_encap, + * u16 behavior, void *plugin_mem) + */ int rv = 0; - rv = sr_policy_add (&bsid_addr, - segments, - ntohl (mp->sids.weight), - mp->is_spray, ntohl (mp->fib_table), mp->is_encap, 0, - NULL); + rv = + sr_policy_add (&bsid_addr, segments, NULL, ntohl (mp->sids.weight), + mp->is_spray, ntohl (mp->fib_table), mp->is_encap, 0, NULL); vec_free (segments); REPLY_MACRO (VL_API_SR_POLICY_ADD_REPLY); @@ -115,18 +114,93 @@ vl_api_sr_policy_mod_t_handler (vl_api_sr_policy_mod_t * mp) ip6_address_decode (mp->bsid_addr, &bsid_addr); int rv = 0; -/* - * int - * sr_policy_mod(ip6_address_t *bsid, u32 index, u32 fib_table, - * u8 operation, ip6_address_t *segments, u32 sl_index, - * u32 weight, u8 is_encap) - */ - rv = sr_policy_mod (&bsid_addr, - ntohl (mp->sr_policy_index), - ntohl (mp->fib_table), - mp->operation, - segments, ntohl (mp->sl_index), - ntohl (mp->sids.weight)); + /* + * int + * sr_policy_mod(ip6_address_t *bsid, u32 index, u32 fib_table, + * u8 operation, ip6_address_t *segments, + * ip6_address_t *encap_src, u32 sl_index, + * u32 weight, u8 is_encap) + */ + rv = sr_policy_mod (&bsid_addr, ntohl (mp->sr_policy_index), + ntohl (mp->fib_table), mp->operation, segments, NULL, + ntohl (mp->sl_index), ntohl (mp->sids.weight)); + vec_free (segments); + + REPLY_MACRO (VL_API_SR_POLICY_MOD_REPLY); +} + +static void +vl_api_sr_policy_add_v2_t_handler (vl_api_sr_policy_add_v2_t *mp) +{ + vl_api_sr_policy_add_v2_reply_t *rmp; + ip6_address_t *segments = 0, *seg; + ip6_address_t bsid_addr; + ip6_address_t encap_src; + + int i; + for (i = 0; i < mp->sids.num_sids; i++) + { + vec_add2 (segments, seg, 1); + ip6_address_decode (mp->sids.sids[i], seg); + } + + ip6_address_decode (mp->bsid_addr, &bsid_addr); + ip6_address_decode (mp->encap_src, &encap_src); + + if (ip6_address_is_zero (&encap_src)) + { + encap_src = *sr_get_encaps_source (); + } + /* + * sr_policy_add (ip6_address_t *bsid, ip6_address_t *segments, + * ip6_address_t *encap_src, + * u32 weight, u8 behavior, u32 fib_table, u8 is_encap, + * u16 behavior, void *plugin_mem) + */ + int rv = 0; + rv = + sr_policy_add (&bsid_addr, segments, &encap_src, ntohl (mp->sids.weight), + mp->type, ntohl (mp->fib_table), mp->is_encap, 0, NULL); + vec_free (segments); + + REPLY_MACRO (VL_API_SR_POLICY_ADD_REPLY); +} + +static void +vl_api_sr_policy_mod_v2_t_handler (vl_api_sr_policy_mod_v2_t *mp) +{ + vl_api_sr_policy_mod_v2_reply_t *rmp; + ip6_address_t *segments = 0, *seg; + ip6_address_t bsid_addr; + ip6_address_t encap_src; + + int i; + for (i = 0; i < mp->sids.num_sids; i++) + { + vec_add2 (segments, seg, 1); + ip6_address_decode (mp->sids.sids[i], seg); + } + + ip6_address_decode (mp->bsid_addr, &bsid_addr); + ip6_address_decode (mp->encap_src, &encap_src); + + if (ip6_address_is_zero (&encap_src)) + { + encap_src = *sr_get_encaps_source (); + } + + int rv = 0; + /* + * int + * sr_policy_mod(ip6_address_t *bsid, u32 index, u32 fib_table, + * u8 operation, ip6_address_t *segments, + * ip6_address_t *encap_src, u32 sl_index, + * u32 weight, u8 is_encap) + */ + rv = + sr_policy_mod (&bsid_addr, ntohl (mp->sr_policy_index), + ntohl (mp->fib_table), mp->operation, segments, &encap_src, + ntohl (mp->sl_index), ntohl (mp->sids.weight)); vec_free (segments); REPLY_MACRO (VL_API_SR_POLICY_MOD_REPLY); @@ -387,7 +461,68 @@ vl_api_sr_policies_dump_t_handler (vl_api_sr_policies_dump_t * mp) /* *INDENT-ON* */ } +static void +send_sr_policies_v2_details (ip6_sr_policy_t *t, vl_api_registration_t *reg, + u32 context) +{ + vl_api_sr_policies_v2_details_t *rmp; + ip6_sr_main_t *sm = &sr_main; + u32 *sl_index, slidx = 0; + ip6_sr_sl_t *segment_list = 0; + ip6_address_t *segment; + vl_api_srv6_sid_list_t *api_sid_list; + + rmp = vl_msg_api_alloc (sizeof (*rmp) + vec_len (t->segments_lists) * + sizeof (vl_api_srv6_sid_list_t)); + clib_memset (rmp, 0, + (sizeof (*rmp) + vec_len (t->segments_lists) * + sizeof (vl_api_srv6_sid_list_t))); + + rmp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_SR_POLICIES_V2_DETAILS); + ip6_address_encode (&t->bsid, rmp->bsid); + ip6_address_encode (&t->encap_src, rmp->encap_src); + rmp->is_encap = t->is_encap; + rmp->type = t->type; + rmp->fib_table = htonl (t->fib_table); + rmp->num_sid_lists = vec_len (t->segments_lists); + + /* Fill in all the segments lists */ + vec_foreach (sl_index, t->segments_lists) + { + segment_list = pool_elt_at_index (sm->sid_lists, *sl_index); + + api_sid_list = &rmp->sid_lists[sl_index - t->segments_lists]; + + api_sid_list->num_sids = vec_len (segment_list->segments); + api_sid_list->weight = htonl (segment_list->weight); + slidx = 0; + vec_foreach (segment, segment_list->segments) + { + ip6_address_encode (segment, api_sid_list->sids[slidx++]); + } + } + + rmp->context = context; + vl_api_send_msg (reg, (u8 *) rmp); +} + +static void +vl_api_sr_policies_v2_dump_t_handler (vl_api_sr_policies_v2_dump_t *mp) +{ + vl_api_registration_t *reg; + ip6_sr_main_t *sm = &sr_main; + ip6_sr_policy_t *t; + + reg = vl_api_client_index_to_registration (mp->client_index); + if (!reg) + return; + + pool_foreach (t, sm->sr_policies) + { + send_sr_policies_v2_details (t, reg, mp->context); + } +} static void send_sr_policies_details_with_sl_index (ip6_sr_policy_t * t, vl_api_registration_t * reg, u32 context) diff --git a/src/vnet/srv6/sr_policy_rewrite.c b/src/vnet/srv6/sr_policy_rewrite.c index 8ad857153e4..69a4d5e398c 100644 --- a/src/vnet/srv6/sr_policy_rewrite.c +++ b/src/vnet/srv6/sr_policy_rewrite.c @@ -193,11 +193,12 @@ VLIB_CLI_COMMAND (set_sr_hop_limit_command, static) = { * @brief SR rewrite string computation for IPv6 encapsulation (inline) * * @param sl is a vector of IPv6 addresses composing the Segment List + * @param src_v6addr is a encaps IPv6 source addr * * @return precomputed rewrite string for encapsulation */ static inline u8 * -compute_rewrite_encaps (ip6_address_t *sl, u8 type) +compute_rewrite_encaps (ip6_address_t *sl, ip6_address_t *src_v6addr, u8 type) { ip6_header_t *iph; ip6_sr_header_t *srh; @@ -225,8 +226,8 @@ compute_rewrite_encaps (ip6_address_t *sl, u8 type) iph = (ip6_header_t *) rs; iph->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (0 | ((6 & 0xF) << 28)); - iph->src_address.as_u64[0] = sr_pr_encaps_src.as_u64[0]; - iph->src_address.as_u64[1] = sr_pr_encaps_src.as_u64[1]; + iph->src_address.as_u64[0] = src_v6addr->as_u64[0]; + iph->src_address.as_u64[1] = src_v6addr->as_u64[1]; iph->payload_length = header_length - IPv6_DEFAULT_HEADER_LENGTH; iph->protocol = IP_PROTOCOL_IPV6; iph->hop_limit = sr_pr_encaps_hop_limit; @@ -370,18 +371,20 @@ compute_rewrite_bsid (ip6_address_t * sl) * * @param sr_policy is the SR policy where the SL will be added * @param sl is a vector of IPv6 addresses composing the Segment List + * @param encap_src is a encaps IPv6 source addr. optional. * @param weight is the weight of the SegmentList (for load-balancing purposes) * @param is_encap represents the mode (SRH insertion vs Encapsulation) * * @return pointer to the just created segment list */ static inline ip6_sr_sl_t * -create_sl (ip6_sr_policy_t * sr_policy, ip6_address_t * sl, u32 weight, - u8 is_encap) +create_sl (ip6_sr_policy_t *sr_policy, ip6_address_t *sl, + ip6_address_t *encap_src, u32 weight, u8 is_encap) { ip6_sr_main_t *sm = &sr_main; ip6_sr_sl_t *segment_list; sr_policy_fn_registration_t *plugin = 0; + ip6_address_t encap_srcv6 = sr_pr_encaps_src; pool_get (sm->sid_lists, segment_list); clib_memset (segment_list, 0, sizeof (*segment_list)); @@ -400,8 +403,14 @@ create_sl (ip6_sr_policy_t * sr_policy, ip6_address_t * sl, u32 weight, if (is_encap) { - segment_list->rewrite = compute_rewrite_encaps (sl, sr_policy->type); + if (encap_src) + { + clib_memcpy_fast (&encap_srcv6, encap_src, sizeof (ip6_address_t)); + } + segment_list->rewrite = + compute_rewrite_encaps (sl, &encap_srcv6, sr_policy->type); segment_list->rewrite_bsid = segment_list->rewrite; + sr_policy->encap_src = encap_srcv6; } else { @@ -660,17 +669,19 @@ update_replicate (ip6_sr_policy_t * sr_policy) * * @param bsid is the bindingSID of the SR Policy * @param segments is a vector of IPv6 address composing the segment list + * @param encap_src is a encaps IPv6 source addr. optional. * @param weight is the weight of the sid list. optional. * @param behavior is the behavior of the SR policy. (default//spray) * @param fib_table is the VRF where to install the FIB entry for the BSID - * @param is_encap (bool) whether SR policy should behave as Encap/SRH Insertion + * @param is_encap (bool) whether SR policy should behave as Encap/SRH + * Insertion * * @return 0 if correct, else error */ int -sr_policy_add (ip6_address_t *bsid, ip6_address_t *segments, u32 weight, - u8 type, u32 fib_table, u8 is_encap, u16 plugin, - void *ls_plugin_mem) +sr_policy_add (ip6_address_t *bsid, ip6_address_t *segments, + ip6_address_t *encap_src, u32 weight, u8 type, u32 fib_table, + u8 is_encap, u16 plugin, void *ls_plugin_mem) { ip6_sr_main_t *sm = &sr_main; ip6_sr_policy_t *sr_policy = 0; @@ -726,7 +737,7 @@ sr_policy_add (ip6_address_t *bsid, ip6_address_t *segments, u32 weight, NULL); /* Create a segment list and add the index to the SR policy */ - create_sl (sr_policy, segments, weight, is_encap); + create_sl (sr_policy, segments, encap_src, weight, is_encap); /* If FIB doesnt exist, create them */ if (sm->fib_table_ip6 == (u32) ~ 0) @@ -856,6 +867,7 @@ sr_policy_del (ip6_address_t * bsid, u32 index) * @param fib_table is the VRF where to install the FIB entry for the BSID * @param operation is the operation to perform (among the top ones) * @param segments is a vector of IPv6 address composing the segment list + * @param encap_src is a encaps IPv6 source addr. optional. * @param sl_index is the index of the Segment List to modify/delete * @param weight is the weight of the sid list. optional. * @param is_encap Mode. Encapsulation or SRH insertion. @@ -863,8 +875,8 @@ sr_policy_del (ip6_address_t * bsid, u32 index) * @return 0 if correct, else error */ int -sr_policy_mod (ip6_address_t * bsid, u32 index, u32 fib_table, - u8 operation, ip6_address_t * segments, u32 sl_index, +sr_policy_mod (ip6_address_t *bsid, u32 index, u32 fib_table, u8 operation, + ip6_address_t *segments, ip6_address_t *encap_src, u32 sl_index, u32 weight) { ip6_sr_main_t *sm = &sr_main; @@ -889,8 +901,8 @@ sr_policy_mod (ip6_address_t * bsid, u32 index, u32 fib_table, if (operation == 1) /* Add SR List to an existing SR policy */ { /* Create the new SL */ - segment_list = - create_sl (sr_policy, segments, weight, sr_policy->is_encap); + segment_list = create_sl (sr_policy, segments, encap_src, weight, + sr_policy->is_encap); /* Create a new LB DPO */ if (sr_policy->type == SR_POLICY_TYPE_DEFAULT) @@ -963,7 +975,7 @@ sr_policy_command_fn (vlib_main_t * vm, unformat_input_t * input, int rv = -1; char is_del = 0, is_add = 0, is_mod = 0; char policy_set = 0; - ip6_address_t bsid, next_address; + ip6_address_t bsid, next_address, src_v6addr; u32 sr_policy_index = (u32) ~ 0, sl_index = (u32) ~ 0; u32 weight = (u32) ~ 0, fib_table = (u32) ~ 0; ip6_address_t *segments = 0, *this_seg; @@ -972,6 +984,7 @@ sr_policy_command_fn (vlib_main_t * vm, unformat_input_t * input, u8 type = SR_POLICY_TYPE_DEFAULT; u16 behavior = 0; void *ls_plugin_mem = 0; + ip6_address_t *encap_src = 0; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { @@ -995,6 +1008,10 @@ sr_policy_command_fn (vlib_main_t * vm, unformat_input_t * input, clib_memcpy_fast (this_seg->as_u8, next_address.as_u8, sizeof (*this_seg)); } + else if (unformat (input, "v6src %U", unformat_ip6_address, &src_v6addr)) + { + encap_src = &src_v6addr; + } else if (unformat (input, "add sl")) operation = 1; else if (unformat (input, "del sl index %d", &sl_index)) @@ -1059,8 +1076,8 @@ sr_policy_command_fn (vlib_main_t * vm, unformat_input_t * input, if (vec_len (segments) == 0) return clib_error_return (0, "No Segment List specified"); - rv = sr_policy_add (&bsid, segments, weight, type, fib_table, is_encap, - behavior, ls_plugin_mem); + rv = sr_policy_add (&bsid, segments, encap_src, weight, type, fib_table, + is_encap, behavior, ls_plugin_mem); vec_free (segments); } @@ -1078,9 +1095,9 @@ sr_policy_command_fn (vlib_main_t * vm, unformat_input_t * input, if (operation == 3 && weight == (u32) ~ 0) return clib_error_return (0, "No new weight for the SL specified"); - rv = sr_policy_mod ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid), + rv = sr_policy_mod ((sr_policy_index != (u32) ~0 ? NULL : &bsid), sr_policy_index, fib_table, operation, segments, - sl_index, weight); + encap_src, sl_index, weight); if (segments) vec_free (segments); @@ -1170,6 +1187,11 @@ show_sr_policies_command_fn (vlib_main_t * vm, unformat_input_t * input, vlib_cli_output (vm, "\tBehavior: %s", (sr_policy->is_encap ? "Encapsulation" : "SRH insertion")); + if (sr_policy->is_encap) + { + vlib_cli_output (vm, "\tEncapSrcIP: %U", format_ip6_address, + &sr_policy->encap_src); + } switch (sr_policy->type) { case SR_POLICY_TYPE_SPRAY: diff --git a/src/vnet/srv6/sr_test.c b/src/vnet/srv6/sr_test.c index 85f64e1e230..be898599e96 100644 --- a/src/vnet/srv6/sr_test.c +++ b/src/vnet/srv6/sr_test.c @@ -79,6 +79,18 @@ api_sr_policy_add (vat_main_t *vam) return -1; } +static int +api_sr_policy_mod_v2 (vat_main_t *vam) +{ + return -1; +} + +static int +api_sr_policy_add_v2 (vat_main_t *vam) +{ + return -1; +} + static int api_sr_localsids_dump (vat_main_t *vam) { @@ -91,6 +103,12 @@ api_sr_policies_dump (vat_main_t *vam) return -1; } +static int +api_sr_policies_v2_dump (vat_main_t *vam) +{ + return -1; +} + static int api_sr_policies_with_sl_index_dump (vat_main_t *vam) { @@ -108,6 +126,11 @@ vl_api_sr_policies_details_t_handler (vl_api_sr_policies_details_t *mp) { } +static void +vl_api_sr_policies_v2_details_t_handler (vl_api_sr_policies_v2_details_t *mp) +{ +} + static void vl_api_sr_localsids_details_t_handler (vl_api_sr_localsids_details_t *mp) { diff --git a/test/test_srv6.py b/test/test_srv6.py index 40b53375ddb..a15c69713a5 100644 --- a/test/test_srv6.py +++ b/test/test_srv6.py @@ -10,6 +10,7 @@ from vpp_srv6 import ( SRv6LocalSIDBehaviors, VppSRv6LocalSID, VppSRv6Policy, + VppSRv6PolicyV2, SRv6PolicyType, VppSRv6Steering, SRv6PolicySteeringTypes, @@ -248,6 +249,121 @@ class TestSRv6(VppTestCase): # cleanup interfaces self.teardown_interfaces() + def test_SRv6_T_Encaps_with_v6src(self): + """Test SRv6 Transit.Encaps behavior for IPv6 and select multiple src v6addr case.""" + # send traffic to one destination interface + # source and destination are IPv6 only + self.setup_interfaces(ipv6=[True, True]) + + # configure FIB entries + route = VppIpRoute( + self, "a4::", 64, [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index)] + ) + route.add_vpp_config() + + # configure encaps IPv6 source address + # needs to be done before SR Policy config + # TODO: API? + self.vapi.cli("set sr encaps source addr a3::") + + bsid = "a3::9999:1" + other_src_ip = "b1::" + # configure SRv6 Policy + # Note: segment list order: first -> last + sr_policy = VppSRv6PolicyV2( + self, + bsid=bsid, + is_encap=1, + sr_type=SRv6PolicyType.SR_POLICY_TYPE_DEFAULT, + weight=1, + fib_table=0, + segments=["a4::", "a5::", "a6::c7"], + encap_src=other_src_ip, + source=other_src_ip, + ) + sr_policy.add_vpp_config() + self.sr_policy = sr_policy + + # log the sr policies + self.logger.info(self.vapi.cli("show sr policies")) + + # steer IPv6 traffic to a7::/64 into SRv6 Policy + # use the bsid of the above self.sr_policy + pol_steering = VppSRv6Steering( + self, + bsid=self.sr_policy.bsid, + prefix="a7::", + mask_width=64, + traffic_type=SRv6PolicySteeringTypes.SR_STEER_IPV6, + sr_policy_index=0, + table_id=0, + sw_if_index=0, + ) + pol_steering.add_vpp_config() + + # log the sr steering policies + self.logger.info(self.vapi.cli("show sr steering-policies")) + + # create packets + count = len(self.pg_packet_sizes) + dst_inner = "a7::1234" + pkts = [] + + # create IPv6 packets without SRH + packet_header = self.create_packet_header_IPv6(dst_inner) + # create traffic stream pg0->pg1 + pkts.extend( + self.create_stream( + self.pg0, self.pg1, packet_header, self.pg_packet_sizes, count + ) + ) + + # create IPv6 packets with SRH + # packets with segments-left 1, active segment a7:: + packet_header = self.create_packet_header_IPv6_SRH( + sidlist=["a8::", "a7::", "a6::"], segleft=1 + ) + # create traffic stream pg0->pg1 + pkts.extend( + self.create_stream( + self.pg0, self.pg1, packet_header, self.pg_packet_sizes, count + ) + ) + + # create IPv6 packets with SRH and IPv6 + # packets with segments-left 1, active segment a7:: + packet_header = self.create_packet_header_IPv6_SRH_IPv6( + dst_inner, sidlist=["a8::", "a7::", "a6::"], segleft=1 + ) + # create traffic stream pg0->pg1 + pkts.extend( + self.create_stream( + self.pg0, self.pg1, packet_header, self.pg_packet_sizes, count + ) + ) + + # send packets and verify received packets + self.send_and_verify_pkts( + self.pg0, pkts, self.pg1, self.compare_rx_tx_packet_T_Encaps + ) + + # log the localsid counters + self.logger.info(self.vapi.cli("show sr localsid")) + + # remove SR steering + pol_steering.remove_vpp_config() + self.logger.info(self.vapi.cli("show sr steering-policies")) + + # remove SR Policies + self.sr_policy.remove_vpp_config() + self.logger.info(self.vapi.cli("show sr policies")) + + # remove FIB entries + # done by tearDown + + # cleanup interfaces + self.teardown_interfaces() + @unittest.skipUnless(0, "PC to fix") def test_SRv6_T_Insert(self): """Test SRv6 Transit.Insert behavior (IPv6 only).""" diff --git a/test/vpp_srv6.py b/test/vpp_srv6.py index d789105d7a7..1b09103f297 100644 --- a/test/vpp_srv6.py +++ b/test/vpp_srv6.py @@ -6,6 +6,7 @@ from vpp_object import VppObject from socket import inet_pton, inet_ntop, AF_INET, AF_INET6 +import copy class SRv6LocalSIDBehaviors: @@ -28,6 +29,7 @@ class SRv6PolicyType: # from src/vnet/srv6/sr.h SR_POLICY_TYPE_DEFAULT = 0 SR_POLICY_TYPE_SPRAY = 1 + SR_POLICY_TYPE_TEF = 2 class SRv6PolicySteeringTypes: @@ -148,6 +150,79 @@ class VppSRv6Policy(VppObject): ) +class VppSRv6PolicyV2(VppObject): + """ + SRv6 Policy + """ + + def __init__( + self, + test, + bsid, + is_encap, + sr_type, + weight, + fib_table, + segments, + encap_src, + source, + ): + self._test = test + self.bsid = bsid + self.is_encap = is_encap + self.sr_type = sr_type + self.weight = weight + self.fib_table = fib_table + self.segments = segments + self.encap_src = encap_src + self.n_segments = len(segments) + + # source not passed to API + # self.source = inet_pton(AF_INET6, source) + self.source = source + self._configured = False + + def add_vpp_config(self): + self._test.vapi.sr_policy_add_v2( + bsid_addr=self.bsid, + weight=self.weight, + is_encap=self.is_encap, + type=self.sr_type, + fib_table=self.fib_table, + encap_src=self.encap_src, + sids={ + "num_sids": self.n_segments, + "sids": self._get_fixed_segments(), + "weight": 1, + }, + ) + self._configured = True + + def remove_vpp_config(self): + self._test.vapi.sr_policy_del(self.bsid) + self._configured = False + + def query_vpp_config(self): + # no API to query SR Policies + # use _configured flag for now + return self._configured + + def object_id(self): + return "%d;%s-><%s>;%d" % ( + self.sr_type, + self.bsid, + ",".join(self.segments), + self.is_encap, + ) + + def _get_fixed_segments(self): + segs = copy.copy(self.segments) + # note: array expect size is 16 + for _ in range(16 - self.n_segments): + segs.append("") + return segs + + class VppSRv6Steering(VppObject): """ SRv6 Steering @@ -177,7 +252,7 @@ class VppSRv6Steering(VppObject): def add_vpp_config(self): self._test.vapi.sr_steering_add_del( is_del=0, - bsid=self.bsid, + bsid_addr=self.bsid, sr_policy_index=self.sr_policy_index, table_id=self.table_id, prefix={"address": self.prefix, "len": self.mask_width}, @@ -189,7 +264,7 @@ class VppSRv6Steering(VppObject): def remove_vpp_config(self): self._test.vapi.sr_steering_add_del( is_del=1, - bsid=self.bsid, + bsid_addr=self.bsid, sr_policy_index=self.sr_policy_index, table_id=self.table_id, prefix={"address": self.prefix, "len": self.mask_width}, -- 2.16.6