7acdccc72b09c10e4151212de05c0db027795adf
[vpp.git] / src / vnet / adj / adj_nbr.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_nbr.h>
17 #include <vnet/adj/adj_internal.h>
18 #include <vnet/ethernet/arp_packet.h>
19 #include <vnet/fib/fib_walk.h>
20
21 #include <vppinfra/bihash_24_8.h>
22
23 /*
24  * Vector Hash tables of neighbour (traditional) adjacencies
25  *  Key: interface(for the vector index), address (and its proto),
26  *       link-type/ether-type.
27  */
28 static BVT(clib_bihash) **adj_nbr_tables[FIB_PROTOCOL_MAX];
29
30 // FIXME SIZE APPROPRIATELY. ASK DAVEB.
31 #define ADJ_NBR_DEFAULT_HASH_NUM_BUCKETS (64 * 64)
32 #define ADJ_NBR_DEFAULT_HASH_MEMORY_SIZE (32<<20)
33
34
35 #define ADJ_NBR_SET_KEY(_key, _lt, _nh)         \
36 {                                               \
37     _key.key[0] = (_nh)->as_u64[0];             \
38     _key.key[1] = (_nh)->as_u64[1];             \
39     _key.key[2] = (_lt);                        \
40 }
41
42 #define ADJ_NBR_ITF_OK(_proto, _itf)                    \
43     (((_itf) < vec_len(adj_nbr_tables[_proto])) &&      \
44      (NULL != adj_nbr_tables[_proto][sw_if_index]))
45
46 static void
47 adj_nbr_insert (fib_protocol_t nh_proto,
48                 vnet_link_t link_type,
49                 const ip46_address_t *nh_addr,
50                 u32 sw_if_index,
51                 adj_index_t adj_index)
52 {
53     BVT(clib_bihash_kv) kv;
54
55     if (sw_if_index >= vec_len(adj_nbr_tables[nh_proto]))
56     {
57         vec_validate(adj_nbr_tables[nh_proto], sw_if_index);
58     }
59     if (NULL == adj_nbr_tables[nh_proto][sw_if_index])
60     {
61         adj_nbr_tables[nh_proto][sw_if_index] =
62             clib_mem_alloc_aligned(sizeof(BVT(clib_bihash)),
63                                    CLIB_CACHE_LINE_BYTES);
64         clib_memset(adj_nbr_tables[nh_proto][sw_if_index],
65                0,
66                sizeof(BVT(clib_bihash)));
67
68         BV(clib_bihash_init) (adj_nbr_tables[nh_proto][sw_if_index],
69                               "Adjacency Neighbour table",
70                               ADJ_NBR_DEFAULT_HASH_NUM_BUCKETS,
71                               ADJ_NBR_DEFAULT_HASH_MEMORY_SIZE);
72     }
73
74     ADJ_NBR_SET_KEY(kv, link_type, nh_addr);
75     kv.value = adj_index;
76
77     BV(clib_bihash_add_del) (adj_nbr_tables[nh_proto][sw_if_index], &kv, 1);
78 }
79
80 void
81 adj_nbr_remove (adj_index_t ai,
82                 fib_protocol_t nh_proto,
83                 vnet_link_t link_type,
84                 const ip46_address_t *nh_addr,
85                 u32 sw_if_index)
86 {
87     BVT(clib_bihash_kv) kv;
88
89     if (!ADJ_NBR_ITF_OK(nh_proto, sw_if_index))
90         return;
91
92     ADJ_NBR_SET_KEY(kv, link_type, nh_addr);
93     kv.value = ai;
94
95     BV(clib_bihash_add_del) (adj_nbr_tables[nh_proto][sw_if_index], &kv, 0);
96 }
97
98 adj_index_t
99 adj_nbr_find (fib_protocol_t nh_proto,
100               vnet_link_t link_type,
101               const ip46_address_t *nh_addr,
102               u32 sw_if_index)
103 {
104     BVT(clib_bihash_kv) kv;
105
106     ADJ_NBR_SET_KEY(kv, link_type, nh_addr);
107
108     if (!ADJ_NBR_ITF_OK(nh_proto, sw_if_index))
109         return (ADJ_INDEX_INVALID);
110
111     if (BV(clib_bihash_search)(adj_nbr_tables[nh_proto][sw_if_index],
112                                &kv, &kv) < 0)
113     {
114         return (ADJ_INDEX_INVALID);
115     }
116     else
117     {
118         return (kv.value);
119     }
120 }
121
122 static inline u32
123 adj_get_nd_node (fib_protocol_t proto)
124 {
125     switch (proto) {
126     case FIB_PROTOCOL_IP4:
127         return (ip4_arp_node.index);
128     case FIB_PROTOCOL_IP6:
129         return (ip6_discover_neighbor_node.index);
130     case FIB_PROTOCOL_MPLS:
131         break;
132     }
133     ASSERT(0);
134     return (ip4_arp_node.index);
135 }
136
137 /**
138  * @brief Check and set feature flags if o/p interface has any o/p features.
139  */
140 static void
141 adj_nbr_evaluate_feature (adj_index_t ai)
142 {
143     ip_adjacency_t *adj;
144     vnet_feature_main_t *fm = &feature_main;
145     i16 feature_count;
146     u8 arc_index;
147     u32 sw_if_index;
148
149     adj = adj_get(ai);
150
151     switch (adj->ia_link)
152     {
153     case VNET_LINK_IP4:
154         arc_index = ip4_main.lookup_main.output_feature_arc_index;
155         break;
156     case VNET_LINK_IP6:
157         arc_index = ip6_main.lookup_main.output_feature_arc_index;
158         break;
159     case VNET_LINK_MPLS:
160         arc_index = mpls_main.output_feature_arc_index;
161         break;
162     default:
163         return;
164     }
165
166     sw_if_index = adj->rewrite_header.sw_if_index;
167     if (vec_len(fm->feature_count_by_sw_if_index[arc_index]) > sw_if_index)
168     {
169         feature_count = fm->feature_count_by_sw_if_index[arc_index][sw_if_index];
170         if (feature_count > 0)
171             adj->rewrite_header.flags |= VNET_REWRITE_HAS_FEATURES;
172     }
173
174     return;
175 }
176
177 static ip_adjacency_t*
178 adj_nbr_alloc (fib_protocol_t nh_proto,
179                vnet_link_t link_type,
180                const ip46_address_t *nh_addr,
181                u32 sw_if_index)
182 {
183     ip_adjacency_t *adj;
184
185     adj = adj_alloc(nh_proto);
186
187     adj_nbr_insert(nh_proto, link_type, nh_addr,
188                    sw_if_index,
189                    adj_get_index(adj));
190
191     /*
192      * since we just added the ADJ we have no rewrite string for it,
193      * so its for ARP
194      */
195     adj->lookup_next_index = IP_LOOKUP_NEXT_ARP;
196     adj->sub_type.nbr.next_hop = *nh_addr;
197     adj->ia_link = link_type;
198     adj->ia_nh_proto = nh_proto;
199     adj->rewrite_header.sw_if_index = sw_if_index;
200     vnet_rewrite_update_mtu(vnet_get_main(), adj->ia_link,
201                             &adj->rewrite_header);
202
203     adj_nbr_evaluate_feature (adj_get_index(adj));
204     return (adj);
205 }
206
207 /*
208  * adj_nbr_add_or_lock
209  *
210  * Add an adjacency for the neighbour requested.
211  *
212  * The key for an adj is:
213  *   - the Next-hops protocol (i.e. v4 or v6)
214  *   - the address of the next-hop
215  *   - the interface the next-hop is reachable through
216  */
217 adj_index_t
218 adj_nbr_add_or_lock (fib_protocol_t nh_proto,
219                      vnet_link_t link_type,
220                      const ip46_address_t *nh_addr,
221                      u32 sw_if_index)
222 {
223     adj_index_t adj_index;
224
225     adj_index = adj_nbr_find(nh_proto, link_type, nh_addr, sw_if_index);
226
227     if (ADJ_INDEX_INVALID == adj_index)
228     {
229         ip_adjacency_t *adj;
230         vnet_main_t *vnm;
231
232         vnm = vnet_get_main();
233         adj = adj_nbr_alloc(nh_proto, link_type, nh_addr, sw_if_index);
234         adj_index = adj_get_index(adj);
235         adj_lock(adj_index);
236
237         if (ip46_address_is_equal(&ADJ_BCAST_ADDR, nh_addr))
238         {
239             adj->lookup_next_index = IP_LOOKUP_NEXT_BCAST;
240         }
241
242         vnet_rewrite_init(vnm, sw_if_index, link_type,
243                           adj_get_nd_node(nh_proto),
244                           vnet_tx_node_index_for_sw_interface(vnm, sw_if_index),
245                           &adj->rewrite_header);
246
247         /*
248          * we need a rewrite where the destination IP address is converted
249          * to the appropriate link-layer address. This is interface specific.
250          * So ask the interface to do it.
251          */
252         vnet_update_adjacency_for_sw_interface(vnm, sw_if_index, adj_index);
253     }
254     else
255     {
256         adj_lock(adj_index);
257     }
258
259     adj_delegate_adj_created(adj_get(adj_index));
260     return (adj_index);
261 }
262
263 adj_index_t
264 adj_nbr_add_or_lock_w_rewrite (fib_protocol_t nh_proto,
265                                vnet_link_t link_type,
266                                const ip46_address_t *nh_addr,
267                                u32 sw_if_index,
268                                u8 *rewrite)
269 {
270     adj_index_t adj_index;
271
272     adj_index = adj_nbr_find(nh_proto, link_type, nh_addr, sw_if_index);
273
274     if (ADJ_INDEX_INVALID == adj_index)
275     {
276         ip_adjacency_t *adj;
277
278         adj = adj_nbr_alloc(nh_proto, link_type, nh_addr, sw_if_index);
279         adj->rewrite_header.sw_if_index = sw_if_index;
280         adj_index = adj_get_index(adj);
281     }
282
283     adj_lock(adj_index);
284     adj_nbr_update_rewrite(adj_index,
285                            ADJ_NBR_REWRITE_FLAG_COMPLETE,
286                            rewrite);
287
288     adj_delegate_adj_created(adj_get(adj_index));
289
290     return (adj_index);
291 }
292
293 /**
294  * adj_nbr_update_rewrite
295  *
296  * Update the adjacency's rewrite string. A NULL string implies the
297  * rewrite is reset (i.e. when ARP/ND entry is gone).
298  * NB: the adj being updated may be handling traffic in the DP.
299  */
300 void
301 adj_nbr_update_rewrite (adj_index_t adj_index,
302                         adj_nbr_rewrite_flag_t flags,
303                         u8 *rewrite)
304 {
305     ip_adjacency_t *adj;
306
307     ASSERT(ADJ_INDEX_INVALID != adj_index);
308
309     adj = adj_get(adj_index);
310
311     if (flags & ADJ_NBR_REWRITE_FLAG_COMPLETE)
312     {
313         /*
314          * update the adj's rewrite string and build the arc
315          * from the rewrite node to the interface's TX node
316          */
317         adj_nbr_update_rewrite_internal(adj, IP_LOOKUP_NEXT_REWRITE,
318                                         adj_get_rewrite_node(adj->ia_link),
319                                         vnet_tx_node_index_for_sw_interface(
320                                             vnet_get_main(),
321                                             adj->rewrite_header.sw_if_index),
322                                         rewrite);
323     }
324     else
325     {
326         adj_nbr_update_rewrite_internal(adj, IP_LOOKUP_NEXT_ARP,
327                                         adj_get_nd_node(adj->ia_nh_proto),
328                                         vnet_tx_node_index_for_sw_interface(
329                                             vnet_get_main(),
330                                             adj->rewrite_header.sw_if_index),
331                                         rewrite);
332     }
333 }
334
335 /**
336  * adj_nbr_update_rewrite_internal
337  *
338  * Update the adjacency's rewrite string. A NULL string implies the
339  * rewrite is reset (i.e. when ARP/ND entry is gone).
340  * NB: the adj being updated may be handling traffic in the DP.
341  */
342 void
343 adj_nbr_update_rewrite_internal (ip_adjacency_t *adj,
344                                  ip_lookup_next_t adj_next_index,
345                                  u32 this_node,
346                                  u32 next_node,
347                                  u8 *rewrite)
348 {
349     ip_adjacency_t *walk_adj;
350     adj_index_t walk_ai, ai;
351     vlib_main_t * vm;
352     u32 old_next;
353     int do_walk;
354
355     vm = vlib_get_main();
356     old_next = adj->lookup_next_index;
357
358     ai = walk_ai = adj_get_index(adj);
359     if (VNET_LINK_MPLS == adj->ia_link)
360     {
361         /*
362          * The link type MPLS has no children in the control plane graph, it only
363          * has children in the data-plane graph. The backwalk is up the former.
364          * So we need to walk from its IP cousin.
365          */
366         walk_ai = adj_nbr_find(adj->ia_nh_proto,
367                                fib_proto_to_link(adj->ia_nh_proto),
368                                &adj->sub_type.nbr.next_hop,
369                                adj->rewrite_header.sw_if_index);
370     }
371
372     /*
373      * Don't call the walk re-entrantly
374      */
375     if (ADJ_INDEX_INVALID != walk_ai)
376     {
377         walk_adj = adj_get(walk_ai);
378         if (ADJ_FLAG_SYNC_WALK_ACTIVE & walk_adj->ia_flags)
379         {
380             do_walk = 0;
381         }
382         else
383         {
384             /*
385              * Prevent re-entrant walk of the same adj
386              */
387             walk_adj->ia_flags |= ADJ_FLAG_SYNC_WALK_ACTIVE;
388             do_walk = 1;
389         }
390     }
391     else
392     {
393         do_walk = 0;
394     }
395
396     /*
397      * lock the adjacencies that are affected by updates this walk will provoke.
398      * Since the aim of the walk is to update children to link to a different
399      * DPO, this adj will no longer be in use and its lock count will drop to 0.
400      * We don't want it to be deleted as part of this endeavour.
401      */
402     adj_lock(ai);
403     adj_lock(walk_ai);
404
405     /*
406      * Updating a rewrite string is not atomic;
407      *  - the rewrite string is too long to write in one instruction
408      *  - when swapping from incomplete to complete, we also need to update
409      *    the VLIB graph next-index of the adj.
410      * ideally we would only want to suspend forwarding via this adj whilst we
411      * do this, but we do not have that level of granularity - it's suspend all
412      * worker threads or nothing.
413      * The other choices are:
414      *  - to mark the adj down and back walk so child load-balances drop this adj
415      *    from the set.
416      *  - update the next_node index of this adj to point to error-drop
417      * both of which will mean for MAC change we will drop for this adj
418      * which is not acceptable. However, when the adj changes type (from
419      * complete to incomplete and vice-versa) the child DPOs, which have the
420      * VLIB graph next node index, will be sending packets to the wrong graph
421      * node. So from the options above, updating the next_node of the adj to
422      * be drop will work, but it relies on each graph node v4/v6/mpls, rewrite/
423      * arp/midchain always be valid w.r.t. a mis-match of adj type and node type
424      * (i.e. a rewrite adj in the arp node). This is not enforceable. Getting it
425      * wrong will lead to hard to find bugs since its a race condition. So we
426      * choose the more reliable method of updating the children to use the drop,
427      * then switching adj's type, then updating the children again. Did I mention
428      * that this doesn't happen often...
429      * So we need to distinguish between the two cases:
430      *  1 - mac change
431      *  2 - adj type change
432      */
433     if (do_walk &&
434         old_next != adj_next_index &&
435         ADJ_INDEX_INVALID != walk_ai)
436     {
437         /*
438          * the adj is changing type. we need to fix all children so that they
439          * stack momentarily on a drop, while the adj changes. If we don't do
440          * this  the children will send packets to a VLIB graph node that does
441          * not correspond to the adj's type - and it goes downhill from there.
442          */
443         fib_node_back_walk_ctx_t bw_ctx = {
444             .fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_DOWN,
445             /*
446              * force this walk to be synchronous. if we don't and a node in the graph
447              * (a heavily shared path-list) chooses to back-ground the walk (make it
448              * async) then it will pause and we will do the adj update below, before
449              * all the children are updated. not good.
450              */
451             .fnbw_flags = FIB_NODE_BW_FLAG_FORCE_SYNC,
452         };
453
454         fib_walk_sync(FIB_NODE_TYPE_ADJ, walk_ai, &bw_ctx);
455         /*
456          * fib_walk_sync may allocate a new adjacency and potentially cuase a
457          * realloc for adj_pool. When that happens, adj pointer is no longer
458          * valid here. We refresh the adj pointer accordingly.
459          */
460         adj = adj_get (ai);
461     }
462
463     /*
464      * If we are just updating the MAC string of the adj (which we also can't
465      * do atomically), then we need to stop packets switching through the adj.
466      * We can't do that on a per-adj basis, so it's all the packets.
467      * If we are updating the type, and we walked back to the children above,
468      * then this barrier serves to flush the queues/frames.
469      */
470     vlib_worker_thread_barrier_sync(vm);
471
472     adj->lookup_next_index = adj_next_index;
473     adj->ia_node_index = this_node;
474
475     if (NULL != rewrite)
476     {
477         /*
478          * new rewrite provided.
479          * fill in the adj's rewrite string, and build the VLIB graph arc.
480          */
481         vnet_rewrite_set_data_internal(&adj->rewrite_header,
482                                        sizeof(adj->rewrite_data),
483                                        rewrite,
484                                        vec_len(rewrite));
485         vec_free(rewrite);
486     }
487     else
488     {
489         vnet_rewrite_clear_data_internal(&adj->rewrite_header,
490                                          sizeof(adj->rewrite_data));
491     }
492     adj->rewrite_header.next_index = vlib_node_add_next(vlib_get_main(),
493                                                         this_node,
494                                                         next_node);
495
496     /*
497      * done with the rewrite update - let the workers loose.
498      */
499     vlib_worker_thread_barrier_release(vm);
500
501     if (do_walk &&
502         (old_next != adj->lookup_next_index) &&
503         (ADJ_INDEX_INVALID != walk_ai))
504     {
505         /*
506          * backwalk to the children so they can stack on the now updated
507          * adjacency
508          */
509         fib_node_back_walk_ctx_t bw_ctx = {
510             .fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE,
511         };
512
513         fib_walk_sync(FIB_NODE_TYPE_ADJ, walk_ai, &bw_ctx);
514     }
515     /*
516      * Prevent re-entrant walk of the same adj
517      */
518     if (do_walk)
519     {
520         walk_adj = adj_get(walk_ai);
521         walk_adj->ia_flags &= ~ADJ_FLAG_SYNC_WALK_ACTIVE;
522     }
523
524     adj_unlock(ai);
525     adj_unlock(walk_ai);
526 }
527
528 typedef struct adj_db_count_ctx_t_ {
529     u64 count;
530 } adj_db_count_ctx_t;
531
532 static int
533 adj_db_count (BVT(clib_bihash_kv) * kvp,
534               void *arg)
535 {
536     adj_db_count_ctx_t * ctx = arg;
537     ctx->count++;
538     return (BIHASH_WALK_CONTINUE);
539 }
540
541 u32
542 adj_nbr_db_size (void)
543 {
544     adj_db_count_ctx_t ctx = {
545         .count = 0,
546     };
547     fib_protocol_t proto;
548     u32 sw_if_index = 0;
549
550     for (proto = FIB_PROTOCOL_IP4; proto <= FIB_PROTOCOL_IP6; proto++)
551     {
552         vec_foreach_index(sw_if_index, adj_nbr_tables[proto])
553         {
554             if (NULL != adj_nbr_tables[proto][sw_if_index])
555             {
556                 BV(clib_bihash_foreach_key_value_pair) (
557                     adj_nbr_tables[proto][sw_if_index],
558                     adj_db_count,
559                     &ctx);
560             }
561         }
562     }
563     return (ctx.count);
564 }
565
566 /**
567  * @brief Context for a walk of the adjacency neighbour DB
568  */
569 typedef struct adj_walk_ctx_t_
570 {
571     adj_walk_cb_t awc_cb;
572     void *awc_ctx;
573 } adj_walk_ctx_t;
574
575 static int
576 adj_nbr_walk_cb (BVT(clib_bihash_kv) * kvp,
577                  void *arg)
578 {
579     adj_walk_ctx_t *ctx = arg;
580
581     // FIXME: can't stop early...
582     if (ADJ_WALK_RC_STOP == ctx->awc_cb(kvp->value, ctx->awc_ctx))
583         return (BIHASH_WALK_STOP);
584     return (BIHASH_WALK_CONTINUE);
585 }
586
587 void
588 adj_nbr_walk (u32 sw_if_index,
589               fib_protocol_t adj_nh_proto,
590               adj_walk_cb_t cb,
591               void *ctx)
592 {
593     if (!ADJ_NBR_ITF_OK(adj_nh_proto, sw_if_index))
594         return;
595
596     adj_walk_ctx_t awc = {
597         .awc_ctx = ctx,
598         .awc_cb = cb,
599     };
600
601     BV(clib_bihash_foreach_key_value_pair) (
602         adj_nbr_tables[adj_nh_proto][sw_if_index],
603         adj_nbr_walk_cb,
604         &awc);
605 }
606
607 /**
608  * @brief Walk adjacencies on a link with a given v4 next-hop.
609  * that is visit the adjacencies with different link types.
610  */
611 void
612 adj_nbr_walk_nh4 (u32 sw_if_index,
613                  const ip4_address_t *addr,
614                  adj_walk_cb_t cb,
615                  void *ctx)
616 {
617     if (!ADJ_NBR_ITF_OK(FIB_PROTOCOL_IP4, sw_if_index))
618         return;
619
620     ip46_address_t nh = {
621         .ip4 = *addr,
622     };
623     vnet_link_t linkt;
624     adj_index_t ai;
625
626     FOR_EACH_VNET_LINK(linkt)
627     {
628         ai = adj_nbr_find (FIB_PROTOCOL_IP4, linkt, &nh, sw_if_index);
629
630         if (INDEX_INVALID != ai)
631             cb(ai, ctx);
632     }
633 }
634
635 /**
636  * @brief Walk adjacencies on a link with a given v6 next-hop.
637  * that is visit the adjacencies with different link types.
638  */
639 void
640 adj_nbr_walk_nh6 (u32 sw_if_index,
641                  const ip6_address_t *addr,
642                  adj_walk_cb_t cb,
643                  void *ctx)
644 {
645     if (!ADJ_NBR_ITF_OK(FIB_PROTOCOL_IP6, sw_if_index))
646         return;
647
648     ip46_address_t nh = {
649         .ip6 = *addr,
650     };
651     vnet_link_t linkt;
652     adj_index_t ai;
653
654     FOR_EACH_VNET_LINK(linkt)
655     {
656         ai = adj_nbr_find (FIB_PROTOCOL_IP6, linkt, &nh, sw_if_index);
657
658         if (INDEX_INVALID != ai)
659             cb(ai, ctx);
660     }
661 }
662
663 /**
664  * @brief Walk adjacencies on a link with a given next-hop.
665  * that is visit the adjacencies with different link types.
666  */
667 void
668 adj_nbr_walk_nh (u32 sw_if_index,
669                  fib_protocol_t adj_nh_proto,
670                  const ip46_address_t *nh,
671                  adj_walk_cb_t cb,
672                  void *ctx)
673 {
674     if (!ADJ_NBR_ITF_OK(adj_nh_proto, sw_if_index))
675         return;
676
677     switch (adj_nh_proto)
678     {
679     case FIB_PROTOCOL_IP4:
680         adj_nbr_walk_nh4(sw_if_index, &nh->ip4, cb, ctx);
681         break; 
682     case FIB_PROTOCOL_IP6:
683         adj_nbr_walk_nh6(sw_if_index, &nh->ip6, cb, ctx);
684         break;
685     case FIB_PROTOCOL_MPLS:
686         ASSERT(0);
687         break;
688     }
689 }
690
691 /**
692  * Flags associated with the interface state walks
693  */
694 typedef enum adj_nbr_interface_flags_t_
695 {
696     ADJ_NBR_INTERFACE_UP = (1 << 0),
697 } adj_nbr_interface_flags_t;
698
699 /**
700  * Context for the state change walk of the DB
701  */
702 typedef struct adj_nbr_interface_state_change_ctx_t_
703 {
704     /**
705      * Flags on the interface
706      */
707     adj_nbr_interface_flags_t flags;
708 } adj_nbr_interface_state_change_ctx_t;
709
710 static adj_walk_rc_t
711 adj_nbr_interface_state_change_one (adj_index_t ai,
712                                     void *arg)
713 {
714     /*
715      * Back walk the graph to inform the forwarding entries
716      * that this interface state has changed. Do this synchronously
717      * since this is the walk that provides convergence
718      */
719     adj_nbr_interface_state_change_ctx_t *ctx = arg;
720     fib_node_back_walk_ctx_t bw_ctx = {
721         .fnbw_reason = ((ctx->flags & ADJ_NBR_INTERFACE_UP) ?
722                         FIB_NODE_BW_REASON_FLAG_INTERFACE_UP :
723                         FIB_NODE_BW_REASON_FLAG_INTERFACE_DOWN),
724         /*
725          * the force sync applies only as far as the first fib_entry.
726          * And it's the fib_entry's we need to converge away from
727          * the adjacencies on the now down link
728          */
729         .fnbw_flags = (!(ctx->flags & ADJ_NBR_INTERFACE_UP) ?
730                        FIB_NODE_BW_FLAG_FORCE_SYNC :
731                        FIB_NODE_BW_FLAG_NONE),
732     };
733     ip_adjacency_t *adj;
734
735     adj = adj_get(ai);
736
737     adj->ia_flags |= ADJ_FLAG_SYNC_WALK_ACTIVE;
738     fib_walk_sync(FIB_NODE_TYPE_ADJ, ai, &bw_ctx);
739     adj->ia_flags &= ~ADJ_FLAG_SYNC_WALK_ACTIVE;
740
741     return (ADJ_WALK_RC_CONTINUE);
742 }
743
744 /**
745  * @brief Registered function for SW interface state changes
746  */
747 static clib_error_t *
748 adj_nbr_sw_interface_state_change (vnet_main_t * vnm,
749                                    u32 sw_if_index,
750                                    u32 flags)
751 {
752     fib_protocol_t proto;
753
754     /*
755      * walk each adj on the interface and trigger a walk from that adj
756      */
757     for (proto = FIB_PROTOCOL_IP4; proto <= FIB_PROTOCOL_IP6; proto++)
758     {
759         adj_nbr_interface_state_change_ctx_t ctx = {
760             .flags = ((flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ?
761                       ADJ_NBR_INTERFACE_UP :
762                       0),
763         };
764
765         adj_nbr_walk(sw_if_index, proto,
766                      adj_nbr_interface_state_change_one,
767                      &ctx);
768     }
769
770     return (NULL);
771 }
772
773 VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION_PRIO(
774     adj_nbr_sw_interface_state_change,
775     VNET_ITF_FUNC_PRIORITY_HIGH);
776
777 /**
778  * @brief Invoked on each SW interface of a HW interface when the
779  * HW interface state changes
780  */
781 static walk_rc_t
782 adj_nbr_hw_sw_interface_state_change (vnet_main_t * vnm,
783                                       u32 sw_if_index,
784                                       void *arg)
785 {
786     adj_nbr_interface_state_change_ctx_t *ctx = arg;
787     fib_protocol_t proto;
788
789     /*
790      * walk each adj on the interface and trigger a walk from that adj
791      */
792     for (proto = FIB_PROTOCOL_IP4; proto <= FIB_PROTOCOL_IP6; proto++)
793     {
794         adj_nbr_walk(sw_if_index, proto,
795                      adj_nbr_interface_state_change_one,
796                      ctx);
797     }
798     return (WALK_CONTINUE);
799 }
800
801 /**
802  * @brief Registered callback for HW interface state changes
803  */
804 static clib_error_t *
805 adj_nbr_hw_interface_state_change (vnet_main_t * vnm,
806                                    u32 hw_if_index,
807                                    u32 flags)
808 {
809     /*
810      * walk SW interface on the HW
811      */
812     adj_nbr_interface_state_change_ctx_t ctx = {
813         .flags = ((flags & VNET_HW_INTERFACE_FLAG_LINK_UP) ?
814                   ADJ_NBR_INTERFACE_UP :
815                   0),
816     };
817
818     vnet_hw_interface_walk_sw(vnm, hw_if_index,
819                               adj_nbr_hw_sw_interface_state_change,
820                               &ctx);
821
822     return (NULL);
823 }
824
825 VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION_PRIO(
826     adj_nbr_hw_interface_state_change,
827     VNET_ITF_FUNC_PRIORITY_HIGH);
828
829 static adj_walk_rc_t
830 adj_nbr_interface_delete_one (adj_index_t ai,
831                               void *arg)
832 {
833     /*
834      * Back walk the graph to inform the forwarding entries
835      * that this interface has been deleted.
836      */
837     fib_node_back_walk_ctx_t bw_ctx = {
838         .fnbw_reason = FIB_NODE_BW_REASON_FLAG_INTERFACE_DELETE,
839     };
840     ip_adjacency_t *adj;
841
842     adj_lock(ai);
843
844     adj = adj_get(ai);
845
846     adj->ia_flags |= ADJ_FLAG_SYNC_WALK_ACTIVE;
847     fib_walk_sync(FIB_NODE_TYPE_ADJ, ai, &bw_ctx);
848     adj->ia_flags &= ~ADJ_FLAG_SYNC_WALK_ACTIVE;
849
850     adj_unlock(ai);
851     return (ADJ_WALK_RC_CONTINUE);
852 }
853
854 /**
855  * adj_nbr_interface_add_del
856  *
857  * Registered to receive interface Add and delete notifications
858  */
859 static clib_error_t *
860 adj_nbr_interface_add_del (vnet_main_t * vnm,
861                            u32 sw_if_index,
862                            u32 is_add)
863 {
864     fib_protocol_t proto;
865
866     if (is_add)
867     {
868         /*
869          * not interested in interface additions. we will not back walk
870          * to resolve paths through newly added interfaces. Why? The control
871          * plane should have the brains to add interfaces first, then routes.
872          * So the case where there are paths with a interface that matches
873          * one just created is the case where the path resolved through an
874          * interface that was deleted, and still has not been removed. The
875          * new interface added, is NO GUARANTEE that the interface being
876          * added now, even though it may have the same sw_if_index, is the
877          * same interface that the path needs. So tough!
878          * If the control plane wants these routes to resolve it needs to
879          * remove and add them again.
880          */
881         return (NULL);
882     }
883
884     for (proto = FIB_PROTOCOL_IP4; proto <= FIB_PROTOCOL_IP6; proto++)
885     {
886         adj_nbr_walk(sw_if_index, proto,
887                      adj_nbr_interface_delete_one,
888                      NULL);
889     }
890
891     return (NULL);
892    
893 }
894
895 VNET_SW_INTERFACE_ADD_DEL_FUNCTION(adj_nbr_interface_add_del);
896
897
898 static adj_walk_rc_t
899 adj_nbr_show_one (adj_index_t ai,
900                   void *arg)
901 {
902     vlib_cli_output (arg, "[@%d]  %U",
903                      ai,
904                      format_ip_adjacency, ai,
905                      FORMAT_IP_ADJACENCY_NONE);
906
907     return (ADJ_WALK_RC_CONTINUE);
908 }
909
910 static clib_error_t *
911 adj_nbr_show (vlib_main_t * vm,
912               unformat_input_t * input,
913               vlib_cli_command_t * cmd)
914 {
915     adj_index_t ai = ADJ_INDEX_INVALID;
916     ip46_address_t nh = ip46_address_initializer;
917     u32 sw_if_index = ~0;
918
919     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
920     {
921         if (unformat (input, "%U",
922                       unformat_vnet_sw_interface, vnet_get_main(),
923                       &sw_if_index))
924             ;
925         else if (unformat (input, "%U",
926                            unformat_ip46_address, &nh, IP46_TYPE_ANY))
927             ;
928         else if (unformat (input, "%d", &ai))
929             ;
930         else
931             break;
932     }
933
934     if (ADJ_INDEX_INVALID != ai)
935     {
936         vlib_cli_output (vm, "[@%d] %U",
937                          ai,
938                          format_ip_adjacency, ai,
939                          FORMAT_IP_ADJACENCY_DETAIL);
940     }
941     else if (~0 != sw_if_index)
942     {
943         fib_protocol_t proto;
944
945         if (ip46_address_is_zero(&nh))
946         {
947             for (proto = FIB_PROTOCOL_IP4; proto <= FIB_PROTOCOL_IP6; proto++)
948             {
949                 adj_nbr_walk(sw_if_index, proto,
950                              adj_nbr_show_one,
951                              vm);
952             }
953         }
954         else
955         {
956             proto = (ip46_address_is_ip4(&nh) ?
957                      FIB_PROTOCOL_IP4 :
958                      FIB_PROTOCOL_IP6);
959             adj_nbr_walk_nh(sw_if_index, proto, &nh,
960                             adj_nbr_show_one,
961                             vm);
962         }
963     }
964     else
965     {
966         fib_protocol_t proto;
967
968         for (proto = FIB_PROTOCOL_IP4; proto <= FIB_PROTOCOL_IP6; proto++)
969         {
970             vec_foreach_index(sw_if_index, adj_nbr_tables[proto])
971             {
972                 adj_nbr_walk(sw_if_index, proto,
973                              adj_nbr_show_one,
974                              vm);
975             }
976         }
977     }
978
979     return 0;
980 }
981
982 /*?
983  * Show all neighbour adjacencies.
984  * @cliexpar
985  * @cliexstart{sh adj nbr}
986  * [@2] ipv4 via 1.0.0.2 loop0: IP4: 00:00:22:aa:bb:cc -> 00:00:11:aa:bb:cc
987  * [@3] mpls via 1.0.0.2 loop0: MPLS_UNICAST: 00:00:22:aa:bb:cc -> 00:00:11:aa:bb:cc
988  * [@4] ipv4 via 1.0.0.3 loop0: IP4: 00:00:22:aa:bb:cc -> 00:00:11:aa:bb:cc
989  * [@5] mpls via 1.0.0.3 loop0: MPLS_UNICAST: 00:00:22:aa:bb:cc -> 00:00:11:aa:bb:cc
990  * @cliexend
991  ?*/
992 VLIB_CLI_COMMAND (ip4_show_fib_command, static) = {
993     .path = "show adj nbr",
994     .short_help = "show adj nbr [<adj_index>] [interface]",
995     .function = adj_nbr_show,
996 };
997
998 u8*
999 format_adj_nbr_incomplete (u8* s, va_list *ap)
1000 {
1001     index_t index = va_arg(*ap, index_t);
1002     CLIB_UNUSED(u32 indent) = va_arg(*ap, u32);
1003     vnet_main_t * vnm = vnet_get_main();
1004     ip_adjacency_t * adj = adj_get(index);
1005
1006     s = format (s, "arp-%U", format_vnet_link, adj->ia_link);
1007     s = format (s, ": via %U",
1008                 format_ip46_address, &adj->sub_type.nbr.next_hop,
1009                 adj_proto_to_46(adj->ia_nh_proto));
1010     s = format (s, " %U",
1011                 format_vnet_sw_if_index_name,
1012                 vnm, adj->rewrite_header.sw_if_index);
1013
1014     return (s);
1015 }
1016
1017 u8*
1018 format_adj_nbr (u8* s, va_list *ap)
1019 {
1020     index_t index = va_arg(*ap, index_t);
1021     CLIB_UNUSED(u32 indent) = va_arg(*ap, u32);
1022     ip_adjacency_t * adj = adj_get(index);
1023
1024     s = format (s, "%U", format_vnet_link, adj->ia_link);
1025     s = format (s, " via %U ",
1026                 format_ip46_address, &adj->sub_type.nbr.next_hop,
1027                 adj_proto_to_46(adj->ia_nh_proto));
1028     s = format (s, "%U",
1029                 format_vnet_rewrite,
1030                 &adj->rewrite_header, sizeof (adj->rewrite_data), 0);
1031
1032     return (s);
1033 }
1034
1035 static void
1036 adj_dpo_lock (dpo_id_t *dpo)
1037 {
1038     adj_lock(dpo->dpoi_index);
1039 }
1040 static void
1041 adj_dpo_unlock (dpo_id_t *dpo)
1042 {
1043     adj_unlock(dpo->dpoi_index);
1044 }
1045
1046 static void
1047 adj_mem_show (void)
1048 {
1049     fib_show_memory_usage("Adjacency",
1050                           pool_elts(adj_pool),
1051                           pool_len(adj_pool),
1052                           sizeof(ip_adjacency_t));
1053 }
1054
1055 const static dpo_vft_t adj_nbr_dpo_vft = {
1056     .dv_lock = adj_dpo_lock,
1057     .dv_unlock = adj_dpo_unlock,
1058     .dv_format = format_adj_nbr,
1059     .dv_mem_show = adj_mem_show,
1060     .dv_get_urpf = adj_dpo_get_urpf,
1061 };
1062 const static dpo_vft_t adj_nbr_incompl_dpo_vft = {
1063     .dv_lock = adj_dpo_lock,
1064     .dv_unlock = adj_dpo_unlock,
1065     .dv_format = format_adj_nbr_incomplete,
1066     .dv_get_urpf = adj_dpo_get_urpf,
1067 };
1068
1069 /**
1070  * @brief The per-protocol VLIB graph nodes that are assigned to an adjacency
1071  *        object.
1072  *
1073  * this means that these graph nodes are ones from which a nbr is the
1074  * parent object in the DPO-graph.
1075  */
1076 const static char* const nbr_ip4_nodes[] =
1077 {
1078     "ip4-rewrite",
1079     NULL,
1080 };
1081 const static char* const nbr_ip6_nodes[] =
1082 {
1083     "ip6-rewrite",
1084     NULL,
1085 };
1086 const static char* const nbr_mpls_nodes[] =
1087 {
1088     "mpls-output",
1089     NULL,
1090 };
1091 const static char* const nbr_ethernet_nodes[] =
1092 {
1093     "adj-l2-rewrite",
1094     NULL,
1095 };
1096 const static char* const * const nbr_nodes[DPO_PROTO_NUM] =
1097 {
1098     [DPO_PROTO_IP4]  = nbr_ip4_nodes,
1099     [DPO_PROTO_IP6]  = nbr_ip6_nodes,
1100     [DPO_PROTO_MPLS] = nbr_mpls_nodes,
1101     [DPO_PROTO_ETHERNET] = nbr_ethernet_nodes,
1102 };
1103
1104 const static char* const nbr_incomplete_ip4_nodes[] =
1105 {
1106     "ip4-arp",
1107     NULL,
1108 };
1109 const static char* const nbr_incomplete_ip6_nodes[] =
1110 {
1111     "ip6-discover-neighbor",
1112     NULL,
1113 };
1114 const static char* const nbr_incomplete_mpls_nodes[] =
1115 {
1116     "mpls-adj-incomplete",
1117     NULL,
1118 };
1119
1120 const static char* const * const nbr_incomplete_nodes[DPO_PROTO_NUM] =
1121 {
1122     [DPO_PROTO_IP4]  = nbr_incomplete_ip4_nodes,
1123     [DPO_PROTO_IP6]  = nbr_incomplete_ip6_nodes,
1124     [DPO_PROTO_MPLS] = nbr_incomplete_mpls_nodes,
1125 };
1126
1127 void
1128 adj_nbr_module_init (void)
1129 {
1130     dpo_register(DPO_ADJACENCY,
1131                  &adj_nbr_dpo_vft,
1132                  nbr_nodes);
1133     dpo_register(DPO_ADJACENCY_INCOMPLETE,
1134                  &adj_nbr_incompl_dpo_vft,
1135                  nbr_incomplete_nodes);
1136 }