Unpack metrics

This commit is contained in:
Brian Candler
2011-04-29 17:04:02 +01:00
parent 54de866e97
commit 8c8d199a09
2 changed files with 54 additions and 22 deletions

View File

@@ -183,6 +183,23 @@ module Netlink
RTA_CACHEINFO = 12 RTA_CACHEINFO = 12
RTA_TABLE = 15 RTA_TABLE = 15
# Keys for Route#metrics
RTAX_UNSPEC = 0
RTAX_LOCK = 1
RTAX_MTU = 2
RTAX_WINDOW = 3
RTAX_RTT = 4
RTAX_RTTVAR = 5
RTAX_SSTHRESH = 6
RTAX_CWND = 7
RTAX_ADVMSS = 8
RTAX_REORDERING = 9
RTAX_HOPLIMIT = 10
RTAX_INITCWND = 11
RTAX_FEATURES = 12
RTAX_RTO_MIN = 13
RTAX_INITRWND = 14
# from linux/if_link.h # from linux/if_link.h
IFLA_UNSPEC = 0 IFLA_UNSPEC = 0
IFLA_ADDRESS = 1 IFLA_ADDRESS = 1

View File

@@ -23,6 +23,9 @@ module Netlink
# Map of numeric message type code => message class # Map of numeric message type code => message class
CODE_TO_MESSAGE = {} CODE_TO_MESSAGE = {}
METRIC_PACK = "SSL".freeze #:nodoc:
METRIC_SIZE = [0,0,0].pack(METRIC_PACK).bytesize #:nodoc:
# Defines each of the possible field types # Defines each of the possible field types
TYPE_INFO = { TYPE_INFO = {
:uchar => { :pattern => "C" }, :uchar => { :pattern => "C" },
@@ -55,6 +58,16 @@ module Netlink
:pack => lambda { |val| val.to_a.pack("L*") }, :pack => lambda { |val| val.to_a.pack("L*") },
:unpack => lambda { |str| IFACacheInfo.new(*(str.unpack("L*"))) }, :unpack => lambda { |str| IFACacheInfo.new(*(str.unpack("L*"))) },
}, },
:metrics => {
:pack => lambda { |pairs|
pairs.map { |code,val| [METRIC_SIZE,code,val].pack(METRIC_PACK) }.join
},
:unpack => lambda { |str|
res = {} # in kernel the dst.metrics structure is array of u32
RtattrMessage.unpack_rtattr(str) { |code,val| res[code] = val.unpack("L").first }
res
},
},
:l3addr => { :l3addr => {
:pack => lambda { |val| val.hton }, :pack => lambda { |val| val.hton },
:unpack => lambda { |val| IPAddr.new_ntoh(val) }, :unpack => lambda { |val| IPAddr.new_ntoh(val) },
@@ -204,20 +217,9 @@ module Netlink
def self.parse(data) def self.parse(data)
res = super res = super
ptr = attr_offset attrs = res.to_hash
while ptr < data.bytesize unpack_rtattr(data, attr_offset) do |code, val|
raise "Truncated rtattr header!" if ptr + RTATTR_SIZE > data.bytesize name, info = self::RTATTRS[code]
len, code = data[ptr, RTATTR_SIZE].unpack(RTATTR_PACK)
raise "Truncated rtattr body!" if ptr + len > data.bytesize
raise "Invalid rtattr len!" if len < RTATTR_SIZE
res._add_attr(code, data[ptr+RTATTR_SIZE, len-RTATTR_SIZE])
ptr = Message.align(ptr + len)
end
res
end
def _add_attr(code, val) # :nodoc:
name, info = self.class::RTATTRS[code]
if name if name
if !info if !info
# skip # skip
@@ -226,11 +228,24 @@ module Netlink
elsif pattern = info[:pattern] elsif pattern = info[:pattern]
val = val.unpack(pattern).first val = val.unpack(pattern).first
end end
warn "Duplicate attribute #{name} (#{code}): #{@attrs[name].inspect} -> #{val.inspect}" if @attrs[name] warn "Duplicate attribute #{name} (#{code}): #{attrs[name].inspect} -> #{val.inspect}" if attrs[name]
@attrs[name] = val attrs[name] = val
else else
warn "Unknown attribute #{code}, value #{val.inspect}" warn "Unknown attribute #{code}, value #{val.inspect}"
@attrs[code] = val attrs[code] = val
end
end
res
end
def self.unpack_rtattr(data, ptr=0) #:nodoc:
while ptr < data.bytesize
raise "Truncated rtattr header!" if ptr + RTATTR_SIZE > data.bytesize
len, code = data[ptr, RTATTR_SIZE].unpack(RTATTR_PACK)
raise "Truncated rtattr body!" if ptr + len > data.bytesize
raise "Invalid rtattr len!" if len < RTATTR_SIZE
yield code, data[ptr+RTATTR_SIZE, len-RTATTR_SIZE]
ptr = Message.align(ptr + len)
end end
end end
end end
@@ -303,7 +318,7 @@ module Netlink
rtattr :gateway, RTA_GATEWAY, :l3addr rtattr :gateway, RTA_GATEWAY, :l3addr
rtattr :priority, RTA_PRIORITY, :uint32 rtattr :priority, RTA_PRIORITY, :uint32
rtattr :prefsrc, RTA_PREFSRC, :l3addr rtattr :prefsrc, RTA_PREFSRC, :l3addr
rtattr :metrics, RTA_METRICS rtattr :metrics, RTA_METRICS, :metrics
rtattr :multipath, RTA_MULTIPATH rtattr :multipath, RTA_MULTIPATH
rtattr :flow, RTA_FLOW rtattr :flow, RTA_FLOW
rtattr :cacheinfo, RTA_CACHEINFO, :rta_cacheinfo rtattr :cacheinfo, RTA_CACHEINFO, :rta_cacheinfo