Line data Source code
1 : /*
2 : * encap.c : L2TPv3 tunnel encapsulation
3 : *
4 : * Copyright (c) 2013 Cisco 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 <vppinfra/error.h>
19 : #include <vppinfra/hash.h>
20 : #include <vnet/vnet.h>
21 : #include <vnet/ip/ip.h>
22 : #include <vnet/ethernet/ethernet.h>
23 : #include <l2tp/l2tp.h>
24 :
25 : /* Statistics (not really errors) */
26 : #define foreach_l2t_encap_error \
27 : _(NETWORK_TO_USER, "L2TP L2 network to user (ip6) pkts") \
28 : _(LOOKUP_FAIL_TO_L3, "L2TP L2 session lookup failed pkts") \
29 : _(ADMIN_DOWN, "L2TP tunnel is down")
30 :
31 : static char *l2t_encap_error_strings[] = {
32 : #define _(sym,string) string,
33 : foreach_l2t_encap_error
34 : #undef _
35 : };
36 :
37 : typedef enum
38 : {
39 : #define _(sym,str) L2T_ENCAP_ERROR_##sym,
40 : foreach_l2t_encap_error
41 : #undef _
42 : L2T_ENCAP_N_ERROR,
43 : } l2t_encap_error_t;
44 :
45 :
46 : typedef enum
47 : {
48 : L2T_ENCAP_NEXT_DROP,
49 : L2T_ENCAP_NEXT_IP6_LOOKUP,
50 : L2T_ENCAP_N_NEXT,
51 : } l2t_encap_next_t;
52 :
53 : typedef struct
54 : {
55 : u32 cached_session_index;
56 : u32 cached_sw_if_index;
57 : vnet_main_t *vnet_main;
58 : } l2tp_encap_runtime_t;
59 :
60 : extern vlib_node_registration_t l2t_encap_node;
61 :
62 : #define NSTAGES 3
63 :
64 : static inline void
65 0 : stage0 (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_buffer_t * b)
66 : {
67 0 : vlib_prefetch_buffer_header (b, STORE);
68 0 : CLIB_PREFETCH (b->data, 2 * CLIB_CACHE_LINE_BYTES, STORE);
69 0 : }
70 :
71 : static inline void
72 0 : stage1 (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_buffer_t * b)
73 : {
74 0 : l2tp_encap_runtime_t *rt = (void *) node->runtime_data;
75 : vnet_hw_interface_t *hi;
76 :
77 0 : u32 sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_TX];
78 0 : u32 session_index = rt->cached_session_index;
79 :
80 0 : if (PREDICT_FALSE (rt->cached_sw_if_index != sw_if_index))
81 : {
82 0 : hi = vnet_get_sup_hw_interface (rt->vnet_main, sw_if_index);
83 0 : session_index = rt->cached_session_index = hi->dev_instance;
84 0 : rt->cached_sw_if_index = sw_if_index;
85 : }
86 :
87 : /* Remember mapping index, prefetch the mini counter */
88 0 : vnet_buffer (b)->l2t.next_index = L2T_ENCAP_NEXT_IP6_LOOKUP;
89 0 : vnet_buffer (b)->l2t.session_index = session_index;
90 :
91 : /* $$$$ prefetch counter... */
92 0 : }
93 :
94 : static inline u32
95 0 : last_stage (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_buffer_t * b)
96 : {
97 0 : l2t_main_t *lm = &l2t_main;
98 0 : vlib_node_t *n = vlib_get_node (vm, l2t_encap_node.index);
99 0 : u32 node_counter_base_index = n->error_heap_index;
100 0 : vlib_error_main_t *em = &vm->error_main;
101 : l2tpv3_header_t *l2tp;
102 : u32 session_index;
103 : u32 counter_index;
104 : l2t_session_t *s;
105 : ip6_header_t *ip6;
106 : u16 payload_length;
107 0 : u32 next_index = L2T_ENCAP_NEXT_IP6_LOOKUP;
108 :
109 : /* Other-than-output pkt? We're done... */
110 0 : if (vnet_buffer (b)->l2t.next_index != L2T_ENCAP_NEXT_IP6_LOOKUP)
111 0 : return vnet_buffer (b)->l2t.next_index;
112 :
113 0 : em->counters[node_counter_base_index + L2T_ENCAP_ERROR_NETWORK_TO_USER] +=
114 : 1;
115 :
116 0 : session_index = vnet_buffer (b)->l2t.session_index;
117 :
118 : counter_index =
119 0 : session_index_to_counter_index (session_index,
120 : SESSION_COUNTER_NETWORK_TO_USER);
121 :
122 : /* per-mapping byte stats include the ethernet header */
123 0 : vlib_increment_combined_counter (&lm->counter_main,
124 0 : vlib_get_thread_index (),
125 : counter_index, 1 /* packet_increment */ ,
126 : vlib_buffer_length_in_chain (vm, b));
127 :
128 0 : s = pool_elt_at_index (lm->sessions, session_index);
129 :
130 0 : vnet_buffer (b)->sw_if_index[VLIB_TX] = s->encap_fib_index;
131 :
132 : /* Paint on an l2tpv3 hdr */
133 0 : vlib_buffer_advance (b, -(s->l2tp_hdr_size));
134 0 : l2tp = vlib_buffer_get_current (b);
135 :
136 0 : l2tp->session_id = s->remote_session_id;
137 0 : l2tp->cookie = s->remote_cookie;
138 0 : if (PREDICT_FALSE (s->l2_sublayer_present))
139 : {
140 0 : l2tp->l2_specific_sublayer = 0;
141 : }
142 :
143 : /* Paint on an ip6 header */
144 0 : vlib_buffer_advance (b, -(sizeof (*ip6)));
145 0 : ip6 = vlib_buffer_get_current (b);
146 :
147 0 : if (PREDICT_FALSE (!(s->admin_up)))
148 : {
149 0 : b->error = node->errors[L2T_ENCAP_ERROR_ADMIN_DOWN];
150 0 : next_index = L2T_ENCAP_NEXT_DROP;
151 0 : goto done;
152 : }
153 :
154 0 : ip6->ip_version_traffic_class_and_flow_label =
155 0 : clib_host_to_net_u32 (0x6 << 28);
156 :
157 : /* calculate ip6 payload length */
158 0 : payload_length = vlib_buffer_length_in_chain (vm, b);
159 0 : payload_length -= sizeof (*ip6);
160 :
161 0 : ip6->payload_length = clib_host_to_net_u16 (payload_length);
162 0 : ip6->protocol = IP_PROTOCOL_L2TP;
163 0 : ip6->hop_limit = 0xff;
164 0 : ip6->src_address.as_u64[0] = s->our_address.as_u64[0];
165 0 : ip6->src_address.as_u64[1] = s->our_address.as_u64[1];
166 0 : ip6->dst_address.as_u64[0] = s->client_address.as_u64[0];
167 0 : ip6->dst_address.as_u64[1] = s->client_address.as_u64[1];
168 :
169 :
170 0 : done:
171 0 : if (PREDICT_FALSE (b->flags & VLIB_BUFFER_IS_TRACED))
172 : {
173 0 : l2t_trace_t *t = vlib_add_trace (vm, node, b, sizeof (*t));
174 0 : t->is_user_to_network = 0;
175 0 : t->our_address.as_u64[0] = ip6->src_address.as_u64[0];
176 0 : t->our_address.as_u64[1] = ip6->src_address.as_u64[1];
177 0 : t->client_address.as_u64[0] = ip6->dst_address.as_u64[0];
178 0 : t->client_address.as_u64[1] = ip6->dst_address.as_u64[1];
179 0 : t->session_index = session_index;
180 : }
181 :
182 0 : return next_index;
183 : }
184 :
185 : #include <vnet/pipeline.h>
186 :
187 2236 : VLIB_NODE_FN (l2t_encap_node) (vlib_main_t * vm,
188 : vlib_node_runtime_t * node,
189 : vlib_frame_t * frame)
190 : {
191 0 : return dispatch_pipeline (vm, node, frame);
192 : }
193 :
194 :
195 : /* *INDENT-OFF* */
196 109240 : VLIB_REGISTER_NODE (l2t_encap_node) = {
197 : .name = "l2tp-encap",
198 : .vector_size = sizeof (u32),
199 : .format_trace = format_l2t_trace,
200 : .type = VLIB_NODE_TYPE_INTERNAL,
201 : .runtime_data_bytes = sizeof (l2tp_encap_runtime_t),
202 :
203 : .n_errors = ARRAY_LEN(l2t_encap_error_strings),
204 : .error_strings = l2t_encap_error_strings,
205 :
206 : .n_next_nodes = L2T_ENCAP_N_NEXT,
207 :
208 : /* add dispositions here */
209 : .next_nodes = {
210 : [L2T_ENCAP_NEXT_IP6_LOOKUP] = "ip6-lookup",
211 : [L2T_ENCAP_NEXT_DROP] = "error-drop",
212 : },
213 : };
214 : /* *INDENT-ON* */
215 :
216 : #ifndef CLIB_MARCH_VARIANT
217 : void
218 613 : l2tp_encap_init (vlib_main_t * vm)
219 : {
220 : l2tp_encap_runtime_t *rt;
221 :
222 613 : rt = vlib_node_get_runtime_data (vm, l2t_encap_node.index);
223 613 : rt->vnet_main = vnet_get_main ();
224 613 : rt->cached_sw_if_index = (u32) ~ 0;
225 613 : rt->cached_session_index = (u32) ~ 0;
226 613 : }
227 : #endif /* CLIB_MARCH_VARIANT */
228 :
229 : /*
230 : * fd.io coding-style-patch-verification: ON
231 : *
232 : * Local Variables:
233 : * eval: (c-set-style "gnu")
234 : * End:
235 : */
|