blob: d289bb6a2a880e08aa9e2d4fccfbc1280bd8429b [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 /*
535 * fib_walk_sync may allocate a new adjacency and potentially cuase a
536 * 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);
796
797 adj->ia_flags |= ADJ_FLAG_SYNC_WALK_ACTIVE;
Neale Rannsb80c5362016-10-08 13:03:40 +0100798 fib_walk_sync(FIB_NODE_TYPE_ADJ, ai, &bw_ctx);
Neale Ranns30d53642018-08-27 07:29:15 -0700799 adj->ia_flags &= ~ADJ_FLAG_SYNC_WALK_ACTIVE;
Neale Rannsb80c5362016-10-08 13:03:40 +0100800
Benoît Ganne9f10edb2021-06-08 16:25:14 +0200801 adj_unlock (ai);
Neale Rannsb80c5362016-10-08 13:03:40 +0100802 return (ADJ_WALK_RC_CONTINUE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100803}
804
Neale Ranns8b37b872016-11-21 12:25:22 +0000805/**
806 * @brief Registered function for SW interface state changes
807 */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100808static clib_error_t *
Neale Ranns8b37b872016-11-21 12:25:22 +0000809adj_nbr_sw_interface_state_change (vnet_main_t * vnm,
810 u32 sw_if_index,
811 u32 flags)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100812{
813 fib_protocol_t proto;
814
815 /*
816 * walk each adj on the interface and trigger a walk from that adj
817 */
818 for (proto = FIB_PROTOCOL_IP4; proto <= FIB_PROTOCOL_IP6; proto++)
819 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100820 adj_nbr_interface_state_change_ctx_t ctx = {
Neale Ranns8b37b872016-11-21 12:25:22 +0000821 .flags = ((flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ?
822 ADJ_NBR_INTERFACE_UP :
823 0),
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100824 };
825
Neale Rannsb80c5362016-10-08 13:03:40 +0100826 adj_nbr_walk(sw_if_index, proto,
827 adj_nbr_interface_state_change_one,
828 &ctx);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100829 }
830
831 return (NULL);
832}
833
Neale Ranns8b37b872016-11-21 12:25:22 +0000834VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION_PRIO(
835 adj_nbr_sw_interface_state_change,
836 VNET_ITF_FUNC_PRIORITY_HIGH);
837
838/**
839 * @brief Invoked on each SW interface of a HW interface when the
840 * HW interface state changes
841 */
Neale Ranns0053de62018-05-22 08:40:52 -0700842static walk_rc_t
Neale Ranns8b37b872016-11-21 12:25:22 +0000843adj_nbr_hw_sw_interface_state_change (vnet_main_t * vnm,
844 u32 sw_if_index,
845 void *arg)
846{
847 adj_nbr_interface_state_change_ctx_t *ctx = arg;
848 fib_protocol_t proto;
849
850 /*
851 * walk each adj on the interface and trigger a walk from that adj
852 */
853 for (proto = FIB_PROTOCOL_IP4; proto <= FIB_PROTOCOL_IP6; proto++)
854 {
855 adj_nbr_walk(sw_if_index, proto,
856 adj_nbr_interface_state_change_one,
857 ctx);
858 }
Neale Ranns0053de62018-05-22 08:40:52 -0700859 return (WALK_CONTINUE);
Neale Ranns8b37b872016-11-21 12:25:22 +0000860}
861
862/**
863 * @brief Registered callback for HW interface state changes
864 */
865static clib_error_t *
866adj_nbr_hw_interface_state_change (vnet_main_t * vnm,
867 u32 hw_if_index,
868 u32 flags)
869{
870 /*
871 * walk SW interface on the HW
872 */
873 adj_nbr_interface_state_change_ctx_t ctx = {
874 .flags = ((flags & VNET_HW_INTERFACE_FLAG_LINK_UP) ?
875 ADJ_NBR_INTERFACE_UP :
876 0),
877 };
878
879 vnet_hw_interface_walk_sw(vnm, hw_if_index,
880 adj_nbr_hw_sw_interface_state_change,
881 &ctx);
882
883 return (NULL);
884}
885
886VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION_PRIO(
887 adj_nbr_hw_interface_state_change,
888 VNET_ITF_FUNC_PRIORITY_HIGH);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100889
Neale Rannsb80c5362016-10-08 13:03:40 +0100890static adj_walk_rc_t
891adj_nbr_interface_delete_one (adj_index_t ai,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100892 void *arg)
893{
894 /*
895 * Back walk the graph to inform the forwarding entries
896 * that this interface has been deleted.
897 */
898 fib_node_back_walk_ctx_t bw_ctx = {
899 .fnbw_reason = FIB_NODE_BW_REASON_FLAG_INTERFACE_DELETE,
900 };
Neale Ranns30d53642018-08-27 07:29:15 -0700901 ip_adjacency_t *adj;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100902
Benoît Ganne73911562019-10-16 15:08:37 +0200903 adj_lock(ai);
904
Neale Ranns30d53642018-08-27 07:29:15 -0700905 adj = adj_get(ai);
906
907 adj->ia_flags |= ADJ_FLAG_SYNC_WALK_ACTIVE;
Neale Rannsb80c5362016-10-08 13:03:40 +0100908 fib_walk_sync(FIB_NODE_TYPE_ADJ, ai, &bw_ctx);
Neale Ranns30d53642018-08-27 07:29:15 -0700909 adj->ia_flags &= ~ADJ_FLAG_SYNC_WALK_ACTIVE;
Neale Rannsb80c5362016-10-08 13:03:40 +0100910
Benoît Ganne73911562019-10-16 15:08:37 +0200911 adj_unlock(ai);
Neale Rannsb80c5362016-10-08 13:03:40 +0100912 return (ADJ_WALK_RC_CONTINUE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100913}
914
915/**
916 * adj_nbr_interface_add_del
917 *
918 * Registered to receive interface Add and delete notifications
919 */
920static clib_error_t *
921adj_nbr_interface_add_del (vnet_main_t * vnm,
922 u32 sw_if_index,
923 u32 is_add)
924{
925 fib_protocol_t proto;
926
927 if (is_add)
928 {
929 /*
930 * not interested in interface additions. we will not back walk
931 * to resolve paths through newly added interfaces. Why? The control
932 * plane should have the brains to add interfaces first, then routes.
933 * So the case where there are paths with a interface that matches
934 * one just created is the case where the path resolved through an
935 * interface that was deleted, and still has not been removed. The
936 * new interface added, is NO GUARANTEE that the interface being
937 * added now, even though it may have the same sw_if_index, is the
938 * same interface that the path needs. So tough!
939 * If the control plane wants these routes to resolve it needs to
940 * remove and add them again.
941 */
942 return (NULL);
943 }
944
945 for (proto = FIB_PROTOCOL_IP4; proto <= FIB_PROTOCOL_IP6; proto++)
946 {
Neale Rannsb80c5362016-10-08 13:03:40 +0100947 adj_nbr_walk(sw_if_index, proto,
948 adj_nbr_interface_delete_one,
949 NULL);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100950 }
951
952 return (NULL);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100953}
954
955VNET_SW_INTERFACE_ADD_DEL_FUNCTION(adj_nbr_interface_add_del);
956
957
Neale Rannsb80c5362016-10-08 13:03:40 +0100958static adj_walk_rc_t
Neale Rannsea8adf72021-08-13 08:10:59 +0000959adj_nbr_ethernet_mac_change_one (adj_index_t ai,
960 void *arg)
961{
962 vnet_update_adjacency_for_sw_interface(vnet_get_main(),
963 adj_get_sw_if_index(ai),
964 ai);
965
966 return (ADJ_WALK_RC_CONTINUE);
967}
968
969/**
970 * Callback function invoked when an interface's MAC Address changes
971 */
972static void
973adj_nbr_ethernet_change_mac (ethernet_main_t * em,
974 u32 sw_if_index, uword opaque)
975{
976 fib_protocol_t proto;
977
978 FOR_EACH_FIB_IP_PROTOCOL(proto)
979 {
980 adj_nbr_walk(sw_if_index, proto,
981 adj_nbr_ethernet_mac_change_one,
982 NULL);
983 }
984}
985
986static adj_walk_rc_t
Neale Rannsb80c5362016-10-08 13:03:40 +0100987adj_nbr_show_one (adj_index_t ai,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100988 void *arg)
989{
990 vlib_cli_output (arg, "[@%d] %U",
Neale Rannsb80c5362016-10-08 13:03:40 +0100991 ai,
992 format_ip_adjacency, ai,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100993 FORMAT_IP_ADJACENCY_NONE);
Neale Rannsb80c5362016-10-08 13:03:40 +0100994
995 return (ADJ_WALK_RC_CONTINUE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100996}
997
998static clib_error_t *
999adj_nbr_show (vlib_main_t * vm,
1000 unformat_input_t * input,
1001 vlib_cli_command_t * cmd)
1002{
1003 adj_index_t ai = ADJ_INDEX_INVALID;
Neale Ranns14053c92019-12-29 23:55:18 +00001004 ip46_address_t nh = ip46_address_initializer;
Neale Rannsb80c5362016-10-08 13:03:40 +01001005 u32 sw_if_index = ~0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001006
1007 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1008 {
Neale Ranns14053c92019-12-29 23:55:18 +00001009 if (unformat (input, "%U",
1010 unformat_vnet_sw_interface, vnet_get_main(),
1011 &sw_if_index))
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001012 ;
Neale Rannsb80c5362016-10-08 13:03:40 +01001013 else if (unformat (input, "%U",
Neale Ranns14053c92019-12-29 23:55:18 +00001014 unformat_ip46_address, &nh, IP46_TYPE_ANY))
1015 ;
1016 else if (unformat (input, "%d", &ai))
Neale Rannsb80c5362016-10-08 13:03:40 +01001017 ;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001018 else
1019 break;
1020 }
1021
1022 if (ADJ_INDEX_INVALID != ai)
1023 {
1024 vlib_cli_output (vm, "[@%d] %U",
1025 ai,
Neale Rannsb80c5362016-10-08 13:03:40 +01001026 format_ip_adjacency, ai,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001027 FORMAT_IP_ADJACENCY_DETAIL);
1028 }
Neale Rannsb80c5362016-10-08 13:03:40 +01001029 else if (~0 != sw_if_index)
1030 {
1031 fib_protocol_t proto;
1032
Neale Ranns14053c92019-12-29 23:55:18 +00001033 if (ip46_address_is_zero(&nh))
1034 {
1035 for (proto = FIB_PROTOCOL_IP4; proto <= FIB_PROTOCOL_IP6; proto++)
1036 {
1037 adj_nbr_walk(sw_if_index, proto,
1038 adj_nbr_show_one,
1039 vm);
1040 }
1041 }
1042 else
1043 {
1044 proto = (ip46_address_is_ip4(&nh) ?
1045 FIB_PROTOCOL_IP4 :
1046 FIB_PROTOCOL_IP6);
1047 adj_nbr_walk_nh(sw_if_index, proto, &nh,
1048 adj_nbr_show_one,
1049 vm);
1050 }
Neale Rannsb80c5362016-10-08 13:03:40 +01001051 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001052 else
1053 {
1054 fib_protocol_t proto;
1055
1056 for (proto = FIB_PROTOCOL_IP4; proto <= FIB_PROTOCOL_IP6; proto++)
1057 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001058 vec_foreach_index(sw_if_index, adj_nbr_tables[proto])
1059 {
Neale Rannsb80c5362016-10-08 13:03:40 +01001060 adj_nbr_walk(sw_if_index, proto,
1061 adj_nbr_show_one,
1062 vm);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001063 }
1064 }
1065 }
1066
1067 return 0;
1068}
1069
Neale Rannsb80c5362016-10-08 13:03:40 +01001070/*?
1071 * Show all neighbour adjacencies.
1072 * @cliexpar
1073 * @cliexstart{sh adj nbr}
1074 * [@2] ipv4 via 1.0.0.2 loop0: IP4: 00:00:22:aa:bb:cc -> 00:00:11:aa:bb:cc
1075 * [@3] mpls via 1.0.0.2 loop0: MPLS_UNICAST: 00:00:22:aa:bb:cc -> 00:00:11:aa:bb:cc
1076 * [@4] ipv4 via 1.0.0.3 loop0: IP4: 00:00:22:aa:bb:cc -> 00:00:11:aa:bb:cc
1077 * [@5] mpls via 1.0.0.3 loop0: MPLS_UNICAST: 00:00:22:aa:bb:cc -> 00:00:11:aa:bb:cc
1078 * @cliexend
1079 ?*/
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001080VLIB_CLI_COMMAND (ip4_show_fib_command, static) = {
1081 .path = "show adj nbr",
Neale Rannsb80c5362016-10-08 13:03:40 +01001082 .short_help = "show adj nbr [<adj_index>] [interface]",
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001083 .function = adj_nbr_show,
1084};
1085
1086u8*
1087format_adj_nbr_incomplete (u8* s, va_list *ap)
1088{
Billy McFallcfcf1e22016-10-14 09:51:49 -04001089 index_t index = va_arg(*ap, index_t);
1090 CLIB_UNUSED(u32 indent) = va_arg(*ap, u32);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001091 vnet_main_t * vnm = vnet_get_main();
1092 ip_adjacency_t * adj = adj_get(index);
1093
Neale Ranns924d03a2016-10-19 08:25:46 +01001094 s = format (s, "arp-%U", format_vnet_link, adj->ia_link);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001095 s = format (s, ": via %U",
Neale Rannsb80c5362016-10-08 13:03:40 +01001096 format_ip46_address, &adj->sub_type.nbr.next_hop,
1097 adj_proto_to_46(adj->ia_nh_proto));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001098 s = format (s, " %U",
Steven70488ab2018-03-28 17:59:00 -07001099 format_vnet_sw_if_index_name,
1100 vnm, adj->rewrite_header.sw_if_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001101
1102 return (s);
1103}
1104
1105u8*
1106format_adj_nbr (u8* s, va_list *ap)
1107{
Billy McFallcfcf1e22016-10-14 09:51:49 -04001108 index_t index = va_arg(*ap, index_t);
1109 CLIB_UNUSED(u32 indent) = va_arg(*ap, u32);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001110 ip_adjacency_t * adj = adj_get(index);
1111
Neale Ranns924d03a2016-10-19 08:25:46 +01001112 s = format (s, "%U", format_vnet_link, adj->ia_link);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001113 s = format (s, " via %U ",
Neale Rannsb80c5362016-10-08 13:03:40 +01001114 format_ip46_address, &adj->sub_type.nbr.next_hop,
1115 adj_proto_to_46(adj->ia_nh_proto));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001116 s = format (s, "%U",
1117 format_vnet_rewrite,
Neale Rannsb069a692017-03-15 12:34:25 -04001118 &adj->rewrite_header, sizeof (adj->rewrite_data), 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001119
1120 return (s);
1121}
1122
1123static void
1124adj_dpo_lock (dpo_id_t *dpo)
1125{
1126 adj_lock(dpo->dpoi_index);
1127}
1128static void
1129adj_dpo_unlock (dpo_id_t *dpo)
1130{
1131 adj_unlock(dpo->dpoi_index);
1132}
1133
Neale Ranns6c3ebcc2016-10-02 21:20:15 +01001134static void
1135adj_mem_show (void)
1136{
1137 fib_show_memory_usage("Adjacency",
1138 pool_elts(adj_pool),
1139 pool_len(adj_pool),
1140 sizeof(ip_adjacency_t));
1141}
1142
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001143const static dpo_vft_t adj_nbr_dpo_vft = {
1144 .dv_lock = adj_dpo_lock,
1145 .dv_unlock = adj_dpo_unlock,
1146 .dv_format = format_adj_nbr,
Neale Ranns6c3ebcc2016-10-02 21:20:15 +01001147 .dv_mem_show = adj_mem_show,
Andrew Yourtchenko5f3fcb92017-10-25 05:50:37 -07001148 .dv_get_urpf = adj_dpo_get_urpf,
Neale Ranns8f5fef22020-12-21 08:29:34 +00001149 .dv_get_mtu = adj_dpo_get_mtu,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001150};
1151const static dpo_vft_t adj_nbr_incompl_dpo_vft = {
1152 .dv_lock = adj_dpo_lock,
1153 .dv_unlock = adj_dpo_unlock,
1154 .dv_format = format_adj_nbr_incomplete,
Andrew Yourtchenko5f3fcb92017-10-25 05:50:37 -07001155 .dv_get_urpf = adj_dpo_get_urpf,
Neale Ranns8f5fef22020-12-21 08:29:34 +00001156 .dv_get_mtu = adj_dpo_get_mtu,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001157};
1158
1159/**
1160 * @brief The per-protocol VLIB graph nodes that are assigned to an adjacency
1161 * object.
1162 *
1163 * this means that these graph nodes are ones from which a nbr is the
1164 * parent object in the DPO-graph.
1165 */
1166const static char* const nbr_ip4_nodes[] =
1167{
Neale Rannsf06aea52016-11-29 06:51:37 -08001168 "ip4-rewrite",
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001169 NULL,
1170};
1171const static char* const nbr_ip6_nodes[] =
1172{
1173 "ip6-rewrite",
1174 NULL,
1175};
1176const static char* const nbr_mpls_nodes[] =
1177{
1178 "mpls-output",
1179 NULL,
1180};
Neale Ranns5e575b12016-10-03 09:40:25 +01001181const static char* const nbr_ethernet_nodes[] =
1182{
1183 "adj-l2-rewrite",
1184 NULL,
1185};
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001186const static char* const * const nbr_nodes[DPO_PROTO_NUM] =
1187{
1188 [DPO_PROTO_IP4] = nbr_ip4_nodes,
1189 [DPO_PROTO_IP6] = nbr_ip6_nodes,
1190 [DPO_PROTO_MPLS] = nbr_mpls_nodes,
Neale Ranns5e575b12016-10-03 09:40:25 +01001191 [DPO_PROTO_ETHERNET] = nbr_ethernet_nodes,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001192};
1193
1194const static char* const nbr_incomplete_ip4_nodes[] =
1195{
1196 "ip4-arp",
1197 NULL,
1198};
1199const static char* const nbr_incomplete_ip6_nodes[] =
1200{
1201 "ip6-discover-neighbor",
1202 NULL,
1203};
1204const static char* const nbr_incomplete_mpls_nodes[] =
1205{
1206 "mpls-adj-incomplete",
1207 NULL,
1208};
1209
1210const static char* const * const nbr_incomplete_nodes[DPO_PROTO_NUM] =
1211{
1212 [DPO_PROTO_IP4] = nbr_incomplete_ip4_nodes,
1213 [DPO_PROTO_IP6] = nbr_incomplete_ip6_nodes,
1214 [DPO_PROTO_MPLS] = nbr_incomplete_mpls_nodes,
1215};
1216
1217void
1218adj_nbr_module_init (void)
1219{
1220 dpo_register(DPO_ADJACENCY,
1221 &adj_nbr_dpo_vft,
1222 nbr_nodes);
1223 dpo_register(DPO_ADJACENCY_INCOMPLETE,
1224 &adj_nbr_incompl_dpo_vft,
1225 nbr_incomplete_nodes);
Neale Rannsea8adf72021-08-13 08:10:59 +00001226
1227 ethernet_address_change_ctx_t ctx = {
1228 .function = adj_nbr_ethernet_change_mac,
1229 .function_opaque = 0,
1230 };
1231 vec_add1 (ethernet_main.address_change_callbacks, ctx);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001232}