Blob Blame History Raw
From 49c4581a8ca3c8f9798ce5c6a44a0927307512f5 Mon Sep 17 00:00:00 2001
From: Dan Williams <dcbw@redhat.com>
Date: Tue, 30 Jun 2015 16:43:36 -0500
Subject: [PATCH] [fedora] honor MAC address when configuring networks

Configuring by :interface doesn't work very well because Vagrant has
no idea about what interfaces are present in the VM, for example if
the image has 'docker' installed but not biosdevname, then
interface_names[0] = "docker0" which is usually not what you want
mapped to the first network from the Vagrantfile.

So if the plugins (like vagrant-libvirt) or the Vagrantfile has
given us a network with a MAC address, use that to find the interface
name for the network.  Otherwise use slot numbers as before.
---
 plugins/guests/fedora/cap/configure_networks.rb | 28 ++++++++++++++++++++++---
 1 file changed, 25 insertions(+), 3 deletions(-)

diff --git a/plugins/guests/fedora/cap/configure_networks.rb b/plugins/guests/fedora/cap/configure_networks.rb
index 2f67099..323519c 100644
--- a/plugins/guests/fedora/cap/configure_networks.rb
+++ b/plugins/guests/fedora/cap/configure_networks.rb
@@ -16,6 +16,7 @@ def self.configure_networks(machine, networks)
 
           virtual = false
           interface_names = Array.new
+          interface_names_by_slot = Array.new
           machine.communicate.sudo("/usr/sbin/biosdevname; echo $?") do |_, result|
             virtual = true if ['4', '127'].include? result.chomp
           end
@@ -25,7 +26,7 @@ def self.configure_networks(machine, networks)
               interface_names = result.split("\n")
             end
 
-            interface_names = networks.map do |network|
+            interface_names_by_slot = networks.map do |network|
                "#{interface_names[network[:interface]]}"
             end
           else
@@ -44,18 +45,39 @@ def self.configure_networks(machine, networks)
                "eth#{network[:interface]}"
             end
 
+            interface_names_by_slot = interface_names.dup
             interface_name_pairs.each do |interface_name, previous_interface_name|
               if setting_interface_names.index(previous_interface_name) == nil
-                interface_names.delete(interface_name)
+                interface_names_by_slot.delete(interface_name)
               end
             end
           end
 
+          # Read interface MAC addresses for later matching
+          mac_addresses = Array.new(interface_names.length)
+          interface_names.each_with_index do |ifname, index|
+            machine.communicate.sudo("cat /sys/class/net/#{ifname}/address") do |_, result|
+              mac_addresses[index] = result.strip
+            end
+          end
+
           # Accumulate the configurations to add to the interfaces file as well
           # as what interfaces we're actually configuring since we use that later.
           interfaces = Set.new
           networks.each do |network|
-            interface = interface_names[network[:interface]-1]
+            interface = nil
+            if network[:mac_address]
+              found_idx = mac_addresses.find_index(network[:mac_address])
+              # Ignore network if requested MAC address could not be found
+              next if found_idx.nil?
+              interface = interface_names[found_idx]
+            else
+              ifname_by_slot = interface_names_by_slot[network[:interface]-1]
+              # Don't overwrite if interface was already matched via MAC address
+              next if interfaces.include?(ifname_by_slot)
+              interface = ifname_by_slot
+            end
+
             interfaces.add(interface)
             network[:device] = interface