FD.io VPP  v17.07.01-10-g3be13f0
Vector Packet Processing
sr_mpls_steering.c
Go to the documentation of this file.
1 /*
2  * sr_steering.c: ipv6 segment routing steering into SR policy
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 Packet steering into SR-MPLS Policies
21  *
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
25  * sr_policy_rewrite.c
26  *
27  * Supports:
28  * - Steering of IPv6 traffic Destination Address based
29  * - Steering of IPv4 traffic Destination Address based
30  */
31 
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>
38 
39 #include <vppinfra/error.h>
40 #include <vppinfra/elog.h>
41 
42 /**
43  * @brief Steer traffic L3 traffic through a given SR-MPLS policy
44  *
45  * @param is_del
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
52  *
53  * @return 0 if correct, else error
54  */
55 int
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)
59 {
62  mpls_sr_steering_policy_t *steer_pl;
63  fib_prefix_t pfx = { 0 };
64 
65  mpls_sr_policy_t *sr_policy = 0;
66  uword *p = 0;
67 
68  memset (&key, 0, sizeof (sr_mpls_steering_key_t));
69 
70  /* Compute the steer policy key */
71  if (traffic_type == SR_STEER_IPV4 || traffic_type == SR_STEER_IPV6)
72  {
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);
77  }
78  else
79  return -1;
80 
81  key.traffic_type = traffic_type;
82 
83  /* Search for the item */
84  p = mhash_get (&sm->sr_steer_policies_hash, &key);
85 
86  if (p)
87  {
88  /* Retrieve Steer Policy function */
89  steer_pl = pool_elt_at_index (sm->steer_policies, p[0]);
90 
91  if (is_del)
92  {
93  if (steer_pl->classify.traffic_type == SR_STEER_IPV6)
94  {
95  /* Remove FIB entry */
97  pfx.fp_len = steer_pl->classify.mask_width;
98  pfx.fp_addr.ip6 = steer_pl->classify.prefix.ip6;
99 
102  steer_pl->classify.fib_table), &pfx,
103  FIB_SOURCE_SR);
104  }
105  else if (steer_pl->classify.traffic_type == SR_STEER_IPV4)
106  {
107  /* Remove FIB entry */
109  pfx.fp_len = steer_pl->classify.mask_width;
110  pfx.fp_addr.ip4 = steer_pl->classify.prefix.ip4;
111 
114  steer_pl->classify.fib_table), &pfx,
115  FIB_SOURCE_SR);
116  }
117 
118  /* Delete SR steering policy entry */
119  pool_put (sm->steer_policies, steer_pl);
121 
122  return 1;
123  }
124  else /* It means user requested to update an existing SR steering policy */
125  {
126  /* Retrieve SR steering policy */
127  if (bsid) //TODO FIXME
128  {
129  p = hash_get (sm->sr_policies_index_hash, bsid);
130  if (p)
131  sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
132  else
133  return -2;
134  }
135  else
136  sr_policy = pool_elt_at_index (sm->sr_policies, sr_policy_index);
137 
138  if (!sr_policy)
139  return -2;
140 
141  steer_pl->sr_policy = sr_policy - sm->sr_policies;
142 
143  /* Remove old FIB/hw redirection and create a new one */
144  if (steer_pl->classify.traffic_type == SR_STEER_IPV6)
145  {
146  /* Remove FIB entry */
148  pfx.fp_len = steer_pl->classify.mask_width;
149  pfx.fp_addr.ip6 = steer_pl->classify.prefix.ip6;
150 
153  steer_pl->classify.fib_table), &pfx,
154  FIB_SOURCE_SR);
155 
156  /* Create a new one */
157  goto update_fib;
158  }
159  else if (steer_pl->classify.traffic_type == SR_STEER_IPV4)
160  {
161  /* Remove FIB entry */
163  pfx.fp_len = steer_pl->classify.mask_width;
164  pfx.fp_addr.ip4 = steer_pl->classify.prefix.ip4;
165 
168  steer_pl->classify.fib_table), &pfx,
169  FIB_SOURCE_SR);
170 
171  /* Create a new one */
172  goto update_fib;
173  }
174  }
175  }
176  else
177  /* delete; steering policy does not exist; complain */
178  if (is_del)
179  return -4;
180 
181  /* Retrieve SR policy */
182  if (bsid) //FIX
183  {
184  p = hash_get (sm->sr_policies_index_hash, bsid);
185  if (p)
186  sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
187  else
188  return -2;
189  }
190  else
191  sr_policy = pool_elt_at_index (sm->sr_policies, sr_policy_index);
192 
193  /* Create a new steering policy */
194  pool_get (sm->steer_policies, steer_pl);
195  memset (steer_pl, 0, sizeof (*steer_pl));
196 
197  if (traffic_type == SR_STEER_IPV4 || traffic_type == SR_STEER_IPV6)
198  {
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;
204  }
205  else
206  {
207  /* Incorrect API usage. Should never get here */
208  pool_put (sm->steer_policies, steer_pl);
210  return -1;
211  }
212  steer_pl->sr_policy = sr_policy - sm->sr_policies;
213 
214  /* Create and store key */
215  mhash_set (&sm->sr_steer_policies_hash, &key, steer_pl - sm->steer_policies,
216  NULL);
217 
218 update_fib:;
219 
220  fib_route_path_t path = {
222  .frp_local_label = sr_policy->bsid,
223  .frp_eos = MPLS_EOS,
224  .frp_sw_if_index = ~0,
225  .frp_fib_index = 0,
226  .frp_weight = 1,
227  .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
228  .frp_label_stack = NULL
229  };
230 
231  fib_route_path_t *paths = NULL;
232 
233  /* FIB API calls - Recursive route through the BindingSID */
234  if (traffic_type == SR_STEER_IPV6)
235  {
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;
240 
241  vec_add1 (paths, path);
242 
245  (table_id != (u32) ~ 0 ? table_id : 0)),
246  &pfx, FIB_SOURCE_SR,
248 
249  vec_free (paths);
250  }
251  else if (traffic_type == SR_STEER_IPV4)
252  {
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;
257 
258  vec_add1 (paths, path);
259 
262  (table_id != (u32) ~ 0 ? table_id : 0)),
263  &pfx, FIB_SOURCE_SR,
265 
266  vec_free (paths);
267  }
268 
269  return 0;
270 }
271 
272 static clib_error_t *
274  vlib_cli_command_t * cmd)
275 {
276  int is_del = 0;
277 
278  ip46_address_t prefix;
279  u32 dst_mask_width = 0;
280  u8 traffic_type = 0;
281  u32 fib_table = (u32) ~ 0;
282 
283  mpls_label_t bsid;
284  u32 sr_policy_index = (u32) ~ 0;
285 
286  u8 sr_policy_set = 0;
287 
288  memset (&prefix, 0, sizeof (ip46_address_t));
289 
290  int rv;
292  {
293  if (unformat (input, "del"))
294  is_del = 1;
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",
305  &sr_policy_index))
306  sr_policy_set = 1;
307  else if (!sr_policy_set
308  && unformat (input, "via sr policy bsid %U",
310  sr_policy_set = 1;
311  else if (fib_table == (u32) ~ 0
312  && unformat (input, "fib-table %d", &fib_table));
313  else
314  break;
315  }
316 
317  if (!traffic_type)
318  return clib_error_return (0, "No L3 traffic specified");
319  if (!sr_policy_set)
320  return clib_error_return (0, "No SR policy specified");
321 
322  /* Make sure that the prefixes are clean */
323  if (traffic_type == SR_STEER_IPV4)
324  {
325  u32 mask =
326  (dst_mask_width ? (0xFFFFFFFFu >> (32 - dst_mask_width)) : 0);
327  prefix.ip4.as_u32 &= mask;
328  }
329  else if (traffic_type == SR_STEER_IPV6)
330  {
331  ip6_address_t mask;
332  ip6_address_mask_from_width (&mask, dst_mask_width);
333  ip6_address_mask (&prefix.ip6, &mask);
334  }
335 
336  rv =
337  sr_mpls_steering_policy (is_del, bsid,
338  sr_policy_index, fib_table, &prefix,
339  dst_mask_width, traffic_type);
340 
341  switch (rv)
342  {
343  case 0:
344  break;
345  case 1:
346  return 0;
347  case -1:
348  return clib_error_return (0, "Incorrect API usage.");
349  case -2:
350  return clib_error_return (0,
351  "The requested SR policy could not be located. Review the BSID/index.");
352  case -3:
353  return clib_error_return (0,
354  "Unable to do SW redirect. Incorrect interface.");
355  case -4:
356  return clib_error_return (0,
357  "The requested SR steering policy could not be deleted.");
358  case -5:
359  return clib_error_return (0,
360  "The SR policy is not an encapsulation one.");
361  default:
362  return clib_error_return (0, "BUG: sr steer policy returns %d", rv);
363  }
364  return 0;
365 }
366 
367 /* *INDENT-OFF* */
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>)",
372  .long_help =
373  "\tSteer L3 traffic through an existing SR policy.\n"
374  "\tExamples:\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",
379 };
380 /* *INDENT-ON* */
381 
382 static clib_error_t *
384  unformat_input_t * input,
385  vlib_cli_command_t * cmd)
386 {
388  mpls_sr_steering_policy_t **steer_policies = 0;
389  mpls_sr_steering_policy_t *steer_pl;
390 
391  mpls_sr_policy_t *pl = 0;
392  int i;
393 
394  vlib_cli_output (vm, "SR MPLS steering policies:");
395  /* *INDENT-OFF* */
396  pool_foreach (steer_pl, sm->steer_policies, ({vec_add1(steer_policies, steer_pl);}));
397  /* *INDENT-ON* */
398  vlib_cli_output (vm, "Traffic\t\tSR policy BSID");
399  for (i = 0; i < vec_len (steer_policies); i++)
400  {
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)
404  {
405  vlib_cli_output (vm, "L3 %U/%d\t%U",
407  &steer_pl->classify.prefix.ip4,
408  steer_pl->classify.mask_width,
410  }
411  else if (steer_pl->classify.traffic_type == SR_STEER_IPV6)
412  {
413  vlib_cli_output (vm, "L3 %U/%d\t%U",
415  &steer_pl->classify.prefix.ip6,
416  steer_pl->classify.mask_width,
418  }
419  }
420  return 0;
421 }
422 
423 /* *INDENT-OFF* */
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",
428 };
429 /* *INDENT-ON* */
430 
431 clib_error_t *
433 {
435 
436  /* Init memory for function keys */
437  mhash_init (&sm->sr_steer_policies_hash, sizeof (uword),
438  sizeof (sr_mpls_steering_key_t));
439 
440  return 0;
441 }
442 
443 /* *INDENT-OFF* */
445 /* *INDENT-ON* */
446 
447 /*
448 * fd.io coding-style-patch-verification: ON
449 *
450 * Local Variables:
451 * eval: (c-set-style "gnu")
452 * End:
453 */
static void ip6_address_mask(ip6_address_t *a, ip6_address_t *mask)
Definition: ip6_packet.h:235
fib_protocol_t fp_proto
protocol type
Definition: fib_types.h:169
fib_protocol_t frp_proto
The protocol of the address below.
Definition: fib_types.h:341
u8 traffic_type
Traffic type (IPv4, IPv6, L2)
Definition: sr.h:85
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:337
A representation of a path as described by a route producer.
Definition: fib_types.h:336
#define NULL
Definition: clib.h:55
uword mhash_unset(mhash_t *h, void *key, uword *old_value)
Definition: mhash.c:353
fib_node_index_t fib_table_entry_path_add2(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source, fib_entry_flag_t flags, fib_route_path_t *rpath)
Add n paths to an entry (aka route) in the FIB.
Definition: fib_table.c:538
ip46_address_t prefix
IP address of the prefix.
Definition: sr.h:82
u32 mpls_label_t
A label value only, i.e.
Definition: packet.h:24
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:522
mhash_t sr_steer_policies_hash
MHash table mapping steering rules to SR steer instance.
Definition: sr.h:123
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:200
u32 fib_table
VRF of the prefix.
Definition: sr.h:84
unformat_function_t unformat_mpls_unicast_label
Definition: mpls.h:83
Definition: fib_entry.h:240
format_function_t format_ip4_address
Definition: format.h:79
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:376
unformat_function_t unformat_ip4_address
Definition: format.h:76
static clib_error_t * show_sr_mpls_steering_policies_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
Aggregrate type for a prefix.
Definition: fib_types.h:160
#define clib_error_return(e, args...)
Definition: error.h:99
u32 fib_table_find(fib_protocol_t proto, u32 table_id)
Get the index of the FIB for a Table-ID.
Definition: fib_table.c:1025
u16 fp_len
The mask length.
Definition: fib_types.h:164
#define hash_get(h, key)
Definition: hash.h:248
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:397
ip46_address_t fp_addr
The address type is not deriveable from the fp_addr member.
Definition: fib_types.h:183
struct _unformat_input_t unformat_input_t
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:241
mpls_sr_steering_policy_t * steer_policies
Pool of SR steer policies instances.
Definition: sr.h:118
clib_error_t * sr_mpls_steering_init(vlib_main_t *vm)
static uword mhash_set(mhash_t *h, void *key, uword new_value, uword *old_value)
Definition: mhash.h:117
mpls_label_t bsid
BindingSID (key)
Definition: sr.h:66
static clib_error_t * sr_mpls_steer_policy_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
unformat_function_t unformat_ip6_address
Definition: format.h:94
The fine-grained event logger allows lightweight, thread-safe event logging at minimum cost...
#define UNFORMAT_END_OF_INPUT
Definition: format.h:143
void mhash_init(mhash_t *h, uword n_value_bytes, uword n_key_bytes)
Definition: mhash.c:168
format_function_t format_ip6_address
Definition: format.h:95
mpls_sr_main_t sr_mpls_main
sr_mpls_steering_key_t classify
Traffic classification.
Definition: sr.h:91
u32 mask_width
Mask width of the prefix.
Definition: sr.h:83
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:340
void fib_table_entry_delete(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source)
Delete a FIB entry.
Definition: fib_table.c:835
#define clib_memcpy(a, b, c)
Definition: string.h:69
mpls_sr_policy_t * sr_policies
SR MPLS policies.
Definition: sr.h:108
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:154
Segment Routing main datastructure.
Definition: sr.h:98
unsigned int u32
Definition: types.h:88
static uword * mhash_get(mhash_t *h, const void *key)
Definition: mhash.h:110
uword * sr_policies_index_hash
Hash table mapping BindingSID to SR MPLS policy.
Definition: sr.h:113
u32 sr_policy
SR Policy index.
Definition: sr.h:92
format_function_t format_mpls_unicast_label
Definition: mpls.h:71
u64 uword
Definition: types.h:112
SRv6 and SR-MPLS.
Definition: fib_entry.h:54
#define SR_STEER_IPV6
Definition: sr.h:43
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
Segment Routing MPLS data structures definitions.
static void ip6_address_mask_from_width(ip6_address_t *a, u32 width)
Definition: ip6_packet.h:251
Steering db key.
Definition: sr.h:80
int sr_mpls_steering_policy(int is_del, mpls_label_t bsid, u32 sr_policy_index, u32 table_id, ip46_address_t *prefix, u32 mask_width, u8 traffic_type)
Steer traffic L3 traffic through a given SR-MPLS policy.
u32 frp_fib_index
The FIB index to lookup the nexthop Only valid for recursive paths.
Definition: fib_types.h:379
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:680
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:972
#define SR_STEER_IPV4
Definition: sr.h:42
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169