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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
15 #include <vnet/vnet.h>
16 #include <vnet/ip/ip.h>
17 #include <vnet/ethernet/ethernet.h>
20 #include <vnet/devices/pci/ixgev.h>
21 #include <vnet/devices/pci/ixge.h>
22 #include <vnet/devices/pci/ige.h>
24 #include <vnet/devices/dpdk/dpdk.h>
27 #include <vppinfra/error.h>
28 #include <vppinfra/hash.h>
33 /* Statistics (not really errors) */
34 #define foreach_l2t_l2_error \
35 _(NETWORK_TO_USER, "L2 network to user (ip6) pkts")
37 static char * l2t_l2_error_strings[] = {
38 #define _(sym,string) string,
44 #define _(sym,str) L2T_L2_ERROR_##sym,
51 * Packets go to ethernet-input when they don't match a mapping
55 L2T_L2_NEXT_ETHERNET_INPUT,
56 L2T_L2_NEXT_IP6_LOOKUP,
60 vlib_node_registration_t l2t_l2_node;
64 static inline void stage0 (vlib_main_t * vm,
65 vlib_node_runtime_t * node,
68 vlib_buffer_t *b = vlib_get_buffer (vm, buffer_index);
69 vlib_prefetch_buffer_header (b, STORE);
70 CLIB_PREFETCH (b->data, 2*CLIB_CACHE_LINE_BYTES, STORE);
73 static inline void stage1 (vlib_main_t * vm,
74 vlib_node_runtime_t * node,
77 vlib_buffer_t *b = vlib_get_buffer (vm, bi);
78 l2t_main_t *lm = &l2t_main;
79 ethernet_header_t * eh;
80 ethernet_vlan_header_t *vh;
83 uword vlan_and_sw_if_index_key;
85 /* just in case, needed to test with the tun/tap device */
88 eh = vlib_buffer_get_current (b);
90 /* Not a VLAN pkt? send to ethernet-input... */
91 if (PREDICT_FALSE(eh->type != clib_host_to_net_u16 (0x8100))) {
92 vnet_buffer(b)->l2t.next_index = L2T_L2_NEXT_ETHERNET_INPUT;
95 vh = (ethernet_vlan_header_t *)(eh+1);
98 vlan_and_sw_if_index_key = ((uword)(vh->priority_cfi_and_id)<<32)
99 | vnet_buffer(b)->sw_if_index[VLIB_RX];
101 p = hash_get (lm->session_by_vlan_and_rx_sw_if_index,
102 vlan_and_sw_if_index_key);
104 if (PREDICT_FALSE(p == 0)) {
105 /* $$$ drop here if not for our MAC? */
106 vnet_buffer(b)->l2t.next_index = L2T_L2_NEXT_ETHERNET_INPUT;
109 session_index = p[0];
112 /* Remember mapping index, prefetch the mini counter */
113 vnet_buffer(b)->l2t.next_index = L2T_L2_NEXT_IP6_LOOKUP;
114 vnet_buffer(b)->l2t.session_index = session_index;
116 /* Each mapping has 2 x (pkt, byte) counters, hence the shift */
117 CLIB_PREFETCH(lm->counter_main.mini + (p[0]<<1), CLIB_CACHE_LINE_BYTES,
121 static inline u32 last_stage (vlib_main_t *vm, vlib_node_runtime_t *node,
124 vlib_buffer_t *b = vlib_get_buffer (vm, bi);
125 l2t_main_t *lm = &l2t_main;
126 ethernet_header_t * eh = vlib_buffer_get_current (b);
127 vlib_node_t *n = vlib_get_node (vm, l2t_l2_node.index);
128 u32 node_counter_base_index = n->error_heap_index;
129 vlib_error_main_t * em = &vm->error_main;
130 l2tpv3_header_t * l2t; /* l2 header */
131 ethernet_vlan_header_t * vh; /* 802.1q vlan header */
135 u16 payload_ethertype;
136 u8 dst_mac_address[6];
137 u8 src_mac_address[6];
141 /* Other-than-output pkt? We're done... */
142 if (vnet_buffer(b)->l2t.next_index != L2T_L2_NEXT_IP6_LOOKUP)
143 return vnet_buffer(b)->l2t.next_index;
145 vh = (ethernet_vlan_header_t *)(eh+1);
147 em->counters[node_counter_base_index + L2T_L2_ERROR_NETWORK_TO_USER] += 1;
150 session_index_to_counter_index (vnet_buffer(b)->l2t.session_index,
151 SESSION_COUNTER_NETWORK_TO_USER);
153 /* per-mapping byte stats include the ethernet header */
154 vlib_increment_combined_counter (&lm->counter_main, counter_index,
155 1 /* packet_increment */,
156 vlib_buffer_length_in_chain (vm, b) +
157 sizeof (ethernet_header_t));
159 s = pool_elt_at_index (lm->sessions, vnet_buffer(b)->l2t.session_index);
161 /* Save src/dst MAC addresses */
162 #define _(i) dst_mac_address[i] = eh->dst_address[i];
163 _(0) _(1) _(2) _(3) _(4) _(5);
165 #define _(i) src_mac_address[i] = eh->src_address[i];
166 _(0) _(1) _(2) _(3) _(4) _(5);
169 payload_ethertype = vh->type;
171 /* Splice out the 802.1q vlan tag */
172 vlib_buffer_advance (b, 4);
173 eh = vlib_buffer_get_current (b);
175 /* restore src/dst MAC addresses */
176 #define _(i) eh->dst_address[i] = dst_mac_address[i];
177 _(0) _(1) _(2) _(3) _(4) _(5);
179 #define _(i) eh->src_address[i] = src_mac_address[i];
180 _(0) _(1) _(2) _(3) _(4) _(5);
182 eh->type = payload_ethertype;
184 /* Paint on an l2tpv3 hdr */
185 backup = sizeof(*l2t);
187 /* back up 4 bytes less if no l2 sublayer */
188 backup -= s->l2_sublayer_present ? 0 : 4;
191 vlib_buffer_advance (b, -backup);
192 l2t = vlib_buffer_get_current (b);
194 l2t->session_id = s->remote_session_id;
195 l2t->cookie = s->remote_cookie;
198 if (s->l2_sublayer_present)
199 l2t->l2_specific_sublayer = 0;
202 /* Paint on an ip6 header */
203 vlib_buffer_advance (b, -(sizeof (*ip6)));
204 ip6 = vlib_buffer_get_current (b);
206 ip6->ip_version_traffic_class_and_flow_label =
207 clib_host_to_net_u32 (0x6<<28);
209 /* calculate ip6 payload length */
210 payload_length = vlib_buffer_length_in_chain (vm, b);
211 payload_length -= sizeof (*ip6);
213 ip6->payload_length = clib_host_to_net_u16 (payload_length);
214 ip6->protocol = 0x73; /* l2tpv3 */
215 ip6->hop_limit = 0xff;
216 ip6->src_address.as_u64[0] = s->our_address.as_u64[0];
217 ip6->src_address.as_u64[1] = s->our_address.as_u64[1];
218 ip6->dst_address.as_u64[0] = s->client_address.as_u64[0];
219 ip6->dst_address.as_u64[1] = s->client_address.as_u64[1];
221 return L2T_L2_NEXT_IP6_LOOKUP;
224 #include <vnet/pipeline.h>
226 static uword l2t_l2_node_fn (vlib_main_t * vm,
227 vlib_node_runtime_t * node,
228 vlib_frame_t * frame)
230 return dispatch_pipeline (vm, node, frame);
233 VLIB_REGISTER_NODE (l2t_l2_node) = {
234 .function = l2t_l2_node_fn,
235 .name = "l2t-l2-input",
236 .vector_size = sizeof (u32),
237 .format_trace = format_l2t_trace,
238 .type = VLIB_NODE_TYPE_INTERNAL,
240 .n_errors = ARRAY_LEN(l2t_l2_error_strings),
241 .error_strings = l2t_l2_error_strings,
243 .n_next_nodes = L2T_L2_N_NEXT,
245 /* edit / add dispositions here */
247 [L2T_L2_NEXT_IP6_LOOKUP] = "ip6-lookup",
248 [L2T_L2_NEXT_ETHERNET_INPUT] = "ethernet-input",
249 [L2T_L2_NEXT_DROP] = "error-drop",
253 VLIB_NODE_FUNCTION_MULTIARCH (l2t_l2_node, l2t_l2_node_fn)