blob: 0134f3c083b7a7af9d08c59a784d2d2e94bfc438 [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>
50
51#include <vppinfra/error.h>
52#include <vppinfra/elog.h>
53
54/**
55 * @brief SR policy rewrite trace
56 */
57typedef struct
58{
59 ip6_address_t src, dst;
60} sr_policy_rewrite_trace_t;
61
62/* Graph arcs */
63#define foreach_sr_policy_rewrite_next \
64_(IP6_LOOKUP, "ip6-lookup") \
65_(ERROR, "error-drop")
66
67typedef enum
68{
69#define _(s,n) SR_POLICY_REWRITE_NEXT_##s,
70 foreach_sr_policy_rewrite_next
71#undef _
72 SR_POLICY_REWRITE_N_NEXT,
73} sr_policy_rewrite_next_t;
74
75/* SR rewrite errors */
76#define foreach_sr_policy_rewrite_error \
77_(INTERNAL_ERROR, "Segment Routing undefined error") \
78_(BSID_ZERO, "BSID with SL = 0") \
79_(COUNTER_TOTAL, "SR steered IPv6 packets") \
80_(COUNTER_ENCAP, "SR: Encaps packets") \
81_(COUNTER_INSERT, "SR: SRH inserted packets") \
82_(COUNTER_BSID, "SR: BindingSID steered packets")
83
84typedef enum
85{
86#define _(sym,str) SR_POLICY_REWRITE_ERROR_##sym,
87 foreach_sr_policy_rewrite_error
88#undef _
89 SR_POLICY_REWRITE_N_ERROR,
90} sr_policy_rewrite_error_t;
91
92static char *sr_policy_rewrite_error_strings[] = {
93#define _(sym,string) string,
94 foreach_sr_policy_rewrite_error
95#undef _
96};
97
98/**
99 * @brief Dynamically added SR SL DPO type
100 */
101static dpo_type_t sr_pr_encaps_dpo_type;
102static dpo_type_t sr_pr_insert_dpo_type;
103static dpo_type_t sr_pr_bsid_encaps_dpo_type;
104static dpo_type_t sr_pr_bsid_insert_dpo_type;
105
106/**
107 * @brief IPv6 SA for encapsulated packets
108 */
109static ip6_address_t sr_pr_encaps_src;
Ignas Bačiuseeb5fb32019-10-03 17:15:38 +0300110static u8 sr_pr_encaps_hop_limit = IPv6_DEFAULT_HOP_LIMIT;
Pablo Camarillofb380952016-12-07 18:34:18 +0100111
112/******************* SR rewrite set encaps IPv6 source addr *******************/
113/* Note: This is temporal. We don't know whether to follow this path or
114 take the ip address of a loopback interface or even the OIF */
115
Pablo Camarillo1a5e3012017-11-16 16:02:50 +0100116void
117sr_set_source (ip6_address_t * address)
118{
Dave Barach178cf492018-11-13 16:34:13 -0500119 clib_memcpy_fast (&sr_pr_encaps_src, address, sizeof (sr_pr_encaps_src));
Pablo Camarillo1a5e3012017-11-16 16:02:50 +0100120}
121
Ahmed Abdelsalam448bc812020-11-09 14:04:07 +0000122ip6_address_t *
123sr_get_encaps_source ()
124{
125 return &sr_pr_encaps_src;
126}
127
Pablo Camarillofb380952016-12-07 18:34:18 +0100128static clib_error_t *
129set_sr_src_command_fn (vlib_main_t * vm, unformat_input_t * input,
130 vlib_cli_command_t * cmd)
131{
132 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
133 {
134 if (unformat
135 (input, "addr %U", unformat_ip6_address, &sr_pr_encaps_src))
136 return 0;
137 else
138 return clib_error_return (0, "No address specified");
139 }
140 return clib_error_return (0, "No address specified");
141}
142
143/* *INDENT-OFF* */
144VLIB_CLI_COMMAND (set_sr_src_command, static) = {
145 .path = "set sr encaps source",
146 .short_help = "set sr encaps source addr <ip6_addr>",
147 .function = set_sr_src_command_fn,
148};
149/* *INDENT-ON* */
150
Ignas Bačiuseeb5fb32019-10-03 17:15:38 +0300151/******************** SR rewrite set encaps IPv6 hop-limit ********************/
152
153void
154sr_set_hop_limit (u8 hop_limit)
155{
156 sr_pr_encaps_hop_limit = hop_limit;
157}
158
159u8
160sr_get_hop_limit (void)
161{
162 return sr_pr_encaps_hop_limit;
163}
164
165static clib_error_t *
166set_sr_hop_limit_command_fn (vlib_main_t * vm, unformat_input_t * input,
167 vlib_cli_command_t * cmd)
168{
169 int hop_limit = sr_get_hop_limit ();
170
171 if (unformat_check_input (input) == UNFORMAT_END_OF_INPUT)
172 return clib_error_return (0, "No value specified");
173 if (!unformat (input, "%d", &hop_limit))
174 return clib_error_return (0, "Invalid value");
175 if (hop_limit <= 0 || hop_limit > 255)
176 return clib_error_return (0, "Value out of range [1-255]");
177 sr_pr_encaps_hop_limit = (u8) hop_limit;
178 return 0;
179}
180
181/* *INDENT-OFF* */
182VLIB_CLI_COMMAND (set_sr_hop_limit_command, static) = {
183 .path = "set sr encaps hop-limit",
184 .short_help = "set sr encaps hop-limit <value>",
185 .function = set_sr_hop_limit_command_fn,
186};
187/* *INDENT-ON* */
188
Pablo Camarillofb380952016-12-07 18:34:18 +0100189/*********************** SR rewrite string computation ************************/
190/**
191 * @brief SR rewrite string computation for IPv6 encapsulation (inline)
192 *
193 * @param sl is a vector of IPv6 addresses composing the Segment List
194 *
195 * @return precomputed rewrite string for encapsulation
196 */
197static inline u8 *
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +0000198compute_rewrite_encaps (ip6_address_t *sl, u8 type)
Pablo Camarillofb380952016-12-07 18:34:18 +0100199{
200 ip6_header_t *iph;
201 ip6_sr_header_t *srh;
Ahmed Abdelsalam9cca6942022-06-06 15:54:02 +0000202 ip6_sr_pt_tlv_t *srh_pt_tlv;
Pablo Camarillofb380952016-12-07 18:34:18 +0100203 ip6_address_t *addrp, *this_address;
204 u32 header_length = 0;
205 u8 *rs = NULL;
206
207 header_length = 0;
208 header_length += IPv6_DEFAULT_HEADER_LENGTH;
Ahmed Abdelsalam9cca6942022-06-06 15:54:02 +0000209 if (type == SR_POLICY_TYPE_TEF)
210 {
211 header_length += sizeof (ip6_sr_header_t);
212 header_length += vec_len (sl) * sizeof (ip6_address_t);
213 header_length += sizeof (ip6_sr_pt_tlv_t);
214 }
215 else if (vec_len (sl) > 1)
Pablo Camarillofb380952016-12-07 18:34:18 +0100216 {
217 header_length += sizeof (ip6_sr_header_t);
218 header_length += vec_len (sl) * sizeof (ip6_address_t);
219 }
220
221 vec_validate (rs, header_length - 1);
222
223 iph = (ip6_header_t *) rs;
224 iph->ip_version_traffic_class_and_flow_label =
225 clib_host_to_net_u32 (0 | ((6 & 0xF) << 28));
226 iph->src_address.as_u64[0] = sr_pr_encaps_src.as_u64[0];
227 iph->src_address.as_u64[1] = sr_pr_encaps_src.as_u64[1];
228 iph->payload_length = header_length - IPv6_DEFAULT_HEADER_LENGTH;
229 iph->protocol = IP_PROTOCOL_IPV6;
Ignas Bačiuseeb5fb32019-10-03 17:15:38 +0300230 iph->hop_limit = sr_pr_encaps_hop_limit;
Pablo Camarillofb380952016-12-07 18:34:18 +0100231
Ahmed Abdelsalam9cca6942022-06-06 15:54:02 +0000232 if (type == SR_POLICY_TYPE_TEF)
233 {
234 srh = (ip6_sr_header_t *) (iph + 1);
235 iph->protocol = IP_PROTOCOL_IPV6_ROUTE;
236 srh->protocol = IP_PROTOCOL_IPV6;
237 srh->type = ROUTING_HEADER_TYPE_SR;
238 srh->flags = 0x00;
239 srh->tag = 0x0000;
240 srh->segments_left = vec_len (sl) - 1;
241 srh->last_entry = vec_len (sl) - 1;
242 srh->length =
243 ((sizeof (ip6_sr_header_t) + (vec_len (sl) * sizeof (ip6_address_t)) +
244 sizeof (ip6_sr_pt_tlv_t)) /
245 8) -
246 1;
247 addrp = srh->segments + vec_len (sl) - 1;
248 vec_foreach (this_address, sl)
249 {
250 clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
251 sizeof (ip6_address_t));
252 addrp--;
253 }
254 srh_pt_tlv = (ip6_sr_pt_tlv_t *) (srh->segments + vec_len (sl));
255 srh_pt_tlv->type = IP6_SRH_PT_TLV_TYPE;
256 srh_pt_tlv->length = IP6_SRH_PT_TLV_LEN;
257 }
258 else if (vec_len (sl) > 1)
Pablo Camarillod327c872018-01-08 14:25:55 +0100259 {
260 srh = (ip6_sr_header_t *) (iph + 1);
261 iph->protocol = IP_PROTOCOL_IPV6_ROUTE;
262 srh->protocol = IP_PROTOCOL_IPV6;
263 srh->type = ROUTING_HEADER_TYPE_SR;
264 srh->segments_left = vec_len (sl) - 1;
Ahmed Abdelsalambe837042019-06-20 11:18:57 +0000265 srh->last_entry = vec_len (sl) - 1;
Pablo Camarillod327c872018-01-08 14:25:55 +0100266 srh->length = ((sizeof (ip6_sr_header_t) +
267 (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
268 srh->flags = 0x00;
Ahmed Abdelsalambe837042019-06-20 11:18:57 +0000269 srh->tag = 0x0000;
Pablo Camarillod327c872018-01-08 14:25:55 +0100270 addrp = srh->segments + vec_len (sl) - 1;
271 vec_foreach (this_address, sl)
272 {
Dave Barach178cf492018-11-13 16:34:13 -0500273 clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
274 sizeof (ip6_address_t));
Pablo Camarillod327c872018-01-08 14:25:55 +0100275 addrp--;
276 }
277 }
Pablo Camarillofb380952016-12-07 18:34:18 +0100278 iph->dst_address.as_u64[0] = sl->as_u64[0];
279 iph->dst_address.as_u64[1] = sl->as_u64[1];
280 return rs;
281}
282
283/**
284 * @brief SR rewrite string computation for SRH insertion (inline)
285 *
286 * @param sl is a vector of IPv6 addresses composing the Segment List
287 *
288 * @return precomputed rewrite string for SRH insertion
289 */
290static inline u8 *
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +0000291compute_rewrite_insert (ip6_address_t *sl, u8 type)
Pablo Camarillofb380952016-12-07 18:34:18 +0100292{
293 ip6_sr_header_t *srh;
294 ip6_address_t *addrp, *this_address;
295 u32 header_length = 0;
296 u8 *rs = NULL;
297
298 header_length = 0;
299 header_length += sizeof (ip6_sr_header_t);
300 header_length += (vec_len (sl) + 1) * sizeof (ip6_address_t);
301
302 vec_validate (rs, header_length - 1);
303
304 srh = (ip6_sr_header_t *) rs;
305 srh->type = ROUTING_HEADER_TYPE_SR;
306 srh->segments_left = vec_len (sl);
Ahmed Abdelsalambe837042019-06-20 11:18:57 +0000307 srh->last_entry = vec_len (sl);
Pablo Camarillofb380952016-12-07 18:34:18 +0100308 srh->length = ((sizeof (ip6_sr_header_t) +
309 ((vec_len (sl) + 1) * sizeof (ip6_address_t))) / 8) - 1;
310 srh->flags = 0x00;
Ahmed Abdelsalambe837042019-06-20 11:18:57 +0000311 srh->tag = 0x0000;
Pablo Camarillofb380952016-12-07 18:34:18 +0100312 addrp = srh->segments + vec_len (sl);
313 vec_foreach (this_address, sl)
314 {
Dave Barach178cf492018-11-13 16:34:13 -0500315 clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
316 sizeof (ip6_address_t));
Pablo Camarillofb380952016-12-07 18:34:18 +0100317 addrp--;
318 }
319 return rs;
320}
321
322/**
323 * @brief SR rewrite string computation for SRH insertion with BSID (inline)
324 *
325 * @param sl is a vector of IPv6 addresses composing the Segment List
326 *
327 * @return precomputed rewrite string for SRH insertion with BSID
328 */
329static inline u8 *
330compute_rewrite_bsid (ip6_address_t * sl)
331{
332 ip6_sr_header_t *srh;
333 ip6_address_t *addrp, *this_address;
334 u32 header_length = 0;
335 u8 *rs = NULL;
336
337 header_length = 0;
338 header_length += sizeof (ip6_sr_header_t);
339 header_length += vec_len (sl) * sizeof (ip6_address_t);
340
341 vec_validate (rs, header_length - 1);
342
343 srh = (ip6_sr_header_t *) rs;
344 srh->type = ROUTING_HEADER_TYPE_SR;
345 srh->segments_left = vec_len (sl) - 1;
Ahmed Abdelsalambe837042019-06-20 11:18:57 +0000346 srh->last_entry = vec_len (sl) - 1;
Pablo Camarillofb380952016-12-07 18:34:18 +0100347 srh->length = ((sizeof (ip6_sr_header_t) +
348 (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
349 srh->flags = 0x00;
Ahmed Abdelsalambe837042019-06-20 11:18:57 +0000350 srh->tag = 0x0000;
Pablo Camarillofb380952016-12-07 18:34:18 +0100351 addrp = srh->segments + vec_len (sl) - 1;
352 vec_foreach (this_address, sl)
353 {
Dave Barach178cf492018-11-13 16:34:13 -0500354 clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
355 sizeof (ip6_address_t));
Pablo Camarillofb380952016-12-07 18:34:18 +0100356 addrp--;
357 }
358 return rs;
359}
360
361/*************************** SR LB helper functions **************************/
362/**
363 * @brief Creates a Segment List and adds it to an SR policy
364 *
365 * Creates a Segment List and adds it to the SR policy. Notice that the SL are
366 * not necessarily unique. Hence there might be two Segment List within the
367 * same SR Policy with exactly the same segments and same weight.
368 *
369 * @param sr_policy is the SR policy where the SL will be added
370 * @param sl is a vector of IPv6 addresses composing the Segment List
371 * @param weight is the weight of the SegmentList (for load-balancing purposes)
372 * @param is_encap represents the mode (SRH insertion vs Encapsulation)
373 *
374 * @return pointer to the just created segment list
375 */
376static inline ip6_sr_sl_t *
377create_sl (ip6_sr_policy_t * sr_policy, ip6_address_t * sl, u32 weight,
378 u8 is_encap)
379{
380 ip6_sr_main_t *sm = &sr_main;
381 ip6_sr_sl_t *segment_list;
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800382 sr_policy_fn_registration_t *plugin = 0;
Pablo Camarillofb380952016-12-07 18:34:18 +0100383
384 pool_get (sm->sid_lists, segment_list);
Dave Barachb7b92992018-10-17 10:38:51 -0400385 clib_memset (segment_list, 0, sizeof (*segment_list));
Pablo Camarillofb380952016-12-07 18:34:18 +0100386
387 vec_add1 (sr_policy->segments_lists, segment_list - sm->sid_lists);
388
389 /* Fill in segment list */
390 segment_list->weight =
391 (weight != (u32) ~ 0 ? weight : SR_SEGMENT_LIST_WEIGHT_DEFAULT);
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800392
Pablo Camarillofb380952016-12-07 18:34:18 +0100393 segment_list->segments = vec_dup (sl);
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +0000394 segment_list->policy_type = sr_policy->type;
Pablo Camarillofb380952016-12-07 18:34:18 +0100395
Tetsuya Murakami6b354912021-01-31 16:38:56 -0800396 segment_list->egress_fib_table =
397 ip6_fib_index_from_table_id (sr_policy->fib_table);
398
Pablo Camarillofb380952016-12-07 18:34:18 +0100399 if (is_encap)
400 {
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +0000401 segment_list->rewrite = compute_rewrite_encaps (sl, sr_policy->type);
Pablo Camarillofb380952016-12-07 18:34:18 +0100402 segment_list->rewrite_bsid = segment_list->rewrite;
403 }
404 else
405 {
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +0000406 segment_list->rewrite = compute_rewrite_insert (sl, sr_policy->type);
Pablo Camarillofb380952016-12-07 18:34:18 +0100407 segment_list->rewrite_bsid = compute_rewrite_bsid (sl);
408 }
409
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800410 if (sr_policy->plugin)
411 {
412 plugin =
413 pool_elt_at_index (sm->policy_plugin_functions,
414 sr_policy->plugin - SR_BEHAVIOR_LAST);
415
416 segment_list->plugin = sr_policy->plugin;
417 segment_list->plugin_mem = sr_policy->plugin_mem;
418
419 plugin->creation (sr_policy);
420 }
421
Pablo Camarillofb380952016-12-07 18:34:18 +0100422 /* Create DPO */
423 dpo_reset (&segment_list->bsid_dpo);
424 dpo_reset (&segment_list->ip6_dpo);
425 dpo_reset (&segment_list->ip4_dpo);
426
427 if (is_encap)
428 {
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800429 if (!sr_policy->plugin)
430 {
431 dpo_set (&segment_list->ip6_dpo, sr_pr_encaps_dpo_type,
432 DPO_PROTO_IP6, segment_list - sm->sid_lists);
433 dpo_set (&segment_list->ip4_dpo, sr_pr_encaps_dpo_type,
434 DPO_PROTO_IP4, segment_list - sm->sid_lists);
435 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_encaps_dpo_type,
436 DPO_PROTO_IP6, segment_list - sm->sid_lists);
437 }
438 else
439 {
440 dpo_set (&segment_list->ip6_dpo, plugin->dpo, DPO_PROTO_IP6,
441 segment_list - sm->sid_lists);
442 dpo_set (&segment_list->ip4_dpo, plugin->dpo, DPO_PROTO_IP4,
443 segment_list - sm->sid_lists);
444 dpo_set (&segment_list->bsid_dpo, plugin->dpo, DPO_PROTO_IP6,
445 segment_list - sm->sid_lists);
446 }
Pablo Camarillofb380952016-12-07 18:34:18 +0100447 }
448 else
449 {
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800450 if (!sr_policy->plugin)
451 {
452 dpo_set (&segment_list->ip6_dpo, sr_pr_insert_dpo_type,
453 DPO_PROTO_IP6, segment_list - sm->sid_lists);
454 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_insert_dpo_type,
455 DPO_PROTO_IP6, segment_list - sm->sid_lists);
456 }
457 else
458 {
459 dpo_set (&segment_list->ip6_dpo, plugin->dpo, DPO_PROTO_IP6,
460 segment_list - sm->sid_lists);
461 dpo_set (&segment_list->bsid_dpo, plugin->dpo, DPO_PROTO_IP6,
462 segment_list - sm->sid_lists);
463 }
Pablo Camarillofb380952016-12-07 18:34:18 +0100464 }
465
466 return segment_list;
467}
468
469/**
Nathan Skrzypczak2c77ae42021-09-29 15:36:51 +0200470 * @brief Updates the Load-Balancer after an SR Policy change
Pablo Camarillofb380952016-12-07 18:34:18 +0100471 *
472 * @param sr_policy is the modified SR Policy
473 */
474static inline void
475update_lb (ip6_sr_policy_t * sr_policy)
476{
477 flow_hash_config_t fhc;
478 u32 *sl_index;
479 ip6_sr_sl_t *segment_list;
480 ip6_sr_main_t *sm = &sr_main;
481 load_balance_path_t path;
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100482 path.path_index = FIB_NODE_INDEX_INVALID;
Pablo Camarillofb380952016-12-07 18:34:18 +0100483 load_balance_path_t *ip4_path_vector = 0;
484 load_balance_path_t *ip6_path_vector = 0;
485 load_balance_path_t *b_path_vector = 0;
486
487 /* In case LB does not exist, create it */
488 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
489 {
490 fib_prefix_t pfx = {
491 .fp_proto = FIB_PROTOCOL_IP6,
492 .fp_len = 128,
493 .fp_addr = {
494 .ip6 = sr_policy->bsid,
495 }
496 };
497
498 /* Add FIB entry for BSID */
499 fhc = fib_table_get_flow_hash_config (sr_policy->fib_table,
Neale Rannsd792d9c2017-10-21 10:53:20 -0700500 FIB_PROTOCOL_IP6);
Pablo Camarillofb380952016-12-07 18:34:18 +0100501
502 dpo_set (&sr_policy->bsid_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
503 load_balance_create (0, DPO_PROTO_IP6, fhc));
504
505 dpo_set (&sr_policy->ip6_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
506 load_balance_create (0, DPO_PROTO_IP6, fhc));
507
508 /* Update FIB entry's to point to the LB DPO in the main FIB and hidden one */
Neale Ranns107e7d42017-04-11 09:55:19 -0700509 fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
510 sr_policy->fib_table),
511 &pfx, FIB_SOURCE_SR,
Pablo Camarillofb380952016-12-07 18:34:18 +0100512 FIB_ENTRY_FLAG_EXCLUSIVE,
513 &sr_policy->bsid_dpo);
514
515 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
516 &pfx,
517 FIB_SOURCE_SR,
518 FIB_ENTRY_FLAG_EXCLUSIVE,
519 &sr_policy->ip6_dpo);
520
521 if (sr_policy->is_encap)
522 {
523 dpo_set (&sr_policy->ip4_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP4,
524 load_balance_create (0, DPO_PROTO_IP4, fhc));
525
526 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
527 &pfx,
528 FIB_SOURCE_SR,
529 FIB_ENTRY_FLAG_EXCLUSIVE,
530 &sr_policy->ip4_dpo);
531 }
532
533 }
534
535 /* Create the LB path vector */
Pablo Camarillofb380952016-12-07 18:34:18 +0100536 vec_foreach (sl_index, sr_policy->segments_lists)
537 {
538 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
539 path.path_dpo = segment_list->bsid_dpo;
540 path.path_weight = segment_list->weight;
541 vec_add1 (b_path_vector, path);
542 path.path_dpo = segment_list->ip6_dpo;
543 vec_add1 (ip6_path_vector, path);
544 if (sr_policy->is_encap)
545 {
546 path.path_dpo = segment_list->ip4_dpo;
547 vec_add1 (ip4_path_vector, path);
548 }
549 }
550
551 /* Update LB multipath */
552 load_balance_multipath_update (&sr_policy->bsid_dpo, b_path_vector,
553 LOAD_BALANCE_FLAG_NONE);
554 load_balance_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector,
555 LOAD_BALANCE_FLAG_NONE);
556 if (sr_policy->is_encap)
557 load_balance_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector,
558 LOAD_BALANCE_FLAG_NONE);
559
560 /* Cleanup */
561 vec_free (b_path_vector);
562 vec_free (ip6_path_vector);
563 vec_free (ip4_path_vector);
Pablo Camarillofb380952016-12-07 18:34:18 +0100564}
565
566/**
567 * @brief Updates the Replicate DPO after an SR Policy change
568 *
569 * @param sr_policy is the modified SR Policy (type spray)
570 */
571static inline void
572update_replicate (ip6_sr_policy_t * sr_policy)
573{
574 u32 *sl_index;
575 ip6_sr_sl_t *segment_list;
576 ip6_sr_main_t *sm = &sr_main;
577 load_balance_path_t path;
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100578 path.path_index = FIB_NODE_INDEX_INVALID;
Pablo Camarillofb380952016-12-07 18:34:18 +0100579 load_balance_path_t *b_path_vector = 0;
580 load_balance_path_t *ip6_path_vector = 0;
581 load_balance_path_t *ip4_path_vector = 0;
582
583 /* In case LB does not exist, create it */
584 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
585 {
586 dpo_set (&sr_policy->bsid_dpo, DPO_REPLICATE,
587 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
588
589 dpo_set (&sr_policy->ip6_dpo, DPO_REPLICATE,
590 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
591
592 /* Update FIB entry's DPO to point to SR without LB */
593 fib_prefix_t pfx = {
594 .fp_proto = FIB_PROTOCOL_IP6,
595 .fp_len = 128,
596 .fp_addr = {
597 .ip6 = sr_policy->bsid,
598 }
599 };
Neale Ranns107e7d42017-04-11 09:55:19 -0700600 fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
601 sr_policy->fib_table),
602 &pfx, FIB_SOURCE_SR,
Pablo Camarillofb380952016-12-07 18:34:18 +0100603 FIB_ENTRY_FLAG_EXCLUSIVE,
604 &sr_policy->bsid_dpo);
605
606 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
607 &pfx,
608 FIB_SOURCE_SR,
609 FIB_ENTRY_FLAG_EXCLUSIVE,
610 &sr_policy->ip6_dpo);
611
612 if (sr_policy->is_encap)
613 {
614 dpo_set (&sr_policy->ip4_dpo, DPO_REPLICATE, DPO_PROTO_IP4,
615 replicate_create (0, DPO_PROTO_IP4));
616
617 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
618 &pfx,
619 FIB_SOURCE_SR,
620 FIB_ENTRY_FLAG_EXCLUSIVE,
621 &sr_policy->ip4_dpo);
622 }
623
624 }
625
626 /* Create the replicate path vector */
627 path.path_weight = 1;
628 vec_foreach (sl_index, sr_policy->segments_lists)
629 {
630 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
631 path.path_dpo = segment_list->bsid_dpo;
632 vec_add1 (b_path_vector, path);
633 path.path_dpo = segment_list->ip6_dpo;
634 vec_add1 (ip6_path_vector, path);
635 if (sr_policy->is_encap)
636 {
637 path.path_dpo = segment_list->ip4_dpo;
638 vec_add1 (ip4_path_vector, path);
639 }
640 }
641
642 /* Update replicate multipath */
643 replicate_multipath_update (&sr_policy->bsid_dpo, b_path_vector);
644 replicate_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector);
645 if (sr_policy->is_encap)
646 replicate_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector);
Pablo Camarillofb380952016-12-07 18:34:18 +0100647}
648
649/******************************* SR rewrite API *******************************/
650/* Three functions for handling sr policies:
651 * -> sr_policy_add
652 * -> sr_policy_del
653 * -> sr_policy_mod
654 * All of them are API. CLI function on sr_policy_command_fn */
655
656/**
657 * @brief Create a new SR policy
658 *
659 * @param bsid is the bindingSID of the SR Policy
660 * @param segments is a vector of IPv6 address composing the segment list
661 * @param weight is the weight of the sid list. optional.
662 * @param behavior is the behavior of the SR policy. (default//spray)
663 * @param fib_table is the VRF where to install the FIB entry for the BSID
664 * @param is_encap (bool) whether SR policy should behave as Encap/SRH Insertion
665 *
666 * @return 0 if correct, else error
667 */
668int
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +0000669sr_policy_add (ip6_address_t *bsid, ip6_address_t *segments, u32 weight,
670 u8 type, u32 fib_table, u8 is_encap, u16 plugin,
671 void *ls_plugin_mem)
Pablo Camarillofb380952016-12-07 18:34:18 +0100672{
673 ip6_sr_main_t *sm = &sr_main;
674 ip6_sr_policy_t *sr_policy = 0;
Pablo Camarillofb380952016-12-07 18:34:18 +0100675 uword *p;
676
677 /* Search for existing keys (BSID) */
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100678 p = mhash_get (&sm->sr_policies_index_hash, bsid);
Pablo Camarillofb380952016-12-07 18:34:18 +0100679 if (p)
680 {
681 /* Add SR policy that already exists; complain */
682 return -12;
683 }
684
685 /* Search collision in FIB entries */
686 /* Explanation: It might be possible that some other entity has already
687 * created a route for the BSID. This in theory is impossible, but in
688 * practise we could see it. Assert it and scream if needed */
689 fib_prefix_t pfx = {
690 .fp_proto = FIB_PROTOCOL_IP6,
691 .fp_len = 128,
692 .fp_addr = {
693 .ip6 = *bsid,
694 }
695 };
696
697 /* Lookup the FIB index associated to the table selected */
Neale Ranns107e7d42017-04-11 09:55:19 -0700698 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP6,
699 (fib_table != (u32) ~ 0 ? fib_table : 0));
Pablo Camarillofb380952016-12-07 18:34:18 +0100700 if (fib_index == ~0)
701 return -13;
702
703 /* Lookup whether there exists an entry for the BSID */
704 fib_node_index_t fei = fib_table_lookup_exact_match (fib_index, &pfx);
705 if (FIB_NODE_INDEX_INVALID != fei)
706 return -12; //There is an entry for such lookup
707
708 /* Add an SR policy object */
709 pool_get (sm->sr_policies, sr_policy);
Dave Barachb7b92992018-10-17 10:38:51 -0400710 clib_memset (sr_policy, 0, sizeof (*sr_policy));
Dave Barach178cf492018-11-13 16:34:13 -0500711 clib_memcpy_fast (&sr_policy->bsid, bsid, sizeof (ip6_address_t));
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +0000712 sr_policy->type = type;
Pablo Camarillofb380952016-12-07 18:34:18 +0100713 sr_policy->fib_table = (fib_table != (u32) ~ 0 ? fib_table : 0); //Is default FIB 0 ?
714 sr_policy->is_encap = is_encap;
715
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800716 if (plugin)
717 {
718 sr_policy->plugin = plugin;
719 sr_policy->plugin_mem = ls_plugin_mem;
720 }
721
Pablo Camarillofb380952016-12-07 18:34:18 +0100722 /* Copy the key */
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100723 mhash_set (&sm->sr_policies_index_hash, bsid, sr_policy - sm->sr_policies,
724 NULL);
Pablo Camarillofb380952016-12-07 18:34:18 +0100725
726 /* Create a segment list and add the index to the SR policy */
727 create_sl (sr_policy, segments, weight, is_encap);
728
729 /* If FIB doesnt exist, create them */
730 if (sm->fib_table_ip6 == (u32) ~ 0)
731 {
732 sm->fib_table_ip6 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
Neale Ranns15002542017-09-10 04:39:11 -0700733 FIB_SOURCE_SR,
Pablo Camarillofb380952016-12-07 18:34:18 +0100734 "SRv6 steering of IP6 prefixes through BSIDs");
735 sm->fib_table_ip4 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
Neale Ranns15002542017-09-10 04:39:11 -0700736 FIB_SOURCE_SR,
Pablo Camarillofb380952016-12-07 18:34:18 +0100737 "SRv6 steering of IP4 prefixes through BSIDs");
Pablo Camarillofb380952016-12-07 18:34:18 +0100738 }
739
740 /* Create IPv6 FIB for the BindingSID attached to the DPO of the only SL */
Ahmed Abdelsalam9cca6942022-06-06 15:54:02 +0000741 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT ||
742 sr_policy->type == SR_POLICY_TYPE_TEF)
Pablo Camarillofb380952016-12-07 18:34:18 +0100743 update_lb (sr_policy);
744 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
745 update_replicate (sr_policy);
746 return 0;
747}
748
749/**
750 * @brief Delete a SR policy
751 *
752 * @param bsid is the bindingSID of the SR Policy
753 * @param index is the index of the SR policy
754 *
755 * @return 0 if correct, else error
756 */
757int
758sr_policy_del (ip6_address_t * bsid, u32 index)
759{
760 ip6_sr_main_t *sm = &sr_main;
761 ip6_sr_policy_t *sr_policy = 0;
762 ip6_sr_sl_t *segment_list;
Pablo Camarillofb380952016-12-07 18:34:18 +0100763 u32 *sl_index;
764 uword *p;
765
Pablo Camarillofb380952016-12-07 18:34:18 +0100766 if (bsid)
767 {
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100768 p = mhash_get (&sm->sr_policies_index_hash, bsid);
Pablo Camarillofb380952016-12-07 18:34:18 +0100769 if (p)
770 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
771 else
772 return -1;
773 }
774 else
775 {
776 sr_policy = pool_elt_at_index (sm->sr_policies, index);
Pablo Camarillofb380952016-12-07 18:34:18 +0100777 }
778
779 /* Remove BindingSID FIB entry */
780 fib_prefix_t pfx = {
781 .fp_proto = FIB_PROTOCOL_IP6,
782 .fp_len = 128,
783 .fp_addr = {
784 .ip6 = sr_policy->bsid,
785 }
786 ,
787 };
788
Neale Ranns107e7d42017-04-11 09:55:19 -0700789 fib_table_entry_special_remove (fib_table_find (FIB_PROTOCOL_IP6,
790 sr_policy->fib_table),
Pablo Camarillofb380952016-12-07 18:34:18 +0100791 &pfx, FIB_SOURCE_SR);
792
793 fib_table_entry_special_remove (sm->fib_table_ip6, &pfx, FIB_SOURCE_SR);
794
795 if (sr_policy->is_encap)
796 fib_table_entry_special_remove (sm->fib_table_ip4, &pfx, FIB_SOURCE_SR);
797
798 if (dpo_id_is_valid (&sr_policy->bsid_dpo))
799 {
800 dpo_reset (&sr_policy->bsid_dpo);
801 dpo_reset (&sr_policy->ip4_dpo);
802 dpo_reset (&sr_policy->ip6_dpo);
803 }
804
805 /* Clean SID Lists */
806 vec_foreach (sl_index, sr_policy->segments_lists)
807 {
808 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
809 vec_free (segment_list->segments);
810 vec_free (segment_list->rewrite);
Kris Michielsen91074432017-06-22 13:00:20 +0200811 if (!sr_policy->is_encap)
812 vec_free (segment_list->rewrite_bsid);
Pablo Camarillofb380952016-12-07 18:34:18 +0100813 pool_put_index (sm->sid_lists, *sl_index);
814 }
815
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800816 if (sr_policy->plugin)
817 {
818 sr_policy_fn_registration_t *plugin = 0;
819
820 plugin =
821 pool_elt_at_index (sm->policy_plugin_functions,
822 sr_policy->plugin - SR_BEHAVIOR_LAST);
823
824 plugin->removal (sr_policy);
825 sr_policy->plugin = 0;
826 sr_policy->plugin_mem = NULL;
827 }
828
Pablo Camarillofb380952016-12-07 18:34:18 +0100829 /* Remove SR policy entry */
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100830 mhash_unset (&sm->sr_policies_index_hash, &sr_policy->bsid, NULL);
Pablo Camarillofb380952016-12-07 18:34:18 +0100831 pool_put (sm->sr_policies, sr_policy);
832
833 /* If FIB empty unlock it */
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100834 if (!pool_elts (sm->sr_policies) && !pool_elts (sm->steer_policies))
Pablo Camarillofb380952016-12-07 18:34:18 +0100835 {
Neale Ranns15002542017-09-10 04:39:11 -0700836 fib_table_unlock (sm->fib_table_ip6, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
837 fib_table_unlock (sm->fib_table_ip4, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
Pablo Camarillofb380952016-12-07 18:34:18 +0100838 sm->fib_table_ip6 = (u32) ~ 0;
839 sm->fib_table_ip4 = (u32) ~ 0;
840 }
841
842 return 0;
843}
844
845/**
846 * @brief Modify an existing SR policy
847 *
848 * The possible modifications are adding a new Segment List, modifying an
849 * existing Segment List (modify the weight only) and delete a given
850 * Segment List from the SR Policy.
851 *
852 * @param bsid is the bindingSID of the SR Policy
853 * @param index is the index of the SR policy
854 * @param fib_table is the VRF where to install the FIB entry for the BSID
855 * @param operation is the operation to perform (among the top ones)
856 * @param segments is a vector of IPv6 address composing the segment list
857 * @param sl_index is the index of the Segment List to modify/delete
858 * @param weight is the weight of the sid list. optional.
859 * @param is_encap Mode. Encapsulation or SRH insertion.
860 *
861 * @return 0 if correct, else error
862 */
863int
864sr_policy_mod (ip6_address_t * bsid, u32 index, u32 fib_table,
865 u8 operation, ip6_address_t * segments, u32 sl_index,
866 u32 weight)
867{
868 ip6_sr_main_t *sm = &sr_main;
869 ip6_sr_policy_t *sr_policy = 0;
870 ip6_sr_sl_t *segment_list;
871 u32 *sl_index_iterate;
872 uword *p;
873
874 if (bsid)
875 {
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100876 p = mhash_get (&sm->sr_policies_index_hash, bsid);
Pablo Camarillofb380952016-12-07 18:34:18 +0100877 if (p)
878 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
879 else
880 return -1;
881 }
882 else
883 {
884 sr_policy = pool_elt_at_index (sm->sr_policies, index);
Pablo Camarillofb380952016-12-07 18:34:18 +0100885 }
886
887 if (operation == 1) /* Add SR List to an existing SR policy */
888 {
889 /* Create the new SL */
890 segment_list =
891 create_sl (sr_policy, segments, weight, sr_policy->is_encap);
892
893 /* Create a new LB DPO */
894 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
895 update_lb (sr_policy);
896 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
897 update_replicate (sr_policy);
898 }
899 else if (operation == 2) /* Delete SR List from an existing SR policy */
900 {
901 /* Check that currently there are more than one SID list */
902 if (vec_len (sr_policy->segments_lists) == 1)
903 return -21;
904
905 /* Check that the SR list does exist and is assigned to the sr policy */
906 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
907 if (*sl_index_iterate == sl_index)
908 break;
909
910 if (*sl_index_iterate != sl_index)
911 return -22;
912
913 /* Remove the lucky SR list that is being kicked out */
914 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
915 vec_free (segment_list->segments);
916 vec_free (segment_list->rewrite);
Kris Michielsen91074432017-06-22 13:00:20 +0200917 if (!sr_policy->is_encap)
918 vec_free (segment_list->rewrite_bsid);
Pablo Camarillofb380952016-12-07 18:34:18 +0100919 pool_put_index (sm->sid_lists, sl_index);
920 vec_del1 (sr_policy->segments_lists,
921 sl_index_iterate - sr_policy->segments_lists);
922
923 /* Create a new LB DPO */
924 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
925 update_lb (sr_policy);
926 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
927 update_replicate (sr_policy);
928 }
929 else if (operation == 3) /* Modify the weight of an existing SR List */
930 {
931 /* Find the corresponding SL */
932 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
933 if (*sl_index_iterate == sl_index)
934 break;
935
936 if (*sl_index_iterate != sl_index)
937 return -32;
938
939 /* Change the weight */
940 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
941 segment_list->weight = weight;
942
943 /* Update LB */
944 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
945 update_lb (sr_policy);
946 }
947 else /* Incorrect op. */
948 return -1;
949
950 return 0;
951}
952
953/**
954 * @brief CLI for 'sr policies' command family
955 */
956static clib_error_t *
957sr_policy_command_fn (vlib_main_t * vm, unformat_input_t * input,
958 vlib_cli_command_t * cmd)
959{
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800960 ip6_sr_main_t *sm = &sr_main;
Pablo Camarillofb380952016-12-07 18:34:18 +0100961 int rv = -1;
962 char is_del = 0, is_add = 0, is_mod = 0;
963 char policy_set = 0;
964 ip6_address_t bsid, next_address;
965 u32 sr_policy_index = (u32) ~ 0, sl_index = (u32) ~ 0;
966 u32 weight = (u32) ~ 0, fib_table = (u32) ~ 0;
967 ip6_address_t *segments = 0, *this_seg;
968 u8 operation = 0;
969 char is_encap = 1;
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +0000970 u8 type = SR_POLICY_TYPE_DEFAULT;
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800971 u16 behavior = 0;
972 void *ls_plugin_mem = 0;
Pablo Camarillofb380952016-12-07 18:34:18 +0100973
974 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
975 {
976 if (!is_add && !is_mod && !is_del && unformat (input, "add"))
977 is_add = 1;
978 else if (!is_add && !is_mod && !is_del && unformat (input, "del"))
979 is_del = 1;
980 else if (!is_add && !is_mod && !is_del && unformat (input, "mod"))
981 is_mod = 1;
982 else if (!policy_set
983 && unformat (input, "bsid %U", unformat_ip6_address, &bsid))
984 policy_set = 1;
985 else if (!is_add && !policy_set
986 && unformat (input, "index %d", &sr_policy_index))
987 policy_set = 1;
988 else if (unformat (input, "weight %d", &weight));
989 else
990 if (unformat (input, "next %U", unformat_ip6_address, &next_address))
991 {
992 vec_add2 (segments, this_seg, 1);
Dave Barach178cf492018-11-13 16:34:13 -0500993 clib_memcpy_fast (this_seg->as_u8, next_address.as_u8,
994 sizeof (*this_seg));
Pablo Camarillofb380952016-12-07 18:34:18 +0100995 }
996 else if (unformat (input, "add sl"))
997 operation = 1;
998 else if (unformat (input, "del sl index %d", &sl_index))
999 operation = 2;
1000 else if (unformat (input, "mod sl index %d", &sl_index))
1001 operation = 3;
1002 else if (fib_table == (u32) ~ 0
1003 && unformat (input, "fib-table %d", &fib_table));
1004 else if (unformat (input, "encap"))
1005 is_encap = 1;
1006 else if (unformat (input, "insert"))
1007 is_encap = 0;
1008 else if (unformat (input, "spray"))
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +00001009 type = SR_POLICY_TYPE_SPRAY;
Ahmed Abdelsalam9cca6942022-06-06 15:54:02 +00001010 else if (unformat (input, "tef"))
1011 type = SR_POLICY_TYPE_TEF;
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -08001012 else if (!behavior && unformat (input, "behavior"))
1013 {
1014 sr_policy_fn_registration_t *plugin = 0, **vec_plugins = 0;
1015 sr_policy_fn_registration_t **plugin_it = 0;
1016
1017 /* *INDENT-OFF* */
Damjan Marionb2c31b62020-12-13 21:47:40 +01001018 pool_foreach (plugin, sm->policy_plugin_functions)
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -08001019 {
1020 vec_add1 (vec_plugins, plugin);
Damjan Marionb2c31b62020-12-13 21:47:40 +01001021 }
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -08001022 /* *INDENT-ON* */
1023
1024 vec_foreach (plugin_it, vec_plugins)
1025 {
1026 if (unformat
1027 (input, "%U", (*plugin_it)->ls_unformat, &ls_plugin_mem))
1028 {
1029 behavior = (*plugin_it)->sr_policy_function_number;
1030 break;
1031 }
1032 }
1033
1034 if (!behavior)
1035 {
1036 return clib_error_return (0, "Invalid behavior");
1037 }
1038 }
Pablo Camarillofb380952016-12-07 18:34:18 +01001039 else
1040 break;
1041 }
1042
1043 if (!is_add && !is_mod && !is_del)
1044 return clib_error_return (0, "Incorrect CLI");
1045
1046 if (!policy_set)
1047 return clib_error_return (0, "No SR policy BSID or index specified");
1048
1049 if (is_add)
1050 {
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -08001051 if (behavior && vec_len (segments) == 0)
1052 {
1053 vec_add2 (segments, this_seg, 1);
1054 clib_memset (this_seg, 0, sizeof (*this_seg));
1055 }
1056
Pablo Camarillofb380952016-12-07 18:34:18 +01001057 if (vec_len (segments) == 0)
1058 return clib_error_return (0, "No Segment List specified");
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -08001059
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +00001060 rv = sr_policy_add (&bsid, segments, weight, type, fib_table, is_encap,
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -08001061 behavior, ls_plugin_mem);
1062
John Lod23d39c2018-09-13 15:08:08 -04001063 vec_free (segments);
Pablo Camarillofb380952016-12-07 18:34:18 +01001064 }
1065 else if (is_del)
1066 rv = sr_policy_del ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
1067 sr_policy_index);
1068 else if (is_mod)
1069 {
1070 if (!operation)
1071 return clib_error_return (0, "No SL modification specified");
1072 if (operation != 1 && sl_index == (u32) ~ 0)
1073 return clib_error_return (0, "No Segment List index specified");
1074 if (operation == 1 && vec_len (segments) == 0)
1075 return clib_error_return (0, "No Segment List specified");
1076 if (operation == 3 && weight == (u32) ~ 0)
1077 return clib_error_return (0, "No new weight for the SL specified");
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -08001078
Pablo Camarillofb380952016-12-07 18:34:18 +01001079 rv = sr_policy_mod ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
1080 sr_policy_index, fib_table, operation, segments,
1081 sl_index, weight);
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -08001082
1083 if (segments)
1084 vec_free (segments);
Pablo Camarillofb380952016-12-07 18:34:18 +01001085 }
1086
1087 switch (rv)
1088 {
1089 case 0:
1090 break;
1091 case 1:
1092 return 0;
1093 case -12:
1094 return clib_error_return (0,
1095 "There is already a FIB entry for the BindingSID address.\n"
1096 "The SR policy could not be created.");
1097 case -13:
1098 return clib_error_return (0, "The specified FIB table does not exist.");
1099 case -21:
1100 return clib_error_return (0,
1101 "The selected SR policy only contains ONE segment list. "
1102 "Please remove the SR policy instead");
1103 case -22:
1104 return clib_error_return (0,
1105 "Could not delete the segment list. "
1106 "It is not associated with that SR policy.");
1107 case -32:
1108 return clib_error_return (0,
1109 "Could not modify the segment list. "
1110 "The given SL is not associated with such SR policy.");
1111 default:
1112 return clib_error_return (0, "BUG: sr policy returns %d", rv);
1113 }
1114 return 0;
1115}
1116
1117/* *INDENT-OFF* */
1118VLIB_CLI_COMMAND (sr_policy_command, static) = {
1119 .path = "sr policy",
1120 .short_help = "sr policy [add||del||mod] [bsid 2001::1||index 5] "
1121 "next A:: next B:: next C:: (weight 1) (fib-table 2) (encap|insert)",
1122 .long_help =
1123 "Manipulation of SR policies.\n"
1124 "A Segment Routing policy may contain several SID lists. Each SID list has\n"
1125 "an associated weight (default 1), which will result in wECMP (uECMP).\n"
1126 "Segment Routing policies might be of type encapsulation or srh insertion\n"
1127 "Each SR policy will be associated with a unique BindingSID.\n"
1128 "A BindingSID is a locally allocated SegmentID. For every packet that arrives\n"
1129 "with IPv6_DA:BSID such traffic will be steered into the SR policy.\n"
1130 "The add command will create a SR policy with its first segment list (sl)\n"
1131 "The mod command allows you to add, remove, or modify the existing segment lists\n"
1132 "within an SR policy.\n"
1133 "The del command allows you to delete a SR policy along with all its associated\n"
1134 "SID lists.\n",
1135 .function = sr_policy_command_fn,
1136};
1137/* *INDENT-ON* */
1138
1139/**
1140 * @brief CLI to display onscreen all the SR policies
1141 */
1142static clib_error_t *
1143show_sr_policies_command_fn (vlib_main_t * vm, unformat_input_t * input,
1144 vlib_cli_command_t * cmd)
1145{
1146 ip6_sr_main_t *sm = &sr_main;
1147 u32 *sl_index;
1148 ip6_sr_sl_t *segment_list = 0;
1149 ip6_sr_policy_t *sr_policy = 0;
1150 ip6_sr_policy_t **vec_policies = 0;
1151 ip6_address_t *addr;
1152 u8 *s;
1153 int i = 0;
1154
1155 vlib_cli_output (vm, "SR policies:");
1156
1157 /* *INDENT-OFF* */
Damjan Marionb2c31b62020-12-13 21:47:40 +01001158 pool_foreach (sr_policy, sm->sr_policies)
1159 {vec_add1 (vec_policies, sr_policy); }
Pablo Camarillofb380952016-12-07 18:34:18 +01001160 /* *INDENT-ON* */
1161
1162 vec_foreach_index (i, vec_policies)
1163 {
1164 sr_policy = vec_policies[i];
1165 vlib_cli_output (vm, "[%u].-\tBSID: %U",
1166 (u32) (sr_policy - sm->sr_policies),
1167 format_ip6_address, &sr_policy->bsid);
1168 vlib_cli_output (vm, "\tBehavior: %s",
1169 (sr_policy->is_encap ? "Encapsulation" :
1170 "SRH insertion"));
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +00001171 switch (sr_policy->type)
1172 {
1173 case SR_POLICY_TYPE_SPRAY:
1174 vlib_cli_output (vm, "\tType: %s", "Spray");
1175 break;
Ahmed Abdelsalam9cca6942022-06-06 15:54:02 +00001176 case SR_POLICY_TYPE_TEF:
1177 vlib_cli_output (vm, "\tType: %s",
1178 "TEF (Timestamp, Encapsulate, and Forward)");
1179 break;
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +00001180 default:
1181 vlib_cli_output (vm, "\tType: %s", "Default");
1182 break;
1183 }
Pablo Camarillofb380952016-12-07 18:34:18 +01001184 vlib_cli_output (vm, "\tFIB table: %u",
1185 (sr_policy->fib_table !=
1186 (u32) ~ 0 ? sr_policy->fib_table : 0));
1187 vlib_cli_output (vm, "\tSegment Lists:");
1188 vec_foreach (sl_index, sr_policy->segments_lists)
1189 {
1190 s = NULL;
1191 s = format (s, "\t[%u].- ", *sl_index);
1192 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
1193 s = format (s, "< ");
1194 vec_foreach (addr, segment_list->segments)
1195 {
1196 s = format (s, "%U, ", format_ip6_address, addr);
1197 }
1198 s = format (s, "\b\b > ");
1199 s = format (s, "weight: %u", segment_list->weight);
Benoît Ganneb9753542020-04-17 12:11:26 +02001200 vlib_cli_output (vm, " %v", s);
Pablo Camarillofb380952016-12-07 18:34:18 +01001201 }
1202 vlib_cli_output (vm, "-----------");
1203 }
1204 return 0;
1205}
1206
1207/* *INDENT-OFF* */
1208VLIB_CLI_COMMAND (show_sr_policies_command, static) = {
1209 .path = "show sr policies",
1210 .short_help = "show sr policies",
1211 .function = show_sr_policies_command_fn,
1212};
1213/* *INDENT-ON* */
1214
Ahmed Abdelsalam448bc812020-11-09 14:04:07 +00001215/**
1216 * @brief CLI to display onscreen the SR encaps source addr
1217 */
1218static clib_error_t *
1219show_sr_encaps_source_command_fn (vlib_main_t * vm, unformat_input_t * input,
1220 vlib_cli_command_t * cmd)
1221{
1222 vlib_cli_output (vm, "SR encaps source addr = %U", format_ip6_address,
1223 sr_get_encaps_source ());
1224
1225 return 0;
1226}
1227
1228/* *INDENT-OFF* */
1229VLIB_CLI_COMMAND (show_sr_encaps_source_command, static) = {
1230 .path = "show sr encaps source addr",
1231 .short_help = "show sr encaps source addr",
1232 .function = show_sr_encaps_source_command_fn,
1233};
1234/* *INDENT-ON* */
1235
Ahmed Abdelsalam80f0b882020-11-10 17:19:12 +00001236/**
1237 * @brief CLI to display onscreen the hop-limit value used for SRv6 encapsulation
1238 */
1239static clib_error_t *
1240show_sr_encaps_hop_limit_command_fn (vlib_main_t * vm,
1241 unformat_input_t * input,
1242 vlib_cli_command_t * cmd)
1243{
1244 vlib_cli_output (vm, "SR encaps hop-limit = %u", sr_get_hop_limit ());
1245
1246 return 0;
1247}
1248
1249/* *INDENT-OFF* */
1250VLIB_CLI_COMMAND (show_sr_encaps_hop_limit_command, static) = {
1251 .path = "show sr encaps hop-limit",
1252 .short_help = "show sr encaps hop-limit",
1253 .function = show_sr_encaps_hop_limit_command_fn,
1254};
1255/* *INDENT-ON* */
1256
Pablo Camarillofb380952016-12-07 18:34:18 +01001257/*************************** SR rewrite graph node ****************************/
1258/**
1259 * @brief Trace for the SR Policy Rewrite graph node
1260 */
1261static u8 *
1262format_sr_policy_rewrite_trace (u8 * s, va_list * args)
1263{
1264 //TODO
1265 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1266 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1267 sr_policy_rewrite_trace_t *t = va_arg (*args, sr_policy_rewrite_trace_t *);
1268
1269 s = format
1270 (s, "SR-policy-rewrite: src %U dst %U",
1271 format_ip6_address, &t->src, format_ip6_address, &t->dst);
1272
1273 return s;
1274}
Ahmed Abdelsalam9cca6942022-06-06 15:54:02 +00001275/**
1276 * @brief SRv6 TEF (Timestamp, Encapsulate, and Forward) behavior
1277 */
1278static_always_inline void
1279srv6_tef_behavior (vlib_node_runtime_t *node, vlib_buffer_t *b0,
1280 ip6_header_t *ip0)
1281{
1282 ip6_sr_header_t *srh;
1283 ip6_sr_pt_tlv_t *srh_pt_tlv;
1284 timestamp_64_t ts;
1285 srh = (ip6_sr_header_t *) (ip0 + 1);
1286
1287 srh_pt_tlv =
1288 (ip6_sr_pt_tlv_t *) ((u8 *) ip0 + sizeof (ip6_header_t) +
1289 sizeof (ip6_sr_header_t) +
1290 sizeof (ip6_address_t) * (srh->last_entry + 1));
1291
1292 unix_time_now_nsec_fraction (&ts.sec, &ts.nsec);
1293 srh_pt_tlv->t64.sec = htobe32 (ts.sec);
1294 srh_pt_tlv->t64.nsec = htobe32 (ts.nsec);
1295}
Pablo Camarillofb380952016-12-07 18:34:18 +01001296
1297/**
1298 * @brief IPv6 encapsulation processing as per RFC2473
1299 */
1300static_always_inline void
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +00001301encaps_processing_v6 (vlib_node_runtime_t *node, vlib_buffer_t *b0,
1302 ip6_header_t *ip0, ip6_header_t *ip0_encap,
1303 u8 policy_type)
Pablo Camarillofb380952016-12-07 18:34:18 +01001304{
1305 u32 new_l0;
Jakub Horn91f4a972021-01-21 12:14:58 +00001306 u32 flow_label;
Pablo Camarillofb380952016-12-07 18:34:18 +01001307
1308 ip0_encap->hop_limit -= 1;
1309 new_l0 =
1310 ip0->payload_length + sizeof (ip6_header_t) +
1311 clib_net_to_host_u16 (ip0_encap->payload_length);
1312 ip0->payload_length = clib_host_to_net_u16 (new_l0);
Jakub Horn91f4a972021-01-21 12:14:58 +00001313
1314 flow_label = ip6_compute_flow_hash (ip0_encap, IP_FLOW_HASH_DEFAULT);
1315 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
1316 0 |
1317 (clib_net_to_host_u32 (
1318 ip0_encap->ip_version_traffic_class_and_flow_label) &
1319 0xfff00000) |
1320 (flow_label & 0x0000ffff));
Ahmed Abdelsalam9cca6942022-06-06 15:54:02 +00001321 if (policy_type == SR_POLICY_TYPE_TEF)
1322 srv6_tef_behavior (node, b0, ip0);
Pablo Camarillofb380952016-12-07 18:34:18 +01001323}
1324
1325/**
1326 * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
1327 */
1328static uword
1329sr_policy_rewrite_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
1330 vlib_frame_t * from_frame)
1331{
1332 ip6_sr_main_t *sm = &sr_main;
1333 u32 n_left_from, next_index, *from, *to_next;
1334
1335 from = vlib_frame_vector_args (from_frame);
1336 n_left_from = from_frame->n_vectors;
1337
1338 next_index = node->cached_next_index;
1339
1340 int encap_pkts = 0, bsid_pkts = 0;
1341
1342 while (n_left_from > 0)
1343 {
1344 u32 n_left_to_next;
1345
1346 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1347
1348 /* Quad - Loop */
1349 while (n_left_from >= 8 && n_left_to_next >= 4)
1350 {
1351 u32 bi0, bi1, bi2, bi3;
1352 vlib_buffer_t *b0, *b1, *b2, *b3;
1353 u32 next0, next1, next2, next3;
1354 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1355 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1356 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1357 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1358
1359 /* Prefetch next iteration. */
1360 {
1361 vlib_buffer_t *p4, *p5, *p6, *p7;
1362
1363 p4 = vlib_get_buffer (vm, from[4]);
1364 p5 = vlib_get_buffer (vm, from[5]);
1365 p6 = vlib_get_buffer (vm, from[6]);
1366 p7 = vlib_get_buffer (vm, from[7]);
1367
1368 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1369 vlib_prefetch_buffer_header (p4, LOAD);
1370 vlib_prefetch_buffer_header (p5, LOAD);
1371 vlib_prefetch_buffer_header (p6, LOAD);
1372 vlib_prefetch_buffer_header (p7, LOAD);
1373
Damjan Marionaf7fb042021-07-15 11:54:41 +02001374 clib_prefetch_store (p4->data);
1375 clib_prefetch_store (p5->data);
1376 clib_prefetch_store (p6->data);
1377 clib_prefetch_store (p7->data);
Pablo Camarillofb380952016-12-07 18:34:18 +01001378 }
1379
1380 to_next[0] = bi0 = from[0];
1381 to_next[1] = bi1 = from[1];
1382 to_next[2] = bi2 = from[2];
1383 to_next[3] = bi3 = from[3];
1384 from += 4;
1385 to_next += 4;
1386 n_left_from -= 4;
1387 n_left_to_next -= 4;
1388
1389 b0 = vlib_get_buffer (vm, bi0);
1390 b1 = vlib_get_buffer (vm, bi1);
1391 b2 = vlib_get_buffer (vm, bi2);
1392 b3 = vlib_get_buffer (vm, bi3);
1393
1394 sl0 =
1395 pool_elt_at_index (sm->sid_lists,
1396 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1397 sl1 =
1398 pool_elt_at_index (sm->sid_lists,
1399 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1400 sl2 =
1401 pool_elt_at_index (sm->sid_lists,
1402 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1403 sl3 =
1404 pool_elt_at_index (sm->sid_lists,
1405 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1406
shwethabe146f132017-03-09 16:58:26 +00001407 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1408 vec_len (sl0->rewrite));
1409 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1410 vec_len (sl1->rewrite));
1411 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1412 vec_len (sl2->rewrite));
1413 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1414 vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001415
1416 ip0_encap = vlib_buffer_get_current (b0);
1417 ip1_encap = vlib_buffer_get_current (b1);
1418 ip2_encap = vlib_buffer_get_current (b2);
1419 ip3_encap = vlib_buffer_get_current (b3);
1420
Dave Barach178cf492018-11-13 16:34:13 -05001421 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1422 sl0->rewrite, vec_len (sl0->rewrite));
1423 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1424 sl1->rewrite, vec_len (sl1->rewrite));
1425 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1426 sl2->rewrite, vec_len (sl2->rewrite));
1427 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1428 sl3->rewrite, vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001429
1430 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1431 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1432 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1433 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1434
1435 ip0 = vlib_buffer_get_current (b0);
1436 ip1 = vlib_buffer_get_current (b1);
1437 ip2 = vlib_buffer_get_current (b2);
1438 ip3 = vlib_buffer_get_current (b3);
1439
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +00001440 encaps_processing_v6 (node, b0, ip0, ip0_encap, sl0->policy_type);
1441 encaps_processing_v6 (node, b1, ip1, ip1_encap, sl1->policy_type);
1442 encaps_processing_v6 (node, b2, ip2, ip2_encap, sl2->policy_type);
1443 encaps_processing_v6 (node, b3, ip3, ip3_encap, sl3->policy_type);
Pablo Camarillofb380952016-12-07 18:34:18 +01001444
Tetsuya Murakami6b354912021-01-31 16:38:56 -08001445 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
1446 vnet_buffer (b1)->sw_if_index[VLIB_TX] = sl1->egress_fib_table;
1447 vnet_buffer (b2)->sw_if_index[VLIB_TX] = sl2->egress_fib_table;
1448 vnet_buffer (b3)->sw_if_index[VLIB_TX] = sl3->egress_fib_table;
1449
Pablo Camarillofb380952016-12-07 18:34:18 +01001450 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1451 {
1452 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1453 {
1454 sr_policy_rewrite_trace_t *tr =
1455 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001456 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1457 sizeof (tr->src.as_u8));
1458 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1459 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001460 }
1461
1462 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1463 {
1464 sr_policy_rewrite_trace_t *tr =
1465 vlib_add_trace (vm, node, b1, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001466 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
1467 sizeof (tr->src.as_u8));
1468 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
1469 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001470 }
1471
1472 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1473 {
1474 sr_policy_rewrite_trace_t *tr =
1475 vlib_add_trace (vm, node, b2, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001476 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
1477 sizeof (tr->src.as_u8));
1478 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
1479 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001480 }
1481
1482 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1483 {
1484 sr_policy_rewrite_trace_t *tr =
1485 vlib_add_trace (vm, node, b3, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001486 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
1487 sizeof (tr->src.as_u8));
1488 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
1489 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001490 }
1491 }
1492
1493 encap_pkts += 4;
1494 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1495 n_left_to_next, bi0, bi1, bi2, bi3,
1496 next0, next1, next2, next3);
1497 }
1498
1499 /* Single loop for potentially the last three packets */
1500 while (n_left_from > 0 && n_left_to_next > 0)
1501 {
1502 u32 bi0;
1503 vlib_buffer_t *b0;
1504 ip6_header_t *ip0 = 0, *ip0_encap = 0;
1505 ip6_sr_sl_t *sl0;
1506 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1507
1508 bi0 = from[0];
1509 to_next[0] = bi0;
1510 from += 1;
1511 to_next += 1;
1512 n_left_from -= 1;
1513 n_left_to_next -= 1;
1514 b0 = vlib_get_buffer (vm, bi0);
1515
1516 sl0 =
1517 pool_elt_at_index (sm->sid_lists,
1518 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00001519 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1520 vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001521
1522 ip0_encap = vlib_buffer_get_current (b0);
1523
Dave Barach178cf492018-11-13 16:34:13 -05001524 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1525 sl0->rewrite, vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001526 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1527
1528 ip0 = vlib_buffer_get_current (b0);
1529
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +00001530 encaps_processing_v6 (node, b0, ip0, ip0_encap, sl0->policy_type);
Pablo Camarillofb380952016-12-07 18:34:18 +01001531
Tetsuya Murakami6b354912021-01-31 16:38:56 -08001532 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
1533
Pablo Camarillofb380952016-12-07 18:34:18 +01001534 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1535 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1536 {
1537 sr_policy_rewrite_trace_t *tr =
1538 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001539 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1540 sizeof (tr->src.as_u8));
1541 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1542 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001543 }
1544
1545 encap_pkts++;
1546 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1547 n_left_to_next, bi0, next0);
1548 }
1549
1550 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1551 }
1552
1553 /* Update counters */
1554 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1555 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1556 encap_pkts);
1557 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1558 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1559 bsid_pkts);
1560
1561 return from_frame->n_vectors;
1562}
1563
1564/* *INDENT-OFF* */
1565VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_node) = {
1566 .function = sr_policy_rewrite_encaps,
1567 .name = "sr-pl-rewrite-encaps",
1568 .vector_size = sizeof (u32),
1569 .format_trace = format_sr_policy_rewrite_trace,
1570 .type = VLIB_NODE_TYPE_INTERNAL,
1571 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1572 .error_strings = sr_policy_rewrite_error_strings,
1573 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1574 .next_nodes = {
1575#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1576 foreach_sr_policy_rewrite_next
1577#undef _
1578 },
1579};
1580/* *INDENT-ON* */
1581
1582/**
1583 * @brief IPv4 encapsulation processing as per RFC2473
1584 */
1585static_always_inline void
1586encaps_processing_v4 (vlib_node_runtime_t * node,
1587 vlib_buffer_t * b0,
1588 ip6_header_t * ip0, ip4_header_t * ip0_encap)
1589{
1590 u32 new_l0;
1591 ip6_sr_header_t *sr0;
1592
1593 u32 checksum0;
Jakub Horn91f4a972021-01-21 12:14:58 +00001594 u32 flow_label;
Pablo Camarillofb380952016-12-07 18:34:18 +01001595
1596 /* Inner IPv4: Decrement TTL & update checksum */
1597 ip0_encap->ttl -= 1;
1598 checksum0 = ip0_encap->checksum + clib_host_to_net_u16 (0x0100);
1599 checksum0 += checksum0 >= 0xffff;
1600 ip0_encap->checksum = checksum0;
1601
1602 /* Outer IPv6: Update length, FL, proto */
1603 new_l0 = ip0->payload_length + clib_net_to_host_u16 (ip0_encap->length);
1604 ip0->payload_length = clib_host_to_net_u16 (new_l0);
Jakub Horn91f4a972021-01-21 12:14:58 +00001605 flow_label = ip4_compute_flow_hash (ip0_encap, IP_FLOW_HASH_DEFAULT);
1606 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
1607 0 | ((6 & 0xF) << 28) | ((ip0_encap->tos & 0xFF) << 20) |
1608 (flow_label & 0x0000ffff));
Pablo Camarillod327c872018-01-08 14:25:55 +01001609 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
1610 {
1611 sr0 = (void *) (ip0 + 1);
1612 sr0->protocol = IP_PROTOCOL_IP_IN_IP;
1613 }
1614 else
1615 ip0->protocol = IP_PROTOCOL_IP_IN_IP;
Pablo Camarillofb380952016-12-07 18:34:18 +01001616}
1617
1618/**
1619 * @brief Graph node for applying a SR policy into an IPv4 packet. Encapsulation
1620 */
1621static uword
1622sr_policy_rewrite_encaps_v4 (vlib_main_t * vm, vlib_node_runtime_t * node,
1623 vlib_frame_t * from_frame)
1624{
1625 ip6_sr_main_t *sm = &sr_main;
1626 u32 n_left_from, next_index, *from, *to_next;
1627
1628 from = vlib_frame_vector_args (from_frame);
1629 n_left_from = from_frame->n_vectors;
1630
1631 next_index = node->cached_next_index;
1632
1633 int encap_pkts = 0, bsid_pkts = 0;
1634
1635 while (n_left_from > 0)
1636 {
1637 u32 n_left_to_next;
1638
1639 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1640
1641 /* Quad - Loop */
1642 while (n_left_from >= 8 && n_left_to_next >= 4)
1643 {
1644 u32 bi0, bi1, bi2, bi3;
1645 vlib_buffer_t *b0, *b1, *b2, *b3;
1646 u32 next0, next1, next2, next3;
1647 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1648 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1649 ip4_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1650 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1651
1652 /* Prefetch next iteration. */
1653 {
1654 vlib_buffer_t *p4, *p5, *p6, *p7;
1655
1656 p4 = vlib_get_buffer (vm, from[4]);
1657 p5 = vlib_get_buffer (vm, from[5]);
1658 p6 = vlib_get_buffer (vm, from[6]);
1659 p7 = vlib_get_buffer (vm, from[7]);
1660
1661 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1662 vlib_prefetch_buffer_header (p4, LOAD);
1663 vlib_prefetch_buffer_header (p5, LOAD);
1664 vlib_prefetch_buffer_header (p6, LOAD);
1665 vlib_prefetch_buffer_header (p7, LOAD);
1666
Damjan Marionaf7fb042021-07-15 11:54:41 +02001667 clib_prefetch_store (p4->data);
1668 clib_prefetch_store (p5->data);
1669 clib_prefetch_store (p6->data);
1670 clib_prefetch_store (p7->data);
Pablo Camarillofb380952016-12-07 18:34:18 +01001671 }
1672
1673 to_next[0] = bi0 = from[0];
1674 to_next[1] = bi1 = from[1];
1675 to_next[2] = bi2 = from[2];
1676 to_next[3] = bi3 = from[3];
1677 from += 4;
1678 to_next += 4;
1679 n_left_from -= 4;
1680 n_left_to_next -= 4;
1681
1682 b0 = vlib_get_buffer (vm, bi0);
1683 b1 = vlib_get_buffer (vm, bi1);
1684 b2 = vlib_get_buffer (vm, bi2);
1685 b3 = vlib_get_buffer (vm, bi3);
1686
1687 sl0 =
1688 pool_elt_at_index (sm->sid_lists,
1689 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1690 sl1 =
1691 pool_elt_at_index (sm->sid_lists,
1692 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1693 sl2 =
1694 pool_elt_at_index (sm->sid_lists,
1695 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1696 sl3 =
1697 pool_elt_at_index (sm->sid_lists,
1698 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00001699 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1700 vec_len (sl0->rewrite));
1701 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1702 vec_len (sl1->rewrite));
1703 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1704 vec_len (sl2->rewrite));
1705 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1706 vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001707
1708 ip0_encap = vlib_buffer_get_current (b0);
1709 ip1_encap = vlib_buffer_get_current (b1);
1710 ip2_encap = vlib_buffer_get_current (b2);
1711 ip3_encap = vlib_buffer_get_current (b3);
1712
Dave Barach178cf492018-11-13 16:34:13 -05001713 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1714 sl0->rewrite, vec_len (sl0->rewrite));
1715 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1716 sl1->rewrite, vec_len (sl1->rewrite));
1717 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1718 sl2->rewrite, vec_len (sl2->rewrite));
1719 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1720 sl3->rewrite, vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001721
1722 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1723 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1724 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1725 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1726
1727 ip0 = vlib_buffer_get_current (b0);
1728 ip1 = vlib_buffer_get_current (b1);
1729 ip2 = vlib_buffer_get_current (b2);
1730 ip3 = vlib_buffer_get_current (b3);
1731
1732 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1733 encaps_processing_v4 (node, b1, ip1, ip1_encap);
1734 encaps_processing_v4 (node, b2, ip2, ip2_encap);
1735 encaps_processing_v4 (node, b3, ip3, ip3_encap);
1736
Tetsuya Murakami6b354912021-01-31 16:38:56 -08001737 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
1738 vnet_buffer (b1)->sw_if_index[VLIB_TX] = sl1->egress_fib_table;
1739 vnet_buffer (b2)->sw_if_index[VLIB_TX] = sl2->egress_fib_table;
1740 vnet_buffer (b3)->sw_if_index[VLIB_TX] = sl3->egress_fib_table;
1741
Pablo Camarillofb380952016-12-07 18:34:18 +01001742 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1743 {
1744 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1745 {
1746 sr_policy_rewrite_trace_t *tr =
1747 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001748 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1749 sizeof (tr->src.as_u8));
1750 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1751 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001752 }
1753
1754 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1755 {
1756 sr_policy_rewrite_trace_t *tr =
1757 vlib_add_trace (vm, node, b1, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001758 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
1759 sizeof (tr->src.as_u8));
1760 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
1761 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001762 }
1763
1764 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1765 {
1766 sr_policy_rewrite_trace_t *tr =
1767 vlib_add_trace (vm, node, b2, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001768 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
1769 sizeof (tr->src.as_u8));
1770 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
1771 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001772 }
1773
1774 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1775 {
1776 sr_policy_rewrite_trace_t *tr =
1777 vlib_add_trace (vm, node, b3, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001778 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
1779 sizeof (tr->src.as_u8));
1780 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
1781 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001782 }
1783 }
1784
1785 encap_pkts += 4;
1786 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1787 n_left_to_next, bi0, bi1, bi2, bi3,
1788 next0, next1, next2, next3);
1789 }
1790
1791 /* Single loop for potentially the last three packets */
1792 while (n_left_from > 0 && n_left_to_next > 0)
1793 {
1794 u32 bi0;
1795 vlib_buffer_t *b0;
1796 ip6_header_t *ip0 = 0;
1797 ip4_header_t *ip0_encap = 0;
1798 ip6_sr_sl_t *sl0;
1799 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1800
1801 bi0 = from[0];
1802 to_next[0] = bi0;
1803 from += 1;
1804 to_next += 1;
1805 n_left_from -= 1;
1806 n_left_to_next -= 1;
1807 b0 = vlib_get_buffer (vm, bi0);
1808
1809 sl0 =
1810 pool_elt_at_index (sm->sid_lists,
1811 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00001812 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1813 vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001814
1815 ip0_encap = vlib_buffer_get_current (b0);
1816
Dave Barach178cf492018-11-13 16:34:13 -05001817 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1818 sl0->rewrite, vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001819 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1820
1821 ip0 = vlib_buffer_get_current (b0);
1822
1823 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1824
Tetsuya Murakami6b354912021-01-31 16:38:56 -08001825 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
1826
Pablo Camarillofb380952016-12-07 18:34:18 +01001827 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1828 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1829 {
1830 sr_policy_rewrite_trace_t *tr =
1831 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001832 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1833 sizeof (tr->src.as_u8));
1834 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1835 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001836 }
1837
1838 encap_pkts++;
1839 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1840 n_left_to_next, bi0, next0);
1841 }
1842
1843 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1844 }
1845
1846 /* Update counters */
1847 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1848 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1849 encap_pkts);
1850 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1851 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1852 bsid_pkts);
1853
1854 return from_frame->n_vectors;
1855}
1856
1857/* *INDENT-OFF* */
1858VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_v4_node) = {
1859 .function = sr_policy_rewrite_encaps_v4,
1860 .name = "sr-pl-rewrite-encaps-v4",
1861 .vector_size = sizeof (u32),
1862 .format_trace = format_sr_policy_rewrite_trace,
1863 .type = VLIB_NODE_TYPE_INTERNAL,
1864 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1865 .error_strings = sr_policy_rewrite_error_strings,
1866 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1867 .next_nodes = {
1868#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1869 foreach_sr_policy_rewrite_next
1870#undef _
1871 },
1872};
1873/* *INDENT-ON* */
1874
1875always_inline u32
1876ip_flow_hash (void *data)
1877{
1878 ip4_header_t *iph = (ip4_header_t *) data;
1879
1880 if ((iph->ip_version_and_header_length & 0xF0) == 0x40)
1881 return ip4_compute_flow_hash (iph, IP_FLOW_HASH_DEFAULT);
1882 else
1883 return ip6_compute_flow_hash ((ip6_header_t *) iph, IP_FLOW_HASH_DEFAULT);
1884}
1885
1886always_inline u64
1887mac_to_u64 (u8 * m)
1888{
1889 return (*((u64 *) m) & 0xffffffffffff);
1890}
1891
1892always_inline u32
1893l2_flow_hash (vlib_buffer_t * b0)
1894{
1895 ethernet_header_t *eh;
1896 u64 a, b, c;
1897 uword is_ip, eh_size;
1898 u16 eh_type;
1899
1900 eh = vlib_buffer_get_current (b0);
1901 eh_type = clib_net_to_host_u16 (eh->type);
1902 eh_size = ethernet_buffer_header_size (b0);
1903
1904 is_ip = (eh_type == ETHERNET_TYPE_IP4 || eh_type == ETHERNET_TYPE_IP6);
1905
1906 /* since we have 2 cache lines, use them */
1907 if (is_ip)
1908 a = ip_flow_hash ((u8 *) vlib_buffer_get_current (b0) + eh_size);
1909 else
1910 a = eh->type;
1911
1912 b = mac_to_u64 ((u8 *) eh->dst_address);
1913 c = mac_to_u64 ((u8 *) eh->src_address);
1914 hash_mix64 (a, b, c);
1915
1916 return (u32) c;
1917}
1918
1919/**
1920 * @brief Graph node for applying a SR policy into a L2 frame
1921 */
1922static uword
1923sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
1924 vlib_frame_t * from_frame)
1925{
1926 ip6_sr_main_t *sm = &sr_main;
1927 u32 n_left_from, next_index, *from, *to_next;
1928
1929 from = vlib_frame_vector_args (from_frame);
1930 n_left_from = from_frame->n_vectors;
1931
1932 next_index = node->cached_next_index;
1933
1934 int encap_pkts = 0, bsid_pkts = 0;
1935
1936 while (n_left_from > 0)
1937 {
1938 u32 n_left_to_next;
1939
1940 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1941
1942 /* Quad - Loop */
1943 while (n_left_from >= 8 && n_left_to_next >= 4)
1944 {
1945 u32 bi0, bi1, bi2, bi3;
1946 vlib_buffer_t *b0, *b1, *b2, *b3;
1947 u32 next0, next1, next2, next3;
1948 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1949 ethernet_header_t *en0, *en1, *en2, *en3;
1950 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1951 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1952 ip6_sr_policy_t *sp0, *sp1, *sp2, *sp3;
1953 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
Jakub Horn91f4a972021-01-21 12:14:58 +00001954 u32 flow_label0, flow_label1, flow_label2, flow_label3;
Pablo Camarillofb380952016-12-07 18:34:18 +01001955
1956 /* Prefetch next iteration. */
1957 {
1958 vlib_buffer_t *p4, *p5, *p6, *p7;
1959
1960 p4 = vlib_get_buffer (vm, from[4]);
1961 p5 = vlib_get_buffer (vm, from[5]);
1962 p6 = vlib_get_buffer (vm, from[6]);
1963 p7 = vlib_get_buffer (vm, from[7]);
1964
1965 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1966 vlib_prefetch_buffer_header (p4, LOAD);
1967 vlib_prefetch_buffer_header (p5, LOAD);
1968 vlib_prefetch_buffer_header (p6, LOAD);
1969 vlib_prefetch_buffer_header (p7, LOAD);
1970
Damjan Marionaf7fb042021-07-15 11:54:41 +02001971 clib_prefetch_store (p4->data);
1972 clib_prefetch_store (p5->data);
1973 clib_prefetch_store (p6->data);
1974 clib_prefetch_store (p7->data);
Pablo Camarillofb380952016-12-07 18:34:18 +01001975 }
1976
1977 to_next[0] = bi0 = from[0];
1978 to_next[1] = bi1 = from[1];
1979 to_next[2] = bi2 = from[2];
1980 to_next[3] = bi3 = from[3];
1981 from += 4;
1982 to_next += 4;
1983 n_left_from -= 4;
1984 n_left_to_next -= 4;
1985
1986 b0 = vlib_get_buffer (vm, bi0);
1987 b1 = vlib_get_buffer (vm, bi1);
1988 b2 = vlib_get_buffer (vm, bi2);
1989 b3 = vlib_get_buffer (vm, bi3);
1990
1991 sp0 = pool_elt_at_index (sm->sr_policies,
1992 sm->sw_iface_sr_policies[vnet_buffer
1993 (b0)->sw_if_index
1994 [VLIB_RX]]);
1995
1996 sp1 = pool_elt_at_index (sm->sr_policies,
1997 sm->sw_iface_sr_policies[vnet_buffer
1998 (b1)->sw_if_index
1999 [VLIB_RX]]);
2000
2001 sp2 = pool_elt_at_index (sm->sr_policies,
2002 sm->sw_iface_sr_policies[vnet_buffer
2003 (b2)->sw_if_index
2004 [VLIB_RX]]);
2005
2006 sp3 = pool_elt_at_index (sm->sr_policies,
2007 sm->sw_iface_sr_policies[vnet_buffer
2008 (b3)->sw_if_index
2009 [VLIB_RX]]);
Jakub Horn91f4a972021-01-21 12:14:58 +00002010 flow_label0 = l2_flow_hash (b0);
2011 flow_label1 = l2_flow_hash (b1);
2012 flow_label2 = l2_flow_hash (b2);
2013 flow_label3 = l2_flow_hash (b3);
Pablo Camarillofb380952016-12-07 18:34:18 +01002014
2015 if (vec_len (sp0->segments_lists) == 1)
2016 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
2017 else
2018 {
Jakub Horn91f4a972021-01-21 12:14:58 +00002019 vnet_buffer (b0)->ip.flow_hash = flow_label0;
Pablo Camarillofb380952016-12-07 18:34:18 +01002020 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
2021 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
2022 (vec_len (sp0->segments_lists) - 1))];
2023 }
2024
2025 if (vec_len (sp1->segments_lists) == 1)
2026 vnet_buffer (b1)->ip.adj_index[VLIB_TX] = sp1->segments_lists[1];
2027 else
2028 {
Jakub Horn91f4a972021-01-21 12:14:58 +00002029 vnet_buffer (b1)->ip.flow_hash = flow_label1;
Pablo Camarillofb380952016-12-07 18:34:18 +01002030 vnet_buffer (b1)->ip.adj_index[VLIB_TX] =
2031 sp1->segments_lists[(vnet_buffer (b1)->ip.flow_hash &
2032 (vec_len (sp1->segments_lists) - 1))];
2033 }
2034
2035 if (vec_len (sp2->segments_lists) == 1)
2036 vnet_buffer (b2)->ip.adj_index[VLIB_TX] = sp2->segments_lists[2];
2037 else
2038 {
Jakub Horn91f4a972021-01-21 12:14:58 +00002039 vnet_buffer (b2)->ip.flow_hash = flow_label2;
Pablo Camarillofb380952016-12-07 18:34:18 +01002040 vnet_buffer (b2)->ip.adj_index[VLIB_TX] =
2041 sp2->segments_lists[(vnet_buffer (b2)->ip.flow_hash &
2042 (vec_len (sp2->segments_lists) - 1))];
2043 }
2044
2045 if (vec_len (sp3->segments_lists) == 1)
2046 vnet_buffer (b3)->ip.adj_index[VLIB_TX] = sp3->segments_lists[3];
2047 else
2048 {
Jakub Horn91f4a972021-01-21 12:14:58 +00002049 vnet_buffer (b3)->ip.flow_hash = flow_label3;
Pablo Camarillofb380952016-12-07 18:34:18 +01002050 vnet_buffer (b3)->ip.adj_index[VLIB_TX] =
2051 sp3->segments_lists[(vnet_buffer (b3)->ip.flow_hash &
2052 (vec_len (sp3->segments_lists) - 1))];
2053 }
2054
2055 sl0 =
2056 pool_elt_at_index (sm->sid_lists,
2057 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2058 sl1 =
2059 pool_elt_at_index (sm->sid_lists,
2060 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2061 sl2 =
2062 pool_elt_at_index (sm->sid_lists,
2063 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2064 sl3 =
2065 pool_elt_at_index (sm->sid_lists,
2066 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2067
shwethabe146f132017-03-09 16:58:26 +00002068 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2069 vec_len (sl0->rewrite));
2070 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2071 vec_len (sl1->rewrite));
2072 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2073 vec_len (sl2->rewrite));
2074 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2075 vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002076
2077 en0 = vlib_buffer_get_current (b0);
2078 en1 = vlib_buffer_get_current (b1);
2079 en2 = vlib_buffer_get_current (b2);
2080 en3 = vlib_buffer_get_current (b3);
2081
Dave Barach178cf492018-11-13 16:34:13 -05002082 clib_memcpy_fast (((u8 *) en0) - vec_len (sl0->rewrite),
2083 sl0->rewrite, vec_len (sl0->rewrite));
2084 clib_memcpy_fast (((u8 *) en1) - vec_len (sl1->rewrite),
2085 sl1->rewrite, vec_len (sl1->rewrite));
2086 clib_memcpy_fast (((u8 *) en2) - vec_len (sl2->rewrite),
2087 sl2->rewrite, vec_len (sl2->rewrite));
2088 clib_memcpy_fast (((u8 *) en3) - vec_len (sl3->rewrite),
2089 sl3->rewrite, vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002090
2091 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2092 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2093 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2094 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2095
2096 ip0 = vlib_buffer_get_current (b0);
2097 ip1 = vlib_buffer_get_current (b1);
2098 ip2 = vlib_buffer_get_current (b2);
2099 ip3 = vlib_buffer_get_current (b3);
2100
2101 ip0->payload_length =
2102 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
2103 ip1->payload_length =
2104 clib_host_to_net_u16 (b1->current_length - sizeof (ip6_header_t));
2105 ip2->payload_length =
2106 clib_host_to_net_u16 (b2->current_length - sizeof (ip6_header_t));
2107 ip3->payload_length =
2108 clib_host_to_net_u16 (b3->current_length - sizeof (ip6_header_t));
2109
Pablo Camarillod327c872018-01-08 14:25:55 +01002110 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
2111 {
2112 sr0 = (void *) (ip0 + 1);
pcamaril30e76712020-02-04 08:36:51 +01002113 sr0->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01002114 }
2115 else
pcamaril30e76712020-02-04 08:36:51 +01002116 ip0->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillofb380952016-12-07 18:34:18 +01002117
Pablo Camarillod327c872018-01-08 14:25:55 +01002118 if (ip1->protocol == IP_PROTOCOL_IPV6_ROUTE)
2119 {
2120 sr1 = (void *) (ip1 + 1);
pcamaril30e76712020-02-04 08:36:51 +01002121 sr1->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01002122 }
2123 else
pcamaril30e76712020-02-04 08:36:51 +01002124 ip1->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01002125
2126 if (ip2->protocol == IP_PROTOCOL_IPV6_ROUTE)
2127 {
2128 sr2 = (void *) (ip2 + 1);
pcamaril30e76712020-02-04 08:36:51 +01002129 sr2->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01002130 }
2131 else
pcamaril30e76712020-02-04 08:36:51 +01002132 ip2->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01002133
2134 if (ip3->protocol == IP_PROTOCOL_IPV6_ROUTE)
2135 {
2136 sr3 = (void *) (ip3 + 1);
pcamaril30e76712020-02-04 08:36:51 +01002137 sr3->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01002138 }
2139 else
pcamaril30e76712020-02-04 08:36:51 +01002140 ip3->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillofb380952016-12-07 18:34:18 +01002141
Jakub Horn91f4a972021-01-21 12:14:58 +00002142 /* TC is set to 0 for all ethernet frames, should be taken from COS
2143 * od DSCP of encapsulated packet in the future */
2144 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2145 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label0 & 0xffff));
2146 ip1->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2147 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label1 & 0xffff));
2148 ip2->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2149 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label2 & 0xffff));
2150 ip3->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2151 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label3 & 0xffff));
Pablo Camarillofb380952016-12-07 18:34:18 +01002152
2153 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2154 {
2155 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2156 {
2157 sr_policy_rewrite_trace_t *tr =
2158 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002159 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2160 sizeof (tr->src.as_u8));
2161 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2162 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002163 }
2164
2165 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2166 {
2167 sr_policy_rewrite_trace_t *tr =
2168 vlib_add_trace (vm, node, b1, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002169 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2170 sizeof (tr->src.as_u8));
2171 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2172 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002173 }
2174
2175 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2176 {
2177 sr_policy_rewrite_trace_t *tr =
2178 vlib_add_trace (vm, node, b2, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002179 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2180 sizeof (tr->src.as_u8));
2181 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2182 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002183 }
2184
2185 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2186 {
2187 sr_policy_rewrite_trace_t *tr =
2188 vlib_add_trace (vm, node, b3, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002189 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2190 sizeof (tr->src.as_u8));
2191 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2192 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002193 }
2194 }
2195
2196 encap_pkts += 4;
2197 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2198 n_left_to_next, bi0, bi1, bi2, bi3,
2199 next0, next1, next2, next3);
2200 }
2201
2202 /* Single loop for potentially the last three packets */
2203 while (n_left_from > 0 && n_left_to_next > 0)
2204 {
2205 u32 bi0;
2206 vlib_buffer_t *b0;
2207 ip6_header_t *ip0 = 0;
2208 ip6_sr_header_t *sr0;
2209 ethernet_header_t *en0;
2210 ip6_sr_policy_t *sp0;
2211 ip6_sr_sl_t *sl0;
2212 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
Jakub Horn91f4a972021-01-21 12:14:58 +00002213 u32 flow_label0;
Pablo Camarillofb380952016-12-07 18:34:18 +01002214
2215 bi0 = from[0];
2216 to_next[0] = bi0;
2217 from += 1;
2218 to_next += 1;
2219 n_left_from -= 1;
2220 n_left_to_next -= 1;
2221 b0 = vlib_get_buffer (vm, bi0);
2222
2223 /* Find the SR policy */
2224 sp0 = pool_elt_at_index (sm->sr_policies,
2225 sm->sw_iface_sr_policies[vnet_buffer
2226 (b0)->sw_if_index
2227 [VLIB_RX]]);
Jakub Horn91f4a972021-01-21 12:14:58 +00002228 flow_label0 = l2_flow_hash (b0);
Pablo Camarillofb380952016-12-07 18:34:18 +01002229
2230 /* In case there is more than one SL, LB among them */
2231 if (vec_len (sp0->segments_lists) == 1)
2232 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
2233 else
2234 {
Jakub Horn91f4a972021-01-21 12:14:58 +00002235 vnet_buffer (b0)->ip.flow_hash = flow_label0;
Pablo Camarillofb380952016-12-07 18:34:18 +01002236 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
2237 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
2238 (vec_len (sp0->segments_lists) - 1))];
2239 }
2240 sl0 =
2241 pool_elt_at_index (sm->sid_lists,
2242 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00002243 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2244 vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002245
2246 en0 = vlib_buffer_get_current (b0);
2247
Dave Barach178cf492018-11-13 16:34:13 -05002248 clib_memcpy_fast (((u8 *) en0) - vec_len (sl0->rewrite),
2249 sl0->rewrite, vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002250
2251 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2252
2253 ip0 = vlib_buffer_get_current (b0);
2254
2255 ip0->payload_length =
2256 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
2257
Pablo Camarillod327c872018-01-08 14:25:55 +01002258 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
2259 {
2260 sr0 = (void *) (ip0 + 1);
pcamaril30e76712020-02-04 08:36:51 +01002261 sr0->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01002262 }
2263 else
pcamaril30e76712020-02-04 08:36:51 +01002264 ip0->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillofb380952016-12-07 18:34:18 +01002265
Jakub Horn91f4a972021-01-21 12:14:58 +00002266 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2267 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label0 & 0xffff));
2268
Pablo Camarillofb380952016-12-07 18:34:18 +01002269 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2270 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2271 {
2272 sr_policy_rewrite_trace_t *tr =
2273 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002274 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2275 sizeof (tr->src.as_u8));
2276 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2277 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002278 }
2279
2280 encap_pkts++;
2281 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2282 n_left_to_next, bi0, next0);
2283 }
2284
2285 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2286 }
2287
2288 /* Update counters */
2289 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
2290 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2291 encap_pkts);
2292 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
2293 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2294 bsid_pkts);
2295
2296 return from_frame->n_vectors;
2297}
2298
2299/* *INDENT-OFF* */
2300VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_l2_node) = {
2301 .function = sr_policy_rewrite_encaps_l2,
2302 .name = "sr-pl-rewrite-encaps-l2",
2303 .vector_size = sizeof (u32),
2304 .format_trace = format_sr_policy_rewrite_trace,
2305 .type = VLIB_NODE_TYPE_INTERNAL,
2306 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2307 .error_strings = sr_policy_rewrite_error_strings,
2308 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2309 .next_nodes = {
2310#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2311 foreach_sr_policy_rewrite_next
2312#undef _
2313 },
2314};
2315/* *INDENT-ON* */
2316
2317/**
2318 * @brief Graph node for applying a SR policy into a packet. SRH insertion.
2319 */
2320static uword
2321sr_policy_rewrite_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2322 vlib_frame_t * from_frame)
2323{
2324 ip6_sr_main_t *sm = &sr_main;
2325 u32 n_left_from, next_index, *from, *to_next;
2326
2327 from = vlib_frame_vector_args (from_frame);
2328 n_left_from = from_frame->n_vectors;
2329
2330 next_index = node->cached_next_index;
2331
2332 int insert_pkts = 0, bsid_pkts = 0;
2333
2334 while (n_left_from > 0)
2335 {
2336 u32 n_left_to_next;
2337
2338 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2339
2340 /* Quad - Loop */
2341 while (n_left_from >= 8 && n_left_to_next >= 4)
2342 {
2343 u32 bi0, bi1, bi2, bi3;
2344 vlib_buffer_t *b0, *b1, *b2, *b3;
2345 u32 next0, next1, next2, next3;
2346 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2347 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2348 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2349 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2350 u16 new_l0, new_l1, new_l2, new_l3;
2351
2352 /* Prefetch next iteration. */
2353 {
2354 vlib_buffer_t *p4, *p5, *p6, *p7;
2355
2356 p4 = vlib_get_buffer (vm, from[4]);
2357 p5 = vlib_get_buffer (vm, from[5]);
2358 p6 = vlib_get_buffer (vm, from[6]);
2359 p7 = vlib_get_buffer (vm, from[7]);
2360
2361 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2362 vlib_prefetch_buffer_header (p4, LOAD);
2363 vlib_prefetch_buffer_header (p5, LOAD);
2364 vlib_prefetch_buffer_header (p6, LOAD);
2365 vlib_prefetch_buffer_header (p7, LOAD);
2366
Damjan Marionaf7fb042021-07-15 11:54:41 +02002367 clib_prefetch_store (p4->data);
2368 clib_prefetch_store (p5->data);
2369 clib_prefetch_store (p6->data);
2370 clib_prefetch_store (p7->data);
Pablo Camarillofb380952016-12-07 18:34:18 +01002371 }
2372
2373 to_next[0] = bi0 = from[0];
2374 to_next[1] = bi1 = from[1];
2375 to_next[2] = bi2 = from[2];
2376 to_next[3] = bi3 = from[3];
2377 from += 4;
2378 to_next += 4;
2379 n_left_from -= 4;
2380 n_left_to_next -= 4;
2381
2382 b0 = vlib_get_buffer (vm, bi0);
2383 b1 = vlib_get_buffer (vm, bi1);
2384 b2 = vlib_get_buffer (vm, bi2);
2385 b3 = vlib_get_buffer (vm, bi3);
2386
2387 sl0 =
2388 pool_elt_at_index (sm->sid_lists,
2389 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2390 sl1 =
2391 pool_elt_at_index (sm->sid_lists,
2392 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2393 sl2 =
2394 pool_elt_at_index (sm->sid_lists,
2395 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2396 sl3 =
2397 pool_elt_at_index (sm->sid_lists,
2398 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00002399 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2400 vec_len (sl0->rewrite));
2401 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2402 vec_len (sl1->rewrite));
2403 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2404 vec_len (sl2->rewrite));
2405 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2406 vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002407
2408 ip0 = vlib_buffer_get_current (b0);
2409 ip1 = vlib_buffer_get_current (b1);
2410 ip2 = vlib_buffer_get_current (b2);
2411 ip3 = vlib_buffer_get_current (b3);
2412
2413 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2414 sr0 =
2415 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2416 ip6_ext_header_len (ip0 + 1));
2417 else
2418 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2419
2420 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2421 sr1 =
2422 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2423 ip6_ext_header_len (ip1 + 1));
2424 else
2425 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2426
2427 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2428 sr2 =
2429 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2430 ip6_ext_header_len (ip2 + 1));
2431 else
2432 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2433
2434 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2435 sr3 =
2436 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2437 ip6_ext_header_len (ip3 + 1));
2438 else
2439 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2440
Dave Barach178cf492018-11-13 16:34:13 -05002441 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2442 (void *) sr0 - (void *) ip0);
2443 clib_memcpy_fast ((u8 *) ip1 - vec_len (sl1->rewrite), (u8 *) ip1,
2444 (void *) sr1 - (void *) ip1);
2445 clib_memcpy_fast ((u8 *) ip2 - vec_len (sl2->rewrite), (u8 *) ip2,
2446 (void *) sr2 - (void *) ip2);
2447 clib_memcpy_fast ((u8 *) ip3 - vec_len (sl3->rewrite), (u8 *) ip3,
2448 (void *) sr3 - (void *) ip3);
Pablo Camarillofb380952016-12-07 18:34:18 +01002449
Dave Barach178cf492018-11-13 16:34:13 -05002450 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite)),
2451 sl0->rewrite, vec_len (sl0->rewrite));
2452 clib_memcpy_fast (((u8 *) sr1 - vec_len (sl1->rewrite)),
2453 sl1->rewrite, vec_len (sl1->rewrite));
2454 clib_memcpy_fast (((u8 *) sr2 - vec_len (sl2->rewrite)),
2455 sl2->rewrite, vec_len (sl2->rewrite));
2456 clib_memcpy_fast (((u8 *) sr3 - vec_len (sl3->rewrite)),
2457 sl3->rewrite, vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002458
2459 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2460 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2461 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2462 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2463
2464 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2465 ip1 = ((void *) ip1) - vec_len (sl1->rewrite);
2466 ip2 = ((void *) ip2) - vec_len (sl2->rewrite);
2467 ip3 = ((void *) ip3) - vec_len (sl3->rewrite);
2468
2469 ip0->hop_limit -= 1;
2470 ip1->hop_limit -= 1;
2471 ip2->hop_limit -= 1;
2472 ip3->hop_limit -= 1;
2473
2474 new_l0 =
2475 clib_net_to_host_u16 (ip0->payload_length) +
2476 vec_len (sl0->rewrite);
2477 new_l1 =
2478 clib_net_to_host_u16 (ip1->payload_length) +
2479 vec_len (sl1->rewrite);
2480 new_l2 =
2481 clib_net_to_host_u16 (ip2->payload_length) +
2482 vec_len (sl2->rewrite);
2483 new_l3 =
2484 clib_net_to_host_u16 (ip3->payload_length) +
2485 vec_len (sl3->rewrite);
2486
2487 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2488 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2489 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2490 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2491
2492 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2493 sr1 = ((void *) sr1) - vec_len (sl1->rewrite);
2494 sr2 = ((void *) sr2) - vec_len (sl2->rewrite);
2495 sr3 = ((void *) sr3) - vec_len (sl3->rewrite);
2496
2497 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2498 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2499 sr1->segments->as_u64[0] = ip1->dst_address.as_u64[0];
2500 sr1->segments->as_u64[1] = ip1->dst_address.as_u64[1];
2501 sr2->segments->as_u64[0] = ip2->dst_address.as_u64[0];
2502 sr2->segments->as_u64[1] = ip2->dst_address.as_u64[1];
2503 sr3->segments->as_u64[0] = ip3->dst_address.as_u64[0];
2504 sr3->segments->as_u64[1] = ip3->dst_address.as_u64[1];
2505
2506 ip0->dst_address.as_u64[0] =
2507 (sr0->segments + sr0->segments_left)->as_u64[0];
2508 ip0->dst_address.as_u64[1] =
2509 (sr0->segments + sr0->segments_left)->as_u64[1];
2510 ip1->dst_address.as_u64[0] =
2511 (sr1->segments + sr1->segments_left)->as_u64[0];
2512 ip1->dst_address.as_u64[1] =
2513 (sr1->segments + sr1->segments_left)->as_u64[1];
2514 ip2->dst_address.as_u64[0] =
2515 (sr2->segments + sr2->segments_left)->as_u64[0];
2516 ip2->dst_address.as_u64[1] =
2517 (sr2->segments + sr2->segments_left)->as_u64[1];
2518 ip3->dst_address.as_u64[0] =
2519 (sr3->segments + sr3->segments_left)->as_u64[0];
2520 ip3->dst_address.as_u64[1] =
2521 (sr3->segments + sr3->segments_left)->as_u64[1];
2522
2523 ip6_ext_header_t *ip_ext;
2524 if (ip0 + 1 == (void *) sr0)
2525 {
2526 sr0->protocol = ip0->protocol;
2527 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2528 }
2529 else
2530 {
2531 ip_ext = (void *) (ip0 + 1);
2532 sr0->protocol = ip_ext->next_hdr;
2533 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2534 }
2535
2536 if (ip1 + 1 == (void *) sr1)
2537 {
2538 sr1->protocol = ip1->protocol;
2539 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2540 }
2541 else
2542 {
2543 ip_ext = (void *) (ip2 + 1);
2544 sr2->protocol = ip_ext->next_hdr;
2545 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2546 }
2547
2548 if (ip2 + 1 == (void *) sr2)
2549 {
2550 sr2->protocol = ip2->protocol;
2551 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2552 }
2553 else
2554 {
2555 ip_ext = (void *) (ip2 + 1);
2556 sr2->protocol = ip_ext->next_hdr;
2557 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2558 }
2559
2560 if (ip3 + 1 == (void *) sr3)
2561 {
2562 sr3->protocol = ip3->protocol;
2563 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2564 }
2565 else
2566 {
2567 ip_ext = (void *) (ip3 + 1);
2568 sr3->protocol = ip_ext->next_hdr;
2569 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2570 }
2571
2572 insert_pkts += 4;
2573
2574 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2575 {
2576 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2577 {
2578 sr_policy_rewrite_trace_t *tr =
2579 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002580 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2581 sizeof (tr->src.as_u8));
2582 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2583 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002584 }
2585
2586 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2587 {
2588 sr_policy_rewrite_trace_t *tr =
2589 vlib_add_trace (vm, node, b1, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002590 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2591 sizeof (tr->src.as_u8));
2592 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2593 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002594 }
2595
2596 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2597 {
2598 sr_policy_rewrite_trace_t *tr =
2599 vlib_add_trace (vm, node, b2, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002600 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2601 sizeof (tr->src.as_u8));
2602 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2603 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002604 }
2605
2606 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2607 {
2608 sr_policy_rewrite_trace_t *tr =
2609 vlib_add_trace (vm, node, b3, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002610 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2611 sizeof (tr->src.as_u8));
2612 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2613 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002614 }
2615 }
2616
2617 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2618 n_left_to_next, bi0, bi1, bi2, bi3,
2619 next0, next1, next2, next3);
2620 }
2621
2622 /* Single loop for potentially the last three packets */
2623 while (n_left_from > 0 && n_left_to_next > 0)
2624 {
2625 u32 bi0;
2626 vlib_buffer_t *b0;
2627 ip6_header_t *ip0 = 0;
2628 ip6_sr_header_t *sr0 = 0;
2629 ip6_sr_sl_t *sl0;
2630 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2631 u16 new_l0 = 0;
2632
2633 bi0 = from[0];
2634 to_next[0] = bi0;
2635 from += 1;
2636 to_next += 1;
2637 n_left_from -= 1;
2638 n_left_to_next -= 1;
2639
2640 b0 = vlib_get_buffer (vm, bi0);
2641 sl0 =
2642 pool_elt_at_index (sm->sid_lists,
2643 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00002644 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2645 vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002646
2647 ip0 = vlib_buffer_get_current (b0);
2648
2649 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2650 sr0 =
2651 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2652 ip6_ext_header_len (ip0 + 1));
2653 else
2654 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2655
Dave Barach178cf492018-11-13 16:34:13 -05002656 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2657 (void *) sr0 - (void *) ip0);
2658 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite)),
2659 sl0->rewrite, vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002660
2661 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2662
2663 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2664 ip0->hop_limit -= 1;
2665 new_l0 =
2666 clib_net_to_host_u16 (ip0->payload_length) +
2667 vec_len (sl0->rewrite);
2668 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2669
2670 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2671 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2672 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2673
2674 ip0->dst_address.as_u64[0] =
2675 (sr0->segments + sr0->segments_left)->as_u64[0];
2676 ip0->dst_address.as_u64[1] =
2677 (sr0->segments + sr0->segments_left)->as_u64[1];
2678
2679 if (ip0 + 1 == (void *) sr0)
2680 {
2681 sr0->protocol = ip0->protocol;
2682 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2683 }
2684 else
2685 {
2686 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2687 sr0->protocol = ip_ext->next_hdr;
2688 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2689 }
2690
2691 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2692 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2693 {
2694 sr_policy_rewrite_trace_t *tr =
2695 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002696 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2697 sizeof (tr->src.as_u8));
2698 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2699 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002700 }
2701
2702 insert_pkts++;
2703
2704 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2705 n_left_to_next, bi0, next0);
2706 }
2707
2708 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2709 }
2710
2711 /* Update counters */
2712 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2713 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2714 insert_pkts);
2715 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2716 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2717 bsid_pkts);
2718 return from_frame->n_vectors;
2719}
2720
2721/* *INDENT-OFF* */
2722VLIB_REGISTER_NODE (sr_policy_rewrite_insert_node) = {
2723 .function = sr_policy_rewrite_insert,
2724 .name = "sr-pl-rewrite-insert",
2725 .vector_size = sizeof (u32),
2726 .format_trace = format_sr_policy_rewrite_trace,
2727 .type = VLIB_NODE_TYPE_INTERNAL,
2728 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2729 .error_strings = sr_policy_rewrite_error_strings,
2730 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2731 .next_nodes = {
2732#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2733 foreach_sr_policy_rewrite_next
2734#undef _
2735 },
2736};
2737/* *INDENT-ON* */
2738
2739/**
2740 * @brief Graph node for applying a SR policy into a packet. BSID - SRH insertion.
2741 */
2742static uword
2743sr_policy_rewrite_b_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2744 vlib_frame_t * from_frame)
2745{
2746 ip6_sr_main_t *sm = &sr_main;
2747 u32 n_left_from, next_index, *from, *to_next;
2748
2749 from = vlib_frame_vector_args (from_frame);
2750 n_left_from = from_frame->n_vectors;
2751
2752 next_index = node->cached_next_index;
2753
2754 int insert_pkts = 0, bsid_pkts = 0;
2755
2756 while (n_left_from > 0)
2757 {
2758 u32 n_left_to_next;
2759
2760 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2761
2762 /* Quad - Loop */
2763 while (n_left_from >= 8 && n_left_to_next >= 4)
2764 {
2765 u32 bi0, bi1, bi2, bi3;
2766 vlib_buffer_t *b0, *b1, *b2, *b3;
2767 u32 next0, next1, next2, next3;
2768 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2769 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2770 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2771 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2772 u16 new_l0, new_l1, new_l2, new_l3;
2773
2774 /* Prefetch next iteration. */
2775 {
2776 vlib_buffer_t *p4, *p5, *p6, *p7;
2777
2778 p4 = vlib_get_buffer (vm, from[4]);
2779 p5 = vlib_get_buffer (vm, from[5]);
2780 p6 = vlib_get_buffer (vm, from[6]);
2781 p7 = vlib_get_buffer (vm, from[7]);
2782
2783 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2784 vlib_prefetch_buffer_header (p4, LOAD);
2785 vlib_prefetch_buffer_header (p5, LOAD);
2786 vlib_prefetch_buffer_header (p6, LOAD);
2787 vlib_prefetch_buffer_header (p7, LOAD);
2788
Damjan Marionaf7fb042021-07-15 11:54:41 +02002789 clib_prefetch_store (p4->data);
2790 clib_prefetch_store (p5->data);
2791 clib_prefetch_store (p6->data);
2792 clib_prefetch_store (p7->data);
Pablo Camarillofb380952016-12-07 18:34:18 +01002793 }
2794
2795 to_next[0] = bi0 = from[0];
2796 to_next[1] = bi1 = from[1];
2797 to_next[2] = bi2 = from[2];
2798 to_next[3] = bi3 = from[3];
2799 from += 4;
2800 to_next += 4;
2801 n_left_from -= 4;
2802 n_left_to_next -= 4;
2803
2804 b0 = vlib_get_buffer (vm, bi0);
2805 b1 = vlib_get_buffer (vm, bi1);
2806 b2 = vlib_get_buffer (vm, bi2);
2807 b3 = vlib_get_buffer (vm, bi3);
2808
2809 sl0 =
2810 pool_elt_at_index (sm->sid_lists,
2811 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2812 sl1 =
2813 pool_elt_at_index (sm->sid_lists,
2814 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2815 sl2 =
2816 pool_elt_at_index (sm->sid_lists,
2817 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2818 sl3 =
2819 pool_elt_at_index (sm->sid_lists,
2820 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00002821 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2822 vec_len (sl0->rewrite_bsid));
2823 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2824 vec_len (sl1->rewrite_bsid));
2825 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2826 vec_len (sl2->rewrite_bsid));
2827 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2828 vec_len (sl3->rewrite_bsid));
Pablo Camarillofb380952016-12-07 18:34:18 +01002829
2830 ip0 = vlib_buffer_get_current (b0);
2831 ip1 = vlib_buffer_get_current (b1);
2832 ip2 = vlib_buffer_get_current (b2);
2833 ip3 = vlib_buffer_get_current (b3);
2834
2835 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2836 sr0 =
2837 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2838 ip6_ext_header_len (ip0 + 1));
2839 else
2840 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2841
2842 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2843 sr1 =
2844 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2845 ip6_ext_header_len (ip1 + 1));
2846 else
2847 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2848
2849 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2850 sr2 =
2851 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2852 ip6_ext_header_len (ip2 + 1));
2853 else
2854 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2855
2856 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2857 sr3 =
2858 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2859 ip6_ext_header_len (ip3 + 1));
2860 else
2861 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2862
Dave Barach178cf492018-11-13 16:34:13 -05002863 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite_bsid),
2864 (u8 *) ip0, (void *) sr0 - (void *) ip0);
2865 clib_memcpy_fast ((u8 *) ip1 - vec_len (sl1->rewrite_bsid),
2866 (u8 *) ip1, (void *) sr1 - (void *) ip1);
2867 clib_memcpy_fast ((u8 *) ip2 - vec_len (sl2->rewrite_bsid),
2868 (u8 *) ip2, (void *) sr2 - (void *) ip2);
2869 clib_memcpy_fast ((u8 *) ip3 - vec_len (sl3->rewrite_bsid),
2870 (u8 *) ip3, (void *) sr3 - (void *) ip3);
Pablo Camarillofb380952016-12-07 18:34:18 +01002871
Dave Barach178cf492018-11-13 16:34:13 -05002872 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2873 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2874 clib_memcpy_fast (((u8 *) sr1 - vec_len (sl1->rewrite_bsid)),
2875 sl1->rewrite_bsid, vec_len (sl1->rewrite_bsid));
2876 clib_memcpy_fast (((u8 *) sr2 - vec_len (sl2->rewrite_bsid)),
2877 sl2->rewrite_bsid, vec_len (sl2->rewrite_bsid));
2878 clib_memcpy_fast (((u8 *) sr3 - vec_len (sl3->rewrite_bsid)),
2879 sl3->rewrite_bsid, vec_len (sl3->rewrite_bsid));
Pablo Camarillofb380952016-12-07 18:34:18 +01002880
2881 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2882 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite_bsid));
2883 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite_bsid));
2884 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite_bsid));
2885
2886 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2887 ip1 = ((void *) ip1) - vec_len (sl1->rewrite_bsid);
2888 ip2 = ((void *) ip2) - vec_len (sl2->rewrite_bsid);
2889 ip3 = ((void *) ip3) - vec_len (sl3->rewrite_bsid);
2890
2891 ip0->hop_limit -= 1;
2892 ip1->hop_limit -= 1;
2893 ip2->hop_limit -= 1;
2894 ip3->hop_limit -= 1;
2895
2896 new_l0 =
2897 clib_net_to_host_u16 (ip0->payload_length) +
2898 vec_len (sl0->rewrite_bsid);
2899 new_l1 =
2900 clib_net_to_host_u16 (ip1->payload_length) +
2901 vec_len (sl1->rewrite_bsid);
2902 new_l2 =
2903 clib_net_to_host_u16 (ip2->payload_length) +
2904 vec_len (sl2->rewrite_bsid);
2905 new_l3 =
2906 clib_net_to_host_u16 (ip3->payload_length) +
2907 vec_len (sl3->rewrite_bsid);
2908
2909 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2910 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2911 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2912 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2913
2914 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2915 sr1 = ((void *) sr1) - vec_len (sl1->rewrite_bsid);
2916 sr2 = ((void *) sr2) - vec_len (sl2->rewrite_bsid);
2917 sr3 = ((void *) sr3) - vec_len (sl3->rewrite_bsid);
2918
2919 ip0->dst_address.as_u64[0] =
2920 (sr0->segments + sr0->segments_left)->as_u64[0];
2921 ip0->dst_address.as_u64[1] =
2922 (sr0->segments + sr0->segments_left)->as_u64[1];
2923 ip1->dst_address.as_u64[0] =
2924 (sr1->segments + sr1->segments_left)->as_u64[0];
2925 ip1->dst_address.as_u64[1] =
2926 (sr1->segments + sr1->segments_left)->as_u64[1];
2927 ip2->dst_address.as_u64[0] =
2928 (sr2->segments + sr2->segments_left)->as_u64[0];
2929 ip2->dst_address.as_u64[1] =
2930 (sr2->segments + sr2->segments_left)->as_u64[1];
2931 ip3->dst_address.as_u64[0] =
2932 (sr3->segments + sr3->segments_left)->as_u64[0];
2933 ip3->dst_address.as_u64[1] =
2934 (sr3->segments + sr3->segments_left)->as_u64[1];
2935
2936 ip6_ext_header_t *ip_ext;
2937 if (ip0 + 1 == (void *) sr0)
2938 {
2939 sr0->protocol = ip0->protocol;
2940 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2941 }
2942 else
2943 {
2944 ip_ext = (void *) (ip0 + 1);
2945 sr0->protocol = ip_ext->next_hdr;
2946 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2947 }
2948
2949 if (ip1 + 1 == (void *) sr1)
2950 {
2951 sr1->protocol = ip1->protocol;
2952 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2953 }
2954 else
2955 {
2956 ip_ext = (void *) (ip2 + 1);
2957 sr2->protocol = ip_ext->next_hdr;
2958 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2959 }
2960
2961 if (ip2 + 1 == (void *) sr2)
2962 {
2963 sr2->protocol = ip2->protocol;
2964 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2965 }
2966 else
2967 {
2968 ip_ext = (void *) (ip2 + 1);
2969 sr2->protocol = ip_ext->next_hdr;
2970 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2971 }
2972
2973 if (ip3 + 1 == (void *) sr3)
2974 {
2975 sr3->protocol = ip3->protocol;
2976 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2977 }
2978 else
2979 {
2980 ip_ext = (void *) (ip3 + 1);
2981 sr3->protocol = ip_ext->next_hdr;
2982 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2983 }
2984
2985 insert_pkts += 4;
2986
2987 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2988 {
2989 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2990 {
2991 sr_policy_rewrite_trace_t *tr =
2992 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002993 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2994 sizeof (tr->src.as_u8));
2995 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2996 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002997 }
2998
2999 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
3000 {
3001 sr_policy_rewrite_trace_t *tr =
3002 vlib_add_trace (vm, node, b1, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003003 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
3004 sizeof (tr->src.as_u8));
3005 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
3006 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003007 }
3008
3009 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
3010 {
3011 sr_policy_rewrite_trace_t *tr =
3012 vlib_add_trace (vm, node, b2, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003013 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
3014 sizeof (tr->src.as_u8));
3015 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
3016 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003017 }
3018
3019 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
3020 {
3021 sr_policy_rewrite_trace_t *tr =
3022 vlib_add_trace (vm, node, b3, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003023 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
3024 sizeof (tr->src.as_u8));
3025 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
3026 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003027 }
3028 }
3029
3030 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
3031 n_left_to_next, bi0, bi1, bi2, bi3,
3032 next0, next1, next2, next3);
3033 }
3034
3035 /* Single loop for potentially the last three packets */
3036 while (n_left_from > 0 && n_left_to_next > 0)
3037 {
3038 u32 bi0;
3039 vlib_buffer_t *b0;
3040 ip6_header_t *ip0 = 0;
3041 ip6_sr_header_t *sr0 = 0;
3042 ip6_sr_sl_t *sl0;
3043 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3044 u16 new_l0 = 0;
3045
3046 bi0 = from[0];
3047 to_next[0] = bi0;
3048 from += 1;
3049 to_next += 1;
3050 n_left_from -= 1;
3051 n_left_to_next -= 1;
3052
3053 b0 = vlib_get_buffer (vm, bi0);
3054 sl0 =
3055 pool_elt_at_index (sm->sid_lists,
3056 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00003057 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3058 vec_len (sl0->rewrite_bsid));
Pablo Camarillofb380952016-12-07 18:34:18 +01003059
3060 ip0 = vlib_buffer_get_current (b0);
3061
3062 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
3063 sr0 =
3064 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
3065 ip6_ext_header_len (ip0 + 1));
3066 else
3067 sr0 = (ip6_sr_header_t *) (ip0 + 1);
3068
Dave Barach178cf492018-11-13 16:34:13 -05003069 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite_bsid),
3070 (u8 *) ip0, (void *) sr0 - (void *) ip0);
3071 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
3072 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
Pablo Camarillofb380952016-12-07 18:34:18 +01003073
3074 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
3075
3076 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
3077 ip0->hop_limit -= 1;
3078 new_l0 =
3079 clib_net_to_host_u16 (ip0->payload_length) +
3080 vec_len (sl0->rewrite_bsid);
3081 ip0->payload_length = clib_host_to_net_u16 (new_l0);
3082
3083 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
3084
3085 ip0->dst_address.as_u64[0] =
3086 (sr0->segments + sr0->segments_left)->as_u64[0];
3087 ip0->dst_address.as_u64[1] =
3088 (sr0->segments + sr0->segments_left)->as_u64[1];
3089
3090 if (ip0 + 1 == (void *) sr0)
3091 {
3092 sr0->protocol = ip0->protocol;
3093 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
3094 }
3095 else
3096 {
3097 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
3098 sr0->protocol = ip_ext->next_hdr;
3099 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
3100 }
3101
3102 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3103 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3104 {
3105 sr_policy_rewrite_trace_t *tr =
3106 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003107 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3108 sizeof (tr->src.as_u8));
3109 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3110 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003111 }
3112
3113 insert_pkts++;
3114
3115 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3116 n_left_to_next, bi0, next0);
3117 }
3118
3119 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3120 }
3121
3122 /* Update counters */
3123 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
3124 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3125 insert_pkts);
3126 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
3127 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3128 bsid_pkts);
3129 return from_frame->n_vectors;
3130}
3131
3132/* *INDENT-OFF* */
3133VLIB_REGISTER_NODE (sr_policy_rewrite_b_insert_node) = {
3134 .function = sr_policy_rewrite_b_insert,
3135 .name = "sr-pl-rewrite-b-insert",
3136 .vector_size = sizeof (u32),
3137 .format_trace = format_sr_policy_rewrite_trace,
3138 .type = VLIB_NODE_TYPE_INTERNAL,
3139 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3140 .error_strings = sr_policy_rewrite_error_strings,
3141 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3142 .next_nodes = {
3143#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3144 foreach_sr_policy_rewrite_next
3145#undef _
3146 },
3147};
3148/* *INDENT-ON* */
3149
3150/**
3151 * @brief Function BSID encapsulation
3152 */
3153static_always_inline void
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +00003154end_bsid_encaps_srh_processing (vlib_node_runtime_t *node, vlib_buffer_t *b0,
3155 ip6_header_t *ip0, ip6_sr_header_t *sr0,
3156 u32 *next0, u8 policy_type)
Pablo Camarillofb380952016-12-07 18:34:18 +01003157{
3158 ip6_address_t *new_dst0;
3159
3160 if (PREDICT_FALSE (!sr0))
3161 goto error_bsid_encaps;
3162
3163 if (PREDICT_TRUE (sr0->type == ROUTING_HEADER_TYPE_SR))
3164 {
3165 if (PREDICT_TRUE (sr0->segments_left != 0))
3166 {
3167 sr0->segments_left -= 1;
3168 new_dst0 = (ip6_address_t *) (sr0->segments);
3169 new_dst0 += sr0->segments_left;
3170 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
3171 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
3172 return;
3173 }
Ahmed Abdelsalam9cca6942022-06-06 15:54:02 +00003174 else if (sr0->segments_left == 0 && policy_type == SR_POLICY_TYPE_TEF)
3175 return;
Pablo Camarillofb380952016-12-07 18:34:18 +01003176 }
3177
3178error_bsid_encaps:
3179 *next0 = SR_POLICY_REWRITE_NEXT_ERROR;
3180 b0->error = node->errors[SR_POLICY_REWRITE_ERROR_BSID_ZERO];
3181}
3182
3183/**
3184 * @brief Graph node for applying a SR policy BSID - Encapsulation
3185 */
3186static uword
3187sr_policy_rewrite_b_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
3188 vlib_frame_t * from_frame)
3189{
3190 ip6_sr_main_t *sm = &sr_main;
3191 u32 n_left_from, next_index, *from, *to_next;
3192
3193 from = vlib_frame_vector_args (from_frame);
3194 n_left_from = from_frame->n_vectors;
3195
3196 next_index = node->cached_next_index;
3197
3198 int encap_pkts = 0, bsid_pkts = 0;
3199
3200 while (n_left_from > 0)
3201 {
3202 u32 n_left_to_next;
3203
3204 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
3205
3206 /* Quad - Loop */
3207 while (n_left_from >= 8 && n_left_to_next >= 4)
3208 {
3209 u32 bi0, bi1, bi2, bi3;
3210 vlib_buffer_t *b0, *b1, *b2, *b3;
3211 u32 next0, next1, next2, next3;
3212 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3213 ip6_header_t *ip0, *ip1, *ip2, *ip3;
3214 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
3215 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
Pablo Camarillofb380952016-12-07 18:34:18 +01003216 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
3217
3218 /* Prefetch next iteration. */
3219 {
3220 vlib_buffer_t *p4, *p5, *p6, *p7;
3221
3222 p4 = vlib_get_buffer (vm, from[4]);
3223 p5 = vlib_get_buffer (vm, from[5]);
3224 p6 = vlib_get_buffer (vm, from[6]);
3225 p7 = vlib_get_buffer (vm, from[7]);
3226
3227 /* Prefetch the buffer header and packet for the N+2 loop iteration */
3228 vlib_prefetch_buffer_header (p4, LOAD);
3229 vlib_prefetch_buffer_header (p5, LOAD);
3230 vlib_prefetch_buffer_header (p6, LOAD);
3231 vlib_prefetch_buffer_header (p7, LOAD);
3232
Damjan Marionaf7fb042021-07-15 11:54:41 +02003233 clib_prefetch_store (p4->data);
3234 clib_prefetch_store (p5->data);
3235 clib_prefetch_store (p6->data);
3236 clib_prefetch_store (p7->data);
Pablo Camarillofb380952016-12-07 18:34:18 +01003237 }
3238
3239 to_next[0] = bi0 = from[0];
3240 to_next[1] = bi1 = from[1];
3241 to_next[2] = bi2 = from[2];
3242 to_next[3] = bi3 = from[3];
3243 from += 4;
3244 to_next += 4;
3245 n_left_from -= 4;
3246 n_left_to_next -= 4;
3247
3248 b0 = vlib_get_buffer (vm, bi0);
3249 b1 = vlib_get_buffer (vm, bi1);
3250 b2 = vlib_get_buffer (vm, bi2);
3251 b3 = vlib_get_buffer (vm, bi3);
3252
3253 sl0 =
3254 pool_elt_at_index (sm->sid_lists,
3255 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3256 sl1 =
3257 pool_elt_at_index (sm->sid_lists,
3258 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
3259 sl2 =
3260 pool_elt_at_index (sm->sid_lists,
3261 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
3262 sl3 =
3263 pool_elt_at_index (sm->sid_lists,
3264 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00003265 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3266 vec_len (sl0->rewrite));
3267 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3268 vec_len (sl1->rewrite));
3269 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3270 vec_len (sl2->rewrite));
3271 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3272 vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01003273
3274 ip0_encap = vlib_buffer_get_current (b0);
3275 ip1_encap = vlib_buffer_get_current (b1);
3276 ip2_encap = vlib_buffer_get_current (b2);
3277 ip3_encap = vlib_buffer_get_current (b3);
3278
Klement Sekera769145c2019-03-06 11:59:57 +01003279 sr0 =
3280 ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
3281 NULL);
3282 sr1 =
3283 ip6_ext_header_find (vm, b1, ip1_encap, IP_PROTOCOL_IPV6_ROUTE,
3284 NULL);
3285 sr2 =
3286 ip6_ext_header_find (vm, b2, ip2_encap, IP_PROTOCOL_IPV6_ROUTE,
3287 NULL);
3288 sr3 =
3289 ip6_ext_header_find (vm, b3, ip3_encap, IP_PROTOCOL_IPV6_ROUTE,
3290 NULL);
Pablo Camarillofb380952016-12-07 18:34:18 +01003291
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +00003292 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0,
3293 sl0->policy_type);
3294 end_bsid_encaps_srh_processing (node, b1, ip1_encap, sr1, &next1,
3295 sl1->policy_type);
3296 end_bsid_encaps_srh_processing (node, b2, ip2_encap, sr2, &next2,
3297 sl2->policy_type);
3298 end_bsid_encaps_srh_processing (node, b3, ip3_encap, sr3, &next3,
3299 sl3->policy_type);
Pablo Camarillofb380952016-12-07 18:34:18 +01003300
Dave Barach178cf492018-11-13 16:34:13 -05003301 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3302 sl0->rewrite, vec_len (sl0->rewrite));
3303 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
3304 sl1->rewrite, vec_len (sl1->rewrite));
3305 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
3306 sl2->rewrite, vec_len (sl2->rewrite));
3307 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
3308 sl3->rewrite, vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01003309
3310 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3311 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
3312 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
3313 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
3314
3315 ip0 = vlib_buffer_get_current (b0);
3316 ip1 = vlib_buffer_get_current (b1);
3317 ip2 = vlib_buffer_get_current (b2);
3318 ip3 = vlib_buffer_get_current (b3);
3319
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +00003320 encaps_processing_v6 (node, b0, ip0, ip0_encap, sl0->policy_type);
3321 encaps_processing_v6 (node, b1, ip1, ip1_encap, sl1->policy_type);
3322 encaps_processing_v6 (node, b2, ip2, ip2_encap, sl2->policy_type);
3323 encaps_processing_v6 (node, b3, ip3, ip3_encap, sl3->policy_type);
Pablo Camarillofb380952016-12-07 18:34:18 +01003324
3325 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
3326 {
3327 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3328 {
3329 sr_policy_rewrite_trace_t *tr =
3330 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003331 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3332 sizeof (tr->src.as_u8));
3333 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3334 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003335 }
3336
3337 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
3338 {
3339 sr_policy_rewrite_trace_t *tr =
3340 vlib_add_trace (vm, node, b1, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003341 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
3342 sizeof (tr->src.as_u8));
3343 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
3344 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003345 }
3346
3347 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
3348 {
3349 sr_policy_rewrite_trace_t *tr =
3350 vlib_add_trace (vm, node, b2, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003351 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
3352 sizeof (tr->src.as_u8));
3353 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
3354 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003355 }
3356
3357 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
3358 {
3359 sr_policy_rewrite_trace_t *tr =
3360 vlib_add_trace (vm, node, b3, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003361 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
3362 sizeof (tr->src.as_u8));
3363 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
3364 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003365 }
3366 }
3367
3368 encap_pkts += 4;
3369 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
3370 n_left_to_next, bi0, bi1, bi2, bi3,
3371 next0, next1, next2, next3);
3372 }
3373
3374 /* Single loop for potentially the last three packets */
3375 while (n_left_from > 0 && n_left_to_next > 0)
3376 {
3377 u32 bi0;
3378 vlib_buffer_t *b0;
3379 ip6_header_t *ip0 = 0, *ip0_encap = 0;
Pablo Camarillofb380952016-12-07 18:34:18 +01003380 ip6_sr_header_t *sr0;
3381 ip6_sr_sl_t *sl0;
3382 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3383
3384 bi0 = from[0];
3385 to_next[0] = bi0;
3386 from += 1;
3387 to_next += 1;
3388 n_left_from -= 1;
3389 n_left_to_next -= 1;
3390 b0 = vlib_get_buffer (vm, bi0);
3391
3392 sl0 =
3393 pool_elt_at_index (sm->sid_lists,
3394 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00003395 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3396 vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01003397
3398 ip0_encap = vlib_buffer_get_current (b0);
Klement Sekera769145c2019-03-06 11:59:57 +01003399 sr0 =
3400 ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
3401 NULL);
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +00003402 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0,
3403 sl0->policy_type);
Pablo Camarillofb380952016-12-07 18:34:18 +01003404
Dave Barach178cf492018-11-13 16:34:13 -05003405 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3406 sl0->rewrite, vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01003407 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3408
3409 ip0 = vlib_buffer_get_current (b0);
3410
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +00003411 encaps_processing_v6 (node, b0, ip0, ip0_encap, sl0->policy_type);
Pablo Camarillofb380952016-12-07 18:34:18 +01003412
3413 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3414 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3415 {
3416 sr_policy_rewrite_trace_t *tr =
3417 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003418 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3419 sizeof (tr->src.as_u8));
3420 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3421 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003422 }
3423
3424 encap_pkts++;
3425 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3426 n_left_to_next, bi0, next0);
3427 }
3428
3429 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3430 }
3431
3432 /* Update counters */
3433 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3434 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3435 encap_pkts);
3436 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3437 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3438 bsid_pkts);
3439
3440 return from_frame->n_vectors;
3441}
3442
3443/* *INDENT-OFF* */
3444VLIB_REGISTER_NODE (sr_policy_rewrite_b_encaps_node) = {
3445 .function = sr_policy_rewrite_b_encaps,
3446 .name = "sr-pl-rewrite-b-encaps",
3447 .vector_size = sizeof (u32),
3448 .format_trace = format_sr_policy_rewrite_trace,
3449 .type = VLIB_NODE_TYPE_INTERNAL,
3450 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3451 .error_strings = sr_policy_rewrite_error_strings,
3452 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3453 .next_nodes = {
3454#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3455 foreach_sr_policy_rewrite_next
3456#undef _
3457 },
3458};
3459/* *INDENT-ON* */
3460
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -08003461/*************************** SR Policy plugins ******************************/
3462/**
3463 * @brief SR Policy plugin registry
3464 */
3465int
3466sr_policy_register_function (vlib_main_t * vm, u8 * fn_name,
3467 u8 * keyword_str, u8 * def_str,
3468 u8 * params_str, u8 prefix_length,
3469 dpo_type_t * dpo,
3470 format_function_t * ls_format,
3471 unformat_function_t * ls_unformat,
3472 sr_p_plugin_callback_t * creation_fn,
3473 sr_p_plugin_callback_t * removal_fn)
3474{
3475 ip6_sr_main_t *sm = &sr_main;
3476 uword *p;
3477
3478 sr_policy_fn_registration_t *plugin;
3479
3480 /* Did this function exist? If so update it */
3481 p = hash_get_mem (sm->policy_plugin_functions_by_key, fn_name);
3482 if (p)
3483 {
3484 plugin = pool_elt_at_index (sm->policy_plugin_functions, p[0]);
3485 }
3486 /* Else create a new one and set hash key */
3487 else
3488 {
3489 pool_get (sm->policy_plugin_functions, plugin);
3490 hash_set_mem (sm->policy_plugin_functions_by_key, fn_name,
3491 plugin - sm->policy_plugin_functions);
3492 }
3493
3494 clib_memset (plugin, 0, sizeof (*plugin));
3495
3496 plugin->sr_policy_function_number = (plugin - sm->policy_plugin_functions);
3497 plugin->sr_policy_function_number += SR_BEHAVIOR_LAST;
3498 plugin->prefix_length = prefix_length;
3499 plugin->ls_format = ls_format;
3500 plugin->ls_unformat = ls_unformat;
3501 plugin->creation = creation_fn;
3502 plugin->removal = removal_fn;
3503 clib_memcpy (&plugin->dpo, dpo, sizeof (dpo_type_t));
3504 plugin->function_name = format (0, "%s%c", fn_name, 0);
3505 plugin->keyword_str = format (0, "%s%c", keyword_str, 0);
3506 plugin->def_str = format (0, "%s%c", def_str, 0);
3507 plugin->params_str = format (0, "%s%c", params_str, 0);
3508
3509 return plugin->sr_policy_function_number;
3510}
3511
3512/**
3513 * @brief CLI function to 'show' all available SR LocalSID behaviors
3514 */
3515static clib_error_t *
3516show_sr_policy_behaviors_command_fn (vlib_main_t * vm,
3517 unformat_input_t * input,
3518 vlib_cli_command_t * cmd)
3519{
3520 ip6_sr_main_t *sm = &sr_main;
3521 sr_policy_fn_registration_t *plugin;
3522 sr_policy_fn_registration_t **plugins_vec = 0;
3523 int i;
3524
3525 vlib_cli_output (vm, "SR Policy behaviors:\n-----------------------\n\n");
3526
3527 /* *INDENT-OFF* */
Damjan Marionb2c31b62020-12-13 21:47:40 +01003528 pool_foreach (plugin, sm->policy_plugin_functions)
3529 { vec_add1 (plugins_vec, plugin); }
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -08003530 /* *INDENT-ON* */
3531
3532 vlib_cli_output (vm, "Plugin behaviors:\n");
3533 for (i = 0; i < vec_len (plugins_vec); i++)
3534 {
3535 plugin = plugins_vec[i];
3536 vlib_cli_output (vm, "\t%s\t-> %s.\n", plugin->keyword_str,
3537 plugin->def_str);
3538 vlib_cli_output (vm, "\t\tParameters: '%s'\n", plugin->params_str);
3539 }
3540 return 0;
3541}
3542
3543/* *INDENT-OFF* */
3544VLIB_CLI_COMMAND (show_sr_policy_behaviors_command, static) = {
3545 .path = "show sr policy behaviors",
3546 .short_help = "show sr policy behaviors",
3547 .function = show_sr_policy_behaviors_command_fn,
3548};
3549/* *INDENT-ON* */
3550
Pablo Camarillofb380952016-12-07 18:34:18 +01003551/*************************** SR Segment Lists DPOs ****************************/
3552static u8 *
3553format_sr_segment_list_dpo (u8 * s, va_list * args)
3554{
3555 ip6_sr_main_t *sm = &sr_main;
3556 ip6_address_t *addr;
3557 ip6_sr_sl_t *sl;
3558
3559 index_t index = va_arg (*args, index_t);
3560 CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
3561 s = format (s, "SR: Segment List index:[%d]", index);
3562 s = format (s, "\n\tSegments:");
3563
3564 sl = pool_elt_at_index (sm->sid_lists, index);
3565
3566 s = format (s, "< ");
3567 vec_foreach (addr, sl->segments)
3568 {
3569 s = format (s, "%U, ", format_ip6_address, addr);
3570 }
3571 s = format (s, "\b\b > - ");
3572 s = format (s, "Weight: %u", sl->weight);
3573
3574 return s;
3575}
3576
3577const static dpo_vft_t sr_policy_rewrite_vft = {
3578 .dv_lock = sr_dpo_lock,
3579 .dv_unlock = sr_dpo_unlock,
3580 .dv_format = format_sr_segment_list_dpo,
3581};
3582
3583const static char *const sr_pr_encaps_ip6_nodes[] = {
3584 "sr-pl-rewrite-encaps",
3585 NULL,
3586};
3587
3588const static char *const sr_pr_encaps_ip4_nodes[] = {
3589 "sr-pl-rewrite-encaps-v4",
3590 NULL,
3591};
3592
3593const static char *const *const sr_pr_encaps_nodes[DPO_PROTO_NUM] = {
3594 [DPO_PROTO_IP6] = sr_pr_encaps_ip6_nodes,
3595 [DPO_PROTO_IP4] = sr_pr_encaps_ip4_nodes,
3596};
3597
3598const static char *const sr_pr_insert_ip6_nodes[] = {
3599 "sr-pl-rewrite-insert",
3600 NULL,
3601};
3602
3603const static char *const *const sr_pr_insert_nodes[DPO_PROTO_NUM] = {
3604 [DPO_PROTO_IP6] = sr_pr_insert_ip6_nodes,
3605};
3606
3607const static char *const sr_pr_bsid_insert_ip6_nodes[] = {
3608 "sr-pl-rewrite-b-insert",
3609 NULL,
3610};
3611
3612const static char *const *const sr_pr_bsid_insert_nodes[DPO_PROTO_NUM] = {
3613 [DPO_PROTO_IP6] = sr_pr_bsid_insert_ip6_nodes,
3614};
3615
3616const static char *const sr_pr_bsid_encaps_ip6_nodes[] = {
3617 "sr-pl-rewrite-b-encaps",
3618 NULL,
3619};
3620
3621const static char *const *const sr_pr_bsid_encaps_nodes[DPO_PROTO_NUM] = {
3622 [DPO_PROTO_IP6] = sr_pr_bsid_encaps_ip6_nodes,
3623};
3624
3625/********************* SR Policy Rewrite initialization ***********************/
3626/**
3627 * @brief SR Policy Rewrite initialization
3628 */
3629clib_error_t *
3630sr_policy_rewrite_init (vlib_main_t * vm)
3631{
3632 ip6_sr_main_t *sm = &sr_main;
3633
3634 /* Init memory for sr policy keys (bsid <-> ip6_address_t) */
Pablo Camarillo4521afa2017-03-16 10:43:05 +01003635 mhash_init (&sm->sr_policies_index_hash, sizeof (uword),
3636 sizeof (ip6_address_t));
Pablo Camarillofb380952016-12-07 18:34:18 +01003637
3638 /* Init SR VPO DPOs type */
3639 sr_pr_encaps_dpo_type =
3640 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_encaps_nodes);
3641
3642 sr_pr_insert_dpo_type =
3643 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_insert_nodes);
3644
3645 sr_pr_bsid_encaps_dpo_type =
3646 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_encaps_nodes);
3647
3648 sr_pr_bsid_insert_dpo_type =
3649 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_insert_nodes);
3650
3651 /* Register the L2 encaps node used in HW redirect */
3652 sm->l2_sr_policy_rewrite_index = sr_policy_rewrite_encaps_node.index;
3653
3654 sm->fib_table_ip6 = (u32) ~ 0;
3655 sm->fib_table_ip4 = (u32) ~ 0;
3656
3657 return 0;
3658}
3659
3660VLIB_INIT_FUNCTION (sr_policy_rewrite_init);
3661
3662
3663/*
3664* fd.io coding-style-patch-verification: ON
3665*
3666* Local Variables:
3667* eval: (c-set-style "gnu")
3668* End:
3669*/