#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include "ofi.h"
#include "ofi_osd.h"
#include <net/if.h>
#include <sys/types.h>
#include <linux/ethtool.h>
#include <linux/sockios.h>
#include <sys/ioctl.h>
#include <inttypes.h>
static size_t ofi_base_page_size;
static unsigned long ofi_smaps_page_size(FILE *file)
{
int n;
unsigned long size = ofi_base_page_size;
char buf[1024];
while (fgets(buf, sizeof(buf), file) != NULL) {
if (!strstr(buf, "KernelPageSize:"))
continue;
n = sscanf(buf, "%*s %lu", &size);
if (n < 1)
continue;
size = size * 1024;
break;
}
return size;
}
ssize_t ofi_get_addr_page_size(const void *addr)
{
pid_t pid;
ssize_t ret;
FILE *file;
char buf[1024];
pid = getpid();
snprintf(buf, sizeof(buf), "/proc/%d/smaps", pid);
if (!ofi_base_page_size) {
ret = ofi_sysconf(_SC_PAGESIZE);
if (ret < 0) {
FI_WARN(&core_prov, FI_LOG_CORE,
"ofi_sysconf(_SC_PAGESIZE) failed: %d:%s\n", -errno,
strerror(errno));
return -FI_EINVAL;
}
ofi_base_page_size = ret;
}
file = fopen(buf, "re");
if (!file)
return ofi_base_page_size;
ret = ofi_base_page_size;
while (fgets(buf, sizeof(buf), file) != NULL) {
int n;
uintptr_t range_start, range_end;
n = sscanf(buf, "%" SCNxPTR "-%" SCNxPTR, &range_start,
&range_end);
if (n < 2)
continue;
if ((uintptr_t) addr >= range_start && (uintptr_t) addr < range_end) {
ret = ofi_smaps_page_size(file);
break;
}
}
fclose(file);
return ret;
}
ssize_t ofi_get_hugepage_size(void)
{
FILE *fd;
char *line = NULL;
size_t len = 0;
ssize_t val = -1;
fd = fopen("/proc/meminfo", "r");
if (!fd)
return -errno;
while (getline(&line, &len, fd) != -1)
if (sscanf(line, "Hugepagesize: %zi kB", &val) == 1)
break;
free(line);
fclose(fd);
if (val == -1)
return -FI_ENOENT;
return val * 1024;
}
#ifdef HAVE_ETHTOOL
#if HAVE_DECL_ETHTOOL_CMD_SPEED
static inline uint32_t ofi_ethtool_cmd_speed(struct ethtool_cmd *ecmd)
{
return ethtool_cmd_speed(ecmd);
}
#else
static inline uint32_t ofi_ethtool_cmd_speed(struct ethtool_cmd *ecmd)
{
return ecmd->speed;
}
#endif
#if HAVE_DECL_SPEED_UNKNOWN
static inline int ofi_ethtool_is_known(uint32_t speed_mbps)
{
return (speed_mbps != SPEED_UNKNOWN);
}
#else
static inline int ofi_ethtool_is_known(uint32_t speed_mbps)
{
return ((speed_mbps != 0) && ((uint16_t)speed_mbps != (uint16_t)-1));
}
#endif
static inline size_t ofi_ethtool_get_speed(struct ethtool_cmd *ecmd)
{
uint32_t speed_mbps = ofi_ethtool_cmd_speed(ecmd);
return (ofi_ethtool_is_known(speed_mbps) ? speed_mbps : 100);
}
size_t ofi_ifaddr_get_speed(struct ifaddrs *ifa)
{
struct ethtool_cmd cmd = {
.cmd = ETHTOOL_GSET,
};
struct ifreq ifr = {
.ifr_data = (void *)&cmd,
};
SOCKET fd;
int ret;
fd = socket(ifa->ifa_addr->sa_family, SOCK_STREAM, IPPROTO_IP);
if (fd < 0)
return 0;
strncpy(ifr.ifr_name, ifa->ifa_name, sizeof(ifr.ifr_name) - 1);
ret = ioctl(fd, SIOCETHTOOL, &ifr);
if (ret) {
close(fd);
return 0;
}
close(fd);
return ofi_ethtool_get_speed(&cmd);
}
#else
size_t ofi_ifaddr_get_speed(struct ifaddrs *ifa)
{
FILE *fd;
char *line = NULL;
size_t len = 0;
char *speed_filename_prefix = "/sys/class/net/";
char *speed_filename_suffix = "/speed";
char *speed_filename;
size_t speed;
size_t filename_len = strlen(speed_filename_prefix) +
strlen(speed_filename_prefix) +
IF_NAMESIZE;
speed_filename = calloc(1, filename_len);
if (!speed_filename)
return 0;
snprintf(speed_filename, filename_len, "%s%s%s",
speed_filename_prefix, ifa->ifa_name, speed_filename_suffix);
fd = fopen(speed_filename, "r");
if (!fd)
goto err1;
if (getline(&line, &len, fd) == -1) {
goto err2;
}
if (sscanf(line, "%zu", &speed) != 1)
goto err3;
free(line);
fclose(fd);
free(speed_filename);
return speed;
err3:
free(line);
err2:
fclose(fd);
err1:
free(speed_filename);
return 0;
}
#endif