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#include <linux/if_ether.h>
53#include <linux/if_vlan.h>
54
55#include "opa_vnic_internal.h"
56
57
58#define OPA_16B_LID_MASK 0xFFFFFull
59#define OPA_16B_SLID_HIGH_SHFT 8
60#define OPA_16B_SLID_MASK 0xF00ull
61#define OPA_16B_DLID_MASK 0xF000ull
62#define OPA_16B_DLID_HIGH_SHFT 12
63#define OPA_16B_LEN_SHFT 20
64#define OPA_16B_SC_SHFT 20
65#define OPA_16B_RC_SHFT 25
66#define OPA_16B_PKEY_SHFT 16
67
68#define OPA_VNIC_L4_HDR_SHFT 16
69
70
71#define OPA_VNIC_HDR_QW_LEN 5
72
73static inline void opa_vnic_make_header(u8 *hdr, u32 slid, u32 dlid, u16 len,
74 u16 pkey, u16 entropy, u8 sc, u8 rc,
75 u8 l4_type, u16 l4_hdr)
76{
77
78 u32 h[OPA_VNIC_HDR_QW_LEN] = {0, 0xc0000000, 0, 0, 0};
79
80 h[2] = l4_type;
81 h[3] = entropy;
82 h[4] = l4_hdr << OPA_VNIC_L4_HDR_SHFT;
83
84
85 h[0] |= (slid & OPA_16B_LID_MASK);
86 h[2] |= ((slid >> (20 - OPA_16B_SLID_HIGH_SHFT)) & OPA_16B_SLID_MASK);
87
88 h[1] |= (dlid & OPA_16B_LID_MASK);
89 h[2] |= ((dlid >> (20 - OPA_16B_DLID_HIGH_SHFT)) & OPA_16B_DLID_MASK);
90
91 h[0] |= (len << OPA_16B_LEN_SHFT);
92 h[1] |= (rc << OPA_16B_RC_SHFT);
93 h[1] |= (sc << OPA_16B_SC_SHFT);
94 h[2] |= ((u32)pkey << OPA_16B_PKEY_SHFT);
95
96 memcpy(hdr, h, OPA_VNIC_HDR_LEN);
97}
98
99
100
101
102
103static void opa_vnic_free_mac_tbl(struct hlist_head *mactbl)
104{
105 struct opa_vnic_mac_tbl_node *node;
106 struct hlist_node *tmp;
107 int bkt;
108
109 if (!mactbl)
110 return;
111
112 vnic_hash_for_each_safe(mactbl, bkt, tmp, node, hlist) {
113 hash_del(&node->hlist);
114 kfree(node);
115 }
116 kfree(mactbl);
117}
118
119static struct hlist_head *opa_vnic_alloc_mac_tbl(void)
120{
121 u32 size = sizeof(struct hlist_head) * OPA_VNIC_MAC_TBL_SIZE;
122 struct hlist_head *mactbl;
123
124 mactbl = kzalloc(size, GFP_KERNEL);
125 if (!mactbl)
126 return ERR_PTR(-ENOMEM);
127
128 vnic_hash_init(mactbl);
129 return mactbl;
130}
131
132
133void opa_vnic_release_mac_tbl(struct opa_vnic_adapter *adapter)
134{
135 struct hlist_head *mactbl;
136
137 mutex_lock(&adapter->mactbl_lock);
138 mactbl = rcu_access_pointer(adapter->mactbl);
139 rcu_assign_pointer(adapter->mactbl, NULL);
140 synchronize_rcu();
141 opa_vnic_free_mac_tbl(mactbl);
142 adapter->info.vport.mac_tbl_digest = 0;
143 mutex_unlock(&adapter->mactbl_lock);
144}
145
146
147
148
149
150
151
152void opa_vnic_query_mac_tbl(struct opa_vnic_adapter *adapter,
153 struct opa_veswport_mactable *tbl)
154{
155 struct opa_vnic_mac_tbl_node *node;
156 struct hlist_head *mactbl;
157 int bkt;
158 u16 loffset, lnum_entries;
159
160 rcu_read_lock();
161 mactbl = rcu_dereference(adapter->mactbl);
162 if (!mactbl)
163 goto get_mac_done;
164
165 loffset = be16_to_cpu(tbl->offset);
166 lnum_entries = be16_to_cpu(tbl->num_entries);
167
168 vnic_hash_for_each(mactbl, bkt, node, hlist) {
169 struct __opa_vnic_mactable_entry *nentry = &node->entry;
170 struct opa_veswport_mactable_entry *entry;
171
172 if ((node->index < loffset) ||
173 (node->index >= (loffset + lnum_entries)))
174 continue;
175
176
177 entry = &tbl->tbl_entries[node->index - loffset];
178 memcpy(entry->mac_addr, nentry->mac_addr,
179 ARRAY_SIZE(entry->mac_addr));
180 memcpy(entry->mac_addr_mask, nentry->mac_addr_mask,
181 ARRAY_SIZE(entry->mac_addr_mask));
182 entry->dlid_sd = cpu_to_be32(nentry->dlid_sd);
183 }
184 tbl->mac_tbl_digest = cpu_to_be32(adapter->info.vport.mac_tbl_digest);
185get_mac_done:
186 rcu_read_unlock();
187}
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204int opa_vnic_update_mac_tbl(struct opa_vnic_adapter *adapter,
205 struct opa_veswport_mactable *tbl)
206{
207 struct opa_vnic_mac_tbl_node *node, *new_node;
208 struct hlist_head *new_mactbl, *old_mactbl;
209 int i, bkt, rc = 0;
210 u8 key;
211 u16 loffset, lnum_entries;
212
213 mutex_lock(&adapter->mactbl_lock);
214
215 new_mactbl = opa_vnic_alloc_mac_tbl();
216 if (IS_ERR(new_mactbl)) {
217 mutex_unlock(&adapter->mactbl_lock);
218 return PTR_ERR(new_mactbl);
219 }
220
221 loffset = be16_to_cpu(tbl->offset);
222 lnum_entries = be16_to_cpu(tbl->num_entries);
223
224
225 for (i = 0; i < lnum_entries; i++) {
226 struct __opa_vnic_mactable_entry *nentry;
227 struct opa_veswport_mactable_entry *entry =
228 &tbl->tbl_entries[i];
229 u8 *mac_addr = entry->mac_addr;
230 u8 empty_mac[ETH_ALEN] = { 0 };
231
232 v_dbg("new mac entry %4d: %02x:%02x:%02x:%02x:%02x:%02x %x\n",
233 loffset + i, mac_addr[0], mac_addr[1], mac_addr[2],
234 mac_addr[3], mac_addr[4], mac_addr[5],
235 entry->dlid_sd);
236
237
238 if (!memcmp(mac_addr, empty_mac, ARRAY_SIZE(empty_mac)))
239 continue;
240
241 node = kzalloc(sizeof(*node), GFP_KERNEL);
242 if (!node) {
243 rc = -ENOMEM;
244 goto updt_done;
245 }
246
247 node->index = loffset + i;
248 nentry = &node->entry;
249 memcpy(nentry->mac_addr, entry->mac_addr,
250 ARRAY_SIZE(nentry->mac_addr));
251 memcpy(nentry->mac_addr_mask, entry->mac_addr_mask,
252 ARRAY_SIZE(nentry->mac_addr_mask));
253 nentry->dlid_sd = be32_to_cpu(entry->dlid_sd);
254 key = node->entry.mac_addr[OPA_VNIC_MAC_HASH_IDX];
255 vnic_hash_add(new_mactbl, &node->hlist, key);
256 }
257
258
259 old_mactbl = rcu_access_pointer(adapter->mactbl);
260 if (!old_mactbl)
261 goto switch_tbl;
262
263 vnic_hash_for_each(old_mactbl, bkt, node, hlist) {
264 if ((node->index >= loffset) &&
265 (node->index < (loffset + lnum_entries)))
266 continue;
267
268 new_node = kzalloc(sizeof(*new_node), GFP_KERNEL);
269 if (!new_node) {
270 rc = -ENOMEM;
271 goto updt_done;
272 }
273
274 new_node->index = node->index;
275 memcpy(&new_node->entry, &node->entry, sizeof(node->entry));
276 key = new_node->entry.mac_addr[OPA_VNIC_MAC_HASH_IDX];
277 vnic_hash_add(new_mactbl, &new_node->hlist, key);
278 }
279
280switch_tbl:
281
282 rcu_assign_pointer(adapter->mactbl, new_mactbl);
283 synchronize_rcu();
284
285 adapter->info.vport.mac_tbl_digest = be32_to_cpu(tbl->mac_tbl_digest);
286updt_done:
287
288 if (rc)
289 opa_vnic_free_mac_tbl(new_mactbl);
290 else
291 opa_vnic_free_mac_tbl(old_mactbl);
292
293 mutex_unlock(&adapter->mactbl_lock);
294 return rc;
295}
296
297
298static uint32_t opa_vnic_chk_mac_tbl(struct opa_vnic_adapter *adapter,
299 struct ethhdr *mac_hdr)
300{
301 struct opa_vnic_mac_tbl_node *node;
302 struct hlist_head *mactbl;
303 u32 dlid = 0;
304 u8 key;
305
306 rcu_read_lock();
307 mactbl = rcu_dereference(adapter->mactbl);
308 if (unlikely(!mactbl))
309 goto chk_done;
310
311 key = mac_hdr->h_dest[OPA_VNIC_MAC_HASH_IDX];
312 vnic_hash_for_each_possible(mactbl, node, hlist, key) {
313 struct __opa_vnic_mactable_entry *entry = &node->entry;
314
315
316 if (unlikely(OPA_VNIC_DLID_SD_IS_SRC_MAC(entry->dlid_sd)))
317 continue;
318
319 if (!memcmp(node->entry.mac_addr, mac_hdr->h_dest,
320 ARRAY_SIZE(node->entry.mac_addr))) {
321
322 dlid = OPA_VNIC_DLID_SD_GET_DLID(node->entry.dlid_sd);
323 break;
324 }
325 }
326
327chk_done:
328 rcu_read_unlock();
329 return dlid;
330}
331
332
333static uint32_t opa_vnic_get_dlid(struct opa_vnic_adapter *adapter,
334 struct sk_buff *skb, u8 def_port)
335{
336 struct __opa_veswport_info *info = &adapter->info;
337 struct ethhdr *mac_hdr = (struct ethhdr *)skb_mac_header(skb);
338 u32 dlid;
339
340 dlid = opa_vnic_chk_mac_tbl(adapter, mac_hdr);
341 if (dlid)
342 return dlid;
343
344 if (is_multicast_ether_addr(mac_hdr->h_dest)) {
345 dlid = info->vesw.u_mcast_dlid;
346 } else {
347 if (is_local_ether_addr(mac_hdr->h_dest)) {
348 dlid = ((uint32_t)mac_hdr->h_dest[5] << 16) |
349 ((uint32_t)mac_hdr->h_dest[4] << 8) |
350 mac_hdr->h_dest[3];
351 if (unlikely(!dlid))
352 v_warn("Null dlid in MAC address\n");
353 } else if (def_port != OPA_VNIC_INVALID_PORT) {
354 if (def_port < OPA_VESW_MAX_NUM_DEF_PORT)
355 dlid = info->vesw.u_ucast_dlid[def_port];
356 }
357 }
358
359 return dlid;
360}
361
362
363static u8 opa_vnic_get_sc(struct __opa_veswport_info *info,
364 struct sk_buff *skb)
365{
366 struct ethhdr *mac_hdr = (struct ethhdr *)skb_mac_header(skb);
367 u16 vlan_tci;
368 u8 sc;
369
370 if (!__vlan_get_tag(skb, &vlan_tci)) {
371 u8 pcp = OPA_VNIC_VLAN_PCP(vlan_tci);
372
373 if (is_multicast_ether_addr(mac_hdr->h_dest))
374 sc = info->vport.pcp_to_sc_mc[pcp];
375 else
376 sc = info->vport.pcp_to_sc_uc[pcp];
377 } else {
378 if (is_multicast_ether_addr(mac_hdr->h_dest))
379 sc = info->vport.non_vlan_sc_mc;
380 else
381 sc = info->vport.non_vlan_sc_uc;
382 }
383
384 return sc;
385}
386
387u8 opa_vnic_get_vl(struct opa_vnic_adapter *adapter, struct sk_buff *skb)
388{
389 struct ethhdr *mac_hdr = (struct ethhdr *)skb_mac_header(skb);
390 struct __opa_veswport_info *info = &adapter->info;
391 u8 vl;
392
393 if (skb_vlan_tag_present(skb)) {
394 u8 pcp = skb_vlan_tag_get(skb) >> VLAN_PRIO_SHIFT;
395
396 if (is_multicast_ether_addr(mac_hdr->h_dest))
397 vl = info->vport.pcp_to_vl_mc[pcp];
398 else
399 vl = info->vport.pcp_to_vl_uc[pcp];
400 } else {
401 if (is_multicast_ether_addr(mac_hdr->h_dest))
402 vl = info->vport.non_vlan_vl_mc;
403 else
404 vl = info->vport.non_vlan_vl_uc;
405 }
406
407 return vl;
408}
409
410
411static u8 opa_vnic_get_rc(struct __opa_veswport_info *info,
412 struct sk_buff *skb)
413{
414 u8 proto, rout_ctrl;
415
416 switch (vlan_get_protocol(skb)) {
417 case htons(ETH_P_IPV6):
418 proto = ipv6_hdr(skb)->nexthdr;
419 if (proto == IPPROTO_TCP)
420 rout_ctrl = OPA_VNIC_ENCAP_RC_EXT(info->vesw.rc,
421 IPV6_TCP);
422 else if (proto == IPPROTO_UDP)
423 rout_ctrl = OPA_VNIC_ENCAP_RC_EXT(info->vesw.rc,
424 IPV6_UDP);
425 else
426 rout_ctrl = OPA_VNIC_ENCAP_RC_EXT(info->vesw.rc, IPV6);
427 break;
428 case htons(ETH_P_IP):
429 proto = ip_hdr(skb)->protocol;
430 if (proto == IPPROTO_TCP)
431 rout_ctrl = OPA_VNIC_ENCAP_RC_EXT(info->vesw.rc,
432 IPV4_TCP);
433 else if (proto == IPPROTO_UDP)
434 rout_ctrl = OPA_VNIC_ENCAP_RC_EXT(info->vesw.rc,
435 IPV4_UDP);
436 else
437 rout_ctrl = OPA_VNIC_ENCAP_RC_EXT(info->vesw.rc, IPV4);
438 break;
439 default:
440 rout_ctrl = OPA_VNIC_ENCAP_RC_EXT(info->vesw.rc, DEFAULT);
441 }
442
443 return rout_ctrl;
444}
445
446
447u8 opa_vnic_calc_entropy(struct sk_buff *skb)
448{
449 u32 hash = skb_get_hash(skb);
450
451
452 hash ^= hash >> 8;
453 hash ^= hash >> 16;
454
455
456 return (u8)(hash & 0xFF);
457}
458
459
460static inline u8 opa_vnic_get_def_port(struct opa_vnic_adapter *adapter,
461 u8 entropy)
462{
463 u8 flow_id;
464
465
466 flow_id = ((entropy & 0xf) + (entropy >> 4));
467 return adapter->flow_tbl[flow_id & (OPA_VNIC_FLOW_TBL_SIZE - 1)];
468}
469
470
471static inline int opa_vnic_wire_length(struct sk_buff *skb)
472{
473 u32 pad_len;
474
475
476 pad_len = -(skb->len + OPA_VNIC_ICRC_TAIL_LEN) & 0x7;
477 pad_len += OPA_VNIC_ICRC_TAIL_LEN;
478
479 return (skb->len + pad_len) >> 3;
480}
481
482
483void opa_vnic_encap_skb(struct opa_vnic_adapter *adapter, struct sk_buff *skb)
484{
485 struct __opa_veswport_info *info = &adapter->info;
486 struct opa_vnic_skb_mdata *mdata;
487 u8 def_port, sc, rc, entropy, *hdr;
488 u16 len, l4_hdr;
489 u32 dlid;
490
491 hdr = skb_push(skb, OPA_VNIC_HDR_LEN);
492
493 entropy = opa_vnic_calc_entropy(skb);
494 def_port = opa_vnic_get_def_port(adapter, entropy);
495 len = opa_vnic_wire_length(skb);
496 dlid = opa_vnic_get_dlid(adapter, skb, def_port);
497 sc = opa_vnic_get_sc(info, skb);
498 rc = opa_vnic_get_rc(info, skb);
499 l4_hdr = info->vesw.vesw_id;
500
501 mdata = skb_push(skb, sizeof(*mdata));
502 mdata->vl = opa_vnic_get_vl(adapter, skb);
503 mdata->entropy = entropy;
504 mdata->flags = 0;
505 if (unlikely(!dlid)) {
506 mdata->flags = OPA_VNIC_SKB_MDATA_ENCAP_ERR;
507 return;
508 }
509
510 opa_vnic_make_header(hdr, info->vport.encap_slid, dlid, len,
511 info->vesw.pkey, entropy, sc, rc,
512 OPA_VNIC_L4_ETHR, l4_hdr);
513}
514