ib_addr.h revision 298486
1234285Sdim/* 2234285Sdim * Copyright (c) 2005 Voltaire Inc. All rights reserved. 3234285Sdim * Copyright (c) 2005 Intel Corporation. All rights reserved. 4234285Sdim * 5234285Sdim * This software is available to you under a choice of one of two 6234285Sdim * licenses. You may choose to be licensed under the terms of the GNU 7234285Sdim * General Public License (GPL) Version 2, available from the file 8234285Sdim * COPYING in the main directory of this source tree, or the 9234285Sdim * OpenIB.org BSD license below: 10234285Sdim * 11234285Sdim * Redistribution and use in source and binary forms, with or 12234285Sdim * without modification, are permitted provided that the following 13234285Sdim * conditions are met: 14234285Sdim * 15234285Sdim * - Redistributions of source code must retain the above 16234285Sdim * copyright notice, this list of conditions and the following 17234285Sdim * disclaimer. 18234285Sdim * 19234285Sdim * - Redistributions in binary form must reproduce the above 20234285Sdim * copyright notice, this list of conditions and the following 21234285Sdim * disclaimer in the documentation and/or other materials 22234285Sdim * provided with the distribution. 23234285Sdim * 24234285Sdim * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25234285Sdim * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26234285Sdim * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27234285Sdim * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28234285Sdim * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29234285Sdim * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30234285Sdim * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31234285Sdim * SOFTWARE. 32234285Sdim */ 33234285Sdim 34234285Sdim#ifndef IB_ADDR_H 35234285Sdim#define IB_ADDR_H 36234285Sdim 37234285Sdim#include <linux/in.h> 38234285Sdim#include <linux/in6.h> 39234285Sdim#include <linux/if_arp.h> 40234285Sdim#include <linux/netdevice.h> 41234285Sdim#include <linux/inetdevice.h> 42234285Sdim#include <linux/socket.h> 43234285Sdim#include <linux/if_vlan.h> 44234285Sdim#include <rdma/ib_verbs.h> 45234285Sdim#include <rdma/ib_pack.h> 46234285Sdim#include <net/if_inet6.h> 47234285Sdim#include <net/ipv6.h> 48234285Sdim 49234285Sdimstruct rdma_addr_client { 50234285Sdim atomic_t refcount; 51234285Sdim struct completion comp; 52234285Sdim}; 53234285Sdim 54234285Sdim/** 55234285Sdim * rdma_addr_register_client - Register an address client. 56234285Sdim */ 57234285Sdimvoid rdma_addr_register_client(struct rdma_addr_client *client); 58234285Sdim 59234285Sdim/** 60234285Sdim * rdma_addr_unregister_client - Deregister an address client. 61234285Sdim * @client: Client object to deregister. 62234285Sdim */ 63234285Sdimvoid rdma_addr_unregister_client(struct rdma_addr_client *client); 64234285Sdim 65234285Sdimstruct rdma_dev_addr { 66234285Sdim unsigned char src_dev_addr[MAX_ADDR_LEN]; 67234285Sdim unsigned char dst_dev_addr[MAX_ADDR_LEN]; 68234285Sdim unsigned char broadcast[MAX_ADDR_LEN]; 69234285Sdim unsigned short dev_type; 70234285Sdim int bound_dev_if; 71234285Sdim enum rdma_transport_type transport; 72234285Sdim}; 73234285Sdim 74234285Sdim/** 75234285Sdim * rdma_translate_ip - Translate a local IP address to an RDMA hardware 76234285Sdim * address. 77234285Sdim */ 78234285Sdimint rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr, 79234285Sdim u16 *vlan_id); 80234285Sdim 81234285Sdim/** 82234285Sdim * rdma_resolve_ip - Resolve source and destination IP addresses to 83234285Sdim * RDMA hardware addresses. 84234285Sdim * @client: Address client associated with request. 85234285Sdim * @src_addr: An optional source address to use in the resolution. If a 86234285Sdim * source address is not provided, a usable address will be returned via 87234285Sdim * the callback. 88234285Sdim * @dst_addr: The destination address to resolve. 89234285Sdim * @addr: A reference to a data location that will receive the resolved 90234285Sdim * addresses. The data location must remain valid until the callback has 91234285Sdim * been invoked. 92234285Sdim * @timeout_ms: Amount of time to wait for the address resolution to complete. 93234285Sdim * @callback: Call invoked once address resolution has completed, timed out, 94234285Sdim * or been canceled. A status of 0 indicates success. 95234285Sdim * @context: User-specified context associated with the call. 96234285Sdim */ 97234285Sdimint rdma_resolve_ip(struct rdma_addr_client *client, 98234285Sdim struct sockaddr *src_addr, struct sockaddr *dst_addr, 99234285Sdim struct rdma_dev_addr *addr, int timeout_ms, 100234285Sdim void (*callback)(int status, struct sockaddr *src_addr, 101234285Sdim struct rdma_dev_addr *addr, void *context), 102234285Sdim void *context); 103234285Sdim 104234285Sdimvoid rdma_addr_cancel(struct rdma_dev_addr *addr); 105234285Sdim 106234285Sdimint rdma_copy_addr(struct rdma_dev_addr *dev_addr, struct net_device *dev, 107234285Sdim const unsigned char *dst_dev_addr); 108234285Sdimint rdma_addr_find_smac_by_sgid(union ib_gid *sgid, u8 *smac, u16 *vlan_id, 109234285Sdim u32 scope_id); 110234285Sdimint rdma_addr_find_dmac_by_grh(union ib_gid *sgid, union ib_gid *dgid, u8 *smac, 111234285Sdim u16 *vlan_id, u32 scope_id); 112234285Sdim 113234285Sdimstatic inline int ip_addr_size(struct sockaddr *addr) 114234285Sdim{ 115234285Sdim return addr->sa_family == AF_INET6 ? 116234285Sdim sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in); 117234285Sdim} 118234285Sdim 119234285Sdimstatic inline u16 ib_addr_get_pkey(struct rdma_dev_addr *dev_addr) 120234285Sdim{ 121234285Sdim return ((u16)dev_addr->broadcast[8] << 8) | (u16)dev_addr->broadcast[9]; 122234285Sdim} 123234285Sdim 124234285Sdimstatic inline void ib_addr_set_pkey(struct rdma_dev_addr *dev_addr, u16 pkey) 125234285Sdim{ 126234285Sdim dev_addr->broadcast[8] = pkey >> 8; 127234285Sdim dev_addr->broadcast[9] = (unsigned char) pkey; 128234285Sdim} 129234285Sdim 130234285Sdimstatic inline void ib_addr_get_mgid(struct rdma_dev_addr *dev_addr, 131234285Sdim union ib_gid *gid) 132234285Sdim{ 133234285Sdim memcpy(gid, dev_addr->broadcast + 4, sizeof *gid); 134234285Sdim} 135234285Sdim 136234285Sdimstatic inline int rdma_addr_gid_offset(struct rdma_dev_addr *dev_addr) 137234285Sdim{ 138234285Sdim return dev_addr->dev_type == ARPHRD_INFINIBAND ? 4 : 0; 139234285Sdim} 140234285Sdim 141234285Sdimstatic inline u16 rdma_vlan_dev_vlan_id(const struct net_device *dev) 142234285Sdim{ 143234285Sdim uint16_t tag; 144234285Sdim 145234285Sdim if (VLAN_TAG(__DECONST(struct ifnet *, dev), &tag) != 0) 146234285Sdim return 0xffff; 147234285Sdim return tag; 148234285Sdim} 149234285Sdim 150234285Sdimstatic inline int rdma_ip2gid(struct sockaddr *addr, union ib_gid *gid) 151234285Sdim{ 152234285Sdim switch (addr->sa_family) { 153234285Sdim case AF_INET: 154234285Sdim ipv6_addr_set_v4mapped(((struct sockaddr_in *)addr)->sin_addr.s_addr, 155234285Sdim (struct in6_addr *)gid); 156234285Sdim break; 157234285Sdim case AF_INET6: 158234285Sdim memcpy(gid->raw, &((struct sockaddr_in6 *)addr)->sin6_addr, 159234285Sdim 16); 160234285Sdim break; 161234285Sdim default: 162234285Sdim return -EINVAL; 163234285Sdim } 164234285Sdim return 0; 165234285Sdim} 166234285Sdim 167234285Sdim/* Important - sockaddr should be a union of sockaddr_in and sockaddr_in6 */ 168234285Sdimstatic inline int rdma_gid2ip(struct sockaddr *out, union ib_gid *gid, 169234285Sdim uint32_t scope_id) 170234285Sdim{ 171234285Sdim if (ipv6_addr_v4mapped((struct in6_addr *)gid)) { 172234285Sdim struct sockaddr_in *out_in = (struct sockaddr_in *)out; 173234285Sdim memset(out_in, 0, sizeof(*out_in)); 174234285Sdim out_in->sin_len = sizeof(*out_in); 175234285Sdim out_in->sin_family = AF_INET; 176234285Sdim memcpy(&out_in->sin_addr.s_addr, gid->raw + 12, 4); 177234285Sdim } else { 178234285Sdim struct sockaddr_in6 *out_in = (struct sockaddr_in6 *)out; 179234285Sdim memset(out_in, 0, sizeof(*out_in)); 180234285Sdim out_in->sin6_len = sizeof(*out_in); 181234285Sdim out_in->sin6_family = AF_INET6; 182234285Sdim memcpy(&out_in->sin6_addr.s6_addr, gid->raw, 16); 183234285Sdim if (scope_id < 256 && 184234285Sdim IN6_IS_SCOPE_LINKLOCAL(&out_in->sin6_addr)) 185234285Sdim out_in->sin6_scope_id = scope_id; 186234285Sdim } 187234285Sdim return 0; 188234285Sdim} 189234285Sdim 190234285Sdimu32 rdma_get_ipv6_scope_id(struct ib_device *ib, u8 port_num); 191234285Sdim 192234285Sdim/* This func is called only in loopback ip address (127.0.0.1) 193234285Sdim * case in which sgid is not relevant 194234285Sdim */ 195234285Sdimstatic inline void iboe_addr_get_sgid(struct rdma_dev_addr *dev_addr, 196234285Sdim union ib_gid *gid) 197234285Sdim{ 198234285Sdim} 199234285Sdim 200234285Sdimstatic inline void rdma_addr_get_sgid(struct rdma_dev_addr *dev_addr, union ib_gid *gid) 201234285Sdim{ 202234285Sdim if (dev_addr->transport == RDMA_TRANSPORT_IB && 203234285Sdim dev_addr->dev_type != ARPHRD_INFINIBAND) 204234285Sdim iboe_addr_get_sgid(dev_addr, gid); 205234285Sdim else 206234285Sdim memcpy(gid, dev_addr->src_dev_addr + 207234285Sdim rdma_addr_gid_offset(dev_addr), sizeof *gid); 208234285Sdim} 209234285Sdim 210234285Sdimstatic inline void rdma_addr_set_sgid(struct rdma_dev_addr *dev_addr, union ib_gid *gid) 211234285Sdim{ 212234285Sdim memcpy(dev_addr->src_dev_addr + rdma_addr_gid_offset(dev_addr), gid, sizeof *gid); 213234285Sdim} 214234285Sdim 215234285Sdimstatic inline void rdma_addr_get_dgid(struct rdma_dev_addr *dev_addr, union ib_gid *gid) 216234285Sdim{ 217234285Sdim memcpy(gid, dev_addr->dst_dev_addr + rdma_addr_gid_offset(dev_addr), sizeof *gid); 218234285Sdim} 219234285Sdim 220234285Sdimstatic inline void rdma_addr_set_dgid(struct rdma_dev_addr *dev_addr, union ib_gid *gid) 221234285Sdim{ 222234285Sdim memcpy(dev_addr->dst_dev_addr + rdma_addr_gid_offset(dev_addr), gid, sizeof *gid); 223234285Sdim} 224234285Sdim 225234285Sdimstatic inline enum ib_mtu iboe_get_mtu(int mtu) 226234285Sdim{ 227234285Sdim /* 228234285Sdim * reduce IB headers from effective IBoE MTU. 28 stands for 229234285Sdim * atomic header which is the biggest possible header after BTH 230234285Sdim */ 231234285Sdim mtu = mtu - IB_GRH_BYTES - IB_BTH_BYTES - 28; 232234285Sdim 233234285Sdim if (mtu >= ib_mtu_enum_to_int(IB_MTU_4096)) 234234285Sdim return IB_MTU_4096; 235234285Sdim else if (mtu >= ib_mtu_enum_to_int(IB_MTU_2048)) 236234285Sdim return IB_MTU_2048; 237234285Sdim else if (mtu >= ib_mtu_enum_to_int(IB_MTU_1024)) 238234285Sdim return IB_MTU_1024; 239234285Sdim else if (mtu >= ib_mtu_enum_to_int(IB_MTU_512)) 240234285Sdim return IB_MTU_512; 241234285Sdim else if (mtu >= ib_mtu_enum_to_int(IB_MTU_256)) 242234285Sdim return IB_MTU_256; 243234285Sdim else 244234285Sdim return 0; 245234285Sdim} 246234285Sdim 247234285Sdimstatic inline int iboe_get_rate(struct net_device *dev) 248234285Sdim{ 249234285Sdim if (dev->if_baudrate >= IF_Gbps(40)) 250234285Sdim return IB_RATE_40_GBPS; 251234285Sdim else if (dev->if_baudrate >= IF_Gbps(30)) 252234285Sdim return IB_RATE_30_GBPS; 253234285Sdim else if (dev->if_baudrate >= IF_Gbps(20)) 254234285Sdim return IB_RATE_20_GBPS; 255234285Sdim else if (dev->if_baudrate >= IF_Gbps(10)) 256234285Sdim return IB_RATE_10_GBPS; 257234285Sdim else 258234285Sdim return IB_RATE_PORT_CURRENT; 259234285Sdim} 260234285Sdim 261234285Sdimstatic inline int rdma_link_local_addr(struct in6_addr *addr) 262234285Sdim{ 263234285Sdim if (addr->s6_addr32[0] == htonl(0xfe800000) && 264234285Sdim addr->s6_addr32[1] == 0) 265234285Sdim return 1; 266234285Sdim 267234285Sdim return 0; 268234285Sdim} 269234285Sdim 270234285Sdimstatic inline void rdma_get_ll_mac(struct in6_addr *addr, u8 *mac) 271234285Sdim{ 272234285Sdim memcpy(mac, &addr->s6_addr[8], 3); 273234285Sdim memcpy(mac + 3, &addr->s6_addr[13], 3); 274234285Sdim mac[0] ^= 2; 275234285Sdim} 276234285Sdim 277234285Sdimstatic inline int rdma_is_multicast_addr(struct in6_addr *addr) 278234285Sdim{ 279234285Sdim return addr->s6_addr[0] == 0xff; 280234285Sdim} 281234285Sdim 282234285Sdimstatic inline void resolve_mcast_mac(struct in6_addr *addr, u8 *mac) 283234285Sdim{ 284234285Sdim if (addr->s6_addr[0] != 0xff) 285234285Sdim return; 286234285Sdim 287234285Sdim#ifdef DUAL_MODE_MCAST_MAC 288234285Sdim if (addr->s6_addr[1] == 0x0e) /* IPv4 */ 289234285Sdim ip_eth_mc_map(addr->s6_addr32[3], mac); 290234285Sdim else 291234285Sdim#endif 292234285Sdim ipv6_eth_mc_map(addr, mac); 293234285Sdim} 294234285Sdim 295234285Sdim 296234285Sdimstatic inline void rdma_get_mcast_mac(struct in6_addr *addr, u8 *mac) 297234285Sdim{ 298234285Sdim int i; 299234285Sdim 300234285Sdim mac[0] = 0x33; 301234285Sdim mac[1] = 0x33; 302234285Sdim for (i = 2; i < 6; ++i) 303234285Sdim mac[i] = addr->s6_addr[i + 10]; 304234285Sdim} 305234285Sdim 306234285Sdimstatic inline u16 rdma_get_vlan_id(union ib_gid *dgid) 307234285Sdim{ 308234285Sdim u16 vid; 309234285Sdim 310234285Sdim vid = dgid->raw[11] << 8 | dgid->raw[12]; 311234285Sdim return vid < 0x1000 ? vid : 0xffff; 312234285Sdim} 313234285Sdim 314234285Sdimstatic inline struct net_device *rdma_vlan_dev_real_dev(const struct net_device *dev) 315234285Sdim{ 316234285Sdim return VLAN_TRUNKDEV(__DECONST(struct ifnet *, dev)); 317234285Sdim} 318234285Sdim 319234285Sdim#endif /* IB_ADDR_H */ 320234285Sdim