netlink: Add ip rule support

This commit is contained in:
nick
2012-07-05 14:54:42 +01:00
parent 38f4f48968
commit 9d9cd3b70b
3 changed files with 122 additions and 12 deletions

View File

@@ -13,6 +13,7 @@ module Netlink
autoload :VlanHandler, 'linux/netlink/route/vlan_handler'
autoload :AddrHandler, 'linux/netlink/route/addr_handler'
autoload :RouteHandler, 'linux/netlink/route/route_handler'
autoload :RuleHandler, 'linux/netlink/route/rule_handler'
# This class formats and receives messages using NETLINK_ROUTE protocol
class Socket < NLSocket
@@ -40,6 +41,10 @@ module Netlink
@route ||= RouteHandler.new(self)
end
def rule
@rule ||= RuleHandler.new(self)
end
# Convert an interface index into name string, or nil if the
# index is nil or 0. Raises exception for unknown values.
#
@@ -69,3 +74,4 @@ module Netlink
end
end
end # module Linux

View File

@@ -8,7 +8,8 @@ module Netlink
# struct rtmsg
class RT < RtattrMessage
code RTM_NEWROUTE, RTM_DELROUTE, RTM_GETROUTE
code RTM_NEWROUTE, RTM_DELROUTE, RTM_GETROUTE,
RTM_NEWRULE, RTM_DELRULE, RTM_GETRULE
field :family, :uchar # Socket::AF_*
field :dst_len, :uchar
@@ -197,3 +198,4 @@ module Netlink
end
end
end # module Linux

View File

@@ -0,0 +1,102 @@
require 'linux/netlink/route'
require 'linux/netlink/route/route_handler'
module Linux
module Netlink
module Route
# This class manipulates the kernel routing table by adding and removing
# rules
class RuleHandler < Handler
def clear_cache
@rule = nil
end
def read_rule(opt=nil, &blk)
@rtsocket.send_request RTM_GETRULE, RT.new(opt),
NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST
@rtsocket.receive_until_done(RTM_NEWRULE, &blk)
end
Filter = RouteHandler::Filter
# Return the memoized rule list, filtered according to
# the optional criteria. Examples:
# :family => Socket::AF_INET
# :table => Linux::RT_TABLE_DEFAULT
# :protocol => Linux::RTPROT_STATIC
# :type => Linux::RTN_UNICAST
# :scope => Linux::RT_SCOPE_HOST
# :flags => Linux::RTM_F_NOTIFY
# :noflags => Linux::RTM_F_CLONED
# :oif => "eth0"
# :iif => "eth1"
def list(filter=nil, &blk)
@rule ||= read_rule
filter[:oif] = index(filter[:oif]) if filter && filter.has_key?(:oif)
filter[:iif] = index(filter[:iif]) if filter && filter.has_key?(:iif)
filter_list(@rule, filter, &blk)
end
alias :each :list
def add(opt)
iproute_modify(RTM_NEWRULE, NLM_F_CREATE|NLM_F_EXCL, opt)
end
def delete(opt)
iproute_modify(RTM_DELRULE, 0, opt)
end
# Get route matching given criteria
def get(msg)
msg = RT.new(msg)
raise "Missing :dst" unless msg.dst
msg.iif = index(msg.iif) if msg.iif.is_a?(String)
msg.oif = index(msg.oif) if msg.oif.is_a?(String)
@rtsocket.cmd RTM_GETRULE, msg, NLM_F_REQUEST, RTM_NEWRULE
end
def iproute_modify(code, flags, msg) #:nodoc:
msg = RT.new(msg)
if code != RTM_DELRULE
msg.protocol ||= RTPROT_BOOT
msg.type ||= RTN_UNICAST
end
# There is scary code in ip/iproute.c for setting defaults
unless msg.table
msg.table = case msg.type
when RTN_LOCAL, RTN_BROADCAST, RTN_NAT, RTN_ANYCAST
RT_TABLE_LOCAL
else
RT_TABLE_MAIN
end
end
unless msg.scope
msg.scope = (code != RTM_DELRULE) ? RT_SCOPE_UNIVERSE : RT_SCOPE_NOWHERE
case msg.type
when RTN_LOCAL, RTN_NAT
msg.scope = RT_SCOPE_HOST
when RTN_BROADCAST, RTN_MULTICAST, RTN_ANYCAST
msg.scope RT_SCOPE_LINK
when RTN_UNICAST, RTN_UNSPEC
if code == RTM_DELRULE
msg.scope = RT_SCOPE_NOWHERE
elsif !msg.gateway && !msg.multipath
msg.scope = RT_SCOPE_LINK
end
end
end
msg.iif = index(msg.iif) if msg.iif.is_a?(String)
msg.oif = index(msg.oif) if msg.oif.is_a?(String)
@rtsocket.cmd code, msg, flags|NLM_F_REQUEST
clear_cache
end
end
end
end
end # module Linux