170ed19855e5d1f0826835f67b69e6bddabf12f6
[vpp.git] / src / vnet / adj / adj_midchain_node.c
1 /*
2  * Copyright (c) 2016 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <vnet/adj/adj_internal.h>
17 #include <vnet/adj/adj_midchain.h>
18
19 /**
20  * @brief Trace data for packets traversing the midchain tx node
21  */
22 typedef struct adj_midchain_tx_trace_t_
23 {
24     /**
25      * @brief the midchain adj we are traversing
26      */
27     adj_index_t ai;
28 } adj_midchain_tx_trace_t;
29
30 always_inline uword
31 adj_midchain_tx_inline (vlib_main_t * vm,
32                         vlib_node_runtime_t * node,
33                         vlib_frame_t * frame,
34                         int interface_count)
35 {
36     vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
37     u16 nexts[VLIB_FRAME_SIZE], *next;
38     u32 * from, n_left, thread_index;
39     vnet_main_t *vnm = vnet_get_main ();
40     vnet_interface_main_t *im = &vnm->interface_main;
41
42     thread_index = vm->thread_index;
43     n_left = frame->n_vectors;
44     from = vlib_frame_vector_args (frame);
45
46     vlib_get_buffers (vm, from, bufs, n_left);
47
48     next = nexts;
49     b = bufs;
50
51     while (n_left > 8)
52     {
53         u32 adj_index0, adj_index1, adj_index2, adj_index3;
54         const ip_adjacency_t *adj0, *adj1, *adj2, *adj3;
55         const dpo_id_t *dpo0, *dpo1, *dpo2, *dpo3;
56
57         /* Prefetch next iteration. */
58         {
59             vlib_prefetch_buffer_header (b[4], LOAD);
60             vlib_prefetch_buffer_header (b[5], LOAD);
61             vlib_prefetch_buffer_header (b[6], LOAD);
62             vlib_prefetch_buffer_header (b[7], LOAD);
63         }
64
65         /* Follow the DPO on which the midchain is stacked */
66         adj_index0 = vnet_buffer(b[0])->ip.adj_index[VLIB_TX];
67         adj_index1 = vnet_buffer(b[1])->ip.adj_index[VLIB_TX];
68         adj_index2 = vnet_buffer(b[2])->ip.adj_index[VLIB_TX];
69         adj_index3 = vnet_buffer(b[3])->ip.adj_index[VLIB_TX];
70
71         adj0 = adj_get(adj_index0);
72         adj1 = adj_get(adj_index1);
73         adj2 = adj_get(adj_index2);
74         adj3 = adj_get(adj_index3);
75
76         dpo0 = &adj0->sub_type.midchain.next_dpo;
77         dpo1 = &adj1->sub_type.midchain.next_dpo;
78         dpo2 = &adj2->sub_type.midchain.next_dpo;
79         dpo3 = &adj3->sub_type.midchain.next_dpo;
80
81         next[0] = dpo0->dpoi_next_node;
82         next[1] = dpo1->dpoi_next_node;
83         next[2] = dpo2->dpoi_next_node;
84         next[3] = dpo3->dpoi_next_node;
85
86         vnet_buffer(b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
87         vnet_buffer(b[1])->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
88         vnet_buffer(b[2])->ip.adj_index[VLIB_TX] = dpo2->dpoi_index;
89         vnet_buffer(b[3])->ip.adj_index[VLIB_TX] = dpo3->dpoi_index;
90
91         if (interface_count)
92         {
93             vlib_increment_combined_counter (im->combined_sw_if_counters
94                                              + VNET_INTERFACE_COUNTER_TX,
95                                              thread_index,
96                                              adj0->rewrite_header.sw_if_index,
97                                              1,
98                                              vlib_buffer_length_in_chain (vm, b[0]));
99             vlib_increment_combined_counter (im->combined_sw_if_counters
100                                              + VNET_INTERFACE_COUNTER_TX,
101                                              thread_index,
102                                              adj1->rewrite_header.sw_if_index,
103                                              1,
104                                              vlib_buffer_length_in_chain (vm, b[1]));
105             vlib_increment_combined_counter (im->combined_sw_if_counters
106                                              + VNET_INTERFACE_COUNTER_TX,
107                                              thread_index,
108                                              adj2->rewrite_header.sw_if_index,
109                                              1,
110                                              vlib_buffer_length_in_chain (vm, b[2]));
111             vlib_increment_combined_counter (im->combined_sw_if_counters
112                                              + VNET_INTERFACE_COUNTER_TX,
113                                              thread_index,
114                                              adj3->rewrite_header.sw_if_index,
115                                              1,
116                                              vlib_buffer_length_in_chain (vm, b[3]));
117         }
118
119         if (PREDICT_FALSE(node->flags & VLIB_NODE_FLAG_TRACE))
120         {
121             if (PREDICT_FALSE(b[0]->flags & VLIB_BUFFER_IS_TRACED))
122             {
123                 adj_midchain_tx_trace_t *tr = vlib_add_trace (vm, node,
124                                                               b[0], sizeof (*tr));
125                 tr->ai = adj_index0;
126             }
127             if (PREDICT_FALSE(b[1]->flags & VLIB_BUFFER_IS_TRACED))
128             {
129                 adj_midchain_tx_trace_t *tr = vlib_add_trace (vm, node,
130                                                               b[1], sizeof (*tr));
131                 tr->ai = adj_index1;
132             }
133             if (PREDICT_FALSE(b[2]->flags & VLIB_BUFFER_IS_TRACED))
134             {
135                 adj_midchain_tx_trace_t *tr = vlib_add_trace (vm, node,
136                                                               b[2], sizeof (*tr));
137                 tr->ai = adj_index2;
138             }
139             if (PREDICT_FALSE(b[3]->flags & VLIB_BUFFER_IS_TRACED))
140             {
141                 adj_midchain_tx_trace_t *tr = vlib_add_trace (vm, node,
142                                                               b[3], sizeof (*tr));
143                 tr->ai = adj_index3;
144             }
145         }
146         n_left -= 4;
147         b += 4;
148         next += 4;
149     }
150
151     while (n_left)
152     {
153         const ip_adjacency_t * adj0;
154         const dpo_id_t *dpo0;
155         u32 adj_index0;
156
157         /* Follow the DPO on which the midchain is stacked */
158         adj_index0 = vnet_buffer(b[0])->ip.adj_index[VLIB_TX];
159         adj0 = adj_get(adj_index0);
160         dpo0 = &adj0->sub_type.midchain.next_dpo;
161         next[0] = dpo0->dpoi_next_node;
162         vnet_buffer(b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
163
164         if (interface_count)
165         {
166             vlib_increment_combined_counter (im->combined_sw_if_counters
167                                              + VNET_INTERFACE_COUNTER_TX,
168                                              thread_index,
169                                              adj0->rewrite_header.sw_if_index,
170                                              1,
171                                              vlib_buffer_length_in_chain (vm, b[0]));
172         }
173
174         if (PREDICT_FALSE(b[0]->flags & VLIB_BUFFER_IS_TRACED))
175         {
176             adj_midchain_tx_trace_t *tr = vlib_add_trace (vm, node,
177                                                           b[0], sizeof (*tr));
178             tr->ai = adj_index0;
179         }
180
181         n_left -= 1;
182         b += 1;
183         next += 1;
184     }
185
186     vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
187
188     return frame->n_vectors;
189 }
190
191 static u8 *
192 format_adj_midchain_tx_trace (u8 * s, va_list * args)
193 {
194     CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
195     CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
196     adj_midchain_tx_trace_t *tr = va_arg (*args, adj_midchain_tx_trace_t*);
197
198     s = format(s, "adj-midchain:[%d]:%U", tr->ai,
199                format_ip_adjacency, tr->ai,
200                FORMAT_IP_ADJACENCY_NONE);
201
202     return (s);
203 }
204
205 static uword
206 adj_midchain_tx (vlib_main_t * vm,
207                  vlib_node_runtime_t * node,
208                  vlib_frame_t * frame)
209 {
210     return (adj_midchain_tx_inline(vm, node, frame, 1));
211 }
212
213 VLIB_REGISTER_NODE (adj_midchain_tx_node) = {
214     .function = adj_midchain_tx,
215     .name = "adj-midchain-tx",
216     .vector_size = sizeof (u32),
217
218     .format_trace = format_adj_midchain_tx_trace,
219
220     .n_next_nodes = 1,
221     .next_nodes = {
222         [0] = "error-drop",
223     },
224 };
225
226 static uword
227 adj_midchain_tx_no_count (vlib_main_t * vm,
228                           vlib_node_runtime_t * node,
229                           vlib_frame_t * frame)
230 {
231     return (adj_midchain_tx_inline(vm, node, frame, 0));
232 }
233
234 VLIB_REGISTER_NODE (adj_midchain_tx_no_count_node) = {
235     .function = adj_midchain_tx_no_count,
236     .name = "adj-midchain-tx-no-count",
237     .vector_size = sizeof (u32),
238
239     .format_trace = format_adj_midchain_tx_trace,
240     .sibling_of = "adj-midchain-tx",
241 };