Class: OsCtld::NetInterface::Veth
- Inherits:
-
NetInterface::Base
- Object
- NetInterface::Base
- OsCtld::NetInterface::Veth
- Includes:
- OsCtl::Lib::Utils::Log, OsCtl::Lib::Utils::System, Utils::Ip, Utils::SwitchUser
- Defined in:
- lib/osctld/net_interface/veth.rb
Instance Attribute Summary collapse
-
#rx_queues ⇒ Integer
readonly
Number of receive queues.
-
#tx_queues ⇒ Integer
readonly
Number of transmit queues.
-
#veth ⇒ Object
readonly
Returns the value of attribute veth.
Instance Method Summary collapse
- #active_ip_versions ⇒ Object
- #add_ip(addr) ⇒ Object
- #create(opts) ⇒ Object
- #del_all_ips(ip_v = nil) ⇒ Object
- #del_ip(addr) ⇒ Object
- #down(host_veth = nil) ⇒ Object
- #dup(new_ct) ⇒ Object
- #fetch_veth_name ⇒ Object protected
- #has_ip?(addr, prefix: true) ⇒ Boolean
- #hook_path(mode, name = nil) ⇒ Object protected
- #ifb_veth ⇒ Object protected
- #ips(v) ⇒ Object
- #is_created? ⇒ Boolean
- #load(cfg) ⇒ Object
-
#load_ip_list(ip_list) {|value| ... } ⇒ Hash<Integer, String>, Hash<Integer, Array<String>>
protected
Take an IP list stored in a config file and return an internal representation, see ##save_ip_list.
- #mode_path(mode) ⇒ Object protected
- #rename(new_name) ⇒ Object
- #render_opts ⇒ Object
- #save ⇒ Object
-
#save_ip_list(ip_list) {|value| ... } ⇒ Hash<String, String>, Hash<String, Array<String>>
protected
Take an internal representation of an IP list and return a version to store in the config file.
- #set(opts) ⇒ Object
- #set_shaper_rx ⇒ Object protected
- #set_shaper_tx ⇒ Object protected
- #setup ⇒ Object
- #unset_shaper_rx ⇒ Object protected
- #unset_shaper_tx ⇒ Object protected
- #up(veth) ⇒ Object
- #veth_hook_dir ⇒ Object protected
Methods included from Utils::SwitchUser
Methods included from Utils::Ip
Instance Attribute Details
#rx_queues ⇒ Integer (readonly)
Number of receive queues
19 20 21 |
# File 'lib/osctld/net_interface/veth.rb', line 19 def rx_queues @rx_queues end |
#tx_queues ⇒ Integer (readonly)
Number of transmit queues
15 16 17 |
# File 'lib/osctld/net_interface/veth.rb', line 15 def tx_queues @tx_queues end |
#veth ⇒ Object (readonly)
Returns the value of attribute veth.
11 12 13 |
# File 'lib/osctld/net_interface/veth.rb', line 11 def veth @veth end |
Instance Method Details
#active_ip_versions ⇒ Object
226 227 228 |
# File 'lib/osctld/net_interface/veth.rb', line 226 def active_ip_versions inclusively { [4, 6].delete_if { |v| @ips[v].empty? } } end |
#add_ip(addr) ⇒ Object
249 250 251 |
# File 'lib/osctld/net_interface/veth.rb', line 249 def add_ip(addr) exclusively { @ips[addr.ipv4? ? 4 : 6] << addr } end |
#create(opts) ⇒ Object
21 22 23 24 25 26 27 |
# File 'lib/osctld/net_interface/veth.rb', line 21 def create(opts) super @tx_queues = opts.fetch(:tx_queues, 1) @rx_queues = opts.fetch(:rx_queues, 1) @ips = { 4 => [], 6 => [] } end |
#del_all_ips(ip_v = nil) ⇒ Object
259 260 261 262 263 264 265 |
# File 'lib/osctld/net_interface/veth.rb', line 259 def del_all_ips(ip_v = nil) exclusively do (ip_v ? [ip_v] : [4, 6]).each do |v| @ips[v].clone.each { |addr| del_ip(addr) } end end end |
#del_ip(addr) ⇒ Object
254 255 256 |
# File 'lib/osctld/net_interface/veth.rb', line 254 def del_ip(addr) exclusively { @ips[addr.ipv4? ? 4 : 6].delete_if { |v| v == addr } } end |
#down(host_veth = nil) ⇒ Object
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 |
# File 'lib/osctld/net_interface/veth.rb', line 190 def down(host_veth = nil) veth_name = host_veth || veth ifb_name = ifb_veth exclusively { @veth = nil } # lxc-user-nic does not support deletion of veth interfaces, delete it ourselves log(:info, ct, "Removing host veth #{veth_name}") begin ip(:all, %W[link del #{veth_name}]) rescue SystemCommandFailed => e log(:warn, ct, "Unable to delete host veth #{veth_name}: #{e.}") end if max_tx > 0 begin ip(:all, %W[link del #{ifb_name}]) rescue SystemCommandFailed => e log(:warn, ct, "Unable to delete ifb host veth #{ifb_name}: #{e.}") end end Eventd.report( :ct_netif, action: :down, pool: ct.pool.name, id: ct.id, name: ) end |
#dup(new_ct) ⇒ Object
267 268 269 270 271 272 |
# File 'lib/osctld/net_interface/veth.rb', line 267 def dup(new_ct) ret = super ret.instance_variable_set('@veth', nil) ret.instance_variable_set('@ips', @ips.transform_values(&:dup)) ret end |
#fetch_veth_name ⇒ Object (protected)
276 277 278 279 280 |
# File 'lib/osctld/net_interface/veth.rb', line 276 def fetch_veth_name v = ContainerControl::Commands::VethName.run!(ct, index) log(:info, ct, "Discovered name for veth ##{index}: #{v}") v end |
#has_ip?(addr, prefix: true) ⇒ Boolean
236 237 238 239 240 241 242 243 244 245 246 |
# File 'lib/osctld/net_interface/veth.rb', line 236 def has_ip?(addr, prefix: true) ip_v = addr.ipv4? ? 4 : 6 exclusively do if prefix @ips[ip_v].include?(addr) else @ips[ip_v].detect { |v| v.to_s == addr.to_s } ? true : false end end end |
#hook_path(mode, name = nil) ⇒ Object (protected)
327 328 329 |
# File 'lib/osctld/net_interface/veth.rb', line 327 def hook_path(mode, name = nil) File.join(mode_path(mode), "#{@ct.id}.#{name || self.name}") end |
#ifb_veth ⇒ Object (protected)
282 283 284 |
# File 'lib/osctld/net_interface/veth.rb', line 282 def ifb_veth "ifb#{veth}" end |
#ips(v) ⇒ Object
230 231 232 |
# File 'lib/osctld/net_interface/veth.rb', line 230 def ips(v) inclusively { @ips[v].clone } end |
#is_created? ⇒ Boolean
222 223 224 |
# File 'lib/osctld/net_interface/veth.rb', line 222 def is_created? inclusively { !veth.nil? } end |
#load(cfg) ⇒ Object
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/osctld/net_interface/veth.rb', line 29 def load(cfg) super @tx_queues = cfg.fetch('tx_queues', 1) @rx_queues = cfg.fetch('rx_queues', 1) @ips = if cfg['ip_addresses'] load_ip_list(cfg['ip_addresses']) do |ips| ips.map { |ip| IPAddress.parse(ip) } end else { 4 => [], 6 => [] } end end |
#load_ip_list(ip_list) {|value| ... } ⇒ Hash<Integer, String>, Hash<Integer, Array<String>> (protected)
Take an IP list stored in a config file and return an internal representation, see ##save_ip_list.
354 355 356 357 358 359 360 361 362 363 364 365 366 367 |
# File 'lib/osctld/net_interface/veth.rb', line 354 def load_ip_list(ip_list) ip_list.to_h do |ip_v, value| # Load also integer keys for backward compatibility if [4, 6].include?(ip_v) [ip_v, yield(value)] elsif /^v(4|6)$/ =~ ip_v [::Regexp.last_match(1).to_i, yield(value)] else raise "unsupported IP version '#{ip_v}': expected v4 or v6" end end end |
#mode_path(mode) ⇒ Object (protected)
323 324 325 |
# File 'lib/osctld/net_interface/veth.rb', line 323 def mode_path(mode) File.join(veth_hook_dir, mode) end |
#rename(new_name) ⇒ Object
143 144 145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/osctld/net_interface/veth.rb', line 143 def rename(new_name) %w[up down].each do |v| begin File.unlink(hook_path(v, name)) rescue Errno::ENOENT # pass end File.symlink(OsCtld.hook_src("veth-#{v}"), hook_path(v, new_name)) end super end |
#render_opts ⇒ Object
157 158 159 160 161 162 163 164 165 166 167 168 169 |
# File 'lib/osctld/net_interface/veth.rb', line 157 def render_opts inclusively do { name:, index:, hwaddr:, tx_queues:, rx_queues:, hook_veth_up: hook_path('up'), hook_veth_down: hook_path('down') } end end |
#save ⇒ Object
45 46 47 48 49 50 51 52 53 |
# File 'lib/osctld/net_interface/veth.rb', line 45 def save inclusively do super.merge( 'tx_queues' => tx_queues, 'rx_queues' => rx_queues, 'ip_addresses' => save_ip_list(@ips) { |v| v.map(&:to_string) } ) end end |
#save_ip_list(ip_list) {|value| ... } ⇒ Hash<String, String>, Hash<String, Array<String>> (protected)
Take an internal representation of an IP list and return a version to store in the config file.
The internal representation is a hash, where keys are IP versions as integer and the yielded value is either a list of addresses, i.e. an array of string, or just one address (string). The caller decides how to encode the value.
The returned hash has IP versions in the hash encoded as strings, i.e.
v4 or v6`. This is to allow storing the config in JSON, which does not
support integer object keys.
345 346 347 |
# File 'lib/osctld/net_interface/veth.rb', line 345 def save_ip_list(ip_list) ip_list.to_h { |ip_v, value| ["v#{ip_v}", yield(value)] } end |
#set(opts) ⇒ Object
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/osctld/net_interface/veth.rb', line 55 def set(opts) @tx_queues = opts[:tx_queues] if opts[:tx_queues] @rx_queues = opts[:rx_queues] if opts[:rx_queues] orig_max_rx = max_rx orig_max_tx = max_tx orig_enable = enable # max_tx/rx is assigned by the parent super return if veth.nil? if opts[:max_rx] && opts[:max_rx] != orig_max_rx if max_rx > 0 set_shaper_rx else unset_shaper_rx end end if opts[:max_tx] && opts[:max_tx] != orig_max_tx if max_tx > 0 set_shaper_tx else unset_shaper_tx end end # rubocop:disable Style/GuardClause if opts.has_key?(:enable) && opts[:enable] != orig_enable if !opts[:enable] && orig_enable begin ip(:all, %W[link set #{veth} down]) rescue SystemCommandFailed => e log(:warn, ct, "Unable to disable host veth #{veth}: #{e.}") end elsif opts[:enable] && !orig_enable begin ip(:all, %W[link set #{veth} up]) rescue SystemCommandFailed => e log(:warn, ct, "Unable to enable host veth #{veth}: #{e.}") end end end # rubocop:enable Style/GuardClause end |
#set_shaper_rx ⇒ Object (protected)
286 287 288 289 |
# File 'lib/osctld/net_interface/veth.rb', line 286 def set_shaper_rx tc(%W[qdisc delete root dev #{veth}], valid_rcs: [2]) tc(%W[qdisc add root dev #{veth} cake bandwidth #{max_rx}bit]) end |
#set_shaper_tx ⇒ Object (protected)
295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 |
# File 'lib/osctld/net_interface/veth.rb', line 295 def set_shaper_tx ifb_exists = Dir.exist?("/sys/devices/virtual/net/#{ifb_veth}") unless ifb_exists ip(:all, %W[link add name #{ifb_veth} type ifb]) tc(%W[qdisc del dev #{veth} ingress], valid_rcs: [2]) tc(%W[qdisc add dev #{veth} handle ffff: ingress]) end tc(%W[qdisc del dev #{ifb_veth} root], valid_rcs: [2]) tc(%W[qdisc add dev #{ifb_veth} root cake bandwidth #{max_tx}bit besteffort]) return if ifb_exists ip(:all, %W[link set #{ifb_veth} up]) tc(%W[filter add dev #{veth} parent ffff: matchall action mirred egress redirect dev #{ifb_veth}]) end |
#setup ⇒ Object
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/osctld/net_interface/veth.rb', line 105 def setup # Setup links for veth up/down hooks in rundir # # Because a CT can have multiple veth interfaces and they can be of # different types, we need to create hooks for specific veth interfaces, # so that we can identify which veth was the hook called for. We simply # symlink the hook to rundir and the symlink's name identifies the veth. begin Dir.mkdir(veth_hook_dir, 0o711) rescue Errno::EEXIST # ignore end %w[up down].each do |v| begin Dir.mkdir(mode_path(v), 0o711) rescue Errno::EEXIST # ignore end symlink = hook_path(v) hook_src = OsCtld.hook_src("veth-#{v}") if File.symlink?(symlink) next if File.readlink(symlink) == hook_src File.unlink(symlink) end File.symlink(hook_src, symlink) end return if ct.fresh_state != :running @veth = fetch_veth_name end |
#unset_shaper_rx ⇒ Object (protected)
291 292 293 |
# File 'lib/osctld/net_interface/veth.rb', line 291 def unset_shaper_rx tc(%W[qdisc delete root dev #{veth}], valid_rcs: [2]) end |
#unset_shaper_tx ⇒ Object (protected)
313 314 315 316 317 |
# File 'lib/osctld/net_interface/veth.rb', line 313 def unset_shaper_tx tc(%W[filter delete dev #{veth} parent ffff:]) tc(%W[qdisc delete dev #{veth} handle ffff: ingress]) ip(:all, %W[link del #{ifb_veth}]) end |
#up(veth) ⇒ Object
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
# File 'lib/osctld/net_interface/veth.rb', line 171 def up(veth) exclusively { @veth = veth } ip(:all, %W[link set #{veth} down]) unless enable set_shaper_rx if max_rx > 0 set_shaper_tx if max_tx > 0 Eventd.report( :ct_netif, action: :up, pool: ct.pool.name, id: ct.id, name:, veth:, enable: ) end |
#veth_hook_dir ⇒ Object (protected)
319 320 321 |
# File 'lib/osctld/net_interface/veth.rb', line 319 def veth_hook_dir File.join(ct.pool.hook_dir, 'veth') end |