Line data Source code
1 : /*
2 : * sr_steering.c: ipv6 segment routing steering into SR policy
3 : *
4 : * Copyright (c) 2016 Cisco and/or its affiliates. Licensed under the Apache
5 : * License, Version 2.0 (the "License"); you may not use this file except in
6 : * compliance with the License. You may obtain a copy of the License at:
7 : *
8 : * http://www.apache.org/licenses/LICENSE-2.0
9 : *
10 : * Unless required by applicable law or agreed to in writing, software
11 : * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 : * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 : * License for the specific language governing permissions and limitations
14 : * under the License.
15 : */
16 :
17 : /**
18 : * @file
19 : * @brief Packet steering into SR-MPLS Policies
20 : *
21 : * This file is in charge of handling the FIB appropiatly to steer packets
22 : * through SR Policies as defined in 'sr_mpls_policy.c'. Notice that here
23 : * we are only doing steering. SR policy application is done in
24 : * sr_policy_rewrite.c
25 : *
26 : * Supports:
27 : * - Steering of IPv6 traffic Destination Address based through BSID
28 : * - Steering of IPv4 traffic Destination Address based through BSID
29 : * - Steering of IPv4 and IPv6 traffic through N,C (SR CP)
30 : */
31 :
32 : #include <vlib/vlib.h>
33 : #include <vnet/vnet.h>
34 : #include <vnet/srmpls/sr_mpls.h>
35 : #include <vnet/ip/ip4_packet.h>
36 : #include <vnet/ip/ip6_packet.h>
37 : #include <vnet/fib/mpls_fib.h>
38 :
39 : #include <vppinfra/error.h>
40 : #include <vppinfra/elog.h>
41 :
42 : #define SRMPLS_TE_OFFSET 50
43 :
44 : /**
45 : * @brief function to sort the colors in descending order
46 : */
47 : int
48 0 : sort_color_descent (const u32 * x, u32 * y)
49 : {
50 0 : return *y - *x;
51 : }
52 :
53 : /********************* Internal (NH, C) labels *******************************/
54 : /**
55 : * @brief find the corresponding label for (endpoint, color) and lock it
56 : * endpoint might be NULL or ANY
57 : * NULL = 0, ANY=~0
58 : */
59 : u32
60 0 : find_or_create_internal_label (ip46_address_t endpoint, u32 color)
61 : {
62 0 : mpls_sr_main_t *sm = &sr_mpls_main;
63 : uword *color_table, *result_label;
64 :
65 0 : if (!sm->sr_policies_c2e2eclabel_hash.hash)
66 0 : mhash_init (&sm->sr_policies_c2e2eclabel_hash, sizeof (mhash_t),
67 : sizeof (u32));
68 :
69 0 : color_table = mhash_get (&sm->sr_policies_c2e2eclabel_hash, &color);
70 0 : if (!color_table)
71 : {
72 : mhash_t color_t;
73 0 : clib_memset (&color_t, 0, sizeof (mhash_t));
74 0 : mhash_init (&color_t, sizeof (u32), sizeof (ip46_address_t));
75 0 : mhash_set_mem (&sm->sr_policies_c2e2eclabel_hash, &color,
76 : (uword *) & color_t, NULL);
77 0 : color_table = mhash_get (&sm->sr_policies_c2e2eclabel_hash, &color);
78 : }
79 :
80 0 : result_label = mhash_get ((mhash_t *) color_table, &endpoint);
81 :
82 0 : if (result_label)
83 0 : return (u32) * result_label;
84 :
85 : /* Create and set a new internal label */
86 0 : u32 *new_internal_label = 0;
87 0 : pool_get (sm->ec_labels, new_internal_label);
88 0 : *new_internal_label = 0;
89 0 : mhash_set ((mhash_t *) color_table, &endpoint,
90 0 : (new_internal_label - sm->ec_labels) + SRMPLS_TE_OFFSET, NULL);
91 :
92 0 : return (new_internal_label - sm->ec_labels) + SRMPLS_TE_OFFSET;
93 : }
94 :
95 : always_inline void
96 0 : internal_label_lock_co (ip46_address_t endpoint, u32 color, char co_bits)
97 : {
98 : ip46_address_t zero, any;
99 0 : ip46_address_reset (&zero);
100 0 : any.as_u64[0] = any.as_u64[1] = (u64) ~ 0;
101 0 : switch (co_bits)
102 : {
103 0 : case SR_TE_CO_BITS_10:
104 0 : internal_label_lock (endpoint, color);
105 0 : internal_label_lock (zero, color);
106 0 : internal_label_lock (any, color);
107 0 : break;
108 0 : case SR_TE_CO_BITS_01:
109 0 : internal_label_lock (endpoint, color);
110 0 : internal_label_lock (zero, color);
111 0 : break;
112 0 : case SR_TE_CO_BITS_00:
113 : case SR_TE_CO_BITS_11:
114 0 : internal_label_lock (endpoint, color);
115 0 : break;
116 : }
117 0 : }
118 :
119 : /**
120 : * @brief lock the label for (NH, C)
121 : * endpoint might be NULL or ANY
122 : * NULL = 0, ANY=~0
123 : */
124 : void
125 0 : internal_label_lock (ip46_address_t endpoint, u32 color)
126 : {
127 0 : mpls_sr_main_t *sm = &sr_mpls_main;
128 : uword *color_table, *result_label;
129 :
130 0 : if (!sm->sr_policies_c2e2eclabel_hash.hash)
131 0 : return;
132 :
133 0 : color_table = mhash_get (&sm->sr_policies_c2e2eclabel_hash, &color);
134 0 : if (!color_table)
135 0 : return;
136 :
137 0 : result_label = mhash_get ((mhash_t *) color_table, &endpoint);
138 :
139 0 : if (!result_label)
140 0 : return;
141 :
142 : /* Lock it */
143 0 : u32 *label_lock =
144 0 : pool_elt_at_index (sm->ec_labels, *result_label - SRMPLS_TE_OFFSET);
145 0 : (*label_lock)++;
146 : }
147 :
148 :
149 : always_inline void
150 0 : internal_label_unlock_co (ip46_address_t endpoint, u32 color, char co_bits)
151 : {
152 : ip46_address_t zero, any;
153 0 : ip46_address_reset (&zero);
154 0 : any.as_u64[0] = any.as_u64[1] = (u64) ~ 0;
155 0 : switch (co_bits)
156 : {
157 0 : case SR_TE_CO_BITS_10:
158 0 : internal_label_unlock (endpoint, color);
159 0 : internal_label_unlock (zero, color);
160 0 : internal_label_unlock (any, color);
161 0 : break;
162 0 : case SR_TE_CO_BITS_01:
163 0 : internal_label_unlock (endpoint, color);
164 0 : internal_label_unlock (zero, color);
165 0 : break;
166 0 : case SR_TE_CO_BITS_00:
167 : case SR_TE_CO_BITS_11:
168 0 : internal_label_unlock (endpoint, color);
169 0 : break;
170 : }
171 0 : }
172 :
173 : /**
174 : * @brief Release lock on label for (endpoint, color)
175 : * endpoint might be NULL or ANY
176 : * NULL = 0, ANY=~0
177 : */
178 : void
179 0 : internal_label_unlock (ip46_address_t endpoint, u32 color)
180 : {
181 0 : mpls_sr_main_t *sm = &sr_mpls_main;
182 : uword *color_table, *result_label;
183 :
184 0 : if (!sm->sr_policies_c2e2eclabel_hash.hash)
185 0 : return;
186 :
187 0 : color_table = mhash_get (&sm->sr_policies_c2e2eclabel_hash, &color);
188 0 : if (!color_table)
189 0 : return;
190 :
191 0 : result_label = mhash_get ((mhash_t *) color_table, &endpoint);
192 :
193 0 : if (!result_label)
194 0 : return;
195 :
196 0 : u32 *label_lock =
197 0 : pool_elt_at_index (sm->ec_labels, *result_label - SRMPLS_TE_OFFSET);
198 0 : (*label_lock)--;
199 :
200 0 : if (*label_lock == 0)
201 : {
202 0 : pool_put (sm->ec_labels, label_lock);
203 0 : mhash_unset ((mhash_t *) color_table, &endpoint, NULL);
204 0 : if (mhash_elts ((mhash_t *) color_table) == 0)
205 : {
206 0 : mhash_free ((mhash_t *) color_table);
207 0 : mhash_unset (&sm->sr_policies_c2e2eclabel_hash, &color, NULL);
208 0 : if (mhash_elts (&sm->sr_policies_c2e2eclabel_hash) == 0)
209 : {
210 0 : mhash_free (&sm->sr_policies_c2e2eclabel_hash);
211 0 : sm->sr_policies_c2e2eclabel_hash.hash = NULL;
212 0 : fib_table_unlock (sm->fib_table_EC, FIB_PROTOCOL_MPLS,
213 : FIB_SOURCE_SR);
214 0 : sm->fib_table_EC = (u32) ~ 0;
215 : }
216 : }
217 : }
218 : }
219 :
220 : /********************* steering computation *********************************/
221 : /**
222 : * @brief function to update the FIB
223 : */
224 : void
225 0 : compute_sr_te_automated_steering_fib_entry (mpls_sr_steering_policy_t *
226 : steer_pl)
227 : {
228 0 : mpls_sr_main_t *sm = &sr_mpls_main;
229 0 : fib_prefix_t pfx = { 0 };
230 :
231 0 : u32 *internal_labels = 0;
232 : ip46_address_t zero, any;
233 0 : ip46_address_reset (&zero);
234 0 : any.as_u64[0] = any.as_u64[1] = (u64) ~ 0;
235 :
236 0 : u32 *color_i = NULL;
237 0 : vec_foreach (color_i, steer_pl->color)
238 : {
239 0 : switch (steer_pl->co_bits)
240 : {
241 0 : case SR_TE_CO_BITS_10:
242 0 : vec_add1 (internal_labels,
243 : find_or_create_internal_label (steer_pl->next_hop,
244 : *color_i));
245 0 : vec_add1 (internal_labels,
246 : find_or_create_internal_label (zero, *color_i));
247 0 : vec_add1 (internal_labels,
248 : find_or_create_internal_label (any, *color_i));
249 0 : break;
250 0 : case SR_TE_CO_BITS_01:
251 0 : vec_add1 (internal_labels,
252 : find_or_create_internal_label (steer_pl->next_hop,
253 : *color_i));
254 0 : vec_add1 (internal_labels,
255 : find_or_create_internal_label (zero, *color_i));
256 0 : break;
257 0 : case SR_TE_CO_BITS_00:
258 : case SR_TE_CO_BITS_11:
259 0 : vec_add1 (internal_labels,
260 : find_or_create_internal_label (steer_pl->next_hop,
261 : *color_i));
262 0 : break;
263 : }
264 0 : }
265 :
266 : /* Does hidden FIB already exist? */
267 0 : if (sm->fib_table_EC == (u32) ~ 0)
268 : {
269 0 : sm->fib_table_EC = fib_table_create_and_lock (FIB_PROTOCOL_MPLS,
270 : FIB_SOURCE_SR,
271 : "SR-MPLS Traffic Engineering (NextHop,Color)");
272 :
273 0 : fib_table_flush (sm->fib_table_EC, FIB_PROTOCOL_MPLS,
274 : FIB_SOURCE_SPECIAL);
275 : }
276 :
277 : /* Add the corresponding FIB entries */
278 0 : fib_route_path_t path = {
279 : .frp_proto = DPO_PROTO_MPLS,
280 : .frp_eos = MPLS_EOS,
281 : .frp_sw_if_index = ~0,
282 0 : .frp_fib_index = sm->fib_table_EC,
283 : .frp_weight = 1,
284 : .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
285 : .frp_label_stack = 0
286 : };
287 0 : fib_route_path_t *paths = NULL;
288 :
289 0 : if (steer_pl->classify.traffic_type == SR_STEER_IPV6)
290 : {
291 0 : pfx.fp_proto = FIB_PROTOCOL_IP6;
292 0 : pfx.fp_len = steer_pl->classify.mask_width;
293 0 : pfx.fp_addr.ip6 = steer_pl->classify.prefix.ip6;
294 : }
295 0 : else if (steer_pl->classify.traffic_type == SR_STEER_IPV4)
296 : {
297 0 : pfx.fp_proto = FIB_PROTOCOL_IP4;
298 0 : pfx.fp_len = steer_pl->classify.mask_width;
299 0 : pfx.fp_addr.ip4 = steer_pl->classify.prefix.ip4;
300 : }
301 :
302 0 : if (steer_pl->vpn_label != (u32) ~ 0)
303 : {
304 0 : fib_mpls_label_t fml = {
305 0 : .fml_value = steer_pl->vpn_label,
306 : };
307 0 : vec_add1 (path.frp_label_stack, fml);
308 0 : path.frp_eos = MPLS_NON_EOS;
309 : }
310 :
311 : u32 label_i;
312 0 : vec_foreach_index (label_i, internal_labels)
313 : {
314 0 : path.frp_local_label = internal_labels[label_i];
315 0 : path.frp_preference = label_i;
316 0 : vec_add1 (paths, path);
317 : }
318 :
319 : /* Finally we must add to FIB IGP to N */
320 0 : clib_memcpy (&path.frp_addr, &steer_pl->next_hop,
321 : sizeof (steer_pl->next_hop));
322 0 : path.frp_preference = vec_len (internal_labels);
323 0 : path.frp_label_stack = NULL;
324 :
325 0 : if (steer_pl->nh_type == SR_STEER_IPV6)
326 : {
327 0 : path.frp_proto = DPO_PROTO_IP6;
328 0 : path.frp_fib_index =
329 0 : fib_table_find (FIB_PROTOCOL_IP6,
330 0 : (steer_pl->classify.fib_table !=
331 : (u32) ~ 0 ? steer_pl->classify.fib_table : 0));
332 : }
333 0 : else if (steer_pl->nh_type == SR_STEER_IPV4)
334 : {
335 0 : path.frp_proto = DPO_PROTO_IP4;
336 0 : path.frp_fib_index =
337 0 : fib_table_find (FIB_PROTOCOL_IP4,
338 0 : (steer_pl->classify.fib_table !=
339 : (u32) ~ 0 ? steer_pl->classify.fib_table : 0));
340 : }
341 :
342 0 : vec_add1 (paths, path);
343 0 : if (steer_pl->classify.traffic_type == SR_STEER_IPV6)
344 0 : fib_table_entry_update (fib_table_find
345 : (FIB_PROTOCOL_IP6,
346 0 : (steer_pl->classify.fib_table !=
347 : (u32) ~ 0 ? steer_pl->classify.fib_table : 0)),
348 : &pfx, FIB_SOURCE_SR,
349 : FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT, paths);
350 0 : else if (steer_pl->classify.traffic_type == SR_STEER_IPV4)
351 0 : fib_table_entry_update (fib_table_find
352 : (FIB_PROTOCOL_IP4,
353 0 : (steer_pl->classify.fib_table !=
354 : (u32) ~ 0 ? steer_pl->classify.fib_table : 0)),
355 : &pfx, FIB_SOURCE_SR,
356 : FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT, paths);
357 :
358 0 : vec_free (paths);
359 0 : paths = NULL;
360 0 : }
361 :
362 : /**
363 : * @brief Steer traffic L3 traffic through a given SR-MPLS policy
364 : *
365 : * @param is_del
366 : * @param bsid is the bindingSID of the SR Policy (alt to sr_policy_index)
367 : * @param sr_policy is the index of the SR Policy (alt to bsid)
368 : * @param table_id is the VRF where to install the FIB entry for the BSID
369 : * @param prefix is the IPv4/v6 address for L3 traffic type
370 : * @param mask_width is the mask for L3 traffic type
371 : * @param traffic_type describes the type of traffic
372 : * @param next_hop SR TE Next-Hop
373 : * @param nh_type is the AF of Next-Hop
374 : * @param color SR TE color
375 : * @param co_bits SR TE color-only bits
376 : *
377 : * @return 0 if correct, else error
378 : */
379 : int
380 0 : sr_mpls_steering_policy_add (mpls_label_t bsid, u32 table_id,
381 : ip46_address_t * prefix, u32 mask_width,
382 : u8 traffic_type, ip46_address_t * next_hop,
383 : u8 nh_type, u32 color, char co_bits,
384 : mpls_label_t vpn_label)
385 : {
386 0 : mpls_sr_main_t *sm = &sr_mpls_main;
387 : sr_mpls_steering_key_t key;
388 : mpls_sr_steering_policy_t *steer_pl;
389 0 : fib_prefix_t pfx = { 0 };
390 :
391 0 : mpls_sr_policy_t *sr_policy = 0;
392 0 : uword *p = 0;
393 :
394 0 : clib_memset (&key, 0, sizeof (sr_mpls_steering_key_t));
395 :
396 0 : if (traffic_type != SR_STEER_IPV4 && traffic_type != SR_STEER_IPV6)
397 0 : return -1;
398 :
399 : /* Compute the steer policy key */
400 0 : key.prefix.as_u64[0] = prefix->as_u64[0];
401 0 : key.prefix.as_u64[1] = prefix->as_u64[1];
402 0 : key.mask_width = mask_width;
403 0 : key.fib_table = (table_id != (u32) ~ 0 ? table_id : 0);
404 0 : key.traffic_type = traffic_type;
405 :
406 : /*
407 : * Search for steering policy. If already exists we are adding a new
408 : * color.
409 : */
410 0 : if (!sm->sr_steer_policies_hash.hash)
411 0 : mhash_init (&sm->sr_steer_policies_hash, sizeof (uword),
412 : sizeof (sr_mpls_steering_key_t));
413 :
414 0 : p = mhash_get (&sm->sr_steer_policies_hash, &key);
415 0 : if (p)
416 : {
417 0 : steer_pl = pool_elt_at_index (sm->steer_policies, p[0]);
418 0 : if (steer_pl->bsid != (u32) ~ 0)
419 0 : return -1; //Means we are rewritting the steering. Not allowed.
420 :
421 : /* Means we are adding a color. Check that NH match. */
422 0 : if (ip46_address_cmp (&steer_pl->next_hop, next_hop))
423 0 : return -2;
424 0 : if (vec_search (steer_pl->color, color) != ~0)
425 0 : return -3;
426 0 : if (steer_pl->co_bits != co_bits)
427 0 : return -4; /* CO colors should be the same */
428 0 : if (steer_pl->vpn_label != vpn_label)
429 0 : return -5; /* VPN label should be the same */
430 :
431 : /* Remove the steering and ReDo it */
432 0 : vec_add1 (steer_pl->color, color);
433 0 : vec_sort_with_function (steer_pl->color, sort_color_descent);
434 0 : compute_sr_te_automated_steering_fib_entry (steer_pl);
435 0 : internal_label_lock_co (steer_pl->next_hop, color, steer_pl->co_bits);
436 0 : return 0;
437 : }
438 :
439 : /* Create a new steering policy */
440 0 : pool_get (sm->steer_policies, steer_pl);
441 0 : clib_memset (steer_pl, 0, sizeof (*steer_pl));
442 0 : clib_memcpy (&steer_pl->classify.prefix, prefix, sizeof (ip46_address_t));
443 0 : clib_memcpy (&steer_pl->next_hop, next_hop, sizeof (ip46_address_t));
444 0 : steer_pl->nh_type = nh_type;
445 0 : steer_pl->co_bits = co_bits;
446 0 : steer_pl->classify.mask_width = mask_width;
447 0 : steer_pl->classify.fib_table = (table_id != (u32) ~ 0 ? table_id : 0);
448 0 : steer_pl->classify.traffic_type = traffic_type;
449 0 : steer_pl->color = NULL;
450 0 : steer_pl->vpn_label = vpn_label;
451 :
452 : /* Create and store key */
453 0 : mhash_set (&sm->sr_steer_policies_hash, &key, steer_pl - sm->steer_policies,
454 : NULL);
455 :
456 : /* Local steering */
457 0 : if (bsid != (u32) ~ 0)
458 : {
459 0 : if (!sm->sr_policies_index_hash)
460 0 : sm->sr_policies_index_hash = hash_create (0, sizeof (mpls_label_t));
461 0 : steer_pl->bsid = bsid;
462 0 : p = hash_get (sm->sr_policies_index_hash, bsid);
463 0 : if (!p)
464 0 : return -1;
465 0 : sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
466 :
467 0 : fib_route_path_t path = {
468 : .frp_proto = DPO_PROTO_MPLS,
469 0 : .frp_local_label = sr_policy->bsid,
470 : .frp_eos = MPLS_EOS,
471 : .frp_sw_if_index = ~0,
472 : .frp_fib_index = 0,
473 : .frp_weight = 1,
474 : .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
475 : .frp_label_stack = 0
476 : };
477 0 : fib_route_path_t *paths = NULL;
478 :
479 0 : if (steer_pl->vpn_label != (u32) ~ 0)
480 : {
481 0 : fib_mpls_label_t fml = {
482 0 : .fml_value = steer_pl->vpn_label,
483 : };
484 0 : vec_add1 (path.frp_label_stack, fml);
485 : }
486 :
487 : /* FIB API calls - Recursive route through the BindingSID */
488 0 : if (traffic_type == SR_STEER_IPV6)
489 : {
490 0 : pfx.fp_proto = FIB_PROTOCOL_IP6;
491 0 : pfx.fp_len = steer_pl->classify.mask_width;
492 0 : pfx.fp_addr.ip6 = steer_pl->classify.prefix.ip6;
493 0 : path.frp_fib_index = 0;
494 0 : path.frp_preference = 0;
495 0 : vec_add1 (paths, path);
496 0 : fib_table_entry_path_add2 (fib_table_find
497 : (FIB_PROTOCOL_IP6,
498 : (table_id != (u32) ~ 0 ? table_id : 0)),
499 : &pfx, FIB_SOURCE_SR,
500 : FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT, paths);
501 0 : vec_free (paths);
502 : }
503 0 : else if (traffic_type == SR_STEER_IPV4)
504 : {
505 0 : pfx.fp_proto = FIB_PROTOCOL_IP4;
506 0 : pfx.fp_len = steer_pl->classify.mask_width;
507 0 : pfx.fp_addr.ip4 = steer_pl->classify.prefix.ip4;
508 0 : path.frp_fib_index = 0;
509 0 : path.frp_preference = 0;
510 0 : vec_add1 (paths, path);
511 0 : fib_table_entry_path_add2 (fib_table_find
512 : (FIB_PROTOCOL_IP4,
513 : (table_id != (u32) ~ 0 ? table_id : 0)),
514 : &pfx, FIB_SOURCE_SR,
515 : FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT, paths);
516 0 : vec_free (paths);
517 : }
518 : }
519 : /* Automated steering */
520 : else
521 : {
522 0 : steer_pl->bsid = (u32) ~ 0;
523 0 : vec_add1 (steer_pl->color, color);
524 0 : compute_sr_te_automated_steering_fib_entry (steer_pl);
525 0 : internal_label_lock_co (steer_pl->next_hop, color, steer_pl->co_bits);
526 : }
527 0 : return 0;
528 : }
529 :
530 : /**
531 : * @brief Delete steering rule for an SR-MPLS policy
532 : *
533 : * @param is_del
534 : * @param bsid is the bindingSID of the SR Policy (alt to sr_policy_index)
535 : * @param sr_policy is the index of the SR Policy (alt to bsid)
536 : * @param table_id is the VRF where to install the FIB entry for the BSID
537 : * @param prefix is the IPv4/v6 address for L3 traffic type
538 : * @param mask_width is the mask for L3 traffic type
539 : * @param traffic_type describes the type of traffic
540 : * @param next_hop SR TE Next-HOP
541 : * @param nh_type is the AF of Next-Hop
542 : * @param color SR TE color
543 : *
544 : * @return 0 if correct, else error
545 : */
546 : int
547 0 : sr_mpls_steering_policy_del (ip46_address_t * prefix, u32 mask_width,
548 : u8 traffic_type, u32 table_id, u32 color)
549 : {
550 0 : mpls_sr_main_t *sm = &sr_mpls_main;
551 : sr_mpls_steering_key_t key;
552 : mpls_sr_steering_policy_t *steer_pl;
553 0 : fib_prefix_t pfx = { 0 };
554 0 : uword *p = 0;
555 :
556 0 : clib_memset (&key, 0, sizeof (sr_mpls_steering_key_t));
557 :
558 : /* Compute the steer policy key */
559 0 : if (traffic_type != SR_STEER_IPV4 && traffic_type != SR_STEER_IPV6)
560 0 : return -1;
561 :
562 0 : key.prefix.as_u64[0] = prefix->as_u64[0];
563 0 : key.prefix.as_u64[1] = prefix->as_u64[1];
564 0 : key.mask_width = mask_width;
565 0 : key.fib_table = (table_id != (u32) ~ 0 ? table_id : 0);
566 0 : key.traffic_type = traffic_type;
567 :
568 0 : if (!sm->sr_steer_policies_hash.hash)
569 0 : mhash_init (&sm->sr_steer_policies_hash, sizeof (uword),
570 : sizeof (sr_mpls_steering_key_t));
571 :
572 : /* Search for the item */
573 0 : p = mhash_get (&sm->sr_steer_policies_hash, &key);
574 :
575 0 : if (!p)
576 0 : return -1;
577 :
578 : /* Retrieve Steer Policy function */
579 0 : steer_pl = pool_elt_at_index (sm->steer_policies, p[0]);
580 :
581 0 : if (steer_pl->bsid == (u32) ~ 0)
582 : {
583 : /* Remove the color from the color vector */
584 0 : vec_del1 (steer_pl->color, vec_search (steer_pl->color, color));
585 :
586 0 : if (vec_len (steer_pl->color))
587 : {
588 : /* Reorder Colors */
589 0 : vec_sort_with_function (steer_pl->color, sort_color_descent);
590 0 : compute_sr_te_automated_steering_fib_entry (steer_pl);
591 : /* Remove all the locks for this ones... */
592 0 : internal_label_unlock_co (steer_pl->next_hop, color,
593 0 : steer_pl->co_bits);
594 0 : return 0;
595 : }
596 : else
597 : {
598 0 : vec_free (steer_pl->color);
599 : /* Remove FIB entry */
600 0 : if (steer_pl->classify.traffic_type == SR_STEER_IPV6)
601 : {
602 0 : pfx.fp_proto = FIB_PROTOCOL_IP6;
603 0 : pfx.fp_len = steer_pl->classify.mask_width;
604 0 : pfx.fp_addr.ip6 = steer_pl->classify.prefix.ip6;
605 0 : fib_table_entry_delete (fib_table_find
606 : (FIB_PROTOCOL_IP6,
607 : steer_pl->classify.fib_table), &pfx,
608 : FIB_SOURCE_SR);
609 : }
610 0 : else if (steer_pl->classify.traffic_type == SR_STEER_IPV4)
611 : {
612 0 : pfx.fp_proto = FIB_PROTOCOL_IP4;
613 0 : pfx.fp_len = steer_pl->classify.mask_width;
614 0 : pfx.fp_addr.ip4 = steer_pl->classify.prefix.ip4;
615 0 : fib_table_entry_delete (fib_table_find
616 : (FIB_PROTOCOL_IP4,
617 : steer_pl->classify.fib_table), &pfx,
618 : FIB_SOURCE_SR);
619 : }
620 : /* Remove all the locks for this ones... */
621 0 : internal_label_unlock_co (steer_pl->next_hop, color,
622 0 : steer_pl->co_bits);
623 : }
624 : }
625 : else //Remove by BSID
626 : {
627 0 : if (steer_pl->classify.traffic_type == SR_STEER_IPV6)
628 : {
629 0 : pfx.fp_proto = FIB_PROTOCOL_IP6;
630 0 : pfx.fp_len = steer_pl->classify.mask_width;
631 0 : pfx.fp_addr.ip6 = steer_pl->classify.prefix.ip6;
632 0 : fib_table_entry_delete (fib_table_find
633 : (FIB_PROTOCOL_IP6,
634 : steer_pl->classify.fib_table), &pfx,
635 : FIB_SOURCE_SR);
636 : }
637 0 : else if (steer_pl->classify.traffic_type == SR_STEER_IPV4)
638 : {
639 0 : pfx.fp_proto = FIB_PROTOCOL_IP4;
640 0 : pfx.fp_len = steer_pl->classify.mask_width;
641 0 : pfx.fp_addr.ip4 = steer_pl->classify.prefix.ip4;
642 0 : fib_table_entry_delete (fib_table_find
643 : (FIB_PROTOCOL_IP4,
644 : steer_pl->classify.fib_table), &pfx,
645 : FIB_SOURCE_SR);
646 : }
647 : }
648 : /* Delete SR steering policy entry */
649 0 : pool_put (sm->steer_policies, steer_pl);
650 0 : mhash_unset (&sm->sr_steer_policies_hash, &key, NULL);
651 0 : if (mhash_elts (&sm->sr_steer_policies_hash) == 0)
652 : {
653 0 : mhash_free (&sm->sr_steer_policies_hash);
654 0 : sm->sr_steer_policies_hash.hash = NULL;
655 : }
656 0 : return 0;
657 : }
658 :
659 : static clib_error_t *
660 0 : sr_mpls_steer_policy_command_fn (vlib_main_t * vm, unformat_input_t * input,
661 : vlib_cli_command_t * cmd)
662 : {
663 0 : int is_del = 0;
664 :
665 : ip46_address_t prefix, nh;
666 0 : u32 dst_mask_width = 0;
667 0 : u8 traffic_type = 0;
668 0 : u8 nh_type = 0;
669 0 : u32 fib_table = (u32) ~ 0, color = (u32) ~ 0;
670 0 : u32 co_bits = 0;
671 :
672 0 : mpls_label_t bsid, vpn_label = (u32) ~ 0;
673 :
674 0 : u8 sr_policy_set = 0;
675 :
676 0 : clib_memset (&prefix, 0, sizeof (ip46_address_t));
677 0 : clib_memset (&nh, 0, sizeof (ip46_address_t));
678 :
679 : int rv;
680 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
681 : {
682 0 : if (unformat (input, "del"))
683 0 : is_del = 1;
684 0 : else if (!traffic_type
685 0 : && unformat (input, "l3 %U/%d", unformat_ip6_address,
686 : &prefix.ip6, &dst_mask_width))
687 0 : traffic_type = SR_STEER_IPV6;
688 0 : else if (!traffic_type
689 0 : && unformat (input, "l3 %U/%d", unformat_ip4_address,
690 : &prefix.ip4, &dst_mask_width))
691 0 : traffic_type = SR_STEER_IPV4;
692 0 : else if (!sr_policy_set
693 0 : && unformat (input, "via sr policy bsid %U",
694 : unformat_mpls_unicast_label, &bsid))
695 0 : sr_policy_set = 1;
696 0 : else if (!sr_policy_set
697 0 : && unformat (input, "via next-hop %U color %d co %d",
698 : unformat_ip4_address, &nh.ip4, &color, &co_bits))
699 : {
700 0 : sr_policy_set = 1;
701 0 : nh_type = SR_STEER_IPV4;
702 : }
703 0 : else if (!sr_policy_set
704 0 : && unformat (input, "via next-hop %U color %d co %d",
705 : unformat_ip6_address, &nh.ip6, &color, &co_bits))
706 : {
707 0 : sr_policy_set = 1;
708 0 : nh_type = SR_STEER_IPV6;
709 : }
710 0 : else if (fib_table == (u32) ~ 0
711 0 : && unformat (input, "fib-table %d", &fib_table));
712 0 : else if (unformat (input, "vpn-label %U",
713 : unformat_mpls_unicast_label, &vpn_label));
714 : else
715 0 : break;
716 : }
717 :
718 0 : if (!traffic_type)
719 0 : return clib_error_return (0, "No L3 traffic specified");
720 0 : if (!sr_policy_set)
721 0 : return clib_error_return (0, "No SR policy specified");
722 :
723 : /* Make sure that the prefixes are clean */
724 0 : if (traffic_type == SR_STEER_IPV4)
725 : {
726 0 : u32 mask =
727 0 : (dst_mask_width ? (0xFFFFFFFFu >> (32 - dst_mask_width)) : 0);
728 0 : prefix.ip4.as_u32 &= mask;
729 : }
730 0 : else if (traffic_type == SR_STEER_IPV6)
731 : {
732 : ip6_address_t mask;
733 0 : ip6_address_mask_from_width (&mask, dst_mask_width);
734 0 : ip6_address_mask (&prefix.ip6, &mask);
735 : }
736 :
737 0 : if (nh_type)
738 0 : bsid = (u32) ~ 0;
739 :
740 0 : if (is_del)
741 : rv =
742 0 : sr_mpls_steering_policy_del (&prefix, dst_mask_width,
743 : traffic_type, fib_table, color);
744 :
745 : else
746 : rv =
747 0 : sr_mpls_steering_policy_add (bsid, fib_table, &prefix, dst_mask_width,
748 : traffic_type, &nh, nh_type, color, co_bits,
749 : vpn_label);
750 :
751 0 : switch (rv)
752 : {
753 0 : case 0:
754 0 : break;
755 0 : case 1:
756 0 : return 0;
757 0 : case -1:
758 0 : return clib_error_return (0, "Incorrect API usage.");
759 0 : case -2:
760 0 : return clib_error_return (0, "The Next-Hop does not match.");
761 0 : case -3:
762 0 : return clib_error_return (0, "The color already exists.");
763 0 : case -4:
764 0 : return clib_error_return (0, "The co-bits do not match.");
765 0 : case -5:
766 0 : return clib_error_return (0, "The VPN-labels do not match.");
767 0 : default:
768 0 : return clib_error_return (0, "BUG: sr steer policy returns %d", rv);
769 : }
770 0 : return 0;
771 : }
772 :
773 : /* *INDENT-OFF* */
774 285289 : VLIB_CLI_COMMAND(sr_mpls_steer_policy_command, static)=
775 : {
776 : .path = "sr mpls steer",
777 : .short_help = "sr mpls steer (del) l3 <ip_addr/mask> "
778 : "via [sr policy bsid <mpls_label> || next-hop <ip46_addr> color <u32> co <0|1|2|3> ](fib-table <fib_table_index>)(vpn-label 500)",
779 : .long_help =
780 : "\tSteer L3 traffic through an existing SR policy.\n"
781 : "\tExamples:\n"
782 : "\t\tsr steer l3 2001::/64 via sr_policy bsid 29999\n"
783 : "\t\tsr steer del l3 2001::/64 via sr_policy bsid 29999\n"
784 : "\t\tsr steer l3 2001::/64 via next-hop 1.1.1.1 color 1234 co 0\n"
785 : "\t\tsr steer l3 2001::/64 via next-hop 2001::1 color 1234 co 2 vpn-label 500\n",
786 : .function = sr_mpls_steer_policy_command_fn,
787 : };
788 : /* *INDENT-ON* */
789 :
790 : static clib_error_t *
791 0 : show_sr_mpls_steering_policies_command_fn (vlib_main_t * vm,
792 : unformat_input_t * input,
793 : vlib_cli_command_t * cmd)
794 : {
795 0 : mpls_sr_main_t *sm = &sr_mpls_main;
796 0 : mpls_sr_steering_policy_t **steer_policies = 0;
797 : mpls_sr_steering_policy_t *steer_pl;
798 :
799 : int i;
800 :
801 0 : vlib_cli_output (vm, "SR MPLS steering policies:");
802 : /* *INDENT-OFF* */
803 0 : pool_foreach (steer_pl, sm->steer_policies) {
804 0 : vec_add1(steer_policies, steer_pl);
805 : }
806 : /* *INDENT-ON* */
807 0 : for (i = 0; i < vec_len (steer_policies); i++)
808 : {
809 0 : vlib_cli_output (vm, "==========================");
810 0 : steer_pl = steer_policies[i];
811 0 : if (steer_pl->classify.traffic_type == SR_STEER_IPV4)
812 : {
813 0 : vlib_cli_output (vm, "Prefix: %U/%d via:",
814 : format_ip4_address,
815 : &steer_pl->classify.prefix.ip4,
816 : steer_pl->classify.mask_width);
817 : }
818 0 : else if (steer_pl->classify.traffic_type == SR_STEER_IPV6)
819 : {
820 0 : vlib_cli_output (vm, "Prefix: %U/%d via:",
821 : format_ip6_address,
822 : &steer_pl->classify.prefix.ip6,
823 : steer_pl->classify.mask_width);
824 : }
825 :
826 0 : if (steer_pl->bsid != (u32) ~ 0)
827 : {
828 0 : vlib_cli_output (vm, "· BSID %U",
829 : format_mpls_unicast_label, steer_pl->bsid);
830 : }
831 : else
832 : {
833 0 : if (steer_pl->nh_type == SR_STEER_IPV4)
834 : {
835 0 : vlib_cli_output (vm, "· Next-hop %U",
836 : format_ip4_address, &steer_pl->next_hop.ip4);
837 : }
838 0 : else if (steer_pl->nh_type == SR_STEER_IPV6)
839 : {
840 0 : vlib_cli_output (vm, "· Next-hop %U",
841 : format_ip6_address, &steer_pl->next_hop.ip6);
842 : }
843 :
844 0 : u32 *color_i = 0;
845 0 : u8 *s = NULL;
846 0 : s = format (s, "[ ");
847 0 : vec_foreach (color_i, steer_pl->color)
848 : {
849 0 : s = format (s, "%d, ", *color_i);
850 : }
851 0 : s = format (s, "\b\b ]");
852 0 : vlib_cli_output (vm, "· Color %s", s);
853 :
854 0 : switch (steer_pl->co_bits)
855 : {
856 0 : case SR_TE_CO_BITS_00:
857 0 : vlib_cli_output (vm, "· CO-bits: 00");
858 0 : break;
859 0 : case SR_TE_CO_BITS_01:
860 0 : vlib_cli_output (vm, "· CO-bits: 01");
861 0 : break;
862 0 : case SR_TE_CO_BITS_10:
863 0 : vlib_cli_output (vm, "· CO-bits: 10");
864 0 : break;
865 0 : case SR_TE_CO_BITS_11:
866 0 : vlib_cli_output (vm, "· CO-bits: 11");
867 0 : break;
868 : }
869 0 : }
870 : }
871 0 : return 0;
872 : }
873 :
874 : /* *INDENT-OFF* */
875 285289 : VLIB_CLI_COMMAND(show_sr_mpls_steering_policies_command, static)=
876 : {
877 : .path = "show sr mpls steering policies",
878 : .short_help = "show sr mpls steering policies",
879 : .function = show_sr_mpls_steering_policies_command_fn,
880 : };
881 : /* *INDENT-ON* */
882 :
883 : clib_error_t *
884 575 : sr_mpls_steering_init (vlib_main_t * vm)
885 : {
886 575 : mpls_sr_main_t *sm = &sr_mpls_main;
887 :
888 : /* Init memory for function keys */
889 575 : sm->sr_steer_policies_hash.hash = NULL;
890 :
891 575 : sm->fib_table_EC = (u32) ~ 0;
892 575 : sm->ec_labels = 0;
893 :
894 575 : return 0;
895 : }
896 :
897 : /* *INDENT-OFF* */
898 70271 : VLIB_INIT_FUNCTION(sr_mpls_steering_init);
899 : /* *INDENT-ON* */
900 :
901 : /*
902 : * fd.io coding-style-patch-verification: ON
903 : *
904 : * Local Variables: eval: (c-set-style "gnu") End:
905 : */
|