blob: 8e6a940befa87b0d369229ed2131de026c27f001 [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>
Neale Ranns5e575b12016-10-03 09:40:25 +010018#include <vnet/adj/adj_l2.h>
Florin Corasce1b4c72017-01-26 14:25:34 -080019#include <vnet/adj/adj_nsh.h>
Neale Ranns5e575b12016-10-03 09:40:25 +010020#include <vnet/adj/adj_midchain.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010021#include <vnet/dpo/drop_dpo.h>
Neale Ranns521a8d72018-12-06 13:46:49 +000022#include <vnet/dpo/load_balance.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010023#include <vnet/fib/fib_walk.h>
Neale Ranns521a8d72018-12-06 13:46:49 +000024#include <vnet/fib/fib_entry.h>
Neale Rannse4031132020-10-26 13:00:06 +000025#include <vnet/ip/ip4_inlines.h>
26#include <vnet/ip/ip6_inlines.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010027
Neale Ranns4ec36c52020-03-31 09:21:29 -040028u8
29adj_is_midchain (adj_index_t ai)
30{
31 ip_adjacency_t *adj;
32
33 adj = adj_get(ai);
34
35 switch (adj->lookup_next_index)
36 {
37 case IP_LOOKUP_NEXT_MIDCHAIN:
38 case IP_LOOKUP_NEXT_MCAST_MIDCHAIN:
39 return (1);
40 case IP_LOOKUP_NEXT_ARP:
41 case IP_LOOKUP_NEXT_GLEAN:
42 case IP_LOOKUP_NEXT_BCAST:
43 case IP_LOOKUP_NEXT_MCAST:
44 case IP_LOOKUP_NEXT_DROP:
45 case IP_LOOKUP_NEXT_PUNT:
46 case IP_LOOKUP_NEXT_LOCAL:
47 case IP_LOOKUP_NEXT_REWRITE:
48 case IP_LOOKUP_NEXT_ICMP_ERROR:
49 case IP_LOOKUP_N_NEXT:
50 return (0);
51 }
52
53 return (0);
54}
Neale Ranns5e575b12016-10-03 09:40:25 +010055
Neale Ranns0bfe5d82016-08-25 15:29:12 +010056static inline u32
Neale Ranns924d03a2016-10-19 08:25:46 +010057adj_get_midchain_node (vnet_link_t link)
Neale Ranns0bfe5d82016-08-25 15:29:12 +010058{
59 switch (link) {
Neale Ranns924d03a2016-10-19 08:25:46 +010060 case VNET_LINK_IP4:
Neale Ranns0bfe5d82016-08-25 15:29:12 +010061 return (ip4_midchain_node.index);
Neale Ranns924d03a2016-10-19 08:25:46 +010062 case VNET_LINK_IP6:
Neale Ranns0bfe5d82016-08-25 15:29:12 +010063 return (ip6_midchain_node.index);
Neale Ranns924d03a2016-10-19 08:25:46 +010064 case VNET_LINK_MPLS:
Neale Ranns0bfe5d82016-08-25 15:29:12 +010065 return (mpls_midchain_node.index);
Neale Ranns924d03a2016-10-19 08:25:46 +010066 case VNET_LINK_ETHERNET:
Neale Ranns5e575b12016-10-03 09:40:25 +010067 return (adj_l2_midchain_node.index);
Florin Corasce1b4c72017-01-26 14:25:34 -080068 case VNET_LINK_NSH:
69 return (adj_nsh_midchain_node.index);
Neale Ranns924d03a2016-10-19 08:25:46 +010070 case VNET_LINK_ARP:
71 break;
Neale Ranns0bfe5d82016-08-25 15:29:12 +010072 }
73 ASSERT(0);
74 return (0);
75}
76
Damjan Marion8b3191e2016-11-09 19:54:20 +010077static u8
Neale Ranns6fdcc3d2021-10-08 07:30:47 +000078adj_midchain_get_feature_arc_index (const ip_adjacency_t *adj)
Neale Ranns5e575b12016-10-03 09:40:25 +010079{
Neale Ranns5e575b12016-10-03 09:40:25 +010080 switch (adj->ia_link)
81 {
Neale Ranns924d03a2016-10-19 08:25:46 +010082 case VNET_LINK_IP4:
Neale Ranns6fdcc3d2021-10-08 07:30:47 +000083 return ip4_main.lookup_main.output_feature_arc_index;
Neale Ranns924d03a2016-10-19 08:25:46 +010084 case VNET_LINK_IP6:
Neale Ranns6fdcc3d2021-10-08 07:30:47 +000085 return ip6_main.lookup_main.output_feature_arc_index;
Neale Ranns924d03a2016-10-19 08:25:46 +010086 case VNET_LINK_MPLS:
Neale Ranns6fdcc3d2021-10-08 07:30:47 +000087 return mpls_main.output_feature_arc_index;
Neale Ranns924d03a2016-10-19 08:25:46 +010088 case VNET_LINK_ETHERNET:
Neale Ranns6fdcc3d2021-10-08 07:30:47 +000089 return ethernet_main.output_feature_arc_index;
Florin Corasce1b4c72017-01-26 14:25:34 -080090 case VNET_LINK_NSH:
Neale Ranns924d03a2016-10-19 08:25:46 +010091 case VNET_LINK_ARP:
Neale Ranns924d03a2016-10-19 08:25:46 +010092 break;
Neale Ranns5e575b12016-10-03 09:40:25 +010093 }
Neale Ranns6fdcc3d2021-10-08 07:30:47 +000094 ASSERT (0);
95 return (0);
Neale Ranns5e575b12016-10-03 09:40:25 +010096}
97
Neale Rannsfa5d1982017-02-20 14:19:51 -080098static u32
99adj_nbr_midchain_get_tx_node (ip_adjacency_t *adj)
100{
Neale Ranns6fdcc3d2021-10-08 07:30:47 +0000101 return (adj_midchain_tx.index);
102}
103
104static u32
105adj_nbr_midchain_get_next_node (ip_adjacency_t *adj)
106{
107 return (vnet_feature_get_end_node(adj_midchain_get_feature_arc_index(adj),
108 adj->rewrite_header.sw_if_index));
Neale Rannsfa5d1982017-02-20 14:19:51 -0800109}
110
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100111/**
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800112 * adj_midchain_setup
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100113 *
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800114 * Setup the adj as a mid-chain
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100115 */
116void
Neale Ranns3ebebc32020-02-18 13:56:24 +0000117adj_midchain_teardown (ip_adjacency_t *adj)
118{
Neale Ranns3ebebc32020-02-18 13:56:24 +0000119 dpo_reset(&adj->sub_type.midchain.next_dpo);
Neale Ranns3ebebc32020-02-18 13:56:24 +0000120}
121
122/**
123 * adj_midchain_setup
124 *
125 * Setup the adj as a mid-chain
126 */
127void
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800128adj_midchain_setup (adj_index_t adj_index,
129 adj_midchain_fixup_t fixup,
Neale Rannsdb14f5a2018-01-29 10:43:33 -0800130 const void *data,
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800131 adj_flags_t flags)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100132{
133 ip_adjacency_t *adj;
134
135 ASSERT(ADJ_INDEX_INVALID != adj_index);
136
137 adj = adj_get(adj_index);
Neale Rannsb80c5362016-10-08 13:03:40 +0100138
Neale Ranns5e575b12016-10-03 09:40:25 +0100139 adj->sub_type.midchain.fixup_func = fixup;
Neale Rannsdb14f5a2018-01-29 10:43:33 -0800140 adj->sub_type.midchain.fixup_data = data;
Neale Ranns521a8d72018-12-06 13:46:49 +0000141 adj->sub_type.midchain.fei = FIB_NODE_INDEX_INVALID;
Neale Rannsfa5d1982017-02-20 14:19:51 -0800142 adj->ia_flags |= flags;
Neale Ranns5e575b12016-10-03 09:40:25 +0100143
Neale Ranns4ec36c52020-03-31 09:21:29 -0400144 if (flags & ADJ_FLAG_MIDCHAIN_FIXUP_IP4O4_HDR)
145 {
146 adj->rewrite_header.flags |= VNET_REWRITE_FIXUP_IP4_O_4;
147 }
148 else
149 {
150 adj->rewrite_header.flags &= ~VNET_REWRITE_FIXUP_IP4_O_4;
151 }
Neale Ranns5c544c82020-11-17 09:47:07 +0000152 if (!(flags & ADJ_FLAG_MIDCHAIN_FIXUP_FLOW_HASH))
153 {
154 adj->rewrite_header.flags &= ~VNET_REWRITE_FIXUP_FLOW_HASH;
155 }
Neale Ranns4ec36c52020-03-31 09:21:29 -0400156
Neale Rannsb80c5362016-10-08 13:03:40 +0100157 /*
158 * stack the midchain on the drop so it's ready to forward in the adj-midchain-tx.
159 * The graph arc used/created here is from the midchain-tx node to the
160 * child's registered node. This is because post adj processing the next
161 * node are any output features, then the midchain-tx. from there we
162 * need to get to the stacked child's node.
163 */
Neale Ranns6fdcc3d2021-10-08 07:30:47 +0000164 dpo_stack_from_node(adj_nbr_midchain_get_tx_node(adj),
Neale Ranns43161a82017-08-12 02:12:00 -0700165 &adj->sub_type.midchain.next_dpo,
166 drop_dpo_get(vnet_link_to_dpo_proto(adj->ia_link)));
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800167}
168
169/**
170 * adj_nbr_midchain_update_rewrite
171 *
172 * Update the adjacency's rewrite string. A NULL string implies the
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700173 * rewrite is reset (i.e. when ARP/ND entry is gone).
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800174 * NB: the adj being updated may be handling traffic in the DP.
175 */
176void
177adj_nbr_midchain_update_rewrite (adj_index_t adj_index,
178 adj_midchain_fixup_t fixup,
Neale Rannsdb14f5a2018-01-29 10:43:33 -0800179 const void *fixup_data,
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800180 adj_flags_t flags,
181 u8 *rewrite)
182{
183 ip_adjacency_t *adj;
184
185 ASSERT(ADJ_INDEX_INVALID != adj_index);
186
187 adj = adj_get(adj_index);
188
189 /*
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700190 * one time only update. since we don't support changing the tunnel
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800191 * src,dst, this is all we need.
192 */
Neale Ranns174959c2020-02-03 10:33:51 +0000193 if (adj->lookup_next_index != IP_LOOKUP_NEXT_MIDCHAIN &&
Neale Ranns14053c92019-12-29 23:55:18 +0000194 adj->lookup_next_index != IP_LOOKUP_NEXT_MCAST_MIDCHAIN)
195 {
196 adj_midchain_setup(adj_index, fixup, fixup_data, flags);
197 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100198
Neale Rannsb80c5362016-10-08 13:03:40 +0100199 /*
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700200 * update the rewrite with the workers paused.
Neale Rannsb80c5362016-10-08 13:03:40 +0100201 */
202 adj_nbr_update_rewrite_internal(adj,
203 IP_LOOKUP_NEXT_MIDCHAIN,
204 adj_get_midchain_node(adj->ia_link),
Neale Ranns6fdcc3d2021-10-08 07:30:47 +0000205 adj_nbr_midchain_get_next_node(adj),
Neale Rannsb80c5362016-10-08 13:03:40 +0100206 rewrite);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100207}
208
Neale Ranns4ec36c52020-03-31 09:21:29 -0400209void
210adj_nbr_midchain_update_next_node (adj_index_t adj_index,
211 u32 next_node)
212{
213 ip_adjacency_t *adj;
214 vlib_main_t * vm;
215
216 ASSERT(ADJ_INDEX_INVALID != adj_index);
217
218 adj = adj_get(adj_index);
219 vm = vlib_get_main();
220
221 vlib_worker_thread_barrier_sync(vm);
222
223 adj->rewrite_header.next_index = vlib_node_add_next(vlib_get_main(),
224 adj->ia_node_index,
225 next_node);
226
Neale Ranns4ec36c52020-03-31 09:21:29 -0400227 vlib_worker_thread_barrier_release(vm);
228}
229
230void
Neale Ranns5d0136f2020-05-12 08:51:02 +0000231adj_nbr_midchain_reset_next_node (adj_index_t adj_index)
Neale Ranns4ec36c52020-03-31 09:21:29 -0400232{
233 ip_adjacency_t *adj;
234 vlib_main_t * vm;
235
236 ASSERT(ADJ_INDEX_INVALID != adj_index);
237
238 adj = adj_get(adj_index);
239 vm = vlib_get_main();
240
241 vlib_worker_thread_barrier_sync(vm);
242
243 adj->rewrite_header.next_index =
244 vlib_node_add_next(vlib_get_main(),
245 adj->ia_node_index,
Neale Ranns6fdcc3d2021-10-08 07:30:47 +0000246 adj_nbr_midchain_get_next_node(adj));
Neale Ranns4ec36c52020-03-31 09:21:29 -0400247
248 vlib_worker_thread_barrier_release(vm);
249}
250
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100251/**
Neale Ranns5e575b12016-10-03 09:40:25 +0100252 * adj_nbr_midchain_unstack
253 *
254 * Unstack the adj. stack it on drop
255 */
256void
257adj_nbr_midchain_unstack (adj_index_t adj_index)
258{
Neale Ranns521a8d72018-12-06 13:46:49 +0000259 fib_node_index_t *entry_indicies, tmp;
Neale Ranns5e575b12016-10-03 09:40:25 +0100260 ip_adjacency_t *adj;
261
262 ASSERT(ADJ_INDEX_INVALID != adj_index);
Neale Ranns521a8d72018-12-06 13:46:49 +0000263 adj = adj_get (adj_index);
Neale Ranns5e575b12016-10-03 09:40:25 +0100264
Neale Ranns521a8d72018-12-06 13:46:49 +0000265 /*
266 * check to see if this unstacking breaks a recursion loop
267 */
268 entry_indicies = NULL;
269 tmp = adj->sub_type.midchain.fei;
270 adj->sub_type.midchain.fei = FIB_NODE_INDEX_INVALID;
271
272 if (FIB_NODE_INDEX_INVALID != tmp)
273 {
274 fib_entry_recursive_loop_detect(tmp, &entry_indicies);
275 vec_free(entry_indicies);
276 }
Neale Ranns5e575b12016-10-03 09:40:25 +0100277
278 /*
279 * stack on the drop
280 */
281 dpo_stack(DPO_ADJACENCY_MIDCHAIN,
Neale Ranns43161a82017-08-12 02:12:00 -0700282 vnet_link_to_dpo_proto(adj->ia_link),
283 &adj->sub_type.midchain.next_dpo,
284 drop_dpo_get(vnet_link_to_dpo_proto(adj->ia_link)));
Neale Ranns5e575b12016-10-03 09:40:25 +0100285 CLIB_MEMORY_BARRIER();
286}
287
Neale Ranns521a8d72018-12-06 13:46:49 +0000288void
289adj_nbr_midchain_stack_on_fib_entry (adj_index_t ai,
290 fib_node_index_t fei,
291 fib_forward_chain_type_t fct)
292{
293 fib_node_index_t *entry_indicies;
294 dpo_id_t tmp = DPO_INVALID;
295 ip_adjacency_t *adj;
296
297 adj = adj_get (ai);
298
299 /*
300 * check to see if this stacking will form a recursion loop
301 */
302 entry_indicies = NULL;
303 adj->sub_type.midchain.fei = fei;
304
305 if (fib_entry_recursive_loop_detect(adj->sub_type.midchain.fei, &entry_indicies))
306 {
307 /*
308 * loop formed, stack on the drop.
309 */
310 dpo_copy(&tmp, drop_dpo_get(fib_forw_chain_type_to_dpo_proto(fct)));
311 }
312 else
313 {
314 fib_entry_contribute_forwarding (fei, fct, &tmp);
315
Neale Ranns5c544c82020-11-17 09:47:07 +0000316 if (DPO_LOAD_BALANCE == tmp.dpoi_type)
Neale Ranns521a8d72018-12-06 13:46:49 +0000317 {
Neale Ranns521a8d72018-12-06 13:46:49 +0000318 load_balance_t *lb;
Neale Ranns521a8d72018-12-06 13:46:49 +0000319
320 lb = load_balance_get (tmp.dpoi_index);
321
Neale Ranns5c544c82020-11-17 09:47:07 +0000322 if ((adj->ia_flags & ADJ_FLAG_MIDCHAIN_IP_STACK) ||
323 lb->lb_n_buckets == 1)
Neale Ranns521a8d72018-12-06 13:46:49 +0000324 {
Neale Ranns5c544c82020-11-17 09:47:07 +0000325 /*
326 * do that hash now and stack on the choice.
327 * If the choice is an incomplete adj then we will need a poke when
328 * it becomes complete. This happens since the adj update walk propagates
329 * as far a recursive paths.
330 */
331 const dpo_id_t *choice;
332 int hash;
Neale Ranns521a8d72018-12-06 13:46:49 +0000333
Neale Ranns5c544c82020-11-17 09:47:07 +0000334 if (FIB_FORW_CHAIN_TYPE_UNICAST_IP4 == fct)
335 {
336 hash = ip4_compute_flow_hash ((ip4_header_t *) adj_get_rewrite (ai),
337 lb->lb_hash_config);
338 }
339 else if (FIB_FORW_CHAIN_TYPE_UNICAST_IP6 == fct)
340 {
341 hash = ip6_compute_flow_hash ((ip6_header_t *) adj_get_rewrite (ai),
342 lb->lb_hash_config);
343 }
344 else
345 {
346 hash = 0;
347 ASSERT(0);
348 }
349
350 choice = load_balance_get_bucket_i (lb, hash & lb->lb_n_buckets_minus_1);
351 dpo_copy (&tmp, choice);
352 }
Neale Ranns65d789e2021-02-08 15:24:56 +0000353 else if (lb->lb_n_buckets > 1)
Neale Ranns5c544c82020-11-17 09:47:07 +0000354 {
Neale Ranns65d789e2021-02-08 15:24:56 +0000355 /*
356 * the client has chosen not to use the stacking to select a
357 * bucket, and there are more than one buckets. there's no
358 * value in using the midchain's fixed rewrite string to select
359 * the path, so force a flow hash on the inner.
360 */
361 adj->rewrite_header.flags |= VNET_REWRITE_FIXUP_FLOW_HASH;
362 }
363
364 if (adj->ia_flags & ADJ_FLAG_MIDCHAIN_FIXUP_FLOW_HASH)
365 {
366 /*
367 * The client, for reasons unbeknownst to adj, wants to force
368 * a flow hash on the inner, we will oblige.
369 */
Neale Ranns5c544c82020-11-17 09:47:07 +0000370 adj->rewrite_header.flags |= VNET_REWRITE_FIXUP_FLOW_HASH;
371 }
Neale Ranns521a8d72018-12-06 13:46:49 +0000372 }
373 }
374 adj_nbr_midchain_stack (ai, &tmp);
375 dpo_reset(&tmp);
376 vec_free(entry_indicies);
377}
378
Neale Ranns5e575b12016-10-03 09:40:25 +0100379/**
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100380 * adj_nbr_midchain_stack
381 */
382void
383adj_nbr_midchain_stack (adj_index_t adj_index,
384 const dpo_id_t *next)
385{
386 ip_adjacency_t *adj;
387
388 ASSERT(ADJ_INDEX_INVALID != adj_index);
389
390 adj = adj_get(adj_index);
391
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800392 ASSERT((IP_LOOKUP_NEXT_MIDCHAIN == adj->lookup_next_index) ||
393 (IP_LOOKUP_NEXT_MCAST_MIDCHAIN == adj->lookup_next_index));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100394
Neale Rannsfa5d1982017-02-20 14:19:51 -0800395 dpo_stack_from_node(adj_nbr_midchain_get_tx_node(adj),
Neale Ranns5e575b12016-10-03 09:40:25 +0100396 &adj->sub_type.midchain.next_dpo,
397 next);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100398}
399
Neale Ranns521a8d72018-12-06 13:46:49 +0000400int
401adj_ndr_midchain_recursive_loop_detect (adj_index_t ai,
402 fib_node_index_t **entry_indicies)
403{
404 fib_node_index_t *entry_index, *entries;
405 ip_adjacency_t * adj;
406
407 adj = adj_get(ai);
408 entries = *entry_indicies;
409
410 vec_foreach(entry_index, entries)
411 {
412 if (*entry_index == adj->sub_type.midchain.fei)
413 {
414 /*
415 * The entry this midchain links to is already in the set
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700416 * of visited entries, this is a loop
Neale Ranns521a8d72018-12-06 13:46:49 +0000417 */
418 adj->ia_flags |= ADJ_FLAG_MIDCHAIN_LOOPED;
419 return (1);
420 }
421 }
422
423 adj->ia_flags &= ~ADJ_FLAG_MIDCHAIN_LOOPED;
424 return (0);
425}
426
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100427u8*
428format_adj_midchain (u8* s, va_list *ap)
429{
Billy McFallcfcf1e22016-10-14 09:51:49 -0400430 index_t index = va_arg(*ap, index_t);
431 u32 indent = va_arg(*ap, u32);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100432 ip_adjacency_t * adj = adj_get(index);
433
Neale Ranns924d03a2016-10-19 08:25:46 +0100434 s = format (s, "%U", format_vnet_link, adj->ia_link);
Neale Ranns25edf142019-03-22 08:12:48 +0000435 if (adj->rewrite_header.flags & VNET_REWRITE_HAS_FEATURES)
436 s = format(s, " [features]");
Neale Rannsc819fc62018-02-16 02:44:05 -0800437 s = format (s, " via %U",
438 format_ip46_address, &adj->sub_type.nbr.next_hop,
439 adj_proto_to_46(adj->ia_nh_proto));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100440 s = format (s, " %U",
Neale Ranns5e575b12016-10-03 09:40:25 +0100441 format_vnet_rewrite,
Neale Rannsb069a692017-03-15 12:34:25 -0400442 &adj->rewrite_header, sizeof (adj->rewrite_data), indent);
Neale Ranns521a8d72018-12-06 13:46:49 +0000443 s = format (s, "\n%Ustacked-on",
444 format_white_space, indent);
445
446 if (FIB_NODE_INDEX_INVALID != adj->sub_type.midchain.fei)
447 {
448 s = format (s, " entry:%d", adj->sub_type.midchain.fei);
449
450 }
451 s = format (s, ":\n%U%U",
Neale Ranns43161a82017-08-12 02:12:00 -0700452 format_white_space, indent+2,
453 format_dpo_id, &adj->sub_type.midchain.next_dpo, indent+2);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100454
455 return (s);
456}
457
458static void
459adj_dpo_lock (dpo_id_t *dpo)
460{
461 adj_lock(dpo->dpoi_index);
462}
463static void
464adj_dpo_unlock (dpo_id_t *dpo)
465{
466 adj_unlock(dpo->dpoi_index);
467}
468
469const static dpo_vft_t adj_midchain_dpo_vft = {
470 .dv_lock = adj_dpo_lock,
471 .dv_unlock = adj_dpo_unlock,
472 .dv_format = format_adj_midchain,
Andrew Yourtchenko5f3fcb92017-10-25 05:50:37 -0700473 .dv_get_urpf = adj_dpo_get_urpf,
Neale Ranns8f5fef22020-12-21 08:29:34 +0000474 .dv_get_mtu = adj_dpo_get_mtu,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100475};
476
477/**
478 * @brief The per-protocol VLIB graph nodes that are assigned to a midchain
479 * object.
480 *
481 * this means that these graph nodes are ones from which a midchain is the
482 * parent object in the DPO-graph.
483 */
484const static char* const midchain_ip4_nodes[] =
485{
486 "ip4-midchain",
487 NULL,
488};
489const static char* const midchain_ip6_nodes[] =
490{
491 "ip6-midchain",
492 NULL,
493};
494const static char* const midchain_mpls_nodes[] =
495{
496 "mpls-midchain",
497 NULL,
498};
Neale Ranns5e575b12016-10-03 09:40:25 +0100499const static char* const midchain_ethernet_nodes[] =
500{
501 "adj-l2-midchain",
502 NULL,
503};
Florin Corasb69111e2017-02-13 23:55:27 -0800504const static char* const midchain_nsh_nodes[] =
505{
506 "adj-nsh-midchain",
507 NULL,
508};
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100509
510const static char* const * const midchain_nodes[DPO_PROTO_NUM] =
511{
512 [DPO_PROTO_IP4] = midchain_ip4_nodes,
513 [DPO_PROTO_IP6] = midchain_ip6_nodes,
514 [DPO_PROTO_MPLS] = midchain_mpls_nodes,
Neale Ranns5e575b12016-10-03 09:40:25 +0100515 [DPO_PROTO_ETHERNET] = midchain_ethernet_nodes,
Florin Corasb69111e2017-02-13 23:55:27 -0800516 [DPO_PROTO_NSH] = midchain_nsh_nodes,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100517};
518
519void
520adj_midchain_module_init (void)
521{
522 dpo_register(DPO_ADJACENCY_MIDCHAIN, &adj_midchain_dpo_vft, midchain_nodes);
523}