blob: ad73d29d51864e1782a531e447083fe433362de7 [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;
110
111/******************* SR rewrite set encaps IPv6 source addr *******************/
112/* Note: This is temporal. We don't know whether to follow this path or
113 take the ip address of a loopback interface or even the OIF */
114
Pablo Camarillo1a5e3012017-11-16 16:02:50 +0100115void
116sr_set_source (ip6_address_t * address)
117{
118 clib_memcpy (&sr_pr_encaps_src, address, sizeof (sr_pr_encaps_src));
119}
120
Pablo Camarillofb380952016-12-07 18:34:18 +0100121static clib_error_t *
122set_sr_src_command_fn (vlib_main_t * vm, unformat_input_t * input,
123 vlib_cli_command_t * cmd)
124{
125 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
126 {
127 if (unformat
128 (input, "addr %U", unformat_ip6_address, &sr_pr_encaps_src))
129 return 0;
130 else
131 return clib_error_return (0, "No address specified");
132 }
133 return clib_error_return (0, "No address specified");
134}
135
136/* *INDENT-OFF* */
137VLIB_CLI_COMMAND (set_sr_src_command, static) = {
138 .path = "set sr encaps source",
139 .short_help = "set sr encaps source addr <ip6_addr>",
140 .function = set_sr_src_command_fn,
141};
142/* *INDENT-ON* */
143
144/*********************** SR rewrite string computation ************************/
145/**
146 * @brief SR rewrite string computation for IPv6 encapsulation (inline)
147 *
148 * @param sl is a vector of IPv6 addresses composing the Segment List
149 *
150 * @return precomputed rewrite string for encapsulation
151 */
152static inline u8 *
153compute_rewrite_encaps (ip6_address_t * sl)
154{
155 ip6_header_t *iph;
156 ip6_sr_header_t *srh;
157 ip6_address_t *addrp, *this_address;
158 u32 header_length = 0;
159 u8 *rs = NULL;
160
161 header_length = 0;
162 header_length += IPv6_DEFAULT_HEADER_LENGTH;
163 if (vec_len (sl) > 1)
164 {
165 header_length += sizeof (ip6_sr_header_t);
166 header_length += vec_len (sl) * sizeof (ip6_address_t);
167 }
168
169 vec_validate (rs, header_length - 1);
170
171 iph = (ip6_header_t *) rs;
172 iph->ip_version_traffic_class_and_flow_label =
173 clib_host_to_net_u32 (0 | ((6 & 0xF) << 28));
174 iph->src_address.as_u64[0] = sr_pr_encaps_src.as_u64[0];
175 iph->src_address.as_u64[1] = sr_pr_encaps_src.as_u64[1];
176 iph->payload_length = header_length - IPv6_DEFAULT_HEADER_LENGTH;
177 iph->protocol = IP_PROTOCOL_IPV6;
178 iph->hop_limit = IPv6_DEFAULT_HOP_LIMIT;
179
Pablo Camarillod327c872018-01-08 14:25:55 +0100180 if (vec_len (sl) > 1)
181 {
182 srh = (ip6_sr_header_t *) (iph + 1);
183 iph->protocol = IP_PROTOCOL_IPV6_ROUTE;
184 srh->protocol = IP_PROTOCOL_IPV6;
185 srh->type = ROUTING_HEADER_TYPE_SR;
186 srh->segments_left = vec_len (sl) - 1;
187 srh->first_segment = vec_len (sl) - 1;
188 srh->length = ((sizeof (ip6_sr_header_t) +
189 (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
190 srh->flags = 0x00;
191 srh->reserved = 0x00;
192 addrp = srh->segments + vec_len (sl) - 1;
193 vec_foreach (this_address, sl)
194 {
195 clib_memcpy (addrp->as_u8, this_address->as_u8,
196 sizeof (ip6_address_t));
197 addrp--;
198 }
199 }
Pablo Camarillofb380952016-12-07 18:34:18 +0100200 iph->dst_address.as_u64[0] = sl->as_u64[0];
201 iph->dst_address.as_u64[1] = sl->as_u64[1];
202 return rs;
203}
204
205/**
206 * @brief SR rewrite string computation for SRH insertion (inline)
207 *
208 * @param sl is a vector of IPv6 addresses composing the Segment List
209 *
210 * @return precomputed rewrite string for SRH insertion
211 */
212static inline u8 *
213compute_rewrite_insert (ip6_address_t * sl)
214{
215 ip6_sr_header_t *srh;
216 ip6_address_t *addrp, *this_address;
217 u32 header_length = 0;
218 u8 *rs = NULL;
219
220 header_length = 0;
221 header_length += sizeof (ip6_sr_header_t);
222 header_length += (vec_len (sl) + 1) * sizeof (ip6_address_t);
223
224 vec_validate (rs, header_length - 1);
225
226 srh = (ip6_sr_header_t *) rs;
227 srh->type = ROUTING_HEADER_TYPE_SR;
228 srh->segments_left = vec_len (sl);
229 srh->first_segment = vec_len (sl);
230 srh->length = ((sizeof (ip6_sr_header_t) +
231 ((vec_len (sl) + 1) * sizeof (ip6_address_t))) / 8) - 1;
232 srh->flags = 0x00;
233 srh->reserved = 0x0000;
234 addrp = srh->segments + vec_len (sl);
235 vec_foreach (this_address, sl)
236 {
237 clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
238 addrp--;
239 }
240 return rs;
241}
242
243/**
244 * @brief SR rewrite string computation for SRH insertion with BSID (inline)
245 *
246 * @param sl is a vector of IPv6 addresses composing the Segment List
247 *
248 * @return precomputed rewrite string for SRH insertion with BSID
249 */
250static inline u8 *
251compute_rewrite_bsid (ip6_address_t * sl)
252{
253 ip6_sr_header_t *srh;
254 ip6_address_t *addrp, *this_address;
255 u32 header_length = 0;
256 u8 *rs = NULL;
257
258 header_length = 0;
259 header_length += sizeof (ip6_sr_header_t);
260 header_length += vec_len (sl) * sizeof (ip6_address_t);
261
262 vec_validate (rs, header_length - 1);
263
264 srh = (ip6_sr_header_t *) rs;
265 srh->type = ROUTING_HEADER_TYPE_SR;
266 srh->segments_left = vec_len (sl) - 1;
267 srh->first_segment = vec_len (sl) - 1;
268 srh->length = ((sizeof (ip6_sr_header_t) +
269 (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
270 srh->flags = 0x00;
271 srh->reserved = 0x0000;
272 addrp = srh->segments + vec_len (sl) - 1;
273 vec_foreach (this_address, sl)
274 {
275 clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
276 addrp--;
277 }
278 return rs;
279}
280
281/*************************** SR LB helper functions **************************/
282/**
283 * @brief Creates a Segment List and adds it to an SR policy
284 *
285 * Creates a Segment List and adds it to the SR policy. Notice that the SL are
286 * not necessarily unique. Hence there might be two Segment List within the
287 * same SR Policy with exactly the same segments and same weight.
288 *
289 * @param sr_policy is the SR policy where the SL will be added
290 * @param sl is a vector of IPv6 addresses composing the Segment List
291 * @param weight is the weight of the SegmentList (for load-balancing purposes)
292 * @param is_encap represents the mode (SRH insertion vs Encapsulation)
293 *
294 * @return pointer to the just created segment list
295 */
296static inline ip6_sr_sl_t *
297create_sl (ip6_sr_policy_t * sr_policy, ip6_address_t * sl, u32 weight,
298 u8 is_encap)
299{
300 ip6_sr_main_t *sm = &sr_main;
301 ip6_sr_sl_t *segment_list;
302
303 pool_get (sm->sid_lists, segment_list);
304 memset (segment_list, 0, sizeof (*segment_list));
305
306 vec_add1 (sr_policy->segments_lists, segment_list - sm->sid_lists);
307
308 /* Fill in segment list */
309 segment_list->weight =
310 (weight != (u32) ~ 0 ? weight : SR_SEGMENT_LIST_WEIGHT_DEFAULT);
311 segment_list->segments = vec_dup (sl);
312
313 if (is_encap)
314 {
315 segment_list->rewrite = compute_rewrite_encaps (sl);
316 segment_list->rewrite_bsid = segment_list->rewrite;
317 }
318 else
319 {
320 segment_list->rewrite = compute_rewrite_insert (sl);
321 segment_list->rewrite_bsid = compute_rewrite_bsid (sl);
322 }
323
324 /* Create DPO */
325 dpo_reset (&segment_list->bsid_dpo);
326 dpo_reset (&segment_list->ip6_dpo);
327 dpo_reset (&segment_list->ip4_dpo);
328
329 if (is_encap)
330 {
331 dpo_set (&segment_list->ip6_dpo, sr_pr_encaps_dpo_type, DPO_PROTO_IP6,
332 segment_list - sm->sid_lists);
333 dpo_set (&segment_list->ip4_dpo, sr_pr_encaps_dpo_type, DPO_PROTO_IP4,
334 segment_list - sm->sid_lists);
335 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_encaps_dpo_type,
336 DPO_PROTO_IP6, segment_list - sm->sid_lists);
337 }
338 else
339 {
340 dpo_set (&segment_list->ip6_dpo, sr_pr_insert_dpo_type, DPO_PROTO_IP6,
341 segment_list - sm->sid_lists);
342 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_insert_dpo_type,
343 DPO_PROTO_IP6, segment_list - sm->sid_lists);
344 }
345
346 return segment_list;
347}
348
349/**
350 * @brief Updates the Load Balancer after an SR Policy change
351 *
352 * @param sr_policy is the modified SR Policy
353 */
354static inline void
355update_lb (ip6_sr_policy_t * sr_policy)
356{
357 flow_hash_config_t fhc;
358 u32 *sl_index;
359 ip6_sr_sl_t *segment_list;
360 ip6_sr_main_t *sm = &sr_main;
361 load_balance_path_t path;
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100362 path.path_index = FIB_NODE_INDEX_INVALID;
Pablo Camarillofb380952016-12-07 18:34:18 +0100363 load_balance_path_t *ip4_path_vector = 0;
364 load_balance_path_t *ip6_path_vector = 0;
365 load_balance_path_t *b_path_vector = 0;
366
367 /* In case LB does not exist, create it */
368 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
369 {
370 fib_prefix_t pfx = {
371 .fp_proto = FIB_PROTOCOL_IP6,
372 .fp_len = 128,
373 .fp_addr = {
374 .ip6 = sr_policy->bsid,
375 }
376 };
377
378 /* Add FIB entry for BSID */
379 fhc = fib_table_get_flow_hash_config (sr_policy->fib_table,
Neale Rannsd792d9c2017-10-21 10:53:20 -0700380 FIB_PROTOCOL_IP6);
Pablo Camarillofb380952016-12-07 18:34:18 +0100381
382 dpo_set (&sr_policy->bsid_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
383 load_balance_create (0, DPO_PROTO_IP6, fhc));
384
385 dpo_set (&sr_policy->ip6_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
386 load_balance_create (0, DPO_PROTO_IP6, fhc));
387
388 /* Update FIB entry's to point to the LB DPO in the main FIB and hidden one */
Neale Ranns107e7d42017-04-11 09:55:19 -0700389 fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
390 sr_policy->fib_table),
391 &pfx, FIB_SOURCE_SR,
Pablo Camarillofb380952016-12-07 18:34:18 +0100392 FIB_ENTRY_FLAG_EXCLUSIVE,
393 &sr_policy->bsid_dpo);
394
395 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
396 &pfx,
397 FIB_SOURCE_SR,
398 FIB_ENTRY_FLAG_EXCLUSIVE,
399 &sr_policy->ip6_dpo);
400
401 if (sr_policy->is_encap)
402 {
403 dpo_set (&sr_policy->ip4_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP4,
404 load_balance_create (0, DPO_PROTO_IP4, fhc));
405
406 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
407 &pfx,
408 FIB_SOURCE_SR,
409 FIB_ENTRY_FLAG_EXCLUSIVE,
410 &sr_policy->ip4_dpo);
411 }
412
413 }
414
415 /* Create the LB path vector */
416 //path_vector = vec_new(load_balance_path_t, vec_len(sr_policy->segments_lists));
417 vec_foreach (sl_index, sr_policy->segments_lists)
418 {
419 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
420 path.path_dpo = segment_list->bsid_dpo;
421 path.path_weight = segment_list->weight;
422 vec_add1 (b_path_vector, path);
423 path.path_dpo = segment_list->ip6_dpo;
424 vec_add1 (ip6_path_vector, path);
425 if (sr_policy->is_encap)
426 {
427 path.path_dpo = segment_list->ip4_dpo;
428 vec_add1 (ip4_path_vector, path);
429 }
430 }
431
432 /* Update LB multipath */
433 load_balance_multipath_update (&sr_policy->bsid_dpo, b_path_vector,
434 LOAD_BALANCE_FLAG_NONE);
435 load_balance_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector,
436 LOAD_BALANCE_FLAG_NONE);
437 if (sr_policy->is_encap)
438 load_balance_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector,
439 LOAD_BALANCE_FLAG_NONE);
440
441 /* Cleanup */
442 vec_free (b_path_vector);
443 vec_free (ip6_path_vector);
444 vec_free (ip4_path_vector);
445
446}
447
448/**
449 * @brief Updates the Replicate DPO after an SR Policy change
450 *
451 * @param sr_policy is the modified SR Policy (type spray)
452 */
453static inline void
454update_replicate (ip6_sr_policy_t * sr_policy)
455{
456 u32 *sl_index;
457 ip6_sr_sl_t *segment_list;
458 ip6_sr_main_t *sm = &sr_main;
459 load_balance_path_t path;
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100460 path.path_index = FIB_NODE_INDEX_INVALID;
Pablo Camarillofb380952016-12-07 18:34:18 +0100461 load_balance_path_t *b_path_vector = 0;
462 load_balance_path_t *ip6_path_vector = 0;
463 load_balance_path_t *ip4_path_vector = 0;
464
465 /* In case LB does not exist, create it */
466 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
467 {
468 dpo_set (&sr_policy->bsid_dpo, DPO_REPLICATE,
469 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
470
471 dpo_set (&sr_policy->ip6_dpo, DPO_REPLICATE,
472 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
473
474 /* Update FIB entry's DPO to point to SR without LB */
475 fib_prefix_t pfx = {
476 .fp_proto = FIB_PROTOCOL_IP6,
477 .fp_len = 128,
478 .fp_addr = {
479 .ip6 = sr_policy->bsid,
480 }
481 };
Neale Ranns107e7d42017-04-11 09:55:19 -0700482 fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
483 sr_policy->fib_table),
484 &pfx, FIB_SOURCE_SR,
Pablo Camarillofb380952016-12-07 18:34:18 +0100485 FIB_ENTRY_FLAG_EXCLUSIVE,
486 &sr_policy->bsid_dpo);
487
488 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
489 &pfx,
490 FIB_SOURCE_SR,
491 FIB_ENTRY_FLAG_EXCLUSIVE,
492 &sr_policy->ip6_dpo);
493
494 if (sr_policy->is_encap)
495 {
496 dpo_set (&sr_policy->ip4_dpo, DPO_REPLICATE, DPO_PROTO_IP4,
497 replicate_create (0, DPO_PROTO_IP4));
498
499 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
500 &pfx,
501 FIB_SOURCE_SR,
502 FIB_ENTRY_FLAG_EXCLUSIVE,
503 &sr_policy->ip4_dpo);
504 }
505
506 }
507
508 /* Create the replicate path vector */
509 path.path_weight = 1;
510 vec_foreach (sl_index, sr_policy->segments_lists)
511 {
512 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
513 path.path_dpo = segment_list->bsid_dpo;
514 vec_add1 (b_path_vector, path);
515 path.path_dpo = segment_list->ip6_dpo;
516 vec_add1 (ip6_path_vector, path);
517 if (sr_policy->is_encap)
518 {
519 path.path_dpo = segment_list->ip4_dpo;
520 vec_add1 (ip4_path_vector, path);
521 }
522 }
523
524 /* Update replicate multipath */
525 replicate_multipath_update (&sr_policy->bsid_dpo, b_path_vector);
526 replicate_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector);
527 if (sr_policy->is_encap)
528 replicate_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector);
Pablo Camarillofb380952016-12-07 18:34:18 +0100529}
530
531/******************************* SR rewrite API *******************************/
532/* Three functions for handling sr policies:
533 * -> sr_policy_add
534 * -> sr_policy_del
535 * -> sr_policy_mod
536 * All of them are API. CLI function on sr_policy_command_fn */
537
538/**
539 * @brief Create a new SR policy
540 *
541 * @param bsid is the bindingSID of the SR Policy
542 * @param segments is a vector of IPv6 address composing the segment list
543 * @param weight is the weight of the sid list. optional.
544 * @param behavior is the behavior of the SR policy. (default//spray)
545 * @param fib_table is the VRF where to install the FIB entry for the BSID
546 * @param is_encap (bool) whether SR policy should behave as Encap/SRH Insertion
547 *
548 * @return 0 if correct, else error
549 */
550int
551sr_policy_add (ip6_address_t * bsid, ip6_address_t * segments,
552 u32 weight, u8 behavior, u32 fib_table, u8 is_encap)
553{
554 ip6_sr_main_t *sm = &sr_main;
555 ip6_sr_policy_t *sr_policy = 0;
Pablo Camarillofb380952016-12-07 18:34:18 +0100556 uword *p;
557
558 /* Search for existing keys (BSID) */
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100559 p = mhash_get (&sm->sr_policies_index_hash, bsid);
Pablo Camarillofb380952016-12-07 18:34:18 +0100560 if (p)
561 {
562 /* Add SR policy that already exists; complain */
563 return -12;
564 }
565
566 /* Search collision in FIB entries */
567 /* Explanation: It might be possible that some other entity has already
568 * created a route for the BSID. This in theory is impossible, but in
569 * practise we could see it. Assert it and scream if needed */
570 fib_prefix_t pfx = {
571 .fp_proto = FIB_PROTOCOL_IP6,
572 .fp_len = 128,
573 .fp_addr = {
574 .ip6 = *bsid,
575 }
576 };
577
578 /* Lookup the FIB index associated to the table selected */
Neale Ranns107e7d42017-04-11 09:55:19 -0700579 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP6,
580 (fib_table != (u32) ~ 0 ? fib_table : 0));
Pablo Camarillofb380952016-12-07 18:34:18 +0100581 if (fib_index == ~0)
582 return -13;
583
584 /* Lookup whether there exists an entry for the BSID */
585 fib_node_index_t fei = fib_table_lookup_exact_match (fib_index, &pfx);
586 if (FIB_NODE_INDEX_INVALID != fei)
587 return -12; //There is an entry for such lookup
588
589 /* Add an SR policy object */
590 pool_get (sm->sr_policies, sr_policy);
591 memset (sr_policy, 0, sizeof (*sr_policy));
592 clib_memcpy (&sr_policy->bsid, bsid, sizeof (ip6_address_t));
593 sr_policy->type = behavior;
594 sr_policy->fib_table = (fib_table != (u32) ~ 0 ? fib_table : 0); //Is default FIB 0 ?
595 sr_policy->is_encap = is_encap;
596
597 /* Copy the key */
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100598 mhash_set (&sm->sr_policies_index_hash, bsid, sr_policy - sm->sr_policies,
599 NULL);
Pablo Camarillofb380952016-12-07 18:34:18 +0100600
601 /* Create a segment list and add the index to the SR policy */
602 create_sl (sr_policy, segments, weight, is_encap);
603
604 /* If FIB doesnt exist, create them */
605 if (sm->fib_table_ip6 == (u32) ~ 0)
606 {
607 sm->fib_table_ip6 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
Neale Ranns15002542017-09-10 04:39:11 -0700608 FIB_SOURCE_SR,
Pablo Camarillofb380952016-12-07 18:34:18 +0100609 "SRv6 steering of IP6 prefixes through BSIDs");
610 sm->fib_table_ip4 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
Neale Ranns15002542017-09-10 04:39:11 -0700611 FIB_SOURCE_SR,
Pablo Camarillofb380952016-12-07 18:34:18 +0100612 "SRv6 steering of IP4 prefixes through BSIDs");
Pablo Camarillofb380952016-12-07 18:34:18 +0100613 }
614
615 /* Create IPv6 FIB for the BindingSID attached to the DPO of the only SL */
616 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
617 update_lb (sr_policy);
618 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
619 update_replicate (sr_policy);
620 return 0;
621}
622
623/**
624 * @brief Delete a SR policy
625 *
626 * @param bsid is the bindingSID of the SR Policy
627 * @param index is the index of the SR policy
628 *
629 * @return 0 if correct, else error
630 */
631int
632sr_policy_del (ip6_address_t * bsid, u32 index)
633{
634 ip6_sr_main_t *sm = &sr_main;
635 ip6_sr_policy_t *sr_policy = 0;
636 ip6_sr_sl_t *segment_list;
Pablo Camarillofb380952016-12-07 18:34:18 +0100637 u32 *sl_index;
638 uword *p;
639
Pablo Camarillofb380952016-12-07 18:34:18 +0100640 if (bsid)
641 {
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100642 p = mhash_get (&sm->sr_policies_index_hash, bsid);
Pablo Camarillofb380952016-12-07 18:34:18 +0100643 if (p)
644 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
645 else
646 return -1;
647 }
648 else
649 {
650 sr_policy = pool_elt_at_index (sm->sr_policies, index);
651 if (!sr_policy)
652 return -1;
653 }
654
655 /* Remove BindingSID FIB entry */
656 fib_prefix_t pfx = {
657 .fp_proto = FIB_PROTOCOL_IP6,
658 .fp_len = 128,
659 .fp_addr = {
660 .ip6 = sr_policy->bsid,
661 }
662 ,
663 };
664
Neale Ranns107e7d42017-04-11 09:55:19 -0700665 fib_table_entry_special_remove (fib_table_find (FIB_PROTOCOL_IP6,
666 sr_policy->fib_table),
Pablo Camarillofb380952016-12-07 18:34:18 +0100667 &pfx, FIB_SOURCE_SR);
668
669 fib_table_entry_special_remove (sm->fib_table_ip6, &pfx, FIB_SOURCE_SR);
670
671 if (sr_policy->is_encap)
672 fib_table_entry_special_remove (sm->fib_table_ip4, &pfx, FIB_SOURCE_SR);
673
674 if (dpo_id_is_valid (&sr_policy->bsid_dpo))
675 {
676 dpo_reset (&sr_policy->bsid_dpo);
677 dpo_reset (&sr_policy->ip4_dpo);
678 dpo_reset (&sr_policy->ip6_dpo);
679 }
680
681 /* Clean SID Lists */
682 vec_foreach (sl_index, sr_policy->segments_lists)
683 {
684 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
685 vec_free (segment_list->segments);
686 vec_free (segment_list->rewrite);
Kris Michielsen91074432017-06-22 13:00:20 +0200687 if (!sr_policy->is_encap)
688 vec_free (segment_list->rewrite_bsid);
Pablo Camarillofb380952016-12-07 18:34:18 +0100689 pool_put_index (sm->sid_lists, *sl_index);
690 }
691
692 /* Remove SR policy entry */
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100693 mhash_unset (&sm->sr_policies_index_hash, &sr_policy->bsid, NULL);
Pablo Camarillofb380952016-12-07 18:34:18 +0100694 pool_put (sm->sr_policies, sr_policy);
695
696 /* If FIB empty unlock it */
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100697 if (!pool_elts (sm->sr_policies) && !pool_elts (sm->steer_policies))
Pablo Camarillofb380952016-12-07 18:34:18 +0100698 {
Neale Ranns15002542017-09-10 04:39:11 -0700699 fib_table_unlock (sm->fib_table_ip6, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
700 fib_table_unlock (sm->fib_table_ip4, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
Pablo Camarillofb380952016-12-07 18:34:18 +0100701 sm->fib_table_ip6 = (u32) ~ 0;
702 sm->fib_table_ip4 = (u32) ~ 0;
703 }
704
705 return 0;
706}
707
708/**
709 * @brief Modify an existing SR policy
710 *
711 * The possible modifications are adding a new Segment List, modifying an
712 * existing Segment List (modify the weight only) and delete a given
713 * Segment List from the SR Policy.
714 *
715 * @param bsid is the bindingSID of the SR Policy
716 * @param index is the index of the SR policy
717 * @param fib_table is the VRF where to install the FIB entry for the BSID
718 * @param operation is the operation to perform (among the top ones)
719 * @param segments is a vector of IPv6 address composing the segment list
720 * @param sl_index is the index of the Segment List to modify/delete
721 * @param weight is the weight of the sid list. optional.
722 * @param is_encap Mode. Encapsulation or SRH insertion.
723 *
724 * @return 0 if correct, else error
725 */
726int
727sr_policy_mod (ip6_address_t * bsid, u32 index, u32 fib_table,
728 u8 operation, ip6_address_t * segments, u32 sl_index,
729 u32 weight)
730{
731 ip6_sr_main_t *sm = &sr_main;
732 ip6_sr_policy_t *sr_policy = 0;
733 ip6_sr_sl_t *segment_list;
734 u32 *sl_index_iterate;
735 uword *p;
736
737 if (bsid)
738 {
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100739 p = mhash_get (&sm->sr_policies_index_hash, bsid);
Pablo Camarillofb380952016-12-07 18:34:18 +0100740 if (p)
741 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
742 else
743 return -1;
744 }
745 else
746 {
747 sr_policy = pool_elt_at_index (sm->sr_policies, index);
748 if (!sr_policy)
749 return -1;
750 }
751
752 if (operation == 1) /* Add SR List to an existing SR policy */
753 {
754 /* Create the new SL */
755 segment_list =
756 create_sl (sr_policy, segments, weight, sr_policy->is_encap);
757
758 /* Create a new LB DPO */
759 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
760 update_lb (sr_policy);
761 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
762 update_replicate (sr_policy);
763 }
764 else if (operation == 2) /* Delete SR List from an existing SR policy */
765 {
766 /* Check that currently there are more than one SID list */
767 if (vec_len (sr_policy->segments_lists) == 1)
768 return -21;
769
770 /* Check that the SR list does exist and is assigned to the sr policy */
771 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
772 if (*sl_index_iterate == sl_index)
773 break;
774
775 if (*sl_index_iterate != sl_index)
776 return -22;
777
778 /* Remove the lucky SR list that is being kicked out */
779 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
780 vec_free (segment_list->segments);
781 vec_free (segment_list->rewrite);
Kris Michielsen91074432017-06-22 13:00:20 +0200782 if (!sr_policy->is_encap)
783 vec_free (segment_list->rewrite_bsid);
Pablo Camarillofb380952016-12-07 18:34:18 +0100784 pool_put_index (sm->sid_lists, sl_index);
785 vec_del1 (sr_policy->segments_lists,
786 sl_index_iterate - sr_policy->segments_lists);
787
788 /* Create a new LB DPO */
789 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
790 update_lb (sr_policy);
791 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
792 update_replicate (sr_policy);
793 }
794 else if (operation == 3) /* Modify the weight of an existing SR List */
795 {
796 /* Find the corresponding SL */
797 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
798 if (*sl_index_iterate == sl_index)
799 break;
800
801 if (*sl_index_iterate != sl_index)
802 return -32;
803
804 /* Change the weight */
805 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
806 segment_list->weight = weight;
807
808 /* Update LB */
809 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
810 update_lb (sr_policy);
811 }
812 else /* Incorrect op. */
813 return -1;
814
815 return 0;
816}
817
818/**
819 * @brief CLI for 'sr policies' command family
820 */
821static clib_error_t *
822sr_policy_command_fn (vlib_main_t * vm, unformat_input_t * input,
823 vlib_cli_command_t * cmd)
824{
825 int rv = -1;
826 char is_del = 0, is_add = 0, is_mod = 0;
827 char policy_set = 0;
828 ip6_address_t bsid, next_address;
829 u32 sr_policy_index = (u32) ~ 0, sl_index = (u32) ~ 0;
830 u32 weight = (u32) ~ 0, fib_table = (u32) ~ 0;
831 ip6_address_t *segments = 0, *this_seg;
832 u8 operation = 0;
833 char is_encap = 1;
834 char is_spray = 0;
835
836 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
837 {
838 if (!is_add && !is_mod && !is_del && unformat (input, "add"))
839 is_add = 1;
840 else if (!is_add && !is_mod && !is_del && unformat (input, "del"))
841 is_del = 1;
842 else if (!is_add && !is_mod && !is_del && unformat (input, "mod"))
843 is_mod = 1;
844 else if (!policy_set
845 && unformat (input, "bsid %U", unformat_ip6_address, &bsid))
846 policy_set = 1;
847 else if (!is_add && !policy_set
848 && unformat (input, "index %d", &sr_policy_index))
849 policy_set = 1;
850 else if (unformat (input, "weight %d", &weight));
851 else
852 if (unformat (input, "next %U", unformat_ip6_address, &next_address))
853 {
854 vec_add2 (segments, this_seg, 1);
855 clib_memcpy (this_seg->as_u8, next_address.as_u8,
856 sizeof (*this_seg));
857 }
858 else if (unformat (input, "add sl"))
859 operation = 1;
860 else if (unformat (input, "del sl index %d", &sl_index))
861 operation = 2;
862 else if (unformat (input, "mod sl index %d", &sl_index))
863 operation = 3;
864 else if (fib_table == (u32) ~ 0
865 && unformat (input, "fib-table %d", &fib_table));
866 else if (unformat (input, "encap"))
867 is_encap = 1;
868 else if (unformat (input, "insert"))
869 is_encap = 0;
870 else if (unformat (input, "spray"))
871 is_spray = 1;
872 else
873 break;
874 }
875
876 if (!is_add && !is_mod && !is_del)
877 return clib_error_return (0, "Incorrect CLI");
878
879 if (!policy_set)
880 return clib_error_return (0, "No SR policy BSID or index specified");
881
882 if (is_add)
883 {
884 if (vec_len (segments) == 0)
885 return clib_error_return (0, "No Segment List specified");
886 rv = sr_policy_add (&bsid, segments, weight,
887 (is_spray ? SR_POLICY_TYPE_SPRAY :
888 SR_POLICY_TYPE_DEFAULT), fib_table, is_encap);
889 }
890 else if (is_del)
891 rv = sr_policy_del ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
892 sr_policy_index);
893 else if (is_mod)
894 {
895 if (!operation)
896 return clib_error_return (0, "No SL modification specified");
897 if (operation != 1 && sl_index == (u32) ~ 0)
898 return clib_error_return (0, "No Segment List index specified");
899 if (operation == 1 && vec_len (segments) == 0)
900 return clib_error_return (0, "No Segment List specified");
901 if (operation == 3 && weight == (u32) ~ 0)
902 return clib_error_return (0, "No new weight for the SL specified");
903 rv = sr_policy_mod ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
904 sr_policy_index, fib_table, operation, segments,
905 sl_index, weight);
906 }
907
908 switch (rv)
909 {
910 case 0:
911 break;
912 case 1:
913 return 0;
914 case -12:
915 return clib_error_return (0,
916 "There is already a FIB entry for the BindingSID address.\n"
917 "The SR policy could not be created.");
918 case -13:
919 return clib_error_return (0, "The specified FIB table does not exist.");
920 case -21:
921 return clib_error_return (0,
922 "The selected SR policy only contains ONE segment list. "
923 "Please remove the SR policy instead");
924 case -22:
925 return clib_error_return (0,
926 "Could not delete the segment list. "
927 "It is not associated with that SR policy.");
928 case -32:
929 return clib_error_return (0,
930 "Could not modify the segment list. "
931 "The given SL is not associated with such SR policy.");
932 default:
933 return clib_error_return (0, "BUG: sr policy returns %d", rv);
934 }
935 return 0;
936}
937
938/* *INDENT-OFF* */
939VLIB_CLI_COMMAND (sr_policy_command, static) = {
940 .path = "sr policy",
941 .short_help = "sr policy [add||del||mod] [bsid 2001::1||index 5] "
942 "next A:: next B:: next C:: (weight 1) (fib-table 2) (encap|insert)",
943 .long_help =
944 "Manipulation of SR policies.\n"
945 "A Segment Routing policy may contain several SID lists. Each SID list has\n"
946 "an associated weight (default 1), which will result in wECMP (uECMP).\n"
947 "Segment Routing policies might be of type encapsulation or srh insertion\n"
948 "Each SR policy will be associated with a unique BindingSID.\n"
949 "A BindingSID is a locally allocated SegmentID. For every packet that arrives\n"
950 "with IPv6_DA:BSID such traffic will be steered into the SR policy.\n"
951 "The add command will create a SR policy with its first segment list (sl)\n"
952 "The mod command allows you to add, remove, or modify the existing segment lists\n"
953 "within an SR policy.\n"
954 "The del command allows you to delete a SR policy along with all its associated\n"
955 "SID lists.\n",
956 .function = sr_policy_command_fn,
957};
958/* *INDENT-ON* */
959
960/**
961 * @brief CLI to display onscreen all the SR policies
962 */
963static clib_error_t *
964show_sr_policies_command_fn (vlib_main_t * vm, unformat_input_t * input,
965 vlib_cli_command_t * cmd)
966{
967 ip6_sr_main_t *sm = &sr_main;
968 u32 *sl_index;
969 ip6_sr_sl_t *segment_list = 0;
970 ip6_sr_policy_t *sr_policy = 0;
971 ip6_sr_policy_t **vec_policies = 0;
972 ip6_address_t *addr;
973 u8 *s;
974 int i = 0;
975
976 vlib_cli_output (vm, "SR policies:");
977
978 /* *INDENT-OFF* */
979 pool_foreach (sr_policy, sm->sr_policies,
980 {vec_add1 (vec_policies, sr_policy); } );
981 /* *INDENT-ON* */
982
983 vec_foreach_index (i, vec_policies)
984 {
985 sr_policy = vec_policies[i];
986 vlib_cli_output (vm, "[%u].-\tBSID: %U",
987 (u32) (sr_policy - sm->sr_policies),
988 format_ip6_address, &sr_policy->bsid);
989 vlib_cli_output (vm, "\tBehavior: %s",
990 (sr_policy->is_encap ? "Encapsulation" :
991 "SRH insertion"));
992 vlib_cli_output (vm, "\tType: %s",
993 (sr_policy->type ==
994 SR_POLICY_TYPE_DEFAULT ? "Default" : "Spray"));
995 vlib_cli_output (vm, "\tFIB table: %u",
996 (sr_policy->fib_table !=
997 (u32) ~ 0 ? sr_policy->fib_table : 0));
998 vlib_cli_output (vm, "\tSegment Lists:");
999 vec_foreach (sl_index, sr_policy->segments_lists)
1000 {
1001 s = NULL;
1002 s = format (s, "\t[%u].- ", *sl_index);
1003 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
1004 s = format (s, "< ");
1005 vec_foreach (addr, segment_list->segments)
1006 {
1007 s = format (s, "%U, ", format_ip6_address, addr);
1008 }
1009 s = format (s, "\b\b > ");
1010 s = format (s, "weight: %u", segment_list->weight);
1011 vlib_cli_output (vm, " %s", s);
1012 }
1013 vlib_cli_output (vm, "-----------");
1014 }
1015 return 0;
1016}
1017
1018/* *INDENT-OFF* */
1019VLIB_CLI_COMMAND (show_sr_policies_command, static) = {
1020 .path = "show sr policies",
1021 .short_help = "show sr policies",
1022 .function = show_sr_policies_command_fn,
1023};
1024/* *INDENT-ON* */
1025
1026/*************************** SR rewrite graph node ****************************/
1027/**
1028 * @brief Trace for the SR Policy Rewrite graph node
1029 */
1030static u8 *
1031format_sr_policy_rewrite_trace (u8 * s, va_list * args)
1032{
1033 //TODO
1034 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1035 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1036 sr_policy_rewrite_trace_t *t = va_arg (*args, sr_policy_rewrite_trace_t *);
1037
1038 s = format
1039 (s, "SR-policy-rewrite: src %U dst %U",
1040 format_ip6_address, &t->src, format_ip6_address, &t->dst);
1041
1042 return s;
1043}
1044
1045/**
1046 * @brief IPv6 encapsulation processing as per RFC2473
1047 */
1048static_always_inline void
1049encaps_processing_v6 (vlib_node_runtime_t * node,
1050 vlib_buffer_t * b0,
1051 ip6_header_t * ip0, ip6_header_t * ip0_encap)
1052{
1053 u32 new_l0;
1054
1055 ip0_encap->hop_limit -= 1;
1056 new_l0 =
1057 ip0->payload_length + sizeof (ip6_header_t) +
1058 clib_net_to_host_u16 (ip0_encap->payload_length);
1059 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1060 ip0->ip_version_traffic_class_and_flow_label =
1061 ip0_encap->ip_version_traffic_class_and_flow_label;
1062}
1063
1064/**
1065 * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
1066 */
1067static uword
1068sr_policy_rewrite_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
1069 vlib_frame_t * from_frame)
1070{
1071 ip6_sr_main_t *sm = &sr_main;
1072 u32 n_left_from, next_index, *from, *to_next;
1073
1074 from = vlib_frame_vector_args (from_frame);
1075 n_left_from = from_frame->n_vectors;
1076
1077 next_index = node->cached_next_index;
1078
1079 int encap_pkts = 0, bsid_pkts = 0;
1080
1081 while (n_left_from > 0)
1082 {
1083 u32 n_left_to_next;
1084
1085 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1086
1087 /* Quad - Loop */
1088 while (n_left_from >= 8 && n_left_to_next >= 4)
1089 {
1090 u32 bi0, bi1, bi2, bi3;
1091 vlib_buffer_t *b0, *b1, *b2, *b3;
1092 u32 next0, next1, next2, next3;
1093 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1094 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1095 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1096 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1097
1098 /* Prefetch next iteration. */
1099 {
1100 vlib_buffer_t *p4, *p5, *p6, *p7;
1101
1102 p4 = vlib_get_buffer (vm, from[4]);
1103 p5 = vlib_get_buffer (vm, from[5]);
1104 p6 = vlib_get_buffer (vm, from[6]);
1105 p7 = vlib_get_buffer (vm, from[7]);
1106
1107 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1108 vlib_prefetch_buffer_header (p4, LOAD);
1109 vlib_prefetch_buffer_header (p5, LOAD);
1110 vlib_prefetch_buffer_header (p6, LOAD);
1111 vlib_prefetch_buffer_header (p7, LOAD);
1112
1113 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1114 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1115 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1116 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1117 }
1118
1119 to_next[0] = bi0 = from[0];
1120 to_next[1] = bi1 = from[1];
1121 to_next[2] = bi2 = from[2];
1122 to_next[3] = bi3 = from[3];
1123 from += 4;
1124 to_next += 4;
1125 n_left_from -= 4;
1126 n_left_to_next -= 4;
1127
1128 b0 = vlib_get_buffer (vm, bi0);
1129 b1 = vlib_get_buffer (vm, bi1);
1130 b2 = vlib_get_buffer (vm, bi2);
1131 b3 = vlib_get_buffer (vm, bi3);
1132
1133 sl0 =
1134 pool_elt_at_index (sm->sid_lists,
1135 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1136 sl1 =
1137 pool_elt_at_index (sm->sid_lists,
1138 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1139 sl2 =
1140 pool_elt_at_index (sm->sid_lists,
1141 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1142 sl3 =
1143 pool_elt_at_index (sm->sid_lists,
1144 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1145
shwethabe146f132017-03-09 16:58:26 +00001146 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1147 vec_len (sl0->rewrite));
1148 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1149 vec_len (sl1->rewrite));
1150 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1151 vec_len (sl2->rewrite));
1152 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1153 vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001154
1155 ip0_encap = vlib_buffer_get_current (b0);
1156 ip1_encap = vlib_buffer_get_current (b1);
1157 ip2_encap = vlib_buffer_get_current (b2);
1158 ip3_encap = vlib_buffer_get_current (b3);
1159
1160 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1161 sl0->rewrite, vec_len (sl0->rewrite));
1162 clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1163 sl1->rewrite, vec_len (sl1->rewrite));
1164 clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1165 sl2->rewrite, vec_len (sl2->rewrite));
1166 clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1167 sl3->rewrite, vec_len (sl3->rewrite));
1168
1169 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1170 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1171 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1172 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1173
1174 ip0 = vlib_buffer_get_current (b0);
1175 ip1 = vlib_buffer_get_current (b1);
1176 ip2 = vlib_buffer_get_current (b2);
1177 ip3 = vlib_buffer_get_current (b3);
1178
1179 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1180 encaps_processing_v6 (node, b1, ip1, ip1_encap);
1181 encaps_processing_v6 (node, b2, ip2, ip2_encap);
1182 encaps_processing_v6 (node, b3, ip3, ip3_encap);
1183
1184 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1185 {
1186 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1187 {
1188 sr_policy_rewrite_trace_t *tr =
1189 vlib_add_trace (vm, node, b0, sizeof (*tr));
1190 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1191 sizeof (tr->src.as_u8));
1192 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1193 sizeof (tr->dst.as_u8));
1194 }
1195
1196 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1197 {
1198 sr_policy_rewrite_trace_t *tr =
1199 vlib_add_trace (vm, node, b1, sizeof (*tr));
1200 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1201 sizeof (tr->src.as_u8));
1202 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1203 sizeof (tr->dst.as_u8));
1204 }
1205
1206 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1207 {
1208 sr_policy_rewrite_trace_t *tr =
1209 vlib_add_trace (vm, node, b2, sizeof (*tr));
1210 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1211 sizeof (tr->src.as_u8));
1212 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1213 sizeof (tr->dst.as_u8));
1214 }
1215
1216 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1217 {
1218 sr_policy_rewrite_trace_t *tr =
1219 vlib_add_trace (vm, node, b3, sizeof (*tr));
1220 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1221 sizeof (tr->src.as_u8));
1222 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1223 sizeof (tr->dst.as_u8));
1224 }
1225 }
1226
1227 encap_pkts += 4;
1228 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1229 n_left_to_next, bi0, bi1, bi2, bi3,
1230 next0, next1, next2, next3);
1231 }
1232
1233 /* Single loop for potentially the last three packets */
1234 while (n_left_from > 0 && n_left_to_next > 0)
1235 {
1236 u32 bi0;
1237 vlib_buffer_t *b0;
1238 ip6_header_t *ip0 = 0, *ip0_encap = 0;
1239 ip6_sr_sl_t *sl0;
1240 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1241
1242 bi0 = from[0];
1243 to_next[0] = bi0;
1244 from += 1;
1245 to_next += 1;
1246 n_left_from -= 1;
1247 n_left_to_next -= 1;
1248 b0 = vlib_get_buffer (vm, bi0);
1249
1250 sl0 =
1251 pool_elt_at_index (sm->sid_lists,
1252 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00001253 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1254 vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001255
1256 ip0_encap = vlib_buffer_get_current (b0);
1257
1258 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1259 sl0->rewrite, vec_len (sl0->rewrite));
1260 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1261
1262 ip0 = vlib_buffer_get_current (b0);
1263
1264 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1265
1266 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1267 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1268 {
1269 sr_policy_rewrite_trace_t *tr =
1270 vlib_add_trace (vm, node, b0, sizeof (*tr));
1271 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1272 sizeof (tr->src.as_u8));
1273 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1274 sizeof (tr->dst.as_u8));
1275 }
1276
1277 encap_pkts++;
1278 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1279 n_left_to_next, bi0, next0);
1280 }
1281
1282 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1283 }
1284
1285 /* Update counters */
1286 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1287 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1288 encap_pkts);
1289 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1290 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1291 bsid_pkts);
1292
1293 return from_frame->n_vectors;
1294}
1295
1296/* *INDENT-OFF* */
1297VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_node) = {
1298 .function = sr_policy_rewrite_encaps,
1299 .name = "sr-pl-rewrite-encaps",
1300 .vector_size = sizeof (u32),
1301 .format_trace = format_sr_policy_rewrite_trace,
1302 .type = VLIB_NODE_TYPE_INTERNAL,
1303 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1304 .error_strings = sr_policy_rewrite_error_strings,
1305 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1306 .next_nodes = {
1307#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1308 foreach_sr_policy_rewrite_next
1309#undef _
1310 },
1311};
1312/* *INDENT-ON* */
1313
1314/**
1315 * @brief IPv4 encapsulation processing as per RFC2473
1316 */
1317static_always_inline void
1318encaps_processing_v4 (vlib_node_runtime_t * node,
1319 vlib_buffer_t * b0,
1320 ip6_header_t * ip0, ip4_header_t * ip0_encap)
1321{
1322 u32 new_l0;
1323 ip6_sr_header_t *sr0;
1324
1325 u32 checksum0;
1326
1327 /* Inner IPv4: Decrement TTL & update checksum */
1328 ip0_encap->ttl -= 1;
1329 checksum0 = ip0_encap->checksum + clib_host_to_net_u16 (0x0100);
1330 checksum0 += checksum0 >= 0xffff;
1331 ip0_encap->checksum = checksum0;
1332
1333 /* Outer IPv6: Update length, FL, proto */
1334 new_l0 = ip0->payload_length + clib_net_to_host_u16 (ip0_encap->length);
1335 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1336 ip0->ip_version_traffic_class_and_flow_label =
1337 clib_host_to_net_u32 (0 | ((6 & 0xF) << 28) |
1338 ((ip0_encap->tos & 0xFF) << 20));
Pablo Camarillod327c872018-01-08 14:25:55 +01001339 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
1340 {
1341 sr0 = (void *) (ip0 + 1);
1342 sr0->protocol = IP_PROTOCOL_IP_IN_IP;
1343 }
1344 else
1345 ip0->protocol = IP_PROTOCOL_IP_IN_IP;
Pablo Camarillofb380952016-12-07 18:34:18 +01001346}
1347
1348/**
1349 * @brief Graph node for applying a SR policy into an IPv4 packet. Encapsulation
1350 */
1351static uword
1352sr_policy_rewrite_encaps_v4 (vlib_main_t * vm, vlib_node_runtime_t * node,
1353 vlib_frame_t * from_frame)
1354{
1355 ip6_sr_main_t *sm = &sr_main;
1356 u32 n_left_from, next_index, *from, *to_next;
1357
1358 from = vlib_frame_vector_args (from_frame);
1359 n_left_from = from_frame->n_vectors;
1360
1361 next_index = node->cached_next_index;
1362
1363 int encap_pkts = 0, bsid_pkts = 0;
1364
1365 while (n_left_from > 0)
1366 {
1367 u32 n_left_to_next;
1368
1369 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1370
1371 /* Quad - Loop */
1372 while (n_left_from >= 8 && n_left_to_next >= 4)
1373 {
1374 u32 bi0, bi1, bi2, bi3;
1375 vlib_buffer_t *b0, *b1, *b2, *b3;
1376 u32 next0, next1, next2, next3;
1377 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1378 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1379 ip4_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1380 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1381
1382 /* Prefetch next iteration. */
1383 {
1384 vlib_buffer_t *p4, *p5, *p6, *p7;
1385
1386 p4 = vlib_get_buffer (vm, from[4]);
1387 p5 = vlib_get_buffer (vm, from[5]);
1388 p6 = vlib_get_buffer (vm, from[6]);
1389 p7 = vlib_get_buffer (vm, from[7]);
1390
1391 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1392 vlib_prefetch_buffer_header (p4, LOAD);
1393 vlib_prefetch_buffer_header (p5, LOAD);
1394 vlib_prefetch_buffer_header (p6, LOAD);
1395 vlib_prefetch_buffer_header (p7, LOAD);
1396
1397 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1398 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1399 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1400 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1401 }
1402
1403 to_next[0] = bi0 = from[0];
1404 to_next[1] = bi1 = from[1];
1405 to_next[2] = bi2 = from[2];
1406 to_next[3] = bi3 = from[3];
1407 from += 4;
1408 to_next += 4;
1409 n_left_from -= 4;
1410 n_left_to_next -= 4;
1411
1412 b0 = vlib_get_buffer (vm, bi0);
1413 b1 = vlib_get_buffer (vm, bi1);
1414 b2 = vlib_get_buffer (vm, bi2);
1415 b3 = vlib_get_buffer (vm, bi3);
1416
1417 sl0 =
1418 pool_elt_at_index (sm->sid_lists,
1419 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1420 sl1 =
1421 pool_elt_at_index (sm->sid_lists,
1422 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1423 sl2 =
1424 pool_elt_at_index (sm->sid_lists,
1425 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1426 sl3 =
1427 pool_elt_at_index (sm->sid_lists,
1428 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00001429 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1430 vec_len (sl0->rewrite));
1431 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1432 vec_len (sl1->rewrite));
1433 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1434 vec_len (sl2->rewrite));
1435 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1436 vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001437
1438 ip0_encap = vlib_buffer_get_current (b0);
1439 ip1_encap = vlib_buffer_get_current (b1);
1440 ip2_encap = vlib_buffer_get_current (b2);
1441 ip3_encap = vlib_buffer_get_current (b3);
1442
1443 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1444 sl0->rewrite, vec_len (sl0->rewrite));
1445 clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1446 sl1->rewrite, vec_len (sl1->rewrite));
1447 clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1448 sl2->rewrite, vec_len (sl2->rewrite));
1449 clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1450 sl3->rewrite, vec_len (sl3->rewrite));
1451
1452 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1453 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1454 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1455 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1456
1457 ip0 = vlib_buffer_get_current (b0);
1458 ip1 = vlib_buffer_get_current (b1);
1459 ip2 = vlib_buffer_get_current (b2);
1460 ip3 = vlib_buffer_get_current (b3);
1461
1462 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1463 encaps_processing_v4 (node, b1, ip1, ip1_encap);
1464 encaps_processing_v4 (node, b2, ip2, ip2_encap);
1465 encaps_processing_v4 (node, b3, ip3, ip3_encap);
1466
1467 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1468 {
1469 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1470 {
1471 sr_policy_rewrite_trace_t *tr =
1472 vlib_add_trace (vm, node, b0, sizeof (*tr));
1473 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1474 sizeof (tr->src.as_u8));
1475 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1476 sizeof (tr->dst.as_u8));
1477 }
1478
1479 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1480 {
1481 sr_policy_rewrite_trace_t *tr =
1482 vlib_add_trace (vm, node, b1, sizeof (*tr));
1483 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1484 sizeof (tr->src.as_u8));
1485 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1486 sizeof (tr->dst.as_u8));
1487 }
1488
1489 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1490 {
1491 sr_policy_rewrite_trace_t *tr =
1492 vlib_add_trace (vm, node, b2, sizeof (*tr));
1493 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1494 sizeof (tr->src.as_u8));
1495 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1496 sizeof (tr->dst.as_u8));
1497 }
1498
1499 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1500 {
1501 sr_policy_rewrite_trace_t *tr =
1502 vlib_add_trace (vm, node, b3, sizeof (*tr));
1503 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1504 sizeof (tr->src.as_u8));
1505 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1506 sizeof (tr->dst.as_u8));
1507 }
1508 }
1509
1510 encap_pkts += 4;
1511 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1512 n_left_to_next, bi0, bi1, bi2, bi3,
1513 next0, next1, next2, next3);
1514 }
1515
1516 /* Single loop for potentially the last three packets */
1517 while (n_left_from > 0 && n_left_to_next > 0)
1518 {
1519 u32 bi0;
1520 vlib_buffer_t *b0;
1521 ip6_header_t *ip0 = 0;
1522 ip4_header_t *ip0_encap = 0;
1523 ip6_sr_sl_t *sl0;
1524 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1525
1526 bi0 = from[0];
1527 to_next[0] = bi0;
1528 from += 1;
1529 to_next += 1;
1530 n_left_from -= 1;
1531 n_left_to_next -= 1;
1532 b0 = vlib_get_buffer (vm, bi0);
1533
1534 sl0 =
1535 pool_elt_at_index (sm->sid_lists,
1536 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00001537 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1538 vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001539
1540 ip0_encap = vlib_buffer_get_current (b0);
1541
1542 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1543 sl0->rewrite, vec_len (sl0->rewrite));
1544 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1545
1546 ip0 = vlib_buffer_get_current (b0);
1547
1548 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1549
1550 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1551 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1552 {
1553 sr_policy_rewrite_trace_t *tr =
1554 vlib_add_trace (vm, node, b0, sizeof (*tr));
1555 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1556 sizeof (tr->src.as_u8));
1557 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1558 sizeof (tr->dst.as_u8));
1559 }
1560
1561 encap_pkts++;
1562 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1563 n_left_to_next, bi0, next0);
1564 }
1565
1566 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1567 }
1568
1569 /* Update counters */
1570 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1571 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1572 encap_pkts);
1573 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1574 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1575 bsid_pkts);
1576
1577 return from_frame->n_vectors;
1578}
1579
1580/* *INDENT-OFF* */
1581VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_v4_node) = {
1582 .function = sr_policy_rewrite_encaps_v4,
1583 .name = "sr-pl-rewrite-encaps-v4",
1584 .vector_size = sizeof (u32),
1585 .format_trace = format_sr_policy_rewrite_trace,
1586 .type = VLIB_NODE_TYPE_INTERNAL,
1587 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1588 .error_strings = sr_policy_rewrite_error_strings,
1589 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1590 .next_nodes = {
1591#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1592 foreach_sr_policy_rewrite_next
1593#undef _
1594 },
1595};
1596/* *INDENT-ON* */
1597
1598always_inline u32
1599ip_flow_hash (void *data)
1600{
1601 ip4_header_t *iph = (ip4_header_t *) data;
1602
1603 if ((iph->ip_version_and_header_length & 0xF0) == 0x40)
1604 return ip4_compute_flow_hash (iph, IP_FLOW_HASH_DEFAULT);
1605 else
1606 return ip6_compute_flow_hash ((ip6_header_t *) iph, IP_FLOW_HASH_DEFAULT);
1607}
1608
1609always_inline u64
1610mac_to_u64 (u8 * m)
1611{
1612 return (*((u64 *) m) & 0xffffffffffff);
1613}
1614
1615always_inline u32
1616l2_flow_hash (vlib_buffer_t * b0)
1617{
1618 ethernet_header_t *eh;
1619 u64 a, b, c;
1620 uword is_ip, eh_size;
1621 u16 eh_type;
1622
1623 eh = vlib_buffer_get_current (b0);
1624 eh_type = clib_net_to_host_u16 (eh->type);
1625 eh_size = ethernet_buffer_header_size (b0);
1626
1627 is_ip = (eh_type == ETHERNET_TYPE_IP4 || eh_type == ETHERNET_TYPE_IP6);
1628
1629 /* since we have 2 cache lines, use them */
1630 if (is_ip)
1631 a = ip_flow_hash ((u8 *) vlib_buffer_get_current (b0) + eh_size);
1632 else
1633 a = eh->type;
1634
1635 b = mac_to_u64 ((u8 *) eh->dst_address);
1636 c = mac_to_u64 ((u8 *) eh->src_address);
1637 hash_mix64 (a, b, c);
1638
1639 return (u32) c;
1640}
1641
1642/**
1643 * @brief Graph node for applying a SR policy into a L2 frame
1644 */
1645static uword
1646sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
1647 vlib_frame_t * from_frame)
1648{
1649 ip6_sr_main_t *sm = &sr_main;
1650 u32 n_left_from, next_index, *from, *to_next;
1651
1652 from = vlib_frame_vector_args (from_frame);
1653 n_left_from = from_frame->n_vectors;
1654
1655 next_index = node->cached_next_index;
1656
1657 int encap_pkts = 0, bsid_pkts = 0;
1658
1659 while (n_left_from > 0)
1660 {
1661 u32 n_left_to_next;
1662
1663 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1664
1665 /* Quad - Loop */
1666 while (n_left_from >= 8 && n_left_to_next >= 4)
1667 {
1668 u32 bi0, bi1, bi2, bi3;
1669 vlib_buffer_t *b0, *b1, *b2, *b3;
1670 u32 next0, next1, next2, next3;
1671 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1672 ethernet_header_t *en0, *en1, *en2, *en3;
1673 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1674 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1675 ip6_sr_policy_t *sp0, *sp1, *sp2, *sp3;
1676 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1677
1678 /* Prefetch next iteration. */
1679 {
1680 vlib_buffer_t *p4, *p5, *p6, *p7;
1681
1682 p4 = vlib_get_buffer (vm, from[4]);
1683 p5 = vlib_get_buffer (vm, from[5]);
1684 p6 = vlib_get_buffer (vm, from[6]);
1685 p7 = vlib_get_buffer (vm, from[7]);
1686
1687 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1688 vlib_prefetch_buffer_header (p4, LOAD);
1689 vlib_prefetch_buffer_header (p5, LOAD);
1690 vlib_prefetch_buffer_header (p6, LOAD);
1691 vlib_prefetch_buffer_header (p7, LOAD);
1692
1693 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1694 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1695 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1696 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1697 }
1698
1699 to_next[0] = bi0 = from[0];
1700 to_next[1] = bi1 = from[1];
1701 to_next[2] = bi2 = from[2];
1702 to_next[3] = bi3 = from[3];
1703 from += 4;
1704 to_next += 4;
1705 n_left_from -= 4;
1706 n_left_to_next -= 4;
1707
1708 b0 = vlib_get_buffer (vm, bi0);
1709 b1 = vlib_get_buffer (vm, bi1);
1710 b2 = vlib_get_buffer (vm, bi2);
1711 b3 = vlib_get_buffer (vm, bi3);
1712
1713 sp0 = pool_elt_at_index (sm->sr_policies,
1714 sm->sw_iface_sr_policies[vnet_buffer
1715 (b0)->sw_if_index
1716 [VLIB_RX]]);
1717
1718 sp1 = pool_elt_at_index (sm->sr_policies,
1719 sm->sw_iface_sr_policies[vnet_buffer
1720 (b1)->sw_if_index
1721 [VLIB_RX]]);
1722
1723 sp2 = pool_elt_at_index (sm->sr_policies,
1724 sm->sw_iface_sr_policies[vnet_buffer
1725 (b2)->sw_if_index
1726 [VLIB_RX]]);
1727
1728 sp3 = pool_elt_at_index (sm->sr_policies,
1729 sm->sw_iface_sr_policies[vnet_buffer
1730 (b3)->sw_if_index
1731 [VLIB_RX]]);
1732
1733 if (vec_len (sp0->segments_lists) == 1)
1734 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1735 else
1736 {
1737 vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
1738 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1739 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1740 (vec_len (sp0->segments_lists) - 1))];
1741 }
1742
1743 if (vec_len (sp1->segments_lists) == 1)
1744 vnet_buffer (b1)->ip.adj_index[VLIB_TX] = sp1->segments_lists[1];
1745 else
1746 {
1747 vnet_buffer (b1)->ip.flow_hash = l2_flow_hash (b1);
1748 vnet_buffer (b1)->ip.adj_index[VLIB_TX] =
1749 sp1->segments_lists[(vnet_buffer (b1)->ip.flow_hash &
1750 (vec_len (sp1->segments_lists) - 1))];
1751 }
1752
1753 if (vec_len (sp2->segments_lists) == 1)
1754 vnet_buffer (b2)->ip.adj_index[VLIB_TX] = sp2->segments_lists[2];
1755 else
1756 {
1757 vnet_buffer (b2)->ip.flow_hash = l2_flow_hash (b2);
1758 vnet_buffer (b2)->ip.adj_index[VLIB_TX] =
1759 sp2->segments_lists[(vnet_buffer (b2)->ip.flow_hash &
1760 (vec_len (sp2->segments_lists) - 1))];
1761 }
1762
1763 if (vec_len (sp3->segments_lists) == 1)
1764 vnet_buffer (b3)->ip.adj_index[VLIB_TX] = sp3->segments_lists[3];
1765 else
1766 {
1767 vnet_buffer (b3)->ip.flow_hash = l2_flow_hash (b3);
1768 vnet_buffer (b3)->ip.adj_index[VLIB_TX] =
1769 sp3->segments_lists[(vnet_buffer (b3)->ip.flow_hash &
1770 (vec_len (sp3->segments_lists) - 1))];
1771 }
1772
1773 sl0 =
1774 pool_elt_at_index (sm->sid_lists,
1775 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1776 sl1 =
1777 pool_elt_at_index (sm->sid_lists,
1778 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1779 sl2 =
1780 pool_elt_at_index (sm->sid_lists,
1781 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1782 sl3 =
1783 pool_elt_at_index (sm->sid_lists,
1784 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1785
shwethabe146f132017-03-09 16:58:26 +00001786 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1787 vec_len (sl0->rewrite));
1788 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1789 vec_len (sl1->rewrite));
1790 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1791 vec_len (sl2->rewrite));
1792 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1793 vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001794
1795 en0 = vlib_buffer_get_current (b0);
1796 en1 = vlib_buffer_get_current (b1);
1797 en2 = vlib_buffer_get_current (b2);
1798 en3 = vlib_buffer_get_current (b3);
1799
1800 clib_memcpy (((u8 *) en0) - vec_len (sl0->rewrite), sl0->rewrite,
1801 vec_len (sl0->rewrite));
1802 clib_memcpy (((u8 *) en1) - vec_len (sl1->rewrite), sl1->rewrite,
1803 vec_len (sl1->rewrite));
1804 clib_memcpy (((u8 *) en2) - vec_len (sl2->rewrite), sl2->rewrite,
1805 vec_len (sl2->rewrite));
1806 clib_memcpy (((u8 *) en3) - vec_len (sl3->rewrite), sl3->rewrite,
1807 vec_len (sl3->rewrite));
1808
1809 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1810 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1811 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1812 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1813
1814 ip0 = vlib_buffer_get_current (b0);
1815 ip1 = vlib_buffer_get_current (b1);
1816 ip2 = vlib_buffer_get_current (b2);
1817 ip3 = vlib_buffer_get_current (b3);
1818
1819 ip0->payload_length =
1820 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
1821 ip1->payload_length =
1822 clib_host_to_net_u16 (b1->current_length - sizeof (ip6_header_t));
1823 ip2->payload_length =
1824 clib_host_to_net_u16 (b2->current_length - sizeof (ip6_header_t));
1825 ip3->payload_length =
1826 clib_host_to_net_u16 (b3->current_length - sizeof (ip6_header_t));
1827
Pablo Camarillod327c872018-01-08 14:25:55 +01001828 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
1829 {
1830 sr0 = (void *) (ip0 + 1);
1831 sr0->protocol = IP_PROTOCOL_IP6_NONXT;
1832 }
1833 else
1834 ip0->protocol = IP_PROTOCOL_IP6_NONXT;
Pablo Camarillofb380952016-12-07 18:34:18 +01001835
Pablo Camarillod327c872018-01-08 14:25:55 +01001836 if (ip1->protocol == IP_PROTOCOL_IPV6_ROUTE)
1837 {
1838 sr1 = (void *) (ip1 + 1);
1839 sr1->protocol = IP_PROTOCOL_IP6_NONXT;
1840 }
1841 else
1842 ip1->protocol = IP_PROTOCOL_IP6_NONXT;
1843
1844 if (ip2->protocol == IP_PROTOCOL_IPV6_ROUTE)
1845 {
1846 sr2 = (void *) (ip2 + 1);
1847 sr2->protocol = IP_PROTOCOL_IP6_NONXT;
1848 }
1849 else
1850 ip2->protocol = IP_PROTOCOL_IP6_NONXT;
1851
1852 if (ip3->protocol == IP_PROTOCOL_IPV6_ROUTE)
1853 {
1854 sr3 = (void *) (ip3 + 1);
1855 sr3->protocol = IP_PROTOCOL_IP6_NONXT;
1856 }
1857 else
1858 ip3->protocol = IP_PROTOCOL_IP6_NONXT;
Pablo Camarillofb380952016-12-07 18:34:18 +01001859
1860 /* Which Traffic class and flow label do I set ? */
1861 //ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32(0|((6&0xF)<<28)|((ip0_encap->tos&0xFF)<<20));
1862
1863 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1864 {
1865 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1866 {
1867 sr_policy_rewrite_trace_t *tr =
1868 vlib_add_trace (vm, node, b0, sizeof (*tr));
1869 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1870 sizeof (tr->src.as_u8));
1871 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1872 sizeof (tr->dst.as_u8));
1873 }
1874
1875 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1876 {
1877 sr_policy_rewrite_trace_t *tr =
1878 vlib_add_trace (vm, node, b1, sizeof (*tr));
1879 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1880 sizeof (tr->src.as_u8));
1881 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1882 sizeof (tr->dst.as_u8));
1883 }
1884
1885 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1886 {
1887 sr_policy_rewrite_trace_t *tr =
1888 vlib_add_trace (vm, node, b2, sizeof (*tr));
1889 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1890 sizeof (tr->src.as_u8));
1891 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1892 sizeof (tr->dst.as_u8));
1893 }
1894
1895 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1896 {
1897 sr_policy_rewrite_trace_t *tr =
1898 vlib_add_trace (vm, node, b3, sizeof (*tr));
1899 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1900 sizeof (tr->src.as_u8));
1901 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1902 sizeof (tr->dst.as_u8));
1903 }
1904 }
1905
1906 encap_pkts += 4;
1907 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1908 n_left_to_next, bi0, bi1, bi2, bi3,
1909 next0, next1, next2, next3);
1910 }
1911
1912 /* Single loop for potentially the last three packets */
1913 while (n_left_from > 0 && n_left_to_next > 0)
1914 {
1915 u32 bi0;
1916 vlib_buffer_t *b0;
1917 ip6_header_t *ip0 = 0;
1918 ip6_sr_header_t *sr0;
1919 ethernet_header_t *en0;
1920 ip6_sr_policy_t *sp0;
1921 ip6_sr_sl_t *sl0;
1922 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1923
1924 bi0 = from[0];
1925 to_next[0] = bi0;
1926 from += 1;
1927 to_next += 1;
1928 n_left_from -= 1;
1929 n_left_to_next -= 1;
1930 b0 = vlib_get_buffer (vm, bi0);
1931
1932 /* Find the SR policy */
1933 sp0 = pool_elt_at_index (sm->sr_policies,
1934 sm->sw_iface_sr_policies[vnet_buffer
1935 (b0)->sw_if_index
1936 [VLIB_RX]]);
1937
1938 /* In case there is more than one SL, LB among them */
1939 if (vec_len (sp0->segments_lists) == 1)
1940 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1941 else
1942 {
1943 vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
1944 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1945 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1946 (vec_len (sp0->segments_lists) - 1))];
1947 }
1948 sl0 =
1949 pool_elt_at_index (sm->sid_lists,
1950 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00001951 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1952 vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001953
1954 en0 = vlib_buffer_get_current (b0);
1955
1956 clib_memcpy (((u8 *) en0) - vec_len (sl0->rewrite), sl0->rewrite,
1957 vec_len (sl0->rewrite));
1958
1959 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1960
1961 ip0 = vlib_buffer_get_current (b0);
1962
1963 ip0->payload_length =
1964 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
1965
Pablo Camarillod327c872018-01-08 14:25:55 +01001966 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
1967 {
1968 sr0 = (void *) (ip0 + 1);
1969 sr0->protocol = IP_PROTOCOL_IP6_NONXT;
1970 }
1971 else
1972 ip0->protocol = IP_PROTOCOL_IP6_NONXT;
Pablo Camarillofb380952016-12-07 18:34:18 +01001973
1974 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1975 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1976 {
1977 sr_policy_rewrite_trace_t *tr =
1978 vlib_add_trace (vm, node, b0, sizeof (*tr));
1979 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1980 sizeof (tr->src.as_u8));
1981 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1982 sizeof (tr->dst.as_u8));
1983 }
1984
1985 encap_pkts++;
1986 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1987 n_left_to_next, bi0, next0);
1988 }
1989
1990 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1991 }
1992
1993 /* Update counters */
1994 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1995 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1996 encap_pkts);
1997 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1998 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1999 bsid_pkts);
2000
2001 return from_frame->n_vectors;
2002}
2003
2004/* *INDENT-OFF* */
2005VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_l2_node) = {
2006 .function = sr_policy_rewrite_encaps_l2,
2007 .name = "sr-pl-rewrite-encaps-l2",
2008 .vector_size = sizeof (u32),
2009 .format_trace = format_sr_policy_rewrite_trace,
2010 .type = VLIB_NODE_TYPE_INTERNAL,
2011 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2012 .error_strings = sr_policy_rewrite_error_strings,
2013 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2014 .next_nodes = {
2015#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2016 foreach_sr_policy_rewrite_next
2017#undef _
2018 },
2019};
2020/* *INDENT-ON* */
2021
2022/**
2023 * @brief Graph node for applying a SR policy into a packet. SRH insertion.
2024 */
2025static uword
2026sr_policy_rewrite_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2027 vlib_frame_t * from_frame)
2028{
2029 ip6_sr_main_t *sm = &sr_main;
2030 u32 n_left_from, next_index, *from, *to_next;
2031
2032 from = vlib_frame_vector_args (from_frame);
2033 n_left_from = from_frame->n_vectors;
2034
2035 next_index = node->cached_next_index;
2036
2037 int insert_pkts = 0, bsid_pkts = 0;
2038
2039 while (n_left_from > 0)
2040 {
2041 u32 n_left_to_next;
2042
2043 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2044
2045 /* Quad - Loop */
2046 while (n_left_from >= 8 && n_left_to_next >= 4)
2047 {
2048 u32 bi0, bi1, bi2, bi3;
2049 vlib_buffer_t *b0, *b1, *b2, *b3;
2050 u32 next0, next1, next2, next3;
2051 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2052 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2053 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2054 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2055 u16 new_l0, new_l1, new_l2, new_l3;
2056
2057 /* Prefetch next iteration. */
2058 {
2059 vlib_buffer_t *p4, *p5, *p6, *p7;
2060
2061 p4 = vlib_get_buffer (vm, from[4]);
2062 p5 = vlib_get_buffer (vm, from[5]);
2063 p6 = vlib_get_buffer (vm, from[6]);
2064 p7 = vlib_get_buffer (vm, from[7]);
2065
2066 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2067 vlib_prefetch_buffer_header (p4, LOAD);
2068 vlib_prefetch_buffer_header (p5, LOAD);
2069 vlib_prefetch_buffer_header (p6, LOAD);
2070 vlib_prefetch_buffer_header (p7, LOAD);
2071
2072 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2073 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2074 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2075 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2076 }
2077
2078 to_next[0] = bi0 = from[0];
2079 to_next[1] = bi1 = from[1];
2080 to_next[2] = bi2 = from[2];
2081 to_next[3] = bi3 = from[3];
2082 from += 4;
2083 to_next += 4;
2084 n_left_from -= 4;
2085 n_left_to_next -= 4;
2086
2087 b0 = vlib_get_buffer (vm, bi0);
2088 b1 = vlib_get_buffer (vm, bi1);
2089 b2 = vlib_get_buffer (vm, bi2);
2090 b3 = vlib_get_buffer (vm, bi3);
2091
2092 sl0 =
2093 pool_elt_at_index (sm->sid_lists,
2094 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2095 sl1 =
2096 pool_elt_at_index (sm->sid_lists,
2097 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2098 sl2 =
2099 pool_elt_at_index (sm->sid_lists,
2100 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2101 sl3 =
2102 pool_elt_at_index (sm->sid_lists,
2103 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00002104 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2105 vec_len (sl0->rewrite));
2106 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2107 vec_len (sl1->rewrite));
2108 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2109 vec_len (sl2->rewrite));
2110 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2111 vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002112
2113 ip0 = vlib_buffer_get_current (b0);
2114 ip1 = vlib_buffer_get_current (b1);
2115 ip2 = vlib_buffer_get_current (b2);
2116 ip3 = vlib_buffer_get_current (b3);
2117
2118 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2119 sr0 =
2120 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2121 ip6_ext_header_len (ip0 + 1));
2122 else
2123 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2124
2125 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2126 sr1 =
2127 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2128 ip6_ext_header_len (ip1 + 1));
2129 else
2130 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2131
2132 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2133 sr2 =
2134 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2135 ip6_ext_header_len (ip2 + 1));
2136 else
2137 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2138
2139 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2140 sr3 =
2141 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2142 ip6_ext_header_len (ip3 + 1));
2143 else
2144 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2145
2146 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2147 (void *) sr0 - (void *) ip0);
2148 clib_memcpy ((u8 *) ip1 - vec_len (sl1->rewrite), (u8 *) ip1,
2149 (void *) sr1 - (void *) ip1);
2150 clib_memcpy ((u8 *) ip2 - vec_len (sl2->rewrite), (u8 *) ip2,
2151 (void *) sr2 - (void *) ip2);
2152 clib_memcpy ((u8 *) ip3 - vec_len (sl3->rewrite), (u8 *) ip3,
2153 (void *) sr3 - (void *) ip3);
2154
2155 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite)), sl0->rewrite,
2156 vec_len (sl0->rewrite));
2157 clib_memcpy (((u8 *) sr1 - vec_len (sl1->rewrite)), sl1->rewrite,
2158 vec_len (sl1->rewrite));
2159 clib_memcpy (((u8 *) sr2 - vec_len (sl2->rewrite)), sl2->rewrite,
2160 vec_len (sl2->rewrite));
2161 clib_memcpy (((u8 *) sr3 - vec_len (sl3->rewrite)), sl3->rewrite,
2162 vec_len (sl3->rewrite));
2163
2164 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2165 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2166 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2167 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2168
2169 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2170 ip1 = ((void *) ip1) - vec_len (sl1->rewrite);
2171 ip2 = ((void *) ip2) - vec_len (sl2->rewrite);
2172 ip3 = ((void *) ip3) - vec_len (sl3->rewrite);
2173
2174 ip0->hop_limit -= 1;
2175 ip1->hop_limit -= 1;
2176 ip2->hop_limit -= 1;
2177 ip3->hop_limit -= 1;
2178
2179 new_l0 =
2180 clib_net_to_host_u16 (ip0->payload_length) +
2181 vec_len (sl0->rewrite);
2182 new_l1 =
2183 clib_net_to_host_u16 (ip1->payload_length) +
2184 vec_len (sl1->rewrite);
2185 new_l2 =
2186 clib_net_to_host_u16 (ip2->payload_length) +
2187 vec_len (sl2->rewrite);
2188 new_l3 =
2189 clib_net_to_host_u16 (ip3->payload_length) +
2190 vec_len (sl3->rewrite);
2191
2192 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2193 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2194 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2195 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2196
2197 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2198 sr1 = ((void *) sr1) - vec_len (sl1->rewrite);
2199 sr2 = ((void *) sr2) - vec_len (sl2->rewrite);
2200 sr3 = ((void *) sr3) - vec_len (sl3->rewrite);
2201
2202 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2203 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2204 sr1->segments->as_u64[0] = ip1->dst_address.as_u64[0];
2205 sr1->segments->as_u64[1] = ip1->dst_address.as_u64[1];
2206 sr2->segments->as_u64[0] = ip2->dst_address.as_u64[0];
2207 sr2->segments->as_u64[1] = ip2->dst_address.as_u64[1];
2208 sr3->segments->as_u64[0] = ip3->dst_address.as_u64[0];
2209 sr3->segments->as_u64[1] = ip3->dst_address.as_u64[1];
2210
2211 ip0->dst_address.as_u64[0] =
2212 (sr0->segments + sr0->segments_left)->as_u64[0];
2213 ip0->dst_address.as_u64[1] =
2214 (sr0->segments + sr0->segments_left)->as_u64[1];
2215 ip1->dst_address.as_u64[0] =
2216 (sr1->segments + sr1->segments_left)->as_u64[0];
2217 ip1->dst_address.as_u64[1] =
2218 (sr1->segments + sr1->segments_left)->as_u64[1];
2219 ip2->dst_address.as_u64[0] =
2220 (sr2->segments + sr2->segments_left)->as_u64[0];
2221 ip2->dst_address.as_u64[1] =
2222 (sr2->segments + sr2->segments_left)->as_u64[1];
2223 ip3->dst_address.as_u64[0] =
2224 (sr3->segments + sr3->segments_left)->as_u64[0];
2225 ip3->dst_address.as_u64[1] =
2226 (sr3->segments + sr3->segments_left)->as_u64[1];
2227
2228 ip6_ext_header_t *ip_ext;
2229 if (ip0 + 1 == (void *) sr0)
2230 {
2231 sr0->protocol = ip0->protocol;
2232 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2233 }
2234 else
2235 {
2236 ip_ext = (void *) (ip0 + 1);
2237 sr0->protocol = ip_ext->next_hdr;
2238 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2239 }
2240
2241 if (ip1 + 1 == (void *) sr1)
2242 {
2243 sr1->protocol = ip1->protocol;
2244 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2245 }
2246 else
2247 {
2248 ip_ext = (void *) (ip2 + 1);
2249 sr2->protocol = ip_ext->next_hdr;
2250 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2251 }
2252
2253 if (ip2 + 1 == (void *) sr2)
2254 {
2255 sr2->protocol = ip2->protocol;
2256 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2257 }
2258 else
2259 {
2260 ip_ext = (void *) (ip2 + 1);
2261 sr2->protocol = ip_ext->next_hdr;
2262 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2263 }
2264
2265 if (ip3 + 1 == (void *) sr3)
2266 {
2267 sr3->protocol = ip3->protocol;
2268 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2269 }
2270 else
2271 {
2272 ip_ext = (void *) (ip3 + 1);
2273 sr3->protocol = ip_ext->next_hdr;
2274 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2275 }
2276
2277 insert_pkts += 4;
2278
2279 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2280 {
2281 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2282 {
2283 sr_policy_rewrite_trace_t *tr =
2284 vlib_add_trace (vm, node, b0, sizeof (*tr));
2285 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2286 sizeof (tr->src.as_u8));
2287 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2288 sizeof (tr->dst.as_u8));
2289 }
2290
2291 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2292 {
2293 sr_policy_rewrite_trace_t *tr =
2294 vlib_add_trace (vm, node, b1, sizeof (*tr));
2295 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2296 sizeof (tr->src.as_u8));
2297 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2298 sizeof (tr->dst.as_u8));
2299 }
2300
2301 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2302 {
2303 sr_policy_rewrite_trace_t *tr =
2304 vlib_add_trace (vm, node, b2, sizeof (*tr));
2305 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
2306 sizeof (tr->src.as_u8));
2307 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
2308 sizeof (tr->dst.as_u8));
2309 }
2310
2311 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2312 {
2313 sr_policy_rewrite_trace_t *tr =
2314 vlib_add_trace (vm, node, b3, sizeof (*tr));
2315 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
2316 sizeof (tr->src.as_u8));
2317 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
2318 sizeof (tr->dst.as_u8));
2319 }
2320 }
2321
2322 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2323 n_left_to_next, bi0, bi1, bi2, bi3,
2324 next0, next1, next2, next3);
2325 }
2326
2327 /* Single loop for potentially the last three packets */
2328 while (n_left_from > 0 && n_left_to_next > 0)
2329 {
2330 u32 bi0;
2331 vlib_buffer_t *b0;
2332 ip6_header_t *ip0 = 0;
2333 ip6_sr_header_t *sr0 = 0;
2334 ip6_sr_sl_t *sl0;
2335 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2336 u16 new_l0 = 0;
2337
2338 bi0 = from[0];
2339 to_next[0] = bi0;
2340 from += 1;
2341 to_next += 1;
2342 n_left_from -= 1;
2343 n_left_to_next -= 1;
2344
2345 b0 = vlib_get_buffer (vm, bi0);
2346 sl0 =
2347 pool_elt_at_index (sm->sid_lists,
2348 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00002349 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2350 vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002351
2352 ip0 = vlib_buffer_get_current (b0);
2353
2354 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2355 sr0 =
2356 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2357 ip6_ext_header_len (ip0 + 1));
2358 else
2359 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2360
2361 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2362 (void *) sr0 - (void *) ip0);
2363 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite)), sl0->rewrite,
2364 vec_len (sl0->rewrite));
2365
2366 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2367
2368 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2369 ip0->hop_limit -= 1;
2370 new_l0 =
2371 clib_net_to_host_u16 (ip0->payload_length) +
2372 vec_len (sl0->rewrite);
2373 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2374
2375 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2376 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2377 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2378
2379 ip0->dst_address.as_u64[0] =
2380 (sr0->segments + sr0->segments_left)->as_u64[0];
2381 ip0->dst_address.as_u64[1] =
2382 (sr0->segments + sr0->segments_left)->as_u64[1];
2383
2384 if (ip0 + 1 == (void *) sr0)
2385 {
2386 sr0->protocol = ip0->protocol;
2387 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2388 }
2389 else
2390 {
2391 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2392 sr0->protocol = ip_ext->next_hdr;
2393 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2394 }
2395
2396 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2397 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2398 {
2399 sr_policy_rewrite_trace_t *tr =
2400 vlib_add_trace (vm, node, b0, sizeof (*tr));
2401 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2402 sizeof (tr->src.as_u8));
2403 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2404 sizeof (tr->dst.as_u8));
2405 }
2406
2407 insert_pkts++;
2408
2409 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2410 n_left_to_next, bi0, next0);
2411 }
2412
2413 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2414 }
2415
2416 /* Update counters */
2417 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2418 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2419 insert_pkts);
2420 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2421 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2422 bsid_pkts);
2423 return from_frame->n_vectors;
2424}
2425
2426/* *INDENT-OFF* */
2427VLIB_REGISTER_NODE (sr_policy_rewrite_insert_node) = {
2428 .function = sr_policy_rewrite_insert,
2429 .name = "sr-pl-rewrite-insert",
2430 .vector_size = sizeof (u32),
2431 .format_trace = format_sr_policy_rewrite_trace,
2432 .type = VLIB_NODE_TYPE_INTERNAL,
2433 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2434 .error_strings = sr_policy_rewrite_error_strings,
2435 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2436 .next_nodes = {
2437#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2438 foreach_sr_policy_rewrite_next
2439#undef _
2440 },
2441};
2442/* *INDENT-ON* */
2443
2444/**
2445 * @brief Graph node for applying a SR policy into a packet. BSID - SRH insertion.
2446 */
2447static uword
2448sr_policy_rewrite_b_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2449 vlib_frame_t * from_frame)
2450{
2451 ip6_sr_main_t *sm = &sr_main;
2452 u32 n_left_from, next_index, *from, *to_next;
2453
2454 from = vlib_frame_vector_args (from_frame);
2455 n_left_from = from_frame->n_vectors;
2456
2457 next_index = node->cached_next_index;
2458
2459 int insert_pkts = 0, bsid_pkts = 0;
2460
2461 while (n_left_from > 0)
2462 {
2463 u32 n_left_to_next;
2464
2465 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2466
2467 /* Quad - Loop */
2468 while (n_left_from >= 8 && n_left_to_next >= 4)
2469 {
2470 u32 bi0, bi1, bi2, bi3;
2471 vlib_buffer_t *b0, *b1, *b2, *b3;
2472 u32 next0, next1, next2, next3;
2473 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2474 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2475 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2476 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2477 u16 new_l0, new_l1, new_l2, new_l3;
2478
2479 /* Prefetch next iteration. */
2480 {
2481 vlib_buffer_t *p4, *p5, *p6, *p7;
2482
2483 p4 = vlib_get_buffer (vm, from[4]);
2484 p5 = vlib_get_buffer (vm, from[5]);
2485 p6 = vlib_get_buffer (vm, from[6]);
2486 p7 = vlib_get_buffer (vm, from[7]);
2487
2488 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2489 vlib_prefetch_buffer_header (p4, LOAD);
2490 vlib_prefetch_buffer_header (p5, LOAD);
2491 vlib_prefetch_buffer_header (p6, LOAD);
2492 vlib_prefetch_buffer_header (p7, LOAD);
2493
2494 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2495 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2496 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2497 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2498 }
2499
2500 to_next[0] = bi0 = from[0];
2501 to_next[1] = bi1 = from[1];
2502 to_next[2] = bi2 = from[2];
2503 to_next[3] = bi3 = from[3];
2504 from += 4;
2505 to_next += 4;
2506 n_left_from -= 4;
2507 n_left_to_next -= 4;
2508
2509 b0 = vlib_get_buffer (vm, bi0);
2510 b1 = vlib_get_buffer (vm, bi1);
2511 b2 = vlib_get_buffer (vm, bi2);
2512 b3 = vlib_get_buffer (vm, bi3);
2513
2514 sl0 =
2515 pool_elt_at_index (sm->sid_lists,
2516 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2517 sl1 =
2518 pool_elt_at_index (sm->sid_lists,
2519 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2520 sl2 =
2521 pool_elt_at_index (sm->sid_lists,
2522 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2523 sl3 =
2524 pool_elt_at_index (sm->sid_lists,
2525 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00002526 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2527 vec_len (sl0->rewrite_bsid));
2528 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2529 vec_len (sl1->rewrite_bsid));
2530 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2531 vec_len (sl2->rewrite_bsid));
2532 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2533 vec_len (sl3->rewrite_bsid));
Pablo Camarillofb380952016-12-07 18:34:18 +01002534
2535 ip0 = vlib_buffer_get_current (b0);
2536 ip1 = vlib_buffer_get_current (b1);
2537 ip2 = vlib_buffer_get_current (b2);
2538 ip3 = vlib_buffer_get_current (b3);
2539
2540 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2541 sr0 =
2542 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2543 ip6_ext_header_len (ip0 + 1));
2544 else
2545 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2546
2547 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2548 sr1 =
2549 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2550 ip6_ext_header_len (ip1 + 1));
2551 else
2552 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2553
2554 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2555 sr2 =
2556 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2557 ip6_ext_header_len (ip2 + 1));
2558 else
2559 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2560
2561 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2562 sr3 =
2563 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2564 ip6_ext_header_len (ip3 + 1));
2565 else
2566 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2567
2568 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite_bsid), (u8 *) ip0,
2569 (void *) sr0 - (void *) ip0);
2570 clib_memcpy ((u8 *) ip1 - vec_len (sl1->rewrite_bsid), (u8 *) ip1,
2571 (void *) sr1 - (void *) ip1);
2572 clib_memcpy ((u8 *) ip2 - vec_len (sl2->rewrite_bsid), (u8 *) ip2,
2573 (void *) sr2 - (void *) ip2);
2574 clib_memcpy ((u8 *) ip3 - vec_len (sl3->rewrite_bsid), (u8 *) ip3,
2575 (void *) sr3 - (void *) ip3);
2576
2577 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2578 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2579 clib_memcpy (((u8 *) sr1 - vec_len (sl1->rewrite_bsid)),
2580 sl1->rewrite_bsid, vec_len (sl1->rewrite_bsid));
2581 clib_memcpy (((u8 *) sr2 - vec_len (sl2->rewrite_bsid)),
2582 sl2->rewrite_bsid, vec_len (sl2->rewrite_bsid));
2583 clib_memcpy (((u8 *) sr3 - vec_len (sl3->rewrite_bsid)),
2584 sl3->rewrite_bsid, vec_len (sl3->rewrite_bsid));
2585
2586 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2587 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite_bsid));
2588 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite_bsid));
2589 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite_bsid));
2590
2591 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2592 ip1 = ((void *) ip1) - vec_len (sl1->rewrite_bsid);
2593 ip2 = ((void *) ip2) - vec_len (sl2->rewrite_bsid);
2594 ip3 = ((void *) ip3) - vec_len (sl3->rewrite_bsid);
2595
2596 ip0->hop_limit -= 1;
2597 ip1->hop_limit -= 1;
2598 ip2->hop_limit -= 1;
2599 ip3->hop_limit -= 1;
2600
2601 new_l0 =
2602 clib_net_to_host_u16 (ip0->payload_length) +
2603 vec_len (sl0->rewrite_bsid);
2604 new_l1 =
2605 clib_net_to_host_u16 (ip1->payload_length) +
2606 vec_len (sl1->rewrite_bsid);
2607 new_l2 =
2608 clib_net_to_host_u16 (ip2->payload_length) +
2609 vec_len (sl2->rewrite_bsid);
2610 new_l3 =
2611 clib_net_to_host_u16 (ip3->payload_length) +
2612 vec_len (sl3->rewrite_bsid);
2613
2614 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2615 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2616 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2617 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2618
2619 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2620 sr1 = ((void *) sr1) - vec_len (sl1->rewrite_bsid);
2621 sr2 = ((void *) sr2) - vec_len (sl2->rewrite_bsid);
2622 sr3 = ((void *) sr3) - vec_len (sl3->rewrite_bsid);
2623
2624 ip0->dst_address.as_u64[0] =
2625 (sr0->segments + sr0->segments_left)->as_u64[0];
2626 ip0->dst_address.as_u64[1] =
2627 (sr0->segments + sr0->segments_left)->as_u64[1];
2628 ip1->dst_address.as_u64[0] =
2629 (sr1->segments + sr1->segments_left)->as_u64[0];
2630 ip1->dst_address.as_u64[1] =
2631 (sr1->segments + sr1->segments_left)->as_u64[1];
2632 ip2->dst_address.as_u64[0] =
2633 (sr2->segments + sr2->segments_left)->as_u64[0];
2634 ip2->dst_address.as_u64[1] =
2635 (sr2->segments + sr2->segments_left)->as_u64[1];
2636 ip3->dst_address.as_u64[0] =
2637 (sr3->segments + sr3->segments_left)->as_u64[0];
2638 ip3->dst_address.as_u64[1] =
2639 (sr3->segments + sr3->segments_left)->as_u64[1];
2640
2641 ip6_ext_header_t *ip_ext;
2642 if (ip0 + 1 == (void *) sr0)
2643 {
2644 sr0->protocol = ip0->protocol;
2645 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2646 }
2647 else
2648 {
2649 ip_ext = (void *) (ip0 + 1);
2650 sr0->protocol = ip_ext->next_hdr;
2651 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2652 }
2653
2654 if (ip1 + 1 == (void *) sr1)
2655 {
2656 sr1->protocol = ip1->protocol;
2657 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2658 }
2659 else
2660 {
2661 ip_ext = (void *) (ip2 + 1);
2662 sr2->protocol = ip_ext->next_hdr;
2663 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2664 }
2665
2666 if (ip2 + 1 == (void *) sr2)
2667 {
2668 sr2->protocol = ip2->protocol;
2669 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2670 }
2671 else
2672 {
2673 ip_ext = (void *) (ip2 + 1);
2674 sr2->protocol = ip_ext->next_hdr;
2675 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2676 }
2677
2678 if (ip3 + 1 == (void *) sr3)
2679 {
2680 sr3->protocol = ip3->protocol;
2681 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2682 }
2683 else
2684 {
2685 ip_ext = (void *) (ip3 + 1);
2686 sr3->protocol = ip_ext->next_hdr;
2687 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2688 }
2689
2690 insert_pkts += 4;
2691
2692 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2693 {
2694 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2695 {
2696 sr_policy_rewrite_trace_t *tr =
2697 vlib_add_trace (vm, node, b0, sizeof (*tr));
2698 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2699 sizeof (tr->src.as_u8));
2700 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2701 sizeof (tr->dst.as_u8));
2702 }
2703
2704 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2705 {
2706 sr_policy_rewrite_trace_t *tr =
2707 vlib_add_trace (vm, node, b1, sizeof (*tr));
2708 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2709 sizeof (tr->src.as_u8));
2710 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2711 sizeof (tr->dst.as_u8));
2712 }
2713
2714 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2715 {
2716 sr_policy_rewrite_trace_t *tr =
2717 vlib_add_trace (vm, node, b2, sizeof (*tr));
2718 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
2719 sizeof (tr->src.as_u8));
2720 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
2721 sizeof (tr->dst.as_u8));
2722 }
2723
2724 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2725 {
2726 sr_policy_rewrite_trace_t *tr =
2727 vlib_add_trace (vm, node, b3, sizeof (*tr));
2728 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
2729 sizeof (tr->src.as_u8));
2730 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
2731 sizeof (tr->dst.as_u8));
2732 }
2733 }
2734
2735 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2736 n_left_to_next, bi0, bi1, bi2, bi3,
2737 next0, next1, next2, next3);
2738 }
2739
2740 /* Single loop for potentially the last three packets */
2741 while (n_left_from > 0 && n_left_to_next > 0)
2742 {
2743 u32 bi0;
2744 vlib_buffer_t *b0;
2745 ip6_header_t *ip0 = 0;
2746 ip6_sr_header_t *sr0 = 0;
2747 ip6_sr_sl_t *sl0;
2748 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2749 u16 new_l0 = 0;
2750
2751 bi0 = from[0];
2752 to_next[0] = bi0;
2753 from += 1;
2754 to_next += 1;
2755 n_left_from -= 1;
2756 n_left_to_next -= 1;
2757
2758 b0 = vlib_get_buffer (vm, bi0);
2759 sl0 =
2760 pool_elt_at_index (sm->sid_lists,
2761 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00002762 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2763 vec_len (sl0->rewrite_bsid));
Pablo Camarillofb380952016-12-07 18:34:18 +01002764
2765 ip0 = vlib_buffer_get_current (b0);
2766
2767 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2768 sr0 =
2769 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2770 ip6_ext_header_len (ip0 + 1));
2771 else
2772 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2773
2774 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite_bsid), (u8 *) ip0,
2775 (void *) sr0 - (void *) ip0);
2776 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2777 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2778
2779 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2780
2781 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2782 ip0->hop_limit -= 1;
2783 new_l0 =
2784 clib_net_to_host_u16 (ip0->payload_length) +
2785 vec_len (sl0->rewrite_bsid);
2786 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2787
2788 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2789
2790 ip0->dst_address.as_u64[0] =
2791 (sr0->segments + sr0->segments_left)->as_u64[0];
2792 ip0->dst_address.as_u64[1] =
2793 (sr0->segments + sr0->segments_left)->as_u64[1];
2794
2795 if (ip0 + 1 == (void *) sr0)
2796 {
2797 sr0->protocol = ip0->protocol;
2798 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2799 }
2800 else
2801 {
2802 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2803 sr0->protocol = ip_ext->next_hdr;
2804 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2805 }
2806
2807 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2808 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2809 {
2810 sr_policy_rewrite_trace_t *tr =
2811 vlib_add_trace (vm, node, b0, sizeof (*tr));
2812 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2813 sizeof (tr->src.as_u8));
2814 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2815 sizeof (tr->dst.as_u8));
2816 }
2817
2818 insert_pkts++;
2819
2820 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2821 n_left_to_next, bi0, next0);
2822 }
2823
2824 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2825 }
2826
2827 /* Update counters */
2828 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2829 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2830 insert_pkts);
2831 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2832 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2833 bsid_pkts);
2834 return from_frame->n_vectors;
2835}
2836
2837/* *INDENT-OFF* */
2838VLIB_REGISTER_NODE (sr_policy_rewrite_b_insert_node) = {
2839 .function = sr_policy_rewrite_b_insert,
2840 .name = "sr-pl-rewrite-b-insert",
2841 .vector_size = sizeof (u32),
2842 .format_trace = format_sr_policy_rewrite_trace,
2843 .type = VLIB_NODE_TYPE_INTERNAL,
2844 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2845 .error_strings = sr_policy_rewrite_error_strings,
2846 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2847 .next_nodes = {
2848#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2849 foreach_sr_policy_rewrite_next
2850#undef _
2851 },
2852};
2853/* *INDENT-ON* */
2854
2855/**
2856 * @brief Function BSID encapsulation
2857 */
2858static_always_inline void
2859end_bsid_encaps_srh_processing (vlib_node_runtime_t * node,
2860 vlib_buffer_t * b0,
2861 ip6_header_t * ip0,
2862 ip6_sr_header_t * sr0, u32 * next0)
2863{
2864 ip6_address_t *new_dst0;
2865
2866 if (PREDICT_FALSE (!sr0))
2867 goto error_bsid_encaps;
2868
2869 if (PREDICT_TRUE (sr0->type == ROUTING_HEADER_TYPE_SR))
2870 {
2871 if (PREDICT_TRUE (sr0->segments_left != 0))
2872 {
2873 sr0->segments_left -= 1;
2874 new_dst0 = (ip6_address_t *) (sr0->segments);
2875 new_dst0 += sr0->segments_left;
2876 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
2877 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
2878 return;
2879 }
2880 }
2881
2882error_bsid_encaps:
2883 *next0 = SR_POLICY_REWRITE_NEXT_ERROR;
2884 b0->error = node->errors[SR_POLICY_REWRITE_ERROR_BSID_ZERO];
2885}
2886
2887/**
2888 * @brief Graph node for applying a SR policy BSID - Encapsulation
2889 */
2890static uword
2891sr_policy_rewrite_b_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
2892 vlib_frame_t * from_frame)
2893{
2894 ip6_sr_main_t *sm = &sr_main;
2895 u32 n_left_from, next_index, *from, *to_next;
2896
2897 from = vlib_frame_vector_args (from_frame);
2898 n_left_from = from_frame->n_vectors;
2899
2900 next_index = node->cached_next_index;
2901
2902 int encap_pkts = 0, bsid_pkts = 0;
2903
2904 while (n_left_from > 0)
2905 {
2906 u32 n_left_to_next;
2907
2908 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2909
2910 /* Quad - Loop */
2911 while (n_left_from >= 8 && n_left_to_next >= 4)
2912 {
2913 u32 bi0, bi1, bi2, bi3;
2914 vlib_buffer_t *b0, *b1, *b2, *b3;
2915 u32 next0, next1, next2, next3;
2916 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2917 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2918 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
2919 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2920 ip6_ext_header_t *prev0, *prev1, *prev2, *prev3;
2921 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2922
2923 /* Prefetch next iteration. */
2924 {
2925 vlib_buffer_t *p4, *p5, *p6, *p7;
2926
2927 p4 = vlib_get_buffer (vm, from[4]);
2928 p5 = vlib_get_buffer (vm, from[5]);
2929 p6 = vlib_get_buffer (vm, from[6]);
2930 p7 = vlib_get_buffer (vm, from[7]);
2931
2932 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2933 vlib_prefetch_buffer_header (p4, LOAD);
2934 vlib_prefetch_buffer_header (p5, LOAD);
2935 vlib_prefetch_buffer_header (p6, LOAD);
2936 vlib_prefetch_buffer_header (p7, LOAD);
2937
2938 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2939 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2940 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2941 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2942 }
2943
2944 to_next[0] = bi0 = from[0];
2945 to_next[1] = bi1 = from[1];
2946 to_next[2] = bi2 = from[2];
2947 to_next[3] = bi3 = from[3];
2948 from += 4;
2949 to_next += 4;
2950 n_left_from -= 4;
2951 n_left_to_next -= 4;
2952
2953 b0 = vlib_get_buffer (vm, bi0);
2954 b1 = vlib_get_buffer (vm, bi1);
2955 b2 = vlib_get_buffer (vm, bi2);
2956 b3 = vlib_get_buffer (vm, bi3);
2957
2958 sl0 =
2959 pool_elt_at_index (sm->sid_lists,
2960 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2961 sl1 =
2962 pool_elt_at_index (sm->sid_lists,
2963 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2964 sl2 =
2965 pool_elt_at_index (sm->sid_lists,
2966 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2967 sl3 =
2968 pool_elt_at_index (sm->sid_lists,
2969 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00002970 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2971 vec_len (sl0->rewrite));
2972 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2973 vec_len (sl1->rewrite));
2974 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2975 vec_len (sl2->rewrite));
2976 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2977 vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002978
2979 ip0_encap = vlib_buffer_get_current (b0);
2980 ip1_encap = vlib_buffer_get_current (b1);
2981 ip2_encap = vlib_buffer_get_current (b2);
2982 ip3_encap = vlib_buffer_get_current (b3);
2983
2984 ip6_ext_header_find_t (ip0_encap, prev0, sr0,
2985 IP_PROTOCOL_IPV6_ROUTE);
2986 ip6_ext_header_find_t (ip1_encap, prev1, sr1,
2987 IP_PROTOCOL_IPV6_ROUTE);
2988 ip6_ext_header_find_t (ip2_encap, prev2, sr2,
2989 IP_PROTOCOL_IPV6_ROUTE);
2990 ip6_ext_header_find_t (ip3_encap, prev3, sr3,
2991 IP_PROTOCOL_IPV6_ROUTE);
2992
2993 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
2994 end_bsid_encaps_srh_processing (node, b1, ip1_encap, sr1, &next1);
2995 end_bsid_encaps_srh_processing (node, b2, ip2_encap, sr2, &next2);
2996 end_bsid_encaps_srh_processing (node, b3, ip3_encap, sr3, &next3);
2997
2998 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
2999 sl0->rewrite, vec_len (sl0->rewrite));
3000 clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
3001 sl1->rewrite, vec_len (sl1->rewrite));
3002 clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
3003 sl2->rewrite, vec_len (sl2->rewrite));
3004 clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
3005 sl3->rewrite, vec_len (sl3->rewrite));
3006
3007 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3008 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
3009 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
3010 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
3011
3012 ip0 = vlib_buffer_get_current (b0);
3013 ip1 = vlib_buffer_get_current (b1);
3014 ip2 = vlib_buffer_get_current (b2);
3015 ip3 = vlib_buffer_get_current (b3);
3016
3017 encaps_processing_v6 (node, b0, ip0, ip0_encap);
3018 encaps_processing_v6 (node, b1, ip1, ip1_encap);
3019 encaps_processing_v6 (node, b2, ip2, ip2_encap);
3020 encaps_processing_v6 (node, b3, ip3, ip3_encap);
3021
3022 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
3023 {
3024 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3025 {
3026 sr_policy_rewrite_trace_t *tr =
3027 vlib_add_trace (vm, node, b0, sizeof (*tr));
3028 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
3029 sizeof (tr->src.as_u8));
3030 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
3031 sizeof (tr->dst.as_u8));
3032 }
3033
3034 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
3035 {
3036 sr_policy_rewrite_trace_t *tr =
3037 vlib_add_trace (vm, node, b1, sizeof (*tr));
3038 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
3039 sizeof (tr->src.as_u8));
3040 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
3041 sizeof (tr->dst.as_u8));
3042 }
3043
3044 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
3045 {
3046 sr_policy_rewrite_trace_t *tr =
3047 vlib_add_trace (vm, node, b2, sizeof (*tr));
3048 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
3049 sizeof (tr->src.as_u8));
3050 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
3051 sizeof (tr->dst.as_u8));
3052 }
3053
3054 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
3055 {
3056 sr_policy_rewrite_trace_t *tr =
3057 vlib_add_trace (vm, node, b3, sizeof (*tr));
3058 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
3059 sizeof (tr->src.as_u8));
3060 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
3061 sizeof (tr->dst.as_u8));
3062 }
3063 }
3064
3065 encap_pkts += 4;
3066 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
3067 n_left_to_next, bi0, bi1, bi2, bi3,
3068 next0, next1, next2, next3);
3069 }
3070
3071 /* Single loop for potentially the last three packets */
3072 while (n_left_from > 0 && n_left_to_next > 0)
3073 {
3074 u32 bi0;
3075 vlib_buffer_t *b0;
3076 ip6_header_t *ip0 = 0, *ip0_encap = 0;
3077 ip6_ext_header_t *prev0;
3078 ip6_sr_header_t *sr0;
3079 ip6_sr_sl_t *sl0;
3080 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3081
3082 bi0 = from[0];
3083 to_next[0] = bi0;
3084 from += 1;
3085 to_next += 1;
3086 n_left_from -= 1;
3087 n_left_to_next -= 1;
3088 b0 = vlib_get_buffer (vm, bi0);
3089
3090 sl0 =
3091 pool_elt_at_index (sm->sid_lists,
3092 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00003093 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3094 vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01003095
3096 ip0_encap = vlib_buffer_get_current (b0);
3097 ip6_ext_header_find_t (ip0_encap, prev0, sr0,
3098 IP_PROTOCOL_IPV6_ROUTE);
3099 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
3100
3101 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3102 sl0->rewrite, vec_len (sl0->rewrite));
3103 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3104
3105 ip0 = vlib_buffer_get_current (b0);
3106
3107 encaps_processing_v6 (node, b0, ip0, ip0_encap);
3108
3109 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3110 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3111 {
3112 sr_policy_rewrite_trace_t *tr =
3113 vlib_add_trace (vm, node, b0, sizeof (*tr));
3114 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
3115 sizeof (tr->src.as_u8));
3116 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
3117 sizeof (tr->dst.as_u8));
3118 }
3119
3120 encap_pkts++;
3121 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3122 n_left_to_next, bi0, next0);
3123 }
3124
3125 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3126 }
3127
3128 /* Update counters */
3129 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3130 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3131 encap_pkts);
3132 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3133 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3134 bsid_pkts);
3135
3136 return from_frame->n_vectors;
3137}
3138
3139/* *INDENT-OFF* */
3140VLIB_REGISTER_NODE (sr_policy_rewrite_b_encaps_node) = {
3141 .function = sr_policy_rewrite_b_encaps,
3142 .name = "sr-pl-rewrite-b-encaps",
3143 .vector_size = sizeof (u32),
3144 .format_trace = format_sr_policy_rewrite_trace,
3145 .type = VLIB_NODE_TYPE_INTERNAL,
3146 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3147 .error_strings = sr_policy_rewrite_error_strings,
3148 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3149 .next_nodes = {
3150#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3151 foreach_sr_policy_rewrite_next
3152#undef _
3153 },
3154};
3155/* *INDENT-ON* */
3156
3157/*************************** SR Segment Lists DPOs ****************************/
3158static u8 *
3159format_sr_segment_list_dpo (u8 * s, va_list * args)
3160{
3161 ip6_sr_main_t *sm = &sr_main;
3162 ip6_address_t *addr;
3163 ip6_sr_sl_t *sl;
3164
3165 index_t index = va_arg (*args, index_t);
3166 CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
3167 s = format (s, "SR: Segment List index:[%d]", index);
3168 s = format (s, "\n\tSegments:");
3169
3170 sl = pool_elt_at_index (sm->sid_lists, index);
3171
3172 s = format (s, "< ");
3173 vec_foreach (addr, sl->segments)
3174 {
3175 s = format (s, "%U, ", format_ip6_address, addr);
3176 }
3177 s = format (s, "\b\b > - ");
3178 s = format (s, "Weight: %u", sl->weight);
3179
3180 return s;
3181}
3182
3183const static dpo_vft_t sr_policy_rewrite_vft = {
3184 .dv_lock = sr_dpo_lock,
3185 .dv_unlock = sr_dpo_unlock,
3186 .dv_format = format_sr_segment_list_dpo,
3187};
3188
3189const static char *const sr_pr_encaps_ip6_nodes[] = {
3190 "sr-pl-rewrite-encaps",
3191 NULL,
3192};
3193
3194const static char *const sr_pr_encaps_ip4_nodes[] = {
3195 "sr-pl-rewrite-encaps-v4",
3196 NULL,
3197};
3198
3199const static char *const *const sr_pr_encaps_nodes[DPO_PROTO_NUM] = {
3200 [DPO_PROTO_IP6] = sr_pr_encaps_ip6_nodes,
3201 [DPO_PROTO_IP4] = sr_pr_encaps_ip4_nodes,
3202};
3203
3204const static char *const sr_pr_insert_ip6_nodes[] = {
3205 "sr-pl-rewrite-insert",
3206 NULL,
3207};
3208
3209const static char *const *const sr_pr_insert_nodes[DPO_PROTO_NUM] = {
3210 [DPO_PROTO_IP6] = sr_pr_insert_ip6_nodes,
3211};
3212
3213const static char *const sr_pr_bsid_insert_ip6_nodes[] = {
3214 "sr-pl-rewrite-b-insert",
3215 NULL,
3216};
3217
3218const static char *const *const sr_pr_bsid_insert_nodes[DPO_PROTO_NUM] = {
3219 [DPO_PROTO_IP6] = sr_pr_bsid_insert_ip6_nodes,
3220};
3221
3222const static char *const sr_pr_bsid_encaps_ip6_nodes[] = {
3223 "sr-pl-rewrite-b-encaps",
3224 NULL,
3225};
3226
3227const static char *const *const sr_pr_bsid_encaps_nodes[DPO_PROTO_NUM] = {
3228 [DPO_PROTO_IP6] = sr_pr_bsid_encaps_ip6_nodes,
3229};
3230
3231/********************* SR Policy Rewrite initialization ***********************/
3232/**
3233 * @brief SR Policy Rewrite initialization
3234 */
3235clib_error_t *
3236sr_policy_rewrite_init (vlib_main_t * vm)
3237{
3238 ip6_sr_main_t *sm = &sr_main;
3239
3240 /* Init memory for sr policy keys (bsid <-> ip6_address_t) */
Pablo Camarillo4521afa2017-03-16 10:43:05 +01003241 mhash_init (&sm->sr_policies_index_hash, sizeof (uword),
3242 sizeof (ip6_address_t));
Pablo Camarillofb380952016-12-07 18:34:18 +01003243
3244 /* Init SR VPO DPOs type */
3245 sr_pr_encaps_dpo_type =
3246 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_encaps_nodes);
3247
3248 sr_pr_insert_dpo_type =
3249 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_insert_nodes);
3250
3251 sr_pr_bsid_encaps_dpo_type =
3252 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_encaps_nodes);
3253
3254 sr_pr_bsid_insert_dpo_type =
3255 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_insert_nodes);
3256
3257 /* Register the L2 encaps node used in HW redirect */
3258 sm->l2_sr_policy_rewrite_index = sr_policy_rewrite_encaps_node.index;
3259
3260 sm->fib_table_ip6 = (u32) ~ 0;
3261 sm->fib_table_ip4 = (u32) ~ 0;
3262
3263 return 0;
3264}
3265
3266VLIB_INIT_FUNCTION (sr_policy_rewrite_init);
3267
3268
3269/*
3270* fd.io coding-style-patch-verification: ON
3271*
3272* Local Variables:
3273* eval: (c-set-style "gnu")
3274* End:
3275*/