FD.io VPP  v19.04.2-12-g66b1689
Vector Packet Processing
nsh_md2_ioam.c
Go to the documentation of this file.
1 /*
2  * nsh_md2_ioam.c - NSH iOAM functions for MD type 2
3  *
4  * Copyright (c) 2017 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 #include <vnet/vnet.h>
19 #include <vnet/plugin/plugin.h>
20 #include <nsh/nsh.h>
21 #include <nsh/nsh_packet.h>
22 #include <vnet/ip/ip.h>
24 
25 #include <vlibapi/api.h>
26 #include <vlibmemory/api.h>
27 
28 #include <vnet/fib/ip6_fib.h>
29 #include <vnet/fib/ip4_fib.h>
30 #include <vnet/fib/fib_entry.h>
31 
32 /* define message structures */
33 #define vl_typedefs
34 #include <nsh/nsh.api.h>
35 #undef vl_typedefs
36 
37 /* define generated endian-swappers */
38 #define vl_endianfun
39 #include <nsh/nsh.api.h>
40 #undef vl_endianfun
41 
43 
44 static void
46  u32 sw_if_index0,
47  u8 is_add)
48 {
49 
50 
51 
52  vnet_feature_enable_disable ("ip4-output",
53  "nsh-md2-ioam-encap-transit",
54  sw_if_index0, is_add,
55  0 /* void *feature_config */ ,
56  0 /* u32 n_feature_config_bytes */ );
57  return;
58 }
59 
60 void
62 {
63  vnet_sw_interface_t *si = 0;
64  vnet_main_t *vnm = vnet_get_main ();
66 
67  pool_foreach (si, im->sw_interfaces, (
68  {
69  nsh_md2_ioam_set_clear_output_feature_on_intf
70  (vm, si->sw_if_index, 0);
71  }));
72  return;
73 }
74 
75 
78 
79 int
81  ip46_address_t dst_addr,
82  u32 outer_fib_index,
83  u8 is_ipv4, u8 is_add)
84 {
86  u32 fib_index0 = 0;
87 
88  fib_node_index_t fei = ~0;
89  u32 *sw_if_index0 = NULL;
90 #if 0
91  fib_entry_t *fib_entry;
92  u32 adj_index0;
93  ip_adjacency_t *adj0;
94  load_balance_t *lb_m, *lb_b;
95  const dpo_id_t *dpo0, *dpo1;
96  u32 i, j, k;
97 #endif
98  u32 *intf_list = NULL;
99  fib_prefix_t fib_prefix;
100 
101  if (is_ipv4)
102  {
103  clib_memset (&fib_prefix, 0, sizeof (fib_prefix_t));
104  fib_prefix.fp_len = 32;
105  fib_prefix.fp_proto = FIB_PROTOCOL_IP4;
106 #define TRANSIT_UNIT_TEST_HACK 1
107 #ifdef TRANSIT_UNIT_TEST_HACK
108  clib_memset(&dst_addr, 0, sizeof(dst_addr));
109  dst_addr.ip4.as_u32 = clib_net_to_host_u32(0x14020102);
110 #endif
111  fib_prefix.fp_addr = dst_addr;
112  }
113  else
114  {
115  return 0;
116  }
117 
118  fei = fib_table_lookup (fib_index0, &fib_prefix);
119 #if 0
120  fib_entry = fib_entry_get (fei);
121 
122 
123  if (!dpo_id_is_valid (&fib_entry->fe_lb))
124  {
125  return (-1);
126  }
127 
128  lb_m = load_balance_get (fib_entry->fe_lb.dpoi_index);
129 
130  for (i = 0; i < lb_m->lb_n_buckets; i++)
131  {
132  dpo0 = load_balance_get_bucket_i (lb_m, i);
133 
134  if (dpo0->dpoi_type == DPO_LOAD_BALANCE ||
135  dpo0->dpoi_type == DPO_ADJACENCY)
136  {
137  if (dpo0->dpoi_type == DPO_ADJACENCY)
138  {
139  k = 1;
140  }
141  else
142  {
143  lb_b = load_balance_get (dpo0->dpoi_index);
144  k = lb_b->lb_n_buckets;
145  }
146 
147  for (j = 0; j < k; j++)
148  {
149  if (dpo0->dpoi_type == DPO_ADJACENCY)
150  {
151  dpo1 = dpo0;
152  }
153  else
154  {
155  dpo1 = load_balance_get_bucket_i (lb_b, j);
156  }
157 
158  if (dpo1->dpoi_type == DPO_ADJACENCY)
159  {
160  adj_index0 = dpo1->dpoi_index;
161 
162  if (ADJ_INDEX_INVALID == adj_index0)
163  {
164  continue;
165  }
166 
167  adj0 =
168  ip_get_adjacency (&(ip4_main.lookup_main), adj_index0);
169  sw_if_index0 = adj0->rewrite_header.sw_if_index;
170 
171  if (~0 == sw_if_index0)
172  {
173  continue;
174  }
175 
176 
177  if (is_add)
178  {
179  vnet_feature_enable_disable ("ip4-output",
180  "nsh-md2-ioam-encap-transit",
181  sw_if_index0, is_add, 0,
182  /* void *feature_config */
183  0 /* u32 n_feature_config_bytes */
184  );
185 
187  sw_if_index0, ~0);
188  hm->bool_ref_by_sw_if_index[sw_if_index0] = 1;
189  }
190  else
191  {
192  hm->bool_ref_by_sw_if_index[sw_if_index0] = ~0;
193  }
194  }
195  }
196  }
197  }
198 #else
199 
202  vec_foreach(sw_if_index0, intf_list)
203  if (is_add)
204  {
205  vnet_feature_enable_disable ("ip4-output",
206  "nsh-md2-ioam-encap-transit",
207  *sw_if_index0, is_add, 0,
208  /* void *feature_config */
209  0 /* u32 n_feature_config_bytes */
210  );
211 
213  *sw_if_index0, ~0);
214  hm->bool_ref_by_sw_if_index[*sw_if_index0] = 1;
215  }
216  else
217  {
218  hm->bool_ref_by_sw_if_index[*sw_if_index0] = ~0;
219  }
220 
221 #endif
222 
223  if (is_ipv4)
224  {
225  uword *t = NULL;
227  fib_prefix_t key4, *key4_copy;
228  hash_pair_t *hp;
229  clib_memset (&key4, 0, sizeof (key4));
230  key4.fp_proto = FIB_PROTOCOL_IP4;
231  key4.fp_addr.ip4.as_u32 = fib_prefix.fp_addr.ip4.as_u32;
232  t = hash_get_mem (hm->dst_by_ip4, &key4);
233  if (is_add)
234  {
235  if (t)
236  {
237  return 0;
238  }
240  clib_memset (t1, 0, sizeof (*t1));
242  t1->dst_addr.ip4.as_u32 = fib_prefix.fp_addr.ip4.as_u32;
243  key4_copy = clib_mem_alloc (sizeof (*key4_copy));
244  clib_memset(key4_copy, 0, sizeof(*key4_copy));
245  clib_memcpy_fast (key4_copy, &key4, sizeof (*key4_copy));
246  hash_set_mem (hm->dst_by_ip4, key4_copy, t1 - hm->dst_tunnels);
247  /*
248  * Attach to the FIB entry for the VxLAN-GPE destination
249  * and become its child. The dest route will invoke a callback
250  * when the fib entry changes, it can be used to
251  * re-program the output feature on the egress interface.
252  */
253 
254  const fib_prefix_t tun_dst_pfx = {
255  .fp_len = 32,
256  .fp_proto = FIB_PROTOCOL_IP4,
257  .fp_addr = {.ip4 = t1->dst_addr.ip4,}
258  };
259 
260  t1->fib_entry_index =
261  fib_table_entry_special_add (outer_fib_index,
262  &tun_dst_pfx,
265  t1->sibling_index =
267  hm->fib_entry_type, t1 - hm->dst_tunnels);
268  t1->outer_fib_index = outer_fib_index;
269 
270  }
271  else
272  {
273  if (!t)
274  {
275  return 0;
276  }
277  t1 = pool_elt_at_index (hm->dst_tunnels, t[0]);
278  hp = hash_get_pair (hm->dst_by_ip4, &key4);
279  key4_copy = (void *) (hp->key);
280  hash_unset_mem (hm->dst_by_ip4, &key4);
281  clib_mem_free (key4_copy);
282  pool_put (hm->dst_tunnels, t1);
283  }
284  }
285  else
286  {
287  // TBD for IPv6
288  }
289 
290  return 0;
291 }
292 
293 void
295 {
297  nsh_main_t *gm = &nsh_main;
299  u32 i;
300 
301  if (pool_elts (hm->dst_tunnels) == 0)
302  return;
303 
308  pool_foreach (t, hm->dst_tunnels, (
309  {
310  nsh_md2_ioam_enable_disable_for_dest
311  (gm->vlib_main,
312  t->dst_addr,
313  t->outer_fib_index,
314  (t->fp_proto == FIB_PROTOCOL_IP4), 1
315  /* is_add */
316  );
317  }
318  ));
319  return;
320 }
321 
322 void
324 {
326  nsh_main_t *gm = &nsh_main;
327 
328  u32 sw_if_index0 = 0;
329  for (sw_if_index0 = 0;
330  sw_if_index0 < vec_len (hm->bool_ref_by_sw_if_index); sw_if_index0++)
331  {
332  if (hm->bool_ref_by_sw_if_index[sw_if_index0] == 0xFF)
333  {
335  (gm->vlib_main, sw_if_index0, 0);
336  }
337  }
338 
339  return;
340 }
341 
342 
343 
344 
345 clib_error_t *
346 nsh_md2_ioam_enable_disable (int has_trace_option, int has_pot_option,
347  int has_ppc_option)
348 {
350 
351  hm->has_trace_option = has_trace_option;
352  hm->has_pot_option = has_pot_option;
353  hm->has_ppc_option = has_ppc_option;
354 
355  if (hm->has_trace_option)
356  {
358  }
359  else if (!hm->has_trace_option)
360  {
362  }
363 
364  return 0;
365 }
366 
367 
369  (vlib_main_t * vm, ip46_address_t dst_addr, u32 outer_fib_index,
370  u8 ipv4_set)
371 {
374  nsh_main_t *gm = &nsh_main;
375 
377  dst_addr, outer_fib_index,
378  ipv4_set, 0);
379  if (pool_elts (hm->dst_tunnels) == 0)
380  {
382  return 0;
383  }
384 
385  pool_foreach (t, hm->dst_tunnels, (
386  {
387  nsh_md2_ioam_enable_disable_for_dest
388  (gm->vlib_main,
389  t->dst_addr,
390  t->outer_fib_index,
391  (t->fp_proto ==
392  FIB_PROTOCOL_IP4), 1 /* is_add */ );
393  }
394  ));
396  return (0);
397 
398 }
399 
402 {
403  nsh_main_t *gm = &nsh_main;
404  ip46_address_t dst_addr;
405  u8 dst_addr_set = 0;
406  u8 ipv4_set = 0;
407  u8 ipv6_set = 0;
408  u8 disable = 0;
409  clib_error_t *rv = 0;
410  u32 outer_fib_index = 0;
412  {
413  if (unformat (input, "dst-ip %U", unformat_ip4_address, &dst_addr.ip4))
414  {
415  dst_addr_set = 1;
416  ipv4_set = 1;
417  }
418  else
419  if (unformat
420  (input, "dst-ip %U", unformat_ip6_address, &dst_addr.ip6))
421  {
422  dst_addr_set = 1;
423  ipv6_set = 1;
424  }
425  else if (unformat (input, "outer-fib-index %d", &outer_fib_index))
426  {
427  }
428 
429  else if (unformat (input, "disable"))
430  disable = 1;
431  else
432  break;
433  }
434 
435  if (dst_addr_set == 0)
436  return clib_error_return (0,
437  "LISP-GPE Tunnel destination address not specified");
438  if (ipv4_set && ipv6_set)
439  return clib_error_return (0, "both IPv4 and IPv6 addresses specified");
440  if (!disable)
441  {
443  dst_addr, outer_fib_index,
444  ipv4_set, 1);
445  }
446  else
447  {
449  (vm, dst_addr, outer_fib_index, ipv4_set);
450  }
451  return rv;
452 }
453 
454 /* *INDENT-OFF* */
455 VLIB_CLI_COMMAND (nsh_md2_ioam_set_transit_rewrite_cmd, static) = {
456  .path = "set nsh-md2-ioam-transit",
457  .short_help = "set nsh-ioam-lisp-gpe-transit dst-ip <dst_ip> [outer-fib-index <outer_fib_index>] [disable]",
459 };
460 
461 /**
462  * Function definition to backwalk a FIB node
463  */
466 {
469 }
470 
471 /**
472  * Function definition to get a FIB node from its index
473  */
474 static fib_node_t *
476 {
478  return (&hm->node);
479 }
480 
481 /**
482  * Function definition to inform the FIB node that its last lock has gone.
483  */
484 static void
486 {
487  ASSERT (0);
488 }
489 
490 
491 /*
492  * Virtual function table registered by MPLS GRE tunnels
493  * for participation in the FIB object graph.
494  */
495 const static fib_node_vft_t nsh_md2_ioam_vft = {
497  .fnv_last_lock = nsh_md2_ioam_last_lock_gone,
498  .fnv_back_walk = nsh_md2_ioam_back_walk,
499 };
500 
501 void
503 {
505  hm->fib_entry_type = fib_node_register_new_type (&nsh_md2_ioam_vft);
506  return;
507 }
508 
u16 lb_n_buckets
number of buckets in the load-balance.
Definition: load_balance.h:116
fib_protocol_t fp_proto
protocol type
Definition: fib_types.h:212
fib_forward_chain_type_t fib_entry_get_default_chain_type(const fib_entry_t *fib_entry)
Definition: fib_entry.c:80
u8 * bool_ref_by_sw_if_index
per sw_if_index, to maintain bitmap
Definition: nsh_md2_ioam.h:88
Recursive resolution source.
Definition: fib_entry.h:125
An entry in a FIB table.
Definition: fib_entry.h:462
vnet_main_t * vnet_get_main(void)
Definition: misc.c:47
vnet_interface_main_t interface_main
Definition: vnet.h:56
u32 fib_entry_child_add(fib_node_index_t fib_entry_index, fib_node_type_t child_type, fib_node_index_t child_index)
Definition: fib_entry.c:565
static int dpo_id_is_valid(const dpo_id_t *dpoi)
Return true if the DPO object is valid, i.e.
Definition: dpo.h:207
fib_node_t node
Linkage into the FIB object graph.
Definition: nsh_md2_ioam.h:44
#define clib_memcpy_fast(a, b, c)
Definition: string.h:81
#define NULL
Definition: clib.h:58
IP unicast adjacency.
Definition: adj.h:221
enum fib_node_back_walk_rc_t_ fib_node_back_walk_rc_t
Return code from a back walk function.
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:522
int i
#define hash_set_mem(h, key, value)
Definition: hash.h:275
clib_memset(h->entries, 0, sizeof(h->entries[0])*entries)
ip_lookup_main_t lookup_main
Definition: ip4.h:98
void nsh_md2_ioam_refresh_output_feature_on_all_dest(void)
Definition: nsh_md2_ioam.c:294
int nsh_md2_ioam_trace_profile_cleanup(void)
unsigned char u8
Definition: types.h:56
fib_node_type_t fib_entry_type
Definition: nsh_md2_ioam.h:89
fib_node_type_t fib_node_register_new_type(const fib_node_vft_t *vft)
Create a new FIB node type and Register the function table for it.
Definition: fib_node.c:80
static clib_error_t * nsh_md2_ioam_set_transit_rewrite_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: nsh_md2_ioam.c:401
void nsh_md2_ioam_clear_output_feature_on_select_intfs(void)
Definition: nsh_md2_ioam.c:323
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:493
unformat_function_t unformat_ip4_address
Definition: format.h:70
static void nsh_md2_ioam_set_clear_output_feature_on_intf(vlib_main_t *vm, u32 sw_if_index0, u8 is_add)
Definition: nsh_md2_ioam.c:45
Aggregrate type for a prefix.
Definition: fib_types.h:203
#define clib_error_return(e, args...)
Definition: error.h:99
fib_node_index_t fib_entry_index
Definition: nsh_md2_ioam.h:35
static fib_node_back_walk_rc_t nsh_md2_ioam_back_walk(fib_node_t *node, fib_node_back_walk_ctx_t *ctx)
Function definition to backwalk a FIB node.
Definition: nsh_md2_ioam.c:465
#define hash_get_pair(h, key)
Definition: hash.h:252
unsigned int u32
Definition: types.h:88
u16 fp_len
The mask length.
Definition: fib_types.h:207
fib_node_index_t fib_table_lookup(u32 fib_index, const fib_prefix_t *prefix)
Perfom a longest prefix match in the non-forwarding table.
Definition: fib_table.c:66
int nsh_md2_ioam_disable_for_dest(vlib_main_t *vm, ip46_address_t dst_addr, u32 outer_fib_index, u8 ipv4_set)
Definition: nsh_md2_ioam.c:369
Definition: fib_entry.h:275
clib_error_t * nsh_md2_ioam_enable_disable(int has_trace_option, int has_pot_option, int has_ppc_option)
Definition: nsh_md2_ioam.c:346
The identity of a DPO is a combination of its type and its instance number/index of objects of that t...
Definition: dpo.h:168
#define ADJ_INDEX_INVALID
Invalid ADJ index - used when no adj is known likewise blazoned capitals INVALID speak volumes where ...
Definition: adj_types.h:36
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:514
#define hash_unset_mem(h, key)
Definition: hash.h:291
ip46_address_t fp_addr
The address type is not deriveable from the fp_addr member.
Definition: fib_types.h:226
nsh_md2_ioam_main_t nsh_md2_ioam_main
Definition: nsh_md2_ioam.c:42
#define gm
Definition: dlmalloc.c:1217
dpo_type_t dpoi_type
the type
Definition: dpo.h:172
static const dpo_id_t * load_balance_get_bucket_i(const load_balance_t *lb, u32 bucket)
Definition: load_balance.h:228
long ctx[MAX_CONNS]
Definition: main.c:144
struct _unformat_input_t unformat_input_t
load-balancing over a choice of [un]equal cost paths
Definition: dpo.h:102
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:286
The FIB DPO provieds;.
Definition: load_balance.h:106
static fib_node_t * nsh_md2_ioam_fib_node_get(fib_node_index_t index)
Function definition to get a FIB node from its index.
Definition: nsh_md2_ioam.c:475
An node in the FIB graph.
Definition: fib_node.h:291
void nsh_md2_ioam_clear_output_feature_on_all_intfs(vlib_main_t *vm)
Definition: nsh_md2_ioam.c:61
unformat_function_t unformat_ip6_address
Definition: format.h:91
#define pool_get_aligned(P, E, A)
Allocate an object E from a pool P with alignment A.
Definition: pool.h:230
fib_node_index_t fib_table_entry_special_add(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source, fib_entry_flag_t flags)
Add a &#39;special&#39; entry to the FIB.
Definition: fib_table.c:388
#define UNFORMAT_END_OF_INPUT
Definition: format.h:144
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:341
static void nsh_md2_ioam_last_lock_gone(fib_node_t *node)
Function definition to inform the FIB node that its last lock has gone.
Definition: nsh_md2_ioam.c:485
fib_node_get_t fnv_get
Definition: fib_node.h:279
nsh_main_t nsh_main
Definition: nsh.c:28
u32 fib_node_index_t
A typedef of a node index.
Definition: fib_types.h:30
fib_entry_t * fib_entry_get(fib_node_index_t index)
Definition: fib_entry.c:50
Context passed between object during a back walk.
Definition: fib_node.h:204
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:155
#define ASSERT(truth)
u8 is_add
Definition: ipsec_gre.api:36
static load_balance_t * load_balance_get(index_t lbi)
Definition: load_balance.h:219
void nsh_md2_ioam_interface_init(void)
Definition: nsh_md2_ioam.c:502
int nsh_md2_ioam_enable_disable_for_dest(vlib_main_t *vm, ip46_address_t dst_addr, u32 outer_fib_index, u8 is_ipv4, u8 is_add)
Definition: nsh_md2_ioam.c:80
static void clib_mem_free(void *p)
Definition: mem.h:205
enum fib_forward_chain_type_t_ fib_forward_chain_type_t
FIB output chain type.
vlib_main_t * vlib_main
Definition: nsh.h:167
static void * clib_mem_alloc(uword size)
Definition: mem.h:132
dpo_id_t fe_lb
The load-balance used for forwarding.
Definition: fib_entry.h:488
u32 fib_path_get_resolving_interface(fib_node_index_t path_index)
Definition: fib_path.c:2087
index_t dpoi_index
the index of objects of that type
Definition: dpo.h:184
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
u64 uword
Definition: types.h:112
vnet_sw_interface_t * sw_interfaces
Definition: interface.h:815
#define hash_get_mem(h, key)
Definition: hash.h:269
A FIB graph nodes virtual function table.
Definition: fib_node.h:278
ip4_main_t ip4_main
Global ip4 main structure.
Definition: ip4_forward.c:905
#define vec_foreach(var, vec)
Vector iterator.
int nsh_md2_ioam_trace_profile_setup(void)
nsh_md2_ioam_dest_tunnels_t * dst_tunnels
Definition: nsh_md2_ioam.h:83
#define vec_validate_init_empty(V, I, INIT)
Make sure vector is long enough for given index and initialize empty space (no header, unspecified alignment)
Definition: vec.h:486
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:59
uword key
Definition: hash.h:162
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:972
int vnet_feature_enable_disable(const char *arc_name, const char *node_name, u32 sw_if_index, int enable_disable, void *feature_config, u32 n_feature_config_bytes)
Definition: feature.c:274
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:170
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:128