Line data Source code
1 : /*
2 : * sr_localsid.c: ipv6 segment routing Endpoint behaviors
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 Processing of packets with a SRH
21 : *
22 : * CLI to define new Segment Routing End processing functions.
23 : * Graph node to support such functions.
24 : *
25 : * Each function associates an SRv6 segment (IPv6 address) with an specific
26 : * Segment Routing function.
27 : *
28 : */
29 :
30 : #include <vlib/vlib.h>
31 : #include <vnet/vnet.h>
32 : #include <vnet/srv6/sr.h>
33 : #include <vnet/ip/ip.h>
34 : #include <vnet/srv6/sr_packet.h>
35 : #include <vnet/ip/ip6_packet.h>
36 : #include <vnet/fib/ip6_fib.h>
37 : #include <vnet/dpo/dpo.h>
38 : #include <vnet/adj/adj.h>
39 :
40 : #include <vppinfra/error.h>
41 : #include <vppinfra/elog.h>
42 :
43 : /**
44 : * @brief Dynamically added SR localsid DPO type
45 : */
46 : static dpo_type_t sr_localsid_dpo_type;
47 : static dpo_type_t sr_localsid_d_dpo_type;
48 : static dpo_type_t sr_localsid_un_dpo_type;
49 : static dpo_type_t sr_localsid_un_perf_dpo_type;
50 :
51 : static void
52 49 : sr_localsid_key_create (sr_localsid_key_t * key, ip6_address_t * addr,
53 : u16 pref_len)
54 : {
55 49 : clib_memset (key, 0, sizeof (sr_localsid_key_t));
56 49 : clib_memcpy (&key->address, addr, sizeof (ip6_address_t));
57 49 : key->pref_len = pref_len;
58 49 : }
59 :
60 : /**
61 : * @brief SR localsid add/del
62 : *
63 : * Function to add or delete SR LocalSIDs.
64 : *
65 : * @param is_del Boolean of whether its a delete instruction
66 : * @param localsid_addr IPv6 address of the localsid
67 : * @param is_decap Boolean of whether decapsulation is allowed in this function
68 : * @param behavior Type of behavior (function) for this localsid
69 : * @param sw_if_index Only for L2/L3 xconnect. OIF. In VRF variant the fib_table.
70 : * @param vlan_index Only for L2 xconnect. Outgoing VLAN tag.
71 : * @param fib_table FIB table in which we should install the localsid entry
72 : * @param nh_addr Next Hop IPv4/IPv6 address. Only for L2/L3 xconnect.
73 : *
74 : * @return 0 on success, error otherwise.
75 : */
76 : int
77 49 : sr_cli_localsid (char is_del, ip6_address_t * localsid_addr,
78 : u16 localsid_prefix_len, char end_psp, u8 behavior,
79 : u32 sw_if_index, u32 vlan_index, u32 fib_table,
80 : ip46_address_t * nh_addr, int usid_len, void *ls_plugin_mem)
81 : {
82 49 : ip6_sr_main_t *sm = &sr_main;
83 : uword *p;
84 : int rv;
85 49 : u8 pref_length = 128;
86 49 : sr_localsid_fn_registration_t *plugin = 0;
87 : sr_localsid_key_t key;
88 :
89 49 : ip6_sr_localsid_t *ls = 0;
90 :
91 49 : dpo_id_t dpo = DPO_INVALID;
92 :
93 : /* Search for the item */
94 49 : sr_localsid_key_create (&key, localsid_addr, localsid_prefix_len);
95 49 : p = mhash_get (&sm->sr_localsids_index_hash, &key);
96 :
97 49 : if (p)
98 : {
99 20 : if (is_del)
100 : {
101 : /* Retrieve localsid */
102 20 : ls = pool_elt_at_index (sm->localsids, p[0]);
103 20 : if (ls->behavior >= SR_BEHAVIOR_LAST)
104 : {
105 11 : plugin = pool_elt_at_index (sm->plugin_functions,
106 : ls->behavior - SR_BEHAVIOR_LAST);
107 11 : pref_length = plugin->prefix_length;
108 : }
109 :
110 20 : if (localsid_prefix_len != 0)
111 : {
112 9 : pref_length = localsid_prefix_len;
113 : }
114 :
115 : /* Delete FIB entry */
116 20 : fib_prefix_t pfx = {
117 : .fp_proto = FIB_PROTOCOL_IP6,
118 : .fp_len = pref_length,
119 : .fp_addr = {
120 : .ip6 = *localsid_addr,
121 : }
122 : };
123 :
124 20 : fib_table_entry_delete (fib_table_find
125 : (FIB_PROTOCOL_IP6, fib_table), &pfx,
126 : FIB_SOURCE_SR);
127 :
128 : /* In case it is a Xconnect iface remove the (OIF, NHOP) adj */
129 20 : if (ls->behavior == SR_BEHAVIOR_X || ls->behavior == SR_BEHAVIOR_DX6
130 17 : || ls->behavior == SR_BEHAVIOR_DX4)
131 4 : adj_unlock (ls->nh_adj);
132 :
133 20 : if (ls->behavior >= SR_BEHAVIOR_LAST)
134 : {
135 : /* Callback plugin removal function */
136 11 : rv = plugin->removal (ls);
137 : }
138 :
139 : /* Delete localsid registry */
140 20 : pool_put (sm->localsids, ls);
141 20 : mhash_unset (&sm->sr_localsids_index_hash, &key, NULL);
142 20 : return 0;
143 : }
144 : else /* create with function already existing; complain */
145 0 : return -1;
146 : }
147 : else
148 : /* delete; localsid does not exist; complain */
149 29 : if (is_del)
150 0 : return -2;
151 :
152 29 : if (behavior >= SR_BEHAVIOR_LAST)
153 : {
154 14 : sr_localsid_fn_registration_t *plugin = 0;
155 14 : plugin =
156 14 : pool_elt_at_index (sm->plugin_functions, behavior - SR_BEHAVIOR_LAST);
157 14 : pref_length = plugin->prefix_length;
158 : }
159 :
160 29 : if (localsid_prefix_len != 0)
161 : {
162 17 : pref_length = localsid_prefix_len;
163 : }
164 :
165 : /* Check whether there exists a FIB entry with such address */
166 29 : fib_prefix_t pfx = {
167 : .fp_proto = FIB_PROTOCOL_IP6,
168 : .fp_len = pref_length,
169 : };
170 :
171 29 : pfx.fp_addr.as_u64[0] = localsid_addr->as_u64[0];
172 29 : pfx.fp_addr.as_u64[1] = localsid_addr->as_u64[1];
173 29 : pfx.fp_len = pref_length;
174 :
175 : /* Lookup the FIB index associated to the table id provided */
176 29 : u32 fib_index = fib_table_find (FIB_PROTOCOL_IP6, fib_table);
177 29 : if (fib_index == ~0)
178 0 : return -3;
179 :
180 : /* Lookup the localsid in such FIB table */
181 29 : fib_node_index_t fei = fib_table_lookup_exact_match (fib_index, &pfx);
182 29 : if (FIB_NODE_INDEX_INVALID != fei)
183 0 : return -4; //There is an entry for such address (the localsid addr)
184 :
185 : /* Create a new localsid registry */
186 29 : pool_get (sm->localsids, ls);
187 29 : clib_memset (ls, 0, sizeof (*ls));
188 :
189 29 : clib_memcpy (&ls->localsid, localsid_addr, sizeof (ip6_address_t));
190 29 : ls->localsid_prefix_len = pref_length;
191 29 : ls->end_psp = end_psp;
192 29 : ls->behavior = behavior;
193 29 : ls->nh_adj = (u32) ~ 0;
194 29 : ls->fib_table = fib_table;
195 29 : switch (behavior)
196 : {
197 4 : case SR_BEHAVIOR_END:
198 4 : break;
199 4 : case SR_BEHAVIOR_END_UN:
200 : case SR_BEHAVIOR_END_UN_PERF:
201 4 : if (usid_len)
202 : {
203 : int usid_width;
204 4 : clib_memcpy (&ls->usid_block, localsid_addr,
205 : sizeof (ip6_address_t));
206 :
207 4 : usid_width = pref_length - usid_len;
208 4 : ip6_address_mask_from_width (&ls->usid_block_mask, usid_width);
209 :
210 4 : ls->usid_index = usid_width / 8;
211 4 : ls->usid_len = usid_len / 8;
212 4 : ls->usid_next_index = ls->usid_index + ls->usid_len;
213 4 : ls->usid_next_len = 16 - ls->usid_next_index;
214 : }
215 4 : break;
216 2 : case SR_BEHAVIOR_X:
217 2 : ls->sw_if_index = sw_if_index;
218 2 : clib_memcpy (&ls->next_hop.ip6, &nh_addr->ip6, sizeof (ip6_address_t));
219 2 : break;
220 0 : case SR_BEHAVIOR_T:
221 0 : ls->vrf_index = fib_table_find (FIB_PROTOCOL_IP6, sw_if_index);
222 0 : break;
223 1 : case SR_BEHAVIOR_DX4:
224 1 : ls->sw_if_index = sw_if_index;
225 1 : clib_memcpy (&ls->next_hop.ip4, &nh_addr->ip4, sizeof (ip4_address_t));
226 1 : break;
227 1 : case SR_BEHAVIOR_DX6:
228 1 : ls->sw_if_index = sw_if_index;
229 1 : clib_memcpy (&ls->next_hop.ip6, &nh_addr->ip6, sizeof (ip6_address_t));
230 1 : break;
231 1 : case SR_BEHAVIOR_DT6:
232 1 : ls->vrf_index = fib_table_find (FIB_PROTOCOL_IP6, sw_if_index);
233 1 : break;
234 1 : case SR_BEHAVIOR_DT4:
235 1 : ls->vrf_index = fib_table_find (FIB_PROTOCOL_IP4, sw_if_index);
236 1 : break;
237 1 : case SR_BEHAVIOR_DX2:
238 1 : ls->sw_if_index = sw_if_index;
239 1 : ls->vlan_index = vlan_index;
240 1 : break;
241 : }
242 :
243 : /* Figure out the adjacency magic for Xconnect variants */
244 29 : if (ls->behavior == SR_BEHAVIOR_X || ls->behavior == SR_BEHAVIOR_DX4
245 26 : || ls->behavior == SR_BEHAVIOR_DX6)
246 : {
247 4 : adj_index_t nh_adj_index = ADJ_INDEX_INVALID;
248 :
249 : /* Retrieve the adjacency corresponding to the (OIF, next_hop) */
250 4 : if (ls->behavior == SR_BEHAVIOR_DX6 || ls->behavior == SR_BEHAVIOR_X)
251 3 : nh_adj_index = adj_nbr_add_or_lock (FIB_PROTOCOL_IP6, VNET_LINK_IP6,
252 : nh_addr, sw_if_index);
253 :
254 1 : else if (ls->behavior == SR_BEHAVIOR_DX4)
255 1 : nh_adj_index = adj_nbr_add_or_lock (FIB_PROTOCOL_IP4, VNET_LINK_IP4,
256 : nh_addr, sw_if_index);
257 :
258 : /* Check for ADJ creation error. If so panic */
259 4 : if (nh_adj_index == ADJ_INDEX_INVALID)
260 : {
261 0 : pool_put (sm->localsids, ls);
262 0 : return -5;
263 : }
264 :
265 4 : ls->nh_adj = nh_adj_index;
266 : }
267 :
268 : /* Set DPO */
269 29 : if (ls->behavior == SR_BEHAVIOR_END || ls->behavior == SR_BEHAVIOR_X
270 23 : || ls->behavior == SR_BEHAVIOR_T)
271 6 : dpo_set (&dpo, sr_localsid_dpo_type, DPO_PROTO_IP6, ls - sm->localsids);
272 23 : else if (ls->behavior == SR_BEHAVIOR_END_UN)
273 2 : dpo_set (&dpo, sr_localsid_un_dpo_type, DPO_PROTO_IP6,
274 2 : ls - sm->localsids);
275 21 : else if (ls->behavior == SR_BEHAVIOR_END_UN_PERF)
276 2 : dpo_set (&dpo, sr_localsid_un_perf_dpo_type, DPO_PROTO_IP6,
277 2 : ls - sm->localsids);
278 19 : else if (ls->behavior > SR_BEHAVIOR_D_FIRST
279 19 : && ls->behavior < SR_BEHAVIOR_LAST)
280 5 : dpo_set (&dpo, sr_localsid_d_dpo_type, DPO_PROTO_IP6, ls - sm->localsids);
281 14 : else if (ls->behavior >= SR_BEHAVIOR_LAST)
282 : {
283 14 : sr_localsid_fn_registration_t *plugin = 0;
284 14 : plugin = pool_elt_at_index (sm->plugin_functions,
285 : ls->behavior - SR_BEHAVIOR_LAST);
286 : /* Copy the unformat memory result */
287 14 : ls->plugin_mem = ls_plugin_mem;
288 : /* Callback plugin creation function */
289 14 : rv = plugin->creation (ls);
290 14 : if (rv)
291 : {
292 0 : pool_put (sm->localsids, ls);
293 0 : return -6;
294 : }
295 14 : dpo_set (&dpo, plugin->dpo, DPO_PROTO_IP6, ls - sm->localsids);
296 : }
297 :
298 : /* Set hash key for searching localsid by address */
299 29 : mhash_set (&sm->sr_localsids_index_hash, &key, ls - sm->localsids, NULL);
300 :
301 29 : fib_table_entry_special_dpo_add (fib_index, &pfx, FIB_SOURCE_SR,
302 : FIB_ENTRY_FLAG_EXCLUSIVE, &dpo);
303 29 : dpo_reset (&dpo);
304 :
305 : /* Set counter to zero */
306 29 : vlib_validate_combined_counter (&(sm->sr_ls_valid_counters),
307 29 : ls - sm->localsids);
308 29 : vlib_validate_combined_counter (&(sm->sr_ls_invalid_counters),
309 29 : ls - sm->localsids);
310 :
311 29 : vlib_zero_combined_counter (&(sm->sr_ls_valid_counters),
312 29 : ls - sm->localsids);
313 29 : vlib_zero_combined_counter (&(sm->sr_ls_invalid_counters),
314 29 : ls - sm->localsids);
315 :
316 29 : return 0;
317 : }
318 :
319 : /**
320 : * @brief SR LocalSID CLI function.
321 : *
322 : * @see sr_cli_localsid
323 : */
324 : static clib_error_t *
325 29 : sr_cli_localsid_command_fn (vlib_main_t * vm, unformat_input_t * input,
326 : vlib_cli_command_t * cmd)
327 : {
328 29 : vnet_main_t *vnm = vnet_get_main ();
329 29 : ip6_sr_main_t *sm = &sr_main;
330 29 : u32 sw_if_index = (u32) ~ 0, vlan_index = (u32) ~ 0, fib_index = 0;
331 29 : int prefix_len = 0;
332 29 : int is_del = 0;
333 29 : int end_psp = 0;
334 : ip6_address_t resulting_address;
335 : ip46_address_t next_hop;
336 29 : char address_set = 0;
337 29 : char behavior = 0;
338 29 : void *ls_plugin_mem = 0;
339 29 : int usid_size = 0;
340 :
341 : int rv;
342 :
343 29 : clib_memset (&resulting_address, 0, sizeof (ip6_address_t));
344 29 : ip46_address_reset (&next_hop);
345 :
346 87 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
347 : {
348 58 : if (unformat (input, "del"))
349 11 : is_del = 1;
350 47 : else if (!address_set
351 29 : && unformat (input, "prefix %U/%u", unformat_ip6_address,
352 : &resulting_address, &prefix_len))
353 6 : address_set = 1;
354 41 : else if (!address_set
355 23 : && unformat (input, "address %U", unformat_ip6_address,
356 : &resulting_address))
357 23 : address_set = 1;
358 18 : else if (!address_set
359 0 : && unformat (input, "addr %U", unformat_ip6_address,
360 : &resulting_address))
361 0 : address_set = 1;
362 18 : else if (unformat (input, "fib-table %u", &fib_index));
363 18 : else if (vlan_index == (u32) ~ 0
364 18 : && unformat (input, "vlan %u", &vlan_index));
365 18 : else if (!behavior && unformat (input, "behavior"))
366 : {
367 18 : if (unformat (input, "end.x %U %U",
368 : unformat_vnet_sw_interface, vnm, &sw_if_index,
369 : unformat_ip6_address, &next_hop.ip6))
370 0 : behavior = SR_BEHAVIOR_X;
371 18 : else if (unformat (input, "end.t %u", &sw_if_index))
372 0 : behavior = SR_BEHAVIOR_T;
373 18 : else if (unformat (input, "end.dx6 %U %U",
374 : unformat_vnet_sw_interface, vnm, &sw_if_index,
375 : unformat_ip6_address, &next_hop.ip6))
376 0 : behavior = SR_BEHAVIOR_DX6;
377 18 : else if (unformat (input, "end.dx4 %U %U",
378 : unformat_vnet_sw_interface, vnm, &sw_if_index,
379 : unformat_ip4_address, &next_hop.ip4))
380 0 : behavior = SR_BEHAVIOR_DX4;
381 18 : else if (unformat (input, "end.dx2 %U",
382 : unformat_vnet_sw_interface, vnm, &sw_if_index))
383 0 : behavior = SR_BEHAVIOR_DX2;
384 18 : else if (unformat (input, "end.dt6 %u", &sw_if_index))
385 0 : behavior = SR_BEHAVIOR_DT6;
386 18 : else if (unformat (input, "end.dt4 %u", &sw_if_index))
387 0 : behavior = SR_BEHAVIOR_DT4;
388 18 : else if (unformat (input, "un %u", &usid_size))
389 2 : behavior = SR_BEHAVIOR_END_UN_PERF;
390 16 : else if (unformat (input, "un.flex %u", &usid_size))
391 2 : behavior = SR_BEHAVIOR_END_UN;
392 : else
393 : {
394 : /* Loop over all the plugin behavior format functions */
395 14 : sr_localsid_fn_registration_t *plugin = 0, **vec_plugins = 0;
396 14 : sr_localsid_fn_registration_t **plugin_it = 0;
397 :
398 : /* Create a vector out of the plugin pool as recommended */
399 : /* *INDENT-OFF* */
400 140 : pool_foreach (plugin, sm->plugin_functions)
401 : {
402 126 : vec_add1 (vec_plugins, plugin);
403 : }
404 : /* *INDENT-ON* */
405 :
406 49 : vec_foreach (plugin_it, vec_plugins)
407 : {
408 49 : if (unformat
409 49 : (input, "%U", (*plugin_it)->ls_unformat, &ls_plugin_mem))
410 : {
411 14 : behavior = (*plugin_it)->sr_localsid_function_number;
412 14 : break;
413 : }
414 : }
415 : }
416 :
417 18 : if (!behavior)
418 : {
419 0 : if (unformat (input, "end"))
420 0 : behavior = SR_BEHAVIOR_END;
421 : else
422 0 : break;
423 : }
424 : }
425 0 : else if (!end_psp && unformat (input, "psp"))
426 0 : end_psp = 1;
427 : else
428 : break;
429 : }
430 :
431 29 : if (!behavior && end_psp)
432 0 : behavior = SR_BEHAVIOR_END;
433 :
434 29 : if (usid_size)
435 : {
436 4 : if (prefix_len < usid_size)
437 0 : return clib_error_return (0,
438 : "Error: Prefix length must be greater"
439 : " than uSID length.");
440 :
441 4 : if (usid_size != 16 && usid_size != 32)
442 0 : return clib_error_return (0,
443 : "Error: Invalid uSID length (16 or 32).");
444 :
445 4 : if ((prefix_len - usid_size) & 0x7)
446 0 : return clib_error_return (0,
447 : "Error: Prefix Length must be multiple of 8.");
448 : }
449 :
450 29 : if (!address_set)
451 0 : return clib_error_return (0,
452 : "Error: SRv6 LocalSID address is mandatory.");
453 29 : if (!is_del && !behavior)
454 0 : return clib_error_return (0,
455 : "Error: SRv6 LocalSID behavior is mandatory.");
456 29 : if (vlan_index != (u32) ~ 0)
457 0 : return clib_error_return (0,
458 : "Error: SRv6 End.DX2 with rewrite VLAN tag not supported by now.");
459 29 : if (end_psp && !(behavior == SR_BEHAVIOR_END || behavior == SR_BEHAVIOR_X))
460 0 : return clib_error_return (0,
461 : "Error: SRv6 PSP only compatible with End and End.X");
462 :
463 : rv =
464 29 : sr_cli_localsid (is_del, &resulting_address, prefix_len, end_psp,
465 : behavior, sw_if_index, vlan_index, fib_index, &next_hop,
466 : usid_size, ls_plugin_mem);
467 :
468 29 : if (behavior == SR_BEHAVIOR_END_UN_PERF)
469 : {
470 2 : if (rv == 0)
471 : {
472 : u16 perf_len;
473 2 : perf_len = prefix_len + usid_size;
474 2 : rv = sr_cli_localsid (is_del, &resulting_address, perf_len, end_psp,
475 : SR_BEHAVIOR_END, sw_if_index, vlan_index,
476 : fib_index, &next_hop, 0, ls_plugin_mem);
477 : }
478 : }
479 :
480 29 : switch (rv)
481 : {
482 29 : case 0:
483 29 : break;
484 0 : case 1:
485 0 : return 0;
486 0 : case -1:
487 0 : return clib_error_return (0,
488 : "Identical localsid already exists. Requested localsid not created.");
489 0 : case -2:
490 0 : return clib_error_return (0,
491 : "The requested localsid could not be deleted. SR localsid not found");
492 0 : case -3:
493 0 : return clib_error_return (0, "FIB table %u does not exist", fib_index);
494 0 : case -4:
495 0 : return clib_error_return (0, "There is already one FIB entry for the"
496 : "requested localsid non segment routing related");
497 0 : case -5:
498 0 : return clib_error_return (0,
499 : "Could not create ARP/ND entry for such next_hop. Internal error.");
500 0 : case -6:
501 0 : return clib_error_return (0,
502 : "Error on the plugin based localsid creation.");
503 0 : default:
504 0 : return clib_error_return (0, "BUG: sr localsid returns %d", rv);
505 : }
506 29 : return 0;
507 : }
508 :
509 : /* *INDENT-OFF* */
510 285289 : VLIB_CLI_COMMAND (sr_localsid_command, static) = {
511 : .path = "sr localsid",
512 : .short_help = "sr localsid (del) address XX:XX::YY:YY"
513 : "(fib-table 8) behavior STRING",
514 : .long_help =
515 : "Create SR LocalSID and binds it to a particular behavior\n"
516 : "Arguments:\n"
517 : "\tlocalSID IPv6_addr(128b) LocalSID IPv6 address\n"
518 : "\t(fib-table X) Optional. VRF where to install SRv6 localsid\n"
519 : "\tbehavior STRING Specifies the behavior\n"
520 : "\n\tBehaviors:\n"
521 : "\tEnd\t-> Endpoint.\n"
522 : "\tEnd.uN\t-> Endpoint with uSID.\n"
523 : "\tEnd.X\t-> Endpoint with decapsulation and Layer-3 cross-connect.\n"
524 : "\t\tParameters: '<iface> <ip6_next_hop>'\n"
525 : "\tEnd.DX2\t-> Endpoint with decapsulation and Layer-2 cross-connect.\n"
526 : "\t\tParameters: '<iface>'\n"
527 : "\tEnd.DX6\t-> Endpoint with decapsulation and IPv6 cross-connect.\n"
528 : "\t\tParameters: '<iface> <ip6_next_hop>'\n"
529 : "\tEnd.DX4\t-> Endpoint with decapsulation and IPv4 cross-connect.\n"
530 : "\t\tParameters: '<iface> <ip4_next_hop>'\n"
531 : "\tEnd.DT6\t-> Endpoint with decapsulation and specific IPv6 table lookup.\n"
532 : "\t\tParameters: '<ip6_fib_table>'\n"
533 : "\tEnd.DT4\t-> Endpoint with decapsulation and specific IPv4 table lookup.\n"
534 : "\t\tParameters: '<ip4_fib_table>'\n",
535 : .function = sr_cli_localsid_command_fn,
536 : };
537 : /* *INDENT-ON* */
538 :
539 : /**
540 : * @brief CLI function to 'show' all SR LocalSIDs on console.
541 : */
542 : static clib_error_t *
543 59 : show_sr_localsid_command_fn (vlib_main_t * vm, unformat_input_t * input,
544 : vlib_cli_command_t * cmd)
545 : {
546 59 : vnet_main_t *vnm = vnet_get_main ();
547 59 : ip6_sr_main_t *sm = &sr_main;
548 59 : ip6_sr_localsid_t **localsid_list = 0;
549 : ip6_sr_localsid_t *ls;
550 : int i;
551 :
552 59 : vlib_cli_output (vm, "SRv6 - My LocalSID Table:");
553 59 : vlib_cli_output (vm, "=========================");
554 : /* *INDENT-OFF* */
555 119 : pool_foreach (ls, sm->localsids) { vec_add1 (localsid_list, ls); }
556 : /* *INDENT-ON* */
557 119 : for (i = 0; i < vec_len (localsid_list); i++)
558 : {
559 60 : ls = localsid_list[i];
560 60 : switch (ls->behavior)
561 : {
562 6 : case SR_BEHAVIOR_END:
563 6 : vlib_cli_output (vm, "\tAddress: \t%U\n\tBehavior: \tEnd",
564 : format_ip6_address, &ls->localsid);
565 6 : break;
566 2 : case SR_BEHAVIOR_END_UN:
567 2 : vlib_cli_output (vm,
568 : "\tAddress: \t%U\n\tBehavior: \tEnd (flex) [uSID:\t%U/%d, length: %d]",
569 : format_ip6_address, &ls->localsid,
570 : format_ip6_address, &ls->usid_block,
571 2 : ls->usid_index * 8, ls->usid_len * 8);
572 2 : break;
573 2 : case SR_BEHAVIOR_END_UN_PERF:
574 2 : vlib_cli_output (vm,
575 : "\tAddress: \t%U\n\tBehavior: \tEnd [uSID:\t%U/%d, length: %d]",
576 : format_ip6_address, &ls->localsid,
577 : format_ip6_address, &ls->usid_block,
578 2 : ls->usid_index * 8, ls->usid_len * 8);
579 2 : break;
580 4 : case SR_BEHAVIOR_X:
581 4 : vlib_cli_output (vm,
582 : "\tAddress: \t%U/%u\n\tBehavior: \tX (Endpoint with Layer-3 cross-connect)"
583 : "\n\tIface: \t%U\n\tNext hop: \t%U",
584 : format_ip6_address, &ls->localsid,
585 4 : ls->localsid_prefix_len,
586 : format_vnet_sw_if_index_name, vnm, ls->sw_if_index,
587 : format_ip6_address, &ls->next_hop.ip6);
588 4 : break;
589 0 : case SR_BEHAVIOR_T:
590 0 : vlib_cli_output (vm,
591 : "\tAddress: \t%U/%u\n\tBehavior: \tT (Endpoint with specific IPv6 table lookup)"
592 : "\n\tTable: \t%u",
593 : format_ip6_address, &ls->localsid,
594 0 : ls->localsid_prefix_len,
595 : fib_table_get_table_id (ls->vrf_index,
596 : FIB_PROTOCOL_IP6));
597 0 : break;
598 2 : case SR_BEHAVIOR_DX4:
599 2 : vlib_cli_output (vm,
600 : "\tAddress: \t%U/%u\n\tBehavior: \tDX4 (Endpoint with decapsulation and IPv4 cross-connect)"
601 : "\n\tIface: \t%U\n\tNext hop: \t%U",
602 : format_ip6_address, &ls->localsid,
603 2 : ls->localsid_prefix_len,
604 : format_vnet_sw_if_index_name, vnm, ls->sw_if_index,
605 : format_ip4_address, &ls->next_hop.ip4);
606 2 : break;
607 2 : case SR_BEHAVIOR_DX6:
608 2 : vlib_cli_output (vm,
609 : "\tAddress: \t%U/%u\n\tBehavior: \tDX6 (Endpoint with decapsulation and IPv6 cross-connect)"
610 : "\n\tIface: \t%U\n\tNext hop: \t%U",
611 : format_ip6_address, &ls->localsid,
612 2 : ls->localsid_prefix_len,
613 : format_vnet_sw_if_index_name, vnm, ls->sw_if_index,
614 : format_ip6_address, &ls->next_hop.ip6);
615 2 : break;
616 2 : case SR_BEHAVIOR_DX2:
617 2 : if (ls->vlan_index == (u32) ~ 0)
618 0 : vlib_cli_output (vm,
619 : "\tAddress: \t%U/%u\n\tBehavior: \tDX2 (Endpoint with decapulation and Layer-2 cross-connect)"
620 : "\n\tIface: \t%U", format_ip6_address,
621 0 : &ls->localsid, ls->localsid_prefix_len,
622 : format_vnet_sw_if_index_name, vnm,
623 : ls->sw_if_index);
624 : else
625 2 : vlib_cli_output (vm,
626 : "Unsupported yet. (DX2 with egress VLAN rewrite)");
627 2 : break;
628 2 : case SR_BEHAVIOR_DT6:
629 2 : vlib_cli_output (vm,
630 : "\tAddress: \t%U/%u\n\tBehavior: \tDT6 (Endpoint with decapsulation and specific IPv6 table lookup)"
631 : "\n\tTable: %u", format_ip6_address, &ls->localsid,
632 2 : ls->localsid_prefix_len,
633 : fib_table_get_table_id (ls->vrf_index,
634 : FIB_PROTOCOL_IP6));
635 2 : break;
636 2 : case SR_BEHAVIOR_DT4:
637 2 : vlib_cli_output (vm,
638 : "\tAddress: \t%U/%u\n\tBehavior: \tDT4 (Endpoint with decapsulation and specific IPv4 table lookup)"
639 : "\n\tTable: \t%u", format_ip6_address,
640 2 : &ls->localsid, ls->localsid_prefix_len,
641 : fib_table_get_table_id (ls->vrf_index,
642 : FIB_PROTOCOL_IP4));
643 2 : break;
644 36 : default:
645 36 : if (ls->behavior >= SR_BEHAVIOR_LAST)
646 : {
647 36 : sr_localsid_fn_registration_t *plugin =
648 36 : pool_elt_at_index (sm->plugin_functions,
649 : ls->behavior - SR_BEHAVIOR_LAST);
650 :
651 36 : vlib_cli_output (vm, "\tAddress: \t%U/%u\n"
652 : "\tBehavior: \t%s (%s)\n\t%U",
653 : format_ip6_address, &ls->localsid,
654 36 : ls->localsid_prefix_len, plugin->keyword_str,
655 : plugin->def_str, plugin->ls_format,
656 : ls->plugin_mem);
657 : }
658 : else
659 : //Should never get here...
660 0 : vlib_cli_output (vm, "Internal error");
661 36 : break;
662 : }
663 60 : if (ls->end_psp)
664 4 : vlib_cli_output (vm, "\tPSP: \tTrue\n");
665 :
666 : /* Print counters */
667 : vlib_counter_t valid, invalid;
668 60 : vlib_get_combined_counter (&(sm->sr_ls_valid_counters), i, &valid);
669 60 : vlib_get_combined_counter (&(sm->sr_ls_invalid_counters), i, &invalid);
670 60 : vlib_cli_output (vm, "\tGood traffic: \t[%Ld packets : %Ld bytes]\n",
671 : valid.packets, valid.bytes);
672 60 : vlib_cli_output (vm, "\tBad traffic: \t[%Ld packets : %Ld bytes]\n",
673 : invalid.packets, invalid.bytes);
674 60 : vlib_cli_output (vm, "--------------------");
675 : }
676 59 : return 0;
677 : }
678 :
679 : /* *INDENT-OFF* */
680 285289 : VLIB_CLI_COMMAND (show_sr_localsid_command, static) = {
681 : .path = "show sr localsids",
682 : .short_help = "show sr localsids",
683 : .function = show_sr_localsid_command_fn,
684 : };
685 : /* *INDENT-ON* */
686 :
687 : /**
688 : * @brief Function to 'clear' ALL SR localsid counters
689 : */
690 : static clib_error_t *
691 0 : clear_sr_localsid_counters_command_fn (vlib_main_t * vm,
692 : unformat_input_t * input,
693 : vlib_cli_command_t * cmd)
694 : {
695 0 : ip6_sr_main_t *sm = &sr_main;
696 :
697 0 : vlib_clear_combined_counters (&(sm->sr_ls_valid_counters));
698 0 : vlib_clear_combined_counters (&(sm->sr_ls_invalid_counters));
699 :
700 0 : return 0;
701 : }
702 :
703 : /* *INDENT-OFF* */
704 285289 : VLIB_CLI_COMMAND (clear_sr_localsid_counters_command, static) = {
705 : .path = "clear sr localsid-counters",
706 : .short_help = "clear sr localsid-counters",
707 : .function = clear_sr_localsid_counters_command_fn,
708 : };
709 : /* *INDENT-ON* */
710 :
711 : /************************ SR LocalSID graphs node ****************************/
712 : /**
713 : * @brief SR localsid node trace
714 : */
715 : typedef struct
716 : {
717 : ip6_address_t localsid;
718 : u16 behavior;
719 : u8 sr[256];
720 : u8 num_segments;
721 : u8 segments_left;
722 : } sr_localsid_trace_t;
723 :
724 : #define foreach_sr_localsid_error \
725 : _(NO_INNER_HEADER, "(SR-Error) No inner IP header") \
726 : _(NO_MORE_SEGMENTS, "(SR-Error) No more segments") \
727 : _(NO_SRH, "(SR-Error) No SR header") \
728 : _(NO_PSP, "(SR-Error) PSP Not available (segments left > 0)") \
729 : _(NOT_LS, "(SR-Error) Decaps not available (segments left > 0)") \
730 : _(L2, "(SR-Error) SRv6 decapsulated a L2 frame without dest")
731 :
732 : typedef enum
733 : {
734 : #define _(sym,str) SR_LOCALSID_ERROR_##sym,
735 : foreach_sr_localsid_error
736 : #undef _
737 : SR_LOCALSID_N_ERROR,
738 : } sr_localsid_error_t;
739 :
740 : static char *sr_localsid_error_strings[] = {
741 : #define _(sym,string) string,
742 : foreach_sr_localsid_error
743 : #undef _
744 : };
745 :
746 : #define foreach_sr_localsid_next \
747 : _(ERROR, "error-drop") \
748 : _(IP6_LOOKUP, "ip6-lookup") \
749 : _(IP4_LOOKUP, "ip4-lookup") \
750 : _(IP6_REWRITE, "ip6-rewrite") \
751 : _(IP4_REWRITE, "ip4-rewrite") \
752 : _(INTERFACE_OUTPUT, "interface-output")
753 :
754 : typedef enum
755 : {
756 : #define _(s,n) SR_LOCALSID_NEXT_##s,
757 : foreach_sr_localsid_next
758 : #undef _
759 : SR_LOCALSID_N_NEXT,
760 : } sr_localsid_next_t;
761 :
762 : /**
763 : * @brief SR LocalSID graph node trace function
764 : *
765 : * @see sr_localsid
766 : */
767 : u8 *
768 71 : format_sr_localsid_trace (u8 * s, va_list * args)
769 : {
770 71 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
771 71 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
772 71 : sr_localsid_trace_t *t = va_arg (*args, sr_localsid_trace_t *);
773 :
774 : s =
775 71 : format (s, "SR-LOCALSID:\n\tLocalsid: %U\n", format_ip6_address,
776 : &t->localsid);
777 71 : switch (t->behavior)
778 : {
779 15 : case SR_BEHAVIOR_END:
780 15 : s = format (s, "\tBehavior: End\n");
781 15 : break;
782 4 : case SR_BEHAVIOR_END_UN:
783 4 : s = format (s, "\tBehavior: End.uN (flex)\n");
784 4 : break;
785 4 : case SR_BEHAVIOR_END_UN_PERF:
786 4 : s = format (s, "\tBehavior: End.uN\n");
787 4 : break;
788 6 : case SR_BEHAVIOR_DX6:
789 6 : s = format (s, "\tBehavior: Decapsulation with IPv6 L3 xconnect\n");
790 6 : break;
791 6 : case SR_BEHAVIOR_DX4:
792 6 : s = format (s, "\tBehavior: Decapsulation with IPv4 L3 xconnect\n");
793 6 : break;
794 12 : case SR_BEHAVIOR_X:
795 12 : s = format (s, "\tBehavior: IPv6 L3 xconnect\n");
796 12 : break;
797 0 : case SR_BEHAVIOR_T:
798 0 : s = format (s, "\tBehavior: IPv6 specific table lookup\n");
799 0 : break;
800 6 : case SR_BEHAVIOR_DT6:
801 6 : s = format (s, "\tBehavior: Decapsulation with IPv6 Table lookup\n");
802 6 : break;
803 6 : case SR_BEHAVIOR_DT4:
804 6 : s = format (s, "\tBehavior: Decapsulation with IPv4 Table lookup\n");
805 6 : break;
806 12 : case SR_BEHAVIOR_DX2:
807 12 : s = format (s, "\tBehavior: Decapsulation with L2 xconnect\n");
808 12 : break;
809 0 : default:
810 0 : s = format (s, "\tBehavior: defined in plugin\n"); //TODO
811 0 : break;
812 : }
813 71 : if (t->num_segments != 0xFF)
814 : {
815 29 : if (t->num_segments > 0)
816 : {
817 20 : s = format (s, "\tSegments left: %d\n", t->segments_left);
818 20 : s = format (s, "\tSID list: [in ietf order]");
819 20 : int i = 0;
820 78 : for (i = 0; i < t->num_segments; i++)
821 : {
822 58 : s = format (s, "\n\t-> %U", format_ip6_address,
823 58 : (ip6_address_t *) & t->sr[i *
824 : sizeof (ip6_address_t)]);
825 : }
826 : }
827 : }
828 71 : return s;
829 : }
830 :
831 : /**
832 : * @brief Function doing End processing.
833 : */
834 : static_always_inline void
835 27 : end_srh_processing (vlib_node_runtime_t * node,
836 : vlib_buffer_t * b0,
837 : ip6_header_t * ip0,
838 : ip6_sr_header_t * sr0,
839 : ip6_sr_localsid_t * ls0,
840 : u32 * next0, u8 psp, ip6_ext_header_t * prev0)
841 : {
842 : ip6_address_t *new_dst0;
843 :
844 27 : if (PREDICT_TRUE (sr0 && sr0->type == ROUTING_HEADER_TYPE_SR))
845 : {
846 24 : if (sr0->segments_left == 1 && psp)
847 6 : {
848 : u32 new_l0, sr_len;
849 : u64 *copy_dst0, *copy_src0;
850 6 : u32 copy_len_u64s0 = 0;
851 :
852 6 : ip0->dst_address.as_u64[0] = sr0->segments->as_u64[0];
853 6 : ip0->dst_address.as_u64[1] = sr0->segments->as_u64[1];
854 :
855 : /* Remove the SRH taking care of the rest of IPv6 ext header */
856 6 : if (prev0)
857 0 : prev0->next_hdr = sr0->protocol;
858 : else
859 6 : ip0->protocol = sr0->protocol;
860 :
861 6 : sr_len = ip6_ext_header_len (sr0);
862 6 : vlib_buffer_advance (b0, sr_len);
863 6 : new_l0 = clib_net_to_host_u16 (ip0->payload_length) - sr_len;
864 6 : ip0->payload_length = clib_host_to_net_u16 (new_l0);
865 6 : copy_src0 = (u64 *) ip0;
866 6 : copy_dst0 = copy_src0 + (sr0->length + 1);
867 : /* number of 8 octet units to copy
868 : * By default in absence of extension headers it is equal to length of ip6 header
869 : * With extension headers it number of 8 octet units of ext headers preceding
870 : * SR header
871 : */
872 6 : copy_len_u64s0 =
873 6 : (((u8 *) sr0 - (u8 *) ip0) - sizeof (ip6_header_t)) >> 3;
874 6 : copy_dst0[4 + copy_len_u64s0] = copy_src0[4 + copy_len_u64s0];
875 6 : copy_dst0[3 + copy_len_u64s0] = copy_src0[3 + copy_len_u64s0];
876 6 : copy_dst0[2 + copy_len_u64s0] = copy_src0[2 + copy_len_u64s0];
877 6 : copy_dst0[1 + copy_len_u64s0] = copy_src0[1 + copy_len_u64s0];
878 6 : copy_dst0[0 + copy_len_u64s0] = copy_src0[0 + copy_len_u64s0];
879 :
880 : int i;
881 6 : for (i = copy_len_u64s0 - 1; i >= 0; i--)
882 : {
883 0 : copy_dst0[i] = copy_src0[i];
884 : }
885 :
886 6 : if (ls0->behavior == SR_BEHAVIOR_X)
887 : {
888 3 : vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ls0->nh_adj;
889 3 : *next0 = SR_LOCALSID_NEXT_IP6_REWRITE;
890 : }
891 3 : else if (ls0->behavior == SR_BEHAVIOR_T)
892 : {
893 0 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = ls0->vrf_index;
894 : }
895 : }
896 18 : else if (PREDICT_TRUE (sr0->segments_left > 0))
897 : {
898 18 : sr0->segments_left -= 1;
899 18 : new_dst0 = (ip6_address_t *) (sr0->segments);
900 18 : new_dst0 += sr0->segments_left;
901 18 : ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
902 18 : ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
903 :
904 18 : if (ls0->behavior == SR_BEHAVIOR_X)
905 : {
906 9 : vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ls0->nh_adj;
907 9 : *next0 = SR_LOCALSID_NEXT_IP6_REWRITE;
908 : }
909 9 : else if (ls0->behavior == SR_BEHAVIOR_T)
910 : {
911 0 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = ls0->vrf_index;
912 : }
913 : }
914 : else
915 : {
916 0 : *next0 = SR_LOCALSID_NEXT_ERROR;
917 0 : b0->error = node->errors[SR_LOCALSID_ERROR_NO_MORE_SEGMENTS];
918 : }
919 : }
920 : else
921 : {
922 : /* Error. Routing header of type != SR */
923 3 : *next0 = SR_LOCALSID_NEXT_ERROR;
924 3 : b0->error = node->errors[SR_LOCALSID_ERROR_NO_SRH];
925 : }
926 27 : }
927 :
928 : /**
929 : * @brief Function doing End uN processing.
930 : */
931 : static_always_inline void
932 4 : end_un_srh_processing (vlib_node_runtime_t * node,
933 : vlib_buffer_t * b0,
934 : ip6_header_t * ip0,
935 : ip6_sr_header_t * sr0,
936 : ip6_sr_localsid_t * ls0,
937 : u32 * next0, u8 psp, ip6_ext_header_t * prev0)
938 : {
939 : ip6_address_t *new_dst0;
940 4 : bool next_usid = false;
941 : u8 next_usid_index;
942 : u8 usid_len;
943 : u8 index;
944 :
945 4 : usid_len = ls0->usid_len;
946 4 : next_usid_index = ls0->usid_next_index;
947 :
948 : /* uSID */
949 4 : for (index = 0; index < usid_len; index++)
950 : {
951 4 : if (ip0->dst_address.as_u8[next_usid_index + index] != 0)
952 : {
953 4 : next_usid = true;
954 4 : break;
955 : }
956 : }
957 :
958 4 : if (PREDICT_TRUE (next_usid))
959 : {
960 : u8 offset;
961 :
962 4 : index = ls0->usid_index;
963 :
964 : /* advance next usid */
965 44 : for (offset = 0; offset < ls0->usid_next_len; offset++)
966 : {
967 40 : ip0->dst_address.as_u8[index + offset] =
968 40 : ip0->dst_address.as_u8[next_usid_index + offset];
969 : }
970 :
971 12 : for (index = 16 - usid_len; index < 16; index++)
972 : {
973 8 : ip0->dst_address.as_u8[index] = 0;
974 : }
975 :
976 4 : return;
977 : }
978 :
979 0 : if (PREDICT_TRUE (sr0 && sr0->type == ROUTING_HEADER_TYPE_SR))
980 : {
981 0 : if (sr0->segments_left == 1 && psp)
982 0 : {
983 : u32 new_l0, sr_len;
984 : u64 *copy_dst0, *copy_src0;
985 0 : u32 copy_len_u64s0 = 0;
986 :
987 0 : ip0->dst_address.as_u64[0] = sr0->segments->as_u64[0];
988 0 : ip0->dst_address.as_u64[1] = sr0->segments->as_u64[1];
989 :
990 : /* Remove the SRH taking care of the rest of IPv6 ext header */
991 0 : if (prev0)
992 0 : prev0->next_hdr = sr0->protocol;
993 : else
994 0 : ip0->protocol = sr0->protocol;
995 :
996 0 : sr_len = ip6_ext_header_len (sr0);
997 0 : vlib_buffer_advance (b0, sr_len);
998 0 : new_l0 = clib_net_to_host_u16 (ip0->payload_length) - sr_len;
999 0 : ip0->payload_length = clib_host_to_net_u16 (new_l0);
1000 0 : copy_src0 = (u64 *) ip0;
1001 0 : copy_dst0 = copy_src0 + (sr0->length + 1);
1002 : /* number of 8 octet units to copy
1003 : * By default in absence of extension headers it is equal to length of ip6 header
1004 : * With extension headers it number of 8 octet units of ext headers preceding
1005 : * SR header
1006 : */
1007 0 : copy_len_u64s0 =
1008 0 : (((u8 *) sr0 - (u8 *) ip0) - sizeof (ip6_header_t)) >> 3;
1009 0 : copy_dst0[4 + copy_len_u64s0] = copy_src0[4 + copy_len_u64s0];
1010 0 : copy_dst0[3 + copy_len_u64s0] = copy_src0[3 + copy_len_u64s0];
1011 0 : copy_dst0[2 + copy_len_u64s0] = copy_src0[2 + copy_len_u64s0];
1012 0 : copy_dst0[1 + copy_len_u64s0] = copy_src0[1 + copy_len_u64s0];
1013 0 : copy_dst0[0 + copy_len_u64s0] = copy_src0[0 + copy_len_u64s0];
1014 :
1015 : int i;
1016 0 : for (i = copy_len_u64s0 - 1; i >= 0; i--)
1017 : {
1018 0 : copy_dst0[i] = copy_src0[i];
1019 : }
1020 : }
1021 0 : else if (PREDICT_TRUE (sr0->segments_left > 0))
1022 : {
1023 0 : sr0->segments_left -= 1;
1024 0 : new_dst0 = (ip6_address_t *) (sr0->segments);
1025 0 : new_dst0 += sr0->segments_left;
1026 0 : ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
1027 0 : ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
1028 : }
1029 : else
1030 : {
1031 0 : *next0 = SR_LOCALSID_NEXT_ERROR;
1032 0 : b0->error = node->errors[SR_LOCALSID_ERROR_NO_MORE_SEGMENTS];
1033 : }
1034 : }
1035 : else
1036 : {
1037 : /* Error. Routing header of type != SR */
1038 0 : *next0 = SR_LOCALSID_NEXT_ERROR;
1039 0 : b0->error = node->errors[SR_LOCALSID_ERROR_NO_SRH];
1040 : }
1041 : }
1042 :
1043 : static_always_inline void
1044 4 : end_un_processing (ip6_header_t * ip0, ip6_sr_localsid_t * ls0)
1045 : {
1046 : u8 next_usid_index;
1047 : u8 index;
1048 : u8 offset;
1049 :
1050 : /* uSID */
1051 4 : index = ls0->usid_index;
1052 4 : next_usid_index = ls0->usid_next_index;
1053 :
1054 : /* advance next usid */
1055 44 : for (offset = 0; offset < ls0->usid_next_len; offset++)
1056 : {
1057 40 : ip0->dst_address.as_u8[index + offset] =
1058 40 : ip0->dst_address.as_u8[next_usid_index + offset];
1059 : }
1060 :
1061 12 : for (index = 16 - ls0->usid_len; index < 16; index++)
1062 : {
1063 8 : ip0->dst_address.as_u8[index] = 0;
1064 : }
1065 :
1066 4 : return;
1067 : }
1068 :
1069 : /*
1070 : * @brief Function doing SRH processing for D* variants
1071 : */
1072 : static_always_inline void
1073 36 : end_decaps_srh_processing (vlib_node_runtime_t * node,
1074 : vlib_buffer_t * b0,
1075 : ip6_header_t * ip0,
1076 : ip6_sr_header_t * sr0,
1077 : ip6_sr_localsid_t * ls0, u32 * next0)
1078 : {
1079 : /* Compute the size of the IPv6 header with all Ext. headers */
1080 : u8 next_proto;
1081 : ip6_ext_header_t *next_ext_header;
1082 36 : u16 total_size = 0;
1083 :
1084 36 : next_proto = ip0->protocol;
1085 36 : next_ext_header = (void *) (ip0 + 1);
1086 36 : total_size = sizeof (ip6_header_t);
1087 54 : while (ip6_ext_hdr (next_proto))
1088 : {
1089 18 : total_size += ip6_ext_header_len (next_ext_header);
1090 18 : next_proto = next_ext_header->next_hdr;
1091 18 : next_ext_header = ip6_ext_next_header (next_ext_header);
1092 : }
1093 :
1094 : /* Ensure this is the last segment. Otherwise drop. */
1095 36 : if (sr0 && sr0->segments_left != 0)
1096 : {
1097 0 : *next0 = SR_LOCALSID_NEXT_ERROR;
1098 0 : b0->error = node->errors[SR_LOCALSID_ERROR_NOT_LS];
1099 0 : return;
1100 : }
1101 :
1102 36 : switch (next_proto)
1103 : {
1104 12 : case IP_PROTOCOL_IPV6:
1105 : /* Encap-End IPv6. Pop outer IPv6 header. */
1106 12 : if (ls0->behavior == SR_BEHAVIOR_DX6)
1107 : {
1108 6 : vlib_buffer_advance (b0, total_size);
1109 6 : vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ls0->nh_adj;
1110 6 : *next0 = SR_LOCALSID_NEXT_IP6_REWRITE;
1111 6 : return;
1112 : }
1113 6 : else if (ls0->behavior == SR_BEHAVIOR_DT6)
1114 : {
1115 6 : vlib_buffer_advance (b0, total_size);
1116 6 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = ls0->vrf_index;
1117 6 : return;
1118 : }
1119 0 : break;
1120 12 : case IP_PROTOCOL_IP_IN_IP:
1121 : /* Encap-End IPv4. Pop outer IPv6 header */
1122 12 : if (ls0->behavior == SR_BEHAVIOR_DX4)
1123 : {
1124 6 : vlib_buffer_advance (b0, total_size);
1125 6 : vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ls0->nh_adj;
1126 6 : *next0 = SR_LOCALSID_NEXT_IP4_REWRITE;
1127 6 : return;
1128 : }
1129 6 : else if (ls0->behavior == SR_BEHAVIOR_DT4)
1130 : {
1131 6 : vlib_buffer_advance (b0, total_size);
1132 6 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = ls0->vrf_index;
1133 6 : *next0 = SR_LOCALSID_NEXT_IP4_LOOKUP;
1134 6 : return;
1135 : }
1136 0 : break;
1137 12 : case IP_PROTOCOL_IP6_ETHERNET:
1138 : /* L2 encaps */
1139 12 : if (ls0->behavior == SR_BEHAVIOR_DX2)
1140 : {
1141 12 : vlib_buffer_advance (b0, total_size);
1142 12 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = ls0->sw_if_index;
1143 12 : *next0 = SR_LOCALSID_NEXT_INTERFACE_OUTPUT;
1144 12 : return;
1145 : }
1146 0 : break;
1147 : }
1148 0 : *next0 = SR_LOCALSID_NEXT_ERROR;
1149 0 : b0->error = node->errors[SR_LOCALSID_ERROR_NO_INNER_HEADER];
1150 0 : return;
1151 : }
1152 :
1153 : /**
1154 : * @brief SR LocalSID graph node. Supports all default SR Endpoint variants with decaps
1155 : */
1156 : static uword
1157 5 : sr_localsid_d_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
1158 : vlib_frame_t * from_frame)
1159 : {
1160 : u32 n_left_from, next_index, *from, *to_next;
1161 5 : ip6_sr_main_t *sm = &sr_main;
1162 5 : from = vlib_frame_vector_args (from_frame);
1163 5 : n_left_from = from_frame->n_vectors;
1164 5 : next_index = node->cached_next_index;
1165 5 : u32 thread_index = vm->thread_index;
1166 :
1167 10 : while (n_left_from > 0)
1168 : {
1169 : u32 n_left_to_next;
1170 5 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1171 :
1172 : /* Quad - Loop */
1173 7 : while (n_left_from >= 8 && n_left_to_next >= 4)
1174 : {
1175 : u32 bi0, bi1, bi2, bi3;
1176 : vlib_buffer_t *b0, *b1, *b2, *b3;
1177 : ip6_header_t *ip0, *ip1, *ip2, *ip3;
1178 : ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1179 : u32 next0, next1, next2, next3;
1180 2 : next0 = next1 = next2 = next3 = SR_LOCALSID_NEXT_IP6_LOOKUP;
1181 : ip6_sr_localsid_t *ls0, *ls1, *ls2, *ls3;
1182 :
1183 : /* Prefetch next iteration. */
1184 : {
1185 : vlib_buffer_t *p4, *p5, *p6, *p7;
1186 :
1187 2 : p4 = vlib_get_buffer (vm, from[4]);
1188 2 : p5 = vlib_get_buffer (vm, from[5]);
1189 2 : p6 = vlib_get_buffer (vm, from[6]);
1190 2 : p7 = vlib_get_buffer (vm, from[7]);
1191 :
1192 : /* Prefetch the buffer header and packet for the N+4 loop iteration */
1193 2 : vlib_prefetch_buffer_header (p4, LOAD);
1194 2 : vlib_prefetch_buffer_header (p5, LOAD);
1195 2 : vlib_prefetch_buffer_header (p6, LOAD);
1196 2 : vlib_prefetch_buffer_header (p7, LOAD);
1197 :
1198 2 : clib_prefetch_store (p4->data);
1199 2 : clib_prefetch_store (p5->data);
1200 2 : clib_prefetch_store (p6->data);
1201 2 : clib_prefetch_store (p7->data);
1202 : }
1203 :
1204 2 : to_next[0] = bi0 = from[0];
1205 2 : to_next[1] = bi1 = from[1];
1206 2 : to_next[2] = bi2 = from[2];
1207 2 : to_next[3] = bi3 = from[3];
1208 2 : from += 4;
1209 2 : to_next += 4;
1210 2 : n_left_from -= 4;
1211 2 : n_left_to_next -= 4;
1212 :
1213 2 : b0 = vlib_get_buffer (vm, bi0);
1214 2 : b1 = vlib_get_buffer (vm, bi1);
1215 2 : b2 = vlib_get_buffer (vm, bi2);
1216 2 : b3 = vlib_get_buffer (vm, bi3);
1217 :
1218 2 : ls0 =
1219 2 : pool_elt_at_index (sm->localsids,
1220 : vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1221 2 : ls1 =
1222 2 : pool_elt_at_index (sm->localsids,
1223 : vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1224 2 : ls2 =
1225 2 : pool_elt_at_index (sm->localsids,
1226 : vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1227 2 : ls3 =
1228 2 : pool_elt_at_index (sm->localsids,
1229 : vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1230 :
1231 2 : ip0 = vlib_buffer_get_current (b0);
1232 2 : ip1 = vlib_buffer_get_current (b1);
1233 2 : ip2 = vlib_buffer_get_current (b2);
1234 2 : ip3 = vlib_buffer_get_current (b3);
1235 :
1236 : sr0 =
1237 2 : ip6_ext_header_find (vm, b0, ip0, IP_PROTOCOL_IPV6_ROUTE, NULL);
1238 : sr1 =
1239 2 : ip6_ext_header_find (vm, b1, ip1, IP_PROTOCOL_IPV6_ROUTE, NULL);
1240 : sr2 =
1241 2 : ip6_ext_header_find (vm, b2, ip2, IP_PROTOCOL_IPV6_ROUTE, NULL);
1242 : sr3 =
1243 2 : ip6_ext_header_find (vm, b3, ip3, IP_PROTOCOL_IPV6_ROUTE, NULL);
1244 :
1245 2 : end_decaps_srh_processing (node, b0, ip0, sr0, ls0, &next0);
1246 2 : end_decaps_srh_processing (node, b1, ip1, sr1, ls1, &next1);
1247 2 : end_decaps_srh_processing (node, b2, ip2, sr2, ls2, &next2);
1248 2 : end_decaps_srh_processing (node, b3, ip3, sr3, ls3, &next3);
1249 :
1250 2 : if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1251 : {
1252 : sr_localsid_trace_t *tr =
1253 2 : vlib_add_trace (vm, node, b0, sizeof (*tr));
1254 2 : tr->num_segments = 0;
1255 2 : clib_memcpy (tr->localsid.as_u8, ls0->localsid.as_u8,
1256 : sizeof (tr->localsid.as_u8));
1257 2 : tr->behavior = ls0->behavior;
1258 2 : if (ip0 == vlib_buffer_get_current (b0))
1259 : {
1260 0 : if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE
1261 0 : && sr0->type == ROUTING_HEADER_TYPE_SR)
1262 : {
1263 0 : clib_memcpy (tr->sr, sr0->segments, sr0->length * 8);
1264 0 : tr->num_segments =
1265 0 : sr0->length * 8 / sizeof (ip6_address_t);
1266 0 : tr->segments_left = sr0->segments_left;
1267 : }
1268 : }
1269 : else
1270 2 : tr->num_segments = 0xFF;
1271 : }
1272 :
1273 2 : if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1274 : {
1275 : sr_localsid_trace_t *tr =
1276 2 : vlib_add_trace (vm, node, b1, sizeof (*tr));
1277 2 : tr->num_segments = 0;
1278 2 : clib_memcpy (tr->localsid.as_u8, ls1->localsid.as_u8,
1279 : sizeof (tr->localsid.as_u8));
1280 2 : tr->behavior = ls1->behavior;
1281 2 : if (ip1 == vlib_buffer_get_current (b1))
1282 : {
1283 0 : if (ip1->protocol == IP_PROTOCOL_IPV6_ROUTE
1284 0 : && sr1->type == ROUTING_HEADER_TYPE_SR)
1285 : {
1286 0 : clib_memcpy (tr->sr, sr1->segments, sr1->length * 8);
1287 0 : tr->num_segments =
1288 0 : sr1->length * 8 / sizeof (ip6_address_t);
1289 0 : tr->segments_left = sr1->segments_left;
1290 : }
1291 : }
1292 : else
1293 2 : tr->num_segments = 0xFF;
1294 : }
1295 :
1296 2 : if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1297 : {
1298 : sr_localsid_trace_t *tr =
1299 2 : vlib_add_trace (vm, node, b2, sizeof (*tr));
1300 2 : tr->num_segments = 0;
1301 2 : clib_memcpy (tr->localsid.as_u8, ls2->localsid.as_u8,
1302 : sizeof (tr->localsid.as_u8));
1303 2 : tr->behavior = ls2->behavior;
1304 2 : if (ip2 == vlib_buffer_get_current (b2))
1305 : {
1306 0 : if (ip2->protocol == IP_PROTOCOL_IPV6_ROUTE
1307 0 : && sr2->type == ROUTING_HEADER_TYPE_SR)
1308 : {
1309 0 : clib_memcpy (tr->sr, sr2->segments, sr2->length * 8);
1310 0 : tr->num_segments =
1311 0 : sr2->length * 8 / sizeof (ip6_address_t);
1312 0 : tr->segments_left = sr2->segments_left;
1313 : }
1314 : }
1315 : else
1316 2 : tr->num_segments = 0xFF;
1317 : }
1318 :
1319 2 : if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1320 : {
1321 : sr_localsid_trace_t *tr =
1322 2 : vlib_add_trace (vm, node, b3, sizeof (*tr));
1323 2 : tr->num_segments = 0;
1324 2 : clib_memcpy (tr->localsid.as_u8, ls3->localsid.as_u8,
1325 : sizeof (tr->localsid.as_u8));
1326 2 : tr->behavior = ls3->behavior;
1327 2 : if (ip3 == vlib_buffer_get_current (b3))
1328 : {
1329 0 : if (ip3->protocol == IP_PROTOCOL_IPV6_ROUTE
1330 0 : && sr3->type == ROUTING_HEADER_TYPE_SR)
1331 : {
1332 0 : clib_memcpy (tr->sr, sr3->segments, sr3->length * 8);
1333 0 : tr->num_segments =
1334 0 : sr3->length * 8 / sizeof (ip6_address_t);
1335 0 : tr->segments_left = sr3->segments_left;
1336 : }
1337 : }
1338 : else
1339 2 : tr->num_segments = 0xFF;
1340 : }
1341 :
1342 4 : vlib_increment_combined_counter
1343 2 : (((next0 ==
1344 : SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1345 2 : &(sm->sr_ls_valid_counters)), thread_index, ls0 - sm->localsids,
1346 : 1, vlib_buffer_length_in_chain (vm, b0));
1347 :
1348 4 : vlib_increment_combined_counter
1349 2 : (((next1 ==
1350 : SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1351 2 : &(sm->sr_ls_valid_counters)), thread_index, ls1 - sm->localsids,
1352 : 1, vlib_buffer_length_in_chain (vm, b1));
1353 :
1354 4 : vlib_increment_combined_counter
1355 2 : (((next2 ==
1356 : SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1357 2 : &(sm->sr_ls_valid_counters)), thread_index, ls2 - sm->localsids,
1358 : 1, vlib_buffer_length_in_chain (vm, b2));
1359 :
1360 4 : vlib_increment_combined_counter
1361 2 : (((next3 ==
1362 : SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1363 2 : &(sm->sr_ls_valid_counters)), thread_index, ls3 - sm->localsids,
1364 : 1, vlib_buffer_length_in_chain (vm, b3));
1365 :
1366 2 : vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1367 : n_left_to_next, bi0, bi1, bi2, bi3,
1368 : next0, next1, next2, next3);
1369 : }
1370 :
1371 : /* Single loop for potentially the last three packets */
1372 33 : while (n_left_from > 0 && n_left_to_next > 0)
1373 : {
1374 : u32 bi0;
1375 : vlib_buffer_t *b0;
1376 : ip6_header_t *ip0;
1377 : ip6_sr_header_t *sr0;
1378 28 : u32 next0 = SR_LOCALSID_NEXT_IP6_LOOKUP;
1379 : ip6_sr_localsid_t *ls0;
1380 :
1381 28 : bi0 = from[0];
1382 28 : to_next[0] = bi0;
1383 28 : from += 1;
1384 28 : to_next += 1;
1385 28 : n_left_from -= 1;
1386 28 : n_left_to_next -= 1;
1387 :
1388 28 : b0 = vlib_get_buffer (vm, bi0);
1389 28 : ip0 = vlib_buffer_get_current (b0);
1390 :
1391 : /* Lookup the SR End behavior based on IP DA (adj) */
1392 28 : ls0 =
1393 28 : pool_elt_at_index (sm->localsids,
1394 : vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1395 :
1396 : /* Find SRH as well as previous header */
1397 : sr0 =
1398 28 : ip6_ext_header_find (vm, b0, ip0, IP_PROTOCOL_IPV6_ROUTE, NULL);
1399 :
1400 : /* SRH processing and End variants */
1401 28 : end_decaps_srh_processing (node, b0, ip0, sr0, ls0, &next0);
1402 :
1403 28 : if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1404 : {
1405 : sr_localsid_trace_t *tr =
1406 28 : vlib_add_trace (vm, node, b0, sizeof (*tr));
1407 28 : tr->num_segments = 0;
1408 28 : clib_memcpy (tr->localsid.as_u8, ls0->localsid.as_u8,
1409 : sizeof (tr->localsid.as_u8));
1410 28 : tr->behavior = ls0->behavior;
1411 28 : if (ip0 == vlib_buffer_get_current (b0))
1412 : {
1413 0 : if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE
1414 0 : && sr0->type == ROUTING_HEADER_TYPE_SR)
1415 : {
1416 0 : clib_memcpy (tr->sr, sr0->segments, sr0->length * 8);
1417 0 : tr->num_segments =
1418 0 : sr0->length * 8 / sizeof (ip6_address_t);
1419 0 : tr->segments_left = sr0->segments_left;
1420 : }
1421 : }
1422 : else
1423 28 : tr->num_segments = 0xFF;
1424 : }
1425 :
1426 : /* Increase the counters */
1427 56 : vlib_increment_combined_counter
1428 28 : (((next0 ==
1429 : SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1430 28 : &(sm->sr_ls_valid_counters)), thread_index, ls0 - sm->localsids,
1431 : 1, vlib_buffer_length_in_chain (vm, b0));
1432 :
1433 28 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1434 : n_left_to_next, bi0, next0);
1435 : }
1436 5 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1437 : }
1438 5 : return from_frame->n_vectors;
1439 : }
1440 :
1441 : /* *INDENT-OFF* */
1442 183788 : VLIB_REGISTER_NODE (sr_localsid_d_node) = {
1443 : .function = sr_localsid_d_fn,
1444 : .name = "sr-localsid-d",
1445 : .vector_size = sizeof (u32),
1446 : .format_trace = format_sr_localsid_trace,
1447 : .type = VLIB_NODE_TYPE_INTERNAL,
1448 : .n_errors = SR_LOCALSID_N_ERROR,
1449 : .error_strings = sr_localsid_error_strings,
1450 : .n_next_nodes = SR_LOCALSID_N_NEXT,
1451 : .next_nodes = {
1452 : #define _(s,n) [SR_LOCALSID_NEXT_##s] = n,
1453 : foreach_sr_localsid_next
1454 : #undef _
1455 : },
1456 : };
1457 : /* *INDENT-ON* */
1458 :
1459 : /**
1460 : * @brief SR LocalSID graph node. Supports all default SR Endpoint without decaps
1461 : */
1462 : static uword
1463 4 : sr_localsid_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
1464 : vlib_frame_t * from_frame)
1465 : {
1466 : u32 n_left_from, next_index, *from, *to_next;
1467 4 : ip6_sr_main_t *sm = &sr_main;
1468 4 : from = vlib_frame_vector_args (from_frame);
1469 4 : n_left_from = from_frame->n_vectors;
1470 4 : next_index = node->cached_next_index;
1471 4 : u32 thread_index = vm->thread_index;
1472 :
1473 8 : while (n_left_from > 0)
1474 : {
1475 : u32 n_left_to_next;
1476 4 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1477 :
1478 : /* Quad - Loop */
1479 5 : while (n_left_from >= 8 && n_left_to_next >= 4)
1480 : {
1481 : u32 bi0, bi1, bi2, bi3;
1482 : vlib_buffer_t *b0, *b1, *b2, *b3;
1483 : ip6_header_t *ip0, *ip1, *ip2, *ip3;
1484 : ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1485 : ip6_ext_header_t *prev0, *prev1, *prev2, *prev3;
1486 : u32 next0, next1, next2, next3;
1487 1 : next0 = next1 = next2 = next3 = SR_LOCALSID_NEXT_IP6_LOOKUP;
1488 : ip6_sr_localsid_t *ls0, *ls1, *ls2, *ls3;
1489 :
1490 : /* Prefetch next iteration. */
1491 : {
1492 : vlib_buffer_t *p4, *p5, *p6, *p7;
1493 :
1494 1 : p4 = vlib_get_buffer (vm, from[4]);
1495 1 : p5 = vlib_get_buffer (vm, from[5]);
1496 1 : p6 = vlib_get_buffer (vm, from[6]);
1497 1 : p7 = vlib_get_buffer (vm, from[7]);
1498 :
1499 : /* Prefetch the buffer header and packet for the N+2 loop iteration */
1500 1 : vlib_prefetch_buffer_header (p4, LOAD);
1501 1 : vlib_prefetch_buffer_header (p5, LOAD);
1502 1 : vlib_prefetch_buffer_header (p6, LOAD);
1503 1 : vlib_prefetch_buffer_header (p7, LOAD);
1504 :
1505 1 : clib_prefetch_store (p4->data);
1506 1 : clib_prefetch_store (p5->data);
1507 1 : clib_prefetch_store (p6->data);
1508 1 : clib_prefetch_store (p7->data);
1509 : }
1510 :
1511 1 : to_next[0] = bi0 = from[0];
1512 1 : to_next[1] = bi1 = from[1];
1513 1 : to_next[2] = bi2 = from[2];
1514 1 : to_next[3] = bi3 = from[3];
1515 1 : from += 4;
1516 1 : to_next += 4;
1517 1 : n_left_from -= 4;
1518 1 : n_left_to_next -= 4;
1519 :
1520 1 : b0 = vlib_get_buffer (vm, bi0);
1521 1 : b1 = vlib_get_buffer (vm, bi1);
1522 1 : b2 = vlib_get_buffer (vm, bi2);
1523 1 : b3 = vlib_get_buffer (vm, bi3);
1524 :
1525 1 : ip0 = vlib_buffer_get_current (b0);
1526 1 : ip1 = vlib_buffer_get_current (b1);
1527 1 : ip2 = vlib_buffer_get_current (b2);
1528 1 : ip3 = vlib_buffer_get_current (b3);
1529 :
1530 : sr0 =
1531 1 : ip6_ext_header_find (vm, b0, ip0, IP_PROTOCOL_IPV6_ROUTE, &prev0);
1532 : sr1 =
1533 1 : ip6_ext_header_find (vm, b1, ip1, IP_PROTOCOL_IPV6_ROUTE, &prev1);
1534 : sr2 =
1535 1 : ip6_ext_header_find (vm, b2, ip2, IP_PROTOCOL_IPV6_ROUTE, &prev2);
1536 : sr3 =
1537 1 : ip6_ext_header_find (vm, b3, ip3, IP_PROTOCOL_IPV6_ROUTE, &prev3);
1538 :
1539 1 : ls0 =
1540 1 : pool_elt_at_index (sm->localsids,
1541 : vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1542 1 : ls1 =
1543 1 : pool_elt_at_index (sm->localsids,
1544 : vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1545 1 : ls2 =
1546 1 : pool_elt_at_index (sm->localsids,
1547 : vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1548 1 : ls3 =
1549 1 : pool_elt_at_index (sm->localsids,
1550 : vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1551 :
1552 1 : end_srh_processing (node, b0, ip0, sr0, ls0, &next0, ls0->end_psp,
1553 : prev0);
1554 1 : end_srh_processing (node, b1, ip1, sr1, ls1, &next1, ls1->end_psp,
1555 : prev1);
1556 1 : end_srh_processing (node, b2, ip2, sr2, ls2, &next2, ls2->end_psp,
1557 : prev2);
1558 1 : end_srh_processing (node, b3, ip3, sr3, ls3, &next3, ls3->end_psp,
1559 : prev3);
1560 :
1561 1 : if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1562 : {
1563 : sr_localsid_trace_t *tr =
1564 1 : vlib_add_trace (vm, node, b0, sizeof (*tr));
1565 1 : tr->num_segments = 0;
1566 1 : clib_memcpy (tr->localsid.as_u8, ls0->localsid.as_u8,
1567 : sizeof (tr->localsid.as_u8));
1568 1 : tr->behavior = ls0->behavior;
1569 1 : if (ip0 == vlib_buffer_get_current (b0))
1570 : {
1571 1 : if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE
1572 1 : && sr0->type == ROUTING_HEADER_TYPE_SR)
1573 : {
1574 1 : clib_memcpy (tr->sr, sr0->segments, sr0->length * 8);
1575 1 : tr->num_segments =
1576 1 : sr0->length * 8 / sizeof (ip6_address_t);
1577 1 : tr->segments_left = sr0->segments_left;
1578 : }
1579 : }
1580 : else
1581 0 : tr->num_segments = 0xFF;
1582 : }
1583 :
1584 1 : if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1585 : {
1586 : sr_localsid_trace_t *tr =
1587 1 : vlib_add_trace (vm, node, b1, sizeof (*tr));
1588 1 : tr->num_segments = 0;
1589 1 : clib_memcpy (tr->localsid.as_u8, ls1->localsid.as_u8,
1590 : sizeof (tr->localsid.as_u8));
1591 1 : tr->behavior = ls1->behavior;
1592 1 : if (ip1 == vlib_buffer_get_current (b1))
1593 : {
1594 1 : if (ip1->protocol == IP_PROTOCOL_IPV6_ROUTE
1595 1 : && sr1->type == ROUTING_HEADER_TYPE_SR)
1596 : {
1597 1 : clib_memcpy (tr->sr, sr1->segments, sr1->length * 8);
1598 1 : tr->num_segments =
1599 1 : sr1->length * 8 / sizeof (ip6_address_t);
1600 1 : tr->segments_left = sr1->segments_left;
1601 : }
1602 : }
1603 : else
1604 0 : tr->num_segments = 0xFF;
1605 : }
1606 :
1607 1 : if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1608 : {
1609 : sr_localsid_trace_t *tr =
1610 1 : vlib_add_trace (vm, node, b2, sizeof (*tr));
1611 1 : tr->num_segments = 0;
1612 1 : clib_memcpy (tr->localsid.as_u8, ls2->localsid.as_u8,
1613 : sizeof (tr->localsid.as_u8));
1614 1 : tr->behavior = ls2->behavior;
1615 1 : if (ip2 == vlib_buffer_get_current (b2))
1616 : {
1617 1 : if (ip2->protocol == IP_PROTOCOL_IPV6_ROUTE
1618 1 : && sr2->type == ROUTING_HEADER_TYPE_SR)
1619 : {
1620 1 : clib_memcpy (tr->sr, sr2->segments, sr2->length * 8);
1621 1 : tr->num_segments =
1622 1 : sr2->length * 8 / sizeof (ip6_address_t);
1623 1 : tr->segments_left = sr2->segments_left;
1624 : }
1625 : }
1626 : else
1627 0 : tr->num_segments = 0xFF;
1628 : }
1629 :
1630 1 : if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1631 : {
1632 : sr_localsid_trace_t *tr =
1633 1 : vlib_add_trace (vm, node, b3, sizeof (*tr));
1634 1 : tr->num_segments = 0;
1635 1 : clib_memcpy (tr->localsid.as_u8, ls3->localsid.as_u8,
1636 : sizeof (tr->localsid.as_u8));
1637 1 : tr->behavior = ls3->behavior;
1638 1 : if (ip3 == vlib_buffer_get_current (b3))
1639 : {
1640 1 : if (ip3->protocol == IP_PROTOCOL_IPV6_ROUTE
1641 1 : && sr3->type == ROUTING_HEADER_TYPE_SR)
1642 : {
1643 1 : clib_memcpy (tr->sr, sr3->segments, sr3->length * 8);
1644 1 : tr->num_segments =
1645 1 : sr3->length * 8 / sizeof (ip6_address_t);
1646 1 : tr->segments_left = sr3->segments_left;
1647 : }
1648 : }
1649 : else
1650 0 : tr->num_segments = 0xFF;
1651 : }
1652 :
1653 2 : vlib_increment_combined_counter
1654 1 : (((next0 ==
1655 : SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1656 1 : &(sm->sr_ls_valid_counters)), thread_index, ls0 - sm->localsids,
1657 : 1, vlib_buffer_length_in_chain (vm, b0));
1658 :
1659 2 : vlib_increment_combined_counter
1660 1 : (((next1 ==
1661 : SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1662 1 : &(sm->sr_ls_valid_counters)), thread_index, ls1 - sm->localsids,
1663 : 1, vlib_buffer_length_in_chain (vm, b1));
1664 :
1665 2 : vlib_increment_combined_counter
1666 1 : (((next2 ==
1667 : SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1668 1 : &(sm->sr_ls_valid_counters)), thread_index, ls2 - sm->localsids,
1669 : 1, vlib_buffer_length_in_chain (vm, b2));
1670 :
1671 2 : vlib_increment_combined_counter
1672 1 : (((next3 ==
1673 : SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1674 1 : &(sm->sr_ls_valid_counters)), thread_index, ls3 - sm->localsids,
1675 : 1, vlib_buffer_length_in_chain (vm, b3));
1676 :
1677 1 : vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1678 : n_left_to_next, bi0, bi1, bi2, bi3,
1679 : next0, next1, next2, next3);
1680 : }
1681 :
1682 : /* Single loop for potentially the last three packets */
1683 27 : while (n_left_from > 0 && n_left_to_next > 0)
1684 : {
1685 : u32 bi0;
1686 : vlib_buffer_t *b0;
1687 23 : ip6_header_t *ip0 = 0;
1688 : ip6_ext_header_t *prev0;
1689 : ip6_sr_header_t *sr0;
1690 23 : u32 next0 = SR_LOCALSID_NEXT_IP6_LOOKUP;
1691 : ip6_sr_localsid_t *ls0;
1692 :
1693 23 : bi0 = from[0];
1694 23 : to_next[0] = bi0;
1695 23 : from += 1;
1696 23 : to_next += 1;
1697 23 : n_left_from -= 1;
1698 23 : n_left_to_next -= 1;
1699 :
1700 23 : b0 = vlib_get_buffer (vm, bi0);
1701 23 : ip0 = vlib_buffer_get_current (b0);
1702 : sr0 =
1703 23 : ip6_ext_header_find (vm, b0, ip0, IP_PROTOCOL_IPV6_ROUTE, &prev0);
1704 :
1705 : /* Lookup the SR End behavior based on IP DA (adj) */
1706 23 : ls0 =
1707 23 : pool_elt_at_index (sm->localsids,
1708 : vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1709 :
1710 : /* SRH processing */
1711 23 : end_srh_processing (node, b0, ip0, sr0, ls0, &next0, ls0->end_psp,
1712 : prev0);
1713 :
1714 23 : if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1715 : {
1716 : sr_localsid_trace_t *tr =
1717 23 : vlib_add_trace (vm, node, b0, sizeof (*tr));
1718 23 : tr->num_segments = 0;
1719 23 : clib_memcpy (tr->localsid.as_u8, ls0->localsid.as_u8,
1720 : sizeof (tr->localsid.as_u8));
1721 23 : tr->behavior = ls0->behavior;
1722 23 : if (ip0 == vlib_buffer_get_current (b0))
1723 : {
1724 17 : if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE
1725 14 : && sr0->type == ROUTING_HEADER_TYPE_SR)
1726 : {
1727 14 : clib_memcpy (tr->sr, sr0->segments, sr0->length * 8);
1728 14 : tr->num_segments =
1729 14 : sr0->length * 8 / sizeof (ip6_address_t);
1730 14 : tr->segments_left = sr0->segments_left;
1731 : }
1732 : }
1733 : else
1734 6 : tr->num_segments = 0xFF;
1735 : }
1736 :
1737 46 : vlib_increment_combined_counter
1738 23 : (((next0 ==
1739 : SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1740 23 : &(sm->sr_ls_valid_counters)), thread_index, ls0 - sm->localsids,
1741 : 1, vlib_buffer_length_in_chain (vm, b0));
1742 :
1743 23 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1744 : n_left_to_next, bi0, next0);
1745 : }
1746 4 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1747 : }
1748 4 : return from_frame->n_vectors;
1749 : }
1750 :
1751 : /* *INDENT-OFF* */
1752 183788 : VLIB_REGISTER_NODE (sr_localsid_node) = {
1753 : .function = sr_localsid_fn,
1754 : .name = "sr-localsid",
1755 : .vector_size = sizeof (u32),
1756 : .format_trace = format_sr_localsid_trace,
1757 : .type = VLIB_NODE_TYPE_INTERNAL,
1758 : .n_errors = SR_LOCALSID_N_ERROR,
1759 : .error_strings = sr_localsid_error_strings,
1760 : .n_next_nodes = SR_LOCALSID_N_NEXT,
1761 : .next_nodes = {
1762 : #define _(s,n) [SR_LOCALSID_NEXT_##s] = n,
1763 : foreach_sr_localsid_next
1764 : #undef _
1765 : },
1766 : };
1767 : /* *INDENT-ON* */
1768 :
1769 : /**
1770 : * @brief SR LocalSID uN graph node. Supports all default SR Endpoint without decaps
1771 : */
1772 : static uword
1773 2 : sr_localsid_un_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
1774 : vlib_frame_t * from_frame)
1775 : {
1776 : u32 n_left_from, next_index, *from, *to_next;
1777 2 : ip6_sr_main_t *sm = &sr_main;
1778 2 : from = vlib_frame_vector_args (from_frame);
1779 2 : n_left_from = from_frame->n_vectors;
1780 2 : next_index = node->cached_next_index;
1781 2 : u32 thread_index = vm->thread_index;
1782 :
1783 4 : while (n_left_from > 0)
1784 : {
1785 : u32 n_left_to_next;
1786 2 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1787 :
1788 : /* Quad - Loop */
1789 2 : while (n_left_from >= 8 && n_left_to_next >= 4)
1790 : {
1791 : u32 bi0, bi1, bi2, bi3;
1792 : vlib_buffer_t *b0, *b1, *b2, *b3;
1793 : ip6_header_t *ip0, *ip1, *ip2, *ip3;
1794 : ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1795 : ip6_ext_header_t *prev0, *prev1, *prev2, *prev3;
1796 : u32 next0, next1, next2, next3;
1797 0 : next0 = next1 = next2 = next3 = SR_LOCALSID_NEXT_IP6_LOOKUP;
1798 : ip6_sr_localsid_t *ls0, *ls1, *ls2, *ls3;
1799 :
1800 : /* Prefetch next iteration. */
1801 : {
1802 : vlib_buffer_t *p4, *p5, *p6, *p7;
1803 :
1804 0 : p4 = vlib_get_buffer (vm, from[4]);
1805 0 : p5 = vlib_get_buffer (vm, from[5]);
1806 0 : p6 = vlib_get_buffer (vm, from[6]);
1807 0 : p7 = vlib_get_buffer (vm, from[7]);
1808 :
1809 : /* Prefetch the buffer header and packet for the N+2 loop iteration */
1810 0 : vlib_prefetch_buffer_header (p4, LOAD);
1811 0 : vlib_prefetch_buffer_header (p5, LOAD);
1812 0 : vlib_prefetch_buffer_header (p6, LOAD);
1813 0 : vlib_prefetch_buffer_header (p7, LOAD);
1814 :
1815 0 : clib_prefetch_store (p4->data);
1816 0 : clib_prefetch_store (p5->data);
1817 0 : clib_prefetch_store (p6->data);
1818 0 : clib_prefetch_store (p7->data);
1819 : }
1820 :
1821 0 : to_next[0] = bi0 = from[0];
1822 0 : to_next[1] = bi1 = from[1];
1823 0 : to_next[2] = bi2 = from[2];
1824 0 : to_next[3] = bi3 = from[3];
1825 0 : from += 4;
1826 0 : to_next += 4;
1827 0 : n_left_from -= 4;
1828 0 : n_left_to_next -= 4;
1829 :
1830 0 : b0 = vlib_get_buffer (vm, bi0);
1831 0 : b1 = vlib_get_buffer (vm, bi1);
1832 0 : b2 = vlib_get_buffer (vm, bi2);
1833 0 : b3 = vlib_get_buffer (vm, bi3);
1834 :
1835 0 : ip0 = vlib_buffer_get_current (b0);
1836 0 : ip1 = vlib_buffer_get_current (b1);
1837 0 : ip2 = vlib_buffer_get_current (b2);
1838 0 : ip3 = vlib_buffer_get_current (b3);
1839 :
1840 : sr0 =
1841 0 : ip6_ext_header_find (vm, b0, ip0, IP_PROTOCOL_IPV6_ROUTE, &prev0);
1842 : sr1 =
1843 0 : ip6_ext_header_find (vm, b1, ip1, IP_PROTOCOL_IPV6_ROUTE, &prev1);
1844 : sr2 =
1845 0 : ip6_ext_header_find (vm, b2, ip2, IP_PROTOCOL_IPV6_ROUTE, &prev2);
1846 : sr3 =
1847 0 : ip6_ext_header_find (vm, b3, ip3, IP_PROTOCOL_IPV6_ROUTE, &prev3);
1848 :
1849 0 : ls0 =
1850 0 : pool_elt_at_index (sm->localsids,
1851 : vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1852 0 : ls1 =
1853 0 : pool_elt_at_index (sm->localsids,
1854 : vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1855 0 : ls2 =
1856 0 : pool_elt_at_index (sm->localsids,
1857 : vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1858 0 : ls3 =
1859 0 : pool_elt_at_index (sm->localsids,
1860 : vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1861 :
1862 0 : end_un_srh_processing (node, b0, ip0, sr0, ls0, &next0,
1863 0 : ls0->end_psp, prev0);
1864 0 : end_un_srh_processing (node, b1, ip1, sr1, ls1, &next1,
1865 0 : ls1->end_psp, prev1);
1866 0 : end_un_srh_processing (node, b2, ip2, sr2, ls2, &next2,
1867 0 : ls2->end_psp, prev2);
1868 0 : end_un_srh_processing (node, b3, ip3, sr3, ls3, &next3,
1869 0 : ls3->end_psp, prev3);
1870 :
1871 0 : if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1872 : {
1873 : sr_localsid_trace_t *tr =
1874 0 : vlib_add_trace (vm, node, b0, sizeof (*tr));
1875 0 : tr->num_segments = 0;
1876 0 : clib_memcpy (tr->localsid.as_u8, ls0->localsid.as_u8,
1877 : sizeof (tr->localsid.as_u8));
1878 0 : tr->behavior = ls0->behavior;
1879 0 : if (ip0 == vlib_buffer_get_current (b0))
1880 : {
1881 0 : if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE
1882 0 : && sr0->type == ROUTING_HEADER_TYPE_SR)
1883 : {
1884 0 : clib_memcpy (tr->sr, sr0->segments, sr0->length * 8);
1885 0 : tr->num_segments =
1886 0 : sr0->length * 8 / sizeof (ip6_address_t);
1887 0 : tr->segments_left = sr0->segments_left;
1888 : }
1889 : }
1890 : else
1891 0 : tr->num_segments = 0xFF;
1892 : }
1893 :
1894 0 : if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1895 : {
1896 : sr_localsid_trace_t *tr =
1897 0 : vlib_add_trace (vm, node, b1, sizeof (*tr));
1898 0 : tr->num_segments = 0;
1899 0 : clib_memcpy (tr->localsid.as_u8, ls1->localsid.as_u8,
1900 : sizeof (tr->localsid.as_u8));
1901 0 : tr->behavior = ls1->behavior;
1902 0 : if (ip1 == vlib_buffer_get_current (b1))
1903 : {
1904 0 : if (ip1->protocol == IP_PROTOCOL_IPV6_ROUTE
1905 0 : && sr1->type == ROUTING_HEADER_TYPE_SR)
1906 : {
1907 0 : clib_memcpy (tr->sr, sr1->segments, sr1->length * 8);
1908 0 : tr->num_segments =
1909 0 : sr1->length * 8 / sizeof (ip6_address_t);
1910 0 : tr->segments_left = sr1->segments_left;
1911 : }
1912 : }
1913 : else
1914 0 : tr->num_segments = 0xFF;
1915 : }
1916 :
1917 0 : if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1918 : {
1919 : sr_localsid_trace_t *tr =
1920 0 : vlib_add_trace (vm, node, b2, sizeof (*tr));
1921 0 : tr->num_segments = 0;
1922 0 : clib_memcpy (tr->localsid.as_u8, ls2->localsid.as_u8,
1923 : sizeof (tr->localsid.as_u8));
1924 0 : tr->behavior = ls2->behavior;
1925 0 : if (ip2 == vlib_buffer_get_current (b2))
1926 : {
1927 0 : if (ip2->protocol == IP_PROTOCOL_IPV6_ROUTE
1928 0 : && sr2->type == ROUTING_HEADER_TYPE_SR)
1929 : {
1930 0 : clib_memcpy (tr->sr, sr2->segments, sr2->length * 8);
1931 0 : tr->num_segments =
1932 0 : sr2->length * 8 / sizeof (ip6_address_t);
1933 0 : tr->segments_left = sr2->segments_left;
1934 : }
1935 : }
1936 : else
1937 0 : tr->num_segments = 0xFF;
1938 : }
1939 :
1940 0 : if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1941 : {
1942 : sr_localsid_trace_t *tr =
1943 0 : vlib_add_trace (vm, node, b3, sizeof (*tr));
1944 0 : tr->num_segments = 0;
1945 0 : clib_memcpy (tr->localsid.as_u8, ls3->localsid.as_u8,
1946 : sizeof (tr->localsid.as_u8));
1947 0 : tr->behavior = ls3->behavior;
1948 0 : if (ip3 == vlib_buffer_get_current (b3))
1949 : {
1950 0 : if (ip3->protocol == IP_PROTOCOL_IPV6_ROUTE
1951 0 : && sr3->type == ROUTING_HEADER_TYPE_SR)
1952 : {
1953 0 : clib_memcpy (tr->sr, sr3->segments, sr3->length * 8);
1954 0 : tr->num_segments =
1955 0 : sr3->length * 8 / sizeof (ip6_address_t);
1956 0 : tr->segments_left = sr3->segments_left;
1957 : }
1958 : }
1959 : else
1960 0 : tr->num_segments = 0xFF;
1961 : }
1962 :
1963 0 : vlib_increment_combined_counter
1964 0 : (((next0 ==
1965 : SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1966 0 : &(sm->sr_ls_valid_counters)), thread_index, ls0 - sm->localsids,
1967 : 1, vlib_buffer_length_in_chain (vm, b0));
1968 :
1969 0 : vlib_increment_combined_counter
1970 0 : (((next1 ==
1971 : SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1972 0 : &(sm->sr_ls_valid_counters)), thread_index, ls1 - sm->localsids,
1973 : 1, vlib_buffer_length_in_chain (vm, b1));
1974 :
1975 0 : vlib_increment_combined_counter
1976 0 : (((next2 ==
1977 : SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1978 0 : &(sm->sr_ls_valid_counters)), thread_index, ls2 - sm->localsids,
1979 : 1, vlib_buffer_length_in_chain (vm, b2));
1980 :
1981 0 : vlib_increment_combined_counter
1982 0 : (((next3 ==
1983 : SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1984 0 : &(sm->sr_ls_valid_counters)), thread_index, ls3 - sm->localsids,
1985 : 1, vlib_buffer_length_in_chain (vm, b3));
1986 :
1987 0 : vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1988 : n_left_to_next, bi0, bi1, bi2, bi3,
1989 : next0, next1, next2, next3);
1990 : }
1991 :
1992 : /* Single loop for potentially the last three packets */
1993 6 : while (n_left_from > 0 && n_left_to_next > 0)
1994 : {
1995 : u32 bi0;
1996 : vlib_buffer_t *b0;
1997 4 : ip6_header_t *ip0 = 0;
1998 : ip6_ext_header_t *prev0;
1999 : ip6_sr_header_t *sr0;
2000 4 : u32 next0 = SR_LOCALSID_NEXT_IP6_LOOKUP;
2001 : ip6_sr_localsid_t *ls0;
2002 :
2003 4 : bi0 = from[0];
2004 4 : to_next[0] = bi0;
2005 4 : from += 1;
2006 4 : to_next += 1;
2007 4 : n_left_from -= 1;
2008 4 : n_left_to_next -= 1;
2009 :
2010 4 : b0 = vlib_get_buffer (vm, bi0);
2011 4 : ip0 = vlib_buffer_get_current (b0);
2012 : sr0 =
2013 4 : ip6_ext_header_find (vm, b0, ip0, IP_PROTOCOL_IPV6_ROUTE, &prev0);
2014 :
2015 : /* Lookup the SR End behavior based on IP DA (adj) */
2016 4 : ls0 =
2017 4 : pool_elt_at_index (sm->localsids,
2018 : vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2019 :
2020 : /* SRH processing */
2021 4 : end_un_srh_processing (node, b0, ip0, sr0, ls0, &next0,
2022 4 : ls0->end_psp, prev0);
2023 :
2024 4 : if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2025 : {
2026 : sr_localsid_trace_t *tr =
2027 4 : vlib_add_trace (vm, node, b0, sizeof (*tr));
2028 4 : tr->num_segments = 0;
2029 4 : clib_memcpy (tr->localsid.as_u8, ls0->localsid.as_u8,
2030 : sizeof (tr->localsid.as_u8));
2031 4 : tr->behavior = ls0->behavior;
2032 4 : if (ip0 == vlib_buffer_get_current (b0))
2033 : {
2034 4 : if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE
2035 2 : && sr0->type == ROUTING_HEADER_TYPE_SR)
2036 : {
2037 2 : clib_memcpy (tr->sr, sr0->segments, sr0->length * 8);
2038 2 : tr->num_segments =
2039 2 : sr0->length * 8 / sizeof (ip6_address_t);
2040 2 : tr->segments_left = sr0->segments_left;
2041 : }
2042 : }
2043 : else
2044 0 : tr->num_segments = 0xFF;
2045 : }
2046 :
2047 8 : vlib_increment_combined_counter
2048 4 : (((next0 ==
2049 : SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
2050 4 : &(sm->sr_ls_valid_counters)), thread_index, ls0 - sm->localsids,
2051 : 1, vlib_buffer_length_in_chain (vm, b0));
2052 :
2053 4 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2054 : n_left_to_next, bi0, next0);
2055 : }
2056 2 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2057 : }
2058 2 : return from_frame->n_vectors;
2059 : }
2060 :
2061 : /* *INDENT-OFF* */
2062 183788 : VLIB_REGISTER_NODE (sr_localsid_un_node) = {
2063 : .function = sr_localsid_un_fn,
2064 : .name = "sr-localsid-un",
2065 : .vector_size = sizeof (u32),
2066 : .format_trace = format_sr_localsid_trace,
2067 : .type = VLIB_NODE_TYPE_INTERNAL,
2068 : .n_errors = SR_LOCALSID_N_ERROR,
2069 : .error_strings = sr_localsid_error_strings,
2070 : .n_next_nodes = SR_LOCALSID_N_NEXT,
2071 : .next_nodes = {
2072 : #define _(s,n) [SR_LOCALSID_NEXT_##s] = n,
2073 : foreach_sr_localsid_next
2074 : #undef _
2075 : },
2076 : };
2077 : /* *INDENT-ON* */
2078 :
2079 : static uword
2080 2 : sr_localsid_un_perf_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
2081 : vlib_frame_t * from_frame)
2082 : {
2083 : u32 n_left_from, next_index, *from, *to_next;
2084 2 : ip6_sr_main_t *sm = &sr_main;
2085 2 : from = vlib_frame_vector_args (from_frame);
2086 2 : n_left_from = from_frame->n_vectors;
2087 2 : next_index = node->cached_next_index;
2088 2 : u32 thread_index = vm->thread_index;
2089 :
2090 4 : while (n_left_from > 0)
2091 : {
2092 : u32 n_left_to_next;
2093 2 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2094 :
2095 : /* Quad - Loop */
2096 2 : while (n_left_from >= 8 && n_left_to_next >= 4)
2097 : {
2098 : u32 bi0, bi1, bi2, bi3;
2099 : vlib_buffer_t *b0, *b1, *b2, *b3;
2100 : ip6_header_t *ip0, *ip1, *ip2, *ip3;
2101 : u32 next0, next1, next2, next3;
2102 0 : next0 = next1 = next2 = next3 = SR_LOCALSID_NEXT_IP6_LOOKUP;
2103 : ip6_sr_localsid_t *ls0, *ls1, *ls2, *ls3;
2104 :
2105 : /* Prefetch next iteration. */
2106 : {
2107 : vlib_buffer_t *p4, *p5, *p6, *p7;
2108 :
2109 0 : p4 = vlib_get_buffer (vm, from[4]);
2110 0 : p5 = vlib_get_buffer (vm, from[5]);
2111 0 : p6 = vlib_get_buffer (vm, from[6]);
2112 0 : p7 = vlib_get_buffer (vm, from[7]);
2113 :
2114 : /* Prefetch the buffer header and packet for the N+2 loop iteration */
2115 0 : vlib_prefetch_buffer_header (p4, LOAD);
2116 0 : vlib_prefetch_buffer_header (p5, LOAD);
2117 0 : vlib_prefetch_buffer_header (p6, LOAD);
2118 0 : vlib_prefetch_buffer_header (p7, LOAD);
2119 :
2120 0 : clib_prefetch_store (p4->data);
2121 0 : clib_prefetch_store (p5->data);
2122 0 : clib_prefetch_store (p6->data);
2123 0 : clib_prefetch_store (p7->data);
2124 : }
2125 :
2126 0 : to_next[0] = bi0 = from[0];
2127 0 : to_next[1] = bi1 = from[1];
2128 0 : to_next[2] = bi2 = from[2];
2129 0 : to_next[3] = bi3 = from[3];
2130 0 : from += 4;
2131 0 : to_next += 4;
2132 0 : n_left_from -= 4;
2133 0 : n_left_to_next -= 4;
2134 :
2135 0 : b0 = vlib_get_buffer (vm, bi0);
2136 0 : b1 = vlib_get_buffer (vm, bi1);
2137 0 : b2 = vlib_get_buffer (vm, bi2);
2138 0 : b3 = vlib_get_buffer (vm, bi3);
2139 :
2140 0 : ip0 = vlib_buffer_get_current (b0);
2141 0 : ip1 = vlib_buffer_get_current (b1);
2142 0 : ip2 = vlib_buffer_get_current (b2);
2143 0 : ip3 = vlib_buffer_get_current (b3);
2144 :
2145 0 : ls0 =
2146 0 : pool_elt_at_index (sm->localsids,
2147 : vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2148 0 : ls1 =
2149 0 : pool_elt_at_index (sm->localsids,
2150 : vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2151 0 : ls2 =
2152 0 : pool_elt_at_index (sm->localsids,
2153 : vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2154 0 : ls3 =
2155 0 : pool_elt_at_index (sm->localsids,
2156 : vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2157 :
2158 0 : end_un_processing (ip0, ls0);
2159 0 : end_un_processing (ip1, ls1);
2160 0 : end_un_processing (ip2, ls2);
2161 0 : end_un_processing (ip3, ls3);
2162 :
2163 0 : if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2164 : {
2165 : sr_localsid_trace_t *tr =
2166 0 : vlib_add_trace (vm, node, b0, sizeof (*tr));
2167 0 : tr->num_segments = 0;
2168 0 : clib_memcpy (tr->localsid.as_u8, ls0->localsid.as_u8,
2169 : sizeof (tr->localsid.as_u8));
2170 0 : tr->behavior = ls0->behavior;
2171 : }
2172 :
2173 0 : if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2174 : {
2175 : sr_localsid_trace_t *tr =
2176 0 : vlib_add_trace (vm, node, b1, sizeof (*tr));
2177 0 : tr->num_segments = 0;
2178 0 : clib_memcpy (tr->localsid.as_u8, ls1->localsid.as_u8,
2179 : sizeof (tr->localsid.as_u8));
2180 0 : tr->behavior = ls1->behavior;
2181 : }
2182 :
2183 0 : if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2184 : {
2185 : sr_localsid_trace_t *tr =
2186 0 : vlib_add_trace (vm, node, b2, sizeof (*tr));
2187 0 : tr->num_segments = 0;
2188 0 : clib_memcpy (tr->localsid.as_u8, ls2->localsid.as_u8,
2189 : sizeof (tr->localsid.as_u8));
2190 0 : tr->behavior = ls2->behavior;
2191 : }
2192 :
2193 0 : if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2194 : {
2195 : sr_localsid_trace_t *tr =
2196 0 : vlib_add_trace (vm, node, b3, sizeof (*tr));
2197 0 : tr->num_segments = 0;
2198 0 : clib_memcpy (tr->localsid.as_u8, ls3->localsid.as_u8,
2199 : sizeof (tr->localsid.as_u8));
2200 0 : tr->behavior = ls3->behavior;
2201 : }
2202 :
2203 0 : vlib_increment_combined_counter
2204 0 : (&(sm->sr_ls_valid_counters), thread_index, ls0 - sm->localsids,
2205 : 1, vlib_buffer_length_in_chain (vm, b0));
2206 :
2207 0 : vlib_increment_combined_counter
2208 0 : (&(sm->sr_ls_valid_counters), thread_index, ls1 - sm->localsids,
2209 : 1, vlib_buffer_length_in_chain (vm, b1));
2210 :
2211 0 : vlib_increment_combined_counter
2212 0 : (&(sm->sr_ls_valid_counters), thread_index, ls2 - sm->localsids,
2213 : 1, vlib_buffer_length_in_chain (vm, b2));
2214 :
2215 0 : vlib_increment_combined_counter
2216 0 : (&(sm->sr_ls_valid_counters), thread_index, ls3 - sm->localsids,
2217 : 1, vlib_buffer_length_in_chain (vm, b3));
2218 :
2219 0 : vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2220 : n_left_to_next, bi0, bi1, bi2, bi3,
2221 : next0, next1, next2, next3);
2222 : }
2223 :
2224 : /* Single loop for potentially the last three packets */
2225 6 : while (n_left_from > 0 && n_left_to_next > 0)
2226 : {
2227 : u32 bi0;
2228 : vlib_buffer_t *b0;
2229 4 : ip6_header_t *ip0 = 0;
2230 4 : u32 next0 = SR_LOCALSID_NEXT_IP6_LOOKUP;
2231 : ip6_sr_localsid_t *ls0;
2232 :
2233 4 : bi0 = from[0];
2234 4 : to_next[0] = bi0;
2235 4 : from += 1;
2236 4 : to_next += 1;
2237 4 : n_left_from -= 1;
2238 4 : n_left_to_next -= 1;
2239 :
2240 4 : b0 = vlib_get_buffer (vm, bi0);
2241 4 : ip0 = vlib_buffer_get_current (b0);
2242 :
2243 : /* Lookup the SR End behavior based on IP DA (adj) */
2244 4 : ls0 =
2245 4 : pool_elt_at_index (sm->localsids,
2246 : vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2247 :
2248 : /* SRH processing */
2249 4 : end_un_processing (ip0, ls0);
2250 :
2251 4 : if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2252 : {
2253 : sr_localsid_trace_t *tr =
2254 4 : vlib_add_trace (vm, node, b0, sizeof (*tr));
2255 4 : tr->num_segments = 0;
2256 4 : clib_memcpy (tr->localsid.as_u8, ls0->localsid.as_u8,
2257 : sizeof (tr->localsid.as_u8));
2258 4 : tr->behavior = ls0->behavior;
2259 : }
2260 :
2261 4 : vlib_increment_combined_counter
2262 4 : (&(sm->sr_ls_valid_counters), thread_index, ls0 - sm->localsids,
2263 : 1, vlib_buffer_length_in_chain (vm, b0));
2264 :
2265 4 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2266 : n_left_to_next, bi0, next0);
2267 : }
2268 2 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2269 : }
2270 2 : return from_frame->n_vectors;
2271 : }
2272 :
2273 : /* *INDENT-OFF* */
2274 183788 : VLIB_REGISTER_NODE (sr_localsid_un_perf_node) = {
2275 : .function = sr_localsid_un_perf_fn,
2276 : .name = "sr-localsid-un-perf",
2277 : .vector_size = sizeof (u32),
2278 : .format_trace = format_sr_localsid_trace,
2279 : .type = VLIB_NODE_TYPE_INTERNAL,
2280 : .n_errors = SR_LOCALSID_N_ERROR,
2281 : .error_strings = sr_localsid_error_strings,
2282 : .n_next_nodes = SR_LOCALSID_N_NEXT,
2283 : .next_nodes = {
2284 : #define _(s,n) [SR_LOCALSID_NEXT_##s] = n,
2285 : foreach_sr_localsid_next
2286 : #undef _
2287 : },
2288 : };
2289 : /* *INDENT-ON* */
2290 :
2291 : static u8 *
2292 0 : format_sr_dpo (u8 * s, va_list * args)
2293 : {
2294 0 : index_t index = va_arg (*args, index_t);
2295 0 : CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
2296 :
2297 0 : return (format (s, "SR: localsid_index:[%d]", index));
2298 : }
2299 :
2300 : const static dpo_vft_t sr_loc_vft = {
2301 : .dv_lock = sr_dpo_lock,
2302 : .dv_unlock = sr_dpo_unlock,
2303 : .dv_format = format_sr_dpo,
2304 : };
2305 :
2306 : const static char *const sr_loc_ip6_nodes[] = {
2307 : "sr-localsid",
2308 : NULL,
2309 : };
2310 :
2311 : const static char *const *const sr_loc_nodes[DPO_PROTO_NUM] = {
2312 : [DPO_PROTO_IP6] = sr_loc_ip6_nodes,
2313 : };
2314 :
2315 : const static char *const sr_loc_d_ip6_nodes[] = {
2316 : "sr-localsid-d",
2317 : NULL,
2318 : };
2319 :
2320 : const static char *const *const sr_loc_d_nodes[DPO_PROTO_NUM] = {
2321 : [DPO_PROTO_IP6] = sr_loc_d_ip6_nodes,
2322 : };
2323 :
2324 : const static char *const sr_loc_un_ip6_nodes[] = {
2325 : "sr-localsid-un",
2326 : NULL,
2327 : };
2328 :
2329 : const static char *const *const sr_loc_un_nodes[DPO_PROTO_NUM] = {
2330 : [DPO_PROTO_IP6] = sr_loc_un_ip6_nodes,
2331 : };
2332 :
2333 : const static char *const sr_loc_un_perf_ip6_nodes[] = {
2334 : "sr-localsid-un-perf",
2335 : NULL,
2336 : };
2337 :
2338 : const static char *const *const sr_loc_un_perf_nodes[DPO_PROTO_NUM] = {
2339 : [DPO_PROTO_IP6] = sr_loc_un_perf_ip6_nodes,
2340 : };
2341 :
2342 : /*************************** SR LocalSID plugins ******************************/
2343 : /**
2344 : * @brief SR LocalSID plugin registry
2345 : */
2346 : int
2347 5175 : sr_localsid_register_function (vlib_main_t * vm, u8 * fn_name,
2348 : u8 * keyword_str, u8 * def_str,
2349 : u8 * params_str, u8 prefix_length,
2350 : dpo_type_t * dpo,
2351 : format_function_t * ls_format,
2352 : unformat_function_t * ls_unformat,
2353 : sr_plugin_callback_t * creation_fn,
2354 : sr_plugin_callback_t * removal_fn)
2355 : {
2356 5175 : ip6_sr_main_t *sm = &sr_main;
2357 : uword *p;
2358 :
2359 : sr_localsid_fn_registration_t *plugin;
2360 :
2361 : /* Did this function exist? If so update it */
2362 5175 : p = hash_get_mem (sm->plugin_functions_by_key, fn_name);
2363 5175 : if (p)
2364 : {
2365 0 : plugin = pool_elt_at_index (sm->plugin_functions, p[0]);
2366 : }
2367 : /* Else create a new one and set hash key */
2368 : else
2369 : {
2370 5175 : pool_get (sm->plugin_functions, plugin);
2371 10350 : hash_set_mem (sm->plugin_functions_by_key, fn_name,
2372 : plugin - sm->plugin_functions);
2373 : }
2374 :
2375 5175 : clib_memset (plugin, 0, sizeof (*plugin));
2376 :
2377 5175 : plugin->sr_localsid_function_number = (plugin - sm->plugin_functions);
2378 5175 : plugin->sr_localsid_function_number += SR_BEHAVIOR_LAST;
2379 5175 : plugin->prefix_length = prefix_length;
2380 5175 : plugin->ls_format = ls_format;
2381 5175 : plugin->ls_unformat = ls_unformat;
2382 5175 : plugin->creation = creation_fn;
2383 5175 : plugin->removal = removal_fn;
2384 5175 : clib_memcpy (&plugin->dpo, dpo, sizeof (dpo_type_t));
2385 5175 : plugin->function_name = format (0, "%s%c", fn_name, 0);
2386 5175 : plugin->keyword_str = format (0, "%s%c", keyword_str, 0);
2387 5175 : plugin->def_str = format (0, "%s%c", def_str, 0);
2388 5175 : plugin->params_str = format (0, "%s%c", params_str, 0);
2389 :
2390 5175 : return plugin->sr_localsid_function_number;
2391 : }
2392 :
2393 : /**
2394 : * @brief CLI function to 'show' all available SR LocalSID behaviors
2395 : */
2396 : static clib_error_t *
2397 0 : show_sr_localsid_behaviors_command_fn (vlib_main_t * vm,
2398 : unformat_input_t * input,
2399 : vlib_cli_command_t * cmd)
2400 : {
2401 0 : ip6_sr_main_t *sm = &sr_main;
2402 : sr_localsid_fn_registration_t *plugin;
2403 0 : sr_localsid_fn_registration_t **plugins_vec = 0;
2404 : int i;
2405 :
2406 0 : vlib_cli_output (vm,
2407 : "SR LocalSIDs behaviors:\n-----------------------\n\n");
2408 :
2409 : /* *INDENT-OFF* */
2410 0 : pool_foreach (plugin, sm->plugin_functions)
2411 0 : { vec_add1 (plugins_vec, plugin); }
2412 : /* *INDENT-ON* */
2413 :
2414 : /* Print static behaviors */
2415 0 : vlib_cli_output (vm, "Default behaviors:\n"
2416 : "\tEnd\t-> Endpoint.\n"
2417 : "\tEnd.X\t-> Endpoint with Layer-3 cross-connect.\n"
2418 : "\t\tParameters: '<iface> <ip6_next_hop>'\n"
2419 : "\tEnd.T\t-> Endpoint with specific IPv6 table lookup.\n"
2420 : "\t\tParameters: '<fib_table>'\n"
2421 : "\tEnd.DX2\t-> Endpoint with decapsulation and Layer-2 cross-connect.\n"
2422 : "\t\tParameters: '<iface>'\n"
2423 : "\tEnd.DX6\t-> Endpoint with decapsulation and IPv6 cross-connect.\n"
2424 : "\t\tParameters: '<iface> <ip6_next_hop>'\n"
2425 : "\tEnd.DX4\t-> Endpoint with decapsulation and IPv4 cross-connect.\n"
2426 : "\t\tParameters: '<iface> <ip4_next_hop>'\n"
2427 : "\tEnd.DT6\t-> Endpoint with decapsulation and specific IPv6 table lookup.\n"
2428 : "\t\tParameters: '<ip6_fib_table>'\n"
2429 : "\tEnd.DT4\t-> Endpoint with decapsulation and specific IPv4 table lookup.\n"
2430 : "\t\tParameters: '<ip4_fib_table>'\n");
2431 0 : vlib_cli_output (vm, "Plugin behaviors:\n");
2432 0 : for (i = 0; i < vec_len (plugins_vec); i++)
2433 : {
2434 0 : plugin = plugins_vec[i];
2435 0 : vlib_cli_output (vm, "\t%s\t-> %s.\n", plugin->keyword_str,
2436 : plugin->def_str);
2437 0 : vlib_cli_output (vm, "\t\tParameters: '%s'\n", plugin->params_str);
2438 : }
2439 0 : return 0;
2440 : }
2441 :
2442 : /* *INDENT-OFF* */
2443 285289 : VLIB_CLI_COMMAND (show_sr_localsid_behaviors_command, static) = {
2444 : .path = "show sr localsids behaviors",
2445 : .short_help = "show sr localsids behaviors",
2446 : .function = show_sr_localsid_behaviors_command_fn,
2447 : };
2448 : /* *INDENT-ON* */
2449 :
2450 : /**
2451 : * @brief SR LocalSID initialization
2452 : */
2453 : clib_error_t *
2454 575 : sr_localsids_init (vlib_main_t * vm)
2455 : {
2456 : /* Init memory for function keys */
2457 575 : ip6_sr_main_t *sm = &sr_main;
2458 575 : mhash_init (&sm->sr_localsids_index_hash, sizeof (uword),
2459 : sizeof (sr_localsid_key_t));
2460 : /* Init SR behaviors DPO type */
2461 575 : sr_localsid_dpo_type = dpo_register_new_type (&sr_loc_vft, sr_loc_nodes);
2462 : /* Init SR behaviors DPO type */
2463 575 : sr_localsid_d_dpo_type =
2464 575 : dpo_register_new_type (&sr_loc_vft, sr_loc_d_nodes);
2465 : /* Init SR bhaviors DPO type */
2466 575 : sr_localsid_un_dpo_type =
2467 575 : dpo_register_new_type (&sr_loc_vft, sr_loc_un_nodes);
2468 575 : sr_localsid_un_perf_dpo_type =
2469 575 : dpo_register_new_type (&sr_loc_vft, sr_loc_un_perf_nodes);
2470 : /* Init memory for localsid plugins */
2471 575 : sm->plugin_functions_by_key = hash_create_string (0, sizeof (uword));
2472 575 : return 0;
2473 : }
2474 :
2475 67391 : VLIB_INIT_FUNCTION (sr_localsids_init);
2476 : /*
2477 : * fd.io coding-style-patch-verification: ON
2478 : *
2479 : * Local Variables:
2480 : * eval: (c-set-style "gnu")
2481 : * End:
2482 : */
|