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