Line data Source code
1 : /*
2 : * l2_input.h : layer 2 input packet processing
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 : #ifndef included_vnet_l2_input_h
19 : #define included_vnet_l2_input_h
20 :
21 : #include <stdbool.h>
22 :
23 : #include <vlib/vlib.h>
24 : #include <vnet/vnet.h>
25 : #include <vnet/l2/l2_bd.h>
26 : #include <vnet/ethernet/ethernet.h>
27 : #include <vnet/ethernet/packet.h>
28 : #include <vnet/ip/ip4_inlines.h>
29 : #include <vnet/ip/ip6_inlines.h>
30 :
31 : /* l2 connection type */
32 : typedef enum l2_input_flags_t_
33 : {
34 : /* NONE imples L3 mode. */
35 : L2_INPUT_FLAG_NONE = 0,
36 : L2_INPUT_FLAG_XCONNECT = (1 << 0),
37 : L2_INPUT_FLAG_BRIDGE = (1 << 1),
38 : L2_INPUT_FLAG_BVI = (1 << 2),
39 : } __clib_packed l2_input_flags_t;
40 :
41 : /* Per-subinterface L2 feature configuration */
42 : typedef struct
43 : {
44 : u8 __force_u64_alignement[0] __attribute__ ((aligned (8)));
45 :
46 : union
47 : {
48 : /* bridge domain id and values cached from the BD */
49 : struct
50 : {
51 : u16 bd_index;
52 : u8 bd_seq_num;
53 : u8 bd_mac_age;
54 : };
55 : /* for xconnect */
56 : u32 output_sw_if_index;
57 : };
58 :
59 : /* config for which input features are configured on this interface */
60 : u32 feature_bitmap;
61 :
62 : /* config for which input features are configured on this interface's
63 : * BD - this is cahced from the BD struct*/
64 : u32 bd_feature_bitmap;
65 :
66 : /* split horizon group */
67 : u8 shg;
68 :
69 : /* Interface sequence number */
70 : u8 seq_num;
71 :
72 : /* Flags describing this interface */
73 : l2_input_flags_t flags;
74 :
75 : /* A wee bit of spare space */
76 : u8 __pad;
77 : } l2_input_config_t;
78 :
79 : /* Ensure a struct is an even multiple of 8 bytes,
80 : * so they do not stradle cache lines */
81 : STATIC_ASSERT_SIZEOF (l2_input_config_t, 2 * sizeof (u64));
82 :
83 : typedef struct
84 : {
85 :
86 : /* Next nodes for the feature bitmap */
87 : u32 feat_next_node_index[32];
88 :
89 : /* config vector indexed by sw_if_index */
90 : l2_input_config_t *configs;
91 :
92 : /* bridge domain config vector indexed by bd_index */
93 : l2_bridge_domain_t *bd_configs;
94 :
95 : /* convenience variables */
96 : vlib_main_t *vlib_main;
97 : vnet_main_t *vnet_main;
98 :
99 : u16 msg_id_base;
100 : } l2input_main_t;
101 :
102 : extern l2input_main_t l2input_main;
103 :
104 : extern vlib_node_registration_t l2input_node;
105 :
106 : static_always_inline l2_bridge_domain_t *
107 81 : l2input_bd_config_from_index (l2input_main_t * l2im, u32 bd_index)
108 : {
109 : l2_bridge_domain_t *bd_config;
110 :
111 81 : bd_config = vec_elt_at_index (l2im->bd_configs, bd_index);
112 81 : return bd_is_valid (bd_config) ? bd_config : NULL;
113 : }
114 :
115 : static_always_inline l2_bridge_domain_t *
116 3171 : l2input_bd_config (u32 bd_index)
117 : {
118 3171 : l2input_main_t *mp = &l2input_main;
119 : l2_bridge_domain_t *bd_config;
120 :
121 3171 : vec_validate (mp->bd_configs, bd_index);
122 3171 : bd_config = vec_elt_at_index (mp->bd_configs, bd_index);
123 3171 : return bd_config;
124 : }
125 :
126 : /* L2 input indication packet is from BVI, using -2 */
127 : #define L2INPUT_BVI ((u32) (~0-1))
128 :
129 : /* L2 input features */
130 :
131 : /* Mappings from feature ID to graph node name in reverse order */
132 : #define foreach_l2input_feat \
133 : _(DROP, "feature-bitmap-drop") \
134 : _(XCONNECT, "l2-output") \
135 : _(FLOOD, "l2-flood") \
136 : _(ARP_UFWD, "l2-uu-fwd") \
137 : _(ARP_TERM, "arp-term-l2bd") \
138 : _(UU_FLOOD, "l2-flood") \
139 : _(UU_FWD, "l2-uu-fwd") \
140 : _(FWD, "l2-fwd") \
141 : _(RW, "l2-rw") \
142 : _(LEARN, "l2-learn") \
143 : _(VTR, "l2-input-vtr") \
144 : _(L2_IP_QOS_RECORD, "l2-ip-qos-record") \
145 : _(VPATH, "vpath-input-l2") \
146 : _(ACL, "l2-input-acl") \
147 : _(POLICER_CLAS, "l2-policer-classify") \
148 : _(INPUT_FEAT_ARC, "l2-input-feat-arc") \
149 : _(INPUT_CLASSIFY, "l2-input-classify") \
150 : _(SPAN, "span-l2-input")
151 :
152 : /* Feature bitmap positions */
153 : typedef enum
154 : {
155 : #define _(sym,str) L2INPUT_FEAT_##sym##_BIT,
156 : foreach_l2input_feat
157 : #undef _
158 : L2INPUT_N_FEAT
159 : } l2input_feat_t;
160 :
161 : STATIC_ASSERT (L2INPUT_N_FEAT <= 32, "too many l2 input features");
162 :
163 : /* Feature bit masks */
164 : typedef enum
165 : {
166 : L2INPUT_FEAT_NONE = 0,
167 : #define _(sym,str) L2INPUT_FEAT_##sym = (1<<L2INPUT_FEAT_##sym##_BIT),
168 : foreach_l2input_feat
169 : #undef _
170 : L2INPUT_VALID_MASK =
171 : #define _(sym,str) L2INPUT_FEAT_##sym |
172 : foreach_l2input_feat
173 : #undef _
174 : 0
175 : } l2input_feat_masks_t;
176 :
177 : STATIC_ASSERT ((u64) L2INPUT_VALID_MASK == (1ull << L2INPUT_N_FEAT) - 1, "");
178 :
179 : /** Return an array of strings containing graph node names of each feature */
180 : char **l2input_get_feat_names (void);
181 :
182 : /* arg0 - u32 feature_bitmap, arg1 - u32 verbose */
183 : u8 *format_l2_input_feature_bitmap (u8 * s, va_list * args);
184 : u8 *format_l2_input_features (u8 * s, va_list * args);
185 : u8 *format_l2_input (u8 * s, va_list * args);
186 :
187 : static_always_inline u8
188 81 : bd_feature_flood (l2_bridge_domain_t * bd_config)
189 : {
190 81 : return ((bd_config->feature_bitmap & L2INPUT_FEAT_FLOOD) ==
191 : L2INPUT_FEAT_FLOOD);
192 : }
193 :
194 : static_always_inline u8
195 81 : bd_feature_uu_flood (l2_bridge_domain_t * bd_config)
196 : {
197 81 : return ((bd_config->feature_bitmap & L2INPUT_FEAT_UU_FLOOD) ==
198 : L2INPUT_FEAT_UU_FLOOD);
199 : }
200 :
201 : static_always_inline u8
202 81 : bd_feature_forward (l2_bridge_domain_t * bd_config)
203 : {
204 81 : return ((bd_config->feature_bitmap & L2INPUT_FEAT_FWD) == L2INPUT_FEAT_FWD);
205 : }
206 :
207 : static_always_inline u8
208 81 : bd_feature_learn (l2_bridge_domain_t * bd_config)
209 : {
210 81 : return ((bd_config->feature_bitmap & L2INPUT_FEAT_LEARN) ==
211 : L2INPUT_FEAT_LEARN);
212 : }
213 :
214 : static_always_inline u8
215 81 : bd_feature_arp_term (l2_bridge_domain_t * bd_config)
216 : {
217 81 : return ((bd_config->feature_bitmap & L2INPUT_FEAT_ARP_TERM) ==
218 : L2INPUT_FEAT_ARP_TERM);
219 : }
220 :
221 : static_always_inline u8
222 81 : bd_feature_arp_ufwd (l2_bridge_domain_t * bd_config)
223 : {
224 81 : return ((bd_config->feature_bitmap & L2INPUT_FEAT_ARP_UFWD) ==
225 : L2INPUT_FEAT_ARP_UFWD);
226 : }
227 :
228 : static inline bool
229 52477004 : l2_input_is_bridge (const l2_input_config_t * input)
230 : {
231 52477004 : return (input->flags & L2_INPUT_FLAG_BRIDGE);
232 : }
233 :
234 : static inline bool
235 20096 : l2_input_is_xconnect (const l2_input_config_t * input)
236 : {
237 20096 : return (input->flags & L2_INPUT_FLAG_XCONNECT);
238 : }
239 :
240 : static inline bool
241 706 : l2_input_is_bvi (const l2_input_config_t * input)
242 : {
243 706 : return (input->flags & L2_INPUT_FLAG_BVI);
244 : }
245 :
246 : static_always_inline u8
247 52442538 : l2_input_seq_num (u32 sw_if_index)
248 : {
249 : l2_input_config_t *input;
250 :
251 52442538 : input = vec_elt_at_index (l2input_main.configs, sw_if_index);
252 :
253 52442538 : return input->seq_num;
254 : }
255 :
256 :
257 : /** Masks for eliminating features that do not apply to a packet */
258 :
259 : /** Get a pointer to the config for the given interface */
260 : l2_input_config_t *l2input_intf_config (u32 sw_if_index);
261 :
262 : /* Enable (or disable) the feature in the bitmap for the given interface */
263 : u32 l2input_intf_bitmap_enable (u32 sw_if_index,
264 : l2input_feat_masks_t feature_bitmap,
265 : u32 enable);
266 :
267 : /* Sets modifies flags from a bridge domain */
268 : u32 l2input_set_bridge_features (u32 bd_index, u32 feat_mask, u32 feat_value);
269 :
270 : void l2input_interface_mac_change (u32 sw_if_index,
271 : const u8 * old_address,
272 : const u8 * new_address);
273 :
274 : void l2_input_seq_num_inc (u32 sw_if_index);
275 : walk_rc_t l2input_recache (u32 bd_index, u32 sw_if_index);
276 :
277 : #define MODE_L3 0
278 : #define MODE_L2_BRIDGE 1
279 : #define MODE_L2_XC 2
280 : #define MODE_L2_CLASSIFY 3
281 :
282 : #define MODE_ERROR_ETH 1
283 : #define MODE_ERROR_BVI_DEF 2
284 :
285 : u32 set_int_l2_mode (vlib_main_t * vm,
286 : vnet_main_t * vnet_main,
287 : u32 mode,
288 : u32 sw_if_index,
289 : u32 bd_index, l2_bd_port_type_t port_type,
290 : u32 shg, u32 xc_sw_if_index);
291 :
292 : static inline u16
293 1064 : vnet_update_l2_len (vlib_buffer_t *b)
294 : {
295 : ethernet_header_t *eth;
296 : u16 ethertype;
297 1064 : u8 vlan_count = 0;
298 :
299 : /* point at current l2 hdr */
300 1064 : eth = vlib_buffer_get_current (b);
301 :
302 : /*
303 : * l2-output pays no attention to this
304 : * but the tag push/pop code on an l2 subif needs it.
305 : *
306 : * Determine l2 header len, check for up to 2 vlans
307 : */
308 1064 : vnet_buffer (b)->l2.l2_len = sizeof (ethernet_header_t);
309 1064 : ethertype = clib_net_to_host_u16 (eth->type);
310 1064 : if (ethernet_frame_is_tagged (ethertype))
311 : {
312 : ethernet_vlan_header_t *vlan;
313 0 : vnet_buffer (b)->l2.l2_len += sizeof (*vlan);
314 0 : vlan_count = 1;
315 0 : vlan = (void *) (eth + 1);
316 0 : ethertype = clib_net_to_host_u16 (vlan->type);
317 0 : if (ethertype == ETHERNET_TYPE_VLAN)
318 : {
319 0 : vnet_buffer (b)->l2.l2_len += sizeof (*vlan);
320 0 : vlan_count = 2;
321 : }
322 : }
323 1064 : ethernet_buffer_set_vlan_count (b, vlan_count);
324 :
325 1064 : return (ethertype);
326 : }
327 :
328 : /*
329 : * Compute flow hash of an ethernet packet, use 5-tuple hash if L3 packet
330 : * is ip4 or ip6. Otherwise hash on smac/dmac/etype.
331 : * The vlib buffer current pointer is expected to be at ethernet header
332 : * and vnet l2.l2_len is expected to be setup already.
333 : */
334 : static inline u32
335 407 : vnet_l2_compute_flow_hash (vlib_buffer_t * b)
336 : {
337 407 : ethernet_header_t *eh = vlib_buffer_get_current (b);
338 407 : u8 *l3h = (u8 *) eh + vnet_buffer (b)->l2.l2_len;
339 407 : u16 ethertype = clib_net_to_host_u16 (*(u16 *) (l3h - 2));
340 :
341 407 : if (ethertype == ETHERNET_TYPE_IP4)
342 384 : return ip4_compute_flow_hash ((ip4_header_t *) l3h, IP_FLOW_HASH_DEFAULT);
343 23 : else if (ethertype == ETHERNET_TYPE_IP6)
344 20 : return ip6_compute_flow_hash ((ip6_header_t *) l3h, IP_FLOW_HASH_DEFAULT);
345 : else
346 : {
347 : u32 a, b, c;
348 3 : u32 *ap = (u32 *) & eh->dst_address[2];
349 3 : u32 *bp = (u32 *) & eh->src_address[2];
350 3 : a = *ap;
351 3 : b = *bp;
352 3 : c = ethertype;
353 3 : hash_v3_mix32 (a, b, c);
354 3 : hash_v3_finalize32 (a, b, c);
355 3 : return c;
356 : }
357 : }
358 :
359 : #endif
360 :
361 :
362 : /*
363 : * fd.io coding-style-patch-verification: ON
364 : *
365 : * Local Variables:
366 : * eval: (c-set-style "gnu")
367 : * End:
368 : */
|