acl-plugin: hash lookup bitmask not cleared when ACL is unapplied from interface...
[vpp.git] / src / plugins / pppoe / pppoe_encap.c
1 /*
2  * Copyright (c) 2017 Intel 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 #include <vppinfra/error.h>
16 #include <vppinfra/hash.h>
17 #include <vnet/vnet.h>
18 #include <vnet/ip/ip.h>
19 #include <vnet/ethernet/ethernet.h>
20 #include <pppoe/pppoe.h>
21
22 /* Statistics (not all errors) */
23 #define foreach_pppoe_encap_error    \
24 _(ENCAPSULATED, "good packets encapsulated")
25
26 static char * pppoe_encap_error_strings[] = {
27 #define _(sym,string) string,
28   foreach_pppoe_encap_error
29 #undef _
30 };
31
32 typedef enum {
33 #define _(sym,str) PPPOE_ENCAP_ERROR_##sym,
34     foreach_pppoe_encap_error
35 #undef _
36     PPPOE_ENCAP_N_ERROR,
37 } pppoe_encap_error_t;
38
39 #define foreach_pppoe_encap_next       \
40 _(DROP, "error-drop")                  \
41 _(INTERFACE, "interface-output" )      \
42
43 typedef enum
44 {
45 #define _(s,n) PPPOE_ENCAP_NEXT_##s,
46   foreach_pppoe_encap_next
47 #undef _
48     PPPOE_ENCAP_N_NEXT,
49 } pppoe_encap_next_t;
50
51 typedef struct {
52   u32 session_index;
53   u32 session_id;
54 } pppoe_encap_trace_t;
55
56 u8 * format_pppoe_encap_trace (u8 * s, va_list * args)
57 {
58   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
59   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
60   pppoe_encap_trace_t * t
61       = va_arg (*args, pppoe_encap_trace_t *);
62
63   s = format (s, "PPPOE encap to pppoe_session%d session_id %d",
64               t->session_index, t->session_id);
65   return s;
66 }
67
68
69 #define foreach_fixed_header2_offset            \
70         _(0) _(1)
71
72
73 static uword
74 pppoe_encap (vlib_main_t * vm,
75               vlib_node_runtime_t * node,
76               vlib_frame_t * from_frame)
77 {
78   u32 n_left_from, next_index, * from, * to_next;
79   pppoe_main_t * pem = &pppoe_main;
80   vnet_main_t * vnm = pem->vnet_main;
81   vnet_interface_main_t * im = &vnm->interface_main;
82   u32 pkts_encapsulated = 0;
83   u32 thread_index = vlib_get_thread_index();
84   u32 stats_sw_if_index, stats_n_packets, stats_n_bytes;
85   u32 sw_if_index0 = 0, sw_if_index1 = 0;
86   u32 next0 = 0, next1 = 0;
87   pppoe_session_t * t0 = NULL, * t1 = NULL;
88
89   from = vlib_frame_vector_args (from_frame);
90   n_left_from = from_frame->n_vectors;
91
92   next_index = node->cached_next_index;
93   stats_sw_if_index = node->runtime_data[0];
94   stats_n_packets = stats_n_bytes = 0;
95
96   while (n_left_from > 0)
97     {
98       u32 n_left_to_next;
99
100       vlib_get_next_frame (vm, node, next_index,
101                            to_next, n_left_to_next);
102
103       while (n_left_from >= 4 && n_left_to_next >= 2)
104         {
105           u32 bi0, bi1;
106           vlib_buffer_t * b0, * b1;
107           u32 len0, len1;
108           ethernet_header_t * eth0, * eth1;
109           pppoe_header_t * pppoe0, * pppoe1;
110           u64 * copy_src0, * copy_dst0;
111           u64 * copy_src1, * copy_dst1;
112           u16 * copy_src_last0, * copy_dst_last0;
113           u16 * copy_src_last1, * copy_dst_last1;
114           u16 new_l0, new_l1;
115           u32 session_id0, session_id1;
116
117           /* Prefetch next iteration. */
118           {
119             vlib_buffer_t * p2, * p3;
120
121             p2 = vlib_get_buffer (vm, from[2]);
122             p3 = vlib_get_buffer (vm, from[3]);
123
124             vlib_prefetch_buffer_header (p2, LOAD);
125             vlib_prefetch_buffer_header (p3, LOAD);
126
127             CLIB_PREFETCH (p2->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
128             CLIB_PREFETCH (p3->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
129           }
130
131           bi0 = from[0];
132           bi1 = from[1];
133           to_next[0] = bi0;
134           to_next[1] = bi1;
135           from += 2;
136           to_next += 2;
137           n_left_to_next -= 2;
138           n_left_from -= 2;
139
140           b0 = vlib_get_buffer (vm, bi0);
141           b1 = vlib_get_buffer (vm, bi1);
142
143           /* Get next node index and if-index from session */
144           sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_TX];
145           session_id0 = pem->session_index_by_sw_if_index[sw_if_index0];
146           t0 = pool_elt_at_index(pem->sessions, session_id0);
147           next0 = PPPOE_ENCAP_NEXT_INTERFACE;
148           vnet_buffer(b0)->sw_if_index[VLIB_TX] = t0->encap_if_index;
149
150           /* Get next node index and if-index from session */
151           sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_TX];
152           session_id1 = pem->session_index_by_sw_if_index[sw_if_index1];
153           t1 = pool_elt_at_index(pem->sessions, session_id1);
154           next1 = PPPOE_ENCAP_NEXT_INTERFACE;
155           vnet_buffer(b1)->sw_if_index[VLIB_TX] = t1->encap_if_index;
156
157           /* Apply the rewrite string. $$$$ vnet_rewrite? */
158           vlib_buffer_advance (b0, -(word)_vec_len(t0->rewrite));
159           vlib_buffer_advance (b1, -(word)_vec_len(t1->rewrite));
160
161           eth0 = (ethernet_header_t *)(vlib_buffer_get_current(b0));
162           eth1 = (ethernet_header_t *)(vlib_buffer_get_current(b1));
163
164           /* Copy the fixed header */
165           copy_dst0 = (u64 *) eth0;
166           copy_src0 = (u64 *) t0->rewrite;
167           copy_dst1 = (u64 *) eth1;
168           copy_src1 = (u64 *) t1->rewrite;
169           /* Copy first 8-bytes at a time */
170 #define _(offs) copy_dst0[offs] = copy_src0[offs];
171           foreach_fixed_header2_offset;
172 #undef _
173           /* Last 6 octets. Hopefully gcc will be our friend */
174           copy_dst_last0 = (u16 *)(&copy_dst0[2]);
175           copy_src_last0 = (u16 *)(&copy_src0[2]);
176           copy_dst_last0[0] = copy_src_last0[0];
177           copy_dst_last0[1] = copy_src_last0[1];
178           copy_dst_last0[2] = copy_src_last0[2];
179
180 #define _(offs) copy_dst1[offs] = copy_src1[offs];
181           foreach_fixed_header2_offset;
182 #undef _
183           /* Last 6 octets. Hopefully gcc will be our friend */
184           copy_dst_last1 = (u16 *)(&copy_dst1[2]);
185           copy_src_last1 = (u16 *)(&copy_src1[2]);
186           copy_dst_last1[0] = copy_src_last1[0];
187           copy_dst_last1[1] = copy_src_last1[1];
188           copy_dst_last1[2] = copy_src_last1[2];
189
190           /* Fix PPPoE length */
191           new_l0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain(vm, b0)
192                                          - sizeof (*pppoe0) - sizeof(*eth0));
193           pppoe0 = (pppoe_header_t *)(eth0 + 1);
194           pppoe0->length = new_l0;
195
196           new_l1 = clib_host_to_net_u16 (vlib_buffer_length_in_chain(vm, b1)
197                                          - sizeof (*pppoe1) - sizeof(*eth1));
198           pppoe1 = (pppoe_header_t *)(eth1 + 1);
199           pppoe1->length = new_l1;
200
201           pkts_encapsulated += 2;
202           len0 = vlib_buffer_length_in_chain (vm, b0);
203           len1 = vlib_buffer_length_in_chain (vm, b1);
204           stats_n_packets += 2;
205           stats_n_bytes += len0 + len1;
206
207           /* Batch stats increment on the same pppoe session so counter is not
208              incremented per packet. Note stats are still incremented for deleted
209              and admin-down session where packets are dropped. It is not worthwhile
210              to check for this rare case and affect normal path performance. */
211           if (PREDICT_FALSE ((sw_if_index0 != stats_sw_if_index) ||
212                              (sw_if_index1 != stats_sw_if_index)))
213             {
214               stats_n_packets -= 2;
215               stats_n_bytes -= len0 + len1;
216               if (sw_if_index0 == sw_if_index1)
217                 {
218                   if (stats_n_packets)
219                     vlib_increment_combined_counter
220                       (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_TX,
221                        thread_index, stats_sw_if_index,
222                        stats_n_packets, stats_n_bytes);
223                   stats_sw_if_index = sw_if_index0;
224                   stats_n_packets = 2;
225                   stats_n_bytes = len0 + len1;
226                 }
227               else
228                 {
229                   vlib_increment_combined_counter
230                       (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_TX,
231                        thread_index, sw_if_index0, 1, len0);
232                   vlib_increment_combined_counter
233                       (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_TX,
234                        thread_index, sw_if_index1, 1, len1);
235                 }
236             }
237
238           if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
239             {
240               pppoe_encap_trace_t *tr =
241                 vlib_add_trace (vm, node, b0, sizeof (*tr));
242               tr->session_index = t0 - pem->sessions;
243               tr->session_id = t0->session_id;
244            }
245
246           if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
247             {
248               pppoe_encap_trace_t *tr =
249                 vlib_add_trace (vm, node, b1, sizeof (*tr));
250               tr->session_index = t1 - pem->sessions;
251               tr->session_id = t1->session_id;
252             }
253
254           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
255                                            to_next, n_left_to_next,
256                                            bi0, bi1, next0, next1);
257         }
258
259       while (n_left_from > 0 && n_left_to_next > 0)
260         {
261           u32 bi0;
262           vlib_buffer_t * b0;
263           ethernet_header_t * eth0;
264           pppoe_header_t * pppoe0;
265           u64 * copy_src0, * copy_dst0;
266           u16 * copy_src_last0, * copy_dst_last0;
267           u16 new_l0;
268           u32 len0;
269           u32 session_id0;
270
271           bi0 = from[0];
272           to_next[0] = bi0;
273           from += 1;
274           to_next += 1;
275           n_left_from -= 1;
276           n_left_to_next -= 1;
277
278           b0 = vlib_get_buffer (vm, bi0);
279
280           /* Get next node index and if-index from session */
281           sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_TX];
282           session_id0 = pem->session_index_by_sw_if_index[sw_if_index0];
283           t0 = pool_elt_at_index(pem->sessions, session_id0);
284           next0 = PPPOE_ENCAP_NEXT_INTERFACE;
285           vnet_buffer(b0)->sw_if_index[VLIB_TX] = t0->encap_if_index;
286
287           /* Apply the rewrite string. $$$$ vnet_rewrite? */
288           vlib_buffer_advance (b0, -(word)_vec_len(t0->rewrite));
289
290           eth0 = (ethernet_header_t *)(vlib_buffer_get_current(b0));
291           /* Copy the fixed header */
292           copy_dst0 = (u64 *) eth0;
293           copy_src0 = (u64 *) t0->rewrite;
294
295           /* Copy first 8-bytes at a time */
296 #define _(offs) copy_dst0[offs] = copy_src0[offs];
297           foreach_fixed_header2_offset;
298 #undef _
299           /* Last 6 octets. Hopefully gcc will be our friend */
300           copy_dst_last0 = (u16 *)(&copy_dst0[2]);
301           copy_src_last0 = (u16 *)(&copy_src0[2]);
302           copy_dst_last0[0] = copy_src_last0[0];
303           copy_dst_last0[1] = copy_src_last0[1];
304           copy_dst_last0[2] = copy_src_last0[2];
305
306           /* Fix PPPoE length */
307           new_l0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain(vm, b0)
308                                          - sizeof (*pppoe0) - sizeof(*eth0));
309           pppoe0 = (pppoe_header_t *)(eth0 + 1);
310           pppoe0->length = new_l0;
311
312           pkts_encapsulated ++;
313           len0 = vlib_buffer_length_in_chain (vm, b0);
314           stats_n_packets += 1;
315           stats_n_bytes += len0;
316
317           /* Batch stats increment on the same pppoe session so counter is not
318              incremented per packet. Note stats are still incremented for deleted
319              and admin-down session where packets are dropped. It is not worthwhile
320              to check for this rare case and affect normal path performance. */
321           if (PREDICT_FALSE (sw_if_index0 != stats_sw_if_index))
322             {
323               stats_n_packets -= 1;
324               stats_n_bytes -= len0;
325               if (stats_n_packets)
326                 vlib_increment_combined_counter
327                   (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_TX,
328                    thread_index, stats_sw_if_index,
329                    stats_n_packets, stats_n_bytes);
330               stats_n_packets = 1;
331               stats_n_bytes = len0;
332               stats_sw_if_index = sw_if_index0;
333             }
334
335           if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
336             {
337               pppoe_encap_trace_t *tr =
338                 vlib_add_trace (vm, node, b0, sizeof (*tr));
339               tr->session_index = t0 - pem->sessions;
340               tr->session_id = t0->session_id;
341             }
342           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
343                                            to_next, n_left_to_next,
344                                            bi0, next0);
345         }
346
347       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
348     }
349
350   /* Do we still need this now that session tx stats is kept? */
351   vlib_node_increment_counter (vm, node->node_index,
352                                PPPOE_ENCAP_ERROR_ENCAPSULATED,
353                                pkts_encapsulated);
354
355   /* Increment any remaining batch stats */
356   if (stats_n_packets)
357     {
358       vlib_increment_combined_counter
359         (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_TX,
360          thread_index, stats_sw_if_index, stats_n_packets, stats_n_bytes);
361       node->runtime_data[0] = stats_sw_if_index;
362     }
363
364   return from_frame->n_vectors;
365 }
366
367 VLIB_REGISTER_NODE (pppoe_encap_node) = {
368   .function = pppoe_encap,
369   .name = "pppoe-encap",
370   .vector_size = sizeof (u32),
371   .format_trace = format_pppoe_encap_trace,
372   .type = VLIB_NODE_TYPE_INTERNAL,
373   .n_errors = ARRAY_LEN(pppoe_encap_error_strings),
374   .error_strings = pppoe_encap_error_strings,
375   .n_next_nodes = PPPOE_ENCAP_N_NEXT,
376   .next_nodes = {
377 #define _(s,n) [PPPOE_ENCAP_NEXT_##s] = n,
378     foreach_pppoe_encap_next
379 #undef _
380   },
381 };
382
383 VLIB_NODE_FUNCTION_MULTIARCH (pppoe_encap_node, pppoe_encap)
384