blob: fdbf0dd08fa5be3ee304efeff60b5ec009bcee9e [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;
202 ip6_address_t *addrp, *this_address;
203 u32 header_length = 0;
204 u8 *rs = NULL;
205
206 header_length = 0;
207 header_length += IPv6_DEFAULT_HEADER_LENGTH;
208 if (vec_len (sl) > 1)
209 {
210 header_length += sizeof (ip6_sr_header_t);
211 header_length += vec_len (sl) * sizeof (ip6_address_t);
212 }
213
214 vec_validate (rs, header_length - 1);
215
216 iph = (ip6_header_t *) rs;
217 iph->ip_version_traffic_class_and_flow_label =
218 clib_host_to_net_u32 (0 | ((6 & 0xF) << 28));
219 iph->src_address.as_u64[0] = sr_pr_encaps_src.as_u64[0];
220 iph->src_address.as_u64[1] = sr_pr_encaps_src.as_u64[1];
221 iph->payload_length = header_length - IPv6_DEFAULT_HEADER_LENGTH;
222 iph->protocol = IP_PROTOCOL_IPV6;
Ignas Bačiuseeb5fb32019-10-03 17:15:38 +0300223 iph->hop_limit = sr_pr_encaps_hop_limit;
Pablo Camarillofb380952016-12-07 18:34:18 +0100224
Pablo Camarillod327c872018-01-08 14:25:55 +0100225 if (vec_len (sl) > 1)
226 {
227 srh = (ip6_sr_header_t *) (iph + 1);
228 iph->protocol = IP_PROTOCOL_IPV6_ROUTE;
229 srh->protocol = IP_PROTOCOL_IPV6;
230 srh->type = ROUTING_HEADER_TYPE_SR;
231 srh->segments_left = vec_len (sl) - 1;
Ahmed Abdelsalambe837042019-06-20 11:18:57 +0000232 srh->last_entry = vec_len (sl) - 1;
Pablo Camarillod327c872018-01-08 14:25:55 +0100233 srh->length = ((sizeof (ip6_sr_header_t) +
234 (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
235 srh->flags = 0x00;
Ahmed Abdelsalambe837042019-06-20 11:18:57 +0000236 srh->tag = 0x0000;
Pablo Camarillod327c872018-01-08 14:25:55 +0100237 addrp = srh->segments + vec_len (sl) - 1;
238 vec_foreach (this_address, sl)
239 {
Dave Barach178cf492018-11-13 16:34:13 -0500240 clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
241 sizeof (ip6_address_t));
Pablo Camarillod327c872018-01-08 14:25:55 +0100242 addrp--;
243 }
244 }
Pablo Camarillofb380952016-12-07 18:34:18 +0100245 iph->dst_address.as_u64[0] = sl->as_u64[0];
246 iph->dst_address.as_u64[1] = sl->as_u64[1];
247 return rs;
248}
249
250/**
251 * @brief SR rewrite string computation for SRH insertion (inline)
252 *
253 * @param sl is a vector of IPv6 addresses composing the Segment List
254 *
255 * @return precomputed rewrite string for SRH insertion
256 */
257static inline u8 *
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +0000258compute_rewrite_insert (ip6_address_t *sl, u8 type)
Pablo Camarillofb380952016-12-07 18:34:18 +0100259{
260 ip6_sr_header_t *srh;
261 ip6_address_t *addrp, *this_address;
262 u32 header_length = 0;
263 u8 *rs = NULL;
264
265 header_length = 0;
266 header_length += sizeof (ip6_sr_header_t);
267 header_length += (vec_len (sl) + 1) * sizeof (ip6_address_t);
268
269 vec_validate (rs, header_length - 1);
270
271 srh = (ip6_sr_header_t *) rs;
272 srh->type = ROUTING_HEADER_TYPE_SR;
273 srh->segments_left = vec_len (sl);
Ahmed Abdelsalambe837042019-06-20 11:18:57 +0000274 srh->last_entry = vec_len (sl);
Pablo Camarillofb380952016-12-07 18:34:18 +0100275 srh->length = ((sizeof (ip6_sr_header_t) +
276 ((vec_len (sl) + 1) * sizeof (ip6_address_t))) / 8) - 1;
277 srh->flags = 0x00;
Ahmed Abdelsalambe837042019-06-20 11:18:57 +0000278 srh->tag = 0x0000;
Pablo Camarillofb380952016-12-07 18:34:18 +0100279 addrp = srh->segments + vec_len (sl);
280 vec_foreach (this_address, sl)
281 {
Dave Barach178cf492018-11-13 16:34:13 -0500282 clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
283 sizeof (ip6_address_t));
Pablo Camarillofb380952016-12-07 18:34:18 +0100284 addrp--;
285 }
286 return rs;
287}
288
289/**
290 * @brief SR rewrite string computation for SRH insertion with BSID (inline)
291 *
292 * @param sl is a vector of IPv6 addresses composing the Segment List
293 *
294 * @return precomputed rewrite string for SRH insertion with BSID
295 */
296static inline u8 *
297compute_rewrite_bsid (ip6_address_t * sl)
298{
299 ip6_sr_header_t *srh;
300 ip6_address_t *addrp, *this_address;
301 u32 header_length = 0;
302 u8 *rs = NULL;
303
304 header_length = 0;
305 header_length += sizeof (ip6_sr_header_t);
306 header_length += vec_len (sl) * sizeof (ip6_address_t);
307
308 vec_validate (rs, header_length - 1);
309
310 srh = (ip6_sr_header_t *) rs;
311 srh->type = ROUTING_HEADER_TYPE_SR;
312 srh->segments_left = vec_len (sl) - 1;
Ahmed Abdelsalambe837042019-06-20 11:18:57 +0000313 srh->last_entry = vec_len (sl) - 1;
Pablo Camarillofb380952016-12-07 18:34:18 +0100314 srh->length = ((sizeof (ip6_sr_header_t) +
315 (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
316 srh->flags = 0x00;
Ahmed Abdelsalambe837042019-06-20 11:18:57 +0000317 srh->tag = 0x0000;
Pablo Camarillofb380952016-12-07 18:34:18 +0100318 addrp = srh->segments + vec_len (sl) - 1;
319 vec_foreach (this_address, sl)
320 {
Dave Barach178cf492018-11-13 16:34:13 -0500321 clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
322 sizeof (ip6_address_t));
Pablo Camarillofb380952016-12-07 18:34:18 +0100323 addrp--;
324 }
325 return rs;
326}
327
328/*************************** SR LB helper functions **************************/
329/**
330 * @brief Creates a Segment List and adds it to an SR policy
331 *
332 * Creates a Segment List and adds it to the SR policy. Notice that the SL are
333 * not necessarily unique. Hence there might be two Segment List within the
334 * same SR Policy with exactly the same segments and same weight.
335 *
336 * @param sr_policy is the SR policy where the SL will be added
337 * @param sl is a vector of IPv6 addresses composing the Segment List
338 * @param weight is the weight of the SegmentList (for load-balancing purposes)
339 * @param is_encap represents the mode (SRH insertion vs Encapsulation)
340 *
341 * @return pointer to the just created segment list
342 */
343static inline ip6_sr_sl_t *
344create_sl (ip6_sr_policy_t * sr_policy, ip6_address_t * sl, u32 weight,
345 u8 is_encap)
346{
347 ip6_sr_main_t *sm = &sr_main;
348 ip6_sr_sl_t *segment_list;
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800349 sr_policy_fn_registration_t *plugin = 0;
Pablo Camarillofb380952016-12-07 18:34:18 +0100350
351 pool_get (sm->sid_lists, segment_list);
Dave Barachb7b92992018-10-17 10:38:51 -0400352 clib_memset (segment_list, 0, sizeof (*segment_list));
Pablo Camarillofb380952016-12-07 18:34:18 +0100353
354 vec_add1 (sr_policy->segments_lists, segment_list - sm->sid_lists);
355
356 /* Fill in segment list */
357 segment_list->weight =
358 (weight != (u32) ~ 0 ? weight : SR_SEGMENT_LIST_WEIGHT_DEFAULT);
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800359
Pablo Camarillofb380952016-12-07 18:34:18 +0100360 segment_list->segments = vec_dup (sl);
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +0000361 segment_list->policy_type = sr_policy->type;
Pablo Camarillofb380952016-12-07 18:34:18 +0100362
Tetsuya Murakami6b354912021-01-31 16:38:56 -0800363 segment_list->egress_fib_table =
364 ip6_fib_index_from_table_id (sr_policy->fib_table);
365
Pablo Camarillofb380952016-12-07 18:34:18 +0100366 if (is_encap)
367 {
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +0000368 segment_list->rewrite = compute_rewrite_encaps (sl, sr_policy->type);
Pablo Camarillofb380952016-12-07 18:34:18 +0100369 segment_list->rewrite_bsid = segment_list->rewrite;
370 }
371 else
372 {
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +0000373 segment_list->rewrite = compute_rewrite_insert (sl, sr_policy->type);
Pablo Camarillofb380952016-12-07 18:34:18 +0100374 segment_list->rewrite_bsid = compute_rewrite_bsid (sl);
375 }
376
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800377 if (sr_policy->plugin)
378 {
379 plugin =
380 pool_elt_at_index (sm->policy_plugin_functions,
381 sr_policy->plugin - SR_BEHAVIOR_LAST);
382
383 segment_list->plugin = sr_policy->plugin;
384 segment_list->plugin_mem = sr_policy->plugin_mem;
385
386 plugin->creation (sr_policy);
387 }
388
Pablo Camarillofb380952016-12-07 18:34:18 +0100389 /* Create DPO */
390 dpo_reset (&segment_list->bsid_dpo);
391 dpo_reset (&segment_list->ip6_dpo);
392 dpo_reset (&segment_list->ip4_dpo);
393
394 if (is_encap)
395 {
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800396 if (!sr_policy->plugin)
397 {
398 dpo_set (&segment_list->ip6_dpo, sr_pr_encaps_dpo_type,
399 DPO_PROTO_IP6, segment_list - sm->sid_lists);
400 dpo_set (&segment_list->ip4_dpo, sr_pr_encaps_dpo_type,
401 DPO_PROTO_IP4, segment_list - sm->sid_lists);
402 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_encaps_dpo_type,
403 DPO_PROTO_IP6, segment_list - sm->sid_lists);
404 }
405 else
406 {
407 dpo_set (&segment_list->ip6_dpo, plugin->dpo, DPO_PROTO_IP6,
408 segment_list - sm->sid_lists);
409 dpo_set (&segment_list->ip4_dpo, plugin->dpo, DPO_PROTO_IP4,
410 segment_list - sm->sid_lists);
411 dpo_set (&segment_list->bsid_dpo, plugin->dpo, DPO_PROTO_IP6,
412 segment_list - sm->sid_lists);
413 }
Pablo Camarillofb380952016-12-07 18:34:18 +0100414 }
415 else
416 {
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800417 if (!sr_policy->plugin)
418 {
419 dpo_set (&segment_list->ip6_dpo, sr_pr_insert_dpo_type,
420 DPO_PROTO_IP6, segment_list - sm->sid_lists);
421 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_insert_dpo_type,
422 DPO_PROTO_IP6, segment_list - sm->sid_lists);
423 }
424 else
425 {
426 dpo_set (&segment_list->ip6_dpo, plugin->dpo, DPO_PROTO_IP6,
427 segment_list - sm->sid_lists);
428 dpo_set (&segment_list->bsid_dpo, plugin->dpo, DPO_PROTO_IP6,
429 segment_list - sm->sid_lists);
430 }
Pablo Camarillofb380952016-12-07 18:34:18 +0100431 }
432
433 return segment_list;
434}
435
436/**
Nathan Skrzypczak2c77ae42021-09-29 15:36:51 +0200437 * @brief Updates the Load-Balancer after an SR Policy change
Pablo Camarillofb380952016-12-07 18:34:18 +0100438 *
439 * @param sr_policy is the modified SR Policy
440 */
441static inline void
442update_lb (ip6_sr_policy_t * sr_policy)
443{
444 flow_hash_config_t fhc;
445 u32 *sl_index;
446 ip6_sr_sl_t *segment_list;
447 ip6_sr_main_t *sm = &sr_main;
448 load_balance_path_t path;
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100449 path.path_index = FIB_NODE_INDEX_INVALID;
Pablo Camarillofb380952016-12-07 18:34:18 +0100450 load_balance_path_t *ip4_path_vector = 0;
451 load_balance_path_t *ip6_path_vector = 0;
452 load_balance_path_t *b_path_vector = 0;
453
454 /* In case LB does not exist, create it */
455 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
456 {
457 fib_prefix_t pfx = {
458 .fp_proto = FIB_PROTOCOL_IP6,
459 .fp_len = 128,
460 .fp_addr = {
461 .ip6 = sr_policy->bsid,
462 }
463 };
464
465 /* Add FIB entry for BSID */
466 fhc = fib_table_get_flow_hash_config (sr_policy->fib_table,
Neale Rannsd792d9c2017-10-21 10:53:20 -0700467 FIB_PROTOCOL_IP6);
Pablo Camarillofb380952016-12-07 18:34:18 +0100468
469 dpo_set (&sr_policy->bsid_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
470 load_balance_create (0, DPO_PROTO_IP6, fhc));
471
472 dpo_set (&sr_policy->ip6_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
473 load_balance_create (0, DPO_PROTO_IP6, fhc));
474
475 /* Update FIB entry's to point to the LB DPO in the main FIB and hidden one */
Neale Ranns107e7d42017-04-11 09:55:19 -0700476 fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
477 sr_policy->fib_table),
478 &pfx, FIB_SOURCE_SR,
Pablo Camarillofb380952016-12-07 18:34:18 +0100479 FIB_ENTRY_FLAG_EXCLUSIVE,
480 &sr_policy->bsid_dpo);
481
482 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
483 &pfx,
484 FIB_SOURCE_SR,
485 FIB_ENTRY_FLAG_EXCLUSIVE,
486 &sr_policy->ip6_dpo);
487
488 if (sr_policy->is_encap)
489 {
490 dpo_set (&sr_policy->ip4_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP4,
491 load_balance_create (0, DPO_PROTO_IP4, fhc));
492
493 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
494 &pfx,
495 FIB_SOURCE_SR,
496 FIB_ENTRY_FLAG_EXCLUSIVE,
497 &sr_policy->ip4_dpo);
498 }
499
500 }
501
502 /* Create the LB path vector */
Pablo Camarillofb380952016-12-07 18:34:18 +0100503 vec_foreach (sl_index, sr_policy->segments_lists)
504 {
505 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
506 path.path_dpo = segment_list->bsid_dpo;
507 path.path_weight = segment_list->weight;
508 vec_add1 (b_path_vector, path);
509 path.path_dpo = segment_list->ip6_dpo;
510 vec_add1 (ip6_path_vector, path);
511 if (sr_policy->is_encap)
512 {
513 path.path_dpo = segment_list->ip4_dpo;
514 vec_add1 (ip4_path_vector, path);
515 }
516 }
517
518 /* Update LB multipath */
519 load_balance_multipath_update (&sr_policy->bsid_dpo, b_path_vector,
520 LOAD_BALANCE_FLAG_NONE);
521 load_balance_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector,
522 LOAD_BALANCE_FLAG_NONE);
523 if (sr_policy->is_encap)
524 load_balance_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector,
525 LOAD_BALANCE_FLAG_NONE);
526
527 /* Cleanup */
528 vec_free (b_path_vector);
529 vec_free (ip6_path_vector);
530 vec_free (ip4_path_vector);
Pablo Camarillofb380952016-12-07 18:34:18 +0100531}
532
533/**
534 * @brief Updates the Replicate DPO after an SR Policy change
535 *
536 * @param sr_policy is the modified SR Policy (type spray)
537 */
538static inline void
539update_replicate (ip6_sr_policy_t * sr_policy)
540{
541 u32 *sl_index;
542 ip6_sr_sl_t *segment_list;
543 ip6_sr_main_t *sm = &sr_main;
544 load_balance_path_t path;
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100545 path.path_index = FIB_NODE_INDEX_INVALID;
Pablo Camarillofb380952016-12-07 18:34:18 +0100546 load_balance_path_t *b_path_vector = 0;
547 load_balance_path_t *ip6_path_vector = 0;
548 load_balance_path_t *ip4_path_vector = 0;
549
550 /* In case LB does not exist, create it */
551 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
552 {
553 dpo_set (&sr_policy->bsid_dpo, DPO_REPLICATE,
554 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
555
556 dpo_set (&sr_policy->ip6_dpo, DPO_REPLICATE,
557 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
558
559 /* Update FIB entry's DPO to point to SR without LB */
560 fib_prefix_t pfx = {
561 .fp_proto = FIB_PROTOCOL_IP6,
562 .fp_len = 128,
563 .fp_addr = {
564 .ip6 = sr_policy->bsid,
565 }
566 };
Neale Ranns107e7d42017-04-11 09:55:19 -0700567 fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
568 sr_policy->fib_table),
569 &pfx, FIB_SOURCE_SR,
Pablo Camarillofb380952016-12-07 18:34:18 +0100570 FIB_ENTRY_FLAG_EXCLUSIVE,
571 &sr_policy->bsid_dpo);
572
573 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
574 &pfx,
575 FIB_SOURCE_SR,
576 FIB_ENTRY_FLAG_EXCLUSIVE,
577 &sr_policy->ip6_dpo);
578
579 if (sr_policy->is_encap)
580 {
581 dpo_set (&sr_policy->ip4_dpo, DPO_REPLICATE, DPO_PROTO_IP4,
582 replicate_create (0, DPO_PROTO_IP4));
583
584 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
585 &pfx,
586 FIB_SOURCE_SR,
587 FIB_ENTRY_FLAG_EXCLUSIVE,
588 &sr_policy->ip4_dpo);
589 }
590
591 }
592
593 /* Create the replicate path vector */
594 path.path_weight = 1;
595 vec_foreach (sl_index, sr_policy->segments_lists)
596 {
597 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
598 path.path_dpo = segment_list->bsid_dpo;
599 vec_add1 (b_path_vector, path);
600 path.path_dpo = segment_list->ip6_dpo;
601 vec_add1 (ip6_path_vector, path);
602 if (sr_policy->is_encap)
603 {
604 path.path_dpo = segment_list->ip4_dpo;
605 vec_add1 (ip4_path_vector, path);
606 }
607 }
608
609 /* Update replicate multipath */
610 replicate_multipath_update (&sr_policy->bsid_dpo, b_path_vector);
611 replicate_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector);
612 if (sr_policy->is_encap)
613 replicate_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector);
Pablo Camarillofb380952016-12-07 18:34:18 +0100614}
615
616/******************************* SR rewrite API *******************************/
617/* Three functions for handling sr policies:
618 * -> sr_policy_add
619 * -> sr_policy_del
620 * -> sr_policy_mod
621 * All of them are API. CLI function on sr_policy_command_fn */
622
623/**
624 * @brief Create a new SR policy
625 *
626 * @param bsid is the bindingSID of the SR Policy
627 * @param segments is a vector of IPv6 address composing the segment list
628 * @param weight is the weight of the sid list. optional.
629 * @param behavior is the behavior of the SR policy. (default//spray)
630 * @param fib_table is the VRF where to install the FIB entry for the BSID
631 * @param is_encap (bool) whether SR policy should behave as Encap/SRH Insertion
632 *
633 * @return 0 if correct, else error
634 */
635int
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +0000636sr_policy_add (ip6_address_t *bsid, ip6_address_t *segments, u32 weight,
637 u8 type, u32 fib_table, u8 is_encap, u16 plugin,
638 void *ls_plugin_mem)
Pablo Camarillofb380952016-12-07 18:34:18 +0100639{
640 ip6_sr_main_t *sm = &sr_main;
641 ip6_sr_policy_t *sr_policy = 0;
Pablo Camarillofb380952016-12-07 18:34:18 +0100642 uword *p;
643
644 /* Search for existing keys (BSID) */
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100645 p = mhash_get (&sm->sr_policies_index_hash, bsid);
Pablo Camarillofb380952016-12-07 18:34:18 +0100646 if (p)
647 {
648 /* Add SR policy that already exists; complain */
649 return -12;
650 }
651
652 /* Search collision in FIB entries */
653 /* Explanation: It might be possible that some other entity has already
654 * created a route for the BSID. This in theory is impossible, but in
655 * practise we could see it. Assert it and scream if needed */
656 fib_prefix_t pfx = {
657 .fp_proto = FIB_PROTOCOL_IP6,
658 .fp_len = 128,
659 .fp_addr = {
660 .ip6 = *bsid,
661 }
662 };
663
664 /* Lookup the FIB index associated to the table selected */
Neale Ranns107e7d42017-04-11 09:55:19 -0700665 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP6,
666 (fib_table != (u32) ~ 0 ? fib_table : 0));
Pablo Camarillofb380952016-12-07 18:34:18 +0100667 if (fib_index == ~0)
668 return -13;
669
670 /* Lookup whether there exists an entry for the BSID */
671 fib_node_index_t fei = fib_table_lookup_exact_match (fib_index, &pfx);
672 if (FIB_NODE_INDEX_INVALID != fei)
673 return -12; //There is an entry for such lookup
674
675 /* Add an SR policy object */
676 pool_get (sm->sr_policies, sr_policy);
Dave Barachb7b92992018-10-17 10:38:51 -0400677 clib_memset (sr_policy, 0, sizeof (*sr_policy));
Dave Barach178cf492018-11-13 16:34:13 -0500678 clib_memcpy_fast (&sr_policy->bsid, bsid, sizeof (ip6_address_t));
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +0000679 sr_policy->type = type;
Pablo Camarillofb380952016-12-07 18:34:18 +0100680 sr_policy->fib_table = (fib_table != (u32) ~ 0 ? fib_table : 0); //Is default FIB 0 ?
681 sr_policy->is_encap = is_encap;
682
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800683 if (plugin)
684 {
685 sr_policy->plugin = plugin;
686 sr_policy->plugin_mem = ls_plugin_mem;
687 }
688
Pablo Camarillofb380952016-12-07 18:34:18 +0100689 /* Copy the key */
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100690 mhash_set (&sm->sr_policies_index_hash, bsid, sr_policy - sm->sr_policies,
691 NULL);
Pablo Camarillofb380952016-12-07 18:34:18 +0100692
693 /* Create a segment list and add the index to the SR policy */
694 create_sl (sr_policy, segments, weight, is_encap);
695
696 /* If FIB doesnt exist, create them */
697 if (sm->fib_table_ip6 == (u32) ~ 0)
698 {
699 sm->fib_table_ip6 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
Neale Ranns15002542017-09-10 04:39:11 -0700700 FIB_SOURCE_SR,
Pablo Camarillofb380952016-12-07 18:34:18 +0100701 "SRv6 steering of IP6 prefixes through BSIDs");
702 sm->fib_table_ip4 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
Neale Ranns15002542017-09-10 04:39:11 -0700703 FIB_SOURCE_SR,
Pablo Camarillofb380952016-12-07 18:34:18 +0100704 "SRv6 steering of IP4 prefixes through BSIDs");
Pablo Camarillofb380952016-12-07 18:34:18 +0100705 }
706
707 /* Create IPv6 FIB for the BindingSID attached to the DPO of the only SL */
708 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
709 update_lb (sr_policy);
710 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
711 update_replicate (sr_policy);
712 return 0;
713}
714
715/**
716 * @brief Delete a SR policy
717 *
718 * @param bsid is the bindingSID of the SR Policy
719 * @param index is the index of the SR policy
720 *
721 * @return 0 if correct, else error
722 */
723int
724sr_policy_del (ip6_address_t * bsid, u32 index)
725{
726 ip6_sr_main_t *sm = &sr_main;
727 ip6_sr_policy_t *sr_policy = 0;
728 ip6_sr_sl_t *segment_list;
Pablo Camarillofb380952016-12-07 18:34:18 +0100729 u32 *sl_index;
730 uword *p;
731
Pablo Camarillofb380952016-12-07 18:34:18 +0100732 if (bsid)
733 {
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100734 p = mhash_get (&sm->sr_policies_index_hash, bsid);
Pablo Camarillofb380952016-12-07 18:34:18 +0100735 if (p)
736 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
737 else
738 return -1;
739 }
740 else
741 {
742 sr_policy = pool_elt_at_index (sm->sr_policies, index);
Pablo Camarillofb380952016-12-07 18:34:18 +0100743 }
744
745 /* Remove BindingSID FIB entry */
746 fib_prefix_t pfx = {
747 .fp_proto = FIB_PROTOCOL_IP6,
748 .fp_len = 128,
749 .fp_addr = {
750 .ip6 = sr_policy->bsid,
751 }
752 ,
753 };
754
Neale Ranns107e7d42017-04-11 09:55:19 -0700755 fib_table_entry_special_remove (fib_table_find (FIB_PROTOCOL_IP6,
756 sr_policy->fib_table),
Pablo Camarillofb380952016-12-07 18:34:18 +0100757 &pfx, FIB_SOURCE_SR);
758
759 fib_table_entry_special_remove (sm->fib_table_ip6, &pfx, FIB_SOURCE_SR);
760
761 if (sr_policy->is_encap)
762 fib_table_entry_special_remove (sm->fib_table_ip4, &pfx, FIB_SOURCE_SR);
763
764 if (dpo_id_is_valid (&sr_policy->bsid_dpo))
765 {
766 dpo_reset (&sr_policy->bsid_dpo);
767 dpo_reset (&sr_policy->ip4_dpo);
768 dpo_reset (&sr_policy->ip6_dpo);
769 }
770
771 /* Clean SID Lists */
772 vec_foreach (sl_index, sr_policy->segments_lists)
773 {
774 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
775 vec_free (segment_list->segments);
776 vec_free (segment_list->rewrite);
Kris Michielsen91074432017-06-22 13:00:20 +0200777 if (!sr_policy->is_encap)
778 vec_free (segment_list->rewrite_bsid);
Pablo Camarillofb380952016-12-07 18:34:18 +0100779 pool_put_index (sm->sid_lists, *sl_index);
780 }
781
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800782 if (sr_policy->plugin)
783 {
784 sr_policy_fn_registration_t *plugin = 0;
785
786 plugin =
787 pool_elt_at_index (sm->policy_plugin_functions,
788 sr_policy->plugin - SR_BEHAVIOR_LAST);
789
790 plugin->removal (sr_policy);
791 sr_policy->plugin = 0;
792 sr_policy->plugin_mem = NULL;
793 }
794
Pablo Camarillofb380952016-12-07 18:34:18 +0100795 /* Remove SR policy entry */
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100796 mhash_unset (&sm->sr_policies_index_hash, &sr_policy->bsid, NULL);
Pablo Camarillofb380952016-12-07 18:34:18 +0100797 pool_put (sm->sr_policies, sr_policy);
798
799 /* If FIB empty unlock it */
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100800 if (!pool_elts (sm->sr_policies) && !pool_elts (sm->steer_policies))
Pablo Camarillofb380952016-12-07 18:34:18 +0100801 {
Neale Ranns15002542017-09-10 04:39:11 -0700802 fib_table_unlock (sm->fib_table_ip6, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
803 fib_table_unlock (sm->fib_table_ip4, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
Pablo Camarillofb380952016-12-07 18:34:18 +0100804 sm->fib_table_ip6 = (u32) ~ 0;
805 sm->fib_table_ip4 = (u32) ~ 0;
806 }
807
808 return 0;
809}
810
811/**
812 * @brief Modify an existing SR policy
813 *
814 * The possible modifications are adding a new Segment List, modifying an
815 * existing Segment List (modify the weight only) and delete a given
816 * Segment List from the SR Policy.
817 *
818 * @param bsid is the bindingSID of the SR Policy
819 * @param index is the index of the SR policy
820 * @param fib_table is the VRF where to install the FIB entry for the BSID
821 * @param operation is the operation to perform (among the top ones)
822 * @param segments is a vector of IPv6 address composing the segment list
823 * @param sl_index is the index of the Segment List to modify/delete
824 * @param weight is the weight of the sid list. optional.
825 * @param is_encap Mode. Encapsulation or SRH insertion.
826 *
827 * @return 0 if correct, else error
828 */
829int
830sr_policy_mod (ip6_address_t * bsid, u32 index, u32 fib_table,
831 u8 operation, ip6_address_t * segments, u32 sl_index,
832 u32 weight)
833{
834 ip6_sr_main_t *sm = &sr_main;
835 ip6_sr_policy_t *sr_policy = 0;
836 ip6_sr_sl_t *segment_list;
837 u32 *sl_index_iterate;
838 uword *p;
839
840 if (bsid)
841 {
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100842 p = mhash_get (&sm->sr_policies_index_hash, bsid);
Pablo Camarillofb380952016-12-07 18:34:18 +0100843 if (p)
844 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
845 else
846 return -1;
847 }
848 else
849 {
850 sr_policy = pool_elt_at_index (sm->sr_policies, index);
Pablo Camarillofb380952016-12-07 18:34:18 +0100851 }
852
853 if (operation == 1) /* Add SR List to an existing SR policy */
854 {
855 /* Create the new SL */
856 segment_list =
857 create_sl (sr_policy, segments, weight, sr_policy->is_encap);
858
859 /* Create a new LB DPO */
860 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
861 update_lb (sr_policy);
862 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
863 update_replicate (sr_policy);
864 }
865 else if (operation == 2) /* Delete SR List from an existing SR policy */
866 {
867 /* Check that currently there are more than one SID list */
868 if (vec_len (sr_policy->segments_lists) == 1)
869 return -21;
870
871 /* Check that the SR list does exist and is assigned to the sr policy */
872 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
873 if (*sl_index_iterate == sl_index)
874 break;
875
876 if (*sl_index_iterate != sl_index)
877 return -22;
878
879 /* Remove the lucky SR list that is being kicked out */
880 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
881 vec_free (segment_list->segments);
882 vec_free (segment_list->rewrite);
Kris Michielsen91074432017-06-22 13:00:20 +0200883 if (!sr_policy->is_encap)
884 vec_free (segment_list->rewrite_bsid);
Pablo Camarillofb380952016-12-07 18:34:18 +0100885 pool_put_index (sm->sid_lists, sl_index);
886 vec_del1 (sr_policy->segments_lists,
887 sl_index_iterate - sr_policy->segments_lists);
888
889 /* Create a new LB DPO */
890 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
891 update_lb (sr_policy);
892 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
893 update_replicate (sr_policy);
894 }
895 else if (operation == 3) /* Modify the weight of an existing SR List */
896 {
897 /* Find the corresponding SL */
898 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
899 if (*sl_index_iterate == sl_index)
900 break;
901
902 if (*sl_index_iterate != sl_index)
903 return -32;
904
905 /* Change the weight */
906 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
907 segment_list->weight = weight;
908
909 /* Update LB */
910 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
911 update_lb (sr_policy);
912 }
913 else /* Incorrect op. */
914 return -1;
915
916 return 0;
917}
918
919/**
920 * @brief CLI for 'sr policies' command family
921 */
922static clib_error_t *
923sr_policy_command_fn (vlib_main_t * vm, unformat_input_t * input,
924 vlib_cli_command_t * cmd)
925{
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800926 ip6_sr_main_t *sm = &sr_main;
Pablo Camarillofb380952016-12-07 18:34:18 +0100927 int rv = -1;
928 char is_del = 0, is_add = 0, is_mod = 0;
929 char policy_set = 0;
930 ip6_address_t bsid, next_address;
931 u32 sr_policy_index = (u32) ~ 0, sl_index = (u32) ~ 0;
932 u32 weight = (u32) ~ 0, fib_table = (u32) ~ 0;
933 ip6_address_t *segments = 0, *this_seg;
934 u8 operation = 0;
935 char is_encap = 1;
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +0000936 u8 type = SR_POLICY_TYPE_DEFAULT;
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800937 u16 behavior = 0;
938 void *ls_plugin_mem = 0;
Pablo Camarillofb380952016-12-07 18:34:18 +0100939
940 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
941 {
942 if (!is_add && !is_mod && !is_del && unformat (input, "add"))
943 is_add = 1;
944 else if (!is_add && !is_mod && !is_del && unformat (input, "del"))
945 is_del = 1;
946 else if (!is_add && !is_mod && !is_del && unformat (input, "mod"))
947 is_mod = 1;
948 else if (!policy_set
949 && unformat (input, "bsid %U", unformat_ip6_address, &bsid))
950 policy_set = 1;
951 else if (!is_add && !policy_set
952 && unformat (input, "index %d", &sr_policy_index))
953 policy_set = 1;
954 else if (unformat (input, "weight %d", &weight));
955 else
956 if (unformat (input, "next %U", unformat_ip6_address, &next_address))
957 {
958 vec_add2 (segments, this_seg, 1);
Dave Barach178cf492018-11-13 16:34:13 -0500959 clib_memcpy_fast (this_seg->as_u8, next_address.as_u8,
960 sizeof (*this_seg));
Pablo Camarillofb380952016-12-07 18:34:18 +0100961 }
962 else if (unformat (input, "add sl"))
963 operation = 1;
964 else if (unformat (input, "del sl index %d", &sl_index))
965 operation = 2;
966 else if (unformat (input, "mod sl index %d", &sl_index))
967 operation = 3;
968 else if (fib_table == (u32) ~ 0
969 && unformat (input, "fib-table %d", &fib_table));
970 else if (unformat (input, "encap"))
971 is_encap = 1;
972 else if (unformat (input, "insert"))
973 is_encap = 0;
974 else if (unformat (input, "spray"))
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +0000975 type = SR_POLICY_TYPE_SPRAY;
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800976 else if (!behavior && unformat (input, "behavior"))
977 {
978 sr_policy_fn_registration_t *plugin = 0, **vec_plugins = 0;
979 sr_policy_fn_registration_t **plugin_it = 0;
980
981 /* *INDENT-OFF* */
Damjan Marionb2c31b62020-12-13 21:47:40 +0100982 pool_foreach (plugin, sm->policy_plugin_functions)
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800983 {
984 vec_add1 (vec_plugins, plugin);
Damjan Marionb2c31b62020-12-13 21:47:40 +0100985 }
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800986 /* *INDENT-ON* */
987
988 vec_foreach (plugin_it, vec_plugins)
989 {
990 if (unformat
991 (input, "%U", (*plugin_it)->ls_unformat, &ls_plugin_mem))
992 {
993 behavior = (*plugin_it)->sr_policy_function_number;
994 break;
995 }
996 }
997
998 if (!behavior)
999 {
1000 return clib_error_return (0, "Invalid behavior");
1001 }
1002 }
Pablo Camarillofb380952016-12-07 18:34:18 +01001003 else
1004 break;
1005 }
1006
1007 if (!is_add && !is_mod && !is_del)
1008 return clib_error_return (0, "Incorrect CLI");
1009
1010 if (!policy_set)
1011 return clib_error_return (0, "No SR policy BSID or index specified");
1012
1013 if (is_add)
1014 {
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -08001015 if (behavior && vec_len (segments) == 0)
1016 {
1017 vec_add2 (segments, this_seg, 1);
1018 clib_memset (this_seg, 0, sizeof (*this_seg));
1019 }
1020
Pablo Camarillofb380952016-12-07 18:34:18 +01001021 if (vec_len (segments) == 0)
1022 return clib_error_return (0, "No Segment List specified");
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -08001023
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +00001024 rv = sr_policy_add (&bsid, segments, weight, type, fib_table, is_encap,
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -08001025 behavior, ls_plugin_mem);
1026
John Lod23d39c2018-09-13 15:08:08 -04001027 vec_free (segments);
Pablo Camarillofb380952016-12-07 18:34:18 +01001028 }
1029 else if (is_del)
1030 rv = sr_policy_del ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
1031 sr_policy_index);
1032 else if (is_mod)
1033 {
1034 if (!operation)
1035 return clib_error_return (0, "No SL modification specified");
1036 if (operation != 1 && sl_index == (u32) ~ 0)
1037 return clib_error_return (0, "No Segment List index specified");
1038 if (operation == 1 && vec_len (segments) == 0)
1039 return clib_error_return (0, "No Segment List specified");
1040 if (operation == 3 && weight == (u32) ~ 0)
1041 return clib_error_return (0, "No new weight for the SL specified");
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -08001042
Pablo Camarillofb380952016-12-07 18:34:18 +01001043 rv = sr_policy_mod ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
1044 sr_policy_index, fib_table, operation, segments,
1045 sl_index, weight);
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -08001046
1047 if (segments)
1048 vec_free (segments);
Pablo Camarillofb380952016-12-07 18:34:18 +01001049 }
1050
1051 switch (rv)
1052 {
1053 case 0:
1054 break;
1055 case 1:
1056 return 0;
1057 case -12:
1058 return clib_error_return (0,
1059 "There is already a FIB entry for the BindingSID address.\n"
1060 "The SR policy could not be created.");
1061 case -13:
1062 return clib_error_return (0, "The specified FIB table does not exist.");
1063 case -21:
1064 return clib_error_return (0,
1065 "The selected SR policy only contains ONE segment list. "
1066 "Please remove the SR policy instead");
1067 case -22:
1068 return clib_error_return (0,
1069 "Could not delete the segment list. "
1070 "It is not associated with that SR policy.");
1071 case -32:
1072 return clib_error_return (0,
1073 "Could not modify the segment list. "
1074 "The given SL is not associated with such SR policy.");
1075 default:
1076 return clib_error_return (0, "BUG: sr policy returns %d", rv);
1077 }
1078 return 0;
1079}
1080
1081/* *INDENT-OFF* */
1082VLIB_CLI_COMMAND (sr_policy_command, static) = {
1083 .path = "sr policy",
1084 .short_help = "sr policy [add||del||mod] [bsid 2001::1||index 5] "
1085 "next A:: next B:: next C:: (weight 1) (fib-table 2) (encap|insert)",
1086 .long_help =
1087 "Manipulation of SR policies.\n"
1088 "A Segment Routing policy may contain several SID lists. Each SID list has\n"
1089 "an associated weight (default 1), which will result in wECMP (uECMP).\n"
1090 "Segment Routing policies might be of type encapsulation or srh insertion\n"
1091 "Each SR policy will be associated with a unique BindingSID.\n"
1092 "A BindingSID is a locally allocated SegmentID. For every packet that arrives\n"
1093 "with IPv6_DA:BSID such traffic will be steered into the SR policy.\n"
1094 "The add command will create a SR policy with its first segment list (sl)\n"
1095 "The mod command allows you to add, remove, or modify the existing segment lists\n"
1096 "within an SR policy.\n"
1097 "The del command allows you to delete a SR policy along with all its associated\n"
1098 "SID lists.\n",
1099 .function = sr_policy_command_fn,
1100};
1101/* *INDENT-ON* */
1102
1103/**
1104 * @brief CLI to display onscreen all the SR policies
1105 */
1106static clib_error_t *
1107show_sr_policies_command_fn (vlib_main_t * vm, unformat_input_t * input,
1108 vlib_cli_command_t * cmd)
1109{
1110 ip6_sr_main_t *sm = &sr_main;
1111 u32 *sl_index;
1112 ip6_sr_sl_t *segment_list = 0;
1113 ip6_sr_policy_t *sr_policy = 0;
1114 ip6_sr_policy_t **vec_policies = 0;
1115 ip6_address_t *addr;
1116 u8 *s;
1117 int i = 0;
1118
1119 vlib_cli_output (vm, "SR policies:");
1120
1121 /* *INDENT-OFF* */
Damjan Marionb2c31b62020-12-13 21:47:40 +01001122 pool_foreach (sr_policy, sm->sr_policies)
1123 {vec_add1 (vec_policies, sr_policy); }
Pablo Camarillofb380952016-12-07 18:34:18 +01001124 /* *INDENT-ON* */
1125
1126 vec_foreach_index (i, vec_policies)
1127 {
1128 sr_policy = vec_policies[i];
1129 vlib_cli_output (vm, "[%u].-\tBSID: %U",
1130 (u32) (sr_policy - sm->sr_policies),
1131 format_ip6_address, &sr_policy->bsid);
1132 vlib_cli_output (vm, "\tBehavior: %s",
1133 (sr_policy->is_encap ? "Encapsulation" :
1134 "SRH insertion"));
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +00001135 switch (sr_policy->type)
1136 {
1137 case SR_POLICY_TYPE_SPRAY:
1138 vlib_cli_output (vm, "\tType: %s", "Spray");
1139 break;
1140 default:
1141 vlib_cli_output (vm, "\tType: %s", "Default");
1142 break;
1143 }
Pablo Camarillofb380952016-12-07 18:34:18 +01001144 vlib_cli_output (vm, "\tFIB table: %u",
1145 (sr_policy->fib_table !=
1146 (u32) ~ 0 ? sr_policy->fib_table : 0));
1147 vlib_cli_output (vm, "\tSegment Lists:");
1148 vec_foreach (sl_index, sr_policy->segments_lists)
1149 {
1150 s = NULL;
1151 s = format (s, "\t[%u].- ", *sl_index);
1152 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
1153 s = format (s, "< ");
1154 vec_foreach (addr, segment_list->segments)
1155 {
1156 s = format (s, "%U, ", format_ip6_address, addr);
1157 }
1158 s = format (s, "\b\b > ");
1159 s = format (s, "weight: %u", segment_list->weight);
Benoît Ganneb9753542020-04-17 12:11:26 +02001160 vlib_cli_output (vm, " %v", s);
Pablo Camarillofb380952016-12-07 18:34:18 +01001161 }
1162 vlib_cli_output (vm, "-----------");
1163 }
1164 return 0;
1165}
1166
1167/* *INDENT-OFF* */
1168VLIB_CLI_COMMAND (show_sr_policies_command, static) = {
1169 .path = "show sr policies",
1170 .short_help = "show sr policies",
1171 .function = show_sr_policies_command_fn,
1172};
1173/* *INDENT-ON* */
1174
Ahmed Abdelsalam448bc812020-11-09 14:04:07 +00001175/**
1176 * @brief CLI to display onscreen the SR encaps source addr
1177 */
1178static clib_error_t *
1179show_sr_encaps_source_command_fn (vlib_main_t * vm, unformat_input_t * input,
1180 vlib_cli_command_t * cmd)
1181{
1182 vlib_cli_output (vm, "SR encaps source addr = %U", format_ip6_address,
1183 sr_get_encaps_source ());
1184
1185 return 0;
1186}
1187
1188/* *INDENT-OFF* */
1189VLIB_CLI_COMMAND (show_sr_encaps_source_command, static) = {
1190 .path = "show sr encaps source addr",
1191 .short_help = "show sr encaps source addr",
1192 .function = show_sr_encaps_source_command_fn,
1193};
1194/* *INDENT-ON* */
1195
Ahmed Abdelsalam80f0b882020-11-10 17:19:12 +00001196/**
1197 * @brief CLI to display onscreen the hop-limit value used for SRv6 encapsulation
1198 */
1199static clib_error_t *
1200show_sr_encaps_hop_limit_command_fn (vlib_main_t * vm,
1201 unformat_input_t * input,
1202 vlib_cli_command_t * cmd)
1203{
1204 vlib_cli_output (vm, "SR encaps hop-limit = %u", sr_get_hop_limit ());
1205
1206 return 0;
1207}
1208
1209/* *INDENT-OFF* */
1210VLIB_CLI_COMMAND (show_sr_encaps_hop_limit_command, static) = {
1211 .path = "show sr encaps hop-limit",
1212 .short_help = "show sr encaps hop-limit",
1213 .function = show_sr_encaps_hop_limit_command_fn,
1214};
1215/* *INDENT-ON* */
1216
Pablo Camarillofb380952016-12-07 18:34:18 +01001217/*************************** SR rewrite graph node ****************************/
1218/**
1219 * @brief Trace for the SR Policy Rewrite graph node
1220 */
1221static u8 *
1222format_sr_policy_rewrite_trace (u8 * s, va_list * args)
1223{
1224 //TODO
1225 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1226 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1227 sr_policy_rewrite_trace_t *t = va_arg (*args, sr_policy_rewrite_trace_t *);
1228
1229 s = format
1230 (s, "SR-policy-rewrite: src %U dst %U",
1231 format_ip6_address, &t->src, format_ip6_address, &t->dst);
1232
1233 return s;
1234}
1235
1236/**
1237 * @brief IPv6 encapsulation processing as per RFC2473
1238 */
1239static_always_inline void
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +00001240encaps_processing_v6 (vlib_node_runtime_t *node, vlib_buffer_t *b0,
1241 ip6_header_t *ip0, ip6_header_t *ip0_encap,
1242 u8 policy_type)
Pablo Camarillofb380952016-12-07 18:34:18 +01001243{
1244 u32 new_l0;
Jakub Horn91f4a972021-01-21 12:14:58 +00001245 u32 flow_label;
Pablo Camarillofb380952016-12-07 18:34:18 +01001246
1247 ip0_encap->hop_limit -= 1;
1248 new_l0 =
1249 ip0->payload_length + sizeof (ip6_header_t) +
1250 clib_net_to_host_u16 (ip0_encap->payload_length);
1251 ip0->payload_length = clib_host_to_net_u16 (new_l0);
Jakub Horn91f4a972021-01-21 12:14:58 +00001252
1253 flow_label = ip6_compute_flow_hash (ip0_encap, IP_FLOW_HASH_DEFAULT);
1254 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
1255 0 |
1256 (clib_net_to_host_u32 (
1257 ip0_encap->ip_version_traffic_class_and_flow_label) &
1258 0xfff00000) |
1259 (flow_label & 0x0000ffff));
Pablo Camarillofb380952016-12-07 18:34:18 +01001260}
1261
1262/**
1263 * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
1264 */
1265static uword
1266sr_policy_rewrite_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
1267 vlib_frame_t * from_frame)
1268{
1269 ip6_sr_main_t *sm = &sr_main;
1270 u32 n_left_from, next_index, *from, *to_next;
1271
1272 from = vlib_frame_vector_args (from_frame);
1273 n_left_from = from_frame->n_vectors;
1274
1275 next_index = node->cached_next_index;
1276
1277 int encap_pkts = 0, bsid_pkts = 0;
1278
1279 while (n_left_from > 0)
1280 {
1281 u32 n_left_to_next;
1282
1283 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1284
1285 /* Quad - Loop */
1286 while (n_left_from >= 8 && n_left_to_next >= 4)
1287 {
1288 u32 bi0, bi1, bi2, bi3;
1289 vlib_buffer_t *b0, *b1, *b2, *b3;
1290 u32 next0, next1, next2, next3;
1291 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1292 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1293 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1294 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1295
1296 /* Prefetch next iteration. */
1297 {
1298 vlib_buffer_t *p4, *p5, *p6, *p7;
1299
1300 p4 = vlib_get_buffer (vm, from[4]);
1301 p5 = vlib_get_buffer (vm, from[5]);
1302 p6 = vlib_get_buffer (vm, from[6]);
1303 p7 = vlib_get_buffer (vm, from[7]);
1304
1305 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1306 vlib_prefetch_buffer_header (p4, LOAD);
1307 vlib_prefetch_buffer_header (p5, LOAD);
1308 vlib_prefetch_buffer_header (p6, LOAD);
1309 vlib_prefetch_buffer_header (p7, LOAD);
1310
Damjan Marionaf7fb042021-07-15 11:54:41 +02001311 clib_prefetch_store (p4->data);
1312 clib_prefetch_store (p5->data);
1313 clib_prefetch_store (p6->data);
1314 clib_prefetch_store (p7->data);
Pablo Camarillofb380952016-12-07 18:34:18 +01001315 }
1316
1317 to_next[0] = bi0 = from[0];
1318 to_next[1] = bi1 = from[1];
1319 to_next[2] = bi2 = from[2];
1320 to_next[3] = bi3 = from[3];
1321 from += 4;
1322 to_next += 4;
1323 n_left_from -= 4;
1324 n_left_to_next -= 4;
1325
1326 b0 = vlib_get_buffer (vm, bi0);
1327 b1 = vlib_get_buffer (vm, bi1);
1328 b2 = vlib_get_buffer (vm, bi2);
1329 b3 = vlib_get_buffer (vm, bi3);
1330
1331 sl0 =
1332 pool_elt_at_index (sm->sid_lists,
1333 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1334 sl1 =
1335 pool_elt_at_index (sm->sid_lists,
1336 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1337 sl2 =
1338 pool_elt_at_index (sm->sid_lists,
1339 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1340 sl3 =
1341 pool_elt_at_index (sm->sid_lists,
1342 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1343
shwethabe146f132017-03-09 16:58:26 +00001344 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1345 vec_len (sl0->rewrite));
1346 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1347 vec_len (sl1->rewrite));
1348 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1349 vec_len (sl2->rewrite));
1350 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1351 vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001352
1353 ip0_encap = vlib_buffer_get_current (b0);
1354 ip1_encap = vlib_buffer_get_current (b1);
1355 ip2_encap = vlib_buffer_get_current (b2);
1356 ip3_encap = vlib_buffer_get_current (b3);
1357
Dave Barach178cf492018-11-13 16:34:13 -05001358 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1359 sl0->rewrite, vec_len (sl0->rewrite));
1360 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1361 sl1->rewrite, vec_len (sl1->rewrite));
1362 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1363 sl2->rewrite, vec_len (sl2->rewrite));
1364 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1365 sl3->rewrite, vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001366
1367 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1368 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1369 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1370 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1371
1372 ip0 = vlib_buffer_get_current (b0);
1373 ip1 = vlib_buffer_get_current (b1);
1374 ip2 = vlib_buffer_get_current (b2);
1375 ip3 = vlib_buffer_get_current (b3);
1376
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +00001377 encaps_processing_v6 (node, b0, ip0, ip0_encap, sl0->policy_type);
1378 encaps_processing_v6 (node, b1, ip1, ip1_encap, sl1->policy_type);
1379 encaps_processing_v6 (node, b2, ip2, ip2_encap, sl2->policy_type);
1380 encaps_processing_v6 (node, b3, ip3, ip3_encap, sl3->policy_type);
Pablo Camarillofb380952016-12-07 18:34:18 +01001381
Tetsuya Murakami6b354912021-01-31 16:38:56 -08001382 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
1383 vnet_buffer (b1)->sw_if_index[VLIB_TX] = sl1->egress_fib_table;
1384 vnet_buffer (b2)->sw_if_index[VLIB_TX] = sl2->egress_fib_table;
1385 vnet_buffer (b3)->sw_if_index[VLIB_TX] = sl3->egress_fib_table;
1386
Pablo Camarillofb380952016-12-07 18:34:18 +01001387 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1388 {
1389 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1390 {
1391 sr_policy_rewrite_trace_t *tr =
1392 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001393 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1394 sizeof (tr->src.as_u8));
1395 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1396 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001397 }
1398
1399 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1400 {
1401 sr_policy_rewrite_trace_t *tr =
1402 vlib_add_trace (vm, node, b1, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001403 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
1404 sizeof (tr->src.as_u8));
1405 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
1406 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001407 }
1408
1409 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1410 {
1411 sr_policy_rewrite_trace_t *tr =
1412 vlib_add_trace (vm, node, b2, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001413 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
1414 sizeof (tr->src.as_u8));
1415 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
1416 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001417 }
1418
1419 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1420 {
1421 sr_policy_rewrite_trace_t *tr =
1422 vlib_add_trace (vm, node, b3, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001423 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
1424 sizeof (tr->src.as_u8));
1425 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
1426 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001427 }
1428 }
1429
1430 encap_pkts += 4;
1431 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1432 n_left_to_next, bi0, bi1, bi2, bi3,
1433 next0, next1, next2, next3);
1434 }
1435
1436 /* Single loop for potentially the last three packets */
1437 while (n_left_from > 0 && n_left_to_next > 0)
1438 {
1439 u32 bi0;
1440 vlib_buffer_t *b0;
1441 ip6_header_t *ip0 = 0, *ip0_encap = 0;
1442 ip6_sr_sl_t *sl0;
1443 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1444
1445 bi0 = from[0];
1446 to_next[0] = bi0;
1447 from += 1;
1448 to_next += 1;
1449 n_left_from -= 1;
1450 n_left_to_next -= 1;
1451 b0 = vlib_get_buffer (vm, bi0);
1452
1453 sl0 =
1454 pool_elt_at_index (sm->sid_lists,
1455 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00001456 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1457 vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001458
1459 ip0_encap = vlib_buffer_get_current (b0);
1460
Dave Barach178cf492018-11-13 16:34:13 -05001461 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1462 sl0->rewrite, vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001463 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1464
1465 ip0 = vlib_buffer_get_current (b0);
1466
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +00001467 encaps_processing_v6 (node, b0, ip0, ip0_encap, sl0->policy_type);
Pablo Camarillofb380952016-12-07 18:34:18 +01001468
Tetsuya Murakami6b354912021-01-31 16:38:56 -08001469 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
1470
Pablo Camarillofb380952016-12-07 18:34:18 +01001471 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1472 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1473 {
1474 sr_policy_rewrite_trace_t *tr =
1475 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001476 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1477 sizeof (tr->src.as_u8));
1478 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1479 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001480 }
1481
1482 encap_pkts++;
1483 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1484 n_left_to_next, bi0, next0);
1485 }
1486
1487 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1488 }
1489
1490 /* Update counters */
1491 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1492 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1493 encap_pkts);
1494 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1495 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1496 bsid_pkts);
1497
1498 return from_frame->n_vectors;
1499}
1500
1501/* *INDENT-OFF* */
1502VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_node) = {
1503 .function = sr_policy_rewrite_encaps,
1504 .name = "sr-pl-rewrite-encaps",
1505 .vector_size = sizeof (u32),
1506 .format_trace = format_sr_policy_rewrite_trace,
1507 .type = VLIB_NODE_TYPE_INTERNAL,
1508 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1509 .error_strings = sr_policy_rewrite_error_strings,
1510 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1511 .next_nodes = {
1512#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1513 foreach_sr_policy_rewrite_next
1514#undef _
1515 },
1516};
1517/* *INDENT-ON* */
1518
1519/**
1520 * @brief IPv4 encapsulation processing as per RFC2473
1521 */
1522static_always_inline void
1523encaps_processing_v4 (vlib_node_runtime_t * node,
1524 vlib_buffer_t * b0,
1525 ip6_header_t * ip0, ip4_header_t * ip0_encap)
1526{
1527 u32 new_l0;
1528 ip6_sr_header_t *sr0;
1529
1530 u32 checksum0;
Jakub Horn91f4a972021-01-21 12:14:58 +00001531 u32 flow_label;
Pablo Camarillofb380952016-12-07 18:34:18 +01001532
1533 /* Inner IPv4: Decrement TTL & update checksum */
1534 ip0_encap->ttl -= 1;
1535 checksum0 = ip0_encap->checksum + clib_host_to_net_u16 (0x0100);
1536 checksum0 += checksum0 >= 0xffff;
1537 ip0_encap->checksum = checksum0;
1538
1539 /* Outer IPv6: Update length, FL, proto */
1540 new_l0 = ip0->payload_length + clib_net_to_host_u16 (ip0_encap->length);
1541 ip0->payload_length = clib_host_to_net_u16 (new_l0);
Jakub Horn91f4a972021-01-21 12:14:58 +00001542 flow_label = ip4_compute_flow_hash (ip0_encap, IP_FLOW_HASH_DEFAULT);
1543 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
1544 0 | ((6 & 0xF) << 28) | ((ip0_encap->tos & 0xFF) << 20) |
1545 (flow_label & 0x0000ffff));
Pablo Camarillod327c872018-01-08 14:25:55 +01001546 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
1547 {
1548 sr0 = (void *) (ip0 + 1);
1549 sr0->protocol = IP_PROTOCOL_IP_IN_IP;
1550 }
1551 else
1552 ip0->protocol = IP_PROTOCOL_IP_IN_IP;
Pablo Camarillofb380952016-12-07 18:34:18 +01001553}
1554
1555/**
1556 * @brief Graph node for applying a SR policy into an IPv4 packet. Encapsulation
1557 */
1558static uword
1559sr_policy_rewrite_encaps_v4 (vlib_main_t * vm, vlib_node_runtime_t * node,
1560 vlib_frame_t * from_frame)
1561{
1562 ip6_sr_main_t *sm = &sr_main;
1563 u32 n_left_from, next_index, *from, *to_next;
1564
1565 from = vlib_frame_vector_args (from_frame);
1566 n_left_from = from_frame->n_vectors;
1567
1568 next_index = node->cached_next_index;
1569
1570 int encap_pkts = 0, bsid_pkts = 0;
1571
1572 while (n_left_from > 0)
1573 {
1574 u32 n_left_to_next;
1575
1576 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1577
1578 /* Quad - Loop */
1579 while (n_left_from >= 8 && n_left_to_next >= 4)
1580 {
1581 u32 bi0, bi1, bi2, bi3;
1582 vlib_buffer_t *b0, *b1, *b2, *b3;
1583 u32 next0, next1, next2, next3;
1584 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1585 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1586 ip4_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1587 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1588
1589 /* Prefetch next iteration. */
1590 {
1591 vlib_buffer_t *p4, *p5, *p6, *p7;
1592
1593 p4 = vlib_get_buffer (vm, from[4]);
1594 p5 = vlib_get_buffer (vm, from[5]);
1595 p6 = vlib_get_buffer (vm, from[6]);
1596 p7 = vlib_get_buffer (vm, from[7]);
1597
1598 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1599 vlib_prefetch_buffer_header (p4, LOAD);
1600 vlib_prefetch_buffer_header (p5, LOAD);
1601 vlib_prefetch_buffer_header (p6, LOAD);
1602 vlib_prefetch_buffer_header (p7, LOAD);
1603
Damjan Marionaf7fb042021-07-15 11:54:41 +02001604 clib_prefetch_store (p4->data);
1605 clib_prefetch_store (p5->data);
1606 clib_prefetch_store (p6->data);
1607 clib_prefetch_store (p7->data);
Pablo Camarillofb380952016-12-07 18:34:18 +01001608 }
1609
1610 to_next[0] = bi0 = from[0];
1611 to_next[1] = bi1 = from[1];
1612 to_next[2] = bi2 = from[2];
1613 to_next[3] = bi3 = from[3];
1614 from += 4;
1615 to_next += 4;
1616 n_left_from -= 4;
1617 n_left_to_next -= 4;
1618
1619 b0 = vlib_get_buffer (vm, bi0);
1620 b1 = vlib_get_buffer (vm, bi1);
1621 b2 = vlib_get_buffer (vm, bi2);
1622 b3 = vlib_get_buffer (vm, bi3);
1623
1624 sl0 =
1625 pool_elt_at_index (sm->sid_lists,
1626 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1627 sl1 =
1628 pool_elt_at_index (sm->sid_lists,
1629 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1630 sl2 =
1631 pool_elt_at_index (sm->sid_lists,
1632 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1633 sl3 =
1634 pool_elt_at_index (sm->sid_lists,
1635 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00001636 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1637 vec_len (sl0->rewrite));
1638 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1639 vec_len (sl1->rewrite));
1640 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1641 vec_len (sl2->rewrite));
1642 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1643 vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001644
1645 ip0_encap = vlib_buffer_get_current (b0);
1646 ip1_encap = vlib_buffer_get_current (b1);
1647 ip2_encap = vlib_buffer_get_current (b2);
1648 ip3_encap = vlib_buffer_get_current (b3);
1649
Dave Barach178cf492018-11-13 16:34:13 -05001650 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1651 sl0->rewrite, vec_len (sl0->rewrite));
1652 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1653 sl1->rewrite, vec_len (sl1->rewrite));
1654 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1655 sl2->rewrite, vec_len (sl2->rewrite));
1656 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1657 sl3->rewrite, vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001658
1659 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1660 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1661 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1662 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1663
1664 ip0 = vlib_buffer_get_current (b0);
1665 ip1 = vlib_buffer_get_current (b1);
1666 ip2 = vlib_buffer_get_current (b2);
1667 ip3 = vlib_buffer_get_current (b3);
1668
1669 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1670 encaps_processing_v4 (node, b1, ip1, ip1_encap);
1671 encaps_processing_v4 (node, b2, ip2, ip2_encap);
1672 encaps_processing_v4 (node, b3, ip3, ip3_encap);
1673
Tetsuya Murakami6b354912021-01-31 16:38:56 -08001674 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
1675 vnet_buffer (b1)->sw_if_index[VLIB_TX] = sl1->egress_fib_table;
1676 vnet_buffer (b2)->sw_if_index[VLIB_TX] = sl2->egress_fib_table;
1677 vnet_buffer (b3)->sw_if_index[VLIB_TX] = sl3->egress_fib_table;
1678
Pablo Camarillofb380952016-12-07 18:34:18 +01001679 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1680 {
1681 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1682 {
1683 sr_policy_rewrite_trace_t *tr =
1684 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001685 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1686 sizeof (tr->src.as_u8));
1687 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1688 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001689 }
1690
1691 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1692 {
1693 sr_policy_rewrite_trace_t *tr =
1694 vlib_add_trace (vm, node, b1, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001695 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
1696 sizeof (tr->src.as_u8));
1697 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
1698 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001699 }
1700
1701 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1702 {
1703 sr_policy_rewrite_trace_t *tr =
1704 vlib_add_trace (vm, node, b2, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001705 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
1706 sizeof (tr->src.as_u8));
1707 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
1708 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001709 }
1710
1711 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1712 {
1713 sr_policy_rewrite_trace_t *tr =
1714 vlib_add_trace (vm, node, b3, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001715 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
1716 sizeof (tr->src.as_u8));
1717 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
1718 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001719 }
1720 }
1721
1722 encap_pkts += 4;
1723 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1724 n_left_to_next, bi0, bi1, bi2, bi3,
1725 next0, next1, next2, next3);
1726 }
1727
1728 /* Single loop for potentially the last three packets */
1729 while (n_left_from > 0 && n_left_to_next > 0)
1730 {
1731 u32 bi0;
1732 vlib_buffer_t *b0;
1733 ip6_header_t *ip0 = 0;
1734 ip4_header_t *ip0_encap = 0;
1735 ip6_sr_sl_t *sl0;
1736 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1737
1738 bi0 = from[0];
1739 to_next[0] = bi0;
1740 from += 1;
1741 to_next += 1;
1742 n_left_from -= 1;
1743 n_left_to_next -= 1;
1744 b0 = vlib_get_buffer (vm, bi0);
1745
1746 sl0 =
1747 pool_elt_at_index (sm->sid_lists,
1748 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00001749 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1750 vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001751
1752 ip0_encap = vlib_buffer_get_current (b0);
1753
Dave Barach178cf492018-11-13 16:34:13 -05001754 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1755 sl0->rewrite, vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001756 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1757
1758 ip0 = vlib_buffer_get_current (b0);
1759
1760 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1761
Tetsuya Murakami6b354912021-01-31 16:38:56 -08001762 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
1763
Pablo Camarillofb380952016-12-07 18:34:18 +01001764 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1765 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1766 {
1767 sr_policy_rewrite_trace_t *tr =
1768 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001769 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1770 sizeof (tr->src.as_u8));
1771 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1772 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001773 }
1774
1775 encap_pkts++;
1776 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1777 n_left_to_next, bi0, next0);
1778 }
1779
1780 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1781 }
1782
1783 /* Update counters */
1784 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1785 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1786 encap_pkts);
1787 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1788 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1789 bsid_pkts);
1790
1791 return from_frame->n_vectors;
1792}
1793
1794/* *INDENT-OFF* */
1795VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_v4_node) = {
1796 .function = sr_policy_rewrite_encaps_v4,
1797 .name = "sr-pl-rewrite-encaps-v4",
1798 .vector_size = sizeof (u32),
1799 .format_trace = format_sr_policy_rewrite_trace,
1800 .type = VLIB_NODE_TYPE_INTERNAL,
1801 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1802 .error_strings = sr_policy_rewrite_error_strings,
1803 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1804 .next_nodes = {
1805#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1806 foreach_sr_policy_rewrite_next
1807#undef _
1808 },
1809};
1810/* *INDENT-ON* */
1811
1812always_inline u32
1813ip_flow_hash (void *data)
1814{
1815 ip4_header_t *iph = (ip4_header_t *) data;
1816
1817 if ((iph->ip_version_and_header_length & 0xF0) == 0x40)
1818 return ip4_compute_flow_hash (iph, IP_FLOW_HASH_DEFAULT);
1819 else
1820 return ip6_compute_flow_hash ((ip6_header_t *) iph, IP_FLOW_HASH_DEFAULT);
1821}
1822
1823always_inline u64
1824mac_to_u64 (u8 * m)
1825{
1826 return (*((u64 *) m) & 0xffffffffffff);
1827}
1828
1829always_inline u32
1830l2_flow_hash (vlib_buffer_t * b0)
1831{
1832 ethernet_header_t *eh;
1833 u64 a, b, c;
1834 uword is_ip, eh_size;
1835 u16 eh_type;
1836
1837 eh = vlib_buffer_get_current (b0);
1838 eh_type = clib_net_to_host_u16 (eh->type);
1839 eh_size = ethernet_buffer_header_size (b0);
1840
1841 is_ip = (eh_type == ETHERNET_TYPE_IP4 || eh_type == ETHERNET_TYPE_IP6);
1842
1843 /* since we have 2 cache lines, use them */
1844 if (is_ip)
1845 a = ip_flow_hash ((u8 *) vlib_buffer_get_current (b0) + eh_size);
1846 else
1847 a = eh->type;
1848
1849 b = mac_to_u64 ((u8 *) eh->dst_address);
1850 c = mac_to_u64 ((u8 *) eh->src_address);
1851 hash_mix64 (a, b, c);
1852
1853 return (u32) c;
1854}
1855
1856/**
1857 * @brief Graph node for applying a SR policy into a L2 frame
1858 */
1859static uword
1860sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
1861 vlib_frame_t * from_frame)
1862{
1863 ip6_sr_main_t *sm = &sr_main;
1864 u32 n_left_from, next_index, *from, *to_next;
1865
1866 from = vlib_frame_vector_args (from_frame);
1867 n_left_from = from_frame->n_vectors;
1868
1869 next_index = node->cached_next_index;
1870
1871 int encap_pkts = 0, bsid_pkts = 0;
1872
1873 while (n_left_from > 0)
1874 {
1875 u32 n_left_to_next;
1876
1877 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1878
1879 /* Quad - Loop */
1880 while (n_left_from >= 8 && n_left_to_next >= 4)
1881 {
1882 u32 bi0, bi1, bi2, bi3;
1883 vlib_buffer_t *b0, *b1, *b2, *b3;
1884 u32 next0, next1, next2, next3;
1885 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1886 ethernet_header_t *en0, *en1, *en2, *en3;
1887 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1888 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1889 ip6_sr_policy_t *sp0, *sp1, *sp2, *sp3;
1890 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
Jakub Horn91f4a972021-01-21 12:14:58 +00001891 u32 flow_label0, flow_label1, flow_label2, flow_label3;
Pablo Camarillofb380952016-12-07 18:34:18 +01001892
1893 /* Prefetch next iteration. */
1894 {
1895 vlib_buffer_t *p4, *p5, *p6, *p7;
1896
1897 p4 = vlib_get_buffer (vm, from[4]);
1898 p5 = vlib_get_buffer (vm, from[5]);
1899 p6 = vlib_get_buffer (vm, from[6]);
1900 p7 = vlib_get_buffer (vm, from[7]);
1901
1902 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1903 vlib_prefetch_buffer_header (p4, LOAD);
1904 vlib_prefetch_buffer_header (p5, LOAD);
1905 vlib_prefetch_buffer_header (p6, LOAD);
1906 vlib_prefetch_buffer_header (p7, LOAD);
1907
Damjan Marionaf7fb042021-07-15 11:54:41 +02001908 clib_prefetch_store (p4->data);
1909 clib_prefetch_store (p5->data);
1910 clib_prefetch_store (p6->data);
1911 clib_prefetch_store (p7->data);
Pablo Camarillofb380952016-12-07 18:34:18 +01001912 }
1913
1914 to_next[0] = bi0 = from[0];
1915 to_next[1] = bi1 = from[1];
1916 to_next[2] = bi2 = from[2];
1917 to_next[3] = bi3 = from[3];
1918 from += 4;
1919 to_next += 4;
1920 n_left_from -= 4;
1921 n_left_to_next -= 4;
1922
1923 b0 = vlib_get_buffer (vm, bi0);
1924 b1 = vlib_get_buffer (vm, bi1);
1925 b2 = vlib_get_buffer (vm, bi2);
1926 b3 = vlib_get_buffer (vm, bi3);
1927
1928 sp0 = pool_elt_at_index (sm->sr_policies,
1929 sm->sw_iface_sr_policies[vnet_buffer
1930 (b0)->sw_if_index
1931 [VLIB_RX]]);
1932
1933 sp1 = pool_elt_at_index (sm->sr_policies,
1934 sm->sw_iface_sr_policies[vnet_buffer
1935 (b1)->sw_if_index
1936 [VLIB_RX]]);
1937
1938 sp2 = pool_elt_at_index (sm->sr_policies,
1939 sm->sw_iface_sr_policies[vnet_buffer
1940 (b2)->sw_if_index
1941 [VLIB_RX]]);
1942
1943 sp3 = pool_elt_at_index (sm->sr_policies,
1944 sm->sw_iface_sr_policies[vnet_buffer
1945 (b3)->sw_if_index
1946 [VLIB_RX]]);
Jakub Horn91f4a972021-01-21 12:14:58 +00001947 flow_label0 = l2_flow_hash (b0);
1948 flow_label1 = l2_flow_hash (b1);
1949 flow_label2 = l2_flow_hash (b2);
1950 flow_label3 = l2_flow_hash (b3);
Pablo Camarillofb380952016-12-07 18:34:18 +01001951
1952 if (vec_len (sp0->segments_lists) == 1)
1953 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1954 else
1955 {
Jakub Horn91f4a972021-01-21 12:14:58 +00001956 vnet_buffer (b0)->ip.flow_hash = flow_label0;
Pablo Camarillofb380952016-12-07 18:34:18 +01001957 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1958 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1959 (vec_len (sp0->segments_lists) - 1))];
1960 }
1961
1962 if (vec_len (sp1->segments_lists) == 1)
1963 vnet_buffer (b1)->ip.adj_index[VLIB_TX] = sp1->segments_lists[1];
1964 else
1965 {
Jakub Horn91f4a972021-01-21 12:14:58 +00001966 vnet_buffer (b1)->ip.flow_hash = flow_label1;
Pablo Camarillofb380952016-12-07 18:34:18 +01001967 vnet_buffer (b1)->ip.adj_index[VLIB_TX] =
1968 sp1->segments_lists[(vnet_buffer (b1)->ip.flow_hash &
1969 (vec_len (sp1->segments_lists) - 1))];
1970 }
1971
1972 if (vec_len (sp2->segments_lists) == 1)
1973 vnet_buffer (b2)->ip.adj_index[VLIB_TX] = sp2->segments_lists[2];
1974 else
1975 {
Jakub Horn91f4a972021-01-21 12:14:58 +00001976 vnet_buffer (b2)->ip.flow_hash = flow_label2;
Pablo Camarillofb380952016-12-07 18:34:18 +01001977 vnet_buffer (b2)->ip.adj_index[VLIB_TX] =
1978 sp2->segments_lists[(vnet_buffer (b2)->ip.flow_hash &
1979 (vec_len (sp2->segments_lists) - 1))];
1980 }
1981
1982 if (vec_len (sp3->segments_lists) == 1)
1983 vnet_buffer (b3)->ip.adj_index[VLIB_TX] = sp3->segments_lists[3];
1984 else
1985 {
Jakub Horn91f4a972021-01-21 12:14:58 +00001986 vnet_buffer (b3)->ip.flow_hash = flow_label3;
Pablo Camarillofb380952016-12-07 18:34:18 +01001987 vnet_buffer (b3)->ip.adj_index[VLIB_TX] =
1988 sp3->segments_lists[(vnet_buffer (b3)->ip.flow_hash &
1989 (vec_len (sp3->segments_lists) - 1))];
1990 }
1991
1992 sl0 =
1993 pool_elt_at_index (sm->sid_lists,
1994 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1995 sl1 =
1996 pool_elt_at_index (sm->sid_lists,
1997 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1998 sl2 =
1999 pool_elt_at_index (sm->sid_lists,
2000 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2001 sl3 =
2002 pool_elt_at_index (sm->sid_lists,
2003 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2004
shwethabe146f132017-03-09 16:58:26 +00002005 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2006 vec_len (sl0->rewrite));
2007 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2008 vec_len (sl1->rewrite));
2009 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2010 vec_len (sl2->rewrite));
2011 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2012 vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002013
2014 en0 = vlib_buffer_get_current (b0);
2015 en1 = vlib_buffer_get_current (b1);
2016 en2 = vlib_buffer_get_current (b2);
2017 en3 = vlib_buffer_get_current (b3);
2018
Dave Barach178cf492018-11-13 16:34:13 -05002019 clib_memcpy_fast (((u8 *) en0) - vec_len (sl0->rewrite),
2020 sl0->rewrite, vec_len (sl0->rewrite));
2021 clib_memcpy_fast (((u8 *) en1) - vec_len (sl1->rewrite),
2022 sl1->rewrite, vec_len (sl1->rewrite));
2023 clib_memcpy_fast (((u8 *) en2) - vec_len (sl2->rewrite),
2024 sl2->rewrite, vec_len (sl2->rewrite));
2025 clib_memcpy_fast (((u8 *) en3) - vec_len (sl3->rewrite),
2026 sl3->rewrite, vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002027
2028 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2029 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2030 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2031 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2032
2033 ip0 = vlib_buffer_get_current (b0);
2034 ip1 = vlib_buffer_get_current (b1);
2035 ip2 = vlib_buffer_get_current (b2);
2036 ip3 = vlib_buffer_get_current (b3);
2037
2038 ip0->payload_length =
2039 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
2040 ip1->payload_length =
2041 clib_host_to_net_u16 (b1->current_length - sizeof (ip6_header_t));
2042 ip2->payload_length =
2043 clib_host_to_net_u16 (b2->current_length - sizeof (ip6_header_t));
2044 ip3->payload_length =
2045 clib_host_to_net_u16 (b3->current_length - sizeof (ip6_header_t));
2046
Pablo Camarillod327c872018-01-08 14:25:55 +01002047 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
2048 {
2049 sr0 = (void *) (ip0 + 1);
pcamaril30e76712020-02-04 08:36:51 +01002050 sr0->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01002051 }
2052 else
pcamaril30e76712020-02-04 08:36:51 +01002053 ip0->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillofb380952016-12-07 18:34:18 +01002054
Pablo Camarillod327c872018-01-08 14:25:55 +01002055 if (ip1->protocol == IP_PROTOCOL_IPV6_ROUTE)
2056 {
2057 sr1 = (void *) (ip1 + 1);
pcamaril30e76712020-02-04 08:36:51 +01002058 sr1->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01002059 }
2060 else
pcamaril30e76712020-02-04 08:36:51 +01002061 ip1->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01002062
2063 if (ip2->protocol == IP_PROTOCOL_IPV6_ROUTE)
2064 {
2065 sr2 = (void *) (ip2 + 1);
pcamaril30e76712020-02-04 08:36:51 +01002066 sr2->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01002067 }
2068 else
pcamaril30e76712020-02-04 08:36:51 +01002069 ip2->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01002070
2071 if (ip3->protocol == IP_PROTOCOL_IPV6_ROUTE)
2072 {
2073 sr3 = (void *) (ip3 + 1);
pcamaril30e76712020-02-04 08:36:51 +01002074 sr3->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01002075 }
2076 else
pcamaril30e76712020-02-04 08:36:51 +01002077 ip3->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillofb380952016-12-07 18:34:18 +01002078
Jakub Horn91f4a972021-01-21 12:14:58 +00002079 /* TC is set to 0 for all ethernet frames, should be taken from COS
2080 * od DSCP of encapsulated packet in the future */
2081 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2082 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label0 & 0xffff));
2083 ip1->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2084 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label1 & 0xffff));
2085 ip2->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2086 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label2 & 0xffff));
2087 ip3->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2088 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label3 & 0xffff));
Pablo Camarillofb380952016-12-07 18:34:18 +01002089
2090 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2091 {
2092 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2093 {
2094 sr_policy_rewrite_trace_t *tr =
2095 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002096 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2097 sizeof (tr->src.as_u8));
2098 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2099 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002100 }
2101
2102 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2103 {
2104 sr_policy_rewrite_trace_t *tr =
2105 vlib_add_trace (vm, node, b1, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002106 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2107 sizeof (tr->src.as_u8));
2108 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2109 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002110 }
2111
2112 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2113 {
2114 sr_policy_rewrite_trace_t *tr =
2115 vlib_add_trace (vm, node, b2, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002116 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2117 sizeof (tr->src.as_u8));
2118 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2119 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002120 }
2121
2122 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2123 {
2124 sr_policy_rewrite_trace_t *tr =
2125 vlib_add_trace (vm, node, b3, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002126 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2127 sizeof (tr->src.as_u8));
2128 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2129 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002130 }
2131 }
2132
2133 encap_pkts += 4;
2134 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2135 n_left_to_next, bi0, bi1, bi2, bi3,
2136 next0, next1, next2, next3);
2137 }
2138
2139 /* Single loop for potentially the last three packets */
2140 while (n_left_from > 0 && n_left_to_next > 0)
2141 {
2142 u32 bi0;
2143 vlib_buffer_t *b0;
2144 ip6_header_t *ip0 = 0;
2145 ip6_sr_header_t *sr0;
2146 ethernet_header_t *en0;
2147 ip6_sr_policy_t *sp0;
2148 ip6_sr_sl_t *sl0;
2149 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
Jakub Horn91f4a972021-01-21 12:14:58 +00002150 u32 flow_label0;
Pablo Camarillofb380952016-12-07 18:34:18 +01002151
2152 bi0 = from[0];
2153 to_next[0] = bi0;
2154 from += 1;
2155 to_next += 1;
2156 n_left_from -= 1;
2157 n_left_to_next -= 1;
2158 b0 = vlib_get_buffer (vm, bi0);
2159
2160 /* Find the SR policy */
2161 sp0 = pool_elt_at_index (sm->sr_policies,
2162 sm->sw_iface_sr_policies[vnet_buffer
2163 (b0)->sw_if_index
2164 [VLIB_RX]]);
Jakub Horn91f4a972021-01-21 12:14:58 +00002165 flow_label0 = l2_flow_hash (b0);
Pablo Camarillofb380952016-12-07 18:34:18 +01002166
2167 /* In case there is more than one SL, LB among them */
2168 if (vec_len (sp0->segments_lists) == 1)
2169 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
2170 else
2171 {
Jakub Horn91f4a972021-01-21 12:14:58 +00002172 vnet_buffer (b0)->ip.flow_hash = flow_label0;
Pablo Camarillofb380952016-12-07 18:34:18 +01002173 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
2174 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
2175 (vec_len (sp0->segments_lists) - 1))];
2176 }
2177 sl0 =
2178 pool_elt_at_index (sm->sid_lists,
2179 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00002180 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2181 vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002182
2183 en0 = vlib_buffer_get_current (b0);
2184
Dave Barach178cf492018-11-13 16:34:13 -05002185 clib_memcpy_fast (((u8 *) en0) - vec_len (sl0->rewrite),
2186 sl0->rewrite, vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002187
2188 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2189
2190 ip0 = vlib_buffer_get_current (b0);
2191
2192 ip0->payload_length =
2193 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
2194
Pablo Camarillod327c872018-01-08 14:25:55 +01002195 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
2196 {
2197 sr0 = (void *) (ip0 + 1);
pcamaril30e76712020-02-04 08:36:51 +01002198 sr0->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01002199 }
2200 else
pcamaril30e76712020-02-04 08:36:51 +01002201 ip0->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillofb380952016-12-07 18:34:18 +01002202
Jakub Horn91f4a972021-01-21 12:14:58 +00002203 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2204 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label0 & 0xffff));
2205
Pablo Camarillofb380952016-12-07 18:34:18 +01002206 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2207 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2208 {
2209 sr_policy_rewrite_trace_t *tr =
2210 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002211 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2212 sizeof (tr->src.as_u8));
2213 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2214 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002215 }
2216
2217 encap_pkts++;
2218 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2219 n_left_to_next, bi0, next0);
2220 }
2221
2222 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2223 }
2224
2225 /* Update counters */
2226 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
2227 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2228 encap_pkts);
2229 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
2230 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2231 bsid_pkts);
2232
2233 return from_frame->n_vectors;
2234}
2235
2236/* *INDENT-OFF* */
2237VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_l2_node) = {
2238 .function = sr_policy_rewrite_encaps_l2,
2239 .name = "sr-pl-rewrite-encaps-l2",
2240 .vector_size = sizeof (u32),
2241 .format_trace = format_sr_policy_rewrite_trace,
2242 .type = VLIB_NODE_TYPE_INTERNAL,
2243 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2244 .error_strings = sr_policy_rewrite_error_strings,
2245 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2246 .next_nodes = {
2247#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2248 foreach_sr_policy_rewrite_next
2249#undef _
2250 },
2251};
2252/* *INDENT-ON* */
2253
2254/**
2255 * @brief Graph node for applying a SR policy into a packet. SRH insertion.
2256 */
2257static uword
2258sr_policy_rewrite_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2259 vlib_frame_t * from_frame)
2260{
2261 ip6_sr_main_t *sm = &sr_main;
2262 u32 n_left_from, next_index, *from, *to_next;
2263
2264 from = vlib_frame_vector_args (from_frame);
2265 n_left_from = from_frame->n_vectors;
2266
2267 next_index = node->cached_next_index;
2268
2269 int insert_pkts = 0, bsid_pkts = 0;
2270
2271 while (n_left_from > 0)
2272 {
2273 u32 n_left_to_next;
2274
2275 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2276
2277 /* Quad - Loop */
2278 while (n_left_from >= 8 && n_left_to_next >= 4)
2279 {
2280 u32 bi0, bi1, bi2, bi3;
2281 vlib_buffer_t *b0, *b1, *b2, *b3;
2282 u32 next0, next1, next2, next3;
2283 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2284 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2285 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2286 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2287 u16 new_l0, new_l1, new_l2, new_l3;
2288
2289 /* Prefetch next iteration. */
2290 {
2291 vlib_buffer_t *p4, *p5, *p6, *p7;
2292
2293 p4 = vlib_get_buffer (vm, from[4]);
2294 p5 = vlib_get_buffer (vm, from[5]);
2295 p6 = vlib_get_buffer (vm, from[6]);
2296 p7 = vlib_get_buffer (vm, from[7]);
2297
2298 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2299 vlib_prefetch_buffer_header (p4, LOAD);
2300 vlib_prefetch_buffer_header (p5, LOAD);
2301 vlib_prefetch_buffer_header (p6, LOAD);
2302 vlib_prefetch_buffer_header (p7, LOAD);
2303
Damjan Marionaf7fb042021-07-15 11:54:41 +02002304 clib_prefetch_store (p4->data);
2305 clib_prefetch_store (p5->data);
2306 clib_prefetch_store (p6->data);
2307 clib_prefetch_store (p7->data);
Pablo Camarillofb380952016-12-07 18:34:18 +01002308 }
2309
2310 to_next[0] = bi0 = from[0];
2311 to_next[1] = bi1 = from[1];
2312 to_next[2] = bi2 = from[2];
2313 to_next[3] = bi3 = from[3];
2314 from += 4;
2315 to_next += 4;
2316 n_left_from -= 4;
2317 n_left_to_next -= 4;
2318
2319 b0 = vlib_get_buffer (vm, bi0);
2320 b1 = vlib_get_buffer (vm, bi1);
2321 b2 = vlib_get_buffer (vm, bi2);
2322 b3 = vlib_get_buffer (vm, bi3);
2323
2324 sl0 =
2325 pool_elt_at_index (sm->sid_lists,
2326 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2327 sl1 =
2328 pool_elt_at_index (sm->sid_lists,
2329 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2330 sl2 =
2331 pool_elt_at_index (sm->sid_lists,
2332 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2333 sl3 =
2334 pool_elt_at_index (sm->sid_lists,
2335 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00002336 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2337 vec_len (sl0->rewrite));
2338 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2339 vec_len (sl1->rewrite));
2340 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2341 vec_len (sl2->rewrite));
2342 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2343 vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002344
2345 ip0 = vlib_buffer_get_current (b0);
2346 ip1 = vlib_buffer_get_current (b1);
2347 ip2 = vlib_buffer_get_current (b2);
2348 ip3 = vlib_buffer_get_current (b3);
2349
2350 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2351 sr0 =
2352 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2353 ip6_ext_header_len (ip0 + 1));
2354 else
2355 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2356
2357 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2358 sr1 =
2359 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2360 ip6_ext_header_len (ip1 + 1));
2361 else
2362 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2363
2364 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2365 sr2 =
2366 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2367 ip6_ext_header_len (ip2 + 1));
2368 else
2369 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2370
2371 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2372 sr3 =
2373 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2374 ip6_ext_header_len (ip3 + 1));
2375 else
2376 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2377
Dave Barach178cf492018-11-13 16:34:13 -05002378 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2379 (void *) sr0 - (void *) ip0);
2380 clib_memcpy_fast ((u8 *) ip1 - vec_len (sl1->rewrite), (u8 *) ip1,
2381 (void *) sr1 - (void *) ip1);
2382 clib_memcpy_fast ((u8 *) ip2 - vec_len (sl2->rewrite), (u8 *) ip2,
2383 (void *) sr2 - (void *) ip2);
2384 clib_memcpy_fast ((u8 *) ip3 - vec_len (sl3->rewrite), (u8 *) ip3,
2385 (void *) sr3 - (void *) ip3);
Pablo Camarillofb380952016-12-07 18:34:18 +01002386
Dave Barach178cf492018-11-13 16:34:13 -05002387 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite)),
2388 sl0->rewrite, vec_len (sl0->rewrite));
2389 clib_memcpy_fast (((u8 *) sr1 - vec_len (sl1->rewrite)),
2390 sl1->rewrite, vec_len (sl1->rewrite));
2391 clib_memcpy_fast (((u8 *) sr2 - vec_len (sl2->rewrite)),
2392 sl2->rewrite, vec_len (sl2->rewrite));
2393 clib_memcpy_fast (((u8 *) sr3 - vec_len (sl3->rewrite)),
2394 sl3->rewrite, vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002395
2396 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2397 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2398 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2399 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2400
2401 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2402 ip1 = ((void *) ip1) - vec_len (sl1->rewrite);
2403 ip2 = ((void *) ip2) - vec_len (sl2->rewrite);
2404 ip3 = ((void *) ip3) - vec_len (sl3->rewrite);
2405
2406 ip0->hop_limit -= 1;
2407 ip1->hop_limit -= 1;
2408 ip2->hop_limit -= 1;
2409 ip3->hop_limit -= 1;
2410
2411 new_l0 =
2412 clib_net_to_host_u16 (ip0->payload_length) +
2413 vec_len (sl0->rewrite);
2414 new_l1 =
2415 clib_net_to_host_u16 (ip1->payload_length) +
2416 vec_len (sl1->rewrite);
2417 new_l2 =
2418 clib_net_to_host_u16 (ip2->payload_length) +
2419 vec_len (sl2->rewrite);
2420 new_l3 =
2421 clib_net_to_host_u16 (ip3->payload_length) +
2422 vec_len (sl3->rewrite);
2423
2424 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2425 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2426 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2427 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2428
2429 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2430 sr1 = ((void *) sr1) - vec_len (sl1->rewrite);
2431 sr2 = ((void *) sr2) - vec_len (sl2->rewrite);
2432 sr3 = ((void *) sr3) - vec_len (sl3->rewrite);
2433
2434 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2435 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2436 sr1->segments->as_u64[0] = ip1->dst_address.as_u64[0];
2437 sr1->segments->as_u64[1] = ip1->dst_address.as_u64[1];
2438 sr2->segments->as_u64[0] = ip2->dst_address.as_u64[0];
2439 sr2->segments->as_u64[1] = ip2->dst_address.as_u64[1];
2440 sr3->segments->as_u64[0] = ip3->dst_address.as_u64[0];
2441 sr3->segments->as_u64[1] = ip3->dst_address.as_u64[1];
2442
2443 ip0->dst_address.as_u64[0] =
2444 (sr0->segments + sr0->segments_left)->as_u64[0];
2445 ip0->dst_address.as_u64[1] =
2446 (sr0->segments + sr0->segments_left)->as_u64[1];
2447 ip1->dst_address.as_u64[0] =
2448 (sr1->segments + sr1->segments_left)->as_u64[0];
2449 ip1->dst_address.as_u64[1] =
2450 (sr1->segments + sr1->segments_left)->as_u64[1];
2451 ip2->dst_address.as_u64[0] =
2452 (sr2->segments + sr2->segments_left)->as_u64[0];
2453 ip2->dst_address.as_u64[1] =
2454 (sr2->segments + sr2->segments_left)->as_u64[1];
2455 ip3->dst_address.as_u64[0] =
2456 (sr3->segments + sr3->segments_left)->as_u64[0];
2457 ip3->dst_address.as_u64[1] =
2458 (sr3->segments + sr3->segments_left)->as_u64[1];
2459
2460 ip6_ext_header_t *ip_ext;
2461 if (ip0 + 1 == (void *) sr0)
2462 {
2463 sr0->protocol = ip0->protocol;
2464 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2465 }
2466 else
2467 {
2468 ip_ext = (void *) (ip0 + 1);
2469 sr0->protocol = ip_ext->next_hdr;
2470 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2471 }
2472
2473 if (ip1 + 1 == (void *) sr1)
2474 {
2475 sr1->protocol = ip1->protocol;
2476 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2477 }
2478 else
2479 {
2480 ip_ext = (void *) (ip2 + 1);
2481 sr2->protocol = ip_ext->next_hdr;
2482 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2483 }
2484
2485 if (ip2 + 1 == (void *) sr2)
2486 {
2487 sr2->protocol = ip2->protocol;
2488 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2489 }
2490 else
2491 {
2492 ip_ext = (void *) (ip2 + 1);
2493 sr2->protocol = ip_ext->next_hdr;
2494 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2495 }
2496
2497 if (ip3 + 1 == (void *) sr3)
2498 {
2499 sr3->protocol = ip3->protocol;
2500 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2501 }
2502 else
2503 {
2504 ip_ext = (void *) (ip3 + 1);
2505 sr3->protocol = ip_ext->next_hdr;
2506 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2507 }
2508
2509 insert_pkts += 4;
2510
2511 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2512 {
2513 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2514 {
2515 sr_policy_rewrite_trace_t *tr =
2516 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002517 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2518 sizeof (tr->src.as_u8));
2519 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2520 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002521 }
2522
2523 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2524 {
2525 sr_policy_rewrite_trace_t *tr =
2526 vlib_add_trace (vm, node, b1, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002527 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2528 sizeof (tr->src.as_u8));
2529 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2530 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002531 }
2532
2533 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2534 {
2535 sr_policy_rewrite_trace_t *tr =
2536 vlib_add_trace (vm, node, b2, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002537 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2538 sizeof (tr->src.as_u8));
2539 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2540 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002541 }
2542
2543 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2544 {
2545 sr_policy_rewrite_trace_t *tr =
2546 vlib_add_trace (vm, node, b3, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002547 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2548 sizeof (tr->src.as_u8));
2549 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2550 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002551 }
2552 }
2553
2554 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2555 n_left_to_next, bi0, bi1, bi2, bi3,
2556 next0, next1, next2, next3);
2557 }
2558
2559 /* Single loop for potentially the last three packets */
2560 while (n_left_from > 0 && n_left_to_next > 0)
2561 {
2562 u32 bi0;
2563 vlib_buffer_t *b0;
2564 ip6_header_t *ip0 = 0;
2565 ip6_sr_header_t *sr0 = 0;
2566 ip6_sr_sl_t *sl0;
2567 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2568 u16 new_l0 = 0;
2569
2570 bi0 = from[0];
2571 to_next[0] = bi0;
2572 from += 1;
2573 to_next += 1;
2574 n_left_from -= 1;
2575 n_left_to_next -= 1;
2576
2577 b0 = vlib_get_buffer (vm, bi0);
2578 sl0 =
2579 pool_elt_at_index (sm->sid_lists,
2580 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00002581 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2582 vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002583
2584 ip0 = vlib_buffer_get_current (b0);
2585
2586 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2587 sr0 =
2588 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2589 ip6_ext_header_len (ip0 + 1));
2590 else
2591 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2592
Dave Barach178cf492018-11-13 16:34:13 -05002593 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2594 (void *) sr0 - (void *) ip0);
2595 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite)),
2596 sl0->rewrite, vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002597
2598 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2599
2600 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2601 ip0->hop_limit -= 1;
2602 new_l0 =
2603 clib_net_to_host_u16 (ip0->payload_length) +
2604 vec_len (sl0->rewrite);
2605 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2606
2607 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2608 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2609 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2610
2611 ip0->dst_address.as_u64[0] =
2612 (sr0->segments + sr0->segments_left)->as_u64[0];
2613 ip0->dst_address.as_u64[1] =
2614 (sr0->segments + sr0->segments_left)->as_u64[1];
2615
2616 if (ip0 + 1 == (void *) sr0)
2617 {
2618 sr0->protocol = ip0->protocol;
2619 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2620 }
2621 else
2622 {
2623 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2624 sr0->protocol = ip_ext->next_hdr;
2625 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2626 }
2627
2628 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2629 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2630 {
2631 sr_policy_rewrite_trace_t *tr =
2632 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002633 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2634 sizeof (tr->src.as_u8));
2635 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2636 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002637 }
2638
2639 insert_pkts++;
2640
2641 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2642 n_left_to_next, bi0, next0);
2643 }
2644
2645 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2646 }
2647
2648 /* Update counters */
2649 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2650 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2651 insert_pkts);
2652 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2653 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2654 bsid_pkts);
2655 return from_frame->n_vectors;
2656}
2657
2658/* *INDENT-OFF* */
2659VLIB_REGISTER_NODE (sr_policy_rewrite_insert_node) = {
2660 .function = sr_policy_rewrite_insert,
2661 .name = "sr-pl-rewrite-insert",
2662 .vector_size = sizeof (u32),
2663 .format_trace = format_sr_policy_rewrite_trace,
2664 .type = VLIB_NODE_TYPE_INTERNAL,
2665 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2666 .error_strings = sr_policy_rewrite_error_strings,
2667 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2668 .next_nodes = {
2669#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2670 foreach_sr_policy_rewrite_next
2671#undef _
2672 },
2673};
2674/* *INDENT-ON* */
2675
2676/**
2677 * @brief Graph node for applying a SR policy into a packet. BSID - SRH insertion.
2678 */
2679static uword
2680sr_policy_rewrite_b_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2681 vlib_frame_t * from_frame)
2682{
2683 ip6_sr_main_t *sm = &sr_main;
2684 u32 n_left_from, next_index, *from, *to_next;
2685
2686 from = vlib_frame_vector_args (from_frame);
2687 n_left_from = from_frame->n_vectors;
2688
2689 next_index = node->cached_next_index;
2690
2691 int insert_pkts = 0, bsid_pkts = 0;
2692
2693 while (n_left_from > 0)
2694 {
2695 u32 n_left_to_next;
2696
2697 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2698
2699 /* Quad - Loop */
2700 while (n_left_from >= 8 && n_left_to_next >= 4)
2701 {
2702 u32 bi0, bi1, bi2, bi3;
2703 vlib_buffer_t *b0, *b1, *b2, *b3;
2704 u32 next0, next1, next2, next3;
2705 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2706 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2707 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2708 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2709 u16 new_l0, new_l1, new_l2, new_l3;
2710
2711 /* Prefetch next iteration. */
2712 {
2713 vlib_buffer_t *p4, *p5, *p6, *p7;
2714
2715 p4 = vlib_get_buffer (vm, from[4]);
2716 p5 = vlib_get_buffer (vm, from[5]);
2717 p6 = vlib_get_buffer (vm, from[6]);
2718 p7 = vlib_get_buffer (vm, from[7]);
2719
2720 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2721 vlib_prefetch_buffer_header (p4, LOAD);
2722 vlib_prefetch_buffer_header (p5, LOAD);
2723 vlib_prefetch_buffer_header (p6, LOAD);
2724 vlib_prefetch_buffer_header (p7, LOAD);
2725
Damjan Marionaf7fb042021-07-15 11:54:41 +02002726 clib_prefetch_store (p4->data);
2727 clib_prefetch_store (p5->data);
2728 clib_prefetch_store (p6->data);
2729 clib_prefetch_store (p7->data);
Pablo Camarillofb380952016-12-07 18:34:18 +01002730 }
2731
2732 to_next[0] = bi0 = from[0];
2733 to_next[1] = bi1 = from[1];
2734 to_next[2] = bi2 = from[2];
2735 to_next[3] = bi3 = from[3];
2736 from += 4;
2737 to_next += 4;
2738 n_left_from -= 4;
2739 n_left_to_next -= 4;
2740
2741 b0 = vlib_get_buffer (vm, bi0);
2742 b1 = vlib_get_buffer (vm, bi1);
2743 b2 = vlib_get_buffer (vm, bi2);
2744 b3 = vlib_get_buffer (vm, bi3);
2745
2746 sl0 =
2747 pool_elt_at_index (sm->sid_lists,
2748 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2749 sl1 =
2750 pool_elt_at_index (sm->sid_lists,
2751 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2752 sl2 =
2753 pool_elt_at_index (sm->sid_lists,
2754 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2755 sl3 =
2756 pool_elt_at_index (sm->sid_lists,
2757 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00002758 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2759 vec_len (sl0->rewrite_bsid));
2760 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2761 vec_len (sl1->rewrite_bsid));
2762 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2763 vec_len (sl2->rewrite_bsid));
2764 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2765 vec_len (sl3->rewrite_bsid));
Pablo Camarillofb380952016-12-07 18:34:18 +01002766
2767 ip0 = vlib_buffer_get_current (b0);
2768 ip1 = vlib_buffer_get_current (b1);
2769 ip2 = vlib_buffer_get_current (b2);
2770 ip3 = vlib_buffer_get_current (b3);
2771
2772 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2773 sr0 =
2774 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2775 ip6_ext_header_len (ip0 + 1));
2776 else
2777 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2778
2779 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2780 sr1 =
2781 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2782 ip6_ext_header_len (ip1 + 1));
2783 else
2784 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2785
2786 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2787 sr2 =
2788 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2789 ip6_ext_header_len (ip2 + 1));
2790 else
2791 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2792
2793 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2794 sr3 =
2795 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2796 ip6_ext_header_len (ip3 + 1));
2797 else
2798 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2799
Dave Barach178cf492018-11-13 16:34:13 -05002800 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite_bsid),
2801 (u8 *) ip0, (void *) sr0 - (void *) ip0);
2802 clib_memcpy_fast ((u8 *) ip1 - vec_len (sl1->rewrite_bsid),
2803 (u8 *) ip1, (void *) sr1 - (void *) ip1);
2804 clib_memcpy_fast ((u8 *) ip2 - vec_len (sl2->rewrite_bsid),
2805 (u8 *) ip2, (void *) sr2 - (void *) ip2);
2806 clib_memcpy_fast ((u8 *) ip3 - vec_len (sl3->rewrite_bsid),
2807 (u8 *) ip3, (void *) sr3 - (void *) ip3);
Pablo Camarillofb380952016-12-07 18:34:18 +01002808
Dave Barach178cf492018-11-13 16:34:13 -05002809 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2810 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2811 clib_memcpy_fast (((u8 *) sr1 - vec_len (sl1->rewrite_bsid)),
2812 sl1->rewrite_bsid, vec_len (sl1->rewrite_bsid));
2813 clib_memcpy_fast (((u8 *) sr2 - vec_len (sl2->rewrite_bsid)),
2814 sl2->rewrite_bsid, vec_len (sl2->rewrite_bsid));
2815 clib_memcpy_fast (((u8 *) sr3 - vec_len (sl3->rewrite_bsid)),
2816 sl3->rewrite_bsid, vec_len (sl3->rewrite_bsid));
Pablo Camarillofb380952016-12-07 18:34:18 +01002817
2818 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2819 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite_bsid));
2820 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite_bsid));
2821 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite_bsid));
2822
2823 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2824 ip1 = ((void *) ip1) - vec_len (sl1->rewrite_bsid);
2825 ip2 = ((void *) ip2) - vec_len (sl2->rewrite_bsid);
2826 ip3 = ((void *) ip3) - vec_len (sl3->rewrite_bsid);
2827
2828 ip0->hop_limit -= 1;
2829 ip1->hop_limit -= 1;
2830 ip2->hop_limit -= 1;
2831 ip3->hop_limit -= 1;
2832
2833 new_l0 =
2834 clib_net_to_host_u16 (ip0->payload_length) +
2835 vec_len (sl0->rewrite_bsid);
2836 new_l1 =
2837 clib_net_to_host_u16 (ip1->payload_length) +
2838 vec_len (sl1->rewrite_bsid);
2839 new_l2 =
2840 clib_net_to_host_u16 (ip2->payload_length) +
2841 vec_len (sl2->rewrite_bsid);
2842 new_l3 =
2843 clib_net_to_host_u16 (ip3->payload_length) +
2844 vec_len (sl3->rewrite_bsid);
2845
2846 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2847 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2848 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2849 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2850
2851 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2852 sr1 = ((void *) sr1) - vec_len (sl1->rewrite_bsid);
2853 sr2 = ((void *) sr2) - vec_len (sl2->rewrite_bsid);
2854 sr3 = ((void *) sr3) - vec_len (sl3->rewrite_bsid);
2855
2856 ip0->dst_address.as_u64[0] =
2857 (sr0->segments + sr0->segments_left)->as_u64[0];
2858 ip0->dst_address.as_u64[1] =
2859 (sr0->segments + sr0->segments_left)->as_u64[1];
2860 ip1->dst_address.as_u64[0] =
2861 (sr1->segments + sr1->segments_left)->as_u64[0];
2862 ip1->dst_address.as_u64[1] =
2863 (sr1->segments + sr1->segments_left)->as_u64[1];
2864 ip2->dst_address.as_u64[0] =
2865 (sr2->segments + sr2->segments_left)->as_u64[0];
2866 ip2->dst_address.as_u64[1] =
2867 (sr2->segments + sr2->segments_left)->as_u64[1];
2868 ip3->dst_address.as_u64[0] =
2869 (sr3->segments + sr3->segments_left)->as_u64[0];
2870 ip3->dst_address.as_u64[1] =
2871 (sr3->segments + sr3->segments_left)->as_u64[1];
2872
2873 ip6_ext_header_t *ip_ext;
2874 if (ip0 + 1 == (void *) sr0)
2875 {
2876 sr0->protocol = ip0->protocol;
2877 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2878 }
2879 else
2880 {
2881 ip_ext = (void *) (ip0 + 1);
2882 sr0->protocol = ip_ext->next_hdr;
2883 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2884 }
2885
2886 if (ip1 + 1 == (void *) sr1)
2887 {
2888 sr1->protocol = ip1->protocol;
2889 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2890 }
2891 else
2892 {
2893 ip_ext = (void *) (ip2 + 1);
2894 sr2->protocol = ip_ext->next_hdr;
2895 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2896 }
2897
2898 if (ip2 + 1 == (void *) sr2)
2899 {
2900 sr2->protocol = ip2->protocol;
2901 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2902 }
2903 else
2904 {
2905 ip_ext = (void *) (ip2 + 1);
2906 sr2->protocol = ip_ext->next_hdr;
2907 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2908 }
2909
2910 if (ip3 + 1 == (void *) sr3)
2911 {
2912 sr3->protocol = ip3->protocol;
2913 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2914 }
2915 else
2916 {
2917 ip_ext = (void *) (ip3 + 1);
2918 sr3->protocol = ip_ext->next_hdr;
2919 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2920 }
2921
2922 insert_pkts += 4;
2923
2924 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2925 {
2926 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2927 {
2928 sr_policy_rewrite_trace_t *tr =
2929 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002930 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2931 sizeof (tr->src.as_u8));
2932 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2933 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002934 }
2935
2936 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2937 {
2938 sr_policy_rewrite_trace_t *tr =
2939 vlib_add_trace (vm, node, b1, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002940 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2941 sizeof (tr->src.as_u8));
2942 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2943 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002944 }
2945
2946 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2947 {
2948 sr_policy_rewrite_trace_t *tr =
2949 vlib_add_trace (vm, node, b2, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002950 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2951 sizeof (tr->src.as_u8));
2952 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2953 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002954 }
2955
2956 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2957 {
2958 sr_policy_rewrite_trace_t *tr =
2959 vlib_add_trace (vm, node, b3, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002960 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2961 sizeof (tr->src.as_u8));
2962 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2963 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002964 }
2965 }
2966
2967 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2968 n_left_to_next, bi0, bi1, bi2, bi3,
2969 next0, next1, next2, next3);
2970 }
2971
2972 /* Single loop for potentially the last three packets */
2973 while (n_left_from > 0 && n_left_to_next > 0)
2974 {
2975 u32 bi0;
2976 vlib_buffer_t *b0;
2977 ip6_header_t *ip0 = 0;
2978 ip6_sr_header_t *sr0 = 0;
2979 ip6_sr_sl_t *sl0;
2980 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2981 u16 new_l0 = 0;
2982
2983 bi0 = from[0];
2984 to_next[0] = bi0;
2985 from += 1;
2986 to_next += 1;
2987 n_left_from -= 1;
2988 n_left_to_next -= 1;
2989
2990 b0 = vlib_get_buffer (vm, bi0);
2991 sl0 =
2992 pool_elt_at_index (sm->sid_lists,
2993 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00002994 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2995 vec_len (sl0->rewrite_bsid));
Pablo Camarillofb380952016-12-07 18:34:18 +01002996
2997 ip0 = vlib_buffer_get_current (b0);
2998
2999 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
3000 sr0 =
3001 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
3002 ip6_ext_header_len (ip0 + 1));
3003 else
3004 sr0 = (ip6_sr_header_t *) (ip0 + 1);
3005
Dave Barach178cf492018-11-13 16:34:13 -05003006 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite_bsid),
3007 (u8 *) ip0, (void *) sr0 - (void *) ip0);
3008 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
3009 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
Pablo Camarillofb380952016-12-07 18:34:18 +01003010
3011 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
3012
3013 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
3014 ip0->hop_limit -= 1;
3015 new_l0 =
3016 clib_net_to_host_u16 (ip0->payload_length) +
3017 vec_len (sl0->rewrite_bsid);
3018 ip0->payload_length = clib_host_to_net_u16 (new_l0);
3019
3020 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
3021
3022 ip0->dst_address.as_u64[0] =
3023 (sr0->segments + sr0->segments_left)->as_u64[0];
3024 ip0->dst_address.as_u64[1] =
3025 (sr0->segments + sr0->segments_left)->as_u64[1];
3026
3027 if (ip0 + 1 == (void *) sr0)
3028 {
3029 sr0->protocol = ip0->protocol;
3030 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
3031 }
3032 else
3033 {
3034 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
3035 sr0->protocol = ip_ext->next_hdr;
3036 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
3037 }
3038
3039 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3040 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3041 {
3042 sr_policy_rewrite_trace_t *tr =
3043 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003044 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3045 sizeof (tr->src.as_u8));
3046 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3047 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003048 }
3049
3050 insert_pkts++;
3051
3052 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3053 n_left_to_next, bi0, next0);
3054 }
3055
3056 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3057 }
3058
3059 /* Update counters */
3060 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
3061 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3062 insert_pkts);
3063 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
3064 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3065 bsid_pkts);
3066 return from_frame->n_vectors;
3067}
3068
3069/* *INDENT-OFF* */
3070VLIB_REGISTER_NODE (sr_policy_rewrite_b_insert_node) = {
3071 .function = sr_policy_rewrite_b_insert,
3072 .name = "sr-pl-rewrite-b-insert",
3073 .vector_size = sizeof (u32),
3074 .format_trace = format_sr_policy_rewrite_trace,
3075 .type = VLIB_NODE_TYPE_INTERNAL,
3076 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3077 .error_strings = sr_policy_rewrite_error_strings,
3078 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3079 .next_nodes = {
3080#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3081 foreach_sr_policy_rewrite_next
3082#undef _
3083 },
3084};
3085/* *INDENT-ON* */
3086
3087/**
3088 * @brief Function BSID encapsulation
3089 */
3090static_always_inline void
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +00003091end_bsid_encaps_srh_processing (vlib_node_runtime_t *node, vlib_buffer_t *b0,
3092 ip6_header_t *ip0, ip6_sr_header_t *sr0,
3093 u32 *next0, u8 policy_type)
Pablo Camarillofb380952016-12-07 18:34:18 +01003094{
3095 ip6_address_t *new_dst0;
3096
3097 if (PREDICT_FALSE (!sr0))
3098 goto error_bsid_encaps;
3099
3100 if (PREDICT_TRUE (sr0->type == ROUTING_HEADER_TYPE_SR))
3101 {
3102 if (PREDICT_TRUE (sr0->segments_left != 0))
3103 {
3104 sr0->segments_left -= 1;
3105 new_dst0 = (ip6_address_t *) (sr0->segments);
3106 new_dst0 += sr0->segments_left;
3107 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
3108 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
3109 return;
3110 }
3111 }
3112
3113error_bsid_encaps:
3114 *next0 = SR_POLICY_REWRITE_NEXT_ERROR;
3115 b0->error = node->errors[SR_POLICY_REWRITE_ERROR_BSID_ZERO];
3116}
3117
3118/**
3119 * @brief Graph node for applying a SR policy BSID - Encapsulation
3120 */
3121static uword
3122sr_policy_rewrite_b_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
3123 vlib_frame_t * from_frame)
3124{
3125 ip6_sr_main_t *sm = &sr_main;
3126 u32 n_left_from, next_index, *from, *to_next;
3127
3128 from = vlib_frame_vector_args (from_frame);
3129 n_left_from = from_frame->n_vectors;
3130
3131 next_index = node->cached_next_index;
3132
3133 int encap_pkts = 0, bsid_pkts = 0;
3134
3135 while (n_left_from > 0)
3136 {
3137 u32 n_left_to_next;
3138
3139 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
3140
3141 /* Quad - Loop */
3142 while (n_left_from >= 8 && n_left_to_next >= 4)
3143 {
3144 u32 bi0, bi1, bi2, bi3;
3145 vlib_buffer_t *b0, *b1, *b2, *b3;
3146 u32 next0, next1, next2, next3;
3147 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3148 ip6_header_t *ip0, *ip1, *ip2, *ip3;
3149 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
3150 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
Pablo Camarillofb380952016-12-07 18:34:18 +01003151 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
3152
3153 /* Prefetch next iteration. */
3154 {
3155 vlib_buffer_t *p4, *p5, *p6, *p7;
3156
3157 p4 = vlib_get_buffer (vm, from[4]);
3158 p5 = vlib_get_buffer (vm, from[5]);
3159 p6 = vlib_get_buffer (vm, from[6]);
3160 p7 = vlib_get_buffer (vm, from[7]);
3161
3162 /* Prefetch the buffer header and packet for the N+2 loop iteration */
3163 vlib_prefetch_buffer_header (p4, LOAD);
3164 vlib_prefetch_buffer_header (p5, LOAD);
3165 vlib_prefetch_buffer_header (p6, LOAD);
3166 vlib_prefetch_buffer_header (p7, LOAD);
3167
Damjan Marionaf7fb042021-07-15 11:54:41 +02003168 clib_prefetch_store (p4->data);
3169 clib_prefetch_store (p5->data);
3170 clib_prefetch_store (p6->data);
3171 clib_prefetch_store (p7->data);
Pablo Camarillofb380952016-12-07 18:34:18 +01003172 }
3173
3174 to_next[0] = bi0 = from[0];
3175 to_next[1] = bi1 = from[1];
3176 to_next[2] = bi2 = from[2];
3177 to_next[3] = bi3 = from[3];
3178 from += 4;
3179 to_next += 4;
3180 n_left_from -= 4;
3181 n_left_to_next -= 4;
3182
3183 b0 = vlib_get_buffer (vm, bi0);
3184 b1 = vlib_get_buffer (vm, bi1);
3185 b2 = vlib_get_buffer (vm, bi2);
3186 b3 = vlib_get_buffer (vm, bi3);
3187
3188 sl0 =
3189 pool_elt_at_index (sm->sid_lists,
3190 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3191 sl1 =
3192 pool_elt_at_index (sm->sid_lists,
3193 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
3194 sl2 =
3195 pool_elt_at_index (sm->sid_lists,
3196 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
3197 sl3 =
3198 pool_elt_at_index (sm->sid_lists,
3199 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00003200 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3201 vec_len (sl0->rewrite));
3202 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3203 vec_len (sl1->rewrite));
3204 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3205 vec_len (sl2->rewrite));
3206 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3207 vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01003208
3209 ip0_encap = vlib_buffer_get_current (b0);
3210 ip1_encap = vlib_buffer_get_current (b1);
3211 ip2_encap = vlib_buffer_get_current (b2);
3212 ip3_encap = vlib_buffer_get_current (b3);
3213
Klement Sekera769145c2019-03-06 11:59:57 +01003214 sr0 =
3215 ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
3216 NULL);
3217 sr1 =
3218 ip6_ext_header_find (vm, b1, ip1_encap, IP_PROTOCOL_IPV6_ROUTE,
3219 NULL);
3220 sr2 =
3221 ip6_ext_header_find (vm, b2, ip2_encap, IP_PROTOCOL_IPV6_ROUTE,
3222 NULL);
3223 sr3 =
3224 ip6_ext_header_find (vm, b3, ip3_encap, IP_PROTOCOL_IPV6_ROUTE,
3225 NULL);
Pablo Camarillofb380952016-12-07 18:34:18 +01003226
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +00003227 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0,
3228 sl0->policy_type);
3229 end_bsid_encaps_srh_processing (node, b1, ip1_encap, sr1, &next1,
3230 sl1->policy_type);
3231 end_bsid_encaps_srh_processing (node, b2, ip2_encap, sr2, &next2,
3232 sl2->policy_type);
3233 end_bsid_encaps_srh_processing (node, b3, ip3_encap, sr3, &next3,
3234 sl3->policy_type);
Pablo Camarillofb380952016-12-07 18:34:18 +01003235
Dave Barach178cf492018-11-13 16:34:13 -05003236 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3237 sl0->rewrite, vec_len (sl0->rewrite));
3238 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
3239 sl1->rewrite, vec_len (sl1->rewrite));
3240 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
3241 sl2->rewrite, vec_len (sl2->rewrite));
3242 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
3243 sl3->rewrite, vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01003244
3245 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3246 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
3247 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
3248 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
3249
3250 ip0 = vlib_buffer_get_current (b0);
3251 ip1 = vlib_buffer_get_current (b1);
3252 ip2 = vlib_buffer_get_current (b2);
3253 ip3 = vlib_buffer_get_current (b3);
3254
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +00003255 encaps_processing_v6 (node, b0, ip0, ip0_encap, sl0->policy_type);
3256 encaps_processing_v6 (node, b1, ip1, ip1_encap, sl1->policy_type);
3257 encaps_processing_v6 (node, b2, ip2, ip2_encap, sl2->policy_type);
3258 encaps_processing_v6 (node, b3, ip3, ip3_encap, sl3->policy_type);
Pablo Camarillofb380952016-12-07 18:34:18 +01003259
3260 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
3261 {
3262 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3263 {
3264 sr_policy_rewrite_trace_t *tr =
3265 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003266 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3267 sizeof (tr->src.as_u8));
3268 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3269 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003270 }
3271
3272 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
3273 {
3274 sr_policy_rewrite_trace_t *tr =
3275 vlib_add_trace (vm, node, b1, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003276 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
3277 sizeof (tr->src.as_u8));
3278 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
3279 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003280 }
3281
3282 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
3283 {
3284 sr_policy_rewrite_trace_t *tr =
3285 vlib_add_trace (vm, node, b2, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003286 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
3287 sizeof (tr->src.as_u8));
3288 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
3289 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003290 }
3291
3292 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
3293 {
3294 sr_policy_rewrite_trace_t *tr =
3295 vlib_add_trace (vm, node, b3, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003296 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
3297 sizeof (tr->src.as_u8));
3298 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
3299 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003300 }
3301 }
3302
3303 encap_pkts += 4;
3304 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
3305 n_left_to_next, bi0, bi1, bi2, bi3,
3306 next0, next1, next2, next3);
3307 }
3308
3309 /* Single loop for potentially the last three packets */
3310 while (n_left_from > 0 && n_left_to_next > 0)
3311 {
3312 u32 bi0;
3313 vlib_buffer_t *b0;
3314 ip6_header_t *ip0 = 0, *ip0_encap = 0;
Pablo Camarillofb380952016-12-07 18:34:18 +01003315 ip6_sr_header_t *sr0;
3316 ip6_sr_sl_t *sl0;
3317 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3318
3319 bi0 = from[0];
3320 to_next[0] = bi0;
3321 from += 1;
3322 to_next += 1;
3323 n_left_from -= 1;
3324 n_left_to_next -= 1;
3325 b0 = vlib_get_buffer (vm, bi0);
3326
3327 sl0 =
3328 pool_elt_at_index (sm->sid_lists,
3329 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00003330 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3331 vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01003332
3333 ip0_encap = vlib_buffer_get_current (b0);
Klement Sekera769145c2019-03-06 11:59:57 +01003334 sr0 =
3335 ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
3336 NULL);
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +00003337 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0,
3338 sl0->policy_type);
Pablo Camarillofb380952016-12-07 18:34:18 +01003339
Dave Barach178cf492018-11-13 16:34:13 -05003340 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3341 sl0->rewrite, vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01003342 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3343
3344 ip0 = vlib_buffer_get_current (b0);
3345
Ahmed Abdelsalamad8b82d2021-08-24 15:59:39 +00003346 encaps_processing_v6 (node, b0, ip0, ip0_encap, sl0->policy_type);
Pablo Camarillofb380952016-12-07 18:34:18 +01003347
3348 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3349 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3350 {
3351 sr_policy_rewrite_trace_t *tr =
3352 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003353 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3354 sizeof (tr->src.as_u8));
3355 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3356 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003357 }
3358
3359 encap_pkts++;
3360 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3361 n_left_to_next, bi0, next0);
3362 }
3363
3364 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3365 }
3366
3367 /* Update counters */
3368 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3369 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3370 encap_pkts);
3371 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3372 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3373 bsid_pkts);
3374
3375 return from_frame->n_vectors;
3376}
3377
3378/* *INDENT-OFF* */
3379VLIB_REGISTER_NODE (sr_policy_rewrite_b_encaps_node) = {
3380 .function = sr_policy_rewrite_b_encaps,
3381 .name = "sr-pl-rewrite-b-encaps",
3382 .vector_size = sizeof (u32),
3383 .format_trace = format_sr_policy_rewrite_trace,
3384 .type = VLIB_NODE_TYPE_INTERNAL,
3385 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3386 .error_strings = sr_policy_rewrite_error_strings,
3387 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3388 .next_nodes = {
3389#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3390 foreach_sr_policy_rewrite_next
3391#undef _
3392 },
3393};
3394/* *INDENT-ON* */
3395
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -08003396/*************************** SR Policy plugins ******************************/
3397/**
3398 * @brief SR Policy plugin registry
3399 */
3400int
3401sr_policy_register_function (vlib_main_t * vm, u8 * fn_name,
3402 u8 * keyword_str, u8 * def_str,
3403 u8 * params_str, u8 prefix_length,
3404 dpo_type_t * dpo,
3405 format_function_t * ls_format,
3406 unformat_function_t * ls_unformat,
3407 sr_p_plugin_callback_t * creation_fn,
3408 sr_p_plugin_callback_t * removal_fn)
3409{
3410 ip6_sr_main_t *sm = &sr_main;
3411 uword *p;
3412
3413 sr_policy_fn_registration_t *plugin;
3414
3415 /* Did this function exist? If so update it */
3416 p = hash_get_mem (sm->policy_plugin_functions_by_key, fn_name);
3417 if (p)
3418 {
3419 plugin = pool_elt_at_index (sm->policy_plugin_functions, p[0]);
3420 }
3421 /* Else create a new one and set hash key */
3422 else
3423 {
3424 pool_get (sm->policy_plugin_functions, plugin);
3425 hash_set_mem (sm->policy_plugin_functions_by_key, fn_name,
3426 plugin - sm->policy_plugin_functions);
3427 }
3428
3429 clib_memset (plugin, 0, sizeof (*plugin));
3430
3431 plugin->sr_policy_function_number = (plugin - sm->policy_plugin_functions);
3432 plugin->sr_policy_function_number += SR_BEHAVIOR_LAST;
3433 plugin->prefix_length = prefix_length;
3434 plugin->ls_format = ls_format;
3435 plugin->ls_unformat = ls_unformat;
3436 plugin->creation = creation_fn;
3437 plugin->removal = removal_fn;
3438 clib_memcpy (&plugin->dpo, dpo, sizeof (dpo_type_t));
3439 plugin->function_name = format (0, "%s%c", fn_name, 0);
3440 plugin->keyword_str = format (0, "%s%c", keyword_str, 0);
3441 plugin->def_str = format (0, "%s%c", def_str, 0);
3442 plugin->params_str = format (0, "%s%c", params_str, 0);
3443
3444 return plugin->sr_policy_function_number;
3445}
3446
3447/**
3448 * @brief CLI function to 'show' all available SR LocalSID behaviors
3449 */
3450static clib_error_t *
3451show_sr_policy_behaviors_command_fn (vlib_main_t * vm,
3452 unformat_input_t * input,
3453 vlib_cli_command_t * cmd)
3454{
3455 ip6_sr_main_t *sm = &sr_main;
3456 sr_policy_fn_registration_t *plugin;
3457 sr_policy_fn_registration_t **plugins_vec = 0;
3458 int i;
3459
3460 vlib_cli_output (vm, "SR Policy behaviors:\n-----------------------\n\n");
3461
3462 /* *INDENT-OFF* */
Damjan Marionb2c31b62020-12-13 21:47:40 +01003463 pool_foreach (plugin, sm->policy_plugin_functions)
3464 { vec_add1 (plugins_vec, plugin); }
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -08003465 /* *INDENT-ON* */
3466
3467 vlib_cli_output (vm, "Plugin behaviors:\n");
3468 for (i = 0; i < vec_len (plugins_vec); i++)
3469 {
3470 plugin = plugins_vec[i];
3471 vlib_cli_output (vm, "\t%s\t-> %s.\n", plugin->keyword_str,
3472 plugin->def_str);
3473 vlib_cli_output (vm, "\t\tParameters: '%s'\n", plugin->params_str);
3474 }
3475 return 0;
3476}
3477
3478/* *INDENT-OFF* */
3479VLIB_CLI_COMMAND (show_sr_policy_behaviors_command, static) = {
3480 .path = "show sr policy behaviors",
3481 .short_help = "show sr policy behaviors",
3482 .function = show_sr_policy_behaviors_command_fn,
3483};
3484/* *INDENT-ON* */
3485
Pablo Camarillofb380952016-12-07 18:34:18 +01003486/*************************** SR Segment Lists DPOs ****************************/
3487static u8 *
3488format_sr_segment_list_dpo (u8 * s, va_list * args)
3489{
3490 ip6_sr_main_t *sm = &sr_main;
3491 ip6_address_t *addr;
3492 ip6_sr_sl_t *sl;
3493
3494 index_t index = va_arg (*args, index_t);
3495 CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
3496 s = format (s, "SR: Segment List index:[%d]", index);
3497 s = format (s, "\n\tSegments:");
3498
3499 sl = pool_elt_at_index (sm->sid_lists, index);
3500
3501 s = format (s, "< ");
3502 vec_foreach (addr, sl->segments)
3503 {
3504 s = format (s, "%U, ", format_ip6_address, addr);
3505 }
3506 s = format (s, "\b\b > - ");
3507 s = format (s, "Weight: %u", sl->weight);
3508
3509 return s;
3510}
3511
3512const static dpo_vft_t sr_policy_rewrite_vft = {
3513 .dv_lock = sr_dpo_lock,
3514 .dv_unlock = sr_dpo_unlock,
3515 .dv_format = format_sr_segment_list_dpo,
3516};
3517
3518const static char *const sr_pr_encaps_ip6_nodes[] = {
3519 "sr-pl-rewrite-encaps",
3520 NULL,
3521};
3522
3523const static char *const sr_pr_encaps_ip4_nodes[] = {
3524 "sr-pl-rewrite-encaps-v4",
3525 NULL,
3526};
3527
3528const static char *const *const sr_pr_encaps_nodes[DPO_PROTO_NUM] = {
3529 [DPO_PROTO_IP6] = sr_pr_encaps_ip6_nodes,
3530 [DPO_PROTO_IP4] = sr_pr_encaps_ip4_nodes,
3531};
3532
3533const static char *const sr_pr_insert_ip6_nodes[] = {
3534 "sr-pl-rewrite-insert",
3535 NULL,
3536};
3537
3538const static char *const *const sr_pr_insert_nodes[DPO_PROTO_NUM] = {
3539 [DPO_PROTO_IP6] = sr_pr_insert_ip6_nodes,
3540};
3541
3542const static char *const sr_pr_bsid_insert_ip6_nodes[] = {
3543 "sr-pl-rewrite-b-insert",
3544 NULL,
3545};
3546
3547const static char *const *const sr_pr_bsid_insert_nodes[DPO_PROTO_NUM] = {
3548 [DPO_PROTO_IP6] = sr_pr_bsid_insert_ip6_nodes,
3549};
3550
3551const static char *const sr_pr_bsid_encaps_ip6_nodes[] = {
3552 "sr-pl-rewrite-b-encaps",
3553 NULL,
3554};
3555
3556const static char *const *const sr_pr_bsid_encaps_nodes[DPO_PROTO_NUM] = {
3557 [DPO_PROTO_IP6] = sr_pr_bsid_encaps_ip6_nodes,
3558};
3559
3560/********************* SR Policy Rewrite initialization ***********************/
3561/**
3562 * @brief SR Policy Rewrite initialization
3563 */
3564clib_error_t *
3565sr_policy_rewrite_init (vlib_main_t * vm)
3566{
3567 ip6_sr_main_t *sm = &sr_main;
3568
3569 /* Init memory for sr policy keys (bsid <-> ip6_address_t) */
Pablo Camarillo4521afa2017-03-16 10:43:05 +01003570 mhash_init (&sm->sr_policies_index_hash, sizeof (uword),
3571 sizeof (ip6_address_t));
Pablo Camarillofb380952016-12-07 18:34:18 +01003572
3573 /* Init SR VPO DPOs type */
3574 sr_pr_encaps_dpo_type =
3575 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_encaps_nodes);
3576
3577 sr_pr_insert_dpo_type =
3578 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_insert_nodes);
3579
3580 sr_pr_bsid_encaps_dpo_type =
3581 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_encaps_nodes);
3582
3583 sr_pr_bsid_insert_dpo_type =
3584 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_insert_nodes);
3585
3586 /* Register the L2 encaps node used in HW redirect */
3587 sm->l2_sr_policy_rewrite_index = sr_policy_rewrite_encaps_node.index;
3588
3589 sm->fib_table_ip6 = (u32) ~ 0;
3590 sm->fib_table_ip4 = (u32) ~ 0;
3591
3592 return 0;
3593}
3594
3595VLIB_INIT_FUNCTION (sr_policy_rewrite_init);
3596
3597
3598/*
3599* fd.io coding-style-patch-verification: ON
3600*
3601* Local Variables:
3602* eval: (c-set-style "gnu")
3603* End:
3604*/