netlink: Add ip rule support
This commit is contained in:
@@ -13,7 +13,8 @@ module Netlink
|
|||||||
autoload :VlanHandler, 'linux/netlink/route/vlan_handler'
|
autoload :VlanHandler, 'linux/netlink/route/vlan_handler'
|
||||||
autoload :AddrHandler, 'linux/netlink/route/addr_handler'
|
autoload :AddrHandler, 'linux/netlink/route/addr_handler'
|
||||||
autoload :RouteHandler, 'linux/netlink/route/route_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
|
# This class formats and receives messages using NETLINK_ROUTE protocol
|
||||||
class Socket < NLSocket
|
class Socket < NLSocket
|
||||||
def initialize(opt={})
|
def initialize(opt={})
|
||||||
@@ -24,22 +25,26 @@ module Netlink
|
|||||||
def link
|
def link
|
||||||
@link ||= LinkHandler.new(self)
|
@link ||= LinkHandler.new(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Return a VlanHandler object for manipulating vlans
|
# Return a VlanHandler object for manipulating vlans
|
||||||
def vlan
|
def vlan
|
||||||
@vlan ||= VlanHandler.new(self)
|
@vlan ||= VlanHandler.new(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Return a AddrHandler object for manipulating addresses
|
# Return a AddrHandler object for manipulating addresses
|
||||||
def addr
|
def addr
|
||||||
@addr ||= AddrHandler.new(self)
|
@addr ||= AddrHandler.new(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Return a RT object for manipulating routes
|
# Return a RT object for manipulating routes
|
||||||
def route
|
def route
|
||||||
@route ||= RouteHandler.new(self)
|
@route ||= RouteHandler.new(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def rule
|
||||||
|
@rule ||= RuleHandler.new(self)
|
||||||
|
end
|
||||||
|
|
||||||
# Convert an interface index into name string, or nil if the
|
# Convert an interface index into name string, or nil if the
|
||||||
# index is nil or 0. Raises exception for unknown values.
|
# index is nil or 0. Raises exception for unknown values.
|
||||||
#
|
#
|
||||||
@@ -52,7 +57,7 @@ module Netlink
|
|||||||
return nil if index.nil? || index == 0
|
return nil if index.nil? || index == 0
|
||||||
link[index].ifname
|
link[index].ifname
|
||||||
end
|
end
|
||||||
|
|
||||||
# Convert an interface name into index. Returns 0 for nil or empty
|
# Convert an interface name into index. Returns 0 for nil or empty
|
||||||
# string. Otherwise raises an exception for unknown values.
|
# string. Otherwise raises an exception for unknown values.
|
||||||
def index(name)
|
def index(name)
|
||||||
@@ -69,3 +74,4 @@ module Netlink
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end # module Linux
|
end # module Linux
|
||||||
|
|
||||||
|
@@ -8,7 +8,8 @@ module Netlink
|
|||||||
|
|
||||||
# struct rtmsg
|
# struct rtmsg
|
||||||
class RT < RtattrMessage
|
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 :family, :uchar # Socket::AF_*
|
||||||
field :dst_len, :uchar
|
field :dst_len, :uchar
|
||||||
@@ -59,7 +60,7 @@ module Netlink
|
|||||||
def clear_cache
|
def clear_cache
|
||||||
@route = nil
|
@route = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
# Send message to download the kernel routing table. Either returns an
|
# Send message to download the kernel routing table. Either returns an
|
||||||
# array of Netlink::RT objects, or yields them to the supplied block.
|
# array of Netlink::RT objects, or yields them to the supplied block.
|
||||||
#
|
#
|
||||||
@@ -98,7 +99,7 @@ module Netlink
|
|||||||
filter(:oif) { |o,v| o.oif == v }
|
filter(:oif) { |o,v| o.oif == v }
|
||||||
filter(:iif) { |o,v| o.iif == v }
|
filter(:iif) { |o,v| o.iif == v }
|
||||||
end
|
end
|
||||||
|
|
||||||
# Return the memoized route table, filtered according to
|
# Return the memoized route table, filtered according to
|
||||||
# the optional criteria. Examples:
|
# the optional criteria. Examples:
|
||||||
# :family => Socket::AF_INET
|
# :family => Socket::AF_INET
|
||||||
@@ -117,7 +118,7 @@ module Netlink
|
|||||||
filter_list(@route, filter, &blk)
|
filter_list(@route, filter, &blk)
|
||||||
end
|
end
|
||||||
alias :each :list
|
alias :each :list
|
||||||
|
|
||||||
def add(opt)
|
def add(opt)
|
||||||
iproute_modify(RTM_NEWROUTE, NLM_F_CREATE|NLM_F_EXCL, opt)
|
iproute_modify(RTM_NEWROUTE, NLM_F_CREATE|NLM_F_EXCL, opt)
|
||||||
end
|
end
|
||||||
@@ -125,7 +126,7 @@ module Netlink
|
|||||||
def change(opt)
|
def change(opt)
|
||||||
iproute_modify(RTM_NEWROUTE, NLM_F_REPLACE, opt)
|
iproute_modify(RTM_NEWROUTE, NLM_F_REPLACE, opt)
|
||||||
end
|
end
|
||||||
|
|
||||||
def replace(opt)
|
def replace(opt)
|
||||||
iproute_modify(RTM_NEWROUTE, NLM_F_CREATE|NLM_F_REPLACE, opt)
|
iproute_modify(RTM_NEWROUTE, NLM_F_CREATE|NLM_F_REPLACE, opt)
|
||||||
end
|
end
|
||||||
@@ -154,10 +155,10 @@ module Netlink
|
|||||||
msg.oif = index(msg.oif) if msg.oif.is_a?(String)
|
msg.oif = index(msg.oif) if msg.oif.is_a?(String)
|
||||||
@rtsocket.cmd RTM_GETROUTE, msg, NLM_F_REQUEST, RTM_NEWROUTE
|
@rtsocket.cmd RTM_GETROUTE, msg, NLM_F_REQUEST, RTM_NEWROUTE
|
||||||
end
|
end
|
||||||
|
|
||||||
def iproute_modify(code, flags, msg) #:nodoc:
|
def iproute_modify(code, flags, msg) #:nodoc:
|
||||||
msg = RT.new(msg)
|
msg = RT.new(msg)
|
||||||
|
|
||||||
if code != RTM_DELROUTE
|
if code != RTM_DELROUTE
|
||||||
msg.protocol ||= RTPROT_BOOT
|
msg.protocol ||= RTPROT_BOOT
|
||||||
msg.type ||= RTN_UNICAST
|
msg.type ||= RTN_UNICAST
|
||||||
@@ -197,3 +198,4 @@ module Netlink
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end # module Linux
|
end # module Linux
|
||||||
|
|
||||||
|
102
lib/linux/netlink/route/rule_handler.rb
Normal file
102
lib/linux/netlink/route/rule_handler.rb
Normal 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
|
||||||
|
|
Reference in New Issue
Block a user