blob: 69a4d5e398cc026145a6e54af7aecb03681629ab [file] [log] [blame]
Pablo Camarillofb380952016-12-07 18:34:18 +01001/*
2 * sr_policy_rewrite.c: ipv6 sr policy creation
3 *
4 * Copyright (c) 2016 Cisco and/or its affiliates.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18/**
19 * @file
20 * @brief SR policy creation and application
21 *
22 * Create an SR policy.
23 * An SR policy can be either of 'default' type or 'spray' type
24 * An SR policy has attached a list of SID lists.
25 * In case the SR policy is a default one it will load balance among them.
26 * An SR policy has associated a BindingSID.
27 * In case any packet arrives with IPv6 DA == BindingSID then the SR policy
28 * associated to such bindingSID will be applied to such packet.
29 *
30 * SR policies can be applied either by using IPv6 encapsulation or
31 * SRH insertion. Both methods can be found on this file.
32 *
33 * Traffic input usually is IPv6 packets. However it is possible to have
34 * IPv4 packets or L2 frames. (that are encapsulated into IPv6 with SRH)
35 *
Nathan Skrzypczak2c77ae42021-09-29 15:36:51 +020036 * This file provides the appropriate VPP graph nodes to do any of these
Pablo Camarillofb380952016-12-07 18:34:18 +010037 * methods.
38 *
39 */
40
41#include <vlib/vlib.h>
42#include <vnet/vnet.h>
Pablo Camarillo5d73eec2017-04-24 17:51:56 +020043#include <vnet/srv6/sr.h>
Neale Rannse4031132020-10-26 13:00:06 +000044#include <vnet/ip/ip4_inlines.h>
45#include <vnet/ip/ip6_inlines.h>
Pablo Camarillo5d73eec2017-04-24 17:51:56 +020046#include <vnet/srv6/sr_packet.h>
Pablo Camarillofb380952016-12-07 18:34:18 +010047#include <vnet/fib/ip6_fib.h>
48#include <vnet/dpo/dpo.h>
49#include <vnet/dpo/replicate_dpo.h>
Ahmed Abdelsalamd50e6612022-06-29 17:11:08 +000050#include <vnet/srv6/sr_pt.h>
Pablo Camarillofb380952016-12-07 18:34:18 +010051
Guillaume Solignac897fbba2023-01-06 13:55:04 +010052#include <vppinfra/byte_order.h>
Pablo Camarillofb380952016-12-07 18:34:18 +010053#include <vppinfra/error.h>
54#include <vppinfra/elog.h>
55
56/**
57 * @brief SR policy rewrite trace
58 */
59typedef struct
60{
61 ip6_address_t src, dst;
62} sr_policy_rewrite_trace_t;
63
64/* Graph arcs */
65#define foreach_sr_policy_rewrite_next \
66_(IP6_LOOKUP, "ip6-lookup") \
67_(ERROR, "error-drop")
68
69typedef enum
70{
71#define _(s,n) SR_POLICY_REWRITE_NEXT_##s,
72 foreach_sr_policy_rewrite_next
73#undef _
74 SR_POLICY_REWRITE_N_NEXT,
75} sr_policy_rewrite_next_t;
76
77/* SR rewrite errors */
78#define foreach_sr_policy_rewrite_error \
79_(INTERNAL_ERROR, "Segment Routing undefined error") \
80_(BSID_ZERO, "BSID with SL = 0") \
81_(COUNTER_TOTAL, "SR steered IPv6 packets") \
82_(COUNTER_ENCAP, "SR: Encaps packets") \
83_(COUNTER_INSERT, "SR: SRH inserted packets") \
84_(COUNTER_BSID, "SR: BindingSID steered packets")
85
86typedef enum
87{
88#define _(sym,str) SR_POLICY_REWRITE_ERROR_##sym,
89 foreach_sr_policy_rewrite_error
90#undef _
91 SR_POLICY_REWRITE_N_ERROR,
92} sr_policy_rewrite_error_t;
93
94static char *sr_policy_rewrite_error_strings[] = {
95#define _(sym,string) string,
96 foreach_sr_policy_rewrite_error
97#undef _
98};
99
100/**
101 * @brief Dynamically added SR SL DPO type
102 */
103static dpo_type_t sr_pr_encaps_dpo_type;
104static dpo_type_t sr_pr_insert_dpo_type;
105static dpo_type_t sr_pr_bsid_encaps_dpo_type;
106static dpo_type_t sr_pr_bsid_insert_dpo_type;
107
108/**
109 * @brief IPv6 SA for encapsulated packets
110 */
111static ip6_address_t sr_pr_encaps_src;
Ignas Bačiuseeb5fb32019-10-03 17:15:38 +0300112static u8 sr_pr_encaps_hop_limit = IPv6_DEFAULT_HOP_LIMIT;
Pablo Camarillofb380952016-12-07 18:34:18 +0100113
114/******************* SR rewrite set encaps IPv6 source addr *******************/
115/* Note: This is temporal. We don't know whether to follow this path or
116 take the ip address of a loopback interface or even the OIF */
117
Pablo Camarillo1a5e3012017-11-16 16:02:50 +0100118void
119sr_set_source (ip6_address_t * address)
120{
Dave Barach178cf492018-11-13 16:34:13 -0500121 clib_memcpy_fast (&sr_pr_encaps_src, address, sizeof (sr_pr_encaps_src));
Pablo Camarillo1a5e3012017-11-16 16:02:50 +0100122}
123
Ahmed Abdelsalam448bc812020-11-09 14:04:07 +0000124ip6_address_t *
125sr_get_encaps_source ()
126{
127 return &sr_pr_encaps_src;
128}
129
Pablo Camarillofb380952016-12-07 18:34:18 +0100130static clib_error_t *
131set_sr_src_command_fn (vlib_main_t * vm, unformat_input_t * input,
132 vlib_cli_command_t * cmd)
133{
134 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
135 {
136 if (unformat
137 (input, "addr %U", unformat_ip6_address, &sr_pr_encaps_src))
138 return 0;
139 else
140 return clib_error_return (0, "No address specified");
141 }
142 return clib_error_return (0, "No address specified");
143}
144
145/* *INDENT-OFF* */
146VLIB_CLI_COMMAND (set_sr_src_command, static) = {
147 .path = "set sr encaps source",
148 .short_help = "set sr encaps source addr <ip6_addr>",
149 .function = set_sr_src_command_fn,
150};
151/* *INDENT-ON* */
152
Ignas Bačiuseeb5fb32019-10-03 17:15:38 +0300153/******************** SR rewrite set encaps IPv6 hop-limit ********************/
154
155void
156sr_set_hop_limit (u8 hop_limit)
157{
158 sr_pr_encaps_hop_limit = hop_limit;
159}
160
161u8
162sr_get_hop_limit (void)
163{
164 return sr_pr_encaps_hop_limit;
165}
166
167static clib_error_t *
168set_sr_hop_limit_command_fn (vlib_main_t * vm, unformat_input_t * input,
169 vlib_cli_command_t * cmd)
170{
171 int hop_limit = sr_get_hop_limit ();
172
173 if (unformat_check_input (input) == UNFORMAT_END_OF_INPUT)
174 return clib_error_return (0, "No value specified");
175 if (!unformat (input, "%d", &hop_limit))
176 return clib_error_return (0, "Invalid value");
177 if (hop_limit <= 0 || hop_limit > 255)
178 return clib_error_return (0, "Value out of range [1-255]");
179 sr_pr_encaps_hop_limit = (u8) hop_limit;
180 return 0;
181}
182
183/* *INDENT-OFF* */
184VLIB_CLI_COMMAND (set_sr_hop_limit_command, static) = {
185 .path = "set sr encaps hop-limit",
186 .short_help = "set sr encaps hop-limit <value>",
187 .function = set_sr_hop_limit_command_fn,
188};
189/* *INDENT-ON* */
190
Pablo Camarillofb380952016-12-07 18:34:18 +0100191/*********************** SR rewrite string computation ************************/
192/**
193 * @brief SR rewrite string computation for IPv6 encapsulation (inline)
194 *
195 * @param sl is a vector of IPv6 addresses composing the Segment List
Takeru Hayasakac4c205b2022-12-30 16:41:44 +0900196 * @param src_v6addr is a encaps IPv6 source addr
Pablo Camarillofb380952016-12-07 18:34:18 +0100197 *
198 * @return precomputed rewrite string for encapsulation
199 */
200static inline u8 *
Takeru Hayasakac4c205b2022-12-30 16:41:44 +0900201compute_rewrite_encaps (ip6_address_t *sl, ip6_address_t *src_v6addr, u8 type)
Pablo Camarillofb380952016-12-07 18:34:18 +0100202{
203 ip6_header_t *iph;
204 ip6_sr_header_t *srh;
Ahmed Abdelsalam9cca6942022-06-06 15:54:02 +0000205 ip6_sr_pt_tlv_t *srh_pt_tlv;
Pablo Camarillofb380952016-12-07 18:34:18 +0100206 ip6_address_t *addrp, *this_address;
207 u32 header_length = 0;
208 u8 *rs = NULL;
209
210 header_length = 0;
211 header_length += IPv6_DEFAULT_HEADER_LENGTH;
Ahmed Abdelsalam9cca6942022-06-06 15:54:02 +0000212 if (type == SR_POLICY_TYPE_TEF)
213 {
214 header_length += sizeof (ip6_sr_header_t);
215 header_length += vec_len (sl) * sizeof (ip6_address_t);
216 header_length += sizeof (ip6_sr_pt_tlv_t);
217 }
218 else if (vec_len (sl) > 1)
Pablo Camarillofb380952016-12-07 18:34:18 +0100219 {
220 header_length += sizeof (ip6_sr_header_t);
221 header_length += vec_len (sl) * sizeof (ip6_address_t);
222 }
223
224 vec_validate (rs, header_length - 1);
225
226 iph = (ip6_header_t *) rs;
227 iph->ip_version_traffic_class_and_flow_label =
228 clib_host_to_net_u32 (0 | ((6 & 0xF) << 28));
Takeru Hayasakac4c205b2022-12-30 16:41:44 +0900229 iph->src_address.as_u64[0] = src_v6addr->as_u64[0];
230 iph->src_address.as_u64[1] = src_v6addr->as_u64[1];
Pablo Camarillofb380952016-12-07 18:34:18 +0100231 iph->payload_length = header_length - IPv6_DEFAULT_HEADER_LENGTH;
232 iph->protocol = IP_PROTOCOL_IPV6;
Ignas Bačiuseeb5fb32019-10-03 17:15:38 +0300233 iph->hop_limit = sr_pr_encaps_hop_limit;
Pablo Camarillofb380952016-12-07 18:34:18 +0100234
Ahmed Abdelsalam9cca6942022-06-06 15:54:02 +0000235 if (type == SR_POLICY_TYPE_TEF)
236 {
237 srh = (ip6_sr_header_t *) (iph + 1);
238 iph->protocol = IP_PROTOCOL_IPV6_ROUTE;
239 srh->protocol = IP_PROTOCOL_IPV6;
240 srh->type = ROUTING_HEADER_TYPE_SR;
241 srh->flags = 0x00;
242 srh->tag = 0x0000;
243 srh->segments_left = vec_len (sl) - 1;
244 srh->last_entry = vec_len (sl) - 1;
245 srh->length =
246 ((sizeof (ip6_sr_header_t) + (vec_len (sl) * sizeof (ip6_address_t)) +
247 sizeof (ip6_sr_pt_tlv_t)) /
248 8) -
249 1;
250 addrp = srh->segments + vec_len (sl) - 1;
251 vec_foreach (this_address, sl)
252 {
253 clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
254 sizeof (ip6_address_t));
255 addrp--;
256 }
257 srh_pt_tlv = (ip6_sr_pt_tlv_t *) (srh->segments + vec_len (sl));
258 srh_pt_tlv->type = IP6_SRH_PT_TLV_TYPE;
259 srh_pt_tlv->length = IP6_SRH_PT_TLV_LEN;
260 }
261 else if (vec_len (sl) > 1)
Pablo Camarillod327c872018-01-08 14:25:55 +0100262 {
263 srh = (ip6_sr_header_t *) (iph + 1);
264 iph->protocol = IP_PROTOCOL_IPV6_ROUTE;
265 srh->protocol = IP_PROTOCOL_IPV6;
266 srh->type = ROUTING_HEADER_TYPE_SR;
267 srh->segments_left = vec_len (sl) - 1;
Ahmed Abdelsalambe837042019-06-20 11:18:57 +0000268 srh->last_entry = vec_len (sl) - 1;
Pablo Camarillod327c872018-01-08 14:25:55 +0100269 srh->length = ((sizeof (ip6_sr_header_t) +
270 (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
271 srh->flags = 0x00;
Ahmed Abdelsalambe837042019-06-20 11:18:57 +0000272 srh->tag = 0x0000;
Pablo Camarillod327c872018-01-08 14:25:55 +0100273 addrp = srh->segments + vec_len (sl) - 1;
274 vec_foreach (this_address, sl)
275 {
Dave Barach178cf492018-11-13 16:34:13 -0500276 clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
277 sizeof (ip6_address_t));
Pablo Camarillod327c872018-01-08 14:25:55 +0100278 addrp--;
279 }
280 }
Pablo Camarillofb380952016-12-07 18:34:18 +0100281 iph->dst_address.as_u64[0] = sl->as_u64[0];
282 iph->dst_address.as_u64[1] = sl->as_u64[1];
283 return rs;
284}
285
286/**
287 * @brief SR rewrite string computation for SRH insertion (inline)
288 *
289 * @param sl is a vector of IPv6 addresses composing the Segment List
290 *
291 * @return precomputed rewrite string for SRH insertion
292 */
293static inline u8 *
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +0000294compute_rewrite_insert (ip6_address_t *sl, u8 type)
Pablo Camarillofb380952016-12-07 18:34:18 +0100295{
296 ip6_sr_header_t *srh;
297 ip6_address_t *addrp, *this_address;
298 u32 header_length = 0;
299 u8 *rs = NULL;
300
301 header_length = 0;
302 header_length += sizeof (ip6_sr_header_t);
303 header_length += (vec_len (sl) + 1) * sizeof (ip6_address_t);
304
305 vec_validate (rs, header_length - 1);
306
307 srh = (ip6_sr_header_t *) rs;
308 srh->type = ROUTING_HEADER_TYPE_SR;
309 srh->segments_left = vec_len (sl);
Ahmed Abdelsalambe837042019-06-20 11:18:57 +0000310 srh->last_entry = vec_len (sl);
Pablo Camarillofb380952016-12-07 18:34:18 +0100311 srh->length = ((sizeof (ip6_sr_header_t) +
312 ((vec_len (sl) + 1) * sizeof (ip6_address_t))) / 8) - 1;
313 srh->flags = 0x00;
Ahmed Abdelsalambe837042019-06-20 11:18:57 +0000314 srh->tag = 0x0000;
Pablo Camarillofb380952016-12-07 18:34:18 +0100315 addrp = srh->segments + vec_len (sl);
316 vec_foreach (this_address, sl)
317 {
Dave Barach178cf492018-11-13 16:34:13 -0500318 clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
319 sizeof (ip6_address_t));
Pablo Camarillofb380952016-12-07 18:34:18 +0100320 addrp--;
321 }
322 return rs;
323}
324
325/**
326 * @brief SR rewrite string computation for SRH insertion with BSID (inline)
327 *
328 * @param sl is a vector of IPv6 addresses composing the Segment List
329 *
330 * @return precomputed rewrite string for SRH insertion with BSID
331 */
332static inline u8 *
333compute_rewrite_bsid (ip6_address_t * sl)
334{
335 ip6_sr_header_t *srh;
336 ip6_address_t *addrp, *this_address;
337 u32 header_length = 0;
338 u8 *rs = NULL;
339
340 header_length = 0;
341 header_length += sizeof (ip6_sr_header_t);
342 header_length += vec_len (sl) * sizeof (ip6_address_t);
343
344 vec_validate (rs, header_length - 1);
345
346 srh = (ip6_sr_header_t *) rs;
347 srh->type = ROUTING_HEADER_TYPE_SR;
348 srh->segments_left = vec_len (sl) - 1;
Ahmed Abdelsalambe837042019-06-20 11:18:57 +0000349 srh->last_entry = vec_len (sl) - 1;
Pablo Camarillofb380952016-12-07 18:34:18 +0100350 srh->length = ((sizeof (ip6_sr_header_t) +
351 (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
352 srh->flags = 0x00;
Ahmed Abdelsalambe837042019-06-20 11:18:57 +0000353 srh->tag = 0x0000;
Pablo Camarillofb380952016-12-07 18:34:18 +0100354 addrp = srh->segments + vec_len (sl) - 1;
355 vec_foreach (this_address, sl)
356 {
Dave Barach178cf492018-11-13 16:34:13 -0500357 clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
358 sizeof (ip6_address_t));
Pablo Camarillofb380952016-12-07 18:34:18 +0100359 addrp--;
360 }
361 return rs;
362}
363
364/*************************** SR LB helper functions **************************/
365/**
366 * @brief Creates a Segment List and adds it to an SR policy
367 *
368 * Creates a Segment List and adds it to the SR policy. Notice that the SL are
369 * not necessarily unique. Hence there might be two Segment List within the
370 * same SR Policy with exactly the same segments and same weight.
371 *
372 * @param sr_policy is the SR policy where the SL will be added
373 * @param sl is a vector of IPv6 addresses composing the Segment List
Takeru Hayasakac4c205b2022-12-30 16:41:44 +0900374 * @param encap_src is a encaps IPv6 source addr. optional.
Pablo Camarillofb380952016-12-07 18:34:18 +0100375 * @param weight is the weight of the SegmentList (for load-balancing purposes)
376 * @param is_encap represents the mode (SRH insertion vs Encapsulation)
377 *
378 * @return pointer to the just created segment list
379 */
380static inline ip6_sr_sl_t *
Takeru Hayasakac4c205b2022-12-30 16:41:44 +0900381create_sl (ip6_sr_policy_t *sr_policy, ip6_address_t *sl,
382 ip6_address_t *encap_src, u32 weight, u8 is_encap)
Pablo Camarillofb380952016-12-07 18:34:18 +0100383{
384 ip6_sr_main_t *sm = &sr_main;
385 ip6_sr_sl_t *segment_list;
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800386 sr_policy_fn_registration_t *plugin = 0;
Takeru Hayasakac4c205b2022-12-30 16:41:44 +0900387 ip6_address_t encap_srcv6 = sr_pr_encaps_src;
Pablo Camarillofb380952016-12-07 18:34:18 +0100388
389 pool_get (sm->sid_lists, segment_list);
Dave Barachb7b92992018-10-17 10:38:51 -0400390 clib_memset (segment_list, 0, sizeof (*segment_list));
Pablo Camarillofb380952016-12-07 18:34:18 +0100391
392 vec_add1 (sr_policy->segments_lists, segment_list - sm->sid_lists);
393
394 /* Fill in segment list */
395 segment_list->weight =
396 (weight != (u32) ~ 0 ? weight : SR_SEGMENT_LIST_WEIGHT_DEFAULT);
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800397
Pablo Camarillofb380952016-12-07 18:34:18 +0100398 segment_list->segments = vec_dup (sl);
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +0000399 segment_list->policy_type = sr_policy->type;
Pablo Camarillofb380952016-12-07 18:34:18 +0100400
Tetsuya Murakami6b354912021-01-31 16:38:56 -0800401 segment_list->egress_fib_table =
402 ip6_fib_index_from_table_id (sr_policy->fib_table);
403
Pablo Camarillofb380952016-12-07 18:34:18 +0100404 if (is_encap)
405 {
Takeru Hayasakac4c205b2022-12-30 16:41:44 +0900406 if (encap_src)
407 {
408 clib_memcpy_fast (&encap_srcv6, encap_src, sizeof (ip6_address_t));
409 }
410 segment_list->rewrite =
411 compute_rewrite_encaps (sl, &encap_srcv6, sr_policy->type);
Pablo Camarillofb380952016-12-07 18:34:18 +0100412 segment_list->rewrite_bsid = segment_list->rewrite;
Takeru Hayasakac4c205b2022-12-30 16:41:44 +0900413 sr_policy->encap_src = encap_srcv6;
Pablo Camarillofb380952016-12-07 18:34:18 +0100414 }
415 else
416 {
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +0000417 segment_list->rewrite = compute_rewrite_insert (sl, sr_policy->type);
Pablo Camarillofb380952016-12-07 18:34:18 +0100418 segment_list->rewrite_bsid = compute_rewrite_bsid (sl);
419 }
420
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800421 if (sr_policy->plugin)
422 {
423 plugin =
424 pool_elt_at_index (sm->policy_plugin_functions,
425 sr_policy->plugin - SR_BEHAVIOR_LAST);
426
427 segment_list->plugin = sr_policy->plugin;
428 segment_list->plugin_mem = sr_policy->plugin_mem;
429
430 plugin->creation (sr_policy);
431 }
432
Pablo Camarillofb380952016-12-07 18:34:18 +0100433 /* Create DPO */
434 dpo_reset (&segment_list->bsid_dpo);
435 dpo_reset (&segment_list->ip6_dpo);
436 dpo_reset (&segment_list->ip4_dpo);
437
438 if (is_encap)
439 {
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800440 if (!sr_policy->plugin)
441 {
442 dpo_set (&segment_list->ip6_dpo, sr_pr_encaps_dpo_type,
443 DPO_PROTO_IP6, segment_list - sm->sid_lists);
444 dpo_set (&segment_list->ip4_dpo, sr_pr_encaps_dpo_type,
445 DPO_PROTO_IP4, segment_list - sm->sid_lists);
446 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_encaps_dpo_type,
447 DPO_PROTO_IP6, segment_list - sm->sid_lists);
448 }
449 else
450 {
451 dpo_set (&segment_list->ip6_dpo, plugin->dpo, DPO_PROTO_IP6,
452 segment_list - sm->sid_lists);
453 dpo_set (&segment_list->ip4_dpo, plugin->dpo, DPO_PROTO_IP4,
454 segment_list - sm->sid_lists);
455 dpo_set (&segment_list->bsid_dpo, plugin->dpo, DPO_PROTO_IP6,
456 segment_list - sm->sid_lists);
457 }
Pablo Camarillofb380952016-12-07 18:34:18 +0100458 }
459 else
460 {
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800461 if (!sr_policy->plugin)
462 {
463 dpo_set (&segment_list->ip6_dpo, sr_pr_insert_dpo_type,
464 DPO_PROTO_IP6, segment_list - sm->sid_lists);
465 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_insert_dpo_type,
466 DPO_PROTO_IP6, segment_list - sm->sid_lists);
467 }
468 else
469 {
470 dpo_set (&segment_list->ip6_dpo, plugin->dpo, DPO_PROTO_IP6,
471 segment_list - sm->sid_lists);
472 dpo_set (&segment_list->bsid_dpo, plugin->dpo, DPO_PROTO_IP6,
473 segment_list - sm->sid_lists);
474 }
Pablo Camarillofb380952016-12-07 18:34:18 +0100475 }
476
477 return segment_list;
478}
479
480/**
Nathan Skrzypczak2c77ae42021-09-29 15:36:51 +0200481 * @brief Updates the Load-Balancer after an SR Policy change
Pablo Camarillofb380952016-12-07 18:34:18 +0100482 *
483 * @param sr_policy is the modified SR Policy
484 */
485static inline void
486update_lb (ip6_sr_policy_t * sr_policy)
487{
488 flow_hash_config_t fhc;
489 u32 *sl_index;
490 ip6_sr_sl_t *segment_list;
491 ip6_sr_main_t *sm = &sr_main;
492 load_balance_path_t path;
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100493 path.path_index = FIB_NODE_INDEX_INVALID;
Pablo Camarillofb380952016-12-07 18:34:18 +0100494 load_balance_path_t *ip4_path_vector = 0;
495 load_balance_path_t *ip6_path_vector = 0;
496 load_balance_path_t *b_path_vector = 0;
497
498 /* In case LB does not exist, create it */
499 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
500 {
501 fib_prefix_t pfx = {
502 .fp_proto = FIB_PROTOCOL_IP6,
503 .fp_len = 128,
504 .fp_addr = {
505 .ip6 = sr_policy->bsid,
506 }
507 };
508
509 /* Add FIB entry for BSID */
510 fhc = fib_table_get_flow_hash_config (sr_policy->fib_table,
Neale Rannsd792d9c2017-10-21 10:53:20 -0700511 FIB_PROTOCOL_IP6);
Pablo Camarillofb380952016-12-07 18:34:18 +0100512
513 dpo_set (&sr_policy->bsid_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
514 load_balance_create (0, DPO_PROTO_IP6, fhc));
515
516 dpo_set (&sr_policy->ip6_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
517 load_balance_create (0, DPO_PROTO_IP6, fhc));
518
519 /* Update FIB entry's to point to the LB DPO in the main FIB and hidden one */
Neale Ranns107e7d42017-04-11 09:55:19 -0700520 fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
521 sr_policy->fib_table),
522 &pfx, FIB_SOURCE_SR,
Pablo Camarillofb380952016-12-07 18:34:18 +0100523 FIB_ENTRY_FLAG_EXCLUSIVE,
524 &sr_policy->bsid_dpo);
525
526 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
527 &pfx,
528 FIB_SOURCE_SR,
529 FIB_ENTRY_FLAG_EXCLUSIVE,
530 &sr_policy->ip6_dpo);
531
532 if (sr_policy->is_encap)
533 {
534 dpo_set (&sr_policy->ip4_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP4,
535 load_balance_create (0, DPO_PROTO_IP4, fhc));
536
537 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
538 &pfx,
539 FIB_SOURCE_SR,
540 FIB_ENTRY_FLAG_EXCLUSIVE,
541 &sr_policy->ip4_dpo);
542 }
543
544 }
545
546 /* Create the LB path vector */
Pablo Camarillofb380952016-12-07 18:34:18 +0100547 vec_foreach (sl_index, sr_policy->segments_lists)
548 {
549 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
550 path.path_dpo = segment_list->bsid_dpo;
551 path.path_weight = segment_list->weight;
552 vec_add1 (b_path_vector, path);
553 path.path_dpo = segment_list->ip6_dpo;
554 vec_add1 (ip6_path_vector, path);
555 if (sr_policy->is_encap)
556 {
557 path.path_dpo = segment_list->ip4_dpo;
558 vec_add1 (ip4_path_vector, path);
559 }
560 }
561
562 /* Update LB multipath */
563 load_balance_multipath_update (&sr_policy->bsid_dpo, b_path_vector,
564 LOAD_BALANCE_FLAG_NONE);
565 load_balance_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector,
566 LOAD_BALANCE_FLAG_NONE);
567 if (sr_policy->is_encap)
568 load_balance_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector,
569 LOAD_BALANCE_FLAG_NONE);
570
571 /* Cleanup */
572 vec_free (b_path_vector);
573 vec_free (ip6_path_vector);
574 vec_free (ip4_path_vector);
Pablo Camarillofb380952016-12-07 18:34:18 +0100575}
576
577/**
578 * @brief Updates the Replicate DPO after an SR Policy change
579 *
580 * @param sr_policy is the modified SR Policy (type spray)
581 */
582static inline void
583update_replicate (ip6_sr_policy_t * sr_policy)
584{
585 u32 *sl_index;
586 ip6_sr_sl_t *segment_list;
587 ip6_sr_main_t *sm = &sr_main;
588 load_balance_path_t path;
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100589 path.path_index = FIB_NODE_INDEX_INVALID;
Pablo Camarillofb380952016-12-07 18:34:18 +0100590 load_balance_path_t *b_path_vector = 0;
591 load_balance_path_t *ip6_path_vector = 0;
592 load_balance_path_t *ip4_path_vector = 0;
593
594 /* In case LB does not exist, create it */
595 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
596 {
597 dpo_set (&sr_policy->bsid_dpo, DPO_REPLICATE,
598 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
599
600 dpo_set (&sr_policy->ip6_dpo, DPO_REPLICATE,
601 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
602
603 /* Update FIB entry's DPO to point to SR without LB */
604 fib_prefix_t pfx = {
605 .fp_proto = FIB_PROTOCOL_IP6,
606 .fp_len = 128,
607 .fp_addr = {
608 .ip6 = sr_policy->bsid,
609 }
610 };
Neale Ranns107e7d42017-04-11 09:55:19 -0700611 fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
612 sr_policy->fib_table),
613 &pfx, FIB_SOURCE_SR,
Pablo Camarillofb380952016-12-07 18:34:18 +0100614 FIB_ENTRY_FLAG_EXCLUSIVE,
615 &sr_policy->bsid_dpo);
616
617 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
618 &pfx,
619 FIB_SOURCE_SR,
620 FIB_ENTRY_FLAG_EXCLUSIVE,
621 &sr_policy->ip6_dpo);
622
623 if (sr_policy->is_encap)
624 {
625 dpo_set (&sr_policy->ip4_dpo, DPO_REPLICATE, DPO_PROTO_IP4,
626 replicate_create (0, DPO_PROTO_IP4));
627
628 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
629 &pfx,
630 FIB_SOURCE_SR,
631 FIB_ENTRY_FLAG_EXCLUSIVE,
632 &sr_policy->ip4_dpo);
633 }
634
635 }
636
637 /* Create the replicate path vector */
638 path.path_weight = 1;
639 vec_foreach (sl_index, sr_policy->segments_lists)
640 {
641 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
642 path.path_dpo = segment_list->bsid_dpo;
643 vec_add1 (b_path_vector, path);
644 path.path_dpo = segment_list->ip6_dpo;
645 vec_add1 (ip6_path_vector, path);
646 if (sr_policy->is_encap)
647 {
648 path.path_dpo = segment_list->ip4_dpo;
649 vec_add1 (ip4_path_vector, path);
650 }
651 }
652
653 /* Update replicate multipath */
654 replicate_multipath_update (&sr_policy->bsid_dpo, b_path_vector);
655 replicate_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector);
656 if (sr_policy->is_encap)
657 replicate_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector);
Pablo Camarillofb380952016-12-07 18:34:18 +0100658}
659
660/******************************* SR rewrite API *******************************/
661/* Three functions for handling sr policies:
662 * -> sr_policy_add
663 * -> sr_policy_del
664 * -> sr_policy_mod
665 * All of them are API. CLI function on sr_policy_command_fn */
666
667/**
668 * @brief Create a new SR policy
669 *
670 * @param bsid is the bindingSID of the SR Policy
671 * @param segments is a vector of IPv6 address composing the segment list
Takeru Hayasakac4c205b2022-12-30 16:41:44 +0900672 * @param encap_src is a encaps IPv6 source addr. optional.
Pablo Camarillofb380952016-12-07 18:34:18 +0100673 * @param weight is the weight of the sid list. optional.
674 * @param behavior is the behavior of the SR policy. (default//spray)
675 * @param fib_table is the VRF where to install the FIB entry for the BSID
Takeru Hayasakac4c205b2022-12-30 16:41:44 +0900676 * @param is_encap (bool) whether SR policy should behave as Encap/SRH
677 * Insertion
Pablo Camarillofb380952016-12-07 18:34:18 +0100678 *
679 * @return 0 if correct, else error
680 */
681int
Takeru Hayasakac4c205b2022-12-30 16:41:44 +0900682sr_policy_add (ip6_address_t *bsid, ip6_address_t *segments,
683 ip6_address_t *encap_src, u32 weight, u8 type, u32 fib_table,
684 u8 is_encap, u16 plugin, void *ls_plugin_mem)
Pablo Camarillofb380952016-12-07 18:34:18 +0100685{
686 ip6_sr_main_t *sm = &sr_main;
687 ip6_sr_policy_t *sr_policy = 0;
Pablo Camarillofb380952016-12-07 18:34:18 +0100688 uword *p;
689
690 /* Search for existing keys (BSID) */
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100691 p = mhash_get (&sm->sr_policies_index_hash, bsid);
Pablo Camarillofb380952016-12-07 18:34:18 +0100692 if (p)
693 {
694 /* Add SR policy that already exists; complain */
695 return -12;
696 }
697
698 /* Search collision in FIB entries */
699 /* Explanation: It might be possible that some other entity has already
700 * created a route for the BSID. This in theory is impossible, but in
701 * practise we could see it. Assert it and scream if needed */
702 fib_prefix_t pfx = {
703 .fp_proto = FIB_PROTOCOL_IP6,
704 .fp_len = 128,
705 .fp_addr = {
706 .ip6 = *bsid,
707 }
708 };
709
710 /* Lookup the FIB index associated to the table selected */
Neale Ranns107e7d42017-04-11 09:55:19 -0700711 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP6,
712 (fib_table != (u32) ~ 0 ? fib_table : 0));
Pablo Camarillofb380952016-12-07 18:34:18 +0100713 if (fib_index == ~0)
714 return -13;
715
716 /* Lookup whether there exists an entry for the BSID */
717 fib_node_index_t fei = fib_table_lookup_exact_match (fib_index, &pfx);
718 if (FIB_NODE_INDEX_INVALID != fei)
719 return -12; //There is an entry for such lookup
720
721 /* Add an SR policy object */
722 pool_get (sm->sr_policies, sr_policy);
Dave Barachb7b92992018-10-17 10:38:51 -0400723 clib_memset (sr_policy, 0, sizeof (*sr_policy));
Dave Barach178cf492018-11-13 16:34:13 -0500724 clib_memcpy_fast (&sr_policy->bsid, bsid, sizeof (ip6_address_t));
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +0000725 sr_policy->type = type;
Pablo Camarillofb380952016-12-07 18:34:18 +0100726 sr_policy->fib_table = (fib_table != (u32) ~ 0 ? fib_table : 0); //Is default FIB 0 ?
727 sr_policy->is_encap = is_encap;
728
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800729 if (plugin)
730 {
731 sr_policy->plugin = plugin;
732 sr_policy->plugin_mem = ls_plugin_mem;
733 }
734
Pablo Camarillofb380952016-12-07 18:34:18 +0100735 /* Copy the key */
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100736 mhash_set (&sm->sr_policies_index_hash, bsid, sr_policy - sm->sr_policies,
737 NULL);
Pablo Camarillofb380952016-12-07 18:34:18 +0100738
739 /* Create a segment list and add the index to the SR policy */
Takeru Hayasakac4c205b2022-12-30 16:41:44 +0900740 create_sl (sr_policy, segments, encap_src, weight, is_encap);
Pablo Camarillofb380952016-12-07 18:34:18 +0100741
742 /* If FIB doesnt exist, create them */
743 if (sm->fib_table_ip6 == (u32) ~ 0)
744 {
745 sm->fib_table_ip6 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
Neale Ranns15002542017-09-10 04:39:11 -0700746 FIB_SOURCE_SR,
Pablo Camarillofb380952016-12-07 18:34:18 +0100747 "SRv6 steering of IP6 prefixes through BSIDs");
748 sm->fib_table_ip4 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
Neale Ranns15002542017-09-10 04:39:11 -0700749 FIB_SOURCE_SR,
Pablo Camarillofb380952016-12-07 18:34:18 +0100750 "SRv6 steering of IP4 prefixes through BSIDs");
Pablo Camarillofb380952016-12-07 18:34:18 +0100751 }
752
753 /* Create IPv6 FIB for the BindingSID attached to the DPO of the only SL */
Ahmed Abdelsalam9cca6942022-06-06 15:54:02 +0000754 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT ||
755 sr_policy->type == SR_POLICY_TYPE_TEF)
Pablo Camarillofb380952016-12-07 18:34:18 +0100756 update_lb (sr_policy);
757 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
758 update_replicate (sr_policy);
759 return 0;
760}
761
762/**
763 * @brief Delete a SR policy
764 *
765 * @param bsid is the bindingSID of the SR Policy
766 * @param index is the index of the SR policy
767 *
768 * @return 0 if correct, else error
769 */
770int
771sr_policy_del (ip6_address_t * bsid, u32 index)
772{
773 ip6_sr_main_t *sm = &sr_main;
774 ip6_sr_policy_t *sr_policy = 0;
775 ip6_sr_sl_t *segment_list;
Pablo Camarillofb380952016-12-07 18:34:18 +0100776 u32 *sl_index;
777 uword *p;
778
Pablo Camarillofb380952016-12-07 18:34:18 +0100779 if (bsid)
780 {
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100781 p = mhash_get (&sm->sr_policies_index_hash, bsid);
Pablo Camarillofb380952016-12-07 18:34:18 +0100782 if (p)
783 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
784 else
785 return -1;
786 }
787 else
788 {
789 sr_policy = pool_elt_at_index (sm->sr_policies, index);
Pablo Camarillofb380952016-12-07 18:34:18 +0100790 }
791
792 /* Remove BindingSID FIB entry */
793 fib_prefix_t pfx = {
794 .fp_proto = FIB_PROTOCOL_IP6,
795 .fp_len = 128,
796 .fp_addr = {
797 .ip6 = sr_policy->bsid,
798 }
799 ,
800 };
801
Neale Ranns107e7d42017-04-11 09:55:19 -0700802 fib_table_entry_special_remove (fib_table_find (FIB_PROTOCOL_IP6,
803 sr_policy->fib_table),
Pablo Camarillofb380952016-12-07 18:34:18 +0100804 &pfx, FIB_SOURCE_SR);
805
806 fib_table_entry_special_remove (sm->fib_table_ip6, &pfx, FIB_SOURCE_SR);
807
808 if (sr_policy->is_encap)
809 fib_table_entry_special_remove (sm->fib_table_ip4, &pfx, FIB_SOURCE_SR);
810
811 if (dpo_id_is_valid (&sr_policy->bsid_dpo))
812 {
813 dpo_reset (&sr_policy->bsid_dpo);
814 dpo_reset (&sr_policy->ip4_dpo);
815 dpo_reset (&sr_policy->ip6_dpo);
816 }
817
818 /* Clean SID Lists */
819 vec_foreach (sl_index, sr_policy->segments_lists)
820 {
821 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
822 vec_free (segment_list->segments);
823 vec_free (segment_list->rewrite);
Kris Michielsen91074432017-06-22 13:00:20 +0200824 if (!sr_policy->is_encap)
825 vec_free (segment_list->rewrite_bsid);
Pablo Camarillofb380952016-12-07 18:34:18 +0100826 pool_put_index (sm->sid_lists, *sl_index);
827 }
828
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800829 if (sr_policy->plugin)
830 {
831 sr_policy_fn_registration_t *plugin = 0;
832
833 plugin =
834 pool_elt_at_index (sm->policy_plugin_functions,
835 sr_policy->plugin - SR_BEHAVIOR_LAST);
836
837 plugin->removal (sr_policy);
838 sr_policy->plugin = 0;
839 sr_policy->plugin_mem = NULL;
840 }
841
Pablo Camarillofb380952016-12-07 18:34:18 +0100842 /* Remove SR policy entry */
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100843 mhash_unset (&sm->sr_policies_index_hash, &sr_policy->bsid, NULL);
Pablo Camarillofb380952016-12-07 18:34:18 +0100844 pool_put (sm->sr_policies, sr_policy);
845
846 /* If FIB empty unlock it */
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100847 if (!pool_elts (sm->sr_policies) && !pool_elts (sm->steer_policies))
Pablo Camarillofb380952016-12-07 18:34:18 +0100848 {
Neale Ranns15002542017-09-10 04:39:11 -0700849 fib_table_unlock (sm->fib_table_ip6, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
850 fib_table_unlock (sm->fib_table_ip4, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
Pablo Camarillofb380952016-12-07 18:34:18 +0100851 sm->fib_table_ip6 = (u32) ~ 0;
852 sm->fib_table_ip4 = (u32) ~ 0;
853 }
854
855 return 0;
856}
857
858/**
859 * @brief Modify an existing SR policy
860 *
861 * The possible modifications are adding a new Segment List, modifying an
862 * existing Segment List (modify the weight only) and delete a given
863 * Segment List from the SR Policy.
864 *
865 * @param bsid is the bindingSID of the SR Policy
866 * @param index is the index of the SR policy
867 * @param fib_table is the VRF where to install the FIB entry for the BSID
868 * @param operation is the operation to perform (among the top ones)
869 * @param segments is a vector of IPv6 address composing the segment list
Takeru Hayasakac4c205b2022-12-30 16:41:44 +0900870 * @param encap_src is a encaps IPv6 source addr. optional.
Pablo Camarillofb380952016-12-07 18:34:18 +0100871 * @param sl_index is the index of the Segment List to modify/delete
872 * @param weight is the weight of the sid list. optional.
873 * @param is_encap Mode. Encapsulation or SRH insertion.
874 *
875 * @return 0 if correct, else error
876 */
877int
Takeru Hayasakac4c205b2022-12-30 16:41:44 +0900878sr_policy_mod (ip6_address_t *bsid, u32 index, u32 fib_table, u8 operation,
879 ip6_address_t *segments, ip6_address_t *encap_src, u32 sl_index,
Pablo Camarillofb380952016-12-07 18:34:18 +0100880 u32 weight)
881{
882 ip6_sr_main_t *sm = &sr_main;
883 ip6_sr_policy_t *sr_policy = 0;
884 ip6_sr_sl_t *segment_list;
885 u32 *sl_index_iterate;
886 uword *p;
887
888 if (bsid)
889 {
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100890 p = mhash_get (&sm->sr_policies_index_hash, bsid);
Pablo Camarillofb380952016-12-07 18:34:18 +0100891 if (p)
892 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
893 else
894 return -1;
895 }
896 else
897 {
898 sr_policy = pool_elt_at_index (sm->sr_policies, index);
Pablo Camarillofb380952016-12-07 18:34:18 +0100899 }
900
901 if (operation == 1) /* Add SR List to an existing SR policy */
902 {
903 /* Create the new SL */
Takeru Hayasakac4c205b2022-12-30 16:41:44 +0900904 segment_list = create_sl (sr_policy, segments, encap_src, weight,
905 sr_policy->is_encap);
Pablo Camarillofb380952016-12-07 18:34:18 +0100906
907 /* Create a new LB DPO */
908 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
909 update_lb (sr_policy);
910 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
911 update_replicate (sr_policy);
912 }
913 else if (operation == 2) /* Delete SR List from an existing SR policy */
914 {
915 /* Check that currently there are more than one SID list */
916 if (vec_len (sr_policy->segments_lists) == 1)
917 return -21;
918
919 /* Check that the SR list does exist and is assigned to the sr policy */
920 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
921 if (*sl_index_iterate == sl_index)
922 break;
923
924 if (*sl_index_iterate != sl_index)
925 return -22;
926
927 /* Remove the lucky SR list that is being kicked out */
928 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
929 vec_free (segment_list->segments);
930 vec_free (segment_list->rewrite);
Kris Michielsen91074432017-06-22 13:00:20 +0200931 if (!sr_policy->is_encap)
932 vec_free (segment_list->rewrite_bsid);
Pablo Camarillofb380952016-12-07 18:34:18 +0100933 pool_put_index (sm->sid_lists, sl_index);
934 vec_del1 (sr_policy->segments_lists,
935 sl_index_iterate - sr_policy->segments_lists);
936
937 /* Create a new LB DPO */
938 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
939 update_lb (sr_policy);
940 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
941 update_replicate (sr_policy);
942 }
943 else if (operation == 3) /* Modify the weight of an existing SR List */
944 {
945 /* Find the corresponding SL */
946 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
947 if (*sl_index_iterate == sl_index)
948 break;
949
950 if (*sl_index_iterate != sl_index)
951 return -32;
952
953 /* Change the weight */
954 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
955 segment_list->weight = weight;
956
957 /* Update LB */
958 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
959 update_lb (sr_policy);
960 }
961 else /* Incorrect op. */
962 return -1;
963
964 return 0;
965}
966
967/**
968 * @brief CLI for 'sr policies' command family
969 */
970static clib_error_t *
971sr_policy_command_fn (vlib_main_t * vm, unformat_input_t * input,
972 vlib_cli_command_t * cmd)
973{
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800974 ip6_sr_main_t *sm = &sr_main;
Pablo Camarillofb380952016-12-07 18:34:18 +0100975 int rv = -1;
976 char is_del = 0, is_add = 0, is_mod = 0;
977 char policy_set = 0;
Takeru Hayasakac4c205b2022-12-30 16:41:44 +0900978 ip6_address_t bsid, next_address, src_v6addr;
Pablo Camarillofb380952016-12-07 18:34:18 +0100979 u32 sr_policy_index = (u32) ~ 0, sl_index = (u32) ~ 0;
980 u32 weight = (u32) ~ 0, fib_table = (u32) ~ 0;
981 ip6_address_t *segments = 0, *this_seg;
982 u8 operation = 0;
983 char is_encap = 1;
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +0000984 u8 type = SR_POLICY_TYPE_DEFAULT;
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800985 u16 behavior = 0;
986 void *ls_plugin_mem = 0;
Takeru Hayasakac4c205b2022-12-30 16:41:44 +0900987 ip6_address_t *encap_src = 0;
Pablo Camarillofb380952016-12-07 18:34:18 +0100988
989 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
990 {
991 if (!is_add && !is_mod && !is_del && unformat (input, "add"))
992 is_add = 1;
993 else if (!is_add && !is_mod && !is_del && unformat (input, "del"))
994 is_del = 1;
995 else if (!is_add && !is_mod && !is_del && unformat (input, "mod"))
996 is_mod = 1;
997 else if (!policy_set
998 && unformat (input, "bsid %U", unformat_ip6_address, &bsid))
999 policy_set = 1;
1000 else if (!is_add && !policy_set
1001 && unformat (input, "index %d", &sr_policy_index))
1002 policy_set = 1;
1003 else if (unformat (input, "weight %d", &weight));
1004 else
1005 if (unformat (input, "next %U", unformat_ip6_address, &next_address))
1006 {
1007 vec_add2 (segments, this_seg, 1);
Dave Barach178cf492018-11-13 16:34:13 -05001008 clib_memcpy_fast (this_seg->as_u8, next_address.as_u8,
1009 sizeof (*this_seg));
Pablo Camarillofb380952016-12-07 18:34:18 +01001010 }
Takeru Hayasakac4c205b2022-12-30 16:41:44 +09001011 else if (unformat (input, "v6src %U", unformat_ip6_address, &src_v6addr))
1012 {
1013 encap_src = &src_v6addr;
1014 }
Pablo Camarillofb380952016-12-07 18:34:18 +01001015 else if (unformat (input, "add sl"))
1016 operation = 1;
1017 else if (unformat (input, "del sl index %d", &sl_index))
1018 operation = 2;
1019 else if (unformat (input, "mod sl index %d", &sl_index))
1020 operation = 3;
1021 else if (fib_table == (u32) ~ 0
1022 && unformat (input, "fib-table %d", &fib_table));
1023 else if (unformat (input, "encap"))
1024 is_encap = 1;
1025 else if (unformat (input, "insert"))
1026 is_encap = 0;
1027 else if (unformat (input, "spray"))
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +00001028 type = SR_POLICY_TYPE_SPRAY;
Ahmed Abdelsalam9cca6942022-06-06 15:54:02 +00001029 else if (unformat (input, "tef"))
1030 type = SR_POLICY_TYPE_TEF;
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -08001031 else if (!behavior && unformat (input, "behavior"))
1032 {
1033 sr_policy_fn_registration_t *plugin = 0, **vec_plugins = 0;
1034 sr_policy_fn_registration_t **plugin_it = 0;
1035
1036 /* *INDENT-OFF* */
Damjan Marionb2c31b62020-12-13 21:47:40 +01001037 pool_foreach (plugin, sm->policy_plugin_functions)
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -08001038 {
1039 vec_add1 (vec_plugins, plugin);
Damjan Marionb2c31b62020-12-13 21:47:40 +01001040 }
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -08001041 /* *INDENT-ON* */
1042
1043 vec_foreach (plugin_it, vec_plugins)
1044 {
1045 if (unformat
1046 (input, "%U", (*plugin_it)->ls_unformat, &ls_plugin_mem))
1047 {
1048 behavior = (*plugin_it)->sr_policy_function_number;
1049 break;
1050 }
1051 }
1052
1053 if (!behavior)
1054 {
1055 return clib_error_return (0, "Invalid behavior");
1056 }
1057 }
Pablo Camarillofb380952016-12-07 18:34:18 +01001058 else
1059 break;
1060 }
1061
1062 if (!is_add && !is_mod && !is_del)
1063 return clib_error_return (0, "Incorrect CLI");
1064
1065 if (!policy_set)
1066 return clib_error_return (0, "No SR policy BSID or index specified");
1067
1068 if (is_add)
1069 {
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -08001070 if (behavior && vec_len (segments) == 0)
1071 {
1072 vec_add2 (segments, this_seg, 1);
1073 clib_memset (this_seg, 0, sizeof (*this_seg));
1074 }
1075
Pablo Camarillofb380952016-12-07 18:34:18 +01001076 if (vec_len (segments) == 0)
1077 return clib_error_return (0, "No Segment List specified");
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -08001078
Takeru Hayasakac4c205b2022-12-30 16:41:44 +09001079 rv = sr_policy_add (&bsid, segments, encap_src, weight, type, fib_table,
1080 is_encap, behavior, ls_plugin_mem);
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -08001081
John Lod23d39c2018-09-13 15:08:08 -04001082 vec_free (segments);
Pablo Camarillofb380952016-12-07 18:34:18 +01001083 }
1084 else if (is_del)
1085 rv = sr_policy_del ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
1086 sr_policy_index);
1087 else if (is_mod)
1088 {
1089 if (!operation)
1090 return clib_error_return (0, "No SL modification specified");
1091 if (operation != 1 && sl_index == (u32) ~ 0)
1092 return clib_error_return (0, "No Segment List index specified");
1093 if (operation == 1 && vec_len (segments) == 0)
1094 return clib_error_return (0, "No Segment List specified");
1095 if (operation == 3 && weight == (u32) ~ 0)
1096 return clib_error_return (0, "No new weight for the SL specified");
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -08001097
Takeru Hayasakac4c205b2022-12-30 16:41:44 +09001098 rv = sr_policy_mod ((sr_policy_index != (u32) ~0 ? NULL : &bsid),
Pablo Camarillofb380952016-12-07 18:34:18 +01001099 sr_policy_index, fib_table, operation, segments,
Takeru Hayasakac4c205b2022-12-30 16:41:44 +09001100 encap_src, sl_index, weight);
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -08001101
1102 if (segments)
1103 vec_free (segments);
Pablo Camarillofb380952016-12-07 18:34:18 +01001104 }
1105
1106 switch (rv)
1107 {
1108 case 0:
1109 break;
1110 case 1:
1111 return 0;
1112 case -12:
1113 return clib_error_return (0,
1114 "There is already a FIB entry for the BindingSID address.\n"
1115 "The SR policy could not be created.");
1116 case -13:
1117 return clib_error_return (0, "The specified FIB table does not exist.");
1118 case -21:
1119 return clib_error_return (0,
1120 "The selected SR policy only contains ONE segment list. "
1121 "Please remove the SR policy instead");
1122 case -22:
1123 return clib_error_return (0,
1124 "Could not delete the segment list. "
1125 "It is not associated with that SR policy.");
1126 case -32:
1127 return clib_error_return (0,
1128 "Could not modify the segment list. "
1129 "The given SL is not associated with such SR policy.");
1130 default:
1131 return clib_error_return (0, "BUG: sr policy returns %d", rv);
1132 }
1133 return 0;
1134}
1135
1136/* *INDENT-OFF* */
1137VLIB_CLI_COMMAND (sr_policy_command, static) = {
1138 .path = "sr policy",
1139 .short_help = "sr policy [add||del||mod] [bsid 2001::1||index 5] "
1140 "next A:: next B:: next C:: (weight 1) (fib-table 2) (encap|insert)",
1141 .long_help =
1142 "Manipulation of SR policies.\n"
1143 "A Segment Routing policy may contain several SID lists. Each SID list has\n"
1144 "an associated weight (default 1), which will result in wECMP (uECMP).\n"
1145 "Segment Routing policies might be of type encapsulation or srh insertion\n"
1146 "Each SR policy will be associated with a unique BindingSID.\n"
1147 "A BindingSID is a locally allocated SegmentID. For every packet that arrives\n"
1148 "with IPv6_DA:BSID such traffic will be steered into the SR policy.\n"
1149 "The add command will create a SR policy with its first segment list (sl)\n"
1150 "The mod command allows you to add, remove, or modify the existing segment lists\n"
1151 "within an SR policy.\n"
1152 "The del command allows you to delete a SR policy along with all its associated\n"
1153 "SID lists.\n",
1154 .function = sr_policy_command_fn,
1155};
1156/* *INDENT-ON* */
1157
1158/**
1159 * @brief CLI to display onscreen all the SR policies
1160 */
1161static clib_error_t *
1162show_sr_policies_command_fn (vlib_main_t * vm, unformat_input_t * input,
1163 vlib_cli_command_t * cmd)
1164{
1165 ip6_sr_main_t *sm = &sr_main;
1166 u32 *sl_index;
1167 ip6_sr_sl_t *segment_list = 0;
1168 ip6_sr_policy_t *sr_policy = 0;
1169 ip6_sr_policy_t **vec_policies = 0;
1170 ip6_address_t *addr;
1171 u8 *s;
1172 int i = 0;
1173
1174 vlib_cli_output (vm, "SR policies:");
1175
1176 /* *INDENT-OFF* */
Damjan Marionb2c31b62020-12-13 21:47:40 +01001177 pool_foreach (sr_policy, sm->sr_policies)
1178 {vec_add1 (vec_policies, sr_policy); }
Pablo Camarillofb380952016-12-07 18:34:18 +01001179 /* *INDENT-ON* */
1180
1181 vec_foreach_index (i, vec_policies)
1182 {
1183 sr_policy = vec_policies[i];
1184 vlib_cli_output (vm, "[%u].-\tBSID: %U",
1185 (u32) (sr_policy - sm->sr_policies),
1186 format_ip6_address, &sr_policy->bsid);
1187 vlib_cli_output (vm, "\tBehavior: %s",
1188 (sr_policy->is_encap ? "Encapsulation" :
1189 "SRH insertion"));
Takeru Hayasakac4c205b2022-12-30 16:41:44 +09001190 if (sr_policy->is_encap)
1191 {
1192 vlib_cli_output (vm, "\tEncapSrcIP: %U", format_ip6_address,
1193 &sr_policy->encap_src);
1194 }
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +00001195 switch (sr_policy->type)
1196 {
1197 case SR_POLICY_TYPE_SPRAY:
1198 vlib_cli_output (vm, "\tType: %s", "Spray");
1199 break;
Ahmed Abdelsalam9cca6942022-06-06 15:54:02 +00001200 case SR_POLICY_TYPE_TEF:
1201 vlib_cli_output (vm, "\tType: %s",
1202 "TEF (Timestamp, Encapsulate, and Forward)");
1203 break;
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +00001204 default:
1205 vlib_cli_output (vm, "\tType: %s", "Default");
1206 break;
1207 }
Pablo Camarillofb380952016-12-07 18:34:18 +01001208 vlib_cli_output (vm, "\tFIB table: %u",
1209 (sr_policy->fib_table !=
1210 (u32) ~ 0 ? sr_policy->fib_table : 0));
1211 vlib_cli_output (vm, "\tSegment Lists:");
1212 vec_foreach (sl_index, sr_policy->segments_lists)
1213 {
1214 s = NULL;
1215 s = format (s, "\t[%u].- ", *sl_index);
1216 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
1217 s = format (s, "< ");
1218 vec_foreach (addr, segment_list->segments)
1219 {
1220 s = format (s, "%U, ", format_ip6_address, addr);
1221 }
1222 s = format (s, "\b\b > ");
1223 s = format (s, "weight: %u", segment_list->weight);
Benoît Ganneb9753542020-04-17 12:11:26 +02001224 vlib_cli_output (vm, " %v", s);
Pablo Camarillofb380952016-12-07 18:34:18 +01001225 }
1226 vlib_cli_output (vm, "-----------");
1227 }
1228 return 0;
1229}
1230
1231/* *INDENT-OFF* */
1232VLIB_CLI_COMMAND (show_sr_policies_command, static) = {
1233 .path = "show sr policies",
1234 .short_help = "show sr policies",
1235 .function = show_sr_policies_command_fn,
1236};
1237/* *INDENT-ON* */
1238
Ahmed Abdelsalam448bc812020-11-09 14:04:07 +00001239/**
1240 * @brief CLI to display onscreen the SR encaps source addr
1241 */
1242static clib_error_t *
1243show_sr_encaps_source_command_fn (vlib_main_t * vm, unformat_input_t * input,
1244 vlib_cli_command_t * cmd)
1245{
1246 vlib_cli_output (vm, "SR encaps source addr = %U", format_ip6_address,
1247 sr_get_encaps_source ());
1248
1249 return 0;
1250}
1251
1252/* *INDENT-OFF* */
1253VLIB_CLI_COMMAND (show_sr_encaps_source_command, static) = {
1254 .path = "show sr encaps source addr",
1255 .short_help = "show sr encaps source addr",
1256 .function = show_sr_encaps_source_command_fn,
1257};
1258/* *INDENT-ON* */
1259
Ahmed Abdelsalam80f0b882020-11-10 17:19:12 +00001260/**
1261 * @brief CLI to display onscreen the hop-limit value used for SRv6 encapsulation
1262 */
1263static clib_error_t *
1264show_sr_encaps_hop_limit_command_fn (vlib_main_t * vm,
1265 unformat_input_t * input,
1266 vlib_cli_command_t * cmd)
1267{
1268 vlib_cli_output (vm, "SR encaps hop-limit = %u", sr_get_hop_limit ());
1269
1270 return 0;
1271}
1272
1273/* *INDENT-OFF* */
1274VLIB_CLI_COMMAND (show_sr_encaps_hop_limit_command, static) = {
1275 .path = "show sr encaps hop-limit",
1276 .short_help = "show sr encaps hop-limit",
1277 .function = show_sr_encaps_hop_limit_command_fn,
1278};
1279/* *INDENT-ON* */
1280
Pablo Camarillofb380952016-12-07 18:34:18 +01001281/*************************** SR rewrite graph node ****************************/
1282/**
1283 * @brief Trace for the SR Policy Rewrite graph node
1284 */
1285static u8 *
1286format_sr_policy_rewrite_trace (u8 * s, va_list * args)
1287{
1288 //TODO
1289 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1290 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1291 sr_policy_rewrite_trace_t *t = va_arg (*args, sr_policy_rewrite_trace_t *);
1292
1293 s = format
1294 (s, "SR-policy-rewrite: src %U dst %U",
1295 format_ip6_address, &t->src, format_ip6_address, &t->dst);
1296
1297 return s;
1298}
Ahmed Abdelsalam9cca6942022-06-06 15:54:02 +00001299/**
1300 * @brief SRv6 TEF (Timestamp, Encapsulate, and Forward) behavior
1301 */
1302static_always_inline void
1303srv6_tef_behavior (vlib_node_runtime_t *node, vlib_buffer_t *b0,
1304 ip6_header_t *ip0)
1305{
1306 ip6_sr_header_t *srh;
1307 ip6_sr_pt_tlv_t *srh_pt_tlv;
1308 timestamp_64_t ts;
Ahmed Abdelsalamd50e6612022-06-29 17:11:08 +00001309 sr_pt_iface_t *ls = 0;
1310 u16 id_ld = 0;
Ahmed Abdelsalam9cca6942022-06-06 15:54:02 +00001311 srh = (ip6_sr_header_t *) (ip0 + 1);
1312
1313 srh_pt_tlv =
1314 (ip6_sr_pt_tlv_t *) ((u8 *) ip0 + sizeof (ip6_header_t) +
1315 sizeof (ip6_sr_header_t) +
1316 sizeof (ip6_address_t) * (srh->last_entry + 1));
1317
1318 unix_time_now_nsec_fraction (&ts.sec, &ts.nsec);
Guillaume Solignac897fbba2023-01-06 13:55:04 +01001319 srh_pt_tlv->t64.sec = clib_host_to_net_u32 (ts.sec);
1320 srh_pt_tlv->t64.nsec = clib_host_to_net_u32 (ts.nsec);
Ahmed Abdelsalamd50e6612022-06-29 17:11:08 +00001321 ls = sr_pt_find_iface (vnet_buffer (b0)->sw_if_index[VLIB_RX]);
1322 if (ls)
1323 {
1324 id_ld = ls->id << 4;
1325 id_ld |= ls->ingress_load;
Guillaume Solignac897fbba2023-01-06 13:55:04 +01001326 srh_pt_tlv->id_ld = clib_host_to_net_u16 (id_ld);
Ahmed Abdelsalamd50e6612022-06-29 17:11:08 +00001327 }
Ahmed Abdelsalam9cca6942022-06-06 15:54:02 +00001328}
Pablo Camarillofb380952016-12-07 18:34:18 +01001329
1330/**
1331 * @brief IPv6 encapsulation processing as per RFC2473
1332 */
1333static_always_inline void
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +00001334encaps_processing_v6 (vlib_node_runtime_t *node, vlib_buffer_t *b0,
1335 ip6_header_t *ip0, ip6_header_t *ip0_encap,
1336 u8 policy_type)
Pablo Camarillofb380952016-12-07 18:34:18 +01001337{
1338 u32 new_l0;
Jakub Horn91f4a972021-01-21 12:14:58 +00001339 u32 flow_label;
Pablo Camarillofb380952016-12-07 18:34:18 +01001340
1341 ip0_encap->hop_limit -= 1;
1342 new_l0 =
1343 ip0->payload_length + sizeof (ip6_header_t) +
1344 clib_net_to_host_u16 (ip0_encap->payload_length);
1345 ip0->payload_length = clib_host_to_net_u16 (new_l0);
Jakub Horn91f4a972021-01-21 12:14:58 +00001346
1347 flow_label = ip6_compute_flow_hash (ip0_encap, IP_FLOW_HASH_DEFAULT);
1348 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
1349 0 |
1350 (clib_net_to_host_u32 (
1351 ip0_encap->ip_version_traffic_class_and_flow_label) &
1352 0xfff00000) |
1353 (flow_label & 0x0000ffff));
Ahmed Abdelsalam9cca6942022-06-06 15:54:02 +00001354 if (policy_type == SR_POLICY_TYPE_TEF)
1355 srv6_tef_behavior (node, b0, ip0);
Pablo Camarillofb380952016-12-07 18:34:18 +01001356}
1357
1358/**
1359 * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
1360 */
1361static uword
1362sr_policy_rewrite_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
1363 vlib_frame_t * from_frame)
1364{
1365 ip6_sr_main_t *sm = &sr_main;
1366 u32 n_left_from, next_index, *from, *to_next;
1367
1368 from = vlib_frame_vector_args (from_frame);
1369 n_left_from = from_frame->n_vectors;
1370
1371 next_index = node->cached_next_index;
1372
1373 int encap_pkts = 0, bsid_pkts = 0;
1374
1375 while (n_left_from > 0)
1376 {
1377 u32 n_left_to_next;
1378
1379 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1380
1381 /* Quad - Loop */
1382 while (n_left_from >= 8 && n_left_to_next >= 4)
1383 {
1384 u32 bi0, bi1, bi2, bi3;
1385 vlib_buffer_t *b0, *b1, *b2, *b3;
1386 u32 next0, next1, next2, next3;
1387 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1388 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1389 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1390 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1391
1392 /* Prefetch next iteration. */
1393 {
1394 vlib_buffer_t *p4, *p5, *p6, *p7;
1395
1396 p4 = vlib_get_buffer (vm, from[4]);
1397 p5 = vlib_get_buffer (vm, from[5]);
1398 p6 = vlib_get_buffer (vm, from[6]);
1399 p7 = vlib_get_buffer (vm, from[7]);
1400
1401 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1402 vlib_prefetch_buffer_header (p4, LOAD);
1403 vlib_prefetch_buffer_header (p5, LOAD);
1404 vlib_prefetch_buffer_header (p6, LOAD);
1405 vlib_prefetch_buffer_header (p7, LOAD);
1406
Damjan Marionaf7fb042021-07-15 11:54:41 +02001407 clib_prefetch_store (p4->data);
1408 clib_prefetch_store (p5->data);
1409 clib_prefetch_store (p6->data);
1410 clib_prefetch_store (p7->data);
Pablo Camarillofb380952016-12-07 18:34:18 +01001411 }
1412
1413 to_next[0] = bi0 = from[0];
1414 to_next[1] = bi1 = from[1];
1415 to_next[2] = bi2 = from[2];
1416 to_next[3] = bi3 = from[3];
1417 from += 4;
1418 to_next += 4;
1419 n_left_from -= 4;
1420 n_left_to_next -= 4;
1421
1422 b0 = vlib_get_buffer (vm, bi0);
1423 b1 = vlib_get_buffer (vm, bi1);
1424 b2 = vlib_get_buffer (vm, bi2);
1425 b3 = vlib_get_buffer (vm, bi3);
1426
1427 sl0 =
1428 pool_elt_at_index (sm->sid_lists,
1429 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1430 sl1 =
1431 pool_elt_at_index (sm->sid_lists,
1432 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1433 sl2 =
1434 pool_elt_at_index (sm->sid_lists,
1435 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1436 sl3 =
1437 pool_elt_at_index (sm->sid_lists,
1438 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1439
shwethabe146f132017-03-09 16:58:26 +00001440 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1441 vec_len (sl0->rewrite));
1442 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1443 vec_len (sl1->rewrite));
1444 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1445 vec_len (sl2->rewrite));
1446 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1447 vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001448
1449 ip0_encap = vlib_buffer_get_current (b0);
1450 ip1_encap = vlib_buffer_get_current (b1);
1451 ip2_encap = vlib_buffer_get_current (b2);
1452 ip3_encap = vlib_buffer_get_current (b3);
1453
Dave Barach178cf492018-11-13 16:34:13 -05001454 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1455 sl0->rewrite, vec_len (sl0->rewrite));
1456 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1457 sl1->rewrite, vec_len (sl1->rewrite));
1458 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1459 sl2->rewrite, vec_len (sl2->rewrite));
1460 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1461 sl3->rewrite, vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001462
1463 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1464 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1465 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1466 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1467
1468 ip0 = vlib_buffer_get_current (b0);
1469 ip1 = vlib_buffer_get_current (b1);
1470 ip2 = vlib_buffer_get_current (b2);
1471 ip3 = vlib_buffer_get_current (b3);
1472
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +00001473 encaps_processing_v6 (node, b0, ip0, ip0_encap, sl0->policy_type);
1474 encaps_processing_v6 (node, b1, ip1, ip1_encap, sl1->policy_type);
1475 encaps_processing_v6 (node, b2, ip2, ip2_encap, sl2->policy_type);
1476 encaps_processing_v6 (node, b3, ip3, ip3_encap, sl3->policy_type);
Pablo Camarillofb380952016-12-07 18:34:18 +01001477
Tetsuya Murakami6b354912021-01-31 16:38:56 -08001478 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
1479 vnet_buffer (b1)->sw_if_index[VLIB_TX] = sl1->egress_fib_table;
1480 vnet_buffer (b2)->sw_if_index[VLIB_TX] = sl2->egress_fib_table;
1481 vnet_buffer (b3)->sw_if_index[VLIB_TX] = sl3->egress_fib_table;
1482
Pablo Camarillofb380952016-12-07 18:34:18 +01001483 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1484 {
1485 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1486 {
1487 sr_policy_rewrite_trace_t *tr =
1488 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001489 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1490 sizeof (tr->src.as_u8));
1491 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1492 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001493 }
1494
1495 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1496 {
1497 sr_policy_rewrite_trace_t *tr =
1498 vlib_add_trace (vm, node, b1, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001499 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
1500 sizeof (tr->src.as_u8));
1501 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
1502 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001503 }
1504
1505 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1506 {
1507 sr_policy_rewrite_trace_t *tr =
1508 vlib_add_trace (vm, node, b2, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001509 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
1510 sizeof (tr->src.as_u8));
1511 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
1512 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001513 }
1514
1515 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1516 {
1517 sr_policy_rewrite_trace_t *tr =
1518 vlib_add_trace (vm, node, b3, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001519 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
1520 sizeof (tr->src.as_u8));
1521 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
1522 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001523 }
1524 }
1525
1526 encap_pkts += 4;
1527 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1528 n_left_to_next, bi0, bi1, bi2, bi3,
1529 next0, next1, next2, next3);
1530 }
1531
1532 /* Single loop for potentially the last three packets */
1533 while (n_left_from > 0 && n_left_to_next > 0)
1534 {
1535 u32 bi0;
1536 vlib_buffer_t *b0;
1537 ip6_header_t *ip0 = 0, *ip0_encap = 0;
1538 ip6_sr_sl_t *sl0;
1539 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1540
1541 bi0 = from[0];
1542 to_next[0] = bi0;
1543 from += 1;
1544 to_next += 1;
1545 n_left_from -= 1;
1546 n_left_to_next -= 1;
1547 b0 = vlib_get_buffer (vm, bi0);
1548
1549 sl0 =
1550 pool_elt_at_index (sm->sid_lists,
1551 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00001552 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1553 vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001554
1555 ip0_encap = vlib_buffer_get_current (b0);
1556
Dave Barach178cf492018-11-13 16:34:13 -05001557 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1558 sl0->rewrite, vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001559 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1560
1561 ip0 = vlib_buffer_get_current (b0);
1562
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +00001563 encaps_processing_v6 (node, b0, ip0, ip0_encap, sl0->policy_type);
Pablo Camarillofb380952016-12-07 18:34:18 +01001564
Tetsuya Murakami6b354912021-01-31 16:38:56 -08001565 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
1566
Pablo Camarillofb380952016-12-07 18:34:18 +01001567 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1568 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1569 {
1570 sr_policy_rewrite_trace_t *tr =
1571 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001572 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1573 sizeof (tr->src.as_u8));
1574 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1575 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001576 }
1577
1578 encap_pkts++;
1579 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1580 n_left_to_next, bi0, next0);
1581 }
1582
1583 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1584 }
1585
1586 /* Update counters */
1587 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1588 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1589 encap_pkts);
1590 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1591 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1592 bsid_pkts);
1593
1594 return from_frame->n_vectors;
1595}
1596
1597/* *INDENT-OFF* */
1598VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_node) = {
1599 .function = sr_policy_rewrite_encaps,
1600 .name = "sr-pl-rewrite-encaps",
1601 .vector_size = sizeof (u32),
1602 .format_trace = format_sr_policy_rewrite_trace,
1603 .type = VLIB_NODE_TYPE_INTERNAL,
1604 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1605 .error_strings = sr_policy_rewrite_error_strings,
1606 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1607 .next_nodes = {
1608#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1609 foreach_sr_policy_rewrite_next
1610#undef _
1611 },
1612};
1613/* *INDENT-ON* */
1614
1615/**
1616 * @brief IPv4 encapsulation processing as per RFC2473
1617 */
1618static_always_inline void
1619encaps_processing_v4 (vlib_node_runtime_t * node,
1620 vlib_buffer_t * b0,
1621 ip6_header_t * ip0, ip4_header_t * ip0_encap)
1622{
1623 u32 new_l0;
1624 ip6_sr_header_t *sr0;
1625
1626 u32 checksum0;
Jakub Horn91f4a972021-01-21 12:14:58 +00001627 u32 flow_label;
Pablo Camarillofb380952016-12-07 18:34:18 +01001628
1629 /* Inner IPv4: Decrement TTL & update checksum */
1630 ip0_encap->ttl -= 1;
1631 checksum0 = ip0_encap->checksum + clib_host_to_net_u16 (0x0100);
1632 checksum0 += checksum0 >= 0xffff;
1633 ip0_encap->checksum = checksum0;
1634
1635 /* Outer IPv6: Update length, FL, proto */
1636 new_l0 = ip0->payload_length + clib_net_to_host_u16 (ip0_encap->length);
1637 ip0->payload_length = clib_host_to_net_u16 (new_l0);
Jakub Horn91f4a972021-01-21 12:14:58 +00001638 flow_label = ip4_compute_flow_hash (ip0_encap, IP_FLOW_HASH_DEFAULT);
1639 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
1640 0 | ((6 & 0xF) << 28) | ((ip0_encap->tos & 0xFF) << 20) |
1641 (flow_label & 0x0000ffff));
Pablo Camarillod327c872018-01-08 14:25:55 +01001642 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
1643 {
1644 sr0 = (void *) (ip0 + 1);
1645 sr0->protocol = IP_PROTOCOL_IP_IN_IP;
1646 }
1647 else
1648 ip0->protocol = IP_PROTOCOL_IP_IN_IP;
Pablo Camarillofb380952016-12-07 18:34:18 +01001649}
1650
1651/**
1652 * @brief Graph node for applying a SR policy into an IPv4 packet. Encapsulation
1653 */
1654static uword
1655sr_policy_rewrite_encaps_v4 (vlib_main_t * vm, vlib_node_runtime_t * node,
1656 vlib_frame_t * from_frame)
1657{
1658 ip6_sr_main_t *sm = &sr_main;
1659 u32 n_left_from, next_index, *from, *to_next;
1660
1661 from = vlib_frame_vector_args (from_frame);
1662 n_left_from = from_frame->n_vectors;
1663
1664 next_index = node->cached_next_index;
1665
1666 int encap_pkts = 0, bsid_pkts = 0;
1667
1668 while (n_left_from > 0)
1669 {
1670 u32 n_left_to_next;
1671
1672 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1673
1674 /* Quad - Loop */
1675 while (n_left_from >= 8 && n_left_to_next >= 4)
1676 {
1677 u32 bi0, bi1, bi2, bi3;
1678 vlib_buffer_t *b0, *b1, *b2, *b3;
1679 u32 next0, next1, next2, next3;
1680 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1681 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1682 ip4_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1683 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1684
1685 /* Prefetch next iteration. */
1686 {
1687 vlib_buffer_t *p4, *p5, *p6, *p7;
1688
1689 p4 = vlib_get_buffer (vm, from[4]);
1690 p5 = vlib_get_buffer (vm, from[5]);
1691 p6 = vlib_get_buffer (vm, from[6]);
1692 p7 = vlib_get_buffer (vm, from[7]);
1693
1694 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1695 vlib_prefetch_buffer_header (p4, LOAD);
1696 vlib_prefetch_buffer_header (p5, LOAD);
1697 vlib_prefetch_buffer_header (p6, LOAD);
1698 vlib_prefetch_buffer_header (p7, LOAD);
1699
Damjan Marionaf7fb042021-07-15 11:54:41 +02001700 clib_prefetch_store (p4->data);
1701 clib_prefetch_store (p5->data);
1702 clib_prefetch_store (p6->data);
1703 clib_prefetch_store (p7->data);
Pablo Camarillofb380952016-12-07 18:34:18 +01001704 }
1705
1706 to_next[0] = bi0 = from[0];
1707 to_next[1] = bi1 = from[1];
1708 to_next[2] = bi2 = from[2];
1709 to_next[3] = bi3 = from[3];
1710 from += 4;
1711 to_next += 4;
1712 n_left_from -= 4;
1713 n_left_to_next -= 4;
1714
1715 b0 = vlib_get_buffer (vm, bi0);
1716 b1 = vlib_get_buffer (vm, bi1);
1717 b2 = vlib_get_buffer (vm, bi2);
1718 b3 = vlib_get_buffer (vm, bi3);
1719
1720 sl0 =
1721 pool_elt_at_index (sm->sid_lists,
1722 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1723 sl1 =
1724 pool_elt_at_index (sm->sid_lists,
1725 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1726 sl2 =
1727 pool_elt_at_index (sm->sid_lists,
1728 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1729 sl3 =
1730 pool_elt_at_index (sm->sid_lists,
1731 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00001732 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1733 vec_len (sl0->rewrite));
1734 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1735 vec_len (sl1->rewrite));
1736 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1737 vec_len (sl2->rewrite));
1738 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1739 vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001740
1741 ip0_encap = vlib_buffer_get_current (b0);
1742 ip1_encap = vlib_buffer_get_current (b1);
1743 ip2_encap = vlib_buffer_get_current (b2);
1744 ip3_encap = vlib_buffer_get_current (b3);
1745
Dave Barach178cf492018-11-13 16:34:13 -05001746 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1747 sl0->rewrite, vec_len (sl0->rewrite));
1748 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1749 sl1->rewrite, vec_len (sl1->rewrite));
1750 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1751 sl2->rewrite, vec_len (sl2->rewrite));
1752 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1753 sl3->rewrite, vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001754
1755 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1756 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1757 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1758 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1759
1760 ip0 = vlib_buffer_get_current (b0);
1761 ip1 = vlib_buffer_get_current (b1);
1762 ip2 = vlib_buffer_get_current (b2);
1763 ip3 = vlib_buffer_get_current (b3);
1764
1765 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1766 encaps_processing_v4 (node, b1, ip1, ip1_encap);
1767 encaps_processing_v4 (node, b2, ip2, ip2_encap);
1768 encaps_processing_v4 (node, b3, ip3, ip3_encap);
1769
Tetsuya Murakami6b354912021-01-31 16:38:56 -08001770 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
1771 vnet_buffer (b1)->sw_if_index[VLIB_TX] = sl1->egress_fib_table;
1772 vnet_buffer (b2)->sw_if_index[VLIB_TX] = sl2->egress_fib_table;
1773 vnet_buffer (b3)->sw_if_index[VLIB_TX] = sl3->egress_fib_table;
1774
Pablo Camarillofb380952016-12-07 18:34:18 +01001775 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1776 {
1777 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1778 {
1779 sr_policy_rewrite_trace_t *tr =
1780 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001781 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1782 sizeof (tr->src.as_u8));
1783 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1784 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001785 }
1786
1787 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1788 {
1789 sr_policy_rewrite_trace_t *tr =
1790 vlib_add_trace (vm, node, b1, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001791 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
1792 sizeof (tr->src.as_u8));
1793 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
1794 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001795 }
1796
1797 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1798 {
1799 sr_policy_rewrite_trace_t *tr =
1800 vlib_add_trace (vm, node, b2, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001801 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
1802 sizeof (tr->src.as_u8));
1803 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
1804 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001805 }
1806
1807 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1808 {
1809 sr_policy_rewrite_trace_t *tr =
1810 vlib_add_trace (vm, node, b3, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001811 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
1812 sizeof (tr->src.as_u8));
1813 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
1814 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001815 }
1816 }
1817
1818 encap_pkts += 4;
1819 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1820 n_left_to_next, bi0, bi1, bi2, bi3,
1821 next0, next1, next2, next3);
1822 }
1823
1824 /* Single loop for potentially the last three packets */
1825 while (n_left_from > 0 && n_left_to_next > 0)
1826 {
1827 u32 bi0;
1828 vlib_buffer_t *b0;
1829 ip6_header_t *ip0 = 0;
1830 ip4_header_t *ip0_encap = 0;
1831 ip6_sr_sl_t *sl0;
1832 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1833
1834 bi0 = from[0];
1835 to_next[0] = bi0;
1836 from += 1;
1837 to_next += 1;
1838 n_left_from -= 1;
1839 n_left_to_next -= 1;
1840 b0 = vlib_get_buffer (vm, bi0);
1841
1842 sl0 =
1843 pool_elt_at_index (sm->sid_lists,
1844 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00001845 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1846 vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001847
1848 ip0_encap = vlib_buffer_get_current (b0);
1849
Dave Barach178cf492018-11-13 16:34:13 -05001850 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1851 sl0->rewrite, vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001852 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1853
1854 ip0 = vlib_buffer_get_current (b0);
1855
1856 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1857
Tetsuya Murakami6b354912021-01-31 16:38:56 -08001858 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
1859
Pablo Camarillofb380952016-12-07 18:34:18 +01001860 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1861 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1862 {
1863 sr_policy_rewrite_trace_t *tr =
1864 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001865 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1866 sizeof (tr->src.as_u8));
1867 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1868 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001869 }
1870
1871 encap_pkts++;
1872 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1873 n_left_to_next, bi0, next0);
1874 }
1875
1876 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1877 }
1878
1879 /* Update counters */
1880 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1881 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1882 encap_pkts);
1883 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1884 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1885 bsid_pkts);
1886
1887 return from_frame->n_vectors;
1888}
1889
1890/* *INDENT-OFF* */
1891VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_v4_node) = {
1892 .function = sr_policy_rewrite_encaps_v4,
1893 .name = "sr-pl-rewrite-encaps-v4",
1894 .vector_size = sizeof (u32),
1895 .format_trace = format_sr_policy_rewrite_trace,
1896 .type = VLIB_NODE_TYPE_INTERNAL,
1897 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1898 .error_strings = sr_policy_rewrite_error_strings,
1899 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1900 .next_nodes = {
1901#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1902 foreach_sr_policy_rewrite_next
1903#undef _
1904 },
1905};
1906/* *INDENT-ON* */
1907
1908always_inline u32
1909ip_flow_hash (void *data)
1910{
1911 ip4_header_t *iph = (ip4_header_t *) data;
1912
1913 if ((iph->ip_version_and_header_length & 0xF0) == 0x40)
1914 return ip4_compute_flow_hash (iph, IP_FLOW_HASH_DEFAULT);
1915 else
1916 return ip6_compute_flow_hash ((ip6_header_t *) iph, IP_FLOW_HASH_DEFAULT);
1917}
1918
1919always_inline u64
1920mac_to_u64 (u8 * m)
1921{
1922 return (*((u64 *) m) & 0xffffffffffff);
1923}
1924
1925always_inline u32
1926l2_flow_hash (vlib_buffer_t * b0)
1927{
1928 ethernet_header_t *eh;
1929 u64 a, b, c;
1930 uword is_ip, eh_size;
1931 u16 eh_type;
1932
1933 eh = vlib_buffer_get_current (b0);
1934 eh_type = clib_net_to_host_u16 (eh->type);
1935 eh_size = ethernet_buffer_header_size (b0);
1936
1937 is_ip = (eh_type == ETHERNET_TYPE_IP4 || eh_type == ETHERNET_TYPE_IP6);
1938
1939 /* since we have 2 cache lines, use them */
1940 if (is_ip)
1941 a = ip_flow_hash ((u8 *) vlib_buffer_get_current (b0) + eh_size);
1942 else
1943 a = eh->type;
1944
1945 b = mac_to_u64 ((u8 *) eh->dst_address);
1946 c = mac_to_u64 ((u8 *) eh->src_address);
1947 hash_mix64 (a, b, c);
1948
1949 return (u32) c;
1950}
1951
1952/**
1953 * @brief Graph node for applying a SR policy into a L2 frame
1954 */
1955static uword
1956sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
1957 vlib_frame_t * from_frame)
1958{
1959 ip6_sr_main_t *sm = &sr_main;
1960 u32 n_left_from, next_index, *from, *to_next;
1961
1962 from = vlib_frame_vector_args (from_frame);
1963 n_left_from = from_frame->n_vectors;
1964
1965 next_index = node->cached_next_index;
1966
1967 int encap_pkts = 0, bsid_pkts = 0;
1968
1969 while (n_left_from > 0)
1970 {
1971 u32 n_left_to_next;
1972
1973 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1974
1975 /* Quad - Loop */
1976 while (n_left_from >= 8 && n_left_to_next >= 4)
1977 {
1978 u32 bi0, bi1, bi2, bi3;
1979 vlib_buffer_t *b0, *b1, *b2, *b3;
1980 u32 next0, next1, next2, next3;
1981 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1982 ethernet_header_t *en0, *en1, *en2, *en3;
1983 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1984 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1985 ip6_sr_policy_t *sp0, *sp1, *sp2, *sp3;
1986 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
Jakub Horn91f4a972021-01-21 12:14:58 +00001987 u32 flow_label0, flow_label1, flow_label2, flow_label3;
Pablo Camarillofb380952016-12-07 18:34:18 +01001988
1989 /* Prefetch next iteration. */
1990 {
1991 vlib_buffer_t *p4, *p5, *p6, *p7;
1992
1993 p4 = vlib_get_buffer (vm, from[4]);
1994 p5 = vlib_get_buffer (vm, from[5]);
1995 p6 = vlib_get_buffer (vm, from[6]);
1996 p7 = vlib_get_buffer (vm, from[7]);
1997
1998 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1999 vlib_prefetch_buffer_header (p4, LOAD);
2000 vlib_prefetch_buffer_header (p5, LOAD);
2001 vlib_prefetch_buffer_header (p6, LOAD);
2002 vlib_prefetch_buffer_header (p7, LOAD);
2003
Damjan Marionaf7fb042021-07-15 11:54:41 +02002004 clib_prefetch_store (p4->data);
2005 clib_prefetch_store (p5->data);
2006 clib_prefetch_store (p6->data);
2007 clib_prefetch_store (p7->data);
Pablo Camarillofb380952016-12-07 18:34:18 +01002008 }
2009
2010 to_next[0] = bi0 = from[0];
2011 to_next[1] = bi1 = from[1];
2012 to_next[2] = bi2 = from[2];
2013 to_next[3] = bi3 = from[3];
2014 from += 4;
2015 to_next += 4;
2016 n_left_from -= 4;
2017 n_left_to_next -= 4;
2018
2019 b0 = vlib_get_buffer (vm, bi0);
2020 b1 = vlib_get_buffer (vm, bi1);
2021 b2 = vlib_get_buffer (vm, bi2);
2022 b3 = vlib_get_buffer (vm, bi3);
2023
2024 sp0 = pool_elt_at_index (sm->sr_policies,
2025 sm->sw_iface_sr_policies[vnet_buffer
2026 (b0)->sw_if_index
2027 [VLIB_RX]]);
2028
2029 sp1 = pool_elt_at_index (sm->sr_policies,
2030 sm->sw_iface_sr_policies[vnet_buffer
2031 (b1)->sw_if_index
2032 [VLIB_RX]]);
2033
2034 sp2 = pool_elt_at_index (sm->sr_policies,
2035 sm->sw_iface_sr_policies[vnet_buffer
2036 (b2)->sw_if_index
2037 [VLIB_RX]]);
2038
2039 sp3 = pool_elt_at_index (sm->sr_policies,
2040 sm->sw_iface_sr_policies[vnet_buffer
2041 (b3)->sw_if_index
2042 [VLIB_RX]]);
Jakub Horn91f4a972021-01-21 12:14:58 +00002043 flow_label0 = l2_flow_hash (b0);
2044 flow_label1 = l2_flow_hash (b1);
2045 flow_label2 = l2_flow_hash (b2);
2046 flow_label3 = l2_flow_hash (b3);
Pablo Camarillofb380952016-12-07 18:34:18 +01002047
2048 if (vec_len (sp0->segments_lists) == 1)
2049 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
2050 else
2051 {
Jakub Horn91f4a972021-01-21 12:14:58 +00002052 vnet_buffer (b0)->ip.flow_hash = flow_label0;
Pablo Camarillofb380952016-12-07 18:34:18 +01002053 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
2054 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
2055 (vec_len (sp0->segments_lists) - 1))];
2056 }
2057
2058 if (vec_len (sp1->segments_lists) == 1)
2059 vnet_buffer (b1)->ip.adj_index[VLIB_TX] = sp1->segments_lists[1];
2060 else
2061 {
Jakub Horn91f4a972021-01-21 12:14:58 +00002062 vnet_buffer (b1)->ip.flow_hash = flow_label1;
Pablo Camarillofb380952016-12-07 18:34:18 +01002063 vnet_buffer (b1)->ip.adj_index[VLIB_TX] =
2064 sp1->segments_lists[(vnet_buffer (b1)->ip.flow_hash &
2065 (vec_len (sp1->segments_lists) - 1))];
2066 }
2067
2068 if (vec_len (sp2->segments_lists) == 1)
2069 vnet_buffer (b2)->ip.adj_index[VLIB_TX] = sp2->segments_lists[2];
2070 else
2071 {
Jakub Horn91f4a972021-01-21 12:14:58 +00002072 vnet_buffer (b2)->ip.flow_hash = flow_label2;
Pablo Camarillofb380952016-12-07 18:34:18 +01002073 vnet_buffer (b2)->ip.adj_index[VLIB_TX] =
2074 sp2->segments_lists[(vnet_buffer (b2)->ip.flow_hash &
2075 (vec_len (sp2->segments_lists) - 1))];
2076 }
2077
2078 if (vec_len (sp3->segments_lists) == 1)
2079 vnet_buffer (b3)->ip.adj_index[VLIB_TX] = sp3->segments_lists[3];
2080 else
2081 {
Jakub Horn91f4a972021-01-21 12:14:58 +00002082 vnet_buffer (b3)->ip.flow_hash = flow_label3;
Pablo Camarillofb380952016-12-07 18:34:18 +01002083 vnet_buffer (b3)->ip.adj_index[VLIB_TX] =
2084 sp3->segments_lists[(vnet_buffer (b3)->ip.flow_hash &
2085 (vec_len (sp3->segments_lists) - 1))];
2086 }
2087
2088 sl0 =
2089 pool_elt_at_index (sm->sid_lists,
2090 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2091 sl1 =
2092 pool_elt_at_index (sm->sid_lists,
2093 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2094 sl2 =
2095 pool_elt_at_index (sm->sid_lists,
2096 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2097 sl3 =
2098 pool_elt_at_index (sm->sid_lists,
2099 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2100
shwethabe146f132017-03-09 16:58:26 +00002101 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2102 vec_len (sl0->rewrite));
2103 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2104 vec_len (sl1->rewrite));
2105 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2106 vec_len (sl2->rewrite));
2107 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2108 vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002109
2110 en0 = vlib_buffer_get_current (b0);
2111 en1 = vlib_buffer_get_current (b1);
2112 en2 = vlib_buffer_get_current (b2);
2113 en3 = vlib_buffer_get_current (b3);
2114
Dave Barach178cf492018-11-13 16:34:13 -05002115 clib_memcpy_fast (((u8 *) en0) - vec_len (sl0->rewrite),
2116 sl0->rewrite, vec_len (sl0->rewrite));
2117 clib_memcpy_fast (((u8 *) en1) - vec_len (sl1->rewrite),
2118 sl1->rewrite, vec_len (sl1->rewrite));
2119 clib_memcpy_fast (((u8 *) en2) - vec_len (sl2->rewrite),
2120 sl2->rewrite, vec_len (sl2->rewrite));
2121 clib_memcpy_fast (((u8 *) en3) - vec_len (sl3->rewrite),
2122 sl3->rewrite, vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002123
2124 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2125 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2126 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2127 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2128
2129 ip0 = vlib_buffer_get_current (b0);
2130 ip1 = vlib_buffer_get_current (b1);
2131 ip2 = vlib_buffer_get_current (b2);
2132 ip3 = vlib_buffer_get_current (b3);
2133
2134 ip0->payload_length =
2135 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
2136 ip1->payload_length =
2137 clib_host_to_net_u16 (b1->current_length - sizeof (ip6_header_t));
2138 ip2->payload_length =
2139 clib_host_to_net_u16 (b2->current_length - sizeof (ip6_header_t));
2140 ip3->payload_length =
2141 clib_host_to_net_u16 (b3->current_length - sizeof (ip6_header_t));
2142
Pablo Camarillod327c872018-01-08 14:25:55 +01002143 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
2144 {
2145 sr0 = (void *) (ip0 + 1);
pcamaril30e76712020-02-04 08:36:51 +01002146 sr0->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01002147 }
2148 else
pcamaril30e76712020-02-04 08:36:51 +01002149 ip0->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillofb380952016-12-07 18:34:18 +01002150
Pablo Camarillod327c872018-01-08 14:25:55 +01002151 if (ip1->protocol == IP_PROTOCOL_IPV6_ROUTE)
2152 {
2153 sr1 = (void *) (ip1 + 1);
pcamaril30e76712020-02-04 08:36:51 +01002154 sr1->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01002155 }
2156 else
pcamaril30e76712020-02-04 08:36:51 +01002157 ip1->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01002158
2159 if (ip2->protocol == IP_PROTOCOL_IPV6_ROUTE)
2160 {
2161 sr2 = (void *) (ip2 + 1);
pcamaril30e76712020-02-04 08:36:51 +01002162 sr2->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01002163 }
2164 else
pcamaril30e76712020-02-04 08:36:51 +01002165 ip2->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01002166
2167 if (ip3->protocol == IP_PROTOCOL_IPV6_ROUTE)
2168 {
2169 sr3 = (void *) (ip3 + 1);
pcamaril30e76712020-02-04 08:36:51 +01002170 sr3->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01002171 }
2172 else
pcamaril30e76712020-02-04 08:36:51 +01002173 ip3->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillofb380952016-12-07 18:34:18 +01002174
Jakub Horn91f4a972021-01-21 12:14:58 +00002175 /* TC is set to 0 for all ethernet frames, should be taken from COS
2176 * od DSCP of encapsulated packet in the future */
2177 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2178 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label0 & 0xffff));
2179 ip1->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2180 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label1 & 0xffff));
2181 ip2->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2182 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label2 & 0xffff));
2183 ip3->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2184 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label3 & 0xffff));
Pablo Camarillofb380952016-12-07 18:34:18 +01002185
2186 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2187 {
2188 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2189 {
2190 sr_policy_rewrite_trace_t *tr =
2191 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002192 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2193 sizeof (tr->src.as_u8));
2194 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2195 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002196 }
2197
2198 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2199 {
2200 sr_policy_rewrite_trace_t *tr =
2201 vlib_add_trace (vm, node, b1, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002202 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2203 sizeof (tr->src.as_u8));
2204 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2205 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002206 }
2207
2208 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2209 {
2210 sr_policy_rewrite_trace_t *tr =
2211 vlib_add_trace (vm, node, b2, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002212 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2213 sizeof (tr->src.as_u8));
2214 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2215 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002216 }
2217
2218 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2219 {
2220 sr_policy_rewrite_trace_t *tr =
2221 vlib_add_trace (vm, node, b3, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002222 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2223 sizeof (tr->src.as_u8));
2224 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2225 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002226 }
2227 }
2228
2229 encap_pkts += 4;
2230 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2231 n_left_to_next, bi0, bi1, bi2, bi3,
2232 next0, next1, next2, next3);
2233 }
2234
2235 /* Single loop for potentially the last three packets */
2236 while (n_left_from > 0 && n_left_to_next > 0)
2237 {
2238 u32 bi0;
2239 vlib_buffer_t *b0;
2240 ip6_header_t *ip0 = 0;
2241 ip6_sr_header_t *sr0;
2242 ethernet_header_t *en0;
2243 ip6_sr_policy_t *sp0;
2244 ip6_sr_sl_t *sl0;
2245 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
Jakub Horn91f4a972021-01-21 12:14:58 +00002246 u32 flow_label0;
Pablo Camarillofb380952016-12-07 18:34:18 +01002247
2248 bi0 = from[0];
2249 to_next[0] = bi0;
2250 from += 1;
2251 to_next += 1;
2252 n_left_from -= 1;
2253 n_left_to_next -= 1;
2254 b0 = vlib_get_buffer (vm, bi0);
2255
2256 /* Find the SR policy */
2257 sp0 = pool_elt_at_index (sm->sr_policies,
2258 sm->sw_iface_sr_policies[vnet_buffer
2259 (b0)->sw_if_index
2260 [VLIB_RX]]);
Jakub Horn91f4a972021-01-21 12:14:58 +00002261 flow_label0 = l2_flow_hash (b0);
Pablo Camarillofb380952016-12-07 18:34:18 +01002262
2263 /* In case there is more than one SL, LB among them */
2264 if (vec_len (sp0->segments_lists) == 1)
2265 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
2266 else
2267 {
Jakub Horn91f4a972021-01-21 12:14:58 +00002268 vnet_buffer (b0)->ip.flow_hash = flow_label0;
Pablo Camarillofb380952016-12-07 18:34:18 +01002269 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
2270 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
2271 (vec_len (sp0->segments_lists) - 1))];
2272 }
2273 sl0 =
2274 pool_elt_at_index (sm->sid_lists,
2275 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00002276 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2277 vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002278
2279 en0 = vlib_buffer_get_current (b0);
2280
Dave Barach178cf492018-11-13 16:34:13 -05002281 clib_memcpy_fast (((u8 *) en0) - vec_len (sl0->rewrite),
2282 sl0->rewrite, vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002283
2284 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2285
2286 ip0 = vlib_buffer_get_current (b0);
2287
2288 ip0->payload_length =
2289 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
2290
Pablo Camarillod327c872018-01-08 14:25:55 +01002291 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
2292 {
2293 sr0 = (void *) (ip0 + 1);
pcamaril30e76712020-02-04 08:36:51 +01002294 sr0->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01002295 }
2296 else
pcamaril30e76712020-02-04 08:36:51 +01002297 ip0->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillofb380952016-12-07 18:34:18 +01002298
Jakub Horn91f4a972021-01-21 12:14:58 +00002299 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2300 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label0 & 0xffff));
2301
Pablo Camarillofb380952016-12-07 18:34:18 +01002302 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2303 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2304 {
2305 sr_policy_rewrite_trace_t *tr =
2306 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002307 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2308 sizeof (tr->src.as_u8));
2309 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2310 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002311 }
2312
2313 encap_pkts++;
2314 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2315 n_left_to_next, bi0, next0);
2316 }
2317
2318 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2319 }
2320
2321 /* Update counters */
2322 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
2323 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2324 encap_pkts);
2325 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
2326 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2327 bsid_pkts);
2328
2329 return from_frame->n_vectors;
2330}
2331
2332/* *INDENT-OFF* */
2333VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_l2_node) = {
2334 .function = sr_policy_rewrite_encaps_l2,
2335 .name = "sr-pl-rewrite-encaps-l2",
2336 .vector_size = sizeof (u32),
2337 .format_trace = format_sr_policy_rewrite_trace,
2338 .type = VLIB_NODE_TYPE_INTERNAL,
2339 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2340 .error_strings = sr_policy_rewrite_error_strings,
2341 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2342 .next_nodes = {
2343#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2344 foreach_sr_policy_rewrite_next
2345#undef _
2346 },
2347};
2348/* *INDENT-ON* */
2349
2350/**
2351 * @brief Graph node for applying a SR policy into a packet. SRH insertion.
2352 */
2353static uword
2354sr_policy_rewrite_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2355 vlib_frame_t * from_frame)
2356{
2357 ip6_sr_main_t *sm = &sr_main;
2358 u32 n_left_from, next_index, *from, *to_next;
2359
2360 from = vlib_frame_vector_args (from_frame);
2361 n_left_from = from_frame->n_vectors;
2362
2363 next_index = node->cached_next_index;
2364
2365 int insert_pkts = 0, bsid_pkts = 0;
2366
2367 while (n_left_from > 0)
2368 {
2369 u32 n_left_to_next;
2370
2371 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2372
2373 /* Quad - Loop */
2374 while (n_left_from >= 8 && n_left_to_next >= 4)
2375 {
2376 u32 bi0, bi1, bi2, bi3;
2377 vlib_buffer_t *b0, *b1, *b2, *b3;
2378 u32 next0, next1, next2, next3;
2379 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2380 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2381 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2382 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2383 u16 new_l0, new_l1, new_l2, new_l3;
2384
2385 /* Prefetch next iteration. */
2386 {
2387 vlib_buffer_t *p4, *p5, *p6, *p7;
2388
2389 p4 = vlib_get_buffer (vm, from[4]);
2390 p5 = vlib_get_buffer (vm, from[5]);
2391 p6 = vlib_get_buffer (vm, from[6]);
2392 p7 = vlib_get_buffer (vm, from[7]);
2393
2394 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2395 vlib_prefetch_buffer_header (p4, LOAD);
2396 vlib_prefetch_buffer_header (p5, LOAD);
2397 vlib_prefetch_buffer_header (p6, LOAD);
2398 vlib_prefetch_buffer_header (p7, LOAD);
2399
Damjan Marionaf7fb042021-07-15 11:54:41 +02002400 clib_prefetch_store (p4->data);
2401 clib_prefetch_store (p5->data);
2402 clib_prefetch_store (p6->data);
2403 clib_prefetch_store (p7->data);
Pablo Camarillofb380952016-12-07 18:34:18 +01002404 }
2405
2406 to_next[0] = bi0 = from[0];
2407 to_next[1] = bi1 = from[1];
2408 to_next[2] = bi2 = from[2];
2409 to_next[3] = bi3 = from[3];
2410 from += 4;
2411 to_next += 4;
2412 n_left_from -= 4;
2413 n_left_to_next -= 4;
2414
2415 b0 = vlib_get_buffer (vm, bi0);
2416 b1 = vlib_get_buffer (vm, bi1);
2417 b2 = vlib_get_buffer (vm, bi2);
2418 b3 = vlib_get_buffer (vm, bi3);
2419
2420 sl0 =
2421 pool_elt_at_index (sm->sid_lists,
2422 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2423 sl1 =
2424 pool_elt_at_index (sm->sid_lists,
2425 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2426 sl2 =
2427 pool_elt_at_index (sm->sid_lists,
2428 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2429 sl3 =
2430 pool_elt_at_index (sm->sid_lists,
2431 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00002432 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2433 vec_len (sl0->rewrite));
2434 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2435 vec_len (sl1->rewrite));
2436 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2437 vec_len (sl2->rewrite));
2438 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2439 vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002440
2441 ip0 = vlib_buffer_get_current (b0);
2442 ip1 = vlib_buffer_get_current (b1);
2443 ip2 = vlib_buffer_get_current (b2);
2444 ip3 = vlib_buffer_get_current (b3);
2445
2446 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2447 sr0 =
2448 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2449 ip6_ext_header_len (ip0 + 1));
2450 else
2451 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2452
2453 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2454 sr1 =
2455 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2456 ip6_ext_header_len (ip1 + 1));
2457 else
2458 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2459
2460 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2461 sr2 =
2462 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2463 ip6_ext_header_len (ip2 + 1));
2464 else
2465 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2466
2467 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2468 sr3 =
2469 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2470 ip6_ext_header_len (ip3 + 1));
2471 else
2472 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2473
Dave Barach178cf492018-11-13 16:34:13 -05002474 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2475 (void *) sr0 - (void *) ip0);
2476 clib_memcpy_fast ((u8 *) ip1 - vec_len (sl1->rewrite), (u8 *) ip1,
2477 (void *) sr1 - (void *) ip1);
2478 clib_memcpy_fast ((u8 *) ip2 - vec_len (sl2->rewrite), (u8 *) ip2,
2479 (void *) sr2 - (void *) ip2);
2480 clib_memcpy_fast ((u8 *) ip3 - vec_len (sl3->rewrite), (u8 *) ip3,
2481 (void *) sr3 - (void *) ip3);
Pablo Camarillofb380952016-12-07 18:34:18 +01002482
Dave Barach178cf492018-11-13 16:34:13 -05002483 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite)),
2484 sl0->rewrite, vec_len (sl0->rewrite));
2485 clib_memcpy_fast (((u8 *) sr1 - vec_len (sl1->rewrite)),
2486 sl1->rewrite, vec_len (sl1->rewrite));
2487 clib_memcpy_fast (((u8 *) sr2 - vec_len (sl2->rewrite)),
2488 sl2->rewrite, vec_len (sl2->rewrite));
2489 clib_memcpy_fast (((u8 *) sr3 - vec_len (sl3->rewrite)),
2490 sl3->rewrite, vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002491
2492 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2493 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2494 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2495 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2496
2497 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2498 ip1 = ((void *) ip1) - vec_len (sl1->rewrite);
2499 ip2 = ((void *) ip2) - vec_len (sl2->rewrite);
2500 ip3 = ((void *) ip3) - vec_len (sl3->rewrite);
2501
2502 ip0->hop_limit -= 1;
2503 ip1->hop_limit -= 1;
2504 ip2->hop_limit -= 1;
2505 ip3->hop_limit -= 1;
2506
2507 new_l0 =
2508 clib_net_to_host_u16 (ip0->payload_length) +
2509 vec_len (sl0->rewrite);
2510 new_l1 =
2511 clib_net_to_host_u16 (ip1->payload_length) +
2512 vec_len (sl1->rewrite);
2513 new_l2 =
2514 clib_net_to_host_u16 (ip2->payload_length) +
2515 vec_len (sl2->rewrite);
2516 new_l3 =
2517 clib_net_to_host_u16 (ip3->payload_length) +
2518 vec_len (sl3->rewrite);
2519
2520 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2521 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2522 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2523 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2524
2525 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2526 sr1 = ((void *) sr1) - vec_len (sl1->rewrite);
2527 sr2 = ((void *) sr2) - vec_len (sl2->rewrite);
2528 sr3 = ((void *) sr3) - vec_len (sl3->rewrite);
2529
2530 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2531 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2532 sr1->segments->as_u64[0] = ip1->dst_address.as_u64[0];
2533 sr1->segments->as_u64[1] = ip1->dst_address.as_u64[1];
2534 sr2->segments->as_u64[0] = ip2->dst_address.as_u64[0];
2535 sr2->segments->as_u64[1] = ip2->dst_address.as_u64[1];
2536 sr3->segments->as_u64[0] = ip3->dst_address.as_u64[0];
2537 sr3->segments->as_u64[1] = ip3->dst_address.as_u64[1];
2538
2539 ip0->dst_address.as_u64[0] =
2540 (sr0->segments + sr0->segments_left)->as_u64[0];
2541 ip0->dst_address.as_u64[1] =
2542 (sr0->segments + sr0->segments_left)->as_u64[1];
2543 ip1->dst_address.as_u64[0] =
2544 (sr1->segments + sr1->segments_left)->as_u64[0];
2545 ip1->dst_address.as_u64[1] =
2546 (sr1->segments + sr1->segments_left)->as_u64[1];
2547 ip2->dst_address.as_u64[0] =
2548 (sr2->segments + sr2->segments_left)->as_u64[0];
2549 ip2->dst_address.as_u64[1] =
2550 (sr2->segments + sr2->segments_left)->as_u64[1];
2551 ip3->dst_address.as_u64[0] =
2552 (sr3->segments + sr3->segments_left)->as_u64[0];
2553 ip3->dst_address.as_u64[1] =
2554 (sr3->segments + sr3->segments_left)->as_u64[1];
2555
2556 ip6_ext_header_t *ip_ext;
2557 if (ip0 + 1 == (void *) sr0)
2558 {
2559 sr0->protocol = ip0->protocol;
2560 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2561 }
2562 else
2563 {
2564 ip_ext = (void *) (ip0 + 1);
2565 sr0->protocol = ip_ext->next_hdr;
2566 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2567 }
2568
2569 if (ip1 + 1 == (void *) sr1)
2570 {
2571 sr1->protocol = ip1->protocol;
2572 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2573 }
2574 else
2575 {
2576 ip_ext = (void *) (ip2 + 1);
2577 sr2->protocol = ip_ext->next_hdr;
2578 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2579 }
2580
2581 if (ip2 + 1 == (void *) sr2)
2582 {
2583 sr2->protocol = ip2->protocol;
2584 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2585 }
2586 else
2587 {
2588 ip_ext = (void *) (ip2 + 1);
2589 sr2->protocol = ip_ext->next_hdr;
2590 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2591 }
2592
2593 if (ip3 + 1 == (void *) sr3)
2594 {
2595 sr3->protocol = ip3->protocol;
2596 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2597 }
2598 else
2599 {
2600 ip_ext = (void *) (ip3 + 1);
2601 sr3->protocol = ip_ext->next_hdr;
2602 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2603 }
2604
2605 insert_pkts += 4;
2606
2607 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2608 {
2609 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2610 {
2611 sr_policy_rewrite_trace_t *tr =
2612 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002613 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2614 sizeof (tr->src.as_u8));
2615 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2616 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002617 }
2618
2619 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2620 {
2621 sr_policy_rewrite_trace_t *tr =
2622 vlib_add_trace (vm, node, b1, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002623 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2624 sizeof (tr->src.as_u8));
2625 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2626 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002627 }
2628
2629 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2630 {
2631 sr_policy_rewrite_trace_t *tr =
2632 vlib_add_trace (vm, node, b2, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002633 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2634 sizeof (tr->src.as_u8));
2635 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2636 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002637 }
2638
2639 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2640 {
2641 sr_policy_rewrite_trace_t *tr =
2642 vlib_add_trace (vm, node, b3, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002643 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2644 sizeof (tr->src.as_u8));
2645 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2646 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002647 }
2648 }
2649
2650 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2651 n_left_to_next, bi0, bi1, bi2, bi3,
2652 next0, next1, next2, next3);
2653 }
2654
2655 /* Single loop for potentially the last three packets */
2656 while (n_left_from > 0 && n_left_to_next > 0)
2657 {
2658 u32 bi0;
2659 vlib_buffer_t *b0;
2660 ip6_header_t *ip0 = 0;
2661 ip6_sr_header_t *sr0 = 0;
2662 ip6_sr_sl_t *sl0;
2663 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2664 u16 new_l0 = 0;
2665
2666 bi0 = from[0];
2667 to_next[0] = bi0;
2668 from += 1;
2669 to_next += 1;
2670 n_left_from -= 1;
2671 n_left_to_next -= 1;
2672
2673 b0 = vlib_get_buffer (vm, bi0);
2674 sl0 =
2675 pool_elt_at_index (sm->sid_lists,
2676 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00002677 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2678 vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002679
2680 ip0 = vlib_buffer_get_current (b0);
2681
2682 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2683 sr0 =
2684 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2685 ip6_ext_header_len (ip0 + 1));
2686 else
2687 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2688
Dave Barach178cf492018-11-13 16:34:13 -05002689 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2690 (void *) sr0 - (void *) ip0);
2691 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite)),
2692 sl0->rewrite, vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002693
2694 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2695
2696 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2697 ip0->hop_limit -= 1;
2698 new_l0 =
2699 clib_net_to_host_u16 (ip0->payload_length) +
2700 vec_len (sl0->rewrite);
2701 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2702
2703 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2704 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2705 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2706
2707 ip0->dst_address.as_u64[0] =
2708 (sr0->segments + sr0->segments_left)->as_u64[0];
2709 ip0->dst_address.as_u64[1] =
2710 (sr0->segments + sr0->segments_left)->as_u64[1];
2711
2712 if (ip0 + 1 == (void *) sr0)
2713 {
2714 sr0->protocol = ip0->protocol;
2715 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2716 }
2717 else
2718 {
2719 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2720 sr0->protocol = ip_ext->next_hdr;
2721 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2722 }
2723
2724 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2725 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2726 {
2727 sr_policy_rewrite_trace_t *tr =
2728 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002729 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2730 sizeof (tr->src.as_u8));
2731 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2732 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002733 }
2734
2735 insert_pkts++;
2736
2737 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2738 n_left_to_next, bi0, next0);
2739 }
2740
2741 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2742 }
2743
2744 /* Update counters */
2745 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2746 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2747 insert_pkts);
2748 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2749 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2750 bsid_pkts);
2751 return from_frame->n_vectors;
2752}
2753
2754/* *INDENT-OFF* */
2755VLIB_REGISTER_NODE (sr_policy_rewrite_insert_node) = {
2756 .function = sr_policy_rewrite_insert,
2757 .name = "sr-pl-rewrite-insert",
2758 .vector_size = sizeof (u32),
2759 .format_trace = format_sr_policy_rewrite_trace,
2760 .type = VLIB_NODE_TYPE_INTERNAL,
2761 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2762 .error_strings = sr_policy_rewrite_error_strings,
2763 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2764 .next_nodes = {
2765#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2766 foreach_sr_policy_rewrite_next
2767#undef _
2768 },
2769};
2770/* *INDENT-ON* */
2771
2772/**
2773 * @brief Graph node for applying a SR policy into a packet. BSID - SRH insertion.
2774 */
2775static uword
2776sr_policy_rewrite_b_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2777 vlib_frame_t * from_frame)
2778{
2779 ip6_sr_main_t *sm = &sr_main;
2780 u32 n_left_from, next_index, *from, *to_next;
2781
2782 from = vlib_frame_vector_args (from_frame);
2783 n_left_from = from_frame->n_vectors;
2784
2785 next_index = node->cached_next_index;
2786
2787 int insert_pkts = 0, bsid_pkts = 0;
2788
2789 while (n_left_from > 0)
2790 {
2791 u32 n_left_to_next;
2792
2793 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2794
2795 /* Quad - Loop */
2796 while (n_left_from >= 8 && n_left_to_next >= 4)
2797 {
2798 u32 bi0, bi1, bi2, bi3;
2799 vlib_buffer_t *b0, *b1, *b2, *b3;
2800 u32 next0, next1, next2, next3;
2801 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2802 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2803 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2804 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2805 u16 new_l0, new_l1, new_l2, new_l3;
2806
2807 /* Prefetch next iteration. */
2808 {
2809 vlib_buffer_t *p4, *p5, *p6, *p7;
2810
2811 p4 = vlib_get_buffer (vm, from[4]);
2812 p5 = vlib_get_buffer (vm, from[5]);
2813 p6 = vlib_get_buffer (vm, from[6]);
2814 p7 = vlib_get_buffer (vm, from[7]);
2815
2816 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2817 vlib_prefetch_buffer_header (p4, LOAD);
2818 vlib_prefetch_buffer_header (p5, LOAD);
2819 vlib_prefetch_buffer_header (p6, LOAD);
2820 vlib_prefetch_buffer_header (p7, LOAD);
2821
Damjan Marionaf7fb042021-07-15 11:54:41 +02002822 clib_prefetch_store (p4->data);
2823 clib_prefetch_store (p5->data);
2824 clib_prefetch_store (p6->data);
2825 clib_prefetch_store (p7->data);
Pablo Camarillofb380952016-12-07 18:34:18 +01002826 }
2827
2828 to_next[0] = bi0 = from[0];
2829 to_next[1] = bi1 = from[1];
2830 to_next[2] = bi2 = from[2];
2831 to_next[3] = bi3 = from[3];
2832 from += 4;
2833 to_next += 4;
2834 n_left_from -= 4;
2835 n_left_to_next -= 4;
2836
2837 b0 = vlib_get_buffer (vm, bi0);
2838 b1 = vlib_get_buffer (vm, bi1);
2839 b2 = vlib_get_buffer (vm, bi2);
2840 b3 = vlib_get_buffer (vm, bi3);
2841
2842 sl0 =
2843 pool_elt_at_index (sm->sid_lists,
2844 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2845 sl1 =
2846 pool_elt_at_index (sm->sid_lists,
2847 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2848 sl2 =
2849 pool_elt_at_index (sm->sid_lists,
2850 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2851 sl3 =
2852 pool_elt_at_index (sm->sid_lists,
2853 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00002854 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2855 vec_len (sl0->rewrite_bsid));
2856 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2857 vec_len (sl1->rewrite_bsid));
2858 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2859 vec_len (sl2->rewrite_bsid));
2860 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2861 vec_len (sl3->rewrite_bsid));
Pablo Camarillofb380952016-12-07 18:34:18 +01002862
2863 ip0 = vlib_buffer_get_current (b0);
2864 ip1 = vlib_buffer_get_current (b1);
2865 ip2 = vlib_buffer_get_current (b2);
2866 ip3 = vlib_buffer_get_current (b3);
2867
2868 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2869 sr0 =
2870 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2871 ip6_ext_header_len (ip0 + 1));
2872 else
2873 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2874
2875 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2876 sr1 =
2877 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2878 ip6_ext_header_len (ip1 + 1));
2879 else
2880 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2881
2882 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2883 sr2 =
2884 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2885 ip6_ext_header_len (ip2 + 1));
2886 else
2887 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2888
2889 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2890 sr3 =
2891 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2892 ip6_ext_header_len (ip3 + 1));
2893 else
2894 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2895
Dave Barach178cf492018-11-13 16:34:13 -05002896 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite_bsid),
2897 (u8 *) ip0, (void *) sr0 - (void *) ip0);
2898 clib_memcpy_fast ((u8 *) ip1 - vec_len (sl1->rewrite_bsid),
2899 (u8 *) ip1, (void *) sr1 - (void *) ip1);
2900 clib_memcpy_fast ((u8 *) ip2 - vec_len (sl2->rewrite_bsid),
2901 (u8 *) ip2, (void *) sr2 - (void *) ip2);
2902 clib_memcpy_fast ((u8 *) ip3 - vec_len (sl3->rewrite_bsid),
2903 (u8 *) ip3, (void *) sr3 - (void *) ip3);
Pablo Camarillofb380952016-12-07 18:34:18 +01002904
Dave Barach178cf492018-11-13 16:34:13 -05002905 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2906 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2907 clib_memcpy_fast (((u8 *) sr1 - vec_len (sl1->rewrite_bsid)),
2908 sl1->rewrite_bsid, vec_len (sl1->rewrite_bsid));
2909 clib_memcpy_fast (((u8 *) sr2 - vec_len (sl2->rewrite_bsid)),
2910 sl2->rewrite_bsid, vec_len (sl2->rewrite_bsid));
2911 clib_memcpy_fast (((u8 *) sr3 - vec_len (sl3->rewrite_bsid)),
2912 sl3->rewrite_bsid, vec_len (sl3->rewrite_bsid));
Pablo Camarillofb380952016-12-07 18:34:18 +01002913
2914 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2915 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite_bsid));
2916 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite_bsid));
2917 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite_bsid));
2918
2919 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2920 ip1 = ((void *) ip1) - vec_len (sl1->rewrite_bsid);
2921 ip2 = ((void *) ip2) - vec_len (sl2->rewrite_bsid);
2922 ip3 = ((void *) ip3) - vec_len (sl3->rewrite_bsid);
2923
2924 ip0->hop_limit -= 1;
2925 ip1->hop_limit -= 1;
2926 ip2->hop_limit -= 1;
2927 ip3->hop_limit -= 1;
2928
2929 new_l0 =
2930 clib_net_to_host_u16 (ip0->payload_length) +
2931 vec_len (sl0->rewrite_bsid);
2932 new_l1 =
2933 clib_net_to_host_u16 (ip1->payload_length) +
2934 vec_len (sl1->rewrite_bsid);
2935 new_l2 =
2936 clib_net_to_host_u16 (ip2->payload_length) +
2937 vec_len (sl2->rewrite_bsid);
2938 new_l3 =
2939 clib_net_to_host_u16 (ip3->payload_length) +
2940 vec_len (sl3->rewrite_bsid);
2941
2942 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2943 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2944 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2945 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2946
2947 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2948 sr1 = ((void *) sr1) - vec_len (sl1->rewrite_bsid);
2949 sr2 = ((void *) sr2) - vec_len (sl2->rewrite_bsid);
2950 sr3 = ((void *) sr3) - vec_len (sl3->rewrite_bsid);
2951
2952 ip0->dst_address.as_u64[0] =
2953 (sr0->segments + sr0->segments_left)->as_u64[0];
2954 ip0->dst_address.as_u64[1] =
2955 (sr0->segments + sr0->segments_left)->as_u64[1];
2956 ip1->dst_address.as_u64[0] =
2957 (sr1->segments + sr1->segments_left)->as_u64[0];
2958 ip1->dst_address.as_u64[1] =
2959 (sr1->segments + sr1->segments_left)->as_u64[1];
2960 ip2->dst_address.as_u64[0] =
2961 (sr2->segments + sr2->segments_left)->as_u64[0];
2962 ip2->dst_address.as_u64[1] =
2963 (sr2->segments + sr2->segments_left)->as_u64[1];
2964 ip3->dst_address.as_u64[0] =
2965 (sr3->segments + sr3->segments_left)->as_u64[0];
2966 ip3->dst_address.as_u64[1] =
2967 (sr3->segments + sr3->segments_left)->as_u64[1];
2968
2969 ip6_ext_header_t *ip_ext;
2970 if (ip0 + 1 == (void *) sr0)
2971 {
2972 sr0->protocol = ip0->protocol;
2973 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2974 }
2975 else
2976 {
2977 ip_ext = (void *) (ip0 + 1);
2978 sr0->protocol = ip_ext->next_hdr;
2979 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2980 }
2981
2982 if (ip1 + 1 == (void *) sr1)
2983 {
2984 sr1->protocol = ip1->protocol;
2985 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2986 }
2987 else
2988 {
2989 ip_ext = (void *) (ip2 + 1);
2990 sr2->protocol = ip_ext->next_hdr;
2991 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2992 }
2993
2994 if (ip2 + 1 == (void *) sr2)
2995 {
2996 sr2->protocol = ip2->protocol;
2997 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2998 }
2999 else
3000 {
3001 ip_ext = (void *) (ip2 + 1);
3002 sr2->protocol = ip_ext->next_hdr;
3003 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
3004 }
3005
3006 if (ip3 + 1 == (void *) sr3)
3007 {
3008 sr3->protocol = ip3->protocol;
3009 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
3010 }
3011 else
3012 {
3013 ip_ext = (void *) (ip3 + 1);
3014 sr3->protocol = ip_ext->next_hdr;
3015 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
3016 }
3017
3018 insert_pkts += 4;
3019
3020 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
3021 {
3022 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3023 {
3024 sr_policy_rewrite_trace_t *tr =
3025 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003026 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3027 sizeof (tr->src.as_u8));
3028 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3029 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003030 }
3031
3032 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
3033 {
3034 sr_policy_rewrite_trace_t *tr =
3035 vlib_add_trace (vm, node, b1, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003036 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
3037 sizeof (tr->src.as_u8));
3038 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
3039 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003040 }
3041
3042 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
3043 {
3044 sr_policy_rewrite_trace_t *tr =
3045 vlib_add_trace (vm, node, b2, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003046 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
3047 sizeof (tr->src.as_u8));
3048 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
3049 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003050 }
3051
3052 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
3053 {
3054 sr_policy_rewrite_trace_t *tr =
3055 vlib_add_trace (vm, node, b3, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003056 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
3057 sizeof (tr->src.as_u8));
3058 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
3059 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003060 }
3061 }
3062
3063 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
3064 n_left_to_next, bi0, bi1, bi2, bi3,
3065 next0, next1, next2, next3);
3066 }
3067
3068 /* Single loop for potentially the last three packets */
3069 while (n_left_from > 0 && n_left_to_next > 0)
3070 {
3071 u32 bi0;
3072 vlib_buffer_t *b0;
3073 ip6_header_t *ip0 = 0;
3074 ip6_sr_header_t *sr0 = 0;
3075 ip6_sr_sl_t *sl0;
3076 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3077 u16 new_l0 = 0;
3078
3079 bi0 = from[0];
3080 to_next[0] = bi0;
3081 from += 1;
3082 to_next += 1;
3083 n_left_from -= 1;
3084 n_left_to_next -= 1;
3085
3086 b0 = vlib_get_buffer (vm, bi0);
3087 sl0 =
3088 pool_elt_at_index (sm->sid_lists,
3089 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00003090 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3091 vec_len (sl0->rewrite_bsid));
Pablo Camarillofb380952016-12-07 18:34:18 +01003092
3093 ip0 = vlib_buffer_get_current (b0);
3094
3095 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
3096 sr0 =
3097 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
3098 ip6_ext_header_len (ip0 + 1));
3099 else
3100 sr0 = (ip6_sr_header_t *) (ip0 + 1);
3101
Dave Barach178cf492018-11-13 16:34:13 -05003102 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite_bsid),
3103 (u8 *) ip0, (void *) sr0 - (void *) ip0);
3104 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
3105 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
Pablo Camarillofb380952016-12-07 18:34:18 +01003106
3107 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
3108
3109 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
3110 ip0->hop_limit -= 1;
3111 new_l0 =
3112 clib_net_to_host_u16 (ip0->payload_length) +
3113 vec_len (sl0->rewrite_bsid);
3114 ip0->payload_length = clib_host_to_net_u16 (new_l0);
3115
3116 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
3117
3118 ip0->dst_address.as_u64[0] =
3119 (sr0->segments + sr0->segments_left)->as_u64[0];
3120 ip0->dst_address.as_u64[1] =
3121 (sr0->segments + sr0->segments_left)->as_u64[1];
3122
3123 if (ip0 + 1 == (void *) sr0)
3124 {
3125 sr0->protocol = ip0->protocol;
3126 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
3127 }
3128 else
3129 {
3130 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
3131 sr0->protocol = ip_ext->next_hdr;
3132 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
3133 }
3134
3135 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3136 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3137 {
3138 sr_policy_rewrite_trace_t *tr =
3139 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003140 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3141 sizeof (tr->src.as_u8));
3142 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3143 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003144 }
3145
3146 insert_pkts++;
3147
3148 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3149 n_left_to_next, bi0, next0);
3150 }
3151
3152 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3153 }
3154
3155 /* Update counters */
3156 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
3157 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3158 insert_pkts);
3159 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
3160 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3161 bsid_pkts);
3162 return from_frame->n_vectors;
3163}
3164
3165/* *INDENT-OFF* */
3166VLIB_REGISTER_NODE (sr_policy_rewrite_b_insert_node) = {
3167 .function = sr_policy_rewrite_b_insert,
3168 .name = "sr-pl-rewrite-b-insert",
3169 .vector_size = sizeof (u32),
3170 .format_trace = format_sr_policy_rewrite_trace,
3171 .type = VLIB_NODE_TYPE_INTERNAL,
3172 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3173 .error_strings = sr_policy_rewrite_error_strings,
3174 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3175 .next_nodes = {
3176#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3177 foreach_sr_policy_rewrite_next
3178#undef _
3179 },
3180};
3181/* *INDENT-ON* */
3182
3183/**
3184 * @brief Function BSID encapsulation
3185 */
3186static_always_inline void
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +00003187end_bsid_encaps_srh_processing (vlib_node_runtime_t *node, vlib_buffer_t *b0,
3188 ip6_header_t *ip0, ip6_sr_header_t *sr0,
3189 u32 *next0, u8 policy_type)
Pablo Camarillofb380952016-12-07 18:34:18 +01003190{
3191 ip6_address_t *new_dst0;
3192
3193 if (PREDICT_FALSE (!sr0))
3194 goto error_bsid_encaps;
3195
3196 if (PREDICT_TRUE (sr0->type == ROUTING_HEADER_TYPE_SR))
3197 {
3198 if (PREDICT_TRUE (sr0->segments_left != 0))
3199 {
3200 sr0->segments_left -= 1;
3201 new_dst0 = (ip6_address_t *) (sr0->segments);
3202 new_dst0 += sr0->segments_left;
3203 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
3204 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
3205 return;
3206 }
Ahmed Abdelsalam9cca6942022-06-06 15:54:02 +00003207 else if (sr0->segments_left == 0 && policy_type == SR_POLICY_TYPE_TEF)
3208 return;
Pablo Camarillofb380952016-12-07 18:34:18 +01003209 }
3210
3211error_bsid_encaps:
3212 *next0 = SR_POLICY_REWRITE_NEXT_ERROR;
3213 b0->error = node->errors[SR_POLICY_REWRITE_ERROR_BSID_ZERO];
3214}
3215
3216/**
3217 * @brief Graph node for applying a SR policy BSID - Encapsulation
3218 */
3219static uword
3220sr_policy_rewrite_b_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
3221 vlib_frame_t * from_frame)
3222{
3223 ip6_sr_main_t *sm = &sr_main;
3224 u32 n_left_from, next_index, *from, *to_next;
3225
3226 from = vlib_frame_vector_args (from_frame);
3227 n_left_from = from_frame->n_vectors;
3228
3229 next_index = node->cached_next_index;
3230
3231 int encap_pkts = 0, bsid_pkts = 0;
3232
3233 while (n_left_from > 0)
3234 {
3235 u32 n_left_to_next;
3236
3237 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
3238
3239 /* Quad - Loop */
3240 while (n_left_from >= 8 && n_left_to_next >= 4)
3241 {
3242 u32 bi0, bi1, bi2, bi3;
3243 vlib_buffer_t *b0, *b1, *b2, *b3;
3244 u32 next0, next1, next2, next3;
3245 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3246 ip6_header_t *ip0, *ip1, *ip2, *ip3;
3247 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
3248 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
Pablo Camarillofb380952016-12-07 18:34:18 +01003249 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
3250
3251 /* Prefetch next iteration. */
3252 {
3253 vlib_buffer_t *p4, *p5, *p6, *p7;
3254
3255 p4 = vlib_get_buffer (vm, from[4]);
3256 p5 = vlib_get_buffer (vm, from[5]);
3257 p6 = vlib_get_buffer (vm, from[6]);
3258 p7 = vlib_get_buffer (vm, from[7]);
3259
3260 /* Prefetch the buffer header and packet for the N+2 loop iteration */
3261 vlib_prefetch_buffer_header (p4, LOAD);
3262 vlib_prefetch_buffer_header (p5, LOAD);
3263 vlib_prefetch_buffer_header (p6, LOAD);
3264 vlib_prefetch_buffer_header (p7, LOAD);
3265
Damjan Marionaf7fb042021-07-15 11:54:41 +02003266 clib_prefetch_store (p4->data);
3267 clib_prefetch_store (p5->data);
3268 clib_prefetch_store (p6->data);
3269 clib_prefetch_store (p7->data);
Pablo Camarillofb380952016-12-07 18:34:18 +01003270 }
3271
3272 to_next[0] = bi0 = from[0];
3273 to_next[1] = bi1 = from[1];
3274 to_next[2] = bi2 = from[2];
3275 to_next[3] = bi3 = from[3];
3276 from += 4;
3277 to_next += 4;
3278 n_left_from -= 4;
3279 n_left_to_next -= 4;
3280
3281 b0 = vlib_get_buffer (vm, bi0);
3282 b1 = vlib_get_buffer (vm, bi1);
3283 b2 = vlib_get_buffer (vm, bi2);
3284 b3 = vlib_get_buffer (vm, bi3);
3285
3286 sl0 =
3287 pool_elt_at_index (sm->sid_lists,
3288 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3289 sl1 =
3290 pool_elt_at_index (sm->sid_lists,
3291 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
3292 sl2 =
3293 pool_elt_at_index (sm->sid_lists,
3294 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
3295 sl3 =
3296 pool_elt_at_index (sm->sid_lists,
3297 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00003298 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3299 vec_len (sl0->rewrite));
3300 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3301 vec_len (sl1->rewrite));
3302 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3303 vec_len (sl2->rewrite));
3304 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3305 vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01003306
3307 ip0_encap = vlib_buffer_get_current (b0);
3308 ip1_encap = vlib_buffer_get_current (b1);
3309 ip2_encap = vlib_buffer_get_current (b2);
3310 ip3_encap = vlib_buffer_get_current (b3);
3311
Klement Sekera769145c2019-03-06 11:59:57 +01003312 sr0 =
3313 ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
3314 NULL);
3315 sr1 =
3316 ip6_ext_header_find (vm, b1, ip1_encap, IP_PROTOCOL_IPV6_ROUTE,
3317 NULL);
3318 sr2 =
3319 ip6_ext_header_find (vm, b2, ip2_encap, IP_PROTOCOL_IPV6_ROUTE,
3320 NULL);
3321 sr3 =
3322 ip6_ext_header_find (vm, b3, ip3_encap, IP_PROTOCOL_IPV6_ROUTE,
3323 NULL);
Pablo Camarillofb380952016-12-07 18:34:18 +01003324
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +00003325 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0,
3326 sl0->policy_type);
3327 end_bsid_encaps_srh_processing (node, b1, ip1_encap, sr1, &next1,
3328 sl1->policy_type);
3329 end_bsid_encaps_srh_processing (node, b2, ip2_encap, sr2, &next2,
3330 sl2->policy_type);
3331 end_bsid_encaps_srh_processing (node, b3, ip3_encap, sr3, &next3,
3332 sl3->policy_type);
Pablo Camarillofb380952016-12-07 18:34:18 +01003333
Dave Barach178cf492018-11-13 16:34:13 -05003334 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3335 sl0->rewrite, vec_len (sl0->rewrite));
3336 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
3337 sl1->rewrite, vec_len (sl1->rewrite));
3338 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
3339 sl2->rewrite, vec_len (sl2->rewrite));
3340 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
3341 sl3->rewrite, vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01003342
3343 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3344 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
3345 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
3346 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
3347
3348 ip0 = vlib_buffer_get_current (b0);
3349 ip1 = vlib_buffer_get_current (b1);
3350 ip2 = vlib_buffer_get_current (b2);
3351 ip3 = vlib_buffer_get_current (b3);
3352
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +00003353 encaps_processing_v6 (node, b0, ip0, ip0_encap, sl0->policy_type);
3354 encaps_processing_v6 (node, b1, ip1, ip1_encap, sl1->policy_type);
3355 encaps_processing_v6 (node, b2, ip2, ip2_encap, sl2->policy_type);
3356 encaps_processing_v6 (node, b3, ip3, ip3_encap, sl3->policy_type);
Pablo Camarillofb380952016-12-07 18:34:18 +01003357
3358 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
3359 {
3360 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3361 {
3362 sr_policy_rewrite_trace_t *tr =
3363 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003364 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3365 sizeof (tr->src.as_u8));
3366 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3367 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003368 }
3369
3370 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
3371 {
3372 sr_policy_rewrite_trace_t *tr =
3373 vlib_add_trace (vm, node, b1, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003374 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
3375 sizeof (tr->src.as_u8));
3376 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
3377 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003378 }
3379
3380 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
3381 {
3382 sr_policy_rewrite_trace_t *tr =
3383 vlib_add_trace (vm, node, b2, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003384 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
3385 sizeof (tr->src.as_u8));
3386 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
3387 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003388 }
3389
3390 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
3391 {
3392 sr_policy_rewrite_trace_t *tr =
3393 vlib_add_trace (vm, node, b3, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003394 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
3395 sizeof (tr->src.as_u8));
3396 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
3397 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003398 }
3399 }
3400
3401 encap_pkts += 4;
3402 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
3403 n_left_to_next, bi0, bi1, bi2, bi3,
3404 next0, next1, next2, next3);
3405 }
3406
3407 /* Single loop for potentially the last three packets */
3408 while (n_left_from > 0 && n_left_to_next > 0)
3409 {
3410 u32 bi0;
3411 vlib_buffer_t *b0;
3412 ip6_header_t *ip0 = 0, *ip0_encap = 0;
Pablo Camarillofb380952016-12-07 18:34:18 +01003413 ip6_sr_header_t *sr0;
3414 ip6_sr_sl_t *sl0;
3415 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3416
3417 bi0 = from[0];
3418 to_next[0] = bi0;
3419 from += 1;
3420 to_next += 1;
3421 n_left_from -= 1;
3422 n_left_to_next -= 1;
3423 b0 = vlib_get_buffer (vm, bi0);
3424
3425 sl0 =
3426 pool_elt_at_index (sm->sid_lists,
3427 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00003428 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3429 vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01003430
3431 ip0_encap = vlib_buffer_get_current (b0);
Klement Sekera769145c2019-03-06 11:59:57 +01003432 sr0 =
3433 ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
3434 NULL);
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +00003435 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0,
3436 sl0->policy_type);
Pablo Camarillofb380952016-12-07 18:34:18 +01003437
Dave Barach178cf492018-11-13 16:34:13 -05003438 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3439 sl0->rewrite, vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01003440 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3441
3442 ip0 = vlib_buffer_get_current (b0);
3443
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +00003444 encaps_processing_v6 (node, b0, ip0, ip0_encap, sl0->policy_type);
Pablo Camarillofb380952016-12-07 18:34:18 +01003445
3446 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3447 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3448 {
3449 sr_policy_rewrite_trace_t *tr =
3450 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003451 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3452 sizeof (tr->src.as_u8));
3453 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3454 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003455 }
3456
3457 encap_pkts++;
3458 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3459 n_left_to_next, bi0, next0);
3460 }
3461
3462 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3463 }
3464
3465 /* Update counters */
3466 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3467 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3468 encap_pkts);
3469 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3470 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3471 bsid_pkts);
3472
3473 return from_frame->n_vectors;
3474}
3475
3476/* *INDENT-OFF* */
3477VLIB_REGISTER_NODE (sr_policy_rewrite_b_encaps_node) = {
3478 .function = sr_policy_rewrite_b_encaps,
3479 .name = "sr-pl-rewrite-b-encaps",
3480 .vector_size = sizeof (u32),
3481 .format_trace = format_sr_policy_rewrite_trace,
3482 .type = VLIB_NODE_TYPE_INTERNAL,
3483 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3484 .error_strings = sr_policy_rewrite_error_strings,
3485 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3486 .next_nodes = {
3487#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3488 foreach_sr_policy_rewrite_next
3489#undef _
3490 },
3491};
3492/* *INDENT-ON* */
3493
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -08003494/*************************** SR Policy plugins ******************************/
3495/**
3496 * @brief SR Policy plugin registry
3497 */
3498int
3499sr_policy_register_function (vlib_main_t * vm, u8 * fn_name,
3500 u8 * keyword_str, u8 * def_str,
3501 u8 * params_str, u8 prefix_length,
3502 dpo_type_t * dpo,
3503 format_function_t * ls_format,
3504 unformat_function_t * ls_unformat,
3505 sr_p_plugin_callback_t * creation_fn,
3506 sr_p_plugin_callback_t * removal_fn)
3507{
3508 ip6_sr_main_t *sm = &sr_main;
3509 uword *p;
3510
3511 sr_policy_fn_registration_t *plugin;
3512
3513 /* Did this function exist? If so update it */
3514 p = hash_get_mem (sm->policy_plugin_functions_by_key, fn_name);
3515 if (p)
3516 {
3517 plugin = pool_elt_at_index (sm->policy_plugin_functions, p[0]);
3518 }
3519 /* Else create a new one and set hash key */
3520 else
3521 {
3522 pool_get (sm->policy_plugin_functions, plugin);
3523 hash_set_mem (sm->policy_plugin_functions_by_key, fn_name,
3524 plugin - sm->policy_plugin_functions);
3525 }
3526
3527 clib_memset (plugin, 0, sizeof (*plugin));
3528
3529 plugin->sr_policy_function_number = (plugin - sm->policy_plugin_functions);
3530 plugin->sr_policy_function_number += SR_BEHAVIOR_LAST;
3531 plugin->prefix_length = prefix_length;
3532 plugin->ls_format = ls_format;
3533 plugin->ls_unformat = ls_unformat;
3534 plugin->creation = creation_fn;
3535 plugin->removal = removal_fn;
3536 clib_memcpy (&plugin->dpo, dpo, sizeof (dpo_type_t));
3537 plugin->function_name = format (0, "%s%c", fn_name, 0);
3538 plugin->keyword_str = format (0, "%s%c", keyword_str, 0);
3539 plugin->def_str = format (0, "%s%c", def_str, 0);
3540 plugin->params_str = format (0, "%s%c", params_str, 0);
3541
3542 return plugin->sr_policy_function_number;
3543}
3544
3545/**
3546 * @brief CLI function to 'show' all available SR LocalSID behaviors
3547 */
3548static clib_error_t *
3549show_sr_policy_behaviors_command_fn (vlib_main_t * vm,
3550 unformat_input_t * input,
3551 vlib_cli_command_t * cmd)
3552{
3553 ip6_sr_main_t *sm = &sr_main;
3554 sr_policy_fn_registration_t *plugin;
3555 sr_policy_fn_registration_t **plugins_vec = 0;
3556 int i;
3557
3558 vlib_cli_output (vm, "SR Policy behaviors:\n-----------------------\n\n");
3559
3560 /* *INDENT-OFF* */
Damjan Marionb2c31b62020-12-13 21:47:40 +01003561 pool_foreach (plugin, sm->policy_plugin_functions)
3562 { vec_add1 (plugins_vec, plugin); }
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -08003563 /* *INDENT-ON* */
3564
3565 vlib_cli_output (vm, "Plugin behaviors:\n");
3566 for (i = 0; i < vec_len (plugins_vec); i++)
3567 {
3568 plugin = plugins_vec[i];
3569 vlib_cli_output (vm, "\t%s\t-> %s.\n", plugin->keyword_str,
3570 plugin->def_str);
3571 vlib_cli_output (vm, "\t\tParameters: '%s'\n", plugin->params_str);
3572 }
3573 return 0;
3574}
3575
3576/* *INDENT-OFF* */
3577VLIB_CLI_COMMAND (show_sr_policy_behaviors_command, static) = {
3578 .path = "show sr policy behaviors",
3579 .short_help = "show sr policy behaviors",
3580 .function = show_sr_policy_behaviors_command_fn,
3581};
3582/* *INDENT-ON* */
3583
Pablo Camarillofb380952016-12-07 18:34:18 +01003584/*************************** SR Segment Lists DPOs ****************************/
3585static u8 *
3586format_sr_segment_list_dpo (u8 * s, va_list * args)
3587{
3588 ip6_sr_main_t *sm = &sr_main;
3589 ip6_address_t *addr;
3590 ip6_sr_sl_t *sl;
3591
3592 index_t index = va_arg (*args, index_t);
3593 CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
3594 s = format (s, "SR: Segment List index:[%d]", index);
3595 s = format (s, "\n\tSegments:");
3596
3597 sl = pool_elt_at_index (sm->sid_lists, index);
3598
3599 s = format (s, "< ");
3600 vec_foreach (addr, sl->segments)
3601 {
3602 s = format (s, "%U, ", format_ip6_address, addr);
3603 }
3604 s = format (s, "\b\b > - ");
3605 s = format (s, "Weight: %u", sl->weight);
3606
3607 return s;
3608}
3609
3610const static dpo_vft_t sr_policy_rewrite_vft = {
3611 .dv_lock = sr_dpo_lock,
3612 .dv_unlock = sr_dpo_unlock,
3613 .dv_format = format_sr_segment_list_dpo,
3614};
3615
3616const static char *const sr_pr_encaps_ip6_nodes[] = {
3617 "sr-pl-rewrite-encaps",
3618 NULL,
3619};
3620
3621const static char *const sr_pr_encaps_ip4_nodes[] = {
3622 "sr-pl-rewrite-encaps-v4",
3623 NULL,
3624};
3625
3626const static char *const *const sr_pr_encaps_nodes[DPO_PROTO_NUM] = {
3627 [DPO_PROTO_IP6] = sr_pr_encaps_ip6_nodes,
3628 [DPO_PROTO_IP4] = sr_pr_encaps_ip4_nodes,
3629};
3630
3631const static char *const sr_pr_insert_ip6_nodes[] = {
3632 "sr-pl-rewrite-insert",
3633 NULL,
3634};
3635
3636const static char *const *const sr_pr_insert_nodes[DPO_PROTO_NUM] = {
3637 [DPO_PROTO_IP6] = sr_pr_insert_ip6_nodes,
3638};
3639
3640const static char *const sr_pr_bsid_insert_ip6_nodes[] = {
3641 "sr-pl-rewrite-b-insert",
3642 NULL,
3643};
3644
3645const static char *const *const sr_pr_bsid_insert_nodes[DPO_PROTO_NUM] = {
3646 [DPO_PROTO_IP6] = sr_pr_bsid_insert_ip6_nodes,
3647};
3648
3649const static char *const sr_pr_bsid_encaps_ip6_nodes[] = {
3650 "sr-pl-rewrite-b-encaps",
3651 NULL,
3652};
3653
3654const static char *const *const sr_pr_bsid_encaps_nodes[DPO_PROTO_NUM] = {
3655 [DPO_PROTO_IP6] = sr_pr_bsid_encaps_ip6_nodes,
3656};
3657
3658/********************* SR Policy Rewrite initialization ***********************/
3659/**
3660 * @brief SR Policy Rewrite initialization
3661 */
3662clib_error_t *
3663sr_policy_rewrite_init (vlib_main_t * vm)
3664{
3665 ip6_sr_main_t *sm = &sr_main;
3666
3667 /* Init memory for sr policy keys (bsid <-> ip6_address_t) */
Pablo Camarillo4521afa2017-03-16 10:43:05 +01003668 mhash_init (&sm->sr_policies_index_hash, sizeof (uword),
3669 sizeof (ip6_address_t));
Pablo Camarillofb380952016-12-07 18:34:18 +01003670
3671 /* Init SR VPO DPOs type */
3672 sr_pr_encaps_dpo_type =
3673 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_encaps_nodes);
3674
3675 sr_pr_insert_dpo_type =
3676 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_insert_nodes);
3677
3678 sr_pr_bsid_encaps_dpo_type =
3679 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_encaps_nodes);
3680
3681 sr_pr_bsid_insert_dpo_type =
3682 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_insert_nodes);
3683
3684 /* Register the L2 encaps node used in HW redirect */
3685 sm->l2_sr_policy_rewrite_index = sr_policy_rewrite_encaps_node.index;
3686
3687 sm->fib_table_ip6 = (u32) ~ 0;
3688 sm->fib_table_ip4 = (u32) ~ 0;
3689
3690 return 0;
3691}
3692
3693VLIB_INIT_FUNCTION (sr_policy_rewrite_init);
3694
3695
3696/*
3697* fd.io coding-style-patch-verification: ON
3698*
3699* Local Variables:
3700* eval: (c-set-style "gnu")
3701* End:
3702*/