blob: b12e78d2755603a0abb8fe503b3597e8700ac16e [file] [log] [blame]
Pablo Camarillo5d73eec2017-04-24 17:51:56 +02001/*
2 * sr_steering.c: ipv6 segment routing steering into SR policy
3 *
Pablo Camarillo42998822017-07-13 09:41:32 +02004 * 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:
Pablo Camarillo5d73eec2017-04-24 17:51:56 +02007 *
Pablo Camarillo42998822017-07-13 09:41:32 +02008 * http://www.apache.org/licenses/LICENSE-2.0
Pablo Camarillo5d73eec2017-04-24 17:51:56 +02009 *
10 * Unless required by applicable law or agreed to in writing, software
Pablo Camarillo42998822017-07-13 09:41:32 +020011 * 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.
Pablo Camarillo5d73eec2017-04-24 17:51:56 +020015 */
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:
Pablo Camarillo42998822017-07-13 09:41:32 +020027 * - 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)
Pablo Camarillo5d73eec2017-04-24 17:51:56 +020030 */
31
32#include <vlib/vlib.h>
33#include <vnet/vnet.h>
Pablo Camarillo42998822017-07-13 09:41:32 +020034#include <vnet/srmpls/sr_mpls.h>
Pablo Camarillo5d73eec2017-04-24 17:51:56 +020035#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
Pablo Camarillo42998822017-07-13 09:41:32 +020042#define SRMPLS_TE_OFFSET 50
43
44/**
45 * @brief function to sort the colors in descending order
46 */
47int
48sort_color_descent (const u32 * x, u32 * y)
49{
50 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 */
59u32
60find_or_create_internal_label (ip46_address_t endpoint, u32 color)
61{
62 mpls_sr_main_t *sm = &sr_mpls_main;
63 uword *color_table, *result_label;
64
65 if (!sm->sr_policies_c2e2eclabel_hash.hash)
66 mhash_init (&sm->sr_policies_c2e2eclabel_hash, sizeof (mhash_t),
67 sizeof (u32));
68
69 color_table = mhash_get (&sm->sr_policies_c2e2eclabel_hash, &color);
70 if (!color_table)
71 {
72 mhash_t color_t;
Dave Barachb7b92992018-10-17 10:38:51 -040073 clib_memset (&color_t, 0, sizeof (mhash_t));
Pablo Camarillo42998822017-07-13 09:41:32 +020074 mhash_init (&color_t, sizeof (u32), sizeof (ip46_address_t));
75 mhash_set_mem (&sm->sr_policies_c2e2eclabel_hash, &color,
76 (uword *) & color_t, NULL);
77 color_table = mhash_get (&sm->sr_policies_c2e2eclabel_hash, &color);
78 }
79
80 result_label = mhash_get ((mhash_t *) color_table, &endpoint);
81
82 if (result_label)
83 return (u32) * result_label;
84
85 /* Create and set a new internal label */
86 u32 *new_internal_label = 0;
87 pool_get (sm->ec_labels, new_internal_label);
88 *new_internal_label = 0;
89 mhash_set ((mhash_t *) color_table, &endpoint,
90 (new_internal_label - sm->ec_labels) + SRMPLS_TE_OFFSET, NULL);
91
92 return (new_internal_label - sm->ec_labels) + SRMPLS_TE_OFFSET;
93}
94
95always_inline void
96internal_label_lock_co (ip46_address_t endpoint, u32 color, char co_bits)
97{
98 ip46_address_t zero, any;
99 ip46_address_reset (&zero);
100 any.as_u64[0] = any.as_u64[1] = (u64) ~ 0;
101 switch (co_bits)
102 {
103 case SR_TE_CO_BITS_10:
104 internal_label_lock (endpoint, color);
105 internal_label_lock (zero, color);
106 internal_label_lock (any, color);
107 break;
108 case SR_TE_CO_BITS_01:
109 internal_label_lock (endpoint, color);
110 internal_label_lock (zero, color);
111 break;
112 case SR_TE_CO_BITS_00:
113 case SR_TE_CO_BITS_11:
114 internal_label_lock (endpoint, color);
115 break;
116 }
117}
118
119/**
120 * @brief lock the label for (NH, C)
121 * endpoint might be NULL or ANY
122 * NULL = 0, ANY=~0
123 */
124void
125internal_label_lock (ip46_address_t endpoint, u32 color)
126{
127 mpls_sr_main_t *sm = &sr_mpls_main;
128 uword *color_table, *result_label;
129
130 if (!sm->sr_policies_c2e2eclabel_hash.hash)
131 return;
132
133 color_table = mhash_get (&sm->sr_policies_c2e2eclabel_hash, &color);
134 if (!color_table)
135 return;
136
137 result_label = mhash_get ((mhash_t *) color_table, &endpoint);
138
139 if (!result_label)
140 return;
141
142 /* Lock it */
143 u32 *label_lock =
144 pool_elt_at_index (sm->ec_labels, *result_label - SRMPLS_TE_OFFSET);
145 (*label_lock)++;
146}
147
148
149always_inline void
150internal_label_unlock_co (ip46_address_t endpoint, u32 color, char co_bits)
151{
152 ip46_address_t zero, any;
153 ip46_address_reset (&zero);
154 any.as_u64[0] = any.as_u64[1] = (u64) ~ 0;
155 switch (co_bits)
156 {
157 case SR_TE_CO_BITS_10:
158 internal_label_unlock (endpoint, color);
159 internal_label_unlock (zero, color);
160 internal_label_unlock (any, color);
161 break;
162 case SR_TE_CO_BITS_01:
163 internal_label_unlock (endpoint, color);
164 internal_label_unlock (zero, color);
165 break;
166 case SR_TE_CO_BITS_00:
167 case SR_TE_CO_BITS_11:
168 internal_label_unlock (endpoint, color);
169 break;
170 }
171}
172
173/**
174 * @brief Release lock on label for (endpoint, color)
175 * endpoint might be NULL or ANY
176 * NULL = 0, ANY=~0
177 */
178void
179internal_label_unlock (ip46_address_t endpoint, u32 color)
180{
181 mpls_sr_main_t *sm = &sr_mpls_main;
182 uword *color_table, *result_label;
183
184 if (!sm->sr_policies_c2e2eclabel_hash.hash)
185 return;
186
187 color_table = mhash_get (&sm->sr_policies_c2e2eclabel_hash, &color);
188 if (!color_table)
189 return;
190
191 result_label = mhash_get ((mhash_t *) color_table, &endpoint);
192
193 if (!result_label)
194 return;
195
196 u32 *label_lock =
197 pool_elt_at_index (sm->ec_labels, *result_label - SRMPLS_TE_OFFSET);
198 (*label_lock)--;
199
200 if (*label_lock == 0)
201 {
202 pool_put (sm->ec_labels, label_lock);
203 mhash_unset ((mhash_t *) color_table, &endpoint, NULL);
204 if (mhash_elts ((mhash_t *) color_table) == 0)
205 {
206 mhash_free ((mhash_t *) color_table);
207 mhash_unset (&sm->sr_policies_c2e2eclabel_hash, &color, NULL);
208 if (mhash_elts (&sm->sr_policies_c2e2eclabel_hash) == 0)
209 {
210 mhash_free (&sm->sr_policies_c2e2eclabel_hash);
211 sm->sr_policies_c2e2eclabel_hash.hash = NULL;
212 fib_table_unlock (sm->fib_table_EC, FIB_PROTOCOL_MPLS,
213 FIB_SOURCE_SR);
214 sm->fib_table_EC = (u32) ~ 0;
215 }
216 }
217 }
218}
219
220/********************* steering computation *********************************/
221/**
222 * @brief function to update the FIB
223 */
224void
225compute_sr_te_automated_steering_fib_entry (mpls_sr_steering_policy_t *
226 steer_pl)
227{
228 mpls_sr_main_t *sm = &sr_mpls_main;
229 fib_prefix_t pfx = { 0 };
230
231 u32 *internal_labels = 0;
232 ip46_address_t zero, any;
233 ip46_address_reset (&zero);
234 any.as_u64[0] = any.as_u64[1] = (u64) ~ 0;
235
236 u32 *color_i = NULL;
237 vec_foreach (color_i, steer_pl->color)
238 {
239 switch (steer_pl->co_bits)
240 {
241 case SR_TE_CO_BITS_10:
242 vec_add1 (internal_labels,
243 find_or_create_internal_label (steer_pl->next_hop,
244 *color_i));
245 vec_add1 (internal_labels,
246 find_or_create_internal_label (zero, *color_i));
247 vec_add1 (internal_labels,
248 find_or_create_internal_label (any, *color_i));
249 break;
250 case SR_TE_CO_BITS_01:
251 vec_add1 (internal_labels,
252 find_or_create_internal_label (steer_pl->next_hop,
253 *color_i));
254 vec_add1 (internal_labels,
255 find_or_create_internal_label (zero, *color_i));
256 break;
257 case SR_TE_CO_BITS_00:
258 case SR_TE_CO_BITS_11:
259 vec_add1 (internal_labels,
260 find_or_create_internal_label (steer_pl->next_hop,
261 *color_i));
262 break;
263 }
264 }
265
266 /* Does hidden FIB already exist? */
267 if (sm->fib_table_EC == (u32) ~ 0)
268 {
269 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 fib_table_flush (sm->fib_table_EC, FIB_PROTOCOL_MPLS,
274 FIB_SOURCE_SPECIAL);
275 }
276
277 /* Add the corresponding FIB entries */
278 fib_route_path_t path = {
279 .frp_proto = DPO_PROTO_MPLS,
280 .frp_eos = MPLS_EOS,
281 .frp_sw_if_index = ~0,
282 .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 fib_route_path_t *paths = NULL;
288
289 if (steer_pl->classify.traffic_type == SR_STEER_IPV6)
290 {
291 pfx.fp_proto = FIB_PROTOCOL_IP6;
292 pfx.fp_len = steer_pl->classify.mask_width;
293 pfx.fp_addr.ip6 = steer_pl->classify.prefix.ip6;
294 }
295 else if (steer_pl->classify.traffic_type == SR_STEER_IPV4)
296 {
297 pfx.fp_proto = FIB_PROTOCOL_IP4;
298 pfx.fp_len = steer_pl->classify.mask_width;
299 pfx.fp_addr.ip4 = steer_pl->classify.prefix.ip4;
300 }
301
302 if (steer_pl->vpn_label != (u32) ~ 0)
303 {
Neale Ranns31ed7442018-02-23 05:29:09 -0800304 fib_mpls_label_t fml = {
305 .fml_value = steer_pl->vpn_label,
306 };
307 vec_add1 (path.frp_label_stack, fml);
Pablo Camarillo42998822017-07-13 09:41:32 +0200308 path.frp_eos = MPLS_NON_EOS;
309 }
310
311 u32 label_i;
312 vec_foreach_index (label_i, internal_labels)
313 {
314 path.frp_local_label = internal_labels[label_i];
315 path.frp_preference = label_i;
316 vec_add1 (paths, path);
317 }
318
319 /* Finally we must add to FIB IGP to N */
320 clib_memcpy (&path.frp_addr, &steer_pl->next_hop,
321 sizeof (steer_pl->next_hop));
322 path.frp_preference = vec_len (internal_labels);
323 path.frp_label_stack = NULL;
324
325 if (steer_pl->nh_type == SR_STEER_IPV6)
326 {
327 path.frp_proto = DPO_PROTO_IP6;
328 path.frp_fib_index =
329 fib_table_find (FIB_PROTOCOL_IP6,
330 (steer_pl->classify.fib_table !=
331 (u32) ~ 0 ? steer_pl->classify.fib_table : 0));
332 }
333 else if (steer_pl->nh_type == SR_STEER_IPV4)
334 {
335 path.frp_proto = DPO_PROTO_IP4;
336 path.frp_fib_index =
337 fib_table_find (FIB_PROTOCOL_IP4,
338 (steer_pl->classify.fib_table !=
339 (u32) ~ 0 ? steer_pl->classify.fib_table : 0));
340 }
341
342 vec_add1 (paths, path);
343 if (steer_pl->classify.traffic_type == SR_STEER_IPV6)
344 fib_table_entry_update (fib_table_find
345 (FIB_PROTOCOL_IP6,
346 (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 else if (steer_pl->classify.traffic_type == SR_STEER_IPV4)
351 fib_table_entry_update (fib_table_find
352 (FIB_PROTOCOL_IP4,
353 (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 vec_free (paths);
359 paths = NULL;
360}
361
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200362/**
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
Pablo Camarillo42998822017-07-13 09:41:32 +0200372 * @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
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200376 *
377 * @return 0 if correct, else error
378 */
379int
Pablo Camarillo42998822017-07-13 09:41:32 +0200380sr_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)
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200385{
386 mpls_sr_main_t *sm = &sr_mpls_main;
387 sr_mpls_steering_key_t key;
388 mpls_sr_steering_policy_t *steer_pl;
389 fib_prefix_t pfx = { 0 };
390
391 mpls_sr_policy_t *sr_policy = 0;
392 uword *p = 0;
393
Dave Barachb7b92992018-10-17 10:38:51 -0400394 clib_memset (&key, 0, sizeof (sr_mpls_steering_key_t));
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200395
Pablo Camarillo42998822017-07-13 09:41:32 +0200396 if (traffic_type != SR_STEER_IPV4 && traffic_type != SR_STEER_IPV6)
397 return -1;
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200398
Chris Luke30684ac2018-03-29 12:56:58 -0700399 /* Compute the steer policy key */
400 key.prefix.as_u64[0] = prefix->as_u64[0];
401 key.prefix.as_u64[1] = prefix->as_u64[1];
402 key.mask_width = mask_width;
403 key.fib_table = (table_id != (u32) ~ 0 ? table_id : 0);
404 key.traffic_type = traffic_type;
405
Pablo Camarillo42998822017-07-13 09:41:32 +0200406 /*
407 * Search for steering policy. If already exists we are adding a new
408 * color.
409 */
410 if (!sm->sr_steer_policies_hash.hash)
411 mhash_init (&sm->sr_steer_policies_hash, sizeof (uword),
412 sizeof (sr_mpls_steering_key_t));
413
414 p = mhash_get (&sm->sr_steer_policies_hash, &key);
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200415 if (p)
416 {
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200417 steer_pl = pool_elt_at_index (sm->steer_policies, p[0]);
Pablo Camarillo42998822017-07-13 09:41:32 +0200418 if (steer_pl->bsid != (u32) ~ 0)
419 return -1; //Means we are rewritting the steering. Not allowed.
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200420
Pablo Camarillo42998822017-07-13 09:41:32 +0200421 /* Means we are adding a color. Check that NH match. */
422 if (ip46_address_cmp (&steer_pl->next_hop, next_hop))
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200423 return -2;
Pablo Camarillo42998822017-07-13 09:41:32 +0200424 if (vec_search (steer_pl->color, color) != ~0)
425 return -3;
426 if (steer_pl->co_bits != co_bits)
427 return -4; /* CO colors should be the same */
428 if (steer_pl->vpn_label != vpn_label)
429 return -5; /* VPN label should be the same */
430
431 /* Remove the steering and ReDo it */
432 vec_add1 (steer_pl->color, color);
433 vec_sort_with_function (steer_pl->color, sort_color_descent);
434 compute_sr_te_automated_steering_fib_entry (steer_pl);
435 internal_label_lock_co (steer_pl->next_hop, color, steer_pl->co_bits);
436 return 0;
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200437 }
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200438
439 /* Create a new steering policy */
440 pool_get (sm->steer_policies, steer_pl);
Dave Barachb7b92992018-10-17 10:38:51 -0400441 clib_memset (steer_pl, 0, sizeof (*steer_pl));
Pablo Camarillo42998822017-07-13 09:41:32 +0200442 clib_memcpy (&steer_pl->classify.prefix, prefix, sizeof (ip46_address_t));
443 clib_memcpy (&steer_pl->next_hop, next_hop, sizeof (ip46_address_t));
444 steer_pl->nh_type = nh_type;
445 steer_pl->co_bits = co_bits;
446 steer_pl->classify.mask_width = mask_width;
447 steer_pl->classify.fib_table = (table_id != (u32) ~ 0 ? table_id : 0);
448 steer_pl->classify.traffic_type = traffic_type;
449 steer_pl->color = NULL;
450 steer_pl->vpn_label = vpn_label;
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200451
452 /* Create and store key */
453 mhash_set (&sm->sr_steer_policies_hash, &key, steer_pl - sm->steer_policies,
454 NULL);
455
Pablo Camarillo42998822017-07-13 09:41:32 +0200456 /* Local steering */
457 if (bsid != (u32) ~ 0)
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200458 {
Pablo Camarillo42998822017-07-13 09:41:32 +0200459 if (!sm->sr_policies_index_hash)
460 sm->sr_policies_index_hash = hash_create (0, sizeof (mpls_label_t));
461 steer_pl->bsid = bsid;
462 p = hash_get (sm->sr_policies_index_hash, bsid);
463 if (!p)
464 return -1;
465 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200466
Pablo Camarillo42998822017-07-13 09:41:32 +0200467 fib_route_path_t path = {
468 .frp_proto = DPO_PROTO_MPLS,
469 .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 fib_route_path_t *paths = NULL;
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200478
Pablo Camarillo42998822017-07-13 09:41:32 +0200479 if (steer_pl->vpn_label != (u32) ~ 0)
Neale Ranns31ed7442018-02-23 05:29:09 -0800480 {
481 fib_mpls_label_t fml = {
482 .fml_value = steer_pl->vpn_label,
483 };
484 vec_add1 (path.frp_label_stack, fml);
485 }
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200486
Pablo Camarillo42998822017-07-13 09:41:32 +0200487 /* FIB API calls - Recursive route through the BindingSID */
488 if (traffic_type == SR_STEER_IPV6)
489 {
490 pfx.fp_proto = FIB_PROTOCOL_IP6;
491 pfx.fp_len = steer_pl->classify.mask_width;
492 pfx.fp_addr.ip6 = steer_pl->classify.prefix.ip6;
493 path.frp_fib_index = 0;
494 path.frp_preference = 0;
495 vec_add1 (paths, path);
496 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 vec_free (paths);
502 }
503 else if (traffic_type == SR_STEER_IPV4)
504 {
505 pfx.fp_proto = FIB_PROTOCOL_IP4;
506 pfx.fp_len = steer_pl->classify.mask_width;
507 pfx.fp_addr.ip4 = steer_pl->classify.prefix.ip4;
508 path.frp_fib_index = 0;
509 path.frp_preference = 0;
510 vec_add1 (paths, path);
511 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 vec_free (paths);
517 }
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200518 }
Pablo Camarillo42998822017-07-13 09:41:32 +0200519 /* Automated steering */
520 else
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200521 {
Pablo Camarillo42998822017-07-13 09:41:32 +0200522 steer_pl->bsid = (u32) ~ 0;
523 vec_add1 (steer_pl->color, color);
524 compute_sr_te_automated_steering_fib_entry (steer_pl);
525 internal_label_lock_co (steer_pl->next_hop, color, steer_pl->co_bits);
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200526 }
Pablo Camarillo42998822017-07-13 09:41:32 +0200527 return 0;
528}
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200529
Pablo Camarillo42998822017-07-13 09:41:32 +0200530/**
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 */
546int
547sr_mpls_steering_policy_del (ip46_address_t * prefix, u32 mask_width,
548 u8 traffic_type, u32 table_id, u32 color)
549{
550 mpls_sr_main_t *sm = &sr_mpls_main;
551 sr_mpls_steering_key_t key;
552 mpls_sr_steering_policy_t *steer_pl;
553 fib_prefix_t pfx = { 0 };
554 uword *p = 0;
555
Dave Barachb7b92992018-10-17 10:38:51 -0400556 clib_memset (&key, 0, sizeof (sr_mpls_steering_key_t));
Pablo Camarillo42998822017-07-13 09:41:32 +0200557
558 /* Compute the steer policy key */
559 if (traffic_type != SR_STEER_IPV4 && traffic_type != SR_STEER_IPV6)
560 return -1;
561
562 key.prefix.as_u64[0] = prefix->as_u64[0];
563 key.prefix.as_u64[1] = prefix->as_u64[1];
564 key.mask_width = mask_width;
565 key.fib_table = (table_id != (u32) ~ 0 ? table_id : 0);
566 key.traffic_type = traffic_type;
567
568 if (!sm->sr_steer_policies_hash.hash)
569 mhash_init (&sm->sr_steer_policies_hash, sizeof (uword),
570 sizeof (sr_mpls_steering_key_t));
571
572 /* Search for the item */
573 p = mhash_get (&sm->sr_steer_policies_hash, &key);
574
575 if (!p)
576 return -1;
577
578 /* Retrieve Steer Policy function */
579 steer_pl = pool_elt_at_index (sm->steer_policies, p[0]);
580
581 if (steer_pl->bsid == (u32) ~ 0)
582 {
583 /* Remove the color from the color vector */
584 vec_del1 (steer_pl->color, vec_search (steer_pl->color, color));
585
586 if (vec_len (steer_pl->color))
587 {
588 /* Reorder Colors */
589 vec_sort_with_function (steer_pl->color, sort_color_descent);
590 compute_sr_te_automated_steering_fib_entry (steer_pl);
591 /* Remove all the locks for this ones... */
592 internal_label_unlock_co (steer_pl->next_hop, color,
593 steer_pl->co_bits);
594 return 0;
595 }
596 else
597 {
598 vec_free (steer_pl->color);
599 /* Remove FIB entry */
600 if (steer_pl->classify.traffic_type == SR_STEER_IPV6)
601 {
602 pfx.fp_proto = FIB_PROTOCOL_IP6;
603 pfx.fp_len = steer_pl->classify.mask_width;
604 pfx.fp_addr.ip6 = steer_pl->classify.prefix.ip6;
605 fib_table_entry_delete (fib_table_find
606 (FIB_PROTOCOL_IP6,
607 steer_pl->classify.fib_table), &pfx,
608 FIB_SOURCE_SR);
609 }
610 else if (steer_pl->classify.traffic_type == SR_STEER_IPV4)
611 {
612 pfx.fp_proto = FIB_PROTOCOL_IP4;
613 pfx.fp_len = steer_pl->classify.mask_width;
614 pfx.fp_addr.ip4 = steer_pl->classify.prefix.ip4;
615 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 internal_label_unlock_co (steer_pl->next_hop, color,
622 steer_pl->co_bits);
623 }
624 }
625 else //Remove by BSID
626 {
627 if (steer_pl->classify.traffic_type == SR_STEER_IPV6)
628 {
629 pfx.fp_proto = FIB_PROTOCOL_IP6;
630 pfx.fp_len = steer_pl->classify.mask_width;
631 pfx.fp_addr.ip6 = steer_pl->classify.prefix.ip6;
632 fib_table_entry_delete (fib_table_find
633 (FIB_PROTOCOL_IP6,
634 steer_pl->classify.fib_table), &pfx,
635 FIB_SOURCE_SR);
636 }
637 else if (steer_pl->classify.traffic_type == SR_STEER_IPV4)
638 {
639 pfx.fp_proto = FIB_PROTOCOL_IP4;
640 pfx.fp_len = steer_pl->classify.mask_width;
641 pfx.fp_addr.ip4 = steer_pl->classify.prefix.ip4;
642 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 pool_put (sm->steer_policies, steer_pl);
650 mhash_unset (&sm->sr_steer_policies_hash, &key, NULL);
651 if (mhash_elts (&sm->sr_steer_policies_hash) == 0)
652 {
653 mhash_free (&sm->sr_steer_policies_hash);
654 sm->sr_steer_policies_hash.hash = NULL;
655 }
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200656 return 0;
657}
658
659static clib_error_t *
660sr_mpls_steer_policy_command_fn (vlib_main_t * vm, unformat_input_t * input,
661 vlib_cli_command_t * cmd)
662{
663 int is_del = 0;
664
Pablo Camarillo42998822017-07-13 09:41:32 +0200665 ip46_address_t prefix, nh;
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200666 u32 dst_mask_width = 0;
667 u8 traffic_type = 0;
Pablo Camarillo42998822017-07-13 09:41:32 +0200668 u8 nh_type = 0;
669 u32 fib_table = (u32) ~ 0, color = (u32) ~ 0;
670 u32 co_bits = 0;
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200671
Pablo Camarillo42998822017-07-13 09:41:32 +0200672 mpls_label_t bsid, vpn_label = (u32) ~ 0;
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200673
674 u8 sr_policy_set = 0;
675
Dave Barachb7b92992018-10-17 10:38:51 -0400676 clib_memset (&prefix, 0, sizeof (ip46_address_t));
677 clib_memset (&nh, 0, sizeof (ip46_address_t));
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200678
679 int rv;
680 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
681 {
682 if (unformat (input, "del"))
683 is_del = 1;
684 else if (!traffic_type
685 && unformat (input, "l3 %U/%d", unformat_ip6_address,
686 &prefix.ip6, &dst_mask_width))
687 traffic_type = SR_STEER_IPV6;
688 else if (!traffic_type
689 && unformat (input, "l3 %U/%d", unformat_ip4_address,
690 &prefix.ip4, &dst_mask_width))
691 traffic_type = SR_STEER_IPV4;
692 else if (!sr_policy_set
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200693 && unformat (input, "via sr policy bsid %U",
694 unformat_mpls_unicast_label, &bsid))
695 sr_policy_set = 1;
Pablo Camarillo42998822017-07-13 09:41:32 +0200696 else if (!sr_policy_set
697 && unformat (input, "via next-hop %U color %d co %d",
698 unformat_ip4_address, &nh.ip4, &color, &co_bits))
699 {
700 sr_policy_set = 1;
701 nh_type = SR_STEER_IPV4;
702 }
703 else if (!sr_policy_set
704 && unformat (input, "via next-hop %U color %d co %d",
705 unformat_ip6_address, &nh.ip6, &color, &co_bits))
706 {
707 sr_policy_set = 1;
708 nh_type = SR_STEER_IPV6;
709 }
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200710 else if (fib_table == (u32) ~ 0
711 && unformat (input, "fib-table %d", &fib_table));
Pablo Camarillo42998822017-07-13 09:41:32 +0200712 else if (unformat (input, "vpn-label %U",
713 unformat_mpls_unicast_label, &vpn_label));
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200714 else
715 break;
716 }
717
718 if (!traffic_type)
719 return clib_error_return (0, "No L3 traffic specified");
720 if (!sr_policy_set)
721 return clib_error_return (0, "No SR policy specified");
722
723 /* Make sure that the prefixes are clean */
724 if (traffic_type == SR_STEER_IPV4)
725 {
726 u32 mask =
727 (dst_mask_width ? (0xFFFFFFFFu >> (32 - dst_mask_width)) : 0);
728 prefix.ip4.as_u32 &= mask;
729 }
730 else if (traffic_type == SR_STEER_IPV6)
731 {
732 ip6_address_t mask;
733 ip6_address_mask_from_width (&mask, dst_mask_width);
734 ip6_address_mask (&prefix.ip6, &mask);
735 }
736
Pablo Camarillo42998822017-07-13 09:41:32 +0200737 if (nh_type)
738 bsid = (u32) ~ 0;
739
740 if (is_del)
741 rv =
742 sr_mpls_steering_policy_del (&prefix, dst_mask_width,
743 traffic_type, fib_table, color);
744
745 else
746 rv =
747 sr_mpls_steering_policy_add (bsid, fib_table, &prefix, dst_mask_width,
748 traffic_type, &nh, nh_type, color, co_bits,
749 vpn_label);
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200750
751 switch (rv)
752 {
753 case 0:
754 break;
755 case 1:
756 return 0;
757 case -1:
758 return clib_error_return (0, "Incorrect API usage.");
759 case -2:
Pablo Camarillo42998822017-07-13 09:41:32 +0200760 return clib_error_return (0, "The Next-Hop does not match.");
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200761 case -3:
Pablo Camarillo42998822017-07-13 09:41:32 +0200762 return clib_error_return (0, "The color already exists.");
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200763 case -4:
Pablo Camarillo42998822017-07-13 09:41:32 +0200764 return clib_error_return (0, "The co-bits do not match.");
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200765 case -5:
Pablo Camarillo42998822017-07-13 09:41:32 +0200766 return clib_error_return (0, "The VPN-labels do not match.");
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200767 default:
768 return clib_error_return (0, "BUG: sr steer policy returns %d", rv);
769 }
770 return 0;
771}
772
773/* *INDENT-OFF* */
Pablo Camarillo42998822017-07-13 09:41:32 +0200774VLIB_CLI_COMMAND(sr_mpls_steer_policy_command, static)=
775{
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200776 .path = "sr mpls steer",
Pablo Camarillo42998822017-07-13 09:41:32 +0200777 .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 =
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200780 "\tSteer L3 traffic through an existing SR policy.\n"
781 "\tExamples:\n"
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200782 "\t\tsr steer l3 2001::/64 via sr_policy bsid 29999\n"
Pablo Camarillo42998822017-07-13 09:41:32 +0200783 "\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,
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200787};
788/* *INDENT-ON* */
789
790static clib_error_t *
791show_sr_mpls_steering_policies_command_fn (vlib_main_t * vm,
792 unformat_input_t * input,
793 vlib_cli_command_t * cmd)
794{
795 mpls_sr_main_t *sm = &sr_mpls_main;
796 mpls_sr_steering_policy_t **steer_policies = 0;
797 mpls_sr_steering_policy_t *steer_pl;
798
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200799 int i;
800
801 vlib_cli_output (vm, "SR MPLS steering policies:");
802 /* *INDENT-OFF* */
Damjan Marionb2c31b62020-12-13 21:47:40 +0100803 pool_foreach (steer_pl, sm->steer_policies) {
Pablo Camarillo42998822017-07-13 09:41:32 +0200804 vec_add1(steer_policies, steer_pl);
Damjan Marionb2c31b62020-12-13 21:47:40 +0100805 }
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200806 /* *INDENT-ON* */
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200807 for (i = 0; i < vec_len (steer_policies); i++)
808 {
Pablo Camarillo42998822017-07-13 09:41:32 +0200809 vlib_cli_output (vm, "==========================");
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200810 steer_pl = steer_policies[i];
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200811 if (steer_pl->classify.traffic_type == SR_STEER_IPV4)
812 {
Pablo Camarillo42998822017-07-13 09:41:32 +0200813 vlib_cli_output (vm, "Prefix: %U/%d via:",
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200814 format_ip4_address,
815 &steer_pl->classify.prefix.ip4,
Pablo Camarillo42998822017-07-13 09:41:32 +0200816 steer_pl->classify.mask_width);
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200817 }
818 else if (steer_pl->classify.traffic_type == SR_STEER_IPV6)
819 {
Pablo Camarillo42998822017-07-13 09:41:32 +0200820 vlib_cli_output (vm, "Prefix: %U/%d via:",
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200821 format_ip6_address,
822 &steer_pl->classify.prefix.ip6,
Pablo Camarillo42998822017-07-13 09:41:32 +0200823 steer_pl->classify.mask_width);
824 }
825
826 if (steer_pl->bsid != (u32) ~ 0)
827 {
828 vlib_cli_output (vm, "· BSID %U",
829 format_mpls_unicast_label, steer_pl->bsid);
830 }
831 else
832 {
833 if (steer_pl->nh_type == SR_STEER_IPV4)
834 {
835 vlib_cli_output (vm, "· Next-hop %U",
836 format_ip4_address, &steer_pl->next_hop.ip4);
837 }
838 else if (steer_pl->nh_type == SR_STEER_IPV6)
839 {
840 vlib_cli_output (vm, "· Next-hop %U",
841 format_ip6_address, &steer_pl->next_hop.ip6);
842 }
843
844 u32 *color_i = 0;
845 u8 *s = NULL;
846 s = format (s, "[ ");
847 vec_foreach (color_i, steer_pl->color)
848 {
849 s = format (s, "%d, ", *color_i);
850 }
851 s = format (s, "\b\b ]");
852 vlib_cli_output (vm, "· Color %s", s);
853
854 switch (steer_pl->co_bits)
855 {
856 case SR_TE_CO_BITS_00:
857 vlib_cli_output (vm, "· CO-bits: 00");
858 break;
859 case SR_TE_CO_BITS_01:
860 vlib_cli_output (vm, "· CO-bits: 01");
861 break;
862 case SR_TE_CO_BITS_10:
863 vlib_cli_output (vm, "· CO-bits: 10");
864 break;
865 case SR_TE_CO_BITS_11:
866 vlib_cli_output (vm, "· CO-bits: 11");
867 break;
868 }
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200869 }
870 }
871 return 0;
872}
873
874/* *INDENT-OFF* */
Pablo Camarillo42998822017-07-13 09:41:32 +0200875VLIB_CLI_COMMAND(show_sr_mpls_steering_policies_command, static)=
876{
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200877 .path = "show sr mpls steering policies",
Pablo Camarillo42998822017-07-13 09:41:32 +0200878 .short_help = "show sr mpls steering policies",
879 .function = show_sr_mpls_steering_policies_command_fn,
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200880};
881/* *INDENT-ON* */
882
883clib_error_t *
884sr_mpls_steering_init (vlib_main_t * vm)
885{
886 mpls_sr_main_t *sm = &sr_mpls_main;
887
888 /* Init memory for function keys */
Pablo Camarillo42998822017-07-13 09:41:32 +0200889 sm->sr_steer_policies_hash.hash = NULL;
890
891 sm->fib_table_EC = (u32) ~ 0;
892 sm->ec_labels = 0;
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200893
894 return 0;
895}
896
897/* *INDENT-OFF* */
Pablo Camarillo42998822017-07-13 09:41:32 +0200898VLIB_INIT_FUNCTION(sr_mpls_steering_init);
Pablo Camarillo5d73eec2017-04-24 17:51:56 +0200899/* *INDENT-ON* */
900
901/*
Pablo Camarillo42998822017-07-13 09:41:32 +0200902 * fd.io coding-style-patch-verification: ON
903 *
904 * Local Variables: eval: (c-set-style "gnu") End:
905 */