#!/usr/bin/perl
# 
# This scans the network, bridges, bonds and interfaces.
# 
# Examples;
# 
# Exit codes;
# 0 = Normal exit.
# 1 = Startup failure (not running as root, no DB, bad file read, etc)
# 
# TODO: 
# - 
#

use strict;
use warnings;
use Anvil::Tools;
use Data::Dumper;

# Disable buffering
$| = 1;

# Prevent a discrepency between UID/GID and EUID/EGID from throwing an error.
$< = $>;
$( = $);

my $THIS_FILE           =  ($0 =~ /^.*\/(.*)$/)[0];
my $running_directory   =  ($0 =~ /^(.*?)\/$THIS_FILE$/)[0];
if (($running_directory =~ /^\./) && ($ENV{PWD}))
{
	$running_directory =~ s/^\./$ENV{PWD}/;
}

my $anvil = Anvil::Tools->new();

# Make sure we're running as 'root'
# $< == real UID, $> == effective UID
if (($< != 0) && ($> != 0))
{
	# Not root
	print $anvil->Words->string({key => "error_0005"})."\n";
	$anvil->nice_exit({exit_code => 1});
}

#$anvil->Storage->read_config();
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "log_0115", variables => { program => $THIS_FILE }});

# Read switches
$anvil->Get->switches({list => ["purge"], man => $THIS_FILE});

# Handle start-up tasks
my $problem = $anvil->ScanCore->agent_startup({agent => $THIS_FILE});
if ($problem)
{
	$anvil->nice_exit({exit_code => 1});
}

if ($anvil->data->{switches}{purge})
{
	# This can be called when doing bulk-database purges.
	my $schema_file = $anvil->data->{path}{directories}{scan_agents}."/".$THIS_FILE."/".$THIS_FILE.".sql";
	$anvil->Database->purge_data({
		debug  => 2,
		tables => $anvil->Database->get_tables_from_schema({schema_file => $schema_file}),
	});
	$anvil->nice_exit({exit_code => 0});
}

# If there's no DB (or cached data isn't recorded to the database yet), this will store those records.
$anvil->data->{cache}{new_file} = "# interface (nm_device),timestamp,mac_address,speed,link_state,operational,nm_uuid,nm_name\n";
process_interface_cache($anvil);

# Read the data.
collect_data($anvil);

# Load stored data.
read_last_scan($anvil);

# Look for changes.
find_changes($anvil);

# Finally, process health weights.
process_health($anvil);

# This clears the TX and RX variable data for interfaces older than 'scancore::database::age_out'.
clear_old_variables($anvil);

# This removes network interfaces that have been marked as DELETED for a while now.
clear_old_interfaces($anvil);

# Write out the interface cache
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 
	"cache::new_file"           => $anvil->data->{cache}{new_file}, 
	"path::data::network_cache" => $anvil->data->{path}{data}{network_cache}, 
}});
$anvil->Storage->write_file({
	body      => $anvil->data->{cache}{new_file},
	file      => $anvil->data->{path}{data}{network_cache},
	overwrite => 1,
	backup    => 0,
});

# Shut down.
$anvil->ScanCore->agent_shutdown({agent => $THIS_FILE});


#############################################################################################################
# Functions                                                                                                 #
#############################################################################################################

# This reads in the interface cache file and looks for records that haven't been stored in the database yet.
sub process_interface_cache
{
	my ($anvil) = @_;
	
	# Does the file exist? If so, read it in.
	if (-e $anvil->data->{path}{data}{network_cache})
	{
		my $body = $anvil->Storage->read_file({debug => 2, cache => 0, force_read => 1, file => $anvil->data->{path}{data}{network_cache}});
		foreach my $line (split/\n/, $body)
		{
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }});
			next if $line =~ /^#/;
			my ($nm_device, $timestamp, $mac_address, $speed, $link_state, $operational, $nm_uuid, $nm_name) = (split/,/, $line);
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				timestamp   => $timestamp, 
				speed       => $speed, 
				mac_address => $mac_address, 
				link_state  => $link_state, 
				operational => $operational, 
				nm_uuid     => $nm_uuid,
				nm_device   => $nm_device, 
			}});
			
			if ($anvil->data->{sys}{database}{connections})
			{
				my ($network_interface_uuid) = $anvil->Database->insert_or_update_network_interfaces({
					debug                         => 2, 
					link_only                     => 1,
					timestamp                     => $timestamp, 
					network_interface_name        => $nm_device, 
					network_interface_link_state  => $link_state, 
					network_interface_mac_address => $mac_address, 
					network_interface_operational => $operational, 
					network_interface_speed       => $speed, 
					network_interface_nm_uuid     => $nm_uuid, 
					network_interface_device      => $nm_device,
				});
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { network_interface_uuid => $network_interface_uuid }});
				if (not $network_interface_uuid)
				{
					# Failed to update, could be that we cached data for an interface not yet 
					# seen. If so, the coming scan will add it and this cache should flush out 
					# next time.
					$anvil->data->{cache}{new_file} .= $line."\n";
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "cache::new_file" => $anvil->data->{cache}{new_file} }});
				}
			}
			else
			{
				# No database, re-cache
				$anvil->data->{cache}{new_file} .= $line."\n";
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "cache::new_file" => $anvil->data->{cache}{new_file} }});
			}
		}
	}
	
	return(0);
}

# This removes network interfaces that have been marked as DELETED for a while now.
sub clear_old_interfaces
{
	my ($anvil) = @_;
	
	# Read in all interfaces and for each, delete historical records over the age-out time.
	my $age = $anvil->data->{scancore}{database}{age_out};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { age => $age }});
	
	if ($age =~ /\D/)
	{
		# Age is not valid, set it to defaults.
		$age = 24;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { age => $age }});
	}
	
	my $query         = "SELECT now() - '".$age."h'::interval;";
	my $old_timestamp = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0];
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		query         => $query, 
		old_timestamp => $old_timestamp, 
	}});
	
	# It is possible that a record exists on one DB, but not the other. Unsure how this happens, but this
	# cleans it up.
	foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{cache}{database_handle}})
	{
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			uuid => $anvil->Database->get_host_from_uuid({debug => 2, short => 1, host_uuid => $uuid})." (".$uuid.")", 
		}});
		my $query = "
SELECT 
    ip_address_uuid, 
    ip_address_address 
FROM 
    ip_addresses 
WHERE 
    ip_address_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." 
AND 
    ip_address_note      = 'DELETED' 
AND 
    modified_date        < '".$old_timestamp."' 
ORDER BY 
    ip_address_address ASC
;";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
		my $results = $anvil->Database->query({uuid => $uuid, query => $query, source => $THIS_FILE, line => __LINE__});
		my $count   = @{$results};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			results => $results, 
			count   => $count,
		}});
		foreach my $row (@{$results})
		{
			my $ip_address_uuid    = $row->[0];
			my $ip_address_address = $row->[1];
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				's1:ip_address_uuid'    => $ip_address_uuid, 
				's2:ip_address_address' => $ip_address_address, 
			}});
		
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_network_log_0005", variables => { 
				age => $age, 
				ip  => $ip_address_address,
			}});
			
			my $queries = [];
			push @{$queries}, "DELETE FROM history.ip_addresses WHERE ip_address_uuid = '".$ip_address_uuid."';";
			push @{$queries}, "DELETE FROM ip_addresses WHERE ip_address_uuid = '".$ip_address_uuid."';";
			foreach my $query (@{$queries})
			{
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
			}
			# Write to both DBs.
			$anvil->Database->write({query => $queries, source => $THIS_FILE, line => __LINE__});
		}
		
		# Remove interfaces
		$query = "
SELECT 
    network_interface_uuid, 
    network_interface_mac_address, 
    network_interface_name 
FROM 
    network_interfaces 
WHERE 
    network_interface_host_uuid   = ".$anvil->Database->quote($anvil->Get->host_uuid)." 
AND 
    network_interface_operational = 'DELETED' 
AND  
    modified_date                 < '".$old_timestamp."' 
ORDER BY 
    network_interface_name ASC
;";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
		$results = $anvil->Database->query({uuid => $uuid, query => $query, source => $THIS_FILE, line => __LINE__});
		$count   = @{$results};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			results => $results, 
			count   => $count,
		}});
		foreach my $row (@{$results})
		{
			my $network_interface_uuid        = $row->[0];
			my $network_interface_mac_address = $row->[1];
			my $network_interface_name        = $row->[2];
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				's1:network_interface_uuid'        => $network_interface_uuid, 
				's2:network_interface_mac_address' => $network_interface_mac_address, 
				's3:network_interface_name'        => $network_interface_name,
			}});
		
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_network_log_0002", variables => { 
				age  => $age, 
				mac  => $network_interface_mac_address,
				name => $network_interface_name,
			}});
			
			my $queries = [];
			push @{$queries}, "DELETE FROM history.network_interfaces WHERE network_interface_uuid = '".$network_interface_uuid."';";
			push @{$queries}, "DELETE FROM network_interfaces WHERE network_interface_uuid = '".$network_interface_uuid."';";
			foreach my $query (@{$queries})
			{
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
			}
			# Write to both DBs.
			$anvil->Database->write({query => $queries, source => $THIS_FILE, line => __LINE__});
		}
		
		# Delete old bonds
		$query = "
SELECT 
    bond_uuid, 
    bond_name 
FROM 
    bonds 
WHERE 
    bond_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." 
AND 
    bond_mode      = 'DELETED' 
AND 
    modified_date  < '".$old_timestamp."' 
ORDER BY 
    bond_name ASC
;";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
		$results = $anvil->Database->query({uuid => $uuid, query => $query, source => $THIS_FILE, line => __LINE__});
		$count   = @{$results};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			results => $results, 
			count   => $count,
		}});
		foreach my $row (@{$results})
		{
			my $bond_uuid = $row->[0];
			my $bond_name = $row->[1];
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				's1:bond_uuid' => $bond_uuid, 
				's2:bond_name' => $bond_name,
			}});
		
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_network_log_0003", variables => { 
				age  => $age, 
				name => $bond_name,
			}});
			
			my $queries = [];
			push @{$queries}, "DELETE FROM history.bonds WHERE bond_uuid = '".$bond_uuid."';";
			push @{$queries}, "DELETE FROM bonds WHERE bond_uuid = '".$bond_uuid."';";
			foreach my $query (@{$queries})
			{
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
			}
			# Write to both DBs.
			$anvil->Database->write({query => $queries, source => $THIS_FILE, line => __LINE__});
		}
		
		# Delete old bridges
		$query = "
SELECT 
    bridge_uuid, 
    bridge_name 
FROM 
    bridges 
WHERE 
    bridge_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." 
AND 
    bridge_id        = 'DELETED' 
AND 
    modified_date    < '".$old_timestamp."' 
ORDER BY 
    bridge_name ASC
;";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
		$results = $anvil->Database->query({uuid => $uuid, query => $query, source => $THIS_FILE, line => __LINE__});
		$count   = @{$results};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			results => $results, 
			count   => $count,
		}});
		foreach my $row (@{$results})
		{
			my $bridge_uuid = $row->[0];
			my $bridge_name = $row->[1];
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				's1:bridge_uuid' => $bridge_uuid, 
				's2:bridge_name' => $bridge_name,
			}});
		
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_network_log_0004", variables => { 
				age  => $age, 
				name => $bridge_name,
			}});
			
			# Is there a bond connected to this? If so, don't delete, we'd hit a foreign key 
			# constraint.
			my $subquery = "SELECT COUNT(*) FROM bonds WHERE bond_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";";
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { subquery => $subquery }});
			
			my $count = $anvil->Database->query({query => $subquery, source => $THIS_FILE, line => __LINE__})->[0]->[0];
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }});
			
			if (not $count)
			{
				my $queries = [];
				push @{$queries}, "DELETE FROM history.bridges WHERE bridge_uuid = '".$bridge_uuid."';";
				push @{$queries}, "DELETE FROM bridges WHERE bridge_uuid = '".$bridge_uuid."';";
				foreach my $query (@{$queries})
				{
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
				}
				# Write to both DBs.
				$anvil->Database->write({query => $queries, source => $THIS_FILE, line => __LINE__});
			}
		}
	}
	
	return(0);
}

# This clears the TX and RX variable data for interfaces older than 'scancore::database::age_out'.
sub clear_old_variables
{
	my ($anvil) = @_;
	
	# Only Strikers run this.
	my $host_type = $anvil->Get->host_type();
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_type => $host_type }});
	if ($host_type ne "striker")
	{
		return(0);
	}
	
	# Read in all interfaces and for each, delete historical records over the age-out time.
	my $age = $anvil->data->{scancore}{database}{age_out};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { age => $age }});
	
	if ($age =~ /\D/)
	{
		# Age is not valid, set it to defaults.
		$age = 24;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { age => $age }});
	}
	
	# Get the timestamp to delete thermal and power records older than $age hours.
	my $query         = "SELECT now() - '".$age."h'::interval;";
	my $old_timestamp = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0];
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 
		query         => $query, 
		old_timestamp => $old_timestamp, 
	}});
	
	# Read in all interface RX and TX variables.
	foreach my $uuid (keys %{$anvil->data->{cache}{database_handle}})
	{
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 
			uuid    => $uuid, 
			db_host => $anvil->Get->host_name_from_uuid({host_uuid => $uuid}),
		}});
		my $queries = [];
		   $query   = "
SELECT 
    variable_uuid, 
    variable_name 
FROM 
    variables 
WHERE 
    variable_name LIKE '%::tx_bytes' 
OR 
    variable_name LIKE '%::rx_bytes'
;";
		my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
		my $count   = @{$results};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			results => $results, 
			count   => $count,
		}});
		foreach my $row (@{$results})
		{
			my $variable_uuid = $row->[0];
			my $variable_name = $row->[1];
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				's1:variable_name' => $variable_name, 
				's2:variable_uuid' => $variable_uuid,
			}});
			
			# Find out of there are any records to remove at all.
			my $query = "SELECT history_id FROM history.variables WHERE variable_uuid = ".$anvil->Database->quote($variable_uuid)." AND modified_date <= '".$old_timestamp."';";
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
			
			my $results = $anvil->Database->query({uuid => $uuid, query => $query, source => $THIS_FILE, line => __LINE__});
			my $count   = @{$results};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				results => $results, 
				count   => $count, 
			}});
			
			if ($count)
			{
				# Find how many records will be left. If it's 0, we'll use an OFFSET 1.
				my $query = "SELECT history_id FROM history.variables WHERE variable_uuid = ".$anvil->Database->quote($variable_uuid)." AND modified_date > '".$old_timestamp."';";
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
				
				my $results = $anvil->Database->query({uuid => $uuid, query => $query, source => $THIS_FILE, line => __LINE__});
				my $count   = @{$results};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					results => $results, 
					count   => $count, 
				}});
				if ($count)
				{
					# At least one record will be left, we can do a simple delete.
					my $query = "DELETE FROM history.variables WHERE variable_uuid = ".$anvil->Database->quote($variable_uuid)." AND modified_date <= '".$old_timestamp."';";
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
					push @{$queries}, $query;
				}
				else
				{
					# This would delete everything, reserve at least one record.
					foreach my $row (@{$results})
					{
						my $history_id = $row->[0];
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { history_id => $history_id }});
						
						my $query = "DELETE FROM history.variables WHERE variable_uuid = ".$anvil->Database->quote($variable_uuid)." AND history_id = '".$history_id."';";
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
						push @{$queries}, $query;
					}
				}
			}
		}
		
		my $commits = @{$queries};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { commits => $commits }});
		if ($commits)
		{
			# Commit the DELETEs.
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_network_log_0001", variables => { 
				age     => $age,
				records => $commits,
				host    => $anvil->Get->host_name_from_uuid({host_uuid => $uuid}), 
			}});
			$anvil->Database->write({debug => 2, uuid => $uuid, query => $queries, source => $THIS_FILE, line => __LINE__});
			undef $queries;
		}
	}
	
	return(0);
}

# This reads in all of the network data
sub collect_data
{
	my ($anvil) = @_;
	
	# Read in data from Network Manager
	my $uptime = $anvil->Get->uptime;
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { uptime => $uptime }});
	if ($uptime < 600)
	{
		# Check for / start down but configured interfaces.
		$anvil->Network->collect_data({up => 1, debug => 2});
	}
	else
	{
		# Just collect data.
		$anvil->Network->collect_data({debug => 2});
	}
	
	### TODO: We can get the IPs from collect_data, we should phase this out.
	# The 'local_host' is needed to pull data recorded by Network->get_ips();
	$anvil->Network->get_ips({debug => 2});
	my $local_host = $anvil->Get->short_host_name();
	my $directory  = "/sys/class/net";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		local_host => $local_host, 
		directory  => $directory,
	}});
	
	### TODO: Convert this to use Sys::Virt
	# Make sure there are no virsh bridges, removing any found.
	my $host_type = $anvil->Get->host_type();
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_type => $host_type }});
	if (($host_type eq "node") or ($host_type eq "dr"))
	{
		my $default_network = "/etc/libvirt/qemu/networks/default.xml";
		if (-e $default_network)
		{
			my $shell_call = $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." net-destroy default";
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
			my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				output      => $output,
				return_code => $return_code, 
			}});
			
			$shell_call = $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." net-undefine default";
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
			($output, $return_code) = $anvil->System->call({shell_call => $shell_call});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				output      => $output,
				return_code => $return_code, 
			}});
			
			# Register an alert
			my $variables = {
				bridge => "default",
			};
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0001", variables => $variables});
			$anvil->Alert->register({
				alert_level => "notice", 
				message     => "scan_network_alert_0001",
				variables   => $variables,
				set_by      => $THIS_FILE,
			});
		}
	}
	
	# Collect data from nmcli
	$anvil->Network->collect_data({debug => 2});

	# Walk through the sysfs files.
	local(*DIRECTORY);
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0018", variables => { directory => $directory }});
	opendir(DIRECTORY, $directory);
	while(my $file = readdir(DIRECTORY))
	{
		next if $file eq ".";
		next if $file eq "..";
		next if $file eq "lo"; 
		my $full_path = $directory."/".$file;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { full_path => $full_path }});
		if (-d $full_path)
		{
			### NOTE: The 'interface' maps to the network manager 'GENERAL.IP-IFACE', which is 
			###       'network_interface_device'. The 'network_interface_name' is the biosdevname.
			# Pull out the data I want. Note that some of these don't exist with virtio-net interfaces.
			my $interface   = $file;
			my $link_state  = -e $full_path."/carrier"         ? $anvil->Storage->read_file({file => $full_path."/carrier"})         : 0;
			   $link_state  =~ s/\n$//;
			my $mtu         = -e $full_path."/mtu"             ? $anvil->Storage->read_file({file => $full_path."/mtu"})             : 0;
			   $mtu         =~ s/\n$//;
			my $duplex      = -e $full_path."/duplex"          ? $anvil->Storage->read_file({file => $full_path."/duplex"})          : "unknown";	# full or half?
			   $duplex      =~ s/\n$//;
			my $operational = -e $full_path."/operstate"       ? $anvil->Storage->read_file({file => $full_path."/operstate"})       : "unknown";	# up or down
			   $operational =~ s/\n$//;
			my $modalias    = -e $full_path."/device/modalias" ? $anvil->Storage->read_file({file => $full_path."/device/modalias"}) : "unknown";
			   $modalias    =~ s/\n$//;
			my $speed       = $link_state ? $anvil->Storage->read_file({file => $full_path."/speed"}) : 0;	# Mbps (ie: 1000 = Gbps), gives a very high number for unplugged link
			   $speed       =~ s/\n$//;
			my $media       =  "unknown";
			my $type        =  "interface";
			my $driver      =  "";
			my $tx_bytes    =  0;	# How many bytes transmitted
			my $rx_bytes    =  0;	# How many bytes received
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				interface   => $interface, 
				link_state  => $link_state, 
				mtu         => $mtu,
				duplex      => $duplex, 
				operational => $operational,
				speed       => $speed, 
				modalias    => $modalias, 
			}});
			
			# Try to find the nm_uuid
			my $nm_uuid = "";
			if ((exists $anvil->data->{nmcli}{name}{$interface}) && ($anvil->data->{nmcli}{name}{$interface}{uuid}))
			{
				$nm_uuid = $anvil->data->{nmcli}{name}{$interface}{uuid};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { nm_uuid => $nm_uuid }});
			}
			elsif ((exists $anvil->data->{nmcli}{device}{$interface}) && ($anvil->data->{nmcli}{device}{$interface}{uuid}))
			{
				$nm_uuid = $anvil->data->{nmcli}{device}{$interface}{uuid};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { nm_uuid => $nm_uuid }});
			}
			
			my $nm_device = "";	# biosdevname
			my $nm_name   = "";	# ip name
			if ($nm_uuid)
			{
				$nm_device = $anvil->data->{nmcli}{uuid}{$nm_uuid}{device};
				$nm_name   = $anvil->data->{nmcli}{uuid}{$nm_uuid}{name};
			}
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				nm_device => $nm_device,
				nm_name   => $nm_name, 
			}});
			
			### NOTE: This only parses virtio so far.
			# Pick out our driver.
			if ($modalias =~ /^virtio:/)
			{
				$driver = "virtio";
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { driver => $driver }});
			}
			
			# The MAC address can faked by a number of ways, so we make an explicit call to 'ethtool' to get the permanent mac address.
			my $mac_address = "";
			my $shell_call  = $anvil->data->{path}{exe}{ethtool}." -P ".$interface;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
			
			my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				output      => $output,
				return_code => $return_code, 
			}});
			if ($output =~ /(\w\w:\w\w:\w\w:\w\w:\w\w:\w\w)$/)
			{
				$mac_address = lc($1);
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_address => $mac_address }});
			}
			else
			{
				# Get it by reading the address file.
				if (-e $full_path."/bonding_slave/perm_hwaddr")
				{
					$mac_address = $anvil->Storage->read_file({file => $full_path."/bonding_slave/perm_hwaddr"});
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_address => $mac_address }});
				}
				elsif (-e $full_path."/address")
				{
					$mac_address =  $anvil->Storage->read_file({file => $full_path."/address"});
					$mac_address =~ s/\n//;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_address => $mac_address }});
				}
			}
			
			# These are variables that will be needed if this is a bond interface.
			my $ip_address           = "";
			my $subnet_mask          = "";
			my $bond_mode            = "";
			my $primary_interface    = "";
			my $primary_reselect     = "";
			my $active_interface     = ""; 
			my $mii_polling_interval = "";
			my $up_delay             = "";
			my $down_delay           = "";
			my $bond_master          = "";
			
			# These are variables that will be needed if this is a bridge interface
			my $bridge_id          = "";
			my $bridge_stp_enabled = "";
			
			# Explicitly check for the existing of the hash so that we don't auto-vivivate the interface.
			if (exists $anvil->data->{network}{$local_host}{interface}{$interface})
			{
				$ip_address  = defined $anvil->data->{network}{$local_host}{interface}{$interface}{ip}          ? $anvil->data->{network}{$local_host}{interface}{$interface}{ip}          : "";
				$subnet_mask = defined $anvil->data->{network}{$local_host}{interface}{$interface}{subnet_mask} ? $anvil->data->{network}{$local_host}{interface}{$interface}{subnet_mask} : "";
				$type        = defined $anvil->data->{network}{$local_host}{interface}{$interface}{type}        ? $anvil->data->{network}{$local_host}{interface}{$interface}{type}        : "interface";
				$tx_bytes    = defined $anvil->data->{network}{$local_host}{interface}{$interface}{tx_bytes}    ? $anvil->data->{network}{$local_host}{interface}{$interface}{tx_bytes}    : 0;
				$rx_bytes    = defined $anvil->data->{network}{$local_host}{interface}{$interface}{rx_bytes}    ? $anvil->data->{network}{$local_host}{interface}{$interface}{rx_bytes}    : 0;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					ip_address  => $ip_address, 
					subnet_mask => $subnet_mask,
					type        => $type, 
					rx_bytes    => $rx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $rx_bytes}).")", 
					tx_bytes    => $tx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $tx_bytes}).")", 
				}});
			}
			
			# If this interface is already a bond slave, the real mac address will be in a 
			# sub-directory.
			my $mac_bond_file = $directory."/".$file."/bonding_slave/perm_hwaddr";
			if (-e $mac_bond_file)
			{
				# It's a slave.
				$mac_address =  $anvil->Storage->read_file({file => $mac_bond_file});
				$mac_address =~ s/\n$//;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_address => $mac_address }});
			}
			
			# If this is a virtual interface, set some fake values that don't actually exist on 
			# the system for the sake of a cleaner display.
			if (($mac_address =~ /^52:54:00/) or ($driver eq "virtio"))
			{
				### Set some fake values.
				# Speed is "as fast as possible", so we'll record 100 Gbps, but that is really kind of arbitrary.
				if ((not $speed) or ($speed eq "-1"))
				{
					$speed = 10000;
				}
				if ((not $duplex) or ($duplex eq "unknown"))
				{
					$duplex = "full";
				}
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					speed  => $speed, 
					duplex => $duplex,
				}});
			}
			# If the state is 'down', set the speed to '0'.
			if (not $link_state)
			{
				$speed = 0;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { speed => $speed }});
			}
			
			# Is this a bond interface?
			if (-e "/proc/net/bonding/".$interface)
			{
				# Yup, we'll neet to dig into the bond proc files to get the proper slaved 
				# interface MAC addresses.
				$type    = "bond";
				$nm_uuid = $anvil->data->{nmcli}{bond}{$interface}{uuid};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					type    => $type,
					nm_uuid => $nm_uuid, 
				}});
				
				# Read the bond mode.
				$bond_mode            =  $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/mode"});
				$primary_interface    =  $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/primary"});
				$primary_reselect     =  $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/primary_reselect"});
				$active_interface     =  $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/active_slave"});
				$mii_polling_interval =  $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/miimon"});
				$up_delay             =  $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/updelay"});
				$down_delay           =  $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/downdelay"});
				$bond_mode            =~ s/\s.*//;
				$bond_mode            =~ s/\n$//;
				$primary_interface    =~ s/\n$//;
				$primary_reselect     =~ s/\s.*//;
				$primary_reselect     =~ s/\n$//;
				$active_interface     =~ s/\n$//;
				$mii_polling_interval =~ s/\n$//;
				$up_delay             =~ s/\n$//;
				$down_delay           =~ s/\n$//;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					active_interface     => $active_interface, 
					bond_mode            => $bond_mode, 
					mii_polling_interval => $mii_polling_interval, 
					primary_reselect     => $primary_reselect, 
					primary_interface    => $primary_interface, 
					type                 => $type,
				}});
			}
			elsif ((-e $full_path."/master") && ($interface !~ /^vnet/))
			{
				# We're in a bond.
				my $target      = readlink($full_path."/master");
				   $bond_master = ($target =~ /^.*\/(.*)$/)[0];
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					target      => $target, 
					bond_master => $bond_master, 
				}});
			}
			elsif (-d $full_path."/bridge")
			{
				# It's a bridge
				$type      =  "bridge";
				$bridge_id =  $anvil->Storage->read_file({debug => 3, file => $full_path."/bridge/bridge_id"});
				$bridge_id =~ s/\n$//;
				$speed     = 0;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					type      => $type,
					bridge_id => $bridge_id, 
				}});
			}
			
			# If this is a 'vnet' device, set 'operational' to up
			if ($interface =~ /^vnet/)
			{
				$operational = "up";
				$media       = "virtual";
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					operational => $operational,
					media       => $media, 
				}});
			}
			
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				active_interface     => $active_interface, 
				bond_master          => $bond_master, 
				bond_mode            => $bond_mode, 
				bridge_id            => $bridge_id, 
				down_delay           => $down_delay, 
				duplex               => $duplex, 
				interface            => $interface,
				mac_address          => $mac_address, 
				mii_polling_interval => $mii_polling_interval, 
				mtu                  => $mtu, 
				operational          => $operational, 
				primary_reselect     => $primary_reselect, 
				primary_interface    => $primary_interface, 
				speed                => $speed, 
				subnet_mask          => $subnet_mask, 
				type                 => $type, 
				up_delay             => $up_delay, 
			}});
			
			# If the MAC address starts with '52:54:00', we've got a virtio NIC.
			if ((not defined $speed) or ($speed eq ""))
			{
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_error_0001", variables => { file => $full_path."/speed" }});
				next;
			}
			if ($speed =~ /\D/)
			{
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_error_0002", variables => { 
					file  => $full_path."/speed",
					speed => $speed,
				}});
				next;
			}
			if ($speed > 100000)
			{
				# NOTE: This is probably 0 now... Though someday >100 Gbps will be reasonable
				#       and we'll need to change this.
				$speed = 0;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { speed => $speed }});
			}
			
			# Find the media, if possible.
			(my $ethtool, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{ethtool}." ".$interface});
			foreach my $line (split/\n/, $ethtool)
			{
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }});
				if ($line =~ /Supported ports: \[ (.*?) \]/i)
				{
					$media = lc($1);
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { media => $media }});
					
					# This can be 'tp	 mii', which breaks json.
					if ($media =~ /\t/)
					{
						$media =~ s/\t/,/g;
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { media => $media }});
					}
					last;
				}
			}
			
			# Store new information we found.
			$anvil->data->{network}{$local_host}{interface}{$interface}{nm_uuid}              = $nm_uuid; 
			$anvil->data->{network}{$local_host}{interface}{$interface}{nm_device}            = $nm_device; 
			$anvil->data->{network}{$local_host}{interface}{$interface}{nm_name}              = $nm_name; 
			$anvil->data->{network}{$local_host}{interface}{$interface}{active_interface}     = $active_interface; 
			$anvil->data->{network}{$local_host}{interface}{$interface}{bond_mode}            = $bond_mode; 
			$anvil->data->{network}{$local_host}{interface}{$interface}{bond_master}          = $bond_master; 
			$anvil->data->{network}{$local_host}{interface}{$interface}{bridge_id}            = $bridge_id; 
			$anvil->data->{network}{$local_host}{interface}{$interface}{down_delay}           = $down_delay; 
			$anvil->data->{network}{$local_host}{interface}{$interface}{duplex}               = $duplex;
			$anvil->data->{network}{$local_host}{interface}{$interface}{ip}                   = $ip_address; 
			$anvil->data->{network}{$local_host}{interface}{$interface}{link_state}           = $link_state; 
			$anvil->data->{network}{$local_host}{interface}{$interface}{mac_address}          = $mac_address; 
			$anvil->data->{network}{$local_host}{interface}{$interface}{media}                = $media; 
			$anvil->data->{network}{$local_host}{interface}{$interface}{mii_polling_interval} = $mii_polling_interval; 
			$anvil->data->{network}{$local_host}{interface}{$interface}{mtu}                  = $mtu; 
			$anvil->data->{network}{$local_host}{interface}{$interface}{operational}          = $operational;
			$anvil->data->{network}{$local_host}{interface}{$interface}{primary_reselect}     = $primary_reselect; 
			$anvil->data->{network}{$local_host}{interface}{$interface}{primary_interface}    = $primary_interface; 
			$anvil->data->{network}{$local_host}{interface}{$interface}{speed}                = $speed;
			$anvil->data->{network}{$local_host}{interface}{$interface}{subnet_mask}          = $subnet_mask; 
			$anvil->data->{network}{$local_host}{interface}{$interface}{type}                 = $type; 
			$anvil->data->{network}{$local_host}{interface}{$interface}{up_delay}             = $up_delay; 
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"network::${local_host}::interface::${interface}::nm_uuid"              => $anvil->data->{network}{$local_host}{interface}{$interface}{nm_uuid},
				"network::${local_host}::interface::${interface}::nm_device"            => $anvil->data->{network}{$local_host}{interface}{$interface}{nm_device},
				"network::${local_host}::interface::${interface}::nm_name"              => $anvil->data->{network}{$local_host}{interface}{$interface}{nm_name},
				"network::${local_host}::interface::${interface}::active_interface"     => $anvil->data->{network}{$local_host}{interface}{$interface}{active_interface},
				"network::${local_host}::interface::${interface}::bond_mode"            => $anvil->data->{network}{$local_host}{interface}{$interface}{bond_mode},
				"network::${local_host}::interface::${interface}::bond_master"          => $anvil->data->{network}{$local_host}{interface}{$interface}{bond_master},
				"network::${local_host}::interface::${interface}::bridge_id"            => $anvil->data->{network}{$local_host}{interface}{$interface}{bridge_id}, 
				"network::${local_host}::interface::${interface}::down_delay"           => $anvil->data->{network}{$local_host}{interface}{$interface}{down_delay},
				"network::${local_host}::interface::${interface}::duplex"               => $anvil->data->{network}{$local_host}{interface}{$interface}{duplex},
				"network::${local_host}::interface::${interface}::ip"                   => $anvil->data->{network}{$local_host}{interface}{$interface}{ip},
				"network::${local_host}::interface::${interface}::link_state"           => $anvil->data->{network}{$local_host}{interface}{$interface}{link_state}, 
				"network::${local_host}::interface::${interface}::mac_address"          => $anvil->data->{network}{$local_host}{interface}{$interface}{mac_address}, 
				"network::${local_host}::interface::${interface}::media"                => $anvil->data->{network}{$local_host}{interface}{$interface}{media}, 
				"network::${local_host}::interface::${interface}::mii_polling_interval" => $anvil->data->{network}{$local_host}{interface}{$interface}{mii_polling_interval},
				"network::${local_host}::interface::${interface}::mtu"                  => $anvil->data->{network}{$local_host}{interface}{$interface}{mtu}, 
				"network::${local_host}::interface::${interface}::operational"          => $anvil->data->{network}{$local_host}{interface}{$interface}{operational},
				"network::${local_host}::interface::${interface}::primary_reselect"     => $anvil->data->{network}{$local_host}{interface}{$interface}{primary_reselect},
				"network::${local_host}::interface::${interface}::primary_interface"    => $anvil->data->{network}{$local_host}{interface}{$interface}{primary_interface},
				"network::${local_host}::interface::${interface}::speed"                => $anvil->data->{network}{$local_host}{interface}{$interface}{speed},
				"network::${local_host}::interface::${interface}::subnet_mask"          => $anvil->data->{network}{$local_host}{interface}{$interface}{subnet_mask},
				"network::${local_host}::interface::${interface}::type"                 => $anvil->data->{network}{$local_host}{interface}{$interface}{type},
				"network::${local_host}::interface::${interface}::up_delay"             => $anvil->data->{network}{$local_host}{interface}{$interface}{up_delay},
			}});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"network::${local_host}::interface::${interface}::link_state"  => $anvil->data->{network}{$local_host}{interface}{$interface}{link_state}, 
				"network::${local_host}::interface::${interface}::operational" => $anvil->data->{network}{$local_host}{interface}{$interface}{operational},
			}});
			
			# If this is a link and there's no database connections, cache the data.
			if (($type eq "interface") && (not $anvil->data->{sys}{database}{connections}))
			{
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					nm_name   => $nm_name,
					nm_device => $nm_device, 
				}});
								 # nm_device,timestamp,mac_address,speed,link_state,operational,nm_uuid,nm_name
				$anvil->data->{cache}{new_file} .= $nm_device.",".$anvil->Database->refresh_timestamp.",".$mac_address.",".$speed.",".$link_state.",".$operational.",".$nm_uuid.",".$nm_name."\n";
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					"cache::new_file" => $anvil->data->{cache}{new_file},
				}});
			}
		}
	}
	closedir(DIRECTORY);
	
	# Find what interfaces are connected to which bridges
	$anvil->Network->bridge_info({debug => 2});
	foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{network}{$local_host}{interface}})
	{
		my $ip_address = $anvil->data->{network}{$local_host}{interface}{$interface}{ip};
		my $type       = $anvil->data->{network}{$local_host}{interface}{$interface}{type};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			interface  => $interface, 
			ip_address => $ip_address, 
			type       => $type,
		}});
		
		$anvil->data->{interface}{name_to_type}{$interface} = $type;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"interface::name_to_type::${interface}" => $anvil->data->{interface}{name_to_type}{$interface}, 
		}});
		
		if ($type eq "bridge")
		{
			# Store the bridge
			$anvil->data->{new}{bridge}{$interface}{nm_uuid}     = $anvil->data->{network}{$local_host}{interface}{$interface}{nm_uuid};
			$anvil->data->{new}{bridge}{$interface}{id}          = $anvil->data->{network}{$local_host}{interface}{$interface}{bridge_id};
			$anvil->data->{new}{bridge}{$interface}{mac_address} = $anvil->data->{network}{$local_host}{interface}{$interface}{mac_address}; 
			$anvil->data->{new}{bridge}{$interface}{mtu}         = $anvil->data->{network}{$local_host}{interface}{$interface}{mtu};
			$anvil->data->{new}{bridge}{$interface}{tx_bytes}    = $anvil->data->{network}{$local_host}{interface}{$interface}{tx_bytes};
			$anvil->data->{new}{bridge}{$interface}{rx_bytes}    = $anvil->data->{network}{$local_host}{interface}{$interface}{rx_bytes}; 
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"new::bridge::${interface}::nm_uuid"     => $anvil->data->{new}{bridge}{$interface}{nm_uuid}, 
				"new::bridge::${interface}::id"          => $anvil->data->{new}{bridge}{$interface}{id}, 
				"new::bridge::${interface}::mac_address" => $anvil->data->{new}{bridge}{$interface}{mac_address}, 
				"new::bridge::${interface}::mtu"         => $anvil->data->{new}{bridge}{$interface}{mtu}, 
				"new::bridge::${interface}::tx_bytes"    => $anvil->data->{new}{bridge}{$interface}{tx_bytes}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{new}{bridge}{$interface}{tx_bytes}}).")", 
				"new::bridge::${interface}::rx_bytes"    => $anvil->data->{new}{bridge}{$interface}{rx_bytes}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{new}{bridge}{$interface}{rx_bytes}}).")", 
			}});
		}
		elsif ($type eq "bond")
		{
			# Store the bond
			$anvil->data->{new}{bond}{$interface}{nm_uuid}              = $anvil->data->{network}{$local_host}{interface}{$interface}{nm_uuid};
			$anvil->data->{new}{bond}{$interface}{mode}                 = $anvil->data->{network}{$local_host}{interface}{$interface}{bond_mode};
			$anvil->data->{new}{bond}{$interface}{mtu}                  = $anvil->data->{network}{$local_host}{interface}{$interface}{mtu}; 
			$anvil->data->{new}{bond}{$interface}{master}               = $anvil->data->{network}{$local_host}{interface}{$interface}{bond_master};
			$anvil->data->{new}{bond}{$interface}{link_state}           = $anvil->data->{network}{$local_host}{interface}{$interface}{link_state}; 
			$anvil->data->{new}{bond}{$interface}{operational}          = $anvil->data->{network}{$local_host}{interface}{$interface}{operational}; 
			$anvil->data->{new}{bond}{$interface}{mac_address}          = $anvil->data->{network}{$local_host}{interface}{$interface}{mac_address}; 
			$anvil->data->{new}{bond}{$interface}{primary_interface}    = $anvil->data->{network}{$local_host}{interface}{$interface}{primary_interface}; 
			$anvil->data->{new}{bond}{$interface}{primary_reselect}     = $anvil->data->{network}{$local_host}{interface}{$interface}{primary_reselect}; 
			$anvil->data->{new}{bond}{$interface}{active_interface}     = $anvil->data->{network}{$local_host}{interface}{$interface}{active_interface}; 
			$anvil->data->{new}{bond}{$interface}{mii_polling_interval} = $anvil->data->{network}{$local_host}{interface}{$interface}{mii_polling_interval}; 
			$anvil->data->{new}{bond}{$interface}{up_delay}             = $anvil->data->{network}{$local_host}{interface}{$interface}{up_delay}; 
			$anvil->data->{new}{bond}{$interface}{down_delay}           = $anvil->data->{network}{$local_host}{interface}{$interface}{down_delay}; 
			$anvil->data->{new}{bond}{$interface}{bridge_uuid}          = ""; 	# We'll dig his out later as the bridge might not be in the database yet.
			$anvil->data->{new}{bond}{$interface}{tx_bytes}             = $anvil->data->{network}{$local_host}{interface}{$interface}{tx_bytes};
			$anvil->data->{new}{bond}{$interface}{rx_bytes}             = $anvil->data->{network}{$local_host}{interface}{$interface}{rx_bytes}; 
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"new::bond::${interface}::nm_uuid"              => $anvil->data->{new}{bond}{$interface}{nm_uuid}, 
				"new::bond::${interface}::mode"                 => $anvil->data->{new}{bond}{$interface}{mode}, 
				"new::bond::${interface}::mtu"                  => $anvil->data->{new}{bond}{$interface}{mtu}, 
				"new::bond::${interface}::master"               => $anvil->data->{new}{bond}{$interface}{master}, 
				"new::bond::${interface}::link_state"           => $anvil->data->{new}{bond}{$interface}{link_state}, 
				"new::bond::${interface}::operational"          => $anvil->data->{new}{bond}{$interface}{operational}, 
				"new::bond::${interface}::mac_address"          => $anvil->data->{new}{bond}{$interface}{mac_address}, 
				"new::bond::${interface}::primary_interface"    => $anvil->data->{new}{bond}{$interface}{primary_interface}, 
				"new::bond::${interface}::primary_reselect"     => $anvil->data->{new}{bond}{$interface}{primary_reselect}, 
				"new::bond::${interface}::active_interface"     => $anvil->data->{new}{bond}{$interface}{active_interface}, 
				"new::bond::${interface}::mii_polling_interval" => $anvil->data->{new}{bond}{$interface}{mii_polling_interval}, 
				"new::bond::${interface}::up_delay"             => $anvil->data->{new}{bond}{$interface}{up_delay}, 
				"new::bond::${interface}::down_delay"           => $anvil->data->{new}{bond}{$interface}{down_delay}, 
				"new::bond::${interface}::bridge_uuid"          => $anvil->data->{new}{bond}{$interface}{bridge_uuid}, 
				"new::bond::${interface}::tx_bytes"             => $anvil->data->{new}{bond}{$interface}{tx_bytes}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{new}{bond}{$interface}{tx_bytes}}).")", 
				"new::bond::${interface}::rx_bytes"             => $anvil->data->{new}{bond}{$interface}{rx_bytes}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{new}{bond}{$interface}{rx_bytes}}).")", 
			}});
		}
		elsif ($type eq "interface")
		{
			# Store the interface
			$anvil->data->{new}{interface}{$interface}{nm_uuid}     = $anvil->data->{network}{$local_host}{interface}{$interface}{nm_uuid};
			$anvil->data->{new}{interface}{$interface}{nm_device}   = $anvil->data->{network}{$local_host}{interface}{$interface}{nm_device};
			$anvil->data->{new}{interface}{$interface}{nm_name}     = $anvil->data->{network}{$local_host}{interface}{$interface}{nm_name};
			$anvil->data->{new}{interface}{$interface}{bond_uuid}   = "";
			$anvil->data->{new}{interface}{$interface}{bond_name}   = $anvil->data->{network}{$local_host}{interface}{$interface}{bond_master};
			$anvil->data->{new}{interface}{$interface}{bridge_uuid} = ""; 
			$anvil->data->{new}{interface}{$interface}{bridge_name} = ""; 
			$anvil->data->{new}{interface}{$interface}{duplex}      = $anvil->data->{network}{$local_host}{interface}{$interface}{duplex}; 
			$anvil->data->{new}{interface}{$interface}{link_state}  = $anvil->data->{network}{$local_host}{interface}{$interface}{link_state}; 
			$anvil->data->{new}{interface}{$interface}{operational} = $anvil->data->{network}{$local_host}{interface}{$interface}{operational}; 
			$anvil->data->{new}{interface}{$interface}{mac_address} = $anvil->data->{network}{$local_host}{interface}{$interface}{mac_address}; 
			$anvil->data->{new}{interface}{$interface}{medium}      = $anvil->data->{network}{$local_host}{interface}{$interface}{media}; 
			$anvil->data->{new}{interface}{$interface}{mtu}         = $anvil->data->{network}{$local_host}{interface}{$interface}{mtu}; 
			$anvil->data->{new}{interface}{$interface}{speed}       = $anvil->data->{network}{$local_host}{interface}{$interface}{speed}; 
			$anvil->data->{new}{interface}{$interface}{tx_bytes}    = $anvil->data->{network}{$local_host}{interface}{$interface}{tx_bytes};
			$anvil->data->{new}{interface}{$interface}{rx_bytes}    = $anvil->data->{network}{$local_host}{interface}{$interface}{rx_bytes}; 
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"new::interface::${interface}::nm_uuid"     => $anvil->data->{new}{interface}{$interface}{nm_uuid}, 
				"new::interface::${interface}::nm_device"   => $anvil->data->{new}{interface}{$interface}{nm_device}, 
				"new::interface::${interface}::nm_name"     => $anvil->data->{new}{interface}{$interface}{nm_name}, 
				"new::interface::${interface}::bond_uuid"   => $anvil->data->{new}{interface}{$interface}{bond_uuid}, 
				"new::interface::${interface}::bond_name"   => $anvil->data->{new}{interface}{$interface}{bond_name}, 
				"new::interface::${interface}::bridge_uuid" => $anvil->data->{new}{interface}{$interface}{bridge_uuid}, 
				"new::interface::${interface}::bridge_name" => $anvil->data->{new}{interface}{$interface}{bridge_name}, 
				"new::interface::${interface}::duplex"      => $anvil->data->{new}{interface}{$interface}{duplex}, 
				"new::interface::${interface}::link_state"  => $anvil->data->{new}{interface}{$interface}{link_state}, 
				"new::interface::${interface}::operational" => $anvil->data->{new}{interface}{$interface}{operational}, 
				"new::interface::${interface}::mac_address" => $anvil->data->{new}{interface}{$interface}{mac_address}, 
				"new::interface::${interface}::medium"      => $anvil->data->{new}{interface}{$interface}{medium}, 
				"new::interface::${interface}::mtu"         => $anvil->data->{new}{interface}{$interface}{mtu}, 
				"new::interface::${interface}::speed"       => $anvil->data->{new}{interface}{$interface}{speed}, 
				"new::interface::${interface}::tx_bytes"    => $anvil->data->{new}{interface}{$interface}{tx_bytes}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{new}{interface}{$interface}{tx_bytes}}).")", 
				"new::interface::${interface}::rx_bytes"    => $anvil->data->{new}{interface}{$interface}{rx_bytes}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{new}{interface}{$interface}{rx_bytes}}).")", 
			}});
		}
		
		# Record the IP address info.
		if ($ip_address)
		{
			$anvil->data->{new}{ip_address}{$ip_address}{on_interface}    = $interface;
			$anvil->data->{new}{ip_address}{$ip_address}{subnet_mask}     = $anvil->data->{network}{$local_host}{interface}{$interface}{subnet_mask};
			$anvil->data->{new}{ip_address}{$ip_address}{gateway}         = $anvil->data->{network}{$local_host}{interface}{$interface}{gateway};
			$anvil->data->{new}{ip_address}{$ip_address}{default_gateway} = $anvil->data->{network}{$local_host}{interface}{$interface}{default_gateway};
			$anvil->data->{new}{ip_address}{$ip_address}{dns}             = $anvil->data->{network}{$local_host}{interface}{$interface}{dns};
			$anvil->data->{new}{ip_address}{$ip_address}{on_uuid}         = "";
			$anvil->data->{new}{ip_address}{$ip_address}{note}            = "";
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"new::ip_address::${ip_address}::on_interface"    => $anvil->data->{new}{ip_address}{$ip_address}{on_interface}, 
				"new::ip_address::${ip_address}::subnet_mask"     => $anvil->data->{new}{ip_address}{$ip_address}{subnet_mask}, 
				"new::ip_address::${ip_address}::gateway"         => $anvil->data->{new}{ip_address}{$ip_address}{gateway}, 
				"new::ip_address::${ip_address}::default_gateway" => $anvil->data->{new}{ip_address}{$ip_address}{default_gateway}, 
				"new::ip_address::${ip_address}::dns"             => $anvil->data->{new}{ip_address}{$ip_address}{dns}, 
				"new::ip_address::${ip_address}::on_uuid"         => $anvil->data->{new}{ip_address}{$ip_address}{on_uuid}, 
				"new::ip_address::${ip_address}::note"            => $anvil->data->{new}{ip_address}{$ip_address}{note}, 
			}});
		}
	}
	
	return(0);
}

# This reads in the states from the last can
sub read_last_scan
{
	my ($anvil) = @_;
	
	### NOTE: There is a bug somewhere where interfaces are periodically being added twice per host. This
	###       checks for / cleans those up. Remove this when the core issue is resolved.
	clear_duplicates($anvil);
	
	# Read in the old bridge data.
	load_bridge_data($anvil);
	load_bond_data($anvil);
	load_interface_data($anvil);
	load_ip_address_data($anvil);

	return(0);
}

# There is a bug somewhere where interfaces, bridges and ip addresses are periodically being added twice per 
# host. This checks for / cleans those up. Remove this when the core issue is resolved.
sub clear_duplicates
{
	my ($anvil) = @_;
	
	# Look for duplicate bridges.
	my $query = "
SELECT 
    bridge_uuid, 
    bridge_name, 
    bridge_id, 
    bridge_mac_address 
FROM 
    bridges 
WHERE 
    bridge_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)."
ORDER BY 
    bridge_name ASC, 
    bridge_id DESC
;";
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }});
	my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
	my $count   = @{$results};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		results => $results, 
		count   => $count,
	}});
	foreach my $row (@{$results})
	{
		my $bridge_uuid        = $row->[0];
		my $bridge_name        = $row->[1];
		my $bridge_id          = $row->[2];
		my $bridge_mac_address = $row->[3];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			bridge_uuid        => $bridge_uuid, 
			bridge_name        => $bridge_name, 
			bridge_id          => $bridge_id, 
			bridge_mac_address => $bridge_mac_address, 
		}});
		
		if (not exists $anvil->data->{duplicate_bridges}{seen}{$bridge_name})
		{
			$anvil->data->{duplicate_bridges}{seen}{$bridge_name} = [];
		}
		push @{$anvil->data->{duplicate_bridges}{seen}{$bridge_name}}, $bridge_uuid;
		
		$anvil->data->{duplicate_bridges}{bridge_uuid}{$bridge_uuid}{bridge_name}        = $bridge_name;
		$anvil->data->{duplicate_bridges}{bridge_uuid}{$bridge_uuid}{bridge_mac_address} = $bridge_mac_address;
		$anvil->data->{duplicate_bridges}{bridge_uuid}{$bridge_uuid}{bridge_id}          = $bridge_id;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"duplicate_bridges::bridge_uuid::${bridge_uuid}::bridge_name"        => $anvil->data->{duplicate_bridges}{bridge_uuid}{$bridge_uuid}{bridge_name}, 
			"duplicate_bridges::bridge_uuid::${bridge_uuid}::bridge_id"          => $anvil->data->{duplicate_bridges}{bridge_uuid}{$bridge_uuid}{bridge_id}, 
			"duplicate_bridges::bridge_uuid::${bridge_uuid}::bridge_mac_address" => $anvil->data->{duplicate_bridges}{bridge_uuid}{$bridge_uuid}{bridge_mac_address}, 
		}});
		
		$anvil->data->{deleted_bridges}{$bridge_uuid} = 0;
	}
	foreach my $bridge_name (sort {$a cmp $b} keys %{$anvil->data->{duplicate_bridges}{seen}})
	{
		my $count = @{$anvil->data->{duplicate_bridges}{seen}{$bridge_name}};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			's1:bridge_name' => $bridge_name, 
			's2:count'       => $count,
		}});
		
		if ($count > 1)
		{
			# Duplicate! Is one of them marked as DELETED?
			foreach my $bridge_uuid (@{$anvil->data->{duplicate_bridges}{seen}{$bridge_name}})
			{
				# Is this one deleted?
				my $bridge_mac_address = $anvil->data->{duplicate_bridges}{bridge_uuid}{$bridge_uuid}{bridge_mac_address};
				my $bridge_id          = $anvil->data->{duplicate_bridges}{bridge_uuid}{$bridge_uuid}{bridge_id};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					bridge_uuid        => $bridge_uuid, 
					bridge_mac_address => $anvil->data->{duplicate_bridges}{bridge_uuid}{$bridge_uuid}{bridge_mac_address}, 
					bridge_id          => $anvil->data->{duplicate_bridges}{bridge_uuid}{$bridge_uuid}{bridge_id}, 
				}});
				if ($bridge_id eq "DELETED")
				{
					# Take this one out.
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0685", variables => { 
						name => $bridge_name,
						uuid => $bridge_uuid,
					}});
					
					# If there's a bond connected to this bridge, get it's bond_uuid so 
					# we can remove any interfaces linked to it.
					my $bond_uuid = "";
					my $query     = "SELECT bond_uuid FROM bonds WHERE bond_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";";
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }});
					my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
					my $count   = @{$results};
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						results => $results, 
						count   => $count,
					}});
					if ($count)
					{
						$bond_uuid = $results->[0]->[0];
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bond_uuid => $bond_uuid }});
					}
					
					my $queries = [];
					push @{$queries}, "DELETE FROM history.network_interfaces WHERE network_interface_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";";
					push @{$queries}, "DELETE FROM network_interfaces WHERE network_interface_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";";
					if ($bond_uuid)
					{
						push @{$queries}, "DELETE FROM history.network_interfaces WHERE network_interface_bond_uuid = ".$anvil->Database->quote($bond_uuid).";";
						push @{$queries}, "DELETE FROM network_interfaces WHERE network_interface_bond_uuid = ".$anvil->Database->quote($bond_uuid).";";
					}
					push @{$queries}, "DELETE FROM history.bonds WHERE bond_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";";
					push @{$queries}, "DELETE FROM bonds WHERE bond_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";";
					push @{$queries}, "DELETE FROM history.bridges WHERE bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";";
					push @{$queries}, "DELETE FROM bridges WHERE bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";";
					
					# Write it out.
					$anvil->Database->write({debug => 2, query => $queries, source => $THIS_FILE, line => __LINE__});
					
					$count--;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }});
					
					$anvil->data->{deleted_bridges}{$bridge_uuid} = 1;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						"deleted_bridges::${bridge_uuid}" => $anvil->data->{deleted_bridges}{$bridge_uuid},
					}});
				}
				last if $count == 1;
			}
			
			# If count is still > 1, we need to arbitrarily delete an interface.
			if ($count > 1)
			{
				foreach my $bridge_uuid (@{$anvil->data->{duplicate_bridges}{seen}{$bridge_name}})
				{
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0685", variables => { 
						name => $bridge_name,
						uuid => $bridge_uuid,
					}});
					
					# If there's a bond connected to this bridge, get it's bond_uuid so 
					# we can remove any interfaces linked to it.
					my $bond_uuid = "";
					my $query     = "SELECT bond_uuid FROM bonds WHERE bond_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";";
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }});
					my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
					my $count   = @{$results};
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						results => $results, 
						count   => $count,
					}});
					if ($count)
					{
						$bond_uuid = $results->[0]->[0];
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bond_uuid => $bond_uuid }});
					}
					
					my $queries = [];
					push @{$queries}, "DELETE FROM history.network_interfaces WHERE network_interface_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";";
					push @{$queries}, "DELETE FROM network_interfaces WHERE network_interface_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";";
					if ($bond_uuid)
					{
						push @{$queries}, "DELETE FROM history.network_interfaces WHERE network_interface_bond_uuid = ".$anvil->Database->quote($bond_uuid).";";
						push @{$queries}, "DELETE FROM network_interfaces WHERE network_interface_bond_uuid = ".$anvil->Database->quote($bond_uuid).";";
					}
					push @{$queries}, "DELETE FROM history.bonds WHERE bond_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";";
					push @{$queries}, "DELETE FROM bonds WHERE bond_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";";
					push @{$queries}, "DELETE FROM history.bridges WHERE bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";";
					push @{$queries}, "DELETE FROM bridges WHERE bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";";
					
					# Write it out.
					$anvil->Database->write({debug => 2, query => $queries, source => $THIS_FILE, line => __LINE__});
					
					$count--;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }});
					
					$anvil->data->{deleted_bridges}{$bridge_uuid} = 1;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						"deleted_bridges::${bridge_uuid}" => $anvil->data->{deleted_bridges}{$bridge_uuid},
					}});
				}
				last if $count == 1;
			}
		}
	}
	delete $anvil->data->{duplicate_bridges};
	
	# Load the bridges again.
	$anvil->Database->get_bridges({include_deleted => 1});
	
	# Look for duplicate bonds.
	$query = "
SELECT 
    bond_uuid, 
    bond_name, 
    bond_operational, 
    bond_mac_address, 
    bond_bridge_uuid 
FROM 
    bonds 
WHERE 
    bond_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)."
ORDER BY 
    bond_name ASC, 
    bond_operational DESC
;";
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }});
	$results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
	$count   = @{$results};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		results => $results, 
		count   => $count,
	}});
	foreach my $row (@{$results})
	{
		my $bond_uuid        =         $row->[0];
		my $bond_name        =         $row->[1];
		my $bond_operational =         $row->[2];
		my $bond_mac_address =         $row->[3];
		my $bond_bridge_uuid = defined $row->[4] ? $row->[4] : "";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			bond_uuid        => $bond_uuid, 
			bond_name        => $bond_name, 
			bond_operational => $bond_operational, 
			bond_mac_address => $bond_mac_address, 
			bond_bridge_uuid => $bond_bridge_uuid, 
		}});
		
		if (not exists $anvil->data->{duplicate_bonds}{seen}{$bond_name})
		{
			$anvil->data->{duplicate_bonds}{seen}{$bond_name} = [];
		}
		push @{$anvil->data->{duplicate_bonds}{seen}{$bond_name}}, $bond_uuid;
		
		$anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_name}        = $bond_name;
		$anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_mac_address} = $bond_mac_address;
		$anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_operational} = $bond_operational;
		$anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_bridge_uuid} = $bond_bridge_uuid;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"duplicate_bonds::bond_uuid::${bond_uuid}::bond_name"        => $anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_name}, 
			"duplicate_bonds::bond_uuid::${bond_uuid}::bond_operational" => $anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_operational}, 
			"duplicate_bonds::bond_uuid::${bond_uuid}::bond_mac_address" => $anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_mac_address}, 
			"duplicate_bonds::bond_uuid::${bond_uuid}::bond_bridge_uuid" => $anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_bridge_uuid}, 
		}});
		
		$anvil->data->{deleted_bonds}{$bond_uuid} = 0;
	}
	foreach my $bond_name (sort {$a cmp $b} keys %{$anvil->data->{duplicate_bonds}{seen}})
	{
		my $count = @{$anvil->data->{duplicate_bonds}{seen}{$bond_name}};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			's1:bond_name' => $bond_name, 
			's2:count'     => $count,
		}});
		
		if ($count > 1)
		{
			# Duplicate! Is one of them marked as DELETED?
			foreach my $bond_uuid (@{$anvil->data->{duplicate_bonds}{seen}{$bond_name}})
			{
				# Is this one deleted?
				my $bond_mac_address = $anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_mac_address};
				my $bond_operational = $anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_operational};
				my $bond_bridge_uuid = $anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_bridge_uuid};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					bond_uuid        => $bond_uuid, 
					bond_mac_address => $bond_mac_address, 
					bond_operational => $bond_operational, 
					bond_bridge_uuid => $bond_bridge_uuid,
				}});
				if ((($bond_bridge_uuid) && ($anvil->data->{deleted_bridges}{$bond_bridge_uuid})) or ($bond_operational eq "DELETED"))
				{
					# Take this one out.
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0685", variables => { 
						name => $bond_name,
						uuid => $bond_uuid,
					}});
					
					my $queries = [];
					push @{$queries}, "DELETE FROM history.network_interfaces WHERE network_interface_bond_uuid = ".$anvil->Database->quote($bond_uuid).";";
					push @{$queries}, "DELETE FROM network_interfaces WHERE network_interface_bond_uuid = ".$anvil->Database->quote($bond_uuid).";";
					push @{$queries}, "DELETE FROM history.bonds WHERE bond_uuid = ".$anvil->Database->quote($bond_uuid).";";
					push @{$queries}, "DELETE FROM bonds WHERE bond_uuid = ".$anvil->Database->quote($bond_uuid).";";
					
					# Write it out.
					$anvil->Database->write({debug => 2, query => $queries, source => $THIS_FILE, line => __LINE__});
					
					$count--;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }});
					
					$anvil->data->{deleted_bonds}{$bond_uuid} = 1;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						"deleted_bonds::${bond_uuid}" => $anvil->data->{deleted_bonds}{$bond_uuid},
					}});
				}
			}
			
			# If count is still > 1, we need to arbitrarily delete an interface.
			if ($count > 1)
			{
				foreach my $bond_uuid (@{$anvil->data->{duplicate_bonds}{seen}{$bond_name}})
				{
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0685", variables => { 
						name => $bond_name,
						uuid => $bond_uuid,
					}});
					
					my $queries = [];
					push @{$queries}, "DELETE FROM history.network_interfaces WHERE network_interface_bond_uuid = ".$anvil->Database->quote($bond_uuid).";";
					push @{$queries}, "DELETE FROM network_interfaces WHERE network_interface_bond_uuid = ".$anvil->Database->quote($bond_uuid).";";
					push @{$queries}, "DELETE FROM history.bonds WHERE bond_uuid = ".$anvil->Database->quote($bond_uuid).";";
					push @{$queries}, "DELETE FROM bonds WHERE bond_uuid = ".$anvil->Database->quote($bond_uuid).";";
					
					# Write it out.
					$anvil->Database->write({debug => 2, query => $queries, source => $THIS_FILE, line => __LINE__});
					
					$count--;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }});
					
					$anvil->data->{deleted_bonds}{$bond_uuid} = 1;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						"deleted_bonds::${bond_uuid}" => $anvil->data->{deleted_bonds}{$bond_uuid},
					}});
				}
				last if $count == 1;
			}
		}
	}
	delete $anvil->data->{duplicate_bonds};
	
	
	# Look for duplicate network interfaces
	$query = "
SELECT 
    network_interface_uuid, 
    network_interface_name, 
    network_interface_mac_address, 
    network_interface_operational, 
    network_interface_bond_uuid, 
    network_interface_bridge_uuid 
FROM 
    network_interfaces 
WHERE 
    network_interface_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." 
ORDER BY 
    network_interface_name ASC
;";
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }});
	$results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
	$count   = @{$results};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		results => $results, 
		count   => $count,
	}});
	foreach my $row (@{$results})
	{
		my $network_interface_uuid        =         $row->[0];
		my $network_interface_name        =         $row->[1];
		my $network_interface_mac_address =         $row->[2];
		my $network_interface_operational =         $row->[3];
		my $network_interface_bond_uuid   = defined $row->[4] ? $row->[4] : "";
		my $network_interface_bridge_uuid = defined $row->[5] ? $row->[5] : "";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			network_interface_uuid        => $network_interface_uuid, 
			network_interface_name        => $network_interface_name, 
			network_interface_mac_address => $network_interface_mac_address, 
			network_interface_operational => $network_interface_operational, 
			network_interface_bond_uuid   => $network_interface_bond_uuid, 
			network_interface_bridge_uuid => $network_interface_bridge_uuid, 
		}});
		
		if (not exists $anvil->data->{duplicate_nics}{seen}{$network_interface_name})
		{
			$anvil->data->{duplicate_nics}{seen}{$network_interface_name} = [];
		}
		push @{$anvil->data->{duplicate_nics}{seen}{$network_interface_name}}, $network_interface_uuid;
		
		$anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_name}        = $network_interface_name;
		$anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_mac_address} = $network_interface_mac_address;
		$anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_operational} = $network_interface_operational;
		$anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_bond_uuid}   = $network_interface_bond_uuid;
		$anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_bridge_uuid} = $network_interface_bridge_uuid;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"duplicate_nics::network_interface_uuid::${network_interface_uuid}::network_interface_name"        => $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_name}, 
			"duplicate_nics::network_interface_uuid::${network_interface_uuid}::network_interface_mac_address" => $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_mac_address}, 
			"duplicate_nics::network_interface_uuid::${network_interface_uuid}::network_interface_operational" => $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_operational}, 
			"duplicate_nics::network_interface_uuid::${network_interface_uuid}::network_interface_bond_uuid"   => $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_bond_uuid}, 
			"duplicate_nics::network_interface_uuid::${network_interface_uuid}::network_interface_bridge_uuid" => $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_bridge_uuid}, 
		}});
	}
	foreach my $network_interface_name (sort {$a cmp $b} keys %{$anvil->data->{duplicate_nics}{seen}})
	{
		my $count = @{$anvil->data->{duplicate_nics}{seen}{$network_interface_name}};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			's1:network_interface_name' => $network_interface_name, 
			's2:count'                  => $count,
		}});
		
		if ($count > 1)
		{
			# Duplicate! Is one of them marked as DELETED?
			foreach my $network_interface_uuid (@{$anvil->data->{duplicate_nics}{seen}{$network_interface_name}})
			{
				# Is this one deleted?
				my $network_interface_mac_address = $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_mac_address};
				my $network_interface_operational = $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_operational};
				my $network_interface_bond_uuid   = $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_bond_uuid};
				my $network_interface_bridge_uuid = $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_bridge_uuid};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					network_interface_uuid        => $network_interface_uuid, 
					network_interface_mac_address => $network_interface_mac_address, 
					network_interface_operational => $network_interface_operational, 
					network_interface_bond_uuid   => $network_interface_bond_uuid, 
					network_interface_bridge_uuid => $network_interface_bridge_uuid, 
				}});
				if ((($network_interface_bond_uuid)   && ($anvil->data->{deleted_bonds}{$network_interface_bond_uuid}))     or 
				    (($network_interface_bridge_uuid) && ($anvil->data->{deleted_bridges}{$network_interface_bridge_uuid})) or 
				     ($network_interface_operational eq "DELETED"))
				{
					# Take this one out.
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0647", variables => { 
						name => $network_interface_name,
						uuid => $network_interface_uuid,
					}});
					
					my $queries = [];
					push @{$queries}, "DELETE FROM history.network_interfaces WHERE network_interface_uuid = ".$anvil->Database->quote($network_interface_uuid).";";
					push @{$queries}, "DELETE FROM network_interfaces WHERE network_interface_uuid = ".$anvil->Database->quote($network_interface_uuid).";";
					foreach my $query (@{$queries})
					{
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
					}
					$anvil->Database->write({query => $queries, source => $THIS_FILE, line => __LINE__});
					
					$count--;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }});
				}
			}
			
			# If count is still > 1, we need to arbitrarily delete an interface.
			if ($count > 1)
			{
				foreach my $network_interface_uuid (@{$anvil->data->{duplicate_nics}{seen}{$network_interface_name}})
				{
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0647", variables => { 
						name => $network_interface_name,
						uuid => $network_interface_uuid,
					}});
					
					my $queries = [];
					push @{$queries}, "DELETE FROM history.network_interfaces WHERE network_interface_uuid = ".$anvil->Database->quote($network_interface_uuid).";";
					push @{$queries}, "DELETE FROM network_interfaces WHERE network_interface_uuid = ".$anvil->Database->quote($network_interface_uuid).";";
					foreach my $query (@{$queries})
					{
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
					}
					$anvil->Database->write({query => $queries, source => $THIS_FILE, line => __LINE__});
					
					$count--;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }});
				}
				last if $count == 1;
			}
		}
	}
	
	delete $anvil->data->{duplicate_nics};
	
	$query = "
SELECT 
    ip_address_uuid, 
    ip_address_address, 
    ip_address_note 
FROM 
    ip_addresses 
WHERE 
    ip_address_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." 
ORDER BY 
    ip_address_address ASC
;";
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }});
	$results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
	$count   = @{$results};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		results => $results, 
		count   => $count,
	}});
	foreach my $row (@{$results})
	{
		my $ip_address_uuid    = $row->[0];
		my $ip_address_address = $row->[1];
		my $ip_address_note    = $row->[2];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			ip_address_uuid    => $ip_address_uuid, 
			ip_address_address => $ip_address_address, 
			ip_address_note    => $ip_address_note, 
		}});
		
		if (not exists $anvil->data->{duplicate_ips}{seen}{$ip_address_address})
		{
			$anvil->data->{duplicate_ips}{seen}{$ip_address_address} = [];
		}
		push @{$anvil->data->{duplicate_ips}{seen}{$ip_address_address}}, $ip_address_uuid;
		
		$anvil->data->{duplicate_ips}{ip_address_uuid}{$ip_address_uuid}{ip_address_address} = $ip_address_address;
		$anvil->data->{duplicate_ips}{ip_address_uuid}{$ip_address_uuid}{ip_address_note}    = $ip_address_note;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"duplicate_ips::ip_address_uuid::${ip_address_uuid}::ip_address_address" => $anvil->data->{duplicate_ips}{ip_address_uuid}{$ip_address_uuid}{ip_address_address}, 
			"duplicate_ips::ip_address_uuid::${ip_address_uuid}::ip_address_note"    => $anvil->data->{duplicate_ips}{ip_address_uuid}{$ip_address_uuid}{ip_address_note}, 
		}});
	}
	foreach my $ip_address_address (sort {$a cmp $b} keys %{$anvil->data->{duplicate_ips}{seen}})
	{
		my $count = @{$anvil->data->{duplicate_ips}{seen}{$ip_address_address}};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			's1:ip_address_address' => $ip_address_address, 
			's2:count'              => $count,
		}});
		
		if ($count > 1)
		{
			# Duplicate! Is one of them marked as DELETED?
			foreach my $ip_address_uuid (@{$anvil->data->{duplicate_ips}{seen}{$ip_address_address}})
			{
				# Is this one deleted?
				my $ip_address_note = $anvil->data->{duplicate_ips}{ip_address_uuid}{$ip_address_uuid}{ip_address_note};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					ip_address_uuid => $ip_address_uuid, 
					ip_address_note => $anvil->data->{duplicate_ips}{ip_address_uuid}{$ip_address_uuid}{ip_address_note}, 
				}});
				if ($ip_address_note eq "DELETED")
				{
					# Take this one out.
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0664", variables => { 
						ip   => $ip_address_address,
						uuid => $ip_address_uuid,
					}});
					
					my $queries = [];
					push @{$queries}, "DELETE FROM history.ip_addresses WHERE ip_address_uuid = ".$anvil->Database->quote($ip_address_uuid).";";
					push @{$queries}, "DELETE FROM ip_addresses WHERE ip_address_uuid = ".$anvil->Database->quote($ip_address_uuid).";";
					foreach my $query (@{$queries})
					{
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
					}
					$anvil->Database->write({query => $queries, source => $THIS_FILE, line => __LINE__});
					
					$count--;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }});
				}
				last if $count == 1;
			}
			
			# If count is still > 1, we need to arbitrarily delete an interface.
			if ($count > 1)
			{
				foreach my $ip_address_uuid (@{$anvil->data->{duplicate_ips}{seen}{$ip_address_address}})
				{
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0664", variables => { 
						ip   => $ip_address_address,
						uuid => $ip_address_uuid,
					}});
					
					my $queries = [];
					push @{$queries}, "DELETE FROM history.ip_addresses WHERE ip_address_uuid = ".$anvil->Database->quote($ip_address_uuid).";";
					push @{$queries}, "DELETE FROM ip_addresses WHERE ip_address_uuid = ".$anvil->Database->quote($ip_address_uuid).";";
					foreach my $query (@{$queries})
					{
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
					}
					$anvil->Database->write({query => $queries, source => $THIS_FILE, line => __LINE__});
					
					$count--;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }});
				}
				last if $count == 1;
			}
		}
	}
	
	
	return(0);
}

sub load_ip_address_data
{
	my ($anvil) = @_;
	
	# Now record the IPs.
	my $query = "
SELECT 
    ip_address_uuid, 
    ip_address_on_type, 
    ip_address_on_uuid, 
    ip_address_address, 
    ip_address_subnet_mask, 
    ip_address_gateway, 
    ip_address_default_gateway, 
    ip_address_dns, 
    ip_address_note 
FROM 
    ip_addresses 
WHERE 
    ip_address_host_uuid =  ".$anvil->Database->quote($anvil->data->{sys}{host_uuid})."
;";
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }});
	my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
	my $count   = @{$results};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		results => $results, 
		count   => $count,
	}});
	foreach my $row (@{$results})
	{
		my $ip_address_uuid    = $row->[0];
		my $ip_address_on_type = $row->[1];
		my $ip_address_address = $row->[3];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			ip_address_uuid    => $ip_address_uuid, 
			ip_address_on_type => $ip_address_on_type, 
			ip_address_address => $ip_address_address, 
		}});
		
		$anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_on_type}         = $ip_address_on_type;
		$anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_on_uuid}         = $row->[2];
		$anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_address}         = $ip_address_address;
		$anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_subnet_mask}     = $row->[4];
		$anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_gateway}         = $row->[5];
		$anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_default_gateway} = $row->[6];
		$anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_dns}             = $row->[7];
		$anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_note}            = $row->[8];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"old::ip_addresses::ip_address_uuid::${ip_address_uuid}::ip_address_on_type"         => $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_on_type}, 
			"old::ip_addresses::ip_address_uuid::${ip_address_uuid}::ip_address_on_uuid"         => $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_on_uuid}, 
			"old::ip_addresses::ip_address_uuid::${ip_address_uuid}::ip_address_address"         => $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_address}, 
			"old::ip_addresses::ip_address_uuid::${ip_address_uuid}::ip_address_subnet_mask"     => $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_subnet_mask}, 
			"old::ip_addresses::ip_address_uuid::${ip_address_uuid}::ip_address_gateway"         => $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_gateway}, 
			"old::ip_addresses::ip_address_uuid::${ip_address_uuid}::ip_address_default_gateway" => $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_default_gateway}, 
			"old::ip_addresses::ip_address_uuid::${ip_address_uuid}::ip_address_dns"             => $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_dns}, 
			"old::ip_addresses::ip_address_uuid::${ip_address_uuid}::ip_address_note"            => $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_note}, 
		}});
		
		$anvil->data->{old}{ip_addresses}{ip_to_uuid}{$ip_address_address} = $ip_address_uuid;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"old::ip_addresses::ip_to_uuid::${ip_address_address}" => $anvil->data->{old}{ip_addresses}{ip_to_uuid}{$ip_address_address}, 
		}});
	}
	
	return(0);
}

sub load_interface_data
{
	my ($anvil) = @_;
	
	# Process interfaces
	my $query = "
SELECT 
    network_interface_uuid,  
    network_interface_nm_uuid, 
    network_interface_mac_address, 
    network_interface_name, 
    network_interface_device, 
    network_interface_speed, 
    network_interface_mtu, 
    network_interface_link_state, 
    network_interface_operational, 
    network_interface_duplex, 
    network_interface_medium, 
    network_interface_bond_uuid, 
    network_interface_bridge_uuid 
FROM 
    network_interfaces 
WHERE 
    network_interface_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." 
;";
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }});
	my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
	my $count   = @{$results};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		results => $results, 
		count   => $count,
	}});
	
	foreach my $row (@{$results})
	{
		my $network_interface_uuid        = $row->[0];
		my $network_interface_mac_address = $row->[2];
		my $network_interface_name        = $row->[3];
		my $network_interface_device      = $row->[4];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			network_interface_uuid        => $network_interface_uuid,
			network_interface_mac_address => $network_interface_mac_address, 
			network_interface_name        => $network_interface_name, 
			network_interface_device      => $network_interface_device, 
		}});
		
		# Read in the RX/TX values, set to '0' if not found.
		my ($rx_bytes, $rx_variable_uuid, $modified_date) = $anvil->Database->read_variable({
			variable_name         => "network_interface::".$network_interface_name."::rx_bytes",
			variable_source_uuid  => $network_interface_uuid, 
			variable_source_table => "network_interfaces", 
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			rx_bytes         => $rx_bytes, 
			rx_variable_uuid => $rx_variable_uuid, 
		}});
		(my $tx_bytes, my $tx_variable_uuid, $modified_date) = $anvil->Database->read_variable({
			variable_name         => "network_interface::".$network_interface_name."::tx_bytes",
			variable_source_uuid  => $network_interface_uuid, 
			variable_source_table => "network_interfaces", 
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			tx_bytes         => $tx_bytes, 
			tx_variable_uuid => $tx_variable_uuid, 
		}});
		
		$anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_nm_uuid}     =         $row->[1];
		$anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_mac_address} =         $network_interface_mac_address;
		$anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_name}        =         $network_interface_name;
		$anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_device}      =         $network_interface_device;
		$anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_speed}       =         $row->[5];
		$anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_mtu}         =         $row->[6];
		$anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_link_state}  =         $row->[7];
		$anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_operational} =         $row->[8];
		$anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_duplex}      =         $row->[9];
		$anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_medium}      =         $row->[10];
		$anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_bond_uuid}   = defined $row->[11] ? $row->[11] : '';
		$anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_bridge_uuid} = defined $row->[12] ? $row->[12] : '';
		$anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{rx_bytes}                      = $rx_bytes =~ /^\d+$/ ? $rx_bytes : 0;
		$anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{rx_variable_uuid}              = $rx_variable_uuid;
		$anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{tx_bytes}                      = $tx_bytes =~ /^\d+$/ ? $tx_bytes : 0;
		$anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{tx_variable_uuid}              = $tx_variable_uuid;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"old::network_interfaces::network_interface_uuid::${network_interface_uuid}::network_interface_nm_uuid"     => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_nm_uuid},
			"old::network_interfaces::network_interface_uuid::${network_interface_uuid}::network_interface_mac_address" => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_mac_address},
			"old::network_interfaces::network_interface_uuid::${network_interface_uuid}::network_interface_name"        => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_name},
			"old::network_interfaces::network_interface_uuid::${network_interface_uuid}::network_interface_device"      => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_device},
			"old::network_interfaces::network_interface_uuid::${network_interface_uuid}::network_interface_speed"       => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_speed},
			"old::network_interfaces::network_interface_uuid::${network_interface_uuid}::network_interface_mtu"         => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_mtu},
			"old::network_interfaces::network_interface_uuid::${network_interface_uuid}::network_interface_link_state"  => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_link_state},
			"old::network_interfaces::network_interface_uuid::${network_interface_uuid}::network_interface_operational" => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_operational},
			"old::network_interfaces::network_interface_uuid::${network_interface_uuid}::network_interface_duplex"      => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_duplex},
			"old::network_interfaces::network_interface_uuid::${network_interface_uuid}::network_interface_medium"      => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_medium},
			"old::network_interfaces::network_interface_uuid::${network_interface_uuid}::network_interface_bond_uuid"   => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_bond_uuid},
			"old::network_interfaces::network_interface_uuid::${network_interface_uuid}::network_interface_bridge_uuid" => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_bridge_uuid},
			"old::network_interfaces::network_interface_uuid::${network_interface_uuid}::rx_bytes"                      => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{rx_bytes}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{rx_bytes}}).")", 
			"old::network_interfaces::network_interface_uuid::${network_interface_uuid}::rx_variable_uuid"              => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{rx_variable_uuid}, 
			"old::network_interfaces::network_interface_uuid::${network_interface_uuid}::tx_bytes"                      => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{tx_bytes}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{tx_bytes}}).")", 
			"old::network_interfaces::network_interface_uuid::${network_interface_uuid}::tx_variable_uuid"              => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{tx_variable_uuid}, 
		}});
		
		$anvil->data->{network_interfaces}{name_to_uuid}{$network_interface_name}       = $network_interface_uuid;
		$anvil->data->{network_interfaces}{device_to_uuid}{$network_interface_device}   = $network_interface_uuid;
		$anvil->data->{network_interfaces}{uuid_to_name}{$network_interface_uuid}       = $network_interface_name;
		$anvil->data->{network_interfaces}{mac_to_uuid}{$network_interface_mac_address} = $network_interface_uuid;
		$anvil->data->{interface}{name_to_uuid}{$network_interface_name}                = $network_interface_uuid;
		$anvil->data->{interface}{device_to_uuid}{$network_interface_device}            = $network_interface_uuid;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"network_interfaces::name_to_uuid::${network_interface_name}"       => $anvil->data->{network_interfaces}{name_to_uuid}{$network_interface_name},
			"network_interfaces::device_to_uuid::${network_interface_device}"   => $anvil->data->{network_interfaces}{device_to_uuid}{$network_interface_device},
			"network_interfaces::uuid_to_name::${network_interface_name}"       => $anvil->data->{network_interfaces}{uuid_to_name}{$network_interface_uuid},
			"network_interfaces::mac_to_uuid::${network_interface_mac_address}" => $anvil->data->{network_interfaces}{mac_to_uuid}{$network_interface_mac_address},
			"interface::name_to_uuid::${network_interface_name}"                => $anvil->data->{interface}{name_to_uuid}{$network_interface_name}, 
			"interface::device_to_uuid::${network_interface_device}"            => $anvil->data->{interface}{device_to_uuid}{$network_interface_device}, 
		}});
	}
	
	return(0);
}

sub load_bond_data
{
	my ($anvil) = @_;
	
	# 'bond_mode' will be 'DELETED' if the bond was removed.
	my $query = "
SELECT 
    bond_uuid, 
    bond_name, 
    bond_mode, 
    bond_mtu, 
    bond_primary_interface, 
    bond_primary_reselect, 
    bond_active_interface, 
    bond_mii_polling_interval, 
    bond_up_delay, 
    bond_down_delay, 
    bond_mac_address, 
    bond_operational, 
    bond_bridge_uuid 
FROM 
    bonds 
WHERE 
    bond_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)."
;";
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }});
	my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
	my $count   = @{$results};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		results => $results, 
		count   => $count,
	}});
	foreach my $row (@{$results})
	{
		my $bond_uuid        =         $row->[0];
		my $bond_name        =         $row->[1];
		my $bond_bridge_uuid = defined $row->[12] ? $row->[12] : "";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			bond_uuid        => $bond_uuid, 
			bond_name        => $bond_name, 
			bond_bridge_uuid => $bond_bridge_uuid, 
		}});
		
		# Read in the RX/TX values, set to '0' if not found.
		my ($rx_bytes, $rx_variable_uuid, $modified_date) = $anvil->Database->read_variable({
			debug                 => 2,
			variable_name         => "bond::".$bond_name."::rx_bytes",
			variable_source_uuid  => $bond_uuid, 
			variable_source_table => "bonds", 
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			rx_bytes         => $rx_bytes, 
			rx_variable_uuid => $rx_variable_uuid, 
		}});
		(my $tx_bytes, my $tx_variable_uuid, $modified_date) = $anvil->Database->read_variable({
			debug                 => 2,
			variable_name         => "bond::".$bond_name."::tx_bytes",
			variable_source_uuid  => $bond_uuid, 
			variable_source_table => "bonds", 
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			tx_bytes         => $tx_bytes, 
			tx_variable_uuid => $tx_variable_uuid, 
		}});
		
		$anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_name}                 = $bond_name;
		$anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_mode}                 = $row->[2];
		$anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_mtu}                  = $row->[3];
		$anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_primary_interface}    = $row->[4];
		$anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_primary_reselect}     = $row->[5];
		$anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_active_interface}     = $row->[6];
		$anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_mii_polling_interval} = $row->[7];
		$anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_up_delay}             = $row->[8];
		$anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_down_delay}           = $row->[9];
		$anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_mac_address}          = $row->[10];
		$anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_operational}          = $row->[11];
		$anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_bridge_uuid}          = $bond_bridge_uuid;
		$anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{rx_bytes}                  = $rx_bytes =~ /\d/ ? $rx_bytes : 0;
		$anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{rx_variable_uuid}          = $rx_variable_uuid;
		$anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{tx_bytes}                  = $tx_bytes =~ /\d/ ? $tx_bytes : 0;
		$anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{tx_variable_uuid}          = $tx_variable_uuid;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"old::bonds::bond_uuid::${bond_uuid}::bond_name"                 => $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_name},
			"old::bonds::bond_uuid::${bond_uuid}::bond_mode"                 => $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_mode},
			"old::bonds::bond_uuid::${bond_uuid}::bond_mtu"                  => $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_mtu},
			"old::bonds::bond_uuid::${bond_uuid}::bond_primary_interface"    => $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_primary_interface},
			"old::bonds::bond_uuid::${bond_uuid}::bond_primary_reselect"     => $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_primary_reselect},
			"old::bonds::bond_uuid::${bond_uuid}::bond_active_interface"     => $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_active_interface},
			"old::bonds::bond_uuid::${bond_uuid}::bond_mii_polling_interval" => $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_mii_polling_interval},
			"old::bonds::bond_uuid::${bond_uuid}::bond_up_delay"             => $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_up_delay},
			"old::bonds::bond_uuid::${bond_uuid}::bond_down_delay"           => $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_down_delay},
			"old::bonds::bond_uuid::${bond_uuid}::bond_mac_address"          => $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_mac_address},
			"old::bonds::bond_uuid::${bond_uuid}::bond_operational"          => $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_operational},
			"old::bonds::bond_uuid::${bond_uuid}::bond_bridge_uuid"          => $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_bridge_uuid},
			"old::bonds::bond_uuid::${bond_uuid}::rx_bytes"                  => $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{rx_bytes}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{rx_bytes}}).")", 
			"old::bonds::bond_uuid::${bond_uuid}::rx_variable_uuid"          => $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{rx_variable_uuid}, 
			"old::bonds::bond_uuid::${bond_uuid}::tx_bytes"                  => $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{tx_bytes}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{tx_bytes}}).")", 
			"old::bonds::bond_uuid::${bond_uuid}::tx_variable_uuid"          => $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{tx_variable_uuid}, 
		}});
		
		$anvil->data->{bonds}{name_to_uuid}{$bond_name}     = $bond_uuid;
		$anvil->data->{bonds}{uuid_to_name}{$bond_uuid}     = $bond_name;
		$anvil->data->{interface}{name_to_uuid}{$bond_name} = $bond_uuid;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"bonds::name_to_uuid::${bond_name}"     => $anvil->data->{bonds}{name_to_uuid}{$bond_name}, 
			"bonds::uuid_to_name::${bond_uuid}"     => $anvil->data->{bonds}{uuid_to_name}{$bond_uuid}, 
			"interface::name_to_uuid::${bond_name}" => $anvil->data->{interface}{name_to_uuid}{$bond_name}, 
		}});
	}
	
	return(0);
}

sub load_bridge_data
{
	my ($anvil) = @_;
	
	# The 'bridge_id' will be DELETED if the bridge was removed earlier.
	my $query = "
SELECT 
    bridge_uuid, 
    bridge_name, 
    bridge_id, 
    bridge_mac_address, 
    bridge_mtu,  
    bridge_stp_enabled 
FROM 
    bridges 
WHERE 
    bridge_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)."
;";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
	my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
	my $count   = @{$results};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		results => $results, 
		count   => $count, 
	}});
	foreach my $row (@{$results})
	{
		my $bridge_uuid = $row->[0];
		my $bridge_name = $row->[1];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			bridge_uuid => $bridge_uuid, 
			bridge_name => $bridge_name, 
		}});
		
		# Read in the RX/TX values, set to '0' if not found.
		my ($rx_bytes, $rx_variable_uuid, $modified_date) = $anvil->Database->read_variable({
			debug                 => 2,
			variable_name         => "bridge::".$bridge_name."::rx_bytes",
			variable_source_uuid  => $bridge_uuid, 
			variable_source_table => "bridges", 
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			rx_bytes         => $rx_bytes, 
			rx_variable_uuid => $rx_variable_uuid, 
		}});
		(my $tx_bytes, my $tx_variable_uuid, $modified_date) = $anvil->Database->read_variable({
			debug                 => 2,
			variable_name         => "bridge::".$bridge_name."::tx_bytes",
			variable_source_uuid  => $bridge_uuid, 
			variable_source_table => "bridges", 
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			tx_bytes         => $tx_bytes, 
			tx_variable_uuid => $tx_variable_uuid, 
		}});
		
		# Record the data in the hash, too.
		$anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{bridge_name}        = $bridge_name;
		$anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{bridge_id}          = $row->[2];
		$anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{bridge_mac_address} = $row->[3];
		$anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{bridge_mtu}         = $row->[4];
		$anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{bridge_stp_enabled} = $row->[5];
		$anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{rx_bytes}           = $rx_bytes =~ /\d/ ? $rx_bytes : 0;
		$anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{rx_variable_uuid}   = $rx_variable_uuid;
		$anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{tx_bytes}           = $tx_bytes =~ /\d/ ? $tx_bytes : 0;
		$anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{tx_variable_uuid}   = $tx_variable_uuid;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"old::bridges::bridge_uuid::${bridge_uuid}::bridge_name"        => $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{bridge_name}, 
			"old::bridges::bridge_uuid::${bridge_uuid}::bridge_id"          => $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{bridge_id}, 
			"old::bridges::bridge_uuid::${bridge_uuid}::bridge_mac_address" => $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{bridge_mac_address}, 
			"old::bridges::bridge_uuid::${bridge_uuid}::bridge_mtu"         => $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{bridge_mtu}, 
			"old::bridges::bridge_uuid::${bridge_uuid}::bridge_stp_enabled" => $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{bridge_stp_enabled}, 
			"old::bridges::bridge_uuid::${bridge_uuid}::rx_bytes"           => $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{rx_bytes}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{rx_bytes}}).")", 
			"old::bridges::bridge_uuid::${bridge_uuid}::rx_variable_uuid"   => $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{rx_variable_uuid}, 
			"old::bridges::bridge_uuid::${bridge_uuid}::tx_bytes"           => $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{tx_bytes}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{tx_bytes}}).")", 
			"old::bridges::bridge_uuid::${bridge_uuid}::tx_variable_uuid"   => $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{tx_variable_uuid}, 
		}});
		
		$anvil->data->{bridges}{name_to_uuid}{$bridge_name}   = $bridge_uuid;
		$anvil->data->{bridges}{uuid_to_name}{$bridge_uuid}   = $bridge_name;
		$anvil->data->{interface}{name_to_uuid}{$bridge_name} = $bridge_uuid;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"bridges::name_to_uuid::${bridge_name}"   => $anvil->data->{bridges}{name_to_uuid}{$bridge_name}, 
			"bridges::uuid_to_name::${bridge_uuid}"   => $anvil->data->{bridges}{uuid_to_name}{$bridge_uuid}, 
			"interface::name_to_uuid::${bridge_name}" => $anvil->data->{interface}{name_to_uuid}{$bridge_name},
		}});
	}
	
	return(0);
}

# This compares the last scan and the read state info and handles changes.
sub find_changes
{
	my ($anvil) = @_;
	
	check_bridges($anvil);
	check_bonds($anvil);
	check_interfaces($anvil);
	check_ip_addresses($anvil);

	return(0);
}

# Handle IP addresses
sub check_ip_addresses
{
	my ($anvil) = @_;
	
	foreach my $ip_address (sort {$a cmp $b} keys %{$anvil->data->{new}{ip_address}})
	{
		my $on_interface        = $anvil->data->{new}{ip_address}{$ip_address}{on_interface};
		my $new_on_type         = $anvil->data->{interface}{name_to_type}{$on_interface};
		my $new_subnet_mask     = $anvil->data->{new}{ip_address}{$ip_address}{subnet_mask};
		my $new_gateway         = $anvil->data->{new}{ip_address}{$ip_address}{gateway};
		my $new_default_gateway = $anvil->data->{new}{ip_address}{$ip_address}{default_gateway};
		my $new_dns             = $anvil->data->{new}{ip_address}{$ip_address}{dns};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			ip_address          => $ip_address, 
			on_interface        => $on_interface, 
			new_on_type         => $new_on_type, 
			new_subnet_mask     => $new_subnet_mask, 
			new_gateway         => $new_gateway, 
			new_default_gateway => $new_default_gateway, 
			new_dns             => $new_dns, 
		}});
		my $new_on_uuid = "";
		if ($anvil->data->{interface}{name_to_uuid}{$on_interface})
		{
			$new_on_uuid = $anvil->data->{interface}{name_to_uuid}{$on_interface};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_on_uuid => $new_on_uuid }});
		}
		elsif ($anvil->data->{interface}{device_to_uuid}{$on_interface})
		{
			$new_on_uuid = $anvil->data->{interface}{device_to_uuid}{$on_interface};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_on_uuid => $new_on_uuid }});
		}
		
		if (exists $anvil->data->{old}{ip_addresses}{ip_to_uuid}{$ip_address})
		{
			# Existing, update?
			my $ip_address_uuid     = $anvil->data->{old}{ip_addresses}{ip_to_uuid}{$ip_address};
			my $old_on_type         = $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_on_type};
			my $old_on_uuid         = $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_on_uuid};
			my $old_subnet_mask     = $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_subnet_mask};
			my $old_gateway         = $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_gateway};
			my $old_default_gateway = $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_default_gateway};
			my $old_dns             = $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_dns};
			my $old_note            = $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_note};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				ip_address          => $ip_address, 
				old_on_type         => $old_on_type, 
				old_on_uuid         => $old_on_uuid, 
				old_subnet_mask     => $old_subnet_mask, 
				old_gateway         => $old_gateway, 
				old_default_gateway => $old_default_gateway, 
				old_dns             => $old_dns, 
				old_note            => $old_note, 
			}});
			
			# Delete this old entry so we know we've processed it.
			delete $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid};
			
			my $say_old_interface = "--";
			if ($old_on_type eq "bridge")
			{
				$say_old_interface = $anvil->data->{bridges}{uuid_to_name}{$old_on_uuid};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { say_old_interface => $say_old_interface }});
			}
			elsif ($old_on_type eq "bond")
			{
				$say_old_interface = $anvil->data->{bonds}{uuid_to_name}{$old_on_uuid};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { say_old_interface => $say_old_interface }});
			}
			elsif ($old_on_type eq "interface")
			{
				$say_old_interface = $anvil->data->{network_interfaces}{uuid_to_name}{$old_on_uuid};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { say_old_interface => $say_old_interface }});
			}
			
			# Now look for changes.
			my $changes = 0;
			
			# These will always change together.
			if (($new_on_type ne $old_on_type) or ($new_on_uuid ne $old_on_uuid))
			{
				# This was likely changed by an admin, so it's a notice level alert.
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
				
				my $variables = {
					ip_address => $ip_address,
					old        => $say_old_interface, 
					new        => $on_interface,
				};
				
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0050", variables => $variables});
				$anvil->Alert->register({
					alert_level => "notice", 
					message     => "scan_network_alert_0050", 
					variables   => $variables,
					set_by      => $THIS_FILE,
				});
			}
			if ($new_subnet_mask ne $old_subnet_mask)
			{
				# This was likely changed by an admin, so it's a notice level alert.
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
				
				my $variables = {
					ip_address => $ip_address,
					interface  => $on_interface,
					old        => $ip_address."/".$old_subnet_mask, 
					new        => $ip_address."/".$new_subnet_mask,
				};
				
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0051", variables => $variables});
				$anvil->Alert->register({
					alert_level => "notice", 
					message     => "scan_network_alert_0051", 
					variables   => $variables,
					set_by      => $THIS_FILE,
				});
			}
			if ($new_gateway ne $old_gateway)
			{
				# This was likely changed by an admin, so it's a notice level alert.
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
				
				my $variables = {
					ip_address => $ip_address,
					interface  => $on_interface,
					old        => $old_gateway eq "" ? "--" : $old_gateway, 
					new        => $new_gateway eq "" ? "--" : $new_gateway,
				};
				
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0052", variables => $variables});
				$anvil->Alert->register({
					alert_level => "notice", 
					message     => "scan_network_alert_0052", 
					variables   => $variables,
					set_by      => $THIS_FILE,
				});
			}
			if ($new_default_gateway ne $old_default_gateway)
			{
				# This was likely changed by an admin, so it's a notice level alert.
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
				
				my $variables = {
					ip_address => $ip_address,
					interface  => $on_interface,
					old        => $old_default_gateway ? "#!string!unit_0001!#" : "#!string!unit_0002!#", 
					new        => $new_default_gateway ? "#!string!unit_0001!#" : "#!string!unit_0002!#",
				};
				
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0053", variables => $variables});
				$anvil->Alert->register({
					alert_level => "notice", 
					message     => "scan_network_alert_0053", 
					variables   => $variables,
					set_by      => $THIS_FILE,
				});
			}
			if ($new_dns ne $old_dns)
			{
				# This was likely changed by an admin, so it's a notice level alert.
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
				
				my $variables = {
					ip_address => $ip_address,
					interface  => $on_interface,
					old        => $old_dns eq "" ? "--" : $old_dns, 
					new        => $new_dns eq "" ? "--" : $new_dns,
				};
				
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0054", variables => $variables});
				$anvil->Alert->register({
					alert_level => "notice", 
					message     => "scan_network_alert_0054", 
					variables   => $variables,
					set_by      => $THIS_FILE,
				});
			}
			
			# We only care about 'old_note' if it's set to 'DELETED'.
			if ($old_note eq "DELETED")
			{
				# This was likely changed by an admin, so it's a notice level alert.
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
				
				my $variables = {
					ip_address => $ip_address,
					interface  => $on_interface,
				};
				
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0055", variables => $variables});
				$anvil->Alert->register({
					alert_level => "notice", 
					message     => "scan_network_alert_0055", 
					variables   => $variables,
					set_by      => $THIS_FILE,
				});
			}
			
			if ($changes)
			{
				# If the note was 'DELETED', change it to ''. Otherwise, use the old note.
				$old_note = "" if $old_note eq "DELETED";
				my $ip_address_uuid = $anvil->Database->insert_or_update_ip_addresses({
					debug                      => 2,
					ip_address_uuid            => $ip_address_uuid,
					ip_address_on_type         => $new_on_type, 
					ip_address_on_uuid         => $new_on_uuid, 
					ip_address_address         => $ip_address, 
					ip_address_subnet_mask     => $new_subnet_mask, 
					ip_address_gateway         => $new_gateway, 
					ip_address_default_gateway => $new_default_gateway, 
					ip_address_dns             => $new_dns, 
					ip_address_note            => $old_note,
				});
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ip_address_uuid => $ip_address_uuid }});
			}
		}
		else
		{
			# New, store.
			my $ip_address_uuid = $anvil->Database->insert_or_update_ip_addresses({
				debug                      => 2,
				ip_address_on_type         => $new_on_type, 
				ip_address_on_uuid         => $new_on_uuid, 
				ip_address_address         => $ip_address, 
				ip_address_subnet_mask     => $new_subnet_mask, 
				ip_address_gateway         => $new_gateway, 
				ip_address_default_gateway => $new_default_gateway, 
				ip_address_dns             => $new_dns, 
				ip_address_note            => "",
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ip_address_uuid => $ip_address_uuid }});
			
			# Register a notice level alert.
			my $variables = {
				ip_address      => $ip_address,
				interface       => $on_interface,
				subnet_mask     => $new_subnet_mask, 
				gateway         => $new_gateway         eq "" ? "--"                   : $new_gateway,
				default_gateway => $new_default_gateway       ? "#!string!unit_0001!#" : "#!string!unit_0002!#",
				dns             => $new_dns             eq "" ? "--"                   : $new_dns, 
			};
			
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0056", variables => $variables});
			$anvil->Alert->register({
				alert_level => "notice", 
				message     => "scan_network_alert_0056", 
				variables   => $variables,
				set_by      => $THIS_FILE,
			});
		}
	}
	
	# Look for left over / deleted bonds.
	$anvil->Database->get_mac_to_ip({debug => 2});
	my $host = $anvil->Get->short_host_name();
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host => $host }});
	foreach my $ip_address_uuid (keys %{$anvil->data->{old}{ip_addresses}{ip_address_uuid}})
	{
		# Skip if already deleted.
		next if $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_note} eq "DELETED";
		
		my $ip_address_address = $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_address};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ip_address_address => $ip_address_address }});
		
		# Is this an alternate IP?
		if ((exists $anvil->data->{network}{$host}{ip_address}{$ip_address_address}) && 
		    ($anvil->data->{network}{$host}{ip_address}{$ip_address_address}{interface}))
		{
			# This is an alternate IP, don't delete it.
			next;
		}
		
		my $variables = { ip => $ip_address_address };
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0060", variables => $variables});
		$anvil->Alert->register({
			alert_level => "warning", 
			message     => "scan_network_alert_0060", 
			variables   => $variables,
			set_by      => $THIS_FILE,
		});
		
		my $ip_address_uuid = $anvil->Database->insert_or_update_ip_addresses({
			debug           => 2,
			ip_address_uuid => $ip_address_uuid, 
			'delete'        => 1, 
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ip_address_uuid => $ip_address_uuid }});
	}
	
	# Look for alternate IPs
	foreach my $ip_address (sort {$a cmp $b} keys %{$anvil->data->{network}{$host}{ip_address}})
	{
		my $interface   = $anvil->data->{network}{$host}{ip_address}{$ip_address}{interface};
		my $subnet_mask = $anvil->data->{network}{$host}{ip_address}{$ip_address}{subnet_mask};
		my $mac_address = $anvil->data->{network}{$host}{interface}{$interface}{mac_address};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"s1:ip_address"  => $ip_address, 
			"s2:interface"   => $interface,
			"s3:subnet_mask" => $subnet_mask,
			"s4:mac_address" => $mac_address, 
		}});
		
		# Is this a new IP?
		if (($interface) && ($mac_address))
		{
			if (not exists $anvil->data->{mac_to_ip}{mac_to_ip_ip_address}{$ip_address})
			{
				# Record it.
				my ($mac_to_ip_uuid) = $anvil->Database->insert_or_update_mac_to_ip({
					debug                 => 2, 
					mac_to_ip_mac_address => $mac_address, 
					mac_to_ip_ip_address  => $ip_address,
					mac_to_ip_note        => "on ".$host.":".$interface,
					update_note           => 0, 
				});
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_to_ip_uuid => $mac_to_ip_uuid }});
				
				# reload the mac_to_ips.
				$anvil->Database->get_mac_to_ip({debug => 2});
				
				my $variables = { 
					ip_address => $ip_address,
					interface  => $interface, 
				};
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0064", variables => $variables});
				$anvil->Alert->register({
					alert_level => "notice", 
					message     => "scan_network_alert_0064", 
					variables   => $variables,
					set_by      => $THIS_FILE,
				});
			}
		}
		
		if ($anvil->data->{mac_to_ip}{mac_to_ip_ip_address}{$ip_address}{mac_to_ip_uuid})
		{
			# Add a note that we've got the IP.
			my $mac_to_ip_uuid = $anvil->data->{mac_to_ip}{mac_to_ip_ip_address}{$ip_address}{mac_to_ip_uuid};
			my $mac_to_ip_note = $anvil->data->{mac_to_ip}{mac_to_ip_uuid}{$mac_to_ip_uuid}{mac_to_ip_note};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				's1:ip_address'     => $ip_address, 
				's2:mac_to_ip_uuid' => $mac_to_ip_uuid,
				's3:mac_to_ip_note' => $mac_to_ip_note, 
			}});
			
			if (($mac_to_ip_uuid) && (not $mac_to_ip_note))
			{
				my ($mac_to_ip_uuid) = $anvil->Database->insert_or_update_mac_to_ip({
					debug                 => 2, 
					mac_to_ip_uuid        => $mac_to_ip_uuid, 
					mac_to_ip_mac_address => $mac_address, 
					mac_to_ip_ip_address  => $ip_address,
					mac_to_ip_note        => "on ".$host.":".$interface,
					update_note           => 0, 
				});
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_to_ip_uuid => $mac_to_ip_uuid }});
			}
		}
	}
	
	return(0);
}

# Look for changes in network interfaces.
sub check_interfaces
{
	my ($anvil) = @_;
	
	my $interfaces = keys %{$anvil->data->{new}{interface}};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { interfaces => $interfaces }});
	foreach my $network_interface_name (sort {$a cmp $b} keys %{$anvil->data->{new}{interface}})
	{
		my $new_nm_uuid     = $anvil->data->{new}{interface}{$network_interface_name}{nm_uuid};
		my $new_nm_name     = $anvil->data->{new}{interface}{$network_interface_name}{nm_name};
		my $new_nm_device   = $anvil->data->{new}{interface}{$network_interface_name}{nm_device};
		my $new_bond_uuid   = $anvil->data->{new}{interface}{$network_interface_name}{bond_uuid};
		my $new_bond_name   = $anvil->data->{new}{interface}{$network_interface_name}{bond_name};
		my $new_bridge_uuid = $anvil->data->{new}{interface}{$network_interface_name}{bridge_uuid};
		my $new_bridge_name = $anvil->data->{new}{interface}{$network_interface_name}{bridge_name};
		my $new_duplex      = $anvil->data->{new}{interface}{$network_interface_name}{duplex};
		my $new_link_state  = $anvil->data->{new}{interface}{$network_interface_name}{link_state};
		my $new_operational = $anvil->data->{new}{interface}{$network_interface_name}{operational};
		my $new_mac_address = $anvil->data->{new}{interface}{$network_interface_name}{mac_address};
		my $new_medium      = $anvil->data->{new}{interface}{$network_interface_name}{medium};
		my $new_mtu         = $anvil->data->{new}{interface}{$network_interface_name}{mtu};
		my $new_speed       = $anvil->data->{new}{interface}{$network_interface_name}{speed};
		my $new_tx_bytes    = $anvil->data->{new}{interface}{$network_interface_name}{tx_bytes};
		my $new_rx_bytes    = $anvil->data->{new}{interface}{$network_interface_name}{rx_bytes};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			network_interface_name => $network_interface_name, 
			new_nm_uuid            => $new_nm_uuid, 
			new_nm_name            => $new_nm_name, 
			new_nm_device          => $new_nm_device, 
			new_bond_uuid          => $new_bond_uuid,
			new_bond_name          => $new_bond_name, 
			new_bridge_uuid        => $new_bridge_uuid,
			new_bridge_name        => $new_bridge_name, 
			new_duplex             => $new_duplex,
			new_link_state         => $new_link_state,
			new_operational        => $new_operational,
			new_mac_address        => $new_mac_address,
			new_medium             => $new_medium,
			new_mtu                => $new_mtu,
			new_speed              => $new_speed,
			new_tx_bytes           => $new_tx_bytes,
			new_rx_bytes           => $new_rx_bytes,
		}});
		
		# This is likely an unused interface, like a wireless adapter.
		next if not $new_nm_name;
		
		# Find the bridge, if any, and the bond UUID, if there's a bond name.
		if ($new_bond_name)
		{
			$new_bond_uuid = $anvil->data->{bonds}{name_to_uuid}{$new_bond_name};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_bond_uuid => $new_bond_uuid }});
		}
		if (exists $anvil->data->{interface_to_bridge}{$network_interface_name})
		{
			# This interface is on a bridge
			$new_bridge_name = $anvil->data->{interface_to_bridge}{$network_interface_name};
			$new_bridge_uuid = $anvil->data->{bridges}{name_to_uuid}{$new_bridge_name};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				new_bridge_name => $new_bridge_name, 
				new_bridge_uuid => $new_bridge_uuid, 
			}});
		}
		
		# New or existing?
		my $network_interface_uuid = "";
		if (exists $anvil->data->{network_interfaces}{name_to_uuid}{$network_interface_name})
		{
			$network_interface_uuid = $anvil->data->{network_interfaces}{name_to_uuid}{$network_interface_name};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_uuid => $network_interface_uuid }});
		}
		elsif (exists $anvil->data->{network_interfaces}{device_to_uuid}{$network_interface_name})
		{
			$network_interface_uuid = $anvil->data->{network_interfaces}{device_to_uuid}{$network_interface_name};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_uuid => $network_interface_uuid }});
		}
		elsif (($new_mac_address) && (exists $anvil->data->{network_interfaces}{mac_to_uuid}{$new_mac_address}))
		{
			$network_interface_uuid = $anvil->data->{network_interfaces}{mac_to_uuid}{$new_mac_address};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_uuid => $network_interface_uuid }});
		}
		if ($network_interface_uuid)
		{
			# Existing. Changes?
			my $old_nm_name      = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_name};
			my $old_nm_device    = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_device};
			my $old_bond_uuid    = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_bond_uuid};
			my $old_bond_name    = "";
			my $old_bridge_uuid  = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_bridge_uuid};
			my $old_bridge_name  = "";
			my $old_duplex       = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_duplex};
			my $old_link_state   = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_link_state};
			my $old_operational  = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_operational};
			my $old_mac_address  = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_mac_address};
			my $old_medium       = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_medium};
			my $old_mtu          = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_mtu};
			my $old_speed        = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_speed};
			my $old_rx_bytes     = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{rx_bytes};
			my $rx_variable_uuid = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{rx_variable_uuid};
			my $old_tx_bytes     = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{tx_bytes};
			my $tx_variable_uuid = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{tx_variable_uuid};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				old_nm_name      => $old_nm_name, 
				old_nm_device    => $old_nm_device, 
				old_bond_uuid    => $old_bond_uuid,
				old_bridge_uuid  => $old_bridge_uuid,
				old_duplex       => $old_duplex,
				old_link_state   => $old_link_state,
				old_operational  => $old_operational,
				old_mac_address  => $old_mac_address,
				old_medium       => $old_medium,
				old_mtu          => $old_mtu,
				old_speed        => $old_speed,
				old_tx_bytes     => $old_tx_bytes,
				tx_variable_uuid => $tx_variable_uuid, 
				old_rx_bytes     => $old_rx_bytes,
				rx_variable_uuid => $rx_variable_uuid, 
			}});
			
			# Delete this so we know it's processed.
			delete $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid};
			
			# Get the old bridge or bond name, if required.
			if ($old_bridge_uuid)
			{
				# Get the bridge name
				$old_bridge_name = $anvil->data->{bridges}{uuid_to_name}{$old_bridge_uuid};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_bridge_name => $old_bridge_name }});
			}
			if ($old_bond_uuid)
			{
				$old_bond_name = $anvil->data->{bonds}{uuid_to_name}{$old_bond_uuid};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_bond_name => $old_bond_name }});
			}
			
			# Look for changes.
			my $changes = 0;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				new_nm_name => $new_nm_name,
				old_nm_name => $old_nm_name,
			}});
			if ($new_nm_name ne $old_nm_name)
			{
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
				
				my $variables = {
					name => $network_interface_name,
					old  => $old_nm_name, 
					new  => $new_nm_name,
				};
				
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0062", variables => $variables});
				$anvil->Alert->register({
					alert_level => "notice", 
					message     => "scan_network_alert_0062", 
					variables   => $variables,
					set_by      => $THIS_FILE,
				});
			}
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				new_nm_device => $new_nm_device,
				old_nm_device => $old_nm_device,
			}});
			if ($new_nm_device ne $old_nm_device)
			{
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
				
				my $variables = {
					name => $network_interface_name,
					old  => $old_nm_device, 
					new  => $new_nm_device,
				};
				
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0063", variables => $variables});
				$anvil->Alert->register({
					alert_level => "notice", 
					message     => "scan_network_alert_0063", 
					variables   => $variables,
					set_by      => $THIS_FILE,
				});
			}
			if ($new_bond_uuid ne $old_bond_uuid)
			{
				# We're making this a warning level alert as it should not be changing.
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
				
				my $message_key = "scan_network_alert_0032";
				if (not $new_bond_uuid)
				{
					# Left the bond
					$message_key = "scan_network_alert_0031";
				}
				elsif (not $old_bond_uuid)
				{
					# Joined the bond
					$message_key = "scan_network_alert_0030";
				}
				
				my $variables = {
					name => $network_interface_name,
					old  => $old_bond_name." (".$old_bond_uuid.")", 
					new  => $new_bond_name." (".$new_bond_uuid.")",
				};
				
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $message_key, variables => $variables});
				$anvil->Alert->register({
					alert_level => "warning", 
					message     => $message_key, 
					variables   => $variables,
					set_by      => $THIS_FILE,
				});
			}
			if ($new_bridge_uuid ne $old_bridge_uuid)
			{
				# If this is a vnet* device, it's a notice level alert. Otherwise it's a 
				# warning level alert. The vnetX devices come and go with VMs.
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
				
				my $log_level   = 1;
				my $alert_level = "warning";
				my $message_key = "scan_network_alert_0035";
				if ($network_interface_name =~ /^vnet/)
				{
					# Left the bridge
					$log_level   = 1;
					$alert_level = "warning";
				}
				if ($new_bridge_uuid)
				{
					# Left the bridge
					$message_key = "scan_network_alert_0034";
				}
				elsif (not $old_bridge_uuid)
				{
					# Joined the bridge
					$message_key = "scan_network_alert_0033";
				}
				
				my $variables = {
					name => $network_interface_name,
					old  => $old_bridge_name." (".$old_bridge_uuid.")", 
					new  => $new_bridge_name." (".$new_bridge_uuid.")",
				};
				
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $message_key, variables => $variables});
				$anvil->Alert->register({
					alert_level => "warning", 
					message     => $message_key, 
					variables   => $variables,
					set_by      => $THIS_FILE,
				});
			}
			if ($new_duplex ne $old_duplex)
			{
				# This is always a warning
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
				
				my $clear       = 0;
				my $message_key = "scan_network_alert_0036";
				my $alert_level = "notice";
				if ($new_duplex eq "full")
				{
					# Duplex is back to being OK
					$clear       = 1;
					$message_key = "scan_network_alert_0037";
				}
				
				# Is this one of our interface?
				if (not $anvil->Network->is_our_interface({interface => $network_interface_name}))
				{
					# Not an interface we care about.
					$alert_level = "notice";
				}
				
				my $variables = {
					name => $network_interface_name,
					old  => $old_duplex, 
					new  => $new_duplex, 
				};
				
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $message_key, variables => $variables});
				$anvil->Alert->register({
					alert_level => $alert_level, 
					clear_alert => $clear, 
					message     => $message_key, 
					variables   => $variables,
					set_by      => $THIS_FILE,
				});
			}
			if ($new_link_state ne $old_link_state)
			{
				# This is always a warning, if it's a NIC we care about.
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
				
				my $clear       = 0;
				my $message_key = "scan_network_alert_0038";
				my $alert_level = "warning";
				if ($new_link_state)
				{
					# Link is up
					$clear       = 1;
					$message_key = "scan_network_alert_0039";
				}
				
				# Is this one of our interface?
				if (not $anvil->Network->is_our_interface({interface => $network_interface_name}))
				{
					# Not an interface we care about.
					$alert_level = "notice";
				}
				
				my $variables = {
					name => $network_interface_name,
					old  => $old_link_state, 
					new  => $new_link_state, 
				};
				
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $message_key, variables => $variables});
				$anvil->Alert->register({
					alert_level => $alert_level, 
					clear_alert => $clear, 
					message     => $message_key, 
					variables   => $variables,
					set_by      => $THIS_FILE,
				});
			}
			# Operation can be DELETED
			if ($new_operational ne $old_operational)
			{
				# This is always a warning
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
				
				# Is it up or down?
				my $clear       = 0;
				my $message_key = "scan_network_alert_0040";
				my $alert_level = "warning";
				if ($old_operational eq "DELETED")
				{
					# Link is back. Is it up?
					if ($new_operational eq "up")
					{
						# It's up
						$clear       = 1;
						$message_key = "scan_network_alert_0042";
					}
					else
					{
						# It's back, but down
						$message_key = "scan_network_alert_0043";
					}
				}
				elsif ($new_operational eq "up")
				{
					# It's up
					$clear       = 1;
					$message_key = "scan_network_alert_0041";
				}
				
				# Is this one of our interface?
				if (not $anvil->Network->is_our_interface({interface => $network_interface_name}))
				{
					# Not an interface we care about.
					$alert_level = "notice";
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { alert_level => $alert_level }});
				}
				
				# vnet devices come and go all the time, no need to be an alert level warning.
				if ($network_interface_name =~ /^vnet/)
				{
					$alert_level = "notice";
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { alert_level => $alert_level }});
				}
				
				my $variables = {
					name => $network_interface_name,
					old  => $old_operational, 
					new  => $new_operational, 
				};
				
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $message_key, variables => $variables});
				$anvil->Alert->register({
					alert_level => $alert_level, 
					clear_alert => $clear, 
					message     => $message_key, 
					variables   => $variables,
					set_by      => $THIS_FILE,
				});
			}
			if ($new_mac_address ne $old_mac_address)
			{
				# This is a notice level alert as it's almost certainly a NIC change 
				# performed by an admin.
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});

				my $variables = {
					name => $network_interface_name,
					old  => $old_mac_address, 
					new  => $new_mac_address, 
				};
				
				my $message_key = "scan_network_alert_0044";
				if ($network_interface_name =~ /^vnet/)
				{
					# This is a server booting or migrating
					$message_key = "scan_network_alert_0061";
				}
				
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $message_key, variables => $variables});
				$anvil->Alert->register({
					alert_level => "notice", 
					message     => $message_key, 
					variables   => $variables,
					set_by      => $THIS_FILE,
				});
			}
			if ($new_medium ne $old_medium)
			{
				# This is a notice level alert as it's almost certainly a NIC change 
				# performed by an admin.
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});

				my $variables = {
					name => $network_interface_name,
					old  => $old_medium, 
					new  => $new_medium, 
				};
				
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0045", variables => $variables});
				$anvil->Alert->register({
					alert_level => "notice", 
					message     => "scan_network_alert_0045", 
					variables   => $variables,
					set_by      => $THIS_FILE,
				});
			}
			if ($new_mtu ne $old_mtu)
			{
				# We're making this a warning level alert if the MTU drops.
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
				
				my $variables = {
					name => $network_interface_name,
					old  => $old_mtu, 
					new  => $new_mtu, 
				};
				
				my $log_level   = 2;
				my $alert_level = "notice";
				my $message_key = "scan_network_alert_0046";
				if ($new_mtu < $old_mtu)
				{
					# Make it an alert
					$log_level   = 1;
					$alert_level = "warning";
					$message_key = "scan_network_alert_0047";
				}
				
				# Is this one of our interface?
				if (not $anvil->Network->is_our_interface({interface => $network_interface_name}))
				{
					# Not an interface we care about.
					$alert_level = "notice";
				}
				
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $log_level, key => $message_key, variables => $variables});
				$anvil->Alert->register({
					alert_level => $alert_level, 
					message     => $message_key, 
					variables   => $variables,
					set_by      => $THIS_FILE,
				});
			}
			if ($new_speed ne $old_speed)
			{
				# We're making this a warning level as speed shouldn't change
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
				
				my $variables = {
					name => $network_interface_name,
					old  => $old_speed, 
					new  => $new_speed, 
				};
				
				my $message_key = "scan_network_alert_0048";
				if ($new_speed > $old_speed)
				{
					# Speed dropped, likely a faulty network cable
					$message_key = "scan_network_alert_0049";
				}
				
				# Is this one of our interface?
				my $alert_level = "notice";
				if (not $anvil->Network->is_our_interface({interface => $network_interface_name}))
				{
					# Not an interface we care about.
					$alert_level = "notice";
				}
				
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $message_key, variables => $variables});
				$anvil->Alert->register({
					alert_level => $alert_level, 
					message     => $message_key, 
					variables   => $variables,
					set_by      => $THIS_FILE,
				});
			}
			
			if ($changes)
			{
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					new_nm_name   => $new_nm_name,
					new_nm_device => $new_nm_device, 
				}});
				my $network_interface_uuid = $anvil->Database->insert_or_update_network_interfaces({
					debug                         => 2,
					network_interface_nm_uuid     => $new_nm_uuid, 
					network_interface_bond_uuid   => $new_bond_uuid, 
					network_interface_bridge_uuid => $new_bridge_uuid, 
					network_interface_name        => $new_nm_name,   # biosdevname
					network_interface_device      => $new_nm_device, # ip name 
					network_interface_duplex      => $new_duplex, 
					network_interface_link_state  => $new_link_state, 
					network_interface_operational => $new_operational, 
					network_interface_mac_address => $new_mac_address, 
					network_interface_medium      => $new_medium, 
					network_interface_mtu         => $new_mtu, 
					network_interface_speed       => $new_speed, 
				});
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_uuid => $network_interface_uuid }});
			}
			
			# Track usage of interfaces we care about
			if ($anvil->Network->is_our_interface({interface => $network_interface_name}))
			{
				# Rx and Tx almost always change, so they're only info-level alerts.
				if ($new_tx_bytes ne $old_tx_bytes)
				{
					if ($tx_variable_uuid)
					{
						my $variable_uuid = $anvil->Database->insert_or_update_variables({
							debug             => 2,
							variable_uuid     => $tx_variable_uuid, 
							update_value_only => 1,
							variable_value    => $new_tx_bytes,
						});
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable_uuid => $variable_uuid }});
					}
					else
					{
						# No value seen before, create
						my $variable_uuid = $anvil->Database->insert_or_update_variables({
							debug                 => 2,
							variable_name         => "network_interface::".$network_interface_name."::tx_bytes",
							variable_value        => $new_tx_bytes,
							variable_default      => 0, 
							variable_description  => "striker_0291", 
							variable_section      => "stats", 
							variable_source_uuid  => $network_interface_uuid, 
							variable_source_table => "network_interfaces", 
						});
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable_uuid => $variable_uuid }});
					}
					
					my $variables = {
						name => $network_interface_name,
						old  => $old_tx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $old_tx_bytes}).")", 
						new  => $new_tx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_tx_bytes}).")", 
					};
					
					# Reset or normal increase?
					my $message_key = "scan_network_alert_0007";
					my $alert_level = "info";
					my $log_level   = 2;
					if ($old_tx_bytes > $new_tx_bytes)
					{
						# Reset
						$message_key = "scan_network_alert_0008";
						$alert_level = "notice";
						$log_level   = 2;
					}
					
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $log_level, key => $message_key, variables => $variables});
					$anvil->Alert->register({
						alert_level => $alert_level, 
						message     => $message_key, 
						variables   => $variables,
						set_by      => $THIS_FILE,
					});
				}
				if ($new_rx_bytes ne $old_rx_bytes)
				{
					if ($rx_variable_uuid)
					{
						my $variable_uuid = $anvil->Database->insert_or_update_variables({
							debug             => 2,
							variable_uuid     => $rx_variable_uuid, 
							update_value_only => 1,
							variable_value    => $new_rx_bytes,
						});
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable_uuid => $variable_uuid }});
					}
					else
					{
						# No value seen before, create
						my $variable_uuid = $anvil->Database->insert_or_update_variables({
							debug                 => 2,
							variable_name         => "network_interface::".$network_interface_name."::rx_bytes",
							variable_value        => $new_rx_bytes,
							variable_default      => 0, 
							variable_description  => "striker_0290", 
							variable_section      => "stats", 
							variable_source_uuid  => $network_interface_uuid, 
							variable_source_table => "network_interfaces", 
						});
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable_uuid => $variable_uuid }});
					}
					
					my $variables = {
						name => $network_interface_name,
						old  => $old_rx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $old_rx_bytes}).")", 
						new  => $new_rx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_rx_bytes}).")", 
					};
					
					# Reset or normal increase?
					my $message_key = "scan_network_alert_0009";
					my $alert_level = "info";
					my $log_level   = 2;
					if ($old_rx_bytes > $new_rx_bytes)
					{
						# Reset
						$message_key = "scan_network_alert_0010";
						$alert_level = "notice";
						$log_level   = 2;
					}
					
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $log_level, key => $message_key, variables => $variables});
					$anvil->Alert->register({
						alert_level => $alert_level, 
						message     => $message_key, 
						variables   => $variables,
						set_by      => $THIS_FILE,
					});
				}
			}
		}
		else
		{
			# Record the interface
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				new_nm_name            => $new_nm_name,
				network_interface_name => $network_interface_name,
				new_nm_device          => $new_nm_device, 
			}});
			
			# If there's no device and no interface name, ignore it.
			next if ((not $new_nm_name) && (not $new_nm_device));
			
			my $network_interface_uuid = $anvil->Database->insert_or_update_network_interfaces({
				debug                         => 2,
				network_interface_nm_uuid     => $new_nm_uuid, 
				network_interface_bond_uuid   => $new_bond_uuid, 
				network_interface_bridge_uuid => $new_bridge_uuid, 
				network_interface_name        => $new_nm_name,
				network_interface_device      => $network_interface_name,
				network_interface_duplex      => $new_duplex, 
				network_interface_link_state  => $new_link_state, 
				network_interface_operational => $new_operational, 
				network_interface_mac_address => $new_mac_address, 
				network_interface_medium      => $new_medium, 
				network_interface_mtu         => $new_mtu, 
				network_interface_speed       => $new_speed, 
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_uuid => $network_interface_uuid }});
			
			# Store the interface so IPs can find our UUID.
			$anvil->data->{network_interfaces}{name_to_uuid}{$network_interface_name} = $network_interface_uuid;
			$anvil->data->{network_interfaces}{uuid_to_name}{$network_interface_uuid} = $network_interface_name;
			$anvil->data->{network_interfaces}{mac_to_uuid}{$new_mac_address}         = $network_interface_uuid;
			$anvil->data->{interface}{name_to_uuid}{$network_interface_name}          = $network_interface_uuid;
			$anvil->data->{interface}{device_to_uuid}{$new_nm_device}                 = $network_interface_uuid;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"network_interfaces::name_to_uuid::${network_interface_name}" => $anvil->data->{network_interfaces}{name_to_uuid}{$network_interface_name}, 
				"network_interfaces::uuid_to_name::${network_interface_uuid}" => $anvil->data->{network_interfaces}{uuid_to_name}{$network_interface_uuid}, 
				"network_interfaces::mac_to_uuid::${new_mac_address}"         => $anvil->data->{network_interfaces}{mac_to_uuid}{$new_mac_address}, 
				"interface::name_to_uuid::${network_interface_name}"          => $anvil->data->{interface}{name_to_uuid}{$network_interface_name},
				"interface::device_to_uuid::${new_nm_device}"                 => $anvil->data->{interface}{device_to_uuid}{$new_nm_device},
			}});
			
			# Store the rx_bytes and tx_bytes
			my $rx_variable_uuid = $anvil->Database->insert_or_update_variables({
				debug                 => 2,
				variable_name         => "network_interface::".$network_interface_name."::rx_bytes",
				variable_value        => $new_rx_bytes,
				variable_default      => 0, 
				variable_description  => "striker_0290", 
				variable_section      => "stats", 
				variable_source_uuid  => $new_bond_uuid, 
				variable_source_table => "bonds", 
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { rx_variable_uuid => $rx_variable_uuid }});
			my $tx_variable_uuid = $anvil->Database->insert_or_update_variables({
				debug                 => 2,
				variable_name         => "network_interface::".$network_interface_name."::tx_bytes",
				variable_value        => $new_tx_bytes,
				variable_default      => 0, 
				variable_description  => "striker_0291", 
				variable_section      => "stats", 
				variable_source_uuid  => $new_bond_uuid, 
				variable_source_table => "bonds", 
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { tx_variable_uuid => $tx_variable_uuid }});
			
			# Report.
			my $say_duplex = "#!string!unit_0004!#";
			if ($new_duplex =~ /full/i)
			{
				$say_duplex = "#!string!unit_0015!#";
			}
			elsif ($new_duplex =~ /half/i)
			{
				$say_duplex = "#!string!unit_0016!#";
			}
			my $variables = {
				interface_name => $network_interface_name,
				bond_name      => $new_bond_name   ? $new_bond_name   : "--", 
				bridge_name    => $new_bridge_name ? $new_bridge_name : "--", 
				duplex         => $say_duplex, 
				link_state     => $new_link_state ? "#!string!unit_0013!#" : "#!string!unit_0014!#", # up / down
				operational    => $new_operational, 
				mac_address    => $new_mac_address, 
				medium         => $new_medium, 
				mtu            => $new_mtu, 
				speed          => $new_speed, 
				say_tx         => $anvil->Convert->add_commas({number => $new_tx_bytes})." #!string!suffix_0057!# (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_tx_bytes}).")",
				say_rx         => $anvil->Convert->add_commas({number => $new_rx_bytes})." #!string!suffix_0057!# (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_rx_bytes}).")",
			};
			
			# If this a vnet device, it's only a notice message as this is expected when a VM boots.
			my $alert_level = "warning";
			if ($network_interface_name =~ /^vnet/)
			{
				$alert_level = "notice";
			}
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { alert_level => $alert_level }});
			
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0029", variables => $variables});
			$anvil->Alert->register({
				alert_level => $alert_level, 
				message     => "scan_network_alert_0029", 
				variables   => $variables,
				set_by      => $THIS_FILE,
			});
		}
	}
	
	# Look for left over / deleted bonds.
	foreach my $network_interface_uuid (keys %{$anvil->data->{old}{network_interfaces}{network_interface_uuid}})
	{
		# Skip if already deleted.
		next if $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_operational} eq "DELETED";
		
		my $network_interface_name = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_name};
		my $tx_bytes               = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{tx_bytes};
		my $rx_bytes               = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{rx_bytes};
		
		my $variables = {
			name => $network_interface_name,
			tx   => $anvil->Convert->add_commas({number => $tx_bytes})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $tx_bytes}).")", 
			rx   => $anvil->Convert->add_commas({number => $rx_bytes})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $rx_bytes}).")", 
		};
		
		# If this a vnet device, it's only a notice message as this is expected when a VM migrates or
		# shuts down.
		my $alert_level = "warning";
		if ($network_interface_name =~ /^vnet/)
		{
			$alert_level = "notice";
		}
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { alert_level => $alert_level }});
		
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0059", variables => $variables});
		$anvil->Alert->register({
			alert_level => "warning", 
			message     => "scan_network_alert_0059", 
			variables   => $variables,
			set_by      => $THIS_FILE,
		});
		
		my $network_interface_uuid = $anvil->Database->insert_or_update_network_interfaces({
			debug                  => 2,
			network_interface_uuid => $network_interface_uuid, 
			'delete'               => 1, 
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_uuid => $network_interface_uuid }});
	}
	
	return(0);
}

# Look for changes in the bonds.
sub check_bonds
{
	my ($anvil) = @_;
	
	foreach my $bond_name (sort {$a cmp $b} keys %{$anvil->data->{new}{bond}})
	{
		# Store the bond
		my $new_nm_uuid              = $anvil->data->{new}{bond}{$bond_name}{nm_uuid};
		my $new_mode                 = $anvil->data->{new}{bond}{$bond_name}{mode};
		my $new_mtu                  = $anvil->data->{new}{bond}{$bond_name}{mtu};
		my $new_operational          = $anvil->data->{new}{bond}{$bond_name}{operational};
		my $new_mac_address          = $anvil->data->{new}{bond}{$bond_name}{mac_address};
		my $new_primary_interface    = $anvil->data->{new}{bond}{$bond_name}{primary_interface};
		my $new_primary_reselect     = $anvil->data->{new}{bond}{$bond_name}{primary_reselect};
		my $new_active_interface     = $anvil->data->{new}{bond}{$bond_name}{active_interface};
		my $new_mii_polling_interval = $anvil->data->{new}{bond}{$bond_name}{mii_polling_interval};
		my $new_up_delay             = $anvil->data->{new}{bond}{$bond_name}{up_delay};
		my $new_down_delay           = $anvil->data->{new}{bond}{$bond_name}{down_delay};
		my $new_tx_bytes             = $anvil->data->{new}{bond}{$bond_name}{tx_bytes};
		my $new_rx_bytes             = $anvil->data->{new}{bond}{$bond_name}{rx_bytes};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			bond_name                => $bond_name, 
			new_mode                 => $new_mode, 
			new_mtu                  => $new_mtu, 
			new_operational          => $new_operational, 
			new_mac_address          => $new_mac_address, 
			new_primary_interface    => $new_primary_interface, 
			new_primary_reselect     => $new_primary_reselect, 
			new_active_interface     => $new_active_interface, 
			new_mii_polling_interval => $new_mii_polling_interval, 
			new_up_delay             => $new_up_delay, 
			new_down_delay           => $new_down_delay, 
			new_tx_bytes             => $new_tx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_tx_bytes}).")", 
			new_rx_bytes             => $new_rx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_rx_bytes}).")", 
		}});
		
		# If we don't have a bridge_uuid, find it by the name.
		my $new_bridge_uuid = "";
		my $new_bridge_name = "";
		if (exists $anvil->data->{interface_to_bridge}{$bond_name})
		{
			# This bond is on a bridge
			$new_bridge_name = $anvil->data->{interface_to_bridge}{$bond_name};
			$new_bridge_uuid = $anvil->data->{bridges}{name_to_uuid}{$new_bridge_name};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				new_bridge_name => $new_bridge_name, 
				new_bridge_uuid => $new_bridge_uuid, 
			}});
		}
		
		# New or existing?
		if (exists $anvil->data->{bonds}{name_to_uuid}{$bond_name})
		{
			# Existing, look for changes.
			my $bond_uuid                = $anvil->data->{bonds}{name_to_uuid}{$bond_name};
			my $old_mode                 = $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_mode};
			my $old_mtu                  = $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_mtu};
			my $old_primary_interface    = $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_primary_interface};
			my $old_primary_reselect     = $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_primary_reselect};
			my $old_active_interface     = $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_active_interface};
			my $old_mii_polling_interval = $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_mii_polling_interval};
			my $old_up_delay             = $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_up_delay};
			my $old_down_delay           = $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_down_delay};
			my $old_mac_address          = $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_mac_address};
			my $old_operational          = $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_operational};
			my $old_bridge_uuid          = $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_bridge_uuid};
			my $old_rx_bytes             = $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{rx_bytes};
			my $rx_variable_uuid         = $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{rx_variable_uuid};
			my $old_tx_bytes             = $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{tx_bytes};
			my $tx_variable_uuid         = $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{tx_variable_uuid};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				bond_uuid                => $bond_uuid,
				old_mode                 => $old_mode,
				old_mtu                  => $old_mtu,
				old_primary_interface    => $old_primary_interface,
				old_primary_reselect     => $old_primary_reselect,
				old_active_interface     => $old_active_interface,
				old_mii_polling_interval => $old_mii_polling_interval,
				old_up_delay             => $old_up_delay,
				old_down_delay           => $old_down_delay,
				old_mac_address          => $old_mac_address,
				old_operational          => $old_operational,
				old_bridge_uuid          => $old_bridge_uuid, 
				old_rx_bytes             => $old_rx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $old_rx_bytes}).")", 
				rx_variable_uuid         => $rx_variable_uuid,
				old_tx_bytes             => $old_tx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $old_tx_bytes}).")", 
				tx_variable_uuid         => $tx_variable_uuid,
			}});
			
			# Delete the old record so we know it's been processed.
			delete $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid};
			
			my $old_bridge_name = "";
			if ($old_bridge_uuid)
			{
				$old_bridge_name = $anvil->data->{bridges}{uuid_to_name}{$old_bridge_uuid};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_bridge_name => $old_bridge_name }});
			}
			
			my $changes = 0;
			if ($new_mode ne $old_mode)
			{
				# We're making this a warning level alert as it should not be changing.
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
				
				my $say_old_name        = "scan_network_bond_".$old_mode."_name";
				my $say_old_number      = "scan_network_bond_".$old_mode."_number";
				my $say_old_description = "scan_network_bond_".$old_mode."_description";
				my $say_new_name        = "scan_network_bond_".$new_mode."_name";
				my $say_new_number      = "scan_network_bond_".$new_mode."_number";
				my $say_new_description = "scan_network_bond_".$new_mode."_description";
				
				my $variables = {
					name            => $bond_name,
					old             => $say_old_name, 
					old_number      => $say_old_number, 
					old_description => $say_old_description, 
					new             => $say_new_name, 
					new_number      => $say_new_number, 
					new_description => $say_new_description, 
				};
				
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_network_alert_0012", variables => $variables});
				$anvil->Alert->register({
					alert_level => "warning", 
					message     => "scan_network_alert_0012", 
					variables   => $variables,
					set_by      => $THIS_FILE,
				});
			}
			if ($new_mtu ne $old_mtu)
			{
				# We're making this a warning level alert if the MTU drops.
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
				
				my $variables = {
					name => $bond_name,
					old  => $old_mtu, 
					new  => $new_mtu, 
				};
				
				my $log_level   = 2;
				my $alert_level = "notice";
				my $message_key = "scan_network_alert_0013";
				if ($new_mtu < $old_mtu)
				{
					# Make it an alert
					$log_level   = 1;
					$alert_level = "warning";
					$message_key = "scan_network_alert_0014";
				}
				
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $log_level, key => $message_key, variables => $variables});
				$anvil->Alert->register({
					alert_level => $alert_level, 
					message     => $message_key, 
					variables   => $variables,
					set_by      => $THIS_FILE,
				});
			}
			if ($new_bridge_name ne $old_bridge_name)
			{
				# We're making this a warning level alert as it should not be changing.
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
				
				my $variables = {
					name => $bond_name,
					old  => $old_bridge_name ? $old_bridge_name : "--", 
					new  => $new_bridge_name ? $new_bridge_name : "--", 
				};
				
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0015", variables => $variables});
				$anvil->Alert->register({
					alert_level => "warning", 
					message     => "scan_network_alert_0015", 
					variables   => $variables,
					set_by      => $THIS_FILE,
				});
			}
			if ($new_operational ne $old_operational)
			{
				# We're making this a warning level alert as it should not be changing.
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
				
				my $variables = {
					name => $bond_name,
					old  => $old_operational eq "up" ? "#!string!unit_0013!#" : "#!string!unit_0014!#", 
					new  => $new_operational eq "up" ? "#!string!unit_0013!#" : "#!string!unit_0014!#", 
				};
				
				# Gone up, down or returned?
				my $message_key = "scan_network_alert_0016";
				if ($old_operational eq "DELETED")
				{
					# Bond is back from being deleted. Is it up or down?
					if ($new_operational eq "up")
					{
						# Back and up
						$message_key = "scan_network_alert_0027";
					}
					else
					{
						# Back but down
						$message_key = "scan_network_alert_0028";
					}
				}
				elsif ($new_operational eq "up")
				{
					$message_key = "scan_network_alert_0017";
				}
				
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $message_key, variables => $variables});
				$anvil->Alert->register({
					alert_level => "warning", 
					message     => $message_key, 
					variables   => $variables,
					set_by      => $THIS_FILE,
				});
			}
			if ($new_mac_address ne $old_mac_address)
			{
				# We're making this a notice as it can change with the active interface 
				# changing. There will be a warning if a given interface dropped.
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
				
				my $variables = {
					name => $bond_name,
					old  => $old_mac_address, 
					new  => $new_mac_address, 
				};
				
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_network_alert_0018", variables => $variables});
				$anvil->Alert->register({
					alert_level => "notice", 
					message     => "scan_network_alert_0018", 
					variables   => $variables,
					set_by      => $THIS_FILE,
				});
			}
			if ($new_primary_interface ne $old_primary_interface)
			{
				# We're making this a notice as it will only change if an admin did it.
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
				
				my $variables = {
					name => $bond_name,
					old  => $old_primary_interface, 
					new  => $new_primary_interface, 
				};
				
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_network_alert_0019", variables => $variables});
				$anvil->Alert->register({
					alert_level => "notice", 
					message     => "scan_network_alert_0019", 
					variables   => $variables,
					set_by      => $THIS_FILE,
				});
			}
			if ($new_primary_reselect ne $old_primary_reselect)
			{
				# We're making this a notice as it will only change if an admin did it.
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
				
				my $variables = {
					name => $bond_name,
					old  => $old_primary_reselect, 
					new  => $new_primary_reselect, 
				};
				
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_network_alert_0020", variables => $variables});
				$anvil->Alert->register({
					alert_level => "notice", 
					message     => "scan_network_alert_0020", 
					variables   => $variables,
					set_by      => $THIS_FILE,
				});
			}
			if ($new_active_interface ne $old_active_interface)
			{
				# We're making this a warning as this generally happens when a link drops or returns.
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
				
				my $variables = {
					name => $bond_name,
					old  => $old_active_interface, 
					new  => $new_active_interface, 
				};
				
				# Did the primary interface return?
				my $message_key = "scan_network_alert_0021";
				if ($new_active_interface eq $new_primary_interface)
				{
					# Primary link is back
					$message_key = "scan_network_alert_0022";
				}
				
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $message_key, variables => $variables});
				$anvil->Alert->register({
					alert_level => "warning", 
					message     => $message_key, 
					variables   => $variables,
					set_by      => $THIS_FILE,
				});
			}
			if ($new_mii_polling_interval ne $old_mii_polling_interval)
			{
				# We're making this a notice as this will only ever change by an admin.
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
				
				my $variables = {
					name => $bond_name,
					old  => $old_mii_polling_interval, 
					new  => $new_mii_polling_interval, 
				};
				
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0023", variables => $variables});
				$anvil->Alert->register({
					alert_level => "warning", 
					message     => "scan_network_alert_0023", 
					variables   => $variables,
					set_by      => $THIS_FILE,
				});
			}
			if ($new_up_delay ne $old_up_delay)
			{
				# We're making this a notice as this will only ever change by an admin.
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
				
				my $variables = {
					name => $bond_name,
					old  => $old_up_delay, 
					new  => $new_up_delay, 
				};
				
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_network_alert_0024", variables => $variables});
				$anvil->Alert->register({
					alert_level => "notice", 
					message     => "scan_network_alert_0024", 
					variables   => $variables,
					set_by      => $THIS_FILE,
				});
			}
			if ($new_down_delay ne $old_down_delay)
			{
				# We're making this a notice as this will only ever change by an admin.
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
				
				my $variables = {
					name => $bond_name,
					old  => $old_down_delay, 
					new  => $new_down_delay, 
				};
				
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_network_alert_0025", variables => $variables});
				$anvil->Alert->register({
					alert_level => "notice", 
					message     => "scan_network_alert_0025", 
					variables   => $variables,
					set_by      => $THIS_FILE,
				});
			}
			
			# Save the changes, if any.
			if ($changes)
			{
				my $bond_uuid = $anvil->Database->insert_or_update_bonds({
					debug                     => 2,
					bond_nm_uuid              => $new_nm_uuid, 
					bond_name                 => $bond_name,
					bond_mode                 => $new_mode, 
					bond_mtu                  => $new_mtu, 
					bond_operational          => $new_operational, 
					bond_mac_address          => $new_mac_address, 
					bond_primary_interface    => $new_primary_interface, 
					bond_primary_reselect     => $new_primary_reselect, 
					bond_active_interface     => $new_active_interface, 
					bond_mii_polling_interval => $new_mii_polling_interval, 
					bond_up_delay             => $new_up_delay, 
					bond_down_delay           => $new_down_delay, 
					bond_bridge_uuid          => $new_bridge_uuid, 
				});
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bond_uuid => $bond_uuid }});
			}
			
			# Rx and Tx almost always change, so they're only info-level alerts.
			if ($new_tx_bytes ne $old_tx_bytes)
			{
				if ($tx_variable_uuid)
				{
					my $variable_uuid = $anvil->Database->insert_or_update_variables({
						debug             => 2,
						variable_uuid     => $tx_variable_uuid, 
						update_value_only => 1,
						variable_value    => $new_tx_bytes,
					});
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable_uuid => $variable_uuid }});
				}
				else
				{
					# No value seen before, create
					my $variable_uuid = $anvil->Database->insert_or_update_variables({
						debug                 => 2,
						variable_name         => "bond::".$bond_name."::tx_bytes",
						variable_value        => $new_tx_bytes,
						variable_default      => 0, 
						variable_description  => "striker_0291", 
						variable_section      => "stats", 
						variable_source_uuid  => $bond_uuid, 
						variable_source_table => "bonds", 
					});
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable_uuid => $variable_uuid }});
				}
				
				my $variables = {
					name => $bond_name,
					old  => $old_tx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $old_tx_bytes}).")", 
					new  => $new_tx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_tx_bytes}).")", 
				};
				
				# Reset or normal increase?
				my $message_key = "scan_network_alert_0007";
				my $alert_level = "info";
				my $log_level   = 2;
				if ($old_tx_bytes > $new_tx_bytes)
				{
					# Reset
					$message_key = "scan_network_alert_0008";
					$alert_level = "notice";
					$log_level   = 2;
				}
				
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $log_level, key => $message_key, variables => $variables});
				$anvil->Alert->register({
					alert_level => $alert_level, 
					message     => $message_key, 
					variables   => $variables,
					set_by      => $THIS_FILE,
				});
			}
			if ($new_rx_bytes ne $old_rx_bytes)
			{
				if ($rx_variable_uuid)
				{
					my $variable_uuid = $anvil->Database->insert_or_update_variables({
						debug             => 2,
						variable_uuid     => $rx_variable_uuid, 
						update_value_only => 1,
						variable_value    => $new_rx_bytes,
					});
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable_uuid => $variable_uuid }});
				}
				else
				{
					# No value seen before, create
					my $variable_uuid = $anvil->Database->insert_or_update_variables({
						debug                 => 2,
						variable_name         => "bond::".$bond_name."::rx_bytes",
						variable_value        => $new_rx_bytes,
						variable_default      => 0, 
						variable_description  => "striker_0290", 
						variable_section      => "stats", 
						variable_source_uuid  => $bond_uuid, 
						variable_source_table => "bonds", 
					});
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable_uuid => $variable_uuid }});
				}
				
				my $variables = {
					name => $bond_name,
					old  => $old_rx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $old_rx_bytes}).")", 
					new  => $new_rx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_rx_bytes}).")", 
				};
				
				# Reset or normal increase?               Reset                       Normal increase
				my $message_key = "scan_network_alert_0009";
				my $alert_level = "info";
				my $log_level   = 2;
				if ($old_rx_bytes > $new_rx_bytes)
				{
					# Reset
					$message_key = "scan_network_alert_0010";
					$alert_level = "notice";
					$log_level   = 2;
				}
				
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $log_level, key => $message_key, variables => $variables});
				$anvil->Alert->register({
					alert_level => $alert_level, 
					message     => $message_key, 
					variables   => $variables,
					set_by      => $THIS_FILE,
				});
			}
		}
		else
		{
			# New bond. Is it on a bridge?
			my $bridge_name = "";
			my $bridge_uuid = "";
			if (exists $anvil->data->{interface_to_bridge}{$bond_name})
			{
				$bridge_name = $anvil->data->{interface_to_bridge}{$bond_name};
				$bridge_uuid = $anvil->data->{bridges}{name_to_uuid}{$bridge_name};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					bridge_name => $bridge_name,
					bridge_uuid => $bridge_uuid, 
				}});
			}
			
			# Record the bond
			my $bond_uuid = $anvil->Database->insert_or_update_bonds({
				debug                     => 2,
				bond_name                 => $bond_name,
				bond_mode                 => $new_mode, 
				bond_mtu                  => $new_mtu, 
				bond_operational          => $new_operational, 
				bond_mac_address          => $new_mac_address, 
				bond_primary_interface    => $new_primary_interface, 
				bond_primary_reselect     => $new_primary_reselect, 
				bond_active_interface     => $new_active_interface, 
				bond_mii_polling_interval => $new_mii_polling_interval, 
				bond_up_delay             => $new_up_delay, 
				bond_down_delay           => $new_down_delay, 
				bond_bridge_uuid          => $bridge_uuid, 
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bond_uuid => $bond_uuid }});
			
			# Store the bond so our links can find our UUID.
			$anvil->data->{bonds}{name_to_uuid}{$bond_name}     = $bond_uuid;
			$anvil->data->{bonds}{uuid_to_name}{$bond_uuid}     = $bond_name;
			$anvil->data->{interface}{name_to_uuid}{$bond_name} = $bond_uuid;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"bonds::name_to_uuid::${bond_name}"     => $anvil->data->{bonds}{name_to_uuid}{$bond_name}, 
				"bonds::uuid_to_name::${bond_uuid}"     => $anvil->data->{bonds}{uuid_to_name}{$bond_uuid}, 
				"interface::name_to_uuid::${bond_name}" => $anvil->data->{interface}{name_to_uuid}{$bond_name},
			}});
			
			# Store the rx_bytes and tx_bytes
			my $rx_variable_uuid = $anvil->Database->insert_or_update_variables({
				debug                 => 2,
				variable_name         => "bond::".$bond_name."::rx_bytes",
				variable_value        => $new_rx_bytes,
				variable_default      => 0, 
				variable_description  => "striker_0290", 
				variable_section      => "stats", 
				variable_source_uuid  => $bond_uuid, 
				variable_source_table => "bonds", 
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { rx_variable_uuid => $rx_variable_uuid }});
			my $tx_variable_uuid = $anvil->Database->insert_or_update_variables({
				debug                 => 2,
				variable_name         => "bond::".$bond_name."::tx_bytes",
				variable_value        => $new_tx_bytes,
				variable_default      => 0, 
				variable_description  => "striker_0291", 
				variable_section      => "stats", 
				variable_source_uuid  => $bond_uuid, 
				variable_source_table => "bonds", 
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { tx_variable_uuid => $tx_variable_uuid }});
			
			# Report.
			my $variables = {
				bond_name            => $bond_name,
				mode                 => "scan_network_bond_".$new_mode."_name", 
				number               => "scan_network_bond_".$new_mode."_number",
				description          => "scan_network_bond_".$new_mode."_description",
				mtu                  => $new_mtu, 
				bridge               => $bridge_name             ? $bridge_name           : "--", 
				operational          => $new_operational eq "up" ? "#!string!unit_0013!#" : "#!string!unit_0014!#", 
				mac_address          => $new_mac_address, 
				primary_interface    => $new_primary_interface, 
				primary_reselect     => $new_primary_reselect, 
				active_interface     => $new_active_interface, 
				mii_polling_interval => $new_mii_polling_interval, 
				up_delay             => $new_up_delay, 
				down_delay           => $new_down_delay, 
				say_tx               => $anvil->Convert->add_commas({number => $new_tx_bytes})." #!string!suffix_0057!# (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_tx_bytes}).")",
				say_rx               => $anvil->Convert->add_commas({number => $new_rx_bytes})." #!string!suffix_0057!# (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_rx_bytes}).")",
			};
			
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0011", variables => $variables});
			$anvil->Alert->register({
				alert_level => "warning", 
				message     => "scan_network_alert_0011", 
				variables   => $variables,
				set_by      => $THIS_FILE,
			});
		}
	}
	
	# Look for left over / deleted bonds.
	foreach my $bond_uuid (keys %{$anvil->data->{old}{bonds}{bond_uuid}})
	{
		# Skip if already deleted.
		next if $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_operational} eq "DELETED";
		
		my $bond_name = $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_name};
		my $tx_bytes  = $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{tx_bytes};
		my $rx_bytes  = $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{rx_bytes};
		
		my $variables = {
			name => $bond_name,
			tx   => $anvil->Convert->add_commas({number => $tx_bytes})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $tx_bytes}).")", 
			rx   => $anvil->Convert->add_commas({number => $rx_bytes})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $rx_bytes}).")", 
		};
		
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0058", variables => $variables});
		$anvil->Alert->register({
			alert_level => "warning", 
			message     => "scan_network_alert_0058", 
			variables   => $variables,
			set_by      => $THIS_FILE,
		});
		
		my $bond_uuid = $anvil->Database->insert_or_update_bonds({
			debug       => 2,
			bond_uuid => $bond_uuid, 
			'delete'    => 1, 
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bond_uuid => $bond_uuid }});
	}
	
	return(0);
}

# Look for changes in the bridges.
sub check_bridges
{
	my ($anvil) = @_;
	
	# Loop through the new stuff found and look for changes. Bridges first.
	foreach my $bridge_name (sort {$a cmp $b} keys %{$anvil->data->{new}{bridge}})
	{
		# The RX/TX always change.
		my $new_bridge_id   = $anvil->data->{new}{bridge}{$bridge_name}{id};
		my $new_mac_address = $anvil->data->{new}{bridge}{$bridge_name}{mac_address};
		my $new_mtu         = $anvil->data->{new}{bridge}{$bridge_name}{mtu};
		my $nmcli_uuid      = $anvil->data->{nmcli}{name}{$bridge_name}{uuid};
		my $new_stp_enabled = $nmcli_uuid ? $anvil->data->{nmcli}{uuid}{$nmcli_uuid}{'bridge.stp'} : "unknown";
		my $new_tx_bytes    = $anvil->data->{new}{bridge}{$bridge_name}{tx_bytes};
		my $new_rx_bytes    = $anvil->data->{new}{bridge}{$bridge_name}{rx_bytes};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			bridge_name     => $bridge_name, 
			new_bridge_id   => $new_bridge_id, 
			new_mac_address => $new_mac_address, 
			new_mtu         => $new_mtu, 
			nmcli_uuid      => $nmcli_uuid,
			new_stp_enabled => $new_stp_enabled, 
			new_tx_bytes    => $new_tx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_tx_bytes}).")", 
			new_rx_bytes    => $new_rx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_rx_bytes}).")", 
		}});

		# This needs to be off to work with Cisco BPDU Guard. If STP is enabled, Cisco shuts down the port.
		if ($new_stp_enabled eq "yes") 
		{
			# If the user has disabled STP management, don't proceed.
			if ((exists $anvil->data->{network}{stp}{manage}) && ($anvil->data->{network}{stp}{manage} eq 0))
			{
				# Don't proceed.
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_network_alert_0066", variables => { name => $bridge_name }});
			}
			else
			{
				# Change it to no.
				my ($output, $return_code) = $anvil->Network->modify_connection({uuid => $nmcli_uuid, variable => "bridge.stp", value => "no"});
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					output      => $output,
					return_code => $return_code, 
				}});

				$new_stp_enabled = "no";
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_stp_enabled => $new_stp_enabled }});

				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_network_alert_0065", variables => { name => $bridge_name }});
				$anvil->Alert->register({
					alert_level => "notice", 
					message     => "scan_network_alert_0065", 
					variables   => { name => $bridge_name },
					set_by      => $THIS_FILE,
				});
			}
		}
		
		# New or existing?
		if (exists $anvil->data->{bridges}{name_to_uuid}{$bridge_name})
		{
			# Existing, look for changes.
			my $bridge_uuid      = $anvil->data->{bridges}{name_to_uuid}{$bridge_name};
			my $old_bridge_id    = $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{bridge_id};
			my $old_mac_address  = $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{bridge_mac_address};
			my $old_mtu          = $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{bridge_mtu};
			my $old_stp_enabled  = $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{bridge_stp_enabled};
			my $old_tx_bytes     = $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{tx_bytes};
			my $tx_variable_uuid = $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{tx_variable_uuid};
			my $old_rx_bytes     = $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{rx_bytes};
			my $rx_variable_uuid = $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{rx_variable_uuid};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				bridge_uuid      => $bridge_uuid,
				old_bridges_id   => $old_bridge_id, 
				old_mac_address  => $old_mac_address, 
				old_mtu          => $old_mtu, 
				old_stp_enabled  => $old_stp_enabled, 
				old_tx_bytes     => $old_tx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $old_tx_bytes}).")", 
				tx_variable_uuid => $tx_variable_uuid, 
				old_rx_bytes     => $old_rx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $old_rx_bytes}).")", 
				rx_variable_uuid => $rx_variable_uuid, 
			}});
			
			# Delete the old record so we know it's been processed.
			delete $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid};
			
			my $changes = 0;
			if ($new_bridge_id ne $old_bridge_id)
			{
				# We're making this a notice level alert as it has no impact on the system, 
				# unless it's returned from being deleted.
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
				
				my $variables = {
					name => $bridge_name,
					old  => $old_bridge_id, 
					new  => $new_bridge_id, 
				};
				
				# Did the bridge return?
				my $message_key = "scan_network_alert_0003";
				my $log_level   = 2;
				my $alert_level = "notice";
				if ($old_bridge_id eq "DELETED")
				{
					# Bridge is back.
					$message_key = "scan_network_alert_0026";
					$log_level   = 1;
					$alert_level = "warning";
				}
				
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $log_level, key => $message_key, variables => $variables});
				$anvil->Alert->register({
					alert_level => $alert_level, 
					message     => $message_key, 
					variables   => $variables,
					set_by      => $THIS_FILE,
				});
			}
			elsif ($new_mac_address ne $old_mac_address)
			{
				# This is odd, but not harmful
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
				
				my $variables = {
					name => $bridge_name,
					old  => $old_mac_address, 
					new  => $new_mac_address, 
				};
				
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_network_alert_0004", variables => $variables});
				$anvil->Alert->register({
					alert_level => "notice", 
					message     => "scan_network_alert_0004", 
					variables   => $variables,
					set_by      => $THIS_FILE,
				});
			}
			elsif ($new_mtu ne $old_mtu)
			{
				# This is a waning, need to ensure the client understands what's going on here.
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
				
				my $variables = {
					name => $bridge_name,
					old  => $old_mtu, 
					new  => $new_mtu, 
				};
				
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0005", variables => $variables});
				$anvil->Alert->register({
					alert_level => "warning", 
					message     => "scan_network_alert_0005", 
					variables   => $variables,
					set_by      => $THIS_FILE,
				});
			}
			elsif ($new_stp_enabled ne $old_stp_enabled)
			{
				# This is a notice
				$changes = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }});
				
				my $variables = {
					name => $bridge_name,
					old  => $old_stp_enabled, 
					new  => $new_stp_enabled, 
				};
				
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_network_alert_0006", variables => $variables});
				$anvil->Alert->register({
					alert_level => "notice", 
					message     => "scan_network_alert_0006", 
					variables   => $variables,
					set_by      => $THIS_FILE,
				});
			}
			
			if ($changes)
			{
				# Update
				my $bridge_uuid = $anvil->Database->insert_or_update_bridges({
					debug              => 2,
					bridge_name        => $bridge_name, 
					bridge_id          => $new_bridge_id, 
					bridge_mac_address => $new_mac_address, 
					bridge_mtu         => $new_mtu, 
					bridge_stp_enabled => $new_stp_enabled, 
				});
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bridge_uuid => $bridge_uuid }});
			}
			
			# Rx and Tx almost always change, so they're only info-level alerts.
			if ($new_tx_bytes ne $old_tx_bytes)
			{
				if ($tx_variable_uuid)
				{
					my $variable_uuid = $anvil->Database->insert_or_update_variables({
						debug             => 2,
						variable_uuid     => $tx_variable_uuid, 
						update_value_only => 1,
						variable_value    => $new_tx_bytes,
					});
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable_uuid => $variable_uuid }});
				}
				else
				{
					# No value seen before, create
					my $variable_uuid = $anvil->Database->insert_or_update_variables({
						debug                 => 2,
						variable_name         => "bridge::".$bridge_name."::tx_bytes",
						variable_value        => $new_tx_bytes,
						variable_default      => 0, 
						variable_description  => "striker_0291", 
						variable_section      => "stats", 
						variable_source_uuid  => $bridge_uuid, 
						variable_source_table => "bridges", 
					});
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable_uuid => $variable_uuid }});
				}
				
				my $variables = {
					name => $bridge_name,
					old  => $old_tx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $old_tx_bytes}).")", 
					new  => $new_tx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_tx_bytes}).")", 
				};
				
				# Reset or normal increase?
				my $message_key = "scan_network_alert_0007";
				my $alert_level = "info";
				my $log_level   = 2;
				if ($old_tx_bytes > $new_tx_bytes)
				{
					# Reset
					$message_key = "scan_network_alert_0008";
					$alert_level = "notice";
					$log_level   = 2;
				}
				
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $log_level, key => $message_key, variables => $variables});
				$anvil->Alert->register({
					alert_level => $alert_level, 
					message     => $message_key, 
					variables   => $variables,
					set_by      => $THIS_FILE,
				});
			}
			if ($new_rx_bytes ne $old_rx_bytes)
			{
				if ($rx_variable_uuid)
				{
					my $variable_uuid = $anvil->Database->insert_or_update_variables({
						debug             => 2,
						variable_uuid     => $rx_variable_uuid, 
						update_value_only => 1,
						variable_value    => $new_rx_bytes,
					});
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable_uuid => $variable_uuid }});
				}
				else
				{
					# No value seen before, create
					my $variable_uuid = $anvil->Database->insert_or_update_variables({
						debug                 => 2,
						variable_name         => "bridge::".$bridge_name."::rx_bytes",
						variable_value        => $new_rx_bytes,
						variable_default      => 0, 
						variable_description  => "striker_0290", 
						variable_section      => "stats", 
						variable_source_uuid  => $bridge_uuid, 
						variable_source_table => "bridges", 
					});
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable_uuid => $variable_uuid }});
				}
				
				my $variables = {
					name => $bridge_name,
					old  => $old_rx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $old_rx_bytes}).")", 
					new  => $new_rx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_rx_bytes}).")", 
				};
				
				# Reset or normal increase?               Reset                       Normal increase
				my $message_key = "scan_network_alert_0009";
				my $alert_level = "info";
				my $log_level   = 2;
				if ($old_rx_bytes > $new_rx_bytes)
				{
					# Reset
					$message_key = "scan_network_alert_0010";
					$alert_level = "notice";
					$log_level   = 2;
				}
				
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $log_level, key => $message_key, variables => $variables});
				$anvil->Alert->register({
					alert_level => $alert_level, 
					message     => $message_key, 
					variables   => $variables,
					set_by      => $THIS_FILE,
				});
			}
		}
		else
		{
			# New, INSERT it and record the new UUID for the interfaces connected on this bridge
			# to find.
			my $bridge_uuid = $anvil->Database->insert_or_update_bridges({
				debug              => 2,
				bridge_name        => $bridge_name, 
				bridge_id          => $new_bridge_id, 
				bridge_mac_address => $new_mac_address, 
				bridge_mtu         => $new_mtu, 
				bridge_stp_enabled => $new_stp_enabled, 
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bridge_uuid => $bridge_uuid }});
			
			$anvil->data->{bridges}{name_to_uuid}{$bridge_name}   = $bridge_uuid;
			$anvil->data->{bridges}{uuid_to_name}{$bridge_uuid}   = $bridge_name;
			$anvil->data->{interface}{name_to_uuid}{$bridge_name} = $bridge_uuid;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"old::bridges::name_to_uuid::${bridge_name}" => $anvil->data->{bridges}{name_to_uuid}{$bridge_name}, 
				"old::bridges::uuid_to_name::${bridge_uuid}" => $anvil->data->{bridges}{uuid_to_name}{$bridge_uuid}, 
				"interface::name_to_uuid::${bridge_name}"    => $anvil->data->{interface}{name_to_uuid}{$bridge_name}, 
			}});
			
			# Store the rx_bytes and tx_bytes
			my $rx_variable_uuid = $anvil->Database->insert_or_update_variables({
				debug                 => 2,
				variable_name         => "bridge::".$bridge_name."::rx_bytes",
				variable_value        => $new_rx_bytes,
				variable_default      => 0, 
				variable_description  => "striker_0290", 
				variable_section      => "stats", 
				variable_source_uuid  => $bridge_uuid, 
				variable_source_table => "bridges", 
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { rx_variable_uuid => $rx_variable_uuid }});
			my $tx_variable_uuid = $anvil->Database->insert_or_update_variables({
				debug                 => 2,
				variable_name         => "bridge::".$bridge_name."::tx_bytes",
				variable_value        => $new_tx_bytes,
				variable_default      => 0, 
				variable_description  => "striker_0291", 
				variable_section      => "stats", 
				variable_source_uuid  => $bridge_uuid, 
				variable_source_table => "bridges", 
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { tx_variable_uuid => $tx_variable_uuid }});
			
			# Report.
			my $variables = {
				bridge_name => $bridge_name, 
				bridge_id   => $new_bridge_id, 
				mac_address => $new_mac_address, 
				mtu         => $new_mtu, 
				stp_enabled => $new_stp_enabled, 
				say_tx      => $anvil->Convert->add_commas({number => $new_tx_bytes})." #!string!suffix_0057!# (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_tx_bytes}).")",
				say_rx      => $anvil->Convert->add_commas({number => $new_rx_bytes})." #!string!suffix_0057!# (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_rx_bytes}).")",
			};
			
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0002", variables => $variables});
			$anvil->Alert->register({
				alert_level => "warning", 
				message     => "scan_network_alert_0002", 
				variables   => $variables,
				set_by      => $THIS_FILE,
			});
		}
	}
	
	# Look for left over / deleted bridges.
	foreach my $bridge_uuid (keys %{$anvil->data->{old}{bridges}{bridge_uuid}})
	{
		# Skip if already deleted.
		if (not $bridge_uuid)
		{
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_warning_0001"});
			$anvil->nice_exit({exit_code => 1});
		}
		
		my $bridge_name = $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{bridge_name};
		my $bridge_id   = $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{bridge_id};
		my $tx_bytes    = $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{tx_bytes};
		my $rx_bytes    = $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{rx_bytes};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			bridge_uuid => $bridge_uuid,
			bridge_name => $bridge_name, 
			tx_bytes    => $tx_bytes, 
			rx_bytes    => $rx_bytes, 
		}});
		next if $bridge_id eq "DELETED";
		
		my $variables = {
			name => $bridge_name,
			tx   => $anvil->Convert->add_commas({number => $tx_bytes})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $tx_bytes}).")", 
			rx   => $anvil->Convert->add_commas({number => $rx_bytes})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $rx_bytes}).")", 
		};
		
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0057", variables => $variables});
		$anvil->Alert->register({
			alert_level => "warning", 
			message     => "scan_network_alert_0057", 
			variables   => $variables,
			set_by      => $THIS_FILE,
		});
		
		my $bridge_uuid = $anvil->Database->insert_or_update_bridges({
			debug       => 2,
			bridge_uuid => $bridge_uuid, 
			'delete'    => 1, 
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bridge_uuid => $bridge_uuid }});
	}
	
	return(0);
}

# This handles health record changes.
sub process_health
{
	my ($anvil) = @_;
	
	# Get the existing health scores, if any.
	my $query = "
SELECT 
    health_uuid, 
    health_source_name, 
    health_source_weight 
FROM 
    health 
WHERE 
    health_host_uuid   = ".$anvil->Database->quote($anvil->Get->host_uuid)."
AND 
    health_source_name LIKE '".$THIS_FILE."%'
;";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
	
	my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
	my $count   = @{$results};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		results => $results, 
		count   => $count, 
	}});
	foreach my $row (@{$results})
	{
		# We've got an entry in the 'scan_hardware' table, so now we'll look for data in the node and 
		# services tables.
		my $health_source_name = $row->[1]; 
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { health_source_name => $health_source_name }});
		
		$anvil->data->{old}{health}{$health_source_name}{health_uuid}          = $row->[0];
		$anvil->data->{old}{health}{$health_source_name}{health_source_weight} = $row->[2];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"old::health::${health_source_name}::health_uuid"          => $anvil->data->{old}{health}{$health_source_name}{health_uuid}, 
			"old::health::${health_source_name}::health_source_weight" => $anvil->data->{old}{health}{$health_source_name}{health_source_weight}, 
		}});
	}
	
	# Now look for interfaces that are down. For now, that's all we look for to set / clear health.
	foreach my $network_interface_name (sort {$a cmp $b} keys %{$anvil->data->{new}{interface}})
	{
		my $new_duplex      = $anvil->data->{new}{interface}{$network_interface_name}{duplex};
		my $new_link_state  = $anvil->data->{new}{interface}{$network_interface_name}{link_state};
		my $new_operational = $anvil->data->{new}{interface}{$network_interface_name}{operational};
		my $source_name     = $THIS_FILE."::".$network_interface_name."::problem";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			network_interface_name => $network_interface_name, 
			new_duplex             => $new_duplex,
			new_link_state         => $new_link_state,
			new_operational        => $new_operational,
			source_name            => $source_name, 
		}});
		
		# Don't set / clear interfaces that appear down but aren't named ifn/bcn/sn as they're probably 
		# unconfigured/unusued interfaces.
		my $problem   = 0;
		my $check     = 0;
		my $monitored = $anvil->Network->is_our_interface({interface => $network_interface_name});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { monitored => $monitored }});
		if ($monitored)
		{
			# One we monitor
			$check = 1;
		}
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { check => $check }});
		
		if (($check) && ((not $new_link_state) or ($new_operational eq "down") or ($new_duplex ne "full")))
		{
			$problem = 1;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }});
			
			if (exists $anvil->data->{old}{health}{$source_name})
			{
				# Already registered.
				delete $anvil->data->{old}{health}{$source_name};
			}
			else
			{
				# Has the interface been down for at least a minute?
				my $age = $anvil->Alert->check_condition_age({
					debug     => 2,
					name      => $source_name,
					host_uuid => $anvil->Get->host_uuid, 
				});
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { age => $age }});
				if ($age > 60)
				{
					# New, save.
					my ($health_uuid) = $anvil->Database->insert_or_update_health({
						debug                => 2,
						health_agent_name    => $THIS_FILE,
						health_source_name   => $source_name,
						health_source_weight => 1,
					});
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { health_uuid => $health_uuid }});
				}
			}
		}
		else
		{
			# Clear any old conditions.
			my $age = $anvil->Alert->check_condition_age({
				debug     => 2,
				clear     => 1,
				name      => $source_name,
				host_uuid => $anvil->Get->host_uuid, 
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { age => $age }});
		}
	}
	
	# Any remaining health scores can be deleted.
	foreach my $health_source_name (sort {$a cmp $b} keys %{$anvil->data->{old}{health}})
	{
		my $health_uuid = $anvil->data->{old}{health}{$health_source_name}{health_uuid};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			health_source_name => $health_source_name, 
			health_uuid        => $health_uuid,
		}});
		$anvil->Database->insert_or_update_health({
			debug       => 2,
			health_uuid => $health_uuid,
			'delete'    => 1,
		});
	}
	
	return(0);
}
