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 : * llc_node.c: llc 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 :
44 : #define foreach_llc_input_next \
45 : _ (PUNT, "error-punt") \
46 : _ (DROP, "error-drop")
47 :
48 : typedef enum
49 : {
50 : #define _(s,n) LLC_INPUT_NEXT_##s,
51 : foreach_llc_input_next
52 : #undef _
53 : LLC_INPUT_N_NEXT,
54 : } llc_input_next_t;
55 :
56 : typedef struct
57 : {
58 : u8 packet_data[32];
59 : } llc_input_trace_t;
60 :
61 : static u8 *
62 4 : format_llc_input_trace (u8 * s, va_list * va)
63 : {
64 4 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
65 4 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
66 4 : llc_input_trace_t *t = va_arg (*va, llc_input_trace_t *);
67 :
68 4 : s = format (s, "%U", format_llc_header, t->packet_data);
69 :
70 4 : return s;
71 : }
72 :
73 : static uword
74 4 : llc_input (vlib_main_t * vm,
75 : vlib_node_runtime_t * node, vlib_frame_t * from_frame)
76 : {
77 4 : llc_main_t *lm = &llc_main;
78 : u32 n_left_from, next_index, *from, *to_next;
79 :
80 4 : from = vlib_frame_vector_args (from_frame);
81 4 : n_left_from = from_frame->n_vectors;
82 :
83 4 : if (node->flags & VLIB_NODE_FLAG_TRACE)
84 4 : vlib_trace_frame_buffers_only (vm, node,
85 : from,
86 : n_left_from,
87 : sizeof (from[0]),
88 : sizeof (llc_input_trace_t));
89 :
90 4 : next_index = node->cached_next_index;
91 :
92 8 : while (n_left_from > 0)
93 : {
94 : u32 n_left_to_next;
95 :
96 4 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
97 :
98 4 : while (n_left_from >= 4 && n_left_to_next >= 2)
99 : {
100 : u32 bi0, bi1;
101 : vlib_buffer_t *b0, *b1;
102 : llc_header_t *h0, *h1;
103 : u8 next0, next1, len0, len1, enqueue_code;
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 : len0 = llc_header_length (h0);
135 0 : len1 = llc_header_length (h1);
136 :
137 0 : vlib_buffer_advance (b0, len0);
138 0 : vlib_buffer_advance (b1, len1);
139 :
140 0 : next0 = lm->input_next_by_protocol[h0->dst_sap];
141 0 : next1 = lm->input_next_by_protocol[h1->dst_sap];
142 :
143 0 : b0->error =
144 0 : node->errors[next0 ==
145 : LLC_INPUT_NEXT_DROP ? LLC_ERROR_UNKNOWN_PROTOCOL :
146 : LLC_ERROR_NONE];
147 0 : b1->error =
148 0 : node->errors[next1 ==
149 : LLC_INPUT_NEXT_DROP ? LLC_ERROR_UNKNOWN_PROTOCOL :
150 : LLC_ERROR_NONE];
151 :
152 0 : enqueue_code = (next0 != next_index) + 2 * (next1 != next_index);
153 :
154 0 : if (PREDICT_FALSE (enqueue_code != 0))
155 : {
156 0 : switch (enqueue_code)
157 : {
158 0 : case 1:
159 : /* A B A */
160 0 : to_next[-2] = bi1;
161 0 : to_next -= 1;
162 0 : n_left_to_next += 1;
163 0 : vlib_set_next_frame_buffer (vm, node, next0, bi0);
164 0 : break;
165 :
166 0 : case 2:
167 : /* A A B */
168 0 : to_next -= 1;
169 0 : n_left_to_next += 1;
170 0 : vlib_set_next_frame_buffer (vm, node, next1, bi1);
171 0 : break;
172 :
173 0 : case 3:
174 : /* A B B or A B C */
175 0 : to_next -= 2;
176 0 : n_left_to_next += 2;
177 0 : vlib_set_next_frame_buffer (vm, node, next0, bi0);
178 0 : vlib_set_next_frame_buffer (vm, node, next1, bi1);
179 0 : if (next0 == next1)
180 : {
181 0 : vlib_put_next_frame (vm, node, next_index,
182 : n_left_to_next);
183 0 : next_index = next1;
184 0 : vlib_get_next_frame (vm, node, next_index, to_next,
185 : n_left_to_next);
186 : }
187 : }
188 : }
189 : }
190 :
191 8 : while (n_left_from > 0 && n_left_to_next > 0)
192 : {
193 : u32 bi0;
194 : vlib_buffer_t *b0;
195 : llc_header_t *h0;
196 : u8 next0, len0;
197 :
198 4 : bi0 = from[0];
199 4 : to_next[0] = bi0;
200 4 : from += 1;
201 4 : to_next += 1;
202 4 : n_left_from -= 1;
203 4 : n_left_to_next -= 1;
204 :
205 4 : b0 = vlib_get_buffer (vm, bi0);
206 :
207 4 : h0 = vlib_buffer_get_current (b0);
208 :
209 4 : len0 = llc_header_length (h0);
210 :
211 4 : vlib_buffer_advance (b0, len0);
212 :
213 4 : next0 = lm->input_next_by_protocol[h0->dst_sap];
214 :
215 4 : b0->error =
216 4 : node->errors[next0 ==
217 : LLC_INPUT_NEXT_DROP ? LLC_ERROR_UNKNOWN_PROTOCOL :
218 : LLC_ERROR_NONE];
219 :
220 : /* Sent packet to wrong next? */
221 4 : if (PREDICT_FALSE (next0 != next_index))
222 : {
223 : /* Return old frame; remove incorrectly enqueued packet. */
224 2 : vlib_put_next_frame (vm, node, next_index, n_left_to_next + 1);
225 :
226 : /* Send to correct next. */
227 2 : next_index = next0;
228 2 : vlib_get_next_frame (vm, node, next_index,
229 : to_next, n_left_to_next);
230 :
231 2 : to_next[0] = bi0;
232 2 : to_next += 1;
233 2 : n_left_to_next -= 1;
234 : }
235 : }
236 :
237 4 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
238 : }
239 :
240 4 : return from_frame->n_vectors;
241 : }
242 :
243 : static char *llc_error_strings[] = {
244 : #define _(f,s) s,
245 : foreach_llc_error
246 : #undef _
247 : };
248 :
249 : /* *INDENT-OFF* */
250 178120 : VLIB_REGISTER_NODE (llc_input_node) = {
251 : .function = llc_input,
252 : .name = "llc-input",
253 : /* Takes a vector of packets. */
254 : .vector_size = sizeof (u32),
255 :
256 : .n_errors = LLC_N_ERROR,
257 : .error_strings = llc_error_strings,
258 :
259 : .n_next_nodes = LLC_INPUT_N_NEXT,
260 : .next_nodes = {
261 : #define _(s,n) [LLC_INPUT_NEXT_##s] = n,
262 : foreach_llc_input_next
263 : #undef _
264 : },
265 :
266 : .format_buffer = format_llc_header_with_length,
267 : .format_trace = format_llc_input_trace,
268 : .unformat_buffer = unformat_llc_header,
269 : };
270 : /* *INDENT-ON* */
271 :
272 : static void
273 559 : llc_setup_node (vlib_main_t *vm, u32 node_index)
274 : {
275 559 : vlib_node_t *n = vlib_get_node (vm, node_index);
276 559 : pg_node_t *pn = pg_get_node (node_index);
277 :
278 559 : n->format_buffer = format_llc_header_with_length;
279 559 : n->unformat_buffer = unformat_llc_header;
280 559 : pn->unformat_edit = unformat_pg_llc_header;
281 559 : }
282 :
283 : static clib_error_t *
284 559 : llc_input_init (vlib_main_t * vm)
285 : {
286 559 : llc_main_t *lm = &llc_main;
287 :
288 : {
289 559 : clib_error_t *error = vlib_call_init_function (vm, llc_init);
290 559 : if (error)
291 0 : clib_error_report (error);
292 : }
293 :
294 559 : llc_setup_node (vm, llc_input_node.index);
295 :
296 : {
297 : int i;
298 143663 : for (i = 0; i < ARRAY_LEN (lm->input_next_by_protocol); i++)
299 143104 : lm->input_next_by_protocol[i] = LLC_INPUT_NEXT_DROP;
300 : }
301 :
302 559 : return 0;
303 : }
304 :
305 29119 : VLIB_INIT_FUNCTION (llc_input_init);
306 :
307 : void
308 3354 : llc_register_input_protocol (vlib_main_t * vm,
309 : llc_protocol_t protocol, u32 node_index)
310 : {
311 3354 : llc_main_t *lm = &llc_main;
312 : llc_protocol_info_t *pi;
313 :
314 : {
315 3354 : clib_error_t *error = vlib_call_init_function (vm, llc_input_init);
316 3354 : if (error)
317 0 : clib_error_report (error);
318 : /* Otherwise, osi_input_init will wipe out e.g. the snap init */
319 3354 : error = vlib_call_init_function (vm, osi_input_init);
320 3354 : if (error)
321 0 : clib_error_report (error);
322 : }
323 :
324 3354 : pi = llc_get_protocol_info (lm, protocol);
325 3354 : pi->node_index = node_index;
326 3354 : pi->next_index = vlib_node_add_next (vm, llc_input_node.index, node_index);
327 :
328 3354 : lm->input_next_by_protocol[protocol] = pi->next_index;
329 3354 : }
330 :
331 : /*
332 : * fd.io coding-style-patch-verification: ON
333 : *
334 : * Local Variables:
335 : * eval: (c-set-style "gnu")
336 : * End:
337 : */
|