mirror of
https://github.com/CumulusNetworks/ifupdown2.git
synced 2024-05-06 15:54:50 +00:00
Add rtnetlink api's for link creates
Ticket: CM-3346 Reviewed By: Testing Done:
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
from ifupdown.iface import *
|
||||
from ifupdownaddons.modulebase import moduleBase
|
||||
from ifupdownaddons.iproute2 import iproute2
|
||||
import ifupdown.rtnetlink_api as rtnetlink_api
|
||||
import logging
|
||||
import os
|
||||
import glob
|
||||
@@ -49,7 +50,9 @@ class addressvirtual(moduleBase):
|
||||
# Create a macvlan device on this device and set the virtual
|
||||
# router mac and ip on it
|
||||
macvlan_ifacename = '%s-%d' %(macvlan_prefix, av_idx)
|
||||
self.ipcmd.link_create_macvlan(macvlan_ifacename, realifacename)
|
||||
if not self.ipcmd.link_exists(macvlan_ifacename):
|
||||
rtnetlink_api.rtnl_api.create_macvlan(macvlan_ifacename,
|
||||
realifacename)
|
||||
if av_attrs[0] != 'None':
|
||||
self.ipcmd.link_set_hwaddress(macvlan_ifacename, av_attrs[0])
|
||||
self.ipcmd.addr_add_multiple(macvlan_ifacename, av_attrs[1:],
|
||||
|
@@ -58,6 +58,37 @@ class ethtool(moduleBase):
|
||||
self.log_warn('%s: %s' %(ifaceobj.name, str(e)))
|
||||
|
||||
def _query_check(self, ifaceobj, ifaceobjcurr):
|
||||
"""
|
||||
Advertised auto-negotiation: No
|
||||
Speed: 1000Mb/s
|
||||
Duplex: Full"""
|
||||
ethtool_attrs = self.dict_key_subset(ifaceobj.config,
|
||||
self.get_mod_attrs())
|
||||
if not ethtool_attrs:
|
||||
return
|
||||
try:
|
||||
speed = ifaceobj.get_attr_value_first('link-speed')
|
||||
if speed:
|
||||
running_speed = self.read_file_oneline(
|
||||
'/sys/class/net/%s/speed' %ifaceobj.name)
|
||||
if running_speed and running_speed != speed:
|
||||
ifaceobjcurr.update_config_with_status('link-speed',
|
||||
running_speed, 1)
|
||||
else:
|
||||
ifaceobjcurr.update_config_with_status('link-speed',
|
||||
running_speed, 0)
|
||||
duplex = ifaceobj.get_attr_value_first('link-duplex')
|
||||
if duplex:
|
||||
running_duplex = self.read_file_oneline(
|
||||
'/sys/class/net/%s/duplex' %ifaceobj.name)
|
||||
if running_duplex and running_duplex != duplex:
|
||||
ifaceobjcurr.update_config_with_status('link-duplex',
|
||||
running_duplex, 1)
|
||||
else:
|
||||
ifaceobjcurr.update_config_with_status('link-duplex',
|
||||
running_duplex, 0)
|
||||
except Exception, e:
|
||||
pass
|
||||
return
|
||||
|
||||
def _query_running(self, ifaceobjrunning):
|
||||
|
@@ -7,6 +7,7 @@
|
||||
from ifupdown.iface import *
|
||||
from ifupdownaddons.modulebase import moduleBase
|
||||
from ifupdownaddons.iproute2 import iproute2
|
||||
import ifupdown.rtnetlink_api as rtnetlink_api
|
||||
import logging
|
||||
|
||||
class vlan(moduleBase):
|
||||
@@ -97,8 +98,9 @@ class vlan(moduleBase):
|
||||
vlanrawdevice = self._get_vlan_raw_device(ifaceobj)
|
||||
if not vlanrawdevice:
|
||||
raise Exception('could not determine vlan raw device')
|
||||
self.ipcmd.link_create_vlan(ifaceobj.name,
|
||||
vlanrawdevice, vlanid)
|
||||
if not self.ipcmd.link_exists(ifaceobj.name):
|
||||
rtnetlink_api.rtnl_api.create_vlan(vlanrawdevice,
|
||||
ifaceobj.name, vlanid)
|
||||
|
||||
def _down(self, ifaceobj):
|
||||
vlanid = self._get_vlan_id(ifaceobj)
|
||||
|
36
ifupdown/iff.py
Executable file
36
ifupdown/iff.py
Executable file
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
|
||||
#
|
||||
# Author: Scott Feldman, sfeldma@cumulusnetworks.com
|
||||
#
|
||||
#
|
||||
# from /usr/include/linux/if.h
|
||||
#
|
||||
|
||||
# Standard interface flags (netdevice->flags).
|
||||
|
||||
IFF_UP = 0x1 # interface is up
|
||||
IFF_BROADCAST = 0x2 # broadcast address valid
|
||||
IFF_DEBUG = 0x4 # turn on debugging
|
||||
IFF_LOOPBACK = 0x8 # is a loopback net
|
||||
IFF_POINTOPOINT = 0x10 # interface is has p-p link
|
||||
IFF_NOTRAILERS = 0x20 # avoid use of trailers
|
||||
IFF_RUNNING = 0x40 # interface RFC2863 OPER_UP
|
||||
IFF_NOARP = 0x80 # no ARP protocol
|
||||
IFF_PROMISC = 0x100 # receive all packets
|
||||
IFF_ALLMULTI = 0x200 # receive all multicast packets
|
||||
|
||||
IFF_MASTER = 0x400 # master of a load balancer
|
||||
IFF_SLAVE = 0x800 # slave of a load balancer
|
||||
|
||||
IFF_MULTICAST = 0x1000 # Supports multicast
|
||||
|
||||
IFF_PORTSEL = 0x2000 # can set media type
|
||||
IFF_AUTOMEDIA = 0x4000 # auto media select active
|
||||
IFF_DYNAMIC = 0x8000 # dialup device with changing addresses
|
||||
|
||||
IFF_LOWER_UP = 0x10000 # driver signals L1 up
|
||||
IFF_DORMANT = 0x20000 # driver signals dormant
|
||||
|
||||
IFF_ECHO = 0x40000 # echo sent packets
|
@@ -12,6 +12,7 @@ import subprocess
|
||||
import re
|
||||
import os
|
||||
from iface import *
|
||||
import rtnetlink_api as rtnetlink_api
|
||||
|
||||
class ifupdownBase(object):
|
||||
|
||||
@@ -65,7 +66,7 @@ class ifupdownBase(object):
|
||||
return os.path.exists('/sys/class/net/%s' %ifacename)
|
||||
|
||||
def link_up(self, ifacename):
|
||||
self.exec_command('ifconfig %s up' %ifacename)
|
||||
rtnetlink_api.rtnl_api.link_set(ifacename, "up")
|
||||
|
||||
def link_down(self, ifacename):
|
||||
self.exec_command('ifconfig %s down' %ifacename)
|
||||
rtnetlink_api.rtnl_api.link_set(ifacename, "down")
|
||||
|
@@ -34,8 +34,8 @@ from sets import Set
|
||||
|
||||
_tickmark = u'\u2713'
|
||||
_crossmark = u'\u2717'
|
||||
_success_sym = ''
|
||||
_error_sym = '(x)'
|
||||
_success_sym = '(%s)' %_tickmark
|
||||
_error_sym = '(%s)' %_crossmark
|
||||
|
||||
class ifupdownMain(ifupdownBase):
|
||||
""" ifupdown2 main class """
|
||||
|
242
ifupdown/netlink.py
Normal file
242
ifupdown/netlink.py
Normal file
@@ -0,0 +1,242 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
|
||||
# Author: Scott Feldman, sfeldma@cumulusnetworks.com
|
||||
#
|
||||
|
||||
from os import strerror
|
||||
import select
|
||||
from time import time
|
||||
import socket
|
||||
from ctypes import *
|
||||
from errno import *
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
#
|
||||
# from /usr/include/linux/netlink.h
|
||||
#
|
||||
|
||||
NETLINK_ROUTE = 0 # Routing/device hook
|
||||
NETLINK_UNUSED = 1 # Unused number
|
||||
NETLINK_USERSOCK = 2 # Reserved for user mode socket protocols
|
||||
NETLINK_FIREWALL = 3 # Firewalling hook
|
||||
NETLINK_INET_DIAG = 4 # INET socket monitoring
|
||||
NETLINK_NFLOG = 5 # netfilter/iptables ULOG
|
||||
NETLINK_XFRM = 6 # ipsec
|
||||
NETLINK_SELINUX = 7 # SELinux event notifications
|
||||
NETLINK_ISCSI = 8 # Open-iSCSI
|
||||
NETLINK_AUDIT = 9 # auditing
|
||||
NETLINK_FIB_LOOKUP = 10
|
||||
NETLINK_CONNECTOR = 11
|
||||
NETLINK_NETFILTER = 12 # netfilter subsystem
|
||||
NETLINK_IP6_FW = 13
|
||||
NETLINK_DNRTMSG = 14 # DECnet routing messages
|
||||
NETLINK_KOBJECT_UEVENT = 15 # Kernel messages to userspace
|
||||
NETLINK_GENERIC = 16
|
||||
NETLINK_SCSITRANSPORT = 18 # SCSI Transports
|
||||
NETLINK_ECRYPTFS = 19
|
||||
NETLINK_RDMA = 20
|
||||
NETLINK_CRYPTO = 21 # Crypto layer
|
||||
|
||||
NLMSG_NOOP = 1 # Nothing.
|
||||
NLMSG_ERROR = 2 # Error
|
||||
NLMSG_DONE = 3 # End of a dump
|
||||
NLMSG_OVERRUN = 4 # Data lost
|
||||
|
||||
NETLINK_NO_ENOBUFS = 5
|
||||
|
||||
SOL_NETLINK = 270
|
||||
|
||||
class Nlmsghdr(Structure):
|
||||
|
||||
_fields_ = [
|
||||
('nlmsg_len', c_uint32),
|
||||
('nlmsg_type', c_uint16),
|
||||
('nlmsg_flags', c_uint16),
|
||||
('nlmsg_seq', c_uint32),
|
||||
('nlmsg_pid', c_uint32)
|
||||
]
|
||||
|
||||
def dump(self):
|
||||
print 'nlmsg_len', self.nlmsg_len
|
||||
print 'nlmsg_type', self.nlmsg_type
|
||||
print 'nlmsg_flags 0x%04x' % self.nlmsg_flags
|
||||
print 'nlmsg_seq', self.nlmsg_seq
|
||||
print 'nlmsg_pid', self.nlmsg_pid
|
||||
|
||||
# Flags values
|
||||
|
||||
NLM_F_REQUEST = 1 # It is request message.
|
||||
NLM_F_MULTI = 2 # Multipart message, terminated by NLMSG_DONE
|
||||
NLM_F_ACK = 4 # Reply with ack, with zero or error code
|
||||
NLM_F_ECHO = 8 # Echo this request
|
||||
NLM_F_DUMP_INTR = 16 # Dump was inconsistent due to sequence change
|
||||
|
||||
# Modifiers to GET request
|
||||
NLM_F_ROOT = 0x100 # specify tree root
|
||||
NLM_F_MATCH = 0x200 # return all matching
|
||||
NLM_F_ATOMIC = 0x400 # atomic GET
|
||||
NLM_F_DUMP = (NLM_F_ROOT|NLM_F_MATCH)
|
||||
|
||||
# Modifiers to NEW request
|
||||
NLM_F_REPLACE = 0x100 # Override existing
|
||||
NLM_F_EXCL = 0x200 # Do not touch, if it exists
|
||||
NLM_F_CREATE = 0x400 # Create, if it does not exist
|
||||
NLM_F_APPEND = 0x800 # Add to end of list
|
||||
|
||||
NLMSG_ALIGNTO = 4
|
||||
def NLMSG_ALIGN(len):
|
||||
return (len + NLMSG_ALIGNTO - 1) & ~(NLMSG_ALIGNTO - 1)
|
||||
def NLMSG_HDRLEN():
|
||||
return NLMSG_ALIGN(sizeof(Nlmsghdr))
|
||||
def NLMSG_LENGTH(len):
|
||||
return len + NLMSG_ALIGN(NLMSG_HDRLEN())
|
||||
def NLMSG_SPACE(len):
|
||||
return NLMSG_ALIGN(NLMSG_LENGTH(len))
|
||||
def NLMSG_DATA(nlh):
|
||||
return addressof(nlh) + NLMSG_LENGTH(0)
|
||||
def NLMSG_NEXT(nlh, len):
|
||||
cur = NLMSG_ALIGN(nlh.nlmsg_len)
|
||||
nlh = Nlmsghdr.from_address(addressof(nlh) + cur)
|
||||
return len - cur, nlh
|
||||
def NLMSG_OK(nlh, len):
|
||||
return len >= sizeof(Nlmsghdr) and \
|
||||
nlh.nlmsg_len >= sizeof(Nlmsghdr) and \
|
||||
nlh.nlmsg_len <= len
|
||||
|
||||
class Nlmsgerr(Structure):
|
||||
|
||||
_fields_ = [
|
||||
('error', c_int),
|
||||
('msg', Nlmsghdr),
|
||||
]
|
||||
|
||||
class NetlinkError(Exception):
|
||||
|
||||
def __init__(self, message):
|
||||
Exception.__init__(self, message)
|
||||
#logger.error(message)
|
||||
print(message)
|
||||
|
||||
class Netlink(socket.socket):
|
||||
|
||||
def __init__(self, pid, proto):
|
||||
|
||||
self.pid = pid
|
||||
self.recvbuf = bytearray(8 * 1024)
|
||||
self.sendbuf = bytearray(8 * 1024)
|
||||
self.seq = int(time())
|
||||
|
||||
try:
|
||||
|
||||
socket.socket.__init__(self, socket.AF_NETLINK, \
|
||||
socket.SOCK_RAW, proto)
|
||||
self.setblocking(0)
|
||||
|
||||
# Need to turn off ENOBUFS for netlink socket otherwise
|
||||
# in a kernel overrun situation, the socket will return
|
||||
# ENOBUFS on socket recv and be stuck for future recvs.
|
||||
|
||||
self.setsockopt(SOL_NETLINK, NETLINK_NO_ENOBUFS, 1)
|
||||
|
||||
except socket.error as (errno, string):
|
||||
raise NetlinkError("open: socket err[%d]: %s" % \
|
||||
(errno, string))
|
||||
|
||||
def bind(self, groups, cb):
|
||||
|
||||
self._nl_cb = cb
|
||||
|
||||
try:
|
||||
socket.socket.bind(self, (self.pid, groups))
|
||||
|
||||
except socket.error as (errno, string):
|
||||
raise NetlinkError("bind: socket err[%d]: %s" % \
|
||||
(errno, string))
|
||||
|
||||
def sendall(self, string):
|
||||
try:
|
||||
socket.socket.sendall(self, string)
|
||||
except socket.error as (errno, string):
|
||||
raise NetlinkError("send: socket err[%d]: %s" % \
|
||||
(errno, string))
|
||||
|
||||
def _process_nlh(self, recv, nlh):
|
||||
while NLMSG_OK(nlh, recv):
|
||||
yield recv, nlh
|
||||
recv, nlh = NLMSG_NEXT(nlh, recv)
|
||||
|
||||
def process(self, tokens=[]):
|
||||
|
||||
found_done = False
|
||||
|
||||
try:
|
||||
recv, src_addr = self.recvfrom_into(self.recvbuf)
|
||||
if not recv:
|
||||
# EOF
|
||||
print "EOF"
|
||||
return False
|
||||
|
||||
except socket.error as (errno, string):
|
||||
if errno in [EINTR, EAGAIN]:
|
||||
return False
|
||||
raise NetlinkError("process: socket err[%d]: %s" % \
|
||||
(errno, string))
|
||||
|
||||
nlh = Nlmsghdr.from_buffer(self.recvbuf)
|
||||
for recv, nlh in self._process_nlh(recv, nlh):
|
||||
|
||||
# print "type %u, seq %u, pid %u" % \
|
||||
# (nlh.nlmsg_type, nlh.nlmsg_seq, nlh.nlmsg_pid)
|
||||
|
||||
l = nlh.nlmsg_len - sizeof(Nlmsghdr)
|
||||
|
||||
if l < 0 or nlh.nlmsg_len > recv:
|
||||
raise NetlinkError("process: malformed msg: len %d" % \
|
||||
nlh.nlmsg_len)
|
||||
|
||||
if tokens:
|
||||
current = (nlh.nlmsg_pid, nlh.nlmsg_seq)
|
||||
if current not in tokens:
|
||||
continue
|
||||
|
||||
if nlh.nlmsg_type == NLMSG_DONE:
|
||||
found_done = True
|
||||
break
|
||||
|
||||
if nlh.nlmsg_type == NLMSG_ERROR:
|
||||
err = Nlmsgerr.from_address(NLMSG_DATA(nlh))
|
||||
if err.error == 0:
|
||||
return False
|
||||
raise NetlinkError("process: %s" % strerror(abs(err.error)))
|
||||
|
||||
if self._nl_cb:
|
||||
self._nl_cb(nlh)
|
||||
|
||||
if found_done:
|
||||
return False
|
||||
|
||||
remnant = recv - NLMSG_ALIGN(nlh.nlmsg_len) > 0
|
||||
if remnant:
|
||||
raise NetlinkError("process: remnant of size %d" % \
|
||||
remnant)
|
||||
|
||||
return True
|
||||
|
||||
def process_wait(self, tokens):
|
||||
while self.process(tokens):
|
||||
pass
|
||||
|
||||
def process_forever(self):
|
||||
epoll = select.epoll()
|
||||
epoll.register(self.fileno(), select.EPOLLIN)
|
||||
while True:
|
||||
events = epoll.poll()
|
||||
for fileno, event in events:
|
||||
if fileno == self.fileno():
|
||||
self.process()
|
||||
|
||||
def process_event(self, event):
|
||||
return self.process()
|
866
ifupdown/rtnetlink.py
Normal file
866
ifupdown/rtnetlink.py
Normal file
@@ -0,0 +1,866 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
|
||||
#
|
||||
# Author: Scott Feldman, sfeldma@cumulusnetworks.com
|
||||
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
|
||||
#
|
||||
#
|
||||
from socket import NETLINK_ROUTE, AF_INET, AF_INET6
|
||||
from string import printable
|
||||
from ipaddr import *
|
||||
from ctypes import *
|
||||
from netlink import *
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
#
|
||||
# from /usr/include/linux/rtnetlink.h
|
||||
#
|
||||
|
||||
RTMGRP_LINK = 0x1
|
||||
RTMGRP_IPV4_IFADDR = 0x10
|
||||
RTMGRP_IPV4_ROUTE = 0x40
|
||||
RTMGRP_IPV6_IFADDR = 0x100
|
||||
RTMGRP_IPV6_ROUTE = 0x400
|
||||
|
||||
RTM_NEWLINK = 16
|
||||
RTM_DELLINK = 17
|
||||
RTM_GETLINK = 18
|
||||
RTM_NEWADDR = 20
|
||||
RTM_DELADDR = 21
|
||||
RTM_GETADDR = 22
|
||||
RTM_NEWROUTE = 24
|
||||
RTM_DELROUTE = 25
|
||||
RTM_GETROUTE = 26
|
||||
|
||||
# Definitions used in routing table administration.
|
||||
|
||||
class Nlmsg(Structure):
|
||||
|
||||
def _stringify(self):
|
||||
return string_at(addressof(self), sizeof(self))
|
||||
|
||||
def __eq__(self, other):
|
||||
return self._stringify() == other._stringify() and \
|
||||
self.__dict__ == other.__dict__
|
||||
|
||||
def to_rta(self):
|
||||
return Rtattr.from_address(addressof(self) + NLMSG_ALIGN(sizeof(self)))
|
||||
|
||||
def pack_extra(self, extra, addr):
|
||||
memmove(addr, addressof(extra), sizeof(extra))
|
||||
return NLMSG_ALIGN(sizeof(extra))
|
||||
|
||||
def pack_rtas(self, rtas, addr):
|
||||
total_len = 0
|
||||
for rta_type, value in rtas.iteritems():
|
||||
rta = Rtattr.from_address(addr)
|
||||
rta.rta_type = rta_type
|
||||
pack_fn = self.rta_fn(rta_type)
|
||||
rta_len = NLMSG_ALIGN(pack_fn(rta, value))
|
||||
total_len += rta_len
|
||||
addr += rta_len
|
||||
return total_len
|
||||
|
||||
def pack_rtas_new(self, rtas, addr, policy):
|
||||
total_len = 0
|
||||
|
||||
for rta_type, value in rtas.iteritems():
|
||||
if type(value) == dict:
|
||||
rta = Rtattr.from_address(addr)
|
||||
rta.rta_type = rta_type
|
||||
rta.rta_len = RTA_LENGTH(0)
|
||||
rta_len = NLMSG_ALIGN(rta.rta_len)
|
||||
total_len += rta_len
|
||||
addr += rta_len
|
||||
pack_fn = policy.get(rta_type)
|
||||
rta_len = NLMSG_ALIGN(pack_fn(addr, value))
|
||||
|
||||
rta.rta_len += rta_len
|
||||
else:
|
||||
rta = Rtattr.from_address(addr)
|
||||
rta.rta_type = rta_type
|
||||
pack_fn = policy.get(rta_type)
|
||||
rta_len = NLMSG_ALIGN(pack_fn(rta, value))
|
||||
total_len += rta_len
|
||||
addr += rta_len
|
||||
return total_len
|
||||
|
||||
def rta_linkinfo(self, addr, rtas):
|
||||
total_len = 0
|
||||
|
||||
# Start nested linkinfo
|
||||
#rta = Rtattr.from_address(addr)
|
||||
#rta.rta_type = IFLA_LINKINFO
|
||||
#rta.rta_len = RTA_LENGTH(0)
|
||||
#rta_len = NLMSG_ALIGN(rta.rta_len)
|
||||
#total_len += rta_len
|
||||
#addr += rta_len
|
||||
#nest_start_linkinfo = rta
|
||||
|
||||
# Check interface kind
|
||||
kind = rtas.get(IFLA_INFO_KIND)
|
||||
if kind == 'vlan':
|
||||
data_policy = self.rta_linkinfo_data_vlan_policy()
|
||||
else:
|
||||
data_policy = self.rta_linkinfo_data_macvlan_policy()
|
||||
|
||||
# Pack info kind
|
||||
rta = Rtattr.from_address(addr)
|
||||
rta.rta_type = IFLA_INFO_KIND
|
||||
rta_len = NLMSG_ALIGN(self.rta_string(rta, kind))
|
||||
total_len += rta_len
|
||||
addr += rta_len
|
||||
|
||||
# nest start link info data
|
||||
rta = Rtattr.from_address(addr)
|
||||
rta.rta_type = IFLA_INFO_DATA
|
||||
rta.rta_len = RTA_LENGTH(0)
|
||||
rta_len = NLMSG_ALIGN(rta.rta_len)
|
||||
total_len += rta_len
|
||||
addr += rta_len
|
||||
rta_len = self.pack_rtas_new(rtas.get(IFLA_INFO_DATA), addr,
|
||||
data_policy)
|
||||
rta.rta_len += rta_len
|
||||
|
||||
total_len += rta_len
|
||||
addr += rta_len
|
||||
|
||||
return total_len
|
||||
|
||||
def rta_linkinfo_data_vlan(self, addr, rtas):
|
||||
return self.pack_rtas_new(rtas, addr, self.rta_linkinfo_data_vlan_policy())
|
||||
|
||||
def rta_linkinfo_data(self, addr, rtas):
|
||||
return self.pack_rtas_new(rtas, addr, self.rta_linkinfo_data_vlan_policy())
|
||||
|
||||
def unpack_rtas(self, which_ones=[]):
|
||||
len = self.nlh.nlmsg_len - NLMSG_LENGTH(sizeof(self))
|
||||
rta = self.to_rta()
|
||||
rtas = {}
|
||||
while RTA_OK(rta, len):
|
||||
rta_type = rta.rta_type
|
||||
if not which_ones or rta_type in which_ones:
|
||||
unpack_fn = self.rta_fn(rta_type)
|
||||
rtas[rta_type] = unpack_fn(rta)
|
||||
len, rta = RTA_NEXT(rta, len)
|
||||
return rtas
|
||||
|
||||
def dump_rtas(self):
|
||||
rtas = self.unpack_rtas()
|
||||
for type, value in rtas.iteritems():
|
||||
print "rta", type, ":", value
|
||||
|
||||
class _IPv6Addr(BigEndianStructure):
|
||||
_fields_ = [
|
||||
('upper', c_uint64),
|
||||
('lower', c_uint64),
|
||||
]
|
||||
|
||||
class _IPv4Addr(BigEndianStructure):
|
||||
_fields_ = [
|
||||
('addr', c_uint32),
|
||||
]
|
||||
|
||||
def rta_uint8(self, rta, value=None):
|
||||
data = RTA_DATA(rta)
|
||||
if value:
|
||||
c_uint8.from_address(data).value = value
|
||||
rta.rta_len = RTA_LENGTH(sizeof(c_uint8))
|
||||
return rta.rta_len
|
||||
else:
|
||||
return c_uint8.from_address(data).value
|
||||
|
||||
def rta_uint16(self, rta, value=None):
|
||||
data = RTA_DATA(rta)
|
||||
if value:
|
||||
c_uint16.from_address(data).value = value
|
||||
rta.rta_len = RTA_LENGTH(sizeof(c_uint16))
|
||||
return rta.rta_len
|
||||
else:
|
||||
return c_uint16.from_address(data).value
|
||||
|
||||
def rta_uint32(self, rta, value=None):
|
||||
data = RTA_DATA(rta)
|
||||
if value:
|
||||
c_uint32.from_address(data).value = value
|
||||
rta.rta_len = RTA_LENGTH(sizeof(c_uint32))
|
||||
return rta.rta_len
|
||||
else:
|
||||
return c_uint32.from_address(data).value
|
||||
|
||||
def rta_string(self, rta, value=None):
|
||||
data = RTA_DATA(rta)
|
||||
if value:
|
||||
s = create_string_buffer(value)
|
||||
memmove(data, addressof(s), len(value))
|
||||
rta.rta_len = RTA_LENGTH(len(value))
|
||||
return rta.rta_len
|
||||
else:
|
||||
return c_char_p(data).value
|
||||
|
||||
def rta_addr(self, rta, value=None):
|
||||
data = RTA_DATA(rta)
|
||||
if value:
|
||||
if isinstance(value, IPv4Address):
|
||||
self._IPv4Addr.from_address(data).addr = value._ip
|
||||
rta.rta_len = RTA_LENGTH(sizeof(self._IPv4Addr))
|
||||
elif isinstance(value, IPv6Address):
|
||||
addr = self._IPv6Addr.from_address(data)
|
||||
addr.upper = value._ip >> 64
|
||||
addr.lower = value._ip & 0xffffffffffffffff
|
||||
rta.rta_len = RTA_LENGTH(sizeof(self._IPv6Addr))
|
||||
else:
|
||||
assert(False)
|
||||
return rta.rta_len
|
||||
else:
|
||||
if RTA_PAYLOAD(rta) == 4:
|
||||
addr = c_uint32.__ctype_be__.from_address(data).value
|
||||
addr = IPv4Address(addr)
|
||||
else:
|
||||
addr = self._IPv6Addr.from_address(data)
|
||||
addr = IPv6Address((addr.upper << 64) + addr.lower)
|
||||
return addr
|
||||
|
||||
def rta_uint8_array(self, rta, value=None):
|
||||
if value:
|
||||
assert(False)
|
||||
else:
|
||||
data = RTA_DATA(rta)
|
||||
array = (c_uint8 * RTA_PAYLOAD(rta))()
|
||||
memmove(array, data, RTA_PAYLOAD(rta))
|
||||
return array
|
||||
|
||||
def rta_uint32_array(self, rta, value=None):
|
||||
if value:
|
||||
assert(False)
|
||||
else:
|
||||
data = RTA_DATA(rta)
|
||||
size = RTA_PAYLOAD(rta) / sizeof(c_uint32)
|
||||
array = (c_uint32 * size)()
|
||||
memmove(array, data, RTA_PAYLOAD(rta))
|
||||
return array
|
||||
|
||||
def rta_multipath(self, rta, value=None):
|
||||
# XXX implement this
|
||||
return None
|
||||
|
||||
def rta_wtf(self, rta, value=None):
|
||||
return None
|
||||
|
||||
def rta_none(self, rta, value=None):
|
||||
return None
|
||||
|
||||
def rta_fn(self, rta_type):
|
||||
return None
|
||||
|
||||
|
||||
# rtm_type
|
||||
|
||||
RTN_UNSPEC = 0
|
||||
RTN_UNICAST = 1 # Gateway or direct route
|
||||
RTN_LOCAL = 2 # Accept locally
|
||||
RTN_BROADCAST = 3 # Accept locally as broadcast,
|
||||
# send as broadcast
|
||||
RTN_ANYCAST = 4 # Accept locally as broadcast,
|
||||
# but send as unicast
|
||||
RTN_MULTICAST = 5 # Multicast route
|
||||
RTN_BLACKHOLE = 6 # Drop
|
||||
RTN_UNREACHABLE = 7 # Destination is unreachable
|
||||
RTN_PROHIBIT = 8 # Administratively prohibited
|
||||
RTN_THROW = 9 # Not in this table
|
||||
RTN_NAT = 10 # Translate this address
|
||||
RTN_XRESOLVE = 11 # Use external resolver
|
||||
RTN_MAX = 11
|
||||
|
||||
# rtm_protocol
|
||||
|
||||
RTPROT_UNSPEC = 0
|
||||
RTPROT_REDIRECT = 1 # Route installed by ICMP redirects;
|
||||
# not used by current IPv4
|
||||
RTPROT_KERNEL = 2 # Route installed by kernel
|
||||
RTPROT_BOOT = 3 # Route installed during boot
|
||||
RTPROT_STATIC = 4 # Route installed by administrator
|
||||
|
||||
# Values of protocol >= RTPROT_STATIC are not interpreted by kernel;
|
||||
# they are just passed from user and back as is.
|
||||
# It will be used by hypothetical multiple routing daemons.
|
||||
# Note that protocol values should be standardized in order to
|
||||
# avoid conflicts.
|
||||
|
||||
RTPROT_GATED = 8 # Apparently, GateD
|
||||
RTPROT_RA = 9 # RDISC/ND router advertisements
|
||||
RTPROT_MRT = 10 # Merit MRT
|
||||
RTPROT_ZEBRA = 11 # Zebra
|
||||
RTPROT_BIRD = 12 # BIRD
|
||||
RTPROT_DNROUTED = 13 # DECnet routing daemon
|
||||
RTPROT_XORP = 14 # XORP
|
||||
RTPROT_NTK = 15 # Netsukuku
|
||||
RTPROT_DHCP = 16 # DHCP client
|
||||
|
||||
# rtm_scope
|
||||
|
||||
# Really it is not scope, but sort of distance to the destination.
|
||||
# NOWHERE are reserved for not existing destinations, HOST is our
|
||||
# local addresses, LINK are destinations, located on directly attached
|
||||
# link and UNIVERSE is everywhere in the Universe.
|
||||
|
||||
# Intermediate values are also possible f.e. interior routes
|
||||
# could be assigned a value between UNIVERSE and LINK.
|
||||
|
||||
RT_SCOPE_UNIVERSE = 0
|
||||
# User defined values
|
||||
RT_SCOPE_SITE = 200
|
||||
RT_SCOPE_LINK = 253
|
||||
RT_SCOPE_HOST = 254
|
||||
RT_SCOPE_NOWHERE=255
|
||||
|
||||
# rtm_flags
|
||||
|
||||
RTM_F_NOTIFY = 0x100 # Notify user of route change
|
||||
RTM_F_CLONED = 0x200 # This route is cloned
|
||||
RTM_F_EQUALIZE = 0x400 # Multipath equalizer: NI
|
||||
RTM_F_PREFIX = 0x800 # Prefix addresses
|
||||
|
||||
# Reserved table identifiers
|
||||
|
||||
RT_TABLE_UNSPEC = 0
|
||||
# User defined values
|
||||
RT_TABLE_COMPAT = 252
|
||||
RT_TABLE_DEFAULT = 253
|
||||
RT_TABLE_MAIN = 254
|
||||
RT_TABLE_LOCAL = 255
|
||||
RT_TABLE_MAX = 0xFFFFFFFF
|
||||
|
||||
# Generic structure for encapsulation of optional route information.
|
||||
# It is reminiscent of sockaddr, but with sa_family replaced
|
||||
# with attribute type.
|
||||
|
||||
class Rtattr(Structure):
|
||||
|
||||
_fields_ = [
|
||||
('rta_len', c_uint16),
|
||||
('rta_type', c_uint16),
|
||||
]
|
||||
|
||||
# Routing message attributes
|
||||
|
||||
RTA_UNSPEC = 0
|
||||
RTA_DST = 1
|
||||
RTA_SRC = 2
|
||||
RTA_IIF = 3
|
||||
RTA_OIF = 4
|
||||
RTA_GATEWAY = 5
|
||||
RTA_PRIORITY = 6
|
||||
RTA_PREFSRC = 7
|
||||
RTA_METRICS = 8
|
||||
RTA_MULTIPATH = 9
|
||||
RTA_PROTOINFO = 10 # no longer used
|
||||
RTA_FLOW = 11
|
||||
RTA_CACHEINFO = 12
|
||||
RTA_SESSION = 13 # no longer used
|
||||
RTA_MP_ALGO = 14 # no longer used
|
||||
RTA_TABLE = 15
|
||||
RTA_MAX = 15
|
||||
|
||||
# Macros to handle rtattributes
|
||||
|
||||
RTA_ALIGNTO = 4
|
||||
def RTA_ALIGN(len):
|
||||
return (len + RTA_ALIGNTO - 1) & ~(RTA_ALIGNTO - 1)
|
||||
def RTA_OK(rta, len):
|
||||
return len >= sizeof(Rtattr) and \
|
||||
rta.rta_len >= sizeof(Rtattr) and \
|
||||
rta.rta_len <= len
|
||||
def RTA_NEXT(rta, len):
|
||||
cur = RTA_ALIGN(rta.rta_len)
|
||||
rta = Rtattr.from_address(addressof(rta) + cur)
|
||||
return len - cur, rta
|
||||
def RTA_LENGTH(len):
|
||||
return len + RTA_ALIGN(sizeof(Rtattr))
|
||||
def RTA_SPACE(len):
|
||||
return RTA_ALIGN(RTA_LENGTH(len))
|
||||
def RTA_DATA(rta):
|
||||
return addressof(rta) + RTA_LENGTH(0)
|
||||
def RTA_PAYLOAD(rta):
|
||||
return rta.rta_len - RTA_LENGTH(0)
|
||||
|
||||
RTNH_F_DEAD = 1 # Nexthop is dead (used by multipath)
|
||||
RTNH_F_PERVASIVE = 2 # Do recursive gateway lookup
|
||||
RTNH_F_ONLINK = 4 # Gateway is forced on link
|
||||
|
||||
# Reserved table identifiers
|
||||
|
||||
RT_TABLE_UNSPEC = 0
|
||||
# User defined values
|
||||
RT_TABLE_COMPAT = 252
|
||||
RT_TABLE_DEFAULT = 253
|
||||
RT_TABLE_MAIN = 254
|
||||
RT_TABLE_LOCAL = 255
|
||||
RT_TABLE_MAX = 0xFFFFFFFF
|
||||
|
||||
class Rtmsg(Nlmsg):
|
||||
|
||||
_fields_ = [
|
||||
('rtm_family', c_uint8),
|
||||
('rtm_dst_len', c_uint8),
|
||||
('rtm_src_len', c_uint8),
|
||||
('rtm_tos', c_uint8),
|
||||
('rtm_table', c_uint8),
|
||||
('rtm_protocol', c_uint8),
|
||||
('rtm_scope', c_uint8),
|
||||
('rtm_type', c_uint8),
|
||||
('rtm_flags', c_uint32),
|
||||
]
|
||||
|
||||
_table_str = {
|
||||
RT_TABLE_UNSPEC: "unspecified",
|
||||
RT_TABLE_COMPAT: "compat",
|
||||
RT_TABLE_DEFAULT: "default",
|
||||
RT_TABLE_MAIN: "main",
|
||||
RT_TABLE_LOCAL: "local",
|
||||
}
|
||||
|
||||
_proto_str = {
|
||||
RTPROT_UNSPEC: "none",
|
||||
RTPROT_REDIRECT: "redirect",
|
||||
RTPROT_KERNEL: "kernel",
|
||||
RTPROT_BOOT: "boot",
|
||||
RTPROT_STATIC: "static",
|
||||
RTPROT_GATED: "gated",
|
||||
RTPROT_RA: "ra",
|
||||
RTPROT_MRT: "mrtmrt",
|
||||
RTPROT_ZEBRA: "zebra",
|
||||
RTPROT_BIRD: "bird",
|
||||
RTPROT_DNROUTED: "dnrouted",
|
||||
RTPROT_XORP: "xorp",
|
||||
RTPROT_NTK: "ntk",
|
||||
RTPROT_DHCP: "dhcp",
|
||||
}
|
||||
|
||||
_scope_str = {
|
||||
RT_SCOPE_UNIVERSE: "universe",
|
||||
RT_SCOPE_SITE: "site",
|
||||
RT_SCOPE_LINK: "link",
|
||||
RT_SCOPE_HOST: "host",
|
||||
RT_SCOPE_NOWHERE: "nowhere",
|
||||
}
|
||||
|
||||
_type_str = {
|
||||
RTN_UNSPEC: "unspecified",
|
||||
RTN_UNICAST: "unicast",
|
||||
RTN_LOCAL: "local",
|
||||
RTN_BROADCAST: "broadcast",
|
||||
RTN_ANYCAST: "anycast",
|
||||
RTN_MULTICAST: "multicast",
|
||||
RTN_BLACKHOLE: "blackhole",
|
||||
RTN_UNREACHABLE: "unreachable",
|
||||
RTN_PROHIBIT: "prohibit",
|
||||
RTN_THROW: "throw",
|
||||
RTN_NAT: "nat",
|
||||
RTN_XRESOLVE: "xresolve",
|
||||
}
|
||||
|
||||
def dump(self):
|
||||
print 'rtm_family', self.rtm_family
|
||||
print 'rtm_dst_len', self.rtm_dst_len
|
||||
print 'rtm_src_len', self.rtm_src_len
|
||||
print 'rtm_tos', self.rtm_tos
|
||||
print 'rtm_table', self._table_str.get(self.rtm_table, self.rtm_table)
|
||||
print 'rtm_protocol', self._proto_str.get(self.rtm_protocol)
|
||||
print 'rtm_scope', self._scope_str.get(self.rtm_scope)
|
||||
print 'rtm_type', self._type_str.get(self.rtm_type)
|
||||
print 'rtm_flags 0x%08x' % self.rtm_flags
|
||||
|
||||
def rta_fn(self, rta_type):
|
||||
fns = {
|
||||
RTA_DST: self.rta_addr,
|
||||
RTA_SRC: self.rta_addr,
|
||||
RTA_IIF: self.rta_uint32,
|
||||
RTA_OIF: self.rta_uint32,
|
||||
RTA_GATEWAY: self.rta_addr,
|
||||
RTA_PRIORITY: self.rta_uint32,
|
||||
RTA_PREFSRC: self.rta_addr,
|
||||
RTA_METRICS: self.rta_uint32_array,
|
||||
RTA_MULTIPATH: self.rta_multipath,
|
||||
RTA_PROTOINFO: self.rta_none,
|
||||
RTA_FLOW: self.rta_uint32,
|
||||
RTA_CACHEINFO: self.rta_none,
|
||||
RTA_SESSION: self.rta_none,
|
||||
RTA_MP_ALGO: self.rta_none,
|
||||
RTA_TABLE: self.rta_uint32,
|
||||
}
|
||||
|
||||
return fns.get(rta_type)
|
||||
|
||||
class Rtgenmsg(Nlmsg):
|
||||
|
||||
_fields_ = [
|
||||
('rtgen_family', c_uint8),
|
||||
]
|
||||
|
||||
def dump(self):
|
||||
print 'rtgen_family', self.rtgen_family
|
||||
|
||||
# New extended info filters for IFLA_EXT_MASK
|
||||
RTEXT_FILTER_VF = (1 << 0)
|
||||
|
||||
# passes link level specific information, not dependent
|
||||
# on network protocol.
|
||||
|
||||
IFLA_UNSPEC = 0
|
||||
IFLA_ADDRESS = 1
|
||||
IFLA_BROADCAST = 2
|
||||
IFLA_IFNAME = 3
|
||||
IFLA_MTU = 4
|
||||
IFLA_LINK = 5
|
||||
IFLA_QDISC = 6
|
||||
IFLA_STATS = 7
|
||||
IFLA_COST = 8
|
||||
IFLA_PRIORITY = 9
|
||||
IFLA_MASTER = 10
|
||||
IFLA_WIRELESS = 11 # Wireless Extension event - see wireless.h
|
||||
IFLA_PROTINFO = 12 # Protocol specific information for a link
|
||||
IFLA_TXQLEN = 13
|
||||
IFLA_MAP = 14
|
||||
IFLA_WEIGHT = 15
|
||||
IFLA_OPERSTATE = 16
|
||||
IFLA_LINKMODE = 17
|
||||
IFLA_LINKINFO = 18
|
||||
IFLA_NET_NS_PID = 19
|
||||
IFLA_IFALIAS = 20
|
||||
IFLA_NUM_VF = 21 # Number of VFs if device is SR-IOV PF
|
||||
IFLA_VFINFO_LIST = 22
|
||||
IFLA_STATS64 = 23
|
||||
IFLA_VF_PORTS = 24
|
||||
IFLA_PORT_SELF = 25
|
||||
IFLA_AF_SPEC = 26
|
||||
IFLA_GROUP = 27 # Group the device belongs to
|
||||
IFLA_NET_NS_FD = 28
|
||||
IFLA_EXT_MASK = 29 # Extended info mask, VFs, etc
|
||||
IFLA_MAX = 29
|
||||
|
||||
|
||||
# IFLA_LINKINFO attributes
|
||||
IFLA_INFO_UNSPEC = 0
|
||||
IFLA_INFO_KIND = 1
|
||||
IFLA_INFO_DATA = 2
|
||||
IFLA_INFO_XSTATS = 3
|
||||
IFLA_INFO_MAX = 4
|
||||
|
||||
# IFLA_LINKINFO_DATA attributes for vlan
|
||||
IFLA_VLAN_UNSPEC = 0
|
||||
IFLA_VLAN_ID = 1
|
||||
|
||||
# IFLA_LINKINFO_DATA attributes for macvlan
|
||||
IFLA_MACVLAN_UNSPEC = 0
|
||||
IFLA_MACVLAN_MODE = 1
|
||||
|
||||
# macvlan modes
|
||||
MACVLAN_MODE_PRIVATE = 1
|
||||
MACVLAN_MODE_VEPA = 2
|
||||
MACVLAN_MODE_BRIDGE = 3
|
||||
MACVLAN_MODE_PASSTHRU = 4
|
||||
|
||||
class Ifinfomsg(Nlmsg):
|
||||
|
||||
_fields_ = [
|
||||
('ifi_family', c_uint8),
|
||||
('__ifi_pad', c_uint8),
|
||||
('ifi_type', c_uint16), # ARPHRD_*
|
||||
('ifi_index', c_int32), # Link index
|
||||
('ifi_flags', c_uint32), # IFF_* flags
|
||||
('ifi_change', c_uint32), # IFF_* change mask
|
||||
]
|
||||
|
||||
def dump(self):
|
||||
print 'ifi_family', self.ifi_family
|
||||
print 'ifi_type', self.ifi_type
|
||||
print 'ifi_index', self.ifi_index
|
||||
print 'ifi_flags 0x%08x' % self.ifi_flags
|
||||
print 'ifi_change 0x%08x' % self.ifi_change
|
||||
|
||||
def rta_linkinfo_data_vlan_policy(self):
|
||||
fns = {
|
||||
IFLA_VLAN_ID : self.rta_uint16,
|
||||
}
|
||||
return fns
|
||||
|
||||
def rta_linkinfo_data_macvlan_policy(self):
|
||||
fns = {
|
||||
IFLA_MACVLAN_MODE : self.rta_uint32,
|
||||
}
|
||||
return fns
|
||||
|
||||
def rta_linkinfo_policy(self):
|
||||
fns = {
|
||||
IFLA_INFO_KIND : self.rta_string,
|
||||
IFLA_INFO_DATA : self.rta_linkinfo_data,
|
||||
}
|
||||
return fns
|
||||
|
||||
def rta_policy(self):
|
||||
fns = {
|
||||
IFLA_UNSPEC: self.rta_wtf,
|
||||
IFLA_ADDRESS: self.rta_uint8_array,
|
||||
IFLA_BROADCAST: self.rta_uint8_array,
|
||||
IFLA_IFNAME: self.rta_string,
|
||||
IFLA_MTU: self.rta_uint32,
|
||||
IFLA_LINK: self.rta_uint32,
|
||||
IFLA_QDISC: self.rta_string,
|
||||
IFLA_STATS: self.rta_none,
|
||||
IFLA_COST: self.rta_none,
|
||||
IFLA_PRIORITY: self.rta_none,
|
||||
IFLA_MASTER: self.rta_uint32,
|
||||
IFLA_WIRELESS: self.rta_none,
|
||||
IFLA_PROTINFO: self.rta_none,
|
||||
IFLA_TXQLEN: self.rta_uint32,
|
||||
IFLA_MAP: self.rta_none,
|
||||
IFLA_WEIGHT: self.rta_uint32,
|
||||
IFLA_OPERSTATE: self.rta_uint8,
|
||||
IFLA_LINKMODE: self.rta_uint8,
|
||||
IFLA_LINKINFO: self.rta_linkinfo,
|
||||
IFLA_NET_NS_PID: self.rta_uint32,
|
||||
IFLA_IFALIAS: self.rta_string,
|
||||
IFLA_NUM_VF: self.rta_uint32,
|
||||
IFLA_VFINFO_LIST: self.rta_none,
|
||||
IFLA_STATS64: self.rta_none,
|
||||
IFLA_VF_PORTS: self.rta_none,
|
||||
IFLA_PORT_SELF: self.rta_none,
|
||||
IFLA_AF_SPEC: self.rta_none,
|
||||
IFLA_GROUP: self.rta_none,
|
||||
IFLA_NET_NS_FD: self.rta_none,
|
||||
IFLA_EXT_MASK: self.rta_none,
|
||||
}
|
||||
return fns;
|
||||
|
||||
def rta_fn(self, rta_type):
|
||||
fns = {
|
||||
IFLA_UNSPEC: self.rta_wtf,
|
||||
IFLA_ADDRESS: self.rta_uint8_array,
|
||||
IFLA_BROADCAST: self.rta_uint8_array,
|
||||
IFLA_IFNAME: self.rta_string,
|
||||
IFLA_MTU: self.rta_uint32,
|
||||
IFLA_LINK: self.rta_uint32,
|
||||
IFLA_QDISC: self.rta_string,
|
||||
IFLA_STATS: self.rta_none,
|
||||
IFLA_COST: self.rta_none,
|
||||
IFLA_PRIORITY: self.rta_none,
|
||||
IFLA_MASTER: self.rta_uint32,
|
||||
IFLA_WIRELESS: self.rta_none,
|
||||
IFLA_PROTINFO: self.rta_none,
|
||||
IFLA_TXQLEN: self.rta_uint32,
|
||||
IFLA_MAP: self.rta_none,
|
||||
IFLA_WEIGHT: self.rta_uint32,
|
||||
IFLA_OPERSTATE: self.rta_uint8,
|
||||
IFLA_LINKMODE: self.rta_uint8,
|
||||
IFLA_LINKINFO: self.rta_linkinfo,
|
||||
IFLA_NET_NS_PID: self.rta_uint32,
|
||||
IFLA_IFALIAS: self.rta_string,
|
||||
IFLA_NUM_VF: self.rta_uint32,
|
||||
IFLA_VFINFO_LIST: self.rta_none,
|
||||
IFLA_STATS64: self.rta_none,
|
||||
IFLA_VF_PORTS: self.rta_none,
|
||||
IFLA_PORT_SELF: self.rta_none,
|
||||
IFLA_AF_SPEC: self.rta_none,
|
||||
IFLA_GROUP: self.rta_none,
|
||||
IFLA_NET_NS_FD: self.rta_none,
|
||||
IFLA_EXT_MASK: self.rta_none,
|
||||
}
|
||||
return fns.get(rta_type)
|
||||
|
||||
# passes address specific information
|
||||
|
||||
# Important comment:
|
||||
# IFA_ADDRESS is prefix address, rather than local interface address.
|
||||
# It makes no difference for normally configured broadcast interfaces,
|
||||
# but for point-to-point IFA_ADDRESS is DESTINATION address,
|
||||
# local address is supplied in IFA_LOCAL attribute.
|
||||
|
||||
IFA_UNSPEC = 0
|
||||
IFA_ADDRESS = 1
|
||||
IFA_LOCAL = 2
|
||||
IFA_LABEL = 3
|
||||
IFA_BROADCAST = 4
|
||||
IFA_ANYCAST = 5
|
||||
IFA_CACHEINFO = 6
|
||||
IFA_MULTICAST = 7
|
||||
IFA_MAX = 7
|
||||
|
||||
class Ifaddrmsg(Nlmsg):
|
||||
|
||||
_fields_ = [
|
||||
('ifa_family', c_uint8),
|
||||
('ifa_prefixlen', c_uint8), # The prefix length
|
||||
('ifa_flags', c_uint8), # Flags
|
||||
('ifa_scope', c_uint8), # Address scope
|
||||
('ifa_index', c_uint32), # Link index
|
||||
]
|
||||
|
||||
_family_str = {
|
||||
AF_INET: "inet",
|
||||
AF_INET6: "inet6",
|
||||
}
|
||||
|
||||
def dump(self):
|
||||
print 'ifa_family', self.ifa_family
|
||||
print 'ifa_prefixlen', self.ifa_prefixlen
|
||||
print 'ifa_flags 0x%02x' % self.ifa_flags
|
||||
print 'ifa_scope', self.ifa_scope
|
||||
print 'ifa_index', self.ifa_index
|
||||
|
||||
def rta_fn(self, rta_type):
|
||||
fns = {
|
||||
IFA_ADDRESS: self.rta_addr,
|
||||
IFA_LOCAL: self.rta_addr,
|
||||
IFA_LABEL: self.rta_string,
|
||||
IFA_BROADCAST: self.rta_addr,
|
||||
IFA_ANYCAST: self.rta_addr,
|
||||
IFA_CACHEINFO: self.rta_none,
|
||||
IFA_MULTICAST: self.rta_addr,
|
||||
}
|
||||
return fns.get(rta_type)
|
||||
|
||||
class RtNetlinkError(Exception):
|
||||
|
||||
def __init__(self, message):
|
||||
Exception.__init__(self, message)
|
||||
logger.error(message)
|
||||
|
||||
class RtNetlink(Netlink):
|
||||
|
||||
def __init__(self, pid):
|
||||
Netlink.__init__(self, pid, NETLINK_ROUTE)
|
||||
|
||||
_rt_nlmsg_type_str = {
|
||||
RTM_NEWROUTE: "RTM_NEWROUTE",
|
||||
RTM_DELROUTE: "RTM_DELROUTE",
|
||||
RTM_NEWLINK: "RTM_NEWLINK",
|
||||
RTM_DELLINK: "RTM_DELLINK",
|
||||
RTM_GETLINK: "RTM_GETLINK",
|
||||
RTM_NEWADDR: "RTM_NEWADDR",
|
||||
RTM_DELADDR: "RTM_DELADDR",
|
||||
}
|
||||
|
||||
def _hexdump(self, buf):
|
||||
while buf:
|
||||
chunk = buf[:16]
|
||||
buf = buf[16:]
|
||||
nums = ["%02x" % c for c in chunk]
|
||||
txt = [chr(c) if chr(c) in printable[:-5] else '.' for c in chunk]
|
||||
print " ".join(nums).ljust(48), "".join(txt)
|
||||
|
||||
def dump(self, nlh):
|
||||
nlmsg = self.nlmsg(nlh)
|
||||
print
|
||||
self._hexdump(self.sendbuf[:nlh.nlmsg_len])
|
||||
print
|
||||
nlh.dump()
|
||||
print
|
||||
nlmsg.dump()
|
||||
print
|
||||
nlmsg.dump_rtas()
|
||||
|
||||
def nlmsg(self, nlh):
|
||||
nlmsg_struct = {
|
||||
RTM_NEWROUTE: Rtmsg,
|
||||
RTM_DELROUTE: Rtmsg,
|
||||
RTM_GETROUTE: Rtmsg,
|
||||
RTM_NEWLINK: Ifinfomsg,
|
||||
RTM_DELLINK: Ifinfomsg,
|
||||
RTM_GETLINK: Rtgenmsg,
|
||||
RTM_NEWADDR: Ifaddrmsg,
|
||||
RTM_DELADDR: Ifaddrmsg,
|
||||
RTM_GETADDR: Rtgenmsg,
|
||||
}
|
||||
nldata = NLMSG_DATA(nlh)
|
||||
nlmsg = nlmsg_struct[nlh.nlmsg_type].from_address(nldata)
|
||||
nlmsg.nlh = nlh
|
||||
return nlmsg
|
||||
|
||||
def _nl_cb(self, nlh):
|
||||
# print "nl cb", self._rt_nlmsg_type_str[nlh.nlmsg_type]
|
||||
|
||||
if nlh.nlmsg_type in self._cbs:
|
||||
|
||||
nlmsg = self.nlmsg(nlh)
|
||||
|
||||
# validate nl length
|
||||
if nlh.nlmsg_len - NLMSG_LENGTH(sizeof(nlmsg)) < 0:
|
||||
raise RtNetlinkError("invalid nl length")
|
||||
|
||||
self._cbs[nlh.nlmsg_type](nlh, nlmsg)
|
||||
|
||||
def bind(self, groups, cbs):
|
||||
self._cbs = cbs
|
||||
Netlink.bind(self, groups, self._nl_cb)
|
||||
|
||||
def request(self, nlmsg_type, flags, extra, rtas={}):
|
||||
|
||||
nlh = Nlmsghdr.from_buffer(self.sendbuf)
|
||||
nlh_p = addressof(nlh)
|
||||
|
||||
seq = self.seq
|
||||
pid = self.pid
|
||||
|
||||
nlh.nlmsg_len = NLMSG_HDRLEN()
|
||||
nlh.nlmsg_type = nlmsg_type
|
||||
nlh.nlmsg_flags = flags
|
||||
nlh.nlmsg_pid = pid
|
||||
nlh.nlmsg_seq = seq
|
||||
|
||||
nlmsg = self.nlmsg(nlh)
|
||||
|
||||
nlh.nlmsg_len += nlmsg.pack_extra(extra, nlh_p + nlh.nlmsg_len)
|
||||
nlh.nlmsg_len += nlmsg.pack_rtas_new(rtas, nlh_p + nlh.nlmsg_len, nlmsg.rta_policy())
|
||||
|
||||
#self.dump(nlh)
|
||||
self.sendall(string_at(nlh_p, nlh.nlmsg_len))
|
||||
self.seq += 1
|
||||
|
||||
token = (pid, seq)
|
||||
return token
|
||||
|
||||
def rta_linkinfo_policy(self):
|
||||
fns = {
|
||||
[IFLA_INFO_KIND] : self.rta_string,
|
||||
[IFLA_INFO_DATA] : self.rta_linkinfo_data,
|
||||
}
|
||||
return fns
|
||||
|
||||
def rta_policy(self):
|
||||
fns = {
|
||||
IFLA_UNSPEC: self.rta_wtf,
|
||||
IFLA_ADDRESS: self.rta_uint8_array,
|
||||
IFLA_BROADCAST: self.rta_uint8_array,
|
||||
IFLA_IFNAME: self.rta_string,
|
||||
IFLA_MTU: self.rta_uint32,
|
||||
IFLA_LINK: self.rta_uint32,
|
||||
IFLA_QDISC: self.rta_string,
|
||||
IFLA_STATS: self.rta_none,
|
||||
IFLA_COST: self.rta_none,
|
||||
IFLA_PRIORITY: self.rta_none,
|
||||
IFLA_MASTER: self.rta_uint32,
|
||||
IFLA_WIRELESS: self.rta_none,
|
||||
IFLA_PROTINFO: self.rta_none,
|
||||
IFLA_TXQLEN: self.rta_uint32,
|
||||
IFLA_MAP: self.rta_none,
|
||||
IFLA_WEIGHT: self.rta_uint32,
|
||||
IFLA_OPERSTATE: self.rta_uint8,
|
||||
IFLA_LINKMODE: self.rta_uint8,
|
||||
IFLA_LINKINFO: self.rta_linkinfo,
|
||||
IFLA_NET_NS_PID: self.rta_uint32,
|
||||
IFLA_IFALIAS: self.rta_string,
|
||||
IFLA_NUM_VF: self.rta_uint32,
|
||||
IFLA_VFINFO_LIST: self.rta_none,
|
||||
IFLA_STATS64: self.rta_none,
|
||||
IFLA_VF_PORTS: self.rta_none,
|
||||
IFLA_PORT_SELF: self.rta_none,
|
||||
IFLA_AF_SPEC: self.rta_none,
|
||||
IFLA_GROUP: self.rta_none,
|
||||
IFLA_NET_NS_FD: self.rta_none,
|
||||
IFLA_EXT_MASK: self.rta_none,
|
||||
}
|
||||
return fns;
|
101
ifupdown/rtnetlink_api.py
Normal file
101
ifupdown/rtnetlink_api.py
Normal file
@@ -0,0 +1,101 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
|
||||
#
|
||||
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
|
||||
#
|
||||
#
|
||||
|
||||
from os import getpid
|
||||
from socket import AF_UNSPEC
|
||||
from iff import IFF_UP
|
||||
from rtnetlink import *
|
||||
import os
|
||||
|
||||
class rtnetlinkApi(RtNetlink):
|
||||
|
||||
bind_done = False
|
||||
|
||||
def __init__(self, pid):
|
||||
RtNetlink.__init__(self, pid)
|
||||
self.logger = logging.getLogger('ifupdown.' +
|
||||
self.__class__.__name__)
|
||||
self.bind(0, None)
|
||||
self.bind_done = True
|
||||
self.ifindexmap = {}
|
||||
|
||||
def do_bind(self):
|
||||
if self.bind_done:
|
||||
return True
|
||||
self.bind(0, None)
|
||||
self.bind_done = True
|
||||
|
||||
def get_ifindex(self, ifname):
|
||||
ifindex = self.ifindexmap.get(ifname)
|
||||
if not ifindex:
|
||||
with open('/sys/class/net/%s/ifindex' %ifname, 'r') as f:
|
||||
ifindex = int(f.read())
|
||||
self.ifindexmap[ifname] = ifindex
|
||||
return ifindex
|
||||
|
||||
def create_vlan(self, link, ifname, vlanid):
|
||||
|
||||
try:
|
||||
ifindex = self.get_ifindex(link)
|
||||
except Exception, e:
|
||||
raise Exception('cannot determine ifindex for link %s (%s)' %(link, str(e)))
|
||||
|
||||
self.logger.info('rtnetlink: creating vlan %s' %ifname)
|
||||
ifm = Ifinfomsg(AF_UNSPEC)
|
||||
rtas = {IFLA_IFNAME: ifname,
|
||||
IFLA_LINK : ifindex,
|
||||
IFLA_LINKINFO : {
|
||||
IFLA_INFO_KIND : 'vlan',
|
||||
IFLA_INFO_DATA : {
|
||||
IFLA_VLAN_ID : vlanid,
|
||||
}
|
||||
}
|
||||
}
|
||||
token = self.request(RTM_NEWLINK, NLM_F_CREATE | NLM_F_REQUEST | NLM_F_ACK, ifm, rtas)
|
||||
self.process_wait([token])
|
||||
|
||||
def create_macvlan(self, ifname, link, mode='private'):
|
||||
|
||||
try:
|
||||
ifindex = self.get_ifindex(link)
|
||||
except Exception, e:
|
||||
raise Exception('cannot determine ifindex for link %s (%s)' %(link, str(e)))
|
||||
|
||||
self.logger.info('rtnetlink: creating macvlan %s' %ifname)
|
||||
|
||||
ifm = Ifinfomsg(AF_UNSPEC)
|
||||
rtas = {IFLA_IFNAME: ifname,
|
||||
IFLA_LINK : ifindex,
|
||||
IFLA_LINKINFO : {
|
||||
IFLA_INFO_KIND : 'macvlan',
|
||||
IFLA_INFO_DATA : {
|
||||
IFLA_MACVLAN_MODE : MACVLAN_MODE_PRIVATE,
|
||||
}
|
||||
}
|
||||
}
|
||||
token = self.request(RTM_NEWLINK, NLM_F_CREATE | NLM_F_REQUEST | NLM_F_ACK,
|
||||
ifm, rtas)
|
||||
self.process_wait([token])
|
||||
|
||||
def link_set(self, ifname, state):
|
||||
flags = 0
|
||||
|
||||
self.logger.info('rtnetlink: setting link %s %s' %(ifname, state))
|
||||
|
||||
if state == "up":
|
||||
flags |= IFF_UP
|
||||
else:
|
||||
flags &= ~IFF_UP
|
||||
|
||||
ifm = Ifinfomsg(AF_UNSPEC, ifi_change=IFF_UP, ifi_flags=flags)
|
||||
rtas = {IFLA_IFNAME: ifname}
|
||||
|
||||
token = self.request(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_ACK, ifm, rtas)
|
||||
self.process_wait([token])
|
||||
|
||||
rtnl_api = rtnetlinkApi(os.getpid())
|
@@ -386,7 +386,6 @@ class ifaceScheduler():
|
||||
# if -a is set, we dont really have to sort. We pick the interfaces
|
||||
# that have no parents and
|
||||
if not skip_ifacesort:
|
||||
ifupdownobj.logger.info(indegrees)
|
||||
sorted_ifacenames = cls.get_sorted_iface_list(ifupdownobj,
|
||||
ifacenames, ops, dependency_graph,
|
||||
indegrees)
|
||||
@@ -409,7 +408,6 @@ class ifaceScheduler():
|
||||
run_queue.reverse()
|
||||
|
||||
# run interface list
|
||||
ifupdownobj.logger.info('running interfaces: %s' %str(run_queue))
|
||||
cls.run_iface_list(ifupdownobj, run_queue, ops,
|
||||
parent=None, order=order,
|
||||
followdependents=followdependents)
|
||||
|
Reference in New Issue
Block a user