dpdk: Add support for Mellanox ConnectX-4 devices
[vpp.git] / src / vnet / adj / adj.c
1 /*
2  * Copyright (c) 2016 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <vnet/adj/adj.h>
17 #include <vnet/adj/adj_internal.h>
18 #include <vnet/adj/adj_glean.h>
19 #include <vnet/adj/adj_midchain.h>
20 #include <vnet/fib/fib_node_list.h>
21
22 /*
23  * Special Adj with index zero. we need to define this since the v4 mtrie
24  * assumes an index of 0 implies the ply is empty. therefore all 'real'
25  * adjs need a non-zero index.
26  */
27 static ip_adjacency_t *special_v4_miss_adj_with_index_zero;
28
29 /* Adjacency packet/byte counters indexed by adjacency index. */
30 vlib_combined_counter_main_t adjacency_counters;
31
32 /*
33  * the single adj pool
34  */
35 ip_adjacency_t *adj_pool;
36
37 always_inline void
38 adj_poison (ip_adjacency_t * adj)
39 {
40     if (CLIB_DEBUG > 0)
41     {
42         memset (adj, 0xfe, sizeof (adj[0]));
43     }
44 }
45
46 ip_adjacency_t *
47 adj_alloc (fib_protocol_t proto)
48 {
49     ip_adjacency_t *adj;
50
51     pool_get(adj_pool, adj);
52
53     adj_poison(adj);
54
55     /* Make sure certain fields are always initialized. */
56     /* Validate adjacency counters. */
57     vlib_validate_combined_counter(&adjacency_counters,
58                                    adj_get_index(adj));
59
60     adj->rewrite_header.sw_if_index = ~0;
61     adj->mcast_group_index = ~0;
62     adj->saved_lookup_next_index = 0;
63     adj->n_adj = 1;
64     adj->lookup_next_index = 0;
65
66     fib_node_init(&adj->ia_node,
67                   FIB_NODE_TYPE_ADJ);
68     adj->ia_nh_proto = proto;
69     adj->ia_flags = 0;
70
71     ip4_main.lookup_main.adjacency_heap = adj_pool;
72     ip6_main.lookup_main.adjacency_heap = adj_pool;
73
74     return (adj);
75 }
76
77 static int
78 adj_index_is_special (adj_index_t adj_index)
79 {
80     if (ADJ_INDEX_INVALID == adj_index)
81         return (!0);
82
83     return (0);
84 }
85
86 /**
87  * @brief Pretty print helper function for formatting specific adjacencies.
88  * @param s - input string to format
89  * @param args - other args passed to format function such as:
90  *                 - vnet_main_t
91  *                 - ip_lookup_main_t
92  *                 - adj_index
93  */
94 u8 *
95 format_ip_adjacency (u8 * s, va_list * args)
96 {
97     format_ip_adjacency_flags_t fiaf;
98     ip_adjacency_t * adj;
99     u32 adj_index;
100
101     adj_index = va_arg (*args, u32);
102     fiaf = va_arg (*args, format_ip_adjacency_flags_t);
103     adj = adj_get(adj_index);
104   
105     switch (adj->lookup_next_index)
106     {
107     case IP_LOOKUP_NEXT_REWRITE:
108         s = format (s, "%U", format_adj_nbr, adj_index, 0);
109         break;
110     case IP_LOOKUP_NEXT_ARP:
111         s = format (s, "%U", format_adj_nbr_incomplete, adj_index, 0);
112         break;
113     case IP_LOOKUP_NEXT_GLEAN:
114         s = format (s, "%U", format_adj_glean, adj_index, 0);
115         break;
116     case IP_LOOKUP_NEXT_MIDCHAIN:
117         s = format (s, "%U", format_adj_midchain, adj_index, 2);
118         break;
119     default:
120         break;
121     }
122
123     if (fiaf & FORMAT_IP_ADJACENCY_DETAIL)
124     {
125         s = format (s, "\n locks:%d", adj->ia_node.fn_locks);
126         s = format (s, " node:[%d]:%U",
127                     adj->rewrite_header.node_index,
128                     format_vlib_node_name, vlib_get_main(),
129                     adj->rewrite_header.node_index);
130         s = format (s, " next:[%d]:%U",
131                     adj->rewrite_header.next_index,
132                     format_vlib_next_node_name,
133                     vlib_get_main(),
134                     adj->rewrite_header.node_index,
135                     adj->rewrite_header.next_index);
136         s = format(s, "\n children:\n  ");
137         s = fib_node_children_format(adj->ia_node.fn_children, s);
138     }
139
140     return s;
141 }
142
143 /*
144  * adj_last_lock_gone
145  *
146  * last lock/reference to the adj has gone, we no longer need it.
147  */
148 static void
149 adj_last_lock_gone (ip_adjacency_t *adj)
150 {
151     vlib_main_t * vm = vlib_get_main();
152
153     ASSERT(0 == fib_node_list_get_size(adj->ia_node.fn_children));
154     ADJ_DBG(adj, "last-lock-gone");
155
156     vlib_worker_thread_barrier_sync (vm);
157
158     switch (adj->lookup_next_index)
159     {
160     case IP_LOOKUP_NEXT_MIDCHAIN:
161         dpo_reset(&adj->sub_type.midchain.next_dpo);
162         /* FALL THROUGH */
163     case IP_LOOKUP_NEXT_ARP:
164     case IP_LOOKUP_NEXT_REWRITE:
165         /*
166          * complete and incomplete nbr adjs
167          */
168         adj_nbr_remove(adj_get_index(adj),
169                        adj->ia_nh_proto,
170                        adj->ia_link,
171                        &adj->sub_type.nbr.next_hop,
172                        adj->rewrite_header.sw_if_index);
173         break;
174     case IP_LOOKUP_NEXT_GLEAN:
175         adj_glean_remove(adj->ia_nh_proto,
176                          adj->rewrite_header.sw_if_index);
177         break;
178     default:
179         /*
180          * type not stored in any DB from which we need to remove it
181          */
182         break;
183     }
184
185     vlib_worker_thread_barrier_release(vm);
186
187     fib_node_deinit(&adj->ia_node);
188     pool_put(adj_pool, adj);
189 }
190
191 void
192 adj_lock (adj_index_t adj_index)
193 {
194     ip_adjacency_t *adj;
195
196     if (adj_index_is_special(adj_index))
197     {
198         return;
199     }
200
201     adj = adj_get(adj_index);
202     ASSERT(adj);
203
204     ADJ_DBG(adj, "lock");
205     fib_node_lock(&adj->ia_node);
206 }
207
208 void
209 adj_unlock (adj_index_t adj_index)
210 {
211     ip_adjacency_t *adj;
212
213     if (adj_index_is_special(adj_index))
214     {
215         return;
216     }
217
218     adj = adj_get(adj_index);
219     ASSERT(adj);
220
221     ADJ_DBG(adj, "unlock");
222     ASSERT(adj);
223
224     fib_node_unlock(&adj->ia_node);
225 }
226
227 u32
228 adj_child_add (adj_index_t adj_index,
229                fib_node_type_t child_type,
230                fib_node_index_t child_index)
231 {
232     ASSERT(ADJ_INDEX_INVALID != adj_index);
233     if (adj_index_is_special(adj_index))
234     {
235         return (~0);
236     }
237
238     return (fib_node_child_add(FIB_NODE_TYPE_ADJ,
239                                adj_index,
240                                child_type,
241                                child_index));
242 }
243
244 void
245 adj_child_remove (adj_index_t adj_index,
246                   u32 sibling_index)
247 {
248     if (adj_index_is_special(adj_index))
249     {
250         return;
251     }
252
253     fib_node_child_remove(FIB_NODE_TYPE_ADJ,
254                           adj_index,
255                           sibling_index);
256 }
257
258 /**
259  * @brief Return the link type of the adjacency
260  */
261 vnet_link_t
262 adj_get_link_type (adj_index_t ai)
263 {
264     const ip_adjacency_t *adj;
265
266     adj = adj_get(ai);
267
268     return (adj->ia_link); 
269 }
270
271 /**
272  * @brief Return the sw interface index of the adjacency.
273  */
274 u32
275 adj_get_sw_if_index (adj_index_t ai)
276 {
277     const ip_adjacency_t *adj;
278
279     adj = adj_get(ai);
280
281     return (adj->rewrite_header.sw_if_index);
282 }
283
284 /**
285  * @brief Return the link type of the adjacency
286  */
287 const u8*
288 adj_get_rewrite (adj_index_t ai)
289 {
290     vnet_rewrite_header_t *rw;
291     ip_adjacency_t *adj;
292
293     adj = adj_get(ai);
294     rw = &adj->rewrite_header;
295
296     ASSERT (rw->data_bytes != 0xfefe);
297
298     return (rw->data - rw->data_bytes);
299 }
300
301 static fib_node_t *
302 adj_get_node (fib_node_index_t index)
303 {
304     ip_adjacency_t *adj;
305
306     adj = adj_get(index);
307
308     return (&adj->ia_node);
309 }
310
311 #define ADJ_FROM_NODE(_node)                                            \
312     ((ip_adjacency_t*)((char*)_node - STRUCT_OFFSET_OF(ip_adjacency_t, ia_node)))
313
314 static void
315 adj_node_last_lock_gone (fib_node_t *node)
316 {
317     adj_last_lock_gone(ADJ_FROM_NODE(node));
318 }
319
320 static fib_node_back_walk_rc_t
321 adj_back_walk_notify (fib_node_t *node,
322                       fib_node_back_walk_ctx_t *ctx)
323 {
324     /*
325      * Que pasa. yo soj en el final!
326      */
327     ASSERT(0);
328
329     return (FIB_NODE_BACK_WALK_CONTINUE);
330 }
331
332 /*
333  * Adjacency's graph node virtual function table
334  */
335 static const fib_node_vft_t adj_vft = {
336     .fnv_get = adj_get_node,
337     .fnv_last_lock = adj_node_last_lock_gone,
338     .fnv_back_walk = adj_back_walk_notify,
339 };
340
341 static clib_error_t *
342 adj_module_init (vlib_main_t * vm)
343 {
344     fib_node_register_type(FIB_NODE_TYPE_ADJ, &adj_vft);
345
346     adj_nbr_module_init();
347     adj_glean_module_init();
348     adj_midchain_module_init();
349
350     /*
351      * one special adj to reserve index 0
352      */
353     special_v4_miss_adj_with_index_zero = adj_alloc(FIB_PROTOCOL_IP4);
354
355     return (NULL);
356 }
357
358 VLIB_INIT_FUNCTION (adj_module_init);
359
360 static clib_error_t *
361 adj_show (vlib_main_t * vm,
362           unformat_input_t * input,
363           vlib_cli_command_t * cmd)
364 {
365     adj_index_t ai = ADJ_INDEX_INVALID;
366     u32 sw_if_index = ~0;
367
368     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
369     {
370         if (unformat (input, "%d", &ai))
371             ;
372         else if (unformat (input, "%U",
373                            unformat_vnet_sw_interface, vnet_get_main(),
374                            &sw_if_index))
375             ;
376         else
377             break;
378     }
379
380     if (ADJ_INDEX_INVALID != ai)
381     {
382         if (pool_is_free_index(adj_pool, ai))
383         {
384             vlib_cli_output (vm, "adjacency %d invalid", ai);
385             return 0;
386         }
387
388         vlib_cli_output (vm, "[@%d] %U",
389                          ai,
390                          format_ip_adjacency,  ai,
391                          FORMAT_IP_ADJACENCY_DETAIL);
392     }
393     else
394     {
395         /* *INDENT-OFF* */
396         pool_foreach_index(ai, adj_pool,
397         ({
398             if (~0 != sw_if_index &&
399                 sw_if_index != adj_get_sw_if_index(ai))
400             {
401             }
402             else
403             {
404                 vlib_cli_output (vm, "[@%d] %U",
405                                  ai,
406                                  format_ip_adjacency, ai,
407                                  FORMAT_IP_ADJACENCY_NONE);
408             }
409         }));
410         /* *INDENT-ON* */
411     }
412
413     return 0;
414 }
415
416 /*?
417  * Show all adjacencies.
418  * @cliexpar
419  * @cliexstart{sh adj}
420  * [@0]
421  * [@1]  glean: loop0
422  * [@2] ipv4 via 1.0.0.2 loop0: IP4: 00:00:22:aa:bb:cc -> 00:00:11:aa:bb:cc
423  * [@3] mpls via 1.0.0.2 loop0: MPLS_UNICAST: 00:00:22:aa:bb:cc -> 00:00:11:aa:bb:cc
424  * [@4] ipv4 via 1.0.0.3 loop0: IP4: 00:00:22:aa:bb:cc -> 00:00:11:aa:bb:cc
425  * [@5] mpls via 1.0.0.3 loop0: MPLS_UNICAST: 00:00:22:aa:bb:cc -> 00:00:11:aa:bb:cc
426  * @cliexend
427  ?*/
428 VLIB_CLI_COMMAND (adj_show_command, static) = {
429     .path = "show adj",
430     .short_help = "show adj [<adj_index>] [interface]",
431     .function = adj_show,
432 };
433
434 /* 
435  * DEPRECATED: DO NOT USE
436  */
437 ip_adjacency_t *
438 ip_add_adjacency (ip_lookup_main_t * lm,
439                   ip_adjacency_t * copy_adj,
440                   u32 n_adj,
441                   u32 * adj_index_return)
442 {
443   ip_adjacency_t * adj;
444
445   ASSERT(1==n_adj);
446
447   adj = adj_alloc(FIB_PROTOCOL_IP4);
448
449   if (copy_adj)
450       *adj = *copy_adj;
451
452   *adj_index_return = adj_get_index(adj);
453   return adj;
454 }