aboutsummaryrefslogtreecommitdiffstats
path: root/vnet/vnet/l2/l2_input.h
blob: e650162b593b1d1939889a7cfebaaf31391de71e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
/*
 * l2_input.h : layer 2 input packet processing
 *
 * Copyright (c) 2013 Cisco and/or its affiliates.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef included_vnet_l2_input_h
#define included_vnet_l2_input_h

#include <vlib/vlib.h>
#include <vnet/vnet.h>
#include <vnet/l2/l2_bd.h>
#include <vnet/ethernet/packet.h>
#include <vnet/ip/ip.h>

// Per-subinterface L2 feature configuration

typedef struct {

  union {
    u16 bd_index;                 // bridge domain id
    u32 output_sw_if_index;    // for xconnect
  };

  // Interface mode. If both are 0, this interface is in L3 mode
  u8  xconnect;
  u8  bridge;

  // this is the bvi interface for the bridge-domain
  u8  bvi;  

  // config for which input features are configured on this interface
  u32 feature_bitmap;

  // some of these flags are also in the feature bitmap
  u8  learn_enable;  
  u8  fwd_enable;    
  u8  flood_enable;

  // split horizon group
  u8  shg;

} l2_input_config_t;


typedef struct {

  // Next nodes for the feature bitmap
  u32 feat_next_node_index[32];

  /* config vector indexed by sw_if_index */
  l2_input_config_t *configs;

  /* bridge domain config vector indexed by BD ID */
  l2_bridge_domain_t *bd_configs;

  /* convenience variables */
  vlib_main_t * vlib_main;
  vnet_main_t * vnet_main;
} l2input_main_t;

extern l2input_main_t l2input_main;

static_always_inline l2_bridge_domain_t * 
l2input_bd_config_from_index (l2input_main_t * l2im, u32 bd_index)
{
    l2_bridge_domain_t * bd_config;

    bd_config = vec_elt_at_index (l2im->bd_configs, bd_index);
    return bd_is_valid (bd_config) ? bd_config : NULL;
}

// L2 input features

// Mappings from feature ID to graph node name
#define foreach_l2input_feat \
 _(DROP,          "feature-bitmap-drop")        \
 _(CLASSIFY,      "l2-classify")		\
 _(XCONNECT,      "l2-output")                  \
 _(IPIW,          "feature-bitmap-drop")        \
 _(FLOOD,         "l2-flood")                   \
 _(ARP_TERM,      "arp-term-l2bd")              \
 _(UU_FLOOD,      "l2-flood")                   \
 _(FWD,           "l2-fwd")                     \
 _(LEARN,         "l2-learn")                   \
 _(VTR,           "l2-input-vtr")               \
 _(VPATH,         "vpath-input-l2")             \
 _(CTRL_PKT,      "feature-bitmap-drop")        \
 _(L2PT,          "feature-bitmap-drop")        \
 _(IGMP_SNOOP,    "feature-bitmap-drop")        \
 _(MLD_SNOOP,     "feature-bitmap-drop")        \
 _(DHCP_SNOOP,    "feature-bitmap-drop")        \
 _(DAI,           "feature-bitmap-drop")        \
 _(IPSG,          "feature-bitmap-drop")        \
 _(ACL,           "l2-input-acl")               \
 _(QOS,           "feature-bitmap-drop")        \
 _(CFM,           "feature-bitmap-drop")        \
 _(SPAN,          "feature-bitmap-drop")

// Feature bitmap positions
typedef enum {
#define _(sym,str) L2INPUT_FEAT_##sym##_BIT,
  foreach_l2input_feat
#undef _
  L2INPUT_N_FEAT,
} l2input_feat_t;

// Feature bit masks
typedef enum {
#define _(sym,str) L2INPUT_FEAT_##sym = (1<<L2INPUT_FEAT_##sym##_BIT),
  foreach_l2input_feat
#undef _
} l2input_feat_masks_t;
           
// Return an array of strings containing graph node names of each feature
char **l2input_get_feat_names(void);


static_always_inline u8 bd_feature_flood (l2_bridge_domain_t * bd_config)
{
    return ((bd_config->feature_bitmap & L2INPUT_FEAT_FLOOD) ==
            L2INPUT_FEAT_FLOOD);
}

static_always_inline u8 bd_feature_uu_flood (l2_bridge_domain_t * bd_config)
{
    return ((bd_config->feature_bitmap & L2INPUT_FEAT_UU_FLOOD) ==
            L2INPUT_FEAT_UU_FLOOD);
}

static_always_inline u8 bd_feature_forward (l2_bridge_domain_t * bd_config)
{
    return ((bd_config->feature_bitmap & L2INPUT_FEAT_FWD) ==
            L2INPUT_FEAT_FWD);
}

static_always_inline u8 bd_feature_learn (l2_bridge_domain_t * bd_config)
{
    return ((bd_config->feature_bitmap & L2INPUT_FEAT_LEARN) ==
            L2INPUT_FEAT_LEARN);
}

static_always_inline u8 bd_feature_arp_term (l2_bridge_domain_t * bd_config)
{
    return ((bd_config->feature_bitmap & L2INPUT_FEAT_ARP_TERM) ==
            L2INPUT_FEAT_ARP_TERM);
}

// Masks for eliminating features that do not apply to a packet

#define IP4_FEAT_MASK  ~(L2INPUT_FEAT_CTRL_PKT    | \
                         L2INPUT_FEAT_MLD_SNOOP   | \
                         L2INPUT_FEAT_L2PT        | \
                         L2INPUT_FEAT_CFM         | \
			 L2INPUT_FEAT_DAI)

#define IP6_FEAT_MASK  ~(L2INPUT_FEAT_CTRL_PKT    | \
                         L2INPUT_FEAT_IGMP_SNOOP  | \
                         L2INPUT_FEAT_L2PT        | \
                         L2INPUT_FEAT_CFM         | \
                         L2INPUT_FEAT_DAI)

#define IP_UDP_TCP_FEAT_MASK  ~(L2INPUT_FEAT_CTRL_PKT   | \
                                L2INPUT_FEAT_L2PT       | \
                                L2INPUT_FEAT_IGMP_SNOOP | \
                                L2INPUT_FEAT_MLD_SNOOP  | \
                                L2INPUT_FEAT_DHCP_SNOOP | \
                                L2INPUT_FEAT_CFM        | \
                                L2INPUT_FEAT_DAI)

#define MPLS_FEAT_MASK  ~(L2INPUT_FEAT_CTRL_PKT   | \
                          L2INPUT_FEAT_L2PT       | \
                          L2INPUT_FEAT_IGMP_SNOOP | \
                          L2INPUT_FEAT_MLD_SNOOP  | \
                          L2INPUT_FEAT_DHCP_SNOOP | \
                          L2INPUT_FEAT_CFM        | \
                          L2INPUT_FEAT_DAI)


// Get a pointer to the config for the given interface
l2_input_config_t * l2input_intf_config (u32 sw_if_index);

// Enable (or disable) the feature in the bitmap for the given interface
u32 l2input_intf_bitmap_enable (u32 sw_if_index,
                                 u32 feature_bitmap,
                                 u32 enable);


#define MODE_L3        0
#define MODE_L2_BRIDGE 1
#define MODE_L2_XC     2
#define MODE_L2_CLASSIFY 3

#define MODE_ERROR_ETH        1
#define MODE_ERROR_BVI_DEF    2

u32 set_int_l2_mode (vlib_main_t * vm,
                     vnet_main_t * vnet_main,
                     u32 mode,
                     u32 sw_if_index,
                     u32 bd_index,
                     u32 bvi,  
                     u32 shg,   
                     u32 xc_sw_if_index);

static inline void
vnet_update_l2_len (vlib_buffer_t * b)
{
  ethernet_header_t * eth;
  u16 ethertype;

  /* point at currrent l2 hdr */
  eth = vlib_buffer_get_current (b);

  /* 
   * l2-output pays no attention to this
   * but the tag push/pop code on an l2 subif needs it.
   * 
   * Determine l2 header len, check for up to 2 vlans 
   */
  vnet_buffer(b)->l2.l2_len = sizeof(ethernet_header_t);
  ethertype = clib_net_to_host_u16(eth->type);
  if ((ethertype == ETHERNET_TYPE_VLAN) ||
      (ethertype == ETHERNET_TYPE_DOT1AD) ||
      (ethertype == ETHERNET_TYPE_VLAN_9100) ||
      (ethertype == ETHERNET_TYPE_VLAN_9200)) {    
    ethernet_vlan_header_t * vlan;
    vnet_buffer(b)->l2.l2_len += sizeof (*vlan);
    vlan = (void *) (eth+1);
    ethertype = clib_net_to_host_u16 (vlan->type);
    if (ethertype == ETHERNET_TYPE_VLAN) {
      vnet_buffer(b)->l2.l2_len += sizeof (*vlan);
    }
  }
}

/*
 * Compute flow hash of an ethernet packet, use 5-tuple hash if L3 packet 
 * is ip4 or ip6. Otherwise hash on smac/dmac/etype. 
 * The vlib buffer current pointer is expected to be at ethernet header 
 * and vnet l2.l2_len is exppected to be setup already.
 */
static inline u32 vnet_l2_compute_flow_hash (vlib_buffer_t *b) 
{
  ethernet_header_t * eh = vlib_buffer_get_current(b);
  u8 * l3h = (u8 *)eh + vnet_buffer(b)->l2.l2_len;
  u16 ethertype = clib_net_to_host_u16(*(u16 *)(l3h - 2));

  if (ethertype == ETHERNET_TYPE_IP4) 
    return ip4_compute_flow_hash((ip4_header_t *) l3h, IP_FLOW_HASH_DEFAULT);
  else if (ethertype == ETHERNET_TYPE_IP6) 
    return ip6_compute_flow_hash((ip6_header_t *) l3h, IP_FLOW_HASH_DEFAULT);
  else
    {
      u32 a, b, c;
      u32 * ap = (u32 *) &eh->dst_address[2];
      u32 * bp = (u32 *) &eh->src_address[2];
      a = * ap;
      b = * bp;
      c = ethertype;
      hash_v3_mix32 (a, b, c);
      hash_v3_finalize32 (a, b, c);
      return c;
    }
}

#endif