Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

issue: 569177 use netlink to define alias interface base name #179

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/vma/dev/net_device_table_mgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ int net_device_table_mgr::map_net_devices()
}

bool valid = false;

char base_ifname[IFNAMSIZ];
get_base_interface_name((const char*)(ifa->ifa_name), base_ifname, sizeof(base_ifname));
if (check_device_exist(base_ifname, BOND_DEVICE_FILE)) {
Expand Down
2 changes: 0 additions & 2 deletions src/vma/dev/net_device_val.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -737,9 +737,7 @@ void net_device_val_eth::configure(struct ifaddrs* ifa, struct rdma_cm_id* cma_i
nd_logpanic("m_p_L2_addr allocation error");
}
BULLSEYE_EXCLUDE_BLOCK_END

create_br_address(m_name.c_str());

m_vlan = get_vlan_id_from_ifname(m_name.c_str());
if (m_vlan && m_bond != NO_BOND && m_bond_fail_over_mac == 1) {
vlog_printf(VLOG_WARNING, " ******************************************************************\n");
Expand Down
207 changes: 144 additions & 63 deletions src/vma/util/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,14 @@
#include <sys/resource.h>
#include <string.h>
#include <iostream>
#include <list>
#include "vma/util/if.h"
#include <sys/stat.h>
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
#include <linux/sockios.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <math.h>
#include <linux/ip.h> //IP header (struct iphdr) definition
#include <netinet/udp.h>
Expand Down Expand Up @@ -84,6 +87,7 @@ int get_sys_max_fd_num(int def_max_fd /*=1024*/)
return def_max_fd;
}

//keep order of checks
int get_base_interface_name(const char *if_name, char *base_ifname, size_t sz_base_ifname)
{
BULLSEYE_EXCLUDE_BLOCK_START
Expand All @@ -93,70 +97,25 @@ int get_base_interface_name(const char *if_name, char *base_ifname, size_t sz_ba
BULLSEYE_EXCLUDE_BLOCK_END
memset(base_ifname, 0, sz_base_ifname);

if (get_vlan_base_name_from_ifname(if_name, base_ifname, sz_base_ifname)) {
//bond
if (check_device_exist(if_name, BOND_DEVICE_FILE)) {
snprintf(base_ifname, sz_base_ifname, "%s" ,if_name);
return 0;
}

//Am I already the base (not virtual, not alias, can be bond)
if ((!check_device_exist(if_name, VIRTUAL_DEVICE_FOLDER) ||
check_device_exist(if_name, BOND_DEVICE_FILE)) && !strstr(if_name, ":")) {
//vlan
if (check_device_exist(if_name, VIRTUAL_DEVICE_FOLDER) && get_vlan_base_name_from_ifname(if_name, base_ifname, sz_base_ifname)) {
return 0;
}
//pysical interface or bond
if (check_device_exist(if_name, FLAGS_PARAM_FILE)) {
snprintf(base_ifname, sz_base_ifname, "%s" ,if_name);
return 0;
}

unsigned char vlan_if_address[MAX_L2_ADDR_LEN];
const size_t ADDR_LEN = get_local_ll_addr(if_name, vlan_if_address, MAX_L2_ADDR_LEN, false);
if (ADDR_LEN > 0) {
struct ifaddrs *ifaddr, *ifa;
int rc = getifaddrs(&ifaddr);
BULLSEYE_EXCLUDE_BLOCK_START
if (rc == -1) {
__log_err("getifaddrs failed");
return -1;
}
BULLSEYE_EXCLUDE_BLOCK_END

for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
if (!strcmp(ifa->ifa_name, if_name)) {
continue;
}
if (ifa->ifa_flags & IFF_SLAVE) {
//bond slave
continue;
}

if (strstr(ifa->ifa_name, ":")) {
//alias
continue;
}

if (check_device_exist(ifa->ifa_name, VIRTUAL_DEVICE_FOLDER)) {
//virtual
if (!check_device_exist(ifa->ifa_name, BOND_DEVICE_FILE)) {
continue;
}
}

unsigned char tmp_mac[ADDR_LEN];
if (ADDR_LEN == get_local_ll_addr(ifa->ifa_name, tmp_mac, ADDR_LEN, false)) {
int size_to_compare;
if (ADDR_LEN == ETH_ALEN) size_to_compare = ETH_ALEN;
else size_to_compare = IPOIB_HW_ADDR_GID_LEN;
int offset = ADDR_LEN - size_to_compare;
if (0 == memcmp(vlan_if_address + offset, tmp_mac + offset, size_to_compare)) {
snprintf(base_ifname, sz_base_ifname, "%s" ,ifa->ifa_name);
freeifaddrs(ifaddr);
__log_dbg("Found base_ifname %s for interface %s", base_ifname, if_name);
return 0;
}
}
}

freeifaddrs(ifaddr);
//alias
if(get_alias_base_name_from_ifname(if_name, base_ifname, sz_base_ifname)) {
return 0;
}
snprintf(base_ifname, sz_base_ifname, "%s" ,if_name);
__log_dbg("no base for %s", base_ifname, if_name);
return 0;
return -1;
}

unsigned short compute_ip_checksum(const unsigned short *buf, unsigned int nshort_words)
Expand Down Expand Up @@ -749,6 +708,126 @@ size_t get_vlan_base_name_from_ifname(const char* ifname, char* base_ifname, siz
return 0;
}

size_t get_alias_base_name_from_ifname(const char* ifname, char* base_ifname, size_t sz_base_ifname)
{
int ret;
//create netlink socket
int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (sock < 0) {
__log_dbg("could not open netlink socket (%d %m)", errno);
return 0;
}
struct sockaddr_nl snl;
memset(&snl, 0, sizeof(snl));
snl.nl_family = AF_NETLINK;
snl.nl_pid = getpid();
if (bind(sock, (struct sockaddr *)&snl, sizeof(snl)) < 0) {
__log_dbg("could not bind netlink socket (%d %m)", errno);
close(sock);
return 0;
}

struct
{
struct nlmsghdr nlh;
struct rtgenmsg g;
} req;

//prepare request header
memset(&req, 0, sizeof(req));
req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
req.nlh.nlmsg_type = RTM_GETADDR;//RTM_GETLINK;
req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
req.nlh.nlmsg_seq = 1;
req.nlh.nlmsg_pid = getpid();
req.g.rtgen_family = AF_PACKET;

struct sockaddr_nl kernel;
struct msghdr rtnl_msg;
struct iovec io;
memset(&rtnl_msg, 0, sizeof(rtnl_msg));
memset(&kernel, 0, sizeof(kernel));

kernel.nl_family = AF_NETLINK;
io.iov_base = &req;
io.iov_len = req.nlh.nlmsg_len;
rtnl_msg.msg_iov = &io;
rtnl_msg.msg_iovlen = 1;
rtnl_msg.msg_name = &kernel;
rtnl_msg.msg_namelen = sizeof(kernel);

ret = sendmsg(sock, (struct msghdr *) &rtnl_msg, 0);
if (ret < 0) {
__log_dbg("error sending netlink request (%d %m)", errno);
close(sock);
return 0;
}

unsigned char buffer[4096];
struct nlmsghdr *msg_ptr;
struct msghdr rtnl_reply;
struct iovec io_reply;

memset(&io_reply, 0, sizeof(io_reply));
memset(&rtnl_reply, 0, sizeof(rtnl_reply));

io.iov_base = buffer;
io.iov_len = 10*1024;
rtnl_reply.msg_iov = &io;
rtnl_reply.msg_iovlen = 1;
rtnl_reply.msg_name = &kernel;
rtnl_reply.msg_namelen = sizeof(kernel);
ret = recvmsg(sock, &rtnl_reply, 0); /* read lots of data */
if (ret < 0) {
__log_dbg("error receiving netlink data (%d %m)", errno);
close(sock);
return 0;
}

typedef std::pair<char*, int> int_index;
list<int_index> interface_index_list;
int my_index = -1;
for (msg_ptr = (struct nlmsghdr *) buffer; NLMSG_OK(msg_ptr, (unsigned short)ret) && msg_ptr->nlmsg_type!= NLMSG_DONE; msg_ptr = NLMSG_NEXT(msg_ptr, ret)) {
if (msg_ptr->nlmsg_type == RTM_NEWADDR) {
struct ifaddrmsg *iface;
struct rtattr *attribute;
int len;

iface = (struct ifaddrmsg *)NLMSG_DATA(msg_ptr);
len = msg_ptr->nlmsg_len - NLMSG_LENGTH(sizeof(*iface));
//save interface and it's index in map
for (attribute = IFLA_RTA(iface); RTA_OK(attribute, len); attribute = RTA_NEXT(attribute, len)) {
if(attribute->rta_type == IFA_LABEL) {
char* attr_name = (char*)RTA_DATA(attribute);
int_index elem;
elem.first = attr_name;
elem.second = iface->ifa_index;
interface_index_list.push_back(elem);
//interface_index_list.add()[if_name] = iface->ifa_index;
if (strcmp(attr_name, ifname) == 0) {
my_index = iface->ifa_index;
}
}
}
}
}

//find a physical or bond interface that has the same index as me
size_t name_size = 0;
list<int_index>::iterator interface_index_iter;
for (interface_index_iter=interface_index_list.begin(); interface_index_iter!=interface_index_list.end(); interface_index_iter++) {
if ((interface_index_iter->second == my_index) && strcmp(interface_index_iter->first, ifname) != 0) {
//check that this isn't another alias
if (check_device_exist(interface_index_iter->first, FLAGS_PARAM_FILE)) {
snprintf(base_ifname, sz_base_ifname, "%s" ,interface_index_iter->first);
name_size = strlen(interface_index_iter->first);
}
}
}
close(sock);
return name_size;
}

#if _BullseyeCoverage
#pragma BullseyeCoverage off
#endif
Expand Down Expand Up @@ -946,12 +1025,14 @@ size_t get_local_ll_addr(IN const char * ifname, OUT unsigned char* addr, IN int
{
char l2_addr_path[256] = {0};
char buf[256] = {0};

// In case of alias (ib0/eth0:xx) take only the device name for that interface (ib0/eth0)
size_t ifname_len = strcspn(ifname, ":"); // TODO: this is temp code till we get base interface for any alias format of an interface
const char * l2_addr_path_fmt = is_broadcast ? L2_BR_ADDR_FILE_FMT : L2_ADDR_FILE_FMT;
snprintf(l2_addr_path, sizeof(l2_addr_path)-1, l2_addr_path_fmt, ifname_len, ifname);

char base_ifname[32];
size_t ifname_len = get_alias_base_name_from_ifname(ifname, base_ifname, sizeof base_ifname);
if (ifname_len > 0) {
snprintf(l2_addr_path, sizeof(l2_addr_path)-1, l2_addr_path_fmt, ifname_len, base_ifname);
} else {
snprintf(l2_addr_path, sizeof(l2_addr_path)-1, l2_addr_path_fmt, strlen(ifname), ifname);
}
int len = priv_read_file(l2_addr_path, buf, sizeof(buf));
int bytes_len = (len + 1) / 3; // convert len from semantic of hex format L2 address with ':' delimiter (and optional newline character) into semantic of byte array
__log_dbg("ifname=%s un-aliased-ifname=%.*s l2_addr_path=%s l2-addr=%s (addr-bytes_len=%d)", ifname, ifname_len, ifname, l2_addr_path, buf, bytes_len);
Expand Down
11 changes: 11 additions & 0 deletions src/vma/util/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,17 @@ uint16_t get_vlan_id_from_ifname(const char* ifname);
*/
size_t get_vlan_base_name_from_ifname(const char* ifname, char* base_ifname, size_t sz_base_ifname);

/**
* Get alias base name from interface name
*
* @param ifname input interface name of device (e.g. eth2, eth2.5)
* @param base_ifname output base interface name of device (e.g. eth2)
* @param sz_base_ifname input the size of base_ifname param
* @return the alias base name length or 0 if not found
*/

size_t get_alias_base_name_from_ifname(const char* ifname, char* base_ifname, size_t sz_base_ifname);

/**
* Get peer node IPoIB QP number (remote_qpn) from the peer's IP
* address
Expand Down