0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052 #include <linux/if_ether.h>
0053 #include <linux/if_vlan.h>
0054
0055 #include "opa_vnic_internal.h"
0056
0057
0058 #define OPA_16B_LID_MASK 0xFFFFFull
0059 #define OPA_16B_SLID_HIGH_SHFT 8
0060 #define OPA_16B_SLID_MASK 0xF00ull
0061 #define OPA_16B_DLID_MASK 0xF000ull
0062 #define OPA_16B_DLID_HIGH_SHFT 12
0063 #define OPA_16B_LEN_SHFT 20
0064 #define OPA_16B_SC_SHFT 20
0065 #define OPA_16B_RC_SHFT 25
0066 #define OPA_16B_PKEY_SHFT 16
0067
0068 #define OPA_VNIC_L4_HDR_SHFT 16
0069
0070
0071 #define OPA_VNIC_HDR_QW_LEN 5
0072
0073 static inline void opa_vnic_make_header(u8 *hdr, u32 slid, u32 dlid, u16 len,
0074 u16 pkey, u16 entropy, u8 sc, u8 rc,
0075 u8 l4_type, u16 l4_hdr)
0076 {
0077
0078 u32 h[OPA_VNIC_HDR_QW_LEN] = {0, 0xc0000000, 0, 0, 0};
0079
0080 h[2] = l4_type;
0081 h[3] = entropy;
0082 h[4] = l4_hdr << OPA_VNIC_L4_HDR_SHFT;
0083
0084
0085 h[0] |= (slid & OPA_16B_LID_MASK);
0086 h[2] |= ((slid >> (20 - OPA_16B_SLID_HIGH_SHFT)) & OPA_16B_SLID_MASK);
0087
0088 h[1] |= (dlid & OPA_16B_LID_MASK);
0089 h[2] |= ((dlid >> (20 - OPA_16B_DLID_HIGH_SHFT)) & OPA_16B_DLID_MASK);
0090
0091 h[0] |= (len << OPA_16B_LEN_SHFT);
0092 h[1] |= (rc << OPA_16B_RC_SHFT);
0093 h[1] |= (sc << OPA_16B_SC_SHFT);
0094 h[2] |= ((u32)pkey << OPA_16B_PKEY_SHFT);
0095
0096 memcpy(hdr, h, OPA_VNIC_HDR_LEN);
0097 }
0098
0099
0100
0101
0102
0103 static void opa_vnic_free_mac_tbl(struct hlist_head *mactbl)
0104 {
0105 struct opa_vnic_mac_tbl_node *node;
0106 struct hlist_node *tmp;
0107 int bkt;
0108
0109 if (!mactbl)
0110 return;
0111
0112 vnic_hash_for_each_safe(mactbl, bkt, tmp, node, hlist) {
0113 hash_del(&node->hlist);
0114 kfree(node);
0115 }
0116 kfree(mactbl);
0117 }
0118
0119 static struct hlist_head *opa_vnic_alloc_mac_tbl(void)
0120 {
0121 u32 size = sizeof(struct hlist_head) * OPA_VNIC_MAC_TBL_SIZE;
0122 struct hlist_head *mactbl;
0123
0124 mactbl = kzalloc(size, GFP_KERNEL);
0125 if (!mactbl)
0126 return ERR_PTR(-ENOMEM);
0127
0128 vnic_hash_init(mactbl);
0129 return mactbl;
0130 }
0131
0132
0133 void opa_vnic_release_mac_tbl(struct opa_vnic_adapter *adapter)
0134 {
0135 struct hlist_head *mactbl;
0136
0137 mutex_lock(&adapter->mactbl_lock);
0138 mactbl = rcu_access_pointer(adapter->mactbl);
0139 rcu_assign_pointer(adapter->mactbl, NULL);
0140 synchronize_rcu();
0141 opa_vnic_free_mac_tbl(mactbl);
0142 adapter->info.vport.mac_tbl_digest = 0;
0143 mutex_unlock(&adapter->mactbl_lock);
0144 }
0145
0146
0147
0148
0149
0150
0151
0152 void opa_vnic_query_mac_tbl(struct opa_vnic_adapter *adapter,
0153 struct opa_veswport_mactable *tbl)
0154 {
0155 struct opa_vnic_mac_tbl_node *node;
0156 struct hlist_head *mactbl;
0157 int bkt;
0158 u16 loffset, lnum_entries;
0159
0160 rcu_read_lock();
0161 mactbl = rcu_dereference(adapter->mactbl);
0162 if (!mactbl)
0163 goto get_mac_done;
0164
0165 loffset = be16_to_cpu(tbl->offset);
0166 lnum_entries = be16_to_cpu(tbl->num_entries);
0167
0168 vnic_hash_for_each(mactbl, bkt, node, hlist) {
0169 struct __opa_vnic_mactable_entry *nentry = &node->entry;
0170 struct opa_veswport_mactable_entry *entry;
0171
0172 if ((node->index < loffset) ||
0173 (node->index >= (loffset + lnum_entries)))
0174 continue;
0175
0176
0177 entry = &tbl->tbl_entries[node->index - loffset];
0178 memcpy(entry->mac_addr, nentry->mac_addr,
0179 ARRAY_SIZE(entry->mac_addr));
0180 memcpy(entry->mac_addr_mask, nentry->mac_addr_mask,
0181 ARRAY_SIZE(entry->mac_addr_mask));
0182 entry->dlid_sd = cpu_to_be32(nentry->dlid_sd);
0183 }
0184 tbl->mac_tbl_digest = cpu_to_be32(adapter->info.vport.mac_tbl_digest);
0185 get_mac_done:
0186 rcu_read_unlock();
0187 }
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204 int opa_vnic_update_mac_tbl(struct opa_vnic_adapter *adapter,
0205 struct opa_veswport_mactable *tbl)
0206 {
0207 struct opa_vnic_mac_tbl_node *node, *new_node;
0208 struct hlist_head *new_mactbl, *old_mactbl;
0209 int i, bkt, rc = 0;
0210 u8 key;
0211 u16 loffset, lnum_entries;
0212
0213 mutex_lock(&adapter->mactbl_lock);
0214
0215 new_mactbl = opa_vnic_alloc_mac_tbl();
0216 if (IS_ERR(new_mactbl)) {
0217 mutex_unlock(&adapter->mactbl_lock);
0218 return PTR_ERR(new_mactbl);
0219 }
0220
0221 loffset = be16_to_cpu(tbl->offset);
0222 lnum_entries = be16_to_cpu(tbl->num_entries);
0223
0224
0225 for (i = 0; i < lnum_entries; i++) {
0226 struct __opa_vnic_mactable_entry *nentry;
0227 struct opa_veswport_mactable_entry *entry =
0228 &tbl->tbl_entries[i];
0229 u8 *mac_addr = entry->mac_addr;
0230 u8 empty_mac[ETH_ALEN] = { 0 };
0231
0232 v_dbg("new mac entry %4d: %02x:%02x:%02x:%02x:%02x:%02x %x\n",
0233 loffset + i, mac_addr[0], mac_addr[1], mac_addr[2],
0234 mac_addr[3], mac_addr[4], mac_addr[5],
0235 entry->dlid_sd);
0236
0237
0238 if (!memcmp(mac_addr, empty_mac, ARRAY_SIZE(empty_mac)))
0239 continue;
0240
0241 node = kzalloc(sizeof(*node), GFP_KERNEL);
0242 if (!node) {
0243 rc = -ENOMEM;
0244 goto updt_done;
0245 }
0246
0247 node->index = loffset + i;
0248 nentry = &node->entry;
0249 memcpy(nentry->mac_addr, entry->mac_addr,
0250 ARRAY_SIZE(nentry->mac_addr));
0251 memcpy(nentry->mac_addr_mask, entry->mac_addr_mask,
0252 ARRAY_SIZE(nentry->mac_addr_mask));
0253 nentry->dlid_sd = be32_to_cpu(entry->dlid_sd);
0254 key = node->entry.mac_addr[OPA_VNIC_MAC_HASH_IDX];
0255 vnic_hash_add(new_mactbl, &node->hlist, key);
0256 }
0257
0258
0259 old_mactbl = rcu_access_pointer(adapter->mactbl);
0260 if (!old_mactbl)
0261 goto switch_tbl;
0262
0263 vnic_hash_for_each(old_mactbl, bkt, node, hlist) {
0264 if ((node->index >= loffset) &&
0265 (node->index < (loffset + lnum_entries)))
0266 continue;
0267
0268 new_node = kzalloc(sizeof(*new_node), GFP_KERNEL);
0269 if (!new_node) {
0270 rc = -ENOMEM;
0271 goto updt_done;
0272 }
0273
0274 new_node->index = node->index;
0275 memcpy(&new_node->entry, &node->entry, sizeof(node->entry));
0276 key = new_node->entry.mac_addr[OPA_VNIC_MAC_HASH_IDX];
0277 vnic_hash_add(new_mactbl, &new_node->hlist, key);
0278 }
0279
0280 switch_tbl:
0281
0282 rcu_assign_pointer(adapter->mactbl, new_mactbl);
0283 synchronize_rcu();
0284
0285 adapter->info.vport.mac_tbl_digest = be32_to_cpu(tbl->mac_tbl_digest);
0286 updt_done:
0287
0288 if (rc)
0289 opa_vnic_free_mac_tbl(new_mactbl);
0290 else
0291 opa_vnic_free_mac_tbl(old_mactbl);
0292
0293 mutex_unlock(&adapter->mactbl_lock);
0294 return rc;
0295 }
0296
0297
0298 static uint32_t opa_vnic_chk_mac_tbl(struct opa_vnic_adapter *adapter,
0299 struct ethhdr *mac_hdr)
0300 {
0301 struct opa_vnic_mac_tbl_node *node;
0302 struct hlist_head *mactbl;
0303 u32 dlid = 0;
0304 u8 key;
0305
0306 rcu_read_lock();
0307 mactbl = rcu_dereference(adapter->mactbl);
0308 if (unlikely(!mactbl))
0309 goto chk_done;
0310
0311 key = mac_hdr->h_dest[OPA_VNIC_MAC_HASH_IDX];
0312 vnic_hash_for_each_possible(mactbl, node, hlist, key) {
0313 struct __opa_vnic_mactable_entry *entry = &node->entry;
0314
0315
0316 if (unlikely(OPA_VNIC_DLID_SD_IS_SRC_MAC(entry->dlid_sd)))
0317 continue;
0318
0319 if (!memcmp(node->entry.mac_addr, mac_hdr->h_dest,
0320 ARRAY_SIZE(node->entry.mac_addr))) {
0321
0322 dlid = OPA_VNIC_DLID_SD_GET_DLID(node->entry.dlid_sd);
0323 break;
0324 }
0325 }
0326
0327 chk_done:
0328 rcu_read_unlock();
0329 return dlid;
0330 }
0331
0332
0333 static uint32_t opa_vnic_get_dlid(struct opa_vnic_adapter *adapter,
0334 struct sk_buff *skb, u8 def_port)
0335 {
0336 struct __opa_veswport_info *info = &adapter->info;
0337 struct ethhdr *mac_hdr = (struct ethhdr *)skb_mac_header(skb);
0338 u32 dlid;
0339
0340 dlid = opa_vnic_chk_mac_tbl(adapter, mac_hdr);
0341 if (dlid)
0342 return dlid;
0343
0344 if (is_multicast_ether_addr(mac_hdr->h_dest)) {
0345 dlid = info->vesw.u_mcast_dlid;
0346 } else {
0347 if (is_local_ether_addr(mac_hdr->h_dest)) {
0348 dlid = ((uint32_t)mac_hdr->h_dest[5] << 16) |
0349 ((uint32_t)mac_hdr->h_dest[4] << 8) |
0350 mac_hdr->h_dest[3];
0351 if (unlikely(!dlid))
0352 v_warn("Null dlid in MAC address\n");
0353 } else if (def_port != OPA_VNIC_INVALID_PORT) {
0354 if (def_port < OPA_VESW_MAX_NUM_DEF_PORT)
0355 dlid = info->vesw.u_ucast_dlid[def_port];
0356 }
0357 }
0358
0359 return dlid;
0360 }
0361
0362
0363 static u8 opa_vnic_get_sc(struct __opa_veswport_info *info,
0364 struct sk_buff *skb)
0365 {
0366 struct ethhdr *mac_hdr = (struct ethhdr *)skb_mac_header(skb);
0367 u16 vlan_tci;
0368 u8 sc;
0369
0370 if (!__vlan_get_tag(skb, &vlan_tci)) {
0371 u8 pcp = OPA_VNIC_VLAN_PCP(vlan_tci);
0372
0373 if (is_multicast_ether_addr(mac_hdr->h_dest))
0374 sc = info->vport.pcp_to_sc_mc[pcp];
0375 else
0376 sc = info->vport.pcp_to_sc_uc[pcp];
0377 } else {
0378 if (is_multicast_ether_addr(mac_hdr->h_dest))
0379 sc = info->vport.non_vlan_sc_mc;
0380 else
0381 sc = info->vport.non_vlan_sc_uc;
0382 }
0383
0384 return sc;
0385 }
0386
0387 u8 opa_vnic_get_vl(struct opa_vnic_adapter *adapter, struct sk_buff *skb)
0388 {
0389 struct ethhdr *mac_hdr = (struct ethhdr *)skb_mac_header(skb);
0390 struct __opa_veswport_info *info = &adapter->info;
0391 u8 vl;
0392
0393 if (skb_vlan_tag_present(skb)) {
0394 u8 pcp = skb_vlan_tag_get(skb) >> VLAN_PRIO_SHIFT;
0395
0396 if (is_multicast_ether_addr(mac_hdr->h_dest))
0397 vl = info->vport.pcp_to_vl_mc[pcp];
0398 else
0399 vl = info->vport.pcp_to_vl_uc[pcp];
0400 } else {
0401 if (is_multicast_ether_addr(mac_hdr->h_dest))
0402 vl = info->vport.non_vlan_vl_mc;
0403 else
0404 vl = info->vport.non_vlan_vl_uc;
0405 }
0406
0407 return vl;
0408 }
0409
0410
0411 static u8 opa_vnic_get_rc(struct __opa_veswport_info *info,
0412 struct sk_buff *skb)
0413 {
0414 u8 proto, rout_ctrl;
0415
0416 switch (vlan_get_protocol(skb)) {
0417 case htons(ETH_P_IPV6):
0418 proto = ipv6_hdr(skb)->nexthdr;
0419 if (proto == IPPROTO_TCP)
0420 rout_ctrl = OPA_VNIC_ENCAP_RC_EXT(info->vesw.rc,
0421 IPV6_TCP);
0422 else if (proto == IPPROTO_UDP)
0423 rout_ctrl = OPA_VNIC_ENCAP_RC_EXT(info->vesw.rc,
0424 IPV6_UDP);
0425 else
0426 rout_ctrl = OPA_VNIC_ENCAP_RC_EXT(info->vesw.rc, IPV6);
0427 break;
0428 case htons(ETH_P_IP):
0429 proto = ip_hdr(skb)->protocol;
0430 if (proto == IPPROTO_TCP)
0431 rout_ctrl = OPA_VNIC_ENCAP_RC_EXT(info->vesw.rc,
0432 IPV4_TCP);
0433 else if (proto == IPPROTO_UDP)
0434 rout_ctrl = OPA_VNIC_ENCAP_RC_EXT(info->vesw.rc,
0435 IPV4_UDP);
0436 else
0437 rout_ctrl = OPA_VNIC_ENCAP_RC_EXT(info->vesw.rc, IPV4);
0438 break;
0439 default:
0440 rout_ctrl = OPA_VNIC_ENCAP_RC_EXT(info->vesw.rc, DEFAULT);
0441 }
0442
0443 return rout_ctrl;
0444 }
0445
0446
0447 u8 opa_vnic_calc_entropy(struct sk_buff *skb)
0448 {
0449 u32 hash = skb_get_hash(skb);
0450
0451
0452 hash ^= hash >> 8;
0453 hash ^= hash >> 16;
0454
0455
0456 return (u8)(hash & 0xFF);
0457 }
0458
0459
0460 static inline u8 opa_vnic_get_def_port(struct opa_vnic_adapter *adapter,
0461 u8 entropy)
0462 {
0463 u8 flow_id;
0464
0465
0466 flow_id = ((entropy & 0xf) + (entropy >> 4));
0467 return adapter->flow_tbl[flow_id & (OPA_VNIC_FLOW_TBL_SIZE - 1)];
0468 }
0469
0470
0471 static inline int opa_vnic_wire_length(struct sk_buff *skb)
0472 {
0473 u32 pad_len;
0474
0475
0476 pad_len = -(skb->len + OPA_VNIC_ICRC_TAIL_LEN) & 0x7;
0477 pad_len += OPA_VNIC_ICRC_TAIL_LEN;
0478
0479 return (skb->len + pad_len) >> 3;
0480 }
0481
0482
0483 void opa_vnic_encap_skb(struct opa_vnic_adapter *adapter, struct sk_buff *skb)
0484 {
0485 struct __opa_veswport_info *info = &adapter->info;
0486 struct opa_vnic_skb_mdata *mdata;
0487 u8 def_port, sc, rc, entropy, *hdr;
0488 u16 len, l4_hdr;
0489 u32 dlid;
0490
0491 hdr = skb_push(skb, OPA_VNIC_HDR_LEN);
0492
0493 entropy = opa_vnic_calc_entropy(skb);
0494 def_port = opa_vnic_get_def_port(adapter, entropy);
0495 len = opa_vnic_wire_length(skb);
0496 dlid = opa_vnic_get_dlid(adapter, skb, def_port);
0497 sc = opa_vnic_get_sc(info, skb);
0498 rc = opa_vnic_get_rc(info, skb);
0499 l4_hdr = info->vesw.vesw_id;
0500
0501 mdata = skb_push(skb, sizeof(*mdata));
0502 mdata->vl = opa_vnic_get_vl(adapter, skb);
0503 mdata->entropy = entropy;
0504 mdata->flags = 0;
0505 if (unlikely(!dlid)) {
0506 mdata->flags = OPA_VNIC_SKB_MDATA_ENCAP_ERR;
0507 return;
0508 }
0509
0510 opa_vnic_make_header(hdr, info->vport.encap_slid, dlid, len,
0511 info->vesw.pkey, entropy, sc, rc,
0512 OPA_VNIC_L4_ETHR, l4_hdr);
0513 }