ib_addr.h revision 278886
1219820Sjeff/* 2219820Sjeff * Copyright (c) 2005 Voltaire Inc. All rights reserved. 3219820Sjeff * Copyright (c) 2005 Intel Corporation. All rights reserved. 4219820Sjeff * 5219820Sjeff * This software is available to you under a choice of one of two 6219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 7219820Sjeff * General Public License (GPL) Version 2, available from the file 8219820Sjeff * COPYING in the main directory of this source tree, or the 9219820Sjeff * OpenIB.org BSD license below: 10219820Sjeff * 11219820Sjeff * Redistribution and use in source and binary forms, with or 12219820Sjeff * without modification, are permitted provided that the following 13219820Sjeff * conditions are met: 14219820Sjeff * 15219820Sjeff * - Redistributions of source code must retain the above 16219820Sjeff * copyright notice, this list of conditions and the following 17219820Sjeff * disclaimer. 18219820Sjeff * 19219820Sjeff * - Redistributions in binary form must reproduce the above 20219820Sjeff * copyright notice, this list of conditions and the following 21219820Sjeff * disclaimer in the documentation and/or other materials 22219820Sjeff * provided with the distribution. 23219820Sjeff * 24219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31219820Sjeff * SOFTWARE. 32219820Sjeff */ 33219820Sjeff 34278886Shselasky#ifndef IB_ADDR_H 35219820Sjeff#define IB_ADDR_H 36219820Sjeff 37219820Sjeff#include <linux/in.h> 38219820Sjeff#include <linux/in6.h> 39219820Sjeff#include <linux/if_arp.h> 40219820Sjeff#include <linux/netdevice.h> 41278886Shselasky#include <linux/inetdevice.h> 42219820Sjeff#include <linux/socket.h> 43278886Shselasky#include <linux/if_vlan.h> 44219820Sjeff#include <rdma/ib_verbs.h> 45219820Sjeff#include <rdma/ib_pack.h> 46278886Shselasky#include <net/if_inet6.h> 47278886Shselasky#include <net/ipv6.h> 48219820Sjeff 49219820Sjeffstruct rdma_addr_client { 50219820Sjeff atomic_t refcount; 51219820Sjeff struct completion comp; 52219820Sjeff}; 53219820Sjeff 54219820Sjeff/** 55219820Sjeff * rdma_addr_register_client - Register an address client. 56219820Sjeff */ 57219820Sjeffvoid rdma_addr_register_client(struct rdma_addr_client *client); 58219820Sjeff 59219820Sjeff/** 60219820Sjeff * rdma_addr_unregister_client - Deregister an address client. 61219820Sjeff * @client: Client object to deregister. 62219820Sjeff */ 63219820Sjeffvoid rdma_addr_unregister_client(struct rdma_addr_client *client); 64219820Sjeff 65219820Sjeffstruct rdma_dev_addr { 66219820Sjeff unsigned char src_dev_addr[MAX_ADDR_LEN]; 67219820Sjeff unsigned char dst_dev_addr[MAX_ADDR_LEN]; 68219820Sjeff unsigned char broadcast[MAX_ADDR_LEN]; 69219820Sjeff unsigned short dev_type; 70219820Sjeff int bound_dev_if; 71219820Sjeff enum rdma_transport_type transport; 72219820Sjeff}; 73219820Sjeff 74219820Sjeff/** 75219820Sjeff * rdma_translate_ip - Translate a local IP address to an RDMA hardware 76219820Sjeff * address. 77219820Sjeff */ 78278886Shselaskyint rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr, 79278886Shselasky u16 *vlan_id); 80219820Sjeff 81219820Sjeff/** 82219820Sjeff * rdma_resolve_ip - Resolve source and destination IP addresses to 83219820Sjeff * RDMA hardware addresses. 84219820Sjeff * @client: Address client associated with request. 85219820Sjeff * @src_addr: An optional source address to use in the resolution. If a 86219820Sjeff * source address is not provided, a usable address will be returned via 87219820Sjeff * the callback. 88219820Sjeff * @dst_addr: The destination address to resolve. 89219820Sjeff * @addr: A reference to a data location that will receive the resolved 90219820Sjeff * addresses. The data location must remain valid until the callback has 91219820Sjeff * been invoked. 92219820Sjeff * @timeout_ms: Amount of time to wait for the address resolution to complete. 93219820Sjeff * @callback: Call invoked once address resolution has completed, timed out, 94219820Sjeff * or been canceled. A status of 0 indicates success. 95219820Sjeff * @context: User-specified context associated with the call. 96219820Sjeff */ 97219820Sjeffint rdma_resolve_ip(struct rdma_addr_client *client, 98219820Sjeff struct sockaddr *src_addr, struct sockaddr *dst_addr, 99219820Sjeff struct rdma_dev_addr *addr, int timeout_ms, 100219820Sjeff void (*callback)(int status, struct sockaddr *src_addr, 101219820Sjeff struct rdma_dev_addr *addr, void *context), 102219820Sjeff void *context); 103219820Sjeff 104219820Sjeffvoid rdma_addr_cancel(struct rdma_dev_addr *addr); 105219820Sjeff 106219820Sjeffint rdma_copy_addr(struct rdma_dev_addr *dev_addr, struct net_device *dev, 107219820Sjeff const unsigned char *dst_dev_addr); 108278886Shselaskyint rdma_addr_find_smac_by_sgid(union ib_gid *sgid, u8 *smac, u16 *vlan_id); 109278886Shselaskyint rdma_addr_find_dmac_by_grh(union ib_gid *sgid, union ib_gid *dgid, u8 *smac, 110278886Shselasky u16 *vlan_id); 111219820Sjeff 112219820Sjeffstatic inline int ip_addr_size(struct sockaddr *addr) 113219820Sjeff{ 114219820Sjeff return addr->sa_family == AF_INET6 ? 115219820Sjeff sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in); 116219820Sjeff} 117219820Sjeff 118219820Sjeffstatic inline u16 ib_addr_get_pkey(struct rdma_dev_addr *dev_addr) 119219820Sjeff{ 120219820Sjeff return ((u16)dev_addr->broadcast[8] << 8) | (u16)dev_addr->broadcast[9]; 121219820Sjeff} 122219820Sjeff 123219820Sjeffstatic inline void ib_addr_set_pkey(struct rdma_dev_addr *dev_addr, u16 pkey) 124219820Sjeff{ 125219820Sjeff dev_addr->broadcast[8] = pkey >> 8; 126219820Sjeff dev_addr->broadcast[9] = (unsigned char) pkey; 127219820Sjeff} 128219820Sjeff 129219820Sjeffstatic inline void ib_addr_get_mgid(struct rdma_dev_addr *dev_addr, 130219820Sjeff union ib_gid *gid) 131219820Sjeff{ 132219820Sjeff memcpy(gid, dev_addr->broadcast + 4, sizeof *gid); 133219820Sjeff} 134219820Sjeff 135219820Sjeffstatic inline int rdma_addr_gid_offset(struct rdma_dev_addr *dev_addr) 136219820Sjeff{ 137219820Sjeff return dev_addr->dev_type == ARPHRD_INFINIBAND ? 4 : 0; 138219820Sjeff} 139219820Sjeff 140219820Sjeffstatic inline u16 rdma_vlan_dev_vlan_id(const struct net_device *dev) 141219820Sjeff{ 142219820Sjeff uint16_t tag; 143219820Sjeff 144219820Sjeff if (VLAN_TAG(__DECONST(struct ifnet *, dev), &tag) != 0) 145219820Sjeff return 0xffff; 146219820Sjeff return tag; 147219820Sjeff} 148219820Sjeff 149278886Shselaskystatic inline int rdma_ip2gid(struct sockaddr *addr, union ib_gid *gid) 150219820Sjeff{ 151278886Shselasky switch (addr->sa_family) { 152278886Shselasky case AF_INET: 153278886Shselasky ipv6_addr_set_v4mapped(((struct sockaddr_in *)addr)->sin_addr.s_addr, 154278886Shselasky (struct in6_addr *)gid); 155278886Shselasky break; 156278886Shselasky case AF_INET6: 157278886Shselasky memcpy(gid->raw, &((struct sockaddr_in6 *)addr)->sin6_addr, 158278886Shselasky 16); 159278886Shselasky break; 160278886Shselasky default: 161278886Shselasky return -EINVAL; 162278886Shselasky } 163278886Shselasky return 0; 164278886Shselasky} 165219820Sjeff 166278886Shselasky/* Important - sockaddr should be a union of sockaddr_in and sockaddr_in6 */ 167278886Shselaskystatic inline int rdma_gid2ip(struct sockaddr *out, union ib_gid *gid) 168278886Shselasky{ 169278886Shselasky if (ipv6_addr_v4mapped((struct in6_addr *)gid)) { 170278886Shselasky struct sockaddr_in *out_in = (struct sockaddr_in *)out; 171278886Shselasky memset(out_in, 0, sizeof(*out_in)); 172278886Shselasky out_in->sin_len = sizeof(*out_in); 173278886Shselasky out_in->sin_family = AF_INET; 174278886Shselasky memcpy(&out_in->sin_addr.s_addr, gid->raw + 12, 4); 175278886Shselasky } else { 176278886Shselasky struct sockaddr_in6 *out_in = (struct sockaddr_in6 *)out; 177278886Shselasky memset(out_in, 0, sizeof(*out_in)); 178278886Shselasky out_in->sin6_family = AF_INET6; 179278886Shselasky memcpy(&out_in->sin6_addr.s6_addr, gid->raw, 16); 180219820Sjeff } 181278886Shselasky return 0; 182278886Shselasky} 183219820Sjeff 184278886Shselasky/* This func is called only in loopback ip address (127.0.0.1) 185278886Shselasky * case in which sgid is not relevant 186278886Shselasky */ 187278886Shselaskystatic inline void iboe_addr_get_sgid(struct rdma_dev_addr *dev_addr, 188278886Shselasky union ib_gid *gid) 189278886Shselasky{ 190219820Sjeff} 191219820Sjeff 192219820Sjeffstatic inline void rdma_addr_get_sgid(struct rdma_dev_addr *dev_addr, union ib_gid *gid) 193219820Sjeff{ 194219820Sjeff if (dev_addr->transport == RDMA_TRANSPORT_IB && 195219820Sjeff dev_addr->dev_type != ARPHRD_INFINIBAND) 196219820Sjeff iboe_addr_get_sgid(dev_addr, gid); 197219820Sjeff else 198219820Sjeff memcpy(gid, dev_addr->src_dev_addr + 199219820Sjeff rdma_addr_gid_offset(dev_addr), sizeof *gid); 200219820Sjeff} 201219820Sjeff 202219820Sjeffstatic inline void rdma_addr_set_sgid(struct rdma_dev_addr *dev_addr, union ib_gid *gid) 203219820Sjeff{ 204219820Sjeff memcpy(dev_addr->src_dev_addr + rdma_addr_gid_offset(dev_addr), gid, sizeof *gid); 205219820Sjeff} 206219820Sjeff 207219820Sjeffstatic inline void rdma_addr_get_dgid(struct rdma_dev_addr *dev_addr, union ib_gid *gid) 208219820Sjeff{ 209219820Sjeff memcpy(gid, dev_addr->dst_dev_addr + rdma_addr_gid_offset(dev_addr), sizeof *gid); 210219820Sjeff} 211219820Sjeff 212219820Sjeffstatic inline void rdma_addr_set_dgid(struct rdma_dev_addr *dev_addr, union ib_gid *gid) 213219820Sjeff{ 214219820Sjeff memcpy(dev_addr->dst_dev_addr + rdma_addr_gid_offset(dev_addr), gid, sizeof *gid); 215219820Sjeff} 216219820Sjeff 217219820Sjeffstatic inline enum ib_mtu iboe_get_mtu(int mtu) 218219820Sjeff{ 219219820Sjeff /* 220219820Sjeff * reduce IB headers from effective IBoE MTU. 28 stands for 221219820Sjeff * atomic header which is the biggest possible header after BTH 222219820Sjeff */ 223219820Sjeff mtu = mtu - IB_GRH_BYTES - IB_BTH_BYTES - 28; 224219820Sjeff 225219820Sjeff if (mtu >= ib_mtu_enum_to_int(IB_MTU_4096)) 226219820Sjeff return IB_MTU_4096; 227219820Sjeff else if (mtu >= ib_mtu_enum_to_int(IB_MTU_2048)) 228219820Sjeff return IB_MTU_2048; 229219820Sjeff else if (mtu >= ib_mtu_enum_to_int(IB_MTU_1024)) 230219820Sjeff return IB_MTU_1024; 231219820Sjeff else if (mtu >= ib_mtu_enum_to_int(IB_MTU_512)) 232219820Sjeff return IB_MTU_512; 233219820Sjeff else if (mtu >= ib_mtu_enum_to_int(IB_MTU_256)) 234219820Sjeff return IB_MTU_256; 235219820Sjeff else 236219820Sjeff return 0; 237219820Sjeff} 238219820Sjeff 239219820Sjeffstatic inline int iboe_get_rate(struct net_device *dev) 240219820Sjeff{ 241263102Sglebius if (dev->if_baudrate >= IF_Gbps(40)) 242219820Sjeff return IB_RATE_40_GBPS; 243263102Sglebius else if (dev->if_baudrate >= IF_Gbps(30)) 244219820Sjeff return IB_RATE_30_GBPS; 245263102Sglebius else if (dev->if_baudrate >= IF_Gbps(20)) 246219820Sjeff return IB_RATE_20_GBPS; 247263102Sglebius else if (dev->if_baudrate >= IF_Gbps(10)) 248219820Sjeff return IB_RATE_10_GBPS; 249219820Sjeff else 250219820Sjeff return IB_RATE_PORT_CURRENT; 251219820Sjeff} 252219820Sjeff 253219820Sjeffstatic inline int rdma_link_local_addr(struct in6_addr *addr) 254219820Sjeff{ 255278886Shselasky if (addr->s6_addr32[0] == htonl(0xfe800000) && 256219820Sjeff addr->s6_addr32[1] == 0) 257219820Sjeff return 1; 258219820Sjeff 259219820Sjeff return 0; 260219820Sjeff} 261219820Sjeff 262219820Sjeffstatic inline void rdma_get_ll_mac(struct in6_addr *addr, u8 *mac) 263219820Sjeff{ 264219820Sjeff memcpy(mac, &addr->s6_addr[8], 3); 265219820Sjeff memcpy(mac + 3, &addr->s6_addr[13], 3); 266219820Sjeff mac[0] ^= 2; 267219820Sjeff} 268219820Sjeff 269219820Sjeffstatic inline int rdma_is_multicast_addr(struct in6_addr *addr) 270219820Sjeff{ 271219820Sjeff return addr->s6_addr[0] == 0xff; 272219820Sjeff} 273219820Sjeff 274278886Shselaskystatic inline void resolve_mcast_mac(struct in6_addr *addr, u8 *mac) 275278886Shselasky{ 276278886Shselasky if (addr->s6_addr[0] != 0xff) 277278886Shselasky return; 278278886Shselasky 279278886Shselasky#ifdef DUAL_MODE_MCAST_MAC 280278886Shselasky if (addr->s6_addr[1] == 0x0e) /* IPv4 */ 281278886Shselasky ip_eth_mc_map(addr->s6_addr32[3], mac); 282278886Shselasky else 283278886Shselasky#endif 284278886Shselasky ipv6_eth_mc_map(addr, mac); 285278886Shselasky} 286278886Shselasky 287278886Shselasky 288219820Sjeffstatic inline void rdma_get_mcast_mac(struct in6_addr *addr, u8 *mac) 289219820Sjeff{ 290219820Sjeff int i; 291219820Sjeff 292219820Sjeff mac[0] = 0x33; 293219820Sjeff mac[1] = 0x33; 294219820Sjeff for (i = 2; i < 6; ++i) 295219820Sjeff mac[i] = addr->s6_addr[i + 10]; 296219820Sjeff} 297219820Sjeff 298219820Sjeffstatic inline u16 rdma_get_vlan_id(union ib_gid *dgid) 299219820Sjeff{ 300219820Sjeff u16 vid; 301219820Sjeff 302219820Sjeff vid = dgid->raw[11] << 8 | dgid->raw[12]; 303219820Sjeff return vid < 0x1000 ? vid : 0xffff; 304219820Sjeff} 305219820Sjeff 306219820Sjeffstatic inline struct net_device *rdma_vlan_dev_real_dev(const struct net_device *dev) 307219820Sjeff{ 308219820Sjeff return VLAN_TRUNKDEV(__DECONST(struct ifnet *, dev)); 309219820Sjeff} 310219820Sjeff 311219820Sjeff#endif /* IB_ADDR_H */ 312