1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-03-27 10:50:10 +03:00

Feature #3056: Fix vnet leases in fsck

This commit is contained in:
Carlos Martín 2015-02-12 11:33:19 +01:00
parent 75b0436515
commit 6120d8aba0
2 changed files with 422 additions and 17 deletions

View File

@ -51,6 +51,10 @@ EOT
IMAGE_STATES=%w{INIT READY USED DISABLED LOCKED ERROR CLONE DELETE USED_PERS}
VM_BIN = 0x0000001000000000
NET_BIN = 0x0000004000000000
HOLD = 0xFFFFFFFF
def fsck
########################################################################
@ -756,11 +760,16 @@ EOT
# Init vnet counters
@db.fetch("SELECT oid,body FROM network_pool") do |row|
doc = Document.new(row[:body])
doc = Nokogiri::XML(row[:body]){|c| c.default_xml.noblanks}
ar_leases = {}
doc.root.xpath("AR_POOL/AR/AR_ID").each do |ar_id|
ar_leases[ar_id.text.to_i] = {}
end
counters[:vnet][row[:oid]] = {
:type => doc.root.get_text('TYPE').to_s.to_i,
:ar_leases => {}
:ar_leases => ar_leases
}
end
@ -788,9 +797,9 @@ EOT
end
# VNets used by this VM
vm_doc.root.xpath("TEMPLATE/NIC").each do |e|
vm_doc.root.xpath("TEMPLATE/NIC").each do |nic|
net_id = nil
e.xpath("NETWORK_ID").each do |nid|
nic.xpath("NETWORK_ID").each do |nid|
net_id = nid.text.to_i
end
@ -799,20 +808,25 @@ EOT
log_error("VM #{row[:oid]} is using VNet #{net_id}, "<<
"but it does not exist")
else
=begin
ar_id_e = e.at_xpath('AR_ID')
ar_id_e = nic.at_xpath('AR_ID')
ar_id = ar_id_e.nil? ? -1 : ar_id_e.text.to_i
if counters[:vnet][net_id][:ar_leases][ar_id].nil?
counters[:vnet][net_id][:ar_leases][ar_id] = []
log_error("VM #{row[:oid]} is using VNet #{net_id}, AR #{ar_id}, "<<
"but the AR does not exist")
end
counters[:vnet][net_id][:ar_leases][ar_id] <<
[
e.at_xpath('MAC').text, # MAC
vm_doc.root.at_xpath('ID').text.to_i # VID
]
=end
mac = nic.at_xpath("MAC").nil? ? nil : nic.at_xpath("MAC").text
counters[:vnet][net_id][:ar_leases][ar_id][mac_s_to_i(mac)] = {
:ip => nic.at_xpath("IP").nil? ? nil : nic.at_xpath("IP").text,
:ip6_global => nic.at_xpath("IP6_GLOBAL").nil? ? nil : nic.at_xpath("IP6_GLOBAL").text,
:ip6_link => nic.at_xpath("IP6_LINK").nil? ? nil : nic.at_xpath("IP6_LINK").text,
:ip6_ula => nic.at_xpath("IP6_ULA").nil? ? nil : nic.at_xpath("IP6_ULA").text,
:mac => mac,
:vm => row[:oid],
:vnet => nil
}
end
end
end
@ -1103,6 +1117,360 @@ EOT
log_time()
########################################################################
# VNet
#
# LEASES
########################################################################
@db.fetch("SELECT oid,body,pid FROM network_pool WHERE pid<>-1") do |row|
doc = Nokogiri::XML(row[:body]){|c| c.default_xml.noblanks}
parent_vnet = doc.root.at_xpath("PARENT_NETWORK_ID").text.to_i
if (row[:pid] != parent_vnet)
# TODO
end
doc.root.xpath("AR_POOL/AR").each do |ar|
parent_ar_e = ar.at_xpath("PARENT_NETWORK_AR_ID")
if !(parent_ar_e.nil? || parent_ar_e.text == "")
parent_ar = parent_ar_e.text.to_i
if counters[:vnet][parent_vnet][:ar_leases][parent_ar].nil?
log_error(
"VNet #{row[:oid]} is using parent "<<
"VNet #{parent_vnet}, AR #{parent_ar}, "<<
"but the AR does not exist")
end
# MAC
first_mac = mac_s_to_i(ar.at_xpath("MAC").text)
# IP
first_ip = nil
if (!ar.at_xpath("IP").nil?)
first_ip = IPAddr.new(ar.at_xpath("IP").text, Socket::AF_INET)
end
# IP6
global_prefix = nil
if !ar.at_xpath("GLOBAL_PREFIX").nil?
global_prefix = ip6_prefix_s_to_i(
ar.at_xpath("GLOBAL_PREFIX").text)
end
ula_prefix = nil
if !ar.at_xpath("ULA_PREFIX").nil?
ula_prefix = ip6_prefix_s_to_i(
ar.at_xpath("ULA_PREFIX").text)
end
link_prefix = nil
type = ar.at_xpath("TYPE").text
if ( type == "IP6" || type == "IP4_6" )
link_prefix = 0xfe80000000000000
end
# Parent vnet has a lease for each address of this reservation
ar.at_xpath("SIZE").text.to_i.times do |index|
lease = {
:ip => nil,
:ip6_global => nil,
:ip6_link => nil,
:ip6_ula => nil,
:mac => nil,
:vm => nil,
:vnet => row[:oid]
}
#MAC
mac = (first_mac & 0xFFFF00000000) +
(((first_mac & 0xFFFFFFFF) + index) % 0x100000000)
lease[:mac] = mac_i_to_s(mac)
# IP
if (!first_ip.nil?)
lease[:ip] = IPAddr.new(first_ip.to_i + index,
Socket::AF_INET).to_s
end
# IP6
ip6_suffix = mac_to_ip6_suffix(mac)
if (!global_prefix.nil?)
lease[:ip6_global] = IPAddr.new(
(global_prefix << 64) | ip6_suffix,
Socket::AF_INET6 ).to_s
end
if (!ula_prefix.nil?)
lease[:ip6_ula] = IPAddr.new(
(ula_prefix << 64) | ip6_suffix,
Socket::AF_INET6 ).to_s
end
if (!link_prefix.nil?)
lease[:ip6_link] = IPAddr.new(
(link_prefix << 64) | ip6_suffix,
Socket::AF_INET6 ).to_s
end
counters[:vnet][parent_vnet][
:ar_leases][parent_ar][mac] = lease
end
end
end
end
# Create a new empty table where we will store the new calculated values
@db.run "CREATE TABLE network_pool_new (oid INTEGER PRIMARY KEY, name VARCHAR(128), body MEDIUMTEXT, uid INTEGER, gid INTEGER, owner_u INTEGER, group_u INTEGER, other_u INTEGER, cid INTEGER, pid INTEGER, UNIQUE(name,uid));"
@db.transaction do
@db[:network_pool].each do |row|
doc = Nokogiri::XML(row[:body]){|c| c.default_xml.noblanks}
oid = row[:oid]
used_leases = doc.root.at_xpath("USED_LEASES").text.to_i
new_used_leases = 0
counters[:vnet][row[:oid]][:ar_leases].each do |ar_id, counter_ar|
net_ar = doc.root.at_xpath("AR_POOL/AR[AR_ID=#{ar_id}]")
if (net_ar.nil?)
# TODO shouldn't happen?
end
# MAC
first_mac = mac_s_to_i(net_ar.at_xpath("MAC").text)
# IP
first_ip = nil
if !net_ar.at_xpath("IP").nil?
first_ip = IPAddr.new(net_ar.at_xpath("IP").text, Socket::AF_INET)
end
# IP6
global_prefix = nil
if !net_ar.at_xpath("GLOBAL_PREFIX").nil?
global_prefix = ip6_prefix_s_to_i(
net_ar.at_xpath("GLOBAL_PREFIX").text)
end
ula_prefix = nil
if !net_ar.at_xpath("ULA_PREFIX").nil?
ula_prefix = ip6_prefix_s_to_i(
net_ar.at_xpath("ULA_PREFIX").text)
end
link_prefix = nil
type = net_ar.at_xpath("TYPE").text
if ( type == "IP6" || type == "IP4_6" )
link_prefix = 0xfe80000000000000
end
# Allocated leases
allocated_e = net_ar.at_xpath("ALLOCATED")
allocated = allocated_e.nil? ? "" : allocated_e.text
leases = allocated.scan(/(\d+) (\d+)/)
new_leases = []
leases.each do |lease_str|
index = lease_str[0].to_i
binary_magic = lease_str[1].to_i
lease = {
:ip => nil,
:ip6_global => nil,
:ip6_link => nil,
:ip6_ula => nil,
:mac => nil,
:vm => nil,
:vnet => nil
}
# MAC
mac = (first_mac & 0xFFFF00000000) +
(((first_mac & 0xFFFFFFFF) + index) % 0x100000000)
lease[:mac] = mac_i_to_s(mac)
# IP
if (!first_ip.nil?)
lease[:ip] = IPAddr.new(first_ip.to_i + index,
Socket::AF_INET).to_s
end
# IP6
ip6_suffix = mac_to_ip6_suffix(mac)
if (!global_prefix.nil?)
lease[:ip6_global] = IPAddr.new(
(global_prefix << 64) | ip6_suffix,
Socket::AF_INET6 ).to_s
end
if (!ula_prefix.nil?)
lease[:ip6_ula] = IPAddr.new(
(ula_prefix << 64) | ip6_suffix,
Socket::AF_INET6 ).to_s
end
if (!link_prefix.nil?)
lease[:ip6_link] = IPAddr.new(
(link_prefix << 64) | ip6_suffix,
Socket::AF_INET6 ).to_s
end
# OID
lease_oid = binary_magic & 0x00000000FFFFFFFF
lease_obj = ""
if (binary_magic & VM_BIN != 0)
lease[:vm] = lease_oid
lease_obj = "VM"
else # binary_magic & NET_BIN != 0
lease[:vnet] = lease_oid
lease_obj = "VNet"
end
counter_lease = counter_ar[mac]
counter_ar.delete(mac)
if counter_lease.nil?
if(lease[:vm] != HOLD)
log_error(
"VNet #{oid} AR #{ar_id} has leased #{lease_to_s(lease)} "<<
"to #{lease_obj} #{lease_oid}, but it is actually free")
else
new_leases << lease_str
end
else
if counter_lease != lease
# Things that can be fixed
if (counter_lease[:vm] != lease[:vm] ||
counter_lease[:vnet] != lease[:vnet])
new_lease_obj = ""
new_lease_oid = 0
new_binary_magic = 0
if !counter_lease[:vm].nil?
new_lease_obj = "VM"
new_lease_oid = counter_lease[:vm].to_i
new_binary_magic = (VM_BIN |
(new_lease_oid & 0xFFFFFFFF))
else
new_lease_obj = "VNet"
new_lease_oid = counter_lease[:vnet].to_i
new_binary_magic = (NET_BIN |
(new_lease_oid & 0xFFFFFFFF))
end
if (lease[:vm] == HOLD)
log_error(
"VNet #{oid} AR #{ar_id} has lease "<<
"#{lease_to_s(lease)} on hold, but it is "<<
"actually used by "<<
"#{new_lease_obj} #{new_lease_oid}")
else
log_error(
"VNet #{oid} AR #{ar_id} has leased #{lease_to_s(lease)} "<<
"to #{lease_obj} #{lease_oid}, but it is "<<
"actually used by "<<
"#{new_lease_obj} #{new_lease_oid}")
end
lease_str[1] = new_binary_magic.to_s
end
# Things that can't be fixed
[:ip, :ip6_global, :ip6_link, :ip6_ula].each do |key|
if (counter_lease[key] != lease[key])
log_error(
"VNet #{oid} AR #{ar_id} has a wrong "<<
"lease for "<<
"#{lease_obj} #{lease_oid}. #{key.to_s.upcase} "<<
"does not match: "<<
"#{counter_lease[key]} != #{lease[key]}. "<<
"This can't be fixed")
end
end
end
new_leases << lease_str
end
end
counter_ar.each do |mac, counter_lease|
index = ((mac & 0xFFFFFFFF) - (first_mac & 0xFFFFFFFF) ) % 0x100000000
new_lease_obj = ""
new_lease_oid = 0
new_binary_magic = 0
if !counter_lease[:vm].nil?
new_lease_obj = "VM"
new_lease_oid = counter_lease[:vm].to_i
new_binary_magic = (VM_BIN |
(new_lease_oid & 0xFFFFFFFF))
else
new_lease_obj = "VNet"
new_lease_oid = counter_lease[:vnet].to_i
new_binary_magic = (NET_BIN |
(new_lease_oid & 0xFFFFFFFF))
end
log_error("VNet #{oid} AR #{ar_id} does not have a lease "<<
"for #{mac_i_to_s(mac)}, but it is in use by "<<
"#{new_lease_obj} #{new_lease_oid}")
new_leases << [index.to_s, new_binary_magic.to_s]
end
new_used_leases += new_leases.size
if new_leases.size > 0
allocated_e.content = " #{new_leases.join(" ")}"
else
allocated_e.remove if !allocated_e.nil?
end
end
if (new_used_leases != used_leases)
log_error("VNet #{oid} has #{used_leases} used leases, "<<
"but it is actually #{new_used_leases}")
doc.root.at_xpath("USED_LEASES").content =
new_used_leases.to_s
end
row[:body] = doc.root.to_s
# commit
@db[:network_pool_new].insert(row)
end
end
# Rename table
@db.run("DROP TABLE network_pool")
@db.run("ALTER TABLE network_pool_new RENAME TO network_pool")
log_time()
########################################################################
# Users
#
@ -1477,4 +1845,41 @@ EOT
new_elem.add_child(doc.create_element("SIZE_USED")).content = size_used.to_s
}
end
def mac_s_to_i(mac)
return mac.split(":").map {|e|
e.to_i(16).to_s(16).rjust(2,"0")}.join("").to_i(16)
end
def mac_i_to_s(mac)
mac_s = mac.to_s(16).rjust(12, "0")
return "#{mac_s[0..1]}:#{mac_s[2..3]}:#{mac_s[4..5]}:"<<
"#{mac_s[6..7]}:#{mac_s[8..9]}:#{mac_s[10..11]}"
end
def ip6_prefix_s_to_i(prefix)
return prefix.split(":", 4).map {|e|
e.to_i(16).to_s(16).rjust(4, "0")}.join("").to_i(16)
end
# Copied from AddressRange::set_ip6 in AddressRange.cc
def mac_to_ip6_suffix(mac_i)
mac = [
mac_i & 0x00000000FFFFFFFF,
(mac_i & 0xFFFFFFFF00000000) >> 32
]
mlow = mac[0]
eui64 = [
4261412864 + (mlow & 0x00FFFFFF),
((mac[1]+512)<<16) + ((mlow & 0xFF000000)>>16) + 0x000000FF
]
return (eui64[1] << 32) + eui64[0]
end
def lease_to_s(lease)
return lease[:ip].nil? ? lease[:mac].to_s : lease[:ip].to_s
end
end

View File

@ -1072,12 +1072,12 @@ int AddressRange::free_addr(PoolObjectSQL::ObjectType ot, int obid,
unsigned int index = mac_i[0] - mac[0];
if ((0 <= index) && (index < size))
if ( index < 0)
{
return free_addr(ot, obid, index);
return -1;
}
return -1;
return free_addr(ot, obid, index);
}
/* -------------------------------------------------------------------------- */