blob: 49ac24aa49c11619821fda48c493b2da3c9aa5d1 [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/ethernet/arp_packet.h>
22#include <vnet/dpo/drop_dpo.h>
Neale Ranns521a8d72018-12-06 13:46:49 +000023#include <vnet/dpo/load_balance.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010024#include <vnet/fib/fib_walk.h>
Neale Ranns521a8d72018-12-06 13:46:49 +000025#include <vnet/fib/fib_entry.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010026
Neale Ranns5e575b12016-10-03 09:40:25 +010027/**
Neale Ranns5e575b12016-10-03 09:40:25 +010028 * @brief Trace data for packets traversing the midchain tx node
29 */
30typedef struct adj_midchain_tx_trace_t_
31{
32 /**
33 * @brief the midchain adj we are traversing
34 */
35 adj_index_t ai;
36} adj_midchain_tx_trace_t;
37
38always_inline uword
Damjan Marion77766a12016-11-02 01:21:05 +010039adj_midchain_tx_inline (vlib_main_t * vm,
Neale Ranns5e575b12016-10-03 09:40:25 +010040 vlib_node_runtime_t * node,
41 vlib_frame_t * frame,
42 int interface_count)
43{
Neale Ranns4ec36c52020-03-31 09:21:29 -040044 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
45 u16 nexts[VLIB_FRAME_SIZE], *next;
46 u32 * from, n_left, thread_index;
Neale Ranns5e575b12016-10-03 09:40:25 +010047 vnet_main_t *vnm = vnet_get_main ();
48 vnet_interface_main_t *im = &vnm->interface_main;
Neale Ranns5e575b12016-10-03 09:40:25 +010049
Neale Ranns4ec36c52020-03-31 09:21:29 -040050 thread_index = vm->thread_index;
51 n_left = frame->n_vectors;
Neale Ranns5e575b12016-10-03 09:40:25 +010052 from = vlib_frame_vector_args (frame);
53
Neale Ranns4ec36c52020-03-31 09:21:29 -040054 vlib_get_buffers (vm, from, bufs, n_left);
Neale Ranns5e575b12016-10-03 09:40:25 +010055
Neale Ranns4ec36c52020-03-31 09:21:29 -040056 next = nexts;
57 b = bufs;
Neale Ranns5e575b12016-10-03 09:40:25 +010058
Neale Ranns4ec36c52020-03-31 09:21:29 -040059 while (n_left > 8)
Neale Ranns5e575b12016-10-03 09:40:25 +010060 {
Neale Ranns4ec36c52020-03-31 09:21:29 -040061 u32 adj_index0, adj_index1, adj_index2, adj_index3;
62 const ip_adjacency_t *adj0, *adj1, *adj2, *adj3;
63 const dpo_id_t *dpo0, *dpo1, *dpo2, *dpo3;
Neale Ranns5e575b12016-10-03 09:40:25 +010064
Neale Ranns4ec36c52020-03-31 09:21:29 -040065 /* Prefetch next iteration. */
66 {
67 vlib_prefetch_buffer_header (b[4], LOAD);
68 vlib_prefetch_buffer_header (b[5], LOAD);
69 vlib_prefetch_buffer_header (b[6], LOAD);
70 vlib_prefetch_buffer_header (b[7], LOAD);
71 }
Neale Rannsd3b85b02016-10-22 15:17:21 -070072
Neale Ranns4ec36c52020-03-31 09:21:29 -040073 /* Follow the DPO on which the midchain is stacked */
74 adj_index0 = vnet_buffer(b[0])->ip.adj_index[VLIB_TX];
75 adj_index1 = vnet_buffer(b[1])->ip.adj_index[VLIB_TX];
76 adj_index2 = vnet_buffer(b[2])->ip.adj_index[VLIB_TX];
77 adj_index3 = vnet_buffer(b[3])->ip.adj_index[VLIB_TX];
Neale Rannsd3b85b02016-10-22 15:17:21 -070078
Neale Ranns4ec36c52020-03-31 09:21:29 -040079 adj0 = adj_get(adj_index0);
80 adj1 = adj_get(adj_index1);
81 adj2 = adj_get(adj_index2);
82 adj3 = adj_get(adj_index3);
Neale Rannsd3b85b02016-10-22 15:17:21 -070083
Neale Ranns4ec36c52020-03-31 09:21:29 -040084 dpo0 = &adj0->sub_type.midchain.next_dpo;
85 dpo1 = &adj1->sub_type.midchain.next_dpo;
86 dpo2 = &adj2->sub_type.midchain.next_dpo;
87 dpo3 = &adj3->sub_type.midchain.next_dpo;
Neale Rannsd3b85b02016-10-22 15:17:21 -070088
Neale Ranns4ec36c52020-03-31 09:21:29 -040089 next[0] = dpo0->dpoi_next_node;
90 next[1] = dpo1->dpoi_next_node;
91 next[2] = dpo2->dpoi_next_node;
92 next[3] = dpo3->dpoi_next_node;
Neale Rannsd3b85b02016-10-22 15:17:21 -070093
Neale Ranns4ec36c52020-03-31 09:21:29 -040094 vnet_buffer(b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
95 vnet_buffer(b[1])->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
96 vnet_buffer(b[2])->ip.adj_index[VLIB_TX] = dpo2->dpoi_index;
97 vnet_buffer(b[3])->ip.adj_index[VLIB_TX] = dpo3->dpoi_index;
Neale Rannsd3b85b02016-10-22 15:17:21 -070098
Neale Ranns4ec36c52020-03-31 09:21:29 -040099 if (interface_count)
100 {
101 vlib_increment_combined_counter (im->combined_sw_if_counters
102 + VNET_INTERFACE_COUNTER_TX,
103 thread_index,
104 adj0->rewrite_header.sw_if_index,
105 1,
106 vlib_buffer_length_in_chain (vm, b[0]));
107 vlib_increment_combined_counter (im->combined_sw_if_counters
108 + VNET_INTERFACE_COUNTER_TX,
109 thread_index,
110 adj1->rewrite_header.sw_if_index,
111 1,
112 vlib_buffer_length_in_chain (vm, b[1]));
113 vlib_increment_combined_counter (im->combined_sw_if_counters
114 + VNET_INTERFACE_COUNTER_TX,
115 thread_index,
116 adj2->rewrite_header.sw_if_index,
117 1,
118 vlib_buffer_length_in_chain (vm, b[2]));
119 vlib_increment_combined_counter (im->combined_sw_if_counters
120 + VNET_INTERFACE_COUNTER_TX,
121 thread_index,
122 adj3->rewrite_header.sw_if_index,
123 1,
124 vlib_buffer_length_in_chain (vm, b[3]));
125 }
Neale Rannsd3b85b02016-10-22 15:17:21 -0700126
Neale Ranns4ec36c52020-03-31 09:21:29 -0400127 if (PREDICT_FALSE(node->flags & VLIB_NODE_FLAG_TRACE))
128 {
129 if (PREDICT_FALSE(b[0]->flags & VLIB_BUFFER_IS_TRACED))
130 {
131 adj_midchain_tx_trace_t *tr = vlib_add_trace (vm, node,
132 b[0], sizeof (*tr));
133 tr->ai = adj_index0;
134 }
135 if (PREDICT_FALSE(b[1]->flags & VLIB_BUFFER_IS_TRACED))
136 {
137 adj_midchain_tx_trace_t *tr = vlib_add_trace (vm, node,
138 b[1], sizeof (*tr));
139 tr->ai = adj_index1;
140 }
141 if (PREDICT_FALSE(b[2]->flags & VLIB_BUFFER_IS_TRACED))
142 {
143 adj_midchain_tx_trace_t *tr = vlib_add_trace (vm, node,
144 b[2], sizeof (*tr));
145 tr->ai = adj_index2;
146 }
147 if (PREDICT_FALSE(b[3]->flags & VLIB_BUFFER_IS_TRACED))
148 {
149 adj_midchain_tx_trace_t *tr = vlib_add_trace (vm, node,
150 b[3], sizeof (*tr));
151 tr->ai = adj_index3;
152 }
153 }
154 n_left -= 4;
155 b += 4;
156 next += 4;
Neale Ranns5e575b12016-10-03 09:40:25 +0100157 }
158
Neale Ranns4ec36c52020-03-31 09:21:29 -0400159 while (n_left)
160 {
161 const ip_adjacency_t * adj0;
162 const dpo_id_t *dpo0;
163 u32 adj_index0;
164
165 /* Follow the DPO on which the midchain is stacked */
166 adj_index0 = vnet_buffer(b[0])->ip.adj_index[VLIB_TX];
167 adj0 = adj_get(adj_index0);
168 dpo0 = &adj0->sub_type.midchain.next_dpo;
169 next[0] = dpo0->dpoi_next_node;
170 vnet_buffer(b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
171
172 if (interface_count)
173 {
174 vlib_increment_combined_counter (im->combined_sw_if_counters
175 + VNET_INTERFACE_COUNTER_TX,
176 thread_index,
177 adj0->rewrite_header.sw_if_index,
178 1,
179 vlib_buffer_length_in_chain (vm, b[0]));
180 }
181
182 if (PREDICT_FALSE(b[0]->flags & VLIB_BUFFER_IS_TRACED))
183 {
184 adj_midchain_tx_trace_t *tr = vlib_add_trace (vm, node,
185 b[0], sizeof (*tr));
186 tr->ai = adj_index0;
187 }
188
189 n_left -= 1;
190 b += 1;
191 next += 1;
192 }
193
194 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
195
Neale Ranns5e575b12016-10-03 09:40:25 +0100196 return frame->n_vectors;
197}
198
199static u8 *
200format_adj_midchain_tx_trace (u8 * s, va_list * args)
201{
202 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
203 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
204 adj_midchain_tx_trace_t *tr = va_arg (*args, adj_midchain_tx_trace_t*);
205
206 s = format(s, "adj-midchain:[%d]:%U", tr->ai,
Neale Rannsb80c5362016-10-08 13:03:40 +0100207 format_ip_adjacency, tr->ai,
Neale Ranns5e575b12016-10-03 09:40:25 +0100208 FORMAT_IP_ADJACENCY_NONE);
209
210 return (s);
211}
212
213static uword
214adj_midchain_tx (vlib_main_t * vm,
215 vlib_node_runtime_t * node,
216 vlib_frame_t * frame)
217{
Damjan Marion77766a12016-11-02 01:21:05 +0100218 return (adj_midchain_tx_inline(vm, node, frame, 1));
Neale Ranns5e575b12016-10-03 09:40:25 +0100219}
220
Neale Ranns4ec36c52020-03-31 09:21:29 -0400221VLIB_REGISTER_NODE (adj_midchain_tx_node) = {
Neale Ranns5e575b12016-10-03 09:40:25 +0100222 .function = adj_midchain_tx,
223 .name = "adj-midchain-tx",
224 .vector_size = sizeof (u32),
225
226 .format_trace = format_adj_midchain_tx_trace,
227
228 .n_next_nodes = 1,
229 .next_nodes = {
230 [0] = "error-drop",
231 },
232};
233
234static uword
235adj_midchain_tx_no_count (vlib_main_t * vm,
236 vlib_node_runtime_t * node,
237 vlib_frame_t * frame)
238{
Damjan Marion77766a12016-11-02 01:21:05 +0100239 return (adj_midchain_tx_inline(vm, node, frame, 0));
Neale Ranns5e575b12016-10-03 09:40:25 +0100240}
241
Neale Ranns4ec36c52020-03-31 09:21:29 -0400242VLIB_REGISTER_NODE (adj_midchain_tx_no_count_node) = {
Neale Ranns5e575b12016-10-03 09:40:25 +0100243 .function = adj_midchain_tx_no_count,
244 .name = "adj-midchain-tx-no-count",
245 .vector_size = sizeof (u32),
246
247 .format_trace = format_adj_midchain_tx_trace,
Neale Ranns4ec36c52020-03-31 09:21:29 -0400248 .sibling_of = "adj-midchain-tx",
Neale Ranns5e575b12016-10-03 09:40:25 +0100249};
250
Neale Ranns4ec36c52020-03-31 09:21:29 -0400251#ifndef CLIB_MARCH_VARIANT
252
253u8
254adj_is_midchain (adj_index_t ai)
255{
256 ip_adjacency_t *adj;
257
258 adj = adj_get(ai);
259
260 switch (adj->lookup_next_index)
261 {
262 case IP_LOOKUP_NEXT_MIDCHAIN:
263 case IP_LOOKUP_NEXT_MCAST_MIDCHAIN:
264 return (1);
265 case IP_LOOKUP_NEXT_ARP:
266 case IP_LOOKUP_NEXT_GLEAN:
267 case IP_LOOKUP_NEXT_BCAST:
268 case IP_LOOKUP_NEXT_MCAST:
269 case IP_LOOKUP_NEXT_DROP:
270 case IP_LOOKUP_NEXT_PUNT:
271 case IP_LOOKUP_NEXT_LOCAL:
272 case IP_LOOKUP_NEXT_REWRITE:
273 case IP_LOOKUP_NEXT_ICMP_ERROR:
274 case IP_LOOKUP_N_NEXT:
275 return (0);
276 }
277
278 return (0);
279}
Neale Ranns5e575b12016-10-03 09:40:25 +0100280
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100281static inline u32
Neale Ranns924d03a2016-10-19 08:25:46 +0100282adj_get_midchain_node (vnet_link_t link)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100283{
284 switch (link) {
Neale Ranns924d03a2016-10-19 08:25:46 +0100285 case VNET_LINK_IP4:
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100286 return (ip4_midchain_node.index);
Neale Ranns924d03a2016-10-19 08:25:46 +0100287 case VNET_LINK_IP6:
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100288 return (ip6_midchain_node.index);
Neale Ranns924d03a2016-10-19 08:25:46 +0100289 case VNET_LINK_MPLS:
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100290 return (mpls_midchain_node.index);
Neale Ranns924d03a2016-10-19 08:25:46 +0100291 case VNET_LINK_ETHERNET:
Neale Ranns5e575b12016-10-03 09:40:25 +0100292 return (adj_l2_midchain_node.index);
Florin Corasce1b4c72017-01-26 14:25:34 -0800293 case VNET_LINK_NSH:
294 return (adj_nsh_midchain_node.index);
Neale Ranns924d03a2016-10-19 08:25:46 +0100295 case VNET_LINK_ARP:
296 break;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100297 }
298 ASSERT(0);
299 return (0);
300}
301
Damjan Marion8b3191e2016-11-09 19:54:20 +0100302static u8
303adj_midchain_get_feature_arc_index_for_link_type (const ip_adjacency_t *adj)
Neale Ranns5e575b12016-10-03 09:40:25 +0100304{
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800305 u8 arc = (u8) ~0;
Neale Ranns5e575b12016-10-03 09:40:25 +0100306 switch (adj->ia_link)
307 {
Neale Ranns924d03a2016-10-19 08:25:46 +0100308 case VNET_LINK_IP4:
Neale Ranns5e575b12016-10-03 09:40:25 +0100309 {
Damjan Marion8b3191e2016-11-09 19:54:20 +0100310 arc = ip4_main.lookup_main.output_feature_arc_index;
Neale Ranns5e575b12016-10-03 09:40:25 +0100311 break;
312 }
Neale Ranns924d03a2016-10-19 08:25:46 +0100313 case VNET_LINK_IP6:
Neale Ranns5e575b12016-10-03 09:40:25 +0100314 {
Damjan Marion8b3191e2016-11-09 19:54:20 +0100315 arc = ip6_main.lookup_main.output_feature_arc_index;
Neale Ranns5e575b12016-10-03 09:40:25 +0100316 break;
317 }
Neale Ranns924d03a2016-10-19 08:25:46 +0100318 case VNET_LINK_MPLS:
Neale Ranns5e575b12016-10-03 09:40:25 +0100319 {
Damjan Marion8b3191e2016-11-09 19:54:20 +0100320 arc = mpls_main.output_feature_arc_index;
Neale Ranns5e575b12016-10-03 09:40:25 +0100321 break;
322 }
Neale Ranns924d03a2016-10-19 08:25:46 +0100323 case VNET_LINK_ETHERNET:
Neale Ranns5e575b12016-10-03 09:40:25 +0100324 {
Damjan Marion8b3191e2016-11-09 19:54:20 +0100325 arc = ethernet_main.output_feature_arc_index;
Neale Ranns5e575b12016-10-03 09:40:25 +0100326 break;
327 }
Florin Corasce1b4c72017-01-26 14:25:34 -0800328 case VNET_LINK_NSH:
329 {
Dave Barach11fb09e2020-08-06 12:10:09 -0400330 arc = nsh_main_placeholder.output_feature_arc_index;
Florin Corasce1b4c72017-01-26 14:25:34 -0800331 break;
332 }
Neale Ranns924d03a2016-10-19 08:25:46 +0100333 case VNET_LINK_ARP:
334 ASSERT(0);
335 break;
Neale Ranns5e575b12016-10-03 09:40:25 +0100336 }
337
Damjan Marion8b3191e2016-11-09 19:54:20 +0100338 ASSERT (arc != (u8) ~0);
339
340 return (arc);
Neale Ranns5e575b12016-10-03 09:40:25 +0100341}
342
Neale Rannsfa5d1982017-02-20 14:19:51 -0800343static u32
344adj_nbr_midchain_get_tx_node (ip_adjacency_t *adj)
345{
346 return ((adj->ia_flags & ADJ_FLAG_MIDCHAIN_NO_COUNT) ?
347 adj_midchain_tx_no_count_node.index :
348 adj_midchain_tx_node.index);
349}
350
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100351/**
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800352 * adj_midchain_setup
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100353 *
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800354 * Setup the adj as a mid-chain
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100355 */
356void
Neale Ranns3ebebc32020-02-18 13:56:24 +0000357adj_midchain_teardown (ip_adjacency_t *adj)
358{
Neale Ranns4ec36c52020-03-31 09:21:29 -0400359 vlib_main_t *vm = vlib_get_main();
Neale Ranns3ebebc32020-02-18 13:56:24 +0000360
361 dpo_reset(&adj->sub_type.midchain.next_dpo);
362
Neale Ranns4ec36c52020-03-31 09:21:29 -0400363 vlib_worker_thread_barrier_sync(vm);
Neale Ranns5d0136f2020-05-12 08:51:02 +0000364 adj->ia_cfg_index = vnet_feature_modify_end_node(
Neale Ranns4ec36c52020-03-31 09:21:29 -0400365 adj_midchain_get_feature_arc_index_for_link_type (adj),
366 adj->rewrite_header.sw_if_index,
367 vlib_get_node_by_name (vlib_get_main(),
368 (u8*) "interface-output")->index);
369 vlib_worker_thread_barrier_release(vm);
Neale Ranns3ebebc32020-02-18 13:56:24 +0000370}
371
372/**
373 * adj_midchain_setup
374 *
375 * Setup the adj as a mid-chain
376 */
377void
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800378adj_midchain_setup (adj_index_t adj_index,
379 adj_midchain_fixup_t fixup,
Neale Rannsdb14f5a2018-01-29 10:43:33 -0800380 const void *data,
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800381 adj_flags_t flags)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100382{
Neale Ranns4ec36c52020-03-31 09:21:29 -0400383 vlib_main_t *vm = vlib_get_main();
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100384 ip_adjacency_t *adj;
Neale Ranns4ec36c52020-03-31 09:21:29 -0400385 u32 tx_node;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100386
387 ASSERT(ADJ_INDEX_INVALID != adj_index);
388
389 adj = adj_get(adj_index);
Neale Rannsb80c5362016-10-08 13:03:40 +0100390
Neale Ranns5e575b12016-10-03 09:40:25 +0100391 adj->sub_type.midchain.fixup_func = fixup;
Neale Rannsdb14f5a2018-01-29 10:43:33 -0800392 adj->sub_type.midchain.fixup_data = data;
Neale Ranns521a8d72018-12-06 13:46:49 +0000393 adj->sub_type.midchain.fei = FIB_NODE_INDEX_INVALID;
Neale Rannsfa5d1982017-02-20 14:19:51 -0800394 adj->ia_flags |= flags;
Neale Ranns5e575b12016-10-03 09:40:25 +0100395
Neale Ranns4ec36c52020-03-31 09:21:29 -0400396 if (flags & ADJ_FLAG_MIDCHAIN_FIXUP_IP4O4_HDR)
397 {
398 adj->rewrite_header.flags |= VNET_REWRITE_FIXUP_IP4_O_4;
399 }
400 else
401 {
402 adj->rewrite_header.flags &= ~VNET_REWRITE_FIXUP_IP4_O_4;
403 }
404
Neale Rannsfa5d1982017-02-20 14:19:51 -0800405 tx_node = adj_nbr_midchain_get_tx_node(adj);
Neale Ranns5e575b12016-10-03 09:40:25 +0100406
Neale Ranns4ec36c52020-03-31 09:21:29 -0400407 vlib_worker_thread_barrier_sync(vm);
Neale Ranns5d0136f2020-05-12 08:51:02 +0000408 adj->ia_cfg_index = vnet_feature_modify_end_node(
Neale Ranns4ec36c52020-03-31 09:21:29 -0400409 adj_midchain_get_feature_arc_index_for_link_type (adj),
410 adj->rewrite_header.sw_if_index,
411 tx_node);
412 vlib_worker_thread_barrier_release(vm);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100413
Neale Rannsb80c5362016-10-08 13:03:40 +0100414 /*
415 * stack the midchain on the drop so it's ready to forward in the adj-midchain-tx.
416 * The graph arc used/created here is from the midchain-tx node to the
417 * child's registered node. This is because post adj processing the next
418 * node are any output features, then the midchain-tx. from there we
419 * need to get to the stacked child's node.
420 */
Neale Rannsfa5d1982017-02-20 14:19:51 -0800421 dpo_stack_from_node(tx_node,
Neale Ranns43161a82017-08-12 02:12:00 -0700422 &adj->sub_type.midchain.next_dpo,
423 drop_dpo_get(vnet_link_to_dpo_proto(adj->ia_link)));
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800424}
425
426/**
427 * adj_nbr_midchain_update_rewrite
428 *
429 * Update the adjacency's rewrite string. A NULL string implies the
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700430 * rewrite is reset (i.e. when ARP/ND entry is gone).
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800431 * NB: the adj being updated may be handling traffic in the DP.
432 */
433void
434adj_nbr_midchain_update_rewrite (adj_index_t adj_index,
435 adj_midchain_fixup_t fixup,
Neale Rannsdb14f5a2018-01-29 10:43:33 -0800436 const void *fixup_data,
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800437 adj_flags_t flags,
438 u8 *rewrite)
439{
440 ip_adjacency_t *adj;
441
442 ASSERT(ADJ_INDEX_INVALID != adj_index);
443
444 adj = adj_get(adj_index);
445
446 /*
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700447 * one time only update. since we don't support changing the tunnel
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800448 * src,dst, this is all we need.
449 */
Neale Ranns174959c2020-02-03 10:33:51 +0000450 if (adj->lookup_next_index != IP_LOOKUP_NEXT_MIDCHAIN &&
Neale Ranns14053c92019-12-29 23:55:18 +0000451 adj->lookup_next_index != IP_LOOKUP_NEXT_MCAST_MIDCHAIN)
452 {
453 adj_midchain_setup(adj_index, fixup, fixup_data, flags);
454 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100455
Neale Rannsb80c5362016-10-08 13:03:40 +0100456 /*
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700457 * update the rewrite with the workers paused.
Neale Rannsb80c5362016-10-08 13:03:40 +0100458 */
459 adj_nbr_update_rewrite_internal(adj,
460 IP_LOOKUP_NEXT_MIDCHAIN,
461 adj_get_midchain_node(adj->ia_link),
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800462 adj_nbr_midchain_get_tx_node(adj),
Neale Rannsb80c5362016-10-08 13:03:40 +0100463 rewrite);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100464}
465
Neale Ranns4ec36c52020-03-31 09:21:29 -0400466void
467adj_nbr_midchain_update_next_node (adj_index_t adj_index,
468 u32 next_node)
469{
470 ip_adjacency_t *adj;
471 vlib_main_t * vm;
472
473 ASSERT(ADJ_INDEX_INVALID != adj_index);
474
475 adj = adj_get(adj_index);
476 vm = vlib_get_main();
477
478 vlib_worker_thread_barrier_sync(vm);
479
480 adj->rewrite_header.next_index = vlib_node_add_next(vlib_get_main(),
481 adj->ia_node_index,
482 next_node);
483
Neale Ranns5d0136f2020-05-12 08:51:02 +0000484 adj->ia_cfg_index = vnet_feature_modify_end_node(
Neale Ranns4ec36c52020-03-31 09:21:29 -0400485 adj_midchain_get_feature_arc_index_for_link_type (adj),
486 adj->rewrite_header.sw_if_index,
487 next_node);
488
489 vlib_worker_thread_barrier_release(vm);
490}
491
492void
Neale Ranns5d0136f2020-05-12 08:51:02 +0000493adj_nbr_midchain_reset_next_node (adj_index_t adj_index)
Neale Ranns4ec36c52020-03-31 09:21:29 -0400494{
495 ip_adjacency_t *adj;
496 vlib_main_t * vm;
497
498 ASSERT(ADJ_INDEX_INVALID != adj_index);
499
500 adj = adj_get(adj_index);
501 vm = vlib_get_main();
502
503 vlib_worker_thread_barrier_sync(vm);
504
505 adj->rewrite_header.next_index =
506 vlib_node_add_next(vlib_get_main(),
507 adj->ia_node_index,
508 adj_nbr_midchain_get_tx_node(adj));
509
Neale Ranns5d0136f2020-05-12 08:51:02 +0000510 adj->ia_cfg_index = vnet_feature_modify_end_node(
Neale Ranns4ec36c52020-03-31 09:21:29 -0400511 adj_midchain_get_feature_arc_index_for_link_type (adj),
512 adj->rewrite_header.sw_if_index,
513 adj_nbr_midchain_get_tx_node(adj));
514
515 vlib_worker_thread_barrier_release(vm);
516}
517
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100518/**
Neale Ranns5e575b12016-10-03 09:40:25 +0100519 * adj_nbr_midchain_unstack
520 *
521 * Unstack the adj. stack it on drop
522 */
523void
524adj_nbr_midchain_unstack (adj_index_t adj_index)
525{
Neale Ranns521a8d72018-12-06 13:46:49 +0000526 fib_node_index_t *entry_indicies, tmp;
Neale Ranns5e575b12016-10-03 09:40:25 +0100527 ip_adjacency_t *adj;
528
529 ASSERT(ADJ_INDEX_INVALID != adj_index);
Neale Ranns521a8d72018-12-06 13:46:49 +0000530 adj = adj_get (adj_index);
Neale Ranns5e575b12016-10-03 09:40:25 +0100531
Neale Ranns521a8d72018-12-06 13:46:49 +0000532 /*
533 * check to see if this unstacking breaks a recursion loop
534 */
535 entry_indicies = NULL;
536 tmp = adj->sub_type.midchain.fei;
537 adj->sub_type.midchain.fei = FIB_NODE_INDEX_INVALID;
538
539 if (FIB_NODE_INDEX_INVALID != tmp)
540 {
541 fib_entry_recursive_loop_detect(tmp, &entry_indicies);
542 vec_free(entry_indicies);
543 }
Neale Ranns5e575b12016-10-03 09:40:25 +0100544
545 /*
546 * stack on the drop
547 */
548 dpo_stack(DPO_ADJACENCY_MIDCHAIN,
Neale Ranns43161a82017-08-12 02:12:00 -0700549 vnet_link_to_dpo_proto(adj->ia_link),
550 &adj->sub_type.midchain.next_dpo,
551 drop_dpo_get(vnet_link_to_dpo_proto(adj->ia_link)));
Neale Ranns5e575b12016-10-03 09:40:25 +0100552 CLIB_MEMORY_BARRIER();
553}
554
Neale Ranns521a8d72018-12-06 13:46:49 +0000555void
556adj_nbr_midchain_stack_on_fib_entry (adj_index_t ai,
557 fib_node_index_t fei,
558 fib_forward_chain_type_t fct)
559{
560 fib_node_index_t *entry_indicies;
561 dpo_id_t tmp = DPO_INVALID;
562 ip_adjacency_t *adj;
563
564 adj = adj_get (ai);
565
566 /*
567 * check to see if this stacking will form a recursion loop
568 */
569 entry_indicies = NULL;
570 adj->sub_type.midchain.fei = fei;
571
572 if (fib_entry_recursive_loop_detect(adj->sub_type.midchain.fei, &entry_indicies))
573 {
574 /*
575 * loop formed, stack on the drop.
576 */
577 dpo_copy(&tmp, drop_dpo_get(fib_forw_chain_type_to_dpo_proto(fct)));
578 }
579 else
580 {
581 fib_entry_contribute_forwarding (fei, fct, &tmp);
582
583 if ((adj->ia_flags & ADJ_FLAG_MIDCHAIN_IP_STACK) &&
584 (DPO_LOAD_BALANCE == tmp.dpoi_type))
585 {
586 /*
587 * do that hash now and stack on the choice.
588 * If the choice is an incomplete adj then we will need a poke when
589 * it becomes complete. This happens since the adj update walk propagates
590 * as far a recursive paths.
591 */
592 const dpo_id_t *choice;
593 load_balance_t *lb;
594 int hash;
595
596 lb = load_balance_get (tmp.dpoi_index);
597
598 if (FIB_FORW_CHAIN_TYPE_UNICAST_IP4 == fct)
599 {
600 hash = ip4_compute_flow_hash ((ip4_header_t *) adj_get_rewrite (ai),
601 lb->lb_hash_config);
602 }
603 else if (FIB_FORW_CHAIN_TYPE_UNICAST_IP6 == fct)
604 {
605 hash = ip6_compute_flow_hash ((ip6_header_t *) adj_get_rewrite (ai),
606 lb->lb_hash_config);
607 }
608 else
609 {
610 hash = 0;
611 ASSERT(0);
612 }
613
614 choice = load_balance_get_bucket_i (lb, hash & lb->lb_n_buckets_minus_1);
615 dpo_copy (&tmp, choice);
616 }
617 }
618 adj_nbr_midchain_stack (ai, &tmp);
619 dpo_reset(&tmp);
620 vec_free(entry_indicies);
621}
622
Neale Ranns5e575b12016-10-03 09:40:25 +0100623/**
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100624 * adj_nbr_midchain_stack
625 */
626void
627adj_nbr_midchain_stack (adj_index_t adj_index,
628 const dpo_id_t *next)
629{
630 ip_adjacency_t *adj;
631
632 ASSERT(ADJ_INDEX_INVALID != adj_index);
633
634 adj = adj_get(adj_index);
635
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800636 ASSERT((IP_LOOKUP_NEXT_MIDCHAIN == adj->lookup_next_index) ||
637 (IP_LOOKUP_NEXT_MCAST_MIDCHAIN == adj->lookup_next_index));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100638
Neale Rannsfa5d1982017-02-20 14:19:51 -0800639 dpo_stack_from_node(adj_nbr_midchain_get_tx_node(adj),
Neale Ranns5e575b12016-10-03 09:40:25 +0100640 &adj->sub_type.midchain.next_dpo,
641 next);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100642}
643
Neale Ranns521a8d72018-12-06 13:46:49 +0000644int
645adj_ndr_midchain_recursive_loop_detect (adj_index_t ai,
646 fib_node_index_t **entry_indicies)
647{
648 fib_node_index_t *entry_index, *entries;
649 ip_adjacency_t * adj;
650
651 adj = adj_get(ai);
652 entries = *entry_indicies;
653
654 vec_foreach(entry_index, entries)
655 {
656 if (*entry_index == adj->sub_type.midchain.fei)
657 {
658 /*
659 * The entry this midchain links to is already in the set
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700660 * of visited entries, this is a loop
Neale Ranns521a8d72018-12-06 13:46:49 +0000661 */
662 adj->ia_flags |= ADJ_FLAG_MIDCHAIN_LOOPED;
663 return (1);
664 }
665 }
666
667 adj->ia_flags &= ~ADJ_FLAG_MIDCHAIN_LOOPED;
668 return (0);
669}
670
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100671u8*
672format_adj_midchain (u8* s, va_list *ap)
673{
Billy McFallcfcf1e22016-10-14 09:51:49 -0400674 index_t index = va_arg(*ap, index_t);
675 u32 indent = va_arg(*ap, u32);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100676 ip_adjacency_t * adj = adj_get(index);
677
Neale Ranns924d03a2016-10-19 08:25:46 +0100678 s = format (s, "%U", format_vnet_link, adj->ia_link);
Neale Ranns25edf142019-03-22 08:12:48 +0000679 if (adj->rewrite_header.flags & VNET_REWRITE_HAS_FEATURES)
680 s = format(s, " [features]");
Neale Rannsc819fc62018-02-16 02:44:05 -0800681 s = format (s, " via %U",
682 format_ip46_address, &adj->sub_type.nbr.next_hop,
683 adj_proto_to_46(adj->ia_nh_proto));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100684 s = format (s, " %U",
Neale Ranns5e575b12016-10-03 09:40:25 +0100685 format_vnet_rewrite,
Neale Rannsb069a692017-03-15 12:34:25 -0400686 &adj->rewrite_header, sizeof (adj->rewrite_data), indent);
Neale Ranns521a8d72018-12-06 13:46:49 +0000687 s = format (s, "\n%Ustacked-on",
688 format_white_space, indent);
689
690 if (FIB_NODE_INDEX_INVALID != adj->sub_type.midchain.fei)
691 {
692 s = format (s, " entry:%d", adj->sub_type.midchain.fei);
693
694 }
695 s = format (s, ":\n%U%U",
Neale Ranns43161a82017-08-12 02:12:00 -0700696 format_white_space, indent+2,
697 format_dpo_id, &adj->sub_type.midchain.next_dpo, indent+2);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100698
699 return (s);
700}
701
702static void
703adj_dpo_lock (dpo_id_t *dpo)
704{
705 adj_lock(dpo->dpoi_index);
706}
707static void
708adj_dpo_unlock (dpo_id_t *dpo)
709{
710 adj_unlock(dpo->dpoi_index);
711}
712
713const static dpo_vft_t adj_midchain_dpo_vft = {
714 .dv_lock = adj_dpo_lock,
715 .dv_unlock = adj_dpo_unlock,
716 .dv_format = format_adj_midchain,
Andrew Yourtchenko5f3fcb92017-10-25 05:50:37 -0700717 .dv_get_urpf = adj_dpo_get_urpf,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100718};
719
720/**
721 * @brief The per-protocol VLIB graph nodes that are assigned to a midchain
722 * object.
723 *
724 * this means that these graph nodes are ones from which a midchain is the
725 * parent object in the DPO-graph.
726 */
727const static char* const midchain_ip4_nodes[] =
728{
729 "ip4-midchain",
730 NULL,
731};
732const static char* const midchain_ip6_nodes[] =
733{
734 "ip6-midchain",
735 NULL,
736};
737const static char* const midchain_mpls_nodes[] =
738{
739 "mpls-midchain",
740 NULL,
741};
Neale Ranns5e575b12016-10-03 09:40:25 +0100742const static char* const midchain_ethernet_nodes[] =
743{
744 "adj-l2-midchain",
745 NULL,
746};
Florin Corasb69111e2017-02-13 23:55:27 -0800747const static char* const midchain_nsh_nodes[] =
748{
749 "adj-nsh-midchain",
750 NULL,
751};
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100752
753const static char* const * const midchain_nodes[DPO_PROTO_NUM] =
754{
755 [DPO_PROTO_IP4] = midchain_ip4_nodes,
756 [DPO_PROTO_IP6] = midchain_ip6_nodes,
757 [DPO_PROTO_MPLS] = midchain_mpls_nodes,
Neale Ranns5e575b12016-10-03 09:40:25 +0100758 [DPO_PROTO_ETHERNET] = midchain_ethernet_nodes,
Florin Corasb69111e2017-02-13 23:55:27 -0800759 [DPO_PROTO_NSH] = midchain_nsh_nodes,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100760};
761
762void
763adj_midchain_module_init (void)
764{
765 dpo_register(DPO_ADJACENCY_MIDCHAIN, &adj_midchain_dpo_vft, midchain_nodes);
766}
Neale Ranns4ec36c52020-03-31 09:21:29 -0400767
768#endif