blob: b3a027b7af451251ea93607f281ade9b15f78654 [file] [log] [blame]
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001/*
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/*
22 * Vector Hash tables of neighbour (traditional) adjacencies
23 * Key: interface(for the vector index), address (and its proto),
24 * link-type/ether-type.
25 */
Neale Ranns20aec3d2020-05-25 09:09:36 +000026static uword **adj_nbr_tables[FIB_PROTOCOL_IP_MAX];
Neale Ranns0bfe5d82016-08-25 15:29:12 +010027
Neale Ranns20aec3d2020-05-25 09:09:36 +000028typedef struct adj_nbr_key_t_
29{
30 ip46_address_t ank_ip;
31 u64 ank_linkt;
32} adj_nbr_key_t;
Neale Ranns0bfe5d82016-08-25 15:29:12 +010033
34#define ADJ_NBR_SET_KEY(_key, _lt, _nh) \
35{ \
Neale Ranns20aec3d2020-05-25 09:09:36 +000036 ip46_address_copy(&(_key).ank_ip, (_nh)); \
37 _key.ank_linkt = (_lt); \
Neale Ranns0bfe5d82016-08-25 15:29:12 +010038}
39
40#define ADJ_NBR_ITF_OK(_proto, _itf) \
41 (((_itf) < vec_len(adj_nbr_tables[_proto])) && \
yedgf6698d22020-08-29 14:12:20 +080042 (NULL != adj_nbr_tables[_proto][(_itf)]))
Neale Ranns0bfe5d82016-08-25 15:29:12 +010043
Benoît Gannefaec38f2020-08-13 11:16:56 +020044#define ADJ_NBR_ASSERT_NH_PROTO(nh_proto, err) \
45 do { \
46 ASSERT (nh_proto < FIB_PROTOCOL_IP_MAX); \
47 const fib_protocol_t nh_proto__ = (nh_proto); \
48 if (nh_proto__ >= FIB_PROTOCOL_IP_MAX) \
49 { \
50 clib_warning ("BUG: protocol %d > %d\n", \
51 (int)nh_proto__, \
52 FIB_PROTOCOL_IP_MAX); \
53 return err; \
54 } \
55 } while (0)
56
Neale Ranns0bfe5d82016-08-25 15:29:12 +010057static void
58adj_nbr_insert (fib_protocol_t nh_proto,
Neale Ranns924d03a2016-10-19 08:25:46 +010059 vnet_link_t link_type,
Neale Ranns0bfe5d82016-08-25 15:29:12 +010060 const ip46_address_t *nh_addr,
61 u32 sw_if_index,
62 adj_index_t adj_index)
63{
Neale Ranns20aec3d2020-05-25 09:09:36 +000064 adj_nbr_key_t kv;
Neale Ranns0bfe5d82016-08-25 15:29:12 +010065
Benoît Gannefaec38f2020-08-13 11:16:56 +020066 ADJ_NBR_ASSERT_NH_PROTO (nh_proto,);
67
Neale Ranns0bfe5d82016-08-25 15:29:12 +010068 if (sw_if_index >= vec_len(adj_nbr_tables[nh_proto]))
69 {
70 vec_validate(adj_nbr_tables[nh_proto], sw_if_index);
71 }
72 if (NULL == adj_nbr_tables[nh_proto][sw_if_index])
73 {
74 adj_nbr_tables[nh_proto][sw_if_index] =
Neale Ranns20aec3d2020-05-25 09:09:36 +000075 hash_create_mem(0, sizeof(adj_nbr_key_t), sizeof(adj_index_t));
Neale Ranns0bfe5d82016-08-25 15:29:12 +010076 }
77
78 ADJ_NBR_SET_KEY(kv, link_type, nh_addr);
Neale Ranns0bfe5d82016-08-25 15:29:12 +010079
Neale Ranns20aec3d2020-05-25 09:09:36 +000080 hash_set_mem_alloc (&adj_nbr_tables[nh_proto][sw_if_index],
81 &kv, adj_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +010082}
83
84void
Neale Ranns177bbdc2016-11-15 09:46:51 +000085adj_nbr_remove (adj_index_t ai,
86 fib_protocol_t nh_proto,
Neale Ranns924d03a2016-10-19 08:25:46 +010087 vnet_link_t link_type,
Neale Ranns0bfe5d82016-08-25 15:29:12 +010088 const ip46_address_t *nh_addr,
89 u32 sw_if_index)
90{
Neale Ranns20aec3d2020-05-25 09:09:36 +000091 adj_nbr_key_t kv;
Neale Ranns0bfe5d82016-08-25 15:29:12 +010092
Benoît Gannefaec38f2020-08-13 11:16:56 +020093 ADJ_NBR_ASSERT_NH_PROTO (nh_proto,);
94
Neale Ranns0bfe5d82016-08-25 15:29:12 +010095 if (!ADJ_NBR_ITF_OK(nh_proto, sw_if_index))
96 return;
97
98 ADJ_NBR_SET_KEY(kv, link_type, nh_addr);
99
Neale Ranns20aec3d2020-05-25 09:09:36 +0000100 hash_unset_mem_free(&adj_nbr_tables[nh_proto][sw_if_index], &kv);
101
102 if (0 == hash_elts(adj_nbr_tables[nh_proto][sw_if_index]))
103 {
104 hash_free(adj_nbr_tables[nh_proto][sw_if_index]);
105 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100106}
107
Neale Ranns6fdcc3d2021-10-08 07:30:47 +0000108typedef struct adj_nbr_get_n_adjs_walk_ctx_t_
109{
110 vnet_link_t linkt;
111 u32 count;
112} adj_nbr_get_n_adjs_walk_ctx_t;
113
114static adj_walk_rc_t
115adj_nbr_get_n_adjs_walk (adj_index_t ai,
116 void *data)
117{
118 adj_nbr_get_n_adjs_walk_ctx_t *ctx = data;
119 const ip_adjacency_t *adj;
120
121 adj = adj_get(ai);
122
123 if (ctx->linkt == adj->ia_link)
124 ctx->count++;
125
126 return (ADJ_WALK_RC_CONTINUE);
127}
128
129u32
130adj_nbr_get_n_adjs (vnet_link_t link_type, u32 sw_if_index)
131{
132 adj_nbr_get_n_adjs_walk_ctx_t ctx = {
133 .linkt = link_type,
134 };
135 fib_protocol_t fproto;
136
137 FOR_EACH_FIB_IP_PROTOCOL(fproto)
138 {
139 adj_nbr_walk (sw_if_index,
140 fproto,
141 adj_nbr_get_n_adjs_walk,
142 &ctx);
143 }
144
145 return (ctx.count);
146}
147
Florin Corasf9d05682018-04-26 08:26:52 -0700148adj_index_t
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100149adj_nbr_find (fib_protocol_t nh_proto,
Neale Ranns924d03a2016-10-19 08:25:46 +0100150 vnet_link_t link_type,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100151 const ip46_address_t *nh_addr,
152 u32 sw_if_index)
153{
Neale Ranns20aec3d2020-05-25 09:09:36 +0000154 adj_nbr_key_t kv;
155 uword *p;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100156
Benoît Gannefaec38f2020-08-13 11:16:56 +0200157 ADJ_NBR_ASSERT_NH_PROTO (nh_proto, ADJ_INDEX_INVALID);
158
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100159 ADJ_NBR_SET_KEY(kv, link_type, nh_addr);
160
161 if (!ADJ_NBR_ITF_OK(nh_proto, sw_if_index))
162 return (ADJ_INDEX_INVALID);
163
Neale Ranns20aec3d2020-05-25 09:09:36 +0000164 p = hash_get_mem(adj_nbr_tables[nh_proto][sw_if_index], &kv);
165
166 if (p)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100167 {
Neale Ranns20aec3d2020-05-25 09:09:36 +0000168 return (p[0]);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100169 }
Neale Ranns20aec3d2020-05-25 09:09:36 +0000170 return (ADJ_INDEX_INVALID);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100171}
172
Neale Rannsb80c5362016-10-08 13:03:40 +0100173static inline u32
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100174adj_get_nd_node (fib_protocol_t proto)
175{
176 switch (proto) {
177 case FIB_PROTOCOL_IP4:
Neale Rannsb80c5362016-10-08 13:03:40 +0100178 return (ip4_arp_node.index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100179 case FIB_PROTOCOL_IP6:
Neale Rannsb80c5362016-10-08 13:03:40 +0100180 return (ip6_discover_neighbor_node.index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100181 case FIB_PROTOCOL_MPLS:
182 break;
183 }
184 ASSERT(0);
Neale Rannsb80c5362016-10-08 13:03:40 +0100185 return (ip4_arp_node.index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100186}
187
AkshayaNadahalli17f5f602017-03-27 14:47:41 +0530188/**
189 * @brief Check and set feature flags if o/p interface has any o/p features.
190 */
191static void
192adj_nbr_evaluate_feature (adj_index_t ai)
193{
194 ip_adjacency_t *adj;
195 vnet_feature_main_t *fm = &feature_main;
196 i16 feature_count;
197 u8 arc_index;
198 u32 sw_if_index;
199
200 adj = adj_get(ai);
201
202 switch (adj->ia_link)
203 {
204 case VNET_LINK_IP4:
205 arc_index = ip4_main.lookup_main.output_feature_arc_index;
206 break;
207 case VNET_LINK_IP6:
208 arc_index = ip6_main.lookup_main.output_feature_arc_index;
209 break;
210 case VNET_LINK_MPLS:
211 arc_index = mpls_main.output_feature_arc_index;
212 break;
213 default:
214 return;
215 }
216
217 sw_if_index = adj->rewrite_header.sw_if_index;
AkshayaNadahalli98ab0912017-03-27 17:21:05 +0000218 if (vec_len(fm->feature_count_by_sw_if_index[arc_index]) > sw_if_index)
219 {
220 feature_count = fm->feature_count_by_sw_if_index[arc_index][sw_if_index];
221 if (feature_count > 0)
Neale Ranns4ec36c52020-03-31 09:21:29 -0400222 {
223 vnet_feature_config_main_t *cm;
AkshayaNadahalli17f5f602017-03-27 14:47:41 +0530224
Neale Ranns4ec36c52020-03-31 09:21:29 -0400225 adj->rewrite_header.flags |= VNET_REWRITE_HAS_FEATURES;
226 cm = &fm->feature_config_mains[arc_index];
227
228 adj->ia_cfg_index = vec_elt (cm->config_index_by_sw_if_index,
229 sw_if_index);
230 }
231 }
AkshayaNadahalli17f5f602017-03-27 14:47:41 +0530232 return;
233}
234
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100235static ip_adjacency_t*
236adj_nbr_alloc (fib_protocol_t nh_proto,
Neale Ranns924d03a2016-10-19 08:25:46 +0100237 vnet_link_t link_type,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100238 const ip46_address_t *nh_addr,
239 u32 sw_if_index)
240{
241 ip_adjacency_t *adj;
242
243 adj = adj_alloc(nh_proto);
244
245 adj_nbr_insert(nh_proto, link_type, nh_addr,
246 sw_if_index,
Neale Ranns6c3ebcc2016-10-02 21:20:15 +0100247 adj_get_index(adj));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100248
249 /*
250 * since we just added the ADJ we have no rewrite string for it,
251 * so its for ARP
252 */
253 adj->lookup_next_index = IP_LOOKUP_NEXT_ARP;
254 adj->sub_type.nbr.next_hop = *nh_addr;
255 adj->ia_link = link_type;
256 adj->ia_nh_proto = nh_proto;
Neale Rannsb80c5362016-10-08 13:03:40 +0100257 adj->rewrite_header.sw_if_index = sw_if_index;
Neale Ranns1bce5a92018-10-30 06:34:25 -0700258 vnet_rewrite_update_mtu(vnet_get_main(), adj->ia_link,
259 &adj->rewrite_header);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100260
AkshayaNadahalli17f5f602017-03-27 14:47:41 +0530261 adj_nbr_evaluate_feature (adj_get_index(adj));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100262 return (adj);
263}
264
Neale Ranns8f5fef22020-12-21 08:29:34 +0000265void
266adj_nbr_set_mtu (adj_index_t adj_index, u16 mtu)
267{
268 ip_adjacency_t *adj;
269
270 ASSERT(ADJ_INDEX_INVALID != adj_index);
271
272 adj = adj_get(adj_index);
273
274 if (0 == mtu)
275 vnet_rewrite_update_mtu(vnet_get_main(), adj->ia_link,
276 &adj->rewrite_header);
277 else
278 {
279 vnet_rewrite_update_mtu(vnet_get_main(), adj->ia_link,
280 &adj->rewrite_header);
281 adj->rewrite_header.max_l3_packet_bytes =
282 clib_min (adj->rewrite_header.max_l3_packet_bytes, mtu);
283 }
284}
285
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100286/*
Neale Ranns32e1c012016-11-22 17:07:28 +0000287 * adj_nbr_add_or_lock
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100288 *
289 * Add an adjacency for the neighbour requested.
290 *
291 * The key for an adj is:
292 * - the Next-hops protocol (i.e. v4 or v6)
293 * - the address of the next-hop
294 * - the interface the next-hop is reachable through
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100295 */
296adj_index_t
297adj_nbr_add_or_lock (fib_protocol_t nh_proto,
Neale Ranns924d03a2016-10-19 08:25:46 +0100298 vnet_link_t link_type,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100299 const ip46_address_t *nh_addr,
300 u32 sw_if_index)
301{
302 adj_index_t adj_index;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100303
304 adj_index = adj_nbr_find(nh_proto, link_type, nh_addr, sw_if_index);
305
306 if (ADJ_INDEX_INVALID == adj_index)
307 {
Neale Ranns77cfc012019-12-15 22:26:37 +0000308 ip_adjacency_t *adj;
Neale Rannsb80c5362016-10-08 13:03:40 +0100309 vnet_main_t *vnm;
310
311 vnm = vnet_get_main();
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100312 adj = adj_nbr_alloc(nh_proto, link_type, nh_addr, sw_if_index);
Neale Rannsb80c5362016-10-08 13:03:40 +0100313 adj_index = adj_get_index(adj);
314 adj_lock(adj_index);
315
Neale Ranns1855b8e2018-07-11 10:31:26 -0700316 if (ip46_address_is_equal(&ADJ_BCAST_ADDR, nh_addr))
317 {
318 adj->lookup_next_index = IP_LOOKUP_NEXT_BCAST;
319 }
320
Ole Troand7231612018-06-07 10:17:57 +0200321 vnet_rewrite_init(vnm, sw_if_index, link_type,
Neale Rannsb80c5362016-10-08 13:03:40 +0100322 adj_get_nd_node(nh_proto),
323 vnet_tx_node_index_for_sw_interface(vnm, sw_if_index),
324 &adj->rewrite_header);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100325
326 /*
Neale Rannsb80c5362016-10-08 13:03:40 +0100327 * we need a rewrite where the destination IP address is converted
328 * to the appropriate link-layer address. This is interface specific.
329 * So ask the interface to do it.
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100330 */
Neale Rannsb80c5362016-10-08 13:03:40 +0100331 vnet_update_adjacency_for_sw_interface(vnm, sw_if_index, adj_index);
Neale Ranns8f5fef22020-12-21 08:29:34 +0000332 adj_delegate_adj_created(adj_get(adj_index));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100333 }
334 else
335 {
Neale Rannsb80c5362016-10-08 13:03:40 +0100336 adj_lock(adj_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100337 }
338
Neale Rannsb80c5362016-10-08 13:03:40 +0100339 return (adj_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100340}
341
342adj_index_t
343adj_nbr_add_or_lock_w_rewrite (fib_protocol_t nh_proto,
Neale Ranns924d03a2016-10-19 08:25:46 +0100344 vnet_link_t link_type,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100345 const ip46_address_t *nh_addr,
346 u32 sw_if_index,
347 u8 *rewrite)
348{
349 adj_index_t adj_index;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100350
351 adj_index = adj_nbr_find(nh_proto, link_type, nh_addr, sw_if_index);
352
353 if (ADJ_INDEX_INVALID == adj_index)
354 {
Neale Ranns13a08cc2018-11-07 09:25:54 -0800355 ip_adjacency_t *adj;
356
357 adj = adj_nbr_alloc(nh_proto, link_type, nh_addr, sw_if_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100358 adj->rewrite_header.sw_if_index = sw_if_index;
Neale Ranns13a08cc2018-11-07 09:25:54 -0800359 adj_index = adj_get_index(adj);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100360 }
361
Neale Ranns13a08cc2018-11-07 09:25:54 -0800362 adj_lock(adj_index);
363 adj_nbr_update_rewrite(adj_index,
Neale Rannsb80c5362016-10-08 13:03:40 +0100364 ADJ_NBR_REWRITE_FLAG_COMPLETE,
365 rewrite);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100366
Neale Ranns77cfc012019-12-15 22:26:37 +0000367 adj_delegate_adj_created(adj_get(adj_index));
368
Neale Ranns13a08cc2018-11-07 09:25:54 -0800369 return (adj_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100370}
371
372/**
373 * adj_nbr_update_rewrite
374 *
375 * Update the adjacency's rewrite string. A NULL string implies the
Jim Thompsonf324dec2019-04-08 03:22:21 -0500376 * rewrite is reset (i.e. when ARP/ND entry is gone).
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100377 * NB: the adj being updated may be handling traffic in the DP.
378 */
379void
380adj_nbr_update_rewrite (adj_index_t adj_index,
Neale Rannsb80c5362016-10-08 13:03:40 +0100381 adj_nbr_rewrite_flag_t flags,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100382 u8 *rewrite)
383{
384 ip_adjacency_t *adj;
385
386 ASSERT(ADJ_INDEX_INVALID != adj_index);
387
388 adj = adj_get(adj_index);
Neale Rannsb80c5362016-10-08 13:03:40 +0100389
390 if (flags & ADJ_NBR_REWRITE_FLAG_COMPLETE)
391 {
392 /*
393 * update the adj's rewrite string and build the arc
394 * from the rewrite node to the interface's TX node
395 */
396 adj_nbr_update_rewrite_internal(adj, IP_LOOKUP_NEXT_REWRITE,
397 adj_get_rewrite_node(adj->ia_link),
398 vnet_tx_node_index_for_sw_interface(
399 vnet_get_main(),
400 adj->rewrite_header.sw_if_index),
401 rewrite);
402 }
403 else
404 {
405 adj_nbr_update_rewrite_internal(adj, IP_LOOKUP_NEXT_ARP,
406 adj_get_nd_node(adj->ia_nh_proto),
407 vnet_tx_node_index_for_sw_interface(
408 vnet_get_main(),
409 adj->rewrite_header.sw_if_index),
410 rewrite);
411 }
Neale Rannsb80c5362016-10-08 13:03:40 +0100412}
413
414/**
415 * adj_nbr_update_rewrite_internal
416 *
417 * Update the adjacency's rewrite string. A NULL string implies the
Jim Thompsonf324dec2019-04-08 03:22:21 -0500418 * rewrite is reset (i.e. when ARP/ND entry is gone).
Neale Rannsb80c5362016-10-08 13:03:40 +0100419 * NB: the adj being updated may be handling traffic in the DP.
420 */
421void
422adj_nbr_update_rewrite_internal (ip_adjacency_t *adj,
Neale Rannsfa5d1982017-02-20 14:19:51 -0800423 ip_lookup_next_t adj_next_index,
Neale Rannsb80c5362016-10-08 13:03:40 +0100424 u32 this_node,
425 u32 next_node,
426 u8 *rewrite)
427{
Neale Ranns19c68d22016-12-07 15:38:14 +0000428 ip_adjacency_t *walk_adj;
Neale Ranns66300f62020-01-12 21:16:55 +0000429 adj_index_t walk_ai, ai;
Neale Rannsad95b5d2016-11-10 20:35:14 +0000430 vlib_main_t * vm;
431 u32 old_next;
Neale Ranns19c68d22016-12-07 15:38:14 +0000432 int do_walk;
Neale Rannsad95b5d2016-11-10 20:35:14 +0000433
434 vm = vlib_get_main();
435 old_next = adj->lookup_next_index;
436
Neale Ranns66300f62020-01-12 21:16:55 +0000437 ai = walk_ai = adj_get_index(adj);
Neale Rannsad95b5d2016-11-10 20:35:14 +0000438 if (VNET_LINK_MPLS == adj->ia_link)
439 {
440 /*
441 * The link type MPLS has no children in the control plane graph, it only
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700442 * has children in the data-plane graph. The backwalk is up the former.
Neale Rannsad95b5d2016-11-10 20:35:14 +0000443 * So we need to walk from its IP cousin.
444 */
445 walk_ai = adj_nbr_find(adj->ia_nh_proto,
446 fib_proto_to_link(adj->ia_nh_proto),
447 &adj->sub_type.nbr.next_hop,
448 adj->rewrite_header.sw_if_index);
449 }
Neale Rannsb80c5362016-10-08 13:03:40 +0100450
451 /*
Neale Ranns19c68d22016-12-07 15:38:14 +0000452 * Don't call the walk re-entrantly
453 */
454 if (ADJ_INDEX_INVALID != walk_ai)
455 {
456 walk_adj = adj_get(walk_ai);
Neale Rannsfa5d1982017-02-20 14:19:51 -0800457 if (ADJ_FLAG_SYNC_WALK_ACTIVE & walk_adj->ia_flags)
Neale Ranns19c68d22016-12-07 15:38:14 +0000458 {
459 do_walk = 0;
460 }
461 else
462 {
463 /*
464 * Prevent re-entrant walk of the same adj
465 */
Neale Rannsfa5d1982017-02-20 14:19:51 -0800466 walk_adj->ia_flags |= ADJ_FLAG_SYNC_WALK_ACTIVE;
Neale Ranns19c68d22016-12-07 15:38:14 +0000467 do_walk = 1;
468 }
469 }
470 else
471 {
472 do_walk = 0;
473 }
474
475 /*
476 * lock the adjacencies that are affected by updates this walk will provoke.
477 * Since the aim of the walk is to update children to link to a different
478 * DPO, this adj will no longer be in use and its lock count will drop to 0.
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700479 * We don't want it to be deleted as part of this endeavour.
Neale Ranns19c68d22016-12-07 15:38:14 +0000480 */
Neale Ranns66300f62020-01-12 21:16:55 +0000481 adj_lock(ai);
Neale Ranns19c68d22016-12-07 15:38:14 +0000482 adj_lock(walk_ai);
483
484 /*
Neale Rannsb80c5362016-10-08 13:03:40 +0100485 * Updating a rewrite string is not atomic;
486 * - the rewrite string is too long to write in one instruction
487 * - when swapping from incomplete to complete, we also need to update
Neale Rannsad95b5d2016-11-10 20:35:14 +0000488 * the VLIB graph next-index of the adj.
Neale Rannsb80c5362016-10-08 13:03:40 +0100489 * ideally we would only want to suspend forwarding via this adj whilst we
490 * do this, but we do not have that level of granularity - it's suspend all
491 * worker threads or nothing.
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700492 * The other choices are:
Neale Rannsb80c5362016-10-08 13:03:40 +0100493 * - to mark the adj down and back walk so child load-balances drop this adj
494 * from the set.
495 * - update the next_node index of this adj to point to error-drop
496 * both of which will mean for MAC change we will drop for this adj
Neale Rannsad95b5d2016-11-10 20:35:14 +0000497 * which is not acceptable. However, when the adj changes type (from
498 * complete to incomplete and vice-versa) the child DPOs, which have the
499 * VLIB graph next node index, will be sending packets to the wrong graph
500 * node. So from the options above, updating the next_node of the adj to
501 * be drop will work, but it relies on each graph node v4/v6/mpls, rewrite/
502 * arp/midchain always be valid w.r.t. a mis-match of adj type and node type
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700503 * (i.e. a rewrite adj in the arp node). This is not enforceable. Getting it
Neale Rannsad95b5d2016-11-10 20:35:14 +0000504 * wrong will lead to hard to find bugs since its a race condition. So we
505 * choose the more reliable method of updating the children to use the drop,
506 * then switching adj's type, then updating the children again. Did I mention
507 * that this doesn't happen often...
508 * So we need to distinguish between the two cases:
509 * 1 - mac change
510 * 2 - adj type change
511 */
Neale Ranns19c68d22016-12-07 15:38:14 +0000512 if (do_walk &&
513 old_next != adj_next_index &&
Neale Rannsad95b5d2016-11-10 20:35:14 +0000514 ADJ_INDEX_INVALID != walk_ai)
515 {
516 /*
517 * the adj is changing type. we need to fix all children so that they
518 * stack momentarily on a drop, while the adj changes. If we don't do
519 * this the children will send packets to a VLIB graph node that does
520 * not correspond to the adj's type - and it goes downhill from there.
521 */
522 fib_node_back_walk_ctx_t bw_ctx = {
523 .fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_DOWN,
524 /*
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700525 * force this walk to be synchronous. if we don't and a node in the graph
Neale Rannsad95b5d2016-11-10 20:35:14 +0000526 * (a heavily shared path-list) chooses to back-ground the walk (make it
527 * async) then it will pause and we will do the adj update below, before
528 * all the children are updated. not good.
529 */
530 .fnbw_flags = FIB_NODE_BW_FLAG_FORCE_SYNC,
531 };
532
533 fib_walk_sync(FIB_NODE_TYPE_ADJ, walk_ai, &bw_ctx);
Steven Luong3d5f6222020-01-30 09:11:18 -0800534 /*
Vladislav Grishenko15732f52021-10-27 00:07:01 +0500535 * fib_walk_sync may allocate a new adjacency and potentially cause a
Steven Luong3d5f6222020-01-30 09:11:18 -0800536 * realloc for adj_pool. When that happens, adj pointer is no longer
537 * valid here. We refresh the adj pointer accordingly.
538 */
539 adj = adj_get (ai);
Neale Rannsad95b5d2016-11-10 20:35:14 +0000540 }
541
542 /*
543 * If we are just updating the MAC string of the adj (which we also can't
544 * do atomically), then we need to stop packets switching through the adj.
545 * We can't do that on a per-adj basis, so it's all the packets.
546 * If we are updating the type, and we walked back to the children above,
547 * then this barrier serves to flush the queues/frames.
Neale Rannsb80c5362016-10-08 13:03:40 +0100548 */
549 vlib_worker_thread_barrier_sync(vm);
550
551 adj->lookup_next_index = adj_next_index;
Neale Rannscbe25aa2019-09-30 10:53:31 +0000552 adj->ia_node_index = this_node;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100553
554 if (NULL != rewrite)
555 {
556 /*
557 * new rewrite provided.
Neale Rannsb80c5362016-10-08 13:03:40 +0100558 * fill in the adj's rewrite string, and build the VLIB graph arc.
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100559 */
Neale Rannsb80c5362016-10-08 13:03:40 +0100560 vnet_rewrite_set_data_internal(&adj->rewrite_header,
561 sizeof(adj->rewrite_data),
562 rewrite,
563 vec_len(rewrite));
Neale Rannsb80c5362016-10-08 13:03:40 +0100564 vec_free(rewrite);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100565 }
566 else
567 {
Neale Rannsb80c5362016-10-08 13:03:40 +0100568 vnet_rewrite_clear_data_internal(&adj->rewrite_header,
569 sizeof(adj->rewrite_data));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100570 }
Neale Rannsad95b5d2016-11-10 20:35:14 +0000571 adj->rewrite_header.next_index = vlib_node_add_next(vlib_get_main(),
572 this_node,
573 next_node);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100574
575 /*
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700576 * done with the rewrite update - let the workers loose.
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100577 */
Neale Rannsb80c5362016-10-08 13:03:40 +0100578 vlib_worker_thread_barrier_release(vm);
Neale Rannsad95b5d2016-11-10 20:35:14 +0000579
Neale Ranns19c68d22016-12-07 15:38:14 +0000580 if (do_walk &&
581 (old_next != adj->lookup_next_index) &&
582 (ADJ_INDEX_INVALID != walk_ai))
Neale Rannsad95b5d2016-11-10 20:35:14 +0000583 {
584 /*
585 * backwalk to the children so they can stack on the now updated
586 * adjacency
587 */
588 fib_node_back_walk_ctx_t bw_ctx = {
589 .fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE,
590 };
591
592 fib_walk_sync(FIB_NODE_TYPE_ADJ, walk_ai, &bw_ctx);
593 }
Neale Ranns19c68d22016-12-07 15:38:14 +0000594 /*
595 * Prevent re-entrant walk of the same adj
596 */
597 if (do_walk)
598 {
Neale Ranns37157d52020-01-23 22:46:06 +0000599 walk_adj = adj_get(walk_ai);
Neale Rannsfa5d1982017-02-20 14:19:51 -0800600 walk_adj->ia_flags &= ~ADJ_FLAG_SYNC_WALK_ACTIVE;
Neale Ranns19c68d22016-12-07 15:38:14 +0000601 }
602
Neale Rannse3aeb382021-12-31 09:18:31 +0000603 adj_delegate_adj_modified(adj_get(ai));
Neale Ranns66300f62020-01-12 21:16:55 +0000604 adj_unlock(ai);
Neale Ranns19c68d22016-12-07 15:38:14 +0000605 adj_unlock(walk_ai);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100606}
607
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100608u32
609adj_nbr_db_size (void)
610{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100611 fib_protocol_t proto;
612 u32 sw_if_index = 0;
Neale Ranns20aec3d2020-05-25 09:09:36 +0000613 u64 count = 0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100614
615 for (proto = FIB_PROTOCOL_IP4; proto <= FIB_PROTOCOL_IP6; proto++)
616 {
617 vec_foreach_index(sw_if_index, adj_nbr_tables[proto])
618 {
619 if (NULL != adj_nbr_tables[proto][sw_if_index])
620 {
Neale Ranns20aec3d2020-05-25 09:09:36 +0000621 count += hash_elts(adj_nbr_tables[proto][sw_if_index]);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100622 }
623 }
624 }
Neale Ranns20aec3d2020-05-25 09:09:36 +0000625 return (count);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100626}
627
628/**
Neale Ranns20aec3d2020-05-25 09:09:36 +0000629 * @brief Walk all adjacencies on a link for a given next-hop protocol
Neale Rannsb80c5362016-10-08 13:03:40 +0100630 */
Neale Rannsb80c5362016-10-08 13:03:40 +0100631void
632adj_nbr_walk (u32 sw_if_index,
633 fib_protocol_t adj_nh_proto,
634 adj_walk_cb_t cb,
635 void *ctx)
636{
Neale Ranns22391fa2020-05-29 10:19:41 -0400637 adj_index_t ai, *ais, *aip;
Neale Ranns20aec3d2020-05-25 09:09:36 +0000638 adj_nbr_key_t *key;
Neale Ranns20aec3d2020-05-25 09:09:36 +0000639
Benoît Gannefaec38f2020-08-13 11:16:56 +0200640 ADJ_NBR_ASSERT_NH_PROTO (adj_nh_proto,);
641
Neale Rannsb80c5362016-10-08 13:03:40 +0100642 if (!ADJ_NBR_ITF_OK(adj_nh_proto, sw_if_index))
643 return;
644
Neale Ranns22391fa2020-05-29 10:19:41 -0400645 ais = NULL;
646
647 /* elements may be removed from the table during the walk, so
648 * collect the set first then process them */
649 hash_foreach_mem (key, ai, adj_nbr_tables[adj_nh_proto][sw_if_index],
650 ({
651 vec_add1(ais, ai);
652 }));
653
654 vec_foreach(aip, ais)
Neale Ranns20aec3d2020-05-25 09:09:36 +0000655 {
Neale Ranns22391fa2020-05-29 10:19:41 -0400656 /* An adj may be deleted during the walk so check first */
657 if (!pool_is_free_index(adj_pool, *aip))
658 cb(*aip, ctx);
Neale Ranns20aec3d2020-05-25 09:09:36 +0000659 }
Neale Ranns22391fa2020-05-29 10:19:41 -0400660 vec_free(ais);
Neale Rannsb80c5362016-10-08 13:03:40 +0100661}
662
663/**
Neale Rannsb80c5362016-10-08 13:03:40 +0100664 * @brief Walk adjacencies on a link with a given v4 next-hop.
665 * that is visit the adjacencies with different link types.
666 */
667void
668adj_nbr_walk_nh4 (u32 sw_if_index,
669 const ip4_address_t *addr,
670 adj_walk_cb_t cb,
671 void *ctx)
672{
673 if (!ADJ_NBR_ITF_OK(FIB_PROTOCOL_IP4, sw_if_index))
674 return;
675
676 ip46_address_t nh = {
677 .ip4 = *addr,
678 };
Neale Ranns580bba72018-04-23 05:31:19 -0700679 vnet_link_t linkt;
680 adj_index_t ai;
Neale Rannsb80c5362016-10-08 13:03:40 +0100681
Neale Ranns580bba72018-04-23 05:31:19 -0700682 FOR_EACH_VNET_LINK(linkt)
683 {
684 ai = adj_nbr_find (FIB_PROTOCOL_IP4, linkt, &nh, sw_if_index);
Neale Rannsb80c5362016-10-08 13:03:40 +0100685
Neale Ranns580bba72018-04-23 05:31:19 -0700686 if (INDEX_INVALID != ai)
687 cb(ai, ctx);
688 }
Neale Rannsb80c5362016-10-08 13:03:40 +0100689}
690
691/**
692 * @brief Walk adjacencies on a link with a given v6 next-hop.
693 * that is visit the adjacencies with different link types.
694 */
695void
696adj_nbr_walk_nh6 (u32 sw_if_index,
697 const ip6_address_t *addr,
698 adj_walk_cb_t cb,
699 void *ctx)
700{
701 if (!ADJ_NBR_ITF_OK(FIB_PROTOCOL_IP6, sw_if_index))
702 return;
703
704 ip46_address_t nh = {
705 .ip6 = *addr,
706 };
Neale Ranns580bba72018-04-23 05:31:19 -0700707 vnet_link_t linkt;
708 adj_index_t ai;
Neale Rannsb80c5362016-10-08 13:03:40 +0100709
Neale Ranns580bba72018-04-23 05:31:19 -0700710 FOR_EACH_VNET_LINK(linkt)
711 {
712 ai = adj_nbr_find (FIB_PROTOCOL_IP6, linkt, &nh, sw_if_index);
Neale Rannsb80c5362016-10-08 13:03:40 +0100713
Neale Ranns580bba72018-04-23 05:31:19 -0700714 if (INDEX_INVALID != ai)
715 cb(ai, ctx);
716 }
Neale Rannsb80c5362016-10-08 13:03:40 +0100717}
718
719/**
720 * @brief Walk adjacencies on a link with a given next-hop.
721 * that is visit the adjacencies with different link types.
722 */
723void
724adj_nbr_walk_nh (u32 sw_if_index,
725 fib_protocol_t adj_nh_proto,
726 const ip46_address_t *nh,
727 adj_walk_cb_t cb,
728 void *ctx)
729{
Benoît Gannefaec38f2020-08-13 11:16:56 +0200730 ADJ_NBR_ASSERT_NH_PROTO (adj_nh_proto,);
731
Neale Rannsb80c5362016-10-08 13:03:40 +0100732 if (!ADJ_NBR_ITF_OK(adj_nh_proto, sw_if_index))
733 return;
734
Neale Rannscbe25aa2019-09-30 10:53:31 +0000735 switch (adj_nh_proto)
Neale Ranns580bba72018-04-23 05:31:19 -0700736 {
Neale Rannscbe25aa2019-09-30 10:53:31 +0000737 case FIB_PROTOCOL_IP4:
738 adj_nbr_walk_nh4(sw_if_index, &nh->ip4, cb, ctx);
739 break;
740 case FIB_PROTOCOL_IP6:
741 adj_nbr_walk_nh6(sw_if_index, &nh->ip6, cb, ctx);
742 break;
743 case FIB_PROTOCOL_MPLS:
744 ASSERT(0);
745 break;
Neale Ranns580bba72018-04-23 05:31:19 -0700746 }
Neale Rannsb80c5362016-10-08 13:03:40 +0100747}
748
749/**
Neale Ranns8b37b872016-11-21 12:25:22 +0000750 * Flags associated with the interface state walks
751 */
752typedef enum adj_nbr_interface_flags_t_
753{
754 ADJ_NBR_INTERFACE_UP = (1 << 0),
755} adj_nbr_interface_flags_t;
756
757/**
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100758 * Context for the state change walk of the DB
759 */
760typedef struct adj_nbr_interface_state_change_ctx_t_
761{
762 /**
Neale Ranns8b37b872016-11-21 12:25:22 +0000763 * Flags on the interface
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100764 */
Neale Ranns8b37b872016-11-21 12:25:22 +0000765 adj_nbr_interface_flags_t flags;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100766} adj_nbr_interface_state_change_ctx_t;
767
Neale Rannsb80c5362016-10-08 13:03:40 +0100768static adj_walk_rc_t
769adj_nbr_interface_state_change_one (adj_index_t ai,
Neale Ranns8b37b872016-11-21 12:25:22 +0000770 void *arg)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100771{
772 /*
773 * Back walk the graph to inform the forwarding entries
Neale Ranns8b37b872016-11-21 12:25:22 +0000774 * that this interface state has changed. Do this synchronously
775 * since this is the walk that provides convergence
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100776 */
777 adj_nbr_interface_state_change_ctx_t *ctx = arg;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100778 fib_node_back_walk_ctx_t bw_ctx = {
Neale Ranns8b37b872016-11-21 12:25:22 +0000779 .fnbw_reason = ((ctx->flags & ADJ_NBR_INTERFACE_UP) ?
780 FIB_NODE_BW_REASON_FLAG_INTERFACE_UP :
781 FIB_NODE_BW_REASON_FLAG_INTERFACE_DOWN),
782 /*
783 * the force sync applies only as far as the first fib_entry.
784 * And it's the fib_entry's we need to converge away from
785 * the adjacencies on the now down link
786 */
787 .fnbw_flags = (!(ctx->flags & ADJ_NBR_INTERFACE_UP) ?
788 FIB_NODE_BW_FLAG_FORCE_SYNC :
Neale Ranns30d53642018-08-27 07:29:15 -0700789 FIB_NODE_BW_FLAG_NONE),
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100790 };
Neale Ranns30d53642018-08-27 07:29:15 -0700791 ip_adjacency_t *adj;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100792
Benoît Ganne9f10edb2021-06-08 16:25:14 +0200793 adj_lock (ai);
794
Neale Ranns30d53642018-08-27 07:29:15 -0700795 adj = adj_get(ai);
Neale Ranns30d53642018-08-27 07:29:15 -0700796 adj->ia_flags |= ADJ_FLAG_SYNC_WALK_ACTIVE;
Neale Rannsb80c5362016-10-08 13:03:40 +0100797 fib_walk_sync(FIB_NODE_TYPE_ADJ, ai, &bw_ctx);
Vladislav Grishenko15732f52021-10-27 00:07:01 +0500798
799 /*
800 * fib_walk_sync may allocate a new adjacency and potentially cause a
801 * realloc for adj_pool. When that happens, adj pointer is no longer
802 * valid here. We refresh the adj pointer accordingly.
803 */
804 adj = adj_get(ai);
Neale Ranns30d53642018-08-27 07:29:15 -0700805 adj->ia_flags &= ~ADJ_FLAG_SYNC_WALK_ACTIVE;
Neale Rannsb80c5362016-10-08 13:03:40 +0100806
Benoît Ganne9f10edb2021-06-08 16:25:14 +0200807 adj_unlock (ai);
Neale Rannsb80c5362016-10-08 13:03:40 +0100808 return (ADJ_WALK_RC_CONTINUE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100809}
810
Neale Ranns8b37b872016-11-21 12:25:22 +0000811/**
812 * @brief Registered function for SW interface state changes
813 */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100814static clib_error_t *
Neale Ranns8b37b872016-11-21 12:25:22 +0000815adj_nbr_sw_interface_state_change (vnet_main_t * vnm,
816 u32 sw_if_index,
817 u32 flags)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100818{
819 fib_protocol_t proto;
820
821 /*
822 * walk each adj on the interface and trigger a walk from that adj
823 */
824 for (proto = FIB_PROTOCOL_IP4; proto <= FIB_PROTOCOL_IP6; proto++)
825 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100826 adj_nbr_interface_state_change_ctx_t ctx = {
Neale Ranns8b37b872016-11-21 12:25:22 +0000827 .flags = ((flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ?
828 ADJ_NBR_INTERFACE_UP :
829 0),
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100830 };
831
Neale Rannsb80c5362016-10-08 13:03:40 +0100832 adj_nbr_walk(sw_if_index, proto,
833 adj_nbr_interface_state_change_one,
834 &ctx);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100835 }
836
837 return (NULL);
838}
839
Neale Ranns8b37b872016-11-21 12:25:22 +0000840VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION_PRIO(
841 adj_nbr_sw_interface_state_change,
842 VNET_ITF_FUNC_PRIORITY_HIGH);
843
844/**
845 * @brief Invoked on each SW interface of a HW interface when the
846 * HW interface state changes
847 */
Neale Ranns0053de62018-05-22 08:40:52 -0700848static walk_rc_t
Neale Ranns8b37b872016-11-21 12:25:22 +0000849adj_nbr_hw_sw_interface_state_change (vnet_main_t * vnm,
850 u32 sw_if_index,
851 void *arg)
852{
853 adj_nbr_interface_state_change_ctx_t *ctx = arg;
854 fib_protocol_t proto;
855
856 /*
857 * walk each adj on the interface and trigger a walk from that adj
858 */
859 for (proto = FIB_PROTOCOL_IP4; proto <= FIB_PROTOCOL_IP6; proto++)
860 {
861 adj_nbr_walk(sw_if_index, proto,
862 adj_nbr_interface_state_change_one,
863 ctx);
864 }
Neale Ranns0053de62018-05-22 08:40:52 -0700865 return (WALK_CONTINUE);
Neale Ranns8b37b872016-11-21 12:25:22 +0000866}
867
868/**
869 * @brief Registered callback for HW interface state changes
870 */
871static clib_error_t *
872adj_nbr_hw_interface_state_change (vnet_main_t * vnm,
873 u32 hw_if_index,
874 u32 flags)
875{
876 /*
877 * walk SW interface on the HW
878 */
879 adj_nbr_interface_state_change_ctx_t ctx = {
880 .flags = ((flags & VNET_HW_INTERFACE_FLAG_LINK_UP) ?
881 ADJ_NBR_INTERFACE_UP :
882 0),
883 };
884
885 vnet_hw_interface_walk_sw(vnm, hw_if_index,
886 adj_nbr_hw_sw_interface_state_change,
887 &ctx);
888
889 return (NULL);
890}
891
892VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION_PRIO(
893 adj_nbr_hw_interface_state_change,
894 VNET_ITF_FUNC_PRIORITY_HIGH);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100895
Neale Rannsb80c5362016-10-08 13:03:40 +0100896static adj_walk_rc_t
897adj_nbr_interface_delete_one (adj_index_t ai,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100898 void *arg)
899{
900 /*
901 * Back walk the graph to inform the forwarding entries
902 * that this interface has been deleted.
903 */
904 fib_node_back_walk_ctx_t bw_ctx = {
905 .fnbw_reason = FIB_NODE_BW_REASON_FLAG_INTERFACE_DELETE,
906 };
Neale Ranns30d53642018-08-27 07:29:15 -0700907 ip_adjacency_t *adj;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100908
Benoît Ganne73911562019-10-16 15:08:37 +0200909 adj_lock(ai);
910
Neale Ranns30d53642018-08-27 07:29:15 -0700911 adj = adj_get(ai);
Neale Ranns30d53642018-08-27 07:29:15 -0700912 adj->ia_flags |= ADJ_FLAG_SYNC_WALK_ACTIVE;
Neale Rannsb80c5362016-10-08 13:03:40 +0100913 fib_walk_sync(FIB_NODE_TYPE_ADJ, ai, &bw_ctx);
Vladislav Grishenko15732f52021-10-27 00:07:01 +0500914
915 /*
916 * fib_walk_sync may allocate a new adjacency and potentially cause a
917 * realloc for adj_pool. When that happens, adj pointer is no longer
918 * valid here. We refresh the adj pointer accordingly.
919 */
920 adj = adj_get(ai);
Neale Ranns30d53642018-08-27 07:29:15 -0700921 adj->ia_flags &= ~ADJ_FLAG_SYNC_WALK_ACTIVE;
Neale Rannsb80c5362016-10-08 13:03:40 +0100922
Benoît Ganne73911562019-10-16 15:08:37 +0200923 adj_unlock(ai);
Neale Rannsb80c5362016-10-08 13:03:40 +0100924 return (ADJ_WALK_RC_CONTINUE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100925}
926
927/**
928 * adj_nbr_interface_add_del
929 *
930 * Registered to receive interface Add and delete notifications
931 */
932static clib_error_t *
933adj_nbr_interface_add_del (vnet_main_t * vnm,
934 u32 sw_if_index,
935 u32 is_add)
936{
937 fib_protocol_t proto;
938
939 if (is_add)
940 {
941 /*
942 * not interested in interface additions. we will not back walk
943 * to resolve paths through newly added interfaces. Why? The control
944 * plane should have the brains to add interfaces first, then routes.
945 * So the case where there are paths with a interface that matches
946 * one just created is the case where the path resolved through an
947 * interface that was deleted, and still has not been removed. The
948 * new interface added, is NO GUARANTEE that the interface being
949 * added now, even though it may have the same sw_if_index, is the
950 * same interface that the path needs. So tough!
951 * If the control plane wants these routes to resolve it needs to
952 * remove and add them again.
953 */
954 return (NULL);
955 }
956
957 for (proto = FIB_PROTOCOL_IP4; proto <= FIB_PROTOCOL_IP6; proto++)
958 {
Neale Rannsb80c5362016-10-08 13:03:40 +0100959 adj_nbr_walk(sw_if_index, proto,
960 adj_nbr_interface_delete_one,
961 NULL);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100962 }
963
964 return (NULL);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100965}
966
967VNET_SW_INTERFACE_ADD_DEL_FUNCTION(adj_nbr_interface_add_del);
968
969
Neale Rannsb80c5362016-10-08 13:03:40 +0100970static adj_walk_rc_t
Neale Rannsea8adf72021-08-13 08:10:59 +0000971adj_nbr_ethernet_mac_change_one (adj_index_t ai,
972 void *arg)
973{
974 vnet_update_adjacency_for_sw_interface(vnet_get_main(),
975 adj_get_sw_if_index(ai),
976 ai);
977
978 return (ADJ_WALK_RC_CONTINUE);
979}
980
981/**
982 * Callback function invoked when an interface's MAC Address changes
983 */
984static void
985adj_nbr_ethernet_change_mac (ethernet_main_t * em,
986 u32 sw_if_index, uword opaque)
987{
988 fib_protocol_t proto;
989
990 FOR_EACH_FIB_IP_PROTOCOL(proto)
991 {
992 adj_nbr_walk(sw_if_index, proto,
993 adj_nbr_ethernet_mac_change_one,
994 NULL);
995 }
996}
997
998static adj_walk_rc_t
Neale Rannsb80c5362016-10-08 13:03:40 +0100999adj_nbr_show_one (adj_index_t ai,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001000 void *arg)
1001{
1002 vlib_cli_output (arg, "[@%d] %U",
Neale Rannsb80c5362016-10-08 13:03:40 +01001003 ai,
1004 format_ip_adjacency, ai,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001005 FORMAT_IP_ADJACENCY_NONE);
Neale Rannsb80c5362016-10-08 13:03:40 +01001006
1007 return (ADJ_WALK_RC_CONTINUE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001008}
1009
1010static clib_error_t *
1011adj_nbr_show (vlib_main_t * vm,
1012 unformat_input_t * input,
1013 vlib_cli_command_t * cmd)
1014{
1015 adj_index_t ai = ADJ_INDEX_INVALID;
Neale Ranns14053c92019-12-29 23:55:18 +00001016 ip46_address_t nh = ip46_address_initializer;
Neale Rannsb80c5362016-10-08 13:03:40 +01001017 u32 sw_if_index = ~0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001018
1019 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1020 {
Neale Ranns14053c92019-12-29 23:55:18 +00001021 if (unformat (input, "%U",
1022 unformat_vnet_sw_interface, vnet_get_main(),
1023 &sw_if_index))
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001024 ;
Neale Rannsb80c5362016-10-08 13:03:40 +01001025 else if (unformat (input, "%U",
Neale Ranns14053c92019-12-29 23:55:18 +00001026 unformat_ip46_address, &nh, IP46_TYPE_ANY))
1027 ;
1028 else if (unformat (input, "%d", &ai))
Neale Rannsb80c5362016-10-08 13:03:40 +01001029 ;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001030 else
1031 break;
1032 }
1033
1034 if (ADJ_INDEX_INVALID != ai)
1035 {
1036 vlib_cli_output (vm, "[@%d] %U",
1037 ai,
Neale Rannsb80c5362016-10-08 13:03:40 +01001038 format_ip_adjacency, ai,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001039 FORMAT_IP_ADJACENCY_DETAIL);
1040 }
Neale Rannsb80c5362016-10-08 13:03:40 +01001041 else if (~0 != sw_if_index)
1042 {
1043 fib_protocol_t proto;
1044
Neale Ranns14053c92019-12-29 23:55:18 +00001045 if (ip46_address_is_zero(&nh))
1046 {
1047 for (proto = FIB_PROTOCOL_IP4; proto <= FIB_PROTOCOL_IP6; proto++)
1048 {
1049 adj_nbr_walk(sw_if_index, proto,
1050 adj_nbr_show_one,
1051 vm);
1052 }
1053 }
1054 else
1055 {
1056 proto = (ip46_address_is_ip4(&nh) ?
1057 FIB_PROTOCOL_IP4 :
1058 FIB_PROTOCOL_IP6);
1059 adj_nbr_walk_nh(sw_if_index, proto, &nh,
1060 adj_nbr_show_one,
1061 vm);
1062 }
Neale Rannsb80c5362016-10-08 13:03:40 +01001063 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001064 else
1065 {
1066 fib_protocol_t proto;
1067
1068 for (proto = FIB_PROTOCOL_IP4; proto <= FIB_PROTOCOL_IP6; proto++)
1069 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001070 vec_foreach_index(sw_if_index, adj_nbr_tables[proto])
1071 {
Neale Rannsb80c5362016-10-08 13:03:40 +01001072 adj_nbr_walk(sw_if_index, proto,
1073 adj_nbr_show_one,
1074 vm);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001075 }
1076 }
1077 }
1078
1079 return 0;
1080}
1081
Neale Rannsb80c5362016-10-08 13:03:40 +01001082/*?
1083 * Show all neighbour adjacencies.
1084 * @cliexpar
1085 * @cliexstart{sh adj nbr}
1086 * [@2] ipv4 via 1.0.0.2 loop0: IP4: 00:00:22:aa:bb:cc -> 00:00:11:aa:bb:cc
1087 * [@3] mpls via 1.0.0.2 loop0: MPLS_UNICAST: 00:00:22:aa:bb:cc -> 00:00:11:aa:bb:cc
1088 * [@4] ipv4 via 1.0.0.3 loop0: IP4: 00:00:22:aa:bb:cc -> 00:00:11:aa:bb:cc
1089 * [@5] mpls via 1.0.0.3 loop0: MPLS_UNICAST: 00:00:22:aa:bb:cc -> 00:00:11:aa:bb:cc
1090 * @cliexend
1091 ?*/
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001092VLIB_CLI_COMMAND (ip4_show_fib_command, static) = {
1093 .path = "show adj nbr",
Neale Rannsb80c5362016-10-08 13:03:40 +01001094 .short_help = "show adj nbr [<adj_index>] [interface]",
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001095 .function = adj_nbr_show,
1096};
1097
1098u8*
1099format_adj_nbr_incomplete (u8* s, va_list *ap)
1100{
Billy McFallcfcf1e22016-10-14 09:51:49 -04001101 index_t index = va_arg(*ap, index_t);
1102 CLIB_UNUSED(u32 indent) = va_arg(*ap, u32);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001103 vnet_main_t * vnm = vnet_get_main();
1104 ip_adjacency_t * adj = adj_get(index);
1105
Neale Ranns924d03a2016-10-19 08:25:46 +01001106 s = format (s, "arp-%U", format_vnet_link, adj->ia_link);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001107 s = format (s, ": via %U",
Neale Rannsb80c5362016-10-08 13:03:40 +01001108 format_ip46_address, &adj->sub_type.nbr.next_hop,
1109 adj_proto_to_46(adj->ia_nh_proto));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001110 s = format (s, " %U",
Steven70488ab2018-03-28 17:59:00 -07001111 format_vnet_sw_if_index_name,
1112 vnm, adj->rewrite_header.sw_if_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001113
1114 return (s);
1115}
1116
1117u8*
1118format_adj_nbr (u8* s, va_list *ap)
1119{
Billy McFallcfcf1e22016-10-14 09:51:49 -04001120 index_t index = va_arg(*ap, index_t);
1121 CLIB_UNUSED(u32 indent) = va_arg(*ap, u32);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001122 ip_adjacency_t * adj = adj_get(index);
1123
Neale Ranns924d03a2016-10-19 08:25:46 +01001124 s = format (s, "%U", format_vnet_link, adj->ia_link);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001125 s = format (s, " via %U ",
Neale Rannsb80c5362016-10-08 13:03:40 +01001126 format_ip46_address, &adj->sub_type.nbr.next_hop,
1127 adj_proto_to_46(adj->ia_nh_proto));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001128 s = format (s, "%U",
1129 format_vnet_rewrite,
Neale Rannsb069a692017-03-15 12:34:25 -04001130 &adj->rewrite_header, sizeof (adj->rewrite_data), 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001131
1132 return (s);
1133}
1134
1135static void
1136adj_dpo_lock (dpo_id_t *dpo)
1137{
1138 adj_lock(dpo->dpoi_index);
1139}
1140static void
1141adj_dpo_unlock (dpo_id_t *dpo)
1142{
1143 adj_unlock(dpo->dpoi_index);
1144}
1145
Neale Ranns6c3ebcc2016-10-02 21:20:15 +01001146static void
1147adj_mem_show (void)
1148{
1149 fib_show_memory_usage("Adjacency",
1150 pool_elts(adj_pool),
1151 pool_len(adj_pool),
1152 sizeof(ip_adjacency_t));
1153}
1154
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001155const static dpo_vft_t adj_nbr_dpo_vft = {
1156 .dv_lock = adj_dpo_lock,
1157 .dv_unlock = adj_dpo_unlock,
1158 .dv_format = format_adj_nbr,
Neale Ranns6c3ebcc2016-10-02 21:20:15 +01001159 .dv_mem_show = adj_mem_show,
Andrew Yourtchenko5f3fcb92017-10-25 05:50:37 -07001160 .dv_get_urpf = adj_dpo_get_urpf,
Neale Ranns8f5fef22020-12-21 08:29:34 +00001161 .dv_get_mtu = adj_dpo_get_mtu,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001162};
1163const static dpo_vft_t adj_nbr_incompl_dpo_vft = {
1164 .dv_lock = adj_dpo_lock,
1165 .dv_unlock = adj_dpo_unlock,
1166 .dv_format = format_adj_nbr_incomplete,
Andrew Yourtchenko5f3fcb92017-10-25 05:50:37 -07001167 .dv_get_urpf = adj_dpo_get_urpf,
Neale Ranns8f5fef22020-12-21 08:29:34 +00001168 .dv_get_mtu = adj_dpo_get_mtu,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001169};
1170
1171/**
1172 * @brief The per-protocol VLIB graph nodes that are assigned to an adjacency
1173 * object.
1174 *
1175 * this means that these graph nodes are ones from which a nbr is the
1176 * parent object in the DPO-graph.
1177 */
1178const static char* const nbr_ip4_nodes[] =
1179{
Neale Rannsf06aea52016-11-29 06:51:37 -08001180 "ip4-rewrite",
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001181 NULL,
1182};
1183const static char* const nbr_ip6_nodes[] =
1184{
1185 "ip6-rewrite",
1186 NULL,
1187};
1188const static char* const nbr_mpls_nodes[] =
1189{
1190 "mpls-output",
1191 NULL,
1192};
Neale Ranns5e575b12016-10-03 09:40:25 +01001193const static char* const nbr_ethernet_nodes[] =
1194{
1195 "adj-l2-rewrite",
1196 NULL,
1197};
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001198const static char* const * const nbr_nodes[DPO_PROTO_NUM] =
1199{
1200 [DPO_PROTO_IP4] = nbr_ip4_nodes,
1201 [DPO_PROTO_IP6] = nbr_ip6_nodes,
1202 [DPO_PROTO_MPLS] = nbr_mpls_nodes,
Neale Ranns5e575b12016-10-03 09:40:25 +01001203 [DPO_PROTO_ETHERNET] = nbr_ethernet_nodes,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001204};
1205
1206const static char* const nbr_incomplete_ip4_nodes[] =
1207{
1208 "ip4-arp",
1209 NULL,
1210};
1211const static char* const nbr_incomplete_ip6_nodes[] =
1212{
1213 "ip6-discover-neighbor",
1214 NULL,
1215};
1216const static char* const nbr_incomplete_mpls_nodes[] =
1217{
1218 "mpls-adj-incomplete",
1219 NULL,
1220};
1221
1222const static char* const * const nbr_incomplete_nodes[DPO_PROTO_NUM] =
1223{
1224 [DPO_PROTO_IP4] = nbr_incomplete_ip4_nodes,
1225 [DPO_PROTO_IP6] = nbr_incomplete_ip6_nodes,
1226 [DPO_PROTO_MPLS] = nbr_incomplete_mpls_nodes,
1227};
1228
1229void
1230adj_nbr_module_init (void)
1231{
1232 dpo_register(DPO_ADJACENCY,
1233 &adj_nbr_dpo_vft,
1234 nbr_nodes);
1235 dpo_register(DPO_ADJACENCY_INCOMPLETE,
1236 &adj_nbr_incompl_dpo_vft,
1237 nbr_incomplete_nodes);
Neale Rannsea8adf72021-08-13 08:10:59 +00001238
1239 ethernet_address_change_ctx_t ctx = {
1240 .function = adj_nbr_ethernet_change_mac,
1241 .function_opaque = 0,
1242 };
1243 vec_add1 (ethernet_main.address_change_callbacks, ctx);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001244}