Line data Source code
1 : /*
2 : * Copyright (c) 2015 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 : * snap_node.c: snap packet processing
17 : *
18 : * Copyright (c) 2010 Eliot Dresselhaus
19 : *
20 : * Permission is hereby granted, free of charge, to any person obtaining
21 : * a copy of this software and associated documentation files (the
22 : * "Software"), to deal in the Software without restriction, including
23 : * without limitation the rights to use, copy, modify, merge, publish,
24 : * distribute, sublicense, and/or sell copies of the Software, and to
25 : * permit persons to whom the Software is furnished to do so, subject to
26 : * the following conditions:
27 : *
28 : * The above copyright notice and this permission notice shall be
29 : * included in all copies or substantial portions of the Software.
30 : *
31 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32 : * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33 : * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34 : * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35 : * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36 : * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37 : * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 : */
39 :
40 : #include <vlib/vlib.h>
41 : #include <vnet/pg/pg.h>
42 : #include <vnet/llc/llc.h>
43 : #include <vnet/snap/snap.h>
44 :
45 : typedef enum
46 : {
47 : SNAP_INPUT_NEXT_DROP,
48 : SNAP_INPUT_NEXT_PUNT,
49 : SNAP_INPUT_NEXT_ETHERNET_TYPE,
50 : SNAP_INPUT_N_NEXT,
51 : } snap_input_next_t;
52 :
53 : typedef struct
54 : {
55 : u8 packet_data[32];
56 : } snap_input_trace_t;
57 :
58 : static u8 *
59 3 : format_snap_input_trace (u8 * s, va_list * va)
60 : {
61 3 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
62 3 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
63 3 : snap_input_trace_t *t = va_arg (*va, snap_input_trace_t *);
64 :
65 3 : s = format (s, "%U", format_snap_header, t->packet_data);
66 :
67 3 : return s;
68 : }
69 :
70 : static uword
71 3 : snap_input (vlib_main_t * vm,
72 : vlib_node_runtime_t * node, vlib_frame_t * from_frame)
73 : {
74 3 : snap_main_t *sm = &snap_main;
75 : u32 n_left_from, next_index, *from, *to_next;
76 :
77 3 : from = vlib_frame_vector_args (from_frame);
78 3 : n_left_from = from_frame->n_vectors;
79 :
80 3 : if (node->flags & VLIB_NODE_FLAG_TRACE)
81 3 : vlib_trace_frame_buffers_only (vm, node,
82 : from,
83 : n_left_from,
84 : sizeof (from[0]),
85 : sizeof (snap_input_trace_t));
86 :
87 3 : next_index = node->cached_next_index;
88 :
89 6 : while (n_left_from > 0)
90 : {
91 : u32 n_left_to_next;
92 :
93 3 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
94 :
95 3 : while (n_left_from >= 4 && n_left_to_next >= 2)
96 : {
97 : u32 bi0, bi1;
98 : vlib_buffer_t *b0, *b1;
99 : snap_header_t *h0, *h1;
100 : snap_protocol_info_t *pi0, *pi1;
101 : u8 next0, next1, is_ethernet0, is_ethernet1, len0, len1,
102 : enqueue_code;
103 : u32 oui0, oui1;
104 :
105 : /* Prefetch next iteration. */
106 : {
107 : vlib_buffer_t *b2, *b3;
108 :
109 0 : b2 = vlib_get_buffer (vm, from[2]);
110 0 : b3 = vlib_get_buffer (vm, from[3]);
111 :
112 0 : vlib_prefetch_buffer_header (b2, LOAD);
113 0 : vlib_prefetch_buffer_header (b3, LOAD);
114 :
115 0 : CLIB_PREFETCH (b2->data, sizeof (h0[0]), LOAD);
116 0 : CLIB_PREFETCH (b3->data, sizeof (h1[0]), LOAD);
117 : }
118 :
119 0 : bi0 = from[0];
120 0 : bi1 = from[1];
121 0 : to_next[0] = bi0;
122 0 : to_next[1] = bi1;
123 0 : from += 2;
124 0 : to_next += 2;
125 0 : n_left_to_next -= 2;
126 0 : n_left_from -= 2;
127 :
128 0 : b0 = vlib_get_buffer (vm, bi0);
129 0 : b1 = vlib_get_buffer (vm, bi1);
130 :
131 0 : h0 = vlib_buffer_get_current (b0);
132 0 : h1 = vlib_buffer_get_current (b1);
133 :
134 0 : oui0 = snap_header_get_oui (h0);
135 0 : oui1 = snap_header_get_oui (h1);
136 :
137 0 : is_ethernet0 = oui0 == IEEE_OUI_ethernet;
138 0 : is_ethernet1 = oui1 == IEEE_OUI_ethernet;
139 :
140 0 : len0 = sizeof (h0[0]) - (is_ethernet0 ? sizeof (h0->protocol) : 0);
141 0 : len1 = sizeof (h1[0]) - (is_ethernet1 ? sizeof (h1->protocol) : 0);
142 :
143 0 : vlib_buffer_advance (b0, len0);
144 0 : vlib_buffer_advance (b1, len1);
145 :
146 0 : pi0 = snap_get_protocol_info (sm, h0);
147 0 : pi1 = snap_get_protocol_info (sm, h1);
148 :
149 0 : next0 = pi0 ? pi0->next_index : SNAP_INPUT_NEXT_DROP;
150 0 : next1 = pi1 ? pi1->next_index : SNAP_INPUT_NEXT_DROP;
151 :
152 0 : next0 = is_ethernet0 ? SNAP_INPUT_NEXT_ETHERNET_TYPE : next0;
153 0 : next1 = is_ethernet1 ? SNAP_INPUT_NEXT_ETHERNET_TYPE : next1;
154 :
155 : /* In case of error. */
156 0 : b0->error = node->errors[SNAP_ERROR_UNKNOWN_PROTOCOL];
157 0 : b1->error = node->errors[SNAP_ERROR_UNKNOWN_PROTOCOL];
158 :
159 0 : enqueue_code = (next0 != next_index) + 2 * (next1 != next_index);
160 :
161 0 : if (PREDICT_FALSE (enqueue_code != 0))
162 : {
163 0 : switch (enqueue_code)
164 : {
165 0 : case 1:
166 : /* A B A */
167 0 : to_next[-2] = bi1;
168 0 : to_next -= 1;
169 0 : n_left_to_next += 1;
170 0 : vlib_set_next_frame_buffer (vm, node, next0, bi0);
171 0 : break;
172 :
173 0 : case 2:
174 : /* A A B */
175 0 : to_next -= 1;
176 0 : n_left_to_next += 1;
177 0 : vlib_set_next_frame_buffer (vm, node, next1, bi1);
178 0 : break;
179 :
180 0 : case 3:
181 : /* A B B or A B C */
182 0 : to_next -= 2;
183 0 : n_left_to_next += 2;
184 0 : vlib_set_next_frame_buffer (vm, node, next0, bi0);
185 0 : vlib_set_next_frame_buffer (vm, node, next1, bi1);
186 0 : if (next0 == next1)
187 : {
188 0 : vlib_put_next_frame (vm, node, next_index,
189 : n_left_to_next);
190 0 : next_index = next1;
191 0 : vlib_get_next_frame (vm, node, next_index, to_next,
192 : n_left_to_next);
193 : }
194 : }
195 : }
196 : }
197 :
198 6 : while (n_left_from > 0 && n_left_to_next > 0)
199 : {
200 : u32 bi0;
201 : vlib_buffer_t *b0;
202 : snap_header_t *h0;
203 : snap_protocol_info_t *pi0;
204 : u8 next0, is_ethernet0, len0;
205 : u32 oui0;
206 :
207 3 : bi0 = from[0];
208 3 : to_next[0] = bi0;
209 3 : from += 1;
210 3 : to_next += 1;
211 3 : n_left_from -= 1;
212 3 : n_left_to_next -= 1;
213 :
214 3 : b0 = vlib_get_buffer (vm, bi0);
215 :
216 3 : h0 = vlib_buffer_get_current (b0);
217 :
218 3 : oui0 = snap_header_get_oui (h0);
219 :
220 3 : is_ethernet0 = oui0 == IEEE_OUI_ethernet;
221 :
222 3 : len0 = sizeof (h0[0]) - (is_ethernet0 ? sizeof (h0->protocol) : 0);
223 :
224 3 : vlib_buffer_advance (b0, len0);
225 :
226 3 : pi0 = snap_get_protocol_info (sm, h0);
227 :
228 3 : next0 = pi0 ? pi0->next_index : SNAP_INPUT_NEXT_DROP;
229 :
230 3 : next0 = is_ethernet0 ? SNAP_INPUT_NEXT_ETHERNET_TYPE : next0;
231 :
232 : /* In case of error. */
233 3 : b0->error = node->errors[SNAP_ERROR_UNKNOWN_PROTOCOL];
234 :
235 : /* Sent packet to wrong next? */
236 3 : if (PREDICT_FALSE (next0 != next_index))
237 : {
238 : /* Return old frame; remove incorrectly enqueued packet. */
239 1 : vlib_put_next_frame (vm, node, next_index, n_left_to_next + 1);
240 :
241 : /* Send to correct next. */
242 1 : next_index = next0;
243 1 : vlib_get_next_frame (vm, node, next_index,
244 : to_next, n_left_to_next);
245 :
246 1 : to_next[0] = bi0;
247 1 : to_next += 1;
248 1 : n_left_to_next -= 1;
249 : }
250 : }
251 :
252 3 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
253 : }
254 :
255 3 : return from_frame->n_vectors;
256 : }
257 :
258 : static char *snap_error_strings[] = {
259 : #define _(f,s) s,
260 : foreach_snap_error
261 : #undef _
262 : };
263 :
264 : /* *INDENT-OFF* */
265 178120 : VLIB_REGISTER_NODE (snap_input_node) = {
266 : .function = snap_input,
267 : .name = "snap-input",
268 : /* Takes a vector of packets. */
269 : .vector_size = sizeof (u32),
270 :
271 : .n_errors = SNAP_N_ERROR,
272 : .error_strings = snap_error_strings,
273 :
274 : .n_next_nodes = SNAP_INPUT_N_NEXT,
275 : .next_nodes = {
276 : [SNAP_INPUT_NEXT_DROP] = "error-drop",
277 : [SNAP_INPUT_NEXT_PUNT] = "error-punt",
278 : [SNAP_INPUT_NEXT_ETHERNET_TYPE] = "ethernet-input-type",
279 : },
280 :
281 : .format_buffer = format_snap_header_with_length,
282 : .format_trace = format_snap_input_trace,
283 : .unformat_buffer = unformat_snap_header,
284 : };
285 : /* *INDENT-ON* */
286 :
287 : static void
288 559 : snap_setup_node (vlib_main_t *vm, u32 node_index)
289 : {
290 559 : vlib_node_t *n = vlib_get_node (vm, node_index);
291 559 : pg_node_t *pn = pg_get_node (node_index);
292 :
293 559 : n->format_buffer = format_snap_header_with_length;
294 559 : n->unformat_buffer = unformat_snap_header;
295 559 : pn->unformat_edit = unformat_pg_snap_header;
296 559 : }
297 :
298 : static clib_error_t *
299 559 : snap_input_init (vlib_main_t * vm)
300 : {
301 : {
302 559 : clib_error_t *error = vlib_call_init_function (vm, snap_init);
303 559 : if (error)
304 0 : clib_error_report (error);
305 : }
306 :
307 559 : snap_setup_node (vm, snap_input_node.index);
308 :
309 559 : llc_register_input_protocol (vm, LLC_PROTOCOL_snap, snap_input_node.index);
310 :
311 559 : return 0;
312 : }
313 :
314 30239 : VLIB_INIT_FUNCTION (snap_input_init);
315 :
316 : void
317 2 : snap_register_input_protocol (vlib_main_t * vm,
318 : char *name,
319 : u32 ieee_oui, u16 protocol, u32 node_index)
320 : {
321 2 : snap_main_t *sm = &snap_main;
322 : snap_protocol_info_t *pi;
323 : snap_header_t h;
324 : snap_oui_and_protocol_t key;
325 :
326 : {
327 2 : clib_error_t *error = vlib_call_init_function (vm, snap_input_init);
328 2 : if (error)
329 0 : clib_error_report (error);
330 : }
331 :
332 2 : h.protocol = clib_host_to_net_u16 (protocol);
333 2 : h.oui[0] = (ieee_oui >> 16) & 0xff;
334 2 : h.oui[1] = (ieee_oui >> 8) & 0xff;
335 2 : h.oui[2] = (ieee_oui >> 0) & 0xff;
336 2 : pi = snap_get_protocol_info (sm, &h);
337 2 : if (pi)
338 0 : return;
339 :
340 2 : vec_add2 (sm->protocols, pi, 1);
341 :
342 2 : pi->name = format (0, "%s", name);
343 2 : pi->node_index = node_index;
344 2 : pi->next_index = vlib_node_add_next (vm, snap_input_node.index, node_index);
345 :
346 2 : key.oui = ieee_oui;
347 2 : key.protocol = clib_host_to_net_u16 (protocol);
348 :
349 2 : mhash_set (&sm->protocol_hash, &key, pi - sm->protocols, /* old_value */ 0);
350 4 : hash_set_mem (sm->protocol_info_by_name, name, pi - sm->protocols);
351 : }
352 :
353 : /*
354 : * fd.io coding-style-patch-verification: ON
355 : *
356 : * Local Variables:
357 : * eval: (c-set-style "gnu")
358 : * End:
359 : */
|