beegfs/client_module/source/common/net/sock/NetworkInterfaceCard.c
2025-08-10 01:34:16 +02:00

262 lines
6.4 KiB
C

#include <common/net/sock/RDMASocket.h>
#include <common/net/sock/StandardSocket.h>
#include <common/net/sock/NetworkInterfaceCard.h>
#include <common/toolkit/ListTk.h>
#include <linux/if_arp.h>
#include <linux/in.h>
#include <linux/inetdevice.h>
#include <net/sock.h>
#define NIC_STRING_LEN 1024
static bool __NIC_fillNicAddress(struct net_device* dev, NicAddrType_t nicType,
NicAddress* outAddr);
void NIC_findAll(StrCpyList* allowedInterfaces, bool useRDMA, bool onlyRDMA,
NicAddressList* outList)
{
// find standard TCP/IP interfaces
__NIC_findAllTCP(allowedInterfaces, outList);
// find RDMA interfaces (based on TCP/IP interfaces query results)
if(useRDMA && RDMASocket_rdmaDevicesExist() )
{
NicAddressList tcpInterfaces;
NicAddressList_init(&tcpInterfaces);
__NIC_findAllTCP(allowedInterfaces, &tcpInterfaces);
__NIC_filterInterfacesForRDMA(&tcpInterfaces, outList);
ListTk_kfreeNicAddressListElems(&tcpInterfaces);
NicAddressList_uninit(&tcpInterfaces);
}
if (onlyRDMA)
{
NicAddressListIter nicIter;
NicAddressListIter_init(&nicIter, outList);
while (!NicAddressListIter_end(&nicIter))
{
NicAddress* nicAddr = NicAddressListIter_value(&nicIter);
if (nicAddr->nicType != NICADDRTYPE_RDMA)
{
nicIter = NicAddressListIter_remove(&nicIter);
kfree(nicAddr);
}
else
NicAddressListIter_next(&nicIter);
}
}
}
void __NIC_findAllTCP(StrCpyList* allowedInterfaces, NicAddressList* outList)
{
struct net_device *dev;
// find standard TCP/IP interfaces
// foreach network device
for (dev = first_net_device(&init_net); dev; dev = next_net_device(dev))
{
NicAddress* nicAddr = (NicAddress*)os_kmalloc(sizeof(NicAddress) );
ssize_t metricByListPos = 0;
if(!nicAddr)
{
printk_fhgfs(KERN_WARNING, "%s:%d: memory allocation failed. size: %zu\n",
__func__, __LINE__, sizeof(*nicAddr) );
return;
}
if(__NIC_fillNicAddress(dev, NICADDRTYPE_STANDARD, nicAddr) &&
(!StrCpyList_length(allowedInterfaces) ||
ListTk_listContains(nicAddr->name, allowedInterfaces, &metricByListPos) ) )
{
NicAddressList_append(outList, nicAddr);
}
else
{ // netdevice rejected => clean up
kfree(nicAddr);
}
}
}
bool __NIC_fillNicAddress(struct net_device* dev, NicAddrType_t nicType, NicAddress* outAddr)
{
struct ifreq ifr;
struct in_device* in_dev;
struct in_ifaddr *ifa;
#ifdef BEEGFS_RDMA
outAddr->ibdev = NULL;
#endif
// name
strncpy(outAddr->name, dev->name, IFNAMSIZ);
// SIOCGIFFLAGS:
// get interface flags
ifr.ifr_flags = dev_get_flags(dev);
if(ifr.ifr_flags & IFF_LOOPBACK)
return false; // loopback interface => skip
ifr.ifr_hwaddr.sa_family = dev->type;
// select which hardware types to process
// (on Linux see /usr/include/linux/if_arp.h for the whole list)
switch(ifr.ifr_hwaddr.sa_family)
{
case ARPHRD_LOOPBACK:
return false;
default:
break;
}
// copy nicType
outAddr->nicType = nicType;
// ip address
// note: based on inet_gifconf in /net/ipv4/devinet.c
in_dev = __in_dev_get_rtnl(dev);
if(!in_dev)
{
printk_fhgfs_debug(KERN_NOTICE, "found interface without in_dev: %s\n", dev->name);
return false;
}
ifa = in_dev->ifa_list;
if(!ifa)
{
printk_fhgfs_debug(KERN_NOTICE, "found interface without ifa_list: %s\n", dev->name);
return false;
}
outAddr->ipAddr.s_addr = ifa->ifa_local; // ip address
// code to read multiple addresses
/*
for (; ifa; ifa = ifa->ifa_next)
{
(*(struct sockaddr_in *)&ifr.ifr_addr).sin_family = AF_INET;
(*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr =
ifa->ifa_local;
}
*/
return true;
}
/**
* @return static string (not alloc'ed, so don't free it).
*/
const char* NIC_nicTypeToString(NicAddrType_t nicType)
{
switch(nicType)
{
case NICADDRTYPE_RDMA: return "RDMA";
case NICADDRTYPE_STANDARD: return "TCP";
default: return "<unknown>";
}
}
/**
* @return string will be kalloced and must be kfreed later
*/
char* NIC_nicAddrToString(NicAddress* nicAddr)
{
char* nicAddrStr;
char ipStr[NICADDRESS_IP_STR_LEN];
const char* typeStr;
nicAddrStr = (char*)os_kmalloc(NIC_STRING_LEN);
NicAddress_ipToStr(nicAddr->ipAddr, ipStr);
if(nicAddr->nicType == NICADDRTYPE_RDMA)
typeStr = "RDMA";
else
if(nicAddr->nicType == NICADDRTYPE_STANDARD)
typeStr = "TCP";
else
typeStr = "Unknown";
snprintf(nicAddrStr, NIC_STRING_LEN, "%s[ip addr: %s; type: %s]", nicAddr->name, ipStr, typeStr);
return nicAddrStr;
}
bool NIC_supportsRDMA(NicAddressList* nicList)
{
bool rdmaSupported = false;
NicAddressListIter iter;
NicAddressListIter_init(&iter, nicList);
for( ; !NicAddressListIter_end(&iter); NicAddressListIter_next(&iter) )
{
if(NicAddressListIter_value(&iter)->nicType == NICADDRTYPE_RDMA)
{
rdmaSupported = true;
break;
}
}
return rdmaSupported;
}
void NIC_supportedCapabilities(NicAddressList* nicList, NicListCapabilities* outCapabilities)
{
outCapabilities->supportsRDMA = NIC_supportsRDMA(nicList);
}
/**
* Checks a list of TCP/IP interfaces for RDMA-capable interfaces.
*/
void __NIC_filterInterfacesForRDMA(NicAddressList* nicList, NicAddressList* outList)
{
// Note: This works by binding an RDMASocket to each IP of the passed list.
NicAddressListIter iter;
NicAddressListIter_init(&iter, nicList);
for( ; !NicAddressListIter_end(&iter); NicAddressListIter_next(&iter) )
{
RDMASocket rdmaSock;
Socket* sock = (Socket*)&rdmaSock;
NicAddress* nicAddr = NicAddressListIter_value(&iter);
bool bindRes;
if(!RDMASocket_init(&rdmaSock, nicAddr->ipAddr, NULL) )
continue;
bindRes = sock->ops->bindToAddr(sock, nicAddr->ipAddr, 0);
if(bindRes)
{ // we've got an RDMA-capable interface => append it to outList
NicAddress* nicAddrCopy = os_kmalloc(sizeof(NicAddress) );
*nicAddrCopy = *nicAddr;
#ifdef BEEGFS_RDMA
nicAddrCopy->ibdev = rdmaSock.ibvsock.cm_id->device;
#endif
nicAddrCopy->nicType = NICADDRTYPE_RDMA;
NicAddressList_append(outList, nicAddrCopy);
}
sock->ops->uninit(sock);
}
}