qemu-toolkit / lib / qemu-toolkit / vnic.rb

require 'set'

require 'qemu-toolkit/network/mac_address'

module QemuToolkit
  class Vnic
    class << self
      def for_prefix(prefix, background)
        vnics = VnicCollection.new
        links = background.dladm 'show-vnic', '-po link,over,vid,macaddress'

        re_separator = /(?<!\\):/
        
        links.each_line do |line|
          next unless line.start_with?(prefix)
          link, over, vid, macaddr = line.chomp.split(re_separator)

          # macaddr being the only place escaping takes place, unescape it
          # by replacing \: -> :
          macaddr.gsub!(/\\:/, ':')
          
          # Assumes that vid 0 is always the 'no vlan' VLAN
          over = "#{over}:#{vid}" if vid.to_i > 0
          
          if md=link.match(/^(?<vm>.*)_(?<link_no>\d+)$/)
            vnics << Vnic.new(md[:vm], Integer(md[:link_no]), over, macaddr)
          end
        end
        
        vnics
      end
      
      def create(prefix, over, backend, macaddr=nil)
        # Retrieve links that exist for this prefix and this over interface
        vnics = for_prefix(prefix, backend)
        next_vnic_number = (vnics.map(&:number).max || 0) + 1

        new(prefix, next_vnic_number, over, macaddr).tap { |o|
          o.create(backend) }
      end
      
    end
    
    def initialize(prefix, number, over, macaddr=nil)
      @prefix, @number, @over = prefix, number, over
      @macaddr = macaddr && Network::MacAddress.new(macaddr)

      if vlan_tagged?
        @interface, @vlan = @over.split(':')
      else
        @interface = @over
        @vlan = nil
      end
    end
    
    attr_reader :prefix
    attr_reader :number
    attr_reader :over
    attr_reader :macaddr

    attr_reader :interface
    attr_reader :vlan
    
    def ==(other)
      self.prefix == other.prefix && 
        self.number == other.number && 
        self.over == other.over && 
        self.macaddr == other.macaddr
    end

    def to_s
      "#{vnic_name} (#{vlan || 'g'}/#{macaddr})"
    end

    def vlan_tagged?
      @over.index(':')
    end
    def mac_address?
      @macaddr
    end
    
    def create backend
      opts = ["-l #{interface}"]

      opts << "-v #{vlan}" if vlan_tagged?
      opts << "--mac-address #{macaddr}" if mac_address?

      backend.dladm 'create-vnic', *opts, vnic_name
    end
    
    def vnic_name
      "#{prefix}_#{number}"
    end
  end
end
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.