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. 32331772Shselasky * 33331772Shselasky * $FreeBSD: stable/11/sys/ofed/include/rdma/ib_addr.h 338612 2018-09-12 08:56:08Z hselasky $ 34219820Sjeff */ 35219820Sjeff 36331769Shselasky#if !defined(IB_ADDR_H) 37219820Sjeff#define IB_ADDR_H 38219820Sjeff 39219820Sjeff#include <linux/in.h> 40219820Sjeff#include <linux/in6.h> 41219820Sjeff#include <linux/if_arp.h> 42219820Sjeff#include <linux/netdevice.h> 43278886Shselasky#include <linux/inetdevice.h> 44219820Sjeff#include <linux/socket.h> 45278886Shselasky#include <linux/if_vlan.h> 46331769Shselasky#include <net/ipv6.h> 47331769Shselasky#include <net/if_inet6.h> 48331769Shselasky#include <net/ip.h> 49219820Sjeff#include <rdma/ib_verbs.h> 50219820Sjeff#include <rdma/ib_pack.h> 51278886Shselasky#include <net/ipv6.h> 52219820Sjeff 53219820Sjeffstruct rdma_addr_client { 54219820Sjeff atomic_t refcount; 55219820Sjeff struct completion comp; 56219820Sjeff}; 57219820Sjeff 58219820Sjeff/** 59219820Sjeff * rdma_addr_register_client - Register an address client. 60219820Sjeff */ 61219820Sjeffvoid rdma_addr_register_client(struct rdma_addr_client *client); 62219820Sjeff 63219820Sjeff/** 64219820Sjeff * rdma_addr_unregister_client - Deregister an address client. 65219820Sjeff * @client: Client object to deregister. 66219820Sjeff */ 67219820Sjeffvoid rdma_addr_unregister_client(struct rdma_addr_client *client); 68219820Sjeff 69331769Shselasky/** 70331769Shselasky * struct rdma_dev_addr - Contains resolved RDMA hardware addresses 71331769Shselasky * @src_dev_addr: Source MAC address. 72331769Shselasky * @dst_dev_addr: Destination MAC address. 73331769Shselasky * @broadcast: Broadcast address of the device. 74331769Shselasky * @dev_type: The interface hardware type of the device. 75331769Shselasky * @bound_dev_if: An optional device interface index. 76331769Shselasky * @transport: The transport type used. 77331769Shselasky * @net: Network namespace containing the bound_dev_if net_dev. 78331769Shselasky */ 79331769Shselaskystruct vnet; 80219820Sjeffstruct rdma_dev_addr { 81219820Sjeff unsigned char src_dev_addr[MAX_ADDR_LEN]; 82219820Sjeff unsigned char dst_dev_addr[MAX_ADDR_LEN]; 83219820Sjeff unsigned char broadcast[MAX_ADDR_LEN]; 84219820Sjeff unsigned short dev_type; 85219820Sjeff int bound_dev_if; 86219820Sjeff enum rdma_transport_type transport; 87331769Shselasky struct vnet *net; 88331769Shselasky enum rdma_network_type network; 89331769Shselasky int hoplimit; 90219820Sjeff}; 91219820Sjeff 92219820Sjeff/** 93219820Sjeff * rdma_translate_ip - Translate a local IP address to an RDMA hardware 94219820Sjeff * address. 95331769Shselasky * 96331783Shselasky * The dev_addr->net and dev_addr->bound_dev_if fields must be initialized. 97219820Sjeff */ 98331769Shselaskyint rdma_translate_ip(const struct sockaddr *addr, 99331783Shselasky struct rdma_dev_addr *dev_addr); 100219820Sjeff 101219820Sjeff/** 102219820Sjeff * rdma_resolve_ip - Resolve source and destination IP addresses to 103219820Sjeff * RDMA hardware addresses. 104219820Sjeff * @client: Address client associated with request. 105219820Sjeff * @src_addr: An optional source address to use in the resolution. If a 106219820Sjeff * source address is not provided, a usable address will be returned via 107219820Sjeff * the callback. 108219820Sjeff * @dst_addr: The destination address to resolve. 109219820Sjeff * @addr: A reference to a data location that will receive the resolved 110219820Sjeff * addresses. The data location must remain valid until the callback has 111331769Shselasky * been invoked. The net field of the addr struct must be valid. 112219820Sjeff * @timeout_ms: Amount of time to wait for the address resolution to complete. 113219820Sjeff * @callback: Call invoked once address resolution has completed, timed out, 114219820Sjeff * or been canceled. A status of 0 indicates success. 115219820Sjeff * @context: User-specified context associated with the call. 116219820Sjeff */ 117219820Sjeffint rdma_resolve_ip(struct rdma_addr_client *client, 118219820Sjeff struct sockaddr *src_addr, struct sockaddr *dst_addr, 119219820Sjeff struct rdma_dev_addr *addr, int timeout_ms, 120219820Sjeff void (*callback)(int status, struct sockaddr *src_addr, 121219820Sjeff struct rdma_dev_addr *addr, void *context), 122219820Sjeff void *context); 123219820Sjeff 124331769Shselaskyint rdma_resolve_ip_route(struct sockaddr *src_addr, 125331769Shselasky const struct sockaddr *dst_addr, 126331769Shselasky struct rdma_dev_addr *addr); 127331769Shselasky 128219820Sjeffvoid rdma_addr_cancel(struct rdma_dev_addr *addr); 129219820Sjeff 130219820Sjeffint rdma_copy_addr(struct rdma_dev_addr *dev_addr, struct net_device *dev, 131219820Sjeff const unsigned char *dst_dev_addr); 132331769Shselasky 133331769Shselaskyint rdma_addr_size(struct sockaddr *addr); 134337085Shselaskyint rdma_addr_size_in6(struct sockaddr_in6 *addr); 135337085Shselaskyint rdma_addr_size_kss(struct sockaddr_storage *addr); 136331769Shselasky 137331769Shselaskyint rdma_addr_find_l2_eth_by_grh(const union ib_gid *sgid, 138331769Shselasky const union ib_gid *dgid, 139331783Shselasky u8 *smac, struct net_device *dev, 140331769Shselasky int *hoplimit); 141219820Sjeff 142219820Sjeffstatic inline u16 ib_addr_get_pkey(struct rdma_dev_addr *dev_addr) 143219820Sjeff{ 144219820Sjeff return ((u16)dev_addr->broadcast[8] << 8) | (u16)dev_addr->broadcast[9]; 145219820Sjeff} 146219820Sjeff 147219820Sjeffstatic inline void ib_addr_set_pkey(struct rdma_dev_addr *dev_addr, u16 pkey) 148219820Sjeff{ 149219820Sjeff dev_addr->broadcast[8] = pkey >> 8; 150219820Sjeff dev_addr->broadcast[9] = (unsigned char) pkey; 151219820Sjeff} 152219820Sjeff 153219820Sjeffstatic inline void ib_addr_get_mgid(struct rdma_dev_addr *dev_addr, 154219820Sjeff union ib_gid *gid) 155219820Sjeff{ 156219820Sjeff memcpy(gid, dev_addr->broadcast + 4, sizeof *gid); 157219820Sjeff} 158219820Sjeff 159219820Sjeffstatic inline int rdma_addr_gid_offset(struct rdma_dev_addr *dev_addr) 160219820Sjeff{ 161219820Sjeff return dev_addr->dev_type == ARPHRD_INFINIBAND ? 4 : 0; 162219820Sjeff} 163219820Sjeff 164219820Sjeffstatic inline u16 rdma_vlan_dev_vlan_id(const struct net_device *dev) 165219820Sjeff{ 166219820Sjeff uint16_t tag; 167219820Sjeff 168338612Shselasky if (dev->if_type == IFT_ETHER && dev->if_pcp != IFNET_PCP_NONE) 169337078Shselasky return 0x0000; /* prio-tagged traffic */ 170219820Sjeff if (VLAN_TAG(__DECONST(struct ifnet *, dev), &tag) != 0) 171219820Sjeff return 0xffff; 172219820Sjeff return tag; 173219820Sjeff} 174219820Sjeff 175331769Shselaskystatic inline int rdma_ip2gid(const struct sockaddr *addr, union ib_gid *gid) 176219820Sjeff{ 177278886Shselasky switch (addr->sa_family) { 178278886Shselasky case AF_INET: 179331769Shselasky ipv6_addr_set_v4mapped(((const struct sockaddr_in *) 180331769Shselasky addr)->sin_addr.s_addr, 181278886Shselasky (struct in6_addr *)gid); 182278886Shselasky break; 183278886Shselasky case AF_INET6: 184331769Shselasky memcpy(gid->raw, &((const struct sockaddr_in6 *)addr)->sin6_addr, 16); 185325600Shselasky /* make sure scope ID gets zeroed inside GID */ 186325600Shselasky if (IN6_IS_SCOPE_LINKLOCAL((struct in6_addr *)gid->raw) || 187325600Shselasky IN6_IS_ADDR_MC_INTFACELOCAL((struct in6_addr *)gid->raw)) { 188325600Shselasky gid->raw[2] = 0; 189325600Shselasky gid->raw[3] = 0; 190325600Shselasky } 191278886Shselasky break; 192278886Shselasky default: 193278886Shselasky return -EINVAL; 194278886Shselasky } 195278886Shselasky return 0; 196278886Shselasky} 197219820Sjeff 198278886Shselasky/* Important - sockaddr should be a union of sockaddr_in and sockaddr_in6 */ 199331769Shselaskystatic inline void rdma_gid2ip(struct sockaddr *out, const union ib_gid *gid) 200278886Shselasky{ 201331769Shselasky if (ipv6_addr_v4mapped((const struct in6_addr *)gid)) { 202278886Shselasky struct sockaddr_in *out_in = (struct sockaddr_in *)out; 203278886Shselasky memset(out_in, 0, sizeof(*out_in)); 204278886Shselasky out_in->sin_len = sizeof(*out_in); 205278886Shselasky out_in->sin_family = AF_INET; 206278886Shselasky memcpy(&out_in->sin_addr.s_addr, gid->raw + 12, 4); 207278886Shselasky } else { 208278886Shselasky struct sockaddr_in6 *out_in = (struct sockaddr_in6 *)out; 209278886Shselasky memset(out_in, 0, sizeof(*out_in)); 210298486Shselasky out_in->sin6_len = sizeof(*out_in); 211278886Shselasky out_in->sin6_family = AF_INET6; 212278886Shselasky memcpy(&out_in->sin6_addr.s6_addr, gid->raw, 16); 213219820Sjeff } 214278886Shselasky} 215219820Sjeff 216278886Shselaskystatic inline void iboe_addr_get_sgid(struct rdma_dev_addr *dev_addr, 217278886Shselasky union ib_gid *gid) 218278886Shselasky{ 219331769Shselasky struct net_device *dev; 220331769Shselasky struct ifaddr *ifa; 221331769Shselasky 222338557Shselasky#ifdef VIMAGE 223338557Shselasky if (dev_addr->net == NULL) 224338557Shselasky return; 225338557Shselasky#endif 226338557Shselasky dev = dev_get_by_index(dev_addr->net, dev_addr->bound_dev_if); 227331769Shselasky if (dev) { 228331769Shselasky TAILQ_FOREACH(ifa, &dev->if_addrhead, ifa_link) { 229331769Shselasky if (ifa->ifa_addr == NULL || 230331769Shselasky ifa->ifa_addr->sa_family != AF_INET) 231331769Shselasky continue; 232331769Shselasky ipv6_addr_set_v4mapped(((struct sockaddr_in *) 233331769Shselasky ifa->ifa_addr)->sin_addr.s_addr, 234331769Shselasky (struct in6_addr *)gid); 235331769Shselasky break; 236331769Shselasky } 237331769Shselasky dev_put(dev); 238331769Shselasky } 239219820Sjeff} 240219820Sjeff 241219820Sjeffstatic inline void rdma_addr_get_sgid(struct rdma_dev_addr *dev_addr, union ib_gid *gid) 242219820Sjeff{ 243219820Sjeff if (dev_addr->transport == RDMA_TRANSPORT_IB && 244219820Sjeff dev_addr->dev_type != ARPHRD_INFINIBAND) 245219820Sjeff iboe_addr_get_sgid(dev_addr, gid); 246219820Sjeff else 247219820Sjeff memcpy(gid, dev_addr->src_dev_addr + 248219820Sjeff rdma_addr_gid_offset(dev_addr), sizeof *gid); 249219820Sjeff} 250219820Sjeff 251219820Sjeffstatic inline void rdma_addr_set_sgid(struct rdma_dev_addr *dev_addr, union ib_gid *gid) 252219820Sjeff{ 253219820Sjeff memcpy(dev_addr->src_dev_addr + rdma_addr_gid_offset(dev_addr), gid, sizeof *gid); 254219820Sjeff} 255219820Sjeff 256219820Sjeffstatic inline void rdma_addr_get_dgid(struct rdma_dev_addr *dev_addr, union ib_gid *gid) 257219820Sjeff{ 258219820Sjeff memcpy(gid, dev_addr->dst_dev_addr + rdma_addr_gid_offset(dev_addr), sizeof *gid); 259219820Sjeff} 260219820Sjeff 261219820Sjeffstatic inline void rdma_addr_set_dgid(struct rdma_dev_addr *dev_addr, union ib_gid *gid) 262219820Sjeff{ 263219820Sjeff memcpy(dev_addr->dst_dev_addr + rdma_addr_gid_offset(dev_addr), gid, sizeof *gid); 264219820Sjeff} 265219820Sjeff 266219820Sjeffstatic inline enum ib_mtu iboe_get_mtu(int mtu) 267219820Sjeff{ 268219820Sjeff /* 269219820Sjeff * reduce IB headers from effective IBoE MTU. 28 stands for 270219820Sjeff * atomic header which is the biggest possible header after BTH 271219820Sjeff */ 272219820Sjeff mtu = mtu - IB_GRH_BYTES - IB_BTH_BYTES - 28; 273219820Sjeff 274219820Sjeff if (mtu >= ib_mtu_enum_to_int(IB_MTU_4096)) 275219820Sjeff return IB_MTU_4096; 276219820Sjeff else if (mtu >= ib_mtu_enum_to_int(IB_MTU_2048)) 277219820Sjeff return IB_MTU_2048; 278219820Sjeff else if (mtu >= ib_mtu_enum_to_int(IB_MTU_1024)) 279219820Sjeff return IB_MTU_1024; 280219820Sjeff else if (mtu >= ib_mtu_enum_to_int(IB_MTU_512)) 281219820Sjeff return IB_MTU_512; 282219820Sjeff else if (mtu >= ib_mtu_enum_to_int(IB_MTU_256)) 283219820Sjeff return IB_MTU_256; 284219820Sjeff else 285219820Sjeff return 0; 286219820Sjeff} 287219820Sjeff 288219820Sjeffstatic inline int iboe_get_rate(struct net_device *dev) 289219820Sjeff{ 290331769Shselasky uint64_t baudrate = dev->if_baudrate; 291331769Shselasky#ifdef if_baudrate_pf 292331769Shselasky int exp; 293331769Shselasky for (exp = dev->if_baudrate_pf; exp > 0; exp--) 294331769Shselasky baudrate *= 10; 295331769Shselasky#endif 296331769Shselasky if (baudrate >= IF_Gbps(40)) 297219820Sjeff return IB_RATE_40_GBPS; 298331769Shselasky else if (baudrate >= IF_Gbps(30)) 299219820Sjeff return IB_RATE_30_GBPS; 300331769Shselasky else if (baudrate >= IF_Gbps(20)) 301219820Sjeff return IB_RATE_20_GBPS; 302331769Shselasky else if (baudrate >= IF_Gbps(10)) 303219820Sjeff return IB_RATE_10_GBPS; 304219820Sjeff else 305219820Sjeff return IB_RATE_PORT_CURRENT; 306219820Sjeff} 307219820Sjeff 308219820Sjeffstatic inline int rdma_link_local_addr(struct in6_addr *addr) 309219820Sjeff{ 310278886Shselasky if (addr->s6_addr32[0] == htonl(0xfe800000) && 311219820Sjeff addr->s6_addr32[1] == 0) 312219820Sjeff return 1; 313219820Sjeff 314219820Sjeff return 0; 315219820Sjeff} 316219820Sjeff 317219820Sjeffstatic inline void rdma_get_ll_mac(struct in6_addr *addr, u8 *mac) 318219820Sjeff{ 319219820Sjeff memcpy(mac, &addr->s6_addr[8], 3); 320219820Sjeff memcpy(mac + 3, &addr->s6_addr[13], 3); 321219820Sjeff mac[0] ^= 2; 322219820Sjeff} 323219820Sjeff 324219820Sjeffstatic inline int rdma_is_multicast_addr(struct in6_addr *addr) 325219820Sjeff{ 326337076Shselasky __be32 ipv4_addr; 327337076Shselasky 328337076Shselasky if (addr->s6_addr[0] == 0xff) 329337076Shselasky return 1; 330337076Shselasky 331337076Shselasky ipv4_addr = addr->s6_addr32[3]; 332337076Shselasky return (ipv6_addr_v4mapped(addr) && ipv4_is_multicast(ipv4_addr)); 333219820Sjeff} 334219820Sjeff 335219820Sjeffstatic inline void rdma_get_mcast_mac(struct in6_addr *addr, u8 *mac) 336219820Sjeff{ 337219820Sjeff int i; 338219820Sjeff 339219820Sjeff mac[0] = 0x33; 340219820Sjeff mac[1] = 0x33; 341219820Sjeff for (i = 2; i < 6; ++i) 342219820Sjeff mac[i] = addr->s6_addr[i + 10]; 343219820Sjeff} 344219820Sjeff 345219820Sjeffstatic inline u16 rdma_get_vlan_id(union ib_gid *dgid) 346219820Sjeff{ 347219820Sjeff u16 vid; 348219820Sjeff 349219820Sjeff vid = dgid->raw[11] << 8 | dgid->raw[12]; 350331769Shselasky return vid < 0x1000 ? vid : 0xffff; 351219820Sjeff} 352219820Sjeff 353337078Shselaskystatic inline struct net_device *rdma_vlan_dev_real_dev(struct net_device *dev) 354219820Sjeff{ 355338612Shselasky if (dev->if_type == IFT_ETHER && dev->if_pcp != IFNET_PCP_NONE) 356337078Shselasky return dev; /* prio-tagged traffic */ 357219820Sjeff return VLAN_TRUNKDEV(__DECONST(struct ifnet *, dev)); 358219820Sjeff} 359219820Sjeff 360219820Sjeff#endif /* IB_ADDR_H */ 361