Line data Source code
1 : /*
2 : * decap.c: pppoe session decap packet processing
3 : *
4 : * Copyright (c) 2017 Intel and/or its affiliates.
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at:
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 :
18 : #include <vlib/vlib.h>
19 : #include <vnet/ppp/packet.h>
20 : #include <pppoe/pppoe.h>
21 :
22 : typedef struct {
23 : u32 next_index;
24 : u32 session_index;
25 : u32 session_id;
26 : u32 error;
27 : } pppoe_rx_trace_t;
28 :
29 8 : static u8 * format_pppoe_rx_trace (u8 * s, va_list * args)
30 : {
31 8 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
32 8 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
33 8 : pppoe_rx_trace_t * t = va_arg (*args, pppoe_rx_trace_t *);
34 :
35 8 : if (t->session_index != ~0)
36 : {
37 4 : s = format (s, "PPPoE decap from pppoe_session%d session_id %d next %d error %d",
38 : t->session_index, t->session_id, t->next_index, t->error);
39 : }
40 : else
41 : {
42 4 : s = format (s, "PPPoE decap error - session for session_id %d does not exist",
43 : t->session_id);
44 : }
45 8 : return s;
46 : }
47 :
48 2311 : VLIB_NODE_FN (pppoe_input_node) (vlib_main_t * vm,
49 : vlib_node_runtime_t * node,
50 : vlib_frame_t * from_frame)
51 : {
52 : u32 n_left_from, next_index, * from, * to_next;
53 11 : pppoe_main_t * pem = &pppoe_main;
54 11 : vnet_main_t * vnm = pem->vnet_main;
55 11 : vnet_interface_main_t * im = &vnm->interface_main;
56 11 : u32 pkts_decapsulated = 0;
57 11 : u32 thread_index = vlib_get_thread_index();
58 : u32 stats_sw_if_index, stats_n_packets, stats_n_bytes;
59 : pppoe_entry_key_t cached_key;
60 : pppoe_entry_result_t cached_result;
61 :
62 11 : from = vlib_frame_vector_args (from_frame);
63 11 : n_left_from = from_frame->n_vectors;
64 :
65 : /* Clear the one-entry cache in case session table was updated */
66 11 : cached_key.raw = ~0;
67 11 : cached_result.raw = ~0; /* warning be gone */
68 :
69 11 : next_index = node->cached_next_index;
70 11 : stats_sw_if_index = node->runtime_data[0];
71 11 : stats_n_packets = stats_n_bytes = 0;
72 :
73 22 : while (n_left_from > 0)
74 : {
75 : u32 n_left_to_next;
76 :
77 11 : vlib_get_next_frame (vm, node, next_index,
78 : to_next, n_left_to_next);
79 11 : while (n_left_from >= 4 && n_left_to_next >= 2)
80 : {
81 : u32 bi0, bi1;
82 : vlib_buffer_t * b0, * b1;
83 : u32 next0, next1;
84 : ethernet_header_t *h0, *h1;
85 0 : ethernet_vlan_header_t *vlan0 = 0, *vlan1 = 0;
86 : pppoe_header_t * pppoe0, * pppoe1;
87 0 : u16 ppp_proto0 = 0, ppp_proto1 = 0;
88 : pppoe_session_t * t0, * t1;
89 0 : u32 error0 = 0, error1 = 0;
90 : u32 sw_if_index0, sw_if_index1, len0, len1;
91 : pppoe_entry_key_t key0, key1;
92 : pppoe_entry_result_t result0, result1;
93 : u32 bucket0, bucket1;
94 : u16 type0, type1;
95 :
96 : /* Prefetch next iteration. */
97 : {
98 : vlib_buffer_t * p2, * p3;
99 :
100 0 : p2 = vlib_get_buffer (vm, from[2]);
101 0 : p3 = vlib_get_buffer (vm, from[3]);
102 :
103 0 : vlib_prefetch_buffer_header (p2, LOAD);
104 0 : vlib_prefetch_buffer_header (p3, LOAD);
105 :
106 0 : CLIB_PREFETCH (p2->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
107 0 : CLIB_PREFETCH (p3->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
108 : }
109 :
110 0 : bi0 = from[0];
111 0 : bi1 = from[1];
112 0 : to_next[0] = bi0;
113 0 : to_next[1] = bi1;
114 0 : from += 2;
115 0 : to_next += 2;
116 0 : n_left_to_next -= 2;
117 0 : n_left_from -= 2;
118 :
119 0 : b0 = vlib_get_buffer (vm, bi0);
120 0 : b1 = vlib_get_buffer (vm, bi1);
121 0 : error0 = 0;
122 0 : error1 = 0;
123 :
124 : /* get client mac */
125 0 : vlib_buffer_reset(b0);
126 0 : h0 = vlib_buffer_get_current (b0);
127 :
128 : /* get pppoe header */
129 0 : type0 = clib_net_to_host_u16(h0->type);
130 0 : if(type0 == ETHERNET_TYPE_VLAN){
131 0 : vlan0 = (ethernet_vlan_header_t *)(h0+1);
132 0 : type0 = clib_net_to_host_u16(vlan0->type);
133 0 : pppoe0 = (pppoe_header_t*)(vlan0+1);
134 0 : if( type0 != ETHERNET_TYPE_PPPOE_DISCOVERY && type0 != ETHERNET_TYPE_PPPOE_SESSION ) {
135 0 : error0 = PPPOE_ERROR_BAD_VER_TYPE;
136 0 : result0.fields.session_index =
137 : ~0; // avoid tracing random data
138 0 : next0 = PPPOE_INPUT_NEXT_DROP;
139 0 : goto trace0;
140 : }
141 : } else {
142 0 : pppoe0 = (pppoe_header_t*)(h0+1);
143 : }
144 :
145 0 : ppp_proto0 = clib_net_to_host_u16(pppoe0->ppp_proto);
146 :
147 : /* Manipulate packet 0 */
148 0 : if ((ppp_proto0 != PPP_PROTOCOL_ip4)
149 0 : && (ppp_proto0 != PPP_PROTOCOL_ip6))
150 : {
151 : vlan0 == 0 ?
152 0 : vlib_buffer_advance(b0, sizeof(*h0))
153 0 : :
154 0 : vlib_buffer_advance(b0, sizeof(*h0)+sizeof(*vlan0));
155 0 : error0 = PPPOE_ERROR_CONTROL_PLANE;
156 0 : next0 = PPPOE_INPUT_NEXT_CP_INPUT;
157 0 : result0.fields.session_index = ~0;
158 0 : goto trace0;
159 : }
160 :
161 :
162 0 : pppoe_lookup_1 (&pem->session_table, &cached_key, &cached_result,
163 0 : h0->src_address, pppoe0->session_id,
164 : &key0, &bucket0, &result0);
165 0 : if (PREDICT_FALSE (result0.fields.session_index == ~0))
166 : {
167 0 : error0 = PPPOE_ERROR_NO_SUCH_SESSION;
168 0 : next0 = PPPOE_INPUT_NEXT_DROP;
169 0 : goto trace0;
170 : }
171 :
172 0 : t0 = pool_elt_at_index (pem->sessions,
173 : result0.fields.session_index);
174 :
175 : /* Pop Eth and PPPoE header */
176 : vlan0 == 0 ?
177 0 : vlib_buffer_advance(b0, sizeof(*h0)+sizeof(*pppoe0))
178 0 : :
179 0 : vlib_buffer_advance(b0, sizeof(*h0)+sizeof(*vlan0)+sizeof(*pppoe0));
180 :
181 0 : next0 = (ppp_proto0==PPP_PROTOCOL_ip4)?
182 : PPPOE_INPUT_NEXT_IP4_INPUT
183 0 : : PPPOE_INPUT_NEXT_IP6_INPUT;
184 :
185 0 : sw_if_index0 = t0->sw_if_index;
186 0 : len0 = vlib_buffer_length_in_chain (vm, b0);
187 0 : vnet_buffer(b0)->sw_if_index[VLIB_RX] = sw_if_index0;
188 :
189 0 : pkts_decapsulated ++;
190 0 : stats_n_packets += 1;
191 0 : stats_n_bytes += len0;
192 :
193 : /* Batch stats increment on the same pppoe session so counter
194 : is not incremented per packet */
195 0 : if (PREDICT_FALSE (sw_if_index0 != stats_sw_if_index))
196 : {
197 0 : stats_n_packets -= 1;
198 0 : stats_n_bytes -= len0;
199 0 : if (stats_n_packets)
200 0 : vlib_increment_combined_counter
201 : (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX,
202 : thread_index, stats_sw_if_index,
203 : stats_n_packets, stats_n_bytes);
204 0 : stats_n_packets = 1;
205 0 : stats_n_bytes = len0;
206 0 : stats_sw_if_index = sw_if_index0;
207 : }
208 :
209 0 : trace0:
210 0 : b0->error = error0 ? node->errors[error0] : 0;
211 :
212 0 : if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
213 : {
214 : pppoe_rx_trace_t *tr
215 0 : = vlib_add_trace (vm, node, b0, sizeof (*tr));
216 0 : tr->next_index = next0;
217 0 : tr->error = error0;
218 0 : tr->session_index = result0.fields.session_index;
219 0 : tr->session_id = clib_net_to_host_u32(pppoe0->session_id);
220 : }
221 :
222 : /* get client mac */
223 0 : vlib_buffer_reset(b1);
224 0 : h1 = vlib_buffer_get_current (b1);
225 :
226 : /* get pppoe header */
227 0 : type1 = clib_net_to_host_u16(h1->type);
228 0 : if(type1 == ETHERNET_TYPE_VLAN){
229 0 : vlan1 = (ethernet_vlan_header_t *)(h1+1);
230 0 : type1 = clib_net_to_host_u16(vlan1->type);
231 0 : pppoe1 = (pppoe_header_t*)(vlan1+1);
232 0 : if( type1 != ETHERNET_TYPE_PPPOE_DISCOVERY && type1 != ETHERNET_TYPE_PPPOE_SESSION ) {
233 0 : error1 = PPPOE_ERROR_BAD_VER_TYPE;
234 0 : result1.fields.session_index =
235 : ~0; // avoid tracing random data
236 0 : next1 = PPPOE_INPUT_NEXT_DROP;
237 0 : goto trace1;
238 : }
239 : } else {
240 0 : pppoe1 = (pppoe_header_t*)(h1+1);
241 : }
242 :
243 0 : ppp_proto1 = clib_net_to_host_u16(pppoe1->ppp_proto);
244 :
245 : /* Manipulate packet 1 */
246 0 : if ((ppp_proto1 != PPP_PROTOCOL_ip4)
247 0 : && (ppp_proto1 != PPP_PROTOCOL_ip6))
248 : {
249 : vlan1 == 0 ?
250 0 : vlib_buffer_advance(b1, sizeof(*h1))
251 0 : :
252 0 : vlib_buffer_advance(b1, sizeof(*h1)+sizeof(*vlan1));
253 0 : error1 = PPPOE_ERROR_CONTROL_PLANE;
254 0 : next1 = PPPOE_INPUT_NEXT_CP_INPUT;
255 0 : result1.fields.session_index = ~0;
256 0 : goto trace1;
257 : }
258 :
259 0 : pppoe_lookup_1 (&pem->session_table, &cached_key, &cached_result,
260 0 : h1->src_address, pppoe1->session_id,
261 : &key1, &bucket1, &result1);
262 0 : if (PREDICT_FALSE (result1.fields.session_index == ~0))
263 : {
264 0 : error1 = PPPOE_ERROR_NO_SUCH_SESSION;
265 0 : next1 = PPPOE_INPUT_NEXT_DROP;
266 0 : goto trace1;
267 : }
268 :
269 0 : t1 = pool_elt_at_index (pem->sessions,
270 : result1.fields.session_index);
271 :
272 : /* Pop Eth and PPPoE header */
273 : vlan1 == 0 ?
274 0 : vlib_buffer_advance(b1, sizeof(*h1)+sizeof(*pppoe1))
275 0 : :
276 0 : vlib_buffer_advance(b1, sizeof(*h1)+sizeof(*vlan1)+sizeof(*pppoe1));
277 :
278 0 : next1 = (ppp_proto1==PPP_PROTOCOL_ip4)?
279 : PPPOE_INPUT_NEXT_IP4_INPUT
280 0 : : PPPOE_INPUT_NEXT_IP6_INPUT;
281 :
282 0 : sw_if_index1 = t1->sw_if_index;
283 0 : len1 = vlib_buffer_length_in_chain (vm, b1);
284 0 : vnet_buffer(b1)->sw_if_index[VLIB_RX] = sw_if_index1;
285 :
286 0 : pkts_decapsulated ++;
287 0 : stats_n_packets += 1;
288 0 : stats_n_bytes += len1;
289 :
290 : /* Batch stats increment on the same pppoe session so counter
291 : is not incremented per packet */
292 0 : if (PREDICT_FALSE (sw_if_index1 != stats_sw_if_index))
293 : {
294 0 : stats_n_packets -= 1;
295 0 : stats_n_bytes -= len1;
296 0 : if (stats_n_packets)
297 0 : vlib_increment_combined_counter
298 : (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX,
299 : thread_index, stats_sw_if_index,
300 : stats_n_packets, stats_n_bytes);
301 0 : stats_n_packets = 1;
302 0 : stats_n_bytes = len1;
303 0 : stats_sw_if_index = sw_if_index1;
304 : }
305 :
306 0 : trace1:
307 0 : b1->error = error1 ? node->errors[error1] : 0;
308 :
309 0 : if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
310 : {
311 : pppoe_rx_trace_t *tr
312 0 : = vlib_add_trace (vm, node, b1, sizeof (*tr));
313 0 : tr->next_index = next1;
314 0 : tr->error = error1;
315 0 : tr->session_index = result1.fields.session_index;
316 0 : tr->session_id = clib_net_to_host_u32(pppoe1->session_id);
317 : }
318 :
319 0 : vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
320 : to_next, n_left_to_next,
321 : bi0, bi1, next0, next1);
322 : }
323 :
324 22 : while (n_left_from > 0 && n_left_to_next > 0)
325 : {
326 : u32 bi0;
327 : vlib_buffer_t * b0;
328 : u32 next0;
329 : ethernet_header_t *h0;
330 11 : ethernet_vlan_header_t *vlan0 = 0;
331 : pppoe_header_t * pppoe0;
332 11 : u16 ppp_proto0 = 0;
333 : pppoe_session_t * t0;
334 : u32 error0;
335 : u32 sw_if_index0, len0;
336 : pppoe_entry_key_t key0;
337 : pppoe_entry_result_t result0;
338 : u32 bucket0;
339 : u32 type0;
340 :
341 11 : bi0 = from[0];
342 11 : to_next[0] = bi0;
343 11 : from += 1;
344 11 : to_next += 1;
345 11 : n_left_from -= 1;
346 11 : n_left_to_next -= 1;
347 :
348 11 : b0 = vlib_get_buffer (vm, bi0);
349 11 : error0 = 0;
350 :
351 : /* get client mac */
352 11 : vlib_buffer_reset(b0);
353 11 : h0 = vlib_buffer_get_current (b0);
354 :
355 : /* get pppoe header */
356 11 : type0 = clib_net_to_host_u16(h0->type);
357 11 : if(type0 == ETHERNET_TYPE_VLAN){
358 0 : vlan0 = (ethernet_vlan_header_t *)(h0+1);
359 0 : type0 = clib_net_to_host_u16(vlan0->type);
360 0 : pppoe0 = (pppoe_header_t*)(vlan0+1);
361 0 : if( type0 != ETHERNET_TYPE_PPPOE_DISCOVERY && type0 != ETHERNET_TYPE_PPPOE_SESSION ) {
362 0 : error0 = PPPOE_ERROR_BAD_VER_TYPE;
363 0 : result0.fields.session_index =
364 : ~0; // avoid tracing random data
365 0 : next0 = PPPOE_INPUT_NEXT_DROP;
366 0 : goto trace00;
367 : }
368 : } else {
369 11 : pppoe0 = (pppoe_header_t*)(h0+1);
370 : }
371 :
372 11 : ppp_proto0 = clib_net_to_host_u16(pppoe0->ppp_proto);
373 :
374 11 : if ((ppp_proto0 != PPP_PROTOCOL_ip4)
375 8 : && (ppp_proto0 != PPP_PROTOCOL_ip6))
376 : {
377 : vlan0 == 0 ?
378 8 : vlib_buffer_advance(b0, sizeof(*h0))
379 8 : :
380 0 : vlib_buffer_advance(b0, sizeof(*h0)+sizeof(*vlan0));
381 8 : error0 = PPPOE_ERROR_CONTROL_PLANE;
382 8 : next0 = PPPOE_INPUT_NEXT_CP_INPUT;
383 8 : result0.fields.session_index = ~0;
384 8 : goto trace00;
385 : }
386 :
387 3 : pppoe_lookup_1 (&pem->session_table, &cached_key, &cached_result,
388 3 : h0->src_address, pppoe0->session_id,
389 : &key0, &bucket0, &result0);
390 3 : if (PREDICT_FALSE (result0.fields.session_index == ~0))
391 : {
392 0 : error0 = PPPOE_ERROR_NO_SUCH_SESSION;
393 0 : next0 = PPPOE_INPUT_NEXT_DROP;
394 0 : goto trace00;
395 : }
396 :
397 3 : t0 = pool_elt_at_index (pem->sessions,
398 : result0.fields.session_index);
399 :
400 : /* Pop Eth and PPPoE header */
401 : vlan0 == 0 ?
402 3 : vlib_buffer_advance(b0, sizeof(*h0)+sizeof(*pppoe0))
403 3 : :
404 0 : vlib_buffer_advance(b0, sizeof(*h0)+sizeof(*vlan0)+sizeof(*pppoe0));
405 :
406 3 : next0 = (ppp_proto0==PPP_PROTOCOL_ip4)?
407 : PPPOE_INPUT_NEXT_IP4_INPUT
408 3 : : PPPOE_INPUT_NEXT_IP6_INPUT;
409 :
410 3 : sw_if_index0 = t0->sw_if_index;
411 3 : len0 = vlib_buffer_length_in_chain (vm, b0);
412 3 : vnet_buffer(b0)->sw_if_index[VLIB_RX] = sw_if_index0;
413 :
414 3 : pkts_decapsulated ++;
415 3 : stats_n_packets += 1;
416 3 : stats_n_bytes += len0;
417 :
418 : /* Batch stats increment on the same pppoe session so counter
419 : is not incremented per packet */
420 3 : if (PREDICT_FALSE (sw_if_index0 != stats_sw_if_index))
421 : {
422 2 : stats_n_packets -= 1;
423 2 : stats_n_bytes -= len0;
424 2 : if (stats_n_packets)
425 0 : vlib_increment_combined_counter
426 : (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX,
427 : thread_index, stats_sw_if_index,
428 : stats_n_packets, stats_n_bytes);
429 2 : stats_n_packets = 1;
430 2 : stats_n_bytes = len0;
431 2 : stats_sw_if_index = sw_if_index0;
432 : }
433 :
434 1 : trace00:
435 11 : b0->error = error0 ? node->errors[error0] : 0;
436 :
437 11 : if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
438 : {
439 : pppoe_rx_trace_t *tr
440 11 : = vlib_add_trace (vm, node, b0, sizeof (*tr));
441 11 : tr->next_index = next0;
442 11 : tr->error = error0;
443 11 : tr->session_index = result0.fields.session_index;
444 11 : tr->session_id = clib_net_to_host_u16(pppoe0->session_id);
445 : }
446 11 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
447 : to_next, n_left_to_next,
448 : bi0, next0);
449 : }
450 :
451 11 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
452 : }
453 : /* Do we still need this now that session tx stats is kept? */
454 11 : vlib_node_increment_counter (vm, pppoe_input_node.index,
455 : PPPOE_ERROR_DECAPSULATED,
456 : pkts_decapsulated);
457 :
458 : /* Increment any remaining batch stats */
459 11 : if (stats_n_packets)
460 : {
461 3 : vlib_increment_combined_counter
462 : (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX,
463 : thread_index, stats_sw_if_index, stats_n_packets, stats_n_bytes);
464 3 : node->runtime_data[0] = stats_sw_if_index;
465 : }
466 :
467 11 : return from_frame->n_vectors;
468 : }
469 :
470 : #ifndef CLIB_MARCH_VARIANT
471 : char * pppoe_error_strings[] = {
472 : #define pppoe_error(n,s) s,
473 : #include <pppoe/pppoe_error.def>
474 : #undef pppoe_error
475 : #undef _
476 : };
477 : #endif /* CLIB_MARCH_VARIANT */
478 :
479 45528 : VLIB_REGISTER_NODE (pppoe_input_node) = {
480 : .name = "pppoe-input",
481 : /* Takes a vector of packets. */
482 : .vector_size = sizeof (u32),
483 :
484 : .n_errors = PPPOE_N_ERROR,
485 : .error_strings = pppoe_error_strings,
486 :
487 : .n_next_nodes = PPPOE_INPUT_N_NEXT,
488 : .next_nodes = {
489 : #define _(s,n) [PPPOE_INPUT_NEXT_##s] = n,
490 : foreach_pppoe_input_next
491 : #undef _
492 : },
493 :
494 : .format_trace = format_pppoe_rx_trace,
495 : };
496 :
497 : /* *INDENT-OFF* */
498 24767 : VNET_FEATURE_INIT (pppoe_input_node, static) =
499 : {
500 : .arc_name = "device-input",
501 : .node_name = "pppoe-input",
502 : .runs_before = VNET_FEATURES ("ethernet-input"),
503 : };
504 : /* *INDENT-ON */
|