L3 cross connect
[vpp.git] / src / plugins / l3xc / l3xc_node.c
1 /*
2  * Copyright (c) 2019 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 <plugins/l3xc/l3xc.h>
17 #include <vnet/feature/feature.h>
18
19 typedef enum l3xc_next_t_
20 {
21   L3XC_NEXT_DROP,
22   L3XC_N_NEXT,
23 } l3xc_next_t;
24
25 typedef struct l3xc_input_trace_t_
26 {
27   index_t l3xci;
28   index_t lbi;
29 } l3xc_input_trace_t;
30
31 typedef enum
32 {
33 #define l3xc_error(n,s) L3XC_ERROR_##n,
34 #include "l3xc_error.def"
35 #undef l3xc_error
36   L3XC_N_ERROR,
37 } l3xc_error_t;
38
39 always_inline uword
40 l3xc_input_inline (vlib_main_t * vm,
41                    vlib_node_runtime_t * node,
42                    vlib_frame_t * frame, fib_protocol_t fproto)
43 {
44   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
45   u16 nexts[VLIB_FRAME_SIZE], *next;
46   u32 n_left, *from;
47
48   from = vlib_frame_vector_args (frame);
49   n_left = frame->n_vectors;
50   b = bufs;
51   next = nexts;
52
53   vlib_get_buffers (vm, from, bufs, n_left);
54
55   while (n_left >= 8)
56     {
57       const l3xc_t *l3xc0, *l3xc1, *l3xc2, *l3xc3;
58       u32 l3xci0, l3xci1, l3xci2, l3xci3;
59       u32 next_u32;
60
61       /* Prefetch next iteration. */
62       {
63         vlib_prefetch_buffer_header (b[4], LOAD);
64         vlib_prefetch_buffer_header (b[5], LOAD);
65         vlib_prefetch_buffer_header (b[6], LOAD);
66         vlib_prefetch_buffer_header (b[7], LOAD);
67       }
68
69       l3xci0 =
70         *(u32 *) vnet_feature_next_with_data (&next_u32, b[0],
71                                               sizeof (l3xci0));
72       l3xci1 =
73         *(u32 *) vnet_feature_next_with_data (&next_u32, b[1],
74                                               sizeof (l3xci1));
75       l3xci2 =
76         *(u32 *) vnet_feature_next_with_data (&next_u32, b[2],
77                                               sizeof (l3xci2));
78       l3xci3 =
79         *(u32 *) vnet_feature_next_with_data (&next_u32, b[3],
80                                               sizeof (l3xci3));
81
82       l3xc0 = l3xc_get (l3xci0);
83       l3xc1 = l3xc_get (l3xci1);
84       l3xc2 = l3xc_get (l3xci2);
85       l3xc3 = l3xc_get (l3xci3);
86
87       next[0] = l3xc0->l3xc_dpo.dpoi_next_node;
88       next[1] = l3xc1->l3xc_dpo.dpoi_next_node;
89       next[2] = l3xc2->l3xc_dpo.dpoi_next_node;
90       next[3] = l3xc3->l3xc_dpo.dpoi_next_node;
91
92       vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = l3xc0->l3xc_dpo.dpoi_index;
93       vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = l3xc1->l3xc_dpo.dpoi_index;
94       vnet_buffer (b[2])->ip.adj_index[VLIB_TX] = l3xc2->l3xc_dpo.dpoi_index;
95       vnet_buffer (b[3])->ip.adj_index[VLIB_TX] = l3xc3->l3xc_dpo.dpoi_index;
96
97       if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
98         {
99           if (PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED))
100             {
101               l3xc_input_trace_t *tr;
102
103               tr = vlib_add_trace (vm, node, b[0], sizeof (*tr));
104               tr->l3xci = l3xci0;
105               tr->lbi = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
106             }
107           if (PREDICT_FALSE (b[1]->flags & VLIB_BUFFER_IS_TRACED))
108             {
109               l3xc_input_trace_t *tr;
110
111               tr = vlib_add_trace (vm, node, b[1], sizeof (*tr));
112               tr->l3xci = l3xci1;
113               tr->lbi = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
114             }
115           if (PREDICT_FALSE (b[2]->flags & VLIB_BUFFER_IS_TRACED))
116             {
117               l3xc_input_trace_t *tr;
118
119               tr = vlib_add_trace (vm, node, b[2], sizeof (*tr));
120               tr->l3xci = l3xci2;
121               tr->lbi = vnet_buffer (b[2])->ip.adj_index[VLIB_TX];
122             }
123           if (PREDICT_FALSE (b[3]->flags & VLIB_BUFFER_IS_TRACED))
124             {
125               l3xc_input_trace_t *tr;
126
127               tr = vlib_add_trace (vm, node, b[3], sizeof (*tr));
128               tr->l3xci = l3xci3;
129               tr->lbi = vnet_buffer (b[3])->ip.adj_index[VLIB_TX];
130             }
131         }
132
133       b += 4;
134       next += 4;
135       n_left -= 4;
136     }
137
138   while (n_left > 0)
139     {
140       u32 l3xci0, next_u32;
141       const l3xc_t *l3xc0;
142
143       l3xci0 =
144         *(u32 *) vnet_feature_next_with_data (&next_u32, b[0],
145                                               sizeof (l3xci0));
146
147       l3xc0 = l3xc_get (l3xci0);
148
149       next[0] = l3xc0->l3xc_dpo.dpoi_next_node;
150
151       vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = l3xc0->l3xc_dpo.dpoi_index;
152
153       if (PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED))
154         {
155           l3xc_input_trace_t *tr;
156
157           tr = vlib_add_trace (vm, node, b[0], sizeof (*tr));
158           tr->l3xci = l3xci0;
159           tr->lbi = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
160         }
161
162       b += 1;
163       next += 1;
164       n_left -= 1;
165     }
166
167   vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
168   return frame->n_vectors;
169 }
170
171 static uword
172 l3xc_input_ip4 (vlib_main_t * vm,
173                 vlib_node_runtime_t * node, vlib_frame_t * frame)
174 {
175   return l3xc_input_inline (vm, node, frame, FIB_PROTOCOL_IP4);
176 }
177
178 static uword
179 l3xc_input_ip6 (vlib_main_t * vm,
180                 vlib_node_runtime_t * node, vlib_frame_t * frame)
181 {
182   return l3xc_input_inline (vm, node, frame, FIB_PROTOCOL_IP6);
183 }
184
185 static u8 *
186 format_l3xc_input_trace (u8 * s, va_list * args)
187 {
188   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
189   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
190   l3xc_input_trace_t *t = va_arg (*args, l3xc_input_trace_t *);
191
192   s = format (s, "l3xc-index:%d lb-index:%d", t->l3xci, t->lbi);
193   return s;
194 }
195
196 static char *l3xc_error_strings[] = {
197 #define l3xc_error(n,s) s,
198 #include "l3xc_error.def"
199 #undef l3xc_error
200 };
201
202 /* *INDENT-OFF* */
203 VLIB_REGISTER_NODE (l3xc_ip4_node) =
204 {
205   .function = l3xc_input_ip4,
206   .name = "l3xc-input-ip4",
207   .vector_size = sizeof (u32),
208   .format_trace = format_l3xc_input_trace,
209   .type = VLIB_NODE_TYPE_INTERNAL,
210   .n_errors = L3XC_N_ERROR,
211   .error_strings = l3xc_error_strings,
212   .n_next_nodes = L3XC_N_NEXT,
213   .next_nodes =
214   {
215     [L3XC_NEXT_DROP] = "error-drop",
216   }
217 };
218
219 VLIB_REGISTER_NODE (l3xc_ip6_node) =
220 {
221   .function = l3xc_input_ip6,
222   .name = "l3xc-input-ip6",
223   .vector_size = sizeof (u32),
224   .format_trace = format_l3xc_input_trace,
225   .type = VLIB_NODE_TYPE_INTERNAL,
226   .n_errors = 0,
227   .n_next_nodes = L3XC_N_NEXT,
228
229   .next_nodes =
230   {
231     [L3XC_NEXT_DROP] = "error-drop",
232   }
233 };
234
235 VNET_FEATURE_INIT (l3xc_ip4_feat, static) =
236 {
237   .arc_name = "ip4-unicast",
238   .node_name = "l3xc-input-ip4",
239   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
240 };
241
242 VNET_FEATURE_INIT (l3xc_ip6_feat, static) =
243 {
244   .arc_name = "ip6-unicast",
245   .node_name = "l3xc-input-ip6",
246   .runs_after = VNET_FEATURES ("acl-plugin-in-ip6-fa"),
247 };
248 /* *INDENT-ON* */
249
250 /*
251  * fd.io coding-style-patch-verification: ON
252  *
253  * Local Variables:
254  * eval: (c-set-style "gnu")
255  * End:
256  */