From 77bffa1159156742c8103c9574b5e8af2854a624 Mon Sep 17 00:00:00 2001 From: Gaurav Mehta Date: Mon, 2 Dec 2024 21:05:45 +1100 Subject: [PATCH] The PR improves nic filtering when iscsi sessions are detected. With this change, in case a vlan interface is used for an iscsi session, then the parent interface is filtered from the list of interfaces and is no longer visible in the list of interfaces If there is no iscsi session then the behaviour of the installer remains unchanged. --- pkg/console/network.go | 74 ++++++++++++++++++++++++++++++------------ 1 file changed, 54 insertions(+), 20 deletions(-) diff --git a/pkg/console/network.go b/pkg/console/network.go index 68bf2090e..fc7937ee7 100644 --- a/pkg/console/network.go +++ b/pkg/console/network.go @@ -127,7 +127,7 @@ func upAllLinks() error { } func getNICs() ([]netlink.Link, error) { - var nics []netlink.Link + var nics, vlanNics []netlink.Link links, err := netlink.LinkList() if err != nil { @@ -138,9 +138,24 @@ func getNICs() ([]netlink.Link, error) { if l.Type() == "device" && l.Attrs().EncapType != "loopback" { nics = append(nics, l) } + if l.Type() == "vlan" { + vlanNics = append(vlanNics, l) + } + } + + iscsi := goiscsi.NewLinuxISCSI(nil) + sessions, err := iscsi.GetSessions() + if err != nil { + return nil, fmt.Errorf("error querying iscsi sessions: %v", err) } - return filterISCSIInterfaces(nics) + // no iscsi sessions detected so no additional filtering based on usage for iscsi device + // access is needed and we can break here + if len(sessions) == 0 { + return nics, nil + } + + return filterISCSIInterfaces(nics, vlanNics, sessions) } func getNICState(name string) int { @@ -196,25 +211,47 @@ func getManagementInterfaceName(mgmtInterface config.Network) string { // filterISCSIInterfaces will query the host to identify iscsi sessions, and skip interfaces // used by the existing iscsi session. -func filterISCSIInterfaces(links []netlink.Link) ([]netlink.Link, error) { - iscsi := goiscsi.NewLinuxISCSI(nil) - sessions, err := iscsi.GetSessions() - if err != nil { - return nil, fmt.Errorf("error querying iscsi sessions: %v", err) +func filterISCSIInterfaces(nics, vlanNics []netlink.Link, sessions []goiscsi.ISCSISession) ([]netlink.Link, error) { + hwDeviceMap := make(map[string]netlink.Link) + for _, v := range nics { + hwDeviceMap[v.Attrs().HardwareAddr.String()] = v } - var returnLinks []netlink.Link + // temporary sessionMap to make it easy to correlate interface addressses with session ip address + // should speed up identification of interfaces in use with iscsi sessions + sessionMap := make(map[string]string) + for _, session := range sessions { + sessionMap[session.IfaceIPaddress] = "" + } + + if err := filterNICSBySession(hwDeviceMap, nics, sessionMap); err != nil { + return nil, err + } + + if err := filterNICSBySession(hwDeviceMap, vlanNics, sessionMap); err != nil { + return nil, err + } + logrus.Debugf("identified following iscsi sessions: %v", sessionMap) + // we need to filter the filteredNics to also isolate parent nics if a vlan if is in use + returnedNics := make([]netlink.Link, 0, len(hwDeviceMap)) + for _, v := range hwDeviceMap { + returnedNics = append(returnedNics, v) + } + return returnedNics, nil +} + +func filterNICSBySession(hwDeviceMap map[string]netlink.Link, links []netlink.Link, sessionMap map[string]string) error { for _, link := range links { - var inuse bool + logrus.Debugf("checking if link %s is in use", link.Attrs().Name) if getNICState(link.Attrs().Name) == NICStateUP { iface, err := net.InterfaceByName(link.Attrs().Name) if err != nil { - return nil, fmt.Errorf("error fetching interface details: %v", err) + return fmt.Errorf("error fetching interface details: %v", err) } addresses, err := iface.Addrs() if err != nil { - return nil, fmt.Errorf("error fetching addresses from interface: %v", err) + return fmt.Errorf("error fetching addresses from interface: %v", err) } for _, address := range addresses { @@ -222,18 +259,15 @@ func filterISCSIInterfaces(links []netlink.Link) ([]netlink.Link, error) { // since iscsi session contains just the ip address ipAddress, _, err := net.ParseCIDR(address.String()) if err != nil { - return nil, fmt.Errorf("error parsing ip address: %v", err) + return fmt.Errorf("error parsing ip address: %v", err) } - for _, session := range sessions { - if session.IfaceIPaddress == ipAddress.String() { - inuse = true - } + if _, ok := sessionMap[ipAddress.String()]; ok { + logrus.Debugf("filtering interface %s", link.Attrs().Name) + delete(hwDeviceMap, link.Attrs().HardwareAddr.String()) + break //device is already removed, no point checking for other addresses } } } - if !inuse { - returnLinks = append(returnLinks, link) - } } - return returnLinks, nil + return nil }