blob: c7ac44b591dc0b1f5f4f4a8c9252d294f06ee1c2 [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 *
36 * This file provides the appropiates VPP graph nodes to do any of these
37 * 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 *
198compute_rewrite_encaps (ip6_address_t * sl)
199{
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 *
258compute_rewrite_insert (ip6_address_t * sl)
259{
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);
361
362 if (is_encap)
363 {
364 segment_list->rewrite = compute_rewrite_encaps (sl);
365 segment_list->rewrite_bsid = segment_list->rewrite;
366 }
367 else
368 {
369 segment_list->rewrite = compute_rewrite_insert (sl);
370 segment_list->rewrite_bsid = compute_rewrite_bsid (sl);
371 }
372
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800373 if (sr_policy->plugin)
374 {
375 plugin =
376 pool_elt_at_index (sm->policy_plugin_functions,
377 sr_policy->plugin - SR_BEHAVIOR_LAST);
378
379 segment_list->plugin = sr_policy->plugin;
380 segment_list->plugin_mem = sr_policy->plugin_mem;
381
382 plugin->creation (sr_policy);
383 }
384
Pablo Camarillofb380952016-12-07 18:34:18 +0100385 /* Create DPO */
386 dpo_reset (&segment_list->bsid_dpo);
387 dpo_reset (&segment_list->ip6_dpo);
388 dpo_reset (&segment_list->ip4_dpo);
389
390 if (is_encap)
391 {
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800392 if (!sr_policy->plugin)
393 {
394 dpo_set (&segment_list->ip6_dpo, sr_pr_encaps_dpo_type,
395 DPO_PROTO_IP6, segment_list - sm->sid_lists);
396 dpo_set (&segment_list->ip4_dpo, sr_pr_encaps_dpo_type,
397 DPO_PROTO_IP4, segment_list - sm->sid_lists);
398 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_encaps_dpo_type,
399 DPO_PROTO_IP6, segment_list - sm->sid_lists);
400 }
401 else
402 {
403 dpo_set (&segment_list->ip6_dpo, plugin->dpo, DPO_PROTO_IP6,
404 segment_list - sm->sid_lists);
405 dpo_set (&segment_list->ip4_dpo, plugin->dpo, DPO_PROTO_IP4,
406 segment_list - sm->sid_lists);
407 dpo_set (&segment_list->bsid_dpo, plugin->dpo, DPO_PROTO_IP6,
408 segment_list - sm->sid_lists);
409 }
Pablo Camarillofb380952016-12-07 18:34:18 +0100410 }
411 else
412 {
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800413 if (!sr_policy->plugin)
414 {
415 dpo_set (&segment_list->ip6_dpo, sr_pr_insert_dpo_type,
416 DPO_PROTO_IP6, segment_list - sm->sid_lists);
417 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_insert_dpo_type,
418 DPO_PROTO_IP6, segment_list - sm->sid_lists);
419 }
420 else
421 {
422 dpo_set (&segment_list->ip6_dpo, plugin->dpo, DPO_PROTO_IP6,
423 segment_list - sm->sid_lists);
424 dpo_set (&segment_list->bsid_dpo, plugin->dpo, DPO_PROTO_IP6,
425 segment_list - sm->sid_lists);
426 }
Pablo Camarillofb380952016-12-07 18:34:18 +0100427 }
428
429 return segment_list;
430}
431
432/**
433 * @brief Updates the Load Balancer after an SR Policy change
434 *
435 * @param sr_policy is the modified SR Policy
436 */
437static inline void
438update_lb (ip6_sr_policy_t * sr_policy)
439{
440 flow_hash_config_t fhc;
441 u32 *sl_index;
442 ip6_sr_sl_t *segment_list;
443 ip6_sr_main_t *sm = &sr_main;
444 load_balance_path_t path;
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100445 path.path_index = FIB_NODE_INDEX_INVALID;
Pablo Camarillofb380952016-12-07 18:34:18 +0100446 load_balance_path_t *ip4_path_vector = 0;
447 load_balance_path_t *ip6_path_vector = 0;
448 load_balance_path_t *b_path_vector = 0;
449
450 /* In case LB does not exist, create it */
451 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
452 {
453 fib_prefix_t pfx = {
454 .fp_proto = FIB_PROTOCOL_IP6,
455 .fp_len = 128,
456 .fp_addr = {
457 .ip6 = sr_policy->bsid,
458 }
459 };
460
461 /* Add FIB entry for BSID */
462 fhc = fib_table_get_flow_hash_config (sr_policy->fib_table,
Neale Rannsd792d9c2017-10-21 10:53:20 -0700463 FIB_PROTOCOL_IP6);
Pablo Camarillofb380952016-12-07 18:34:18 +0100464
465 dpo_set (&sr_policy->bsid_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
466 load_balance_create (0, DPO_PROTO_IP6, fhc));
467
468 dpo_set (&sr_policy->ip6_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
469 load_balance_create (0, DPO_PROTO_IP6, fhc));
470
471 /* Update FIB entry's to point to the LB DPO in the main FIB and hidden one */
Neale Ranns107e7d42017-04-11 09:55:19 -0700472 fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
473 sr_policy->fib_table),
474 &pfx, FIB_SOURCE_SR,
Pablo Camarillofb380952016-12-07 18:34:18 +0100475 FIB_ENTRY_FLAG_EXCLUSIVE,
476 &sr_policy->bsid_dpo);
477
478 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
479 &pfx,
480 FIB_SOURCE_SR,
481 FIB_ENTRY_FLAG_EXCLUSIVE,
482 &sr_policy->ip6_dpo);
483
484 if (sr_policy->is_encap)
485 {
486 dpo_set (&sr_policy->ip4_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP4,
487 load_balance_create (0, DPO_PROTO_IP4, fhc));
488
489 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
490 &pfx,
491 FIB_SOURCE_SR,
492 FIB_ENTRY_FLAG_EXCLUSIVE,
493 &sr_policy->ip4_dpo);
494 }
495
496 }
497
498 /* Create the LB path vector */
Pablo Camarillofb380952016-12-07 18:34:18 +0100499 vec_foreach (sl_index, sr_policy->segments_lists)
500 {
501 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
502 path.path_dpo = segment_list->bsid_dpo;
503 path.path_weight = segment_list->weight;
504 vec_add1 (b_path_vector, path);
505 path.path_dpo = segment_list->ip6_dpo;
506 vec_add1 (ip6_path_vector, path);
507 if (sr_policy->is_encap)
508 {
509 path.path_dpo = segment_list->ip4_dpo;
510 vec_add1 (ip4_path_vector, path);
511 }
512 }
513
514 /* Update LB multipath */
515 load_balance_multipath_update (&sr_policy->bsid_dpo, b_path_vector,
516 LOAD_BALANCE_FLAG_NONE);
517 load_balance_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector,
518 LOAD_BALANCE_FLAG_NONE);
519 if (sr_policy->is_encap)
520 load_balance_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector,
521 LOAD_BALANCE_FLAG_NONE);
522
523 /* Cleanup */
524 vec_free (b_path_vector);
525 vec_free (ip6_path_vector);
526 vec_free (ip4_path_vector);
Pablo Camarillofb380952016-12-07 18:34:18 +0100527}
528
529/**
530 * @brief Updates the Replicate DPO after an SR Policy change
531 *
532 * @param sr_policy is the modified SR Policy (type spray)
533 */
534static inline void
535update_replicate (ip6_sr_policy_t * sr_policy)
536{
537 u32 *sl_index;
538 ip6_sr_sl_t *segment_list;
539 ip6_sr_main_t *sm = &sr_main;
540 load_balance_path_t path;
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100541 path.path_index = FIB_NODE_INDEX_INVALID;
Pablo Camarillofb380952016-12-07 18:34:18 +0100542 load_balance_path_t *b_path_vector = 0;
543 load_balance_path_t *ip6_path_vector = 0;
544 load_balance_path_t *ip4_path_vector = 0;
545
546 /* In case LB does not exist, create it */
547 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
548 {
549 dpo_set (&sr_policy->bsid_dpo, DPO_REPLICATE,
550 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
551
552 dpo_set (&sr_policy->ip6_dpo, DPO_REPLICATE,
553 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
554
555 /* Update FIB entry's DPO to point to SR without LB */
556 fib_prefix_t pfx = {
557 .fp_proto = FIB_PROTOCOL_IP6,
558 .fp_len = 128,
559 .fp_addr = {
560 .ip6 = sr_policy->bsid,
561 }
562 };
Neale Ranns107e7d42017-04-11 09:55:19 -0700563 fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
564 sr_policy->fib_table),
565 &pfx, FIB_SOURCE_SR,
Pablo Camarillofb380952016-12-07 18:34:18 +0100566 FIB_ENTRY_FLAG_EXCLUSIVE,
567 &sr_policy->bsid_dpo);
568
569 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
570 &pfx,
571 FIB_SOURCE_SR,
572 FIB_ENTRY_FLAG_EXCLUSIVE,
573 &sr_policy->ip6_dpo);
574
575 if (sr_policy->is_encap)
576 {
577 dpo_set (&sr_policy->ip4_dpo, DPO_REPLICATE, DPO_PROTO_IP4,
578 replicate_create (0, DPO_PROTO_IP4));
579
580 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
581 &pfx,
582 FIB_SOURCE_SR,
583 FIB_ENTRY_FLAG_EXCLUSIVE,
584 &sr_policy->ip4_dpo);
585 }
586
587 }
588
589 /* Create the replicate path vector */
590 path.path_weight = 1;
591 vec_foreach (sl_index, sr_policy->segments_lists)
592 {
593 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
594 path.path_dpo = segment_list->bsid_dpo;
595 vec_add1 (b_path_vector, path);
596 path.path_dpo = segment_list->ip6_dpo;
597 vec_add1 (ip6_path_vector, path);
598 if (sr_policy->is_encap)
599 {
600 path.path_dpo = segment_list->ip4_dpo;
601 vec_add1 (ip4_path_vector, path);
602 }
603 }
604
605 /* Update replicate multipath */
606 replicate_multipath_update (&sr_policy->bsid_dpo, b_path_vector);
607 replicate_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector);
608 if (sr_policy->is_encap)
609 replicate_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector);
Pablo Camarillofb380952016-12-07 18:34:18 +0100610}
611
612/******************************* SR rewrite API *******************************/
613/* Three functions for handling sr policies:
614 * -> sr_policy_add
615 * -> sr_policy_del
616 * -> sr_policy_mod
617 * All of them are API. CLI function on sr_policy_command_fn */
618
619/**
620 * @brief Create a new SR policy
621 *
622 * @param bsid is the bindingSID of the SR Policy
623 * @param segments is a vector of IPv6 address composing the segment list
624 * @param weight is the weight of the sid list. optional.
625 * @param behavior is the behavior of the SR policy. (default//spray)
626 * @param fib_table is the VRF where to install the FIB entry for the BSID
627 * @param is_encap (bool) whether SR policy should behave as Encap/SRH Insertion
628 *
629 * @return 0 if correct, else error
630 */
631int
632sr_policy_add (ip6_address_t * bsid, ip6_address_t * segments,
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800633 u32 weight, u8 behavior, u32 fib_table, u8 is_encap,
634 u16 plugin, void *ls_plugin_mem)
Pablo Camarillofb380952016-12-07 18:34:18 +0100635{
636 ip6_sr_main_t *sm = &sr_main;
637 ip6_sr_policy_t *sr_policy = 0;
Pablo Camarillofb380952016-12-07 18:34:18 +0100638 uword *p;
639
640 /* Search for existing keys (BSID) */
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100641 p = mhash_get (&sm->sr_policies_index_hash, bsid);
Pablo Camarillofb380952016-12-07 18:34:18 +0100642 if (p)
643 {
644 /* Add SR policy that already exists; complain */
645 return -12;
646 }
647
648 /* Search collision in FIB entries */
649 /* Explanation: It might be possible that some other entity has already
650 * created a route for the BSID. This in theory is impossible, but in
651 * practise we could see it. Assert it and scream if needed */
652 fib_prefix_t pfx = {
653 .fp_proto = FIB_PROTOCOL_IP6,
654 .fp_len = 128,
655 .fp_addr = {
656 .ip6 = *bsid,
657 }
658 };
659
660 /* Lookup the FIB index associated to the table selected */
Neale Ranns107e7d42017-04-11 09:55:19 -0700661 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP6,
662 (fib_table != (u32) ~ 0 ? fib_table : 0));
Pablo Camarillofb380952016-12-07 18:34:18 +0100663 if (fib_index == ~0)
664 return -13;
665
666 /* Lookup whether there exists an entry for the BSID */
667 fib_node_index_t fei = fib_table_lookup_exact_match (fib_index, &pfx);
668 if (FIB_NODE_INDEX_INVALID != fei)
669 return -12; //There is an entry for such lookup
670
671 /* Add an SR policy object */
672 pool_get (sm->sr_policies, sr_policy);
Dave Barachb7b92992018-10-17 10:38:51 -0400673 clib_memset (sr_policy, 0, sizeof (*sr_policy));
Dave Barach178cf492018-11-13 16:34:13 -0500674 clib_memcpy_fast (&sr_policy->bsid, bsid, sizeof (ip6_address_t));
Pablo Camarillofb380952016-12-07 18:34:18 +0100675 sr_policy->type = behavior;
676 sr_policy->fib_table = (fib_table != (u32) ~ 0 ? fib_table : 0); //Is default FIB 0 ?
677 sr_policy->is_encap = is_encap;
678
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800679 if (plugin)
680 {
681 sr_policy->plugin = plugin;
682 sr_policy->plugin_mem = ls_plugin_mem;
683 }
684
Pablo Camarillofb380952016-12-07 18:34:18 +0100685 /* Copy the key */
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100686 mhash_set (&sm->sr_policies_index_hash, bsid, sr_policy - sm->sr_policies,
687 NULL);
Pablo Camarillofb380952016-12-07 18:34:18 +0100688
689 /* Create a segment list and add the index to the SR policy */
690 create_sl (sr_policy, segments, weight, is_encap);
691
692 /* If FIB doesnt exist, create them */
693 if (sm->fib_table_ip6 == (u32) ~ 0)
694 {
695 sm->fib_table_ip6 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
Neale Ranns15002542017-09-10 04:39:11 -0700696 FIB_SOURCE_SR,
Pablo Camarillofb380952016-12-07 18:34:18 +0100697 "SRv6 steering of IP6 prefixes through BSIDs");
698 sm->fib_table_ip4 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
Neale Ranns15002542017-09-10 04:39:11 -0700699 FIB_SOURCE_SR,
Pablo Camarillofb380952016-12-07 18:34:18 +0100700 "SRv6 steering of IP4 prefixes through BSIDs");
Pablo Camarillofb380952016-12-07 18:34:18 +0100701 }
702
703 /* Create IPv6 FIB for the BindingSID attached to the DPO of the only SL */
704 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
705 update_lb (sr_policy);
706 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
707 update_replicate (sr_policy);
708 return 0;
709}
710
711/**
712 * @brief Delete a SR policy
713 *
714 * @param bsid is the bindingSID of the SR Policy
715 * @param index is the index of the SR policy
716 *
717 * @return 0 if correct, else error
718 */
719int
720sr_policy_del (ip6_address_t * bsid, u32 index)
721{
722 ip6_sr_main_t *sm = &sr_main;
723 ip6_sr_policy_t *sr_policy = 0;
724 ip6_sr_sl_t *segment_list;
Pablo Camarillofb380952016-12-07 18:34:18 +0100725 u32 *sl_index;
726 uword *p;
727
Pablo Camarillofb380952016-12-07 18:34:18 +0100728 if (bsid)
729 {
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100730 p = mhash_get (&sm->sr_policies_index_hash, bsid);
Pablo Camarillofb380952016-12-07 18:34:18 +0100731 if (p)
732 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
733 else
734 return -1;
735 }
736 else
737 {
738 sr_policy = pool_elt_at_index (sm->sr_policies, index);
739 if (!sr_policy)
740 return -1;
741 }
742
743 /* Remove BindingSID FIB entry */
744 fib_prefix_t pfx = {
745 .fp_proto = FIB_PROTOCOL_IP6,
746 .fp_len = 128,
747 .fp_addr = {
748 .ip6 = sr_policy->bsid,
749 }
750 ,
751 };
752
Neale Ranns107e7d42017-04-11 09:55:19 -0700753 fib_table_entry_special_remove (fib_table_find (FIB_PROTOCOL_IP6,
754 sr_policy->fib_table),
Pablo Camarillofb380952016-12-07 18:34:18 +0100755 &pfx, FIB_SOURCE_SR);
756
757 fib_table_entry_special_remove (sm->fib_table_ip6, &pfx, FIB_SOURCE_SR);
758
759 if (sr_policy->is_encap)
760 fib_table_entry_special_remove (sm->fib_table_ip4, &pfx, FIB_SOURCE_SR);
761
762 if (dpo_id_is_valid (&sr_policy->bsid_dpo))
763 {
764 dpo_reset (&sr_policy->bsid_dpo);
765 dpo_reset (&sr_policy->ip4_dpo);
766 dpo_reset (&sr_policy->ip6_dpo);
767 }
768
769 /* Clean SID Lists */
770 vec_foreach (sl_index, sr_policy->segments_lists)
771 {
772 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
773 vec_free (segment_list->segments);
774 vec_free (segment_list->rewrite);
Kris Michielsen91074432017-06-22 13:00:20 +0200775 if (!sr_policy->is_encap)
776 vec_free (segment_list->rewrite_bsid);
Pablo Camarillofb380952016-12-07 18:34:18 +0100777 pool_put_index (sm->sid_lists, *sl_index);
778 }
779
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800780 if (sr_policy->plugin)
781 {
782 sr_policy_fn_registration_t *plugin = 0;
783
784 plugin =
785 pool_elt_at_index (sm->policy_plugin_functions,
786 sr_policy->plugin - SR_BEHAVIOR_LAST);
787
788 plugin->removal (sr_policy);
789 sr_policy->plugin = 0;
790 sr_policy->plugin_mem = NULL;
791 }
792
Pablo Camarillofb380952016-12-07 18:34:18 +0100793 /* Remove SR policy entry */
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100794 mhash_unset (&sm->sr_policies_index_hash, &sr_policy->bsid, NULL);
Pablo Camarillofb380952016-12-07 18:34:18 +0100795 pool_put (sm->sr_policies, sr_policy);
796
797 /* If FIB empty unlock it */
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100798 if (!pool_elts (sm->sr_policies) && !pool_elts (sm->steer_policies))
Pablo Camarillofb380952016-12-07 18:34:18 +0100799 {
Neale Ranns15002542017-09-10 04:39:11 -0700800 fib_table_unlock (sm->fib_table_ip6, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
801 fib_table_unlock (sm->fib_table_ip4, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
Pablo Camarillofb380952016-12-07 18:34:18 +0100802 sm->fib_table_ip6 = (u32) ~ 0;
803 sm->fib_table_ip4 = (u32) ~ 0;
804 }
805
806 return 0;
807}
808
809/**
810 * @brief Modify an existing SR policy
811 *
812 * The possible modifications are adding a new Segment List, modifying an
813 * existing Segment List (modify the weight only) and delete a given
814 * Segment List from the SR Policy.
815 *
816 * @param bsid is the bindingSID of the SR Policy
817 * @param index is the index of the SR policy
818 * @param fib_table is the VRF where to install the FIB entry for the BSID
819 * @param operation is the operation to perform (among the top ones)
820 * @param segments is a vector of IPv6 address composing the segment list
821 * @param sl_index is the index of the Segment List to modify/delete
822 * @param weight is the weight of the sid list. optional.
823 * @param is_encap Mode. Encapsulation or SRH insertion.
824 *
825 * @return 0 if correct, else error
826 */
827int
828sr_policy_mod (ip6_address_t * bsid, u32 index, u32 fib_table,
829 u8 operation, ip6_address_t * segments, u32 sl_index,
830 u32 weight)
831{
832 ip6_sr_main_t *sm = &sr_main;
833 ip6_sr_policy_t *sr_policy = 0;
834 ip6_sr_sl_t *segment_list;
835 u32 *sl_index_iterate;
836 uword *p;
837
838 if (bsid)
839 {
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100840 p = mhash_get (&sm->sr_policies_index_hash, bsid);
Pablo Camarillofb380952016-12-07 18:34:18 +0100841 if (p)
842 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
843 else
844 return -1;
845 }
846 else
847 {
848 sr_policy = pool_elt_at_index (sm->sr_policies, index);
849 if (!sr_policy)
850 return -1;
851 }
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;
936 char is_spray = 0;
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"))
975 is_spray = 1;
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
Pablo Camarillofb380952016-12-07 18:34:18 +01001024 rv = sr_policy_add (&bsid, segments, weight,
1025 (is_spray ? SR_POLICY_TYPE_SPRAY :
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -08001026 SR_POLICY_TYPE_DEFAULT), fib_table, is_encap,
1027 behavior, ls_plugin_mem);
1028
John Lod23d39c2018-09-13 15:08:08 -04001029 vec_free (segments);
Pablo Camarillofb380952016-12-07 18:34:18 +01001030 }
1031 else if (is_del)
1032 rv = sr_policy_del ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
1033 sr_policy_index);
1034 else if (is_mod)
1035 {
1036 if (!operation)
1037 return clib_error_return (0, "No SL modification specified");
1038 if (operation != 1 && sl_index == (u32) ~ 0)
1039 return clib_error_return (0, "No Segment List index specified");
1040 if (operation == 1 && vec_len (segments) == 0)
1041 return clib_error_return (0, "No Segment List specified");
1042 if (operation == 3 && weight == (u32) ~ 0)
1043 return clib_error_return (0, "No new weight for the SL specified");
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -08001044
Pablo Camarillofb380952016-12-07 18:34:18 +01001045 rv = sr_policy_mod ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
1046 sr_policy_index, fib_table, operation, segments,
1047 sl_index, weight);
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -08001048
1049 if (segments)
1050 vec_free (segments);
Pablo Camarillofb380952016-12-07 18:34:18 +01001051 }
1052
1053 switch (rv)
1054 {
1055 case 0:
1056 break;
1057 case 1:
1058 return 0;
1059 case -12:
1060 return clib_error_return (0,
1061 "There is already a FIB entry for the BindingSID address.\n"
1062 "The SR policy could not be created.");
1063 case -13:
1064 return clib_error_return (0, "The specified FIB table does not exist.");
1065 case -21:
1066 return clib_error_return (0,
1067 "The selected SR policy only contains ONE segment list. "
1068 "Please remove the SR policy instead");
1069 case -22:
1070 return clib_error_return (0,
1071 "Could not delete the segment list. "
1072 "It is not associated with that SR policy.");
1073 case -32:
1074 return clib_error_return (0,
1075 "Could not modify the segment list. "
1076 "The given SL is not associated with such SR policy.");
1077 default:
1078 return clib_error_return (0, "BUG: sr policy returns %d", rv);
1079 }
1080 return 0;
1081}
1082
1083/* *INDENT-OFF* */
1084VLIB_CLI_COMMAND (sr_policy_command, static) = {
1085 .path = "sr policy",
1086 .short_help = "sr policy [add||del||mod] [bsid 2001::1||index 5] "
1087 "next A:: next B:: next C:: (weight 1) (fib-table 2) (encap|insert)",
1088 .long_help =
1089 "Manipulation of SR policies.\n"
1090 "A Segment Routing policy may contain several SID lists. Each SID list has\n"
1091 "an associated weight (default 1), which will result in wECMP (uECMP).\n"
1092 "Segment Routing policies might be of type encapsulation or srh insertion\n"
1093 "Each SR policy will be associated with a unique BindingSID.\n"
1094 "A BindingSID is a locally allocated SegmentID. For every packet that arrives\n"
1095 "with IPv6_DA:BSID such traffic will be steered into the SR policy.\n"
1096 "The add command will create a SR policy with its first segment list (sl)\n"
1097 "The mod command allows you to add, remove, or modify the existing segment lists\n"
1098 "within an SR policy.\n"
1099 "The del command allows you to delete a SR policy along with all its associated\n"
1100 "SID lists.\n",
1101 .function = sr_policy_command_fn,
1102};
1103/* *INDENT-ON* */
1104
1105/**
1106 * @brief CLI to display onscreen all the SR policies
1107 */
1108static clib_error_t *
1109show_sr_policies_command_fn (vlib_main_t * vm, unformat_input_t * input,
1110 vlib_cli_command_t * cmd)
1111{
1112 ip6_sr_main_t *sm = &sr_main;
1113 u32 *sl_index;
1114 ip6_sr_sl_t *segment_list = 0;
1115 ip6_sr_policy_t *sr_policy = 0;
1116 ip6_sr_policy_t **vec_policies = 0;
1117 ip6_address_t *addr;
1118 u8 *s;
1119 int i = 0;
1120
1121 vlib_cli_output (vm, "SR policies:");
1122
1123 /* *INDENT-OFF* */
Damjan Marionb2c31b62020-12-13 21:47:40 +01001124 pool_foreach (sr_policy, sm->sr_policies)
1125 {vec_add1 (vec_policies, sr_policy); }
Pablo Camarillofb380952016-12-07 18:34:18 +01001126 /* *INDENT-ON* */
1127
1128 vec_foreach_index (i, vec_policies)
1129 {
1130 sr_policy = vec_policies[i];
1131 vlib_cli_output (vm, "[%u].-\tBSID: %U",
1132 (u32) (sr_policy - sm->sr_policies),
1133 format_ip6_address, &sr_policy->bsid);
1134 vlib_cli_output (vm, "\tBehavior: %s",
1135 (sr_policy->is_encap ? "Encapsulation" :
1136 "SRH insertion"));
1137 vlib_cli_output (vm, "\tType: %s",
1138 (sr_policy->type ==
1139 SR_POLICY_TYPE_DEFAULT ? "Default" : "Spray"));
1140 vlib_cli_output (vm, "\tFIB table: %u",
1141 (sr_policy->fib_table !=
1142 (u32) ~ 0 ? sr_policy->fib_table : 0));
1143 vlib_cli_output (vm, "\tSegment Lists:");
1144 vec_foreach (sl_index, sr_policy->segments_lists)
1145 {
1146 s = NULL;
1147 s = format (s, "\t[%u].- ", *sl_index);
1148 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
1149 s = format (s, "< ");
1150 vec_foreach (addr, segment_list->segments)
1151 {
1152 s = format (s, "%U, ", format_ip6_address, addr);
1153 }
1154 s = format (s, "\b\b > ");
1155 s = format (s, "weight: %u", segment_list->weight);
Benoît Ganneb9753542020-04-17 12:11:26 +02001156 vlib_cli_output (vm, " %v", s);
Pablo Camarillofb380952016-12-07 18:34:18 +01001157 }
1158 vlib_cli_output (vm, "-----------");
1159 }
1160 return 0;
1161}
1162
1163/* *INDENT-OFF* */
1164VLIB_CLI_COMMAND (show_sr_policies_command, static) = {
1165 .path = "show sr policies",
1166 .short_help = "show sr policies",
1167 .function = show_sr_policies_command_fn,
1168};
1169/* *INDENT-ON* */
1170
Ahmed Abdelsalam448bc812020-11-09 14:04:07 +00001171/**
1172 * @brief CLI to display onscreen the SR encaps source addr
1173 */
1174static clib_error_t *
1175show_sr_encaps_source_command_fn (vlib_main_t * vm, unformat_input_t * input,
1176 vlib_cli_command_t * cmd)
1177{
1178 vlib_cli_output (vm, "SR encaps source addr = %U", format_ip6_address,
1179 sr_get_encaps_source ());
1180
1181 return 0;
1182}
1183
1184/* *INDENT-OFF* */
1185VLIB_CLI_COMMAND (show_sr_encaps_source_command, static) = {
1186 .path = "show sr encaps source addr",
1187 .short_help = "show sr encaps source addr",
1188 .function = show_sr_encaps_source_command_fn,
1189};
1190/* *INDENT-ON* */
1191
Ahmed Abdelsalam80f0b882020-11-10 17:19:12 +00001192/**
1193 * @brief CLI to display onscreen the hop-limit value used for SRv6 encapsulation
1194 */
1195static clib_error_t *
1196show_sr_encaps_hop_limit_command_fn (vlib_main_t * vm,
1197 unformat_input_t * input,
1198 vlib_cli_command_t * cmd)
1199{
1200 vlib_cli_output (vm, "SR encaps hop-limit = %u", sr_get_hop_limit ());
1201
1202 return 0;
1203}
1204
1205/* *INDENT-OFF* */
1206VLIB_CLI_COMMAND (show_sr_encaps_hop_limit_command, static) = {
1207 .path = "show sr encaps hop-limit",
1208 .short_help = "show sr encaps hop-limit",
1209 .function = show_sr_encaps_hop_limit_command_fn,
1210};
1211/* *INDENT-ON* */
1212
Pablo Camarillofb380952016-12-07 18:34:18 +01001213/*************************** SR rewrite graph node ****************************/
1214/**
1215 * @brief Trace for the SR Policy Rewrite graph node
1216 */
1217static u8 *
1218format_sr_policy_rewrite_trace (u8 * s, va_list * args)
1219{
1220 //TODO
1221 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1222 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1223 sr_policy_rewrite_trace_t *t = va_arg (*args, sr_policy_rewrite_trace_t *);
1224
1225 s = format
1226 (s, "SR-policy-rewrite: src %U dst %U",
1227 format_ip6_address, &t->src, format_ip6_address, &t->dst);
1228
1229 return s;
1230}
1231
1232/**
1233 * @brief IPv6 encapsulation processing as per RFC2473
1234 */
1235static_always_inline void
1236encaps_processing_v6 (vlib_node_runtime_t * node,
1237 vlib_buffer_t * b0,
1238 ip6_header_t * ip0, ip6_header_t * ip0_encap)
1239{
1240 u32 new_l0;
Jakub Horn91f4a972021-01-21 12:14:58 +00001241 u32 flow_label;
Pablo Camarillofb380952016-12-07 18:34:18 +01001242
1243 ip0_encap->hop_limit -= 1;
1244 new_l0 =
1245 ip0->payload_length + sizeof (ip6_header_t) +
1246 clib_net_to_host_u16 (ip0_encap->payload_length);
1247 ip0->payload_length = clib_host_to_net_u16 (new_l0);
Jakub Horn91f4a972021-01-21 12:14:58 +00001248
1249 flow_label = ip6_compute_flow_hash (ip0_encap, IP_FLOW_HASH_DEFAULT);
1250 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
1251 0 |
1252 (clib_net_to_host_u32 (
1253 ip0_encap->ip_version_traffic_class_and_flow_label) &
1254 0xfff00000) |
1255 (flow_label & 0x0000ffff));
Pablo Camarillofb380952016-12-07 18:34:18 +01001256}
1257
1258/**
1259 * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
1260 */
1261static uword
1262sr_policy_rewrite_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
1263 vlib_frame_t * from_frame)
1264{
1265 ip6_sr_main_t *sm = &sr_main;
1266 u32 n_left_from, next_index, *from, *to_next;
1267
1268 from = vlib_frame_vector_args (from_frame);
1269 n_left_from = from_frame->n_vectors;
1270
1271 next_index = node->cached_next_index;
1272
1273 int encap_pkts = 0, bsid_pkts = 0;
1274
1275 while (n_left_from > 0)
1276 {
1277 u32 n_left_to_next;
1278
1279 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1280
1281 /* Quad - Loop */
1282 while (n_left_from >= 8 && n_left_to_next >= 4)
1283 {
1284 u32 bi0, bi1, bi2, bi3;
1285 vlib_buffer_t *b0, *b1, *b2, *b3;
1286 u32 next0, next1, next2, next3;
1287 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1288 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1289 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1290 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1291
1292 /* Prefetch next iteration. */
1293 {
1294 vlib_buffer_t *p4, *p5, *p6, *p7;
1295
1296 p4 = vlib_get_buffer (vm, from[4]);
1297 p5 = vlib_get_buffer (vm, from[5]);
1298 p6 = vlib_get_buffer (vm, from[6]);
1299 p7 = vlib_get_buffer (vm, from[7]);
1300
1301 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1302 vlib_prefetch_buffer_header (p4, LOAD);
1303 vlib_prefetch_buffer_header (p5, LOAD);
1304 vlib_prefetch_buffer_header (p6, LOAD);
1305 vlib_prefetch_buffer_header (p7, LOAD);
1306
1307 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1308 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1309 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1310 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1311 }
1312
1313 to_next[0] = bi0 = from[0];
1314 to_next[1] = bi1 = from[1];
1315 to_next[2] = bi2 = from[2];
1316 to_next[3] = bi3 = from[3];
1317 from += 4;
1318 to_next += 4;
1319 n_left_from -= 4;
1320 n_left_to_next -= 4;
1321
1322 b0 = vlib_get_buffer (vm, bi0);
1323 b1 = vlib_get_buffer (vm, bi1);
1324 b2 = vlib_get_buffer (vm, bi2);
1325 b3 = vlib_get_buffer (vm, bi3);
1326
1327 sl0 =
1328 pool_elt_at_index (sm->sid_lists,
1329 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1330 sl1 =
1331 pool_elt_at_index (sm->sid_lists,
1332 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1333 sl2 =
1334 pool_elt_at_index (sm->sid_lists,
1335 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1336 sl3 =
1337 pool_elt_at_index (sm->sid_lists,
1338 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1339
shwethabe146f132017-03-09 16:58:26 +00001340 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1341 vec_len (sl0->rewrite));
1342 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1343 vec_len (sl1->rewrite));
1344 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1345 vec_len (sl2->rewrite));
1346 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1347 vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001348
1349 ip0_encap = vlib_buffer_get_current (b0);
1350 ip1_encap = vlib_buffer_get_current (b1);
1351 ip2_encap = vlib_buffer_get_current (b2);
1352 ip3_encap = vlib_buffer_get_current (b3);
1353
Dave Barach178cf492018-11-13 16:34:13 -05001354 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1355 sl0->rewrite, vec_len (sl0->rewrite));
1356 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1357 sl1->rewrite, vec_len (sl1->rewrite));
1358 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1359 sl2->rewrite, vec_len (sl2->rewrite));
1360 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1361 sl3->rewrite, vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001362
1363 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1364 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1365 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1366 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1367
1368 ip0 = vlib_buffer_get_current (b0);
1369 ip1 = vlib_buffer_get_current (b1);
1370 ip2 = vlib_buffer_get_current (b2);
1371 ip3 = vlib_buffer_get_current (b3);
1372
1373 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1374 encaps_processing_v6 (node, b1, ip1, ip1_encap);
1375 encaps_processing_v6 (node, b2, ip2, ip2_encap);
1376 encaps_processing_v6 (node, b3, ip3, ip3_encap);
1377
1378 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1379 {
1380 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1381 {
1382 sr_policy_rewrite_trace_t *tr =
1383 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001384 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1385 sizeof (tr->src.as_u8));
1386 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1387 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001388 }
1389
1390 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1391 {
1392 sr_policy_rewrite_trace_t *tr =
1393 vlib_add_trace (vm, node, b1, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001394 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
1395 sizeof (tr->src.as_u8));
1396 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
1397 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001398 }
1399
1400 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1401 {
1402 sr_policy_rewrite_trace_t *tr =
1403 vlib_add_trace (vm, node, b2, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001404 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
1405 sizeof (tr->src.as_u8));
1406 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
1407 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001408 }
1409
1410 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1411 {
1412 sr_policy_rewrite_trace_t *tr =
1413 vlib_add_trace (vm, node, b3, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001414 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
1415 sizeof (tr->src.as_u8));
1416 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
1417 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001418 }
1419 }
1420
1421 encap_pkts += 4;
1422 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1423 n_left_to_next, bi0, bi1, bi2, bi3,
1424 next0, next1, next2, next3);
1425 }
1426
1427 /* Single loop for potentially the last three packets */
1428 while (n_left_from > 0 && n_left_to_next > 0)
1429 {
1430 u32 bi0;
1431 vlib_buffer_t *b0;
1432 ip6_header_t *ip0 = 0, *ip0_encap = 0;
1433 ip6_sr_sl_t *sl0;
1434 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1435
1436 bi0 = from[0];
1437 to_next[0] = bi0;
1438 from += 1;
1439 to_next += 1;
1440 n_left_from -= 1;
1441 n_left_to_next -= 1;
1442 b0 = vlib_get_buffer (vm, bi0);
1443
1444 sl0 =
1445 pool_elt_at_index (sm->sid_lists,
1446 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00001447 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1448 vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001449
1450 ip0_encap = vlib_buffer_get_current (b0);
1451
Dave Barach178cf492018-11-13 16:34:13 -05001452 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1453 sl0->rewrite, vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001454 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1455
1456 ip0 = vlib_buffer_get_current (b0);
1457
1458 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1459
1460 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1461 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1462 {
1463 sr_policy_rewrite_trace_t *tr =
1464 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001465 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1466 sizeof (tr->src.as_u8));
1467 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1468 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001469 }
1470
1471 encap_pkts++;
1472 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1473 n_left_to_next, bi0, next0);
1474 }
1475
1476 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1477 }
1478
1479 /* Update counters */
1480 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1481 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1482 encap_pkts);
1483 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1484 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1485 bsid_pkts);
1486
1487 return from_frame->n_vectors;
1488}
1489
1490/* *INDENT-OFF* */
1491VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_node) = {
1492 .function = sr_policy_rewrite_encaps,
1493 .name = "sr-pl-rewrite-encaps",
1494 .vector_size = sizeof (u32),
1495 .format_trace = format_sr_policy_rewrite_trace,
1496 .type = VLIB_NODE_TYPE_INTERNAL,
1497 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1498 .error_strings = sr_policy_rewrite_error_strings,
1499 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1500 .next_nodes = {
1501#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1502 foreach_sr_policy_rewrite_next
1503#undef _
1504 },
1505};
1506/* *INDENT-ON* */
1507
1508/**
1509 * @brief IPv4 encapsulation processing as per RFC2473
1510 */
1511static_always_inline void
1512encaps_processing_v4 (vlib_node_runtime_t * node,
1513 vlib_buffer_t * b0,
1514 ip6_header_t * ip0, ip4_header_t * ip0_encap)
1515{
1516 u32 new_l0;
1517 ip6_sr_header_t *sr0;
1518
1519 u32 checksum0;
Jakub Horn91f4a972021-01-21 12:14:58 +00001520 u32 flow_label;
Pablo Camarillofb380952016-12-07 18:34:18 +01001521
1522 /* Inner IPv4: Decrement TTL & update checksum */
1523 ip0_encap->ttl -= 1;
1524 checksum0 = ip0_encap->checksum + clib_host_to_net_u16 (0x0100);
1525 checksum0 += checksum0 >= 0xffff;
1526 ip0_encap->checksum = checksum0;
1527
1528 /* Outer IPv6: Update length, FL, proto */
1529 new_l0 = ip0->payload_length + clib_net_to_host_u16 (ip0_encap->length);
1530 ip0->payload_length = clib_host_to_net_u16 (new_l0);
Jakub Horn91f4a972021-01-21 12:14:58 +00001531 flow_label = ip4_compute_flow_hash (ip0_encap, IP_FLOW_HASH_DEFAULT);
1532 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
1533 0 | ((6 & 0xF) << 28) | ((ip0_encap->tos & 0xFF) << 20) |
1534 (flow_label & 0x0000ffff));
Pablo Camarillod327c872018-01-08 14:25:55 +01001535 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
1536 {
1537 sr0 = (void *) (ip0 + 1);
1538 sr0->protocol = IP_PROTOCOL_IP_IN_IP;
1539 }
1540 else
1541 ip0->protocol = IP_PROTOCOL_IP_IN_IP;
Pablo Camarillofb380952016-12-07 18:34:18 +01001542}
1543
1544/**
1545 * @brief Graph node for applying a SR policy into an IPv4 packet. Encapsulation
1546 */
1547static uword
1548sr_policy_rewrite_encaps_v4 (vlib_main_t * vm, vlib_node_runtime_t * node,
1549 vlib_frame_t * from_frame)
1550{
1551 ip6_sr_main_t *sm = &sr_main;
1552 u32 n_left_from, next_index, *from, *to_next;
1553
1554 from = vlib_frame_vector_args (from_frame);
1555 n_left_from = from_frame->n_vectors;
1556
1557 next_index = node->cached_next_index;
1558
1559 int encap_pkts = 0, bsid_pkts = 0;
1560
1561 while (n_left_from > 0)
1562 {
1563 u32 n_left_to_next;
1564
1565 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1566
1567 /* Quad - Loop */
1568 while (n_left_from >= 8 && n_left_to_next >= 4)
1569 {
1570 u32 bi0, bi1, bi2, bi3;
1571 vlib_buffer_t *b0, *b1, *b2, *b3;
1572 u32 next0, next1, next2, next3;
1573 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1574 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1575 ip4_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1576 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1577
1578 /* Prefetch next iteration. */
1579 {
1580 vlib_buffer_t *p4, *p5, *p6, *p7;
1581
1582 p4 = vlib_get_buffer (vm, from[4]);
1583 p5 = vlib_get_buffer (vm, from[5]);
1584 p6 = vlib_get_buffer (vm, from[6]);
1585 p7 = vlib_get_buffer (vm, from[7]);
1586
1587 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1588 vlib_prefetch_buffer_header (p4, LOAD);
1589 vlib_prefetch_buffer_header (p5, LOAD);
1590 vlib_prefetch_buffer_header (p6, LOAD);
1591 vlib_prefetch_buffer_header (p7, LOAD);
1592
1593 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1594 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1595 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1596 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1597 }
1598
1599 to_next[0] = bi0 = from[0];
1600 to_next[1] = bi1 = from[1];
1601 to_next[2] = bi2 = from[2];
1602 to_next[3] = bi3 = from[3];
1603 from += 4;
1604 to_next += 4;
1605 n_left_from -= 4;
1606 n_left_to_next -= 4;
1607
1608 b0 = vlib_get_buffer (vm, bi0);
1609 b1 = vlib_get_buffer (vm, bi1);
1610 b2 = vlib_get_buffer (vm, bi2);
1611 b3 = vlib_get_buffer (vm, bi3);
1612
1613 sl0 =
1614 pool_elt_at_index (sm->sid_lists,
1615 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1616 sl1 =
1617 pool_elt_at_index (sm->sid_lists,
1618 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1619 sl2 =
1620 pool_elt_at_index (sm->sid_lists,
1621 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1622 sl3 =
1623 pool_elt_at_index (sm->sid_lists,
1624 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00001625 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1626 vec_len (sl0->rewrite));
1627 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1628 vec_len (sl1->rewrite));
1629 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1630 vec_len (sl2->rewrite));
1631 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1632 vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001633
1634 ip0_encap = vlib_buffer_get_current (b0);
1635 ip1_encap = vlib_buffer_get_current (b1);
1636 ip2_encap = vlib_buffer_get_current (b2);
1637 ip3_encap = vlib_buffer_get_current (b3);
1638
Dave Barach178cf492018-11-13 16:34:13 -05001639 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1640 sl0->rewrite, vec_len (sl0->rewrite));
1641 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1642 sl1->rewrite, vec_len (sl1->rewrite));
1643 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1644 sl2->rewrite, vec_len (sl2->rewrite));
1645 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1646 sl3->rewrite, vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001647
1648 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1649 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1650 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1651 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1652
1653 ip0 = vlib_buffer_get_current (b0);
1654 ip1 = vlib_buffer_get_current (b1);
1655 ip2 = vlib_buffer_get_current (b2);
1656 ip3 = vlib_buffer_get_current (b3);
1657
1658 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1659 encaps_processing_v4 (node, b1, ip1, ip1_encap);
1660 encaps_processing_v4 (node, b2, ip2, ip2_encap);
1661 encaps_processing_v4 (node, b3, ip3, ip3_encap);
1662
1663 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1664 {
1665 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1666 {
1667 sr_policy_rewrite_trace_t *tr =
1668 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001669 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1670 sizeof (tr->src.as_u8));
1671 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1672 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001673 }
1674
1675 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1676 {
1677 sr_policy_rewrite_trace_t *tr =
1678 vlib_add_trace (vm, node, b1, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001679 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
1680 sizeof (tr->src.as_u8));
1681 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
1682 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001683 }
1684
1685 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1686 {
1687 sr_policy_rewrite_trace_t *tr =
1688 vlib_add_trace (vm, node, b2, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001689 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
1690 sizeof (tr->src.as_u8));
1691 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
1692 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001693 }
1694
1695 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1696 {
1697 sr_policy_rewrite_trace_t *tr =
1698 vlib_add_trace (vm, node, b3, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001699 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
1700 sizeof (tr->src.as_u8));
1701 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
1702 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001703 }
1704 }
1705
1706 encap_pkts += 4;
1707 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1708 n_left_to_next, bi0, bi1, bi2, bi3,
1709 next0, next1, next2, next3);
1710 }
1711
1712 /* Single loop for potentially the last three packets */
1713 while (n_left_from > 0 && n_left_to_next > 0)
1714 {
1715 u32 bi0;
1716 vlib_buffer_t *b0;
1717 ip6_header_t *ip0 = 0;
1718 ip4_header_t *ip0_encap = 0;
1719 ip6_sr_sl_t *sl0;
1720 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1721
1722 bi0 = from[0];
1723 to_next[0] = bi0;
1724 from += 1;
1725 to_next += 1;
1726 n_left_from -= 1;
1727 n_left_to_next -= 1;
1728 b0 = vlib_get_buffer (vm, bi0);
1729
1730 sl0 =
1731 pool_elt_at_index (sm->sid_lists,
1732 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00001733 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1734 vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001735
1736 ip0_encap = vlib_buffer_get_current (b0);
1737
Dave Barach178cf492018-11-13 16:34:13 -05001738 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1739 sl0->rewrite, vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001740 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1741
1742 ip0 = vlib_buffer_get_current (b0);
1743
1744 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1745
1746 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1747 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1748 {
1749 sr_policy_rewrite_trace_t *tr =
1750 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001751 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1752 sizeof (tr->src.as_u8));
1753 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1754 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001755 }
1756
1757 encap_pkts++;
1758 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1759 n_left_to_next, bi0, next0);
1760 }
1761
1762 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1763 }
1764
1765 /* Update counters */
1766 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1767 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1768 encap_pkts);
1769 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1770 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1771 bsid_pkts);
1772
1773 return from_frame->n_vectors;
1774}
1775
1776/* *INDENT-OFF* */
1777VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_v4_node) = {
1778 .function = sr_policy_rewrite_encaps_v4,
1779 .name = "sr-pl-rewrite-encaps-v4",
1780 .vector_size = sizeof (u32),
1781 .format_trace = format_sr_policy_rewrite_trace,
1782 .type = VLIB_NODE_TYPE_INTERNAL,
1783 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1784 .error_strings = sr_policy_rewrite_error_strings,
1785 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1786 .next_nodes = {
1787#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1788 foreach_sr_policy_rewrite_next
1789#undef _
1790 },
1791};
1792/* *INDENT-ON* */
1793
1794always_inline u32
1795ip_flow_hash (void *data)
1796{
1797 ip4_header_t *iph = (ip4_header_t *) data;
1798
1799 if ((iph->ip_version_and_header_length & 0xF0) == 0x40)
1800 return ip4_compute_flow_hash (iph, IP_FLOW_HASH_DEFAULT);
1801 else
1802 return ip6_compute_flow_hash ((ip6_header_t *) iph, IP_FLOW_HASH_DEFAULT);
1803}
1804
1805always_inline u64
1806mac_to_u64 (u8 * m)
1807{
1808 return (*((u64 *) m) & 0xffffffffffff);
1809}
1810
1811always_inline u32
1812l2_flow_hash (vlib_buffer_t * b0)
1813{
1814 ethernet_header_t *eh;
1815 u64 a, b, c;
1816 uword is_ip, eh_size;
1817 u16 eh_type;
1818
1819 eh = vlib_buffer_get_current (b0);
1820 eh_type = clib_net_to_host_u16 (eh->type);
1821 eh_size = ethernet_buffer_header_size (b0);
1822
1823 is_ip = (eh_type == ETHERNET_TYPE_IP4 || eh_type == ETHERNET_TYPE_IP6);
1824
1825 /* since we have 2 cache lines, use them */
1826 if (is_ip)
1827 a = ip_flow_hash ((u8 *) vlib_buffer_get_current (b0) + eh_size);
1828 else
1829 a = eh->type;
1830
1831 b = mac_to_u64 ((u8 *) eh->dst_address);
1832 c = mac_to_u64 ((u8 *) eh->src_address);
1833 hash_mix64 (a, b, c);
1834
1835 return (u32) c;
1836}
1837
1838/**
1839 * @brief Graph node for applying a SR policy into a L2 frame
1840 */
1841static uword
1842sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
1843 vlib_frame_t * from_frame)
1844{
1845 ip6_sr_main_t *sm = &sr_main;
1846 u32 n_left_from, next_index, *from, *to_next;
1847
1848 from = vlib_frame_vector_args (from_frame);
1849 n_left_from = from_frame->n_vectors;
1850
1851 next_index = node->cached_next_index;
1852
1853 int encap_pkts = 0, bsid_pkts = 0;
1854
1855 while (n_left_from > 0)
1856 {
1857 u32 n_left_to_next;
1858
1859 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1860
1861 /* Quad - Loop */
1862 while (n_left_from >= 8 && n_left_to_next >= 4)
1863 {
1864 u32 bi0, bi1, bi2, bi3;
1865 vlib_buffer_t *b0, *b1, *b2, *b3;
1866 u32 next0, next1, next2, next3;
1867 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1868 ethernet_header_t *en0, *en1, *en2, *en3;
1869 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1870 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1871 ip6_sr_policy_t *sp0, *sp1, *sp2, *sp3;
1872 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
Jakub Horn91f4a972021-01-21 12:14:58 +00001873 u32 flow_label0, flow_label1, flow_label2, flow_label3;
Pablo Camarillofb380952016-12-07 18:34:18 +01001874
1875 /* Prefetch next iteration. */
1876 {
1877 vlib_buffer_t *p4, *p5, *p6, *p7;
1878
1879 p4 = vlib_get_buffer (vm, from[4]);
1880 p5 = vlib_get_buffer (vm, from[5]);
1881 p6 = vlib_get_buffer (vm, from[6]);
1882 p7 = vlib_get_buffer (vm, from[7]);
1883
1884 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1885 vlib_prefetch_buffer_header (p4, LOAD);
1886 vlib_prefetch_buffer_header (p5, LOAD);
1887 vlib_prefetch_buffer_header (p6, LOAD);
1888 vlib_prefetch_buffer_header (p7, LOAD);
1889
1890 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1891 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1892 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1893 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1894 }
1895
1896 to_next[0] = bi0 = from[0];
1897 to_next[1] = bi1 = from[1];
1898 to_next[2] = bi2 = from[2];
1899 to_next[3] = bi3 = from[3];
1900 from += 4;
1901 to_next += 4;
1902 n_left_from -= 4;
1903 n_left_to_next -= 4;
1904
1905 b0 = vlib_get_buffer (vm, bi0);
1906 b1 = vlib_get_buffer (vm, bi1);
1907 b2 = vlib_get_buffer (vm, bi2);
1908 b3 = vlib_get_buffer (vm, bi3);
1909
1910 sp0 = pool_elt_at_index (sm->sr_policies,
1911 sm->sw_iface_sr_policies[vnet_buffer
1912 (b0)->sw_if_index
1913 [VLIB_RX]]);
1914
1915 sp1 = pool_elt_at_index (sm->sr_policies,
1916 sm->sw_iface_sr_policies[vnet_buffer
1917 (b1)->sw_if_index
1918 [VLIB_RX]]);
1919
1920 sp2 = pool_elt_at_index (sm->sr_policies,
1921 sm->sw_iface_sr_policies[vnet_buffer
1922 (b2)->sw_if_index
1923 [VLIB_RX]]);
1924
1925 sp3 = pool_elt_at_index (sm->sr_policies,
1926 sm->sw_iface_sr_policies[vnet_buffer
1927 (b3)->sw_if_index
1928 [VLIB_RX]]);
Jakub Horn91f4a972021-01-21 12:14:58 +00001929 flow_label0 = l2_flow_hash (b0);
1930 flow_label1 = l2_flow_hash (b1);
1931 flow_label2 = l2_flow_hash (b2);
1932 flow_label3 = l2_flow_hash (b3);
Pablo Camarillofb380952016-12-07 18:34:18 +01001933
1934 if (vec_len (sp0->segments_lists) == 1)
1935 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1936 else
1937 {
Jakub Horn91f4a972021-01-21 12:14:58 +00001938 vnet_buffer (b0)->ip.flow_hash = flow_label0;
Pablo Camarillofb380952016-12-07 18:34:18 +01001939 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1940 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1941 (vec_len (sp0->segments_lists) - 1))];
1942 }
1943
1944 if (vec_len (sp1->segments_lists) == 1)
1945 vnet_buffer (b1)->ip.adj_index[VLIB_TX] = sp1->segments_lists[1];
1946 else
1947 {
Jakub Horn91f4a972021-01-21 12:14:58 +00001948 vnet_buffer (b1)->ip.flow_hash = flow_label1;
Pablo Camarillofb380952016-12-07 18:34:18 +01001949 vnet_buffer (b1)->ip.adj_index[VLIB_TX] =
1950 sp1->segments_lists[(vnet_buffer (b1)->ip.flow_hash &
1951 (vec_len (sp1->segments_lists) - 1))];
1952 }
1953
1954 if (vec_len (sp2->segments_lists) == 1)
1955 vnet_buffer (b2)->ip.adj_index[VLIB_TX] = sp2->segments_lists[2];
1956 else
1957 {
Jakub Horn91f4a972021-01-21 12:14:58 +00001958 vnet_buffer (b2)->ip.flow_hash = flow_label2;
Pablo Camarillofb380952016-12-07 18:34:18 +01001959 vnet_buffer (b2)->ip.adj_index[VLIB_TX] =
1960 sp2->segments_lists[(vnet_buffer (b2)->ip.flow_hash &
1961 (vec_len (sp2->segments_lists) - 1))];
1962 }
1963
1964 if (vec_len (sp3->segments_lists) == 1)
1965 vnet_buffer (b3)->ip.adj_index[VLIB_TX] = sp3->segments_lists[3];
1966 else
1967 {
Jakub Horn91f4a972021-01-21 12:14:58 +00001968 vnet_buffer (b3)->ip.flow_hash = flow_label3;
Pablo Camarillofb380952016-12-07 18:34:18 +01001969 vnet_buffer (b3)->ip.adj_index[VLIB_TX] =
1970 sp3->segments_lists[(vnet_buffer (b3)->ip.flow_hash &
1971 (vec_len (sp3->segments_lists) - 1))];
1972 }
1973
1974 sl0 =
1975 pool_elt_at_index (sm->sid_lists,
1976 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1977 sl1 =
1978 pool_elt_at_index (sm->sid_lists,
1979 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1980 sl2 =
1981 pool_elt_at_index (sm->sid_lists,
1982 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1983 sl3 =
1984 pool_elt_at_index (sm->sid_lists,
1985 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1986
shwethabe146f132017-03-09 16:58:26 +00001987 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1988 vec_len (sl0->rewrite));
1989 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1990 vec_len (sl1->rewrite));
1991 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1992 vec_len (sl2->rewrite));
1993 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1994 vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001995
1996 en0 = vlib_buffer_get_current (b0);
1997 en1 = vlib_buffer_get_current (b1);
1998 en2 = vlib_buffer_get_current (b2);
1999 en3 = vlib_buffer_get_current (b3);
2000
Dave Barach178cf492018-11-13 16:34:13 -05002001 clib_memcpy_fast (((u8 *) en0) - vec_len (sl0->rewrite),
2002 sl0->rewrite, vec_len (sl0->rewrite));
2003 clib_memcpy_fast (((u8 *) en1) - vec_len (sl1->rewrite),
2004 sl1->rewrite, vec_len (sl1->rewrite));
2005 clib_memcpy_fast (((u8 *) en2) - vec_len (sl2->rewrite),
2006 sl2->rewrite, vec_len (sl2->rewrite));
2007 clib_memcpy_fast (((u8 *) en3) - vec_len (sl3->rewrite),
2008 sl3->rewrite, vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002009
2010 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2011 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2012 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2013 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2014
2015 ip0 = vlib_buffer_get_current (b0);
2016 ip1 = vlib_buffer_get_current (b1);
2017 ip2 = vlib_buffer_get_current (b2);
2018 ip3 = vlib_buffer_get_current (b3);
2019
2020 ip0->payload_length =
2021 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
2022 ip1->payload_length =
2023 clib_host_to_net_u16 (b1->current_length - sizeof (ip6_header_t));
2024 ip2->payload_length =
2025 clib_host_to_net_u16 (b2->current_length - sizeof (ip6_header_t));
2026 ip3->payload_length =
2027 clib_host_to_net_u16 (b3->current_length - sizeof (ip6_header_t));
2028
Pablo Camarillod327c872018-01-08 14:25:55 +01002029 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
2030 {
2031 sr0 = (void *) (ip0 + 1);
pcamaril30e76712020-02-04 08:36:51 +01002032 sr0->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01002033 }
2034 else
pcamaril30e76712020-02-04 08:36:51 +01002035 ip0->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillofb380952016-12-07 18:34:18 +01002036
Pablo Camarillod327c872018-01-08 14:25:55 +01002037 if (ip1->protocol == IP_PROTOCOL_IPV6_ROUTE)
2038 {
2039 sr1 = (void *) (ip1 + 1);
pcamaril30e76712020-02-04 08:36:51 +01002040 sr1->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01002041 }
2042 else
pcamaril30e76712020-02-04 08:36:51 +01002043 ip1->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01002044
2045 if (ip2->protocol == IP_PROTOCOL_IPV6_ROUTE)
2046 {
2047 sr2 = (void *) (ip2 + 1);
pcamaril30e76712020-02-04 08:36:51 +01002048 sr2->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01002049 }
2050 else
pcamaril30e76712020-02-04 08:36:51 +01002051 ip2->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01002052
2053 if (ip3->protocol == IP_PROTOCOL_IPV6_ROUTE)
2054 {
2055 sr3 = (void *) (ip3 + 1);
pcamaril30e76712020-02-04 08:36:51 +01002056 sr3->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01002057 }
2058 else
pcamaril30e76712020-02-04 08:36:51 +01002059 ip3->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillofb380952016-12-07 18:34:18 +01002060
Jakub Horn91f4a972021-01-21 12:14:58 +00002061 /* TC is set to 0 for all ethernet frames, should be taken from COS
2062 * od DSCP of encapsulated packet in the future */
2063 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2064 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label0 & 0xffff));
2065 ip1->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2066 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label1 & 0xffff));
2067 ip2->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2068 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label2 & 0xffff));
2069 ip3->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2070 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label3 & 0xffff));
Pablo Camarillofb380952016-12-07 18:34:18 +01002071
2072 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2073 {
2074 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2075 {
2076 sr_policy_rewrite_trace_t *tr =
2077 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002078 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2079 sizeof (tr->src.as_u8));
2080 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2081 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002082 }
2083
2084 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2085 {
2086 sr_policy_rewrite_trace_t *tr =
2087 vlib_add_trace (vm, node, b1, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002088 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2089 sizeof (tr->src.as_u8));
2090 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2091 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002092 }
2093
2094 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2095 {
2096 sr_policy_rewrite_trace_t *tr =
2097 vlib_add_trace (vm, node, b2, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002098 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2099 sizeof (tr->src.as_u8));
2100 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2101 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002102 }
2103
2104 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2105 {
2106 sr_policy_rewrite_trace_t *tr =
2107 vlib_add_trace (vm, node, b3, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002108 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2109 sizeof (tr->src.as_u8));
2110 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2111 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002112 }
2113 }
2114
2115 encap_pkts += 4;
2116 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2117 n_left_to_next, bi0, bi1, bi2, bi3,
2118 next0, next1, next2, next3);
2119 }
2120
2121 /* Single loop for potentially the last three packets */
2122 while (n_left_from > 0 && n_left_to_next > 0)
2123 {
2124 u32 bi0;
2125 vlib_buffer_t *b0;
2126 ip6_header_t *ip0 = 0;
2127 ip6_sr_header_t *sr0;
2128 ethernet_header_t *en0;
2129 ip6_sr_policy_t *sp0;
2130 ip6_sr_sl_t *sl0;
2131 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
Jakub Horn91f4a972021-01-21 12:14:58 +00002132 u32 flow_label0;
Pablo Camarillofb380952016-12-07 18:34:18 +01002133
2134 bi0 = from[0];
2135 to_next[0] = bi0;
2136 from += 1;
2137 to_next += 1;
2138 n_left_from -= 1;
2139 n_left_to_next -= 1;
2140 b0 = vlib_get_buffer (vm, bi0);
2141
2142 /* Find the SR policy */
2143 sp0 = pool_elt_at_index (sm->sr_policies,
2144 sm->sw_iface_sr_policies[vnet_buffer
2145 (b0)->sw_if_index
2146 [VLIB_RX]]);
Jakub Horn91f4a972021-01-21 12:14:58 +00002147 flow_label0 = l2_flow_hash (b0);
Pablo Camarillofb380952016-12-07 18:34:18 +01002148
2149 /* In case there is more than one SL, LB among them */
2150 if (vec_len (sp0->segments_lists) == 1)
2151 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
2152 else
2153 {
Jakub Horn91f4a972021-01-21 12:14:58 +00002154 vnet_buffer (b0)->ip.flow_hash = flow_label0;
Pablo Camarillofb380952016-12-07 18:34:18 +01002155 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
2156 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
2157 (vec_len (sp0->segments_lists) - 1))];
2158 }
2159 sl0 =
2160 pool_elt_at_index (sm->sid_lists,
2161 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00002162 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2163 vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002164
2165 en0 = vlib_buffer_get_current (b0);
2166
Dave Barach178cf492018-11-13 16:34:13 -05002167 clib_memcpy_fast (((u8 *) en0) - vec_len (sl0->rewrite),
2168 sl0->rewrite, vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002169
2170 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2171
2172 ip0 = vlib_buffer_get_current (b0);
2173
2174 ip0->payload_length =
2175 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
2176
Pablo Camarillod327c872018-01-08 14:25:55 +01002177 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
2178 {
2179 sr0 = (void *) (ip0 + 1);
pcamaril30e76712020-02-04 08:36:51 +01002180 sr0->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01002181 }
2182 else
pcamaril30e76712020-02-04 08:36:51 +01002183 ip0->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillofb380952016-12-07 18:34:18 +01002184
Jakub Horn91f4a972021-01-21 12:14:58 +00002185 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2186 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label0 & 0xffff));
2187
Pablo Camarillofb380952016-12-07 18:34:18 +01002188 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2189 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2190 {
2191 sr_policy_rewrite_trace_t *tr =
2192 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002193 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2194 sizeof (tr->src.as_u8));
2195 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2196 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002197 }
2198
2199 encap_pkts++;
2200 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2201 n_left_to_next, bi0, next0);
2202 }
2203
2204 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2205 }
2206
2207 /* Update counters */
2208 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
2209 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2210 encap_pkts);
2211 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
2212 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2213 bsid_pkts);
2214
2215 return from_frame->n_vectors;
2216}
2217
2218/* *INDENT-OFF* */
2219VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_l2_node) = {
2220 .function = sr_policy_rewrite_encaps_l2,
2221 .name = "sr-pl-rewrite-encaps-l2",
2222 .vector_size = sizeof (u32),
2223 .format_trace = format_sr_policy_rewrite_trace,
2224 .type = VLIB_NODE_TYPE_INTERNAL,
2225 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2226 .error_strings = sr_policy_rewrite_error_strings,
2227 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2228 .next_nodes = {
2229#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2230 foreach_sr_policy_rewrite_next
2231#undef _
2232 },
2233};
2234/* *INDENT-ON* */
2235
2236/**
2237 * @brief Graph node for applying a SR policy into a packet. SRH insertion.
2238 */
2239static uword
2240sr_policy_rewrite_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2241 vlib_frame_t * from_frame)
2242{
2243 ip6_sr_main_t *sm = &sr_main;
2244 u32 n_left_from, next_index, *from, *to_next;
2245
2246 from = vlib_frame_vector_args (from_frame);
2247 n_left_from = from_frame->n_vectors;
2248
2249 next_index = node->cached_next_index;
2250
2251 int insert_pkts = 0, bsid_pkts = 0;
2252
2253 while (n_left_from > 0)
2254 {
2255 u32 n_left_to_next;
2256
2257 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2258
2259 /* Quad - Loop */
2260 while (n_left_from >= 8 && n_left_to_next >= 4)
2261 {
2262 u32 bi0, bi1, bi2, bi3;
2263 vlib_buffer_t *b0, *b1, *b2, *b3;
2264 u32 next0, next1, next2, next3;
2265 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2266 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2267 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2268 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2269 u16 new_l0, new_l1, new_l2, new_l3;
2270
2271 /* Prefetch next iteration. */
2272 {
2273 vlib_buffer_t *p4, *p5, *p6, *p7;
2274
2275 p4 = vlib_get_buffer (vm, from[4]);
2276 p5 = vlib_get_buffer (vm, from[5]);
2277 p6 = vlib_get_buffer (vm, from[6]);
2278 p7 = vlib_get_buffer (vm, from[7]);
2279
2280 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2281 vlib_prefetch_buffer_header (p4, LOAD);
2282 vlib_prefetch_buffer_header (p5, LOAD);
2283 vlib_prefetch_buffer_header (p6, LOAD);
2284 vlib_prefetch_buffer_header (p7, LOAD);
2285
2286 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2287 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2288 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2289 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2290 }
2291
2292 to_next[0] = bi0 = from[0];
2293 to_next[1] = bi1 = from[1];
2294 to_next[2] = bi2 = from[2];
2295 to_next[3] = bi3 = from[3];
2296 from += 4;
2297 to_next += 4;
2298 n_left_from -= 4;
2299 n_left_to_next -= 4;
2300
2301 b0 = vlib_get_buffer (vm, bi0);
2302 b1 = vlib_get_buffer (vm, bi1);
2303 b2 = vlib_get_buffer (vm, bi2);
2304 b3 = vlib_get_buffer (vm, bi3);
2305
2306 sl0 =
2307 pool_elt_at_index (sm->sid_lists,
2308 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2309 sl1 =
2310 pool_elt_at_index (sm->sid_lists,
2311 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2312 sl2 =
2313 pool_elt_at_index (sm->sid_lists,
2314 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2315 sl3 =
2316 pool_elt_at_index (sm->sid_lists,
2317 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00002318 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2319 vec_len (sl0->rewrite));
2320 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2321 vec_len (sl1->rewrite));
2322 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2323 vec_len (sl2->rewrite));
2324 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2325 vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002326
2327 ip0 = vlib_buffer_get_current (b0);
2328 ip1 = vlib_buffer_get_current (b1);
2329 ip2 = vlib_buffer_get_current (b2);
2330 ip3 = vlib_buffer_get_current (b3);
2331
2332 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2333 sr0 =
2334 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2335 ip6_ext_header_len (ip0 + 1));
2336 else
2337 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2338
2339 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2340 sr1 =
2341 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2342 ip6_ext_header_len (ip1 + 1));
2343 else
2344 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2345
2346 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2347 sr2 =
2348 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2349 ip6_ext_header_len (ip2 + 1));
2350 else
2351 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2352
2353 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2354 sr3 =
2355 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2356 ip6_ext_header_len (ip3 + 1));
2357 else
2358 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2359
Dave Barach178cf492018-11-13 16:34:13 -05002360 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2361 (void *) sr0 - (void *) ip0);
2362 clib_memcpy_fast ((u8 *) ip1 - vec_len (sl1->rewrite), (u8 *) ip1,
2363 (void *) sr1 - (void *) ip1);
2364 clib_memcpy_fast ((u8 *) ip2 - vec_len (sl2->rewrite), (u8 *) ip2,
2365 (void *) sr2 - (void *) ip2);
2366 clib_memcpy_fast ((u8 *) ip3 - vec_len (sl3->rewrite), (u8 *) ip3,
2367 (void *) sr3 - (void *) ip3);
Pablo Camarillofb380952016-12-07 18:34:18 +01002368
Dave Barach178cf492018-11-13 16:34:13 -05002369 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite)),
2370 sl0->rewrite, vec_len (sl0->rewrite));
2371 clib_memcpy_fast (((u8 *) sr1 - vec_len (sl1->rewrite)),
2372 sl1->rewrite, vec_len (sl1->rewrite));
2373 clib_memcpy_fast (((u8 *) sr2 - vec_len (sl2->rewrite)),
2374 sl2->rewrite, vec_len (sl2->rewrite));
2375 clib_memcpy_fast (((u8 *) sr3 - vec_len (sl3->rewrite)),
2376 sl3->rewrite, vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002377
2378 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2379 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2380 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2381 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2382
2383 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2384 ip1 = ((void *) ip1) - vec_len (sl1->rewrite);
2385 ip2 = ((void *) ip2) - vec_len (sl2->rewrite);
2386 ip3 = ((void *) ip3) - vec_len (sl3->rewrite);
2387
2388 ip0->hop_limit -= 1;
2389 ip1->hop_limit -= 1;
2390 ip2->hop_limit -= 1;
2391 ip3->hop_limit -= 1;
2392
2393 new_l0 =
2394 clib_net_to_host_u16 (ip0->payload_length) +
2395 vec_len (sl0->rewrite);
2396 new_l1 =
2397 clib_net_to_host_u16 (ip1->payload_length) +
2398 vec_len (sl1->rewrite);
2399 new_l2 =
2400 clib_net_to_host_u16 (ip2->payload_length) +
2401 vec_len (sl2->rewrite);
2402 new_l3 =
2403 clib_net_to_host_u16 (ip3->payload_length) +
2404 vec_len (sl3->rewrite);
2405
2406 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2407 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2408 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2409 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2410
2411 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2412 sr1 = ((void *) sr1) - vec_len (sl1->rewrite);
2413 sr2 = ((void *) sr2) - vec_len (sl2->rewrite);
2414 sr3 = ((void *) sr3) - vec_len (sl3->rewrite);
2415
2416 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2417 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2418 sr1->segments->as_u64[0] = ip1->dst_address.as_u64[0];
2419 sr1->segments->as_u64[1] = ip1->dst_address.as_u64[1];
2420 sr2->segments->as_u64[0] = ip2->dst_address.as_u64[0];
2421 sr2->segments->as_u64[1] = ip2->dst_address.as_u64[1];
2422 sr3->segments->as_u64[0] = ip3->dst_address.as_u64[0];
2423 sr3->segments->as_u64[1] = ip3->dst_address.as_u64[1];
2424
2425 ip0->dst_address.as_u64[0] =
2426 (sr0->segments + sr0->segments_left)->as_u64[0];
2427 ip0->dst_address.as_u64[1] =
2428 (sr0->segments + sr0->segments_left)->as_u64[1];
2429 ip1->dst_address.as_u64[0] =
2430 (sr1->segments + sr1->segments_left)->as_u64[0];
2431 ip1->dst_address.as_u64[1] =
2432 (sr1->segments + sr1->segments_left)->as_u64[1];
2433 ip2->dst_address.as_u64[0] =
2434 (sr2->segments + sr2->segments_left)->as_u64[0];
2435 ip2->dst_address.as_u64[1] =
2436 (sr2->segments + sr2->segments_left)->as_u64[1];
2437 ip3->dst_address.as_u64[0] =
2438 (sr3->segments + sr3->segments_left)->as_u64[0];
2439 ip3->dst_address.as_u64[1] =
2440 (sr3->segments + sr3->segments_left)->as_u64[1];
2441
2442 ip6_ext_header_t *ip_ext;
2443 if (ip0 + 1 == (void *) sr0)
2444 {
2445 sr0->protocol = ip0->protocol;
2446 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2447 }
2448 else
2449 {
2450 ip_ext = (void *) (ip0 + 1);
2451 sr0->protocol = ip_ext->next_hdr;
2452 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2453 }
2454
2455 if (ip1 + 1 == (void *) sr1)
2456 {
2457 sr1->protocol = ip1->protocol;
2458 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2459 }
2460 else
2461 {
2462 ip_ext = (void *) (ip2 + 1);
2463 sr2->protocol = ip_ext->next_hdr;
2464 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2465 }
2466
2467 if (ip2 + 1 == (void *) sr2)
2468 {
2469 sr2->protocol = ip2->protocol;
2470 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2471 }
2472 else
2473 {
2474 ip_ext = (void *) (ip2 + 1);
2475 sr2->protocol = ip_ext->next_hdr;
2476 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2477 }
2478
2479 if (ip3 + 1 == (void *) sr3)
2480 {
2481 sr3->protocol = ip3->protocol;
2482 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2483 }
2484 else
2485 {
2486 ip_ext = (void *) (ip3 + 1);
2487 sr3->protocol = ip_ext->next_hdr;
2488 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2489 }
2490
2491 insert_pkts += 4;
2492
2493 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2494 {
2495 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2496 {
2497 sr_policy_rewrite_trace_t *tr =
2498 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002499 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2500 sizeof (tr->src.as_u8));
2501 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2502 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002503 }
2504
2505 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2506 {
2507 sr_policy_rewrite_trace_t *tr =
2508 vlib_add_trace (vm, node, b1, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002509 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2510 sizeof (tr->src.as_u8));
2511 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2512 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002513 }
2514
2515 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2516 {
2517 sr_policy_rewrite_trace_t *tr =
2518 vlib_add_trace (vm, node, b2, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002519 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2520 sizeof (tr->src.as_u8));
2521 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2522 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002523 }
2524
2525 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2526 {
2527 sr_policy_rewrite_trace_t *tr =
2528 vlib_add_trace (vm, node, b3, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002529 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2530 sizeof (tr->src.as_u8));
2531 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2532 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002533 }
2534 }
2535
2536 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2537 n_left_to_next, bi0, bi1, bi2, bi3,
2538 next0, next1, next2, next3);
2539 }
2540
2541 /* Single loop for potentially the last three packets */
2542 while (n_left_from > 0 && n_left_to_next > 0)
2543 {
2544 u32 bi0;
2545 vlib_buffer_t *b0;
2546 ip6_header_t *ip0 = 0;
2547 ip6_sr_header_t *sr0 = 0;
2548 ip6_sr_sl_t *sl0;
2549 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2550 u16 new_l0 = 0;
2551
2552 bi0 = from[0];
2553 to_next[0] = bi0;
2554 from += 1;
2555 to_next += 1;
2556 n_left_from -= 1;
2557 n_left_to_next -= 1;
2558
2559 b0 = vlib_get_buffer (vm, bi0);
2560 sl0 =
2561 pool_elt_at_index (sm->sid_lists,
2562 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00002563 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2564 vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002565
2566 ip0 = vlib_buffer_get_current (b0);
2567
2568 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2569 sr0 =
2570 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2571 ip6_ext_header_len (ip0 + 1));
2572 else
2573 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2574
Dave Barach178cf492018-11-13 16:34:13 -05002575 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2576 (void *) sr0 - (void *) ip0);
2577 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite)),
2578 sl0->rewrite, vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002579
2580 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2581
2582 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2583 ip0->hop_limit -= 1;
2584 new_l0 =
2585 clib_net_to_host_u16 (ip0->payload_length) +
2586 vec_len (sl0->rewrite);
2587 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2588
2589 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2590 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2591 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2592
2593 ip0->dst_address.as_u64[0] =
2594 (sr0->segments + sr0->segments_left)->as_u64[0];
2595 ip0->dst_address.as_u64[1] =
2596 (sr0->segments + sr0->segments_left)->as_u64[1];
2597
2598 if (ip0 + 1 == (void *) sr0)
2599 {
2600 sr0->protocol = ip0->protocol;
2601 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2602 }
2603 else
2604 {
2605 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2606 sr0->protocol = ip_ext->next_hdr;
2607 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2608 }
2609
2610 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2611 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2612 {
2613 sr_policy_rewrite_trace_t *tr =
2614 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002615 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2616 sizeof (tr->src.as_u8));
2617 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2618 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002619 }
2620
2621 insert_pkts++;
2622
2623 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2624 n_left_to_next, bi0, next0);
2625 }
2626
2627 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2628 }
2629
2630 /* Update counters */
2631 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2632 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2633 insert_pkts);
2634 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2635 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2636 bsid_pkts);
2637 return from_frame->n_vectors;
2638}
2639
2640/* *INDENT-OFF* */
2641VLIB_REGISTER_NODE (sr_policy_rewrite_insert_node) = {
2642 .function = sr_policy_rewrite_insert,
2643 .name = "sr-pl-rewrite-insert",
2644 .vector_size = sizeof (u32),
2645 .format_trace = format_sr_policy_rewrite_trace,
2646 .type = VLIB_NODE_TYPE_INTERNAL,
2647 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2648 .error_strings = sr_policy_rewrite_error_strings,
2649 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2650 .next_nodes = {
2651#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2652 foreach_sr_policy_rewrite_next
2653#undef _
2654 },
2655};
2656/* *INDENT-ON* */
2657
2658/**
2659 * @brief Graph node for applying a SR policy into a packet. BSID - SRH insertion.
2660 */
2661static uword
2662sr_policy_rewrite_b_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2663 vlib_frame_t * from_frame)
2664{
2665 ip6_sr_main_t *sm = &sr_main;
2666 u32 n_left_from, next_index, *from, *to_next;
2667
2668 from = vlib_frame_vector_args (from_frame);
2669 n_left_from = from_frame->n_vectors;
2670
2671 next_index = node->cached_next_index;
2672
2673 int insert_pkts = 0, bsid_pkts = 0;
2674
2675 while (n_left_from > 0)
2676 {
2677 u32 n_left_to_next;
2678
2679 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2680
2681 /* Quad - Loop */
2682 while (n_left_from >= 8 && n_left_to_next >= 4)
2683 {
2684 u32 bi0, bi1, bi2, bi3;
2685 vlib_buffer_t *b0, *b1, *b2, *b3;
2686 u32 next0, next1, next2, next3;
2687 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2688 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2689 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2690 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2691 u16 new_l0, new_l1, new_l2, new_l3;
2692
2693 /* Prefetch next iteration. */
2694 {
2695 vlib_buffer_t *p4, *p5, *p6, *p7;
2696
2697 p4 = vlib_get_buffer (vm, from[4]);
2698 p5 = vlib_get_buffer (vm, from[5]);
2699 p6 = vlib_get_buffer (vm, from[6]);
2700 p7 = vlib_get_buffer (vm, from[7]);
2701
2702 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2703 vlib_prefetch_buffer_header (p4, LOAD);
2704 vlib_prefetch_buffer_header (p5, LOAD);
2705 vlib_prefetch_buffer_header (p6, LOAD);
2706 vlib_prefetch_buffer_header (p7, LOAD);
2707
2708 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2709 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2710 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2711 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2712 }
2713
2714 to_next[0] = bi0 = from[0];
2715 to_next[1] = bi1 = from[1];
2716 to_next[2] = bi2 = from[2];
2717 to_next[3] = bi3 = from[3];
2718 from += 4;
2719 to_next += 4;
2720 n_left_from -= 4;
2721 n_left_to_next -= 4;
2722
2723 b0 = vlib_get_buffer (vm, bi0);
2724 b1 = vlib_get_buffer (vm, bi1);
2725 b2 = vlib_get_buffer (vm, bi2);
2726 b3 = vlib_get_buffer (vm, bi3);
2727
2728 sl0 =
2729 pool_elt_at_index (sm->sid_lists,
2730 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2731 sl1 =
2732 pool_elt_at_index (sm->sid_lists,
2733 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2734 sl2 =
2735 pool_elt_at_index (sm->sid_lists,
2736 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2737 sl3 =
2738 pool_elt_at_index (sm->sid_lists,
2739 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00002740 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2741 vec_len (sl0->rewrite_bsid));
2742 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2743 vec_len (sl1->rewrite_bsid));
2744 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2745 vec_len (sl2->rewrite_bsid));
2746 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2747 vec_len (sl3->rewrite_bsid));
Pablo Camarillofb380952016-12-07 18:34:18 +01002748
2749 ip0 = vlib_buffer_get_current (b0);
2750 ip1 = vlib_buffer_get_current (b1);
2751 ip2 = vlib_buffer_get_current (b2);
2752 ip3 = vlib_buffer_get_current (b3);
2753
2754 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2755 sr0 =
2756 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2757 ip6_ext_header_len (ip0 + 1));
2758 else
2759 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2760
2761 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2762 sr1 =
2763 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2764 ip6_ext_header_len (ip1 + 1));
2765 else
2766 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2767
2768 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2769 sr2 =
2770 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2771 ip6_ext_header_len (ip2 + 1));
2772 else
2773 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2774
2775 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2776 sr3 =
2777 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2778 ip6_ext_header_len (ip3 + 1));
2779 else
2780 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2781
Dave Barach178cf492018-11-13 16:34:13 -05002782 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite_bsid),
2783 (u8 *) ip0, (void *) sr0 - (void *) ip0);
2784 clib_memcpy_fast ((u8 *) ip1 - vec_len (sl1->rewrite_bsid),
2785 (u8 *) ip1, (void *) sr1 - (void *) ip1);
2786 clib_memcpy_fast ((u8 *) ip2 - vec_len (sl2->rewrite_bsid),
2787 (u8 *) ip2, (void *) sr2 - (void *) ip2);
2788 clib_memcpy_fast ((u8 *) ip3 - vec_len (sl3->rewrite_bsid),
2789 (u8 *) ip3, (void *) sr3 - (void *) ip3);
Pablo Camarillofb380952016-12-07 18:34:18 +01002790
Dave Barach178cf492018-11-13 16:34:13 -05002791 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2792 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2793 clib_memcpy_fast (((u8 *) sr1 - vec_len (sl1->rewrite_bsid)),
2794 sl1->rewrite_bsid, vec_len (sl1->rewrite_bsid));
2795 clib_memcpy_fast (((u8 *) sr2 - vec_len (sl2->rewrite_bsid)),
2796 sl2->rewrite_bsid, vec_len (sl2->rewrite_bsid));
2797 clib_memcpy_fast (((u8 *) sr3 - vec_len (sl3->rewrite_bsid)),
2798 sl3->rewrite_bsid, vec_len (sl3->rewrite_bsid));
Pablo Camarillofb380952016-12-07 18:34:18 +01002799
2800 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2801 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite_bsid));
2802 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite_bsid));
2803 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite_bsid));
2804
2805 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2806 ip1 = ((void *) ip1) - vec_len (sl1->rewrite_bsid);
2807 ip2 = ((void *) ip2) - vec_len (sl2->rewrite_bsid);
2808 ip3 = ((void *) ip3) - vec_len (sl3->rewrite_bsid);
2809
2810 ip0->hop_limit -= 1;
2811 ip1->hop_limit -= 1;
2812 ip2->hop_limit -= 1;
2813 ip3->hop_limit -= 1;
2814
2815 new_l0 =
2816 clib_net_to_host_u16 (ip0->payload_length) +
2817 vec_len (sl0->rewrite_bsid);
2818 new_l1 =
2819 clib_net_to_host_u16 (ip1->payload_length) +
2820 vec_len (sl1->rewrite_bsid);
2821 new_l2 =
2822 clib_net_to_host_u16 (ip2->payload_length) +
2823 vec_len (sl2->rewrite_bsid);
2824 new_l3 =
2825 clib_net_to_host_u16 (ip3->payload_length) +
2826 vec_len (sl3->rewrite_bsid);
2827
2828 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2829 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2830 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2831 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2832
2833 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2834 sr1 = ((void *) sr1) - vec_len (sl1->rewrite_bsid);
2835 sr2 = ((void *) sr2) - vec_len (sl2->rewrite_bsid);
2836 sr3 = ((void *) sr3) - vec_len (sl3->rewrite_bsid);
2837
2838 ip0->dst_address.as_u64[0] =
2839 (sr0->segments + sr0->segments_left)->as_u64[0];
2840 ip0->dst_address.as_u64[1] =
2841 (sr0->segments + sr0->segments_left)->as_u64[1];
2842 ip1->dst_address.as_u64[0] =
2843 (sr1->segments + sr1->segments_left)->as_u64[0];
2844 ip1->dst_address.as_u64[1] =
2845 (sr1->segments + sr1->segments_left)->as_u64[1];
2846 ip2->dst_address.as_u64[0] =
2847 (sr2->segments + sr2->segments_left)->as_u64[0];
2848 ip2->dst_address.as_u64[1] =
2849 (sr2->segments + sr2->segments_left)->as_u64[1];
2850 ip3->dst_address.as_u64[0] =
2851 (sr3->segments + sr3->segments_left)->as_u64[0];
2852 ip3->dst_address.as_u64[1] =
2853 (sr3->segments + sr3->segments_left)->as_u64[1];
2854
2855 ip6_ext_header_t *ip_ext;
2856 if (ip0 + 1 == (void *) sr0)
2857 {
2858 sr0->protocol = ip0->protocol;
2859 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2860 }
2861 else
2862 {
2863 ip_ext = (void *) (ip0 + 1);
2864 sr0->protocol = ip_ext->next_hdr;
2865 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2866 }
2867
2868 if (ip1 + 1 == (void *) sr1)
2869 {
2870 sr1->protocol = ip1->protocol;
2871 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2872 }
2873 else
2874 {
2875 ip_ext = (void *) (ip2 + 1);
2876 sr2->protocol = ip_ext->next_hdr;
2877 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2878 }
2879
2880 if (ip2 + 1 == (void *) sr2)
2881 {
2882 sr2->protocol = ip2->protocol;
2883 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2884 }
2885 else
2886 {
2887 ip_ext = (void *) (ip2 + 1);
2888 sr2->protocol = ip_ext->next_hdr;
2889 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2890 }
2891
2892 if (ip3 + 1 == (void *) sr3)
2893 {
2894 sr3->protocol = ip3->protocol;
2895 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2896 }
2897 else
2898 {
2899 ip_ext = (void *) (ip3 + 1);
2900 sr3->protocol = ip_ext->next_hdr;
2901 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2902 }
2903
2904 insert_pkts += 4;
2905
2906 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2907 {
2908 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2909 {
2910 sr_policy_rewrite_trace_t *tr =
2911 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002912 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2913 sizeof (tr->src.as_u8));
2914 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2915 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002916 }
2917
2918 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2919 {
2920 sr_policy_rewrite_trace_t *tr =
2921 vlib_add_trace (vm, node, b1, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002922 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2923 sizeof (tr->src.as_u8));
2924 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2925 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002926 }
2927
2928 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2929 {
2930 sr_policy_rewrite_trace_t *tr =
2931 vlib_add_trace (vm, node, b2, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002932 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2933 sizeof (tr->src.as_u8));
2934 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2935 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002936 }
2937
2938 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2939 {
2940 sr_policy_rewrite_trace_t *tr =
2941 vlib_add_trace (vm, node, b3, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002942 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2943 sizeof (tr->src.as_u8));
2944 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2945 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002946 }
2947 }
2948
2949 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2950 n_left_to_next, bi0, bi1, bi2, bi3,
2951 next0, next1, next2, next3);
2952 }
2953
2954 /* Single loop for potentially the last three packets */
2955 while (n_left_from > 0 && n_left_to_next > 0)
2956 {
2957 u32 bi0;
2958 vlib_buffer_t *b0;
2959 ip6_header_t *ip0 = 0;
2960 ip6_sr_header_t *sr0 = 0;
2961 ip6_sr_sl_t *sl0;
2962 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2963 u16 new_l0 = 0;
2964
2965 bi0 = from[0];
2966 to_next[0] = bi0;
2967 from += 1;
2968 to_next += 1;
2969 n_left_from -= 1;
2970 n_left_to_next -= 1;
2971
2972 b0 = vlib_get_buffer (vm, bi0);
2973 sl0 =
2974 pool_elt_at_index (sm->sid_lists,
2975 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00002976 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2977 vec_len (sl0->rewrite_bsid));
Pablo Camarillofb380952016-12-07 18:34:18 +01002978
2979 ip0 = vlib_buffer_get_current (b0);
2980
2981 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2982 sr0 =
2983 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2984 ip6_ext_header_len (ip0 + 1));
2985 else
2986 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2987
Dave Barach178cf492018-11-13 16:34:13 -05002988 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite_bsid),
2989 (u8 *) ip0, (void *) sr0 - (void *) ip0);
2990 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2991 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
Pablo Camarillofb380952016-12-07 18:34:18 +01002992
2993 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2994
2995 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2996 ip0->hop_limit -= 1;
2997 new_l0 =
2998 clib_net_to_host_u16 (ip0->payload_length) +
2999 vec_len (sl0->rewrite_bsid);
3000 ip0->payload_length = clib_host_to_net_u16 (new_l0);
3001
3002 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
3003
3004 ip0->dst_address.as_u64[0] =
3005 (sr0->segments + sr0->segments_left)->as_u64[0];
3006 ip0->dst_address.as_u64[1] =
3007 (sr0->segments + sr0->segments_left)->as_u64[1];
3008
3009 if (ip0 + 1 == (void *) sr0)
3010 {
3011 sr0->protocol = ip0->protocol;
3012 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
3013 }
3014 else
3015 {
3016 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
3017 sr0->protocol = ip_ext->next_hdr;
3018 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
3019 }
3020
3021 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3022 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3023 {
3024 sr_policy_rewrite_trace_t *tr =
3025 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003026 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3027 sizeof (tr->src.as_u8));
3028 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3029 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003030 }
3031
3032 insert_pkts++;
3033
3034 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3035 n_left_to_next, bi0, next0);
3036 }
3037
3038 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3039 }
3040
3041 /* Update counters */
3042 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
3043 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3044 insert_pkts);
3045 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
3046 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3047 bsid_pkts);
3048 return from_frame->n_vectors;
3049}
3050
3051/* *INDENT-OFF* */
3052VLIB_REGISTER_NODE (sr_policy_rewrite_b_insert_node) = {
3053 .function = sr_policy_rewrite_b_insert,
3054 .name = "sr-pl-rewrite-b-insert",
3055 .vector_size = sizeof (u32),
3056 .format_trace = format_sr_policy_rewrite_trace,
3057 .type = VLIB_NODE_TYPE_INTERNAL,
3058 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3059 .error_strings = sr_policy_rewrite_error_strings,
3060 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3061 .next_nodes = {
3062#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3063 foreach_sr_policy_rewrite_next
3064#undef _
3065 },
3066};
3067/* *INDENT-ON* */
3068
3069/**
3070 * @brief Function BSID encapsulation
3071 */
3072static_always_inline void
3073end_bsid_encaps_srh_processing (vlib_node_runtime_t * node,
3074 vlib_buffer_t * b0,
3075 ip6_header_t * ip0,
3076 ip6_sr_header_t * sr0, u32 * next0)
3077{
3078 ip6_address_t *new_dst0;
3079
3080 if (PREDICT_FALSE (!sr0))
3081 goto error_bsid_encaps;
3082
3083 if (PREDICT_TRUE (sr0->type == ROUTING_HEADER_TYPE_SR))
3084 {
3085 if (PREDICT_TRUE (sr0->segments_left != 0))
3086 {
3087 sr0->segments_left -= 1;
3088 new_dst0 = (ip6_address_t *) (sr0->segments);
3089 new_dst0 += sr0->segments_left;
3090 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
3091 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
3092 return;
3093 }
3094 }
3095
3096error_bsid_encaps:
3097 *next0 = SR_POLICY_REWRITE_NEXT_ERROR;
3098 b0->error = node->errors[SR_POLICY_REWRITE_ERROR_BSID_ZERO];
3099}
3100
3101/**
3102 * @brief Graph node for applying a SR policy BSID - Encapsulation
3103 */
3104static uword
3105sr_policy_rewrite_b_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
3106 vlib_frame_t * from_frame)
3107{
3108 ip6_sr_main_t *sm = &sr_main;
3109 u32 n_left_from, next_index, *from, *to_next;
3110
3111 from = vlib_frame_vector_args (from_frame);
3112 n_left_from = from_frame->n_vectors;
3113
3114 next_index = node->cached_next_index;
3115
3116 int encap_pkts = 0, bsid_pkts = 0;
3117
3118 while (n_left_from > 0)
3119 {
3120 u32 n_left_to_next;
3121
3122 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
3123
3124 /* Quad - Loop */
3125 while (n_left_from >= 8 && n_left_to_next >= 4)
3126 {
3127 u32 bi0, bi1, bi2, bi3;
3128 vlib_buffer_t *b0, *b1, *b2, *b3;
3129 u32 next0, next1, next2, next3;
3130 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3131 ip6_header_t *ip0, *ip1, *ip2, *ip3;
3132 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
3133 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
Pablo Camarillofb380952016-12-07 18:34:18 +01003134 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
3135
3136 /* Prefetch next iteration. */
3137 {
3138 vlib_buffer_t *p4, *p5, *p6, *p7;
3139
3140 p4 = vlib_get_buffer (vm, from[4]);
3141 p5 = vlib_get_buffer (vm, from[5]);
3142 p6 = vlib_get_buffer (vm, from[6]);
3143 p7 = vlib_get_buffer (vm, from[7]);
3144
3145 /* Prefetch the buffer header and packet for the N+2 loop iteration */
3146 vlib_prefetch_buffer_header (p4, LOAD);
3147 vlib_prefetch_buffer_header (p5, LOAD);
3148 vlib_prefetch_buffer_header (p6, LOAD);
3149 vlib_prefetch_buffer_header (p7, LOAD);
3150
3151 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
3152 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
3153 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
3154 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
3155 }
3156
3157 to_next[0] = bi0 = from[0];
3158 to_next[1] = bi1 = from[1];
3159 to_next[2] = bi2 = from[2];
3160 to_next[3] = bi3 = from[3];
3161 from += 4;
3162 to_next += 4;
3163 n_left_from -= 4;
3164 n_left_to_next -= 4;
3165
3166 b0 = vlib_get_buffer (vm, bi0);
3167 b1 = vlib_get_buffer (vm, bi1);
3168 b2 = vlib_get_buffer (vm, bi2);
3169 b3 = vlib_get_buffer (vm, bi3);
3170
3171 sl0 =
3172 pool_elt_at_index (sm->sid_lists,
3173 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3174 sl1 =
3175 pool_elt_at_index (sm->sid_lists,
3176 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
3177 sl2 =
3178 pool_elt_at_index (sm->sid_lists,
3179 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
3180 sl3 =
3181 pool_elt_at_index (sm->sid_lists,
3182 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00003183 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3184 vec_len (sl0->rewrite));
3185 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3186 vec_len (sl1->rewrite));
3187 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3188 vec_len (sl2->rewrite));
3189 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3190 vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01003191
3192 ip0_encap = vlib_buffer_get_current (b0);
3193 ip1_encap = vlib_buffer_get_current (b1);
3194 ip2_encap = vlib_buffer_get_current (b2);
3195 ip3_encap = vlib_buffer_get_current (b3);
3196
Klement Sekera769145c2019-03-06 11:59:57 +01003197 sr0 =
3198 ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
3199 NULL);
3200 sr1 =
3201 ip6_ext_header_find (vm, b1, ip1_encap, IP_PROTOCOL_IPV6_ROUTE,
3202 NULL);
3203 sr2 =
3204 ip6_ext_header_find (vm, b2, ip2_encap, IP_PROTOCOL_IPV6_ROUTE,
3205 NULL);
3206 sr3 =
3207 ip6_ext_header_find (vm, b3, ip3_encap, IP_PROTOCOL_IPV6_ROUTE,
3208 NULL);
Pablo Camarillofb380952016-12-07 18:34:18 +01003209
3210 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
3211 end_bsid_encaps_srh_processing (node, b1, ip1_encap, sr1, &next1);
3212 end_bsid_encaps_srh_processing (node, b2, ip2_encap, sr2, &next2);
3213 end_bsid_encaps_srh_processing (node, b3, ip3_encap, sr3, &next3);
3214
Dave Barach178cf492018-11-13 16:34:13 -05003215 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3216 sl0->rewrite, vec_len (sl0->rewrite));
3217 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
3218 sl1->rewrite, vec_len (sl1->rewrite));
3219 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
3220 sl2->rewrite, vec_len (sl2->rewrite));
3221 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
3222 sl3->rewrite, vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01003223
3224 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3225 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
3226 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
3227 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
3228
3229 ip0 = vlib_buffer_get_current (b0);
3230 ip1 = vlib_buffer_get_current (b1);
3231 ip2 = vlib_buffer_get_current (b2);
3232 ip3 = vlib_buffer_get_current (b3);
3233
3234 encaps_processing_v6 (node, b0, ip0, ip0_encap);
3235 encaps_processing_v6 (node, b1, ip1, ip1_encap);
3236 encaps_processing_v6 (node, b2, ip2, ip2_encap);
3237 encaps_processing_v6 (node, b3, ip3, ip3_encap);
3238
3239 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
3240 {
3241 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3242 {
3243 sr_policy_rewrite_trace_t *tr =
3244 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003245 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3246 sizeof (tr->src.as_u8));
3247 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3248 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003249 }
3250
3251 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
3252 {
3253 sr_policy_rewrite_trace_t *tr =
3254 vlib_add_trace (vm, node, b1, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003255 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
3256 sizeof (tr->src.as_u8));
3257 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
3258 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003259 }
3260
3261 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
3262 {
3263 sr_policy_rewrite_trace_t *tr =
3264 vlib_add_trace (vm, node, b2, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003265 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
3266 sizeof (tr->src.as_u8));
3267 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
3268 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003269 }
3270
3271 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
3272 {
3273 sr_policy_rewrite_trace_t *tr =
3274 vlib_add_trace (vm, node, b3, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003275 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
3276 sizeof (tr->src.as_u8));
3277 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
3278 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003279 }
3280 }
3281
3282 encap_pkts += 4;
3283 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
3284 n_left_to_next, bi0, bi1, bi2, bi3,
3285 next0, next1, next2, next3);
3286 }
3287
3288 /* Single loop for potentially the last three packets */
3289 while (n_left_from > 0 && n_left_to_next > 0)
3290 {
3291 u32 bi0;
3292 vlib_buffer_t *b0;
3293 ip6_header_t *ip0 = 0, *ip0_encap = 0;
Pablo Camarillofb380952016-12-07 18:34:18 +01003294 ip6_sr_header_t *sr0;
3295 ip6_sr_sl_t *sl0;
3296 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3297
3298 bi0 = from[0];
3299 to_next[0] = bi0;
3300 from += 1;
3301 to_next += 1;
3302 n_left_from -= 1;
3303 n_left_to_next -= 1;
3304 b0 = vlib_get_buffer (vm, bi0);
3305
3306 sl0 =
3307 pool_elt_at_index (sm->sid_lists,
3308 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00003309 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3310 vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01003311
3312 ip0_encap = vlib_buffer_get_current (b0);
Klement Sekera769145c2019-03-06 11:59:57 +01003313 sr0 =
3314 ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
3315 NULL);
Pablo Camarillofb380952016-12-07 18:34:18 +01003316 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
3317
Dave Barach178cf492018-11-13 16:34:13 -05003318 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3319 sl0->rewrite, vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01003320 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3321
3322 ip0 = vlib_buffer_get_current (b0);
3323
3324 encaps_processing_v6 (node, b0, ip0, ip0_encap);
3325
3326 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3327 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3328 {
3329 sr_policy_rewrite_trace_t *tr =
3330 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003331 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3332 sizeof (tr->src.as_u8));
3333 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3334 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003335 }
3336
3337 encap_pkts++;
3338 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3339 n_left_to_next, bi0, next0);
3340 }
3341
3342 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3343 }
3344
3345 /* Update counters */
3346 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3347 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3348 encap_pkts);
3349 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3350 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3351 bsid_pkts);
3352
3353 return from_frame->n_vectors;
3354}
3355
3356/* *INDENT-OFF* */
3357VLIB_REGISTER_NODE (sr_policy_rewrite_b_encaps_node) = {
3358 .function = sr_policy_rewrite_b_encaps,
3359 .name = "sr-pl-rewrite-b-encaps",
3360 .vector_size = sizeof (u32),
3361 .format_trace = format_sr_policy_rewrite_trace,
3362 .type = VLIB_NODE_TYPE_INTERNAL,
3363 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3364 .error_strings = sr_policy_rewrite_error_strings,
3365 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3366 .next_nodes = {
3367#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3368 foreach_sr_policy_rewrite_next
3369#undef _
3370 },
3371};
3372/* *INDENT-ON* */
3373
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -08003374/*************************** SR Policy plugins ******************************/
3375/**
3376 * @brief SR Policy plugin registry
3377 */
3378int
3379sr_policy_register_function (vlib_main_t * vm, u8 * fn_name,
3380 u8 * keyword_str, u8 * def_str,
3381 u8 * params_str, u8 prefix_length,
3382 dpo_type_t * dpo,
3383 format_function_t * ls_format,
3384 unformat_function_t * ls_unformat,
3385 sr_p_plugin_callback_t * creation_fn,
3386 sr_p_plugin_callback_t * removal_fn)
3387{
3388 ip6_sr_main_t *sm = &sr_main;
3389 uword *p;
3390
3391 sr_policy_fn_registration_t *plugin;
3392
3393 /* Did this function exist? If so update it */
3394 p = hash_get_mem (sm->policy_plugin_functions_by_key, fn_name);
3395 if (p)
3396 {
3397 plugin = pool_elt_at_index (sm->policy_plugin_functions, p[0]);
3398 }
3399 /* Else create a new one and set hash key */
3400 else
3401 {
3402 pool_get (sm->policy_plugin_functions, plugin);
3403 hash_set_mem (sm->policy_plugin_functions_by_key, fn_name,
3404 plugin - sm->policy_plugin_functions);
3405 }
3406
3407 clib_memset (plugin, 0, sizeof (*plugin));
3408
3409 plugin->sr_policy_function_number = (plugin - sm->policy_plugin_functions);
3410 plugin->sr_policy_function_number += SR_BEHAVIOR_LAST;
3411 plugin->prefix_length = prefix_length;
3412 plugin->ls_format = ls_format;
3413 plugin->ls_unformat = ls_unformat;
3414 plugin->creation = creation_fn;
3415 plugin->removal = removal_fn;
3416 clib_memcpy (&plugin->dpo, dpo, sizeof (dpo_type_t));
3417 plugin->function_name = format (0, "%s%c", fn_name, 0);
3418 plugin->keyword_str = format (0, "%s%c", keyword_str, 0);
3419 plugin->def_str = format (0, "%s%c", def_str, 0);
3420 plugin->params_str = format (0, "%s%c", params_str, 0);
3421
3422 return plugin->sr_policy_function_number;
3423}
3424
3425/**
3426 * @brief CLI function to 'show' all available SR LocalSID behaviors
3427 */
3428static clib_error_t *
3429show_sr_policy_behaviors_command_fn (vlib_main_t * vm,
3430 unformat_input_t * input,
3431 vlib_cli_command_t * cmd)
3432{
3433 ip6_sr_main_t *sm = &sr_main;
3434 sr_policy_fn_registration_t *plugin;
3435 sr_policy_fn_registration_t **plugins_vec = 0;
3436 int i;
3437
3438 vlib_cli_output (vm, "SR Policy behaviors:\n-----------------------\n\n");
3439
3440 /* *INDENT-OFF* */
Damjan Marionb2c31b62020-12-13 21:47:40 +01003441 pool_foreach (plugin, sm->policy_plugin_functions)
3442 { vec_add1 (plugins_vec, plugin); }
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -08003443 /* *INDENT-ON* */
3444
3445 vlib_cli_output (vm, "Plugin behaviors:\n");
3446 for (i = 0; i < vec_len (plugins_vec); i++)
3447 {
3448 plugin = plugins_vec[i];
3449 vlib_cli_output (vm, "\t%s\t-> %s.\n", plugin->keyword_str,
3450 plugin->def_str);
3451 vlib_cli_output (vm, "\t\tParameters: '%s'\n", plugin->params_str);
3452 }
3453 return 0;
3454}
3455
3456/* *INDENT-OFF* */
3457VLIB_CLI_COMMAND (show_sr_policy_behaviors_command, static) = {
3458 .path = "show sr policy behaviors",
3459 .short_help = "show sr policy behaviors",
3460 .function = show_sr_policy_behaviors_command_fn,
3461};
3462/* *INDENT-ON* */
3463
Pablo Camarillofb380952016-12-07 18:34:18 +01003464/*************************** SR Segment Lists DPOs ****************************/
3465static u8 *
3466format_sr_segment_list_dpo (u8 * s, va_list * args)
3467{
3468 ip6_sr_main_t *sm = &sr_main;
3469 ip6_address_t *addr;
3470 ip6_sr_sl_t *sl;
3471
3472 index_t index = va_arg (*args, index_t);
3473 CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
3474 s = format (s, "SR: Segment List index:[%d]", index);
3475 s = format (s, "\n\tSegments:");
3476
3477 sl = pool_elt_at_index (sm->sid_lists, index);
3478
3479 s = format (s, "< ");
3480 vec_foreach (addr, sl->segments)
3481 {
3482 s = format (s, "%U, ", format_ip6_address, addr);
3483 }
3484 s = format (s, "\b\b > - ");
3485 s = format (s, "Weight: %u", sl->weight);
3486
3487 return s;
3488}
3489
3490const static dpo_vft_t sr_policy_rewrite_vft = {
3491 .dv_lock = sr_dpo_lock,
3492 .dv_unlock = sr_dpo_unlock,
3493 .dv_format = format_sr_segment_list_dpo,
3494};
3495
3496const static char *const sr_pr_encaps_ip6_nodes[] = {
3497 "sr-pl-rewrite-encaps",
3498 NULL,
3499};
3500
3501const static char *const sr_pr_encaps_ip4_nodes[] = {
3502 "sr-pl-rewrite-encaps-v4",
3503 NULL,
3504};
3505
3506const static char *const *const sr_pr_encaps_nodes[DPO_PROTO_NUM] = {
3507 [DPO_PROTO_IP6] = sr_pr_encaps_ip6_nodes,
3508 [DPO_PROTO_IP4] = sr_pr_encaps_ip4_nodes,
3509};
3510
3511const static char *const sr_pr_insert_ip6_nodes[] = {
3512 "sr-pl-rewrite-insert",
3513 NULL,
3514};
3515
3516const static char *const *const sr_pr_insert_nodes[DPO_PROTO_NUM] = {
3517 [DPO_PROTO_IP6] = sr_pr_insert_ip6_nodes,
3518};
3519
3520const static char *const sr_pr_bsid_insert_ip6_nodes[] = {
3521 "sr-pl-rewrite-b-insert",
3522 NULL,
3523};
3524
3525const static char *const *const sr_pr_bsid_insert_nodes[DPO_PROTO_NUM] = {
3526 [DPO_PROTO_IP6] = sr_pr_bsid_insert_ip6_nodes,
3527};
3528
3529const static char *const sr_pr_bsid_encaps_ip6_nodes[] = {
3530 "sr-pl-rewrite-b-encaps",
3531 NULL,
3532};
3533
3534const static char *const *const sr_pr_bsid_encaps_nodes[DPO_PROTO_NUM] = {
3535 [DPO_PROTO_IP6] = sr_pr_bsid_encaps_ip6_nodes,
3536};
3537
3538/********************* SR Policy Rewrite initialization ***********************/
3539/**
3540 * @brief SR Policy Rewrite initialization
3541 */
3542clib_error_t *
3543sr_policy_rewrite_init (vlib_main_t * vm)
3544{
3545 ip6_sr_main_t *sm = &sr_main;
3546
3547 /* Init memory for sr policy keys (bsid <-> ip6_address_t) */
Pablo Camarillo4521afa2017-03-16 10:43:05 +01003548 mhash_init (&sm->sr_policies_index_hash, sizeof (uword),
3549 sizeof (ip6_address_t));
Pablo Camarillofb380952016-12-07 18:34:18 +01003550
3551 /* Init SR VPO DPOs type */
3552 sr_pr_encaps_dpo_type =
3553 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_encaps_nodes);
3554
3555 sr_pr_insert_dpo_type =
3556 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_insert_nodes);
3557
3558 sr_pr_bsid_encaps_dpo_type =
3559 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_encaps_nodes);
3560
3561 sr_pr_bsid_insert_dpo_type =
3562 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_insert_nodes);
3563
3564 /* Register the L2 encaps node used in HW redirect */
3565 sm->l2_sr_policy_rewrite_index = sr_policy_rewrite_encaps_node.index;
3566
3567 sm->fib_table_ip6 = (u32) ~ 0;
3568 sm->fib_table_ip4 = (u32) ~ 0;
3569
3570 return 0;
3571}
3572
3573VLIB_INIT_FUNCTION (sr_policy_rewrite_init);
3574
3575
3576/*
3577* fd.io coding-style-patch-verification: ON
3578*
3579* Local Variables:
3580* eval: (c-set-style "gnu")
3581* End:
3582*/