blob: 3e8a4e4a9c5f4b28fb1cd45ef2d74ab2f15ec300 [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;
1241
1242 ip0_encap->hop_limit -= 1;
1243 new_l0 =
1244 ip0->payload_length + sizeof (ip6_header_t) +
1245 clib_net_to_host_u16 (ip0_encap->payload_length);
1246 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1247 ip0->ip_version_traffic_class_and_flow_label =
1248 ip0_encap->ip_version_traffic_class_and_flow_label;
1249}
1250
1251/**
1252 * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
1253 */
1254static uword
1255sr_policy_rewrite_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
1256 vlib_frame_t * from_frame)
1257{
1258 ip6_sr_main_t *sm = &sr_main;
1259 u32 n_left_from, next_index, *from, *to_next;
1260
1261 from = vlib_frame_vector_args (from_frame);
1262 n_left_from = from_frame->n_vectors;
1263
1264 next_index = node->cached_next_index;
1265
1266 int encap_pkts = 0, bsid_pkts = 0;
1267
1268 while (n_left_from > 0)
1269 {
1270 u32 n_left_to_next;
1271
1272 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1273
1274 /* Quad - Loop */
1275 while (n_left_from >= 8 && n_left_to_next >= 4)
1276 {
1277 u32 bi0, bi1, bi2, bi3;
1278 vlib_buffer_t *b0, *b1, *b2, *b3;
1279 u32 next0, next1, next2, next3;
1280 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1281 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1282 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1283 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1284
1285 /* Prefetch next iteration. */
1286 {
1287 vlib_buffer_t *p4, *p5, *p6, *p7;
1288
1289 p4 = vlib_get_buffer (vm, from[4]);
1290 p5 = vlib_get_buffer (vm, from[5]);
1291 p6 = vlib_get_buffer (vm, from[6]);
1292 p7 = vlib_get_buffer (vm, from[7]);
1293
1294 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1295 vlib_prefetch_buffer_header (p4, LOAD);
1296 vlib_prefetch_buffer_header (p5, LOAD);
1297 vlib_prefetch_buffer_header (p6, LOAD);
1298 vlib_prefetch_buffer_header (p7, LOAD);
1299
1300 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1301 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1302 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1303 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1304 }
1305
1306 to_next[0] = bi0 = from[0];
1307 to_next[1] = bi1 = from[1];
1308 to_next[2] = bi2 = from[2];
1309 to_next[3] = bi3 = from[3];
1310 from += 4;
1311 to_next += 4;
1312 n_left_from -= 4;
1313 n_left_to_next -= 4;
1314
1315 b0 = vlib_get_buffer (vm, bi0);
1316 b1 = vlib_get_buffer (vm, bi1);
1317 b2 = vlib_get_buffer (vm, bi2);
1318 b3 = vlib_get_buffer (vm, bi3);
1319
1320 sl0 =
1321 pool_elt_at_index (sm->sid_lists,
1322 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1323 sl1 =
1324 pool_elt_at_index (sm->sid_lists,
1325 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1326 sl2 =
1327 pool_elt_at_index (sm->sid_lists,
1328 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1329 sl3 =
1330 pool_elt_at_index (sm->sid_lists,
1331 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1332
shwethabe146f132017-03-09 16:58:26 +00001333 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1334 vec_len (sl0->rewrite));
1335 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1336 vec_len (sl1->rewrite));
1337 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1338 vec_len (sl2->rewrite));
1339 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1340 vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001341
1342 ip0_encap = vlib_buffer_get_current (b0);
1343 ip1_encap = vlib_buffer_get_current (b1);
1344 ip2_encap = vlib_buffer_get_current (b2);
1345 ip3_encap = vlib_buffer_get_current (b3);
1346
Dave Barach178cf492018-11-13 16:34:13 -05001347 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1348 sl0->rewrite, vec_len (sl0->rewrite));
1349 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1350 sl1->rewrite, vec_len (sl1->rewrite));
1351 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1352 sl2->rewrite, vec_len (sl2->rewrite));
1353 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1354 sl3->rewrite, vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001355
1356 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1357 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1358 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1359 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1360
1361 ip0 = vlib_buffer_get_current (b0);
1362 ip1 = vlib_buffer_get_current (b1);
1363 ip2 = vlib_buffer_get_current (b2);
1364 ip3 = vlib_buffer_get_current (b3);
1365
1366 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1367 encaps_processing_v6 (node, b1, ip1, ip1_encap);
1368 encaps_processing_v6 (node, b2, ip2, ip2_encap);
1369 encaps_processing_v6 (node, b3, ip3, ip3_encap);
1370
1371 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1372 {
1373 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1374 {
1375 sr_policy_rewrite_trace_t *tr =
1376 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001377 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1378 sizeof (tr->src.as_u8));
1379 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1380 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001381 }
1382
1383 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1384 {
1385 sr_policy_rewrite_trace_t *tr =
1386 vlib_add_trace (vm, node, b1, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001387 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
1388 sizeof (tr->src.as_u8));
1389 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
1390 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001391 }
1392
1393 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1394 {
1395 sr_policy_rewrite_trace_t *tr =
1396 vlib_add_trace (vm, node, b2, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001397 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
1398 sizeof (tr->src.as_u8));
1399 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
1400 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001401 }
1402
1403 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1404 {
1405 sr_policy_rewrite_trace_t *tr =
1406 vlib_add_trace (vm, node, b3, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001407 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
1408 sizeof (tr->src.as_u8));
1409 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
1410 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001411 }
1412 }
1413
1414 encap_pkts += 4;
1415 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1416 n_left_to_next, bi0, bi1, bi2, bi3,
1417 next0, next1, next2, next3);
1418 }
1419
1420 /* Single loop for potentially the last three packets */
1421 while (n_left_from > 0 && n_left_to_next > 0)
1422 {
1423 u32 bi0;
1424 vlib_buffer_t *b0;
1425 ip6_header_t *ip0 = 0, *ip0_encap = 0;
1426 ip6_sr_sl_t *sl0;
1427 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1428
1429 bi0 = from[0];
1430 to_next[0] = bi0;
1431 from += 1;
1432 to_next += 1;
1433 n_left_from -= 1;
1434 n_left_to_next -= 1;
1435 b0 = vlib_get_buffer (vm, bi0);
1436
1437 sl0 =
1438 pool_elt_at_index (sm->sid_lists,
1439 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00001440 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1441 vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001442
1443 ip0_encap = vlib_buffer_get_current (b0);
1444
Dave Barach178cf492018-11-13 16:34:13 -05001445 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1446 sl0->rewrite, vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001447 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1448
1449 ip0 = vlib_buffer_get_current (b0);
1450
1451 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1452
1453 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1454 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1455 {
1456 sr_policy_rewrite_trace_t *tr =
1457 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001458 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1459 sizeof (tr->src.as_u8));
1460 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1461 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001462 }
1463
1464 encap_pkts++;
1465 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1466 n_left_to_next, bi0, next0);
1467 }
1468
1469 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1470 }
1471
1472 /* Update counters */
1473 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1474 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1475 encap_pkts);
1476 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1477 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1478 bsid_pkts);
1479
1480 return from_frame->n_vectors;
1481}
1482
1483/* *INDENT-OFF* */
1484VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_node) = {
1485 .function = sr_policy_rewrite_encaps,
1486 .name = "sr-pl-rewrite-encaps",
1487 .vector_size = sizeof (u32),
1488 .format_trace = format_sr_policy_rewrite_trace,
1489 .type = VLIB_NODE_TYPE_INTERNAL,
1490 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1491 .error_strings = sr_policy_rewrite_error_strings,
1492 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1493 .next_nodes = {
1494#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1495 foreach_sr_policy_rewrite_next
1496#undef _
1497 },
1498};
1499/* *INDENT-ON* */
1500
1501/**
1502 * @brief IPv4 encapsulation processing as per RFC2473
1503 */
1504static_always_inline void
1505encaps_processing_v4 (vlib_node_runtime_t * node,
1506 vlib_buffer_t * b0,
1507 ip6_header_t * ip0, ip4_header_t * ip0_encap)
1508{
1509 u32 new_l0;
1510 ip6_sr_header_t *sr0;
1511
1512 u32 checksum0;
1513
1514 /* Inner IPv4: Decrement TTL & update checksum */
1515 ip0_encap->ttl -= 1;
1516 checksum0 = ip0_encap->checksum + clib_host_to_net_u16 (0x0100);
1517 checksum0 += checksum0 >= 0xffff;
1518 ip0_encap->checksum = checksum0;
1519
1520 /* Outer IPv6: Update length, FL, proto */
1521 new_l0 = ip0->payload_length + clib_net_to_host_u16 (ip0_encap->length);
1522 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1523 ip0->ip_version_traffic_class_and_flow_label =
1524 clib_host_to_net_u32 (0 | ((6 & 0xF) << 28) |
1525 ((ip0_encap->tos & 0xFF) << 20));
Pablo Camarillod327c872018-01-08 14:25:55 +01001526 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
1527 {
1528 sr0 = (void *) (ip0 + 1);
1529 sr0->protocol = IP_PROTOCOL_IP_IN_IP;
1530 }
1531 else
1532 ip0->protocol = IP_PROTOCOL_IP_IN_IP;
Pablo Camarillofb380952016-12-07 18:34:18 +01001533}
1534
1535/**
1536 * @brief Graph node for applying a SR policy into an IPv4 packet. Encapsulation
1537 */
1538static uword
1539sr_policy_rewrite_encaps_v4 (vlib_main_t * vm, vlib_node_runtime_t * node,
1540 vlib_frame_t * from_frame)
1541{
1542 ip6_sr_main_t *sm = &sr_main;
1543 u32 n_left_from, next_index, *from, *to_next;
1544
1545 from = vlib_frame_vector_args (from_frame);
1546 n_left_from = from_frame->n_vectors;
1547
1548 next_index = node->cached_next_index;
1549
1550 int encap_pkts = 0, bsid_pkts = 0;
1551
1552 while (n_left_from > 0)
1553 {
1554 u32 n_left_to_next;
1555
1556 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1557
1558 /* Quad - Loop */
1559 while (n_left_from >= 8 && n_left_to_next >= 4)
1560 {
1561 u32 bi0, bi1, bi2, bi3;
1562 vlib_buffer_t *b0, *b1, *b2, *b3;
1563 u32 next0, next1, next2, next3;
1564 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1565 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1566 ip4_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1567 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1568
1569 /* Prefetch next iteration. */
1570 {
1571 vlib_buffer_t *p4, *p5, *p6, *p7;
1572
1573 p4 = vlib_get_buffer (vm, from[4]);
1574 p5 = vlib_get_buffer (vm, from[5]);
1575 p6 = vlib_get_buffer (vm, from[6]);
1576 p7 = vlib_get_buffer (vm, from[7]);
1577
1578 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1579 vlib_prefetch_buffer_header (p4, LOAD);
1580 vlib_prefetch_buffer_header (p5, LOAD);
1581 vlib_prefetch_buffer_header (p6, LOAD);
1582 vlib_prefetch_buffer_header (p7, LOAD);
1583
1584 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1585 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1586 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1587 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1588 }
1589
1590 to_next[0] = bi0 = from[0];
1591 to_next[1] = bi1 = from[1];
1592 to_next[2] = bi2 = from[2];
1593 to_next[3] = bi3 = from[3];
1594 from += 4;
1595 to_next += 4;
1596 n_left_from -= 4;
1597 n_left_to_next -= 4;
1598
1599 b0 = vlib_get_buffer (vm, bi0);
1600 b1 = vlib_get_buffer (vm, bi1);
1601 b2 = vlib_get_buffer (vm, bi2);
1602 b3 = vlib_get_buffer (vm, bi3);
1603
1604 sl0 =
1605 pool_elt_at_index (sm->sid_lists,
1606 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1607 sl1 =
1608 pool_elt_at_index (sm->sid_lists,
1609 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1610 sl2 =
1611 pool_elt_at_index (sm->sid_lists,
1612 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1613 sl3 =
1614 pool_elt_at_index (sm->sid_lists,
1615 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00001616 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1617 vec_len (sl0->rewrite));
1618 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1619 vec_len (sl1->rewrite));
1620 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1621 vec_len (sl2->rewrite));
1622 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1623 vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001624
1625 ip0_encap = vlib_buffer_get_current (b0);
1626 ip1_encap = vlib_buffer_get_current (b1);
1627 ip2_encap = vlib_buffer_get_current (b2);
1628 ip3_encap = vlib_buffer_get_current (b3);
1629
Dave Barach178cf492018-11-13 16:34:13 -05001630 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1631 sl0->rewrite, vec_len (sl0->rewrite));
1632 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1633 sl1->rewrite, vec_len (sl1->rewrite));
1634 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1635 sl2->rewrite, vec_len (sl2->rewrite));
1636 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1637 sl3->rewrite, vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001638
1639 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1640 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1641 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1642 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1643
1644 ip0 = vlib_buffer_get_current (b0);
1645 ip1 = vlib_buffer_get_current (b1);
1646 ip2 = vlib_buffer_get_current (b2);
1647 ip3 = vlib_buffer_get_current (b3);
1648
1649 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1650 encaps_processing_v4 (node, b1, ip1, ip1_encap);
1651 encaps_processing_v4 (node, b2, ip2, ip2_encap);
1652 encaps_processing_v4 (node, b3, ip3, ip3_encap);
1653
1654 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1655 {
1656 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1657 {
1658 sr_policy_rewrite_trace_t *tr =
1659 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001660 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1661 sizeof (tr->src.as_u8));
1662 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1663 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001664 }
1665
1666 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1667 {
1668 sr_policy_rewrite_trace_t *tr =
1669 vlib_add_trace (vm, node, b1, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001670 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
1671 sizeof (tr->src.as_u8));
1672 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
1673 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001674 }
1675
1676 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1677 {
1678 sr_policy_rewrite_trace_t *tr =
1679 vlib_add_trace (vm, node, b2, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001680 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
1681 sizeof (tr->src.as_u8));
1682 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
1683 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001684 }
1685
1686 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1687 {
1688 sr_policy_rewrite_trace_t *tr =
1689 vlib_add_trace (vm, node, b3, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001690 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
1691 sizeof (tr->src.as_u8));
1692 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
1693 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001694 }
1695 }
1696
1697 encap_pkts += 4;
1698 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1699 n_left_to_next, bi0, bi1, bi2, bi3,
1700 next0, next1, next2, next3);
1701 }
1702
1703 /* Single loop for potentially the last three packets */
1704 while (n_left_from > 0 && n_left_to_next > 0)
1705 {
1706 u32 bi0;
1707 vlib_buffer_t *b0;
1708 ip6_header_t *ip0 = 0;
1709 ip4_header_t *ip0_encap = 0;
1710 ip6_sr_sl_t *sl0;
1711 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1712
1713 bi0 = from[0];
1714 to_next[0] = bi0;
1715 from += 1;
1716 to_next += 1;
1717 n_left_from -= 1;
1718 n_left_to_next -= 1;
1719 b0 = vlib_get_buffer (vm, bi0);
1720
1721 sl0 =
1722 pool_elt_at_index (sm->sid_lists,
1723 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00001724 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1725 vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001726
1727 ip0_encap = vlib_buffer_get_current (b0);
1728
Dave Barach178cf492018-11-13 16:34:13 -05001729 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1730 sl0->rewrite, vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001731 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1732
1733 ip0 = vlib_buffer_get_current (b0);
1734
1735 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1736
1737 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1738 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1739 {
1740 sr_policy_rewrite_trace_t *tr =
1741 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001742 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1743 sizeof (tr->src.as_u8));
1744 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1745 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001746 }
1747
1748 encap_pkts++;
1749 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1750 n_left_to_next, bi0, next0);
1751 }
1752
1753 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1754 }
1755
1756 /* Update counters */
1757 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1758 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1759 encap_pkts);
1760 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1761 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1762 bsid_pkts);
1763
1764 return from_frame->n_vectors;
1765}
1766
1767/* *INDENT-OFF* */
1768VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_v4_node) = {
1769 .function = sr_policy_rewrite_encaps_v4,
1770 .name = "sr-pl-rewrite-encaps-v4",
1771 .vector_size = sizeof (u32),
1772 .format_trace = format_sr_policy_rewrite_trace,
1773 .type = VLIB_NODE_TYPE_INTERNAL,
1774 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1775 .error_strings = sr_policy_rewrite_error_strings,
1776 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1777 .next_nodes = {
1778#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1779 foreach_sr_policy_rewrite_next
1780#undef _
1781 },
1782};
1783/* *INDENT-ON* */
1784
1785always_inline u32
1786ip_flow_hash (void *data)
1787{
1788 ip4_header_t *iph = (ip4_header_t *) data;
1789
1790 if ((iph->ip_version_and_header_length & 0xF0) == 0x40)
1791 return ip4_compute_flow_hash (iph, IP_FLOW_HASH_DEFAULT);
1792 else
1793 return ip6_compute_flow_hash ((ip6_header_t *) iph, IP_FLOW_HASH_DEFAULT);
1794}
1795
1796always_inline u64
1797mac_to_u64 (u8 * m)
1798{
1799 return (*((u64 *) m) & 0xffffffffffff);
1800}
1801
1802always_inline u32
1803l2_flow_hash (vlib_buffer_t * b0)
1804{
1805 ethernet_header_t *eh;
1806 u64 a, b, c;
1807 uword is_ip, eh_size;
1808 u16 eh_type;
1809
1810 eh = vlib_buffer_get_current (b0);
1811 eh_type = clib_net_to_host_u16 (eh->type);
1812 eh_size = ethernet_buffer_header_size (b0);
1813
1814 is_ip = (eh_type == ETHERNET_TYPE_IP4 || eh_type == ETHERNET_TYPE_IP6);
1815
1816 /* since we have 2 cache lines, use them */
1817 if (is_ip)
1818 a = ip_flow_hash ((u8 *) vlib_buffer_get_current (b0) + eh_size);
1819 else
1820 a = eh->type;
1821
1822 b = mac_to_u64 ((u8 *) eh->dst_address);
1823 c = mac_to_u64 ((u8 *) eh->src_address);
1824 hash_mix64 (a, b, c);
1825
1826 return (u32) c;
1827}
1828
1829/**
1830 * @brief Graph node for applying a SR policy into a L2 frame
1831 */
1832static uword
1833sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
1834 vlib_frame_t * from_frame)
1835{
1836 ip6_sr_main_t *sm = &sr_main;
1837 u32 n_left_from, next_index, *from, *to_next;
1838
1839 from = vlib_frame_vector_args (from_frame);
1840 n_left_from = from_frame->n_vectors;
1841
1842 next_index = node->cached_next_index;
1843
1844 int encap_pkts = 0, bsid_pkts = 0;
1845
1846 while (n_left_from > 0)
1847 {
1848 u32 n_left_to_next;
1849
1850 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1851
1852 /* Quad - Loop */
1853 while (n_left_from >= 8 && n_left_to_next >= 4)
1854 {
1855 u32 bi0, bi1, bi2, bi3;
1856 vlib_buffer_t *b0, *b1, *b2, *b3;
1857 u32 next0, next1, next2, next3;
1858 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1859 ethernet_header_t *en0, *en1, *en2, *en3;
1860 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1861 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1862 ip6_sr_policy_t *sp0, *sp1, *sp2, *sp3;
1863 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1864
1865 /* Prefetch next iteration. */
1866 {
1867 vlib_buffer_t *p4, *p5, *p6, *p7;
1868
1869 p4 = vlib_get_buffer (vm, from[4]);
1870 p5 = vlib_get_buffer (vm, from[5]);
1871 p6 = vlib_get_buffer (vm, from[6]);
1872 p7 = vlib_get_buffer (vm, from[7]);
1873
1874 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1875 vlib_prefetch_buffer_header (p4, LOAD);
1876 vlib_prefetch_buffer_header (p5, LOAD);
1877 vlib_prefetch_buffer_header (p6, LOAD);
1878 vlib_prefetch_buffer_header (p7, LOAD);
1879
1880 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1881 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1882 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1883 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1884 }
1885
1886 to_next[0] = bi0 = from[0];
1887 to_next[1] = bi1 = from[1];
1888 to_next[2] = bi2 = from[2];
1889 to_next[3] = bi3 = from[3];
1890 from += 4;
1891 to_next += 4;
1892 n_left_from -= 4;
1893 n_left_to_next -= 4;
1894
1895 b0 = vlib_get_buffer (vm, bi0);
1896 b1 = vlib_get_buffer (vm, bi1);
1897 b2 = vlib_get_buffer (vm, bi2);
1898 b3 = vlib_get_buffer (vm, bi3);
1899
1900 sp0 = pool_elt_at_index (sm->sr_policies,
1901 sm->sw_iface_sr_policies[vnet_buffer
1902 (b0)->sw_if_index
1903 [VLIB_RX]]);
1904
1905 sp1 = pool_elt_at_index (sm->sr_policies,
1906 sm->sw_iface_sr_policies[vnet_buffer
1907 (b1)->sw_if_index
1908 [VLIB_RX]]);
1909
1910 sp2 = pool_elt_at_index (sm->sr_policies,
1911 sm->sw_iface_sr_policies[vnet_buffer
1912 (b2)->sw_if_index
1913 [VLIB_RX]]);
1914
1915 sp3 = pool_elt_at_index (sm->sr_policies,
1916 sm->sw_iface_sr_policies[vnet_buffer
1917 (b3)->sw_if_index
1918 [VLIB_RX]]);
1919
1920 if (vec_len (sp0->segments_lists) == 1)
1921 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1922 else
1923 {
1924 vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
1925 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1926 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1927 (vec_len (sp0->segments_lists) - 1))];
1928 }
1929
1930 if (vec_len (sp1->segments_lists) == 1)
1931 vnet_buffer (b1)->ip.adj_index[VLIB_TX] = sp1->segments_lists[1];
1932 else
1933 {
1934 vnet_buffer (b1)->ip.flow_hash = l2_flow_hash (b1);
1935 vnet_buffer (b1)->ip.adj_index[VLIB_TX] =
1936 sp1->segments_lists[(vnet_buffer (b1)->ip.flow_hash &
1937 (vec_len (sp1->segments_lists) - 1))];
1938 }
1939
1940 if (vec_len (sp2->segments_lists) == 1)
1941 vnet_buffer (b2)->ip.adj_index[VLIB_TX] = sp2->segments_lists[2];
1942 else
1943 {
1944 vnet_buffer (b2)->ip.flow_hash = l2_flow_hash (b2);
1945 vnet_buffer (b2)->ip.adj_index[VLIB_TX] =
1946 sp2->segments_lists[(vnet_buffer (b2)->ip.flow_hash &
1947 (vec_len (sp2->segments_lists) - 1))];
1948 }
1949
1950 if (vec_len (sp3->segments_lists) == 1)
1951 vnet_buffer (b3)->ip.adj_index[VLIB_TX] = sp3->segments_lists[3];
1952 else
1953 {
1954 vnet_buffer (b3)->ip.flow_hash = l2_flow_hash (b3);
1955 vnet_buffer (b3)->ip.adj_index[VLIB_TX] =
1956 sp3->segments_lists[(vnet_buffer (b3)->ip.flow_hash &
1957 (vec_len (sp3->segments_lists) - 1))];
1958 }
1959
1960 sl0 =
1961 pool_elt_at_index (sm->sid_lists,
1962 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1963 sl1 =
1964 pool_elt_at_index (sm->sid_lists,
1965 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1966 sl2 =
1967 pool_elt_at_index (sm->sid_lists,
1968 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1969 sl3 =
1970 pool_elt_at_index (sm->sid_lists,
1971 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1972
shwethabe146f132017-03-09 16:58:26 +00001973 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1974 vec_len (sl0->rewrite));
1975 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1976 vec_len (sl1->rewrite));
1977 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1978 vec_len (sl2->rewrite));
1979 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1980 vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001981
1982 en0 = vlib_buffer_get_current (b0);
1983 en1 = vlib_buffer_get_current (b1);
1984 en2 = vlib_buffer_get_current (b2);
1985 en3 = vlib_buffer_get_current (b3);
1986
Dave Barach178cf492018-11-13 16:34:13 -05001987 clib_memcpy_fast (((u8 *) en0) - vec_len (sl0->rewrite),
1988 sl0->rewrite, vec_len (sl0->rewrite));
1989 clib_memcpy_fast (((u8 *) en1) - vec_len (sl1->rewrite),
1990 sl1->rewrite, vec_len (sl1->rewrite));
1991 clib_memcpy_fast (((u8 *) en2) - vec_len (sl2->rewrite),
1992 sl2->rewrite, vec_len (sl2->rewrite));
1993 clib_memcpy_fast (((u8 *) en3) - vec_len (sl3->rewrite),
1994 sl3->rewrite, vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001995
1996 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1997 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1998 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1999 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2000
2001 ip0 = vlib_buffer_get_current (b0);
2002 ip1 = vlib_buffer_get_current (b1);
2003 ip2 = vlib_buffer_get_current (b2);
2004 ip3 = vlib_buffer_get_current (b3);
2005
2006 ip0->payload_length =
2007 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
2008 ip1->payload_length =
2009 clib_host_to_net_u16 (b1->current_length - sizeof (ip6_header_t));
2010 ip2->payload_length =
2011 clib_host_to_net_u16 (b2->current_length - sizeof (ip6_header_t));
2012 ip3->payload_length =
2013 clib_host_to_net_u16 (b3->current_length - sizeof (ip6_header_t));
2014
Pablo Camarillod327c872018-01-08 14:25:55 +01002015 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
2016 {
2017 sr0 = (void *) (ip0 + 1);
pcamaril30e76712020-02-04 08:36:51 +01002018 sr0->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01002019 }
2020 else
pcamaril30e76712020-02-04 08:36:51 +01002021 ip0->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillofb380952016-12-07 18:34:18 +01002022
Pablo Camarillod327c872018-01-08 14:25:55 +01002023 if (ip1->protocol == IP_PROTOCOL_IPV6_ROUTE)
2024 {
2025 sr1 = (void *) (ip1 + 1);
pcamaril30e76712020-02-04 08:36:51 +01002026 sr1->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01002027 }
2028 else
pcamaril30e76712020-02-04 08:36:51 +01002029 ip1->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01002030
2031 if (ip2->protocol == IP_PROTOCOL_IPV6_ROUTE)
2032 {
2033 sr2 = (void *) (ip2 + 1);
pcamaril30e76712020-02-04 08:36:51 +01002034 sr2->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01002035 }
2036 else
pcamaril30e76712020-02-04 08:36:51 +01002037 ip2->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01002038
2039 if (ip3->protocol == IP_PROTOCOL_IPV6_ROUTE)
2040 {
2041 sr3 = (void *) (ip3 + 1);
pcamaril30e76712020-02-04 08:36:51 +01002042 sr3->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01002043 }
2044 else
pcamaril30e76712020-02-04 08:36:51 +01002045 ip3->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillofb380952016-12-07 18:34:18 +01002046
2047 /* Which Traffic class and flow label do I set ? */
2048 //ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32(0|((6&0xF)<<28)|((ip0_encap->tos&0xFF)<<20));
2049
2050 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2051 {
2052 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2053 {
2054 sr_policy_rewrite_trace_t *tr =
2055 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002056 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2057 sizeof (tr->src.as_u8));
2058 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2059 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002060 }
2061
2062 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2063 {
2064 sr_policy_rewrite_trace_t *tr =
2065 vlib_add_trace (vm, node, b1, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002066 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2067 sizeof (tr->src.as_u8));
2068 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2069 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002070 }
2071
2072 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2073 {
2074 sr_policy_rewrite_trace_t *tr =
2075 vlib_add_trace (vm, node, b2, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002076 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2077 sizeof (tr->src.as_u8));
2078 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2079 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002080 }
2081
2082 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2083 {
2084 sr_policy_rewrite_trace_t *tr =
2085 vlib_add_trace (vm, node, b3, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002086 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2087 sizeof (tr->src.as_u8));
2088 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2089 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002090 }
2091 }
2092
2093 encap_pkts += 4;
2094 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2095 n_left_to_next, bi0, bi1, bi2, bi3,
2096 next0, next1, next2, next3);
2097 }
2098
2099 /* Single loop for potentially the last three packets */
2100 while (n_left_from > 0 && n_left_to_next > 0)
2101 {
2102 u32 bi0;
2103 vlib_buffer_t *b0;
2104 ip6_header_t *ip0 = 0;
2105 ip6_sr_header_t *sr0;
2106 ethernet_header_t *en0;
2107 ip6_sr_policy_t *sp0;
2108 ip6_sr_sl_t *sl0;
2109 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2110
2111 bi0 = from[0];
2112 to_next[0] = bi0;
2113 from += 1;
2114 to_next += 1;
2115 n_left_from -= 1;
2116 n_left_to_next -= 1;
2117 b0 = vlib_get_buffer (vm, bi0);
2118
2119 /* Find the SR policy */
2120 sp0 = pool_elt_at_index (sm->sr_policies,
2121 sm->sw_iface_sr_policies[vnet_buffer
2122 (b0)->sw_if_index
2123 [VLIB_RX]]);
2124
2125 /* In case there is more than one SL, LB among them */
2126 if (vec_len (sp0->segments_lists) == 1)
2127 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
2128 else
2129 {
2130 vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
2131 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
2132 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
2133 (vec_len (sp0->segments_lists) - 1))];
2134 }
2135 sl0 =
2136 pool_elt_at_index (sm->sid_lists,
2137 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00002138 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2139 vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002140
2141 en0 = vlib_buffer_get_current (b0);
2142
Dave Barach178cf492018-11-13 16:34:13 -05002143 clib_memcpy_fast (((u8 *) en0) - vec_len (sl0->rewrite),
2144 sl0->rewrite, vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002145
2146 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2147
2148 ip0 = vlib_buffer_get_current (b0);
2149
2150 ip0->payload_length =
2151 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
2152
Pablo Camarillod327c872018-01-08 14:25:55 +01002153 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
2154 {
2155 sr0 = (void *) (ip0 + 1);
pcamaril30e76712020-02-04 08:36:51 +01002156 sr0->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01002157 }
2158 else
pcamaril30e76712020-02-04 08:36:51 +01002159 ip0->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillofb380952016-12-07 18:34:18 +01002160
2161 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2162 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2163 {
2164 sr_policy_rewrite_trace_t *tr =
2165 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002166 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2167 sizeof (tr->src.as_u8));
2168 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2169 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002170 }
2171
2172 encap_pkts++;
2173 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2174 n_left_to_next, bi0, next0);
2175 }
2176
2177 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2178 }
2179
2180 /* Update counters */
2181 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
2182 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2183 encap_pkts);
2184 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
2185 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2186 bsid_pkts);
2187
2188 return from_frame->n_vectors;
2189}
2190
2191/* *INDENT-OFF* */
2192VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_l2_node) = {
2193 .function = sr_policy_rewrite_encaps_l2,
2194 .name = "sr-pl-rewrite-encaps-l2",
2195 .vector_size = sizeof (u32),
2196 .format_trace = format_sr_policy_rewrite_trace,
2197 .type = VLIB_NODE_TYPE_INTERNAL,
2198 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2199 .error_strings = sr_policy_rewrite_error_strings,
2200 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2201 .next_nodes = {
2202#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2203 foreach_sr_policy_rewrite_next
2204#undef _
2205 },
2206};
2207/* *INDENT-ON* */
2208
2209/**
2210 * @brief Graph node for applying a SR policy into a packet. SRH insertion.
2211 */
2212static uword
2213sr_policy_rewrite_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2214 vlib_frame_t * from_frame)
2215{
2216 ip6_sr_main_t *sm = &sr_main;
2217 u32 n_left_from, next_index, *from, *to_next;
2218
2219 from = vlib_frame_vector_args (from_frame);
2220 n_left_from = from_frame->n_vectors;
2221
2222 next_index = node->cached_next_index;
2223
2224 int insert_pkts = 0, bsid_pkts = 0;
2225
2226 while (n_left_from > 0)
2227 {
2228 u32 n_left_to_next;
2229
2230 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2231
2232 /* Quad - Loop */
2233 while (n_left_from >= 8 && n_left_to_next >= 4)
2234 {
2235 u32 bi0, bi1, bi2, bi3;
2236 vlib_buffer_t *b0, *b1, *b2, *b3;
2237 u32 next0, next1, next2, next3;
2238 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2239 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2240 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2241 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2242 u16 new_l0, new_l1, new_l2, new_l3;
2243
2244 /* Prefetch next iteration. */
2245 {
2246 vlib_buffer_t *p4, *p5, *p6, *p7;
2247
2248 p4 = vlib_get_buffer (vm, from[4]);
2249 p5 = vlib_get_buffer (vm, from[5]);
2250 p6 = vlib_get_buffer (vm, from[6]);
2251 p7 = vlib_get_buffer (vm, from[7]);
2252
2253 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2254 vlib_prefetch_buffer_header (p4, LOAD);
2255 vlib_prefetch_buffer_header (p5, LOAD);
2256 vlib_prefetch_buffer_header (p6, LOAD);
2257 vlib_prefetch_buffer_header (p7, LOAD);
2258
2259 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2260 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2261 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2262 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2263 }
2264
2265 to_next[0] = bi0 = from[0];
2266 to_next[1] = bi1 = from[1];
2267 to_next[2] = bi2 = from[2];
2268 to_next[3] = bi3 = from[3];
2269 from += 4;
2270 to_next += 4;
2271 n_left_from -= 4;
2272 n_left_to_next -= 4;
2273
2274 b0 = vlib_get_buffer (vm, bi0);
2275 b1 = vlib_get_buffer (vm, bi1);
2276 b2 = vlib_get_buffer (vm, bi2);
2277 b3 = vlib_get_buffer (vm, bi3);
2278
2279 sl0 =
2280 pool_elt_at_index (sm->sid_lists,
2281 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2282 sl1 =
2283 pool_elt_at_index (sm->sid_lists,
2284 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2285 sl2 =
2286 pool_elt_at_index (sm->sid_lists,
2287 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2288 sl3 =
2289 pool_elt_at_index (sm->sid_lists,
2290 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00002291 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2292 vec_len (sl0->rewrite));
2293 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2294 vec_len (sl1->rewrite));
2295 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2296 vec_len (sl2->rewrite));
2297 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2298 vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002299
2300 ip0 = vlib_buffer_get_current (b0);
2301 ip1 = vlib_buffer_get_current (b1);
2302 ip2 = vlib_buffer_get_current (b2);
2303 ip3 = vlib_buffer_get_current (b3);
2304
2305 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2306 sr0 =
2307 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2308 ip6_ext_header_len (ip0 + 1));
2309 else
2310 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2311
2312 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2313 sr1 =
2314 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2315 ip6_ext_header_len (ip1 + 1));
2316 else
2317 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2318
2319 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2320 sr2 =
2321 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2322 ip6_ext_header_len (ip2 + 1));
2323 else
2324 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2325
2326 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2327 sr3 =
2328 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2329 ip6_ext_header_len (ip3 + 1));
2330 else
2331 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2332
Dave Barach178cf492018-11-13 16:34:13 -05002333 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2334 (void *) sr0 - (void *) ip0);
2335 clib_memcpy_fast ((u8 *) ip1 - vec_len (sl1->rewrite), (u8 *) ip1,
2336 (void *) sr1 - (void *) ip1);
2337 clib_memcpy_fast ((u8 *) ip2 - vec_len (sl2->rewrite), (u8 *) ip2,
2338 (void *) sr2 - (void *) ip2);
2339 clib_memcpy_fast ((u8 *) ip3 - vec_len (sl3->rewrite), (u8 *) ip3,
2340 (void *) sr3 - (void *) ip3);
Pablo Camarillofb380952016-12-07 18:34:18 +01002341
Dave Barach178cf492018-11-13 16:34:13 -05002342 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite)),
2343 sl0->rewrite, vec_len (sl0->rewrite));
2344 clib_memcpy_fast (((u8 *) sr1 - vec_len (sl1->rewrite)),
2345 sl1->rewrite, vec_len (sl1->rewrite));
2346 clib_memcpy_fast (((u8 *) sr2 - vec_len (sl2->rewrite)),
2347 sl2->rewrite, vec_len (sl2->rewrite));
2348 clib_memcpy_fast (((u8 *) sr3 - vec_len (sl3->rewrite)),
2349 sl3->rewrite, vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002350
2351 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2352 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2353 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2354 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2355
2356 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2357 ip1 = ((void *) ip1) - vec_len (sl1->rewrite);
2358 ip2 = ((void *) ip2) - vec_len (sl2->rewrite);
2359 ip3 = ((void *) ip3) - vec_len (sl3->rewrite);
2360
2361 ip0->hop_limit -= 1;
2362 ip1->hop_limit -= 1;
2363 ip2->hop_limit -= 1;
2364 ip3->hop_limit -= 1;
2365
2366 new_l0 =
2367 clib_net_to_host_u16 (ip0->payload_length) +
2368 vec_len (sl0->rewrite);
2369 new_l1 =
2370 clib_net_to_host_u16 (ip1->payload_length) +
2371 vec_len (sl1->rewrite);
2372 new_l2 =
2373 clib_net_to_host_u16 (ip2->payload_length) +
2374 vec_len (sl2->rewrite);
2375 new_l3 =
2376 clib_net_to_host_u16 (ip3->payload_length) +
2377 vec_len (sl3->rewrite);
2378
2379 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2380 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2381 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2382 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2383
2384 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2385 sr1 = ((void *) sr1) - vec_len (sl1->rewrite);
2386 sr2 = ((void *) sr2) - vec_len (sl2->rewrite);
2387 sr3 = ((void *) sr3) - vec_len (sl3->rewrite);
2388
2389 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2390 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2391 sr1->segments->as_u64[0] = ip1->dst_address.as_u64[0];
2392 sr1->segments->as_u64[1] = ip1->dst_address.as_u64[1];
2393 sr2->segments->as_u64[0] = ip2->dst_address.as_u64[0];
2394 sr2->segments->as_u64[1] = ip2->dst_address.as_u64[1];
2395 sr3->segments->as_u64[0] = ip3->dst_address.as_u64[0];
2396 sr3->segments->as_u64[1] = ip3->dst_address.as_u64[1];
2397
2398 ip0->dst_address.as_u64[0] =
2399 (sr0->segments + sr0->segments_left)->as_u64[0];
2400 ip0->dst_address.as_u64[1] =
2401 (sr0->segments + sr0->segments_left)->as_u64[1];
2402 ip1->dst_address.as_u64[0] =
2403 (sr1->segments + sr1->segments_left)->as_u64[0];
2404 ip1->dst_address.as_u64[1] =
2405 (sr1->segments + sr1->segments_left)->as_u64[1];
2406 ip2->dst_address.as_u64[0] =
2407 (sr2->segments + sr2->segments_left)->as_u64[0];
2408 ip2->dst_address.as_u64[1] =
2409 (sr2->segments + sr2->segments_left)->as_u64[1];
2410 ip3->dst_address.as_u64[0] =
2411 (sr3->segments + sr3->segments_left)->as_u64[0];
2412 ip3->dst_address.as_u64[1] =
2413 (sr3->segments + sr3->segments_left)->as_u64[1];
2414
2415 ip6_ext_header_t *ip_ext;
2416 if (ip0 + 1 == (void *) sr0)
2417 {
2418 sr0->protocol = ip0->protocol;
2419 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2420 }
2421 else
2422 {
2423 ip_ext = (void *) (ip0 + 1);
2424 sr0->protocol = ip_ext->next_hdr;
2425 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2426 }
2427
2428 if (ip1 + 1 == (void *) sr1)
2429 {
2430 sr1->protocol = ip1->protocol;
2431 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2432 }
2433 else
2434 {
2435 ip_ext = (void *) (ip2 + 1);
2436 sr2->protocol = ip_ext->next_hdr;
2437 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2438 }
2439
2440 if (ip2 + 1 == (void *) sr2)
2441 {
2442 sr2->protocol = ip2->protocol;
2443 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2444 }
2445 else
2446 {
2447 ip_ext = (void *) (ip2 + 1);
2448 sr2->protocol = ip_ext->next_hdr;
2449 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2450 }
2451
2452 if (ip3 + 1 == (void *) sr3)
2453 {
2454 sr3->protocol = ip3->protocol;
2455 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2456 }
2457 else
2458 {
2459 ip_ext = (void *) (ip3 + 1);
2460 sr3->protocol = ip_ext->next_hdr;
2461 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2462 }
2463
2464 insert_pkts += 4;
2465
2466 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2467 {
2468 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2469 {
2470 sr_policy_rewrite_trace_t *tr =
2471 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002472 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2473 sizeof (tr->src.as_u8));
2474 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2475 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002476 }
2477
2478 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2479 {
2480 sr_policy_rewrite_trace_t *tr =
2481 vlib_add_trace (vm, node, b1, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002482 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2483 sizeof (tr->src.as_u8));
2484 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2485 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002486 }
2487
2488 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2489 {
2490 sr_policy_rewrite_trace_t *tr =
2491 vlib_add_trace (vm, node, b2, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002492 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2493 sizeof (tr->src.as_u8));
2494 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2495 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002496 }
2497
2498 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2499 {
2500 sr_policy_rewrite_trace_t *tr =
2501 vlib_add_trace (vm, node, b3, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002502 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2503 sizeof (tr->src.as_u8));
2504 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2505 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002506 }
2507 }
2508
2509 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2510 n_left_to_next, bi0, bi1, bi2, bi3,
2511 next0, next1, next2, next3);
2512 }
2513
2514 /* Single loop for potentially the last three packets */
2515 while (n_left_from > 0 && n_left_to_next > 0)
2516 {
2517 u32 bi0;
2518 vlib_buffer_t *b0;
2519 ip6_header_t *ip0 = 0;
2520 ip6_sr_header_t *sr0 = 0;
2521 ip6_sr_sl_t *sl0;
2522 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2523 u16 new_l0 = 0;
2524
2525 bi0 = from[0];
2526 to_next[0] = bi0;
2527 from += 1;
2528 to_next += 1;
2529 n_left_from -= 1;
2530 n_left_to_next -= 1;
2531
2532 b0 = vlib_get_buffer (vm, bi0);
2533 sl0 =
2534 pool_elt_at_index (sm->sid_lists,
2535 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00002536 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2537 vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002538
2539 ip0 = vlib_buffer_get_current (b0);
2540
2541 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2542 sr0 =
2543 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2544 ip6_ext_header_len (ip0 + 1));
2545 else
2546 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2547
Dave Barach178cf492018-11-13 16:34:13 -05002548 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2549 (void *) sr0 - (void *) ip0);
2550 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite)),
2551 sl0->rewrite, vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002552
2553 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2554
2555 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2556 ip0->hop_limit -= 1;
2557 new_l0 =
2558 clib_net_to_host_u16 (ip0->payload_length) +
2559 vec_len (sl0->rewrite);
2560 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2561
2562 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2563 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2564 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2565
2566 ip0->dst_address.as_u64[0] =
2567 (sr0->segments + sr0->segments_left)->as_u64[0];
2568 ip0->dst_address.as_u64[1] =
2569 (sr0->segments + sr0->segments_left)->as_u64[1];
2570
2571 if (ip0 + 1 == (void *) sr0)
2572 {
2573 sr0->protocol = ip0->protocol;
2574 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2575 }
2576 else
2577 {
2578 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2579 sr0->protocol = ip_ext->next_hdr;
2580 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2581 }
2582
2583 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2584 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2585 {
2586 sr_policy_rewrite_trace_t *tr =
2587 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002588 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2589 sizeof (tr->src.as_u8));
2590 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2591 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002592 }
2593
2594 insert_pkts++;
2595
2596 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2597 n_left_to_next, bi0, next0);
2598 }
2599
2600 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2601 }
2602
2603 /* Update counters */
2604 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2605 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2606 insert_pkts);
2607 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2608 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2609 bsid_pkts);
2610 return from_frame->n_vectors;
2611}
2612
2613/* *INDENT-OFF* */
2614VLIB_REGISTER_NODE (sr_policy_rewrite_insert_node) = {
2615 .function = sr_policy_rewrite_insert,
2616 .name = "sr-pl-rewrite-insert",
2617 .vector_size = sizeof (u32),
2618 .format_trace = format_sr_policy_rewrite_trace,
2619 .type = VLIB_NODE_TYPE_INTERNAL,
2620 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2621 .error_strings = sr_policy_rewrite_error_strings,
2622 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2623 .next_nodes = {
2624#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2625 foreach_sr_policy_rewrite_next
2626#undef _
2627 },
2628};
2629/* *INDENT-ON* */
2630
2631/**
2632 * @brief Graph node for applying a SR policy into a packet. BSID - SRH insertion.
2633 */
2634static uword
2635sr_policy_rewrite_b_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2636 vlib_frame_t * from_frame)
2637{
2638 ip6_sr_main_t *sm = &sr_main;
2639 u32 n_left_from, next_index, *from, *to_next;
2640
2641 from = vlib_frame_vector_args (from_frame);
2642 n_left_from = from_frame->n_vectors;
2643
2644 next_index = node->cached_next_index;
2645
2646 int insert_pkts = 0, bsid_pkts = 0;
2647
2648 while (n_left_from > 0)
2649 {
2650 u32 n_left_to_next;
2651
2652 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2653
2654 /* Quad - Loop */
2655 while (n_left_from >= 8 && n_left_to_next >= 4)
2656 {
2657 u32 bi0, bi1, bi2, bi3;
2658 vlib_buffer_t *b0, *b1, *b2, *b3;
2659 u32 next0, next1, next2, next3;
2660 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2661 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2662 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2663 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2664 u16 new_l0, new_l1, new_l2, new_l3;
2665
2666 /* Prefetch next iteration. */
2667 {
2668 vlib_buffer_t *p4, *p5, *p6, *p7;
2669
2670 p4 = vlib_get_buffer (vm, from[4]);
2671 p5 = vlib_get_buffer (vm, from[5]);
2672 p6 = vlib_get_buffer (vm, from[6]);
2673 p7 = vlib_get_buffer (vm, from[7]);
2674
2675 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2676 vlib_prefetch_buffer_header (p4, LOAD);
2677 vlib_prefetch_buffer_header (p5, LOAD);
2678 vlib_prefetch_buffer_header (p6, LOAD);
2679 vlib_prefetch_buffer_header (p7, LOAD);
2680
2681 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2682 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2683 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2684 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2685 }
2686
2687 to_next[0] = bi0 = from[0];
2688 to_next[1] = bi1 = from[1];
2689 to_next[2] = bi2 = from[2];
2690 to_next[3] = bi3 = from[3];
2691 from += 4;
2692 to_next += 4;
2693 n_left_from -= 4;
2694 n_left_to_next -= 4;
2695
2696 b0 = vlib_get_buffer (vm, bi0);
2697 b1 = vlib_get_buffer (vm, bi1);
2698 b2 = vlib_get_buffer (vm, bi2);
2699 b3 = vlib_get_buffer (vm, bi3);
2700
2701 sl0 =
2702 pool_elt_at_index (sm->sid_lists,
2703 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2704 sl1 =
2705 pool_elt_at_index (sm->sid_lists,
2706 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2707 sl2 =
2708 pool_elt_at_index (sm->sid_lists,
2709 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2710 sl3 =
2711 pool_elt_at_index (sm->sid_lists,
2712 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00002713 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2714 vec_len (sl0->rewrite_bsid));
2715 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2716 vec_len (sl1->rewrite_bsid));
2717 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2718 vec_len (sl2->rewrite_bsid));
2719 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2720 vec_len (sl3->rewrite_bsid));
Pablo Camarillofb380952016-12-07 18:34:18 +01002721
2722 ip0 = vlib_buffer_get_current (b0);
2723 ip1 = vlib_buffer_get_current (b1);
2724 ip2 = vlib_buffer_get_current (b2);
2725 ip3 = vlib_buffer_get_current (b3);
2726
2727 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2728 sr0 =
2729 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2730 ip6_ext_header_len (ip0 + 1));
2731 else
2732 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2733
2734 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2735 sr1 =
2736 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2737 ip6_ext_header_len (ip1 + 1));
2738 else
2739 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2740
2741 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2742 sr2 =
2743 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2744 ip6_ext_header_len (ip2 + 1));
2745 else
2746 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2747
2748 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2749 sr3 =
2750 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2751 ip6_ext_header_len (ip3 + 1));
2752 else
2753 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2754
Dave Barach178cf492018-11-13 16:34:13 -05002755 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite_bsid),
2756 (u8 *) ip0, (void *) sr0 - (void *) ip0);
2757 clib_memcpy_fast ((u8 *) ip1 - vec_len (sl1->rewrite_bsid),
2758 (u8 *) ip1, (void *) sr1 - (void *) ip1);
2759 clib_memcpy_fast ((u8 *) ip2 - vec_len (sl2->rewrite_bsid),
2760 (u8 *) ip2, (void *) sr2 - (void *) ip2);
2761 clib_memcpy_fast ((u8 *) ip3 - vec_len (sl3->rewrite_bsid),
2762 (u8 *) ip3, (void *) sr3 - (void *) ip3);
Pablo Camarillofb380952016-12-07 18:34:18 +01002763
Dave Barach178cf492018-11-13 16:34:13 -05002764 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2765 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2766 clib_memcpy_fast (((u8 *) sr1 - vec_len (sl1->rewrite_bsid)),
2767 sl1->rewrite_bsid, vec_len (sl1->rewrite_bsid));
2768 clib_memcpy_fast (((u8 *) sr2 - vec_len (sl2->rewrite_bsid)),
2769 sl2->rewrite_bsid, vec_len (sl2->rewrite_bsid));
2770 clib_memcpy_fast (((u8 *) sr3 - vec_len (sl3->rewrite_bsid)),
2771 sl3->rewrite_bsid, vec_len (sl3->rewrite_bsid));
Pablo Camarillofb380952016-12-07 18:34:18 +01002772
2773 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2774 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite_bsid));
2775 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite_bsid));
2776 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite_bsid));
2777
2778 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2779 ip1 = ((void *) ip1) - vec_len (sl1->rewrite_bsid);
2780 ip2 = ((void *) ip2) - vec_len (sl2->rewrite_bsid);
2781 ip3 = ((void *) ip3) - vec_len (sl3->rewrite_bsid);
2782
2783 ip0->hop_limit -= 1;
2784 ip1->hop_limit -= 1;
2785 ip2->hop_limit -= 1;
2786 ip3->hop_limit -= 1;
2787
2788 new_l0 =
2789 clib_net_to_host_u16 (ip0->payload_length) +
2790 vec_len (sl0->rewrite_bsid);
2791 new_l1 =
2792 clib_net_to_host_u16 (ip1->payload_length) +
2793 vec_len (sl1->rewrite_bsid);
2794 new_l2 =
2795 clib_net_to_host_u16 (ip2->payload_length) +
2796 vec_len (sl2->rewrite_bsid);
2797 new_l3 =
2798 clib_net_to_host_u16 (ip3->payload_length) +
2799 vec_len (sl3->rewrite_bsid);
2800
2801 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2802 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2803 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2804 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2805
2806 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2807 sr1 = ((void *) sr1) - vec_len (sl1->rewrite_bsid);
2808 sr2 = ((void *) sr2) - vec_len (sl2->rewrite_bsid);
2809 sr3 = ((void *) sr3) - vec_len (sl3->rewrite_bsid);
2810
2811 ip0->dst_address.as_u64[0] =
2812 (sr0->segments + sr0->segments_left)->as_u64[0];
2813 ip0->dst_address.as_u64[1] =
2814 (sr0->segments + sr0->segments_left)->as_u64[1];
2815 ip1->dst_address.as_u64[0] =
2816 (sr1->segments + sr1->segments_left)->as_u64[0];
2817 ip1->dst_address.as_u64[1] =
2818 (sr1->segments + sr1->segments_left)->as_u64[1];
2819 ip2->dst_address.as_u64[0] =
2820 (sr2->segments + sr2->segments_left)->as_u64[0];
2821 ip2->dst_address.as_u64[1] =
2822 (sr2->segments + sr2->segments_left)->as_u64[1];
2823 ip3->dst_address.as_u64[0] =
2824 (sr3->segments + sr3->segments_left)->as_u64[0];
2825 ip3->dst_address.as_u64[1] =
2826 (sr3->segments + sr3->segments_left)->as_u64[1];
2827
2828 ip6_ext_header_t *ip_ext;
2829 if (ip0 + 1 == (void *) sr0)
2830 {
2831 sr0->protocol = ip0->protocol;
2832 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2833 }
2834 else
2835 {
2836 ip_ext = (void *) (ip0 + 1);
2837 sr0->protocol = ip_ext->next_hdr;
2838 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2839 }
2840
2841 if (ip1 + 1 == (void *) sr1)
2842 {
2843 sr1->protocol = ip1->protocol;
2844 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2845 }
2846 else
2847 {
2848 ip_ext = (void *) (ip2 + 1);
2849 sr2->protocol = ip_ext->next_hdr;
2850 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2851 }
2852
2853 if (ip2 + 1 == (void *) sr2)
2854 {
2855 sr2->protocol = ip2->protocol;
2856 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2857 }
2858 else
2859 {
2860 ip_ext = (void *) (ip2 + 1);
2861 sr2->protocol = ip_ext->next_hdr;
2862 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2863 }
2864
2865 if (ip3 + 1 == (void *) sr3)
2866 {
2867 sr3->protocol = ip3->protocol;
2868 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2869 }
2870 else
2871 {
2872 ip_ext = (void *) (ip3 + 1);
2873 sr3->protocol = ip_ext->next_hdr;
2874 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2875 }
2876
2877 insert_pkts += 4;
2878
2879 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2880 {
2881 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2882 {
2883 sr_policy_rewrite_trace_t *tr =
2884 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002885 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2886 sizeof (tr->src.as_u8));
2887 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2888 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002889 }
2890
2891 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2892 {
2893 sr_policy_rewrite_trace_t *tr =
2894 vlib_add_trace (vm, node, b1, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002895 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2896 sizeof (tr->src.as_u8));
2897 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2898 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002899 }
2900
2901 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2902 {
2903 sr_policy_rewrite_trace_t *tr =
2904 vlib_add_trace (vm, node, b2, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002905 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2906 sizeof (tr->src.as_u8));
2907 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2908 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002909 }
2910
2911 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2912 {
2913 sr_policy_rewrite_trace_t *tr =
2914 vlib_add_trace (vm, node, b3, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002915 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2916 sizeof (tr->src.as_u8));
2917 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2918 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002919 }
2920 }
2921
2922 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2923 n_left_to_next, bi0, bi1, bi2, bi3,
2924 next0, next1, next2, next3);
2925 }
2926
2927 /* Single loop for potentially the last three packets */
2928 while (n_left_from > 0 && n_left_to_next > 0)
2929 {
2930 u32 bi0;
2931 vlib_buffer_t *b0;
2932 ip6_header_t *ip0 = 0;
2933 ip6_sr_header_t *sr0 = 0;
2934 ip6_sr_sl_t *sl0;
2935 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2936 u16 new_l0 = 0;
2937
2938 bi0 = from[0];
2939 to_next[0] = bi0;
2940 from += 1;
2941 to_next += 1;
2942 n_left_from -= 1;
2943 n_left_to_next -= 1;
2944
2945 b0 = vlib_get_buffer (vm, bi0);
2946 sl0 =
2947 pool_elt_at_index (sm->sid_lists,
2948 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00002949 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2950 vec_len (sl0->rewrite_bsid));
Pablo Camarillofb380952016-12-07 18:34:18 +01002951
2952 ip0 = vlib_buffer_get_current (b0);
2953
2954 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2955 sr0 =
2956 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2957 ip6_ext_header_len (ip0 + 1));
2958 else
2959 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2960
Dave Barach178cf492018-11-13 16:34:13 -05002961 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite_bsid),
2962 (u8 *) ip0, (void *) sr0 - (void *) ip0);
2963 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2964 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
Pablo Camarillofb380952016-12-07 18:34:18 +01002965
2966 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2967
2968 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2969 ip0->hop_limit -= 1;
2970 new_l0 =
2971 clib_net_to_host_u16 (ip0->payload_length) +
2972 vec_len (sl0->rewrite_bsid);
2973 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2974
2975 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2976
2977 ip0->dst_address.as_u64[0] =
2978 (sr0->segments + sr0->segments_left)->as_u64[0];
2979 ip0->dst_address.as_u64[1] =
2980 (sr0->segments + sr0->segments_left)->as_u64[1];
2981
2982 if (ip0 + 1 == (void *) sr0)
2983 {
2984 sr0->protocol = ip0->protocol;
2985 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2986 }
2987 else
2988 {
2989 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2990 sr0->protocol = ip_ext->next_hdr;
2991 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2992 }
2993
2994 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2995 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2996 {
2997 sr_policy_rewrite_trace_t *tr =
2998 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002999 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3000 sizeof (tr->src.as_u8));
3001 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3002 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003003 }
3004
3005 insert_pkts++;
3006
3007 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3008 n_left_to_next, bi0, next0);
3009 }
3010
3011 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3012 }
3013
3014 /* Update counters */
3015 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
3016 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3017 insert_pkts);
3018 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
3019 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3020 bsid_pkts);
3021 return from_frame->n_vectors;
3022}
3023
3024/* *INDENT-OFF* */
3025VLIB_REGISTER_NODE (sr_policy_rewrite_b_insert_node) = {
3026 .function = sr_policy_rewrite_b_insert,
3027 .name = "sr-pl-rewrite-b-insert",
3028 .vector_size = sizeof (u32),
3029 .format_trace = format_sr_policy_rewrite_trace,
3030 .type = VLIB_NODE_TYPE_INTERNAL,
3031 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3032 .error_strings = sr_policy_rewrite_error_strings,
3033 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3034 .next_nodes = {
3035#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3036 foreach_sr_policy_rewrite_next
3037#undef _
3038 },
3039};
3040/* *INDENT-ON* */
3041
3042/**
3043 * @brief Function BSID encapsulation
3044 */
3045static_always_inline void
3046end_bsid_encaps_srh_processing (vlib_node_runtime_t * node,
3047 vlib_buffer_t * b0,
3048 ip6_header_t * ip0,
3049 ip6_sr_header_t * sr0, u32 * next0)
3050{
3051 ip6_address_t *new_dst0;
3052
3053 if (PREDICT_FALSE (!sr0))
3054 goto error_bsid_encaps;
3055
3056 if (PREDICT_TRUE (sr0->type == ROUTING_HEADER_TYPE_SR))
3057 {
3058 if (PREDICT_TRUE (sr0->segments_left != 0))
3059 {
3060 sr0->segments_left -= 1;
3061 new_dst0 = (ip6_address_t *) (sr0->segments);
3062 new_dst0 += sr0->segments_left;
3063 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
3064 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
3065 return;
3066 }
3067 }
3068
3069error_bsid_encaps:
3070 *next0 = SR_POLICY_REWRITE_NEXT_ERROR;
3071 b0->error = node->errors[SR_POLICY_REWRITE_ERROR_BSID_ZERO];
3072}
3073
3074/**
3075 * @brief Graph node for applying a SR policy BSID - Encapsulation
3076 */
3077static uword
3078sr_policy_rewrite_b_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
3079 vlib_frame_t * from_frame)
3080{
3081 ip6_sr_main_t *sm = &sr_main;
3082 u32 n_left_from, next_index, *from, *to_next;
3083
3084 from = vlib_frame_vector_args (from_frame);
3085 n_left_from = from_frame->n_vectors;
3086
3087 next_index = node->cached_next_index;
3088
3089 int encap_pkts = 0, bsid_pkts = 0;
3090
3091 while (n_left_from > 0)
3092 {
3093 u32 n_left_to_next;
3094
3095 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
3096
3097 /* Quad - Loop */
3098 while (n_left_from >= 8 && n_left_to_next >= 4)
3099 {
3100 u32 bi0, bi1, bi2, bi3;
3101 vlib_buffer_t *b0, *b1, *b2, *b3;
3102 u32 next0, next1, next2, next3;
3103 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3104 ip6_header_t *ip0, *ip1, *ip2, *ip3;
3105 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
3106 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
Pablo Camarillofb380952016-12-07 18:34:18 +01003107 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
3108
3109 /* Prefetch next iteration. */
3110 {
3111 vlib_buffer_t *p4, *p5, *p6, *p7;
3112
3113 p4 = vlib_get_buffer (vm, from[4]);
3114 p5 = vlib_get_buffer (vm, from[5]);
3115 p6 = vlib_get_buffer (vm, from[6]);
3116 p7 = vlib_get_buffer (vm, from[7]);
3117
3118 /* Prefetch the buffer header and packet for the N+2 loop iteration */
3119 vlib_prefetch_buffer_header (p4, LOAD);
3120 vlib_prefetch_buffer_header (p5, LOAD);
3121 vlib_prefetch_buffer_header (p6, LOAD);
3122 vlib_prefetch_buffer_header (p7, LOAD);
3123
3124 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
3125 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
3126 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
3127 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
3128 }
3129
3130 to_next[0] = bi0 = from[0];
3131 to_next[1] = bi1 = from[1];
3132 to_next[2] = bi2 = from[2];
3133 to_next[3] = bi3 = from[3];
3134 from += 4;
3135 to_next += 4;
3136 n_left_from -= 4;
3137 n_left_to_next -= 4;
3138
3139 b0 = vlib_get_buffer (vm, bi0);
3140 b1 = vlib_get_buffer (vm, bi1);
3141 b2 = vlib_get_buffer (vm, bi2);
3142 b3 = vlib_get_buffer (vm, bi3);
3143
3144 sl0 =
3145 pool_elt_at_index (sm->sid_lists,
3146 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3147 sl1 =
3148 pool_elt_at_index (sm->sid_lists,
3149 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
3150 sl2 =
3151 pool_elt_at_index (sm->sid_lists,
3152 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
3153 sl3 =
3154 pool_elt_at_index (sm->sid_lists,
3155 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00003156 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3157 vec_len (sl0->rewrite));
3158 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3159 vec_len (sl1->rewrite));
3160 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3161 vec_len (sl2->rewrite));
3162 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3163 vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01003164
3165 ip0_encap = vlib_buffer_get_current (b0);
3166 ip1_encap = vlib_buffer_get_current (b1);
3167 ip2_encap = vlib_buffer_get_current (b2);
3168 ip3_encap = vlib_buffer_get_current (b3);
3169
Klement Sekera769145c2019-03-06 11:59:57 +01003170 sr0 =
3171 ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
3172 NULL);
3173 sr1 =
3174 ip6_ext_header_find (vm, b1, ip1_encap, IP_PROTOCOL_IPV6_ROUTE,
3175 NULL);
3176 sr2 =
3177 ip6_ext_header_find (vm, b2, ip2_encap, IP_PROTOCOL_IPV6_ROUTE,
3178 NULL);
3179 sr3 =
3180 ip6_ext_header_find (vm, b3, ip3_encap, IP_PROTOCOL_IPV6_ROUTE,
3181 NULL);
Pablo Camarillofb380952016-12-07 18:34:18 +01003182
3183 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
3184 end_bsid_encaps_srh_processing (node, b1, ip1_encap, sr1, &next1);
3185 end_bsid_encaps_srh_processing (node, b2, ip2_encap, sr2, &next2);
3186 end_bsid_encaps_srh_processing (node, b3, ip3_encap, sr3, &next3);
3187
Dave Barach178cf492018-11-13 16:34:13 -05003188 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3189 sl0->rewrite, vec_len (sl0->rewrite));
3190 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
3191 sl1->rewrite, vec_len (sl1->rewrite));
3192 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
3193 sl2->rewrite, vec_len (sl2->rewrite));
3194 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
3195 sl3->rewrite, vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01003196
3197 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3198 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
3199 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
3200 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
3201
3202 ip0 = vlib_buffer_get_current (b0);
3203 ip1 = vlib_buffer_get_current (b1);
3204 ip2 = vlib_buffer_get_current (b2);
3205 ip3 = vlib_buffer_get_current (b3);
3206
3207 encaps_processing_v6 (node, b0, ip0, ip0_encap);
3208 encaps_processing_v6 (node, b1, ip1, ip1_encap);
3209 encaps_processing_v6 (node, b2, ip2, ip2_encap);
3210 encaps_processing_v6 (node, b3, ip3, ip3_encap);
3211
3212 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
3213 {
3214 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3215 {
3216 sr_policy_rewrite_trace_t *tr =
3217 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003218 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3219 sizeof (tr->src.as_u8));
3220 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3221 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003222 }
3223
3224 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
3225 {
3226 sr_policy_rewrite_trace_t *tr =
3227 vlib_add_trace (vm, node, b1, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003228 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
3229 sizeof (tr->src.as_u8));
3230 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
3231 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003232 }
3233
3234 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
3235 {
3236 sr_policy_rewrite_trace_t *tr =
3237 vlib_add_trace (vm, node, b2, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003238 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
3239 sizeof (tr->src.as_u8));
3240 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
3241 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003242 }
3243
3244 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
3245 {
3246 sr_policy_rewrite_trace_t *tr =
3247 vlib_add_trace (vm, node, b3, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003248 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
3249 sizeof (tr->src.as_u8));
3250 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
3251 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003252 }
3253 }
3254
3255 encap_pkts += 4;
3256 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
3257 n_left_to_next, bi0, bi1, bi2, bi3,
3258 next0, next1, next2, next3);
3259 }
3260
3261 /* Single loop for potentially the last three packets */
3262 while (n_left_from > 0 && n_left_to_next > 0)
3263 {
3264 u32 bi0;
3265 vlib_buffer_t *b0;
3266 ip6_header_t *ip0 = 0, *ip0_encap = 0;
Pablo Camarillofb380952016-12-07 18:34:18 +01003267 ip6_sr_header_t *sr0;
3268 ip6_sr_sl_t *sl0;
3269 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3270
3271 bi0 = from[0];
3272 to_next[0] = bi0;
3273 from += 1;
3274 to_next += 1;
3275 n_left_from -= 1;
3276 n_left_to_next -= 1;
3277 b0 = vlib_get_buffer (vm, bi0);
3278
3279 sl0 =
3280 pool_elt_at_index (sm->sid_lists,
3281 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00003282 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3283 vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01003284
3285 ip0_encap = vlib_buffer_get_current (b0);
Klement Sekera769145c2019-03-06 11:59:57 +01003286 sr0 =
3287 ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
3288 NULL);
Pablo Camarillofb380952016-12-07 18:34:18 +01003289 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
3290
Dave Barach178cf492018-11-13 16:34:13 -05003291 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3292 sl0->rewrite, vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01003293 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3294
3295 ip0 = vlib_buffer_get_current (b0);
3296
3297 encaps_processing_v6 (node, b0, ip0, ip0_encap);
3298
3299 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3300 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3301 {
3302 sr_policy_rewrite_trace_t *tr =
3303 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003304 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3305 sizeof (tr->src.as_u8));
3306 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3307 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003308 }
3309
3310 encap_pkts++;
3311 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3312 n_left_to_next, bi0, next0);
3313 }
3314
3315 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3316 }
3317
3318 /* Update counters */
3319 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3320 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3321 encap_pkts);
3322 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3323 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3324 bsid_pkts);
3325
3326 return from_frame->n_vectors;
3327}
3328
3329/* *INDENT-OFF* */
3330VLIB_REGISTER_NODE (sr_policy_rewrite_b_encaps_node) = {
3331 .function = sr_policy_rewrite_b_encaps,
3332 .name = "sr-pl-rewrite-b-encaps",
3333 .vector_size = sizeof (u32),
3334 .format_trace = format_sr_policy_rewrite_trace,
3335 .type = VLIB_NODE_TYPE_INTERNAL,
3336 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3337 .error_strings = sr_policy_rewrite_error_strings,
3338 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3339 .next_nodes = {
3340#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3341 foreach_sr_policy_rewrite_next
3342#undef _
3343 },
3344};
3345/* *INDENT-ON* */
3346
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -08003347/*************************** SR Policy plugins ******************************/
3348/**
3349 * @brief SR Policy plugin registry
3350 */
3351int
3352sr_policy_register_function (vlib_main_t * vm, u8 * fn_name,
3353 u8 * keyword_str, u8 * def_str,
3354 u8 * params_str, u8 prefix_length,
3355 dpo_type_t * dpo,
3356 format_function_t * ls_format,
3357 unformat_function_t * ls_unformat,
3358 sr_p_plugin_callback_t * creation_fn,
3359 sr_p_plugin_callback_t * removal_fn)
3360{
3361 ip6_sr_main_t *sm = &sr_main;
3362 uword *p;
3363
3364 sr_policy_fn_registration_t *plugin;
3365
3366 /* Did this function exist? If so update it */
3367 p = hash_get_mem (sm->policy_plugin_functions_by_key, fn_name);
3368 if (p)
3369 {
3370 plugin = pool_elt_at_index (sm->policy_plugin_functions, p[0]);
3371 }
3372 /* Else create a new one and set hash key */
3373 else
3374 {
3375 pool_get (sm->policy_plugin_functions, plugin);
3376 hash_set_mem (sm->policy_plugin_functions_by_key, fn_name,
3377 plugin - sm->policy_plugin_functions);
3378 }
3379
3380 clib_memset (plugin, 0, sizeof (*plugin));
3381
3382 plugin->sr_policy_function_number = (plugin - sm->policy_plugin_functions);
3383 plugin->sr_policy_function_number += SR_BEHAVIOR_LAST;
3384 plugin->prefix_length = prefix_length;
3385 plugin->ls_format = ls_format;
3386 plugin->ls_unformat = ls_unformat;
3387 plugin->creation = creation_fn;
3388 plugin->removal = removal_fn;
3389 clib_memcpy (&plugin->dpo, dpo, sizeof (dpo_type_t));
3390 plugin->function_name = format (0, "%s%c", fn_name, 0);
3391 plugin->keyword_str = format (0, "%s%c", keyword_str, 0);
3392 plugin->def_str = format (0, "%s%c", def_str, 0);
3393 plugin->params_str = format (0, "%s%c", params_str, 0);
3394
3395 return plugin->sr_policy_function_number;
3396}
3397
3398/**
3399 * @brief CLI function to 'show' all available SR LocalSID behaviors
3400 */
3401static clib_error_t *
3402show_sr_policy_behaviors_command_fn (vlib_main_t * vm,
3403 unformat_input_t * input,
3404 vlib_cli_command_t * cmd)
3405{
3406 ip6_sr_main_t *sm = &sr_main;
3407 sr_policy_fn_registration_t *plugin;
3408 sr_policy_fn_registration_t **plugins_vec = 0;
3409 int i;
3410
3411 vlib_cli_output (vm, "SR Policy behaviors:\n-----------------------\n\n");
3412
3413 /* *INDENT-OFF* */
Damjan Marionb2c31b62020-12-13 21:47:40 +01003414 pool_foreach (plugin, sm->policy_plugin_functions)
3415 { vec_add1 (plugins_vec, plugin); }
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -08003416 /* *INDENT-ON* */
3417
3418 vlib_cli_output (vm, "Plugin behaviors:\n");
3419 for (i = 0; i < vec_len (plugins_vec); i++)
3420 {
3421 plugin = plugins_vec[i];
3422 vlib_cli_output (vm, "\t%s\t-> %s.\n", plugin->keyword_str,
3423 plugin->def_str);
3424 vlib_cli_output (vm, "\t\tParameters: '%s'\n", plugin->params_str);
3425 }
3426 return 0;
3427}
3428
3429/* *INDENT-OFF* */
3430VLIB_CLI_COMMAND (show_sr_policy_behaviors_command, static) = {
3431 .path = "show sr policy behaviors",
3432 .short_help = "show sr policy behaviors",
3433 .function = show_sr_policy_behaviors_command_fn,
3434};
3435/* *INDENT-ON* */
3436
Pablo Camarillofb380952016-12-07 18:34:18 +01003437/*************************** SR Segment Lists DPOs ****************************/
3438static u8 *
3439format_sr_segment_list_dpo (u8 * s, va_list * args)
3440{
3441 ip6_sr_main_t *sm = &sr_main;
3442 ip6_address_t *addr;
3443 ip6_sr_sl_t *sl;
3444
3445 index_t index = va_arg (*args, index_t);
3446 CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
3447 s = format (s, "SR: Segment List index:[%d]", index);
3448 s = format (s, "\n\tSegments:");
3449
3450 sl = pool_elt_at_index (sm->sid_lists, index);
3451
3452 s = format (s, "< ");
3453 vec_foreach (addr, sl->segments)
3454 {
3455 s = format (s, "%U, ", format_ip6_address, addr);
3456 }
3457 s = format (s, "\b\b > - ");
3458 s = format (s, "Weight: %u", sl->weight);
3459
3460 return s;
3461}
3462
3463const static dpo_vft_t sr_policy_rewrite_vft = {
3464 .dv_lock = sr_dpo_lock,
3465 .dv_unlock = sr_dpo_unlock,
3466 .dv_format = format_sr_segment_list_dpo,
3467};
3468
3469const static char *const sr_pr_encaps_ip6_nodes[] = {
3470 "sr-pl-rewrite-encaps",
3471 NULL,
3472};
3473
3474const static char *const sr_pr_encaps_ip4_nodes[] = {
3475 "sr-pl-rewrite-encaps-v4",
3476 NULL,
3477};
3478
3479const static char *const *const sr_pr_encaps_nodes[DPO_PROTO_NUM] = {
3480 [DPO_PROTO_IP6] = sr_pr_encaps_ip6_nodes,
3481 [DPO_PROTO_IP4] = sr_pr_encaps_ip4_nodes,
3482};
3483
3484const static char *const sr_pr_insert_ip6_nodes[] = {
3485 "sr-pl-rewrite-insert",
3486 NULL,
3487};
3488
3489const static char *const *const sr_pr_insert_nodes[DPO_PROTO_NUM] = {
3490 [DPO_PROTO_IP6] = sr_pr_insert_ip6_nodes,
3491};
3492
3493const static char *const sr_pr_bsid_insert_ip6_nodes[] = {
3494 "sr-pl-rewrite-b-insert",
3495 NULL,
3496};
3497
3498const static char *const *const sr_pr_bsid_insert_nodes[DPO_PROTO_NUM] = {
3499 [DPO_PROTO_IP6] = sr_pr_bsid_insert_ip6_nodes,
3500};
3501
3502const static char *const sr_pr_bsid_encaps_ip6_nodes[] = {
3503 "sr-pl-rewrite-b-encaps",
3504 NULL,
3505};
3506
3507const static char *const *const sr_pr_bsid_encaps_nodes[DPO_PROTO_NUM] = {
3508 [DPO_PROTO_IP6] = sr_pr_bsid_encaps_ip6_nodes,
3509};
3510
3511/********************* SR Policy Rewrite initialization ***********************/
3512/**
3513 * @brief SR Policy Rewrite initialization
3514 */
3515clib_error_t *
3516sr_policy_rewrite_init (vlib_main_t * vm)
3517{
3518 ip6_sr_main_t *sm = &sr_main;
3519
3520 /* Init memory for sr policy keys (bsid <-> ip6_address_t) */
Pablo Camarillo4521afa2017-03-16 10:43:05 +01003521 mhash_init (&sm->sr_policies_index_hash, sizeof (uword),
3522 sizeof (ip6_address_t));
Pablo Camarillofb380952016-12-07 18:34:18 +01003523
3524 /* Init SR VPO DPOs type */
3525 sr_pr_encaps_dpo_type =
3526 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_encaps_nodes);
3527
3528 sr_pr_insert_dpo_type =
3529 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_insert_nodes);
3530
3531 sr_pr_bsid_encaps_dpo_type =
3532 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_encaps_nodes);
3533
3534 sr_pr_bsid_insert_dpo_type =
3535 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_insert_nodes);
3536
3537 /* Register the L2 encaps node used in HW redirect */
3538 sm->l2_sr_policy_rewrite_index = sr_policy_rewrite_encaps_node.index;
3539
3540 sm->fib_table_ip6 = (u32) ~ 0;
3541 sm->fib_table_ip4 = (u32) ~ 0;
3542
3543 return 0;
3544}
3545
3546VLIB_INIT_FUNCTION (sr_policy_rewrite_init);
3547
3548
3549/*
3550* fd.io coding-style-patch-verification: ON
3551*
3552* Local Variables:
3553* eval: (c-set-style "gnu")
3554* End:
3555*/