162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2005 Voltaire Inc. All rights reserved. 462306a36Sopenharmony_ci * Copyright (c) 2005 Intel Corporation. All rights reserved. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#ifndef IB_ADDR_H 862306a36Sopenharmony_ci#define IB_ADDR_H 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/ethtool.h> 1162306a36Sopenharmony_ci#include <linux/in.h> 1262306a36Sopenharmony_ci#include <linux/in6.h> 1362306a36Sopenharmony_ci#include <linux/if_arp.h> 1462306a36Sopenharmony_ci#include <linux/netdevice.h> 1562306a36Sopenharmony_ci#include <linux/inetdevice.h> 1662306a36Sopenharmony_ci#include <linux/socket.h> 1762306a36Sopenharmony_ci#include <linux/if_vlan.h> 1862306a36Sopenharmony_ci#include <net/ipv6.h> 1962306a36Sopenharmony_ci#include <net/if_inet6.h> 2062306a36Sopenharmony_ci#include <net/ip.h> 2162306a36Sopenharmony_ci#include <rdma/ib_verbs.h> 2262306a36Sopenharmony_ci#include <rdma/ib_pack.h> 2362306a36Sopenharmony_ci#include <net/net_namespace.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci/** 2662306a36Sopenharmony_ci * struct rdma_dev_addr - Contains resolved RDMA hardware addresses 2762306a36Sopenharmony_ci * @src_dev_addr: Source MAC address. 2862306a36Sopenharmony_ci * @dst_dev_addr: Destination MAC address. 2962306a36Sopenharmony_ci * @broadcast: Broadcast address of the device. 3062306a36Sopenharmony_ci * @dev_type: The interface hardware type of the device. 3162306a36Sopenharmony_ci * @bound_dev_if: An optional device interface index. 3262306a36Sopenharmony_ci * @transport: The transport type used. 3362306a36Sopenharmony_ci * @net: Network namespace containing the bound_dev_if net_dev. 3462306a36Sopenharmony_ci * @sgid_attr: GID attribute to use for identified SGID 3562306a36Sopenharmony_ci */ 3662306a36Sopenharmony_cistruct rdma_dev_addr { 3762306a36Sopenharmony_ci unsigned char src_dev_addr[MAX_ADDR_LEN]; 3862306a36Sopenharmony_ci unsigned char dst_dev_addr[MAX_ADDR_LEN]; 3962306a36Sopenharmony_ci unsigned char broadcast[MAX_ADDR_LEN]; 4062306a36Sopenharmony_ci unsigned short dev_type; 4162306a36Sopenharmony_ci int bound_dev_if; 4262306a36Sopenharmony_ci enum rdma_transport_type transport; 4362306a36Sopenharmony_ci struct net *net; 4462306a36Sopenharmony_ci const struct ib_gid_attr *sgid_attr; 4562306a36Sopenharmony_ci enum rdma_network_type network; 4662306a36Sopenharmony_ci int hoplimit; 4762306a36Sopenharmony_ci}; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci/** 5062306a36Sopenharmony_ci * rdma_translate_ip - Translate a local IP address to an RDMA hardware 5162306a36Sopenharmony_ci * address. 5262306a36Sopenharmony_ci * 5362306a36Sopenharmony_ci * The dev_addr->net field must be initialized. 5462306a36Sopenharmony_ci */ 5562306a36Sopenharmony_ciint rdma_translate_ip(const struct sockaddr *addr, 5662306a36Sopenharmony_ci struct rdma_dev_addr *dev_addr); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci/** 5962306a36Sopenharmony_ci * rdma_resolve_ip - Resolve source and destination IP addresses to 6062306a36Sopenharmony_ci * RDMA hardware addresses. 6162306a36Sopenharmony_ci * @src_addr: An optional source address to use in the resolution. If a 6262306a36Sopenharmony_ci * source address is not provided, a usable address will be returned via 6362306a36Sopenharmony_ci * the callback. 6462306a36Sopenharmony_ci * @dst_addr: The destination address to resolve. 6562306a36Sopenharmony_ci * @addr: A reference to a data location that will receive the resolved 6662306a36Sopenharmony_ci * addresses. The data location must remain valid until the callback has 6762306a36Sopenharmony_ci * been invoked. The net field of the addr struct must be valid. 6862306a36Sopenharmony_ci * @timeout_ms: Amount of time to wait for the address resolution to complete. 6962306a36Sopenharmony_ci * @callback: Call invoked once address resolution has completed, timed out, 7062306a36Sopenharmony_ci * or been canceled. A status of 0 indicates success. 7162306a36Sopenharmony_ci * @resolve_by_gid_attr: Resolve the ip based on the GID attribute from 7262306a36Sopenharmony_ci * rdma_dev_addr. 7362306a36Sopenharmony_ci * @context: User-specified context associated with the call. 7462306a36Sopenharmony_ci */ 7562306a36Sopenharmony_ciint rdma_resolve_ip(struct sockaddr *src_addr, const struct sockaddr *dst_addr, 7662306a36Sopenharmony_ci struct rdma_dev_addr *addr, unsigned long timeout_ms, 7762306a36Sopenharmony_ci void (*callback)(int status, struct sockaddr *src_addr, 7862306a36Sopenharmony_ci struct rdma_dev_addr *addr, void *context), 7962306a36Sopenharmony_ci bool resolve_by_gid_attr, void *context); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_civoid rdma_addr_cancel(struct rdma_dev_addr *addr); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ciint rdma_addr_size(const struct sockaddr *addr); 8462306a36Sopenharmony_ciint rdma_addr_size_in6(struct sockaddr_in6 *addr); 8562306a36Sopenharmony_ciint rdma_addr_size_kss(struct __kernel_sockaddr_storage *addr); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic inline u16 ib_addr_get_pkey(struct rdma_dev_addr *dev_addr) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci return ((u16)dev_addr->broadcast[8] << 8) | (u16)dev_addr->broadcast[9]; 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic inline void ib_addr_set_pkey(struct rdma_dev_addr *dev_addr, u16 pkey) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci dev_addr->broadcast[8] = pkey >> 8; 9562306a36Sopenharmony_ci dev_addr->broadcast[9] = (unsigned char) pkey; 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic inline void ib_addr_get_mgid(struct rdma_dev_addr *dev_addr, 9962306a36Sopenharmony_ci union ib_gid *gid) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci memcpy(gid, dev_addr->broadcast + 4, sizeof *gid); 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic inline int rdma_addr_gid_offset(struct rdma_dev_addr *dev_addr) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci return dev_addr->dev_type == ARPHRD_INFINIBAND ? 4 : 0; 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic inline u16 rdma_vlan_dev_vlan_id(const struct net_device *dev) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci return is_vlan_dev(dev) ? vlan_dev_vlan_id(dev) : 0xffff; 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic inline int rdma_ip2gid(struct sockaddr *addr, union ib_gid *gid) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci switch (addr->sa_family) { 11762306a36Sopenharmony_ci case AF_INET: 11862306a36Sopenharmony_ci ipv6_addr_set_v4mapped(((struct sockaddr_in *) 11962306a36Sopenharmony_ci addr)->sin_addr.s_addr, 12062306a36Sopenharmony_ci (struct in6_addr *)gid); 12162306a36Sopenharmony_ci break; 12262306a36Sopenharmony_ci case AF_INET6: 12362306a36Sopenharmony_ci *(struct in6_addr *)&gid->raw = 12462306a36Sopenharmony_ci ((struct sockaddr_in6 *)addr)->sin6_addr; 12562306a36Sopenharmony_ci break; 12662306a36Sopenharmony_ci default: 12762306a36Sopenharmony_ci return -EINVAL; 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci return 0; 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci/* Important - sockaddr should be a union of sockaddr_in and sockaddr_in6 */ 13362306a36Sopenharmony_cistatic inline void rdma_gid2ip(struct sockaddr *out, const union ib_gid *gid) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci if (ipv6_addr_v4mapped((struct in6_addr *)gid)) { 13662306a36Sopenharmony_ci struct sockaddr_in *out_in = (struct sockaddr_in *)out; 13762306a36Sopenharmony_ci memset(out_in, 0, sizeof(*out_in)); 13862306a36Sopenharmony_ci out_in->sin_family = AF_INET; 13962306a36Sopenharmony_ci memcpy(&out_in->sin_addr.s_addr, gid->raw + 12, 4); 14062306a36Sopenharmony_ci } else { 14162306a36Sopenharmony_ci struct sockaddr_in6 *out_in = (struct sockaddr_in6 *)out; 14262306a36Sopenharmony_ci memset(out_in, 0, sizeof(*out_in)); 14362306a36Sopenharmony_ci out_in->sin6_family = AF_INET6; 14462306a36Sopenharmony_ci memcpy(&out_in->sin6_addr.s6_addr, gid->raw, 16); 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci/* 14962306a36Sopenharmony_ci * rdma_get/set_sgid/dgid() APIs are applicable to IB, and iWarp. 15062306a36Sopenharmony_ci * They are not applicable to RoCE. 15162306a36Sopenharmony_ci * RoCE GIDs are derived from the IP addresses. 15262306a36Sopenharmony_ci */ 15362306a36Sopenharmony_cistatic inline void rdma_addr_get_sgid(struct rdma_dev_addr *dev_addr, union ib_gid *gid) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci memcpy(gid, dev_addr->src_dev_addr + rdma_addr_gid_offset(dev_addr), 15662306a36Sopenharmony_ci sizeof(*gid)); 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_cistatic inline void rdma_addr_set_sgid(struct rdma_dev_addr *dev_addr, union ib_gid *gid) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci memcpy(dev_addr->src_dev_addr + rdma_addr_gid_offset(dev_addr), gid, sizeof *gid); 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic inline void rdma_addr_get_dgid(struct rdma_dev_addr *dev_addr, union ib_gid *gid) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci memcpy(gid, dev_addr->dst_dev_addr + rdma_addr_gid_offset(dev_addr), sizeof *gid); 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic inline void rdma_addr_set_dgid(struct rdma_dev_addr *dev_addr, union ib_gid *gid) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci memcpy(dev_addr->dst_dev_addr + rdma_addr_gid_offset(dev_addr), gid, sizeof *gid); 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic inline enum ib_mtu iboe_get_mtu(int mtu) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci /* 17762306a36Sopenharmony_ci * Reduce IB headers from effective IBoE MTU. 17862306a36Sopenharmony_ci */ 17962306a36Sopenharmony_ci mtu = mtu - (IB_GRH_BYTES + IB_UDP_BYTES + IB_BTH_BYTES + 18062306a36Sopenharmony_ci IB_EXT_XRC_BYTES + IB_EXT_ATOMICETH_BYTES + 18162306a36Sopenharmony_ci IB_ICRC_BYTES); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci if (mtu >= ib_mtu_enum_to_int(IB_MTU_4096)) 18462306a36Sopenharmony_ci return IB_MTU_4096; 18562306a36Sopenharmony_ci else if (mtu >= ib_mtu_enum_to_int(IB_MTU_2048)) 18662306a36Sopenharmony_ci return IB_MTU_2048; 18762306a36Sopenharmony_ci else if (mtu >= ib_mtu_enum_to_int(IB_MTU_1024)) 18862306a36Sopenharmony_ci return IB_MTU_1024; 18962306a36Sopenharmony_ci else if (mtu >= ib_mtu_enum_to_int(IB_MTU_512)) 19062306a36Sopenharmony_ci return IB_MTU_512; 19162306a36Sopenharmony_ci else if (mtu >= ib_mtu_enum_to_int(IB_MTU_256)) 19262306a36Sopenharmony_ci return IB_MTU_256; 19362306a36Sopenharmony_ci else 19462306a36Sopenharmony_ci return 0; 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cistatic inline int rdma_link_local_addr(struct in6_addr *addr) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci if (addr->s6_addr32[0] == htonl(0xfe800000) && 20062306a36Sopenharmony_ci addr->s6_addr32[1] == 0) 20162306a36Sopenharmony_ci return 1; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci return 0; 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic inline void rdma_get_ll_mac(struct in6_addr *addr, u8 *mac) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci memcpy(mac, &addr->s6_addr[8], 3); 20962306a36Sopenharmony_ci memcpy(mac + 3, &addr->s6_addr[13], 3); 21062306a36Sopenharmony_ci mac[0] ^= 2; 21162306a36Sopenharmony_ci} 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_cistatic inline int rdma_is_multicast_addr(struct in6_addr *addr) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci __be32 ipv4_addr; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci if (addr->s6_addr[0] == 0xff) 21862306a36Sopenharmony_ci return 1; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci ipv4_addr = addr->s6_addr32[3]; 22162306a36Sopenharmony_ci return (ipv6_addr_v4mapped(addr) && ipv4_is_multicast(ipv4_addr)); 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cistatic inline void rdma_get_mcast_mac(struct in6_addr *addr, u8 *mac) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci int i; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci mac[0] = 0x33; 22962306a36Sopenharmony_ci mac[1] = 0x33; 23062306a36Sopenharmony_ci for (i = 2; i < 6; ++i) 23162306a36Sopenharmony_ci mac[i] = addr->s6_addr[i + 10]; 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_cistatic inline u16 rdma_get_vlan_id(union ib_gid *dgid) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci u16 vid; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci vid = dgid->raw[11] << 8 | dgid->raw[12]; 23962306a36Sopenharmony_ci return vid < 0x1000 ? vid : 0xffff; 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistatic inline struct net_device *rdma_vlan_dev_real_dev(const struct net_device *dev) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci return is_vlan_dev(dev) ? vlan_dev_real_dev(dev) : NULL; 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci#endif /* IB_ADDR_H */ 248