2 * sr_steering.c: ipv6 segment routing steering into SR policy
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:
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 * @brief Packet steering into SR-MPLS Policies
22 * This file is in charge of handling the FIB appropiatly to steer packets
23 * through SR Policies as defined in 'sr_mpls_policy.c'. Notice that here
24 * we are only doing steering. SR policy application is done in
28 * - Steering of IPv6 traffic Destination Address based
29 * - Steering of IPv4 traffic Destination Address based
32 #include <vlib/vlib.h>
33 #include <vnet/vnet.h>
34 #include <vnet/srmpls/sr.h>
35 #include <vnet/ip/ip4_packet.h>
36 #include <vnet/ip/ip6_packet.h>
37 #include <vnet/fib/mpls_fib.h>
39 #include <vppinfra/error.h>
40 #include <vppinfra/elog.h>
43 * @brief Steer traffic L3 traffic through a given SR-MPLS policy
46 * @param bsid is the bindingSID of the SR Policy (alt to sr_policy_index)
47 * @param sr_policy is the index of the SR Policy (alt to bsid)
48 * @param table_id is the VRF where to install the FIB entry for the BSID
49 * @param prefix is the IPv4/v6 address for L3 traffic type
50 * @param mask_width is the mask for L3 traffic type
51 * @param traffic_type describes the type of traffic
53 * @return 0 if correct, else error
56 sr_mpls_steering_policy (int is_del, mpls_label_t bsid, u32 sr_policy_index,
57 u32 table_id, ip46_address_t * prefix,
58 u32 mask_width, u8 traffic_type)
60 mpls_sr_main_t *sm = &sr_mpls_main;
61 sr_mpls_steering_key_t key;
62 mpls_sr_steering_policy_t *steer_pl;
63 fib_prefix_t pfx = { 0 };
65 mpls_sr_policy_t *sr_policy = 0;
68 memset (&key, 0, sizeof (sr_mpls_steering_key_t));
70 /* Compute the steer policy key */
71 if (traffic_type == SR_STEER_IPV4 || traffic_type == SR_STEER_IPV6)
73 key.prefix.as_u64[0] = prefix->as_u64[0];
74 key.prefix.as_u64[1] = prefix->as_u64[1];
75 key.mask_width = mask_width;
76 key.fib_table = (table_id != (u32) ~ 0 ? table_id : 0);
81 key.traffic_type = traffic_type;
83 /* Search for the item */
84 p = mhash_get (&sm->sr_steer_policies_hash, &key);
88 /* Retrieve Steer Policy function */
89 steer_pl = pool_elt_at_index (sm->steer_policies, p[0]);
93 if (steer_pl->classify.traffic_type == SR_STEER_IPV6)
95 /* Remove FIB entry */
96 pfx.fp_proto = FIB_PROTOCOL_IP6;
97 pfx.fp_len = steer_pl->classify.mask_width;
98 pfx.fp_addr.ip6 = steer_pl->classify.prefix.ip6;
100 fib_table_entry_delete (fib_table_find
102 steer_pl->classify.fib_table), &pfx,
105 else if (steer_pl->classify.traffic_type == SR_STEER_IPV4)
107 /* Remove FIB entry */
108 pfx.fp_proto = FIB_PROTOCOL_IP4;
109 pfx.fp_len = steer_pl->classify.mask_width;
110 pfx.fp_addr.ip4 = steer_pl->classify.prefix.ip4;
112 fib_table_entry_delete (fib_table_find
114 steer_pl->classify.fib_table), &pfx,
118 /* Delete SR steering policy entry */
119 pool_put (sm->steer_policies, steer_pl);
120 mhash_unset (&sm->sr_steer_policies_hash, &key, NULL);
124 else /* It means user requested to update an existing SR steering policy */
126 /* Retrieve SR steering policy */
127 if (bsid) //TODO FIXME
129 p = hash_get (sm->sr_policies_index_hash, bsid);
131 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
136 sr_policy = pool_elt_at_index (sm->sr_policies, sr_policy_index);
141 steer_pl->sr_policy = sr_policy - sm->sr_policies;
143 /* Remove old FIB/hw redirection and create a new one */
144 if (steer_pl->classify.traffic_type == SR_STEER_IPV6)
146 /* Remove FIB entry */
147 pfx.fp_proto = FIB_PROTOCOL_IP6;
148 pfx.fp_len = steer_pl->classify.mask_width;
149 pfx.fp_addr.ip6 = steer_pl->classify.prefix.ip6;
151 fib_table_entry_delete (fib_table_find
153 steer_pl->classify.fib_table), &pfx,
156 /* Create a new one */
159 else if (steer_pl->classify.traffic_type == SR_STEER_IPV4)
161 /* Remove FIB entry */
162 pfx.fp_proto = FIB_PROTOCOL_IP4;
163 pfx.fp_len = steer_pl->classify.mask_width;
164 pfx.fp_addr.ip4 = steer_pl->classify.prefix.ip4;
166 fib_table_entry_delete (fib_table_find
168 steer_pl->classify.fib_table), &pfx,
171 /* Create a new one */
177 /* delete; steering policy does not exist; complain */
181 /* Retrieve SR policy */
184 p = hash_get (sm->sr_policies_index_hash, bsid);
186 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
191 sr_policy = pool_elt_at_index (sm->sr_policies, sr_policy_index);
193 /* Create a new steering policy */
194 pool_get (sm->steer_policies, steer_pl);
195 memset (steer_pl, 0, sizeof (*steer_pl));
197 if (traffic_type == SR_STEER_IPV4 || traffic_type == SR_STEER_IPV6)
199 clib_memcpy (&steer_pl->classify.prefix, prefix,
200 sizeof (ip46_address_t));
201 steer_pl->classify.mask_width = mask_width;
202 steer_pl->classify.fib_table = (table_id != (u32) ~ 0 ? table_id : 0);
203 steer_pl->classify.traffic_type = traffic_type;
207 /* Incorrect API usage. Should never get here */
208 pool_put (sm->steer_policies, steer_pl);
209 mhash_unset (&sm->sr_steer_policies_hash, &key, NULL);
212 steer_pl->sr_policy = sr_policy - sm->sr_policies;
214 /* Create and store key */
215 mhash_set (&sm->sr_steer_policies_hash, &key, steer_pl - sm->steer_policies,
220 fib_route_path_t path = {
221 .frp_proto = DPO_PROTO_MPLS,
222 .frp_local_label = sr_policy->bsid,
224 .frp_sw_if_index = ~0,
227 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
228 .frp_label_stack = NULL
231 fib_route_path_t *paths = NULL;
233 /* FIB API calls - Recursive route through the BindingSID */
234 if (traffic_type == SR_STEER_IPV6)
236 pfx.fp_proto = FIB_PROTOCOL_IP6;
237 pfx.fp_len = steer_pl->classify.mask_width;
238 pfx.fp_addr.ip6 = steer_pl->classify.prefix.ip6;
239 path.frp_fib_index = 0;
241 vec_add1 (paths, path);
243 fib_table_entry_path_add2 (fib_table_find
245 (table_id != (u32) ~ 0 ? table_id : 0)),
247 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT, paths);
251 else if (traffic_type == SR_STEER_IPV4)
253 pfx.fp_proto = FIB_PROTOCOL_IP4;
254 pfx.fp_len = steer_pl->classify.mask_width;
255 pfx.fp_addr.ip4 = steer_pl->classify.prefix.ip4;
256 path.frp_fib_index = 0;
258 vec_add1 (paths, path);
260 fib_table_entry_path_add2 (fib_table_find
262 (table_id != (u32) ~ 0 ? table_id : 0)),
264 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT, paths);
272 static clib_error_t *
273 sr_mpls_steer_policy_command_fn (vlib_main_t * vm, unformat_input_t * input,
274 vlib_cli_command_t * cmd)
278 ip46_address_t prefix;
279 u32 dst_mask_width = 0;
281 u32 fib_table = (u32) ~ 0;
284 u32 sr_policy_index = (u32) ~ 0;
286 u8 sr_policy_set = 0;
288 memset (&prefix, 0, sizeof (ip46_address_t));
291 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
293 if (unformat (input, "del"))
295 else if (!traffic_type
296 && unformat (input, "l3 %U/%d", unformat_ip6_address,
297 &prefix.ip6, &dst_mask_width))
298 traffic_type = SR_STEER_IPV6;
299 else if (!traffic_type
300 && unformat (input, "l3 %U/%d", unformat_ip4_address,
301 &prefix.ip4, &dst_mask_width))
302 traffic_type = SR_STEER_IPV4;
303 else if (!sr_policy_set
304 && unformat (input, "via sr policy index %d",
307 else if (!sr_policy_set
308 && unformat (input, "via sr policy bsid %U",
309 unformat_mpls_unicast_label, &bsid))
311 else if (fib_table == (u32) ~ 0
312 && unformat (input, "fib-table %d", &fib_table));
318 return clib_error_return (0, "No L3 traffic specified");
320 return clib_error_return (0, "No SR policy specified");
322 /* Make sure that the prefixes are clean */
323 if (traffic_type == SR_STEER_IPV4)
326 (dst_mask_width ? (0xFFFFFFFFu >> (32 - dst_mask_width)) : 0);
327 prefix.ip4.as_u32 &= mask;
329 else if (traffic_type == SR_STEER_IPV6)
332 ip6_address_mask_from_width (&mask, dst_mask_width);
333 ip6_address_mask (&prefix.ip6, &mask);
337 sr_mpls_steering_policy (is_del, bsid,
338 sr_policy_index, fib_table, &prefix,
339 dst_mask_width, traffic_type);
348 return clib_error_return (0, "Incorrect API usage.");
350 return clib_error_return (0,
351 "The requested SR policy could not be located. Review the BSID/index.");
353 return clib_error_return (0,
354 "Unable to do SW redirect. Incorrect interface.");
356 return clib_error_return (0,
357 "The requested SR steering policy could not be deleted.");
359 return clib_error_return (0,
360 "The SR policy is not an encapsulation one.");
362 return clib_error_return (0, "BUG: sr steer policy returns %d", rv);
368 VLIB_CLI_COMMAND (sr_mpls_steer_policy_command, static) = {
369 .path = "sr mpls steer",
370 .short_help = "sr mpls steer (del) l3 <ip_addr/mask>"
371 "via sr policy bsid <mpls_label> (fib-table <fib_table_index>)",
373 "\tSteer L3 traffic through an existing SR policy.\n"
375 "\t\tsr steer l3 2001::/64 via sr_policy index 5\n"
376 "\t\tsr steer l3 2001::/64 via sr_policy bsid 29999\n"
377 "\t\tsr steer del l3 2001::/64 via sr_policy index 5\n",
378 .function = sr_mpls_steer_policy_command_fn,
382 static clib_error_t *
383 show_sr_mpls_steering_policies_command_fn (vlib_main_t * vm,
384 unformat_input_t * input,
385 vlib_cli_command_t * cmd)
387 mpls_sr_main_t *sm = &sr_mpls_main;
388 mpls_sr_steering_policy_t **steer_policies = 0;
389 mpls_sr_steering_policy_t *steer_pl;
391 mpls_sr_policy_t *pl = 0;
394 vlib_cli_output (vm, "SR MPLS steering policies:");
396 pool_foreach (steer_pl, sm->steer_policies, ({vec_add1(steer_policies, steer_pl);}));
398 vlib_cli_output (vm, "Traffic\t\tSR policy BSID");
399 for (i = 0; i < vec_len (steer_policies); i++)
401 steer_pl = steer_policies[i];
402 pl = pool_elt_at_index (sm->sr_policies, steer_pl->sr_policy);
403 if (steer_pl->classify.traffic_type == SR_STEER_IPV4)
405 vlib_cli_output (vm, "L3 %U/%d\t%U",
407 &steer_pl->classify.prefix.ip4,
408 steer_pl->classify.mask_width,
409 format_mpls_unicast_label, pl->bsid);
411 else if (steer_pl->classify.traffic_type == SR_STEER_IPV6)
413 vlib_cli_output (vm, "L3 %U/%d\t%U",
415 &steer_pl->classify.prefix.ip6,
416 steer_pl->classify.mask_width,
417 format_mpls_unicast_label, pl->bsid);
424 VLIB_CLI_COMMAND (show_sr_mpls_steering_policies_command, static) = {
425 .path = "show sr mpls steering policies",
426 .short_help = "show sr mpls steering policies",
427 .function = show_sr_mpls_steering_policies_command_fn,
432 sr_mpls_steering_init (vlib_main_t * vm)
434 mpls_sr_main_t *sm = &sr_mpls_main;
436 /* Init memory for function keys */
437 mhash_init (&sm->sr_steer_policies_hash, sizeof (uword),
438 sizeof (sr_mpls_steering_key_t));
444 VLIB_INIT_FUNCTION (sr_mpls_steering_init);
448 * fd.io coding-style-patch-verification: ON
451 * eval: (c-set-style "gnu")