blob: b7fbc4b8cdaa08cdf9020e46b92aaeecbae220e6 [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>
Pablo Camarillofb380952016-12-07 18:34:18 +010044#include <vnet/ip/ip.h>
Pablo Camarillo5d73eec2017-04-24 17:51:56 +020045#include <vnet/srv6/sr_packet.h>
Pablo Camarillofb380952016-12-07 18:34:18 +010046#include <vnet/ip/ip6_packet.h>
47#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
Pablo Camarillofb380952016-12-07 18:34:18 +0100122static clib_error_t *
123set_sr_src_command_fn (vlib_main_t * vm, unformat_input_t * input,
124 vlib_cli_command_t * cmd)
125{
126 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
127 {
128 if (unformat
129 (input, "addr %U", unformat_ip6_address, &sr_pr_encaps_src))
130 return 0;
131 else
132 return clib_error_return (0, "No address specified");
133 }
134 return clib_error_return (0, "No address specified");
135}
136
137/* *INDENT-OFF* */
138VLIB_CLI_COMMAND (set_sr_src_command, static) = {
139 .path = "set sr encaps source",
140 .short_help = "set sr encaps source addr <ip6_addr>",
141 .function = set_sr_src_command_fn,
142};
143/* *INDENT-ON* */
144
Ignas Bačiuseeb5fb32019-10-03 17:15:38 +0300145/******************** SR rewrite set encaps IPv6 hop-limit ********************/
146
147void
148sr_set_hop_limit (u8 hop_limit)
149{
150 sr_pr_encaps_hop_limit = hop_limit;
151}
152
153u8
154sr_get_hop_limit (void)
155{
156 return sr_pr_encaps_hop_limit;
157}
158
159static clib_error_t *
160set_sr_hop_limit_command_fn (vlib_main_t * vm, unformat_input_t * input,
161 vlib_cli_command_t * cmd)
162{
163 int hop_limit = sr_get_hop_limit ();
164
165 if (unformat_check_input (input) == UNFORMAT_END_OF_INPUT)
166 return clib_error_return (0, "No value specified");
167 if (!unformat (input, "%d", &hop_limit))
168 return clib_error_return (0, "Invalid value");
169 if (hop_limit <= 0 || hop_limit > 255)
170 return clib_error_return (0, "Value out of range [1-255]");
171 sr_pr_encaps_hop_limit = (u8) hop_limit;
172 return 0;
173}
174
175/* *INDENT-OFF* */
176VLIB_CLI_COMMAND (set_sr_hop_limit_command, static) = {
177 .path = "set sr encaps hop-limit",
178 .short_help = "set sr encaps hop-limit <value>",
179 .function = set_sr_hop_limit_command_fn,
180};
181/* *INDENT-ON* */
182
Pablo Camarillofb380952016-12-07 18:34:18 +0100183/*********************** SR rewrite string computation ************************/
184/**
185 * @brief SR rewrite string computation for IPv6 encapsulation (inline)
186 *
187 * @param sl is a vector of IPv6 addresses composing the Segment List
188 *
189 * @return precomputed rewrite string for encapsulation
190 */
191static inline u8 *
192compute_rewrite_encaps (ip6_address_t * sl)
193{
194 ip6_header_t *iph;
195 ip6_sr_header_t *srh;
196 ip6_address_t *addrp, *this_address;
197 u32 header_length = 0;
198 u8 *rs = NULL;
199
200 header_length = 0;
201 header_length += IPv6_DEFAULT_HEADER_LENGTH;
202 if (vec_len (sl) > 1)
203 {
204 header_length += sizeof (ip6_sr_header_t);
205 header_length += vec_len (sl) * sizeof (ip6_address_t);
206 }
207
208 vec_validate (rs, header_length - 1);
209
210 iph = (ip6_header_t *) rs;
211 iph->ip_version_traffic_class_and_flow_label =
212 clib_host_to_net_u32 (0 | ((6 & 0xF) << 28));
213 iph->src_address.as_u64[0] = sr_pr_encaps_src.as_u64[0];
214 iph->src_address.as_u64[1] = sr_pr_encaps_src.as_u64[1];
215 iph->payload_length = header_length - IPv6_DEFAULT_HEADER_LENGTH;
216 iph->protocol = IP_PROTOCOL_IPV6;
Ignas Bačiuseeb5fb32019-10-03 17:15:38 +0300217 iph->hop_limit = sr_pr_encaps_hop_limit;
Pablo Camarillofb380952016-12-07 18:34:18 +0100218
Pablo Camarillod327c872018-01-08 14:25:55 +0100219 if (vec_len (sl) > 1)
220 {
221 srh = (ip6_sr_header_t *) (iph + 1);
222 iph->protocol = IP_PROTOCOL_IPV6_ROUTE;
223 srh->protocol = IP_PROTOCOL_IPV6;
224 srh->type = ROUTING_HEADER_TYPE_SR;
225 srh->segments_left = vec_len (sl) - 1;
Ahmed Abdelsalambe837042019-06-20 11:18:57 +0000226 srh->last_entry = vec_len (sl) - 1;
Pablo Camarillod327c872018-01-08 14:25:55 +0100227 srh->length = ((sizeof (ip6_sr_header_t) +
228 (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
229 srh->flags = 0x00;
Ahmed Abdelsalambe837042019-06-20 11:18:57 +0000230 srh->tag = 0x0000;
Pablo Camarillod327c872018-01-08 14:25:55 +0100231 addrp = srh->segments + vec_len (sl) - 1;
232 vec_foreach (this_address, sl)
233 {
Dave Barach178cf492018-11-13 16:34:13 -0500234 clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
235 sizeof (ip6_address_t));
Pablo Camarillod327c872018-01-08 14:25:55 +0100236 addrp--;
237 }
238 }
Pablo Camarillofb380952016-12-07 18:34:18 +0100239 iph->dst_address.as_u64[0] = sl->as_u64[0];
240 iph->dst_address.as_u64[1] = sl->as_u64[1];
241 return rs;
242}
243
244/**
245 * @brief SR rewrite string computation for SRH insertion (inline)
246 *
247 * @param sl is a vector of IPv6 addresses composing the Segment List
248 *
249 * @return precomputed rewrite string for SRH insertion
250 */
251static inline u8 *
252compute_rewrite_insert (ip6_address_t * sl)
253{
254 ip6_sr_header_t *srh;
255 ip6_address_t *addrp, *this_address;
256 u32 header_length = 0;
257 u8 *rs = NULL;
258
259 header_length = 0;
260 header_length += sizeof (ip6_sr_header_t);
261 header_length += (vec_len (sl) + 1) * sizeof (ip6_address_t);
262
263 vec_validate (rs, header_length - 1);
264
265 srh = (ip6_sr_header_t *) rs;
266 srh->type = ROUTING_HEADER_TYPE_SR;
267 srh->segments_left = vec_len (sl);
Ahmed Abdelsalambe837042019-06-20 11:18:57 +0000268 srh->last_entry = vec_len (sl);
Pablo Camarillofb380952016-12-07 18:34:18 +0100269 srh->length = ((sizeof (ip6_sr_header_t) +
270 ((vec_len (sl) + 1) * sizeof (ip6_address_t))) / 8) - 1;
271 srh->flags = 0x00;
Ahmed Abdelsalambe837042019-06-20 11:18:57 +0000272 srh->tag = 0x0000;
Pablo Camarillofb380952016-12-07 18:34:18 +0100273 addrp = srh->segments + vec_len (sl);
274 vec_foreach (this_address, sl)
275 {
Dave Barach178cf492018-11-13 16:34:13 -0500276 clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
277 sizeof (ip6_address_t));
Pablo Camarillofb380952016-12-07 18:34:18 +0100278 addrp--;
279 }
280 return rs;
281}
282
283/**
284 * @brief SR rewrite string computation for SRH insertion with BSID (inline)
285 *
286 * @param sl is a vector of IPv6 addresses composing the Segment List
287 *
288 * @return precomputed rewrite string for SRH insertion with BSID
289 */
290static inline u8 *
291compute_rewrite_bsid (ip6_address_t * sl)
292{
293 ip6_sr_header_t *srh;
294 ip6_address_t *addrp, *this_address;
295 u32 header_length = 0;
296 u8 *rs = NULL;
297
298 header_length = 0;
299 header_length += sizeof (ip6_sr_header_t);
300 header_length += vec_len (sl) * sizeof (ip6_address_t);
301
302 vec_validate (rs, header_length - 1);
303
304 srh = (ip6_sr_header_t *) rs;
305 srh->type = ROUTING_HEADER_TYPE_SR;
306 srh->segments_left = vec_len (sl) - 1;
Ahmed Abdelsalambe837042019-06-20 11:18:57 +0000307 srh->last_entry = vec_len (sl) - 1;
Pablo Camarillofb380952016-12-07 18:34:18 +0100308 srh->length = ((sizeof (ip6_sr_header_t) +
309 (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
310 srh->flags = 0x00;
Ahmed Abdelsalambe837042019-06-20 11:18:57 +0000311 srh->tag = 0x0000;
Pablo Camarillofb380952016-12-07 18:34:18 +0100312 addrp = srh->segments + vec_len (sl) - 1;
313 vec_foreach (this_address, sl)
314 {
Dave Barach178cf492018-11-13 16:34:13 -0500315 clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
316 sizeof (ip6_address_t));
Pablo Camarillofb380952016-12-07 18:34:18 +0100317 addrp--;
318 }
319 return rs;
320}
321
322/*************************** SR LB helper functions **************************/
323/**
324 * @brief Creates a Segment List and adds it to an SR policy
325 *
326 * Creates a Segment List and adds it to the SR policy. Notice that the SL are
327 * not necessarily unique. Hence there might be two Segment List within the
328 * same SR Policy with exactly the same segments and same weight.
329 *
330 * @param sr_policy is the SR policy where the SL will be added
331 * @param sl is a vector of IPv6 addresses composing the Segment List
332 * @param weight is the weight of the SegmentList (for load-balancing purposes)
333 * @param is_encap represents the mode (SRH insertion vs Encapsulation)
334 *
335 * @return pointer to the just created segment list
336 */
337static inline ip6_sr_sl_t *
338create_sl (ip6_sr_policy_t * sr_policy, ip6_address_t * sl, u32 weight,
339 u8 is_encap)
340{
341 ip6_sr_main_t *sm = &sr_main;
342 ip6_sr_sl_t *segment_list;
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800343 sr_policy_fn_registration_t *plugin = 0;
Pablo Camarillofb380952016-12-07 18:34:18 +0100344
345 pool_get (sm->sid_lists, segment_list);
Dave Barachb7b92992018-10-17 10:38:51 -0400346 clib_memset (segment_list, 0, sizeof (*segment_list));
Pablo Camarillofb380952016-12-07 18:34:18 +0100347
348 vec_add1 (sr_policy->segments_lists, segment_list - sm->sid_lists);
349
350 /* Fill in segment list */
351 segment_list->weight =
352 (weight != (u32) ~ 0 ? weight : SR_SEGMENT_LIST_WEIGHT_DEFAULT);
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800353
Pablo Camarillofb380952016-12-07 18:34:18 +0100354 segment_list->segments = vec_dup (sl);
355
356 if (is_encap)
357 {
358 segment_list->rewrite = compute_rewrite_encaps (sl);
359 segment_list->rewrite_bsid = segment_list->rewrite;
360 }
361 else
362 {
363 segment_list->rewrite = compute_rewrite_insert (sl);
364 segment_list->rewrite_bsid = compute_rewrite_bsid (sl);
365 }
366
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800367 if (sr_policy->plugin)
368 {
369 plugin =
370 pool_elt_at_index (sm->policy_plugin_functions,
371 sr_policy->plugin - SR_BEHAVIOR_LAST);
372
373 segment_list->plugin = sr_policy->plugin;
374 segment_list->plugin_mem = sr_policy->plugin_mem;
375
376 plugin->creation (sr_policy);
377 }
378
Pablo Camarillofb380952016-12-07 18:34:18 +0100379 /* Create DPO */
380 dpo_reset (&segment_list->bsid_dpo);
381 dpo_reset (&segment_list->ip6_dpo);
382 dpo_reset (&segment_list->ip4_dpo);
383
384 if (is_encap)
385 {
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800386 if (!sr_policy->plugin)
387 {
388 dpo_set (&segment_list->ip6_dpo, sr_pr_encaps_dpo_type,
389 DPO_PROTO_IP6, segment_list - sm->sid_lists);
390 dpo_set (&segment_list->ip4_dpo, sr_pr_encaps_dpo_type,
391 DPO_PROTO_IP4, segment_list - sm->sid_lists);
392 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_encaps_dpo_type,
393 DPO_PROTO_IP6, segment_list - sm->sid_lists);
394 }
395 else
396 {
397 dpo_set (&segment_list->ip6_dpo, plugin->dpo, DPO_PROTO_IP6,
398 segment_list - sm->sid_lists);
399 dpo_set (&segment_list->ip4_dpo, plugin->dpo, DPO_PROTO_IP4,
400 segment_list - sm->sid_lists);
401 dpo_set (&segment_list->bsid_dpo, plugin->dpo, DPO_PROTO_IP6,
402 segment_list - sm->sid_lists);
403 }
Pablo Camarillofb380952016-12-07 18:34:18 +0100404 }
405 else
406 {
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800407 if (!sr_policy->plugin)
408 {
409 dpo_set (&segment_list->ip6_dpo, sr_pr_insert_dpo_type,
410 DPO_PROTO_IP6, segment_list - sm->sid_lists);
411 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_insert_dpo_type,
412 DPO_PROTO_IP6, segment_list - sm->sid_lists);
413 }
414 else
415 {
416 dpo_set (&segment_list->ip6_dpo, plugin->dpo, DPO_PROTO_IP6,
417 segment_list - sm->sid_lists);
418 dpo_set (&segment_list->bsid_dpo, plugin->dpo, DPO_PROTO_IP6,
419 segment_list - sm->sid_lists);
420 }
Pablo Camarillofb380952016-12-07 18:34:18 +0100421 }
422
423 return segment_list;
424}
425
426/**
427 * @brief Updates the Load Balancer after an SR Policy change
428 *
429 * @param sr_policy is the modified SR Policy
430 */
431static inline void
432update_lb (ip6_sr_policy_t * sr_policy)
433{
434 flow_hash_config_t fhc;
435 u32 *sl_index;
436 ip6_sr_sl_t *segment_list;
437 ip6_sr_main_t *sm = &sr_main;
438 load_balance_path_t path;
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100439 path.path_index = FIB_NODE_INDEX_INVALID;
Pablo Camarillofb380952016-12-07 18:34:18 +0100440 load_balance_path_t *ip4_path_vector = 0;
441 load_balance_path_t *ip6_path_vector = 0;
442 load_balance_path_t *b_path_vector = 0;
443
444 /* In case LB does not exist, create it */
445 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
446 {
447 fib_prefix_t pfx = {
448 .fp_proto = FIB_PROTOCOL_IP6,
449 .fp_len = 128,
450 .fp_addr = {
451 .ip6 = sr_policy->bsid,
452 }
453 };
454
455 /* Add FIB entry for BSID */
456 fhc = fib_table_get_flow_hash_config (sr_policy->fib_table,
Neale Rannsd792d9c2017-10-21 10:53:20 -0700457 FIB_PROTOCOL_IP6);
Pablo Camarillofb380952016-12-07 18:34:18 +0100458
459 dpo_set (&sr_policy->bsid_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
460 load_balance_create (0, DPO_PROTO_IP6, fhc));
461
462 dpo_set (&sr_policy->ip6_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
463 load_balance_create (0, DPO_PROTO_IP6, fhc));
464
465 /* Update FIB entry's to point to the LB DPO in the main FIB and hidden one */
Neale Ranns107e7d42017-04-11 09:55:19 -0700466 fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
467 sr_policy->fib_table),
468 &pfx, FIB_SOURCE_SR,
Pablo Camarillofb380952016-12-07 18:34:18 +0100469 FIB_ENTRY_FLAG_EXCLUSIVE,
470 &sr_policy->bsid_dpo);
471
472 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
473 &pfx,
474 FIB_SOURCE_SR,
475 FIB_ENTRY_FLAG_EXCLUSIVE,
476 &sr_policy->ip6_dpo);
477
478 if (sr_policy->is_encap)
479 {
480 dpo_set (&sr_policy->ip4_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP4,
481 load_balance_create (0, DPO_PROTO_IP4, fhc));
482
483 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
484 &pfx,
485 FIB_SOURCE_SR,
486 FIB_ENTRY_FLAG_EXCLUSIVE,
487 &sr_policy->ip4_dpo);
488 }
489
490 }
491
492 /* Create the LB path vector */
Pablo Camarillofb380952016-12-07 18:34:18 +0100493 vec_foreach (sl_index, sr_policy->segments_lists)
494 {
495 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
496 path.path_dpo = segment_list->bsid_dpo;
497 path.path_weight = segment_list->weight;
498 vec_add1 (b_path_vector, path);
499 path.path_dpo = segment_list->ip6_dpo;
500 vec_add1 (ip6_path_vector, path);
501 if (sr_policy->is_encap)
502 {
503 path.path_dpo = segment_list->ip4_dpo;
504 vec_add1 (ip4_path_vector, path);
505 }
506 }
507
508 /* Update LB multipath */
509 load_balance_multipath_update (&sr_policy->bsid_dpo, b_path_vector,
510 LOAD_BALANCE_FLAG_NONE);
511 load_balance_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector,
512 LOAD_BALANCE_FLAG_NONE);
513 if (sr_policy->is_encap)
514 load_balance_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector,
515 LOAD_BALANCE_FLAG_NONE);
516
517 /* Cleanup */
518 vec_free (b_path_vector);
519 vec_free (ip6_path_vector);
520 vec_free (ip4_path_vector);
Pablo Camarillofb380952016-12-07 18:34:18 +0100521}
522
523/**
524 * @brief Updates the Replicate DPO after an SR Policy change
525 *
526 * @param sr_policy is the modified SR Policy (type spray)
527 */
528static inline void
529update_replicate (ip6_sr_policy_t * sr_policy)
530{
531 u32 *sl_index;
532 ip6_sr_sl_t *segment_list;
533 ip6_sr_main_t *sm = &sr_main;
534 load_balance_path_t path;
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100535 path.path_index = FIB_NODE_INDEX_INVALID;
Pablo Camarillofb380952016-12-07 18:34:18 +0100536 load_balance_path_t *b_path_vector = 0;
537 load_balance_path_t *ip6_path_vector = 0;
538 load_balance_path_t *ip4_path_vector = 0;
539
540 /* In case LB does not exist, create it */
541 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
542 {
543 dpo_set (&sr_policy->bsid_dpo, DPO_REPLICATE,
544 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
545
546 dpo_set (&sr_policy->ip6_dpo, DPO_REPLICATE,
547 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
548
549 /* Update FIB entry's DPO to point to SR without LB */
550 fib_prefix_t pfx = {
551 .fp_proto = FIB_PROTOCOL_IP6,
552 .fp_len = 128,
553 .fp_addr = {
554 .ip6 = sr_policy->bsid,
555 }
556 };
Neale Ranns107e7d42017-04-11 09:55:19 -0700557 fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
558 sr_policy->fib_table),
559 &pfx, FIB_SOURCE_SR,
Pablo Camarillofb380952016-12-07 18:34:18 +0100560 FIB_ENTRY_FLAG_EXCLUSIVE,
561 &sr_policy->bsid_dpo);
562
563 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
564 &pfx,
565 FIB_SOURCE_SR,
566 FIB_ENTRY_FLAG_EXCLUSIVE,
567 &sr_policy->ip6_dpo);
568
569 if (sr_policy->is_encap)
570 {
571 dpo_set (&sr_policy->ip4_dpo, DPO_REPLICATE, DPO_PROTO_IP4,
572 replicate_create (0, DPO_PROTO_IP4));
573
574 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
575 &pfx,
576 FIB_SOURCE_SR,
577 FIB_ENTRY_FLAG_EXCLUSIVE,
578 &sr_policy->ip4_dpo);
579 }
580
581 }
582
583 /* Create the replicate path vector */
584 path.path_weight = 1;
585 vec_foreach (sl_index, sr_policy->segments_lists)
586 {
587 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
588 path.path_dpo = segment_list->bsid_dpo;
589 vec_add1 (b_path_vector, path);
590 path.path_dpo = segment_list->ip6_dpo;
591 vec_add1 (ip6_path_vector, path);
592 if (sr_policy->is_encap)
593 {
594 path.path_dpo = segment_list->ip4_dpo;
595 vec_add1 (ip4_path_vector, path);
596 }
597 }
598
599 /* Update replicate multipath */
600 replicate_multipath_update (&sr_policy->bsid_dpo, b_path_vector);
601 replicate_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector);
602 if (sr_policy->is_encap)
603 replicate_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector);
Pablo Camarillofb380952016-12-07 18:34:18 +0100604}
605
606/******************************* SR rewrite API *******************************/
607/* Three functions for handling sr policies:
608 * -> sr_policy_add
609 * -> sr_policy_del
610 * -> sr_policy_mod
611 * All of them are API. CLI function on sr_policy_command_fn */
612
613/**
614 * @brief Create a new SR policy
615 *
616 * @param bsid is the bindingSID of the SR Policy
617 * @param segments is a vector of IPv6 address composing the segment list
618 * @param weight is the weight of the sid list. optional.
619 * @param behavior is the behavior of the SR policy. (default//spray)
620 * @param fib_table is the VRF where to install the FIB entry for the BSID
621 * @param is_encap (bool) whether SR policy should behave as Encap/SRH Insertion
622 *
623 * @return 0 if correct, else error
624 */
625int
626sr_policy_add (ip6_address_t * bsid, ip6_address_t * segments,
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800627 u32 weight, u8 behavior, u32 fib_table, u8 is_encap,
628 u16 plugin, void *ls_plugin_mem)
Pablo Camarillofb380952016-12-07 18:34:18 +0100629{
630 ip6_sr_main_t *sm = &sr_main;
631 ip6_sr_policy_t *sr_policy = 0;
Pablo Camarillofb380952016-12-07 18:34:18 +0100632 uword *p;
633
634 /* Search for existing keys (BSID) */
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100635 p = mhash_get (&sm->sr_policies_index_hash, bsid);
Pablo Camarillofb380952016-12-07 18:34:18 +0100636 if (p)
637 {
638 /* Add SR policy that already exists; complain */
639 return -12;
640 }
641
642 /* Search collision in FIB entries */
643 /* Explanation: It might be possible that some other entity has already
644 * created a route for the BSID. This in theory is impossible, but in
645 * practise we could see it. Assert it and scream if needed */
646 fib_prefix_t pfx = {
647 .fp_proto = FIB_PROTOCOL_IP6,
648 .fp_len = 128,
649 .fp_addr = {
650 .ip6 = *bsid,
651 }
652 };
653
654 /* Lookup the FIB index associated to the table selected */
Neale Ranns107e7d42017-04-11 09:55:19 -0700655 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP6,
656 (fib_table != (u32) ~ 0 ? fib_table : 0));
Pablo Camarillofb380952016-12-07 18:34:18 +0100657 if (fib_index == ~0)
658 return -13;
659
660 /* Lookup whether there exists an entry for the BSID */
661 fib_node_index_t fei = fib_table_lookup_exact_match (fib_index, &pfx);
662 if (FIB_NODE_INDEX_INVALID != fei)
663 return -12; //There is an entry for such lookup
664
665 /* Add an SR policy object */
666 pool_get (sm->sr_policies, sr_policy);
Dave Barachb7b92992018-10-17 10:38:51 -0400667 clib_memset (sr_policy, 0, sizeof (*sr_policy));
Dave Barach178cf492018-11-13 16:34:13 -0500668 clib_memcpy_fast (&sr_policy->bsid, bsid, sizeof (ip6_address_t));
Pablo Camarillofb380952016-12-07 18:34:18 +0100669 sr_policy->type = behavior;
670 sr_policy->fib_table = (fib_table != (u32) ~ 0 ? fib_table : 0); //Is default FIB 0 ?
671 sr_policy->is_encap = is_encap;
672
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800673 if (plugin)
674 {
675 sr_policy->plugin = plugin;
676 sr_policy->plugin_mem = ls_plugin_mem;
677 }
678
Pablo Camarillofb380952016-12-07 18:34:18 +0100679 /* Copy the key */
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100680 mhash_set (&sm->sr_policies_index_hash, bsid, sr_policy - sm->sr_policies,
681 NULL);
Pablo Camarillofb380952016-12-07 18:34:18 +0100682
683 /* Create a segment list and add the index to the SR policy */
684 create_sl (sr_policy, segments, weight, is_encap);
685
686 /* If FIB doesnt exist, create them */
687 if (sm->fib_table_ip6 == (u32) ~ 0)
688 {
689 sm->fib_table_ip6 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
Neale Ranns15002542017-09-10 04:39:11 -0700690 FIB_SOURCE_SR,
Pablo Camarillofb380952016-12-07 18:34:18 +0100691 "SRv6 steering of IP6 prefixes through BSIDs");
692 sm->fib_table_ip4 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
Neale Ranns15002542017-09-10 04:39:11 -0700693 FIB_SOURCE_SR,
Pablo Camarillofb380952016-12-07 18:34:18 +0100694 "SRv6 steering of IP4 prefixes through BSIDs");
Pablo Camarillofb380952016-12-07 18:34:18 +0100695 }
696
697 /* Create IPv6 FIB for the BindingSID attached to the DPO of the only SL */
698 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
699 update_lb (sr_policy);
700 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
701 update_replicate (sr_policy);
702 return 0;
703}
704
705/**
706 * @brief Delete a SR policy
707 *
708 * @param bsid is the bindingSID of the SR Policy
709 * @param index is the index of the SR policy
710 *
711 * @return 0 if correct, else error
712 */
713int
714sr_policy_del (ip6_address_t * bsid, u32 index)
715{
716 ip6_sr_main_t *sm = &sr_main;
717 ip6_sr_policy_t *sr_policy = 0;
718 ip6_sr_sl_t *segment_list;
Pablo Camarillofb380952016-12-07 18:34:18 +0100719 u32 *sl_index;
720 uword *p;
721
Pablo Camarillofb380952016-12-07 18:34:18 +0100722 if (bsid)
723 {
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100724 p = mhash_get (&sm->sr_policies_index_hash, bsid);
Pablo Camarillofb380952016-12-07 18:34:18 +0100725 if (p)
726 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
727 else
728 return -1;
729 }
730 else
731 {
732 sr_policy = pool_elt_at_index (sm->sr_policies, index);
733 if (!sr_policy)
734 return -1;
735 }
736
737 /* Remove BindingSID FIB entry */
738 fib_prefix_t pfx = {
739 .fp_proto = FIB_PROTOCOL_IP6,
740 .fp_len = 128,
741 .fp_addr = {
742 .ip6 = sr_policy->bsid,
743 }
744 ,
745 };
746
Neale Ranns107e7d42017-04-11 09:55:19 -0700747 fib_table_entry_special_remove (fib_table_find (FIB_PROTOCOL_IP6,
748 sr_policy->fib_table),
Pablo Camarillofb380952016-12-07 18:34:18 +0100749 &pfx, FIB_SOURCE_SR);
750
751 fib_table_entry_special_remove (sm->fib_table_ip6, &pfx, FIB_SOURCE_SR);
752
753 if (sr_policy->is_encap)
754 fib_table_entry_special_remove (sm->fib_table_ip4, &pfx, FIB_SOURCE_SR);
755
756 if (dpo_id_is_valid (&sr_policy->bsid_dpo))
757 {
758 dpo_reset (&sr_policy->bsid_dpo);
759 dpo_reset (&sr_policy->ip4_dpo);
760 dpo_reset (&sr_policy->ip6_dpo);
761 }
762
763 /* Clean SID Lists */
764 vec_foreach (sl_index, sr_policy->segments_lists)
765 {
766 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
767 vec_free (segment_list->segments);
768 vec_free (segment_list->rewrite);
Kris Michielsen91074432017-06-22 13:00:20 +0200769 if (!sr_policy->is_encap)
770 vec_free (segment_list->rewrite_bsid);
Pablo Camarillofb380952016-12-07 18:34:18 +0100771 pool_put_index (sm->sid_lists, *sl_index);
772 }
773
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800774 if (sr_policy->plugin)
775 {
776 sr_policy_fn_registration_t *plugin = 0;
777
778 plugin =
779 pool_elt_at_index (sm->policy_plugin_functions,
780 sr_policy->plugin - SR_BEHAVIOR_LAST);
781
782 plugin->removal (sr_policy);
783 sr_policy->plugin = 0;
784 sr_policy->plugin_mem = NULL;
785 }
786
Pablo Camarillofb380952016-12-07 18:34:18 +0100787 /* Remove SR policy entry */
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100788 mhash_unset (&sm->sr_policies_index_hash, &sr_policy->bsid, NULL);
Pablo Camarillofb380952016-12-07 18:34:18 +0100789 pool_put (sm->sr_policies, sr_policy);
790
791 /* If FIB empty unlock it */
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100792 if (!pool_elts (sm->sr_policies) && !pool_elts (sm->steer_policies))
Pablo Camarillofb380952016-12-07 18:34:18 +0100793 {
Neale Ranns15002542017-09-10 04:39:11 -0700794 fib_table_unlock (sm->fib_table_ip6, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
795 fib_table_unlock (sm->fib_table_ip4, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
Pablo Camarillofb380952016-12-07 18:34:18 +0100796 sm->fib_table_ip6 = (u32) ~ 0;
797 sm->fib_table_ip4 = (u32) ~ 0;
798 }
799
800 return 0;
801}
802
803/**
804 * @brief Modify an existing SR policy
805 *
806 * The possible modifications are adding a new Segment List, modifying an
807 * existing Segment List (modify the weight only) and delete a given
808 * Segment List from the SR Policy.
809 *
810 * @param bsid is the bindingSID of the SR Policy
811 * @param index is the index of the SR policy
812 * @param fib_table is the VRF where to install the FIB entry for the BSID
813 * @param operation is the operation to perform (among the top ones)
814 * @param segments is a vector of IPv6 address composing the segment list
815 * @param sl_index is the index of the Segment List to modify/delete
816 * @param weight is the weight of the sid list. optional.
817 * @param is_encap Mode. Encapsulation or SRH insertion.
818 *
819 * @return 0 if correct, else error
820 */
821int
822sr_policy_mod (ip6_address_t * bsid, u32 index, u32 fib_table,
823 u8 operation, ip6_address_t * segments, u32 sl_index,
824 u32 weight)
825{
826 ip6_sr_main_t *sm = &sr_main;
827 ip6_sr_policy_t *sr_policy = 0;
828 ip6_sr_sl_t *segment_list;
829 u32 *sl_index_iterate;
830 uword *p;
831
832 if (bsid)
833 {
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100834 p = mhash_get (&sm->sr_policies_index_hash, bsid);
Pablo Camarillofb380952016-12-07 18:34:18 +0100835 if (p)
836 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
837 else
838 return -1;
839 }
840 else
841 {
842 sr_policy = pool_elt_at_index (sm->sr_policies, index);
843 if (!sr_policy)
844 return -1;
845 }
846
847 if (operation == 1) /* Add SR List to an existing SR policy */
848 {
849 /* Create the new SL */
850 segment_list =
851 create_sl (sr_policy, segments, weight, sr_policy->is_encap);
852
853 /* Create a new LB DPO */
854 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
855 update_lb (sr_policy);
856 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
857 update_replicate (sr_policy);
858 }
859 else if (operation == 2) /* Delete SR List from an existing SR policy */
860 {
861 /* Check that currently there are more than one SID list */
862 if (vec_len (sr_policy->segments_lists) == 1)
863 return -21;
864
865 /* Check that the SR list does exist and is assigned to the sr policy */
866 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
867 if (*sl_index_iterate == sl_index)
868 break;
869
870 if (*sl_index_iterate != sl_index)
871 return -22;
872
873 /* Remove the lucky SR list that is being kicked out */
874 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
875 vec_free (segment_list->segments);
876 vec_free (segment_list->rewrite);
Kris Michielsen91074432017-06-22 13:00:20 +0200877 if (!sr_policy->is_encap)
878 vec_free (segment_list->rewrite_bsid);
Pablo Camarillofb380952016-12-07 18:34:18 +0100879 pool_put_index (sm->sid_lists, sl_index);
880 vec_del1 (sr_policy->segments_lists,
881 sl_index_iterate - sr_policy->segments_lists);
882
883 /* Create a new LB DPO */
884 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
885 update_lb (sr_policy);
886 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
887 update_replicate (sr_policy);
888 }
889 else if (operation == 3) /* Modify the weight of an existing SR List */
890 {
891 /* Find the corresponding SL */
892 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
893 if (*sl_index_iterate == sl_index)
894 break;
895
896 if (*sl_index_iterate != sl_index)
897 return -32;
898
899 /* Change the weight */
900 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
901 segment_list->weight = weight;
902
903 /* Update LB */
904 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
905 update_lb (sr_policy);
906 }
907 else /* Incorrect op. */
908 return -1;
909
910 return 0;
911}
912
913/**
914 * @brief CLI for 'sr policies' command family
915 */
916static clib_error_t *
917sr_policy_command_fn (vlib_main_t * vm, unformat_input_t * input,
918 vlib_cli_command_t * cmd)
919{
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800920 ip6_sr_main_t *sm = &sr_main;
Pablo Camarillofb380952016-12-07 18:34:18 +0100921 int rv = -1;
922 char is_del = 0, is_add = 0, is_mod = 0;
923 char policy_set = 0;
924 ip6_address_t bsid, next_address;
925 u32 sr_policy_index = (u32) ~ 0, sl_index = (u32) ~ 0;
926 u32 weight = (u32) ~ 0, fib_table = (u32) ~ 0;
927 ip6_address_t *segments = 0, *this_seg;
928 u8 operation = 0;
929 char is_encap = 1;
930 char is_spray = 0;
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800931 u16 behavior = 0;
932 void *ls_plugin_mem = 0;
Pablo Camarillofb380952016-12-07 18:34:18 +0100933
934 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
935 {
936 if (!is_add && !is_mod && !is_del && unformat (input, "add"))
937 is_add = 1;
938 else if (!is_add && !is_mod && !is_del && unformat (input, "del"))
939 is_del = 1;
940 else if (!is_add && !is_mod && !is_del && unformat (input, "mod"))
941 is_mod = 1;
942 else if (!policy_set
943 && unformat (input, "bsid %U", unformat_ip6_address, &bsid))
944 policy_set = 1;
945 else if (!is_add && !policy_set
946 && unformat (input, "index %d", &sr_policy_index))
947 policy_set = 1;
948 else if (unformat (input, "weight %d", &weight));
949 else
950 if (unformat (input, "next %U", unformat_ip6_address, &next_address))
951 {
952 vec_add2 (segments, this_seg, 1);
Dave Barach178cf492018-11-13 16:34:13 -0500953 clib_memcpy_fast (this_seg->as_u8, next_address.as_u8,
954 sizeof (*this_seg));
Pablo Camarillofb380952016-12-07 18:34:18 +0100955 }
956 else if (unformat (input, "add sl"))
957 operation = 1;
958 else if (unformat (input, "del sl index %d", &sl_index))
959 operation = 2;
960 else if (unformat (input, "mod sl index %d", &sl_index))
961 operation = 3;
962 else if (fib_table == (u32) ~ 0
963 && unformat (input, "fib-table %d", &fib_table));
964 else if (unformat (input, "encap"))
965 is_encap = 1;
966 else if (unformat (input, "insert"))
967 is_encap = 0;
968 else if (unformat (input, "spray"))
969 is_spray = 1;
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -0800970 else if (!behavior && unformat (input, "behavior"))
971 {
972 sr_policy_fn_registration_t *plugin = 0, **vec_plugins = 0;
973 sr_policy_fn_registration_t **plugin_it = 0;
974
975 /* *INDENT-OFF* */
976 pool_foreach (plugin, sm->policy_plugin_functions,
977 {
978 vec_add1 (vec_plugins, plugin);
979 });
980 /* *INDENT-ON* */
981
982 vec_foreach (plugin_it, vec_plugins)
983 {
984 if (unformat
985 (input, "%U", (*plugin_it)->ls_unformat, &ls_plugin_mem))
986 {
987 behavior = (*plugin_it)->sr_policy_function_number;
988 break;
989 }
990 }
991
992 if (!behavior)
993 {
994 return clib_error_return (0, "Invalid behavior");
995 }
996 }
Pablo Camarillofb380952016-12-07 18:34:18 +0100997 else
998 break;
999 }
1000
1001 if (!is_add && !is_mod && !is_del)
1002 return clib_error_return (0, "Incorrect CLI");
1003
1004 if (!policy_set)
1005 return clib_error_return (0, "No SR policy BSID or index specified");
1006
1007 if (is_add)
1008 {
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -08001009 if (behavior && vec_len (segments) == 0)
1010 {
1011 vec_add2 (segments, this_seg, 1);
1012 clib_memset (this_seg, 0, sizeof (*this_seg));
1013 }
1014
Pablo Camarillofb380952016-12-07 18:34:18 +01001015 if (vec_len (segments) == 0)
1016 return clib_error_return (0, "No Segment List specified");
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -08001017
Pablo Camarillofb380952016-12-07 18:34:18 +01001018 rv = sr_policy_add (&bsid, segments, weight,
1019 (is_spray ? SR_POLICY_TYPE_SPRAY :
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -08001020 SR_POLICY_TYPE_DEFAULT), fib_table, is_encap,
1021 behavior, ls_plugin_mem);
1022
John Lod23d39c2018-09-13 15:08:08 -04001023 vec_free (segments);
Pablo Camarillofb380952016-12-07 18:34:18 +01001024 }
1025 else if (is_del)
1026 rv = sr_policy_del ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
1027 sr_policy_index);
1028 else if (is_mod)
1029 {
1030 if (!operation)
1031 return clib_error_return (0, "No SL modification specified");
1032 if (operation != 1 && sl_index == (u32) ~ 0)
1033 return clib_error_return (0, "No Segment List index specified");
1034 if (operation == 1 && vec_len (segments) == 0)
1035 return clib_error_return (0, "No Segment List specified");
1036 if (operation == 3 && weight == (u32) ~ 0)
1037 return clib_error_return (0, "No new weight for the SL specified");
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -08001038
Pablo Camarillofb380952016-12-07 18:34:18 +01001039 rv = sr_policy_mod ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
1040 sr_policy_index, fib_table, operation, segments,
1041 sl_index, weight);
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -08001042
1043 if (segments)
1044 vec_free (segments);
Pablo Camarillofb380952016-12-07 18:34:18 +01001045 }
1046
1047 switch (rv)
1048 {
1049 case 0:
1050 break;
1051 case 1:
1052 return 0;
1053 case -12:
1054 return clib_error_return (0,
1055 "There is already a FIB entry for the BindingSID address.\n"
1056 "The SR policy could not be created.");
1057 case -13:
1058 return clib_error_return (0, "The specified FIB table does not exist.");
1059 case -21:
1060 return clib_error_return (0,
1061 "The selected SR policy only contains ONE segment list. "
1062 "Please remove the SR policy instead");
1063 case -22:
1064 return clib_error_return (0,
1065 "Could not delete the segment list. "
1066 "It is not associated with that SR policy.");
1067 case -32:
1068 return clib_error_return (0,
1069 "Could not modify the segment list. "
1070 "The given SL is not associated with such SR policy.");
1071 default:
1072 return clib_error_return (0, "BUG: sr policy returns %d", rv);
1073 }
1074 return 0;
1075}
1076
1077/* *INDENT-OFF* */
1078VLIB_CLI_COMMAND (sr_policy_command, static) = {
1079 .path = "sr policy",
1080 .short_help = "sr policy [add||del||mod] [bsid 2001::1||index 5] "
1081 "next A:: next B:: next C:: (weight 1) (fib-table 2) (encap|insert)",
1082 .long_help =
1083 "Manipulation of SR policies.\n"
1084 "A Segment Routing policy may contain several SID lists. Each SID list has\n"
1085 "an associated weight (default 1), which will result in wECMP (uECMP).\n"
1086 "Segment Routing policies might be of type encapsulation or srh insertion\n"
1087 "Each SR policy will be associated with a unique BindingSID.\n"
1088 "A BindingSID is a locally allocated SegmentID. For every packet that arrives\n"
1089 "with IPv6_DA:BSID such traffic will be steered into the SR policy.\n"
1090 "The add command will create a SR policy with its first segment list (sl)\n"
1091 "The mod command allows you to add, remove, or modify the existing segment lists\n"
1092 "within an SR policy.\n"
1093 "The del command allows you to delete a SR policy along with all its associated\n"
1094 "SID lists.\n",
1095 .function = sr_policy_command_fn,
1096};
1097/* *INDENT-ON* */
1098
1099/**
1100 * @brief CLI to display onscreen all the SR policies
1101 */
1102static clib_error_t *
1103show_sr_policies_command_fn (vlib_main_t * vm, unformat_input_t * input,
1104 vlib_cli_command_t * cmd)
1105{
1106 ip6_sr_main_t *sm = &sr_main;
1107 u32 *sl_index;
1108 ip6_sr_sl_t *segment_list = 0;
1109 ip6_sr_policy_t *sr_policy = 0;
1110 ip6_sr_policy_t **vec_policies = 0;
1111 ip6_address_t *addr;
1112 u8 *s;
1113 int i = 0;
1114
1115 vlib_cli_output (vm, "SR policies:");
1116
1117 /* *INDENT-OFF* */
1118 pool_foreach (sr_policy, sm->sr_policies,
1119 {vec_add1 (vec_policies, sr_policy); } );
1120 /* *INDENT-ON* */
1121
1122 vec_foreach_index (i, vec_policies)
1123 {
1124 sr_policy = vec_policies[i];
1125 vlib_cli_output (vm, "[%u].-\tBSID: %U",
1126 (u32) (sr_policy - sm->sr_policies),
1127 format_ip6_address, &sr_policy->bsid);
1128 vlib_cli_output (vm, "\tBehavior: %s",
1129 (sr_policy->is_encap ? "Encapsulation" :
1130 "SRH insertion"));
1131 vlib_cli_output (vm, "\tType: %s",
1132 (sr_policy->type ==
1133 SR_POLICY_TYPE_DEFAULT ? "Default" : "Spray"));
1134 vlib_cli_output (vm, "\tFIB table: %u",
1135 (sr_policy->fib_table !=
1136 (u32) ~ 0 ? sr_policy->fib_table : 0));
1137 vlib_cli_output (vm, "\tSegment Lists:");
1138 vec_foreach (sl_index, sr_policy->segments_lists)
1139 {
1140 s = NULL;
1141 s = format (s, "\t[%u].- ", *sl_index);
1142 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
1143 s = format (s, "< ");
1144 vec_foreach (addr, segment_list->segments)
1145 {
1146 s = format (s, "%U, ", format_ip6_address, addr);
1147 }
1148 s = format (s, "\b\b > ");
1149 s = format (s, "weight: %u", segment_list->weight);
1150 vlib_cli_output (vm, " %s", s);
1151 }
1152 vlib_cli_output (vm, "-----------");
1153 }
1154 return 0;
1155}
1156
1157/* *INDENT-OFF* */
1158VLIB_CLI_COMMAND (show_sr_policies_command, static) = {
1159 .path = "show sr policies",
1160 .short_help = "show sr policies",
1161 .function = show_sr_policies_command_fn,
1162};
1163/* *INDENT-ON* */
1164
1165/*************************** SR rewrite graph node ****************************/
1166/**
1167 * @brief Trace for the SR Policy Rewrite graph node
1168 */
1169static u8 *
1170format_sr_policy_rewrite_trace (u8 * s, va_list * args)
1171{
1172 //TODO
1173 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1174 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1175 sr_policy_rewrite_trace_t *t = va_arg (*args, sr_policy_rewrite_trace_t *);
1176
1177 s = format
1178 (s, "SR-policy-rewrite: src %U dst %U",
1179 format_ip6_address, &t->src, format_ip6_address, &t->dst);
1180
1181 return s;
1182}
1183
1184/**
1185 * @brief IPv6 encapsulation processing as per RFC2473
1186 */
1187static_always_inline void
1188encaps_processing_v6 (vlib_node_runtime_t * node,
1189 vlib_buffer_t * b0,
1190 ip6_header_t * ip0, ip6_header_t * ip0_encap)
1191{
1192 u32 new_l0;
1193
1194 ip0_encap->hop_limit -= 1;
1195 new_l0 =
1196 ip0->payload_length + sizeof (ip6_header_t) +
1197 clib_net_to_host_u16 (ip0_encap->payload_length);
1198 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1199 ip0->ip_version_traffic_class_and_flow_label =
1200 ip0_encap->ip_version_traffic_class_and_flow_label;
1201}
1202
1203/**
1204 * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
1205 */
1206static uword
1207sr_policy_rewrite_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
1208 vlib_frame_t * from_frame)
1209{
1210 ip6_sr_main_t *sm = &sr_main;
1211 u32 n_left_from, next_index, *from, *to_next;
1212
1213 from = vlib_frame_vector_args (from_frame);
1214 n_left_from = from_frame->n_vectors;
1215
1216 next_index = node->cached_next_index;
1217
1218 int encap_pkts = 0, bsid_pkts = 0;
1219
1220 while (n_left_from > 0)
1221 {
1222 u32 n_left_to_next;
1223
1224 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1225
1226 /* Quad - Loop */
1227 while (n_left_from >= 8 && n_left_to_next >= 4)
1228 {
1229 u32 bi0, bi1, bi2, bi3;
1230 vlib_buffer_t *b0, *b1, *b2, *b3;
1231 u32 next0, next1, next2, next3;
1232 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1233 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1234 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1235 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1236
1237 /* Prefetch next iteration. */
1238 {
1239 vlib_buffer_t *p4, *p5, *p6, *p7;
1240
1241 p4 = vlib_get_buffer (vm, from[4]);
1242 p5 = vlib_get_buffer (vm, from[5]);
1243 p6 = vlib_get_buffer (vm, from[6]);
1244 p7 = vlib_get_buffer (vm, from[7]);
1245
1246 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1247 vlib_prefetch_buffer_header (p4, LOAD);
1248 vlib_prefetch_buffer_header (p5, LOAD);
1249 vlib_prefetch_buffer_header (p6, LOAD);
1250 vlib_prefetch_buffer_header (p7, LOAD);
1251
1252 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1253 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1254 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1255 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1256 }
1257
1258 to_next[0] = bi0 = from[0];
1259 to_next[1] = bi1 = from[1];
1260 to_next[2] = bi2 = from[2];
1261 to_next[3] = bi3 = from[3];
1262 from += 4;
1263 to_next += 4;
1264 n_left_from -= 4;
1265 n_left_to_next -= 4;
1266
1267 b0 = vlib_get_buffer (vm, bi0);
1268 b1 = vlib_get_buffer (vm, bi1);
1269 b2 = vlib_get_buffer (vm, bi2);
1270 b3 = vlib_get_buffer (vm, bi3);
1271
1272 sl0 =
1273 pool_elt_at_index (sm->sid_lists,
1274 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1275 sl1 =
1276 pool_elt_at_index (sm->sid_lists,
1277 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1278 sl2 =
1279 pool_elt_at_index (sm->sid_lists,
1280 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1281 sl3 =
1282 pool_elt_at_index (sm->sid_lists,
1283 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1284
shwethabe146f132017-03-09 16:58:26 +00001285 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1286 vec_len (sl0->rewrite));
1287 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1288 vec_len (sl1->rewrite));
1289 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1290 vec_len (sl2->rewrite));
1291 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1292 vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001293
1294 ip0_encap = vlib_buffer_get_current (b0);
1295 ip1_encap = vlib_buffer_get_current (b1);
1296 ip2_encap = vlib_buffer_get_current (b2);
1297 ip3_encap = vlib_buffer_get_current (b3);
1298
Dave Barach178cf492018-11-13 16:34:13 -05001299 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1300 sl0->rewrite, vec_len (sl0->rewrite));
1301 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1302 sl1->rewrite, vec_len (sl1->rewrite));
1303 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1304 sl2->rewrite, vec_len (sl2->rewrite));
1305 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1306 sl3->rewrite, vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001307
1308 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1309 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1310 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1311 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1312
1313 ip0 = vlib_buffer_get_current (b0);
1314 ip1 = vlib_buffer_get_current (b1);
1315 ip2 = vlib_buffer_get_current (b2);
1316 ip3 = vlib_buffer_get_current (b3);
1317
1318 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1319 encaps_processing_v6 (node, b1, ip1, ip1_encap);
1320 encaps_processing_v6 (node, b2, ip2, ip2_encap);
1321 encaps_processing_v6 (node, b3, ip3, ip3_encap);
1322
1323 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1324 {
1325 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1326 {
1327 sr_policy_rewrite_trace_t *tr =
1328 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001329 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1330 sizeof (tr->src.as_u8));
1331 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1332 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001333 }
1334
1335 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1336 {
1337 sr_policy_rewrite_trace_t *tr =
1338 vlib_add_trace (vm, node, b1, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001339 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
1340 sizeof (tr->src.as_u8));
1341 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
1342 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001343 }
1344
1345 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1346 {
1347 sr_policy_rewrite_trace_t *tr =
1348 vlib_add_trace (vm, node, b2, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001349 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
1350 sizeof (tr->src.as_u8));
1351 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
1352 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001353 }
1354
1355 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1356 {
1357 sr_policy_rewrite_trace_t *tr =
1358 vlib_add_trace (vm, node, b3, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001359 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
1360 sizeof (tr->src.as_u8));
1361 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
1362 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001363 }
1364 }
1365
1366 encap_pkts += 4;
1367 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1368 n_left_to_next, bi0, bi1, bi2, bi3,
1369 next0, next1, next2, next3);
1370 }
1371
1372 /* Single loop for potentially the last three packets */
1373 while (n_left_from > 0 && n_left_to_next > 0)
1374 {
1375 u32 bi0;
1376 vlib_buffer_t *b0;
1377 ip6_header_t *ip0 = 0, *ip0_encap = 0;
1378 ip6_sr_sl_t *sl0;
1379 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1380
1381 bi0 = from[0];
1382 to_next[0] = bi0;
1383 from += 1;
1384 to_next += 1;
1385 n_left_from -= 1;
1386 n_left_to_next -= 1;
1387 b0 = vlib_get_buffer (vm, bi0);
1388
1389 sl0 =
1390 pool_elt_at_index (sm->sid_lists,
1391 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00001392 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1393 vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001394
1395 ip0_encap = vlib_buffer_get_current (b0);
1396
Dave Barach178cf492018-11-13 16:34:13 -05001397 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1398 sl0->rewrite, vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001399 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1400
1401 ip0 = vlib_buffer_get_current (b0);
1402
1403 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1404
1405 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1406 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1407 {
1408 sr_policy_rewrite_trace_t *tr =
1409 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001410 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1411 sizeof (tr->src.as_u8));
1412 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1413 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001414 }
1415
1416 encap_pkts++;
1417 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1418 n_left_to_next, bi0, next0);
1419 }
1420
1421 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1422 }
1423
1424 /* Update counters */
1425 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1426 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1427 encap_pkts);
1428 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1429 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1430 bsid_pkts);
1431
1432 return from_frame->n_vectors;
1433}
1434
1435/* *INDENT-OFF* */
1436VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_node) = {
1437 .function = sr_policy_rewrite_encaps,
1438 .name = "sr-pl-rewrite-encaps",
1439 .vector_size = sizeof (u32),
1440 .format_trace = format_sr_policy_rewrite_trace,
1441 .type = VLIB_NODE_TYPE_INTERNAL,
1442 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1443 .error_strings = sr_policy_rewrite_error_strings,
1444 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1445 .next_nodes = {
1446#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1447 foreach_sr_policy_rewrite_next
1448#undef _
1449 },
1450};
1451/* *INDENT-ON* */
1452
1453/**
1454 * @brief IPv4 encapsulation processing as per RFC2473
1455 */
1456static_always_inline void
1457encaps_processing_v4 (vlib_node_runtime_t * node,
1458 vlib_buffer_t * b0,
1459 ip6_header_t * ip0, ip4_header_t * ip0_encap)
1460{
1461 u32 new_l0;
1462 ip6_sr_header_t *sr0;
1463
1464 u32 checksum0;
1465
1466 /* Inner IPv4: Decrement TTL & update checksum */
1467 ip0_encap->ttl -= 1;
1468 checksum0 = ip0_encap->checksum + clib_host_to_net_u16 (0x0100);
1469 checksum0 += checksum0 >= 0xffff;
1470 ip0_encap->checksum = checksum0;
1471
1472 /* Outer IPv6: Update length, FL, proto */
1473 new_l0 = ip0->payload_length + clib_net_to_host_u16 (ip0_encap->length);
1474 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1475 ip0->ip_version_traffic_class_and_flow_label =
1476 clib_host_to_net_u32 (0 | ((6 & 0xF) << 28) |
1477 ((ip0_encap->tos & 0xFF) << 20));
Pablo Camarillod327c872018-01-08 14:25:55 +01001478 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
1479 {
1480 sr0 = (void *) (ip0 + 1);
1481 sr0->protocol = IP_PROTOCOL_IP_IN_IP;
1482 }
1483 else
1484 ip0->protocol = IP_PROTOCOL_IP_IN_IP;
Pablo Camarillofb380952016-12-07 18:34:18 +01001485}
1486
1487/**
1488 * @brief Graph node for applying a SR policy into an IPv4 packet. Encapsulation
1489 */
1490static uword
1491sr_policy_rewrite_encaps_v4 (vlib_main_t * vm, vlib_node_runtime_t * node,
1492 vlib_frame_t * from_frame)
1493{
1494 ip6_sr_main_t *sm = &sr_main;
1495 u32 n_left_from, next_index, *from, *to_next;
1496
1497 from = vlib_frame_vector_args (from_frame);
1498 n_left_from = from_frame->n_vectors;
1499
1500 next_index = node->cached_next_index;
1501
1502 int encap_pkts = 0, bsid_pkts = 0;
1503
1504 while (n_left_from > 0)
1505 {
1506 u32 n_left_to_next;
1507
1508 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1509
1510 /* Quad - Loop */
1511 while (n_left_from >= 8 && n_left_to_next >= 4)
1512 {
1513 u32 bi0, bi1, bi2, bi3;
1514 vlib_buffer_t *b0, *b1, *b2, *b3;
1515 u32 next0, next1, next2, next3;
1516 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1517 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1518 ip4_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1519 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1520
1521 /* Prefetch next iteration. */
1522 {
1523 vlib_buffer_t *p4, *p5, *p6, *p7;
1524
1525 p4 = vlib_get_buffer (vm, from[4]);
1526 p5 = vlib_get_buffer (vm, from[5]);
1527 p6 = vlib_get_buffer (vm, from[6]);
1528 p7 = vlib_get_buffer (vm, from[7]);
1529
1530 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1531 vlib_prefetch_buffer_header (p4, LOAD);
1532 vlib_prefetch_buffer_header (p5, LOAD);
1533 vlib_prefetch_buffer_header (p6, LOAD);
1534 vlib_prefetch_buffer_header (p7, LOAD);
1535
1536 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1537 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1538 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1539 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1540 }
1541
1542 to_next[0] = bi0 = from[0];
1543 to_next[1] = bi1 = from[1];
1544 to_next[2] = bi2 = from[2];
1545 to_next[3] = bi3 = from[3];
1546 from += 4;
1547 to_next += 4;
1548 n_left_from -= 4;
1549 n_left_to_next -= 4;
1550
1551 b0 = vlib_get_buffer (vm, bi0);
1552 b1 = vlib_get_buffer (vm, bi1);
1553 b2 = vlib_get_buffer (vm, bi2);
1554 b3 = vlib_get_buffer (vm, bi3);
1555
1556 sl0 =
1557 pool_elt_at_index (sm->sid_lists,
1558 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1559 sl1 =
1560 pool_elt_at_index (sm->sid_lists,
1561 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1562 sl2 =
1563 pool_elt_at_index (sm->sid_lists,
1564 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1565 sl3 =
1566 pool_elt_at_index (sm->sid_lists,
1567 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00001568 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1569 vec_len (sl0->rewrite));
1570 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1571 vec_len (sl1->rewrite));
1572 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1573 vec_len (sl2->rewrite));
1574 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1575 vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001576
1577 ip0_encap = vlib_buffer_get_current (b0);
1578 ip1_encap = vlib_buffer_get_current (b1);
1579 ip2_encap = vlib_buffer_get_current (b2);
1580 ip3_encap = vlib_buffer_get_current (b3);
1581
Dave Barach178cf492018-11-13 16:34:13 -05001582 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1583 sl0->rewrite, vec_len (sl0->rewrite));
1584 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1585 sl1->rewrite, vec_len (sl1->rewrite));
1586 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1587 sl2->rewrite, vec_len (sl2->rewrite));
1588 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1589 sl3->rewrite, vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001590
1591 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1592 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1593 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1594 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1595
1596 ip0 = vlib_buffer_get_current (b0);
1597 ip1 = vlib_buffer_get_current (b1);
1598 ip2 = vlib_buffer_get_current (b2);
1599 ip3 = vlib_buffer_get_current (b3);
1600
1601 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1602 encaps_processing_v4 (node, b1, ip1, ip1_encap);
1603 encaps_processing_v4 (node, b2, ip2, ip2_encap);
1604 encaps_processing_v4 (node, b3, ip3, ip3_encap);
1605
1606 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1607 {
1608 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1609 {
1610 sr_policy_rewrite_trace_t *tr =
1611 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001612 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1613 sizeof (tr->src.as_u8));
1614 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1615 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001616 }
1617
1618 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1619 {
1620 sr_policy_rewrite_trace_t *tr =
1621 vlib_add_trace (vm, node, b1, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001622 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
1623 sizeof (tr->src.as_u8));
1624 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
1625 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001626 }
1627
1628 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1629 {
1630 sr_policy_rewrite_trace_t *tr =
1631 vlib_add_trace (vm, node, b2, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001632 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
1633 sizeof (tr->src.as_u8));
1634 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
1635 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001636 }
1637
1638 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1639 {
1640 sr_policy_rewrite_trace_t *tr =
1641 vlib_add_trace (vm, node, b3, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001642 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
1643 sizeof (tr->src.as_u8));
1644 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
1645 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001646 }
1647 }
1648
1649 encap_pkts += 4;
1650 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1651 n_left_to_next, bi0, bi1, bi2, bi3,
1652 next0, next1, next2, next3);
1653 }
1654
1655 /* Single loop for potentially the last three packets */
1656 while (n_left_from > 0 && n_left_to_next > 0)
1657 {
1658 u32 bi0;
1659 vlib_buffer_t *b0;
1660 ip6_header_t *ip0 = 0;
1661 ip4_header_t *ip0_encap = 0;
1662 ip6_sr_sl_t *sl0;
1663 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1664
1665 bi0 = from[0];
1666 to_next[0] = bi0;
1667 from += 1;
1668 to_next += 1;
1669 n_left_from -= 1;
1670 n_left_to_next -= 1;
1671 b0 = vlib_get_buffer (vm, bi0);
1672
1673 sl0 =
1674 pool_elt_at_index (sm->sid_lists,
1675 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00001676 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1677 vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001678
1679 ip0_encap = vlib_buffer_get_current (b0);
1680
Dave Barach178cf492018-11-13 16:34:13 -05001681 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1682 sl0->rewrite, vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001683 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1684
1685 ip0 = vlib_buffer_get_current (b0);
1686
1687 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1688
1689 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1690 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1691 {
1692 sr_policy_rewrite_trace_t *tr =
1693 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05001694 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1695 sizeof (tr->src.as_u8));
1696 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1697 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01001698 }
1699
1700 encap_pkts++;
1701 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1702 n_left_to_next, bi0, next0);
1703 }
1704
1705 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1706 }
1707
1708 /* Update counters */
1709 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1710 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1711 encap_pkts);
1712 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1713 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1714 bsid_pkts);
1715
1716 return from_frame->n_vectors;
1717}
1718
1719/* *INDENT-OFF* */
1720VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_v4_node) = {
1721 .function = sr_policy_rewrite_encaps_v4,
1722 .name = "sr-pl-rewrite-encaps-v4",
1723 .vector_size = sizeof (u32),
1724 .format_trace = format_sr_policy_rewrite_trace,
1725 .type = VLIB_NODE_TYPE_INTERNAL,
1726 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1727 .error_strings = sr_policy_rewrite_error_strings,
1728 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1729 .next_nodes = {
1730#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1731 foreach_sr_policy_rewrite_next
1732#undef _
1733 },
1734};
1735/* *INDENT-ON* */
1736
1737always_inline u32
1738ip_flow_hash (void *data)
1739{
1740 ip4_header_t *iph = (ip4_header_t *) data;
1741
1742 if ((iph->ip_version_and_header_length & 0xF0) == 0x40)
1743 return ip4_compute_flow_hash (iph, IP_FLOW_HASH_DEFAULT);
1744 else
1745 return ip6_compute_flow_hash ((ip6_header_t *) iph, IP_FLOW_HASH_DEFAULT);
1746}
1747
1748always_inline u64
1749mac_to_u64 (u8 * m)
1750{
1751 return (*((u64 *) m) & 0xffffffffffff);
1752}
1753
1754always_inline u32
1755l2_flow_hash (vlib_buffer_t * b0)
1756{
1757 ethernet_header_t *eh;
1758 u64 a, b, c;
1759 uword is_ip, eh_size;
1760 u16 eh_type;
1761
1762 eh = vlib_buffer_get_current (b0);
1763 eh_type = clib_net_to_host_u16 (eh->type);
1764 eh_size = ethernet_buffer_header_size (b0);
1765
1766 is_ip = (eh_type == ETHERNET_TYPE_IP4 || eh_type == ETHERNET_TYPE_IP6);
1767
1768 /* since we have 2 cache lines, use them */
1769 if (is_ip)
1770 a = ip_flow_hash ((u8 *) vlib_buffer_get_current (b0) + eh_size);
1771 else
1772 a = eh->type;
1773
1774 b = mac_to_u64 ((u8 *) eh->dst_address);
1775 c = mac_to_u64 ((u8 *) eh->src_address);
1776 hash_mix64 (a, b, c);
1777
1778 return (u32) c;
1779}
1780
1781/**
1782 * @brief Graph node for applying a SR policy into a L2 frame
1783 */
1784static uword
1785sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
1786 vlib_frame_t * from_frame)
1787{
1788 ip6_sr_main_t *sm = &sr_main;
1789 u32 n_left_from, next_index, *from, *to_next;
1790
1791 from = vlib_frame_vector_args (from_frame);
1792 n_left_from = from_frame->n_vectors;
1793
1794 next_index = node->cached_next_index;
1795
1796 int encap_pkts = 0, bsid_pkts = 0;
1797
1798 while (n_left_from > 0)
1799 {
1800 u32 n_left_to_next;
1801
1802 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1803
1804 /* Quad - Loop */
1805 while (n_left_from >= 8 && n_left_to_next >= 4)
1806 {
1807 u32 bi0, bi1, bi2, bi3;
1808 vlib_buffer_t *b0, *b1, *b2, *b3;
1809 u32 next0, next1, next2, next3;
1810 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1811 ethernet_header_t *en0, *en1, *en2, *en3;
1812 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1813 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1814 ip6_sr_policy_t *sp0, *sp1, *sp2, *sp3;
1815 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1816
1817 /* Prefetch next iteration. */
1818 {
1819 vlib_buffer_t *p4, *p5, *p6, *p7;
1820
1821 p4 = vlib_get_buffer (vm, from[4]);
1822 p5 = vlib_get_buffer (vm, from[5]);
1823 p6 = vlib_get_buffer (vm, from[6]);
1824 p7 = vlib_get_buffer (vm, from[7]);
1825
1826 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1827 vlib_prefetch_buffer_header (p4, LOAD);
1828 vlib_prefetch_buffer_header (p5, LOAD);
1829 vlib_prefetch_buffer_header (p6, LOAD);
1830 vlib_prefetch_buffer_header (p7, LOAD);
1831
1832 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1833 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1834 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1835 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1836 }
1837
1838 to_next[0] = bi0 = from[0];
1839 to_next[1] = bi1 = from[1];
1840 to_next[2] = bi2 = from[2];
1841 to_next[3] = bi3 = from[3];
1842 from += 4;
1843 to_next += 4;
1844 n_left_from -= 4;
1845 n_left_to_next -= 4;
1846
1847 b0 = vlib_get_buffer (vm, bi0);
1848 b1 = vlib_get_buffer (vm, bi1);
1849 b2 = vlib_get_buffer (vm, bi2);
1850 b3 = vlib_get_buffer (vm, bi3);
1851
1852 sp0 = pool_elt_at_index (sm->sr_policies,
1853 sm->sw_iface_sr_policies[vnet_buffer
1854 (b0)->sw_if_index
1855 [VLIB_RX]]);
1856
1857 sp1 = pool_elt_at_index (sm->sr_policies,
1858 sm->sw_iface_sr_policies[vnet_buffer
1859 (b1)->sw_if_index
1860 [VLIB_RX]]);
1861
1862 sp2 = pool_elt_at_index (sm->sr_policies,
1863 sm->sw_iface_sr_policies[vnet_buffer
1864 (b2)->sw_if_index
1865 [VLIB_RX]]);
1866
1867 sp3 = pool_elt_at_index (sm->sr_policies,
1868 sm->sw_iface_sr_policies[vnet_buffer
1869 (b3)->sw_if_index
1870 [VLIB_RX]]);
1871
1872 if (vec_len (sp0->segments_lists) == 1)
1873 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1874 else
1875 {
1876 vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
1877 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1878 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1879 (vec_len (sp0->segments_lists) - 1))];
1880 }
1881
1882 if (vec_len (sp1->segments_lists) == 1)
1883 vnet_buffer (b1)->ip.adj_index[VLIB_TX] = sp1->segments_lists[1];
1884 else
1885 {
1886 vnet_buffer (b1)->ip.flow_hash = l2_flow_hash (b1);
1887 vnet_buffer (b1)->ip.adj_index[VLIB_TX] =
1888 sp1->segments_lists[(vnet_buffer (b1)->ip.flow_hash &
1889 (vec_len (sp1->segments_lists) - 1))];
1890 }
1891
1892 if (vec_len (sp2->segments_lists) == 1)
1893 vnet_buffer (b2)->ip.adj_index[VLIB_TX] = sp2->segments_lists[2];
1894 else
1895 {
1896 vnet_buffer (b2)->ip.flow_hash = l2_flow_hash (b2);
1897 vnet_buffer (b2)->ip.adj_index[VLIB_TX] =
1898 sp2->segments_lists[(vnet_buffer (b2)->ip.flow_hash &
1899 (vec_len (sp2->segments_lists) - 1))];
1900 }
1901
1902 if (vec_len (sp3->segments_lists) == 1)
1903 vnet_buffer (b3)->ip.adj_index[VLIB_TX] = sp3->segments_lists[3];
1904 else
1905 {
1906 vnet_buffer (b3)->ip.flow_hash = l2_flow_hash (b3);
1907 vnet_buffer (b3)->ip.adj_index[VLIB_TX] =
1908 sp3->segments_lists[(vnet_buffer (b3)->ip.flow_hash &
1909 (vec_len (sp3->segments_lists) - 1))];
1910 }
1911
1912 sl0 =
1913 pool_elt_at_index (sm->sid_lists,
1914 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1915 sl1 =
1916 pool_elt_at_index (sm->sid_lists,
1917 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1918 sl2 =
1919 pool_elt_at_index (sm->sid_lists,
1920 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1921 sl3 =
1922 pool_elt_at_index (sm->sid_lists,
1923 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1924
shwethabe146f132017-03-09 16:58:26 +00001925 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1926 vec_len (sl0->rewrite));
1927 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1928 vec_len (sl1->rewrite));
1929 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1930 vec_len (sl2->rewrite));
1931 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1932 vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001933
1934 en0 = vlib_buffer_get_current (b0);
1935 en1 = vlib_buffer_get_current (b1);
1936 en2 = vlib_buffer_get_current (b2);
1937 en3 = vlib_buffer_get_current (b3);
1938
Dave Barach178cf492018-11-13 16:34:13 -05001939 clib_memcpy_fast (((u8 *) en0) - vec_len (sl0->rewrite),
1940 sl0->rewrite, vec_len (sl0->rewrite));
1941 clib_memcpy_fast (((u8 *) en1) - vec_len (sl1->rewrite),
1942 sl1->rewrite, vec_len (sl1->rewrite));
1943 clib_memcpy_fast (((u8 *) en2) - vec_len (sl2->rewrite),
1944 sl2->rewrite, vec_len (sl2->rewrite));
1945 clib_memcpy_fast (((u8 *) en3) - vec_len (sl3->rewrite),
1946 sl3->rewrite, vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001947
1948 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1949 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1950 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1951 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1952
1953 ip0 = vlib_buffer_get_current (b0);
1954 ip1 = vlib_buffer_get_current (b1);
1955 ip2 = vlib_buffer_get_current (b2);
1956 ip3 = vlib_buffer_get_current (b3);
1957
1958 ip0->payload_length =
1959 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
1960 ip1->payload_length =
1961 clib_host_to_net_u16 (b1->current_length - sizeof (ip6_header_t));
1962 ip2->payload_length =
1963 clib_host_to_net_u16 (b2->current_length - sizeof (ip6_header_t));
1964 ip3->payload_length =
1965 clib_host_to_net_u16 (b3->current_length - sizeof (ip6_header_t));
1966
Pablo Camarillod327c872018-01-08 14:25:55 +01001967 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
1968 {
1969 sr0 = (void *) (ip0 + 1);
pcamaril30e76712020-02-04 08:36:51 +01001970 sr0->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01001971 }
1972 else
pcamaril30e76712020-02-04 08:36:51 +01001973 ip0->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillofb380952016-12-07 18:34:18 +01001974
Pablo Camarillod327c872018-01-08 14:25:55 +01001975 if (ip1->protocol == IP_PROTOCOL_IPV6_ROUTE)
1976 {
1977 sr1 = (void *) (ip1 + 1);
pcamaril30e76712020-02-04 08:36:51 +01001978 sr1->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01001979 }
1980 else
pcamaril30e76712020-02-04 08:36:51 +01001981 ip1->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01001982
1983 if (ip2->protocol == IP_PROTOCOL_IPV6_ROUTE)
1984 {
1985 sr2 = (void *) (ip2 + 1);
pcamaril30e76712020-02-04 08:36:51 +01001986 sr2->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01001987 }
1988 else
pcamaril30e76712020-02-04 08:36:51 +01001989 ip2->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01001990
1991 if (ip3->protocol == IP_PROTOCOL_IPV6_ROUTE)
1992 {
1993 sr3 = (void *) (ip3 + 1);
pcamaril30e76712020-02-04 08:36:51 +01001994 sr3->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01001995 }
1996 else
pcamaril30e76712020-02-04 08:36:51 +01001997 ip3->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillofb380952016-12-07 18:34:18 +01001998
1999 /* Which Traffic class and flow label do I set ? */
2000 //ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32(0|((6&0xF)<<28)|((ip0_encap->tos&0xFF)<<20));
2001
2002 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2003 {
2004 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2005 {
2006 sr_policy_rewrite_trace_t *tr =
2007 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002008 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2009 sizeof (tr->src.as_u8));
2010 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2011 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002012 }
2013
2014 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2015 {
2016 sr_policy_rewrite_trace_t *tr =
2017 vlib_add_trace (vm, node, b1, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002018 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2019 sizeof (tr->src.as_u8));
2020 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2021 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002022 }
2023
2024 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2025 {
2026 sr_policy_rewrite_trace_t *tr =
2027 vlib_add_trace (vm, node, b2, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002028 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2029 sizeof (tr->src.as_u8));
2030 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2031 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002032 }
2033
2034 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2035 {
2036 sr_policy_rewrite_trace_t *tr =
2037 vlib_add_trace (vm, node, b3, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002038 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2039 sizeof (tr->src.as_u8));
2040 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2041 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002042 }
2043 }
2044
2045 encap_pkts += 4;
2046 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2047 n_left_to_next, bi0, bi1, bi2, bi3,
2048 next0, next1, next2, next3);
2049 }
2050
2051 /* Single loop for potentially the last three packets */
2052 while (n_left_from > 0 && n_left_to_next > 0)
2053 {
2054 u32 bi0;
2055 vlib_buffer_t *b0;
2056 ip6_header_t *ip0 = 0;
2057 ip6_sr_header_t *sr0;
2058 ethernet_header_t *en0;
2059 ip6_sr_policy_t *sp0;
2060 ip6_sr_sl_t *sl0;
2061 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2062
2063 bi0 = from[0];
2064 to_next[0] = bi0;
2065 from += 1;
2066 to_next += 1;
2067 n_left_from -= 1;
2068 n_left_to_next -= 1;
2069 b0 = vlib_get_buffer (vm, bi0);
2070
2071 /* Find the SR policy */
2072 sp0 = pool_elt_at_index (sm->sr_policies,
2073 sm->sw_iface_sr_policies[vnet_buffer
2074 (b0)->sw_if_index
2075 [VLIB_RX]]);
2076
2077 /* In case there is more than one SL, LB among them */
2078 if (vec_len (sp0->segments_lists) == 1)
2079 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
2080 else
2081 {
2082 vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
2083 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
2084 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
2085 (vec_len (sp0->segments_lists) - 1))];
2086 }
2087 sl0 =
2088 pool_elt_at_index (sm->sid_lists,
2089 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00002090 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2091 vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002092
2093 en0 = vlib_buffer_get_current (b0);
2094
Dave Barach178cf492018-11-13 16:34:13 -05002095 clib_memcpy_fast (((u8 *) en0) - vec_len (sl0->rewrite),
2096 sl0->rewrite, vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002097
2098 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2099
2100 ip0 = vlib_buffer_get_current (b0);
2101
2102 ip0->payload_length =
2103 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
2104
Pablo Camarillod327c872018-01-08 14:25:55 +01002105 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
2106 {
2107 sr0 = (void *) (ip0 + 1);
pcamaril30e76712020-02-04 08:36:51 +01002108 sr0->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillod327c872018-01-08 14:25:55 +01002109 }
2110 else
pcamaril30e76712020-02-04 08:36:51 +01002111 ip0->protocol = IP_PROTOCOL_IP6_ETHERNET;
Pablo Camarillofb380952016-12-07 18:34:18 +01002112
2113 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2114 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2115 {
2116 sr_policy_rewrite_trace_t *tr =
2117 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002118 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2119 sizeof (tr->src.as_u8));
2120 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2121 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002122 }
2123
2124 encap_pkts++;
2125 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2126 n_left_to_next, bi0, next0);
2127 }
2128
2129 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2130 }
2131
2132 /* Update counters */
2133 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
2134 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2135 encap_pkts);
2136 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
2137 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2138 bsid_pkts);
2139
2140 return from_frame->n_vectors;
2141}
2142
2143/* *INDENT-OFF* */
2144VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_l2_node) = {
2145 .function = sr_policy_rewrite_encaps_l2,
2146 .name = "sr-pl-rewrite-encaps-l2",
2147 .vector_size = sizeof (u32),
2148 .format_trace = format_sr_policy_rewrite_trace,
2149 .type = VLIB_NODE_TYPE_INTERNAL,
2150 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2151 .error_strings = sr_policy_rewrite_error_strings,
2152 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2153 .next_nodes = {
2154#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2155 foreach_sr_policy_rewrite_next
2156#undef _
2157 },
2158};
2159/* *INDENT-ON* */
2160
2161/**
2162 * @brief Graph node for applying a SR policy into a packet. SRH insertion.
2163 */
2164static uword
2165sr_policy_rewrite_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2166 vlib_frame_t * from_frame)
2167{
2168 ip6_sr_main_t *sm = &sr_main;
2169 u32 n_left_from, next_index, *from, *to_next;
2170
2171 from = vlib_frame_vector_args (from_frame);
2172 n_left_from = from_frame->n_vectors;
2173
2174 next_index = node->cached_next_index;
2175
2176 int insert_pkts = 0, bsid_pkts = 0;
2177
2178 while (n_left_from > 0)
2179 {
2180 u32 n_left_to_next;
2181
2182 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2183
2184 /* Quad - Loop */
2185 while (n_left_from >= 8 && n_left_to_next >= 4)
2186 {
2187 u32 bi0, bi1, bi2, bi3;
2188 vlib_buffer_t *b0, *b1, *b2, *b3;
2189 u32 next0, next1, next2, next3;
2190 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2191 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2192 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2193 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2194 u16 new_l0, new_l1, new_l2, new_l3;
2195
2196 /* Prefetch next iteration. */
2197 {
2198 vlib_buffer_t *p4, *p5, *p6, *p7;
2199
2200 p4 = vlib_get_buffer (vm, from[4]);
2201 p5 = vlib_get_buffer (vm, from[5]);
2202 p6 = vlib_get_buffer (vm, from[6]);
2203 p7 = vlib_get_buffer (vm, from[7]);
2204
2205 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2206 vlib_prefetch_buffer_header (p4, LOAD);
2207 vlib_prefetch_buffer_header (p5, LOAD);
2208 vlib_prefetch_buffer_header (p6, LOAD);
2209 vlib_prefetch_buffer_header (p7, LOAD);
2210
2211 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2212 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2213 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2214 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2215 }
2216
2217 to_next[0] = bi0 = from[0];
2218 to_next[1] = bi1 = from[1];
2219 to_next[2] = bi2 = from[2];
2220 to_next[3] = bi3 = from[3];
2221 from += 4;
2222 to_next += 4;
2223 n_left_from -= 4;
2224 n_left_to_next -= 4;
2225
2226 b0 = vlib_get_buffer (vm, bi0);
2227 b1 = vlib_get_buffer (vm, bi1);
2228 b2 = vlib_get_buffer (vm, bi2);
2229 b3 = vlib_get_buffer (vm, bi3);
2230
2231 sl0 =
2232 pool_elt_at_index (sm->sid_lists,
2233 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2234 sl1 =
2235 pool_elt_at_index (sm->sid_lists,
2236 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2237 sl2 =
2238 pool_elt_at_index (sm->sid_lists,
2239 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2240 sl3 =
2241 pool_elt_at_index (sm->sid_lists,
2242 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00002243 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2244 vec_len (sl0->rewrite));
2245 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2246 vec_len (sl1->rewrite));
2247 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2248 vec_len (sl2->rewrite));
2249 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2250 vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002251
2252 ip0 = vlib_buffer_get_current (b0);
2253 ip1 = vlib_buffer_get_current (b1);
2254 ip2 = vlib_buffer_get_current (b2);
2255 ip3 = vlib_buffer_get_current (b3);
2256
2257 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2258 sr0 =
2259 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2260 ip6_ext_header_len (ip0 + 1));
2261 else
2262 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2263
2264 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2265 sr1 =
2266 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2267 ip6_ext_header_len (ip1 + 1));
2268 else
2269 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2270
2271 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2272 sr2 =
2273 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2274 ip6_ext_header_len (ip2 + 1));
2275 else
2276 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2277
2278 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2279 sr3 =
2280 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2281 ip6_ext_header_len (ip3 + 1));
2282 else
2283 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2284
Dave Barach178cf492018-11-13 16:34:13 -05002285 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2286 (void *) sr0 - (void *) ip0);
2287 clib_memcpy_fast ((u8 *) ip1 - vec_len (sl1->rewrite), (u8 *) ip1,
2288 (void *) sr1 - (void *) ip1);
2289 clib_memcpy_fast ((u8 *) ip2 - vec_len (sl2->rewrite), (u8 *) ip2,
2290 (void *) sr2 - (void *) ip2);
2291 clib_memcpy_fast ((u8 *) ip3 - vec_len (sl3->rewrite), (u8 *) ip3,
2292 (void *) sr3 - (void *) ip3);
Pablo Camarillofb380952016-12-07 18:34:18 +01002293
Dave Barach178cf492018-11-13 16:34:13 -05002294 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite)),
2295 sl0->rewrite, vec_len (sl0->rewrite));
2296 clib_memcpy_fast (((u8 *) sr1 - vec_len (sl1->rewrite)),
2297 sl1->rewrite, vec_len (sl1->rewrite));
2298 clib_memcpy_fast (((u8 *) sr2 - vec_len (sl2->rewrite)),
2299 sl2->rewrite, vec_len (sl2->rewrite));
2300 clib_memcpy_fast (((u8 *) sr3 - vec_len (sl3->rewrite)),
2301 sl3->rewrite, vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002302
2303 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2304 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2305 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2306 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2307
2308 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2309 ip1 = ((void *) ip1) - vec_len (sl1->rewrite);
2310 ip2 = ((void *) ip2) - vec_len (sl2->rewrite);
2311 ip3 = ((void *) ip3) - vec_len (sl3->rewrite);
2312
2313 ip0->hop_limit -= 1;
2314 ip1->hop_limit -= 1;
2315 ip2->hop_limit -= 1;
2316 ip3->hop_limit -= 1;
2317
2318 new_l0 =
2319 clib_net_to_host_u16 (ip0->payload_length) +
2320 vec_len (sl0->rewrite);
2321 new_l1 =
2322 clib_net_to_host_u16 (ip1->payload_length) +
2323 vec_len (sl1->rewrite);
2324 new_l2 =
2325 clib_net_to_host_u16 (ip2->payload_length) +
2326 vec_len (sl2->rewrite);
2327 new_l3 =
2328 clib_net_to_host_u16 (ip3->payload_length) +
2329 vec_len (sl3->rewrite);
2330
2331 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2332 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2333 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2334 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2335
2336 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2337 sr1 = ((void *) sr1) - vec_len (sl1->rewrite);
2338 sr2 = ((void *) sr2) - vec_len (sl2->rewrite);
2339 sr3 = ((void *) sr3) - vec_len (sl3->rewrite);
2340
2341 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2342 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2343 sr1->segments->as_u64[0] = ip1->dst_address.as_u64[0];
2344 sr1->segments->as_u64[1] = ip1->dst_address.as_u64[1];
2345 sr2->segments->as_u64[0] = ip2->dst_address.as_u64[0];
2346 sr2->segments->as_u64[1] = ip2->dst_address.as_u64[1];
2347 sr3->segments->as_u64[0] = ip3->dst_address.as_u64[0];
2348 sr3->segments->as_u64[1] = ip3->dst_address.as_u64[1];
2349
2350 ip0->dst_address.as_u64[0] =
2351 (sr0->segments + sr0->segments_left)->as_u64[0];
2352 ip0->dst_address.as_u64[1] =
2353 (sr0->segments + sr0->segments_left)->as_u64[1];
2354 ip1->dst_address.as_u64[0] =
2355 (sr1->segments + sr1->segments_left)->as_u64[0];
2356 ip1->dst_address.as_u64[1] =
2357 (sr1->segments + sr1->segments_left)->as_u64[1];
2358 ip2->dst_address.as_u64[0] =
2359 (sr2->segments + sr2->segments_left)->as_u64[0];
2360 ip2->dst_address.as_u64[1] =
2361 (sr2->segments + sr2->segments_left)->as_u64[1];
2362 ip3->dst_address.as_u64[0] =
2363 (sr3->segments + sr3->segments_left)->as_u64[0];
2364 ip3->dst_address.as_u64[1] =
2365 (sr3->segments + sr3->segments_left)->as_u64[1];
2366
2367 ip6_ext_header_t *ip_ext;
2368 if (ip0 + 1 == (void *) sr0)
2369 {
2370 sr0->protocol = ip0->protocol;
2371 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2372 }
2373 else
2374 {
2375 ip_ext = (void *) (ip0 + 1);
2376 sr0->protocol = ip_ext->next_hdr;
2377 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2378 }
2379
2380 if (ip1 + 1 == (void *) sr1)
2381 {
2382 sr1->protocol = ip1->protocol;
2383 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2384 }
2385 else
2386 {
2387 ip_ext = (void *) (ip2 + 1);
2388 sr2->protocol = ip_ext->next_hdr;
2389 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2390 }
2391
2392 if (ip2 + 1 == (void *) sr2)
2393 {
2394 sr2->protocol = ip2->protocol;
2395 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2396 }
2397 else
2398 {
2399 ip_ext = (void *) (ip2 + 1);
2400 sr2->protocol = ip_ext->next_hdr;
2401 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2402 }
2403
2404 if (ip3 + 1 == (void *) sr3)
2405 {
2406 sr3->protocol = ip3->protocol;
2407 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2408 }
2409 else
2410 {
2411 ip_ext = (void *) (ip3 + 1);
2412 sr3->protocol = ip_ext->next_hdr;
2413 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2414 }
2415
2416 insert_pkts += 4;
2417
2418 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2419 {
2420 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2421 {
2422 sr_policy_rewrite_trace_t *tr =
2423 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002424 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2425 sizeof (tr->src.as_u8));
2426 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2427 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002428 }
2429
2430 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2431 {
2432 sr_policy_rewrite_trace_t *tr =
2433 vlib_add_trace (vm, node, b1, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002434 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2435 sizeof (tr->src.as_u8));
2436 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2437 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002438 }
2439
2440 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2441 {
2442 sr_policy_rewrite_trace_t *tr =
2443 vlib_add_trace (vm, node, b2, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002444 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2445 sizeof (tr->src.as_u8));
2446 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2447 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002448 }
2449
2450 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2451 {
2452 sr_policy_rewrite_trace_t *tr =
2453 vlib_add_trace (vm, node, b3, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002454 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2455 sizeof (tr->src.as_u8));
2456 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2457 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002458 }
2459 }
2460
2461 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2462 n_left_to_next, bi0, bi1, bi2, bi3,
2463 next0, next1, next2, next3);
2464 }
2465
2466 /* Single loop for potentially the last three packets */
2467 while (n_left_from > 0 && n_left_to_next > 0)
2468 {
2469 u32 bi0;
2470 vlib_buffer_t *b0;
2471 ip6_header_t *ip0 = 0;
2472 ip6_sr_header_t *sr0 = 0;
2473 ip6_sr_sl_t *sl0;
2474 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2475 u16 new_l0 = 0;
2476
2477 bi0 = from[0];
2478 to_next[0] = bi0;
2479 from += 1;
2480 to_next += 1;
2481 n_left_from -= 1;
2482 n_left_to_next -= 1;
2483
2484 b0 = vlib_get_buffer (vm, bi0);
2485 sl0 =
2486 pool_elt_at_index (sm->sid_lists,
2487 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00002488 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2489 vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002490
2491 ip0 = vlib_buffer_get_current (b0);
2492
2493 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2494 sr0 =
2495 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2496 ip6_ext_header_len (ip0 + 1));
2497 else
2498 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2499
Dave Barach178cf492018-11-13 16:34:13 -05002500 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2501 (void *) sr0 - (void *) ip0);
2502 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite)),
2503 sl0->rewrite, vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002504
2505 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2506
2507 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2508 ip0->hop_limit -= 1;
2509 new_l0 =
2510 clib_net_to_host_u16 (ip0->payload_length) +
2511 vec_len (sl0->rewrite);
2512 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2513
2514 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2515 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2516 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2517
2518 ip0->dst_address.as_u64[0] =
2519 (sr0->segments + sr0->segments_left)->as_u64[0];
2520 ip0->dst_address.as_u64[1] =
2521 (sr0->segments + sr0->segments_left)->as_u64[1];
2522
2523 if (ip0 + 1 == (void *) sr0)
2524 {
2525 sr0->protocol = ip0->protocol;
2526 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2527 }
2528 else
2529 {
2530 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2531 sr0->protocol = ip_ext->next_hdr;
2532 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2533 }
2534
2535 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2536 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2537 {
2538 sr_policy_rewrite_trace_t *tr =
2539 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002540 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2541 sizeof (tr->src.as_u8));
2542 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2543 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002544 }
2545
2546 insert_pkts++;
2547
2548 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2549 n_left_to_next, bi0, next0);
2550 }
2551
2552 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2553 }
2554
2555 /* Update counters */
2556 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2557 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2558 insert_pkts);
2559 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2560 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2561 bsid_pkts);
2562 return from_frame->n_vectors;
2563}
2564
2565/* *INDENT-OFF* */
2566VLIB_REGISTER_NODE (sr_policy_rewrite_insert_node) = {
2567 .function = sr_policy_rewrite_insert,
2568 .name = "sr-pl-rewrite-insert",
2569 .vector_size = sizeof (u32),
2570 .format_trace = format_sr_policy_rewrite_trace,
2571 .type = VLIB_NODE_TYPE_INTERNAL,
2572 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2573 .error_strings = sr_policy_rewrite_error_strings,
2574 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2575 .next_nodes = {
2576#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2577 foreach_sr_policy_rewrite_next
2578#undef _
2579 },
2580};
2581/* *INDENT-ON* */
2582
2583/**
2584 * @brief Graph node for applying a SR policy into a packet. BSID - SRH insertion.
2585 */
2586static uword
2587sr_policy_rewrite_b_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2588 vlib_frame_t * from_frame)
2589{
2590 ip6_sr_main_t *sm = &sr_main;
2591 u32 n_left_from, next_index, *from, *to_next;
2592
2593 from = vlib_frame_vector_args (from_frame);
2594 n_left_from = from_frame->n_vectors;
2595
2596 next_index = node->cached_next_index;
2597
2598 int insert_pkts = 0, bsid_pkts = 0;
2599
2600 while (n_left_from > 0)
2601 {
2602 u32 n_left_to_next;
2603
2604 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2605
2606 /* Quad - Loop */
2607 while (n_left_from >= 8 && n_left_to_next >= 4)
2608 {
2609 u32 bi0, bi1, bi2, bi3;
2610 vlib_buffer_t *b0, *b1, *b2, *b3;
2611 u32 next0, next1, next2, next3;
2612 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2613 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2614 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2615 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2616 u16 new_l0, new_l1, new_l2, new_l3;
2617
2618 /* Prefetch next iteration. */
2619 {
2620 vlib_buffer_t *p4, *p5, *p6, *p7;
2621
2622 p4 = vlib_get_buffer (vm, from[4]);
2623 p5 = vlib_get_buffer (vm, from[5]);
2624 p6 = vlib_get_buffer (vm, from[6]);
2625 p7 = vlib_get_buffer (vm, from[7]);
2626
2627 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2628 vlib_prefetch_buffer_header (p4, LOAD);
2629 vlib_prefetch_buffer_header (p5, LOAD);
2630 vlib_prefetch_buffer_header (p6, LOAD);
2631 vlib_prefetch_buffer_header (p7, LOAD);
2632
2633 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2634 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2635 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2636 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2637 }
2638
2639 to_next[0] = bi0 = from[0];
2640 to_next[1] = bi1 = from[1];
2641 to_next[2] = bi2 = from[2];
2642 to_next[3] = bi3 = from[3];
2643 from += 4;
2644 to_next += 4;
2645 n_left_from -= 4;
2646 n_left_to_next -= 4;
2647
2648 b0 = vlib_get_buffer (vm, bi0);
2649 b1 = vlib_get_buffer (vm, bi1);
2650 b2 = vlib_get_buffer (vm, bi2);
2651 b3 = vlib_get_buffer (vm, bi3);
2652
2653 sl0 =
2654 pool_elt_at_index (sm->sid_lists,
2655 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2656 sl1 =
2657 pool_elt_at_index (sm->sid_lists,
2658 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2659 sl2 =
2660 pool_elt_at_index (sm->sid_lists,
2661 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2662 sl3 =
2663 pool_elt_at_index (sm->sid_lists,
2664 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00002665 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2666 vec_len (sl0->rewrite_bsid));
2667 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2668 vec_len (sl1->rewrite_bsid));
2669 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2670 vec_len (sl2->rewrite_bsid));
2671 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2672 vec_len (sl3->rewrite_bsid));
Pablo Camarillofb380952016-12-07 18:34:18 +01002673
2674 ip0 = vlib_buffer_get_current (b0);
2675 ip1 = vlib_buffer_get_current (b1);
2676 ip2 = vlib_buffer_get_current (b2);
2677 ip3 = vlib_buffer_get_current (b3);
2678
2679 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2680 sr0 =
2681 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2682 ip6_ext_header_len (ip0 + 1));
2683 else
2684 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2685
2686 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2687 sr1 =
2688 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2689 ip6_ext_header_len (ip1 + 1));
2690 else
2691 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2692
2693 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2694 sr2 =
2695 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2696 ip6_ext_header_len (ip2 + 1));
2697 else
2698 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2699
2700 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2701 sr3 =
2702 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2703 ip6_ext_header_len (ip3 + 1));
2704 else
2705 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2706
Dave Barach178cf492018-11-13 16:34:13 -05002707 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite_bsid),
2708 (u8 *) ip0, (void *) sr0 - (void *) ip0);
2709 clib_memcpy_fast ((u8 *) ip1 - vec_len (sl1->rewrite_bsid),
2710 (u8 *) ip1, (void *) sr1 - (void *) ip1);
2711 clib_memcpy_fast ((u8 *) ip2 - vec_len (sl2->rewrite_bsid),
2712 (u8 *) ip2, (void *) sr2 - (void *) ip2);
2713 clib_memcpy_fast ((u8 *) ip3 - vec_len (sl3->rewrite_bsid),
2714 (u8 *) ip3, (void *) sr3 - (void *) ip3);
Pablo Camarillofb380952016-12-07 18:34:18 +01002715
Dave Barach178cf492018-11-13 16:34:13 -05002716 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2717 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2718 clib_memcpy_fast (((u8 *) sr1 - vec_len (sl1->rewrite_bsid)),
2719 sl1->rewrite_bsid, vec_len (sl1->rewrite_bsid));
2720 clib_memcpy_fast (((u8 *) sr2 - vec_len (sl2->rewrite_bsid)),
2721 sl2->rewrite_bsid, vec_len (sl2->rewrite_bsid));
2722 clib_memcpy_fast (((u8 *) sr3 - vec_len (sl3->rewrite_bsid)),
2723 sl3->rewrite_bsid, vec_len (sl3->rewrite_bsid));
Pablo Camarillofb380952016-12-07 18:34:18 +01002724
2725 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2726 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite_bsid));
2727 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite_bsid));
2728 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite_bsid));
2729
2730 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2731 ip1 = ((void *) ip1) - vec_len (sl1->rewrite_bsid);
2732 ip2 = ((void *) ip2) - vec_len (sl2->rewrite_bsid);
2733 ip3 = ((void *) ip3) - vec_len (sl3->rewrite_bsid);
2734
2735 ip0->hop_limit -= 1;
2736 ip1->hop_limit -= 1;
2737 ip2->hop_limit -= 1;
2738 ip3->hop_limit -= 1;
2739
2740 new_l0 =
2741 clib_net_to_host_u16 (ip0->payload_length) +
2742 vec_len (sl0->rewrite_bsid);
2743 new_l1 =
2744 clib_net_to_host_u16 (ip1->payload_length) +
2745 vec_len (sl1->rewrite_bsid);
2746 new_l2 =
2747 clib_net_to_host_u16 (ip2->payload_length) +
2748 vec_len (sl2->rewrite_bsid);
2749 new_l3 =
2750 clib_net_to_host_u16 (ip3->payload_length) +
2751 vec_len (sl3->rewrite_bsid);
2752
2753 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2754 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2755 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2756 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2757
2758 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2759 sr1 = ((void *) sr1) - vec_len (sl1->rewrite_bsid);
2760 sr2 = ((void *) sr2) - vec_len (sl2->rewrite_bsid);
2761 sr3 = ((void *) sr3) - vec_len (sl3->rewrite_bsid);
2762
2763 ip0->dst_address.as_u64[0] =
2764 (sr0->segments + sr0->segments_left)->as_u64[0];
2765 ip0->dst_address.as_u64[1] =
2766 (sr0->segments + sr0->segments_left)->as_u64[1];
2767 ip1->dst_address.as_u64[0] =
2768 (sr1->segments + sr1->segments_left)->as_u64[0];
2769 ip1->dst_address.as_u64[1] =
2770 (sr1->segments + sr1->segments_left)->as_u64[1];
2771 ip2->dst_address.as_u64[0] =
2772 (sr2->segments + sr2->segments_left)->as_u64[0];
2773 ip2->dst_address.as_u64[1] =
2774 (sr2->segments + sr2->segments_left)->as_u64[1];
2775 ip3->dst_address.as_u64[0] =
2776 (sr3->segments + sr3->segments_left)->as_u64[0];
2777 ip3->dst_address.as_u64[1] =
2778 (sr3->segments + sr3->segments_left)->as_u64[1];
2779
2780 ip6_ext_header_t *ip_ext;
2781 if (ip0 + 1 == (void *) sr0)
2782 {
2783 sr0->protocol = ip0->protocol;
2784 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2785 }
2786 else
2787 {
2788 ip_ext = (void *) (ip0 + 1);
2789 sr0->protocol = ip_ext->next_hdr;
2790 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2791 }
2792
2793 if (ip1 + 1 == (void *) sr1)
2794 {
2795 sr1->protocol = ip1->protocol;
2796 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2797 }
2798 else
2799 {
2800 ip_ext = (void *) (ip2 + 1);
2801 sr2->protocol = ip_ext->next_hdr;
2802 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2803 }
2804
2805 if (ip2 + 1 == (void *) sr2)
2806 {
2807 sr2->protocol = ip2->protocol;
2808 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2809 }
2810 else
2811 {
2812 ip_ext = (void *) (ip2 + 1);
2813 sr2->protocol = ip_ext->next_hdr;
2814 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2815 }
2816
2817 if (ip3 + 1 == (void *) sr3)
2818 {
2819 sr3->protocol = ip3->protocol;
2820 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2821 }
2822 else
2823 {
2824 ip_ext = (void *) (ip3 + 1);
2825 sr3->protocol = ip_ext->next_hdr;
2826 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2827 }
2828
2829 insert_pkts += 4;
2830
2831 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2832 {
2833 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2834 {
2835 sr_policy_rewrite_trace_t *tr =
2836 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002837 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2838 sizeof (tr->src.as_u8));
2839 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2840 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002841 }
2842
2843 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2844 {
2845 sr_policy_rewrite_trace_t *tr =
2846 vlib_add_trace (vm, node, b1, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002847 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2848 sizeof (tr->src.as_u8));
2849 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2850 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002851 }
2852
2853 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2854 {
2855 sr_policy_rewrite_trace_t *tr =
2856 vlib_add_trace (vm, node, b2, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002857 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2858 sizeof (tr->src.as_u8));
2859 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2860 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002861 }
2862
2863 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2864 {
2865 sr_policy_rewrite_trace_t *tr =
2866 vlib_add_trace (vm, node, b3, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002867 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2868 sizeof (tr->src.as_u8));
2869 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2870 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002871 }
2872 }
2873
2874 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2875 n_left_to_next, bi0, bi1, bi2, bi3,
2876 next0, next1, next2, next3);
2877 }
2878
2879 /* Single loop for potentially the last three packets */
2880 while (n_left_from > 0 && n_left_to_next > 0)
2881 {
2882 u32 bi0;
2883 vlib_buffer_t *b0;
2884 ip6_header_t *ip0 = 0;
2885 ip6_sr_header_t *sr0 = 0;
2886 ip6_sr_sl_t *sl0;
2887 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2888 u16 new_l0 = 0;
2889
2890 bi0 = from[0];
2891 to_next[0] = bi0;
2892 from += 1;
2893 to_next += 1;
2894 n_left_from -= 1;
2895 n_left_to_next -= 1;
2896
2897 b0 = vlib_get_buffer (vm, bi0);
2898 sl0 =
2899 pool_elt_at_index (sm->sid_lists,
2900 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00002901 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2902 vec_len (sl0->rewrite_bsid));
Pablo Camarillofb380952016-12-07 18:34:18 +01002903
2904 ip0 = vlib_buffer_get_current (b0);
2905
2906 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2907 sr0 =
2908 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2909 ip6_ext_header_len (ip0 + 1));
2910 else
2911 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2912
Dave Barach178cf492018-11-13 16:34:13 -05002913 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite_bsid),
2914 (u8 *) ip0, (void *) sr0 - (void *) ip0);
2915 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2916 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
Pablo Camarillofb380952016-12-07 18:34:18 +01002917
2918 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2919
2920 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2921 ip0->hop_limit -= 1;
2922 new_l0 =
2923 clib_net_to_host_u16 (ip0->payload_length) +
2924 vec_len (sl0->rewrite_bsid);
2925 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2926
2927 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2928
2929 ip0->dst_address.as_u64[0] =
2930 (sr0->segments + sr0->segments_left)->as_u64[0];
2931 ip0->dst_address.as_u64[1] =
2932 (sr0->segments + sr0->segments_left)->as_u64[1];
2933
2934 if (ip0 + 1 == (void *) sr0)
2935 {
2936 sr0->protocol = ip0->protocol;
2937 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2938 }
2939 else
2940 {
2941 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2942 sr0->protocol = ip_ext->next_hdr;
2943 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2944 }
2945
2946 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2947 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2948 {
2949 sr_policy_rewrite_trace_t *tr =
2950 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05002951 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2952 sizeof (tr->src.as_u8));
2953 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2954 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01002955 }
2956
2957 insert_pkts++;
2958
2959 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2960 n_left_to_next, bi0, next0);
2961 }
2962
2963 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2964 }
2965
2966 /* Update counters */
2967 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2968 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2969 insert_pkts);
2970 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2971 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2972 bsid_pkts);
2973 return from_frame->n_vectors;
2974}
2975
2976/* *INDENT-OFF* */
2977VLIB_REGISTER_NODE (sr_policy_rewrite_b_insert_node) = {
2978 .function = sr_policy_rewrite_b_insert,
2979 .name = "sr-pl-rewrite-b-insert",
2980 .vector_size = sizeof (u32),
2981 .format_trace = format_sr_policy_rewrite_trace,
2982 .type = VLIB_NODE_TYPE_INTERNAL,
2983 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2984 .error_strings = sr_policy_rewrite_error_strings,
2985 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2986 .next_nodes = {
2987#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2988 foreach_sr_policy_rewrite_next
2989#undef _
2990 },
2991};
2992/* *INDENT-ON* */
2993
2994/**
2995 * @brief Function BSID encapsulation
2996 */
2997static_always_inline void
2998end_bsid_encaps_srh_processing (vlib_node_runtime_t * node,
2999 vlib_buffer_t * b0,
3000 ip6_header_t * ip0,
3001 ip6_sr_header_t * sr0, u32 * next0)
3002{
3003 ip6_address_t *new_dst0;
3004
3005 if (PREDICT_FALSE (!sr0))
3006 goto error_bsid_encaps;
3007
3008 if (PREDICT_TRUE (sr0->type == ROUTING_HEADER_TYPE_SR))
3009 {
3010 if (PREDICT_TRUE (sr0->segments_left != 0))
3011 {
3012 sr0->segments_left -= 1;
3013 new_dst0 = (ip6_address_t *) (sr0->segments);
3014 new_dst0 += sr0->segments_left;
3015 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
3016 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
3017 return;
3018 }
3019 }
3020
3021error_bsid_encaps:
3022 *next0 = SR_POLICY_REWRITE_NEXT_ERROR;
3023 b0->error = node->errors[SR_POLICY_REWRITE_ERROR_BSID_ZERO];
3024}
3025
3026/**
3027 * @brief Graph node for applying a SR policy BSID - Encapsulation
3028 */
3029static uword
3030sr_policy_rewrite_b_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
3031 vlib_frame_t * from_frame)
3032{
3033 ip6_sr_main_t *sm = &sr_main;
3034 u32 n_left_from, next_index, *from, *to_next;
3035
3036 from = vlib_frame_vector_args (from_frame);
3037 n_left_from = from_frame->n_vectors;
3038
3039 next_index = node->cached_next_index;
3040
3041 int encap_pkts = 0, bsid_pkts = 0;
3042
3043 while (n_left_from > 0)
3044 {
3045 u32 n_left_to_next;
3046
3047 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
3048
3049 /* Quad - Loop */
3050 while (n_left_from >= 8 && n_left_to_next >= 4)
3051 {
3052 u32 bi0, bi1, bi2, bi3;
3053 vlib_buffer_t *b0, *b1, *b2, *b3;
3054 u32 next0, next1, next2, next3;
3055 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3056 ip6_header_t *ip0, *ip1, *ip2, *ip3;
3057 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
3058 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
Pablo Camarillofb380952016-12-07 18:34:18 +01003059 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
3060
3061 /* Prefetch next iteration. */
3062 {
3063 vlib_buffer_t *p4, *p5, *p6, *p7;
3064
3065 p4 = vlib_get_buffer (vm, from[4]);
3066 p5 = vlib_get_buffer (vm, from[5]);
3067 p6 = vlib_get_buffer (vm, from[6]);
3068 p7 = vlib_get_buffer (vm, from[7]);
3069
3070 /* Prefetch the buffer header and packet for the N+2 loop iteration */
3071 vlib_prefetch_buffer_header (p4, LOAD);
3072 vlib_prefetch_buffer_header (p5, LOAD);
3073 vlib_prefetch_buffer_header (p6, LOAD);
3074 vlib_prefetch_buffer_header (p7, LOAD);
3075
3076 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
3077 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
3078 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
3079 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
3080 }
3081
3082 to_next[0] = bi0 = from[0];
3083 to_next[1] = bi1 = from[1];
3084 to_next[2] = bi2 = from[2];
3085 to_next[3] = bi3 = from[3];
3086 from += 4;
3087 to_next += 4;
3088 n_left_from -= 4;
3089 n_left_to_next -= 4;
3090
3091 b0 = vlib_get_buffer (vm, bi0);
3092 b1 = vlib_get_buffer (vm, bi1);
3093 b2 = vlib_get_buffer (vm, bi2);
3094 b3 = vlib_get_buffer (vm, bi3);
3095
3096 sl0 =
3097 pool_elt_at_index (sm->sid_lists,
3098 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3099 sl1 =
3100 pool_elt_at_index (sm->sid_lists,
3101 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
3102 sl2 =
3103 pool_elt_at_index (sm->sid_lists,
3104 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
3105 sl3 =
3106 pool_elt_at_index (sm->sid_lists,
3107 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00003108 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3109 vec_len (sl0->rewrite));
3110 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3111 vec_len (sl1->rewrite));
3112 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3113 vec_len (sl2->rewrite));
3114 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3115 vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01003116
3117 ip0_encap = vlib_buffer_get_current (b0);
3118 ip1_encap = vlib_buffer_get_current (b1);
3119 ip2_encap = vlib_buffer_get_current (b2);
3120 ip3_encap = vlib_buffer_get_current (b3);
3121
Klement Sekera769145c2019-03-06 11:59:57 +01003122 sr0 =
3123 ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
3124 NULL);
3125 sr1 =
3126 ip6_ext_header_find (vm, b1, ip1_encap, IP_PROTOCOL_IPV6_ROUTE,
3127 NULL);
3128 sr2 =
3129 ip6_ext_header_find (vm, b2, ip2_encap, IP_PROTOCOL_IPV6_ROUTE,
3130 NULL);
3131 sr3 =
3132 ip6_ext_header_find (vm, b3, ip3_encap, IP_PROTOCOL_IPV6_ROUTE,
3133 NULL);
Pablo Camarillofb380952016-12-07 18:34:18 +01003134
3135 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
3136 end_bsid_encaps_srh_processing (node, b1, ip1_encap, sr1, &next1);
3137 end_bsid_encaps_srh_processing (node, b2, ip2_encap, sr2, &next2);
3138 end_bsid_encaps_srh_processing (node, b3, ip3_encap, sr3, &next3);
3139
Dave Barach178cf492018-11-13 16:34:13 -05003140 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3141 sl0->rewrite, vec_len (sl0->rewrite));
3142 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
3143 sl1->rewrite, vec_len (sl1->rewrite));
3144 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
3145 sl2->rewrite, vec_len (sl2->rewrite));
3146 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
3147 sl3->rewrite, vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01003148
3149 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3150 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
3151 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
3152 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
3153
3154 ip0 = vlib_buffer_get_current (b0);
3155 ip1 = vlib_buffer_get_current (b1);
3156 ip2 = vlib_buffer_get_current (b2);
3157 ip3 = vlib_buffer_get_current (b3);
3158
3159 encaps_processing_v6 (node, b0, ip0, ip0_encap);
3160 encaps_processing_v6 (node, b1, ip1, ip1_encap);
3161 encaps_processing_v6 (node, b2, ip2, ip2_encap);
3162 encaps_processing_v6 (node, b3, ip3, ip3_encap);
3163
3164 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
3165 {
3166 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3167 {
3168 sr_policy_rewrite_trace_t *tr =
3169 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003170 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3171 sizeof (tr->src.as_u8));
3172 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3173 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003174 }
3175
3176 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
3177 {
3178 sr_policy_rewrite_trace_t *tr =
3179 vlib_add_trace (vm, node, b1, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003180 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
3181 sizeof (tr->src.as_u8));
3182 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
3183 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003184 }
3185
3186 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
3187 {
3188 sr_policy_rewrite_trace_t *tr =
3189 vlib_add_trace (vm, node, b2, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003190 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
3191 sizeof (tr->src.as_u8));
3192 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
3193 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003194 }
3195
3196 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
3197 {
3198 sr_policy_rewrite_trace_t *tr =
3199 vlib_add_trace (vm, node, b3, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003200 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
3201 sizeof (tr->src.as_u8));
3202 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
3203 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003204 }
3205 }
3206
3207 encap_pkts += 4;
3208 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
3209 n_left_to_next, bi0, bi1, bi2, bi3,
3210 next0, next1, next2, next3);
3211 }
3212
3213 /* Single loop for potentially the last three packets */
3214 while (n_left_from > 0 && n_left_to_next > 0)
3215 {
3216 u32 bi0;
3217 vlib_buffer_t *b0;
3218 ip6_header_t *ip0 = 0, *ip0_encap = 0;
Pablo Camarillofb380952016-12-07 18:34:18 +01003219 ip6_sr_header_t *sr0;
3220 ip6_sr_sl_t *sl0;
3221 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3222
3223 bi0 = from[0];
3224 to_next[0] = bi0;
3225 from += 1;
3226 to_next += 1;
3227 n_left_from -= 1;
3228 n_left_to_next -= 1;
3229 b0 = vlib_get_buffer (vm, bi0);
3230
3231 sl0 =
3232 pool_elt_at_index (sm->sid_lists,
3233 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00003234 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3235 vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01003236
3237 ip0_encap = vlib_buffer_get_current (b0);
Klement Sekera769145c2019-03-06 11:59:57 +01003238 sr0 =
3239 ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
3240 NULL);
Pablo Camarillofb380952016-12-07 18:34:18 +01003241 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
3242
Dave Barach178cf492018-11-13 16:34:13 -05003243 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3244 sl0->rewrite, vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01003245 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3246
3247 ip0 = vlib_buffer_get_current (b0);
3248
3249 encaps_processing_v6 (node, b0, ip0, ip0_encap);
3250
3251 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3252 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3253 {
3254 sr_policy_rewrite_trace_t *tr =
3255 vlib_add_trace (vm, node, b0, sizeof (*tr));
Dave Barach178cf492018-11-13 16:34:13 -05003256 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3257 sizeof (tr->src.as_u8));
3258 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3259 sizeof (tr->dst.as_u8));
Pablo Camarillofb380952016-12-07 18:34:18 +01003260 }
3261
3262 encap_pkts++;
3263 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3264 n_left_to_next, bi0, next0);
3265 }
3266
3267 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3268 }
3269
3270 /* Update counters */
3271 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3272 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3273 encap_pkts);
3274 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3275 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3276 bsid_pkts);
3277
3278 return from_frame->n_vectors;
3279}
3280
3281/* *INDENT-OFF* */
3282VLIB_REGISTER_NODE (sr_policy_rewrite_b_encaps_node) = {
3283 .function = sr_policy_rewrite_b_encaps,
3284 .name = "sr-pl-rewrite-b-encaps",
3285 .vector_size = sizeof (u32),
3286 .format_trace = format_sr_policy_rewrite_trace,
3287 .type = VLIB_NODE_TYPE_INTERNAL,
3288 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3289 .error_strings = sr_policy_rewrite_error_strings,
3290 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3291 .next_nodes = {
3292#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3293 foreach_sr_policy_rewrite_next
3294#undef _
3295 },
3296};
3297/* *INDENT-ON* */
3298
Tetsuya Murakami70d8ef82019-12-04 18:57:46 -08003299/*************************** SR Policy plugins ******************************/
3300/**
3301 * @brief SR Policy plugin registry
3302 */
3303int
3304sr_policy_register_function (vlib_main_t * vm, u8 * fn_name,
3305 u8 * keyword_str, u8 * def_str,
3306 u8 * params_str, u8 prefix_length,
3307 dpo_type_t * dpo,
3308 format_function_t * ls_format,
3309 unformat_function_t * ls_unformat,
3310 sr_p_plugin_callback_t * creation_fn,
3311 sr_p_plugin_callback_t * removal_fn)
3312{
3313 ip6_sr_main_t *sm = &sr_main;
3314 uword *p;
3315
3316 sr_policy_fn_registration_t *plugin;
3317
3318 /* Did this function exist? If so update it */
3319 p = hash_get_mem (sm->policy_plugin_functions_by_key, fn_name);
3320 if (p)
3321 {
3322 plugin = pool_elt_at_index (sm->policy_plugin_functions, p[0]);
3323 }
3324 /* Else create a new one and set hash key */
3325 else
3326 {
3327 pool_get (sm->policy_plugin_functions, plugin);
3328 hash_set_mem (sm->policy_plugin_functions_by_key, fn_name,
3329 plugin - sm->policy_plugin_functions);
3330 }
3331
3332 clib_memset (plugin, 0, sizeof (*plugin));
3333
3334 plugin->sr_policy_function_number = (plugin - sm->policy_plugin_functions);
3335 plugin->sr_policy_function_number += SR_BEHAVIOR_LAST;
3336 plugin->prefix_length = prefix_length;
3337 plugin->ls_format = ls_format;
3338 plugin->ls_unformat = ls_unformat;
3339 plugin->creation = creation_fn;
3340 plugin->removal = removal_fn;
3341 clib_memcpy (&plugin->dpo, dpo, sizeof (dpo_type_t));
3342 plugin->function_name = format (0, "%s%c", fn_name, 0);
3343 plugin->keyword_str = format (0, "%s%c", keyword_str, 0);
3344 plugin->def_str = format (0, "%s%c", def_str, 0);
3345 plugin->params_str = format (0, "%s%c", params_str, 0);
3346
3347 return plugin->sr_policy_function_number;
3348}
3349
3350/**
3351 * @brief CLI function to 'show' all available SR LocalSID behaviors
3352 */
3353static clib_error_t *
3354show_sr_policy_behaviors_command_fn (vlib_main_t * vm,
3355 unformat_input_t * input,
3356 vlib_cli_command_t * cmd)
3357{
3358 ip6_sr_main_t *sm = &sr_main;
3359 sr_policy_fn_registration_t *plugin;
3360 sr_policy_fn_registration_t **plugins_vec = 0;
3361 int i;
3362
3363 vlib_cli_output (vm, "SR Policy behaviors:\n-----------------------\n\n");
3364
3365 /* *INDENT-OFF* */
3366 pool_foreach (plugin, sm->policy_plugin_functions,
3367 ({ vec_add1 (plugins_vec, plugin); }));
3368 /* *INDENT-ON* */
3369
3370 vlib_cli_output (vm, "Plugin behaviors:\n");
3371 for (i = 0; i < vec_len (plugins_vec); i++)
3372 {
3373 plugin = plugins_vec[i];
3374 vlib_cli_output (vm, "\t%s\t-> %s.\n", plugin->keyword_str,
3375 plugin->def_str);
3376 vlib_cli_output (vm, "\t\tParameters: '%s'\n", plugin->params_str);
3377 }
3378 return 0;
3379}
3380
3381/* *INDENT-OFF* */
3382VLIB_CLI_COMMAND (show_sr_policy_behaviors_command, static) = {
3383 .path = "show sr policy behaviors",
3384 .short_help = "show sr policy behaviors",
3385 .function = show_sr_policy_behaviors_command_fn,
3386};
3387/* *INDENT-ON* */
3388
Pablo Camarillofb380952016-12-07 18:34:18 +01003389/*************************** SR Segment Lists DPOs ****************************/
3390static u8 *
3391format_sr_segment_list_dpo (u8 * s, va_list * args)
3392{
3393 ip6_sr_main_t *sm = &sr_main;
3394 ip6_address_t *addr;
3395 ip6_sr_sl_t *sl;
3396
3397 index_t index = va_arg (*args, index_t);
3398 CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
3399 s = format (s, "SR: Segment List index:[%d]", index);
3400 s = format (s, "\n\tSegments:");
3401
3402 sl = pool_elt_at_index (sm->sid_lists, index);
3403
3404 s = format (s, "< ");
3405 vec_foreach (addr, sl->segments)
3406 {
3407 s = format (s, "%U, ", format_ip6_address, addr);
3408 }
3409 s = format (s, "\b\b > - ");
3410 s = format (s, "Weight: %u", sl->weight);
3411
3412 return s;
3413}
3414
3415const static dpo_vft_t sr_policy_rewrite_vft = {
3416 .dv_lock = sr_dpo_lock,
3417 .dv_unlock = sr_dpo_unlock,
3418 .dv_format = format_sr_segment_list_dpo,
3419};
3420
3421const static char *const sr_pr_encaps_ip6_nodes[] = {
3422 "sr-pl-rewrite-encaps",
3423 NULL,
3424};
3425
3426const static char *const sr_pr_encaps_ip4_nodes[] = {
3427 "sr-pl-rewrite-encaps-v4",
3428 NULL,
3429};
3430
3431const static char *const *const sr_pr_encaps_nodes[DPO_PROTO_NUM] = {
3432 [DPO_PROTO_IP6] = sr_pr_encaps_ip6_nodes,
3433 [DPO_PROTO_IP4] = sr_pr_encaps_ip4_nodes,
3434};
3435
3436const static char *const sr_pr_insert_ip6_nodes[] = {
3437 "sr-pl-rewrite-insert",
3438 NULL,
3439};
3440
3441const static char *const *const sr_pr_insert_nodes[DPO_PROTO_NUM] = {
3442 [DPO_PROTO_IP6] = sr_pr_insert_ip6_nodes,
3443};
3444
3445const static char *const sr_pr_bsid_insert_ip6_nodes[] = {
3446 "sr-pl-rewrite-b-insert",
3447 NULL,
3448};
3449
3450const static char *const *const sr_pr_bsid_insert_nodes[DPO_PROTO_NUM] = {
3451 [DPO_PROTO_IP6] = sr_pr_bsid_insert_ip6_nodes,
3452};
3453
3454const static char *const sr_pr_bsid_encaps_ip6_nodes[] = {
3455 "sr-pl-rewrite-b-encaps",
3456 NULL,
3457};
3458
3459const static char *const *const sr_pr_bsid_encaps_nodes[DPO_PROTO_NUM] = {
3460 [DPO_PROTO_IP6] = sr_pr_bsid_encaps_ip6_nodes,
3461};
3462
3463/********************* SR Policy Rewrite initialization ***********************/
3464/**
3465 * @brief SR Policy Rewrite initialization
3466 */
3467clib_error_t *
3468sr_policy_rewrite_init (vlib_main_t * vm)
3469{
3470 ip6_sr_main_t *sm = &sr_main;
3471
3472 /* Init memory for sr policy keys (bsid <-> ip6_address_t) */
Pablo Camarillo4521afa2017-03-16 10:43:05 +01003473 mhash_init (&sm->sr_policies_index_hash, sizeof (uword),
3474 sizeof (ip6_address_t));
Pablo Camarillofb380952016-12-07 18:34:18 +01003475
3476 /* Init SR VPO DPOs type */
3477 sr_pr_encaps_dpo_type =
3478 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_encaps_nodes);
3479
3480 sr_pr_insert_dpo_type =
3481 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_insert_nodes);
3482
3483 sr_pr_bsid_encaps_dpo_type =
3484 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_encaps_nodes);
3485
3486 sr_pr_bsid_insert_dpo_type =
3487 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_insert_nodes);
3488
3489 /* Register the L2 encaps node used in HW redirect */
3490 sm->l2_sr_policy_rewrite_index = sr_policy_rewrite_encaps_node.index;
3491
3492 sm->fib_table_ip6 = (u32) ~ 0;
3493 sm->fib_table_ip4 = (u32) ~ 0;
3494
3495 return 0;
3496}
3497
3498VLIB_INIT_FUNCTION (sr_policy_rewrite_init);
3499
3500
3501/*
3502* fd.io coding-style-patch-verification: ON
3503*
3504* Local Variables:
3505* eval: (c-set-style "gnu")
3506* End:
3507*/