Class: Y2Network::UdevRule

Inherits:
Object
  • Object
show all
Defined in:
src/lib/y2network/udev_rule.rb

Overview

Simple udev rule class

This class represents a network udev rule. The current implementation is quite simplistic, featuring a an API which is tailored to our needs.

Basically, udev rules are kept in two different files under /etc/udev/rules.d:

  • 70-persistent-net.rules ('net' group): rules to assign names to interfaces.
  • 79-yast2-drivers.rules ('drivers' group): rules to assign drivers to interfaces.

This class offers a set of constructors to build different kinds of rules. See UdevRule.new_mac_based_rename, UdevRule.new_bus_id_based_rename and UdevRule.new_driver_assignment.

When it comes to write rules to the filesystem, we decided to offer different methods to write to each file. See UdevRule.write_net_rules and UdevRule.write_drivers_rules.

Examples:

Create a rule containing some key/value pairs (rule part)

rule = Y2Network::UdevRule.new(
  Y2Network::UdevRulePart.new("ATTR{address}", "==", "?*31:78:f2"),
  Y2Network::UdevRulePart.new("NAME", "=", "mlx4_ib3")
)
rule.to_s #=> "ACTION==\"add\", SUBSYSTEM==\"net\", ATTR{address}==\"?*31:78:f2\", NAME=\"eth0\""

Create a rule from a string

rule = UdevRule.find_for("eth0")
rule.to_s #=> "ACTION==\"add\", SUBSYSTEM==\"net\", ATTR{address}==\"?*31:78:f2\", NAME=\"eth0\""

Writing renaming rules

rule = UdevRule.new_mac_based_rename("00:12:34:56:78:ab", "eth0")
UdevRule.write_net_rules([rule])

Writing driver assignment rules

rule = UdevRule.new_driver_assignment("virtio:d00000001v00001AF4", "virtio_net")
UdevRule.write_drivers_rules([rule])

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(parts = []) ⇒ UdevRule

Constructor


201
202
203
# File 'src/lib/y2network/udev_rule.rb', line 201

def initialize(parts = [])
  @parts = parts
end

Instance Attribute Details

#partsArray<UdevRulePart> (readonly)


196
197
198
# File 'src/lib/y2network/udev_rule.rb', line 196

def parts
  @parts
end

Class Method Details

.allArray<UdevRule>

Returns all persistent network rules


63
64
65
# File 'src/lib/y2network/udev_rule.rb', line 63

def all
  naming_rules + drivers_rules
end

.drivers_rulesArray<UdevRule>

Returns driver rules


77
78
79
# File 'src/lib/y2network/udev_rule.rb', line 77

def drivers_rules
  find_rules(:drivers)
end

.find_for(device) ⇒ UdevRule

Returns the udev rule for a given device

Only the naming rules are considered.


87
88
89
# File 'src/lib/y2network/udev_rule.rb', line 87

def find_for(device)
  naming_rules.find { |r| r.device == device }
end

.naming_rulesArray<UdevRule>

Returns naming rules


70
71
72
# File 'src/lib/y2network/udev_rule.rb', line 70

def naming_rules
  find_rules(:net)
end

.new_bus_id_based_rename(name, bus_id, dev_port = nil) ⇒ Object

Helper method to create a rename rule based on the BUS ID


115
116
117
118
119
120
# File 'src/lib/y2network/udev_rule.rb', line 115

def new_bus_id_based_rename(name, bus_id, dev_port = nil)
  parts = [UdevRulePart.new("KERNELS", "==", bus_id)]
  parts << UdevRulePart.new("ATTR{dev_port}", "==", dev_port) if dev_port
  parts << UdevRulePart.new("NAME", "=", name)
  new_network_rule(parts)
end

.new_driver_assignment(modalias, driver_name) ⇒ UdevRule

Returns a module assignment rule


146
147
148
149
150
151
152
# File 'src/lib/y2network/udev_rule.rb', line 146

def new_driver_assignment(modalias, driver_name)
  parts = [
    UdevRulePart.new("ENV{MODALIAS}", "==", modalias),
    UdevRulePart.new("ENV{MODALIAS}", "=", driver_name)
  ]
  new(parts)
end

.new_mac_based_rename(name, mac) ⇒ Object

Helper method to create a rename rule based on a MAC address


95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'src/lib/y2network/udev_rule.rb', line 95

def new_mac_based_rename(name, mac)
  new_network_rule(
    [
      # Guard to not try to rename everything with the same MAC address (e.g. vlan devices
      # inherit the MAC address from the underlying device).
      # FIXME: it won't work when using predictable network names (openSUSE)
      # UdevRulePart.new("KERNEL", "==", "eth*"),
      # The port number of a NIC where the ports share the same hardware device.
      UdevRulePart.new("ATTR{dev_id}", "==", "0x0"),
      UdevRulePart.new("ATTR{address}", "==", mac),
      UdevRulePart.new("NAME", "=", name)
    ]
  )
end

.new_network_rule(parts = []) ⇒ UdevRule

Returns a network rule

The network rule includes some parts by default.


128
129
130
131
132
133
134
135
136
137
138
139
# File 'src/lib/y2network/udev_rule.rb', line 128

def new_network_rule(parts = [])
  base_parts = [
    UdevRulePart.new("SUBSYSTEM", "==", "net"),
    UdevRulePart.new("ACTION", "==", "add"),
    UdevRulePart.new("DRIVERS", "==", "?*"),
    # Ethernet devices
    # https://github.com/torvalds/linux/blob/bb7ba8069de933d69cb45dd0a5806b61033796a3/include/uapi/linux/if_arp.h#L31
    # TODO: what about InfiniBand (it is type 32)?
    UdevRulePart.new("ATTR{type}", "==", "1")
  ]
  new(base_parts.concat(parts))
end

.reset_cacheObject

Clears rules cache map


178
179
180
# File 'src/lib/y2network/udev_rule.rb', line 178

def reset_cache
  @all = nil
end

.write_drivers_rules(udev_rules) ⇒ Object

Writes drivers specific udev rules to the filesystem

Those rules that does not have an MODALIAS part will be ignored.


167
168
169
170
171
172
173
174
175
# File 'src/lib/y2network/udev_rule.rb', line 167

def write_drivers_rules(udev_rules)
  rules_hash = udev_rules.each_with_object({}) do |rule, hash|
    driver = rule.part_value_for("ENV{MODALIAS}", "=")
    next unless driver
    hash[driver] = rule.parts.map(&:to_s)
  end
  Yast::SCR.Write(Yast::Path.new(".udev_persistent.drivers"), rules_hash)
  Yast::SCR.Write(Yast::Path.new(".udev_persistent.nil"), []) # Writes changes to the rules file
end

.write_net_rules(udev_rules) ⇒ Object

Writes udev rules to the filesystem


157
158
159
160
# File 'src/lib/y2network/udev_rule.rb', line 157

def write_net_rules(udev_rules)
  Yast::SCR.Write(Yast::Path.new(".udev_persistent.rules"), udev_rules.map(&:to_s))
  Yast::SCR.Write(Yast::Path.new(".udev_persistent.nil"), []) # Writes changes to the rules file
end

Instance Method Details

#add_part(key, operator, value) ⇒ Object

Adds a part to the rule


210
211
212
# File 'src/lib/y2network/udev_rule.rb', line 210

def add_part(key, operator, value)
  @parts << UdevRulePart.new(key, operator, value)
end

#bus_idString?

Returns the BUS ID in the udev rule

See Also:


252
253
254
# File 'src/lib/y2network/udev_rule.rb', line 252

def bus_id
  part_value_for("KERNELS")
end

#dev_portString?

Returns the device port in the udev rule

See Also:


260
261
262
# File 'src/lib/y2network/udev_rule.rb', line 260

def dev_port
  part_value_for("ATTR{dev_port}")
end

#deviceString?

Returns the device mentioned in the rule (if any)


267
268
269
# File 'src/lib/y2network/udev_rule.rb', line 267

def device
  part_value_for("NAME", "=")
end

#driverString?

Returns the modalias


281
282
283
# File 'src/lib/y2network/udev_rule.rb', line 281

def driver
  part_value_for("ENV{MODALIAS}", "=")
end

#macString?

Returns the MAC in the udev rule

See Also:


244
245
246
# File 'src/lib/y2network/udev_rule.rb', line 244

def mac
  part_value_for("ATTR{address}")
end

#original_modaliasString?

Returns the original modalias


274
275
276
# File 'src/lib/y2network/udev_rule.rb', line 274

def original_modalias
  part_value_for("ENV{MODALIAS}", "==")
end

#part_by_key(key, operator = nil) ⇒ Object

Returns the part with the given key


225
226
227
# File 'src/lib/y2network/udev_rule.rb', line 225

def part_by_key(key, operator = nil)
  parts.find { |p| p.key == key && (operator.nil? || p.operator == operator) }
end

#part_value_for(key, operator = nil) ⇒ String?

Returns the value for a given part


234
235
236
237
238
# File 'src/lib/y2network/udev_rule.rb', line 234

def part_value_for(key, operator = nil)
  part = part_by_key(key, operator)
  return nil unless part
  part.value
end

#to_sString

Returns an string representation that can be used in a rules file


217
218
219
# File 'src/lib/y2network/udev_rule.rb', line 217

def to_s
  parts.map(&:to_s).join(", ")
end