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

move get_ib_* functions to cloudinit.distros.networking #2003

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
84 changes: 82 additions & 2 deletions cloudinit/distros/networking.py
@@ -1,6 +1,8 @@
import abc
import logging
import os
import re
from functools import lru_cache
from typing import List, Optional

from cloudinit import net, subp, util
Expand Down Expand Up @@ -59,12 +61,33 @@ def get_devicelist(self) -> list:
return net.get_devicelist()

def get_ib_hwaddrs_by_interface(self) -> dict:
return net.get_ib_hwaddrs_by_interface()
"""Build a dictionary mapping Infiniband interface names to their
hardware address."""
ret = {}
for name, _, _, _ in self.get_interfaces():
ib_mac = self.get_ib_interface_hwaddr(name, False)
if ib_mac is not None and ib_mac in ret:
raise RuntimeError(
"duplicate mac found! both '%s' and '%s' have mac '%s'"
% (name, ret[ib_mac], ib_mac)
)
ret[name] = ib_mac
return ret

def get_ib_interface_hwaddr(
self, devname: DeviceName, ethernet_format: bool
):
return net.get_ib_interface_hwaddr(devname, ethernet_format)
"""Returns the string value of an Infiniband interface's hardware
address. If ethernet_format is True, an Ethernet MAC-style 6 byte
representation of the address will be returned.
"""
# Type 32 is Infiniband.
if net.read_sys_net_safe(devname, "type") == "32":
mac = self.get_interface_mac(devname)
if mac and ethernet_format:
# Use bytes 13-15 and 18-20 of the hardware address.
mac = mac[36:-14] + mac[51:]
return mac

def get_interface_mac(self, devname: DeviceName):
return net.get_interface_mac(devname)
Expand Down Expand Up @@ -260,6 +283,63 @@ def is_renamed(self, devname: DeviceName) -> bool:
return True
return False

def get_ib_interface_hwaddr(
self, devname: DeviceName, ethernet_format: bool
):
"""Returns the string value of an Infiniband interface's hardware
address. If ethernet_format is True, an Ethernet MAC-style 6 byte
representation of the address will be returned.
"""
# Type 32 is Infiniband.
ib = self.get_ib_interfaces()
if devname in ib:
mac = self.get_interface_mac(devname)
if mac and ethernet_format:
# Use bytes 13-15 and 18-20 of the hardware address.
mac = mac[36:-14] + mac[51:]
return mac

def get_ib_hwaddrs_by_interface(self) -> dict:
"""Build a dictionary mapping Infiniband interface names to their
hardware address."""
ret = {}
for dev, guid in self.get_ib_interfaces():
ib_mac = self.get_ib_interface_hwaddr(dev, False)
if ib_mac is not None and ib_mac in ret:
raise RuntimeError(
"duplicate mac found! both '%s' and '%s' have mac '%s'"
% (dev, ret[ib_mac], ib_mac)
)
ret[dev] = ib_mac
return ret

@lru_cache()
def get_ib_interfaces(self) -> dict:
"""Build a dictionary mapping Infiniband interface names to their
hardware address."""
try:
out, _ = subp.subp(["ibv_devices"])
except subp.ProcessExecutionError:
return {}

# The format from ibv_devices starts as follows:
#
# printf(" %-16s\t node GUID\n", "device");
# printf(" %-16s\t----------------\n", "------");
#
# that's the part we need to skip, and then this is the part we need to
# parse:
#
# printf(" %-16s\t%016llx\n",
# ibv_get_device_name(dev_list[i]),
# (unsigned long long)
# be64toh(ibv_get_device_guid(dev_list[i])));

for num, line in enumerate(out.split("\n")):
if num < 2 or re.fullmatch(r"""\s*""", line):
continue
device, guid = line.split()


class LinuxNetworking(Networking):
"""Implementation of networking functionality common to Linux distros."""
Expand Down
13 changes: 13 additions & 0 deletions cloudinit/distros/parsers/ifconfig.py
Expand Up @@ -32,6 +32,7 @@ def __init__(self, name):
self.inet = {}
self.inet6 = {}
self.up = False
self.infiniband = False
self.options = []
self.nd6 = []
self.flags = []
Expand Down Expand Up @@ -160,6 +161,11 @@ def parse(self, text: str) -> Dict[str, Union[Ifstate, List[Ifstate]]]:
if toks[0] == "hwaddr":
dev.macs.append(toks[1])
ifs_by_mac[toks[1]].append(dev)
if toks[0] == "lladdr":
if len(toks[1].split(".")) == 20:
dev.infiniband = True
dev.macs.append(toks[1])
ifs_by_mac[toks[1]].append(dev)

if toks[0] == "groups:":
dev.groups += toks[1:]
Expand Down Expand Up @@ -200,6 +206,13 @@ def parse(self, text: str) -> Dict[str, Union[Ifstate, List[Ifstate]]]:
def ifs_by_mac(self):
return self._ifs_by_mac

def get_ib_interfaces(self):
return {
k: v
for (k, v) in self._ifs_by_name.items()
if v.infiniband is True
}

def _parse_inet(self, toks: list) -> Tuple[str, dict]:
broadcast = None
if "/" in toks[1]:
Expand Down
34 changes: 1 addition & 33 deletions cloudinit/net/__init__.py
Expand Up @@ -700,7 +700,7 @@ def _get_current_rename_info(check_downable=True):
}}
"""
cur_info = {}
for (name, mac, driver, device_id) in get_interfaces():
for name, mac, driver, device_id in get_interfaces():
cur_info[name] = {
"downable": None,
"device_id": device_id,
Expand Down Expand Up @@ -733,7 +733,6 @@ def _get_current_rename_info(check_downable=True):
def _rename_interfaces(
renames, strict_present=True, strict_busy=True, current_info=None
):

if not len(renames):
LOG.debug("no interfaces to rename")
return
Expand Down Expand Up @@ -899,20 +898,6 @@ def get_interface_mac(ifname):
return read_sys_net_safe(ifname, path)


def get_ib_interface_hwaddr(ifname, ethernet_format):
"""Returns the string value of an Infiniband interface's hardware
address. If ethernet_format is True, an Ethernet MAC-style 6 byte
representation of the address will be returned.
"""
# Type 32 is Infiniband.
if read_sys_net_safe(ifname, "type") == "32":
mac = get_interface_mac(ifname)
if mac and ethernet_format:
# Use bytes 13-15 and 18-20 of the hardware address.
mac = mac[36:-14] + mac[51:]
return mac


def get_interfaces_by_mac(blacklist_drivers=None) -> dict:
if util.is_FreeBSD() or util.is_DragonFlyBSD():
return get_interfaces_by_mac_on_freebsd(
Expand Down Expand Up @@ -1065,7 +1050,6 @@ def get_interfaces_by_mac_on_linux(blacklist_drivers=None) -> dict:
# TODO: move this format to openstack
ib_mac = get_ib_interface_hwaddr(name, True)
if ib_mac:

# If an Ethernet mac address happens to collide with a few bits in
# an IB GUID, prefer the ethernet address.
#
Expand Down Expand Up @@ -1141,22 +1125,6 @@ def get_interfaces(blacklist_drivers=None) -> list:
return ret


def get_ib_hwaddrs_by_interface():
"""Build a dictionary mapping Infiniband interface names to their hardware
address."""
ret = {}
for name, _, _, _ in get_interfaces():
ib_mac = get_ib_interface_hwaddr(name, False)
if ib_mac:
if ib_mac in ret:
raise RuntimeError(
"duplicate mac found! both '%s' and '%s' have mac '%s'"
% (name, ret[ib_mac], ib_mac)
)
ret[name] = ib_mac
return ret


def has_url_connectivity(url_data: Dict[str, Any]) -> bool:
"""Return true when the instance has access to the provided URL.

Expand Down
10 changes: 9 additions & 1 deletion tests/data/netinfo/freebsd-ifconfig-output
Expand Up @@ -38,4 +38,12 @@ lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> metric 0 mtu 16384
inet6 fe80::1%lo0 prefixlen 64 scopeid 0x2
inet 127.0.0.1 netmask 0xff000000
groups: lo
nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>
nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>
ib0: flags=8002<BROADCAST,MULTICAST> metric 0 mtu 4092
options=8009b<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING,VLAN_HWCSUM,LINKSTATE>
lladdr 0.0.1.5.fe.80.0.0.0.0.0.0.b8.59.9f.3.0.ec.56.cc
nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
ib1: flags=8002<BROADCAST,MULTICAST> metric 0 mtu 4092
options=8009b<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING,VLAN_HWCSUM,LINKSTATE>
lladdr 0.0.9.5.fe.80.0.0.0.0.0.0.b8.59.9f.3.0.ec.56.cd
nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
15 changes: 15 additions & 0 deletions tests/unittests/distros/test_ifconfig.py
Expand Up @@ -33,6 +33,21 @@ def test_description(self):
ifs = Ifconfig().parse(self.ifs_txt)
assert ifs["vnet0:11"].description == "'associated with jail: webirc'"

def test_infiniband(self):
"""assert ib0 is infiniband and has GUID as MAC"""
ifs = Ifconfig().parse(self.ifs_txt)
assert ifs["ib0"].infiniband is True
assert (
ifs["ib0"].macs[0]
== "0.0.1.5.fe.80.0.0.0.0.0.0.b8.59.9f.3.0.ec.56.cc"
)

def test_get_ib_interfaces(self):
"""assert that Ifconfig.get_ib_interfaces returns ib0 and ib1"""
ifc = Ifconfig()
ifc.parse(self.ifs_txt)
assert list(ifc.get_ib_interfaces().keys()) == ["ib0", "ib1"]

def test_vtnet_options(self):
"""assert vtnet has TXCSUM"""
ifs = Ifconfig().parse(self.ifs_txt)
Expand Down