Skip to content

Commit

Permalink
Merge branch 'network-ng' into network-ng-rename_any_interface
Browse files Browse the repository at this point in the history
* network-ng:
  use type from data if provided
  fix testsuite
  fix rubocop
  Refactoring in type detector / interface file
  Renamed INFINIBANDCHILD -> INFINIBAND_CHILD
  Happy rubocop
  Adapted testsuite
  Use TypeDetector in the interfaces reader
  Converted necessary part of reading iface config from NetworkInterfaces
  Class for interface type detection.
  Relax dependency on LanItems in HwInfo class
  • Loading branch information
imobachgs committed Aug 28, 2019
2 parents 8ef72a6 + b06d273 commit b4a9090
Show file tree
Hide file tree
Showing 12 changed files with 427 additions and 164 deletions.
6 changes: 6 additions & 0 deletions src/lib/y2network/hwinfo.rb
Expand Up @@ -21,6 +21,12 @@
require "y2network/driver"

module Y2Network
class HardwareWrapper
def initialize
Yast.include self, "network/routines.rb"
end
end

# Stores useful (from networking POV) items of hwinfo for an interface
# FIXME: decide whether it should read hwinfo (on demand or at once) for a network
# device and store only necessary info or just parse provided hash
Expand Down
16 changes: 16 additions & 0 deletions src/lib/y2network/interface_type.rb
Expand Up @@ -111,6 +111,8 @@ def method_missing(method_name, *arguments, &block)
WIRELESS = new(N_("Wireless"), "wlan")
# Infiniband card
INFINIBAND = new(N_("Infiniband"), "ib")
# Infiniband card child device. Used in IPoIB (IP-over-InfiniBand)
INFINIBAND_CHILD = new(N_("Infiniband Child"), "ibchild")
# Bonding device
BONDING = new(N_("Bonding"), "bond")
# bridge device
Expand All @@ -136,5 +138,19 @@ def method_missing(method_name, *arguments, &block)
CTC = new(N_("CTC"), "ctc")
# FICON-attached direct access storage devices. s390 specific
FICON = new(N_("FICON"), "ficon")
# Point-to-Point Protocol
PPP = new(N_("Point-to-Point Protocol"), "ppp")
# Ip in Ip protocol
IPIP = new(N_("Ip-in-ip"), "ipip")
# IPv6 Tunnel interface
IPV6TNL = new(N_("IPv6 Tunnel"), "ip6tnl")
# IPv6 over IPv4
SIT = new(N_("IPv6 over IPv4 Tunnel"), "sit")
# IP over IPv4
GRE = new(N_("IP over IPv4 Tunnel"), "gre")
# Infrared
IRDA = new(N_("Infrared"), "irda")
# Loopback
LO = new(N_("Loopback"), "lo")
end
end
78 changes: 60 additions & 18 deletions src/lib/y2network/sysconfig/interface_file.rb
Expand Up @@ -284,6 +284,10 @@ def variable_name(param_name)

## BONDING

# @!attribute [r] bonding_master
# @return [String] whether the interface is a bond device or not
define_variable(:bonding_master)

# @!attribute [r] bonding_slaves
# @return [Hash] Bonding slaves
define_collection_variable(:bonding_slave)
Expand Down Expand Up @@ -368,11 +372,15 @@ def save

# Determines the interface's type
#
# @todo Borrow logic from https://github.com/yast/yast-yast2/blob/6f7a789d00cd03adf62e00da34720f326f0e0633/library/network/src/modules/NetworkInterfaces.rb#L291
#
# @return [Y2Network::InterfaceType] Interface's type depending on the file values
# @return [Y2Network::InterfaceType] Interface's type depending on the configuration
# If particular type cannot be recognized, then
# ETHERNET is returned (same default as in wicked)
def type
type_from_keys || type_from_values || InterfaceType::ETHERNET
type_by_key_value ||
type_by_key_existence ||
type_from_interfacetype ||
type_by_name ||
InterfaceType::ETHERNET
end

# Empties all known values
Expand All @@ -394,25 +402,59 @@ def remove

private

# Determines the Interface type based on specific values
# Detects interface type according to type specific option and its value
#
# @return [Y2Network::InterfaceType, nil]
def type_from_values
return InterfaceType::DUMMY if interfacetype == "dummy"
# @return [Y2Network::InterfaceType, nil] particular type if recognized, nil otherwise
def type_by_key_value
return InterfaceType::BONDING if bonding_master == "yes"
return InterfaceType::BRIDGE if bridge == "yes"
# TODO: Add support for ip-tunnels
return InterfaceType::TUN if tunnel == "tun"
return InterfaceType::TAP if tunnel == "tap"
return InterfaceType.from_short_name(tunnel) if tunnel

# in relation to original implementation ommited ENCAP option which leads to isdn
# and PPPMODE which leads to ppp. Neither of this type has been handled as
# "netcard" - see Yast::NetworkInterfaces for details

nil
end

KEY_TO_TYPE = {
"ETHERDEVICE" => InterfaceType::VLAN,
"WIRELESS_MODE" => InterfaceType::WIRELESS,
"MODEM_DEVICE" => InterfaceType::PPP
}.freeze

# Detects interface type according to type specific option
#
# @return [Y2Network::InterfaceType, nil] particular type if recognized, nil otherwise
def type_by_key_existence
key = KEY_TO_TYPE.keys.find { |k| defined_variables.include?(k) }
return KEY_TO_TYPE[key] if key

nil
end

# Determines the Interface type based on defined variables
# Detects interface type according to sysconfig's INTERFACETYPE option
#
# This option is kind of special that it deserve own method mostly for documenting
# that it should almost never be used. Only meaningful cases for its usage is
# dummy device definition and loopback device (when an additional to standard ifcfg-lo
# is defined)
#
# @return [Y2Network::InterfaceType, nil] type according to INTERFACETYPE option
# value if recognized, nil otherwise
def type_from_interfacetype
return InterfaceType.from_short_name(interfacetype) if interfacetype
nil
end

# Distinguishes interface type by its name
#
# The only case should be loopback device with special name (in sysconfig) "lo"
#
# @return [Y2Network::InterfaceType, nil]
def type_from_keys
return InterfaceType::BONDING if defined_variables.any? { |k| k.start_with?("BOND") }
return InterfaceType::WIRELESS if defined_variables.any? { |k| k.start_with?("WIRELESS") }
return InterfaceType::VLAN if defined_variables.include? "ETHERDEVICE"
return InterfaceType::INFINIBAND if defined_variables.include? "IPOIB_MODE"
# @return [Y2Network::InterfaceType, nil] InterfaceType::LO or nil if not loopback
def type_by_name
InterfaceType::LO if interface == "lo"
nil
end

# Returns a list of those keys that have a value
Expand Down
16 changes: 2 additions & 14 deletions src/lib/y2network/sysconfig/interfaces_reader.rb
Expand Up @@ -26,10 +26,10 @@
require "y2network/sysconfig/connection_config_reader"
require "y2network/interfaces_collection"
require "y2network/connection_configs_collection"
require "y2network/sysconfig/type_detector"
require "y2network/udev_rule"

Yast.import "LanItems"
Yast.import "NetworkInterfaces"

module Y2Network
module Sysconfig
Expand Down Expand Up @@ -111,27 +111,15 @@ def find_connections

# Instantiates an interface given a hash containing hardware details
#
# If there is not information about the type, it will rely on NetworkInterfaces#GetTypeFromSysfs.
# This responsability could be moved to the PhysicalInterface class.
#
# @todo Improve detection logic according to NetworkInterfaces#GetTypeFromIfcfgOrName.
#
# @param data [Hash] hardware information
# @option data [String] "dev_name" Device name ("eth0")
# @option data [String] "name" Device description
# @option data [String] "type" Device type ("eth", "wlan", etc.)
def build_physical_interface(data)
Y2Network::PhysicalInterface.new(data["dev_name"]).tap do |iface|
iface.description = data["name"]
type = data["type"] || Yast::NetworkInterfaces.GetTypeFromSysfs(iface.name)
iface.renaming_mechanism = renaming_mechanism_for(iface.name)
iface.type = case type
when nil then InterfaceType::ETHERNET
when ::String then InterfaceType.from_short_name(type)
when InterfaceType then type
else
raise "Unexpected value in interface type #{type.class.inspect}:#{type.inspect}"
end
iface.type = InterfaceType.from_short_name(data["type"]) || TypeDetector.type_of(iface.name)
end
end

Expand Down
42 changes: 42 additions & 0 deletions src/lib/y2network/sysconfig/type_detector.rb
@@ -0,0 +1,42 @@
# Copyright (c) [2019] SUSE LLC
#
# All Rights Reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of version 2 of the GNU General Public License as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, contact SUSE LLC.
#
# To contact SUSE LLC about this file by physical or electronic mail, you may
# find current contact information at www.suse.com.

require "yast"
require "y2network/interface_type"
require "y2network/type_detector"
require "y2network/sysconfig/interface_file"

module Y2Network
module Sysconfig
# Detects type of given interface. New implementation of what was in
# @see Yast::NetworkInterfaces.GetType
class TypeDetector < Y2Network::TypeDetector
class << self
private

# Checks wheter iface type can be recognized by interface configuration
def type_by_config(iface)
iface_file = Y2Network::Sysconfig::InterfaceFile.find(iface)
iface_file.load
iface_file.type
end
end
end
end
end
141 changes: 141 additions & 0 deletions src/lib/y2network/type_detector.rb
@@ -0,0 +1,141 @@
# Copyright (c) [2019] SUSE LLC
#
# All Rights Reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of version 2 of the GNU General Public License as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, contact SUSE LLC.
#
# To contact SUSE LLC about this file by physical or electronic mail, you may
# find current contact information at www.suse.com.

require "yast"
require "y2network/interface_type"

module Y2Network
# Detects type of given interface. New implementation of what was in
# @see Yast::NetworkInterfaces.GetType
class TypeDetector
class << self
# Finds type of given interface
#
# @param iface [String] interface name
#
# @return [Y2Network::InterfaceType, nil] type of given interface or nil if cannot be recognized
def type_of(iface)
type_by_sys(iface) || type_by_config(iface) || nil
end

private

include Yast::Logger

SYS_TYPE_NUMBERS = {
"1" => InterfaceType::ETHERNET,
"24" => InterfaceType::ETHERNET,
"32" => InterfaceType::INFINIBAND,
"512" => InterfaceType::PPP,
"768" => InterfaceType::IPIP,
"769" => InterfaceType::IPV6TNL,
"772" => InterfaceType::LO,
"776" => InterfaceType::SIT,
"778" => InterfaceType::GRE,
"783" => InterfaceType::IRDA,
"801" => InterfaceType::WIRELESS, # wlan_aux if needed later
"65534" => InterfaceType::TUN
}.freeze

# Checks wheter iface type can be recognized by /sys filesystem
#
# @param iface [String] interface name
# @return [Y2Network::InterfaceType, nil] nil when type can be recognized in /sys,
# interface type otherwise
def type_by_sys(iface)
raise ArgumentError, "An interface has to be given." if iface.nil?

type_dir_path = "/sys/class/net/#{iface}/type"
return nil if !::File.exist?(type_dir_path)

sys_type = Yast::SCR.Read(Yast::Path.new(".target.string"), type_dir_path).to_s.strip
type = SYS_TYPE_NUMBERS[sys_type]

# finer detection for some types
type = case type
when InterfaceType::ETHERNET
eth_type_by_sys(iface)
when InterfaceType::INFINIBAND
ib_type_by_sys(iface)
end

log.info("TypeDetector: #{iface} is of #{type} type according to /sys")

type
end

# Detects a subtype of Ethernet device type according /sys or /proc content
#
# @example
# eth_type_by_sys("eth0") -> Ethernet
# eth_type_by_sys("bond0") -> Bonding
#
# @param iface [String] interface name
# @return [Y2Network::InterfaceType] interface type
def eth_type_by_sys(iface)
sys_dir_path = "/sys/class/net/#{iface}"

if ::File.exist?("#{sys_dir_path}/wireless")
InterfaceType::WIRELESS
elsif ::File.exist?("#{sys_dir_path}/phy80211")
InterfaceType::WIRELESS
elsif ::File.exist?("#{sys_dir_path}/bridge")
InterfaceType::BRIDGE
elsif ::File.exist?("#{sys_dir_path}/bonding")
InterfaceType::BONDING
elsif ::File.exist?("#{sys_dir_path}/tun_flags")
InterfaceType::TUN
elsif ::File.exist?("/proc/net/vlan/#{iface}")
InterfaceType::VLAN
elsif ::File.exist?("/sys/devices/virtual/net/#{iface}") && iface =~ /dummy/
InterfaceType::DUMMY
else
InterfaceType::ETHERNET
end
end

# Detects a subtype of InfiniBand device type according /sys
#
# @example
# ib_type_by_sys("ib0") -> Infiniband
# ib_type_by_sys("bond0") -> Bonding
# ib_type_by_sys("ib0.8001") -> Infiniband child
#
# @param iface [String] interface name
# @return [Y2Network::InterfaceType] interface type
def ib_type_by_sys(iface)
sys_dir_path = "/sys/class/net/#{iface}"

if ::File.exist?("#{sys_dir_path}/bonding")
InterfaceType::BONDING
elsif ::File.exist?("#{sys_dir_path}/create_child")
InterfaceType::INFINIBAND
else
InterfaceType::INFINIBAND_CHILD
end
end

# Checks wheter iface type can be recognized by interface configuration
def type_by_config(_iface)
# this part is backend specific
raise NotImplementedError
end
end
end
end

0 comments on commit b4a9090

Please sign in to comment.