Moni Shoua | 8700e3e | 2016-06-16 16:45:23 +0300 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved. |
| 3 | * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved. |
| 4 | * |
| 5 | * This software is available to you under a choice of one of two |
| 6 | * licenses. You may choose to be licensed under the terms of the GNU |
| 7 | * General Public License (GPL) Version 2, available from the file |
| 8 | * COPYING in the main directory of this source tree, or the |
| 9 | * OpenIB.org BSD license below: |
| 10 | * |
| 11 | * Redistribution and use in source and binary forms, with or |
| 12 | * without modification, are permitted provided that the following |
| 13 | * conditions are met: |
| 14 | * |
| 15 | * - Redistributions of source code must retain the above |
| 16 | * copyright notice, this list of conditions and the following |
| 17 | * disclaimer. |
| 18 | * |
| 19 | * - Redistributions in binary form must reproduce the above |
| 20 | * copyright notice, this list of conditions and the following |
| 21 | * disclaimer in the documentation and/or other materials |
| 22 | * provided with the distribution. |
| 23 | * |
| 24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| 25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| 26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| 27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
| 28 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
| 29 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
| 30 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| 31 | * SOFTWARE. |
| 32 | */ |
| 33 | |
| 34 | #include <linux/skbuff.h> |
| 35 | |
| 36 | #include "rxe.h" |
| 37 | #include "rxe_loc.h" |
| 38 | |
| 39 | static int check_type_state(struct rxe_dev *rxe, struct rxe_pkt_info *pkt, |
| 40 | struct rxe_qp *qp) |
| 41 | { |
| 42 | if (unlikely(!qp->valid)) |
| 43 | goto err1; |
| 44 | |
| 45 | switch (qp_type(qp)) { |
| 46 | case IB_QPT_RC: |
| 47 | if (unlikely((pkt->opcode & IB_OPCODE_RC) != 0)) { |
| 48 | pr_warn_ratelimited("bad qp type\n"); |
| 49 | goto err1; |
| 50 | } |
| 51 | break; |
| 52 | case IB_QPT_UC: |
| 53 | if (unlikely(!(pkt->opcode & IB_OPCODE_UC))) { |
| 54 | pr_warn_ratelimited("bad qp type\n"); |
| 55 | goto err1; |
| 56 | } |
| 57 | break; |
| 58 | case IB_QPT_UD: |
| 59 | case IB_QPT_SMI: |
| 60 | case IB_QPT_GSI: |
| 61 | if (unlikely(!(pkt->opcode & IB_OPCODE_UD))) { |
| 62 | pr_warn_ratelimited("bad qp type\n"); |
| 63 | goto err1; |
| 64 | } |
| 65 | break; |
| 66 | default: |
| 67 | pr_warn_ratelimited("unsupported qp type\n"); |
| 68 | goto err1; |
| 69 | } |
| 70 | |
| 71 | if (pkt->mask & RXE_REQ_MASK) { |
| 72 | if (unlikely(qp->resp.state != QP_STATE_READY)) |
| 73 | goto err1; |
| 74 | } else if (unlikely(qp->req.state < QP_STATE_READY || |
| 75 | qp->req.state > QP_STATE_DRAINED)) { |
| 76 | goto err1; |
| 77 | } |
| 78 | |
| 79 | return 0; |
| 80 | |
| 81 | err1: |
| 82 | return -EINVAL; |
| 83 | } |
| 84 | |
| 85 | static void set_bad_pkey_cntr(struct rxe_port *port) |
| 86 | { |
| 87 | spin_lock_bh(&port->port_lock); |
| 88 | port->attr.bad_pkey_cntr = min((u32)0xffff, |
| 89 | port->attr.bad_pkey_cntr + 1); |
| 90 | spin_unlock_bh(&port->port_lock); |
| 91 | } |
| 92 | |
| 93 | static void set_qkey_viol_cntr(struct rxe_port *port) |
| 94 | { |
| 95 | spin_lock_bh(&port->port_lock); |
| 96 | port->attr.qkey_viol_cntr = min((u32)0xffff, |
| 97 | port->attr.qkey_viol_cntr + 1); |
| 98 | spin_unlock_bh(&port->port_lock); |
| 99 | } |
| 100 | |
| 101 | static int check_keys(struct rxe_dev *rxe, struct rxe_pkt_info *pkt, |
| 102 | u32 qpn, struct rxe_qp *qp) |
| 103 | { |
| 104 | int i; |
| 105 | int found_pkey = 0; |
| 106 | struct rxe_port *port = &rxe->port; |
| 107 | u16 pkey = bth_pkey(pkt); |
| 108 | |
| 109 | pkt->pkey_index = 0; |
| 110 | |
| 111 | if (qpn == 1) { |
| 112 | for (i = 0; i < port->attr.pkey_tbl_len; i++) { |
| 113 | if (pkey_match(pkey, port->pkey_tbl[i])) { |
| 114 | pkt->pkey_index = i; |
| 115 | found_pkey = 1; |
| 116 | break; |
| 117 | } |
| 118 | } |
| 119 | |
| 120 | if (!found_pkey) { |
| 121 | pr_warn_ratelimited("bad pkey = 0x%x\n", pkey); |
| 122 | set_bad_pkey_cntr(port); |
| 123 | goto err1; |
| 124 | } |
| 125 | } else if (qpn != 0) { |
| 126 | if (unlikely(!pkey_match(pkey, |
| 127 | port->pkey_tbl[qp->attr.pkey_index] |
| 128 | ))) { |
| 129 | pr_warn_ratelimited("bad pkey = 0x%0x\n", pkey); |
| 130 | set_bad_pkey_cntr(port); |
| 131 | goto err1; |
| 132 | } |
| 133 | pkt->pkey_index = qp->attr.pkey_index; |
| 134 | } |
| 135 | |
| 136 | if ((qp_type(qp) == IB_QPT_UD || qp_type(qp) == IB_QPT_GSI) && |
| 137 | qpn != 0 && pkt->mask) { |
| 138 | u32 qkey = (qpn == 1) ? GSI_QKEY : qp->attr.qkey; |
| 139 | |
| 140 | if (unlikely(deth_qkey(pkt) != qkey)) { |
| 141 | pr_warn_ratelimited("bad qkey, got 0x%x expected 0x%x for qpn 0x%x\n", |
| 142 | deth_qkey(pkt), qkey, qpn); |
| 143 | set_qkey_viol_cntr(port); |
| 144 | goto err1; |
| 145 | } |
| 146 | } |
| 147 | |
| 148 | return 0; |
| 149 | |
| 150 | err1: |
| 151 | return -EINVAL; |
| 152 | } |
| 153 | |
| 154 | static int check_addr(struct rxe_dev *rxe, struct rxe_pkt_info *pkt, |
| 155 | struct rxe_qp *qp) |
| 156 | { |
| 157 | struct sk_buff *skb = PKT_TO_SKB(pkt); |
| 158 | |
| 159 | if (qp_type(qp) != IB_QPT_RC && qp_type(qp) != IB_QPT_UC) |
| 160 | goto done; |
| 161 | |
| 162 | if (unlikely(pkt->port_num != qp->attr.port_num)) { |
| 163 | pr_warn_ratelimited("port %d != qp port %d\n", |
| 164 | pkt->port_num, qp->attr.port_num); |
| 165 | goto err1; |
| 166 | } |
| 167 | |
| 168 | if (skb->protocol == htons(ETH_P_IP)) { |
| 169 | struct in_addr *saddr = |
| 170 | &qp->pri_av.sgid_addr._sockaddr_in.sin_addr; |
| 171 | struct in_addr *daddr = |
| 172 | &qp->pri_av.dgid_addr._sockaddr_in.sin_addr; |
| 173 | |
| 174 | if (ip_hdr(skb)->daddr != saddr->s_addr) { |
| 175 | pr_warn_ratelimited("dst addr %pI4 != qp source addr %pI4\n", |
| 176 | &ip_hdr(skb)->daddr, |
| 177 | &saddr->s_addr); |
| 178 | goto err1; |
| 179 | } |
| 180 | |
| 181 | if (ip_hdr(skb)->saddr != daddr->s_addr) { |
| 182 | pr_warn_ratelimited("source addr %pI4 != qp dst addr %pI4\n", |
| 183 | &ip_hdr(skb)->saddr, |
| 184 | &daddr->s_addr); |
| 185 | goto err1; |
| 186 | } |
| 187 | |
| 188 | } else if (skb->protocol == htons(ETH_P_IPV6)) { |
| 189 | struct in6_addr *saddr = |
| 190 | &qp->pri_av.sgid_addr._sockaddr_in6.sin6_addr; |
| 191 | struct in6_addr *daddr = |
| 192 | &qp->pri_av.dgid_addr._sockaddr_in6.sin6_addr; |
| 193 | |
| 194 | if (memcmp(&ipv6_hdr(skb)->daddr, saddr, sizeof(*saddr))) { |
| 195 | pr_warn_ratelimited("dst addr %pI6 != qp source addr %pI6\n", |
| 196 | &ipv6_hdr(skb)->daddr, saddr); |
| 197 | goto err1; |
| 198 | } |
| 199 | |
| 200 | if (memcmp(&ipv6_hdr(skb)->saddr, daddr, sizeof(*daddr))) { |
| 201 | pr_warn_ratelimited("source addr %pI6 != qp dst addr %pI6\n", |
| 202 | &ipv6_hdr(skb)->saddr, daddr); |
| 203 | goto err1; |
| 204 | } |
| 205 | } |
| 206 | |
| 207 | done: |
| 208 | return 0; |
| 209 | |
| 210 | err1: |
| 211 | return -EINVAL; |
| 212 | } |
| 213 | |
| 214 | static int hdr_check(struct rxe_pkt_info *pkt) |
| 215 | { |
| 216 | struct rxe_dev *rxe = pkt->rxe; |
| 217 | struct rxe_port *port = &rxe->port; |
| 218 | struct rxe_qp *qp = NULL; |
| 219 | u32 qpn = bth_qpn(pkt); |
| 220 | int index; |
| 221 | int err; |
| 222 | |
| 223 | if (unlikely(bth_tver(pkt) != BTH_TVER)) { |
| 224 | pr_warn_ratelimited("bad tver\n"); |
| 225 | goto err1; |
| 226 | } |
| 227 | |
| 228 | if (qpn != IB_MULTICAST_QPN) { |
| 229 | index = (qpn == 0) ? port->qp_smi_index : |
| 230 | ((qpn == 1) ? port->qp_gsi_index : qpn); |
| 231 | qp = rxe_pool_get_index(&rxe->qp_pool, index); |
| 232 | if (unlikely(!qp)) { |
| 233 | pr_warn_ratelimited("no qp matches qpn 0x%x\n", qpn); |
| 234 | goto err1; |
| 235 | } |
| 236 | |
| 237 | err = check_type_state(rxe, pkt, qp); |
| 238 | if (unlikely(err)) |
| 239 | goto err2; |
| 240 | |
| 241 | err = check_addr(rxe, pkt, qp); |
| 242 | if (unlikely(err)) |
| 243 | goto err2; |
| 244 | |
| 245 | err = check_keys(rxe, pkt, qpn, qp); |
| 246 | if (unlikely(err)) |
| 247 | goto err2; |
| 248 | } else { |
| 249 | if (unlikely((pkt->mask & RXE_GRH_MASK) == 0)) { |
| 250 | pr_warn_ratelimited("no grh for mcast qpn\n"); |
| 251 | goto err1; |
| 252 | } |
| 253 | } |
| 254 | |
| 255 | pkt->qp = qp; |
| 256 | return 0; |
| 257 | |
| 258 | err2: |
| 259 | if (qp) |
| 260 | rxe_drop_ref(qp); |
| 261 | err1: |
| 262 | return -EINVAL; |
| 263 | } |
| 264 | |
| 265 | static inline void rxe_rcv_pkt(struct rxe_dev *rxe, |
| 266 | struct rxe_pkt_info *pkt, |
| 267 | struct sk_buff *skb) |
| 268 | { |
| 269 | if (pkt->mask & RXE_REQ_MASK) |
| 270 | rxe_resp_queue_pkt(rxe, pkt->qp, skb); |
| 271 | else |
| 272 | rxe_comp_queue_pkt(rxe, pkt->qp, skb); |
| 273 | } |
| 274 | |
| 275 | static void rxe_rcv_mcast_pkt(struct rxe_dev *rxe, struct sk_buff *skb) |
| 276 | { |
| 277 | struct rxe_pkt_info *pkt = SKB_TO_PKT(skb); |
| 278 | struct rxe_mc_grp *mcg; |
| 279 | struct sk_buff *skb_copy; |
| 280 | struct rxe_mc_elem *mce; |
| 281 | struct rxe_qp *qp; |
| 282 | union ib_gid dgid; |
| 283 | int err; |
| 284 | |
| 285 | if (skb->protocol == htons(ETH_P_IP)) |
| 286 | ipv6_addr_set_v4mapped(ip_hdr(skb)->daddr, |
| 287 | (struct in6_addr *)&dgid); |
| 288 | else if (skb->protocol == htons(ETH_P_IPV6)) |
| 289 | memcpy(&dgid, &ipv6_hdr(skb)->daddr, sizeof(dgid)); |
| 290 | |
| 291 | /* lookup mcast group corresponding to mgid, takes a ref */ |
| 292 | mcg = rxe_pool_get_key(&rxe->mc_grp_pool, &dgid); |
| 293 | if (!mcg) |
| 294 | goto err1; /* mcast group not registered */ |
| 295 | |
| 296 | spin_lock_bh(&mcg->mcg_lock); |
| 297 | |
| 298 | list_for_each_entry(mce, &mcg->qp_list, qp_list) { |
| 299 | qp = mce->qp; |
| 300 | pkt = SKB_TO_PKT(skb); |
| 301 | |
| 302 | /* validate qp for incoming packet */ |
| 303 | err = check_type_state(rxe, pkt, qp); |
| 304 | if (err) |
| 305 | continue; |
| 306 | |
| 307 | err = check_keys(rxe, pkt, bth_qpn(pkt), qp); |
| 308 | if (err) |
| 309 | continue; |
| 310 | |
| 311 | /* if *not* the last qp in the list |
| 312 | * make a copy of the skb to post to the next qp |
| 313 | */ |
| 314 | skb_copy = (mce->qp_list.next != &mcg->qp_list) ? |
Alexey Khoroshilov | 5e102b3 | 2016-09-02 23:46:53 +0300 | [diff] [blame] | 315 | skb_clone(skb, GFP_ATOMIC) : NULL; |
Moni Shoua | 8700e3e | 2016-06-16 16:45:23 +0300 | [diff] [blame] | 316 | |
| 317 | pkt->qp = qp; |
| 318 | rxe_add_ref(qp); |
| 319 | rxe_rcv_pkt(rxe, pkt, skb); |
| 320 | |
| 321 | skb = skb_copy; |
| 322 | if (!skb) |
| 323 | break; |
| 324 | } |
| 325 | |
| 326 | spin_unlock_bh(&mcg->mcg_lock); |
| 327 | |
| 328 | rxe_drop_ref(mcg); /* drop ref from rxe_pool_get_key. */ |
| 329 | |
| 330 | err1: |
| 331 | if (skb) |
| 332 | kfree_skb(skb); |
| 333 | } |
| 334 | |
| 335 | static int rxe_match_dgid(struct rxe_dev *rxe, struct sk_buff *skb) |
| 336 | { |
| 337 | union ib_gid dgid; |
| 338 | union ib_gid *pdgid; |
| 339 | u16 index; |
| 340 | |
| 341 | if (skb->protocol == htons(ETH_P_IP)) { |
| 342 | ipv6_addr_set_v4mapped(ip_hdr(skb)->daddr, |
| 343 | (struct in6_addr *)&dgid); |
| 344 | pdgid = &dgid; |
| 345 | } else { |
| 346 | pdgid = (union ib_gid *)&ipv6_hdr(skb)->daddr; |
| 347 | } |
| 348 | |
| 349 | return ib_find_cached_gid_by_port(&rxe->ib_dev, pdgid, |
| 350 | IB_GID_TYPE_ROCE_UDP_ENCAP, |
| 351 | 1, rxe->ndev, &index); |
| 352 | } |
| 353 | |
| 354 | /* rxe_rcv is called from the interface driver */ |
| 355 | int rxe_rcv(struct sk_buff *skb) |
| 356 | { |
| 357 | int err; |
| 358 | struct rxe_pkt_info *pkt = SKB_TO_PKT(skb); |
| 359 | struct rxe_dev *rxe = pkt->rxe; |
| 360 | __be32 *icrcp; |
| 361 | u32 calc_icrc, pack_icrc; |
| 362 | |
| 363 | pkt->offset = 0; |
| 364 | |
| 365 | if (unlikely(skb->len < pkt->offset + RXE_BTH_BYTES)) |
| 366 | goto drop; |
| 367 | |
| 368 | if (unlikely(rxe_match_dgid(rxe, skb) < 0)) { |
| 369 | pr_warn_ratelimited("failed matching dgid\n"); |
| 370 | goto drop; |
| 371 | } |
| 372 | |
| 373 | pkt->opcode = bth_opcode(pkt); |
| 374 | pkt->psn = bth_psn(pkt); |
| 375 | pkt->qp = NULL; |
| 376 | pkt->mask |= rxe_opcode[pkt->opcode].mask; |
| 377 | |
| 378 | if (unlikely(skb->len < header_size(pkt))) |
| 379 | goto drop; |
| 380 | |
| 381 | err = hdr_check(pkt); |
| 382 | if (unlikely(err)) |
| 383 | goto drop; |
| 384 | |
| 385 | /* Verify ICRC */ |
| 386 | icrcp = (__be32 *)(pkt->hdr + pkt->paylen - RXE_ICRC_SIZE); |
| 387 | pack_icrc = be32_to_cpu(*icrcp); |
| 388 | |
| 389 | calc_icrc = rxe_icrc_hdr(pkt, skb); |
| 390 | calc_icrc = crc32_le(calc_icrc, (u8 *)payload_addr(pkt), payload_size(pkt)); |
| 391 | calc_icrc = cpu_to_be32(~calc_icrc); |
| 392 | if (unlikely(calc_icrc != pack_icrc)) { |
| 393 | char saddr[sizeof(struct in6_addr)]; |
| 394 | |
| 395 | if (skb->protocol == htons(ETH_P_IPV6)) |
| 396 | sprintf(saddr, "%pI6", &ipv6_hdr(skb)->saddr); |
| 397 | else if (skb->protocol == htons(ETH_P_IP)) |
| 398 | sprintf(saddr, "%pI4", &ip_hdr(skb)->saddr); |
| 399 | else |
| 400 | sprintf(saddr, "unknown"); |
| 401 | |
| 402 | pr_warn_ratelimited("bad ICRC from %s\n", saddr); |
| 403 | goto drop; |
| 404 | } |
| 405 | |
| 406 | if (unlikely(bth_qpn(pkt) == IB_MULTICAST_QPN)) |
| 407 | rxe_rcv_mcast_pkt(rxe, skb); |
| 408 | else |
| 409 | rxe_rcv_pkt(rxe, pkt, skb); |
| 410 | |
| 411 | return 0; |
| 412 | |
| 413 | drop: |
| 414 | if (pkt->qp) |
| 415 | rxe_drop_ref(pkt->qp); |
| 416 | |
| 417 | kfree_skb(skb); |
| 418 | return 0; |
| 419 | } |
| 420 | EXPORT_SYMBOL(rxe_rcv); |