downloads/
eggs/
.eggs/
-lib/
+/lib/
lib64/
parts/
sdist/
-ifupdown2 (1.2.9-1) unstable; urgency=medium
-
- *
-
- -- Julien Fortin <julien@cumulusnetworks.com> Thu, 11 Jul 2019 23:42:42 +0200
+ifupdown2 (2.0.0-1) unstable; urgency=medium
+
+ * Introduction of the live netlink cache
+ * Refactoring and PEP8 fixes
+ * Install systemd ifupdown2.netowrking.service and ifup.service
+ * Addons: bond: bond-primary attributes (closes: #9)
+ * Addons: address-virtual: vrrp support
+ * Addons: address: add arp-accept option
+ * Addons: tunnel: adding "tunnel-" prefix to every attributes
+ * Loopback interface won't go down (unless link-down yes)
+ * Macvlans (address-virtual) can now be configured without ips
+ * Add support for vxlan multicast group (vxlan-mcastgrp)
+ * New sets of poliicies:
+ - bridge polcy for vxlan port: bridge-vxlan-arp-nd-suppres (ON/off)
+ - bridge policy for vxlan port: bridge_vxlan_port_learning (ON/off)
+ - bridge policy for vxlan port:
+ vxlan_bridge_igmp_snooping_enable_port_mcrouter (1/0)
+
+ -- Julien Fortin <julien@cumulusnetworks.com> Tue, 01 Oct 2019 23:42:42 +0200
ifupdown2 (1.2.8-1) unstable; urgency=medium
Section: admin
Priority: optional
Maintainer: Julien Fortin <julien@cumulusnetworks.com>
-Build-Depends: debhelper (>= 9.20160709),
+Build-Depends: debhelper (>=9),
+ dh-systemd,
dh-python,
python-all,
python-setuptools,
python-docutils
Standards-Version: 4.2.1
Homepage: https://github.com/cumulusnetworks/ifupdown2
+X-Python-Version: >= 2.7
Package: ifupdown2
Architecture: all
Conflicts: ifupdown
Replaces: ifupdown
Depends: ${python:Depends}, ${misc:Depends}, iproute2, python-argcomplete, python-ipaddr
-Suggests: isc-dhcp-client, bridge-utils, ethtool, python-gvgen, python-mako, python-pkg-resources
+Suggests: isc-dhcp-client, bridge-utils, ethtool, python-gvgen, python-mako
Description: Network Interface Management tool similar to ifupdown
ifupdown2 is ifupdown re-written in Python. It replaces ifupdown and provides
the same user interface as ifupdown for network interface configuration.
--- /dev/null
+[Unit]
+Description=ifup for %I
+After=local-fs.target network-pre.target networking.service systemd-sysctl.service
+Before=network.target shutdown.target network-online.target
+Conflicts=shutdown.target
+BindsTo=sys-subsystem-net-devices-%i.device
+After=sys-subsystem-net-devices-%i.device
+DefaultDependencies=no
+IgnoreOnIsolate=yes
+
+[Service]
+# avoid stopping on shutdown via stopping system-ifup.slice
+Slice=system.slice
+ExecStart=/sbin/ifup --allow=hotplug %I
+ExecStop=/sbin/ifdown %I
+RemainAfterExit=true
+TimeoutStartSec=2min
-etc/default/networking /etc/default/
etc/network/ifupdown2/addons.conf /etc/network/ifupdown2/
etc/network/ifupdown2/ifupdown2.conf /etc/network/ifupdown2/
[Unit]
-Description=ifupdown2 networking initialization
+Description=Network initialization
Documentation=man:interfaces(5) man:ifup(8) man:ifdown(8)
DefaultDependencies=no
Before=shutdown.target
RemainAfterExit=yes
SyslogIdentifier=networking
TimeoutStopSec=30s
-ExecStart=/usr/share/ifupdown2/sbin/start-networking start
-ExecStop=/usr/share/ifupdown2/sbin/start-networking stop
-ExecReload=/usr/share/ifupdown2/sbin/start-networking reload
+ExecStart=/sbin/ifup -a
+ExecStop=/sbin/ifdown -a
+ExecReload=/sbin/ifreload -a
[Install]
WantedBy=basic.target network.target shutdown.target
+++ /dev/null
-#!/bin/bash
-### BEGIN INIT INFO
-# Provides: networking ifupdown
-# Required-Start: mountkernfs $local_fs urandom
-# Required-Stop: $local_fs
-# Default-Start: S
-# Default-Stop: 0 6
-# Short-Description: Raise network interfaces.
-# Description: Prepare /run/network directory, ifstate file and raise network interfaces, or take them down.
-### END INIT INFO
-
-RUN_DIR="/run/network"
-IFSTATE_LOCKFILE="${RUN_DIR}/ifstatelock"
-
-STATE_DIR="/var/tmp/network"
-IFSTATE_FILE="${STATE_DIR}/ifstatenew"
-
-NAME=networking
-SCRIPTNAME=/etc/init.d/$NAME
-
-[ -x /sbin/ifup ] || exit 0
-[ -x /sbin/ifdown ] || exit 0
-
-. /lib/lsb/init-functions
-
-CONFIGURE_INTERFACES=yes
-
-EXTRA_ARGS=
-
-[ -f /etc/default/networking ] && . /etc/default/networking
-
-[ "$VERBOSE" = yes ] && EXTRA_ARGS=-v
-[ "$DEBUG" = yes ] && EXTRA_ARGS="$EXTRA_ARGS -d"
-[ "$SYSLOG" = yes ] && EXTRA_ARGS="$EXTRA_ARGS --syslog"
-
-gen_examples() {
- # Generate sample interfaces file. The interfaces files are
- # generated under /usr/share/doc/ifupdown2/examples/
- #
-
- # generate files only at boot
- [ -f ${IFSTATE_LOCKFILE} ] && return
-
- python_ifupdown2_docdir="/usr/share/doc/ifupdown2"
- swpfile=${python_ifupdown2_docdir}"/examples/swp_defaults"
- bridgedefaultfile=${python_ifupdown2_docdir}"/examples/bridge_untagged_default"
- interfaces_gen_script=${python_ifupdown2_docdir}"/examples/generate_interfaces.py"
-
- [ ! -e $interfaces_gen_script ] && return
- ret=$($interfaces_gen_script -s 2>&1 >$swpfile)
- ret=$($interfaces_gen_script -b 2>&1 >$bridgedefaultfile)
- return
-}
-
-perf_options() {
- # At bootup lets set perfmode
- [ -f ${IFSTATE_LOCKFILE} ] && echo -n "" && return
-
- echo -n "--perfmode"
-}
-
-process_exclusions() {
- set -- $EXCLUDE_INTERFACES
- exclusions=""
- for d
- do
- exclusions="-X $d $exclusions"
- done
- echo $exclusions
-}
-
-check_network_file_systems() {
- [ -e /proc/mounts ] || return 0
-
- if [ -e /etc/iscsi/iscsi.initramfs ]; then
- log_warning_msg "not deconfiguring network interfaces: iSCSI root is mounted."
- exit 0
- fi
-
- while read DEV MTPT FSTYPE REST; do
- case $DEV in
- /dev/nbd*|/dev/nd[a-z]*|/dev/etherd/e*)
- log_warning_msg "not deconfiguring network interfaces: network devices still mounted."
- exit 0
- ;;
- esac
- case $FSTYPE in
- nfs|nfs4|smbfs|ncp|ncpfs|cifs|coda|ocfs2|gfs|pvfs|pvfs2|fuse.httpfs|fuse.curlftpfs)
- log_warning_msg "not deconfiguring network interfaces: network file systems still mounted."
- exit 0
- ;;
- esac
- done < /proc/mounts
-}
-
-check_network_swap() {
- [ -e /proc/swaps ] || return 0
-
- while read DEV MTPT FSTYPE REST; do
- case $DEV in
- /dev/nbd*|/dev/nd[a-z]*|/dev/etherd/e*)
- log_warning_msg "not deconfiguring network interfaces: network swap still mounted."
- exit 0
- ;;
- esac
- done < /proc/swaps
-}
-
-ifup_hotplug () {
- if [ -d /sys/class/net ]
- then
- ifaces=$(for iface in $(ifquery --list --allow=hotplug 2>/dev/null)
- do
- link=${iface##:*}
- link=${link##.*}
- if [ -e "/sys/class/net/$link" ] && [ "$(cat /sys/class/net/$link/operstate)" = up ]
- then
- echo "$iface"
- fi
- done)
- if [ -n "$ifaces" ]
- then
- ifup $ifaces "$@" || true
- fi
- fi
-}
-
-ifupdown_init() {
- # remove state file at boot
- [ ! -e ${IFSTATE_LOCKFILE} ] && rm -f ${IFSTATE_FILE}
- [ ! -e /run/network ] && mkdir -p /run/network &>/dev/null
- [ ! -e /etc/network/run ] && \
- ln -sf /run/network /etc/network/run &>/dev/null
-}
-
-case "$1" in
-start)
- gen_examples
- ifupdown_init
- if [ "$CONFIGURE_INTERFACES" = no ]
- then
- log_action_msg "Not configuring network interfaces, see /etc/default/networking"
- exit 0
- fi
- set -f
- exclusions=$(process_exclusions)
- perfoptions=$(perf_options)
- log_action_begin_msg "Configuring network interfaces"
- ifup -a $EXTRA_ARGS $exclusions $perfoptions
- log_action_end_msg $?
- ;;
-
-stop)
- if [ "$SKIP_DOWN_AT_SYSRESET" = "yes" ]; then
- shutdown_or_reboot=$(runlevel 2>/dev/null | \
- /usr/bin/tr -s " " | \
- /usr/bin/cut -d " " \
- -f1- --output-delimiter=$'\n' | \
- /bin/grep -e "0" -e "6")
- if [ -n "$shutdown_or_reboot" ]; then
- log_action_begin_msg "Deconfiguring network interfaces..skip"
- log_action_end_msg 0
- exit 0
- fi
- fi
- ifupdown_init
- check_network_file_systems
- check_network_swap
- exclusions=$(process_exclusions)
-
- log_action_begin_msg "Deconfiguring network interfaces"
- ifdown -a $EXTRA_ARGS $exclusions
- log_action_end_msg $?
- ;;
-
-reload)
-
- ifupdown_init
- log_action_begin_msg "Reloading network interfaces configuration"
-
- ifreload -a $EXTRA_ARGS
- log_action_end_msg $?
- ;;
-
-reload-currently-up)
-
- ifupdown_init
- log_action_begin_msg "Reloading currently up network interfaces configuration"
-
- ifreload --currently-up $EXTRA_ARGS
- log_action_end_msg $?
- ;;
-
-force-reload)
-
- ifupdown_init
-
- log_action_begin_msg "Reloading network interfaces configuration"
- ifreload -f -a $EXTRA_ARGS
- log_action_end_msg $?
- ;;
-
-restart)
- ifupdown_init
-
- set -f
- exclusions=$(process_exclusions)
- log_action_begin_msg "Reconfiguring network interfaces"
- ifdown -a $EXTRA_ARGS $exclusions || true
- ifup -a $EXTRA_ARGS $exclusions
- log_action_end_msg $?
- ;;
-
-*)
- echo "Usage: /etc/init.d/networking {start|stop|reload|restart|force-reload}"
- exit 1
- ;;
-esac
-
-exit 0
-
-# vim: noet ts=8
./ifupdown2/man/genmanpages.sh ./ifupdown2/man ./man
dh_installman
+override_dh_install:
+ dh_install
+ mkdir -p debian/ifupdown2/lib/systemd/system/
+ install --mode=644 debian/ifup@.service debian/ifupdown2/lib/systemd/system/
+
+
override_dh_systemd_start:
dh_systemd_start --name=networking --no-start
override_dh_systemd_enable:
dh_systemd_enable --name=networking
-override_dh_installinit:
- dh_installinit --name=networking --no-start
-
override_dh_compress:
dh_compress -X.py
+++ /dev/null
-#
-#
-# Parameters for the /etc/init.d/networking script
-#
-#
-
-# Change the below to yes if you want verbose logging to be enabled
-VERBOSE="no"
-
-# Change the below to yes if you want debug logging to be enabled
-DEBUG="no"
-
-# Change the below to yes if you want logging to go to syslog
-SYSLOG="no"
-
-# Exclude interfaces
-EXCLUDE_INTERFACES=
-
-# Set to 'yes' if you want to skip ifdown during system reboot
-# and shutdown. This is of interest in large scale interface
-# deployments where you dont want to wait for interface
-# deconfiguration to speed up shutdown/reboot
-SKIP_DOWN_AT_SYSRESET="yes"
--- /dev/null
+#!/bin/bash
+### BEGIN INIT INFO
+# Provides: networking ifupdown
+# Required-Start: mountkernfs $local_fs urandom
+# Required-Stop: $local_fs
+# Default-Start: S
+# Default-Stop: 0 6
+# Short-Description: Raise network interfaces.
+# Description: Prepare /run/network directory, ifstate file and raise network interfaces, or take them down.
+### END INIT INFO
+
+RUN_DIR="/run/network"
+IFSTATE_LOCKFILE="${RUN_DIR}/ifstatelock"
+
+STATE_DIR="/var/tmp/network"
+IFSTATE_FILE="${STATE_DIR}/ifstatenew"
+
+NAME=networking
+SCRIPTNAME=/etc/init.d/$NAME
+
+[ -x /sbin/ifup ] || exit 0
+[ -x /sbin/ifdown ] || exit 0
+
+. /lib/lsb/init-functions
+
+CONFIGURE_INTERFACES=yes
+
+EXTRA_ARGS=
+
+[ -f /etc/default/networking ] && . /etc/default/networking
+
+[ "$VERBOSE" = yes ] && EXTRA_ARGS=-v
+[ "$DEBUG" = yes ] && EXTRA_ARGS="$EXTRA_ARGS -d"
+[ "$SYSLOG" = yes ] && EXTRA_ARGS="$EXTRA_ARGS --syslog"
+
+gen_examples() {
+ # Generate sample interfaces file. The interfaces files are
+ # generated under /usr/share/doc/ifupdown2/examples/
+ #
+
+ # generate files only at boot
+ [ -f ${IFSTATE_LOCKFILE} ] && return
+
+ python_ifupdown2_docdir="/usr/share/doc/ifupdown2"
+ swpfile=${python_ifupdown2_docdir}"/examples/swp_defaults"
+ bridgedefaultfile=${python_ifupdown2_docdir}"/examples/bridge_untagged_default"
+ interfaces_gen_script=${python_ifupdown2_docdir}"/examples/generate_interfaces.py"
+
+ [ ! -e $interfaces_gen_script ] && return
+ ret=$($interfaces_gen_script -s 2>&1 >$swpfile)
+ ret=$($interfaces_gen_script -b 2>&1 >$bridgedefaultfile)
+ return
+}
+
+perf_options() {
+ # At bootup lets set perfmode
+ [ -f ${IFSTATE_LOCKFILE} ] && echo -n "" && return
+
+ echo -n "--perfmode"
+}
+
+process_exclusions() {
+ set -- $EXCLUDE_INTERFACES
+ exclusions=""
+ for d
+ do
+ exclusions="-X $d $exclusions"
+ done
+ echo $exclusions
+}
+
+check_network_file_systems() {
+ [ -e /proc/mounts ] || return 0
+
+ if [ -e /etc/iscsi/iscsi.initramfs ]; then
+ log_warning_msg "not deconfiguring network interfaces: iSCSI root is mounted."
+ exit 0
+ fi
+
+ while read DEV MTPT FSTYPE REST; do
+ case $DEV in
+ /dev/nbd*|/dev/nd[a-z]*|/dev/etherd/e*)
+ log_warning_msg "not deconfiguring network interfaces: network devices still mounted."
+ exit 0
+ ;;
+ esac
+ case $FSTYPE in
+ nfs|nfs4|smbfs|ncp|ncpfs|cifs|coda|ocfs2|gfs|pvfs|pvfs2|fuse.httpfs|fuse.curlftpfs)
+ log_warning_msg "not deconfiguring network interfaces: network file systems still mounted."
+ exit 0
+ ;;
+ esac
+ done < /proc/mounts
+}
+
+check_network_swap() {
+ [ -e /proc/swaps ] || return 0
+
+ while read DEV MTPT FSTYPE REST; do
+ case $DEV in
+ /dev/nbd*|/dev/nd[a-z]*|/dev/etherd/e*)
+ log_warning_msg "not deconfiguring network interfaces: network swap still mounted."
+ exit 0
+ ;;
+ esac
+ done < /proc/swaps
+}
+
+ifup_hotplug () {
+ if [ -d /sys/class/net ]
+ then
+ ifaces=$(for iface in $(ifquery --list --allow=hotplug 2>/dev/null)
+ do
+ link=${iface##:*}
+ link=${link##.*}
+ if [ -e "/sys/class/net/$link" ] && [ "$(cat /sys/class/net/$link/operstate)" = up ]
+ then
+ echo "$iface"
+ fi
+ done)
+ if [ -n "$ifaces" ]
+ then
+ ifup $ifaces "$@" || true
+ fi
+ fi
+}
+
+ifupdown_init() {
+ # remove state file at boot
+ [ ! -e ${IFSTATE_LOCKFILE} ] && rm -f ${IFSTATE_FILE}
+ [ ! -e /run/network ] && mkdir -p /run/network &>/dev/null
+ [ ! -e /etc/network/run ] && \
+ ln -sf /run/network /etc/network/run &>/dev/null
+}
+
+case "$1" in
+start)
+ gen_examples
+ ifupdown_init
+ if [ "$CONFIGURE_INTERFACES" = no ]
+ then
+ log_action_msg "Not configuring network interfaces, see /etc/default/networking"
+ exit 0
+ fi
+ set -f
+ exclusions=$(process_exclusions)
+ perfoptions=$(perf_options)
+ log_action_begin_msg "Configuring network interfaces"
+ ifup -a $EXTRA_ARGS $exclusions $perfoptions
+ log_action_end_msg $?
+ ;;
+
+stop)
+ if [ "$SKIP_DOWN_AT_SYSRESET" = "yes" ]; then
+ shutdown_or_reboot=$(runlevel 2>/dev/null | \
+ /usr/bin/tr -s " " | \
+ /usr/bin/cut -d " " \
+ -f1- --output-delimiter=$'\n' | \
+ /bin/grep -e "0" -e "6")
+ if [ -n "$shutdown_or_reboot" ]; then
+ log_action_begin_msg "Deconfiguring network interfaces..skip"
+ log_action_end_msg 0
+ exit 0
+ fi
+ fi
+ ifupdown_init
+ check_network_file_systems
+ check_network_swap
+ exclusions=$(process_exclusions)
+
+ log_action_begin_msg "Deconfiguring network interfaces"
+ ifdown -a $EXTRA_ARGS $exclusions
+ log_action_end_msg $?
+ ;;
+
+reload)
+
+ ifupdown_init
+ log_action_begin_msg "Reloading network interfaces configuration"
+
+ ifreload -a $EXTRA_ARGS
+ log_action_end_msg $?
+ ;;
+
+reload-currently-up)
+
+ ifupdown_init
+ log_action_begin_msg "Reloading currently up network interfaces configuration"
+
+ ifreload --currently-up $EXTRA_ARGS
+ log_action_end_msg $?
+ ;;
+
+force-reload)
+
+ ifupdown_init
+
+ log_action_begin_msg "Reloading network interfaces configuration"
+ ifreload -f -a $EXTRA_ARGS
+ log_action_end_msg $?
+ ;;
+
+restart)
+ ifupdown_init
+
+ set -f
+ exclusions=$(process_exclusions)
+ log_action_begin_msg "Reconfiguring network interfaces"
+ ifdown -a $EXTRA_ARGS $exclusions || true
+ ifup -a $EXTRA_ARGS $exclusions
+ log_action_end_msg $?
+ ;;
+
+*)
+ echo "Usage: /etc/init.d/networking {start|stop|reload|restart|force-reload}"
+ exit 1
+ ;;
+esac
+
+exit 0
+
+# vim: noet ts=8
pre-up,mstpctl
pre-up,tunnel
pre-up,vrf
+pre-up,tunnel
pre-up,ethtool
+pre-up,address
up,dhcp
up,address
up,addressvirtual
post-down,usercmds
post-down,link
post-down,tunnel
-post-down,xfrm
\ No newline at end of file
+post-down,xfrm
# This file contains default settings for ifupdown
#
+# use ifupdown2d
+use_daemon=no
+
# enable templates
template_enable=1
# directory where the state file is stored
# if this directory doesn't exists ifupdown2 will create it
# if directory creation fails or state_dir variable is empty
-# state_dir will default to /run/network/
-state_dir=/run/network/
+# state_dir will default to /var/tmp/network/
+state_dir=/var/tmp/network/
#!/usr/bin/env python
# -*- coding: utf-8 -*-
-__version__ = '1.2.9'
+__version__ = '2.0.0'
-# Copyright (C) 2014,2015,2016,2017,2018,219 Cumulus Networks, Inc. All rights reserved
+# Copyright (C) 2014,2015,2016,2017,2018,2019 Cumulus Networks, Inc. All rights reserved
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
#!/usr/bin/python
+# Copyright (C) 2016, 2017, 2018, 2019 Cumulus Networks, Inc. all rights reserved
#
-# Copyright 2016 Cumulus Networks, Inc. All rights reserved.
-# Author: Julien Fortin, julien@cumulusnetworks.com
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; version 2.
#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# https://www.gnu.org/licenses/gpl-2.0-standalone.html
+#
+# Author:
+# Julien Fortin, julien@cumulusnetworks.com
+#
+# ifupdown2 - Network Manager
#
import os
-import re
import sys
-import json
-import errno
-import struct
-import select
-import socket
-import signal
try:
- import ifupdown2.ifupdown.config as core_config
- from ifupdown2.ifupdown.log import log
+ from ifupdown2.lib.log import LogManager, root_logger
+ from ifupdown2.lib.status import Status
+except:
+ from lib.log import LogManager, root_logger
+ from lib.status import Status
+
+# first thing first, setup the logging infra
+LogManager.get_instance()
+
+try:
+ import ifupdown2.ifupdown.config as config
+
from ifupdown2 import __version__
- core_config.__version__ = __version__
-except:
- import ifupdown.config as core_config
- from ifupdown.log import log
+ config.__version__ = __version__
- core_config.__version__ = __import__('__init__').__version__
+ from ifupdown2.lib.exceptions import ExitWithStatus, ExitWithStatusAndError
+ from ifupdown2.ifupdown.client import Client
+ from ifupdown2.ifupdown.exceptions import ArgvParseHelp
+except:
+ import ifupdown.config as config
-class Ifupdown2Complete(Exception):
- def __init__(self, status):
- self.status = status
+ config.__version__ = __import__("__init__").__version__
+ from lib.exceptions import ExitWithStatus, ExitWithStatusAndError
-class Ifupdown2Client:
- def __init__(self, argv):
+ from ifupdown.client import Client
+ from ifupdown.exceptions import ArgvParseHelp
- self.stdin = None
- self.argv = argv
- self.data = ''
- self.HEADER_SIZE = 4
- self.daemon_pid = -1
- self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
- try:
- self.socket.connect('/var/run/ifupdown2d/uds')
-
- signal.signal(signal.SIGINT, self.signal_handler)
- signal.signal(signal.SIGTERM, self.signal_handler)
- signal.signal(signal.SIGQUIT, self.signal_handler)
-
- try:
- self.SO_PEERCRED = socket.SO_PEERCRED
- except AttributeError:
- # powerpc is the only non-generic we care about. alpha, mips,
- # sparc, and parisc also have non-generic values.
- machine = os.uname()[4]
- if re.search(r'^(ppc|powerpc)', machine):
- self.SO_PASSCRED = 20
- self.SO_PEERCRED = 21
- else:
- self.SO_PASSCRED = 16
- self.SO_PEERCRED = 17
- try:
- self.socket.setsockopt(socket.SOL_SOCKET, self.SO_PASSCRED, 1)
- except Exception as e:
- raise Exception('setsockopt: %s' % str(e))
-
- except socket.error:
- self.socket.close()
- self.socket = None
- sys.stderr.write("""
- ERROR: %s could not connect to ifupdown2d
-
- Try starting ifupdown2d with:
- sudo systemctl start ifupdown2d
-
- To configure ifupdown2d to start when the box boots:
- sudo systemctl enable ifupdown2d
- """ % argv[0])
-
- def __del__(self):
- if self.socket:
- self.socket.close()
-
- def signal_handler(self, sig, frame):
- if self.daemon_pid > 0:
- os.kill(self.daemon_pid, sig)
-
- def read_data(self):
- ready = select.select([self.socket], [], [])
- if ready and ready[0] and ready[0][0] == self.socket:
- d = self.socket.recv(65536)
- if self.data:
- self.data += d
- else:
- self.data = d
- return True
+def daemon_mode():
+ """ Check ifupdown2 config to see if we should start the client """
+ try:
+ with open(config.IFUPDOWN2_CONF_PATH) as f:
+ return "use_daemon=yes" in f.read()
+ except:
return False
- def get_packets(self):
- """
- ifupdown2 output is divided into "json packets"
- the first 4 bytes is the size of the next json
- object to etract
-
- """
- data_size = len(self.data)
- if not data_size:
- raise Ifupdown2Complete(status=1)
- packets = []
- try:
- while data_size > 0:
- packet_len = struct.unpack('=I', self.data[:self.HEADER_SIZE])[0]
- packet_data = self.data[self.HEADER_SIZE:packet_len + self.HEADER_SIZE]
-
- fmt = "=%ds" % packet_len
-
- packets.append(json.loads(struct.unpack(fmt, packet_data)[0]))
-
- self.data = self.data[self.HEADER_SIZE + packet_len:]
- data_size -= self.HEADER_SIZE + packet_len
- except:
- pass
- return packets
-
- def process_packets(self, packets):
- for packet in packets:
- if 'pid' in packet:
- self.daemon_pid = packet['pid']
- if 'stdout' in packet:
- sys.stdout.write(packet['stdout'])
- if 'stderr' in packet:
- sys.stderr.write(packet['stderr'])
- if 'status' in packet:
- raise Ifupdown2Complete(packet['status'])
-
- def run(self):
- status = 1
- if self.socket:
- for arg in ['-i', '--interfaces']:
- try:
- if self.argv[self.argv.index(arg) + 1] == '-':
- self.stdin = sys.stdin.read()
- continue
- except (ValueError, IndexError):
- pass
-
- self.socket.send(json.dumps({
- 'argv': self.argv,
- 'stdin': self.stdin
- }))
-
- try:
- while True:
- try:
- self.read_data()
- self.process_packets(self.get_packets())
- except Ifupdown2Complete as e:
- status = e.status
- break
- except Exception as e:
- if ((isinstance(e.args, tuple) and e[0] == 4)
- or (hasattr(e, 'errno') and e.errno == errno.EINTR)):
- pass
- else:
- raise
- except Exception as e:
- sys.stderr.write(str(e))
- finally:
- self.socket.close()
- return status if status != None else 1
-
-
-def ifupdown2_standalone():
+def client():
+ try:
+ status = Client(sys.argv).run()
+ except ExitWithStatusAndError as e:
+ root_logger.error(e.message)
+ status = e.status
+ except ExitWithStatus as e:
+ status = e.status
+ return status
+
+
+def stand_alone():
+ if not sys.argv[0].endswith("query") and os.geteuid() != 0:
+ sys.stderr.write('must be root to run this command\n')
+ return 1
try:
- import ifupdown2.ifupdown.main as main_ifupdown2
+ from ifupdown2.ifupdown.main import Ifupdown2
+ from ifupdown2.lib.nlcache import NetlinkListenerWithCache, NetlinkListenerWithCacheErrorNotInitialized
except:
- import ifupdown.main as main_ifupdown2
- ifupdown2 = main_ifupdown2.Ifupdown2(daemon=False, uid=os.geteuid())
- ifupdown2.parse_argv(sys.argv)
- ifupdown2.update_logger()
- return ifupdown2.main()
+ from ifupdown.main import Ifupdown2
+ from lib.nlcache import NetlinkListenerWithCache, NetlinkListenerWithCacheErrorNotInitialized
+ ifupdown2 = Ifupdown2(daemon=False, uid=os.geteuid())
+ try:
+ ifupdown2.parse_argv(sys.argv)
+ LogManager.get_instance().start_standalone_logging(ifupdown2.args)
+ except ArgvParseHelp:
+ # on --help parse_args raises SystemExit, we catch it and raise a
+ # custom exception ArgvParseHelp to return 0
+ return 0
+ try:
+ status = ifupdown2.main()
+ finally:
+ try:
+ NetlinkListenerWithCache.get_instance().cleanup()
+ except NetlinkListenerWithCacheErrorNotInitialized:
+ status = Status.Client.STATUS_NLERROR
+ return status
def main():
try:
- if 'use_daemon=yes' in open(core_config.IFUPDOWN2_CONF_PATH).read():
- return Ifupdown2Client(sys.argv).run()
+ if daemon_mode():
+ return client()
else:
- return ifupdown2_standalone()
+ return stand_alone()
+ except ArgvParseHelp:
+ return Status.Client.STATUS_SUCCESS
except KeyboardInterrupt:
- return 1
+ return Status.Client.STATUS_KEYBOARD_INTERRUPT
except Exception as e:
- log.error(str(e))
- return 1
+ root_logger.exception("main: %s" % str(e))
+ return Status.Client.STATUS_EXCEPTION_MAIN
if __name__ == '__main__':
try:
sys.exit(main())
except KeyboardInterrupt:
- sys.exit(1)
+ sys.exit(Status.Client.STATUS_KEYBOARD_INTERRUPT)
import socket
-from ipaddr import IPNetwork, IPv4Network, IPv6Network, _BaseV6
+from ipaddr import IPNetwork, IPv4Network, IPv6Network
try:
+ from ifupdown2.lib.addon import Addon
+ from ifupdown2.nlmanager.nlmanager import Link
+
from ifupdown2.ifupdown.iface import *
from ifupdown2.ifupdown.utils import utils
- from ifupdown2.ifupdown.netlink import netlink
from ifupdown2.ifupdownaddons.dhclient import dhclient
- from ifupdown2.ifupdownaddons.LinkUtils import LinkUtils
from ifupdown2.ifupdownaddons.modulebase import moduleBase
import ifupdown2.ifupdown.statemanager as statemanager
import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
import ifupdown2.ifupdown.ifupdownconfig as ifupdownconfig
except ImportError:
+ from lib.addon import Addon
+ from nlmanager.nlmanager import Link
+
from ifupdown.iface import *
from ifupdown.utils import utils
- from ifupdown.netlink import netlink
from ifupdownaddons.dhclient import dhclient
- from ifupdownaddons.LinkUtils import LinkUtils
from ifupdownaddons.modulebase import moduleBase
import ifupdown.statemanager as statemanager
import ifupdown.ifupdownconfig as ifupdownconfig
-class address(moduleBase):
+class address(Addon, moduleBase):
""" ifupdown2 addon module to configure address, mtu, hwaddress, alias
(description) on an interface """
- _modinfo = {'mhelp' : 'address configuration module for interfaces',
- 'attrs': {
- 'address' :
- {'help' : 'ipv4 or ipv6 addresses',
- 'validvals' : ['<ipv4/prefixlen>', '<ipv6/prefixlen>'],
- 'multiline' : True,
- 'example' : ['address 10.0.12.3/24',
- 'address 2000:1000:1000:1000:3::5/128']},
- 'netmask' :
- {'help': 'netmask',
- 'example' : ['netmask 255.255.255.0'],
- 'compat' : True},
- 'broadcast' :
- {'help': 'broadcast address',
- 'validvals' : ['<ipv4>', ],
- 'example' : ['broadcast 10.0.1.255']},
- 'scope' :
- {'help': 'scope',
- 'validvals' : ['universe', 'site', 'link', 'host', 'nowhere'],
- 'example' : ['scope host']},
- 'preferred-lifetime' :
- {'help': 'preferred lifetime',
- 'validrange' : ['0', '65535'],
- 'example' : ['preferred-lifetime forever',
- 'preferred-lifetime 10']},
- 'gateway' :
- {'help': 'default gateway',
- 'validvals' : ['<ipv4>', '<ipv6>'],
- 'multiline' : True,
- 'example' : ['gateway 255.255.255.0']},
- 'mtu' :
- { 'help': 'interface mtu',
- 'validrange' : ['552', '9216'],
- 'example' : ['mtu 1600'],
- 'default' : '1500'},
- 'hwaddress' :
- {'help' : 'hw address',
- 'validvals' : ['<mac>',],
- 'example': ['hwaddress 44:38:39:00:27:b8']},
- 'alias' :
- { 'help': 'description/alias',
- 'example' : ['alias testnetwork']},
- 'address-purge' :
- { 'help': 'purge existing addresses. By default ' +
- 'any existing ip addresses on an interface are ' +
- 'purged to match persistant addresses in the ' +
- 'interfaces file. Set this attribute to \'no\'' +
- 'if you want to preserve existing addresses',
- 'validvals' : ['yes', 'no'],
- 'default' : 'yes',
- 'example' : ['address-purge yes/no']},
- 'clagd-vxlan-anycast-ip' :
- { 'help' : 'Anycast local IP address for ' +
- 'dual connected VxLANs',
- 'validvals' : ['<ipv4>', ],
- 'example' : ['clagd-vxlan-anycast-ip 36.0.0.11']},
- 'arp-accept' :
- { 'help': 'Allow gratuitous arp to update arp table',
- 'validvals': ['on', 'off', 'yes', 'no', '0', '1'],
- 'default' : 'off',
- 'example' : ['arp-accept on']},
- 'ip-forward' :
- { 'help': 'ip forwarding flag',
- 'validvals': ['on', 'off', 'yes', 'no', '0', '1'],
- 'default' : 'off',
- 'example' : ['ip-forward off']},
- 'ip6-forward' :
- { 'help': 'ipv6 forwarding flag',
- 'validvals': ['on', 'off', 'yes', 'no', '0', '1'],
- 'default' : 'off',
- 'example' : ['ip6-forward off']},
- 'mpls-enable' :
- { 'help': 'mpls enable flag',
- 'validvals': ['yes', 'no'],
- 'default' : 'no',
- 'example' : ['mpls-enable yes']},
- 'ipv6-addrgen': {
- 'help': 'enable disable ipv6 link addrgenmode',
- 'validvals': ['on', 'off'],
- 'default': 'on',
- 'example': [
- 'ipv6-addrgen on',
- 'ipv6-addrgen off'
- ]
- }
- }}
+ _modinfo = {
+ 'mhelp': 'address configuration module for interfaces',
+ 'attrs': {
+ 'address': {
+ 'help': 'The address of the interface. The format of the '
+ 'address depends on the protocol. It is a dotted '
+ 'quad for IP and a sequence of hexadecimal halfwords '
+ 'separated by colons for IPv6. The ADDRESS may be '
+ 'followed by a slash and a decimal number which '
+ 'encodes the network prefix length.',
+ 'validvals': ['<ipv4/prefixlen>', '<ipv6/prefixlen>'],
+ 'multiline': True,
+ 'example': [
+ 'address 10.0.12.3/24',
+ 'address 2000:1000:1000:1000:3::5/128'
+ ]
+ },
+ 'netmask': {
+ 'help': 'Address netmask',
+ 'example': ['netmask 255.255.255.0'],
+ 'compat': True
+ },
+ 'broadcast': {
+ 'help': 'The broadcast address on the interface.',
+ 'validvals': ['<ipv4>'],
+ 'example': ['broadcast 10.0.1.255']
+ },
+ 'scope': {
+ 'help': 'The scope of the area where this address is valid. '
+ 'The available scopes are listed in file /etc/iproute2/rt_scopes. '
+ 'Predefined scope values are: '
+ 'global - the address is globally valid. '
+ 'site - (IPv6 only, deprecated) the address is site local, i.e. it is valid inside this site. '
+ 'link - the address is link local, i.e. it is valid only on this device. '
+ 'host - the address is valid only inside this host.',
+ 'validvals': ['universe', 'site', 'link', 'host', 'nowhere'],
+ 'example': ['scope host']
+ },
+ 'preferred-lifetime': {
+ 'help': 'The preferred lifetime of this address; see section '
+ '5.5.4 of RFC 4862. When it expires, the address is '
+ 'no longer used for new outgoing connections. '
+ 'Defaults to forever.',
+ 'validrange': ['0', '65535'],
+ 'example': [
+ 'preferred-lifetime forever',
+ 'preferred-lifetime 10'
+ ]
+ },
+ 'pointopoint': {
+ 'help': 'Set the remote IP address for a point-to-point link',
+ 'validvals': ['<ipv4/prefixlen>', '<ipv6/prefixlen>'],
+ 'example': [
+ 'pointopoint 10.10.10.42/32'
+ ]
+ },
+ 'gateway': {
+ 'help': 'Default gateway',
+ 'validvals': ['<ipv4>', '<ipv6>'],
+ 'multiline': True,
+ 'example': ['gateway 255.255.255.0']
+ },
+ 'mtu': {
+ 'help': 'Interface MTU (maximum transmission unit)',
+ 'validrange': ['552', '9216'],
+ 'example': ['mtu 1600'],
+ 'default': '1500'
+ },
+ 'hwaddress': {
+ 'help': 'Hardware address (mac)',
+ 'validvals': ['<mac>'],
+ 'example': ['hwaddress 44:38:39:00:27:b8']
+ },
+ 'alias': {
+ 'help': 'description/alias: give the device a symbolic name for easy reference.',
+ 'example': ['alias testnetwork']
+ },
+ 'address-purge': {
+ 'help': 'Purge existing addresses. By default any existing '
+ 'ip addresses on an interface are purged to match '
+ 'persistant addresses in the interfaces file. Set '
+ 'this attribute to \'no\' if you want to preserve '
+ 'existing addresses',
+ 'validvals': ['yes', 'no'],
+ 'default': 'yes',
+ 'example': ['address-purge yes/no']
+ },
+ 'clagd-vxlan-anycast-ip': {
+ 'help': 'Anycast local IP address for dual connected VxLANs',
+ 'validvals': ['<ipv4>'],
+ 'example': ['clagd-vxlan-anycast-ip 36.0.0.11']
+ },
+ 'ip-forward': {
+ 'help': 'ip forwarding flag',
+ 'validvals': ['on', 'off', 'yes', 'no', '0', '1'],
+ 'default': 'off',
+ 'example': ['ip-forward off']
+ },
+ 'ip6-forward': {
+ 'help': 'ipv6 forwarding flag',
+ 'validvals': ['on', 'off', 'yes', 'no', '0', '1'],
+ 'default': 'off',
+ 'example': ['ip6-forward off']
+ },
+ 'mpls-enable': {
+ 'help': 'mpls enable flag',
+ 'validvals': ['yes', 'no'],
+ 'default': 'no',
+ 'example': ['mpls-enable yes']
+ },
+ 'ipv6-addrgen': {
+ 'help': 'enable disable ipv6 link addrgenmode',
+ 'validvals': ['on', 'off'],
+ 'default': 'on',
+ 'example': [
+ 'ipv6-addrgen on',
+ 'ipv6-addrgen off'
+ ]
+ },
+ 'arp-accept': {
+ 'help': 'Allow gratuitous arp to update arp table',
+ 'validvals': ['on', 'off', 'yes', 'no', '0', '1'],
+ 'default': 'off',
+ 'example': ['arp-accept on']
+ },
+ }
+ }
+
+ DEFAULT_MTU_STRING = "1500"
def __init__(self, *args, **kargs):
+ Addon.__init__(self)
moduleBase.__init__(self, *args, **kargs)
- self.ipcmd = None
self._bridge_fdb_query_cache = {}
- self.default_mtu = policymanager.policymanager_api.get_attr_default(module_name=self.__class__.__name__, attr='mtu')
- self.max_mtu = policymanager.policymanager_api.get_module_globals(module_name=self.__class__.__name__, attr='max_mtu')
self.ipforward = policymanager.policymanager_api.get_attr_default(module_name=self.__class__.__name__, attr='ip-forward')
self.ip6forward = policymanager.policymanager_api.get_attr_default(module_name=self.__class__.__name__, attr='ip6-forward')
self.ifaces_defaults = policymanager.policymanager_api.get_iface_defaults(module_name=self.__class__.__name__)
)
)
- if not self.default_mtu:
- self.default_mtu = '1500'
-
- self.logger.info('address: using default mtu %s' %self.default_mtu)
+ self.default_mtu = self.__policy_get_default_mtu()
+ self.max_mtu = self.__policy_get_max_mtu()
- if self.max_mtu:
- self.logger.info('address: using max mtu %s' %self.max_mtu)
-
- self.lower_iface_mtu_checked_list = list()
+ self.default_loopback_addresses = (IPNetwork('127.0.0.1/8'), IPNetwork('::1/128'))
self.l3_intf_arp_accept = utils.get_boolean_from_string(
policymanager.policymanager_api.get_module_globals(
default=True
)
+ def __policy_get_default_mtu(self):
+ default_mtu = policymanager.policymanager_api.get_attr_default(
+ module_name=self.__class__.__name__,
+ attr="mtu"
+ )
+
+ if not default_mtu:
+ default_mtu = self.DEFAULT_MTU_STRING
+
+ try:
+ self.default_mtu_int = int(default_mtu)
+ except ValueError as e:
+ self.logger.error("address: invalid default mtu \"%s\" set via policy: %s" % (default_mtu, str(e)))
+ default_mtu = self.DEFAULT_MTU_STRING
+ self.default_mtu_int = int(self.DEFAULT_MTU_STRING)
+
+ self.logger.info("address: using default mtu %s" % default_mtu)
+
+ return default_mtu
+
+ def __policy_get_max_mtu(self):
+ max_mtu = policymanager.policymanager_api.get_module_globals(module_name=self.__class__.__name__, attr="max_mtu")
+ if max_mtu:
+ try:
+ max_mtu_int = int(max_mtu)
+ self.logger.info("address: using max mtu %s" % self.max_mtu)
+ return max_mtu_int
+ except ValueError as e:
+ self.logger.warning("address: policy max_mtu: %s" % str(e))
+ else:
+ self.logger.info("address: max_mtu undefined")
+ return 0
+
def syntax_check(self, ifaceobj, ifaceobj_getfunc=None):
return (self.syntax_check_multiple_gateway(ifaceobj)
and self.syntax_check_addr_allowed_on(ifaceobj, True)
return result
def syntax_check_mtu(self, ifaceobj, ifaceobj_getfunc):
- mtu = ifaceobj.get_attr_value_first('mtu')
- if mtu:
- return self._check_mtu_config(ifaceobj, mtu, ifaceobj_getfunc,
- syntaxcheck=True)
+ mtu_str = ifaceobj.get_attr_value_first('mtu')
+ if mtu_str:
+ try:
+ mtu_int = int(mtu_str)
+ except ValueError as e:
+ self.logger.warning("%s: invalid mtu %s: %s" % (ifaceobj.name, mtu_str, str(e)))
+ return False
+ return self._check_mtu_config(ifaceobj, mtu_str, mtu_int, ifaceobj_getfunc, syntaxcheck=True)
return True
def syntax_check_addr_allowed_on(self, ifaceobj, syntax_check=False):
arp_accept = ifaceobj.get_attr_value_first('arp-accept')
arp_accept = utils.boolean_support_binary(arp_accept)
is_vlan_dev_on_vlan_aware_bridge = False
- is_bridge = self.ipcmd.is_bridge(ifaceobj.name)
+ is_bridge = self.cache.get_link_kind(ifaceobj.name) == 'bridge'
if not is_bridge:
if ifaceobj.link_kind & ifaceLinkKind.VLAN:
bridgename = ifaceobj.lowerifaces[0]
vlan = self._get_vlan_id(ifaceobj)
- is_vlan_dev_on_vlan_aware_bridge = self.ipcmd.bridge_is_vlan_aware(bridgename)
- if ((is_bridge and not self.ipcmd.bridge_is_vlan_aware(ifaceobj.name))
+ is_vlan_dev_on_vlan_aware_bridge = self.cache.bridge_is_vlan_aware(bridgename)
+ if ((is_bridge and not self.cache.bridge_is_vlan_aware(ifaceobj.name))
or is_vlan_dev_on_vlan_aware_bridge):
if self._address_valid(addrs):
if self.l3_intf_arp_accept:
try:
for old_obj in statemanager.statemanager_api.get_ifaceobjs(ifaceobj.name) or []:
old_hwaddress = old_obj.get_attr_value_first("hwaddress")
- if old_hwaddress and self.ipcmd.mac_str_to_int(old_hwaddress) != self.ipcmd.mac_str_to_int(hwaddress):
- self.ipcmd.bridge_fdb_del(bridgename, old_hwaddress, vlan)
+ if old_hwaddress and utils.mac_str_to_int(old_hwaddress) != utils.mac_str_to_int(hwaddress):
+ self.iproute2.bridge_fdb_del(bridgename, old_hwaddress, vlan)
break
except:
pass
- self.ipcmd.bridge_fdb_add(bridgename, hwaddress, vlan)
+ self.iproute2.bridge_fdb_add(bridgename, hwaddress, vlan)
else:
- self.ipcmd.bridge_fdb_del(bridgename, hwaddress, vlan)
+ self.iproute2.bridge_fdb_del(bridgename, hwaddress, vlan)
- def _get_anycast_addr(self, ifaceobjlist):
- for ifaceobj in ifaceobjlist:
- anycast_addr = ifaceobj.get_attr_value_first('clagd-vxlan-anycast-ip')
- if anycast_addr:
- anycast_addr = anycast_addr+'/32'
- return anycast_addr
- return None
+ def __get_ip_addr_with_attributes(self, ifaceobj_list, ifname):
+ user_config_ip_addrs_list = list()
- def _inet_address_convert_to_cidr(self, ifaceobjlist):
- newaddrs = []
- newaddr_attrs = {}
+ try:
+ for ifaceobj in ifaceobj_list:
- for ifaceobj in ifaceobjlist:
- addrs = ifaceobj.get_attr_value('address')
- if not addrs:
- continue
+ user_addrs = ifaceobj.get_attr_value("address")
- if not self.syntax_check_addr_allowed_on(ifaceobj,
- syntax_check=False):
- return (False, newaddrs, newaddr_attrs)
- # If user address is not in CIDR notation, convert them to CIDR
- for addr_index in range(0, len(addrs)):
- addr = addrs[addr_index]
- newaddr = addr
- if '/' in addr:
- newaddrs.append(addr)
- else:
- netmask = ifaceobj.get_attr_value_n('netmask', addr_index)
- if netmask:
- prefixlen = IPNetwork('%s' %addr +
- '/%s' %netmask).prefixlen
- newaddr = addr + '/%s' %prefixlen
+ if not user_addrs:
+ continue
+
+ if not self.syntax_check_addr_allowed_on(ifaceobj, syntax_check=False):
+ return False, None
+
+ for index, addr in enumerate(user_addrs):
+ addr_attributes = {}
+ addr_obj = None
+
+ # convert the ip from string to IPNetwork object
+ if "/" in addr:
+ addr_obj = IPNetwork(addr)
else:
- # we are here because there is no slash (/xx) and no netmask
- # just let IPNetwork handle the ipv4 or ipv6 address mask
- prefixlen = IPNetwork(addr).prefixlen
- newaddr = addr + '/%s' %prefixlen
- newaddrs.append(newaddr)
-
- attrs = {}
- for a in ['broadcast', 'pointopoint', 'scope',
- 'preferred-lifetime']:
- aval = ifaceobj.get_attr_value_n(a, addr_index)
- if aval:
- attrs[a] = aval
-
- if attrs:
- newaddr_attrs[newaddr]= attrs
- return (True, newaddrs, newaddr_attrs)
-
- def _inet_address_list_config(self, ifaceobj, newaddrs, newaddr_attrs):
- for addr_index in range(0, len(newaddrs)):
- try:
- if newaddr_attrs:
- self.ipcmd.addr_add(ifaceobj.name, newaddrs[addr_index],
- newaddr_attrs.get(newaddrs[addr_index],
- {}).get('broadcast'),
- newaddr_attrs.get(newaddrs[addr_index],
- {}).get('pointopoint'),
- newaddr_attrs.get(newaddrs[addr_index],
- {}).get('scope'),
- newaddr_attrs.get(newaddrs[addr_index],
- {}).get('preferred-lifetime'))
+ netmask = ifaceobj.get_attr_value_n("netmask", index)
+
+ if netmask:
+ addr_obj = IPNetwork("%s/%s" % (addr, netmask))
+ else:
+ addr_obj = IPNetwork(addr)
+
+ for attr_name in ("broadcast", "scope", "preferred-lifetime"):
+ attr_value = ifaceobj.get_attr_value_n(attr_name, index)
+ if attr_value:
+ addr_attributes[attr_name] = attr_value
+
+ pointopoint = ifaceobj.get_attr_value_n("pointopoint", index)
+ try:
+ if pointopoint:
+ addr_attributes["pointopoint"] = IPNetwork(pointopoint)
+ except Exception as e:
+ self.logger.warning("%s: pointopoint %s: %s" % (ifaceobj.name, pointopoint, str(e)))
+
+ user_config_ip_addrs_list.append((addr_obj, addr_attributes))
+ except Exception as e:
+ self.logger.warning("%s: convert string ip address into IPNetwork object: %s" % (ifname, str(e)))
+ return False, None
+
+ return True, user_config_ip_addrs_list
+
+ def __add_ip_addresses_with_attributes(self, ifaceobj, ifname, user_config_ip_addrs):
+ try:
+ for ip, attributes in user_config_ip_addrs:
+ if attributes:
+ self.netlink.addr_add(
+ ifname, ip,
+ scope=attributes.get("scope"),
+ peer=attributes.get("pointopoint"),
+ broadcast=attributes.get("broadcast"),
+ preferred_lifetime=attributes.get("preferred-lifetime")
+ )
else:
- self.ipcmd.addr_add(ifaceobj.name, newaddrs[addr_index])
- except Exception, e:
- self.log_error(str(e), ifaceobj)
+ self.netlink.addr_add(ifname, ip)
+ except Exception as e:
+ self.log_error(str(e), ifaceobj)
- def _inet_address_config(self, ifaceobj, ifaceobj_getfunc=None,
- force_reapply=False):
- squash_addr_config = (True if \
- ifupdownconfig.config.get('addr_config_squash', \
- '0') == '1' else False)
+ @staticmethod
+ def __add_loopback_anycast_ip_to_running_ip_addr_list(ifaceobjlist):
+ """
+ if anycast address is configured on 'lo' and is in running
+ config add it to newaddrs so that ifreload doesn't wipe it out
+ :param ifaceobjlist:
+ :param running_ip_addrs:
+ """
+ anycast_ip_addr = None
- if (squash_addr_config and
- not (ifaceobj.flags & ifaceobj.YOUNGEST_SIBLING)):
+ for ifaceobj in ifaceobjlist:
+ anycast_addr = ifaceobj.get_attr_value_first("clagd-vxlan-anycast-ip")
+ if anycast_addr:
+ anycast_ip_addr = IPNetwork(anycast_addr)
+
+ return str(anycast_ip_addr) if anycast_ip_addr else None
+
+ def process_addresses(self, ifaceobj, ifaceobj_getfunc=None, force_reapply=False):
+ squash_addr_config = ifupdownconfig.config.get("addr_config_squash", "0") == "1"
+
+ if squash_addr_config and not ifaceobj.flags & ifaceobj.YOUNGEST_SIBLING:
return
- purge_addresses = ifaceobj.get_attr_value_first('address-purge')
- if not purge_addresses:
- purge_addresses = 'yes'
+ ifname = ifaceobj.name
+ purge_addresses = utils.get_boolean_from_string(ifaceobj.get_attr_value_first("address-purge"), default=True)
+
+ if not squash_addr_config and ifaceobj.flags & iface.HAS_SIBLINGS:
+ # if youngest sibling and squash addr is not set
+ # print a warning that addresses will not be purged
+ if ifaceobj.flags & iface.YOUNGEST_SIBLING:
+ self.logger.warning("%s: interface has multiple iface stanzas, skip purging existing addresses" % ifname)
+ purge_addresses = False
if squash_addr_config and ifaceobj.flags & iface.HAS_SIBLINGS:
- ifaceobjlist = ifaceobj_getfunc(ifaceobj.name)
+ ifaceobj_list = ifaceobj_getfunc(ifname)
else:
- ifaceobjlist = [ifaceobj]
-
- module_name = self.__class__.__name__
- ifname = ifaceobj.name
+ ifaceobj_list = [ifaceobj]
- (addr_supported, newaddrs, newaddr_attrs) = self._inet_address_convert_to_cidr(ifaceobjlist)
- newaddrs = utils.get_ip_objs(module_name, ifname, newaddrs)
+ addr_supported, user_config_ip_addrs_list = self.__get_ip_addr_with_attributes(ifaceobj_list, ifname)
if not addr_supported:
return
- if (not squash_addr_config and (ifaceobj.flags & iface.HAS_SIBLINGS)):
- # if youngest sibling and squash addr is not set
- # print a warning that addresses will not be purged
- if (ifaceobj.flags & iface.YOUNGEST_SIBLING):
- self.logger.warn('%s: interface has multiple ' %ifaceobj.name +
- 'iface stanzas, skip purging existing addresses')
- purge_addresses = 'no'
- if not ifupdownflags.flags.PERFMODE and purge_addresses == 'yes':
- # if perfmode is not set and purge addresses is not set to 'no'
+ if not ifupdownflags.flags.PERFMODE and purge_addresses:
+ # if perfmode is not set and purge addresses is set to True
# lets purge addresses not in the config
- runningaddrs = self.ipcmd.get_running_addrs(ifaceobj, details=False)
+ anycast_ip = None
+
+ running_ip_addrs = self.cache.get_ifupdown2_addresses_list(ifaceobj_list, ifname)
- # if anycast address is configured on 'lo' and is in running config
- # add it to newaddrs so that ifreload doesn't wipe it out
- anycast_addr = utils.get_normalized_ip_addr(ifaceobj.name, self._get_anycast_addr(ifaceobjlist))
+ if ifaceobj.link_privflags & ifaceLinkPrivFlags.LOOPBACK:
+ anycast_ip = self.__add_loopback_anycast_ip_to_running_ip_addr_list(ifaceobj_list)
- if runningaddrs and anycast_addr and anycast_addr in runningaddrs:
- newaddrs.append(anycast_addr)
+ # user_ip4, user_ip6 and ordered_user_configured_ips IP addresses are now represented
+ # in string format. Comparaisons between IPNetwork object are not reliable, i.e.:
+ # IPNetwork("2001:aa::2/64") == IPNetwork("2001:aa::150/64")
+ user_ip4, user_ip6, ordered_user_configured_ips = self.order_user_configured_addrs(user_config_ip_addrs_list)
- user_ip4, user_ip6, newaddrs = self.order_user_configured_addrs(newaddrs)
+ running_ip_addrs_str = self.get_ipnetwork_object_list_in_string_format(running_ip_addrs)
- if newaddrs == runningaddrs or self.compare_running_ips_and_user_config(user_ip4, user_ip6, runningaddrs):
+ if ordered_user_configured_ips == running_ip_addrs or self.compare_running_ips_and_user_config(user_ip4, user_ip6, running_ip_addrs):
if force_reapply:
- self._inet_address_list_config(ifaceobj, newaddrs, newaddr_attrs)
+ self.__add_ip_addresses_with_attributes(ifaceobj, ifname, user_config_ip_addrs_list)
return
try:
- # if primary address is not same, there is no need to keep any.
- # reset all addresses
- if newaddrs and runningaddrs and newaddrs[0] != runningaddrs[0]:
+ # if primary address is not same, there is no need to keep any, reset all addresses.
+ if ordered_user_configured_ips and running_ip_addrs_str and ordered_user_configured_ips[0] != running_ip_addrs_str[0]:
+ self.logger.info("%s: primary ip changed (from %s to %s) we need to purge all ip addresses and re-add them"
+ % (ifname, ordered_user_configured_ips[0], running_ip_addrs_str[0]))
skip_addrs = []
else:
- skip_addrs = newaddrs or []
- for addr in runningaddrs or []:
+ skip_addrs = ordered_user_configured_ips
+
+ if anycast_ip:
+ skip_addrs.append(anycast_ip)
+
+ for index, addr in enumerate(running_ip_addrs_str):
if addr in skip_addrs:
continue
- self.ipcmd.addr_del(ifaceobj.name, addr)
+ # we still have to send the IPNetwork object
+ # to the netlink "addr_del" API
+ self.netlink.addr_del(ifname, running_ip_addrs[index])
except Exception, e:
self.log_warn(str(e))
- if not newaddrs:
+ if not user_config_ip_addrs_list:
return
- self._inet_address_list_config(ifaceobj, newaddrs, newaddr_attrs)
+ self.__add_ip_addresses_with_attributes(ifaceobj, ifname, user_config_ip_addrs_list)
+
+ def get_ipnetwork_object_list_in_string_format(self, obj_list):
+ return [str(obj) for obj in obj_list]
def compare_running_ips_and_user_config(self, user_ip4, user_ip6, running_addrs):
"""
return i == len_ip6
- def order_user_configured_addrs(self, user_config_addrs):
+ @staticmethod
+ def order_user_configured_addrs(user_config_addrs):
ip4 = []
ip6 = []
- for a in user_config_addrs:
- if isinstance(a, _BaseV6):
+ for a, _ in user_config_addrs:
+ if a.version == 6:
ip6.append(str(a))
else:
ip4.append(str(a))
def _delete_gateway(self, ifaceobj, gateways, vrf, metric):
for del_gw in gateways:
try:
- self.ipcmd.route_del_gateway(ifaceobj.name, del_gw, vrf, metric)
+ self.iproute2.route_del_gateway(ifaceobj.name, del_gw, vrf, metric)
except Exception as e:
self.logger.debug('%s: %s' % (ifaceobj.name, str(e)))
vrf, metric)
for add_gw in gateways:
try:
- self.ipcmd.route_add_gateway(ifaceobj.name, add_gw, vrf, metric, onlink=self.l3_intf_default_gateway_set_onlink)
+ self.iproute2.route_add_gateway(ifaceobj.name, add_gw, vrf, metric, onlink=self.l3_intf_default_gateway_set_onlink)
except Exception as e:
self.log_error('%s: %s' % (ifaceobj.name, str(e)))
return ipv
return prev_gateways
- def _check_mtu_config(self, ifaceobj, mtu, ifaceobj_getfunc, syntaxcheck=False):
+ def _check_mtu_config(self, ifaceobj, mtu_str, mtu_int, ifaceobj_getfunc, syntaxcheck=False):
retval = True
if (ifaceobj.link_kind & ifaceLinkKind.BRIDGE):
if syntaxcheck:
masterobj = ifaceobj_getfunc(ifaceobj.upperifaces[0])
if masterobj:
master_mtu = masterobj[0].get_attr_value_first('mtu')
- if master_mtu and master_mtu != mtu:
+ if master_mtu and master_mtu != mtu_str:
+ log_msg = ("%s: bond slave mtu %s is different from bond master %s mtu %s. "
+ "There is no need to configure mtu on a bond slave." %
+ (ifaceobj.name, mtu_str, masterobj[0].name, master_mtu))
if syntaxcheck:
- self.logger.warn('%s: bond slave mtu %s is different from bond master %s mtu %s. There is no need to configure mtu on a bond slave.' %(ifaceobj.name, mtu, masterobj[0].name, master_mtu))
+ self.logger.warn(log_msg)
retval = False
else:
- self.logger.info('%s: bond slave mtu %s is different from bond master %s mtu %s. There is no need to configure mtu on a bond slave.' %(ifaceobj.name, mtu, masterobj[0].name, master_mtu))
+ self.logger.info(log_msg)
elif ((ifaceobj.link_kind & ifaceLinkKind.VLAN) and
ifaceobj.lowerifaces):
lowerobj = ifaceobj_getfunc(ifaceobj.lowerifaces[0])
if lowerobj:
if syntaxcheck:
- lowerdev_mtu = lowerobj[0].get_attr_value_first('mtu')
+ lowerdev_mtu = int(lowerobj[0].get_attr_value_first('mtu') or 0)
else:
- lowerdev_mtu = self.ipcmd.link_get_mtu_sysfs(lowerobj[0].name)
- if lowerdev_mtu and int(mtu) > int(lowerdev_mtu):
+ lowerdev_mtu = self.cache.get_link_mtu(lowerobj[0].name) # return type: int
+ if lowerdev_mtu and mtu_int > lowerdev_mtu:
self.logger.warn('%s: vlan dev mtu %s is greater than lower realdev %s mtu %s'
- %(ifaceobj.name, mtu, lowerobj[0].name, lowerdev_mtu))
+ %(ifaceobj.name, mtu_str, lowerobj[0].name, lowerdev_mtu))
retval = False
elif (not lowerobj[0].link_kind and
not (lowerobj[0].link_privflags & ifaceLinkPrivFlags.LOOPBACK) and
- not lowerdev_mtu and self.default_mtu and
- (int(mtu) > int(self.default_mtu))):
+ not lowerdev_mtu and self.default_mtu and (mtu_int > self.default_mtu_int)):
# only check default mtu on lower device which is a physical interface
self.logger.warn('%s: vlan dev mtu %s is greater than lower realdev %s mtu %s'
- %(ifaceobj.name, mtu, lowerobj[0].name, self.default_mtu))
+ %(ifaceobj.name, mtu_str, lowerobj[0].name, self.default_mtu))
retval = False
- if self.max_mtu and mtu > self.max_mtu:
+ if self.max_mtu and mtu_int > self.max_mtu:
self.logger.warn('%s: specified mtu %s is greater than max mtu %s'
- %(ifaceobj.name, mtu, self.max_mtu))
+ %(ifaceobj.name, mtu_str, self.max_mtu))
retval = False
return retval
- def _propagate_mtu_to_upper_devs(self, ifaceobj, mtu, ifaceobj_getfunc):
+ def _propagate_mtu_to_upper_devs(self, ifaceobj, mtu_str, mtu_int, ifaceobj_getfunc):
if (not ifaceobj.upperifaces or
(ifaceobj.link_privflags & ifaceLinkPrivFlags.BOND_SLAVE) or
(ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE) or
# only adjust mtu for vlan devices on ifaceobj
umtu = upperobjs[0].get_attr_value_first('mtu')
if not umtu:
- running_mtu = self.ipcmd.link_get_mtu(upperobjs[0].name)
- if not running_mtu or (running_mtu != mtu):
- self.ipcmd.link_set(u, 'mtu', mtu)
+ running_mtu = self.cache.get_link_mtu(upperobjs[0].name)
+ if not running_mtu or running_mtu != mtu_int:
+ self.sysfs.link_set_mtu(u, mtu_str=mtu_str, mtu_int=mtu_int)
- def _process_mtu_config(self, ifaceobj, ifaceobj_getfunc, mtu):
- if mtu:
- if not self._check_mtu_config(ifaceobj, mtu, ifaceobj_getfunc):
- return
- cached_running_mtu = self.ipcmd.link_get_mtu(ifaceobj.name)
- running_mtu = self.ipcmd.link_get_mtu_sysfs(ifaceobj.name)
- if not running_mtu or (running_mtu and running_mtu != mtu):
- force = cached_running_mtu != running_mtu
- self.ipcmd.link_set(ifaceobj.name, 'mtu', mtu, force=force)
- if (not ifupdownflags.flags.ALL and
+ def _process_mtu_config_mtu_valid(self, ifaceobj, ifaceobj_getfunc, mtu_str, mtu_int):
+ if not self._check_mtu_config(ifaceobj, mtu_str, mtu_int, ifaceobj_getfunc):
+ return
+
+ if mtu_int != self.cache.get_link_mtu(ifaceobj.name):
+ self.sysfs.link_set_mtu(ifaceobj.name, mtu_str=mtu_str, mtu_int=mtu_int)
+
+ if (not ifupdownflags.flags.ALL and
not ifaceobj.link_kind and
ifupdownconfig.config.get('adjust_logical_dev_mtu', '1') != '0'):
- # This is additional cost to us, so do it only when
- # ifupdown2 is called on a particular interface and
- # it is a physical interface
- self._propagate_mtu_to_upper_devs(ifaceobj, mtu, ifaceobj_getfunc)
- return
+ # This is additional cost to us, so do it only when
+ # ifupdown2 is called on a particular interface and
+ # it is a physical interface
+ self._propagate_mtu_to_upper_devs(ifaceobj, mtu_str, mtu_int, ifaceobj_getfunc)
+ return
+
+ def _process_mtu_config_mtu_none(self, ifaceobj):
+ cached_link_mtu = self.cache.get_link_mtu(ifaceobj.name)
if ifaceobj.link_kind:
# bonds, vxlan and custom devices (like dummy) need an explicit set of mtu.
# bridges don't need mtu set
- if (ifaceobj.link_kind & ifaceLinkKind.BOND or
- ifaceobj.link_kind & ifaceLinkKind.VXLAN or
- ifaceobj.link_kind & ifaceLinkKind.OTHER
- ):
- running_mtu = self.ipcmd.link_get_mtu(ifaceobj.name)
- if (self.default_mtu and running_mtu != self.default_mtu):
- self.ipcmd.link_set(ifaceobj.name, 'mtu', self.default_mtu)
+ if ifaceobj.link_kind & ifaceLinkKind.BOND \
+ or ifaceobj.link_kind & ifaceLinkKind.VXLAN \
+ or ifaceobj.link_kind & ifaceLinkKind.OTHER:
+ if cached_link_mtu != self.default_mtu_int:
+ self.sysfs.link_set_mtu(ifaceobj.name, mtu_str=self.default_mtu, mtu_int=self.default_mtu_int)
return
+
if (ifupdownconfig.config.get('adjust_logical_dev_mtu', '1') != '0'
and ifaceobj.lowerifaces):
# set vlan interface mtu to lower device mtu
if (ifaceobj.link_kind & ifaceLinkKind.VLAN):
lower_iface = ifaceobj.lowerifaces[0]
- if lower_iface not in self.lower_iface_mtu_checked_list:
- lower_iface_mtu = self.ipcmd.link_get_mtu_sysfs(lower_iface)
- self.ipcmd.cache_update([lower_iface, 'mtu'], lower_iface_mtu)
- self.lower_iface_mtu_checked_list.append(lower_iface)
- else:
- lower_iface_mtu = self.ipcmd.link_get_mtu(lower_iface)
+ lower_iface_mtu_int = self.cache.get_link_mtu(lower_iface)
- if lower_iface_mtu != self.ipcmd.link_get_mtu_sysfs(ifaceobj.name):
- self.ipcmd.link_set_mtu(ifaceobj.name, lower_iface_mtu)
+ if lower_iface_mtu_int != cached_link_mtu:
+ self.sysfs.link_set_mtu(ifaceobj.name, mtu_str=str(lower_iface_mtu_int), mtu_int=lower_iface_mtu_int)
elif (not (ifaceobj.name == 'lo') and not ifaceobj.link_kind and
not (ifaceobj.link_privflags & ifaceLinkPrivFlags.BOND_SLAVE) and
# config by the kernel in play, we try to be cautious here
# on which devices we want to reset mtu to default.
# essentially only physical interfaces which are not bond slaves
- running_mtu = self.ipcmd.link_get_mtu(ifaceobj.name)
- if running_mtu != self.default_mtu:
- self.ipcmd.link_set(ifaceobj.name, 'mtu', self.default_mtu)
+ if cached_link_mtu != self.default_mtu_int:
+ self.sysfs.link_set_mtu(ifaceobj.name, mtu_str=self.default_mtu, mtu_int=self.default_mtu_int)
def _set_bridge_forwarding(self, ifaceobj):
""" set ip forwarding to 0 if bridge interface does not have a
ip nor svi """
ifname = ifaceobj.name
+
+ netconf_ipv4_forwarding = self.cache.get_netconf_forwarding(socket.AF_INET, ifname)
+ netconf_ipv6_forwarding = self.cache.get_netconf_forwarding(socket.AF_INET6, ifname)
+
if not ifaceobj.upperifaces and not ifaceobj.get_attr_value('address'):
- if self.sysctl_get_forwarding_value_from_proc(ifname, "ipv4") == '1':
+ if netconf_ipv4_forwarding:
self.sysctl_write_forwarding_value_to_proc(ifname, "ipv4", 0)
- if self.sysctl_get_forwarding_value_from_proc(ifname, "ipv6") == '1':
+ if netconf_ipv6_forwarding:
self.sysctl_write_forwarding_value_to_proc(ifname, "ipv6", 0)
else:
- if self.sysctl_get_forwarding_value_from_proc(ifname, "ipv4") == '0':
+ if not netconf_ipv4_forwarding:
self.sysctl_write_forwarding_value_to_proc(ifname, "ipv4", 1)
- if self.sysctl_get_forwarding_value_from_proc(ifname, "ipv6") == '0':
+ if not netconf_ipv6_forwarding:
self.sysctl_write_forwarding_value_to_proc(ifname, "ipv6", 1)
- def sysctl_get_forwarding_value_from_proc(self, ifname, family):
- return self.read_file_oneline("/proc/sys/net/%s/conf/%s/forwarding" % (family, ifname))
-
def sysctl_write_forwarding_value_to_proc(self, ifname, family, value):
self.write_file("/proc/sys/net/%s/conf/%s/forwarding" % (family, ifname), "%s\n" % value)
if ifupdownflags.flags.PERFMODE:
running_mpls_enable = '0'
else:
- running_mpls_enable = self.read_file_oneline(
- '/proc/sys/net/mpls/conf/%s/input'
- % ifaceobj.name
- )
+ running_mpls_enable = str(self.cache.get_netconf_mpls_input(ifaceobj.name))
if mpls_enable != running_mpls_enable:
try:
self.log_error('%s: \'ip6-forward\' is not supported for '
'bridge port' %ifaceobj.name)
return
-
setting_default_value = False
if not ipforward:
setting_default_value = True
- ipforward = self.ipforward
-
- if ipforward:
- ipforward = utils.boolean_support_binary(ipforward)
- # File read has been used for better performance
- # instead of using sysctl command
- running_ipforward = self.read_file_oneline(
- '/proc/sys/net/ipv4/conf/%s/forwarding'
- %ifaceobj.name)
-
- if ipforward != running_ipforward:
- try:
-
- self.sysctl_set('net.ipv4.conf.%s.forwarding'
- %('/'.join(ifaceobj.name.split("."))),
- ipforward)
- except Exception as e:
- if not setting_default_value:
- ifaceobj.status = ifaceStatus.ERROR
- self.logger.error('%s: %s' %(ifaceobj.name, str(e)))
-
+ ipforward = (self.ipforward or
+ self.get_mod_subattr('ip-forward', 'default'))
+ ipforward = int(utils.get_boolean_from_string(ipforward))
+ running_ipforward = self.cache.get_netconf_forwarding(socket.AF_INET, ifaceobj.name)
+ if ipforward != running_ipforward:
+ try:
+ self.sysctl_set('net.ipv4.conf.%s.forwarding'
+ %('/'.join(ifaceobj.name.split("."))),
+ ipforward)
+ except Exception as e:
+ if not setting_default_value:
+ ifaceobj.status = ifaceStatus.ERROR
+ self.logger.error('%s: %s' %(ifaceobj.name, str(e)))
setting_default_value = False
if not ip6forward:
setting_default_value = True
- ip6forward = self.ip6forward
-
- if ip6forward:
- ip6forward = utils.boolean_support_binary(ip6forward)
- # File read has been used for better performance
- # instead of using sysctl command
- running_ip6forward = self.read_file_oneline(
- '/proc/sys/net/ipv6/conf/%s/forwarding'
- %ifaceobj.name)
- if ip6forward != running_ip6forward:
- try:
- self.sysctl_set('net.ipv6.conf.%s.forwarding'
- %('/'.join(ifaceobj.name.split("."))),
- ip6forward)
- except Exception as e:
- # There is chance of ipv6 being removed because of,
- # for example, setting mtu < 1280
- # In such cases, log error only if user has configured
- # ip6-forward
- if not setting_default_value:
- ifaceobj.status = ifaceStatus.ERROR
- self.logger.error('%s: %s' %(ifaceobj.name, str(e)))
+ ip6forward = (self.ip6forward or
+ self.get_mod_subattr('ip6-forward', 'default'))
+ ip6forward = int(utils.get_boolean_from_string(ip6forward))
+ running_ip6forward = self.cache.get_netconf_forwarding(socket.AF_INET6, ifaceobj.name)
+ if ip6forward != running_ip6forward:
+ try:
+ self.sysctl_set('net.ipv6.conf.%s.forwarding'
+ %('/'.join(ifaceobj.name.split("."))),
+ ip6forward)
+ except Exception as e:
+ # There is chance of ipv6 being removed because of,
+ # for example, setting mtu < 1280
+ # In such cases, log error only if user has configured
+ # ip6-forward
+ if not setting_default_value:
+ ifaceobj.status = ifaceStatus.ERROR
+ self.logger.error('%s: %s' %(ifaceobj.name, str(e)))
def process_mtu(self, ifaceobj, ifaceobj_getfunc):
- mtu = ifaceobj.get_attr_value_first('mtu')
+ mtu_str = ifaceobj.get_attr_value_first('mtu')
+ mtu_from_policy = False
- if not mtu:
- default_iface_mtu = self.ifaces_defaults.get(ifaceobj.name, {}).get('mtu')
+ if not mtu_str:
+ mtu_str = self.ifaces_defaults.get(ifaceobj.name, {}).get('mtu')
+ mtu_from_policy = True
- if default_iface_mtu:
- try:
- mtu = default_iface_mtu
- int(default_iface_mtu)
- except Exception as e:
- self.logger.warning('%s: MTU value from policy file: %s' % (ifaceobj.name, str(e)))
- return
+ if mtu_str:
+ try:
+ mtu_int = int(mtu_str)
+ except Exception as e:
+ if mtu_from_policy:
+ self.logger.warning("%s: invalid MTU value from policy file (iface_defaults): %s" % (ifaceobj.name, str(e)))
+ else:
+ self.logger.warning("%s: invalid MTU value: %s" % (ifaceobj.name, str(e)))
+ return
- self._process_mtu_config(ifaceobj, ifaceobj_getfunc, mtu)
+ self._process_mtu_config_mtu_valid(ifaceobj, ifaceobj_getfunc, mtu_str, mtu_int)
+ else:
+ self._process_mtu_config_mtu_none(ifaceobj)
def up_ipv6_addrgen(self, ifaceobj):
user_configured_ipv6_addrgen = ifaceobj.get_attr_value_first('ipv6-addrgen')
# no need to go further during perfmode (boot)
return
- if not user_configured_ipv6_addrgen and ifaceobj.addr_method == 'dhcp':
+ if not user_configured_ipv6_addrgen and ifaceobj.addr_method in ["dhcp", "ppp"]:
return
if not user_configured_ipv6_addrgen:
}.get(user_configured_ipv6_addrgen.lower(), None)
if ipv6_addrgen_nl is not None:
- self.ipcmd.ipv6_addrgen(ifaceobj.name, ipv6_addrgen_nl, link_created=True)
+ self.iproute2.batch_start()
+ self.iproute2.link_set_ipv6_addrgen(ifaceobj.name, ipv6_addrgen_nl, link_created=True)
+ self.iproute2.batch_commit()
# link_create=False will flush the addr cache of that intf
else:
self.logger.warning('%s: invalid value "%s" for attribute ipv6-addrgen' % (ifaceobj.name, user_configured_ipv6_addrgen))
- def _up(self, ifaceobj, ifaceobj_getfunc=None):
- if not self.ipcmd.link_exists(ifaceobj.name):
+ def _pre_up(self, ifaceobj, ifaceobj_getfunc=None):
+ if not self.cache.link_exists(ifaceobj.name):
return
if not self.syntax_check_enable_l3_iface_forwardings(ifaceobj, ifaceobj_getfunc):
return
- alias = ifaceobj.get_attr_value_first('alias')
- current_alias = self.ipcmd.link_get_alias(ifaceobj.name)
- if alias and alias != current_alias:
- self.ipcmd.link_set_alias(ifaceobj.name, alias)
- elif not alias and current_alias:
- self.ipcmd.link_set_alias(ifaceobj.name, '')
+ #
+ # alias
+ #
+ self.sysfs.link_set_alias(ifaceobj.name, ifaceobj.get_attr_value_first("alias"))
self._sysctl_config(ifaceobj)
force_reapply = False
try:
# release any stale dhcp addresses if present
- if (addr_method not in ["dhcp", "ppp"] and not ifupdownflags.flags.PERFMODE and
+ if (addr_method not in ["dhcp", "ppp"] and not ifupdownflags.flags.PERFMODE and
not (ifaceobj.flags & iface.HAS_SIBLINGS)):
# if not running in perf mode and ifaceobj does not have
# any sibling iface objects, kill any stale dhclient
if dhclientcmd.is_running(ifaceobj.name):
# release any dhcp leases
dhclientcmd.release(ifaceobj.name)
+ self.cache.force_address_flush_family(ifaceobj.name, socket.AF_INET)
force_reapply = True
elif dhclientcmd.is_running6(ifaceobj.name):
dhclientcmd.release6(ifaceobj.name)
+ self.cache.force_address_flush_family(ifaceobj.name, socket.AF_INET6)
force_reapply = True
except:
pass
- self.ipcmd.batch_start()
self.up_ipv6_addrgen(ifaceobj)
if addr_method not in ["dhcp", "ppp"]:
- self._inet_address_config(ifaceobj, ifaceobj_getfunc,
- force_reapply)
+ self.process_addresses(ifaceobj, ifaceobj_getfunc, force_reapply)
else:
# remove old addresses added by ifupdown2
# (if intf was moved from static config to dhcp)
for old_ifaceobj in statemanager.statemanager_api.get_ifaceobjs(ifaceobj.name) or []:
for addr in old_ifaceobj.get_attr_value("address") or []:
- self.ipcmd.addr_del(ifaceobj.name, addr)
+ self.netlink.addr_del(ifaceobj.name, addr)
self.process_mtu(ifaceobj, ifaceobj_getfunc)
try:
- self.ipcmd.batch_commit()
- except Exception as e:
- self.log_error('%s: %s' % (ifaceobj.name, str(e)), ifaceobj, raise_error=False)
+ self.process_hwaddress(ifaceobj)
- self.up_hwaddress(ifaceobj)
+ # Handle special things on a bridge
+ self._process_bridge(ifaceobj, True)
+ except Exception, e:
+ self.log_error('%s: %s' % (ifaceobj.name, str(e)), ifaceobj)
+ def _up(self, ifaceobj, ifaceobj_getfunc=None):
gateways = ifaceobj.get_attr_value('gateway')
if not gateways:
gateways = []
prev_gw = self._get_prev_gateway(ifaceobj, gateways)
self._add_delete_gateway(ifaceobj, gateways, prev_gw)
- def up_hwaddress(self, ifaceobj):
- try:
- hwaddress = self._get_hwaddress(ifaceobj)
+ def process_hwaddress(self, ifaceobj):
+ hwaddress = self._get_hwaddress(ifaceobj)
- if hwaddress:
- if not ifupdownflags.flags.PERFMODE: # system is clean
- running_hwaddress = self.ipcmd.link_get_hwaddress(ifaceobj.name)
- else:
- running_hwaddress = None
-
- if self.ipcmd.mac_str_to_int(running_hwaddress) != self.ipcmd.mac_str_to_int(hwaddress):
- slave_down = False
- netlink.link_set_updown(ifaceobj.name, "down")
- if ifaceobj.link_kind & ifaceLinkKind.BOND:
- # if bond, down all the slaves
- if ifaceobj.lowerifaces:
- for l in ifaceobj.lowerifaces:
- netlink.link_set_updown(l, "down")
- slave_down = True
- try:
- self.ipcmd.link_set_hwaddress(ifaceobj.name, hwaddress, force=True)
- finally:
- netlink.link_set_updown(ifaceobj.name, "up")
- if slave_down:
- for l in ifaceobj.lowerifaces:
- netlink.link_set_updown(l, "up")
+ if not hwaddress:
+ if ifaceobj.link_kind & ifaceLinkKind.VLAN:
+ # When hwaddress is removed from vlan config
+ # we should go back to system or bridge mac
+ for lower in ifaceobj.lowerifaces:
+ if self.cache.get_link_kind(lower) == "bridge":
+ hwaddress = self.cache.get_link_address(lower)
+ break
+ if not hwaddress:
+ return
+ else:
+ return
- # Handle special things on a bridge
- self._process_bridge(ifaceobj, True)
- except Exception, e:
- self.log_error('%s: %s' % (ifaceobj.name, str(e)), ifaceobj)
+ if not ifupdownflags.flags.PERFMODE: # system is clean
+ running_hwaddress = self.cache.get_link_address(ifaceobj.name)
+ else:
+ running_hwaddress = None
+
+ if utils.mac_str_to_int(hwaddress) != utils.mac_str_to_int(running_hwaddress):
+ slave_down = False
+ if ifaceobj.link_kind & ifaceLinkKind.BOND:
+ # if bond, down all the slaves
+ if ifaceobj.lowerifaces:
+ for l in ifaceobj.lowerifaces:
+ self.netlink.link_down(l)
+ slave_down = True
+ try:
+ self.netlink.link_set_address(ifaceobj.name, hwaddress)
+ finally:
+ if slave_down:
+ for l in ifaceobj.lowerifaces:
+ self.netlink.link_up(l)
def _down(self, ifaceobj, ifaceobj_getfunc=None):
try:
- if not self.ipcmd.link_exists(ifaceobj.name):
+ if not self.cache.link_exists(ifaceobj.name):
return
addr_method = ifaceobj.addr_method
if addr_method not in ["dhcp", "ppp"]:
if ifaceobj.get_attr_value_first('address-purge')=='no':
addrlist = ifaceobj.get_attr_value('address')
- for addr in addrlist:
- self.ipcmd.addr_del(ifaceobj.name, addr)
- #self.ipcmd.addr_del(ifaceobj.name, ifaceobj.get_attr_value('address')[0])
+ for addr in addrlist or []:
+ self.netlink.addr_del(ifaceobj.name, addr)
elif not ifaceobj.link_kind:
# for logical interfaces we don't need to remove the ip addresses
# kernel will do it for us on 'ip link del'
- self.ipcmd.del_addr_all(ifaceobj.name)
+ if ifaceobj_getfunc:
+ ifaceobj_list = ifaceobj_getfunc(ifaceobj.name) or [ifaceobj]
+ else:
+ ifaceobj_list = [ifaceobj]
+
+ for addr in self.cache.get_ifupdown2_addresses_list(ifaceobj_list, ifaceobj.name):
+ self.netlink.addr_del(ifaceobj.name, addr)
+
gateways = ifaceobj.get_attr_value('gateway')
if gateways:
self._delete_gateway(ifaceobj, gateways,
ifaceobj.get_attr_value_first('vrf'),
ifaceobj.get_attr_value_first('metric'))
- mtu = ifaceobj.get_attr_value_first('mtu')
- if (not ifaceobj.link_kind and mtu and
- self.default_mtu and (mtu != self.default_mtu)):
- self.ipcmd.link_set(ifaceobj.name, 'mtu', self.default_mtu)
- alias = ifaceobj.get_attr_value_first('alias')
- if alias:
- self.write_file('/sys/class/net/%s/ifalias' % ifaceobj.name, '\n')
+
+ #
+ # mtu --
+ # If device is not a logical intf and has its MTU configured by
+ # ifupdown2. If this MTU is different from our default mtu,
+ # if so we need to reset it back to default.
+ if not ifaceobj.link_kind and self.default_mtu and ifaceobj.get_attr_value_first('mtu') and self.cache.get_link_mtu(ifaceobj.name) != self.default_mtu_int:
+ self.sysfs.link_set_mtu(ifaceobj.name, mtu_str=self.default_mtu, mtu_int=self.default_mtu_int)
+
+ #
+ # alias
+ # only reset alias on non-logical device
+ if not ifaceobj.link_kind:
+ alias = ifaceobj.get_attr_value_first("alias")
+ if alias:
+ self.sysfs.link_set_alias(ifaceobj.name, None) # None to reset alias.
+
# XXX hwaddress reset cannot happen because we dont know last
# address.
def _get_bridge_fdbs(self, bridgename, vlan):
fdbs = self._bridge_fdb_query_cache.get(bridgename)
if not fdbs:
- fdbs = self.ipcmd.bridge_fdb_show_dev(bridgename)
+ fdbs = self.iproute2.bridge_fdb_show_dev(bridgename)
if not fdbs:
return
self._bridge_fdb_query_cache[bridgename] = fdbs
if ifaceobj.link_kind & ifaceLinkKind.VLAN:
bridgename = ifaceobj.lowerifaces[0]
vlan = self._get_vlan_id(ifaceobj)
- if self.ipcmd.bridge_is_vlan_aware(bridgename):
- fdb_addrs = [self.ipcmd.mac_str_to_int(fdb_addr) for fdb_addr in self._get_bridge_fdbs(bridgename, str(vlan))]
+ if self.cache.bridge_is_vlan_aware(bridgename):
+ fdb_addrs = [utils.mac_str_to_int(fdb_addr) for fdb_addr in self._get_bridge_fdbs(bridgename, str(vlan))]
if not fdb_addrs:
- return False
- hwaddress_int = self.ipcmd.mac_str_to_int(hwaddress)
+ return False
+ hwaddress_int = utils.mac_str_to_int(hwaddress)
if hwaddress_int not in fdb_addrs:
return False
return True
'for bridge port')
ifaceobjcurr.update_config_with_status('ip-forward', 1, None)
else:
- running_ipforward = self.read_file_oneline(
- '/proc/sys/net/ipv4/conf/%s/forwarding'
- %ifaceobj.name)
- running_ipforward = utils.get_boolean_from_string(running_ipforward)
+ running_ipforward = self.cache.get_netconf_forwarding(socket.AF_INET, ifaceobj.name)
config_ipforward = utils.get_boolean_from_string(ipforward)
ifaceobjcurr.update_config_with_status(
'ip-forward',
'for bridge port')
ifaceobjcurr.update_config_with_status('ip6-forward', 1, None)
else:
- running_ip6forward = self.read_file_oneline(
- '/proc/sys/net/ipv6/conf/%s/forwarding'
- %ifaceobj.name)
- running_ip6forward = utils.get_boolean_from_string(running_ip6forward)
+ running_ip6forward = self.cache.get_netconf_forwarding(socket.AF_INET6, ifaceobj.name)
config_ip6forward = utils.get_boolean_from_string(ip6forward)
ifaceobjcurr.update_config_with_status(
'ip6-forward',
)
mpls_enable = ifaceobj.get_attr_value_first('mpls-enable');
if mpls_enable:
- running_mpls_enable = self.read_file_oneline(
- '/proc/sys/net/mpls/conf/%s/input'
- %ifaceobj.name)
- running_mpls_enable = utils.get_yesno_from_onezero(
- running_mpls_enable)
+ running_mpls_enable = utils.get_yesno_from_onezero(str(self.cache.get_netconf_mpls_input(ifaceobj.name)))
ifaceobjcurr.update_config_with_status('mpls-enable',
running_mpls_enable,
mpls_enable != running_mpls_enable)
ifaceobjcurr.update_config_with_status(
'ipv6-addrgen',
ipv6_addrgen,
- utils.get_boolean_from_string(ipv6_addrgen) == self.ipcmd.get_ipv6_addrgen_mode(ifaceobj.name)
+ utils.get_boolean_from_string(ipv6_addrgen) == self.cache.get_link_ipv6_addrgen_mode(ifaceobj.name)
)
else:
ifaceobjcurr.update_config_with_status('ipv6-addrgen', ipv6_addrgen, 1)
def _query_check(self, ifaceobj, ifaceobjcurr, ifaceobj_getfunc=None):
+ """
+ TODO: Check broadcast address, scope, etc
+ """
runningaddrsdict = None
- if not self.ipcmd.link_exists(ifaceobj.name):
+ if not self.cache.link_exists(ifaceobj.name):
self.logger.debug('iface %s not found' %ifaceobj.name)
return
addr_method = ifaceobj.addr_method
self.query_n_update_ifaceobjcurr_attr(ifaceobj, ifaceobjcurr,
- 'mtu', self.ipcmd.link_get_mtu)
+ 'mtu', self.cache.get_link_mtu_str)
hwaddress = self._get_hwaddress(ifaceobj)
if hwaddress:
- rhwaddress = self.ipcmd.link_get_hwaddress(ifaceobj.name)
- if not rhwaddress or self.ipcmd.mac_str_to_int(rhwaddress) != self.ipcmd.mac_str_to_int(hwaddress):
+ rhwaddress = self.cache.get_link_address(ifaceobj.name)
+ if not rhwaddress or utils.mac_str_to_int(rhwaddress) != utils.mac_str_to_int(hwaddress):
ifaceobjcurr.update_config_with_status('hwaddress', rhwaddress,
1)
elif not self._check_addresses_in_bridge(ifaceobj, hwaddress):
ifaceobjcurr.update_config_with_status('hwaddress', rhwaddress,
0)
self.query_n_update_ifaceobjcurr_attr(ifaceobj, ifaceobjcurr,
- 'alias', self.ipcmd.link_get_alias)
+ 'alias', self.cache.get_link_alias)
self._query_sysctl(ifaceobj, ifaceobjcurr)
# compare addresses
if addr_method in ["dhcp", "ppp"]:
return
- addrs = utils.get_normalized_ip_addr(ifaceobj.name,
- self._get_iface_addresses(ifaceobj))
- runningaddrsdict = self.ipcmd.get_running_addrs(ifaceobj)
- # if anycast address is configured on 'lo' and is in running config
- # add it to addrs so that query_check doesn't fail
- anycast_addr = utils.get_normalized_ip_addr(ifaceobj.name, ifaceobj.get_attr_value_first('clagd-vxlan-anycast-ip'))
- if anycast_addr:
- anycast_addr = anycast_addr+'/32'
- if runningaddrsdict and anycast_addr and runningaddrsdict.get(anycast_addr):
- addrs.append(anycast_addr)
+
+ if ifaceobj_getfunc:
+ ifaceobj_list = ifaceobj_getfunc(ifaceobj.name)
+ else:
+ ifaceobj_list = [ifaceobj]
+
+ intf_running_addrs = self.cache.get_ifupdown2_addresses_list(ifaceobj_list, ifaceobj.name)
+ user_config_addrs = self.cache.get_user_config_ip_addrs_with_attrs_in_ipnetwork_format([ifaceobj], details=False)
+
+ try:
+ clagd_vxlan_anycast_ip = IPNetwork(ifaceobj.get_attr_value_first('clagd-vxlan-anycast-ip'))
+
+ if clagd_vxlan_anycast_ip in intf_running_addrs:
+ user_config_addrs.append(clagd_vxlan_anycast_ip)
+ except:
+ pass
# Set ifaceobjcurr method and family
ifaceobjcurr.addr_method = ifaceobj.addr_method
ifaceobjcurr.addr_family = ifaceobj.addr_family
- if not runningaddrsdict and not addrs:
+
+ if not intf_running_addrs and not user_config_addrs:
+ # The device doesn't have any ips configured and the
+ # the user didn't specify any ip in the configuration file
return
- runningaddrs = runningaddrsdict.keys() if runningaddrsdict else []
- # Add /32 netmask to configured address without netmask.
- # This may happen on interfaces where pointopoint is used.
- runningaddrs = [ addr if '/' in addr else addr + '/32' for addr in runningaddrs]
- if runningaddrs != addrs:
- runningaddrsset = set(runningaddrs) if runningaddrs else set([])
- addrsset = set(addrs) if addrs else set([])
- if (ifaceobj.flags & iface.HAS_SIBLINGS):
- if not addrsset:
- return
- # only check for addresses present in running config
- addrsdiff = addrsset.difference(runningaddrsset)
- for addr in addrs:
- if addr in addrsdiff:
- ifaceobjcurr.update_config_with_status('address',
- addr, 1)
- else:
- ifaceobjcurr.update_config_with_status('address',
- addr, 0)
- else:
- addrsdiff = addrsset.symmetric_difference(runningaddrsset)
- for addr in addrsset.union(runningaddrsset):
- if addr in addrsdiff:
- ifaceobjcurr.update_config_with_status('address',
- addr, 1)
- else:
- ifaceobjcurr.update_config_with_status('address',
- addr, 0)
- elif addrs:
- [ifaceobjcurr.update_config_with_status('address',
- addr, 0) for addr in addrs]
- #XXXX Check broadcast address, scope, etc
+
+ for address in user_config_addrs:
+ ifaceobjcurr.update_config_with_status('address', str(address), address not in intf_running_addrs)
+ try:
+ intf_running_addrs.remove(address)
+ except:
+ pass
+
+ # if any ip address is left in 'intf_running_addrs' it means
+ # that they used to be configured by ifupdown2 but not anymore
+ # but are still on the intf, so we need to mark them as fail
+ # we will only mark them as failure on the first sibling
+ if ifaceobj.flags & iface.HAS_SIBLINGS:
+ if not ifaceobj.flags & iface.YOUNGEST_SIBLING:
+ return
+
+ all_stanza_user_config_ip = self.cache.get_user_config_ip_addrs_with_attrs_in_ipnetwork_format(
+ ifaceobj_list,
+ details=False
+ )
+
+ for address in intf_running_addrs:
+ if address not in all_stanza_user_config_ip:
+ ifaceobjcurr.update_config_with_status('address', str(address), 1)
+
return
def query_running_ipv6_addrgen(self, ifaceobjrunning):
- ipv6_addrgen = self.ipcmd.get_ipv6_addrgen_mode(ifaceobjrunning.name)
+ ipv6_addrgen = self.cache.get_link_ipv6_addrgen_mode(ifaceobjrunning.name)
if ipv6_addrgen:
ifaceobjrunning.update_config('ipv6-addrgen', 'off')
def _query_running(self, ifaceobjrunning, ifaceobj_getfunc=None):
- if not self.ipcmd.link_exists(ifaceobjrunning.name):
+ if not self.cache.link_exists(ifaceobjrunning.name):
self.logger.debug('iface %s not found' %ifaceobjrunning.name)
return
dhclientcmd.is_running6(ifaceobjrunning.name)):
# If dhcp is configured on the interface, we skip it
return
- isloopback = self.ipcmd.link_isloopback(ifaceobjrunning.name)
- if isloopback:
- default_addrs = ['127.0.0.1/8', '::1/128']
+
+ intf_running_addrs = self.cache.get_addresses_list(ifaceobjrunning.name) or []
+
+ if self.cache.link_is_loopback(ifaceobjrunning.name):
+ for default_addr in self.default_loopback_addresses:
+ try:
+ intf_running_addrs.remove(default_addr)
+ except:
+ pass
ifaceobjrunning.addr_family.append('inet')
ifaceobjrunning.addr_method = 'loopback'
- else:
- default_addrs = []
- runningaddrsdict = self.ipcmd.get_running_addrs(ifaceobjrunning)
- if runningaddrsdict:
- [ifaceobjrunning.update_config('address', addr)
- for addr, addrattrs in runningaddrsdict.items()
- if addr not in default_addrs]
- mtu = self.ipcmd.link_get_mtu(ifaceobjrunning.name)
+
+ for addr in intf_running_addrs:
+ ifaceobjrunning.update_config('address', str(addr))
+
+ mtu = self.cache.get_link_mtu_str(ifaceobjrunning.name)
if (mtu and
(ifaceobjrunning.name == 'lo' and mtu != '16436') or
(ifaceobjrunning.name != 'lo' and
mtu != self.get_mod_subattr('mtu', 'default'))):
ifaceobjrunning.update_config('mtu', mtu)
- alias = self.ipcmd.link_get_alias(ifaceobjrunning.name)
+
+ alias = self.cache.get_link_alias(ifaceobjrunning.name)
if alias:
ifaceobjrunning.update_config('alias', alias)
- ipforward = self.read_file_oneline(
- '/proc/sys/net/ipv4/conf/%s/forwarding'
- %ifaceobjrunning.name)
-
-
- _run_ops = {'up' : _up,
- 'down' : _down,
- 'query-checkcurr' : _query_check,
- 'query-running' : _query_running }
+ _run_ops = {
+ 'pre-up': _pre_up,
+ 'up': _up,
+ 'down': _down,
+ 'query-checkcurr': _query_check,
+ 'query-running': _query_running
+ }
def get_ops(self):
""" returns list of ops supported by this module """
return self._run_ops.keys()
- def _init_command_handlers(self):
- if not self.ipcmd:
- self.ipcmd = LinkUtils()
-
def run(self, ifaceobj, operation, query_ifaceobj=None, ifaceobj_getfunc=None):
""" run address configuration on the interface object passed as argument
op_handler = self._run_ops.get(operation)
if not op_handler:
return
- self._init_command_handlers()
if operation == 'query-checkcurr':
op_handler(self, ifaceobj, query_ifaceobj,
ifaceobj_getfunc=ifaceobj_getfunc)
import os
import glob
+import subprocess
from collections import deque
from ipaddr import IPNetwork, IPv6Network
try:
+ from ifupdown2.lib.addon import Addon
from ifupdown2.ifupdown.iface import *
from ifupdown2.ifupdown.utils import utils
- from ifupdown2.ifupdown.netlink import netlink
from ifupdown2.nlmanager.nlpacket import Link
- from ifupdown2.ifupdownaddons.cache import *
- from ifupdown2.ifupdownaddons.LinkUtils import LinkUtils
from ifupdown2.ifupdownaddons.modulebase import moduleBase
import ifupdown2.ifupdown.statemanager as statemanager
import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
import ifupdown2.ifupdown.ifupdownconfig as ifupdownconfig
except ImportError:
+ from lib.addon import Addon
from ifupdown.iface import *
from ifupdown.utils import utils
- from ifupdown.netlink import netlink
from nlmanager.nlpacket import Link
- from ifupdownaddons.cache import *
- from ifupdownaddons.LinkUtils import LinkUtils
from ifupdownaddons.modulebase import moduleBase
import ifupdown.statemanager as statemanager
import ifupdown.ifupdownconfig as ifupdownconfig
-class addressvirtual(moduleBase):
+class addressvirtual(Addon, moduleBase):
""" ifupdown2 addon module to configure virtual addresses """
- _modinfo = {'mhelp' : 'address module configures virtual addresses for ' +
- 'interfaces. It creates a macvlan interface for ' +
- 'every mac ip address-virtual line',
- 'attrs' : {
- 'address-virtual' :
- { 'help' : 'bridge router virtual mac and ips',
- 'multivalue' : True,
- 'validvals' : ['<mac-ip/prefixlen-list>',],
- 'example': ['address-virtual 00:11:22:33:44:01 11.0.1.1/24 11.0.1.2/24']
- },
- 'address-virtual-ipv6-addrgen': {
- 'help': 'enable disable ipv6 link addrgenmode',
- 'validvals': ['on', 'off'],
- 'default': 'on',
- 'example': [
- 'address-virtual-ipv6-addrgen on',
- 'address-virtual-ipv6-addrgen off'
- ]
- },
- "vrrp": {
- "help": "VRRP support",
- "multivalue": True,
- "example": [
- "vrrp 1 10.0.0.15/24 2001:0db8::0370:7334/64",
- "vrrp 42 10.0.0.42/24"
- ]
- }
- }}
+ _modinfo = {
+ "mhelp": "address module configures virtual addresses for interfaces. "
+ "It creates a macvlan interface for every mac ip address-virtual line",
+ "attrs": {
+ "address-virtual": {
+ "help": "bridge router virtual mac and ips",
+ "multivalue": True,
+ "validvals": ["<mac-ip/prefixlen-list>", ],
+ "example": ["address-virtual 00:11:22:33:44:01 11.0.1.1/24 11.0.1.2/24"]
+ },
+ "address-virtual-ipv6-addrgen": {
+ "help": "enable disable ipv6 link addrgenmode",
+ "validvals": ["on", "off"],
+ "default": "on",
+ "example": [
+ "address-virtual-ipv6-addrgen on",
+ "address-virtual-ipv6-addrgen off"
+ ]
+ },
+ "vrrp": {
+ "help": "VRRP support",
+ "multivalue": True,
+ "example": [
+ "vrrp 1 10.0.0.15/24 2001:0db8::0370:7334/64",
+ "vrrp 42 10.0.0.42/24"
+ ]
+ }
+ }
+ }
+ DEFAULT_IP_METRIC = 1024
+ ADDR_METRIC_SUPPORT = None
def __init__(self, *args, **kargs):
+ Addon.__init__(self)
moduleBase.__init__(self, *args, **kargs)
- self.ipcmd = None
self._bridge_fdb_query_cache = {}
self.addressvirtual_with_route_metric = utils.get_boolean_from_string(
policymanager.policymanager_api.get_module_globals(
self.address_virtual_ipv6_addrgen_value_dict = {'on': 0, 'yes': 0, '0': 0, 'off': 1, 'no': 1, '1': 1}
+ if addressvirtual.ADDR_METRIC_SUPPORT is None:
+ try:
+ cmd = [utils.ip_cmd, 'addr', 'help']
+ self.logger.info('executing %s addr help' % utils.ip_cmd)
+
+ process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ stdout, stderr = process.communicate()
+ addressvirtual.ADDR_METRIC_SUPPORT = '[ metric METRIC ]' in stderr or ''
+ self.logger.info('address metric support: %s' % ('OK' if addressvirtual.ADDR_METRIC_SUPPORT else 'KO'))
+ except Exception:
+ addressvirtual.ADDR_METRIC_SUPPORT = False
+ self.logger.info('address metric support: KO')
+
+ @classmethod
+ def addr_metric_support(cls):
+ return cls.ADDR_METRIC_SUPPORT
+
+ @classmethod
+ def get_default_ip_metric(cls):
+ return cls.DEFAULT_IP_METRIC
+
def get_dependent_ifacenames(self, ifaceobj, ifacenames_all=None):
if ifaceobj.get_attr_value('address-virtual') or ifaceobj.get_attr_value("vrrp"):
ifaceobj.link_privflags |= ifaceLinkPrivFlags.ADDRESS_VIRTUAL_SLAVE
def _get_macvlan_prefix(self, ifaceobj):
return '%s-v' %ifaceobj.name[0:13].replace('.', '-')
- @staticmethod
- def get_vrrp_prefix(ifname, family):
- return "vrrp%s-%s-" % (family, netlink.get_iface_index(ifname))
+ def get_vrrp_prefix(self, ifname, family):
+ return "vrrp%s-%s-" % (family, self.cache.get_ifindex(ifname))
def _add_addresses_to_bridge(self, ifaceobj, hwaddress):
# XXX: batch the addresses
if ifaceobj.link_kind & ifaceLinkKind.VLAN:
bridgename = ifaceobj.lowerifaces[0]
vlan = self._get_vlan_id(ifaceobj)
- if self.ipcmd.bridge_is_vlan_aware(bridgename):
- [self.ipcmd.bridge_fdb_add(bridgename, addr,
+ if self.cache.bridge_is_vlan_aware(bridgename):
+ [self.iproute2.bridge_fdb_add(bridgename, addr,
vlan) for addr in hwaddress]
- elif self.ipcmd.is_bridge(ifaceobj.name):
- [self.ipcmd.bridge_fdb_add(ifaceobj.name, addr)
+ elif self.cache.link_is_bridge(ifaceobj.name):
+ [self.iproute2.bridge_fdb_add(ifaceobj.name, addr)
for addr in hwaddress]
def _remove_addresses_from_bridge(self, ifaceobj, hwaddress):
if ifaceobj.link_kind & ifaceLinkKind.VLAN:
bridgename = ifaceobj.lowerifaces[0]
vlan = self._get_vlan_id(ifaceobj)
- if self.ipcmd.bridge_is_vlan_aware(bridgename):
+ if self.cache.bridge_is_vlan_aware(bridgename):
for addr in hwaddress:
try:
- self.ipcmd.bridge_fdb_del(bridgename, addr, vlan)
+ self.iproute2.bridge_fdb_del(bridgename, addr, vlan)
except Exception, e:
self.logger.debug("%s: %s" %(ifaceobj.name, str(e)))
pass
- elif self.ipcmd.is_bridge(ifaceobj.name):
+ elif self.cache.link_is_bridge(ifaceobj.name):
for addr in hwaddress:
try:
- self.ipcmd.bridge_fdb_del(ifaceobj.name, addr)
+ self.iproute2.bridge_fdb_del(ifaceobj.name, addr)
except Exception, e:
self.logger.debug("%s: %s" %(ifaceobj.name, str(e)))
pass
def _get_bridge_fdbs(self, bridgename, vlan):
fdbs = self._bridge_fdb_query_cache.get(bridgename)
if not fdbs:
- fdbs = self.ipcmd.bridge_fdb_show_dev(bridgename)
+ fdbs = self.iproute2.bridge_fdb_show_dev(bridgename)
if not fdbs:
return
self._bridge_fdb_query_cache[bridgename] = fdbs
if ifaceobj.link_kind & ifaceLinkKind.VLAN:
bridgename = ifaceobj.lowerifaces[0]
vlan = self._get_vlan_id(ifaceobj)
- if self.ipcmd.bridge_is_vlan_aware(bridgename):
+ if self.cache.bridge_is_vlan_aware(bridgename):
fdb_addrs = self._get_bridge_fdbs(bridgename, str(vlan))
if not fdb_addrs:
return False
- hwaddress_int = self.ipcmd.mac_str_to_int(hwaddress)
+ hwaddress_int = utils.mac_str_to_int(hwaddress)
for mac in fdb_addrs:
- if self.ipcmd.mac_str_to_int(mac) == hwaddress_int:
+ if utils.mac_str_to_int(mac) == hwaddress_int:
return True
return False
return True
route_prefix = '%s/%d' %(ip.network, ip.prefixlen)
if ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE:
- vrf_master = self.ipcmd.link_get_master(ifaceobj.name)
+ vrf_master = self.cache.get_master(ifaceobj.name)
else:
vrf_master = None
- dev = self.ipcmd.ip_route_get_dev(route_prefix, vrf_master=vrf_master)
+ dev = self.iproute2.ip_route_get_dev(route_prefix, vrf_master=vrf_master)
if dev and dev != ifaceobj.name:
self.logger.info('%s: preferred routing entry ' %ifaceobj.name +
'seems to be of the macvlan dev %s'
%vifacename +
' .. flapping macvlan dev to fix entry.')
- self.ipcmd.link_down(vifacename)
- self.ipcmd.link_up(vifacename)
+ self.iproute2.link_down(vifacename)
+ self.iproute2.link_up(vifacename)
except Exception, e:
self.logger.debug('%s: fixing route entry failed (%s)'
% (ifaceobj.name, str(e)))
pass
- def _handle_vrf_slaves(self, macvlan_ifacename, ifaceobj):
- vrfname = self.ipcmd.link_get_master(ifaceobj.name)
- if vrfname:
- self.ipcmd.link_set(macvlan_ifacename, 'master', vrfname)
-
def _get_macs_from_old_config(self, ifaceobj=None):
""" This method returns a list of the mac addresses
in the address-virtual attribute for the bridge. """
return False, None
def _remove_running_address_config(self, ifaceobj):
- if not self.ipcmd.link_exists(ifaceobj.name):
+ if not self.cache.link_exists(ifaceobj.name):
return
hwaddress = []
- self.ipcmd.batch_start()
+
for macvlan_prefix in [
self._get_macvlan_prefix(ifaceobj),
self.get_vrrp_prefix(ifaceobj.name, "4"),
]:
for macvlan_ifacename in glob.glob("/sys/class/net/%s*" % macvlan_prefix):
macvlan_ifacename = os.path.basename(macvlan_ifacename)
- if not self.ipcmd.link_exists(macvlan_ifacename):
+ if not self.cache.link_exists(macvlan_ifacename):
continue
- hwaddress.append(self.ipcmd.link_get_hwaddress(macvlan_ifacename))
- self.ipcmd.link_delete(os.path.basename(macvlan_ifacename))
+ hwaddress.append(self.cache.get_link_address(macvlan_ifacename))
+ self.netlink.link_del(os.path.basename(macvlan_ifacename))
# XXX: Also delete any fdb addresses. This requires, checking mac address
# on individual macvlan interfaces and deleting the vlan from that.
- self.ipcmd.batch_commit()
+
if any(hwaddress):
self._remove_addresses_from_bridge(ifaceobj, hwaddress)
self._remove_running_address_config(ifaceobj)
return
- if not self.ipcmd.link_exists(ifaceobj.name):
+ if not self.cache.link_exists(ifaceobj.name):
return
hwaddress = []
- self.ipcmd.batch_start()
av_idx = 0
macvlan_prefix = self._get_macvlan_prefix(ifaceobj)
for av in address_virtual_list:
av_attrs = av.split()
- if len(av_attrs) < 2:
- self.log_error("%s: incorrect address-virtual attrs '%s'"
- %(ifaceobj.name, av), ifaceobj,
- raise_error=False)
- av_idx += 1
- continue
# Delete the macvlan device on this device
macvlan_ifacename = '%s%d' %(macvlan_prefix, av_idx)
- self.ipcmd.link_delete(os.path.basename(macvlan_ifacename))
+ self.netlink.link_del(os.path.basename(macvlan_ifacename))
if av_attrs[0] != 'None':
hwaddress.append(av_attrs[0])
av_idx += 1
- self.ipcmd.batch_commit()
self._remove_addresses_from_bridge(ifaceobj, hwaddress)
def check_mac_address(self, ifaceobj, mac):
if not ifaceobj_getfunc:
return
if ((ifaceobj.link_kind & ifaceLinkKind.VRF) and
- self.ipcmd.link_exists(ifaceobj.name)):
+ self.cache.link_exists(ifaceobj.name)):
# if I am a vrf device and I have slaves
# that have address virtual config,
# enslave the slaves 'address virtual
# interfaces (macvlans)' to myself:
- running_slaves = self.ipcmd.link_get_lowers(ifaceobj.name)
+ running_slaves = self.sysfs.link_get_lowers(ifaceobj.name)
if running_slaves:
# pick up any existing slaves of a vrf device and
# look for their upperdevices and enslave them to the
(sobjs[0].link_privflags & ifaceLinkPrivFlags.ADDRESS_VIRTUAL_SLAVE)):
# enslave all its upper devices to
# the vrf device
- upperdevs = self.ipcmd.link_get_uppers(sobjs[0].name)
+ upperdevs = self.sysfs.link_get_uppers(sobjs[0].name)
if not upperdevs:
continue
for u in upperdevs:
# upper device list
if u == ifaceobj.name:
continue
- self.ipcmd.link_set(u, 'master', ifaceobj.name,
- state='up')
+ self.netlink.link_set_master(u, ifaceobj.name)
+ self.netlink.link_up(u)
elif ((ifaceobj.link_privflags & ifaceLinkPrivFlags.ADDRESS_VIRTUAL_SLAVE) and
(ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE) and
- self.ipcmd.link_exists(ifaceobj.name)):
+ self.cache.link_exists(ifaceobj.name)):
# If I am a vrf slave and I have 'address virtual'
# config, make sure my addrress virtual interfaces
# (macvlans) are also enslaved to the vrf device
vrfname = ifaceobj.get_attr_value_first('vrf')
- if not vrfname or not self.ipcmd.link_exists(vrfname):
+ if not vrfname or not self.cache.link_exists(vrfname):
return
- running_uppers = self.ipcmd.link_get_uppers(ifaceobj.name)
+ running_uppers = self.sysfs.link_get_uppers(ifaceobj.name)
if not running_uppers:
return
macvlan_prefix = self._get_macvlan_prefix(ifaceobj)
if u == vrfname:
continue
if u.startswith(macvlan_prefix):
- self.ipcmd.link_set(u, 'master', vrfname,
- state='up')
+ self.netlink.link_set_master(u, vrfname)
+ self.netlink.link_up(u)
def create_macvlan_and_apply_config(self, ifaceobj, intf_config_list, vrrp=False):
+
"""
intf_config_list = [
{
},
]
"""
+ hw_address_list = []
+
+ if not intf_config_list:
+ return hw_address_list
+
user_configured_ipv6_addrgenmode, ipv6_addrgen_user_value = self.get_addressvirtual_ipv6_addrgen_user_conf(ifaceobj)
purge_existing = False if ifupdownflags.flags.PERFMODE else True
- hw_address_list = []
ifname = ifaceobj.name
- lower_iface_mtu = update_mtu = None
+ update_mtu = lower_iface_mtu = lower_iface_mtu_str = None
if ifupdownconfig.config.get("adjust_logical_dev_mtu", "1") != "0":
if ifaceobj.lowerifaces and intf_config_list:
update_mtu = True
- self.ipcmd.batch_start()
+ if update_mtu:
+ lower_iface_mtu = self.cache.get_link_mtu(ifaceobj.name)
+ lower_iface_mtu_str = str(lower_iface_mtu)
+
+ self.iproute2.batch_start() # TODO: make sure we only do 1 ip link set down and set up (only one flap in the batch)
for intf_config_dict in intf_config_list:
link_created = False
macvlan_mode = intf_config_dict.get("mode")
ips = intf_config_dict.get("ips")
- if not self.ipcmd.link_exists(macvlan_ifname):
- self.ipcmd.link_add_macvlan(ifname, macvlan_ifname, macvlan_mode)
+ if not self.cache.link_exists(macvlan_ifname):
+ # When creating VRRP macvlan with bridge mode, the kernel
+ # return an error: 'Invalid argument' (22)
+ # so for now we should only use the iproute2 API.
+ # try:
+ # self.netlink.link_add_macvlan(ifname, macvlan_ifname)
+ # except:
+ self.iproute2.link_add_macvlan(ifname, macvlan_ifname, macvlan_mode)
link_created = True
# first thing we need to handle vrf enslavement
if ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE:
- self._handle_vrf_slaves(macvlan_ifname, ifaceobj)
+ vrf_ifname = self.cache.get_master(ifaceobj.name)
+ if vrf_ifname:
+ self.iproute2.link_set_master(macvlan_ifname, vrf_ifname)
# if we are dealing with a VRRP macvlan we need to set addrgenmode
# to RANDOM, and protodown on
if vrrp:
try:
- self.ipcmd.ipv6_addrgen(
+ self.iproute2.link_set_ipv6_addrgen(
macvlan_ifname,
Link.IN6_ADDR_GEN_MODE_RANDOM,
link_created
"operation not supported: %s" % (ifname, macvlan_ifname, macvlan_ifname, str(e)))
try:
if link_created:
- netlink.link_set_protodown(macvlan_ifname, "on")
+ self.netlink.link_set_protodown_on(macvlan_ifname)
except Exception as e:
self.logger.warning("%s: %s: ip link set dev %s protodown on: operation not supported: %s" % (ifname, macvlan_ifname, macvlan_ifname, str(e)))
elif user_configured_ipv6_addrgenmode:
- self.ipcmd.ipv6_addrgen(macvlan_ifname, ipv6_addrgen_user_value, link_created)
+ self.iproute2.link_set_ipv6_addrgen(macvlan_ifname, ipv6_addrgen_user_value, link_created)
if macvlan_hwaddr:
- self.ipcmd.link_set_hwaddress(macvlan_ifname, macvlan_hwaddr, keep_down=ifaceobj.link_privflags & ifaceLinkPrivFlags.KEEP_LINK_DOWN)
+ self.iproute2.link_set_address_and_keep_down(
+ macvlan_ifname,
+ macvlan_hwaddr,
+ keep_down=ifaceobj.link_privflags & ifaceLinkPrivFlags.KEEP_LINK_DOWN
+ )
hw_address_list.append(macvlan_hwaddr)
- if self.addressvirtual_with_route_metric and self.ipcmd.addr_metric_support():
- metric = self.ipcmd.get_default_ip_metric()
+ if self.addressvirtual_with_route_metric and self.addr_metric_support():
+ metric = self.get_default_ip_metric()
else:
metric = None
- self.ipcmd.addr_add_multiple(
+ self.iproute2.add_addresses(
ifaceobj,
macvlan_ifname,
ips,
if ifaceobj.link_privflags & ifaceLinkPrivFlags.KEEP_LINK_DOWN:
self.logger.info("%s: keeping macvlan down - link-down yes on lower device %s" % (macvlan_ifname, ifname))
- netlink.link_set_updown(macvlan_ifname, "down")
+ self.netlink.link_down(macvlan_ifname)
# If link existed before, flap the link
if not link_created:
- if not self.addressvirtual_with_route_metric or not self.ipcmd.addr_metric_support():
+ if not self.addressvirtual_with_route_metric or not self.addr_metric_support():
# if the system doesn't support ip addr set METRIC
# we need to do manually check the ordering of the ip4 routes
self._fix_connected_route(ifaceobj, macvlan_ifname, ips[0])
if update_mtu:
- lower_iface_mtu = self.ipcmd.link_get_mtu(ifname, refresh=True)
update_mtu = False
- if lower_iface_mtu and lower_iface_mtu != self.ipcmd.link_get_mtu(macvlan_ifname, refresh=True):
try:
- self.ipcmd.link_set_mtu(macvlan_ifname,
- lower_iface_mtu)
+ self.sysfs.link_set_mtu(macvlan_ifname, mtu_str=lower_iface_mtu_str, mtu_int=lower_iface_mtu)
except Exception as e:
- self.logger.info('%s: failed to set mtu %s: %s' %
- (macvlan_ifname, lower_iface_mtu, e))
+ self.logger.info('%s: failed to set mtu %s: %s' % (macvlan_ifname, lower_iface_mtu, e))
# set macvlan device to up in anycase.
# since we auto create them here..we are responsible
# to bring them up here in the case they were brought down
# by some other entity in the system.
if not ifaceobj.link_privflags & ifaceLinkPrivFlags.KEEP_LINK_DOWN:
- netlink.link_set_updown(macvlan_ifname, "up")
+ self.netlink.link_up(macvlan_ifname)
else:
try:
- if not self.addressvirtual_with_route_metric or not self.ipcmd.addr_metric_support():
+ if not self.addressvirtual_with_route_metric or not self.addr_metric_support():
# if the system doesn't support ip addr set METRIC
# we need to do manually check the ordering of the ip6 routes
- self.ipcmd.fix_ipv6_route_metric(ifaceobj, macvlan_ifname, ips)
+ self.iproute2.fix_ipv6_route_metric(ifaceobj, macvlan_ifname, ips)
except Exception as e:
self.logger.debug('fix_vrf_slave_ipv6_route_metric: failed: %s' % e)
# Disable IPv6 duplicate address detection on VRR interfaces
+ sysctl_prefix = "net.ipv6.conf.%s" % macvlan_ifname
+
+ try:
+ syskey = "%s.%s" % (sysctl_prefix, "enhanced_dad")
+ if self.sysctl_get(syskey) != "0":
+ self.sysctl_set(syskey, "0")
+ except Exception as e:
+ self.logger.info("sysctl failure: operation not supported: %s" % str(e))
+
for key, sysval in {
"accept_dad": "0",
"dad_transmits": "0"
}.iteritems():
- syskey = "net.ipv6.conf.%s.%s" % (macvlan_ifname, key)
+ syskey = "%s.%s" % (sysctl_prefix, key)
if self.sysctl_get(syskey) != sysval:
self.sysctl_set(syskey, sysval)
- self.ipcmd.batch_commit()
+ self.iproute2.batch_commit()
return hw_address_list
def _up(self, ifaceobj, ifaceobj_getfunc=None):
"with no upper interfaces or parent interfaces)"
% ifaceobj.name, ifaceobj)
- if not self.ipcmd.link_exists(ifaceobj.name):
+ if not self.cache.link_exists(ifaceobj.name):
return
addr_virtual_macs = self.create_macvlan_and_apply_config(
if ip4 or ifquery:
merged_with_existing_obj = False
macvlan_ip4_mac = "00:00:5e:00:01:%s" % hex_id
- macvlan_ip4_mac_int = self.ipcmd.mac_str_to_int(macvlan_ip4_mac)
+ macvlan_ip4_mac_int = utils.mac_str_to_int(macvlan_ip4_mac)
# if the vrr config is defined in different lines for the same ID
# we need to save the ip4 and ip6 in the objects we previously
# created, example:
elif not ip4 and not ifquery:
# special check to see if all ipv4 were removed from the vrrp
# configuration, if so we need to remove the associated macvlan
- if self.ipcmd.link_exists(macvlan_ip4_ifname):
- netlink.link_del(macvlan_ip4_ifname)
+ if self.cache.link_exists(macvlan_ip4_ifname):
+ self.netlink.link_del(macvlan_ip4_ifname)
if ip6 or ifquery:
merged_with_existing_obj = False
macvlan_ip6_mac = "00:00:5e:00:02:%s" % hex_id
- macvlan_ip6_mac_int = self.ipcmd.mac_str_to_int(macvlan_ip6_mac)
+ macvlan_ip6_mac_int = utils.mac_str_to_int(macvlan_ip6_mac)
# if the vrr config is defined in different lines for the same ID
# we need to save the ip4 and ip6 in the objects we previously
# created, example:
elif not ip6 and not ifquery:
# special check to see if all ipv6 were removed from the vrrp
# configuration, if so we need to remove the associated macvlan
- if self.ipcmd.link_exists(macvlan_ip6_ifname):
- netlink.link_del(macvlan_ip6_ifname)
+ if self.cache.link_exists(macvlan_ip6_ifname):
+ self.netlink.link_del(macvlan_ip6_ifname)
if not ifquery:
# check if vrrp attribute was removed/re-assigned
macvlan_ip4_ifname = "%s%s" % (self.get_vrrp_prefix(ifname, "4"), id_to_remove)
macvlan_ip6_ifname = "%s%s" % (self.get_vrrp_prefix(ifname, "6"), id_to_remove)
- if self.ipcmd.link_exists(macvlan_ip4_ifname):
- netlink.link_del(macvlan_ip4_ifname)
+ if self.cache.link_exists(macvlan_ip4_ifname):
+ self.netlink.link_del(macvlan_ip4_ifname)
- if self.ipcmd.link_exists(macvlan_ip6_ifname):
- netlink.link_del(macvlan_ip6_ifname)
+ if self.cache.link_exists(macvlan_ip6_ifname):
+ self.netlink.link_del(macvlan_ip6_ifname)
except Exception as e:
self.logger.debug("%s: vrrp: failure while removing unused macvlan(s)" % ifname)
for index, addr_virtual in enumerate(address_virtual_list):
av_attrs = addr_virtual.split()
-
- if len(av_attrs) < 2:
- self.log_error("%s: incorrect address-virtual attrs '%s'"
- % (ifaceobj.name, addr_virtual), ifaceobj,
- raise_error=False)
- continue
-
mac = av_attrs[0]
if mac:
mac = mac.lower()
if mac != "none":
config["hwaddress"] = mac
- config["hwaddress_int"] = self.ipcmd.mac_str_to_int(mac)
+ config["hwaddress_int"] = utils.mac_str_to_int(mac)
ip_network_obj_list = []
for ip in av_attrs[1:]:
return user_config_list
- def process_macvlans_config(self, ifaceobj, attr_name, virtual_addr_list_raw, macvlan_config_list):
- return self.create_macvlan_and_apply_config(ifaceobj, macvlan_config_list)
-
def _down(self, ifaceobj, ifaceobj_getfunc=None):
try:
self._remove_address_config(ifaceobj,
#### VRR
hwaddress = []
- self.ipcmd.batch_start()
for vrr_prefix in [self.get_vrrp_prefix(ifaceobj.name, "4"), self.get_vrrp_prefix(ifaceobj.name, "6")]:
for macvlan_ifacename in glob.glob("/sys/class/net/%s*" % vrr_prefix):
macvlan_ifacename = os.path.basename(macvlan_ifacename)
- if not self.ipcmd.link_exists(macvlan_ifacename):
+ if not self.cache.link_exists(macvlan_ifacename):
continue
- hwaddress.append(self.ipcmd.link_get_hwaddress(macvlan_ifacename))
- self.ipcmd.link_delete(os.path.basename(macvlan_ifacename))
+ hwaddress.append(self.cache.get_link_address(macvlan_ifacename))
+ self.netlink.link_del(macvlan_ifacename)
# XXX: Also delete any fdb addresses. This requires, checking mac address
# on individual macvlan interfaces and deleting the vlan from that.
- self.ipcmd.batch_commit()
if any(hwaddress):
self._remove_addresses_from_bridge(ifaceobj, hwaddress)
except Exception, e:
def _query_check(self, ifaceobj, ifaceobjcurr):
- if not self.ipcmd.link_exists(ifaceobj.name):
+ if not self.cache.link_exists(ifaceobj.name):
return
user_config_address_virtual_ipv6_addr = ifaceobj.get_attr_value_first('address-virtual-ipv6-addrgen')
return
ifaceobjcurr.update_config_with_status('address-virtual-ipv6-addrgen', user_config_address_virtual_ipv6_addr, 0)
+ @staticmethod
+ def compare_user_config_vs_running_state(running_addrs, user_addrs):
+ ip4 = []
+ ip6 = []
+
+ for ip in user_addrs or []:
+ obj = IPNetwork(ip)
+
+ if type(obj) == IPv6Network:
+ ip6.append(obj)
+ else:
+ ip4.append(obj)
+
+ running_ipobj = []
+ for ip in running_addrs or []:
+ running_ipobj.append(IPNetwork(ip))
+
+ return running_ipobj == (ip4 + ip6)
+
def query_check_macvlan_config(self, ifaceobj, ifaceobjcurr, attr_name, user_config_address_virtual_ipv6_addr, virtual_addr_list_raw, macvlan_config_list):
"""
macvlan_config_list = [
macvlan_ifacename = config.get("ifname")
- if not self.ipcmd.link_exists(macvlan_ifacename):
+ if not self.cache.link_exists(macvlan_ifacename):
ifaceobjcurr.update_config_with_status(attr_name, "", 1)
continue
macvlan_hwaddress_int = config.get("hwaddress_int")
if user_config_address_virtual_ipv6_addr:
- macvlans_running_ipv6_addr.append(self.ipcmd.get_ipv6_addrgen_mode(macvlan_ifacename))
+ macvlans_running_ipv6_addr.append(self.cache.get_link_ipv6_addrgen_mode(macvlan_ifacename))
# Check mac and ip address
- rhwaddress = ip4_macvlan_hwaddress = self.ipcmd.link_get_hwaddress(macvlan_ifacename)
- raddrs = ip4_running_addrs = self.ipcmd.get_running_addrs(
+ rhwaddress = ip4_macvlan_hwaddress = self.cache.get_link_address(macvlan_ifacename)
+ raddrs = ip4_running_addrs =[str(ip) for ip in self.cache.get_ifupdown2_addresses_list(
ifname=macvlan_ifacename,
- details=False,
- addr_virtual_ifaceobj=ifaceobj
- )
+ ifaceobj_list=[ifaceobj],
+ with_address_virtual=True
+ )]
if not is_vrr:
ips = config.get("ips")
- if not raddrs or not rhwaddress:
+ if not rhwaddress:
ifaceobjcurr.update_config_with_status(attr_name, "", 1)
continue
try:
- if self.ipcmd.mac_str_to_int(rhwaddress) == macvlan_hwaddress_int \
- and self.ipcmd.compare_user_config_vs_running_state(raddrs, ips) \
+ if utils.mac_str_to_int(rhwaddress) == macvlan_hwaddress_int \
+ and self.compare_user_config_vs_running_state(raddrs, ips) \
and self._check_addresses_in_bridge(ifaceobj, macvlan_hwaddress):
ifaceobjcurr.update_config_with_status(
attr_name,
ip6_macvlan_hwaddress = ip6_config.get("hwaddress")
# check macvlan ip6 hwaddress (only if ip6 were provided by the user)
- if not ip6_config.get("ips") or self.ipcmd.link_get_hwaddress(ip6_macvlan_ifname) == ip6_macvlan_hwaddress:
+ if not ip6_config.get("ips") or self.cache.get_link_address_raw(ip6_macvlan_ifname) == ip6_config.get("hwaddress_int"):
# check all ip4
- if self.ipcmd.compare_user_config_vs_running_state(
+ if self.compare_user_config_vs_running_state(
ip4_running_addrs,
ip4_config.get("ips")
) and self._check_addresses_in_bridge(ifaceobj, ip4_macvlan_hwaddress):
- ip6_running_addrs = self.ipcmd.get_running_addrs(
+ ip6_running_addrs = [str(ip) for ip in self.cache.get_ifupdown2_addresses_list(
ifname=ip6_macvlan_ifname,
details=False,
- addr_virtual_ifaceobj=ifaceobj
- )
+ ifaceobj_list=[ifaceobj],
+ with_address_virtual=True
+ )]
# check all ip6
- if self.ipcmd.compare_user_config_vs_running_state(
+ if self.compare_user_config_vs_running_state(
ip6_running_addrs,
ip6_config.get("ips")
- ) and self._check_addresses_in_bridge(ifaceobj, ip4_macvlan_hwaddress):
+ ) and self._check_addresses_in_bridge(ifaceobj, ip6_macvlan_hwaddress):
ifaceobjcurr.update_config_with_status(
attr_name,
"%s %s" % (ip4_config.get("id"), " ".join(ip4_config.get("ips") + ip6_config.get("ips"))),
def _query_running(self, ifaceobjrunning, ifaceobj_getfunc=None):
macvlan_prefix = self._get_macvlan_prefix(ifaceobjrunning)
- address_virtuals = []
- for av in linkCache.links:
- if av.startswith(macvlan_prefix):
- address_virtuals.append(av)
-
+ address_virtuals = glob.glob("/sys/class/net/%s*" %macvlan_prefix)
macvlans_ipv6_addrgen_list = []
for av in address_virtuals:
macvlan_ifacename = os.path.basename(av)
- rhwaddress = self.ipcmd.link_get_hwaddress(macvlan_ifacename)
-
- raddress = []
- for obj in ifaceobj_getfunc(ifaceobjrunning.name) or []:
- raddress.extend(self.ipcmd.get_running_addrs(None, macvlan_ifacename, addr_virtual_ifaceobj=obj) or [])
+ rhwaddress = self.cache.get_link_address(macvlan_ifacename)
+ raddress = [str(ip) for ip in self.cache.get_ifupdown2_addresses_list(
+ ifaceobj_list=ifaceobj_getfunc(ifaceobjrunning.name) or [],
+ ifname=ifaceobjrunning.name,
+ with_address_virtual=True
+ )]
raddress = list(set(raddress))
ifaceobjrunning.update_config('address-virtual',
'%s %s' %(rhwaddress, ' '.join(raddress)))
- macvlans_ipv6_addrgen_list.append((macvlan_ifacename, self.ipcmd.get_ipv6_addrgen_mode(macvlan_ifacename)))
+ macvlans_ipv6_addrgen_list.append((macvlan_ifacename, self.cache.get_link_ipv6_addrgen_mode(macvlan_ifacename)))
macvlan_count = len(address_virtuals)
if not macvlan_count:
return
ifaceobjrunning.update_config('address-virtual-ipv6-addrgen', 'off' if ipv6_addrgen else 'on')
-
- _run_ops = {'up' : _up,
- 'down' : _down,
- 'query-checkcurr' : _query_check,
- 'query-running' : _query_running}
+ _run_ops = {
+ 'up': _up,
+ 'down': _down,
+ 'query-checkcurr': _query_check,
+ 'query-running': _query_running
+ }
def get_ops(self):
""" returns list of ops supported by this module """
return self._run_ops.keys()
- def _init_command_handlers(self):
- if not self.ipcmd:
- self.ipcmd = LinkUtils()
def run(self, ifaceobj, operation, query_ifaceobj=None,
ifaceobj_getfunc=None, **extra_args):
op_handler = self._run_ops.get(operation)
if not op_handler:
return
- self._init_command_handlers()
+
if operation == 'query-checkcurr':
op_handler(self, ifaceobj, query_ifaceobj)
else:
#
try:
+ from ifupdown2.lib.addon import Addon
+
from ifupdown2.ifupdown.iface import *
from ifupdown2.ifupdown.utils import utils
from ifupdown2.ifupdownaddons.modulebase import moduleBase
- from ifupdown2.ifupdownaddons.LinkUtils import LinkUtils
- from ifupdown2.ifupdown.netlink import netlink
from ifupdown2.ifupdown.exceptions import moduleNotSupported
import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
except:
+ from lib.addon import Addon
+
from ifupdown.iface import *
from ifupdown.utils import utils
from ifupdownaddons.modulebase import moduleBase
- from ifupdownaddons.LinkUtils import LinkUtils
- from ifupdown.netlink import netlink
from ifupdown.exceptions import moduleNotSupported
import ifupdown.ifupdownflags as ifupdownflags
import subprocess
import os
-class batman_adv (moduleBase):
+
+class batman_adv(Addon, moduleBase):
""" ifupdown2 addon module to configure B.A.T.M.A.N. advanced interfaces """
_modinfo = {
- 'mhelp' : 'batman_adv module configures B.A.T.M.A.N. advanced interfaces.' +
- 'Every B.A.T.M.A.N. advanced interface needs at least on ethernet ' +
- 'interface to be creatable. You can specify a space separated list' +
- 'of interfaces by using the "batma-ifaces" paramater. If this parameter' +
- 'is set for an interfaces this module will do the magic.',
-
- 'attrs' : {
- 'batman-ifaces' : {
- 'help' : 'Interfaces to be part of this B.A.T.M.A.N. advanced instance',
- 'validvals' : [ '<interface-list>' ],
- 'required' : True,
+ 'mhelp': 'batman_adv module configures B.A.T.M.A.N. advanced interfaces.' +
+ 'Every B.A.T.M.A.N. advanced interface needs at least on ethernet ' +
+ 'interface to be creatable. You can specify a space separated list' +
+ 'of interfaces by using the "batma-ifaces" paramater. If this parameter' +
+ 'is set for an interfaces this module will do the magic.',
+ 'attrs': {
+ 'batman-ifaces': {
+ 'help': 'Interfaces to be part of this B.A.T.M.A.N. advanced instance',
+ 'validvals': ['<interface-list>'],
+ 'required': True,
},
-
- 'batman-ifaces-ignore-regex' : {
- 'help' : 'Interfaces to ignore when verifying configuration (regexp)',
- 'required' : False,
+ 'batman-ifaces-ignore-regex': {
+ 'help': 'Interfaces to ignore when verifying configuration (regexp)',
+ 'required': False,
},
-
- 'batman-distributed-arp-table' : {
- 'help' : 'B.A.T.M.A.N. distributed ARP table',
- 'validvals' : [ 'enabled', 'disabled' ],
- 'required' : False,
- 'batman-attr' : True,
+ 'batman-distributed-arp-table': {
+ 'help': 'B.A.T.M.A.N. distributed ARP table',
+ 'validvals': ['enabled', 'disabled'],
+ 'required': False,
+ 'batman-attr': True,
},
-
- 'batman-gw-mode' : {
- 'help' : 'B.A.T.M.A.N. gateway mode',
- 'validvals' : [ 'off', 'client', 'server' ],
- 'required' : False,
- 'example' : [ 'batman-gw-mode client' ],
- 'batman-attr' : True,
+ 'batman-gw-mode': {
+ 'help': 'B.A.T.M.A.N. gateway mode',
+ 'validvals': ['off', 'client', 'server'],
+ 'required': False,
+ 'example': ['batman-gw-mode client'],
+ 'batman-attr': True,
},
-
- 'batman-hop-penalty' : {
- 'help' : 'B.A.T.M.A.N. hop penalty',
- 'validvals' : [ '<number>' ],
- 'required' : False,
- 'batman-attr' : True,
+ 'batman-hop-penalty': {
+ 'help': 'B.A.T.M.A.N. hop penalty',
+ 'validvals': ['<number>'],
+ 'required': False,
+ 'batman-attr': True,
},
-
- 'batman-multicast-mode' : {
- 'help' : 'B.A.T.M.A.N. multicast mode',
- 'validvals' : [ 'enabled', 'disabled' ],
- 'required' : False,
- 'batman-attr' : True,
+ 'batman-multicast-mode': {
+ 'help': 'B.A.T.M.A.N. multicast mode',
+ 'validvals': ['enabled', 'disabled'],
+ 'required': False,
+ 'batman-attr': True,
},
-
- 'batman-routing-algo' : {
- 'help' : 'B.A.T.M.A.N. routing algo',
- 'validvals' : [ 'BATMAN_IV', 'BATMAN_V' ],
- 'required' : False,
- 'batman-attr' : False,
+ 'batman-routing-algo': {
+ 'help': 'B.A.T.M.A.N. routing algo',
+ 'validvals': ['BATMAN_IV', 'BATMAN_V'],
+ 'required': False,
+ 'batman-attr': False,
},
}
}
_batman_attrs = {
}
-
def __init__ (self, *args, **kargs):
+ Addon.__init__(self)
moduleBase.__init__ (self, *args, **kargs)
if not os.path.exists('/usr/sbin/batctl'):
raise moduleNotSupported('module init failed: no /usr/sbin/batctl found')
- self.ipcmd = None
for longname, entry in self._modinfo['attrs'].items ():
if entry.get ('batman-attr', False) == False:
'filename' : attr.replace ("-", "_"),
}
-
def _is_batman_device (self, ifaceobj):
if ifaceobj.get_attr_value_first ('batman-ifaces'):
return True
return False
-
def _get_batman_ifaces (self, ifaceobj ):
batman_ifaces = ifaceobj.get_attr_value_first ('batman-ifaces')
if batman_ifaces:
return sorted (batman_ifaces.split ())
return None
-
def _get_batman_ifaces_ignore_regex (self, ifaceobj):
ifaces_ignore_regex = ifaceobj.get_attr_value_first ('batman-ifaces-ignore-regex')
if ifaces_ignore_regex:
return re.compile (r"%s" % ifaces_ignore_regex)
return None
-
def _get_batman_attr (self, ifaceobj, attr):
if attr not in self._batman_attrs:
raise ValueError ("_get_batman_attr: Invalid or unsupported B.A.T.M.A.N. adv. attribute: %s" % attr)
return None
-
def _read_current_batman_attr (self, ifaceobj, attr, dont_map = False):
# 'routing_algo' needs special handling, D'oh.
if dont_map:
except ValueError:
raise Exception ("_read_current_batman_attr: Integer value expected, got: %s" % value)
-
def _set_batman_attr (self, ifaceobj, attr, value):
if attr not in self._batman_attrs:
raise ValueError ("_set_batman_attr: Invalid or unsupported B.A.T.M.A.N. adv. attribute: %s" % attr)
except IOError as i:
raise Exception ("_set_batman_attr (%s): %s" % (attr, i))
-
def _batctl_if (self, bat_iface, mesh_iface, op):
if op not in [ 'add', 'del' ]:
raise Exception ("_batctl_if() called with invalid \"op\" value: %s" % op)
except Exception as e:
raise Exception ("_set_routing_algo: %s" % e)
-
def _find_member_ifaces (self, ifaceobj, ignore = True):
members = []
iface_ignore_re = self._get_batman_ifaces_ignore_regex (ifaceobj)
return sorted (members)
-
def get_dependent_ifacenames (self, ifaceobj, ifaceobjs_all=None):
if not self._is_batman_device (ifaceobj):
return None
return [None]
-
def _up (self, ifaceobj):
if self._get_batman_ifaces (ifaceobj) == None:
raise Exception ('could not determine batman interfacaes')
# Verify existance of batman interfaces (should be present already)
batman_ifaces = []
for iface in self._get_batman_ifaces (ifaceobj):
- if not self.ipcmd.link_exists (iface):
+ if not self.cache.link_exists (iface):
self.logger.warn ('batman iface %s not present' % iface)
continue
if routing_algo:
self._set_routing_algo (routing_algo)
-
if_ignore_re = self._get_batman_ifaces_ignore_regex (ifaceobj)
# Is the batman main interface already present?
- if self.ipcmd.link_exists (ifaceobj.name):
+ if self.cache.link_exists (ifaceobj.name):
# Verify which member interfaces are present
members = self._find_member_ifaces (ifaceobj)
for iface in members:
netlink.link_set_updown(ifaceobj.name, "up")
-
def _down (self, ifaceobj):
- if not ifupdownflags.flags.PERFMODE and not self.ipcmd.link_exists (ifaceobj.name):
+ if not ifupdownflags.flags.PERFMODE and not self.cache.link_exists (ifaceobj.name):
return
members = self._find_member_ifaces (ifaceobj)
def _query_check (self, ifaceobj, ifaceobjcurr):
- if not self.ipcmd.link_exists (ifaceobj.name):
+ if not self.cache.link_exists (ifaceobj.name):
return
batman_ifaces_cfg = self._get_batman_ifaces (ifaceobj)
ifaceobjcurr.update_config_with_status ('batman-routing-algo', value_curr, value_ok)
-
- def _query_running (self, ifaceobjrunning):
- if not self.ipcmd.link_exists (ifaceobjrunning.name):
- return
-
- # XXX Now what?
-
-
- _run_ops = {'pre-up' : _up,
- 'post-down' : _down,
- 'query-checkcurr' : _query_check}
-# XXX 'query-running' : _query_running}
-
+ _run_ops = {
+ 'pre-up': _up,
+ 'post-down': _down,
+ 'query-checkcurr': _query_check
+ }
def get_ops (self):
""" returns list of ops supported by this module """
return self._run_ops.keys ()
-
- def _init_command_handlers (self):
- if not self.ipcmd:
- self.ipcmd = LinkUtils()
-
-
def run (self, ifaceobj, operation, query_ifaceobj = None, **extra_args):
""" run B.A.T.M.A.N. configuration on the interface object passed as argument
if (operation != 'query-running' and not self._is_batman_device (ifaceobj)):
return
- self._init_command_handlers ()
-
if operation == 'query-checkcurr':
op_handler (self, ifaceobj, query_ifaceobj)
else:
from sets import Set
try:
+ from ifupdown2.lib.addon import Addon
from ifupdown2.nlmanager.nlmanager import Link
from ifupdown2.ifupdown.iface import *
from ifupdown2.ifupdown.utils import utils
- from ifupdown2.ifupdown.netlink import netlink
from ifupdown2.ifupdown.statemanager import statemanager_api as statemanager
import ifupdown2.ifupdown.policymanager as policymanager
import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
- from ifupdown2.ifupdownaddons.LinkUtils import LinkUtils
from ifupdown2.ifupdownaddons.modulebase import moduleBase
except ImportError:
+ from lib.addon import Addon
from nlmanager.nlmanager import Link
from ifupdown.iface import *
from ifupdown.utils import utils
- from ifupdown.netlink import netlink
from ifupdown.statemanager import statemanager_api as statemanager
- from ifupdownaddons.LinkUtils import LinkUtils
from ifupdownaddons.modulebase import moduleBase
import ifupdown.policymanager as policymanager
import ifupdown.ifupdownflags as ifupdownflags
-class bond(moduleBase):
+class bond(Addon, moduleBase):
""" ifupdown2 addon module to configure bond interfaces """
overrides_ifupdown_scripts = ['ifenslave', ]
- _modinfo = { 'mhelp' : 'bond configuration module',
- 'attrs' : {
- 'bond-use-carrier':
- {'help' : 'bond use carrier',
- 'validvals' : ['yes', 'no', '0', '1'],
- 'default' : 'yes',
- 'example': ['bond-use-carrier yes']},
- 'bond-num-grat-arp':
- {'help' : 'bond use carrier',
- 'validrange' : ['0', '255'],
- 'default' : '1',
- 'example' : ['bond-num-grat-arp 1']},
- 'bond-num-unsol-na' :
- {'help' : 'bond slave devices',
- 'validrange' : ['0', '255'],
- 'default' : '1',
- 'example' : ['bond-num-unsol-na 1']},
- 'bond-xmit-hash-policy' :
- {'help' : 'bond slave devices',
- 'validvals' : ['0', 'layer2',
- '1', 'layer3+4',
- '2', 'layer2+3',
- '3', 'encap2+3',
- '4', 'encap3+4'],
- 'default' : 'layer2',
- 'example' : ['bond-xmit-hash-policy layer2']},
- 'bond-miimon' :
- {'help' : 'bond miimon',
- 'validrange' : ['0', '255'],
- 'default' : '0',
- 'example' : ['bond-miimon 0']},
- 'bond-mode' :
- {'help': 'bond mode',
- 'validvals': ['0', 'balance-rr',
- '1', 'active-backup',
- '2', 'balance-xor',
- '3', 'broadcast',
- '4', '802.3ad',
- '5', 'balance-tlb',
- '6', 'balance-alb'],
- 'default': 'balance-rr',
- 'example': ['bond-mode 802.3ad']},
- 'bond-lacp-rate':
- {'help' : 'bond lacp rate',
- 'validvals' : ['0', 'slow', '1', 'fast'],
- 'default' : '0',
- 'example' : ['bond-lacp-rate 0']},
- 'bond-min-links':
- {'help' : 'bond min links',
- 'default' : '0',
- 'validrange' : ['0', '255'],
- 'example' : ['bond-min-links 0']},
- 'bond-ad-sys-priority':
- {'help' : '802.3ad system priority',
- 'default' : '65535',
- 'validrange' : ['0', '65535'],
- 'example' : ['bond-ad-sys-priority 65535'],
- 'deprecated' : True,
- 'new-attribute' : 'bond-ad-actor-sys-prio'},
- 'bond-ad-actor-sys-prio':
- {'help' : '802.3ad system priority',
- 'default' : '65535',
- 'validrange' : ['0', '65535'],
- 'example' : ['bond-ad-actor-sys-prio 65535']},
- 'bond-ad-sys-mac-addr':
- {'help' : '802.3ad system mac address',
- 'validvals': ['<mac>', ],
- 'example' : ['bond-ad-sys-mac-addr 00:00:00:00:00:00'],
- 'deprecated' : True,
- 'new-attribute' : 'bond-ad-actor-system'},
- 'bond-ad-actor-system':
- {'help' : '802.3ad system mac address',
- 'validvals': ['<mac>', ],
- 'example' : ['bond-ad-actor-system 00:00:00:00:00:00'],},
- 'bond-lacp-bypass-allow':
- {'help' : 'allow lacp bypass',
- 'validvals' : ['yes', 'no', '0', '1'],
- 'default' : 'no',
- 'example' : ['bond-lacp-bypass-allow no']},
- 'bond-slaves' :
- {'help' : 'bond slaves',
- 'required' : True,
- 'multivalue' : True,
- 'validvals': ['<interface-list>'],
- 'example' : ['bond-slaves swp1 swp2',
- 'bond-slaves glob swp1-2',
- 'bond-slaves regex (swp[1|2)'],
- 'aliases': ['bond-ports']},
- 'bond-updelay' :
- {'help' : 'bond updelay',
- 'default' : '0',
- 'validrange' : ['0', '65535'],
- 'example' : ['bond-updelay 100']},
- 'bond-downdelay':
- {'help' : 'bond downdelay',
- 'default' : '0',
- 'validrange' : ['0', '65535'],
- 'example' : ['bond-downdelay 100']}
- }}
+ _modinfo = {
+ "mhelp": "bond configuration module",
+ "attrs": {
+ "bond-use-carrier": {
+ "help": "bond use carrier",
+ "validvals": ["yes", "no", "0", "1"],
+ "default": "yes",
+ "example": ["bond-use-carrier yes"]},
+ "bond-num-grat-arp": {
+ "help": "bond use carrier",
+ "validrange": ["0", "255"],
+ "default": "1",
+ "example": ["bond-num-grat-arp 1"]
+ },
+ "bond-num-unsol-na": {
+ "help": "bond slave devices",
+ "validrange": ["0", "255"],
+ "default": "1",
+ "example": ["bond-num-unsol-na 1"]
+ },
+ "bond-xmit-hash-policy": {
+ "help": "bond slave devices",
+ "validvals": [
+ "0", "layer2",
+ "1", "layer3+4",
+ "2", "layer2+3",
+ "3", "encap2+3",
+ "4", "encap3+4"
+ ],
+ "default": "layer2",
+ "example": ["bond-xmit-hash-policy layer2"]
+ },
+ "bond-miimon": {
+ "help": "bond miimon",
+ "validrange": ["0", "255"],
+ "default": "0",
+ "example": ["bond-miimon 0"]
+ },
+ "bond-mode": {
+ "help": "bond mode",
+ "validvals": [
+ "0", "balance-rr",
+ "1", "active-backup",
+ "2", "balance-xor",
+ "3", "broadcast",
+ "4", "802.3ad",
+ "5", "balance-tlb",
+ "6", "balance-alb"
+ ],
+ "default": "balance-rr",
+ "example": ["bond-mode 802.3ad"]
+ },
+ "bond-lacp-rate": {
+ "help": "bond lacp rate",
+ "validvals": ["0", "slow", "1", "fast"],
+ "default": "0",
+ "example": ["bond-lacp-rate 0"]
+ },
+ "bond-min-links": {
+ "help": "bond min links",
+ "default": "0",
+ "validrange": ["0", "255"],
+ "example": ["bond-min-links 0"]
+ },
+ "bond-ad-sys-priority": {
+ "help": "802.3ad system priority",
+ "default": "65535",
+ "validrange": ["0", "65535"],
+ "example": ["bond-ad-sys-priority 65535"],
+ "deprecated": True,
+ "new-attribute": "bond-ad-actor-sys-prio"
+ },
+ "bond-ad-actor-sys-prio": {
+ "help": "802.3ad system priority",
+ "default": "65535",
+ "validrange": ["0", "65535"],
+ "example": ["bond-ad-actor-sys-prio 65535"]
+ },
+ "bond-ad-sys-mac-addr": {
+ "help": "802.3ad system mac address",
+ "validvals": ["<mac>", ],
+ "example": ["bond-ad-sys-mac-addr 00:00:00:00:00:00"],
+ "deprecated": True,
+ "new-attribute": "bond-ad-actor-system"
+ },
+ "bond-ad-actor-system": {
+ "help": "802.3ad system mac address",
+ "validvals": ["<mac>", ],
+ "example": ["bond-ad-actor-system 00:00:00:00:00:00"],
+ },
+ "bond-lacp-bypass-allow": {
+ "help": "allow lacp bypass",
+ "validvals": ["yes", "no", "0", "1"],
+ "default": "no",
+ "example": ["bond-lacp-bypass-allow no"]
+ },
+ "bond-slaves": {
+ "help": "bond slaves",
+ "required": True,
+ "multivalue": True,
+ "validvals": ["<interface-list>"],
+ "example": [
+ "bond-slaves swp1 swp2",
+ "bond-slaves glob swp1-2",
+ "bond-slaves regex (swp[1|2)"
+ ],
+ "aliases": ["bond-ports"]
+ },
+ "bond-updelay": {
+ "help": "bond updelay",
+ "default": "0",
+ "validrange": ["0", "65535"],
+ "example": ["bond-updelay 100"]
+ },
+ "bond-downdelay": {
+ "help": "bond downdelay",
+ "default": "0",
+ "validrange": ["0", "65535"],
+ "example": ["bond-downdelay 100"]
+ },
+ "bond-primary": {
+ "help": "Control which slave interface is "
+ "preferred active member",
+ "example": ["bond-primary swp1"]
+ }
+ }
+ }
_bond_attr_netlink_map = {
'bond-mode': Link.IFLA_BOND_MODE,
'bond-ad-actor-sys-prio': Link.IFLA_BOND_AD_ACTOR_SYS_PRIO,
'bond-lacp-bypass-allow': Link.IFLA_BOND_AD_LACP_BYPASS,
'bond-updelay': Link.IFLA_BOND_UPDELAY,
- 'bond-downdelay': Link.IFLA_BOND_DOWNDELAY
+ 'bond-downdelay': Link.IFLA_BOND_DOWNDELAY,
+ 'bond-primary': Link.IFLA_BOND_PRIMARY
}
# ifquery-check attr dictionary with callable object to translate user data to netlink format
Link.IFLA_BOND_AD_ACTOR_SYS_PRIO: int,
Link.IFLA_BOND_AD_LACP_BYPASS: lambda x: int(utils.get_boolean_from_string(x)),
Link.IFLA_BOND_UPDELAY: int,
- Link.IFLA_BOND_DOWNDELAY: int
+ Link.IFLA_BOND_DOWNDELAY: int,
+ # Link.IFLA_BOND_PRIMARY: self.netlink.get_ifname is added in __init__()
}
# ifup attr list with callable object to translate user data to netlink format
('bond-lacp-rate', Link.IFLA_BOND_AD_LACP_RATE, lambda x: int(utils.get_boolean_from_string(x))),
('bond-lacp-bypass-allow', Link.IFLA_BOND_AD_LACP_BYPASS, lambda x: int(utils.get_boolean_from_string(x))),
('bond-ad-sys-mac-addr', Link.IFLA_BOND_AD_ACTOR_SYSTEM, str),
- ('bond-ad-actor-system', Link.IFLA_BOND_AD_ACTOR_SYSTEM, str),
+ ('bond-ad-actor-system', Link.IFLA_BOND_AD_ACTOR_SYSTEM, str)
+ # ('bond-primary', Link.IFLA_BOND_PRIMARY, self.cache.get_ifindex) added in __init__()
)
def __init__(self, *args, **kargs):
+ Addon.__init__(self)
moduleBase.__init__(self, *args, **kargs)
- self.ipcmd = None
- self.bondcmd = None
if not os.path.exists('/sys/class/net/bonding_masters'):
try:
except Exception as e:
self.logger.info("bond: error while loading bonding module: %s" % str(e))
+ self._bond_attr_ifquery_check_translate_func[Link.IFLA_BOND_PRIMARY] = self.cache.get_ifindex
+ self._bond_attr_set_list = self._bond_attr_set_list + (('bond-primary', Link.IFLA_BOND_PRIMARY, self.cache.get_ifindex),)
+
@staticmethod
def get_bond_slaves(ifaceobj):
slaves = ifaceobj.get_attr_value_first('bond-slaves')
def _is_bond(self, ifaceobj):
# at first link_kind is not set but once ifupdownmain
# calls get_dependent_ifacenames link_kind is set to BOND
- if ifaceobj.link_kind & ifaceLinkKind.BOND or self.get_bond_slaves(ifaceobj):
- return True
- return False
+ return ifaceobj.link_kind & ifaceLinkKind.BOND or self.get_bond_slaves(ifaceobj)
def get_dependent_ifacenames(self, ifaceobj, ifacenames_all=None):
""" Returns list of interfaces dependent on ifaceobj """
return self.syntax_check_updown_delay(ifaceobj)
def get_dependent_ifacenames_running(self, ifaceobj):
- self._init_command_handlers()
- return self.bondcmd.bond_get_slaves(ifaceobj.name)
+ return self.cache.get_slaves(ifaceobj.name)
def _get_slave_list(self, ifaceobj):
""" Returns slave list present in ifaceobj config """
If the intf was previously enslaved to a bridge it is possible ipv6 is still disabled.
"""
try:
- if os.path.exists("/sys/class/net/%s/brport" % ifname):
- self.write_file("/proc/sys/net/ipv6/conf/%s/disable_ipv6" % ifname, "0")
+ for ifaceobj in statemanager.get_ifaceobjs(ifname) or []:
+ if ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT:
+ self.write_file("/proc/sys/net/ipv6/conf/%s/disable_ipv6" % ifname, "0")
+ return
except Exception, e:
self.logger.info(str(e))
return True
return False
- def _add_slaves(self, ifaceobj, ifaceobj_getfunc=None):
- runningslaves = []
-
+ def _add_slaves(self, ifaceobj, runningslaves, ifaceobj_getfunc=None):
slaves = self._get_slave_list(ifaceobj)
if not slaves:
self.logger.debug('%s: no slaves found' %ifaceobj.name)
return
- if not ifupdownflags.flags.PERFMODE:
- runningslaves = self.bondcmd.bond_get_slaves(ifaceobj.name)
-
clag_bond = self._is_clag_bond(ifaceobj)
for slave in Set(slaves).difference(Set(runningslaves)):
if (not ifupdownflags.flags.PERFMODE and
- not self.ipcmd.link_exists(slave)):
+ not self.cache.link_exists(slave)):
self.log_error('%s: skipping slave %s, does not exist'
%(ifaceobj.name, slave), ifaceobj,
raise_error=False)
continue
link_up = False
- if self.ipcmd.is_link_up(slave):
- netlink.link_set_updown(slave, "down")
+ if self.cache.link_is_up(slave):
+ self.netlink.link_down_force(slave)
link_up = True
# If clag bond place the slave in a protodown state; clagd
# will protoup it when it is ready
if clag_bond:
try:
- netlink.link_set_protodown(slave, "on")
+ self.netlink.link_set_protodown_on(slave)
except Exception, e:
self.logger.error('%s: %s' % (ifaceobj.name, str(e)))
+
self.enable_ipv6_if_prev_brport(slave)
- netlink.link_set_master(slave, ifaceobj.name)
+ self.netlink.link_set_master(slave, ifaceobj.name)
+ # TODO: if this fail we should switch to iproute2
+ # start a batch: down - set master - up
if link_up or ifaceobj.link_type != ifaceLinkType.LINK_NA:
try:
if (ifaceobj_getfunc(slave)[0].link_privflags &
ifaceLinkPrivFlags.KEEP_LINK_DOWN):
- netlink.link_set_updown(slave, "down")
+ self.netlink.link_down_force(slave)
else:
- netlink.link_set_updown(slave, "up")
+ self.netlink.link_up(slave)
except Exception, e:
self.logger.debug('%s: %s' % (ifaceobj.name, str(e)))
pass
if runningslaves:
for s in runningslaves:
if s not in slaves:
- self.bondcmd.bond_remove_slave(ifaceobj.name, s)
+ self.sysfs.bond_remove_slave(ifaceobj.name, s)
if clag_bond:
try:
- netlink.link_set_protodown(s, "off")
+ self.netlink.link_set_protodown_off(s)
except Exception, e:
self.logger.error('%s: %s' % (ifaceobj.name, str(e)))
else:
# apply link-down config changes on running slaves
try:
- link_up = self.ipcmd.is_link_up(s)
+ link_up = self.cache.link_is_up(s)
config_link_down = (ifaceobj_getfunc(s)[0].link_privflags &
ifaceLinkPrivFlags.KEEP_LINK_DOWN)
if (config_link_down and link_up):
- netlink.link_set_updown(s, "down")
+ self.netlink.link_down_force(s)
elif (not config_link_down and not link_up):
- netlink.link_set_updown(s, "up")
+ self.netlink.link_up_force(s)
except Exception, e:
self.logger.warn('%s: %s' % (ifaceobj.name, str(e)))
"""
ifla_bond_miimon = ifla_info_data.get(Link.IFLA_BOND_MIIMON)
if link_exists and ifla_bond_miimon is None:
- ifla_bond_miimon = self.bondcmd.link_cache_get([ifaceobj.name, 'linkinfo', Link.IFLA_BOND_MIIMON])
+ ifla_bond_miimon = self.cache.get_link_info_data_attribute(ifaceobj.name, Link.IFLA_BOND_MIIMON)
if ifla_bond_miimon == 0:
for nl_attr, attr_name in self._bond_updown_delay_nl_list:
def _check_bond_mode_user_config(self, ifname, link_exists, ifla_info_data):
ifla_bond_mode = ifla_info_data.get(Link.IFLA_BOND_MODE)
if ifla_bond_mode is None and link_exists:
- ifla_bond_mode = self.bondcmd.link_cache_get([ifname, 'linkinfo', Link.IFLA_BOND_MODE])
+ ifla_bond_mode = self.cache.get_link_info_data_attribute(ifname, Link.IFLA_BOND_MODE)
# in this case the link already exists (we have a cached value):
# if IFLA_BOND_MODE is not present in ifla_info_data it means:
# - that bond-mode was present in the user config and didn't change
if ifla_bond_mode == 4: # 802.3ad
min_links = ifla_info_data.get(Link.IFLA_BOND_MIN_LINKS)
if min_links is None:
- min_links = self.bondcmd.link_cache_get([ifname, 'linkinfo', Link.IFLA_BOND_MIN_LINKS])
+ min_links = self.cache.get_link_info_data_attribute(ifname, Link.IFLA_BOND_MIN_LINKS)
# get_min_links_nl may return None so we need to strictly check 0
if min_links == 0:
self.logger.warn('%s: attribute bond-min-links is set to \'0\'' % ifname)
nl_value = func_ptr(user_config.lower())
if link_exists:
- cached_value = self.bondcmd.link_cache_get([ifname, 'linkinfo', netlink_attr])
+ cached_value = self.cache.get_link_info_data_attribute(ifname, netlink_attr)
if link_exists and cached_value is None:
# the link already exists but we don't have any value
return True
return False
- def should_update_bond_mode(self, ifaceobj, ifname, is_link_up, ifla_info_data):
+ def should_update_bond_mode(self, ifaceobj, ifname, is_link_up, ifla_info_data, bond_slaves):
# if bond-mode was changed the bond needs to be brought
# down and slaves un-slaved before bond mode is changed.
- cached_bond_mode = self.bondcmd.link_cache_get([ifname, 'linkinfo', Link.IFLA_BOND_MODE])
+ cached_bond_mode = self.cache.get_link_info_data_attribute(ifname, Link.IFLA_BOND_MODE)
ifla_bond_mode = ifla_info_data.get(Link.IFLA_BOND_MODE)
# bond-mode was changed or is not specified
self.logger.info('%s: bond mode changed to %s: running ops on bond and slaves'
% (ifname, ifla_bond_mode))
if is_link_up:
- netlink.link_set_updown(ifname, 'down')
+ self.netlink.link_down(ifname)
is_link_up = False
for lower_dev in ifaceobj.lowerifaces:
- netlink.link_set_nomaster(lower_dev)
+ self.netlink.link_set_nomaster(lower_dev)
+ try:
+ bond_slaves.remove(lower_dev)
+ except:
+ pass
- self.bondcmd.cache_delete([ifname, 'linkinfo', 'slaves'])
else:
# bond-mode user config value is the current running(cached) value
# no need to reset it again we can ignore this attribute
del ifla_info_data[Link.IFLA_BOND_MODE]
- return is_link_up
+ return is_link_up, bond_slaves
def create_or_set_bond_config(self, ifaceobj):
ifname = ifaceobj.name
- link_exists = self.ipcmd.link_exists(ifname)
- is_link_up = self.ipcmd.is_link_up(ifname) if link_exists else False
+ link_exists, is_link_up = self.cache.link_exists_and_up(ifname)
ifla_info_data = self.get_ifla_bond_attr_from_user_config(ifaceobj, link_exists)
remove_delay_from_cache = self.check_updown_delay_nl(link_exists, ifaceobj, ifla_info_data)
# if link exists: down link if specific attributes are specified
if link_exists:
# did bond-mode changed?
- is_link_up = self.should_update_bond_mode(ifaceobj, ifname, is_link_up, ifla_info_data)
+ is_link_up, bond_slaves = self.should_update_bond_mode(
+ ifaceobj,
+ ifname,
+ is_link_up,
+ ifla_info_data,
+ self.cache.get_slaves(ifname)
+ )
# if specific attributes need to be set we need to down the bond first
if ifla_info_data and is_link_up:
if self._should_down_bond(ifla_info_data):
- netlink.link_set_updown(ifname, 'down')
+ self.netlink.link_down_force(ifname)
is_link_up = False
+ else:
+ bond_slaves = []
if link_exists and not ifla_info_data:
# if the bond already exists and no attrs need to be set
self.logger.info('%s: already exists, no change detected' % ifname)
else:
try:
- netlink.link_add_set(kind='bond', ifname=ifname, ifla_info_data=ifla_info_data)
+ self.netlink.link_add_bond_with_info_data(ifname, ifla_info_data)
except Exception as e:
# defensive code
# if anything happens, we try to set up the bond with the sysfs api
ifla_info_data[Link.IFLA_BOND_UPDELAY] = 0
ifla_info_data[Link.IFLA_BOND_DOWNDELAY] = 0
- # if link_add doesn't raise we can update the cache, the future
- # netlink listener will update the cache based on the kernel response
- for key, value in ifla_info_data.items():
- self.bondcmd.cache_update([ifname, 'linkinfo', key], value)
-
if link_exists and ifla_info_data and not is_link_up:
- netlink.link_set_updown(ifname, 'up')
+ self.netlink.link_up_force(ifname)
+
+ return bond_slaves
def create_or_set_bond_config_sysfs(self, ifaceobj, ifla_info_data):
- if not self.ipcmd.link_exists(ifaceobj.name):
- self.bondcmd.create_bond(ifaceobj.name)
- self.bondcmd.bond_set_attrs_nl(ifaceobj.name, ifla_info_data)
+ if not self.cache.link_exists(ifaceobj.name):
+ self.sysfs.bond_create(ifaceobj.name)
+ self.sysfs.bond_set_attrs_nl(ifaceobj.name, ifla_info_data)
def _up(self, ifaceobj, ifaceobj_getfunc=None):
try:
- self.create_or_set_bond_config(ifaceobj)
- self._add_slaves(ifaceobj, ifaceobj_getfunc)
+ bond_slaves = self.create_or_set_bond_config(ifaceobj)
+ self._add_slaves(
+ ifaceobj,
+ bond_slaves,
+ ifaceobj_getfunc,
+ )
except Exception, e:
self.log_error(str(e), ifaceobj)
def _down(self, ifaceobj, ifaceobj_getfunc=None):
try:
- netlink.link_del(ifaceobj.name)
- self.bondcmd.cache_delete([ifaceobj.name])
+ self.netlink.link_del(ifaceobj.name)
except Exception as e:
self.log_warn('%s: %s' % (ifaceobj.name, str(e)))
ifaceobjcurr.update_config_with_status(attr, ' '.join(user_bond_slaves) if user_bond_slaves else 'None', query)
def _query_check(self, ifaceobj, ifaceobjcurr, ifaceobj_getfunc=None):
- if not self.bondcmd.bond_exists(ifaceobj.name):
+ if not self.cache.bond_exists(ifaceobj.name):
self.logger.debug('bond iface %s does not exist' % ifaceobj.name)
return
query_slaves = True
if not user_bond_slaves:
user_bond_slaves = self._get_slave_list(ifaceobj)
- running_bond_slaves = self.bondcmd.bond_get_slaves(ifaceobj.name)
+ running_bond_slaves = self.cache.get_slaves(ifaceobj.name)
self._query_check_bond_slaves(ifaceobjcurr, 'bond-slaves', user_bond_slaves, running_bond_slaves)
except:
# if user specified bond-ports we need to display it
if not query_slaves and not user_bond_slaves: # if get_slave_list was already called for slaves
user_bond_slaves = self._get_slave_list(ifaceobj)
- running_bond_slaves = self.bondcmd.bond_get_slaves(ifaceobj.name)
+ running_bond_slaves = self.cache.get_slaves(ifaceobj.name)
self._query_check_bond_slaves(ifaceobjcurr, 'bond-ports', user_bond_slaves, running_bond_slaves)
except:
for attr in iface_attrs:
nl_attr = self._bond_attr_netlink_map[attr]
translate_func = self._bond_attr_ifquery_check_translate_func[nl_attr]
- current_config = self.bondcmd.link_cache_get([ifaceobj.name, 'linkinfo', nl_attr])
+ current_config = self.cache.get_link_info_data_attribute(ifaceobj.name, nl_attr)
user_config = ifaceobj.get_attr_value_first(attr)
if current_config == translate_func(user_config):
return 'fast' if value else 'slow'
def _query_running_attrs(self, bondname):
+ cached_vxlan_ifla_info_data = self.cache.get_link_info_data(bondname)
+
bond_attrs = {
- 'bond-mode': Link.ifla_bond_mode_pretty_tbl.get(self.bondcmd.link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_MODE])),
- 'bond-miimon': self.bondcmd.link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_MIIMON]),
- 'bond-use-carrier': self.translate_nl_value_yesno(self.bondcmd.link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_USE_CARRIER])),
- 'bond-lacp-rate': self.translate_nl_value_slowfast(self.bondcmd.link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_AD_LACP_RATE])),
- 'bond-min-links': self.bondcmd.link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_MIN_LINKS]),
- 'bond-ad-actor-system': self.bondcmd.link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_AD_ACTOR_SYSTEM]),
- 'bond-ad-actor-sys-prio': self.bondcmd.link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_AD_ACTOR_SYS_PRIO]),
- 'bond-xmit-hash-policy': Link.ifla_bond_xmit_hash_policy_pretty_tbl.get(self.bondcmd.link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_XMIT_HASH_POLICY])),
- 'bond-lacp-bypass-allow': self.translate_nl_value_yesno(self.bondcmd.link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_AD_LACP_BYPASS])),
- 'bond-num-unsol-na': self.bondcmd.link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_NUM_PEER_NOTIF]),
- 'bond-num-grat-arp': self.bondcmd.link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_NUM_PEER_NOTIF]),
- 'bond-updelay': self.bondcmd.link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_UPDELAY]),
- 'bond-downdelay': self.bondcmd.link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_DOWNDELAY])
+ 'bond-mode': Link.ifla_bond_mode_pretty_tbl.get(cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_MODE)),
+ 'bond-miimon': cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_MIIMON),
+ 'bond-use-carrier': self.translate_nl_value_yesno(cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_USE_CARRIER)),
+ 'bond-lacp-rate': self.translate_nl_value_slowfast(cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_AD_LACP_RATE)),
+ 'bond-min-links': cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_MIN_LINKS),
+ 'bond-ad-actor-system': cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_AD_ACTOR_SYSTEM),
+ 'bond-ad-actor-sys-prio': cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_AD_ACTOR_SYS_PRIO),
+ 'bond-xmit-hash-policy': Link.ifla_bond_xmit_hash_policy_pretty_tbl.get(cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_XMIT_HASH_POLICY)),
+ 'bond-lacp-bypass-allow': self.translate_nl_value_yesno(cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_AD_LACP_BYPASS)),
+ 'bond-num-unsol-na': cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_NUM_PEER_NOTIF),
+ 'bond-num-grat-arp': cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_NUM_PEER_NOTIF),
+ 'bond-updelay': cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_UPDELAY),
+ 'bond-downdelay': cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_DOWNDELAY)
}
- slaves = self.bondcmd.bond_get_slaves(bondname)
+
+ cached_bond_primary = cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_PRIMARY)
+ if cached_bond_primary:
+ bond_attrs['bond-primary'] = self.cache.get_ifname(cached_bond_primary)
+
+ slaves = self.cache.get_slaves(bondname)
if slaves:
bond_attrs['bond-slaves'] = slaves
return bond_attrs
def _query_running(self, ifaceobjrunning, ifaceobj_getfunc=None):
- if not self.bondcmd.bond_exists(ifaceobjrunning.name):
+ if not self.cache.bond_exists(ifaceobjrunning.name):
return
bond_attrs = self._query_running_attrs(ifaceobjrunning.name)
if bond_attrs.get('bond-slaves'):
""" returns list of ops supported by this module """
return self._run_ops.keys()
- def _init_command_handlers(self):
- if not self.ipcmd:
- self.ipcmd = self.bondcmd = LinkUtils()
-
def run(self, ifaceobj, operation, query_ifaceobj=None,
ifaceobj_getfunc=None):
""" run bond configuration on the interface object passed as argument
return
if operation != 'query-running' and not self._is_bond(ifaceobj):
return
- self._init_command_handlers()
if operation == 'query-checkcurr':
op_handler(self, ifaceobj, query_ifaceobj,
ifaceobj_getfunc=ifaceobj_getfunc)
from collections import Counter
try:
+ from ifupdown2.lib.addon import Addon
+
import ifupdown2.ifupdown.exceptions as exceptions
import ifupdown2.ifupdown.policymanager as policymanager
import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
from ifupdown2.ifupdown.iface import *
from ifupdown2.ifupdown.utils import utils
- from ifupdown2.ifupdown.netlink import netlink
from ifupdown2.ifupdownaddons.cache import *
- from ifupdown2.ifupdownaddons.LinkUtils import LinkUtils
from ifupdown2.ifupdownaddons.modulebase import moduleBase
-
- import ifupdown2.ifupdown.ifupdownconfig as ifupdownconfig
except ImportError:
+ from lib.addon import Addon
+
import ifupdown.exceptions as exceptions
import ifupdown.policymanager as policymanager
import ifupdown.ifupdownflags as ifupdownflags
from ifupdown.iface import *
from ifupdown.utils import utils
- from ifupdown.netlink import netlink
from ifupdownaddons.cache import *
- from ifupdownaddons.LinkUtils import LinkUtils
from ifupdownaddons.modulebase import moduleBase
- import ifupdown.ifupdownconfig as ifupdownconfig
-
class bridgeFlags:
PORT_PROCESSED = 0x1
PORT_PROCESSED_OVERRIDE = 0x2
-class bridge(moduleBase):
+class bridge(Addon, moduleBase):
""" ifupdown2 addon module to configure linux bridges """
- _modinfo = { 'mhelp' : 'Bridge configuration module. Supports both ' +
- 'vlan aware and non vlan aware bridges. For the vlan ' +
- 'aware bridge, the port specific attributes must be ' +
- 'specified under the port. And for vlan unaware bridge ' +
- 'port specific attributes must be specified under the ' +
- 'bridge.',
- 'attrs' : {
- 'bridge-vlan-aware' :
- {'help' : 'vlan aware bridge. Setting this ' +
- 'attribute to yes enables vlan filtering' +
- ' on the bridge',
- 'validvals' : ['yes', 'no'],
- 'example' : ['bridge-vlan-aware yes/no'],
- 'default': 'no'
- },
- 'bridge-ports' :
- {'help' : 'bridge ports',
- 'multivalue' : True,
- 'required' : True,
- 'validvals': ['<interface-list>', 'none'],
- 'example' : ['bridge-ports swp1.100 swp2.100 swp3.100',
- 'bridge-ports glob swp1-3.100',
- 'bridge-ports regex (swp[1|2|3].100)']},
- 'bridge-ports-condone-regex' :
- {'help' : 'bridge ports to ignore/condone when reloading config / removing interfaces',
- 'required' : False,
- 'example' : [ 'bridge-ports-condone-regex ^[a-zA-Z0-9]+_v[0-9]{1,4}$']},
- 'bridge-stp' :
- {'help': 'bridge-stp yes/no',
- 'example' : ['bridge-stp no'],
- 'validvals' : ['yes', 'on', 'off', 'no'],
- 'default' : 'no'},
- 'bridge-bridgeprio' :
- {'help': 'bridge priority',
- 'validrange' : ['0', '65535'],
- 'example' : ['bridge-bridgeprio 32768'],
- 'default' : '32768'},
- 'bridge-ageing' :
- {'help': 'bridge ageing',
- 'validrange' : ['0', '65535'],
- 'example' : ['bridge-ageing 300'],
- 'default' : '300'},
- 'bridge-fd' :
- { 'help' : 'bridge forward delay',
- 'validrange' : ['0', '255'],
- 'example' : ['bridge-fd 15'],
- 'default' : '15'},
- 'bridge-gcint' :
- # XXX: recheck values
- { 'help' : 'bridge garbage collection interval in secs',
- 'validrange' : ['0', '255'],
- 'example' : ['bridge-gcint 4'],
- 'default' : '4',
- 'compat' : True,
- 'deprecated': True},
- 'bridge-hello' :
- { 'help' : 'bridge set hello time',
- 'validrange' : ['0', '255'],
- 'example' : ['bridge-hello 2'],
- 'default' : '2'},
- 'bridge-maxage' :
- { 'help' : 'bridge set maxage',
- 'validrange' : ['0', '255'],
- 'example' : ['bridge-maxage 20'],
- 'default' : '20'},
- 'bridge-pathcosts' :
- { 'help' : 'bridge set port path costs',
- 'validvals': ['<interface-range-list>'],
- 'validrange' : ['0', '65535'],
- 'example' : ['under the port (for vlan aware bridge): bridge-pathcosts 100',
- 'under the bridge (for vlan unaware bridge): bridge-pathcosts swp1=100 swp2=100'],
- 'default' : '100'},
- 'bridge-portprios' :
- { 'help' : 'bridge port prios',
- 'validvals': ['<interface-range-list>'],
- 'validrange' : ['0', '65535'],
- 'example' : ['under the port (for vlan aware bridge): bridge-portprios 32',
- 'under the bridge (for vlan unaware bridge): bridge-portprios swp1=32 swp2=32'],
- 'default' : '32'},
- 'bridge-mclmc' :
- { 'help' : 'set multicast last member count',
- 'validrange' : ['0', '255'],
- 'example' : ['bridge-mclmc 2'],
- 'default' : '2'},
- 'bridge-mcrouter' :
- { 'help': 'Set bridge multicast routers: 0 - disabled - no, 1 - automatic (queried), 2 - permanently enabled - yes',
- 'validvals' : ['yes', 'no', '0', '1', '2'],
- 'example' : ['bridge-mcrouter 1'],
- 'default': 'yes'
- },
- 'bridge-mcsnoop' :
- { 'help' : 'set multicast snooping',
- 'validvals' : ['yes', 'no', '0', '1'],
- 'default' : 'yes',
- 'example' : ['bridge-mcsnoop yes']},
- 'bridge-mcsqc' :
- { 'help' : 'set multicast startup query count',
- 'validrange' : ['0', '255'],
- 'default' : '2',
- 'example' : ['bridge-mcsqc 2']},
- 'bridge-mcqifaddr' :
- { 'help' : 'set multicast query to use ifaddr',
- 'validvals' : ['yes', 'no', '0', '1'],
- 'default' : 'no',
- 'example' : ['bridge-mcqifaddr no']},
- 'bridge-mcquerier' :
- { 'help' : 'set multicast querier',
- 'validvals' : ['yes', 'no', '0', '1'],
- 'default' : 'no',
- 'example' : ['bridge-mcquerier no']},
- 'bridge-hashel' :
- { 'help' : 'set hash elasticity',
- 'validrange' : ['0', '4096'],
- 'default' : '4',
- 'example' : ['bridge-hashel 4096']},
- 'bridge-hashmax' :
- { 'help' : 'set hash max',
- 'validrange' : ['0', '4096'],
- 'default' : '512',
- 'example' : ['bridge-hashmax 4096']},
- 'bridge-mclmi' :
- { 'help' : 'set multicast last member interval (in secs)',
- 'validrange' : ['0', '255'],
- 'default' : '1',
- 'example' : ['bridge-mclmi 1']},
- 'bridge-mcmi' :
- { 'help' : 'set multicast membership interval (in secs)',
- 'validrange' : ['0', '255'],
- 'default' : '260',
- 'example' : ['bridge-mcmi 260']},
- 'bridge-mcqpi' :
- { 'help' : 'set multicast querier interval (in secs)',
- 'validrange' : ['0', '255'],
- 'default' : '255',
- 'example' : ['bridge-mcqpi 255']},
- 'bridge-mcqi' :
- { 'help' : 'set multicast query interval (in secs)',
- 'validrange' : ['0', '255'],
- 'default' : '125',
- 'example' : ['bridge-mcqi 125']},
- 'bridge-mcqri' :
- { 'help' : 'set multicast query response interval (in secs)',
- 'validrange' : ['0', '255'],
- 'default' : '10',
- 'example' : ['bridge-mcqri 10']},
- 'bridge-mcsqi' :
- { 'help' : 'set multicast startup query interval (in secs)',
- 'validrange' : ['0', '255'],
- 'default' : '31',
- 'example' : ['bridge-mcsqi 31']},
- 'bridge-mcqv4src' :
- { 'help' : 'set per VLAN v4 multicast querier source address',
- 'validvals' : ['<number-ipv4-list>', ],
- 'multivalue' : True,
- 'compat' : True,
- 'example' : ['bridge-mcqv4src 100=172.16.100.1 101=172.16.101.1']},
- 'bridge-portmcrouter':
- {
- 'help': 'Set port multicast routers: 0 - disabled, 1 - automatic (queried), 2 - permanently enabled',
- 'validvals': ['<interface-disabled-automatic-enabled>'],
- 'example': [
- 'under the port (for vlan aware bridge): bridge-portmcrouter 0',
- 'under the port (for vlan aware bridge): bridge-portmcrouter 1',
- 'under the port (for vlan aware bridge): bridge-portmcrouter 2',
- 'under the port (for vlan aware bridge): bridge-portmcrouter disabled',
- 'under the port (for vlan aware bridge): bridge-portmcrouter automatic',
- 'under the port (for vlan aware bridge): bridge-portmcrouter enabled',
- 'under the bridge (for vlan unaware bridge): bridge-portmcrouter swp1=0 swp2=1 swp2=2',
- 'under the bridge (for vlan unaware bridge): bridge-portmcrouter swp1=disabled swp2=automatic swp3=enabled',
- 'under the bridge (for vlan unaware bridge): bridge-portmcrouter swp1=2 swp2=disabled swp3=1',
- ]
- },
- 'bridge-portmcfl' :
- { 'help' : 'port multicast fast leave.',
- 'validvals': ['<interface-yes-no-0-1-list>'],
- 'default' : 'no',
- 'example' : ['under the port (for vlan aware bridge): bridge-portmcfl no',
- 'under the bridge (for vlan unaware bridge): bridge-portmcfl swp1=no swp2=no']},
- 'bridge-waitport' :
- { 'help' : 'wait for a max of time secs for the' +
- ' specified ports to become available,' +
- 'if no ports are specified then those' +
- ' specified on bridge-ports will be' +
- ' used here. Specifying no ports here ' +
- 'should not be used if we are using ' +
- 'regex or \"all\" on bridge_ports,' +
- 'as it wouldnt work.',
- 'default' : '0',
- 'validvals': ['<number-interface-list>'],
- 'example' : ['bridge-waitport 4 swp1 swp2']},
- 'bridge-maxwait' :
- { 'help' : 'forces to time seconds the maximum time ' +
- 'that the Debian bridge setup scripts will ' +
- 'wait for the bridge ports to get to the ' +
- 'forwarding status, doesn\'t allow factional ' +
- 'part. If it is equal to 0 then no waiting' +
- ' is done',
- 'validrange' : ['0', '255'],
- 'default' : '0',
- 'example' : ['bridge-maxwait 3']},
- 'bridge-vids' :
- { 'help' : 'bridge port vids. Can be specified ' +
- 'under the bridge or under the port. ' +
- 'If specified under the bridge the ports ' +
- 'inherit it unless overridden by a ' +
- 'bridge-vids attribute under the port',
- 'multivalue' : True,
- 'validvals': ['<number-comma-range-list>'],
- 'example' : ['bridge-vids 4000',
- 'bridge-vids 2000 2200-3000'],
- 'aliases': ['bridge-trunk']},
- 'bridge-pvid' :
- { 'help' : 'bridge port pvid. Must be specified under' +
- ' the bridge port',
- 'validrange' : ['0', '4096'],
- 'example' : ['bridge-pvid 1']},
- 'bridge-access' :
- { 'help' : 'bridge port access vlan. Must be ' +
- 'specified under the bridge port',
- 'validrange' : ['1', '4094'],
- 'example' : ['bridge-access 300']},
- 'bridge-allow-untagged' :
- { 'help' : 'indicate if the bridge port accepts ' +
- 'untagged packets or not. Must be ' +
- 'specified under the bridge port. ' +
- 'Default is \'yes\'',
- 'validvals' : ['yes', 'no'],
- 'example' : ['bridge-allow-untagged yes'],
- 'default' : 'yes'},
- 'bridge-port-vids' :
- { 'help' : 'bridge vlans',
- 'compat': True,
- 'example' : ['bridge-port-vids bond0=1-1000,1010-1020']},
- 'bridge-port-pvids' :
- { 'help' : 'bridge port vlans',
- 'compat': True,
- 'example' : ['bridge-port-pvids bond0=100 bond1=200']},
- 'bridge-learning' :
- { 'help' : 'bridge port learning flag',
- 'validvals': ['on', 'off', '<interface-on-off-list>'],
- 'default': 'on',
- 'example' : ['bridge-learning off']},
- 'bridge-igmp-version' :
- { 'help' : 'mcast igmp version',
- 'validvals': ['2', '3'],
- 'default' : '2',
- 'example' : ['bridge-igmp-version 2']},
- 'bridge-mld-version':
- { 'help' : 'mcast mld version',
- 'validvals': ['1', '2'],
- 'default' : '1',
- 'example' : ['bridge-mld-version 1']},
- 'bridge-unicast-flood' :
- { 'help' : 'bridge port unicast flood flag',
- 'validvals': ['on', 'off', '<interface-on-off-list>'],
- 'default': 'on',
- 'example' : ['under the port (for vlan aware bridge): bridge-unicast-flood on',
- 'under the bridge (for vlan unaware bridge): bridge-unicast-flood swp1=on swp2=on']},
- 'bridge-multicast-flood' :
- { 'help' : 'bridge port multicast flood flag',
- 'validvals': ['on', 'off', '<interface-on-off-list>'],
- 'default': 'on',
- 'example' : ['under the port (for vlan aware bridge): bridge-multicast-flood on',
- 'under the bridge (for vlan unaware bridge): bridge-multicast-flood swp1=on swp2=on']},
- 'bridge-vlan-protocol' :
- { 'help' : 'bridge vlan protocol',
- 'default' : '802.1q',
- 'validvals': ['802.1q', '802.1ad'],
- 'example' : ['bridge-vlan-protocol 802.1q']},
- 'bridge-vlan-stats' :
- { 'help' : 'bridge vlan stats',
- 'default' : 'off',
- 'validvals': ['on', 'off'],
- 'example' : ['bridge-vlan-stats off']},
- 'bridge-arp-nd-suppress' :
- { 'help' : 'bridge port arp nd suppress flag',
- 'validvals': ['on', 'off', '<interface-on-off-list>'],
- 'default': 'off',
- 'example' : ['under the port (for vlan aware bridge): bridge-arp-nd-suppress on',
- 'under the bridge (for vlan unaware bridge): bridge-arp-nd-suppress swp1=on swp2=on']},
- 'bridge-mcstats' :
- { 'help' : 'bridge multicast stats',
- 'default' : 'off',
- 'validvals': ['on', 'off'],
- 'example' : ['bridge-mcstats off']},
- 'bridge-l2protocol-tunnel': {
- 'help': 'layer 2 protocol tunneling',
- 'validvals': [ # XXX: lists all combinations, should move to
- # a better representation
- 'all',
- 'cdp',
- 'cdp lacp',
- 'cdp lacp lldp',
- 'cdp lacp lldp pvst',
- 'cdp lacp lldp stp',
- 'cdp lacp pvst',
- 'cdp lacp pvst stp',
- 'cdp lacp stp',
- 'cdp lldp',
- 'cdp lldp pvst',
- 'cdp lldp pvst stp',
- 'cdp lldp stp',
- 'cdp pvst',
- 'cdp pvst stp',
- 'cdp stp',
- 'lacp',
- 'lacp lldp',
- 'lacp lldp pvst',
- 'lacp lldp pvst stp',
- 'lacp lldp stp',
- 'lacp pvst',
- 'lacp pvst stp',
- 'lacp stp',
- 'lldp',
- 'lldp pvst',
- 'lldp pvst stp',
- 'lldp stp',
- 'pvst',
- 'pvst stp',
- 'stp',
- '<interface-l2protocol-tunnel-list>'],
- 'example': [
- 'under the bridge (for vlan unaware bridge): bridge-l2protocol-tunnel swpX=lacp,stp swpY=cdp swpZ=all',
- 'under the port (for vlan aware bridge): bridge-l2protocol-tunnel lacp stp lldp cdp pvst',
- 'under the port (for vlan aware bridge): bridge-l2protocol-tunnel lldp pvst',
- 'under the port (for vlan aware bridge): bridge-l2protocol-tunnel stp',
- 'under the port (for vlan aware bridge): bridge-l2protocol-tunnel all'
- ]
- }
- }}
+ _modinfo = {
+ "mhelp": "Bridge configuration module. Supports both vlan aware and non "
+ "vlan aware bridges. For the vlan aware bridge, the port "
+ "specific attributes must be specified under the port. And for "
+ "vlan unaware bridge port specific attributes must be specified "
+ "under the bridge.",
+ "attrs": {
+ "bridge-vlan-aware": {
+ "help": "vlan aware bridge. Setting this "
+ "attribute to yes enables vlan filtering"
+ " on the bridge",
+ "validvals": ["yes", "no"],
+ "example": ["bridge-vlan-aware yes/no"],
+ "default": "no"
+ },
+ "bridge-ports": {
+ "help": "bridge ports",
+ "multivalue": True,
+ "required": True,
+ "validvals": ["<interface-list>"],
+ "example": [
+ "bridge-ports swp1.100 swp2.100 swp3.100",
+ "bridge-ports glob swp1-3.100",
+ "bridge-ports regex (swp[1|2|3].100)"
+ ]
+ },
+ "bridge-stp": {
+ "help": "bridge-stp yes/no",
+ "example": ["bridge-stp no"],
+ "validvals": ["yes", "on", "off", "no"],
+ "default": "no"
+ },
+ "bridge-bridgeprio": {
+ "help": "bridge priority",
+ "validrange": ["0", "65535"],
+ "example": ["bridge-bridgeprio 32768"],
+ "default": "32768"
+ },
+ "bridge-ageing": {
+ "help": "bridge ageing",
+ "validrange": ["0", "65535"],
+ "example": ["bridge-ageing 300"],
+ "default": "300"
+ },
+ "bridge-fd": {
+ "help": "bridge forward delay",
+ "validrange": ["0", "255"],
+ "example": ["bridge-fd 15"],
+ "default": "15"
+ },
+ # XXX: recheck values
+ "bridge-gcint": {
+ "help": "bridge garbage collection interval in secs",
+ "validrange": ["0", "255"],
+ "example": ["bridge-gcint 4"],
+ "default": "4",
+ "compat": True,
+ "deprecated": True
+ },
+ "bridge-hello": {
+ "help": "bridge set hello time",
+ "validrange": ["0", "255"],
+ "example": ["bridge-hello 2"],
+ "default": "2"
+ },
+ "bridge-maxage": {
+ "help": "bridge set maxage",
+ "validrange": ["0", "255"],
+ "example": ["bridge-maxage 20"],
+ "default": "20"
+ },
+ "bridge-pathcosts": {
+ "help": "bridge set port path costs",
+ "validvals": ["<interface-range-list>"],
+ "validrange": ["0", "65535"],
+ "example": [
+ "under the port (for vlan aware bridge): bridge-pathcosts 100",
+ "under the bridge (for vlan unaware bridge): bridge-pathcosts swp1=100 swp2=100"
+ ],
+ "default": "100"
+ },
+ "bridge-portprios": {
+ "help": "bridge port prios",
+ "validvals": ["<interface-range-list>"],
+ "validrange": ["0", "65535"],
+ "example": [
+ "under the port (for vlan aware bridge): bridge-portprios 32",
+ "under the bridge (for vlan unaware bridge): bridge-portprios swp1=32 swp2=32"
+ ],
+ },
+ "bridge-mclmc": {
+ "help": "set multicast last member count",
+ "validrange": ["0", "255"],
+ "example": ["bridge-mclmc 2"],
+ "default": "2"
+ },
+ "bridge-mcrouter": {
+ "help": "Set bridge multicast routers: 0 - disabled - no, 1 - automatic (queried), 2 - permanently enabled - yes",
+ "validvals": ["yes", "no", "0", "1", "2"],
+ "example": ["bridge-mcrouter 1"],
+ "default": "yes"
+ },
+ "bridge-mcsnoop": {
+ "help": "set multicast snooping",
+ "validvals": ["yes", "no", "0", "1"],
+ "default": "yes",
+ "example": ["bridge-mcsnoop yes"]
+ },
+ "bridge-mcsqc": {
+ "help": "set multicast startup query count",
+ "validrange": ["0", "255"],
+ "default": "2",
+ "example": ["bridge-mcsqc 2"]
+ },
+ "bridge-mcqifaddr": {
+ "help": "set multicast query to use ifaddr",
+ "validvals": ["yes", "no", "0", "1"],
+ "default": "no",
+ "example": ["bridge-mcqifaddr no"]
+ },
+ "bridge-mcquerier": {
+ "help": "set multicast querier",
+ "validvals": ["yes", "no", "0", "1"],
+ "default": "no",
+ "example": ["bridge-mcquerier no"]
+ },
+ "bridge-hashel": {
+ "help": "set hash elasticity",
+ "validrange": ["0", "4096"],
+ "default": "4",
+ "example": ["bridge-hashel 4096"]
+ },
+ "bridge-hashmax": {
+ "help": "set hash max",
+ "validrange": ["0", "4096"],
+ "default": "512",
+ "example": ["bridge-hashmax 4096"]
+ },
+ "bridge-mclmi": {
+ "help": "set multicast last member interval (in secs)",
+ "validrange": ["0", "255"],
+ "default": "1",
+ "example": ["bridge-mclmi 1"]
+ },
+ "bridge-mcmi": {
+ "help": "set multicast membership interval (in secs)",
+ "validrange": ["0", "255"],
+ "default": "260",
+ "example": ["bridge-mcmi 260"]
+ },
+ "bridge-mcqpi": {
+ "help": "set multicast querier interval (in secs)",
+ "validrange": ["0", "255"],
+ "default": "255",
+ "example": ["bridge-mcqpi 255"]
+ },
+ "bridge-mcqi": {
+ "help": "set multicast query interval (in secs)",
+ "validrange": ["0", "255"],
+ "default": "125",
+ "example": ["bridge-mcqi 125"]
+ },
+ "bridge-mcqri": {
+ "help": "set multicast query response interval (in secs)",
+ "validrange": ["0", "255"],
+ "default": "10",
+ "example": ["bridge-mcqri 10"]
+ },
+ "bridge-mcsqi": {
+ "help": "set multicast startup query interval (in secs)",
+ "validrange": ["0", "255"],
+ "default": "31",
+ "example": ["bridge-mcsqi 31"]
+ },
+ "bridge-mcqv4src": {
+ "help": "set per VLAN v4 multicast querier source address",
+ "validvals": ["<number-ipv4-list>", ],
+ "multivalue": True,
+ "compat": True,
+ "example": ["bridge-mcqv4src 100=172.16.100.1 101=172.16.101.1"]
+ },
+ "bridge-portmcrouter": {
+ "help": "Set port multicast routers: 0 - disabled, 1 - automatic (queried), 2 - permanently enabled",
+ "validvals": ["<interface-disabled-automatic-enabled>"],
+ "example": [
+ "under the port (for vlan aware bridge): bridge-portmcrouter 0",
+ "under the port (for vlan aware bridge): bridge-portmcrouter 1",
+ "under the port (for vlan aware bridge): bridge-portmcrouter 2",
+ "under the port (for vlan aware bridge): bridge-portmcrouter disabled",
+ "under the port (for vlan aware bridge): bridge-portmcrouter automatic",
+ "under the port (for vlan aware bridge): bridge-portmcrouter enabled",
+ "under the bridge (for vlan unaware bridge): bridge-portmcrouter swp1=0 swp2=1 swp2=2",
+ "under the bridge (for vlan unaware bridge): bridge-portmcrouter swp1=disabled swp2=automatic swp3=enabled",
+ "under the bridge (for vlan unaware bridge): bridge-portmcrouter swp1=2 swp2=disabled swp3=1",
+ ]
+ },
+ "bridge-portmcfl": {
+ "help": "port multicast fast leave.",
+ "validvals": ["<interface-yes-no-0-1-list>"],
+ "default": "no",
+ "example": [
+ "under the port (for vlan aware bridge): bridge-portmcfl no",
+ "under the bridge (for vlan unaware bridge): bridge-portmcfl swp1=no swp2=no"
+ ]
+ },
+ "bridge-waitport": {
+ "help": "wait for a max of time secs for the"
+ " specified ports to become available,"
+ "if no ports are specified then those"
+ " specified on bridge-ports will be"
+ " used here. Specifying no ports here "
+ "should not be used if we are using "
+ "regex or \"all\" on bridge_ports,"
+ "as it wouldnt work.",
+ "default": "0",
+ "validvals": ["<number-interface-list>"],
+ "example": ["bridge-waitport 4 swp1 swp2"]
+ },
+ "bridge-maxwait": {
+ "help": "forces to time seconds the maximum time "
+ "that the Debian bridge setup scripts will "
+ "wait for the bridge ports to get to the "
+ "forwarding status, doesn\"t allow factional "
+ "part. If it is equal to 0 then no waiting"
+ " is done",
+ "validrange": ["0", "255"],
+ "default": "0",
+ "example": ["bridge-maxwait 3"]
+ },
+ "bridge-vids": {
+ "help": "bridge port vids. Can be specified "
+ "under the bridge or under the port. "
+ "If specified under the bridge the ports "
+ "inherit it unless overridden by a "
+ "bridge-vids attribute under the port",
+ "multivalue": True,
+ "validvals": ["<number-comma-range-list>"],
+ "example": [
+ "bridge-vids 4000",
+ "bridge-vids 2000 2200-3000"
+ ],
+ "aliases": ["bridge-trunk"]
+ },
+ "bridge-pvid": {
+ "help": "bridge port pvid. Must be specified under"
+ " the bridge port",
+ "validrange": ["0", "4096"],
+ "example": ["bridge-pvid 1"]
+ },
+ "bridge-access": {
+ "help": "bridge port access vlan. Must be "
+ "specified under the bridge port",
+ "validrange": ["1", "4094"],
+ "example": ["bridge-access 300"]
+ },
+ "bridge-allow-untagged": {
+ "help": "indicate if the bridge port accepts "
+ "untagged packets or not. Must be "
+ "specified under the bridge port. "
+ "Default is \"yes\"",
+ "validvals": ["yes", "no"],
+ "example": ["bridge-allow-untagged yes"],
+ "default": "yes"
+ },
+ "bridge-port-vids": {
+ "help": "bridge vlans",
+ "compat": True,
+ "example": ["bridge-port-vids bond0=1-1000,1010-1020"]
+ },
+ "bridge-port-pvids": {
+ "help": "bridge port vlans",
+ "compat": True,
+ "example": ["bridge-port-pvids bond0=100 bond1=200"]
+ },
+ "bridge-learning": {
+ "help": "bridge port learning flag",
+ "validvals": ["on", "off", "<interface-on-off-list>"],
+ "default": "on",
+ "example": ["bridge-learning off"]
+ },
+ "bridge-igmp-version": {
+ "help": "mcast igmp version",
+ "validvals": ["2", "3"],
+ "default": "2",
+ "example": ["bridge-igmp-version 2"]
+ },
+ "bridge-mld-version": {
+ "help": "mcast mld version",
+ "validvals": ["1", "2"],
+ "default": "1",
+ "example": ["bridge-mld-version 1"]
+ },
+ "bridge-unicast-flood": {
+ "help": "bridge port unicast flood flag",
+ "validvals": ["on", "off", "<interface-on-off-list>"],
+ "default": "on",
+ "example": ["under the port (for vlan aware bridge): bridge-unicast-flood on",
+ "under the bridge (for vlan unaware bridge): bridge-unicast-flood swp1=on swp2=on"]
+ },
+ "bridge-multicast-flood": {
+ "help": "bridge port multicast flood flag",
+ "validvals": ["on", "off", "<interface-on-off-list>"],
+ "default": "on",
+ "example": [
+ "under the port (for vlan aware bridge): bridge-multicast-flood on",
+ "under the bridge (for vlan unaware bridge): bridge-multicast-flood swp1=on swp2=on"
+ ]
+ },
+ "bridge-broadcast-flood": {
+ "help": "bridge port broadcast flood flag",
+ "validvals": ["on", "off", "<interface-on-off-list>"],
+ "default": "on",
+ "example": [
+ "under the port (for vlan aware bridge): bridge-broadcast-flood on",
+ "under the bridge (for vlan unaware bridge): bridge-broadcast-flood swp1=on swp2=on"
+ ]
+ },
+ "bridge-vlan-protocol": {
+ "help": "bridge vlan protocol",
+ "default": "802.1q",
+ "validvals": ["802.1q", "802.1ad"],
+ "example": ["bridge-vlan-protocol 802.1q"]
+ },
+ "bridge-vlan-stats": {
+ "help": "bridge vlan stats",
+ "default": "off",
+ "validvals": ["on", "off"],
+ "example": ["bridge-vlan-stats off"]
+ },
+ "bridge-arp-nd-suppress": {
+ "help": "bridge port arp nd suppress flag",
+ "validvals": ["on", "off", "<interface-on-off-list>"],
+ "default": "off",
+ "example": [
+ "under the port (for vlan aware bridge): bridge-arp-nd-suppress on",
+ "under the bridge (for vlan unaware bridge): bridge-arp-nd-suppress swp1=on swp2=on"
+ ]
+ },
+ "bridge-mcstats": {
+ "help": "bridge multicast stats",
+ "default": "off",
+ "validvals": ["on", "off", "1", "0", "yes", "no"],
+ "example": ["bridge-mcstats off"]
+ },
+ "bridge-l2protocol-tunnel": {
+ "help": "layer 2 protocol tunneling",
+ "validvals": [ # XXX: lists all combinations, should move to
+ # a better representation
+ "all",
+ "cdp",
+ "cdp lacp",
+ "cdp lacp lldp",
+ "cdp lacp lldp pvst",
+ "cdp lacp lldp stp",
+ "cdp lacp pvst",
+ "cdp lacp pvst stp",
+ "cdp lacp stp",
+ "cdp lldp",
+ "cdp lldp pvst",
+ "cdp lldp pvst stp",
+ "cdp lldp stp",
+ "cdp pvst",
+ "cdp pvst stp",
+ "cdp stp",
+ "lacp",
+ "lacp lldp",
+ "lacp lldp pvst",
+ "lacp lldp pvst stp",
+ "lacp lldp stp",
+ "lacp pvst",
+ "lacp pvst stp",
+ "lacp stp",
+ "lldp",
+ "lldp pvst",
+ "lldp pvst stp",
+ "lldp stp",
+ "pvst",
+ "pvst stp",
+ "stp",
+ "<interface-l2protocol-tunnel-list>"],
+ "example": [
+ "under the bridge (for vlan unaware bridge): bridge-l2protocol-tunnel swpX=lacp,stp swpY=cdp swpZ=all",
+ "under the port (for vlan aware bridge): bridge-l2protocol-tunnel lacp stp lldp cdp pvst",
+ "under the port (for vlan aware bridge): bridge-l2protocol-tunnel lldp pvst",
+ "under the port (for vlan aware bridge): bridge-l2protocol-tunnel stp",
+ "under the port (for vlan aware bridge): bridge-l2protocol-tunnel all"
+ ]
+ },
+ "bridge-ports-condone-regex": {
+ "help": "bridge ports to ignore/condone when reloading config / removing interfaces",
+ "required": False,
+ "example": ["bridge-ports-condone-regex ^[a-zA-Z0-9]+_v[0-9]{1,4}$"]
+ },
+ }
+ }
+
+ bridge_utils_missing_warning = True
# Netlink attributes not associated with ifupdown2
# attributes are left commented-out for a future use
# and kept in order :)
- _ifla_br_attributes_map = (
+ _ifla_br_attributes_map = {
# Link.IFLA_BR_UNSPEC,
- ('bridge-fd', Link.IFLA_BR_FORWARD_DELAY),
- ('bridge-hello', Link.IFLA_BR_HELLO_TIME),
- ('bridge-maxage', Link.IFLA_BR_MAX_AGE),
- ('bridge-ageing', Link.IFLA_BR_AGEING_TIME),
- ('bridge-stp', Link.IFLA_BR_STP_STATE),
- ('bridge-bridgeprio', Link.IFLA_BR_PRIORITY),
- ('bridge-vlan-aware', Link.IFLA_BR_VLAN_FILTERING),
- ('bridge-vlan-protocol', Link.IFLA_BR_VLAN_PROTOCOL),
+ 'bridge-fd': Link.IFLA_BR_FORWARD_DELAY,
+ 'bridge-hello': Link.IFLA_BR_HELLO_TIME,
+ 'bridge-maxage': Link.IFLA_BR_MAX_AGE,
+ 'bridge-ageing': Link.IFLA_BR_AGEING_TIME,
+ 'bridge-stp': Link.IFLA_BR_STP_STATE,
+ 'bridge-bridgeprio': Link.IFLA_BR_PRIORITY,
+ 'bridge-vlan-aware': Link.IFLA_BR_VLAN_FILTERING,
+ 'bridge-vlan-protocol': Link.IFLA_BR_VLAN_PROTOCOL,
# Link.IFLA_BR_GROUP_FWD_MASK,
# Link.IFLA_BR_ROOT_ID,
# Link.IFLA_BR_BRIDGE_ID,
# Link.IFLA_BR_GC_TIMER,
# Link.IFLA_BR_GROUP_ADDR,
# Link.IFLA_BR_FDB_FLUSH,
- ('bridge-mcrouter', Link.IFLA_BR_MCAST_ROUTER),
+ 'bridge-mcrouter': Link.IFLA_BR_MCAST_ROUTER,
#('bridge-mcsnoop', Link.IFLA_BR_MCAST_SNOOPING), # requires special handling so we won't loop on this attr
- ('bridge-mcqifaddr', Link.IFLA_BR_MCAST_QUERY_USE_IFADDR),
- ('bridge-mcquerier', Link.IFLA_BR_MCAST_QUERIER),
- ('bridge-hashel', Link.IFLA_BR_MCAST_HASH_ELASTICITY),
- ('bridge-hashmax', Link.IFLA_BR_MCAST_HASH_MAX),
- ('bridge-mclmc', Link.IFLA_BR_MCAST_LAST_MEMBER_CNT),
- ('bridge-mcsqc', Link.IFLA_BR_MCAST_STARTUP_QUERY_CNT),
- ('bridge-mclmi', Link.IFLA_BR_MCAST_LAST_MEMBER_INTVL),
- ('bridge-mcmi', Link.IFLA_BR_MCAST_MEMBERSHIP_INTVL),
- ('bridge-mcqpi', Link.IFLA_BR_MCAST_QUERIER_INTVL),
- ('bridge-mcqi', Link.IFLA_BR_MCAST_QUERY_INTVL),
- ('bridge-mcqri', Link.IFLA_BR_MCAST_QUERY_RESPONSE_INTVL),
- ('bridge-mcsqi', Link.IFLA_BR_MCAST_STARTUP_QUERY_INTVL),
+ 'bridge-mcqifaddr': Link.IFLA_BR_MCAST_QUERY_USE_IFADDR,
+ 'bridge-mcquerier': Link.IFLA_BR_MCAST_QUERIER,
+ 'bridge-hashel': Link.IFLA_BR_MCAST_HASH_ELASTICITY,
+ 'bridge-hashmax': Link.IFLA_BR_MCAST_HASH_MAX,
+ 'bridge-mclmc': Link.IFLA_BR_MCAST_LAST_MEMBER_CNT,
+ 'bridge-mcsqc': Link.IFLA_BR_MCAST_STARTUP_QUERY_CNT,
+ 'bridge-mclmi': Link.IFLA_BR_MCAST_LAST_MEMBER_INTVL,
+ 'bridge-mcmi': Link.IFLA_BR_MCAST_MEMBERSHIP_INTVL,
+ 'bridge-mcqpi': Link.IFLA_BR_MCAST_QUERIER_INTVL,
+ 'bridge-mcqi': Link.IFLA_BR_MCAST_QUERY_INTVL,
+ 'bridge-mcqri': Link.IFLA_BR_MCAST_QUERY_RESPONSE_INTVL,
+ 'bridge-mcsqi': Link.IFLA_BR_MCAST_STARTUP_QUERY_INTVL,
# Link.IFLA_BR_NF_CALL_IPTABLES,
# Link.IFLA_BR_NF_CALL_IP6TABLES,
# Link.IFLA_BR_NF_CALL_ARPTABLES,
# Link.IFLA_BR_VLAN_DEFAULT_PVID,
# Link.IFLA_BR_PAD,
# (Link.IFLA_BR_VLAN_STATS_ENABLED, 'bridge-vlan-stats'), # already dealt with, in a separate loop
- ('bridge-igmp-version', Link.IFLA_BR_MCAST_IGMP_VERSION, ),
- ('bridge-mcstats', Link.IFLA_BR_MCAST_STATS_ENABLED),
- ('bridge-mld-version', Link.IFLA_BR_MCAST_MLD_VERSION)
- )
+ 'bridge-igmp-version': Link.IFLA_BR_MCAST_IGMP_VERSION,
+ 'bridge-mcstats': Link.IFLA_BR_MCAST_STATS_ENABLED,
+ 'bridge-mld-version': Link.IFLA_BR_MCAST_MLD_VERSION
+ }
# 'bridge-vlan-stats & bridge-mcstat are commented out even though, today
# they are supported. It is done this way because this dictionary is used
# in a loop, but these attributes require additional work. Thus they are
# excluded from this loop without overhead.
- # we are still using the old linkCache we need an easy way
- # to use this cache with the new full-netlink approach
- _ifla_br_attributes_old_cache_key_map = dict(
- (
- (Link.IFLA_BR_FORWARD_DELAY, 'fd'),
- (Link.IFLA_BR_HELLO_TIME, 'hello'),
- (Link.IFLA_BR_MAX_AGE, 'maxage'),
- (Link.IFLA_BR_AGEING_TIME, 'ageing'),
- (Link.IFLA_BR_STP_STATE, 'stp'),
- (Link.IFLA_BR_PRIORITY, 'bridgeprio'),
- (Link.IFLA_BR_VLAN_FILTERING, 'vlan_filtering'),
- (Link.IFLA_BR_VLAN_PROTOCOL, 'vlan-protocol'),
- (Link.IFLA_BR_MCAST_ROUTER, 'mcrouter'),
- (Link.IFLA_BR_MCAST_SNOOPING, 'mcsnoop'),
- (Link.IFLA_BR_MCAST_QUERY_USE_IFADDR, 'mcqifaddr'),
- (Link.IFLA_BR_MCAST_QUERIER, 'mcquerier'),
- (Link.IFLA_BR_MCAST_HASH_ELASTICITY, 'hashel'),
- (Link.IFLA_BR_MCAST_HASH_MAX, 'hashmax'),
- (Link.IFLA_BR_MCAST_LAST_MEMBER_CNT, 'mclmc'),
- (Link.IFLA_BR_MCAST_STARTUP_QUERY_CNT, 'mcsqc'),
- (Link.IFLA_BR_MCAST_LAST_MEMBER_INTVL, 'mclmi'),
- (Link.IFLA_BR_MCAST_MEMBERSHIP_INTVL, 'mcmi'),
- (Link.IFLA_BR_MCAST_QUERIER_INTVL, 'mcqpi'),
- (Link.IFLA_BR_MCAST_QUERY_INTVL, 'mcqi'),
- (Link.IFLA_BR_MCAST_QUERY_RESPONSE_INTVL, 'mcqri'),
- (Link.IFLA_BR_MCAST_STARTUP_QUERY_INTVL, 'mcsqi'),
- (Link.IFLA_BR_VLAN_STATS_ENABLED, 'vlan-stats'),
- (Link.IFLA_BR_MCAST_STATS_ENABLED, 'mcstats'),
- (Link.IFLA_BR_MCAST_IGMP_VERSION, 'igmp-version'),
- (Link.IFLA_BR_MCAST_MLD_VERSION, 'mld-version')
- )
- )
-
_ifla_br_attributes_translate_user_config_to_netlink_map = dict(
(
# Link.IFLA_BR_UNSPEC,
# Link.IFLA_BR_STP_STATE, # STP is treated outside the loop
(Link.IFLA_BR_PRIORITY, int),
(Link.IFLA_BR_VLAN_FILTERING, utils.get_boolean_from_string),
- (Link.IFLA_BR_VLAN_PROTOCOL, str),
+ (Link.IFLA_BR_VLAN_PROTOCOL, str.upper),
# Link.IFLA_BR_GROUP_FWD_MASK,
# Link.IFLA_BR_ROOT_ID,
# Link.IFLA_BR_BRIDGE_ID,
)
)
- _ifla_brport_attributes_map = (
+ _ifla_brport_attributes_map = {
# Link.IFLA_BRPORT_UNSPEC,
# Link.IFLA_BRPORT_STATE,
- ('bridge-portprios', Link.IFLA_BRPORT_PRIORITY),
- ('bridge-pathcosts', Link.IFLA_BRPORT_COST),
+ 'bridge-portprios': Link.IFLA_BRPORT_PRIORITY,
+ 'bridge-pathcosts': Link.IFLA_BRPORT_COST,
# Link.IFLA_BRPORT_MODE,
# Link.IFLA_BRPORT_GUARD,
# Link.IFLA_BRPORT_PROTECT,
- ('bridge-portmcfl', Link.IFLA_BRPORT_FAST_LEAVE),
- ('bridge-learning', Link.IFLA_BRPORT_LEARNING),
- ('bridge-unicast-flood', Link.IFLA_BRPORT_UNICAST_FLOOD),
+ 'bridge-portmcfl': Link.IFLA_BRPORT_FAST_LEAVE,
+ 'bridge-learning': Link.IFLA_BRPORT_LEARNING,
+ 'bridge-unicast-flood': Link.IFLA_BRPORT_UNICAST_FLOOD,
# Link.IFLA_BRPORT_PROXYARP,
# Link.IFLA_BRPORT_LEARNING_SYNC,
# Link.IFLA_BRPORT_PROXYARP_WIFI,
# Link.IFLA_BRPORT_FORWARD_DELAY_TIMER,
# Link.IFLA_BRPORT_HOLD_TIMER,
# Link.IFLA_BRPORT_FLUSH,
- ('bridge-portmcrouter', Link.IFLA_BRPORT_MULTICAST_ROUTER),
+ 'bridge-portmcrouter': Link.IFLA_BRPORT_MULTICAST_ROUTER,
# Link.IFLA_BRPORT_PAD,
- ('bridge-multicast-flood', Link.IFLA_BRPORT_MCAST_FLOOD),
+ 'bridge-multicast-flood': Link.IFLA_BRPORT_MCAST_FLOOD,
# Link.IFLA_BRPORT_MCAST_TO_UCAST,
# Link.IFLA_BRPORT_VLAN_TUNNEL,
- # Link.IFLA_BRPORT_BCAST_FLOOD
- ('bridge-l2protocol-tunnel', Link.IFLA_BRPORT_GROUP_FWD_MASK),
+ 'bridge-broadcast-flood': Link.IFLA_BRPORT_BCAST_FLOOD,
+ 'bridge-l2protocol-tunnel': Link.IFLA_BRPORT_GROUP_FWD_MASK,
# Link.IFLA_BRPORT_PEER_LINK,
# Link.IFLA_BRPORT_DUAL_LINK,
- ('bridge-arp-nd-suppress', Link.IFLA_BRPORT_ARP_SUPPRESS),
- )
+ 'bridge-arp-nd-suppress': Link.IFLA_BRPORT_NEIGH_SUPPRESS,
+ }
_ifla_brport_multicast_router_dict_to_int = {
'disabled': 0,
'2': 2,
}
+ _ifla_brport_multicast_router_dict_int_to_str = {
+ 0: "disabled",
+ 1: "automatic",
+ 2: "enabled"
+ }
+
# callable to translate <interface-yes-no-0-1-list> to netlink value
_ifla_brport_attributes_translate_user_config_to_netlink_map = dict(
(
(Link.IFLA_BRPORT_LEARNING, utils.get_boolean_from_string),
(Link.IFLA_BRPORT_UNICAST_FLOOD, utils.get_boolean_from_string),
(Link.IFLA_BRPORT_MCAST_FLOOD, utils.get_boolean_from_string),
+ (Link.IFLA_BRPORT_BCAST_FLOOD, utils.get_boolean_from_string),
(Link.IFLA_BRPORT_GROUP_FWD_MASK, lambda x: x),
- (Link.IFLA_BRPORT_ARP_SUPPRESS, utils.get_boolean_from_string)
+ (Link.IFLA_BRPORT_NEIGH_SUPPRESS, utils.get_boolean_from_string)
)
)
def __init__(self, *args, **kargs):
+ Addon.__init__(self)
moduleBase.__init__(self, *args, **kargs)
- self.ipcmd = None
self.name = self.__class__.__name__
- self.brctlcmd = None
- self._running_vidinfo = {}
- self._running_vidinfo_valid = False
self._resv_vlan_range = self._get_reserved_vlan_range()
self.logger.debug('%s: using reserved vlan range %s' % (self.__class__.__name__, str(self._resv_vlan_range)))
default=True
)
+ self.bridge_vxlan_arp_nd_suppress = utils.get_boolean_from_string(
+ policymanager.policymanager_api.get_module_globals(
+ module_name=self.__class__.__name__,
+ attr="bridge-vxlan-arp-nd-suppress"
+ ),
+ default=False
+ )
+ self.bridge_vxlan_arp_nd_suppress_int = int(self.bridge_vxlan_arp_nd_suppress)
+
self.l2protocol_tunnel_callback = {
'all': self._l2protocol_tunnel_set_all,
'stp': self._l2protocol_tunnel_set_stp,
'lacp': self._query_check_l2protocol_tunnel_lacp
}
+ self._bridge_attribute_query_check_handler = {
+ "bridge-maxwait": (self._query_check_br_attr_wait, None),
+ "bridge-waitport": (self._query_check_br_attr_wait, None),
+
+ "bridge-stp": (self._query_check_br_attr_stp, Link.IFLA_BR_STP_STATE),
+
+ "bridge-mcstats": (self._query_check_br_attr_boolean_on_off, Link.IFLA_BR_MCAST_STATS_ENABLED),
+ "bridge-vlan-stats": (self._query_check_br_attr_boolean_on_off, Link.IFLA_BR_VLAN_STATS_ENABLED),
+
+ "bridge-vlan-aware": (self._query_check_br_attr_boolean, Link.IFLA_BR_VLAN_FILTERING),
+ "bridge-mcqifaddr": (self._query_check_br_attr_boolean, Link.IFLA_BR_MCAST_QUERY_USE_IFADDR),
+ "bridge-mcsnoop": (self._query_check_br_attr_boolean, Link.IFLA_BR_MCAST_SNOOPING),
+ "bridge-mcquerier": (self._query_check_br_attr_boolean, Link.IFLA_BR_MCAST_QUERIER),
+ "bridge-mcrouter": (self._query_check_br_attr_boolean, Link.IFLA_BR_MCAST_ROUTER),
+
+ "bridge-vlan-protocol": (self._query_check_br_attr_string, Link.IFLA_BR_VLAN_PROTOCOL),
+
+ "bridge-mcsqc": (self._query_check_br_attr_int, Link.IFLA_BR_MCAST_STARTUP_QUERY_CNT),
+ "bridge-mclmc": (self._query_check_br_attr_int, Link.IFLA_BR_MCAST_LAST_MEMBER_CNT),
+ "bridge-hashmax": (self._query_check_br_attr_int, Link.IFLA_BR_MCAST_HASH_MAX),
+ "bridge-hashel": (self._query_check_br_attr_int, Link.IFLA_BR_MCAST_HASH_ELASTICITY),
+ "bridge-bridgeprio": (self._query_check_br_attr_int, Link.IFLA_BR_PRIORITY),
+ "bridge-igmp-version": (self._query_check_br_attr_int, Link.IFLA_BR_MCAST_IGMP_VERSION),
+ "bridge-mld-version": (self._query_check_br_attr_int, Link.IFLA_BR_MCAST_MLD_VERSION),
+
+ "bridge-maxage": (self._query_check_br_attr_int_divided100, Link.IFLA_BR_MAX_AGE),
+ "bridge-fd": (self._query_check_br_attr_int_divided100, Link.IFLA_BR_FORWARD_DELAY),
+ "bridge-hello": (self._query_check_br_attr_int_divided100, Link.IFLA_BR_HELLO_TIME),
+ "bridge-ageing": (self._query_check_br_attr_int_divided100, Link.IFLA_BR_AGEING_TIME),
+ "bridge-mcmi": (self._query_check_br_attr_int_divided100, Link.IFLA_BR_MCAST_MEMBERSHIP_INTVL),
+ "bridge-mcsqi": (self._query_check_br_attr_int_divided100, Link.IFLA_BR_MCAST_STARTUP_QUERY_INTVL),
+ "bridge-mclmi": (self._query_check_br_attr_int_divided100, Link.IFLA_BR_MCAST_LAST_MEMBER_INTVL),
+ "bridge-mcqri": (self._query_check_br_attr_int_divided100, Link.IFLA_BR_MCAST_QUERY_RESPONSE_INTVL),
+ "bridge-mcqpi": (self._query_check_br_attr_int_divided100, Link.IFLA_BR_MCAST_QUERIER_INTVL),
+ "bridge-mcqi": (self._query_check_br_attr_int_divided100, Link.IFLA_BR_MCAST_QUERY_INTVL),
+ }
+
+ self._brport_attribute_query_check_handler = {
+ "bridge-pathcosts": self._query_check_brport_attr_int,
+ "bridge-portprios": self._query_check_brport_attr_int,
+ "bridge-portmcfl": self._query_check_brport_attr_boolean_yes_no,
+ "bridge-learning": self._query_check_brport_attr_boolean_on_off,
+ "bridge-arp-nd-suppress": self._query_check_brport_attr_boolean_on_off,
+ "bridge-unicast-flood": self._query_check_brport_attr_boolean_on_off,
+ "bridge-multicast-flood": self._query_check_brport_attr_boolean_on_off,
+ "bridge-broadcast-flood": self._query_check_brport_attr_boolean_on_off,
+ "bridge-portmcrouter": self._query_check_brport_attr_portmcrouter,
+ }
+
+ self.bridge_vxlan_port_learning = utils.get_boolean_from_string(
+ policymanager.policymanager_api.get_module_globals(
+ self.__class__.__name__,
+ "bridge_vxlan_port_learning"
+ ),
+ default=True
+ )
+
@staticmethod
def _l2protocol_tunnel_set_pvst(ifla_brport_group_mask, ifla_brport_group_maskhi):
if not ifla_brport_group_maskhi:
return ' '.join(bridge_ports)
- def _is_bridge_port(self, ifaceobj):
- if self.brctlcmd.is_bridge_port(ifaceobj.name):
- return True
- return False
-
def check_valid_bridge(self, ifaceobj, ifname):
- if LinkUtils.link_exists_nodryrun(ifname) and not LinkUtils.is_bridge(ifname):
+ if self.cache.link_exists(ifname) and not self.cache.link_is_bridge(ifname):
self.log_error('misconfiguration of bridge attribute(s) on existing non-bridge interface (%s)' % ifname, ifaceobj=ifaceobj)
return False
return True
ifacenames_all)
def get_dependent_ifacenames_running(self, ifaceobj):
- self._init_command_handlers()
- if not self.brctlcmd.bridge_exists(ifaceobj.name):
+ if not self.cache.bridge_exists(ifaceobj.name):
return None
- return self.brctlcmd.get_bridge_ports(ifaceobj.name)
+ return self.cache.get_slaves(ifaceobj.name)
def _get_bridge_port_list(self, ifaceobj):
starttime = time.time()
while ((time.time() - starttime) < waitporttime):
if all([False for p in waitportlist
- if not self.ipcmd.link_exists(p)]):
+ if not self.cache.link_exists(p)]):
break;
time.sleep(1)
except Exception, e:
except Exception, e:
self.logger.info(str(e))
- def handle_ipv6(self, ports, state, ifaceobj=None):
- if (ifaceobj and
- (ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VXLAN) and
- not ifaceobj.get_attr_value('address') and not ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VLAN_AWARE):
- self._enable_disable_ipv6(ifaceobj.name, state)
+ def handle_ipv6(self, ports, state):
for p in ports:
self._enable_disable_ipv6(p, state)
bridgeportscondoneregex = self._get_bridge_port_condone_regex(ifaceobj)
runningbridgeports = []
- self.ipcmd.batch_start()
self._process_bridge_waitport(ifaceobj, bridgeports)
- self.ipcmd.batch_start()
# Delete active ports not in the new port list
if not ifupdownflags.flags.PERFMODE:
- runningbridgeports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
+ runningbridgeports = self.cache.get_slaves(ifaceobj.name)
if runningbridgeports:
for bport in runningbridgeports:
if not bridgeports or bport not in bridgeports:
if bridgeportscondoneregex and bridgeportscondoneregex.match(bport):
self.logger.info("%s: port %s will stay enslaved as it matches with bridge-ports-condone-regex" % (ifaceobj.name, bport))
continue
- self.ipcmd.link_set(bport, 'nomaster')
+ self.netlink.link_set_nomaster(bport)
# set admin DOWN on all removed ports
# that don't have config outside bridge
if not ifaceobj_getfunc(bport):
- netlink.link_set_updown(bport, "down")
+ self.netlink.link_down(bport)
# enable ipv6 for ports that were removed
self.handle_ipv6([bport], '0')
else:
runningbridgeports = []
if not bridgeports:
- self.ipcmd.batch_commit()
return []
err = 0
- ports = 0
newbridgeports = Set(bridgeports).difference(Set(runningbridgeports))
newly_enslaved_ports = []
if br_port in newbridgeports:
newbridgeports_ordered.append(br_port)
+ self.iproute2.batch_start()
+
for bridgeport in newbridgeports_ordered:
try:
if (not ifupdownflags.flags.DRYRUN and
- not self.ipcmd.link_exists(bridgeport)):
+ not self.cache.link_exists(bridgeport)):
self.log_error('%s: bridge port %s does not exist'
%(ifaceobj.name, bridgeport), ifaceobj)
err += 1
continue
- hwaddress = self.ipcmd.link_get_hwaddress(bridgeport)
+ hwaddress = self.cache.get_link_address(bridgeport)
if not self._valid_ethaddr(hwaddress):
self.log_warn('%s: skipping port %s, ' %(ifaceobj.name,
bridgeport) + 'invalid ether addr %s'
%hwaddress)
continue
- self.ipcmd.link_set(bridgeport, 'master', ifaceobj.name)
+ self.iproute2.link_set_master(bridgeport, ifaceobj.name)
newly_enslaved_ports.append(bridgeport)
self.handle_ipv6([bridgeport], '1')
- self.ipcmd.addr_flush(bridgeport)
- ports += 1
- if ports == 250:
- ports = 0
- self.ipcmd.batch_commit()
- self.ipcmd.batch_start()
+ self.iproute2.addr_flush(bridgeport)
except Exception, e:
self.logger.error(str(e))
pass
- try:
- self.ipcmd.batch_commit()
- except Exception, e:
- self._pretty_print_add_ports_error(str(e), ifaceobj,
- bridgeports)
- pass
+
+ self.iproute2.batch_commit()
+ self.cache.force_add_slave_list(ifaceobj.name, newly_enslaved_ports)
if err:
self.log_error('bridge configuration failed (missing ports)')
def _diff_vids(self, vids1_ints, vids2_ints):
return Set(vids2_ints).difference(vids1_ints), Set(vids1_ints).difference(vids2_ints)
- def _compare_vids(self, vids1, vids2, pvid=None):
+ def _compare_vids(self, vids1, vids2, pvid=None, expand_range=True):
""" Returns true if the vids are same else return false """
- vids1_ints = self._ranges_to_ints(vids1)
- vids2_ints = self._ranges_to_ints(vids2)
+ if expand_range:
+ vids1_ints = self._ranges_to_ints(vids1)
+ vids2_ints = self._ranges_to_ints(vids2)
+ else:
+ vids1_ints = self._ranges_to_ints(vids1)
+ vids2_ints = vids2
set_diff = Set(vids1_ints).symmetric_difference(vids2_ints)
if pvid and int(pvid) in set_diff:
set_diff.remove(int(pvid))
if attrval:
running_mcqv4src = {}
if not ifupdownflags.flags.PERFMODE:
- running_mcqv4src = self.brctlcmd.bridge_get_mcqv4src_sysfs(ifaceobj.name)
+ running_mcqv4src = self.sysfs.bridge_get_mcqv4src(ifaceobj.name)
mcqs = {}
srclist = attrval.split()
for s in srclist:
k_to_del = Set(running_mcqv4src.keys()).difference(mcqs.keys())
for v in k_to_del:
- self.brctlcmd.bridge_del_mcqv4src(ifaceobj.name, v)
+ self.iproute2.bridge_del_mcqv4src(ifaceobj.name, v)
for v in mcqs.keys():
- self.brctlcmd.bridge_set_mcqv4src(ifaceobj.name, v, mcqs[v])
+ self.iproute2.bridge_set_mcqv4src(ifaceobj.name, v, mcqs[v])
elif not ifupdownflags.flags.PERFMODE:
- running_mcqv4src = self.brctlcmd.bridge_get_mcqv4src_sysfs(ifaceobj.name)
+ running_mcqv4src = self.sysfs.bridge_get_mcqv4src(ifaceobj.name)
if running_mcqv4src:
for v in running_mcqv4src.keys():
- self.brctlcmd.bridge_del_mcqv4src(ifaceobj.name, v)
-
- def _get_running_vidinfo(self):
- if self._running_vidinfo_valid:
- return self._running_vidinfo
- self._running_vidinfo = {}
-
- # Removed check for PERFMODE. Need the get in all cases
- # including reboot, so that we can configure the pvid correctly.
- self._running_vidinfo = self.ipcmd.bridge_port_vids_get_all_json()
- self._running_vidinfo_valid = True
- return self._running_vidinfo
+ self.iproute2.bridge_del_mcqv4src(ifaceobj.name, v)
def _set_bridge_vidinfo_compat(self, ifaceobj):
#
try:
(port, pvid) = p.split('=')
pvid = int(pvid)
- running_pvid = self._get_running_pvid(port)
+ running_pvid = self.cache.get_pvid(port)
if running_pvid:
if running_pvid == pvid:
continue
else:
- self.ipcmd.bridge_port_pvid_del(port, running_pvid)
- self.ipcmd.bridge_port_pvid_add(port, pvid)
+ self.iproute2.bridge_vlan_del_pvid(port, running_pvid)
+ self.iproute2.bridge_vlan_add_pvid(port, pvid)
except Exception, e:
self.log_warn('%s: failed to set pvid `%s` (%s)'
%(ifaceobj.name, p, str(e)))
(port, val) = p.split('=')
vids = val.split(',')
vids_int = self._ranges_to_ints(vids)
- running_vids = self.ipcmd.bridge_vlan_get_vids(port)
+ _, running_vids = self.cache.get_pvid_and_vids(port)
if running_vids:
(vids_to_del, vids_to_add) = \
self._diff_vids(vids_int, running_vids)
if vids_to_del:
- self.ipcmd.bridge_port_vids_del(port,
+ self.iproute2.bridge_vlan_del_vid_list(port,
self._compress_into_ranges(vids_to_del))
if vids_to_add:
- self.ipcmd.bridge_port_vids_add(port,
+ self.iproute2.bridge_vlan_add_vid_list(port,
self._compress_into_ranges(vids_to_add))
else:
- self.ipcmd.bridge_port_vids_add(port, vids_int)
+ self.iproute2.bridge_vlan_add_vid_list(port, vids_int)
except Exception, e:
self.log_warn('%s: failed to set vid `%s` (%s)'
%(ifaceobj.name, p, str(e)))
ifname,
nl_attr,
attr_name,
- user_config):
+ user_config,
+ cached_value):
try:
translate_func = self._ifla_br_attributes_translate_user_config_to_netlink_map.get(nl_attr)
attr=attr_name
)
- old_cache_key = self._ifla_br_attributes_old_cache_key_map.get(nl_attr)
- if old_cache_key and not link_just_created:
- cached_value = self.brctlcmd.link_cache_get([ifname, 'linkinfo', old_cache_key])
- if not cached_value or cached_value == "None":
- # the link already exists but we don't have any value
- # cached for this attr, it probably means that the
- # capability is not available on this system (i.e old kernel)
- self.logger.debug('%s: ignoring %s %s: capability '
- 'probably not supported on this system'
- % (ifname, attr_name, user_config))
- return
- # we need to convert the cache value to "netlink" format
- cached_value = translate_func(cached_value.lower())
- else:
- cached_value = None
+ if not link_just_created and cached_value is None:
+ # the link already exists but we don't have any value
+ # cached for this attr, it probably means that the
+ # capability is not available on this system (i.e old kernel)
+ self.logger.debug("%s: ignoring %s %s: capability probably not supported on this system"
+ % (ifname, attr_name, user_config))
+ return
if not user_config and not link_just_created and cached_value is not None:
# there is no user configuration for this attribute
ifla_info_data = dict()
ifname = ifaceobj.name
- self.logger.info('%s: apply bridge settings' % ifname)
+ self.logger.info('%s: applying bridge settings' % ifname)
- for attr_name, nl_attr in self._ifla_br_attributes_map:
+ cached_ifla_info_data = self.cache.get_link_info_data(ifname)
+
+ try:
+ # we compare the user value (or policy value) with the current running state
+ # we need to divide the cached value by 100 to ignore small difference.
+ # i.e. our default value is 31 but the kernel default seems to be 3125
+ cached_ifla_info_data[Link.IFLA_BR_MCAST_STARTUP_QUERY_INTVL] /= 100
+ cached_ifla_info_data[Link.IFLA_BR_MCAST_STARTUP_QUERY_INTVL] *= 100
+ except:
+ pass
+
+ for attr_name, nl_attr in self._ifla_br_attributes_map.iteritems():
self.fill_ifla_info_data_with_ifla_br_attribute(
ifla_info_data=ifla_info_data,
link_just_created=link_just_created,
ifname=ifname,
nl_attr=nl_attr,
attr_name=attr_name,
- user_config=ifaceobj.get_attr_value_first(attr_name)
+ user_config=ifaceobj.get_attr_value_first(attr_name),
+ cached_value=cached_ifla_info_data.get(nl_attr)
)
# bridge-mcsnoop
ifname=ifname,
nl_attr=Link.IFLA_BR_MCAST_SNOOPING,
attr_name='bridge-mcsnoop',
- user_config=self.get_bridge_mcsnoop_value(ifaceobj)
+ user_config=self.get_bridge_mcsnoop_value(ifaceobj),
+ cached_value=cached_ifla_info_data.get(Link.IFLA_BR_MCAST_SNOOPING)
+
)
# bridge-vlan-stats
ifname=ifname,
nl_attr=Link.IFLA_BR_VLAN_STATS_ENABLED,
attr_name='bridge-vlan-stats',
- user_config=ifaceobj.get_attr_value_first('bridge-vlan-stats') or self.default_vlan_stats
+ user_config=ifaceobj.get_attr_value_first('bridge-vlan-stats') or self.default_vlan_stats,
+ cached_value=cached_ifla_info_data.get(Link.IFLA_BR_VLAN_STATS_ENABLED)
)
try:
self.logger.warning('%s: bridge stp: %s' % (ifname, str(e)))
if ifla_info_data:
- netlink.link_add_set(ifname=ifname, kind='bridge', ifla_info_data=ifla_info_data, link_exists=True)
+ self.netlink.link_set_bridge_info_data(ifname, ifla_info_data, link_just_created)
def _check_vids(self, ifaceobj, vids):
ret = True
%(ifaceobj.name, v))
return ret
- def _get_running_pvid(self, ifacename):
- pvid = 0
-
- running_vidinfo = self._get_running_vidinfo()
- for vinfo in running_vidinfo.get(ifacename, {}):
- v = vinfo.get('vlan')
- pvid = v if 'PVID' in vinfo.get('flags', []) else 0
- if pvid:
- return pvid
- return pvid
-
def _get_running_vids_n_pvid_str(self, ifacename):
- vids = []
- pvid = None
-
- (vids, pvid) = self.ipcmd.bridge_vlan_get_vids_n_pvid(ifacename)
+ pvid, vids = self.cache.get_pvid_and_vids(ifacename)
if vids:
ret_vids = self._compress_into_ranges(vids)
if not self._check_vids(bportifaceobj, vids):
return
- (running_vids, running_pvid) = self.ipcmd.bridge_vlan_get_vids_n_pvid(
- bportifaceobj.name)
+ running_pvid, running_vids = self.cache.get_pvid_and_vids(bportifaceobj.name)
if not running_vids and not running_pvid:
# There cannot be a no running pvid.
if vids_to_del:
if pvid_to_add in vids_to_del:
vids_to_del.remove(pvid_to_add)
- self.ipcmd.bridge_vids_del(bportifaceobj.name,
+ self.iproute2.bridge_vlan_del_vid_list_self(bportifaceobj.name,
self._compress_into_ranges(
vids_to_del), isbridge)
except Exception, e:
try:
if pvid_to_del:
- self.ipcmd.bridge_port_pvid_del(bportifaceobj.name,
+ self.iproute2.bridge_vlan_del_pvid(bportifaceobj.name,
pvid_to_del)
except Exception, e:
self.log_warn('%s: failed to del pvid `%s` (%s)'
try:
if vids_to_add:
- self.ipcmd.bridge_vids_add(bportifaceobj.name,
+ self.iproute2.bridge_vlan_add_vid_list_self(bportifaceobj.name,
self._compress_into_ranges(
vids_to_add), isbridge)
except Exception, e:
try:
if pvid_to_add and pvid_to_add != running_pvid:
- self.ipcmd.bridge_port_pvid_add(bportifaceobj.name,
+ self.iproute2.bridge_vlan_add_pvid(bportifaceobj.name,
pvid_to_add)
except Exception, e:
self.log_error('%s: failed to set pvid `%s` (%s)'
if not bridgeports:
self.logger.debug('%s: cannot find bridgeports' %ifaceobj.name)
return
- self.ipcmd.batch_start()
+ self.iproute2.batch_start()
for bport in bridgeports:
- # Use the brctlcmd bulk set method: first build a dictionary
- # and then call set
- if not self.ipcmd.bridge_port_exists(ifaceobj.name, bport):
+ # on link_set_master we need to wait until we cache the correct
+ # notification and register the brport as slave
+ if not self.cache.bridge_port_exists(ifaceobj.name, bport):
self.logger.info('%s: skipping bridge config' %ifaceobj.name +
' for port %s (missing port)' %bport)
continue
%(ifaceobj.name, bport))
bportifaceobjlist = ifaceobj_getfunc(bport)
if not bportifaceobjlist:
- continue
+ continue
for bportifaceobj in bportifaceobjlist:
# Dont process bridge port if it already has been processed
# and there is no override on port_processed
err = True
self.logger.warn('%s: %s' %(ifaceobj.name, str(e)))
pass
- self.ipcmd.bridge_batch_commit()
+ self.iproute2.batch_commit()
if err:
raise Exception('%s: errors applying port settings' %ifaceobj.name)
self.warn_on_untagged_bridge_absence = False
def bridge_port_get_bridge_name(self, ifaceobj):
- bridgename = self.ipcmd.bridge_port_get_bridge_name(ifaceobj.name)
+ bridgename = self.cache.get_bridge_name_from_port(ifaceobj.name)
if not bridgename:
# bridge port is not enslaved to a bridge we need to find
# the bridge in it's upper ifaces then enslave it
for u in ifaceobj.upperifaces:
- if self.ipcmd.is_bridge(u):
+ if self.cache.link_is_bridge(u):
return True, u
return False, None
# return should_enslave port, bridgename
def up_bridge_port_vlan_aware_bridge(self, ifaceobj, ifaceobj_getfunc, bridge_name, should_enslave_port):
if should_enslave_port:
- netlink.link_set_master(ifaceobj.name, bridge_name)
+ self.netlink.link_set_master(ifaceobj.name, bridge_name)
self.handle_ipv6([ifaceobj.name], '1')
bridge_vids = self._get_bridge_vids(bridge_name, ifaceobj_getfunc)
# bridge doesn't exist
return
- vlan_aware_bridge = self.ipcmd.bridge_is_vlan_aware(bridge_name)
+ vlan_aware_bridge = self.cache.bridge_is_vlan_aware(bridge_name)
if vlan_aware_bridge:
self.up_bridge_port_vlan_aware_bridge(ifaceobj,
ifaceobj_getfunc,
ifaceobj.module_flags[self.name] = ifaceobj.module_flags.setdefault(self.name, 0) | bridgeFlags.PORT_PROCESSED
- def up_check_bridge_vlan_aware(self, ifaceobj, ifaceobj_getfunc, link_exists):
+ def up_check_bridge_vlan_aware(self, ifaceobj, ifaceobj_getfunc, link_just_created):
if ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VLAN_AWARE:
if not self.check_bridge_vlan_aware_port(ifaceobj, ifaceobj_getfunc):
return False
- if link_exists:
+ if not link_just_created and not self.cache.bridge_is_vlan_aware(ifaceobj.name):
+ # if bridge-vlan-aware was added on a existing old-bridge, we need to reprocess all ports
ifaceobj.module_flags[self.name] = ifaceobj.module_flags.setdefault(self.name, 0) | bridgeFlags.PORT_PROCESSED_OVERRIDE
return True
return False
config[ifname] = value
return config
- def sync_bridge_learning_to_vxlan_brport(self, bridge_name, bridge_vlan_aware, brport_ifaceobj,
- brport_name, brport_ifla_info_slave_data, brport_learning):
+ def sync_bridge_learning_to_vxlan_brport(self, bridge_name, brport_ifaceobj, brport_name, brport_ifla_info_slave_data, user_config_brport_learning_nl, cached_brport_learning):
"""
brport_ifaceobj.link_kind & ifaceLinkKind.VXLAN
and
kind = None
ifla_info_data = {}
- brport_vxlan_learning_config = brport_ifaceobj.get_attr_value_first('vxlan-learning')
- # if the user explicitly defined vxlan-learning we need to honor his config
- # and not sync vxlan-learning with bridge-learning
+ if user_config_brport_learning_nl is None:
+ user_config_brport_learning_nl = self.bridge_vxlan_port_learning
+ # bridge-learning is not configured by the user or by a policy
+ # use "bridge-vxlan-port-learning" policy to set bridge-learning (default on)
- brport_vxlan_learning = self.ipcmd.get_vxlandev_learning(brport_name)
+ if user_config_brport_learning_nl != cached_brport_learning:
+ brport_ifla_info_slave_data[Link.IFLA_BRPORT_LEARNING] \
+ = cached_brport_learning \
+ = user_config_brport_learning_nl
- # if BRIDGE_LEARNING is in the desired configuration
- # and differs from the running vxlan configuration
- if brport_learning is not None and brport_learning != brport_vxlan_learning and not brport_vxlan_learning_config:
- kind = 'vxlan'
- ifla_info_data = {Link.IFLA_VXLAN_LEARNING: brport_learning}
- self.logger.info('%s: %s: vxlan learning and bridge learning out of sync: set %s'
- % (bridge_name, brport_name, brport_learning))
+ self.logger.info(
+ "%s: %s: set bridge-learning %s"
+ % (bridge_name, brport_name, "on" if user_config_brport_learning_nl else "off")
+ )
+ else:
+ # in this case, the current bridge-learning value is properly configured and
+ # doesn't need to be reset. We need to make sure that BRPORT_LEARNING is not
+ # part of ifla_info_slave_data.
+ try:
+ del brport_ifla_info_slave_data[Link.IFLA_BRPORT_LEARNING]
+ except:
+ pass
+
+ #
+ # vxlan-learning sync:
+ #
- elif brport_learning is None and bridge_vlan_aware:
- # is bridge-learning is not configured but the bridge is vlan-aware
+ brport_vxlan_learning_config = brport_ifaceobj.get_attr_value_first("vxlan-learning")
+ # if vxlan-learning is defined by the user or via policy file we need
+ # to honor his config and not sync vxlan-learning with bridge-learning
- running_value = self.ipcmd.get_brport_learning_bool(brport_name)
- default_value = utils.get_boolean_from_string(self.get_mod_subattr('bridge-learning', 'default'))
+ if not brport_vxlan_learning_config:
+ # check policy file
+ brport_vxlan_learning_config = policymanager.policymanager_api.get_attr_default("vxlan", "vxlan-learning")
- if default_value != running_value:
- brport_ifla_info_slave_data[Link.IFLA_BRPORT_LEARNING] = default_value
+ # convert vxlan-learning string to netlink value (if None use brport-learning value instead)
+ brport_vxlan_learning_config_nl = utils.get_boolean_from_string(brport_vxlan_learning_config) \
+ if brport_vxlan_learning_config \
+ else cached_brport_learning
- if not brport_vxlan_learning_config:
- kind = 'vxlan'
- ifla_info_data = {Link.IFLA_VXLAN_LEARNING: default_value}
- self.logger.info('%s: %s: reset brport learning to %s and sync vxlan learning'
- % (bridge_name, brport_name, default_value))
+ if brport_vxlan_learning_config_nl != self.cache.get_link_info_data_attribute(brport_name, Link.IFLA_VXLAN_LEARNING):
+ self.logger.info(
+ "%s: %s: vxlan learning and bridge learning out of sync: set vxlan-learning %s"
+ % (bridge_name, brport_name, "on" if brport_vxlan_learning_config_nl else "off")
+ )
+ ifla_info_data = {Link.IFLA_VXLAN_LEARNING: brport_vxlan_learning_config_nl}
+ kind = "vxlan"
# if kind and ifla_info_data are set they will be added to the
# netlink request on the VXLAN brport, to sync IFLA_VXLAN_LEARNING
return kind, ifla_info_data
- def check_vxlan_brport_arp_suppress(self, ifaceobj, bridge_vlan_aware, brport_ifaceobj, brport_name, user_config):
- if user_config:
- if self.arp_nd_suppress_only_on_vxlan and not brport_ifaceobj.link_kind & ifaceLinkKind.VXLAN:
- self.logger.warning('%s: %s: \'bridge-arp-nd-suppress\' '
- 'is not supported on a non-vxlan port'
- % (ifaceobj.name, brport_name))
- raise Exception()
- elif (bridge_vlan_aware and
- (not self.arp_nd_suppress_only_on_vxlan or
- (self.arp_nd_suppress_only_on_vxlan and
- brport_ifaceobj.link_kind & ifaceLinkKind.VXLAN))):
- return self.get_mod_subattr('bridge-arp-nd-suppress', 'default')
- return None
-
def up_apply_brports_attributes(self, ifaceobj, ifaceobj_getfunc, bridge_vlan_aware, target_ports=[], newly_enslaved_ports=[]):
ifname = ifaceobj.name
try:
brports_ifla_info_slave_data = dict()
brport_ifaceobj_dict = dict()
+ brport_name_list = []
+
+ cache_brports_ifla_info_slave_data = {}
+
+ port_processed_override = ifaceobj.module_flags.get(self.name, 0x0) & bridgeFlags.PORT_PROCESSED_OVERRIDE
- running_brports = self.brctlcmd.get_bridge_ports(ifname)
+ running_brports = self.cache.get_slaves(ifname)
+ # If target_ports is specified we want to configure only this
+ # sub-list of port, we need to check if these ports are already
+ # enslaved, if not they will be ignored.
+ # If target_ports is not populated we will apply the brport
+ # attributes on all running brport.
if target_ports:
new_targets = []
for brport_name in target_ports:
new_targets.append(brport_name)
running_brports = new_targets
- self.logger.info('%s: applying bridge port configuration: %s' % (ifname, running_brports))
-
- # If target_ports is specified we want to configure only this
- # sub-list of port we need to check if these ports are already
- # enslaved, if not they will be ignored.
- # If target_ports is not populated we will apply the brport
- # attributes on all running brport.
-
for port in running_brports:
brport_list = ifaceobj_getfunc(port)
if brport_list:
- brport_ifaceobj_dict[port] = brport_list[0]
- brports_ifla_info_slave_data[port] = dict()
+ port_already_processed = False
+
+ # ports just added to the bridge have to be processed
+ if port not in newly_enslaved_ports:
+ # check if brport was already processed
+ for brportifaceobj in brport_list:
+ if not port_processed_override and brportifaceobj.module_flags.get(self.name, 0x0) & bridgeFlags.PORT_PROCESSED:
+ # skip port if already processed (probably by `up_bridge_port`)
+ port_already_processed = True
+ self.logger.info("%s: port %s: already processed" % (ifname, port))
+ break
+
+ if not port_already_processed:
+ brport_name_list.append(port)
+ brport_ifaceobj_dict[port] = brport_list[0]
+ brports_ifla_info_slave_data[port] = dict()
+
+ if not ifupdownflags.flags.PERFMODE and port not in newly_enslaved_ports:
+ # if the port has just been enslaved, info_slave_data is not cached yet
+ cache_brports_ifla_info_slave_data[port] = self.cache.get_link_info_slave_data(port)
+ else:
+ cache_brports_ifla_info_slave_data[port] = {}
+
+ if not brport_name_list:
+ self.bridge_process_vidinfo_mcqv4src_maxwait(ifaceobj)
+ return
+
+ self.logger.info('%s: applying bridge port configuration: %s' % (ifname, brport_name_list))
+
+ cached_bridge_mcsnoop = self.cache.get_bridge_multicast_snooping(ifname)
bridge_ports_learning = {}
+ bridge_ports_vxlan_arp_suppress = {}
+ cached_bridge_ports_learning = {}
# we iterate through all IFLA_BRPORT supported attributes
- for attr_name, nl_attr in self._ifla_brport_attributes_map:
+ for attr_name, nl_attr in self._ifla_brport_attributes_map.iteritems():
br_config = ifaceobj.get_attr_value_first(attr_name)
translate_func = self._ifla_brport_attributes_translate_user_config_to_netlink_map.get(nl_attr)
brport_config = brport_ifaceobj.get_attr_value_first(attr_name)
brport_name = brport_ifaceobj.name
- if not ifupdownflags.flags.PERFMODE and brport_name not in newly_enslaved_ports:
- # if the port has just been enslaved, info_slave_data is not cached yet
- cached_value = self.ipcmd.cache_get_info_slave([brport_name, 'info_slave_data', nl_attr])
+ if not ifupdownflags.flags.PERFMODE:
+ cached_value = cache_brports_ifla_info_slave_data.get(brport_name, {}).get(nl_attr, None)
else:
cached_value = None
# attribute specific work
# This shouldn't be here but we don't really have a choice otherwise this
# will require too much code duplication and will make the code very complex
- if nl_attr == Link.IFLA_BRPORT_ARP_SUPPRESS:
+ if nl_attr == Link.IFLA_BRPORT_NEIGH_SUPPRESS:
+ bridge_ports_vxlan_arp_suppress[brport_name] = user_config
try:
- arp_suppress = self.check_vxlan_brport_arp_suppress(ifaceobj,
- bridge_vlan_aware,
- brport_ifaceobj,
- brport_name,
- user_config)
- if arp_suppress:
- user_config = arp_suppress
+ if user_config:
+ if self.arp_nd_suppress_only_on_vxlan and not brport_ifaceobj.link_kind & ifaceLinkKind.VXLAN:
+ self.logger.warning('%s: %s: \'bridge-arp-nd-suppress\' '
+ 'is not supported on a non-vxlan port'
+ % (ifaceobj.name, brport_name))
+ continue
+ elif bridge_vlan_aware:
+ if not self.arp_nd_suppress_only_on_vxlan:
+ user_config = self.get_mod_subattr('bridge-arp-nd-suppress', 'default')
+ elif self.arp_nd_suppress_only_on_vxlan and brport_ifaceobj.link_kind & ifaceLinkKind.VXLAN:
+ # ignore the case of VXLAN brport - handled later in the code
+ continue
except:
continue
elif nl_attr == Link.IFLA_BRPORT_GROUP_FWD_MASK:
# IFLA_BRPORT_LEARNING if the user value is already configured and running
# nevertheless we still need to check if the vxlan-learning is rightly synced with
# the brport since it might go out of sync for X and Y reasons.
+ # we also store the cached value to avoid an extra cache lookup.
bridge_ports_learning[brport_name] = user_config_nl
+ cached_bridge_ports_learning[brport_name] = cached_value
elif cached_value is not None:
# no config found, do we need to reset to default?
if default:
default_netlink = translate_func(default)
- if (nl_attr == Link.IFLA_BRPORT_LEARNING
- and not ifupdownflags.flags.PERFMODE
- and brport_name not in newly_enslaved_ports):
- try:
- if self.ipcmd.get_brport_peer_link(brport_name):
- if default_netlink != cached_value:
- self.logger.debug('%s: %s: bridge port peerlink: ignoring bridge-learning'
- % (ifname, brport_name))
- continue
- bridge_ports_learning[brport_name] = default_netlink
- except Exception as e:
- self.logger.debug('%s: %s: peerlink check: %s' % (ifname, brport_name, str(e)))
+ if nl_attr == Link.IFLA_BRPORT_LEARNING:
+ # for vxlan-learning sync purposes we need to save the user config for each brports.
+ # The dictionary 'brports_ifla_info_slave_data' might not contain any value for
+ # IFLA_BRPORT_LEARNING if the user value is already configured and running
+ # nevertheless we still need to check if the vxlan-learning is rightly synced with
+ # the brport since it might go out of sync for X and Y reasons.
+ # we also store the cached value to avoid an extra cache lookup.
+ cached_bridge_ports_learning[brport_name] = cached_value
+ bridge_ports_learning[brport_name] = self.bridge_vxlan_port_learning
+
+ if brport_ifaceobj.link_kind & ifaceLinkKind.VXLAN:
+ # bridge-learning for vxlan device is handled separatly in sync_bridge_learning_to_vxlan_brport
+ continue
+
+ if not ifupdownflags.flags.PERFMODE and brport_name not in newly_enslaved_ports:
+ # We don't query new slaves and not during boot
+ try:
+ if self.cache.get_link_info_slave_data_attribute(brport_name, Link.IFLA_BRPORT_PEER_LINK):
+ if default_netlink != cached_value:
+ self.logger.debug('%s: %s: bridge port peerlink: ignoring bridge-learning'
+ % (ifname, brport_name))
+ continue
+ except Exception as e:
+ self.logger.debug('%s: %s: peerlink check: %s' % (ifname, brport_name, str(e)))
if default_netlink != cached_value:
self.logger.info('%s: %s: %s: no configuration detected, resetting to default %s'
self.logger.debug('(cache %s)' % cached_value)
brports_ifla_info_slave_data[brport_name][nl_attr] = default_netlink
+ # is the current bridge (ifaceobj) a QinQ bridge?
+ # This variable is initialized to None and will be
+ # change to True/False, so that the check is only
+ # performed once
+ qinq_bridge = None
+
# applying bridge port configuration via netlink
for brport_name, brport_ifla_info_slave_data in brports_ifla_info_slave_data.items():
# if the brport is a VXLAN, we might need to sync the VXLAN learning with the brport_learning val
# we use the same netlink request, by specfying kind=vxlan and ifla_info_data={vxlan_learning=0/1}
kind, ifla_info_data = self.sync_bridge_learning_to_vxlan_brport(ifaceobj.name,
- bridge_vlan_aware,
brport_ifaceobj,
brport_name,
brport_ifla_info_slave_data,
- bridge_ports_learning.get(brport_name))
-
- cached_bridge_mcsnoop = self.brctlcmd.link_cache_get([ifname, 'linkinfo', Link.IFLA_BR_MCAST_SNOOPING])
+ bridge_ports_learning.get(brport_name),
+ cached_bridge_ports_learning.get(brport_name))
if (self.vxlan_bridge_igmp_snooping_enable_port_mcrouter and utils.get_boolean_from_string(
self.get_bridge_mcsnoop_value(ifaceobj)
# if policy "vxlan_bridge_igmp_snooping_enable_port_mcrouter"
# is on and mcsnoop is on (or mcsnoop is already enabled on the
# bridge, set 'bridge-portmcrouter 2' on vxlan ports (if not set by the user)
- if not brport_ifla_info_slave_data.get(Link.IFLA_BRPORT_MULTICAST_ROUTER):
+ if not brport_ifla_info_slave_data.get(Link.IFLA_BRPORT_MULTICAST_ROUTER) \
+ and self.cache.get_bridge_port_multicast_router(brport_name) != 2:
brport_ifla_info_slave_data[Link.IFLA_BRPORT_MULTICAST_ROUTER] = 2
self.logger.info("%s: %s: vxlan bridge igmp snooping: enable port multicast router" % (ifname, brport_name))
+
+ #
+ # handling attribute: bridge-arp-nd-suppress
+ # defaults to bridge-vxlan-arp-nd-suppress policy (default False)
+ #
+ user_config_neigh_suppress = bridge_ports_vxlan_arp_suppress.get(brport_name)
+
+ if user_config_neigh_suppress is None:
+
+ if qinq_bridge is None:
+ # QinQ bridge hasn't been checked yet
+ qinq_bridge = self.is_qinq_bridge(
+ ifaceobj,
+ brport_name,
+ running_brports,
+ brport_ifaceobj_dict,
+ ifaceobj_getfunc
+ )
+
+ if qinq_bridge:
+ # exclude QinQ bridge from arp-nd-suppress default policy on
+ config_neigh_suppress = 0
+ self.logger.info("%s: QinQ bridge detected: %s: set bridge-arp-nd-suppress off" % (ifname, brport_name))
+ else:
+ config_neigh_suppress = self.bridge_vxlan_arp_nd_suppress_int
+ else:
+ config_neigh_suppress = int(utils.get_boolean_from_string(user_config_neigh_suppress))
+
+ brport_neigh_suppress_cached_value = self.cache.get_link_info_slave_data_attribute(
+ brport_name,
+ Link.IFLA_BRPORT_NEIGH_SUPPRESS
+ )
+
+ if config_neigh_suppress != brport_neigh_suppress_cached_value:
+ brport_ifla_info_slave_data[Link.IFLA_BRPORT_NEIGH_SUPPRESS] = config_neigh_suppress
+
+ if not user_config_neigh_suppress:
+ # if the configuration is not explicitely defined by the user
+ # we need report that the default behavior is enabled by policy
+ self.logger.info(
+ "%s: set bridge-arp-nd-suppress %s by default on vxlan port (%s)"
+ % (ifname, "on" if self.bridge_vxlan_arp_nd_suppress else "off", brport_name)
+ )
+ else:
+ # the user configuration (or policy) is already configured and running
+ # we need to remove this attribute from the request dictionary
+ try:
+ del brport_ifla_info_slave_data[Link.IFLA_BRPORT_NEIGH_SUPPRESS]
+ except:
+ pass
+
+ #
+ #
+ #
+
else:
kind = None
ifla_info_data = {}
if brport_ifla_info_slave_data or ifla_info_data:
try:
- netlink.link_add_set(ifname=brport_name,
- kind=kind,
- ifla_info_data=ifla_info_data,
- slave_kind='bridge',
- ifla_info_slave_data=brport_ifla_info_slave_data)
+ self.netlink.link_set_brport_with_info_slave_data(
+ ifname=brport_name,
+ kind=kind,
+ ifla_info_data=ifla_info_data,
+ ifla_info_slave_data=brport_ifla_info_slave_data
+ )
except Exception as e:
self.logger.warning('%s: %s: %s' % (ifname, brport_name, str(e)))
- self._set_bridge_vidinfo_compat(ifaceobj)
- self._set_bridge_mcqv4src_compat(ifaceobj)
- self._process_bridge_maxwait(ifaceobj, self._get_bridge_port_list(ifaceobj))
+ self.bridge_process_vidinfo_mcqv4src_maxwait(ifaceobj)
except Exception as e:
self.log_error(str(e), ifaceobj)
+ def is_qinq_bridge(self, ifaceobj, brport_name, running_brports, brport_ifaceobj_dict, ifaceobj_getfunc):
+ """ Detect QinQ bridge
+ Potential improvement: We could add a ifaceobj.link_privflags called
+ BRIDGE_QINQ but for now it is not necessary.
+ """
+
+ # bridge-vlan-aware case
+ if ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VLAN_AWARE:
+ return (ifaceobj.get_attr_value_first("bridge-vlan-protocol") or "").lower() == "802.1ad"
+
+ # old-bridge
+ else:
+ for qinq_running_brport in running_brports:
+ if qinq_running_brport == brport_name:
+ continue
+
+ qinq_running_brport_ifaceobj = brport_ifaceobj_dict.get(qinq_running_brport)
+
+ if not qinq_running_brport_ifaceobj:
+ continue
+
+ if qinq_running_brport_ifaceobj.link_kind & ifaceLinkKind.VLAN:
+ for lower_iface in qinq_running_brport_ifaceobj.lowerifaces or []:
+ for lower_ifaceobj in ifaceobj_getfunc(lower_iface) or []:
+ if (lower_ifaceobj.get_attr_value_first("vlan-protocol") or "").lower() == "802.1ad":
+ return True
+ return False
+
+ def bridge_process_vidinfo_mcqv4src_maxwait(self, ifaceobj):
+ self._set_bridge_vidinfo_compat(ifaceobj)
+ self._set_bridge_mcqv4src_compat(ifaceobj)
+ self._process_bridge_maxwait(ifaceobj, self._get_bridge_port_list(ifaceobj))
+
def ifla_brport_group_fwd_mask(self, ifname, brport_name, brports_ifla_info_slave_data, user_config, cached_ifla_brport_group_fwd_mask):
"""
Support for IFLA_BRPORT_GROUP_FWD_MASK and IFLA_BRPORT_GROUP_FWD_MASKHI
ifla_brport_group_fwd_mask, ifla_brport_group_fwd_maskhi = callback(ifla_brport_group_fwd_mask, ifla_brport_group_fwd_maskhi)
# cached_ifla_brport_group_fwd_mask is given as parameter because it was already pulled out from the cache in the functio above
- cached_ifla_brport_group_fwd_maskhi = self.ipcmd.cache_get_info_slave([brport_name, 'info_slave_data', Link.IFLA_BRPORT_GROUP_FWD_MASKHI])
+ cached_ifla_brport_group_fwd_maskhi = self.cache.get_link_info_slave_data_attribute(brport_name, Link.IFLA_BRPORT_GROUP_FWD_MASKHI)
log_mask_change = True
# if user specify bridge-l2protocol-tunnel stp cdp
ifname = ifaceobj.name
if ifupdownflags.flags.PERFMODE:
- link_just_created = True
link_exists = False
else:
- link_exists = self.ipcmd.link_exists(ifaceobj.name)
- link_just_created = not link_exists
+ link_exists = self.cache.link_exists(ifaceobj.name)
if not link_exists:
- netlink.link_add_bridge(ifname, self.get_bridge_mtu(ifaceobj))
+ self.netlink.link_add_bridge(ifname, mtu=self.get_bridge_mtu(ifaceobj))
+ link_just_created = True
else:
+ link_just_created = False
self.logger.info('%s: bridge already exists' % ifname)
- bridge_vlan_aware = self.up_check_bridge_vlan_aware(ifaceobj, ifaceobj_getfunc, not link_just_created)
+ bridge_vlan_aware = self.up_check_bridge_vlan_aware(ifaceobj, ifaceobj_getfunc, link_just_created)
self.up_apply_bridge_settings(ifaceobj, link_just_created, bridge_vlan_aware)
running_ports = ''
try:
- running_ports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
+ running_ports = self.cache.get_slaves(ifaceobj.name)
if not running_ports:
return
- self.handle_ipv6([], '1', ifaceobj=ifaceobj)
self._apply_bridge_port_settings_all(ifaceobj,
ifaceobj_getfunc=ifaceobj_getfunc,
bridge_vlan_aware=bridge_vlan_aware)
self.logger.warning('%s: apply bridge settings: %s' % (ifname, str(e)))
finally:
if ifaceobj.link_type != ifaceLinkType.LINK_NA:
+ self.iproute2.batch_start()
for p in running_ports:
ifaceobj_list = ifaceobj_getfunc(p)
if (ifaceobj_list and ifaceobj_list[0].link_privflags & ifaceLinkPrivFlags.KEEP_LINK_DOWN):
- netlink.link_set_updown(p, "down")
+ self.iproute2.link_down(p)
continue
- try:
- netlink.link_set_updown(p, "up")
- except Exception, e:
- self.logger.debug('%s: %s: link set up (%s)'
- % (ifaceobj.name, p, str(e)))
- pass
+ self.iproute2.link_up(p)
+ try:
+ self.iproute2.batch_commit()
+ except Exception as e:
+ # link set up on bridge ports failed - ignore and log debug
+ self.logger.debug("%s: %s" % (ifname, str(e)))
try:
self._up_bridge_mac(ifaceobj, ifaceobj_getfunc)
if iface_user_configured_hwaddress:
iface_mac = iface_user_configured_hwaddress
- if not iface_mac and not self.ipcmd.link_exists(bridge_mac_intf):
+ if not iface_mac and not self.cache.link_exists(bridge_mac_intf):
continue
if not iface_mac:
- iface_mac = self.ipcmd.cache_get('link', [bridge_mac_intf, 'hwaddress'])
+ iface_mac = self.cache.get_link_address(bridge_mac_intf)
# if hwaddress attribute is not configured we use the running mac addr
self.bridge_mac_iface = (bridge_mac_intf, iface_mac)
# what we have in the cache (data retrieved via a netlink dump by
# nlmanager). nlmanager return all macs in lower-case
else:
- iface_mac = self.ipcmd.link_get_hwaddress(port)
+ iface_mac = self.cache.get_link_address(port)
if iface_mac:
self.bridge_mac_iface = (port, iface_mac)
def _add_bridge_mac_to_fdb(self, ifaceobj, bridge_mac):
if not ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VLAN_AWARE and bridge_mac and ifaceobj.get_attr_value('address'):
- self.ipcmd.bridge_fdb_add(ifaceobj.name, bridge_mac, vlan=None, bridge=True, remote=None)
+ self.iproute2.bridge_fdb_add(ifaceobj.name, bridge_mac, vlan=None, bridge=True, remote=None)
def _up_bridge_mac(self, ifaceobj, ifaceobj_getfunc):
"""
# the cache_check won't match because nlmanager return "08:00:27:42:42:04"
# from the kernel. The only way to counter that is to convert all mac to int
# and compare the ints, it will increase perfs and be safer.
- cached_value = self.ipcmd.cache_get('link', [ifname, 'hwaddress'])
+ cached_value = self.cache.get_link_address(ifname)
self.logger.debug('%s: cached hwaddress value: %s' % (ifname, cached_value))
- if cached_value and self.ipcmd.mac_str_to_int(cached_value) == self.ipcmd.mac_str_to_int(bridge_mac):
+ if cached_value and utils.mac_str_to_int(cached_value) == utils.mac_str_to_int(bridge_mac):
# the bridge mac is already set to the bridge_mac_intf's mac
return
self.logger.info('%s: setting bridge mac to port %s mac' % (ifname, mac_intf))
try:
- self.ipcmd.link_set(ifname, 'address', value=bridge_mac, force=True)
+ self.netlink.link_set_address(ifname, bridge_mac) # force=True
except Exception as e:
self.logger.info('%s: %s' % (ifname, str(e)))
# log info this error because the user didn't explicitly configured this
else:
- self._add_bridge_mac_to_fdb(ifaceobj, self.ipcmd.link_get_hwaddress(ifname))
+ self._add_bridge_mac_to_fdb(ifaceobj, self.cache.get_link_address(ifname))
def _up(self, ifaceobj, ifaceobj_getfunc=None):
if ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT:
if not self._is_bridge(ifaceobj):
return
ifname = ifaceobj.name
- if not self.ipcmd.link_exists(ifname):
+ if not self.cache.link_exists(ifname):
return
try:
- running_ports = self.brctlcmd.get_bridge_ports(ifname)
+ running_ports = self.cache.get_slaves(ifname)
if running_ports:
self.handle_ipv6(running_ports, '0')
if ifaceobj.link_type != ifaceLinkType.LINK_NA:
- map(lambda p: netlink.link_set_updown(p, 'down'), running_ports)
+ map(lambda p: self.netlink.link_down(p), running_ports)
except Exception as e:
self.log_error('%s: %s' % (ifaceobj.name, str(e)), ifaceobj)
try:
- netlink.link_del(ifname)
-
- if utils.get_boolean_from_string(ifupdownconfig.config.get("ifreload_down_changed")):
- self.ipcmd.del_cache_entry(ifname)
- for upper in ifaceobj.upperifaces or []:
- try:
- self.ipcmd.del_cache_entry(upper)
- except:
- pass
+ self.netlink.link_del(ifname)
except Exception as e:
ifaceobj.set_status(ifaceStatus.ERROR)
self.logger.error(str(e))
running_bridge_port_vids = ''
for p in ports:
try:
- running_vids = self._get_runing_vids(p)
+ _, running_vids = self.cache.get_pvid_and_vids(p)
if running_vids:
running_bridge_port_vids += ' %s=%s' %(p,
','.join(running_vids))
running_bridge_port_pvid = ''
for p in ports:
try:
- running_pvid = self._get_runing_pvid(p)
+ running_pvid = self.cache.get_pvid(p)
if running_pvid:
running_bridge_port_pvid += ' %s=%s' %(p,
running_pvid)
pass
running_attrs['bridge-port-pvids'] = running_bridge_port_pvid
- running_bridge_vids = self.ipcmd.bridge_vlan_get_vids(ifaceobjrunning.name)
+ _, running_bridge_vids = self.cache.get_pvid_and_vids(ifaceobjrunning.name)
if running_bridge_vids:
running_attrs['bridge-vids'] = ','.join(self._compress_into_ranges(running_bridge_vids))
return running_attrs
return running_attrs
def _query_running_mcqv4src(self, ifaceobjrunning):
- running_mcqv4src = self.brctlcmd.bridge_get_mcqv4src_sysfs(ifaceobjrunning.name)
+ running_mcqv4src = self.sysfs.bridge_get_mcqv4src(ifaceobjrunning.name)
mcqs = ['%s=%s' %(v, i) for v, i in running_mcqv4src.items()]
mcqs.sort()
mcq = ' '.join(mcqs)
def _query_running_attrs(self, ifaceobjrunning, ifaceobj_getfunc,
bridge_vlan_aware=False):
+
+ ifname = ifaceobjrunning.name
bridgeattrdict = {}
userspace_stp = 0
ports = None
- skip_kernel_stp_attrs = 0
-
try:
if self.systcl_get_net_bridge_stp_user_space() == '1':
userspace_stp = 1
except Exception as e:
self.logger.info('%s: %s' % (ifaceobjrunning.name, str(e)))
- tmpbridgeattrdict = self.brctlcmd.get_bridge_attrs(ifaceobjrunning.name)
- if not tmpbridgeattrdict:
- self.logger.warn('%s: unable to get bridge attrs'
- %ifaceobjrunning.name)
- return bridgeattrdict
+ bridge_ifla_info_data = self.cache.get_link_info_data(ifname)
+
# Fill bridge_ports and bridge stp attributes first
- ports = tmpbridgeattrdict.get('ports')
- if ports:
- bridgeattrdict['bridge-ports'] = [' '.join(ports.keys())]
- stp = tmpbridgeattrdict.get('stp', 'no')
- if stp != self.get_mod_subattr('bridge-stp', 'default'):
- bridgeattrdict['bridge-stp'] = [stp]
-
- if stp == 'yes' and userspace_stp:
- skip_kernel_stp_attrs = 1
-
- vlan_stats = utils.get_onff_from_onezero(
- tmpbridgeattrdict.get('vlan-stats', None))
- if (vlan_stats and
- vlan_stats != self.get_mod_subattr('bridge-vlan-stats', 'default')):
- bridgeattrdict['bridge-vlan-stats'] = [vlan_stats]
-
- bool2str = {'0': 'no', '1': 'yes'}
- # pick all other attributes
- for k,v in tmpbridgeattrdict.items():
- if not v:
- continue
- if k == 'ports' or k == 'stp':
- continue
+ #
+ # bridge-ports
+ #
+ bridgeattrdict["bridge-ports"] = [" ".join(self.cache.get_slaves(ifname))]
+
+ #
+ # bridge-stp
+ #
+ cached_stp = bool(bridge_ifla_info_data.get(Link.IFLA_BR_STP_STATE))
+
+ if cached_stp != utils.get_boolean_from_string(
+ self.get_mod_subattr("bridge-stp", "default")
+ ):
+ bridgeattrdict['bridge-stp'] = ["yes" if cached_stp else "no"]
+
+ skip_kernel_stp_attrs = cached_stp and userspace_stp
+
+ if skip_kernel_stp_attrs:
+ bridge_attributes_map = {
+ "bridge-mcqifaddr": Link.IFLA_BR_MCAST_QUERY_USE_IFADDR,
+ "bridge-mcquerier": Link.IFLA_BR_MCAST_QUERIER,
+ "bridge-mcrouter": Link.IFLA_BR_MCAST_ROUTER,
+ "bridge-mcstats": Link.IFLA_BR_MCAST_STATS_ENABLED,
+ "bridge-mcsnoop": Link.IFLA_BR_MCAST_SNOOPING,
+ "bridge-mclmc": Link.IFLA_BR_MCAST_LAST_MEMBER_CNT,
+ "bridge-mclmi": Link.IFLA_BR_MCAST_LAST_MEMBER_INTVL,
+ "bridge-mcqri": Link.IFLA_BR_MCAST_QUERY_RESPONSE_INTVL,
+ "bridge-mcqpi": Link.IFLA_BR_MCAST_QUERIER_INTVL,
+ "bridge-mcsqc": Link.IFLA_BR_MCAST_STARTUP_QUERY_CNT,
+ "bridge-mcsqi": Link.IFLA_BR_MCAST_STARTUP_QUERY_INTVL,
+ "bridge-mcmi": Link.IFLA_BR_MCAST_MEMBERSHIP_INTVL,
+ "bridge-mcqi": Link.IFLA_BR_MCAST_QUERY_INTVL,
+ }
+ else:
+ bridge_attributes_map = dict(self._ifla_br_attributes_map)
+ try:
+ del bridge_attributes_map[Link.IFLA_BR_STP_STATE]
+ except:
+ pass
+
+ #
+ # bridge-vlan-stats
+ #
+ cached_vlan_stats = bridge_ifla_info_data.get(Link.IFLA_BR_VLAN_STATS_ENABLED)
+
+ if cached_vlan_stats != utils.get_boolean_from_string(
+ self.get_mod_subattr("bridge-vlan-stats", "default")
+ ):
+ bridgeattrdict['bridge-vlan-stats'] = ["on" if cached_vlan_stats else "off"]
+
+ try:
+ del bridge_attributes_map[Link.IFLA_BR_VLAN_STATS_ENABLED]
+ except:
+ pass
- if skip_kernel_stp_attrs and k[:2] != 'mc':
- # only include igmp attributes if kernel stp is off
+ lambda_nl_value_int_divide100 = lambda x: str(x / 100)
+ lambda_nl_value_to_yes_no_boolean = lambda x: "yes" if x else "no"
+
+ bridge_attr_value_netlink_to_string_dict = {
+ Link.IFLA_BR_VLAN_PROTOCOL: lambda x: x.lower(), # return lower case vlan protocol
+ Link.IFLA_BR_AGEING_TIME: lambda_nl_value_int_divide100,
+ Link.IFLA_BR_MAX_AGE: lambda_nl_value_int_divide100,
+ Link.IFLA_BR_FORWARD_DELAY: lambda_nl_value_int_divide100,
+ Link.IFLA_BR_HELLO_TIME: lambda_nl_value_int_divide100,
+ Link.IFLA_BR_MCAST_MEMBERSHIP_INTVL: lambda_nl_value_int_divide100,
+ Link.IFLA_BR_MCAST_STARTUP_QUERY_INTVL: lambda_nl_value_int_divide100,
+ Link.IFLA_BR_MCAST_LAST_MEMBER_INTVL: lambda_nl_value_int_divide100,
+ Link.IFLA_BR_MCAST_QUERY_RESPONSE_INTVL: lambda_nl_value_int_divide100,
+ Link.IFLA_BR_MCAST_QUERIER_INTVL: lambda_nl_value_int_divide100,
+ Link.IFLA_BR_MCAST_QUERY_INTVL: lambda_nl_value_int_divide100,
+ Link.IFLA_BR_VLAN_FILTERING: lambda_nl_value_to_yes_no_boolean,
+ Link.IFLA_BR_MCAST_QUERY_USE_IFADDR: lambda_nl_value_to_yes_no_boolean,
+ Link.IFLA_BR_MCAST_SNOOPING: lambda_nl_value_to_yes_no_boolean,
+ Link.IFLA_BR_MCAST_QUERIER: lambda_nl_value_to_yes_no_boolean,
+ Link.IFLA_BR_MCAST_ROUTER: lambda_nl_value_to_yes_no_boolean,
+ }
+
+ for attr_name, attr_nl in bridge_attributes_map.iteritems():
+ default_value = self.get_mod_subattr(attr_name, "default")
+ cached_value = bridge_ifla_info_data.get(attr_nl)
+
+ if cached_value is None:
continue
- attrname = 'bridge-' + k
- mod_default = self.get_mod_subattr(attrname, 'default')
- if v != mod_default:
- # convert '0|1' running values to 'no|yes'
- if v in bool2str.keys() and bool2str[v] == mod_default:
- continue
- bridgeattrdict[attrname] = [v]
+
+ cached_value_string = bridge_attr_value_netlink_to_string_dict.get(attr_nl, str)(cached_value)
+
+ if default_value != cached_value_string:
+ bridgeattrdict[attr_name] = [cached_value_string]
if bridge_vlan_aware:
if not ports:
'bridge-learning' : '',
'bridge-unicast-flood' : '',
'bridge-multicast-flood' : '',
+ 'bridge-broadcast-flood' : '',
'bridge-arp-nd-suppress' : '',
}
for p, v in ports.items():
- v = self.brctlcmd.bridge_get_pathcost(ifaceobjrunning.name, p)
+ v = str(self.cache.get_brport_cost(p))
if v and v != self.get_mod_subattr('bridge-pathcosts',
'default'):
portconfig['bridge-pathcosts'] += ' %s=%s' %(p, v)
- v = self.brctlcmd.bridge_get_portprio(ifaceobjrunning.name, p)
+ v = str(self.cache.get_brport_priority(p))
if v and v != self.get_mod_subattr('bridge-portprios',
'default'):
portconfig['bridge-portprios'] += ' %s=%s' %(p, v)
- v = utils.get_onff_from_onezero(
- self.brctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
- p, 'learning'))
+ v = utils.get_onff_from_onezero(self.cache.get_brport_learning(p))
if (v and
v != self.get_mod_subattr('bridge-learning', 'default')):
portconfig['bridge-learning'] += ' %s=%s' %(p, v)
- v = utils.get_onff_from_onezero(
- self.brctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
- p, 'unicast-flood'))
+ v = utils.get_onff_from_onezero(self.cache.get_brport_unicast_flood(p))
if (v and
v != self.get_mod_subattr('bridge-unicast-flood',
'default')):
portconfig['bridge-unicast-flood'] += ' %s=%s' %(p, v)
- v = utils.get_onff_from_onezero(
- self.brctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
- p, 'multicast-flood'))
+ v = utils.get_onff_from_onezero(self.cache.get_brport_multicast_flood(p))
if (v and
v != self.get_mod_subattr('bridge-multicast-flood',
'default')):
portconfig['bridge-multicast-flood'] += ' %s=%s' %(p, v)
- v = utils.get_onff_from_onezero(
- self.brctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
- p, 'arp-nd-suppress'))
+ v = utils.get_onff_from_onezero(self.cache.get_brport_broadcast_flood(p))
+ if (v and
+ v != self.get_mod_subattr('bridge-broadcast-flood',
+ 'default')):
+ portconfig['bridge-broadcast-flood'] += ' %s=%s' %(p, v)
+
+ v = utils.get_onff_from_onezero(self.cache.get_brport_neigh_suppress(p))
if (v and
v != self.get_mod_subattr('bridge-arp-nd-suppress',
'default')):
ifaceobjcurr.update_config_with_status('bridge-mcqv4src',
running_mcqs, 1 if running_mcqs != mcqsout else 0)
- def _query_check_bridge_vidinfo(self, ifaceobj, ifaceobjcurr):
- err = 0
- attrval = ifaceobj.get_attr_value_first('bridge-port-vids')
- if attrval:
- running_bridge_port_vids = ''
- portlist = self.parse_port_list(ifaceobj.name, attrval)
- if not portlist:
- self.log_warn('%s: could not parse \'bridge-port-vids %s\''
- %(ifaceobj.name, attrval))
+ def _query_check_bridge_vidinfo(self, ifname, ifaceobj, ifaceobjcurr):
+ #
+ # bridge-port-vids
+ #
+ bridge_port_vids_user_config = ifaceobj.get_attr_value_first("bridge-port-vids")
+ if bridge_port_vids_user_config:
+
+ port_list = self.parse_port_list(ifname, bridge_port_vids_user_config)
+
+ if not port_list:
+ self.log_warn("%s: could not parse 'bridge-port-vids %s'"
+ % (ifname, bridge_port_vids_user_config))
+ ifaceobjcurr.update_config_with_status("bridge-port-vids", "ERROR", 1)
return
- err = 0
- for p in portlist:
+
+ error = False
+ for port_config in port_list:
try:
- (port, val) = p.split('=')
- vids = val.split(',')
- running_vids = self.ipcmd.bridge_vlan_get_vids(port)
- if running_vids:
- if not self._compare_vids(vids, running_vids):
- err += 1
- running_bridge_port_vids += ' %s=%s' %(port,
- ','.join(running_vids))
- else:
- running_bridge_port_vids += ' %s' %p
- else:
- err += 1
- except Exception, e:
- self.log_warn('%s: failure checking vid %s (%s)'
- %(ifaceobj.name, p, str(e)))
- if err:
- ifaceobjcurr.update_config_with_status('bridge-port-vids',
- running_bridge_port_vids, 1)
- else:
- ifaceobjcurr.update_config_with_status('bridge-port-vids',
- attrval, 0)
+ port, vids_raw = port_config.split("=")
+ packed_vids = vids_raw.split(",")
+
+ running_pvid, running_vids = self.cache.get_pvid_and_vids(port)
+
+ if not self._compare_vids(packed_vids, running_vids, pvid=running_pvid, expand_range=False):
+ error = True
+ except Exception as e:
+ self.log_warn("%s: failure checking vid %s (%s)" % (ifname, port_config, str(e)))
+
+ ifaceobjcurr.update_config_with_status("bridge-port-vids", bridge_port_vids_user_config, error)
+
+ #
+ # bridge-port-pvids
+ #
attrval = ifaceobj.get_attr_value_first('bridge-port-pvids')
if attrval:
portlist = self.parse_port_list(ifaceobj.name, attrval)
if not portlist:
self.log_warn('%s: could not parse \'bridge-port-pvids %s\''
- %(ifaceobj.name, attrval))
+ % (ifname, attrval))
return
- running_bridge_port_pvids = ''
- err = 0
+
+ error = False
+ running_pvid_config = []
for p in portlist:
- try:
- (port, pvid) = p.split('=')
- running_pvid = self.ipcmd.bridge_vlan_get_vids(port)
- if running_pvid and running_pvid == pvid:
- running_bridge_port_pvids += ' %s' %p
- else:
- err += 1
- running_bridge_port_pvids += ' %s=%s' %(port,
- running_pvid)
- except Exception, e:
- self.log_warn('%s: failure checking pvid %s (%s)'
- %(ifaceobj.name, pvid, str(e)))
- if err:
- ifaceobjcurr.update_config_with_status('bridge-port-pvids',
- running_bridge_port_pvids, 1)
- else:
- ifaceobjcurr.update_config_with_status('bridge-port-pvids',
- running_bridge_port_pvids, 0)
+ (port, pvid) = p.split('=')
+ running_pvid, _ = self.cache.get_pvid_and_vids(port)
+
+ running_pvid_config.append("%s=%s" % (port, running_pvid))
+
+ if running_pvid != int(pvid):
+ error = True
+
+ ifaceobjcurr.update_config_with_status(
+ "bridge-port-pvids",
+ " ".join(running_pvid_config),
+ int(error)
+ )
vids = self.get_ifaceobj_bridge_vids(ifaceobj)
if vids[1]:
and ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VXLAN):
ifaceobj.replace_config('bridge-mcsnoop', 'no')
- def _query_check_bridge(self, ifaceobj, ifaceobjcurr,
- ifaceobj_getfunc=None):
+ def _query_check_bridge(self, ifaceobj, ifaceobjcurr, ifaceobj_getfunc=None):
if not self._is_bridge(ifaceobj):
return
- if not self.brctlcmd.bridge_exists(ifaceobj.name):
- self.logger.info('%s: bridge: does not exist' %(ifaceobj.name))
- return
- self._query_check_snooping_wdefault(ifaceobj)
+ ifname = ifaceobj.name
- ifaceattrs = self.dict_key_subset(ifaceobj.config,
- self.get_mod_attrs())
- #Add default attributes if --with-defaults is set
- if ifupdownflags.flags.WITHDEFAULTS and 'bridge-stp' not in ifaceattrs:
- ifaceattrs.append('bridge-stp')
- if not ifaceattrs:
+ if not self.cache.bridge_exists(ifname):
+ self.logger.info("%s: bridge: does not exist" % (ifname))
return
- try:
- runningattrs = self.brctlcmd.get_bridge_attrs(ifaceobj.name)
- if not runningattrs:
- self.logger.debug('%s: bridge: unable to get bridge attrs'
- %ifaceobj.name)
- runningattrs = {}
- except Exception, e:
- self.logger.warn(str(e))
- runningattrs = {}
- self._query_check_support_yesno_attrs(runningattrs, ifaceobj)
+ self._query_check_snooping_wdefault(ifaceobj)
- filterattrs = ['bridge-vids', 'bridge-trunk', 'bridge-port-vids',
- 'bridge-port-pvids']
+ user_config_attributes = self.dict_key_subset(ifaceobj.config, self.get_mod_attrs())
- diff = Set(ifaceattrs).difference(filterattrs)
+ # add default attributes if --with-defaults is set
+ if ifupdownflags.flags.WITHDEFAULTS and 'bridge-stp' not in user_config_attributes:
+ user_config_attributes.append('bridge-stp')
- if 'bridge-l2protocol-tunnel' in diff:
- diff.remove('bridge-l2protocol-tunnel')
- # bridge-l2protocol-tunnel requires separate handling
+ if not user_config_attributes:
+ return
- if 'bridge-ports' in diff:
- self.query_check_bridge_ports(ifaceobj, ifaceobjcurr, runningattrs.get('ports', {}).keys(), ifaceobj_getfunc)
- diff.remove('bridge-ports')
+ if "bridge-ports" in user_config_attributes:
+ self.query_check_bridge_ports(ifaceobj, ifaceobjcurr, self.cache.get_slaves(ifname), ifaceobj_getfunc)
- if "bridge-ports-condone-regex" in diff:
+ if "bridge-ports-condone-regex" in user_config_attributes:
ifaceobjcurr.update_config_with_status(
"bridge-ports-condone-regex",
self._get_bridge_port_condone_regex(ifaceobj, True),
0
)
- diff.remove("bridge-ports-condone-regex")
-
- for k in diff:
- # get the corresponding ifaceobj attr
- v = ifaceobj.get_attr_value_first(k)
- if not v:
- if ifupdownflags.flags.WITHDEFAULTS and k == 'bridge-stp':
- v = 'on' if self.default_stp_on else 'off'
- else:
- continue
- rv = runningattrs.get(k[7:])
- if k == 'bridge-mcqv4src':
- continue
- if k == 'bridge-maxwait' or k == 'bridge-waitport':
- ifaceobjcurr.update_config_with_status(k, v, 0)
+
+ # Those attributes require separate handling
+ filter_attributes = [
+ "bridge-trunk",
+ "bridge-ports",
+ "bridge-vids",
+ "bridge-trunk",
+ "bridge-mcqv4src",
+ "bridge-port-vids",
+ "bridge-port-pvids",
+ "bridge-l2protocol-tunnel",
+ "bridge-ports-condone-regex"
+ ]
+
+ ignore_attributes = (
+ # bridge-pvid and bridge-vids on a bridge does not correspond
+ # directly to a running config on the bridge. They correspond to
+ # default values for the bridge ports. And they are already checked
+ # against running config of the bridge port and reported against a
+ # bridge port. So, ignore these attributes under the bridge. Use '2'
+ # for ignore today. XXX: '2' will be mapped to a defined value in
+ # subsequent patches.
+ "bridge-pvid",
+ "bridge-allow-untagged",
+ )
+ for attr in ignore_attributes:
+ if attr in user_config_attributes:
+ ifaceobjcurr.update_config_with_status(attr, ifaceobj.get_attr_value_first(attr), 2)
+ filter_attributes.append(attr)
+
+ bridge_config = Set(user_config_attributes).difference(filter_attributes)
+ cached_ifla_info_data = self.cache.get_link_info_data(ifname)
+
+ self._query_check_bridge_attributes(ifaceobj, ifaceobjcurr, bridge_config, cached_ifla_info_data)
+ self._query_check_brport_attributes_on_bridge(ifname, ifaceobj, ifaceobjcurr, bridge_config)
+ self._query_check_bridge_vidinfo(ifname, ifaceobj, ifaceobjcurr)
+ self._query_check_mcqv4src(ifaceobj, ifaceobjcurr)
+ self._query_check_l2protocol_tunnel_on_bridge(ifname, ifaceobj, ifaceobjcurr)
+
+ def _query_check_bridge_attributes(self, ifaceobj, ifaceobjcurr, bridge_config, cached_ifla_info_data):
+ for attr in list(bridge_config):
+ query_check_handler, netlink_attr = self._bridge_attribute_query_check_handler.get(attr, (None, None))
+
+ if callable(query_check_handler):
+ query_check_handler(attr, ifaceobj.get_attr_value_first(attr), ifaceobjcurr, cached_ifla_info_data.get(netlink_attr))
+ bridge_config.remove(attr)
+
+ def _query_check_brport_attributes_on_bridge(self, ifname, ifaceobj, ifaceobjcurr, bridge_config):
+ brports_info_slave_data = {}
+ # bridge_config should only have bridge-port-list attributes
+ for attr in bridge_config:
+ attr_nl = self._ifla_brport_attributes_map.get(attr)
+ brport_query_check_handler = self._brport_attribute_query_check_handler.get(attr)
+
+ if not attr_nl or not brport_query_check_handler:
+ self.logger.warning("%s: query-check: missing handler for attribute: %s (%s)" % (ifname, attr, attr_nl))
continue
- if k == 'bridge-vlan-aware':
- rv = self.ipcmd.bridge_is_vlan_aware(ifaceobj.name)
- if (rv and v == 'yes') or (not rv and v == 'no'):
- ifaceobjcurr.update_config_with_status('bridge-vlan-aware',
- v, 0)
- else:
- ifaceobjcurr.update_config_with_status('bridge-vlan-aware',
- v, 1)
- elif k == 'bridge-stp':
- # special case stp compare because it may
- # contain more than one valid values
- stp_on_vals = ['on', 'yes']
- stp_off_vals = ['off', 'no']
- if ((v in stp_on_vals and rv in stp_on_vals) or
- (v in stp_off_vals and rv in stp_off_vals)):
- ifaceobjcurr.update_config_with_status('bridge-stp',
- rv, 0)
- else:
- ifaceobjcurr.update_config_with_status('bridge-stp',
- rv, 1)
- elif k in ['bridge-pathcosts',
- 'bridge-portprios',
- 'bridge-portmcrouter',
- 'bridge-portmcfl',
- 'bridge-learning',
- 'bridge-unicast-flood',
- 'bridge-multicast-flood',
- 'bridge-arp-nd-suppress',
- ]:
- if k == 'bridge-arp-nd-suppress':
- brctlcmdattrname = k[7:]
- else:
- brctlcmdattrname = k[7:].rstrip('s')
- # for port attributes, the attributes are in a list
- # <portname>=<portattrvalue>
- status = 0
- currstr = ''
- vlist = self.parse_port_list(ifaceobj.name, v)
- if not vlist:
- continue
- for vlistitem in vlist:
- try:
- (p, v) = vlistitem.split('=')
- if k in ['bridge-learning',
- 'bridge-unicast-flood',
- 'bridge-multicast-flood',
- 'bridge-arp-nd-suppress',
- ]:
- currv = utils.get_onoff_bool(
- self.brctlcmd.get_bridgeport_attr(
- ifaceobj.name, p,
- brctlcmdattrname))
- else:
- currv = self.brctlcmd.get_bridgeport_attr(
- ifaceobj.name, p,
- brctlcmdattrname)
- if currv:
- currstr += ' %s=%s' %(p, currv)
- else:
- currstr += ' %s=%s' %(p, 'None')
-
- if k == 'bridge-portmcrouter':
- if self._ifla_brport_multicast_router_dict_to_int.get(v) != int(currv):
- status = 1
- elif currv != v:
- status = 1
- except Exception, e:
- self.log_warn(str(e))
- pass
- ifaceobjcurr.update_config_with_status(k, currstr, status)
- elif k == 'bridge-vlan-stats' or k == 'bridge-mcstats':
- rv = utils.get_onff_from_onezero(rv)
- if v != rv:
- ifaceobjcurr.update_config_with_status(k, rv, 1)
+
+ running_config = []
+ status = 0
+
+ for port_config in self.parse_port_list(ifname, ifaceobj.get_attr_value_first(attr)) or []:
+ port, config = port_config.split("=")
+
+ if not port in brports_info_slave_data:
+ info_slave_data = brports_info_slave_data[port] = self.cache.get_link_info_slave_data(port)
else:
- ifaceobjcurr.update_config_with_status(k, rv, 0)
- elif not rv:
- if k == 'bridge-pvid' or k == 'bridge-vids' or k == 'bridge-trunk' or k == 'bridge-allow-untagged':
- # bridge-pvid and bridge-vids on a bridge does
- # not correspond directly to a running config
- # on the bridge. They correspond to default
- # values for the bridge ports. And they are
- # already checked against running config of the
- # bridge port and reported against a bridge port.
- # So, ignore these attributes under the bridge.
- # Use '2' for ignore today. XXX: '2' will be
- # mapped to a defined value in subsequent patches.
- ifaceobjcurr.update_config_with_status(k, v, 2)
- else:
- ifaceobjcurr.update_config_with_status(k, 'notfound', 1)
- continue
- elif v.upper() != rv.upper():
- ifaceobjcurr.update_config_with_status(k, rv, 1)
+ info_slave_data = brports_info_slave_data[port]
+
+ port_config, port_status = brport_query_check_handler(port, config, info_slave_data.get(attr_nl))
+
+ running_config.append(port_config)
+
+ if port_status:
+ status = 1
+
+ ifaceobjcurr.update_config_with_status(
+ attr,
+ " ".join(running_config),
+ status
+ )
+
+ @staticmethod
+ def _query_check_br_attr_wait(attr, wait_value, ifaceobjcurr, __):
+ ifaceobjcurr.update_config_with_status(attr, wait_value, 0)
+
+ def _query_check_br_attr_stp(self, attr, stp_value, ifaceobjcurr, cached_value):
+ if not stp_value:
+ if ifupdownflags.flags.WITHDEFAULTS:
+ stp_value = "on" if self.default_stp_on else "off"
else:
- ifaceobjcurr.update_config_with_status(k, rv, 0)
+ return
- self._query_check_bridge_vidinfo(ifaceobj, ifaceobjcurr)
+ user_config_to_nl = utils.get_boolean_from_string(stp_value)
- self._query_check_mcqv4src(ifaceobj, ifaceobjcurr)
- self._query_check_l2protocol_tunnel_on_bridge(ifaceobj, ifaceobjcurr, runningattrs)
+ ifaceobjcurr.update_config_with_status(
+ attr,
+ "yes" if cached_value else "no",
+ user_config_to_nl != bool(cached_value)
+ )
+
+ @staticmethod
+ def _query_check_br_attr_int(attr, user_config, ifaceobjcurr, cached_value):
+ ifaceobjcurr.update_config_with_status(
+ attr,
+ str(cached_value),
+ int(user_config) != cached_value
+ )
+
+ @staticmethod
+ def _query_check_br_attr_int_divided100(attr, user_config, ifaceobjcurr, cached_value):
+ value = cached_value / 100
+ ifaceobjcurr.update_config_with_status(
+ attr,
+ str(value),
+ int(user_config) != value
+ )
+
+ @staticmethod
+ def _query_check_br_attr_boolean(attr, user_config, ifaceobjcurr, cached_value):
+ ifaceobjcurr.update_config_with_status(
+ attr,
+ "yes" if cached_value else "no",
+ utils.get_boolean_from_string(user_config) != cached_value
+ )
+
+ @staticmethod
+ def _query_check_br_attr_boolean_on_off(attr, user_config, ifaceobjcurr, cached_value):
+ ifaceobjcurr.update_config_with_status(
+ attr,
+ "on" if cached_value else "off",
+ utils.get_boolean_from_string(user_config) != cached_value
+ )
+
+ @staticmethod
+ def _query_check_br_attr_string(attr, user_config, ifaceobjcurr, cached_value):
+ ifaceobjcurr.update_config_with_status(
+ attr,
+ cached_value,
+ user_config.lower() != cached_value
+ )
+
+ @staticmethod
+ def _query_check_brport_attr_boolean_on_off(port, user_config, cached_value):
+ return "%s=%s" % (port, "on" if cached_value else "off"), utils.get_boolean_from_string(user_config) != cached_value
+
+ @staticmethod
+ def _query_check_brport_attr_boolean_yes_no(port, user_config, cached_value):
+ return "%s=%s" % (port, "yes" if cached_value else "no"), utils.get_boolean_from_string(user_config) != cached_value
+
+ @staticmethod
+ def _query_check_brport_attr_int(port, user_config, cached_value):
+ return "%s=%s" % (port, cached_value), int(user_config) != cached_value
+
+ @classmethod
+ def _query_check_brport_attr_portmcrouter(cls, port, user_config, cached_value):
+ return (
+ "%s=%s" % (port, cls._ifla_brport_multicast_router_dict_int_to_str.get(cached_value)),
+ cls._ifla_brport_multicast_router_dict_to_int.get(user_config) != cached_value
+ )
+
+ ####################################################################################################################
def query_check_bridge_ports(self, ifaceobj, ifaceobjcurr, running_port_list, ifaceobj_getfunc):
bridge_all_ports = []
break
return pvid
- def _get_bridge_name(self, ifaceobj):
- return self.ipcmd.bridge_port_get_bridge_name(ifaceobj.name)
-
- def _query_check_bridge_port_vidinfo(self, ifaceobj, ifaceobjcurr,
- ifaceobj_getfunc, bridgename):
- attr_name = 'bridge-access'
- vid = ifaceobj.get_attr_value_first(attr_name)
- if vid:
- (running_vids, running_pvid) = self._get_running_vids_n_pvid_str(
- ifaceobj.name)
- if (not running_pvid or running_pvid != vid or
- (running_vids and running_vids[0] != vid)):
- ifaceobjcurr.update_config_with_status(attr_name,
- running_pvid, 1)
- else:
- ifaceobjcurr.update_config_with_status(attr_name, vid, 0)
+ def _query_check_bridge_port_vidinfo(self, ifname, bridge_name, ifaceobj, ifaceobjcurr, ifaceobj_getfunc):
+ running_pvid, running_vids = self.cache.get_pvid_and_vids(ifname)
+
+ #
+ # bridge-access
+ #
+ brport_vid_access_user_config = ifaceobj.get_attr_value_first("bridge-access")
+
+ if brport_vid_access_user_config:
+ try:
+ vid_int = int(brport_vid_access_user_config)
+ except ValueError as e:
+ ifaceobjcurr.update_config_with_status("bridge-access", brport_vid_access_user_config, 1)
+ raise Exception("%s: bridge-access invalid value: %s" % (ifname, str(e)))
+
+ ifaceobjcurr.update_config_with_status(
+ "bridge-access",
+ str(running_pvid),
+ running_pvid != vid_int or running_vids[0] != vid_int
+ )
return
- (running_vids, running_pvid) = self._get_running_vids_n_pvid_str(
- ifaceobj.name)
- attr_name = 'bridge-pvid'
- pvid = ifaceobj.get_attr_value_first('bridge-pvid')
- if pvid:
- if running_pvid and running_pvid == pvid:
- ifaceobjcurr.update_config_with_status(attr_name,
- running_pvid, 0)
- else:
- ifaceobjcurr.update_config_with_status(attr_name,
- running_pvid, 1)
+ #
+ # bridge-pvid
+ #
+ brport_pvid_user_config = ifaceobj.get_attr_value_first("bridge-pvid")
+
+ if brport_pvid_user_config:
+ try:
+ pvid = int(brport_pvid_user_config)
+ except ValueError as e:
+ ifaceobjcurr.update_config_with_status("bridge-pvid", brport_pvid_user_config, 1)
+ raise Exception("%s: bridge-pvid invalid value: %s" % (ifname, str(e)))
+
+ ifaceobjcurr.update_config_with_status(
+ "bridge-pvid",
+ str(running_pvid),
+ running_pvid != pvid
+ )
elif (not (ifaceobj.flags & iface.HAS_SIBLINGS) or
((ifaceobj.flags & iface.HAS_SIBLINGS) and
(ifaceobj.flags & iface.OLDEST_SIBLING))):
# if the interface has multiple iface sections,
# we check the below only for the oldest sibling
# or the last iface section
- pvid = self._get_bridge_pvid(bridgename, ifaceobj_getfunc)
+ try:
+ pvid = int(self._get_bridge_pvid(bridge_name, ifaceobj_getfunc))
+ except (TypeError, ValueError):
+ pvid = 0
if pvid:
if not running_pvid or running_pvid != pvid:
ifaceobjcurr.status = ifaceStatus.ERROR
ifaceobjcurr.status_str = 'bridge pvid error'
- elif not running_pvid or running_pvid != '1':
+ elif not running_pvid or running_pvid != 1:
ifaceobjcurr.status = ifaceStatus.ERROR
ifaceobjcurr.status_str = 'bridge pvid error'
attr_name, vids = self.get_ifaceobj_bridge_vids(ifaceobj)
if vids:
vids = re.split(r'[\s\t]\s*', vids)
- if not running_vids or not self._compare_vids(vids, running_vids,
- running_pvid):
+ if not running_vids or not self._compare_vids(vids, running_vids, running_pvid, expand_range=False):
ifaceobjcurr.update_config_with_status(attr_name,
' '.join(running_vids), 1)
else:
# or the last iface section
# check if it matches the bridge vids
- bridge_vids = self._get_bridge_vids(bridgename, ifaceobj_getfunc)
+ bridge_vids = self._get_bridge_vids(bridge_name, ifaceobj_getfunc)
if (bridge_vids and (not running_vids or
- not self._compare_vids(bridge_vids, running_vids, running_pvid))):
+ not self._compare_vids(bridge_vids, running_vids, running_pvid, expand_range=False))):
ifaceobjcurr.status = ifaceStatus.ERROR
ifaceobjcurr.status_str = 'bridge vid error'
+ _query_check_brport_attributes = (
+ "bridge-pvid",
+ "bridge-vids",
+ "bridge-trunk",
+ "bridge-access",
+ "bridge-pathcosts",
+ "bridge-portprios",
+ "bridge-portmcrouter",
+ "bridge-learning",
+ "bridge-portmcfl",
+ "bridge-unicast-flood",
+ "bridge-multicast-flood",
+ "bridge-broadcast-flood",
+ "bridge-arp-nd-suppress",
+ "bridge-l2protocol-tunnel"
+ )
+
def _query_check_bridge_port(self, ifaceobj, ifaceobjcurr,
ifaceobj_getfunc):
- if not self._is_bridge_port(ifaceobj):
- # Mark all bridge attributes as failed
- ifaceobjcurr.check_n_update_config_with_status_many(ifaceobj,
- ['bridge-vids', 'bridge-trunk', 'bridge-pvid', 'bridge-access',
- 'bridge-pathcosts', 'bridge-portprios',
- 'bridge-portmcrouter',
- 'bridge-learning',
- 'bridge-portmcfl', 'bridge-unicast-flood',
- 'bridge-multicast-flood',
- 'bridge-arp-nd-suppress', 'bridge-l2protocol-tunnel'
- ], 1)
+
+ ifname = ifaceobj.name
+
+ if not self.cache.link_is_bridge_port(ifname):
+ # Mark all bridge brport attributes as failed
+ ifaceobjcurr.check_n_update_config_with_status_many(
+ ifaceobj, self._query_check_brport_attributes, 1
+ )
return
- bridgename = self._get_bridge_name(ifaceobj)
- if not bridgename:
- self.logger.warn('%s: unable to determine bridge name'
- %ifaceobj.name)
+
+ bridge_name = self.cache.get_bridge_name_from_port(ifname)
+ if not bridge_name:
+ self.logger.warn("%s: unable to determine bridge name" % ifname)
return
- if self.ipcmd.bridge_is_vlan_aware(bridgename):
- self._query_check_bridge_port_vidinfo(ifaceobj, ifaceobjcurr,
- ifaceobj_getfunc,
- bridgename)
- for attr, dstattr in {'bridge-pathcosts' : 'pathcost',
- 'bridge-portprios' : 'portprio',
- 'bridge-portmcrouter' : 'portmcrouter',
- 'bridge-portmcfl' : 'portmcfl',
- 'bridge-learning' : 'learning',
- 'bridge-unicast-flood' : 'unicast-flood',
- 'bridge-multicast-flood' : 'multicast-flood',
- 'bridge-arp-nd-suppress' : 'arp-nd-suppress',
- }.items():
- attrval = ifaceobj.get_attr_value_first(attr)
- if not attrval:
+ if self.cache.bridge_is_vlan_aware(bridge_name):
+ self._query_check_bridge_port_vidinfo(ifname, bridge_name, ifaceobj, ifaceobjcurr, ifaceobj_getfunc)
+
+ brport_info_slave_data = self.cache.get_link_info_slave_data(ifname)
+
+ #
+ # bridge-portmcfl
+ #
+ portmcfl = ifaceobj.get_attr_value_first("bridge-portmcfl")
+
+ if portmcfl:
+ cached_value = brport_info_slave_data.get(Link.IFLA_BRPORT_FAST_LEAVE)
+
+ ifaceobjcurr.update_config_with_status(
+ "bridge-portmcfl",
+ "yes" if cached_value else "no",
+ utils.get_boolean_from_string(portmcfl) != cached_value
+ )
+
+ #
+ # bridge-portmcrouter
+ #
+ portmcrouter = ifaceobj.get_attr_value_first("bridge-portmcrouter")
+
+ if portmcrouter:
+ cached_value = brport_info_slave_data.get(Link.IFLA_BRPORT_MULTICAST_ROUTER)
+
+ ifaceobjcurr.update_config_with_status(
+ "bridge-portmcrouter",
+ self._ifla_brport_multicast_router_dict_int_to_str.get(cached_value),
+ self._ifla_brport_multicast_router_dict_to_int.get(portmcrouter) != cached_value
+ )
+
+ #
+ # bridge-learning
+ # bridge-unicast-flood
+ # bridge-multicast-flood
+ # bridge-broadcast-flood
+ # bridge-arp-nd-suppress
+ #
+ for attr_name, attr_nl in (
+ ("bridge-learning", Link.IFLA_BRPORT_LEARNING),
+ ("bridge-unicast-flood", Link.IFLA_BRPORT_UNICAST_FLOOD),
+ ("bridge-multicast-flood", Link.IFLA_BRPORT_MCAST_FLOOD),
+ ("bridge-broadcast-flood", Link.IFLA_BRPORT_BCAST_FLOOD),
+ ("bridge-arp-nd-suppress", Link.IFLA_BRPORT_NEIGH_SUPPRESS),
+ ):
+ attribute_value = ifaceobj.get_attr_value_first(attr_name)
+
+ if not attribute_value:
+ continue
+
+ cached_value = brport_info_slave_data.get(attr_nl)
+
+ ifaceobjcurr.update_config_with_status(
+ attr_name,
+ "on" if cached_value else "off",
+ utils.get_boolean_from_string(attribute_value) != cached_value
+ )
+
+ #
+ # bridge-pathcosts
+ # bridge-portprios
+ #
+ for attr_name, attr_nl in (
+ ("bridge-pathcosts", Link.IFLA_BRPORT_COST),
+ ("bridge-portprios", Link.IFLA_BRPORT_PRIORITY),
+ ):
+ attribute_value = ifaceobj.get_attr_value_first(attr_name)
+
+ if not attribute_value:
continue
+ cached_value = brport_info_slave_data.get(attr_nl)
+
try:
- running_attrval = self.brctlcmd.get_bridgeport_attr(
- bridgename, ifaceobj.name, dstattr)
-
- if dstattr == 'portmcfl':
- if not utils.is_binary_bool(attrval) and running_attrval:
- running_attrval = utils.get_yesno_boolean(
- utils.get_boolean_from_string(running_attrval))
- elif dstattr == 'portmcrouter':
- if self._ifla_brport_multicast_router_dict_to_int.get(attrval) == int(running_attrval):
- ifaceobjcurr.update_config_with_status(attr, attrval, 0)
- else:
- ifaceobjcurr.update_config_with_status(attr, attrval, 1)
- continue
- elif dstattr in ['learning',
- 'unicast-flood',
- 'multicast-flood',
- 'arp-nd-suppress',
- ]:
- if not utils.is_binary_bool(attrval) and running_attrval:
- running_attrval = utils.get_onff_from_onezero(
- running_attrval)
-
- if running_attrval != attrval:
- ifaceobjcurr.update_config_with_status(attr,
- running_attrval, 1)
- else:
- ifaceobjcurr.update_config_with_status(attr,
- running_attrval, 0)
- except Exception, e:
- self.log_warn('%s: %s' %(ifaceobj.name, str(e)))
+ ifaceobjcurr.update_config_with_status(
+ attr_name,
+ str(cached_value),
+ int(attribute_value) != cached_value
+ )
+ except ValueError as e:
+ ifaceobjcurr.update_config_with_status(attr_name, str(cached_value), 1)
+ raise Exception("%s: %s invalid value: %s" % (ifname, attr_name, str(e)))
self._query_check_l2protocol_tunnel_on_port(ifaceobj, ifaceobjcurr)
result = 1
ifaceobjcurr.update_config_with_status('bridge-l2protocol-tunnel', user_config_l2protocol_tunnel, result)
- def _query_check_l2protocol_tunnel_on_bridge(self, ifaceobj, ifaceobjcurr, bridge_running_attrs):
+ def _query_check_l2protocol_tunnel_on_bridge(self, ifname, ifaceobj, ifaceobjcurr):
"""
In case the bridge-l2protocol-tunnel is specified under the bridge and not the brport
We need to make sure that all ports comply with the mask given under the bridge
return
else:
config_per_port_dict = {}
- brport_list = bridge_running_attrs.get('ports', {}).keys()
- result = 1
+ brport_list = self.cache.get_slaves(ifname)
+
try:
for brport_name in brport_list:
self._query_check_l2protocol_tunnel(
ifaceobjcurr.update_config_with_status('bridge-l2protocol-tunnel', user_config_l2protocol_tunnel, result)
def _query_check_l2protocol_tunnel(self, brport_name, user_config_l2protocol_tunnel):
- cached_ifla_brport_group_maskhi = self.ipcmd.cache_get_info_slave([brport_name, 'info_slave_data', Link.IFLA_BRPORT_GROUP_FWD_MASKHI])
- cached_ifla_brport_group_mask = self.ipcmd.cache_get_info_slave([brport_name, 'info_slave_data', Link.IFLA_BRPORT_GROUP_FWD_MASK])
+ cached_ifla_brport_group_maskhi = self.cache.get_link_info_slave_data_attribute(brport_name, Link.IFLA_BRPORT_GROUP_FWD_MASKHI)
+ cached_ifla_brport_group_mask = self.cache.get_link_info_slave_data_attribute(brport_name, Link.IFLA_BRPORT_GROUP_FWD_MASK)
for protocol in re.split(',|\s*', user_config_l2protocol_tunnel):
callback = self.query_check_l2protocol_tunnel_callback.get(protocol)
% (brport_name, protocol, cached_ifla_brport_group_mask, cached_ifla_brport_group_maskhi))
def _query_running_bridge_l2protocol_tunnel(self, brport_name, brport_ifaceobj=None, bridge_ifaceobj=None):
- cached_ifla_brport_group_maskhi = self.ipcmd.cache_get_info_slave([brport_name, 'info_slave_data', Link.IFLA_BRPORT_GROUP_FWD_MASKHI])
- cached_ifla_brport_group_mask = self.ipcmd.cache_get_info_slave([brport_name, 'info_slave_data', Link.IFLA_BRPORT_GROUP_FWD_MASK])
+ cached_ifla_brport_group_maskhi = self.cache.get_link_info_slave_data_attribute(brport_name, Link.IFLA_BRPORT_GROUP_FWD_MASKHI)
+ cached_ifla_brport_group_mask = self.cache.get_link_info_slave_data_attribute(brport_name, Link.IFLA_BRPORT_GROUP_FWD_MASK)
running_protocols = []
for protocol_name, callback in self.query_check_l2protocol_tunnel_callback.items():
if protocol_name == 'all' and callback(cached_ifla_brport_group_mask, cached_ifla_brport_group_maskhi):
ifaceobj_getfunc)
def _query_running_bridge(self, ifaceobjrunning, ifaceobj_getfunc):
- if self.ipcmd.bridge_is_vlan_aware(ifaceobjrunning.name):
+ if self.cache.bridge_is_vlan_aware(ifaceobjrunning.name):
ifaceobjrunning.update_config('bridge-vlan-aware', 'yes')
ifaceobjrunning.update_config_dict(self._query_running_attrs(
ifaceobjrunning,
if self.systcl_get_net_bridge_stp_user_space() == '1':
return
- v = self.brctlcmd.bridge_get_pathcost(bridgename, ifaceobjrunning.name)
+ v = str(self.cache.get_brport_cost(ifaceobjrunning.name))
if v and v != self.get_mod_subattr('bridge-pathcosts', 'default'):
ifaceobjrunning.update_config('bridge-pathcosts', v)
- v = self.brctlcmd.bridge_get_pathcost(bridgename, ifaceobjrunning.name)
+ v = str(self.cache.get_brport_priority(ifaceobjrunning.name))
if v and v != self.get_mod_subattr('bridge-portprios', 'default'):
ifaceobjrunning.update_config('bridge-portprios', v)
def _query_running_bridge_port(self, ifaceobjrunning,
ifaceobj_getfunc=None):
- bridgename = self.ipcmd.bridge_port_get_bridge_name(
+ bridgename = self.cache.get_bridge_name_from_port(
ifaceobjrunning.name)
bridge_vids = None
bridge_pvid = None
%ifaceobjrunning.name)
return
- if not self.ipcmd.bridge_is_vlan_aware(bridgename):
+ if not self.cache.bridge_is_vlan_aware(bridgename):
try:
self._query_running_bridge_l2protocol_tunnel(ifaceobjrunning.name, bridge_ifaceobj=ifaceobj_getfunc(bridgename)[0])
except Exception as e:
ifaceobjrunning.update_config('bridge-pvid',
bridge_port_pvid)
- v = utils.get_onff_from_onezero(
- self.brctlcmd.get_bridgeport_attr(bridgename,
- ifaceobjrunning.name,
- 'learning'))
+ v = utils.get_onff_from_onezero(self.cache.get_brport_learning(ifaceobjrunning.name))
if v and v != self.get_mod_subattr('bridge-learning', 'default'):
ifaceobjrunning.update_config('bridge-learning', v)
- v = utils.get_onff_from_onezero(
- self.brctlcmd.get_bridgeport_attr(bridgename,
- ifaceobjrunning.name,
- 'unicast-flood'))
+ v = utils.get_onff_from_onezero(self.cache.get_brport_unicast_flood(ifaceobjrunning.name))
if v and v != self.get_mod_subattr('bridge-unicast-flood', 'default'):
ifaceobjrunning.update_config('bridge-unicast-flood', v)
- v = utils.get_onff_from_onezero(
- self.brctlcmd.get_bridgeport_attr(bridgename,
- ifaceobjrunning.name,
- 'multicast-flood'))
+ v = utils.get_onff_from_onezero(self.cache.get_brport_multicast_flood(ifaceobjrunning.name))
if v and v != self.get_mod_subattr('bridge-multicast-flood', 'default'):
ifaceobjrunning.update_config('bridge-multicast-flood', v)
- v = utils.get_onff_from_onezero(
- self.brctlcmd.get_bridgeport_attr(bridgename,
- ifaceobjrunning.name,
- 'arp-nd-suppress'))
+ v = utils.get_onff_from_onezero(self.cache.get_brport_broadcast_flood(ifaceobjrunning.name))
+ if v and v != self.get_mod_subattr('bridge-broadcast-flood', 'default'):
+ ifaceobjrunning.update_config('bridge-broadcast-flood', v)
+
+ v = utils.get_onff_from_onezero(self.cache.get_brport_neigh_suppress(ifaceobjrunning.name))
# Display running 'arp-nd-suppress' only on vxlan ports
# if 'allow_arp_nd_suppress_only_on_vxlan' is set to 'yes'
# otherwise, display on all bridge-ports
def _query_running(self, ifaceobjrunning, ifaceobj_getfunc=None):
try:
- if self.brctlcmd.bridge_exists(ifaceobjrunning.name):
+ if self.cache.bridge_exists(ifaceobjrunning.name):
self._query_running_bridge(ifaceobjrunning, ifaceobj_getfunc)
- elif self.brctlcmd.is_bridge_port(ifaceobjrunning.name):
+ elif self.cache.link_is_bridge_port(ifaceobjrunning.name):
self._query_running_bridge_port(ifaceobjrunning, ifaceobj_getfunc)
except Exception as e:
raise Exception('%s: %s' % (ifaceobjrunning.name, str(e)))
if self.default_stp_on:
ifaceobj.update_config('bridge-stp', 'yes')
- def _query_check_support_yesno_attrs(self, runningattrs, ifaceobj):
- for attrl in [['mcqifaddr', 'bridge-mcqifaddr'],
- ['mcquerier', 'bridge-mcquerier'],
- ['mcsnoop', 'bridge-mcsnoop']]:
- value = ifaceobj.get_attr_value_first(attrl[1])
- if value and not utils.is_binary_bool(value):
- if attrl[0] in runningattrs:
- bool = utils.get_boolean_from_string(runningattrs[attrl[0]])
- runningattrs[attrl[0]] = utils.get_yesno_boolean(bool)
-
- self._query_check_mcrouter(ifaceobj, runningattrs)
- self._query_check_support_yesno_attr_port(runningattrs, ifaceobj, 'portmcfl', ifaceobj.get_attr_value_first('bridge-portmcfl'))
- self._query_check_support_yesno_attr_port(runningattrs, ifaceobj, 'learning', ifaceobj.get_attr_value_first('bridge-learning'))
- self._query_check_support_yesno_attr_port(runningattrs, ifaceobj, 'unicast-flood', ifaceobj.get_attr_value_first('bridge-unicast-flood'))
- self._query_check_support_yesno_attr_port(runningattrs, ifaceobj, 'multicast-flood', ifaceobj.get_attr_value_first('bridge-multicast-flood'))
- self._query_check_support_yesno_attr_port(runningattrs, ifaceobj, 'arp-nd-suppress', ifaceobj.get_attr_value_first('bridge-arp-nd-suppress'))
-
- def _query_check_mcrouter(self, ifaceobj, running_attrs):
+ def __re_evaluate_bridge_vxlan(self, ifaceobj, ifaceobj_getfunc=None):
"""
- bridge-mcrouter and bridge-portmcrouter supports: yes-no-0-1-2
+ Quick fix for BRIDGE_VXLAN
+
+ BRIDGE_VXLAN is not set on the bridge because the VXLAN hasn't been processed yet
+ (because its defined after the bridge in /e/n/i), here is what happens:
+
+ - ifupdownmain:populate_dependency_info()
+ - loops over all the intf from /e/n/i (with the example config:
+ ['lo', 'eth0', 'swp1', 'swp2', 'bridge', 'vni-10', 'bridge.100', 'vlan100'])
+ ----> bridge is first in the list of interface (that we care about)
+
+ - ifupdownmain:query_lowerifaces()
+ - bridge:get_dependent is called (debug: bridge: evaluating port expr '['swp1', 'swp2', 'vni-10']')
+ - ifupdownmain:preprocess_dependency_list()
+ - calls ifupdownmain:_set_iface_role_n_kind() on all the brports:
+
+ in _set_iface_role_n_kind:
+ ifaceobj is the brport
+ upperifaceobj is the bridge
+
+ it tries to see if the bridge has a VXLAN:
+
+ if (ifaceobj.link_kind & ifaceLinkKind.VXLAN) \
+ and (upperifaceobj.link_kind & ifaceLinkKind.BRIDGE):
+ upperifaceobj.link_privflags |= ifaceLinkPrivFlags.BRIDGE_VXLAN
+
+ but because the bridge is first in the /e/n/i ifupdown2 didn't
+ call vxlan:get_dependent_ifacenames so VXLAN is not set on ifaceobj
+
+ :return:
"""
- if 'mcrouter' in running_attrs:
- value = ifaceobj.get_attr_value_first('bridge-mcrouter')
- if value:
- try:
- int(value)
- except:
- running_attrs['mcrouter'] = 'yes' if utils.get_boolean_from_string(running_attrs['mcrouter']) else 'no'
+ if not ifaceobj_getfunc:
+ return
- def _query_check_support_yesno_attr_port(self, runningattrs, ifaceobj, attr, attrval):
- if attrval:
- portlist = self.parse_port_list(ifaceobj.name, attrval)
- if portlist:
- to_convert = []
- for p in portlist:
- (port, val) = p.split('=')
- if not utils.is_binary_bool(val):
- to_convert.append(port)
- for port in to_convert:
- runningattrs['ports'][port][attr] = utils.get_yesno_boolean(
- utils.get_boolean_from_string(runningattrs['ports'][port][attr]))
+ if ifaceobj.link_kind & ifaceLinkKind.BRIDGE and not ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VXLAN:
+ for port in self._get_bridge_port_list(ifaceobj) or []:
+ for brport_ifaceobj in ifaceobj_getfunc(port):
+ if brport_ifaceobj.link_kind & ifaceLinkKind.VXLAN:
+ ifaceobj.link_privflags |= ifaceLinkPrivFlags.BRIDGE_VXLAN
+ return
+
+ elif ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT and ifaceobj.link_kind & ifaceLinkKind.VXLAN:
+ for iface in ifaceobj.upperifaces if ifaceobj.upperifaces else []:
+ for bridge_ifaceobj in ifaceobj_getfunc(iface) or []:
+ bridge_ifaceobj.link_privflags |= ifaceLinkPrivFlags.BRIDGE_VXLAN
_run_ops = {
'pre-up': _up,
""" returns list of ops supported by this module """
return self._run_ops.keys()
- def _init_command_handlers(self):
- if not self.ipcmd:
- self.ipcmd = self.brctlcmd = LinkUtils()
-
def run(self, ifaceobj, operation, query_ifaceobj=None, ifaceobj_getfunc=None):
""" run bridge configuration on the interface object passed as
argument. Can create bridge interfaces if they dont exist already
op_handler = self._run_ops.get(operation)
if not op_handler:
return
- self._init_command_handlers()
- if (not LinkUtils.bridge_utils_is_installed
+ if (not self.requirements.bridge_utils_is_installed
and (ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT or ifaceobj.link_kind & ifaceLinkKind.BRIDGE)
- and LinkUtils.bridge_utils_missing_warning):
+ and self.bridge_utils_missing_warning):
self.logger.warning('%s: missing - bridge operation may not work as expected. '
'Please check if \'bridge-utils\' package is installed' % utils.brctl_cmd)
- LinkUtils.bridge_utils_missing_warning = False
+ self.bridge_utils_missing_warning = False
+
+ # make sure BRIDGE_VXLAN is set if we have a vxlan port
+ self.__re_evaluate_bridge_vxlan(ifaceobj, ifaceobj_getfunc)
if operation == 'query-checkcurr':
op_handler(self, ifaceobj, query_ifaceobj,
#
try:
+ from ifupdown2.lib.addon import Addon
+
from ifupdown2.ifupdown.iface import *
- from ifupdown2.ifupdownaddons.LinkUtils import LinkUtils
from ifupdown2.ifupdownaddons.modulebase import moduleBase
import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
except ImportError:
+ from lib.addon import Addon
+
from ifupdown.iface import *
- from ifupdownaddons.LinkUtils import LinkUtils
from ifupdownaddons.modulebase import moduleBase
import ifupdown.ifupdownflags as ifupdownflags
-class bridgevlan(moduleBase):
+class bridgevlan(Addon, moduleBase):
""" ifupdown2 addon module to configure vlan attributes on a vlan
aware bridge """
- _modinfo = {'mhelp' : 'bridgevlan module configures vlan attributes ' +
- 'on a vlan aware bridge. This module only ' +
- 'understands vlan interface name ' +
- 'with dot notations. eg br0.100. where br0 is the ' +
- 'vlan aware bridge this config is for',
- 'attrs' : {
- 'bridge-igmp-querier-src' :
- { 'help' : 'bridge igmp querier src. Must be ' +
- 'specified under the vlan interface',
- 'validvals' : ['<ipv4>', ],
- 'example' : ['bridge-igmp-querier-src 172.16.101.1']}}}
+ _modinfo = {
+ "mhelp": "bridgevlan module configures vlan attributes on a vlan aware "
+ "bridge. This module only understands vlan interface name "
+ "with dot notations. eg br0.100. where br0 is the vlan aware "
+ "bridge this config is for",
+ "attrs": {
+ "bridge-igmp-querier-src": {
+ "help": "bridge igmp querier src. Must be specified under "
+ "the vlan interface",
+ "validvals": ["<ipv4>"],
+ "example": ["bridge-igmp-querier-src 172.16.101.1"]
+ }
+ }
+ }
def __init__(self, *args, **kargs):
+ Addon.__init__(self)
moduleBase.__init__(self, *args, **kargs)
- self.brctlcmd = None
- self.ipcmd = None
- def _is_bridge_vlan_device(self, ifaceobj):
- if ifaceobj.type == ifaceType.BRIDGE_VLAN:
- return True
- return False
+ @staticmethod
+ def _is_bridge_vlan_device(ifaceobj):
+ return ifaceobj.type == ifaceType.BRIDGE_VLAN
- def _get_bridge_n_vlan(self, ifaceobj):
+ @staticmethod
+ def _get_bridge_n_vlan(ifaceobj):
vlist = ifaceobj.name.split('.', 1)
if len(vlist) == 2:
- return (vlist[0], vlist[1])
+ return vlist[0], vlist[1]
return None
- def _get_bridgename(self, ifaceobj):
+ @staticmethod
+ def _get_bridgename(ifaceobj):
vlist = ifaceobj.name.split('.', 1)
if len(vlist) == 2:
return vlist[0]
(bridgename, vlan) = self._get_bridge_n_vlan(ifaceobj)
vlanid = int(vlan, 10)
except:
- self.log_error('%s: bridge vlan interface name ' %ifaceobj.name +
- 'does not correspond to format (eg. br0.100)', ifaceobj)
+ self.log_error("%s: bridge vlan interface name does not correspond "
+ "to format (eg. br0.100)" % ifaceobj.name, ifaceobj)
raise
- if not self.ipcmd.link_exists(bridgename):
+ if not self.cache.link_exists(bridgename):
#self.logger.warn('%s: bridge %s does not exist' %(ifaceobj.name,
# bridgename))
return
running_mcqv4src = {}
if not ifupdownflags.flags.PERFMODE:
- running_mcqv4src = self.brctlcmd.bridge_get_mcqv4src_sysfs(bridgename)
+ running_mcqv4src = self.sysfs.bridge_get_mcqv4src(bridgename)
if running_mcqv4src:
r_mcqv4src = running_mcqv4src.get(vlan)
else:
mcqv4src = ifaceobj.get_attr_value_first('bridge-igmp-querier-src')
if not mcqv4src:
if r_mcqv4src:
- self.brctlcmd.bridge_del_mcqv4src(bridgename, vlanid)
+ self.iproute2.bridge_del_mcqv4src(bridgename, vlanid)
return
if r_mcqv4src and r_mcqv4src != mcqv4src:
- self.brctlcmd.bridge_del_mcqv4src(bridgename, vlanid)
- self.brctlcmd.bridge_set_mcqv4src(bridgename, vlanid, mcqv4src)
+ self.iproute2.bridge_del_mcqv4src(bridgename, vlanid)
+ self.iproute2.bridge_set_mcqv4src(bridgename, vlanid, mcqv4src)
else:
- self.brctlcmd.bridge_set_mcqv4src(bridgename, vlanid, mcqv4src)
+ self.iproute2.bridge_set_mcqv4src(bridgename, vlanid, mcqv4src)
def _down(self, ifaceobj):
try:
(bridgename, vlan) = self._get_bridge_n_vlan(ifaceobj)
vlanid = int(vlan, 10)
except:
- self.logger.warn('%s: bridge vlan interface name ' %ifaceobj.name +
- 'does not correspond to format (eg. br0.100)')
+ self.logger.warn("%s: bridge vlan interface name does not "
+ "correspond to format (eg. br0.100)" % ifaceobj.name)
raise
- if not self.ipcmd.link_exists(bridgename):
+ if not self.cache.link_exists(bridgename):
#self.logger.warn('%s: bridge %s does not exist' %(ifaceobj.name,
# bridgename))
return
mcqv4src = ifaceobj.get_attr_value_first('bridge-igmp-querier-src')
if mcqv4src:
- self.brctlcmd.bridge_del_mcqv4src(bridgename, vlanid)
+ self.iproute2.bridge_del_mcqv4src(bridgename, vlanid)
def _query_running_bridge_igmp_querier_src(self, ifaceobj):
(bridgename, vlanid) = ifaceobj.name.split('.')
- running_mcqv4src = self.brctlcmd.bridge_get_mcqv4src_sysfs(bridgename)
+ running_mcqv4src = self.sysfs.bridge_get_mcqv4src(bridgename)
if running_mcqv4src:
- return running_mcqv4src.get(vlanid)
+ return running_mcqv4src.get(vlanid)
return None
def _query_check(self, ifaceobj, ifaceobjcurr):
ifaceobjcurr.status = ifaceStatus.SUCCESS
return
- def _query_running(self, ifaceobjrunning):
- # XXX not supported
- return
-
def syntax_check(self, ifaceobj, ifaceobj_getfunc):
ret = True
bvlan_intf = self._is_bridge_vlan_device(ifaceobj)
- if (ifaceobj.get_attr_value_first('bridge-igmp-querier-src') and
- not bvlan_intf):
- self.logger.error('%s: bridge-igmp-querier-src only allowed under vlan stanza' %ifaceobj.name)
+ if (ifaceobj.get_attr_value_first('bridge-igmp-querier-src') and not bvlan_intf):
+ self.logger.error('%s: bridge-igmp-querier-src only allowed under vlan stanza' % ifaceobj.name)
ret = False
return ret
- _run_ops = {'pre-up' : _up,
- 'post-down' : _down,
- 'query-checkcurr' : _query_check,
- 'query-running' : _query_running}
+ _run_ops = {
+ "pre-up": _up,
+ "post-down": _down,
+ "query-checkcurr": _query_check,
+ }
def get_ops(self):
""" returns list of ops supported by this module """
return self._run_ops.keys()
- def _init_command_handlers(self):
- if not self.ipcmd:
- self.ipcmd = self.brctlcmd = LinkUtils()
-
def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
""" run vlan configuration on the interface object passed as argument
op_handler = self._run_ops.get(operation)
if not op_handler:
return
- if (operation != 'query-running' and
- not self._is_bridge_vlan_device(ifaceobj)):
+ if (operation != 'query-running' and not self._is_bridge_vlan_device(ifaceobj)):
# most common problem is people specify BRIDGE_VLAN
# attribute on a bridge or a vlan device, which
# is incorrect. So, catch them here and warn before
# giving up processing the interface
- if ((ifaceobj.link_kind & ifaceLinkKind.BRIDGE or
- ifaceobj.link_kind & ifaceLinkKind.VLAN) and
- not self.syntax_check(ifaceobj, None)):
+ if (ifaceobj.link_kind & ifaceLinkKind.BRIDGE or ifaceobj.link_kind & ifaceLinkKind.VLAN) \
+ and not self.syntax_check(ifaceobj, None):
ifaceobj.status = ifaceStatus.ERROR
return
- self._init_command_handlers()
if operation == 'query-checkcurr':
op_handler(self, ifaceobj, query_ifaceobj)
else:
import re
import time
+import socket
try:
+ from ifupdown2.lib.addon import Addon
+
import ifupdown2.ifupdown.policymanager as policymanager
import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
from ifupdown2.ifupdown.utils import utils
from ifupdown2.ifupdownaddons.dhclient import dhclient
- from ifupdown2.ifupdownaddons.LinkUtils import LinkUtils
from ifupdown2.ifupdownaddons.modulebase import moduleBase
except ImportError:
+ from lib.addon import Addon
+
import ifupdown.policymanager as policymanager
import ifupdown.ifupdownflags as ifupdownflags
from ifupdown.utils import utils
from ifupdownaddons.dhclient import dhclient
- from ifupdownaddons.LinkUtils import LinkUtils
from ifupdownaddons.modulebase import moduleBase
-class dhcp(moduleBase):
+class dhcp(Addon, moduleBase):
""" ifupdown2 addon module to configure dhcp on interface """
- _modinfo = {
- "mhelp": "Configure dhcp",
- "policies": {
- "dhcp6-duid": {
- "help": "Override the default when selecting the type of DUID to use. By default, DHCPv6 dhclient "
- "creates an identifier based on the link-layer address (DUID-LL) if it is running in stateless "
- "mode (with -S, not requesting an address), or it creates an identifier based on the "
- "link-layer address plus a timestamp (DUID-LLT) if it is running in stateful mode (without -S, "
- "requesting an address). When DHCPv4 is configured to use a DUID using -i option the default "
- "is to use a DUID-LLT. -D overrides these default, with a value of either LL or LLT.",
- "validvals": ["LL", "LLT"],
- "example": ["dhcp6-duid LL"]
- },
- "dhcp-wait": {
- "help": "Wait or not wait and become a daemon immediately (nowait) rather than waiting until an "
- "IP address has been acquired. If not specified default value is true, that is to wait.",
- "validvals": ["true", "false"],
- "example": ["dhcp-wait false"]
- },
- "dhcp6-ll-wait": {
- "help": "Overrides the default wait time before DHCPv6 client is started. During this wait time, "
- "ifupdown2 checks if the interface requesting an address has a valid link-local address. "
- "If not specified default value used is 10 seconds.",
- "validvals": ["whole numbers"],
- "example": ["dhcp6-ll-wait 0"]
- }
- }
- }
-
def __init__(self, *args, **kargs):
+ Addon.__init__(self)
moduleBase.__init__(self, *args, **kargs)
self.dhclientcmd = dhclient(**kargs)
- self.ipcmd = None
def syntax_check(self, ifaceobj, ifaceobj_getfunc):
return self.is_dhcp_allowed_on(ifaceobj, syntax_check=True)
pass
dhcp6_duid = policymanager.policymanager_api.get_iface_default(module_name=self.__class__.__name__, \
ifname=ifaceobj.name, attr='dhcp6-duid')
-
vrf = ifaceobj.get_attr_value_first('vrf')
if (vrf and self.vrf_exec_cmd_prefix and
- self.ipcmd.link_exists(vrf)):
+ self.cache.link_exists(vrf)):
dhclient_cmd_prefix = '%s %s' %(self.vrf_exec_cmd_prefix, vrf)
if 'inet' in ifaceobj.addr_family:
#add delay before starting IPv6 dhclient to
#make sure the configured interface/link is up.
if timeout > 1:
- time.sleep(1)
-
+ time.sleep(1)
while timeout:
addr_output = utils.exec_command('%s -6 addr show %s'
%(utils.ip_cmd, ifaceobj.name))
dhclient_cmd_prefix = None
vrf = ifaceobj.get_attr_value_first('vrf')
if (vrf and self.vrf_exec_cmd_prefix and
- self.ipcmd.link_exists(vrf)):
+ self.cache.link_exists(vrf)):
dhclient_cmd_prefix = '%s %s' %(self.vrf_exec_cmd_prefix, vrf)
dhcp6_duid = policymanager.policymanager_api.get_iface_default(module_name=self.__class__.__name__, \
- ifname=ifaceobj.name, attr='dhcp6-duid')
+ ifname=ifaceobj.name, attr='dhcp6-duid')
if 'inet6' in ifaceobj.addr_family:
self.dhclientcmd.release6(ifaceobj.name, dhclient_cmd_prefix, duid=dhcp6_duid)
+ self.cache.force_address_flush_family(ifaceobj.name, socket.AF_INET6)
if 'inet' in ifaceobj.addr_family:
self.dhclientcmd.release(ifaceobj.name, dhclient_cmd_prefix)
+ self.cache.force_address_flush_family(ifaceobj.name, socket.AF_INET)
def _down(self, ifaceobj):
self._dhcp_down(ifaceobj)
- self.ipcmd.link_down(ifaceobj.name)
+ self.netlink.link_down(ifaceobj.name)
def _query_check(self, ifaceobj, ifaceobjcurr):
status = ifaceStatus.SUCCESS
ifaceobjcurr.status = status
def _query_running(self, ifaceobjrunning):
- if not self.ipcmd.link_exists(ifaceobjrunning.name):
+ if not self.cache.link_exists(ifaceobjrunning.name):
return
if self.dhclientcmd.is_running(ifaceobjrunning.name):
ifaceobjrunning.addr_family.append('inet')
""" returns list of ops supported by this module """
return self._run_ops.keys()
- def _init_command_handlers(self):
- if not self.ipcmd:
- self.ipcmd = LinkUtils()
-
def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
""" run dhcp configuration on the interface object passed as argument
return
if not self.is_dhcp_allowed_on(ifaceobj, syntax_check=False):
return
- self._init_command_handlers()
if operation == 'query-checkcurr':
op_handler(self, ifaceobj, query_ifaceobj)
else:
import os
try:
+ from ifupdown2.lib.addon import Addon
+
import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
import ifupdown2.ifupdown.policymanager as policymanager
from ifupdown2.ifupdown.exceptions import moduleNotSupported
from ifupdown2.ifupdownaddons.utilsbase import *
- from ifupdown2.ifupdownaddons.LinkUtils import LinkUtils
from ifupdown2.ifupdownaddons.modulebase import moduleBase
except ImportError:
+ from lib.addon import Addon
+
import ifupdown.ifupdownflags as ifupdownflags
import ifupdown.policymanager as policymanager
from ifupdown.exceptions import moduleNotSupported
from ifupdownaddons.utilsbase import *
- from ifupdownaddons.LinkUtils import LinkUtils
from ifupdownaddons.modulebase import moduleBase
-class ethtool(moduleBase,utilsBase):
+class ethtool(Addon, moduleBase):
""" ifupdown2 addon module to configure ethtool attributes """
- _modinfo = {'mhelp' : 'ethtool configuration module for interfaces',
- 'attrs': {
- 'link-speed' :
- {'help' : 'set link speed',
- 'validvals' : ['10',
- '100',
- '1000',
- '10000',
- '25000',
- '40000',
- '50000',
- '100000'],
- 'example' : ['link-speed 1000'],
- 'default' : 'varies by platform and port'},
- 'link-duplex' :
- {'help': 'set link duplex',
- 'example' : ['link-duplex full'],
- 'validvals' : ['half', 'full'],
- 'default' : 'full'},
- 'link-autoneg' :
- {'help': 'set autonegotiation',
- 'example' : ['link-autoneg on'],
- 'validvals' : ['yes', 'no', 'on', 'off'],
- 'default' : 'varies by platform and port'},
- 'link-fec' :
- {'help': 'set forward error correction mode',
- 'example' : ['link-fec rs'],
- 'validvals' : ['rs', 'baser', 'auto', 'off'],
- 'default' : 'varies by platform and port'}}}
+ _modinfo = {
+ "mhelp": "ethtool configuration module for interfaces",
+ "attrs": {
+ "link-speed": {
+ "help": "set link speed",
+ "validvals": [
+ "10",
+ "100",
+ "1000",
+ "10000",
+ "25000",
+ "40000",
+ "50000",
+ "100000"
+ ],
+ "example": ["link-speed 1000"],
+ "default": "varies by platform and port"
+ },
+ "link-duplex": {
+ "help": "set link duplex",
+ "example": ["link-duplex full"],
+ "validvals": ["half", "full"],
+ "default": "full"
+ },
+ "link-autoneg": {
+ "help": "set autonegotiation",
+ "example": ["link-autoneg on"],
+ "validvals": ["yes", "no", "on", "off"],
+ "default": "varies by platform and port"
+ },
+ "link-fec": {
+ "help": "set forward error correction mode",
+ "example": ["link-fec rs"],
+ "validvals": ["rs", "baser", "auto", "off"],
+ "default": "varies by platform and port"
+ }
+ }
+ }
def __init__(self, *args, **kargs):
+ Addon.__init__(self)
moduleBase.__init__(self, *args, **kargs)
if not os.path.exists(utils.ethtool_cmd):
raise moduleNotSupported('module init failed: %s: not found' % utils.ethtool_cmd)
- self.ipcmd = None
# keep a list of iface objects who have modified link attributes
self.ifaceobjs_modified_configs = []
+ self.ethtool_ignore_errors = policymanager.policymanager_api.get_module_globals(
+ module_name=self.__class__.__name__,
+ attr='ethtool_ignore_errors'
+ )
+
def do_fec_settings(self, ifaceobj):
feccmd = ''
if default_val:
default_val = default_val.lower()
- if running_val in ["none", "notsupported"]:
- # None and NotSupported ethtool FEC values mean "off"
- running_val = "off"
-
# check running values
if config_val and config_val == running_val:
return
(utils.ethtool_cmd, ifaceobj.name, feccmd))
utils.exec_command(feccmd)
except Exception, e:
- self.log_error('%s: %s' %(ifaceobj.name, str(e)), ifaceobj)
+ if not self.ethtool_ignore_errors:
+ self.log_error('%s: %s' %(ifaceobj.name, str(e)), ifaceobj)
else:
pass
cmd = ('%s -s %s %s' % (utils.ethtool_cmd, ifaceobj.name, cmd))
utils.exec_command(cmd)
except Exception, e:
- self.log_error('%s: %s' % (ifaceobj.name, str(e)), ifaceobj)
+ if not self.ethtool_ignore_errors:
+ self.log_error('%s: %s' % (ifaceobj.name, str(e)), ifaceobj)
def _pre_up(self, ifaceobj, operation='post_up'):
"""
_pre_up and _pre_down will reset the layer 2 attributes to default policy
settings.
"""
- if not self.ipcmd.link_exists(ifaceobj.name):
+ if not self.cache.link_exists(ifaceobj.name):
return
self.do_speed_settings(ifaceobj)
"""
try:
for attr in ethtool_output.splitlines():
- if attr.startswith('FEC encodings'):
+ if attr.startswith('Configured FEC encodings:'):
fec_attrs = attr.split()
- return(fec_attrs[fec_attrs.index(':')+1])
+ return(fec_attrs[fec_attrs.index('encodings:')+1])
except Exception as e:
self.logger.debug('ethtool: problems in ethtool set-fec output'
' %s: %s' %(ethtool_output.splitlines(), str(e)))
(utils.ethtool_cmd, ifaceobj.name))
running_attr = self.get_fec_encoding(ethtool_output=output)
else:
- running_attr = self.read_file_oneline('/sys/class/net/%s/%s' % \
+ running_attr = self.io.read_file_oneline('/sys/class/net/%s/%s' % \
(ifaceobj.name, attr))
except Exception as e:
- # for nonexistent interfaces, we get an error (rc = 256 or 19200)
- self.logger.debug('ethtool: problems calling ethtool or reading'
- ' /sys/class on iface %s for attr %s: %s' %
- (ifaceobj.name, attr, str(e)))
+ if not self.ethtool_ignore_errors:
+ # for nonexistent interfaces, we get an error (rc = 256 or 19200)
+ self.logger.debug('ethtool: problems calling ethtool or reading'
+ ' /sys/class on iface %s for attr %s: %s' %
+ (ifaceobj.name, attr, str(e)))
return running_attr
"""
# do not bother showing swp ifaces that are not up for the speed
# duplex and autoneg are not reliable.
- if not self.ipcmd.is_link_up(ifaceobj.name):
+ if not self.cache.link_is_up(ifaceobj.name):
return
for attr in ['speed', 'duplex', 'autoneg']:
default_val = policymanager.policymanager_api.get_iface_default(
""" returns list of ops supported by this module """
return self._run_ops.keys()
- def _init_command_handlers(self):
- if not self.ipcmd:
- self.ipcmd = LinkUtils()
-
def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
""" run ethtool configuration on the interface object passed as
argument
op_handler = self._run_ops.get(operation)
if not op_handler:
return
- self._init_command_handlers()
if operation == 'query-checkcurr':
op_handler(self, ifaceobj, query_ifaceobj)
else:
# loopback or dummy.
try:
+ from ifupdown2.lib.addon import Addon
from ifupdown2.ifupdown.iface import *
from ifupdown2.ifupdown.utils import utils
- from ifupdown2.ifupdownaddons.LinkUtils import LinkUtils
from ifupdown2.ifupdownaddons.modulebase import moduleBase
import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
import ifupdown2.ifupdown.policymanager as policymanager
except ImportError:
+ from lib.addon import Addon
from ifupdown.iface import *
from ifupdown.utils import utils
- from ifupdownaddons.LinkUtils import LinkUtils
from ifupdownaddons.modulebase import moduleBase
import ifupdown.ifupdownflags as ifupdownflags
import ifupdown.policymanager as policymanager
-class link(moduleBase):
- _modinfo = {'mhelp' : 'create/configure link types. similar to ip-link',
- 'attrs' : {
- 'link-type' :
- {'help' : 'type of link as in \'ip link\' command.',
- 'validvals' : ['dummy', 'veth'],
- 'example' : ['link-type <dummy|veth>']},
- 'link-down' :
- {'help': 'keep link down',
- 'example' : ['link-down yes/no'],
- 'default' : 'no',
- 'validvals' : ['yes', 'no']}}}
+class link(Addon, moduleBase):
+ _modinfo = {
+ "mhelp": "create/configure link types. similar to ip-link",
+ "attrs": {
+ "link-type": {
+ "help": "type of link as in 'ip link' command.",
+ "validvals": ["dummy", "veth"],
+ "example": ["link-type <dummy|veth>"]
+ },
+ "link-down": {
+ "help": "keep link down",
+ "example": ["link-down yes/no"],
+ "default": "no",
+ "validvals": ["yes", "no"]
+ }
+ }
+ }
def __init__(self, *args, **kargs):
+ Addon.__init__(self)
moduleBase.__init__(self, *args, **kargs)
- self.ipcmd = None
- self.check_physical_port_existance = utils.get_boolean_from_string(policymanager.policymanager_api.get_module_globals(
- self.__class__.__name__,
- 'warn_on_physdev_not_present'
- ))
+ self.check_physical_port_existance = utils.get_boolean_from_string(
+ policymanager.policymanager_api.get_module_globals(
+ self.__class__.__name__,
+ 'warn_on_physdev_not_present'
+ )
+ )
def syntax_check(self, ifaceobj, ifaceobj_getfunc):
if self.check_physical_port_existance:
- if not ifaceobj.link_kind and not LinkUtils.link_exists(ifaceobj.name):
+ if not ifaceobj.link_kind and not self.cache.link_exists(ifaceobj.name):
self.logger.warning('%s: interface does not exist' % ifaceobj.name)
return False
return True
- def _is_my_interface(self, ifaceobj):
- if (ifaceobj.get_attr_value_first('link-type')
- or ifaceobj.get_attr_value_first('link-down')):
- return True
- return False
+ @staticmethod
+ def _is_my_interface(ifaceobj):
+ return ifaceobj.get_attr_value_first('link-type') or ifaceobj.get_attr_value_first('link-down')
def get_dependent_ifacenames(self, ifaceobj, ifacenames_all=None):
if ifaceobj.get_attr_value_first('link-down') == 'yes':
def _up(self, ifaceobj):
link_type = ifaceobj.get_attr_value_first('link-type')
if link_type:
- self.ipcmd.link_create(ifaceobj.name,
- ifaceobj.get_attr_value_first('link-type'))
+ self.netlink.link_add(ifname=ifaceobj.name, kind=link_type)
def _down(self, ifaceobj):
if not ifaceobj.get_attr_value_first('link-type'):
return
- if (not ifupdownflags.flags.PERFMODE and
- not self.ipcmd.link_exists(ifaceobj.name)):
- return
+ if not ifupdownflags.flags.PERFMODE and not self.cache.link_exists(ifaceobj.name):
+ return
try:
- self.ipcmd.link_delete(ifaceobj.name)
+ self.netlink.link_del(ifaceobj.name)
except Exception, e:
self.log_warn(str(e))
def _query_check(self, ifaceobj, ifaceobjcurr):
if ifaceobj.get_attr_value('link-type'):
- if not self.ipcmd.link_exists(ifaceobj.name):
+ if not self.cache.link_exists(ifaceobj.name):
ifaceobjcurr.update_config_with_status('link-type', 'None', 1)
else:
link_type = ifaceobj.get_attr_value_first('link-type')
- if self.ipcmd.link_get_kind(ifaceobj.name) == link_type:
- ifaceobjcurr.update_config_with_status('link-type',
- link_type, 0)
+ if self.cache.get_link_kind(ifaceobj.name) == link_type:
+ ifaceobjcurr.update_config_with_status('link-type', link_type, 0)
else:
- ifaceobjcurr.update_config_with_status('link-type',
- link_type, 1)
+ ifaceobjcurr.update_config_with_status('link-type', link_type, 1)
link_down = ifaceobj.get_attr_value_first('link-down')
if link_down:
- link_up = self.ipcmd.is_link_up(ifaceobj.name)
+ link_up = self.cache.link_is_up(ifaceobj.name)
link_should_be_down = utils.get_boolean_from_string(link_down)
if link_should_be_down and link_up:
ifaceobjcurr.update_config_with_status('link-down', link_down, status)
- _run_ops = {'pre-up' : _up,
- 'post-down' : _down,
- 'query-checkcurr' : _query_check}
+ _run_ops = {
+ "pre-up": _up,
+ "post-down": _down,
+ "query-checkcurr": _query_check
+ }
def get_ops(self):
return self._run_ops.keys()
- def _init_command_handlers(self):
- if not self.ipcmd:
- self.ipcmd = LinkUtils()
-
def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
op_handler = self._run_ops.get(operation)
if not op_handler:
if (operation != 'query-running' and
not self._is_my_interface(ifaceobj)):
return
- self._init_command_handlers()
if operation == 'query-checkcurr':
op_handler(self, ifaceobj, query_ifaceobj)
else:
from sets import Set
try:
+ from ifupdown2.lib.addon import Addon
+
from ifupdown2.ifupdown.iface import *
from ifupdown2.ifupdown.utils import utils
- from ifupdown2.ifupdown.netlink import netlink
import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
import ifupdown2.ifupdown.policymanager as policymanager
- from ifupdown2.ifupdownaddons.LinkUtils import LinkUtils
from ifupdown2.ifupdownaddons.modulebase import moduleBase
from ifupdown2.ifupdownaddons.mstpctlutil import mstpctlutil
from ifupdown2.ifupdownaddons.systemutils import systemUtils
from ifupdown2.ifupdown.exceptions import moduleNotSupported
except ImportError:
+ from lib.addon import Addon
+
from ifupdown.iface import *
from ifupdown.utils import utils
- from ifupdown.netlink import netlink
import ifupdown.ifupdownflags as ifupdownflags
import ifupdown.policymanager as policymanager
- from ifupdownaddons.LinkUtils import LinkUtils
from ifupdownaddons.modulebase import moduleBase
from ifupdownaddons.mstpctlutil import mstpctlutil
from ifupdownaddons.systemutils import systemUtils
class mstpctlFlags:
PORT_PROCESSED = 0x1
-class mstpctl(moduleBase):
+class mstpctl(Addon, moduleBase):
""" ifupdown2 addon module to configure mstp attributes """
- _modinfo = {'mhelp' : 'mstp configuration module for bridges',
- 'attrs' : {
- 'mstpctl-ports' :
- {'help' : 'mstp ports',
- 'compat' : True,
- 'deprecated': True,
- 'new-attribute': 'bridge-ports'},
- 'mstpctl-stp' :
- {'help': 'bridge stp yes/no',
- 'validvals' : ['yes', 'no', 'on', 'off'],
- 'compat' : True,
- 'default' : 'no',
- 'deprecated': True,
- 'new-attribute': 'bridge-stp'},
- 'mstpctl-treeprio' :
- {'help': 'tree priority',
- 'default' : '32768',
- 'validvals' : ['0', '4096', '8192', '12288', '16384',
- '20480', '24576', '28672', '32768',
- '36864', '40960', '45056', '49152',
- '53248', '57344', '61440'],
- 'required' : False,
- 'example' : ['mstpctl-treeprio 32768']},
- 'mstpctl-ageing' :
- {'help': 'ageing time',
- 'validrange' : ['0', '4096'],
- 'default' : '300',
- 'required' : False,
- 'jsonAttr': 'ageingTime',
- 'example' : ['mstpctl-ageing 300']},
- 'mstpctl-maxage' :
- { 'help' : 'max message age',
- 'validrange' : ['0', '255'],
- 'default' : '20',
- 'jsonAttr': 'bridgeMaxAge',
- 'required' : False,
- 'example' : ['mstpctl-maxage 20']},
- 'mstpctl-fdelay' :
- { 'help' : 'set forwarding delay',
- 'validrange' : ['0', '255'],
- 'default' : '15',
- 'jsonAttr': 'bridgeFwdDelay',
- 'required' : False,
- 'example' : ['mstpctl-fdelay 15']},
- 'mstpctl-maxhops' :
- { 'help' : 'bridge max hops',
- 'validrange' : ['0', '255'],
- 'default' : '20',
- 'jsonAttr': 'maxHops',
- 'required' : False,
- 'example' : ['mstpctl-maxhops 15']},
- 'mstpctl-txholdcount' :
- { 'help' : 'bridge transmit holdcount',
- 'validrange' : ['0', '255'],
- 'default' : '6',
- 'jsonAttr': 'txHoldCounter',
- 'required' : False,
- 'example' : ['mstpctl-txholdcount 6']},
- 'mstpctl-forcevers' :
- { 'help' : 'bridge force stp version',
- 'validvals' : ['rstp', ],
- 'default' : 'rstp',
- 'required' : False,
- 'jsonAttr': 'forceProtocolVersion',
- 'example' : ['mstpctl-forcevers rstp']},
- 'mstpctl-portpathcost' :
- { 'help' : 'bridge port path cost',
- 'validvals': ['<interface-range-list>'],
- 'validrange' : ['0', '65535'],
- 'default' : '0',
- 'jsonAttr' : 'adminExtPortCost',
- 'required' : False,
- 'example' : ['under the bridge: mstpctl-portpathcost swp1=0 swp2=1',
- 'under the port (recommended): mstpctl-portpathcost 0']},
- 'mstpctl-portp2p' :
- { 'help' : 'bridge port p2p detection mode',
- 'default' : 'auto',
- 'jsonAttr' : 'adminPointToPoint',
- 'validvals' : ['<interface-yes-no-auto-list>'],
- 'required' : False,
- 'example' : ['under the bridge: mstpctl-portp2p swp1=yes swp2=no',
- 'under the port (recommended): mstpctl-portp2p yes']},
- 'mstpctl-portrestrrole' :
- { 'help' :
- 'enable/disable port ability to take root role of the port',
- 'default' : 'no',
- 'jsonAttr' : 'restrictedRole',
- 'validvals' : ['<interface-yes-no-list>'],
- 'required' : False,
- 'example' : ['under the bridge: mstpctl-portrestrrole swp1=yes swp2=no',
- 'under the port (recommended): mstpctl-portrestrrole yes']},
- 'mstpctl-portrestrtcn' :
- { 'help' :
- 'enable/disable port ability to propagate received topology change notification of the port',
- 'default' : 'no',
- 'jsonAttr' : 'restrictedTcn',
- 'validvals' : ['<interface-yes-no-list>'],
- 'required' : False,
- 'example' : ['under the bridge: mstpctl-portrestrtcn swp1=yes swp2=no',
- 'under the port (recommended): mstpctl-portrestrtcn yes']},
- 'mstpctl-bpduguard' :
- { 'help' :
- 'enable/disable bpduguard',
- 'default' : 'no',
- 'jsonAttr' : 'bpduGuardPort',
- 'validvals' : ['<interface-yes-no-list>'],
- 'required' : False,
- 'example' : ['under the bridge: mstpctl-bpduguard swp1=yes swp2=no',
- 'under the port (recommended): mstpctl-bpduguard yes']},
- 'mstpctl-treeportprio' :
- { 'help': 'Sets the <port>\'s priority MSTI instance. '
- 'The priority value must be a number between 0 and 240 and a multiple of 16.',
- 'default' : '128',
- 'validvals': ['<interface-range-list-multiple-of-16>'],
- 'validrange' : ['0', '240'],
- 'jsonAttr': 'treeportprio',
- 'required' : False,
- 'example' : ['under the bridge: mstpctl-treeportprio swp1=128 swp2=128',
- 'under the port (recommended): mstpctl-treeportprio 128']},
- 'mstpctl-hello' :
- { 'help' : 'set hello time',
- 'validrange' : ['0', '255'],
- 'default' : '2',
- 'required' : False,
- 'jsonAttr': 'helloTime',
- 'example' : ['mstpctl-hello 2']},
- 'mstpctl-portnetwork' :
- { 'help' : 'enable/disable bridge assurance capability for a port',
- 'validvals' : ['<interface-yes-no-list>'],
- 'default' : 'no',
- 'jsonAttr' : 'networkPort',
- 'required' : False,
- 'example' : ['under the bridge: mstpctl-portnetwork swp1=yes swp2=no',
- 'under the port (recommended): mstpctl-portnetwork yes']},
- 'mstpctl-portadminedge' :
- { 'help' : 'enable/disable initial edge state of the port',
- 'validvals' : ['<interface-yes-no-list>'],
- 'default' : 'no',
- 'jsonAttr' : 'adminEdgePort',
- 'required' : False,
- 'example' : ['under the bridge: mstpctl-portadminedge swp1=yes swp2=no',
- 'under the port (recommended): mstpctl-portadminedge yes']},
- 'mstpctl-portautoedge' :
- { 'help' : 'enable/disable auto transition to/from edge state of the port',
- 'validvals' : ['<interface-yes-no-list>'],
- 'default' : 'yes',
- 'jsonAttr' : 'autoEdgePort',
- 'required' : False,
- 'example' : ['under the bridge: mstpctl-portautoedge swp1=yes swp2=no',
- 'under the port (recommended): mstpctl-portautoedge yes']},
- 'mstpctl-treeportcost' :
- { 'help' : 'port tree cost',
- 'validrange' : ['0', '255'],
- 'required' : False,
- 'jsonAttr': 'extPortCost',
- },
- 'mstpctl-portbpdufilter' :
- { 'help' : 'enable/disable bpdu filter on a port. ' +
- 'syntax varies when defined under a bridge ' +
- 'vs under a port',
- 'validvals' : ['<interface-yes-no-list>'],
- 'jsonAttr' : 'bpduFilterPort',
- 'default' : 'no',
- 'required' : False,
- 'example' : ['under a bridge: mstpctl-portbpdufilter swp1=no swp2=no',
- 'under a port: mstpctl-portbpdufilter yes']},
- }}
+ _modinfo = {
+ "mhelp": "mstp configuration module for bridges",
+ "attrs": {
+ "mstpctl-ports": {
+ "help": "mstp ports",
+ "compat": True,
+ "deprecated": True,
+ "new-attribute": "bridge-ports"
+ },
+ "mstpctl-stp": {
+ "help": "bridge stp yes/no",
+ "validvals": ["yes", "no", "on", "off"],
+ "compat": True,
+ "default": "no",
+ "deprecated": True,
+ "new-attribute": "bridge-stp"
+ },
+ "mstpctl-treeprio": {
+ "help": "tree priority",
+ "default": "32768",
+ "validvals": [
+ "0", "4096", "8192", "12288", "16384",
+ "20480", "24576", "28672", "32768",
+ "36864", "40960", "45056", "49152",
+ "53248", "57344", "61440"
+ ],
+ "required": False,
+ "example": ["mstpctl-treeprio 32768"]
+ },
+ "mstpctl-ageing": {
+ "help": "ageing time",
+ "validrange": ["0", "4096"],
+ "default": "300",
+ "required": False,
+ "jsonAttr": "ageingTime",
+ "example": ["mstpctl-ageing 300"]
+ },
+ "mstpctl-maxage": {
+ "help": "max message age",
+ "validrange": ["0", "255"],
+ "default": "20",
+ "jsonAttr": "bridgeMaxAge",
+ "required": False,
+ "example": ["mstpctl-maxage 20"]
+ },
+ "mstpctl-fdelay": {
+ "help": "set forwarding delay",
+ "validrange": ["0", "255"],
+ "default": "15",
+ "jsonAttr": "bridgeFwdDelay",
+ "required": False,
+ "example": ["mstpctl-fdelay 15"]
+ },
+ "mstpctl-maxhops": {
+ "help": "bridge max hops",
+ "validrange": ["0", "255"],
+ "default": "20",
+ "jsonAttr": "maxHops",
+ "required": False,
+ "example": ["mstpctl-maxhops 15"]
+ },
+ "mstpctl-txholdcount": {
+ "help": "bridge transmit holdcount",
+ "validrange": ["0", "255"],
+ "default": "6",
+ "jsonAttr": "txHoldCounter",
+ "required": False,
+ "example": ["mstpctl-txholdcount 6"]
+ },
+ "mstpctl-forcevers": {
+ "help": "bridge force stp version",
+ "validvals": ["rstp", ],
+ "default": "rstp",
+ "required": False,
+ "jsonAttr": "forceProtocolVersion",
+ "example": ["mstpctl-forcevers rstp"]
+ },
+ "mstpctl-portpathcost": {
+ "help": "bridge port path cost",
+ "validvals": ["<interface-range-list>"],
+ "validrange": ["0", "65535"],
+ "default": "0",
+ "jsonAttr": "adminExtPortCost",
+ "required": False,
+ "example": [
+ "under the bridge: mstpctl-portpathcost swp1=0 swp2=1",
+ "under the port (recommended): mstpctl-portpathcost 0"
+ ]
+ },
+ "mstpctl-portp2p": {
+ "help": "bridge port p2p detection mode",
+ "default": "auto",
+ "jsonAttr": "adminPointToPoint",
+ "validvals": ["<interface-yes-no-auto-list>"],
+ "required": False,
+ "example": [
+ "under the bridge: mstpctl-portp2p swp1=yes swp2=no",
+ "under the port (recommended): mstpctl-portp2p yes"
+ ]
+ },
+ "mstpctl-portrestrrole": {
+ "help":
+ "enable/disable port ability to take root role of the port",
+ "default": "no",
+ "jsonAttr": "restrictedRole",
+ "validvals": ["<interface-yes-no-list>"],
+ "required": False,
+ "example": [
+ "under the bridge: mstpctl-portrestrrole swp1=yes swp2=no",
+ "under the port (recommended): mstpctl-portrestrrole yes"
+ ]
+ },
+ "mstpctl-portrestrtcn": {
+ "help":
+ "enable/disable port ability to propagate received "
+ "topology change notification of the port",
+ "default": "no",
+ "jsonAttr": "restrictedTcn",
+ "validvals": ["<interface-yes-no-list>"],
+ "required": False,
+ "example": [
+ "under the bridge: mstpctl-portrestrtcn swp1=yes swp2=no",
+ "under the port (recommended): mstpctl-portrestrtcn yes"
+ ]
+ },
+ "mstpctl-bpduguard": {
+ "help":
+ "enable/disable bpduguard",
+ "default": "no",
+ "jsonAttr": "bpduGuardPort",
+ "validvals": ["<interface-yes-no-list>"],
+ "required": False,
+ "example": [
+ "under the bridge: mstpctl-bpduguard swp1=yes swp2=no",
+ "under the port (recommended): mstpctl-bpduguard yes"
+ ]
+ },
+ "mstpctl-treeportprio": {
+ "help": "Sets the <port>'s priority MSTI instance. "
+ "The priority value must be a number between 0 and 240 "
+ "and a multiple of 16.",
+ "default": "128",
+ "validvals": ["<interface-range-list-multiple-of-16>"],
+ "validrange": ["0", "240"],
+ "jsonAttr": "treeportprio",
+ "required": False,
+ "example": [
+ "under the bridge: mstpctl-treeportprio swp1=128 swp2=128",
+ "under the port (recommended): mstpctl-treeportprio 128"
+ ]
+ },
+ "mstpctl-hello": {
+ "help": "set hello time",
+ "validrange": ["0", "255"],
+ "default": "2",
+ "required": False,
+ "jsonAttr": "helloTime",
+ "example": ["mstpctl-hello 2"]
+ },
+ "mstpctl-portnetwork": {
+ "help": "enable/disable bridge assurance capability for a port",
+ "validvals": ["<interface-yes-no-list>"],
+ "default": "no",
+ "jsonAttr": "networkPort",
+ "required": False,
+ "example": [
+ "under the bridge: mstpctl-portnetwork swp1=yes swp2=no",
+ "under the port (recommended): mstpctl-portnetwork yes"
+ ]
+ },
+ "mstpctl-portadminedge": {
+ "help": "enable/disable initial edge state of the port",
+ "validvals": ["<interface-yes-no-list>"],
+ "default": "no",
+ "jsonAttr": "adminEdgePort",
+ "required": False,
+ "example": [
+ "under the bridge: mstpctl-portadminedge swp1=yes swp2=no",
+ "under the port (recommended): mstpctl-portadminedge yes"
+ ]
+ },
+ "mstpctl-portautoedge": {
+ "help": "enable/disable auto transition to/from edge state of the port",
+ "validvals": ["<interface-yes-no-list>"],
+ "default": "yes",
+ "jsonAttr": "autoEdgePort",
+ "required": False,
+ "example": [
+ "under the bridge: mstpctl-portautoedge swp1=yes swp2=no",
+ "under the port (recommended): mstpctl-portautoedge yes"
+ ]
+ },
+ "mstpctl-treeportcost": {
+ "help": "port tree cost",
+ # "validrange": ["0", "255"],
+ "required": False,
+ "jsonAttr": "extPortCost",
+ },
+ "mstpctl-portbpdufilter": {
+ "help": "enable/disable bpdu filter on a port. syntax varies "
+ "when defined under a bridge vs under a port",
+ "validvals": ["<interface-yes-no-list>"],
+ "jsonAttr": "bpduFilterPort",
+ "default": "no",
+ "required": False,
+ "example": [
+ "under a bridge: mstpctl-portbpdufilter swp1=no swp2=no",
+ "under a port: mstpctl-portbpdufilter yes"
+ ]
+ },
+ }
+ }
# Maps mstp bridge attribute names to corresponding mstpctl commands
# XXX: This can be encoded in the modules dict above
'mstpctl-portbpdufilter' : 'portbpdufilter'}
def __init__(self, *args, **kargs):
+ Addon.__init__(self)
moduleBase.__init__(self, *args, **kargs)
if not os.path.exists('/sbin/mstpctl'):
raise moduleNotSupported('module init failed: no /sbin/mstpctl found')
- self.ipcmd = None
self.name = self.__class__.__name__
- self.brctlcmd = None
self.mstpctlcmd = None
self.mstpd_running = (True if systemUtils.is_process_running('mstpd')
else False)
return True
def _is_bridge(self, ifaceobj):
- if (ifaceobj.get_attr_value_first('mstpctl-ports') or
- ifaceobj.get_attr_value_first('bridge-ports')):
- return True
- return False
-
- def _is_bridge_port(self, ifaceobj):
- if self.brctlcmd.is_bridge_port(ifaceobj.name):
- return True
- return False
+ return ifaceobj.link_kind & ifaceLinkKind.BRIDGE \
+ or ifaceobj.get_attr_value_first('mstpctl-ports') \
+ or ifaceobj.get_attr_value_first('bridge-ports')
def get_dependent_ifacenames(self, ifaceobj, ifacenames_all=None):
if not self._is_bridge(ifaceobj):
def get_dependent_ifacenames_running(self, ifaceobj):
self._init_command_handlers()
- if (self.brctlcmd.bridge_exists(ifaceobj.name) and
+ if (self.cache.bridge_exists(ifaceobj.name) and
not self.mstpctlcmd.mstpbridge_exists(ifaceobj.name)):
return None
- return self.brctlcmd.get_bridge_ports(ifaceobj.name)
+ return self.cache.get_slaves(ifaceobj.name)
def _get_bridge_port_attr_value(self, bridgename, portname, attr):
json_attr = self.get_mod_subattr(attr, 'jsonAttr')
runningbridgeports = []
# Delete active ports not in the new port list
if not ifupdownflags.flags.PERFMODE:
- runningbridgeports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
+ runningbridgeports = self.cache.get_slaves(ifaceobj.name)
if runningbridgeports:
- [self.ipcmd.link_set(bport, 'nomaster')
- for bport in runningbridgeports
- if not bridgeports or bport not in bridgeports]
+ for bport in runningbridgeports:
+ if not bridgeports or bport not in bridgeports:
+ self.netlink.link_set_nomaster(bport)
else:
runningbridgeports = []
if not bridgeports:
for bridgeport in Set(bridgeports).difference(Set(runningbridgeports)):
try:
if (not ifupdownflags.flags.DRYRUN and
- not self.ipcmd.link_exists(bridgeport)):
+ not self.cache.link_exists(bridgeport)):
self.log_warn('%s: bridge port %s does not exist'
%(ifaceobj.name, bridgeport))
err += 1
continue
- self.ipcmd.link_set(bridgeport, 'master', ifaceobj.name)
- self.ipcmd.addr_flush(bridgeport)
+ self.netlink.link_set_master(bridgeport, ifaceobj.name)
+ self.netlink.addr_flush(bridgeport)
except Exception, e:
self.log_error(str(e), ifaceobj)
self.logger.warn('%s' %str(e))
pass
- if self.ipcmd.bridge_is_vlan_aware(ifaceobj.name):
+ if self.cache.bridge_is_vlan_aware(ifaceobj.name):
+ return
+ bridgeports = self._get_bridge_port_list(ifaceobj)
+ if not bridgeports:
return
# set bridge port attributes
for attrname, dstattrname in self._port_attrs_map.items():
try:
jsonAttr = self.get_mod_subattr(attrname, 'jsonAttr')
if default_val and jsonAttr:
- bridgeports = self._get_bridge_port_list(ifaceobj)
for port in bridgeports:
- if not self.brctlcmd.is_bridge_port(port):
+ if not self.cache.link_is_bridge_port(port):
continue
bport_ifaceobjs = ifaceobj_getfunc(port)
return self.get_mod_subattr(attr,'default')
return default_val
- def _apply_bridge_port_settings(self, ifaceobj, bridgename=None,
+ def _apply_bridge_port_settings(self, ifaceobj, bvlan_aware, bridgename=None,
bridgeifaceobj=None,
stp_running_on=True,
mstpd_running=True):
%(ifaceobj.name) +
' (stp on bridge %s is not on yet)' %bridgename)
return applied
- bvlan_aware = self.ipcmd.bridge_is_vlan_aware(bridgename)
if (not mstpd_running or
not os.path.exists('/sys/class/net/%s/brport' %ifaceobj.name) or
not bvlan_aware):
self.logger.info('%s: applying mstp configuration '
%ifaceobj.name + 'specific to ports')
# Query running bridge ports. and only apply attributes on them
- bridgeports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
+ bridgeports = self.cache.get_slaves(ifaceobj.name)
if not bridgeports:
self.logger.debug('%s: cannot find bridgeports' %ifaceobj.name)
return
+
+ bvlan_aware = self.cache.bridge_is_vlan_aware(ifaceobj.name)
+
for bport in bridgeports:
self.logger.info('%s: processing mstp config for port %s'
%(ifaceobj.name, bport))
- if not self.ipcmd.link_exists(bport):
- continue
+ if not self.cache.link_exists(bport):
+ continue
if not os.path.exists('/sys/class/net/%s/brport' %bport):
continue
bportifaceobjlist = ifaceobj_getfunc(bport)
mstpctlFlags.PORT_PROCESSED):
continue
try:
- self._apply_bridge_port_settings(bportifaceobj,
+ self._apply_bridge_port_settings(bportifaceobj, bvlan_aware,
ifaceobj.name, ifaceobj)
except Exception, e:
pass
return False
def _up(self, ifaceobj, ifaceobj_getfunc=None):
- # Check if bridge port
- bridgename = self.ipcmd.bridge_port_get_bridge_name(ifaceobj.name)
- if bridgename:
+
+ # bridge port specific:
+ if ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT:
+ bridgename = self.cache.get_master(ifaceobj.name)
+
+ if not bridgename:
+ return
+ bvlan_aware = self.cache.bridge_is_vlan_aware(bridgename)
mstpd_running = self.mstpd_running
- stp_running_on = self._is_running_userspace_stp_state_on(bridgename)
- applied = self._apply_bridge_port_settings(ifaceobj, bridgename,
+ stp_running_on = bool(self.cache.get_bridge_stp(bridgename))
+ applied = self._apply_bridge_port_settings(ifaceobj, bvlan_aware, bridgename,
None, stp_running_on,
mstpd_running)
if applied:
ifaceobj.module_flags.setdefault(self.name,0) | \
mstpctlFlags.PORT_PROCESSED
return
- if not self._is_bridge(ifaceobj):
+
+ elif not self._is_bridge(ifaceobj):
return
# we are now here because the ifaceobj is a bridge
stp = None
if ifaceobj.get_attr_value_first('mstpctl-ports'):
# If bridge ports specified with mstpctl attr, create the
# bridge and also add its ports
- self.ipcmd.batch_start()
- if not ifupdownflags.flags.PERFMODE:
- if not self.ipcmd.link_exists(ifaceobj.name):
- self.ipcmd.link_create(ifaceobj.name, 'bridge')
- else:
- self.ipcmd.link_create(ifaceobj.name, 'bridge')
+ if not self.cache.link_exists(ifaceobj.name):
+ self.netlink.link_add_bridge(ifaceobj.name)
+
try:
self._add_ports(ifaceobj)
except Exception, e:
porterr = True
porterrstr = str(e)
pass
- finally:
- self.ipcmd.batch_commit()
- running_ports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
+
+ running_ports = self.cache.get_slaves(ifaceobj.name)
if running_ports:
# disable ipv6 for ports that were added to bridge
self._ports_enable_disable_ipv6(running_ports, '1')
stp = ifaceobj.get_attr_value_first('mstpctl-stp')
if stp:
self.set_iface_attr(ifaceobj, 'mstpctl-stp',
- self.brctlcmd.bridge_set_stp)
+ self.iproute2.bridge_set_stp)
+ stp = utils.get_boolean_from_string(stp)
else:
- stp = self.brctlcmd.bridge_get_stp(ifaceobj.name)
- if (self.mstpd_running and
- (stp == 'yes' or stp == 'on')):
+ stp = self.cache.get_bridge_stp(ifaceobj.name)
+ if self.mstpd_running and stp:
+ self.mstpctlcmd.batch_start()
self._apply_bridge_settings(ifaceobj, ifaceobj_getfunc)
self._apply_bridge_port_settings_all(ifaceobj,
ifaceobj_getfunc=ifaceobj_getfunc)
+ self.mstpctlcmd.batch_commit()
except Exception, e:
self.log_error(str(e), ifaceobj)
if porterr:
if ifaceobj.get_attr_value_first('mstpctl-ports'):
# If bridge ports specified with mstpctl attr, delete the
# bridge
- ports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
+ ports = self.cache.get_slaves(ifaceobj.name)
if ports:
self._ports_enable_disable_ipv6(ports, '0')
- self.brctlcmd.delete_bridge(ifaceobj.name)
+ self.netlink.link_del(ifaceobj.name)
except Exception, e:
self.log_error(str(e), ifaceobj)
and attrname != 'mstpctl-maxhops'):
bridgeattrdict[attrname] = [v]
- ports = self.brctlcmd.get_bridge_ports(ifaceobjrunning.name)
+ ports = self.cache.get_slaves(ifaceobjrunning.name)
# Do this only for vlan-UNAWARE-bridge
if ports and not bridge_vlan_aware:
portconfig = {'mstpctl-portautoedge' : '',
policymanager.policymanager_api.get_iface_default(module_name='bridge', ifname=ifaceobj.name, attr='bridge-stp'))
return utils.get_boolean_from_string(stp)
- def _get_running_stp(self, ifaceobj):
- stp = self.brctlcmd.bridge_get_stp(ifaceobj.name)
- return utils.get_boolean_from_string(stp)
-
def _query_check_bridge(self, ifaceobj, ifaceobjcurr,
ifaceobj_getfunc=None):
# list of attributes that are not supported currently
blacklistedattrs = ['mstpctl-portpathcost',
'mstpctl-treeportprio', 'mstpctl-treeportcost']
- if not self.brctlcmd.bridge_exists(ifaceobj.name):
+ if not self.cache.bridge_exists(ifaceobj.name):
self.logger.debug('bridge %s does not exist' %ifaceobj.name)
return
ifaceattrs = self.dict_key_subset(ifaceobj.config,
if not runningattrs:
runningattrs = {}
config_stp = self._get_config_stp(ifaceobj)
- running_stp = self._get_running_stp(ifaceobj)
- running_port_list = self.brctlcmd.get_bridge_ports(ifaceobj.name)
+ running_stp = self.cache.get_bridge_stp(ifaceobj.name)
+ running_port_list = self.cache.get_slaves(ifaceobj.name)
for k in ifaceattrs:
# for all mstpctl options
if k in blacklistedattrs:
# contain more than one valid values
stp_on_vals = ['on', 'yes']
stp_off_vals = ['off']
- rv = self.brctlcmd.bridge_get_stp(ifaceobj.name)
+ rv = self.sysfs.bridge_get_stp(ifaceobj.name)
if ((v in stp_on_vals and rv in stp_on_vals) or
(v in stp_off_vals and rv in stp_off_vals)):
ifaceobjcurr.update_config_with_status('mstpctl-stp', v, 0)
self.set_default_mstp_vxlan_bridge_config and
(bifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VLAN_AWARE)):
config_stp = self._get_config_stp(bifaceobj)
- running_stp = self._get_running_stp(bifaceobj)
+ running_stp = self.cache.get_bridge_stp(bifaceobj.name)
if (not config_stp or not running_stp):
continue
for attr in (
def _query_check_bridge_port(self, ifaceobj, ifaceobjcurr):
- if not self.ipcmd.link_exists(ifaceobj.name):
+ if not self.cache.link_exists(ifaceobj.name):
#self.logger.debug('bridge port %s does not exist' %ifaceobj.name)
ifaceobjcurr.status = ifaceStatus.NOTFOUND
return
# Check if this is a bridge port
- if not self._is_bridge_port(ifaceobj):
+ if not self.cache.link_is_bridge_port(ifaceobj.name):
# mark all the bridge attributes as error
ifaceobjcurr.check_n_update_config_with_status_many(ifaceobj,
self._port_attrs_map.keys(), 0)
return
- bridgename = self.ipcmd.bridge_port_get_bridge_name(ifaceobj.name)
+ bridgename = self.cache.get_master(ifaceobj.name)
# list of attributes that are not supported currently
blacklistedattrs = ['mstpctl-portpathcost',
'mstpctl-treeportprio', 'mstpctl-treeportcost']
ifaceobjrunning.update_config(attr, v)
def _query_running_bridge_port(self, ifaceobjrunning):
- bridgename = self.ipcmd.bridge_port_get_bridge_name(
- ifaceobjrunning.name)
+ bridgename = self.cache.get_master(ifaceobjrunning.name)
if not bridgename:
self.logger.warn('%s: unable to determine bridgename'
%ifaceobjrunning.name)
return
- if self.brctlcmd.bridge_get_stp(bridgename) == 'no':
+ if self.sysfs.bridge_get_stp(bridgename) == 'no':
# This bridge does not run stp, return
return
# if userspace stp not set, return
# portconfig['mstpctl-treeportcost'] += ' %s=%s' %(p, v)
def _query_running_bridge(self, ifaceobjrunning):
- if self.brctlcmd.bridge_get_stp(ifaceobjrunning.name) == 'no':
+ if self.sysfs.bridge_get_stp(ifaceobjrunning.name) == 'no':
# This bridge does not run stp, return
return
# if userspace stp not set, return
bridge_vlan_aware))
def _query_running(self, ifaceobjrunning, **extra_args):
- if self.brctlcmd.bridge_exists(ifaceobjrunning.name):
+ if self.cache.bridge_exists(ifaceobjrunning.name):
self._query_running_bridge(ifaceobjrunning)
- elif self.brctlcmd.is_bridge_port(ifaceobjrunning.name):
+ elif self.cache.link_is_bridge_port(ifaceobjrunning.name):
self._query_running_bridge_port(ifaceobjrunning)
def _query_bridge_port(self, ifaceobj, ifaceobj_getfunc=None):
if config:
ifaceobj.replace_config(attr, config)
-
-
- _run_ops = {'pre-up' : _up,
- 'post-down' : _down,
- 'query-checkcurr' : _query_check,
- 'query-running' : _query_running,
- 'query' : _query}
+ _run_ops = {
+ "pre-up": _up,
+ "post-down": _down,
+ "query-checkcurr": _query_check,
+ "query-running": _query_running,
+ "query": _query
+ }
def get_ops(self):
""" returns list of ops supported by this module """
return self._run_ops.keys()
def _init_command_handlers(self):
- if not self.ipcmd:
- self.ipcmd = self.brctlcmd = LinkUtils()
if not self.mstpctlcmd:
self.mstpctlcmd = mstpctlutil()
import hashlib
try:
+ from ifupdown2.lib.addon import Addon
import ifupdown2.ifupdown.statemanager as statemanager
from ifupdown2.ifupdown.iface import *
from ifupdown2.ifupdown.utils import utils
- from ifupdown2.ifupdownaddons.LinkUtils import LinkUtils
from ifupdown2.ifupdownaddons.modulebase import moduleBase
from ifupdown2.ifupdown.exceptions import moduleNotSupported
except ImportError:
+ from lib.addon import Addon
import ifupdown.statemanager as statemanager
from ifupdown.iface import *
from ifupdown.utils import utils
- from ifupdownaddons.LinkUtils import LinkUtils
from ifupdownaddons.modulebase import moduleBase
from ifupdown.exceptions import moduleNotSupported
-class ppp(moduleBase):
+class ppp(Addon, moduleBase):
"""
ifupdown2 addon module to configure ppp
"""
}
def __init__(self, *args, **kargs):
+ Addon.__init__(self)
moduleBase.__init__(self, *args, **kargs)
if not os.path.exists('/usr/bin/pon'):
raise moduleNotSupported('module init failed: no /usr/bin/pon found')
- self.ipcmd = None
@staticmethod
def _is_my_interface(ifaceobj):
# Always save the current config files hash
ifaceobj.update_config('provider_file', config)
- if not self.ipcmd.link_exists(ifaceobj.name):
+ if not self.cache.link_exists(ifaceobj.name):
try:
# This fails if not running
utils.exec_user_command('/bin/ps ax | /bin/grep pppd | /bin/grep -v grep | /bin/grep ' + provider)
utils.exec_commandl(['/usr/bin/poff', old_provider], stdout=None, stderr=None)
utils.exec_commandl(['/usr/bin/pon', provider], stdout=None, stderr=None)
- except Exception, e:
+ except Exception as e:
self.log_warn(str(e))
def _down(self, ifaceobj):
# This fails if not running
utils.exec_user_command('/bin/ps ax | /bin/grep pppd | /bin/grep -v grep | /bin/grep ' + provider)
utils.exec_commandl(['/usr/bin/poff', provider], stdout=None, stderr=None)
- except Exception, e:
+ except Exception as e:
self.log_warn(str(e))
def get_dependent_ifacenames(self, ifaceobj, ifacenames_all=None):
return None
def _query_check(self, ifaceobj, ifaceobjcurr):
- if not self.ipcmd.link_exists(ifaceobj.name):
+ if not self.cache.link_exists(ifaceobj.name):
return
ifaceobjcurr.status = ifaceStatus.SUCCESS
def _query_running(self, ifaceobjrunning):
- if not self.ipcmd.link_exists(ifaceobjrunning.name):
+ if not self.cache.link_exists(ifaceobjrunning.name):
return
# Operations supported by this addon (yet).
def get_ops(self):
return self._run_ops.keys()
- def _init_command_handlers(self):
- if not self.ipcmd:
- self.ipcmd = LinkUtils()
-
def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
op_handler = self._run_ops.get(operation)
if operation != 'query-running' and not self._is_my_interface(ifaceobj):
return
- self._init_command_handlers()
if operation == 'query-checkcurr':
op_handler(self, ifaceobj, query_ifaceobj)
else:
# -- Mon 10 Oct 2016 10:53:13 PM CEST
#
try:
+ from ifupdown2.lib.addon import Addon
+ from ifupdown2.nlmanager.nlmanager import Link
+
from ifupdown2.ifupdown.iface import *
- from ifupdown2.ifupdown.netlink import netlink
- from ifupdown2.ifupdownaddons.LinkUtils import LinkUtils
from ifupdown2.ifupdownaddons.modulebase import moduleBase
import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
except ImportError:
+ from lib.addon import Addon
+ from nlmanager.nlmanager import Link
+
from ifupdown.iface import *
- from ifupdown.netlink import netlink
- from ifupdownaddons.LinkUtils import LinkUtils
from ifupdownaddons.modulebase import moduleBase
import ifupdown.ifupdownflags as ifupdownflags
#
# TODO: Add checks for ipip tunnels.
#
-class tunnel(moduleBase):
+class tunnel(Addon, moduleBase):
"""
ifupdown2 addon module to configure tunnels
"""
_modinfo = {
'mhelp': 'create/configure GRE/IPIP/SIT and GRETAP tunnel interfaces',
'attrs': {
- 'mode': {
+ 'tunnel-mode': {
'help': 'type of tunnel as in \'ip link\' command.',
'validvals': ['gre', 'gretap', 'ipip', 'sit', 'vti', 'ip6gre', 'ipip6', 'ip6ip6', 'vti6'],
'required': True,
'example': ['mode gre']
},
- 'local': {
+ 'tunnel-local': {
'help': 'IP of local tunnel endpoint',
'validvals': ['<ipv4>', '<ipv6>'],
'required': True,
'example': ['local 192.2.0.42']
},
- 'endpoint': {
+ 'tunnel-endpoint': {
'help': 'IP of remote tunnel endpoint',
'validvals': ['<ipv4>', '<ipv6>'],
'required': True,
'example': ['endpoint 192.2.0.23']
},
- 'ttl': {
+ 'tunnel-ttl': {
'help': 'TTL for tunnel packets',
'validvals': ['<number>'],
'required': False,
'example': ['ttl 64']
},
- 'tunnel-physdev': {
+ 'tunnel-dev': {
'help': 'Physical underlay device to use for tunnel packets',
'validvals': ['<interface>'],
'required': False,
def __init__(self, *args, **kargs):
moduleBase.__init__(self, *args, **kargs)
- self.ipcmd = None
+ Addon.__init__(self)
@staticmethod
def _is_my_interface(ifaceobj):
- return ifaceobj.addr_method == "tunnel" and ifaceobj.get_attr_value_first('mode')
+ return ifaceobj.get_attr_value_first("tunnel-mode")
- def _has_config_changed(self, attrs_present, attrs_configured):
+ @staticmethod
+ def _has_config_changed(attrs_present, attrs_configured):
for key, value in attrs_configured.iteritems():
if attrs_present.get(key) != value:
return True
return False
+ def __get_info_data_gre_tunnel(self, info_data):
+ tunnel_link_ifindex = info_data.get(Link.IFLA_GRE_LINK)
+
+ return {
+ "tunnel-endpoint": str(info_data.get(Link.IFLA_GRE_REMOTE)),
+ "tunnel-local": str(info_data.get(Link.IFLA_GRE_LOCAL)),
+ "tunnel-ttl": str(info_data.get(Link.IFLA_GRE_TTL)),
+ "tunnel-dev": self.cache.get_ifname(tunnel_link_ifindex) if tunnel_link_ifindex else ""
+ }
+
+ def __get_info_data_iptun_tunnel(self, info_data):
+ tunnel_link_ifindex = info_data.get(Link.IFLA_IPTUN_LINK)
+
+ return {
+ "tunnel-endpoint": str(info_data.get(Link.IFLA_IPTUN_REMOTE)),
+ "tunnel-local": str(info_data.get(Link.IFLA_IPTUN_LOCAL)),
+ "tunnel-ttl": str(info_data.get(Link.IFLA_IPTUN_TTL)),
+ "tunnel-dev": self.cache.get_ifname(tunnel_link_ifindex) if tunnel_link_ifindex else ""
+ }
+
+ def __get_info_data_vti_tunnel(self, info_data):
+ tunnel_link_ifindex = info_data.get(Link.IFLA_VTI_LINK)
+
+ return {
+ "tunnel-endpoint": str(info_data.get(Link.IFLA_VTI_REMOTE)),
+ "tunnel-local": str(info_data.get(Link.IFLA_VTI_LOCAL)),
+ "tunnel-dev": self.cache.get_ifname(tunnel_link_ifindex) if tunnel_link_ifindex else ""
+ }
+
+ def get_linkinfo_attrs(self, ifname, link_kind):
+ return {
+ "gre": self.__get_info_data_gre_tunnel,
+ "gretap": self.__get_info_data_gre_tunnel,
+ "ip6gre": self.__get_info_data_gre_tunnel,
+ "ip6gretap": self.__get_info_data_gre_tunnel,
+ "ip6erspan": self.__get_info_data_gre_tunnel,
+ "ipip": self.__get_info_data_iptun_tunnel,
+ "sit": self.__get_info_data_iptun_tunnel,
+ "ip6tnl": self.__get_info_data_iptun_tunnel,
+ "vti": self.__get_info_data_vti_tunnel,
+ "vti6": self.__get_info_data_vti_tunnel,
+ }.get(link_kind, lambda x: {})(self.cache.get_link_info_data(ifname))
+
def _up(self, ifaceobj):
attr_map = {
# attr_name -> ip route param name
- 'local': 'local',
- 'endpoint': 'remote',
- 'ttl': 'ttl',
- 'tunnel-physdev': 'dev',
+ 'tunnel-local': 'local',
+ 'tunnel-endpoint': 'remote',
+ 'tunnel-ttl': 'ttl',
+ 'tunnel-dev': 'dev',
}
- mode = ifaceobj.get_attr_value_first('mode')
+ mode = ifaceobj.get_attr_value_first('tunnel-mode')
attrs = {}
attrs_mapped = {}
# to attribute names expected by iproute
for attr, iproute_attr in attr_map.items():
attr_val = ifaceobj.get_attr_value_first(attr)
- if attr_val != None:
+ if attr_val is not None:
attrs_mapped[iproute_attr] = attr_val
attrs[attr] = attr_val
# Create the tunnel if it doesn't exist yet...
- if not self.ipcmd.link_exists(ifaceobj.name):
- self.ipcmd.tunnel_create(ifaceobj.name, mode, attrs_mapped)
+ if not self.cache.link_exists(ifaceobj.name):
+ self.iproute2.tunnel_create(ifaceobj.name, mode, attrs_mapped)
return
# If it's present, check if there were changes
- current_attrs = self.ipcmd.link_get_linkinfo_attrs(ifaceobj.name)
- current_mode = self.ipcmd.link_cache_get([ifaceobj.name, 'kind'])
+ current_mode = self.cache.get_link_kind(ifaceobj.name)
+ current_attrs = self.get_linkinfo_attrs(ifaceobj.name, current_mode)
try:
if current_attrs and current_mode != mode or self._has_config_changed(current_attrs, attrs):
# Mode and some other changes are not possible without recreating the interface,
# so just recreate it IFF there have been changes.
- self.ipcmd.link_delete(ifaceobj.name)
- self.ipcmd.tunnel_create(ifaceobj.name, mode, attrs_mapped)
+ self.netlink.link_del(ifaceobj.name)
+ self.iproute2.tunnel_create(ifaceobj.name, mode, attrs_mapped)
except Exception, e:
self.log_warn(str(e))
def _down(self, ifaceobj):
- if not ifupdownflags.flags.PERFMODE and not self.ipcmd.link_exists(ifaceobj.name):
+ if not ifupdownflags.flags.PERFMODE and not self.cache.link_exists(ifaceobj.name):
return
try:
- self.ipcmd.link_delete(ifaceobj.name)
+ self.netlink.link_del(ifaceobj.name)
except Exception, e:
self.log_warn(str(e))
if not self._is_my_interface(ifaceobj):
return None
- device = ifaceobj.get_attr_value_first('tunnel-physdev')
+ device = ifaceobj.get_attr_value_first('tunnel-dev')
if device:
return [device]
def _query_check(self, ifaceobj, ifaceobjcurr):
ifname = ifaceobj.name
- if not self.ipcmd.link_exists(ifname):
+ if not self.cache.link_exists(ifname):
return
- tunattrs = self.ipcmd.link_get_linkinfo_attrs(ifaceobj.name)
+ link_kind = self.cache.get_link_kind(ifname)
+ tunattrs = self.get_linkinfo_attrs(ifaceobj.name, link_kind)
+
if not tunattrs:
ifaceobjcurr.check_n_update_config_with_status_many(ifaceobj, self.get_mod_attrs(), -1)
return
- tunattrs["mode"] = self.ipcmd.link_get_kind(ifname)
+ tunattrs["tunnel-mode"] = link_kind
- user_config_mode = ifaceobj.get_attr_value_first("mode")
+ user_config_mode = ifaceobj.get_attr_value_first("tunnel-mode")
if user_config_mode in ('ipip6', 'ip6ip6'):
- ifaceobj.replace_config("mode", "ip6tnl")
+ ifaceobj.replace_config("tunnel-mode", "ip6tnl")
for attr in self.get_mod_attrs():
if not ifaceobj.get_attr_value_first(attr):
def get_ops(self):
return self._run_ops.keys()
- def _init_command_handlers(self):
- if not self.ipcmd:
- self.ipcmd = LinkUtils()
-
def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
op_handler = self._run_ops.get(operation)
if not op_handler:
if operation != 'query-running' and not self._is_my_interface(ifaceobj):
return
- self._init_command_handlers()
if operation == 'query-checkcurr':
op_handler(self, ifaceobj, query_ifaceobj)
else:
#
try:
- import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
-
+ from ifupdown2.lib.addon import Addon
from ifupdown2.ifupdown.iface import *
- from ifupdown2.ifupdown.netlink import netlink
-
- from ifupdown2.ifupdownaddons.LinkUtils import LinkUtils
+ from ifupdown2.nlmanager.nlmanager import Link
from ifupdown2.ifupdownaddons.modulebase import moduleBase
+ import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
except ImportError:
- import ifupdown.ifupdownflags as ifupdownflags
-
+ from lib.addon import Addon
from ifupdown.iface import *
- from ifupdown.netlink import netlink
-
- from ifupdownaddons.LinkUtils import LinkUtils
+ from nlmanager.nlmanager import Link
from ifupdownaddons.modulebase import moduleBase
+ import ifupdown.ifupdownflags as ifupdownflags
-
-class vlan(moduleBase):
+class vlan(Addon, moduleBase):
""" ifupdown2 addon module to configure vlans """
- _modinfo = {'mhelp' : 'vlan module configures vlan interfaces.' +
- 'This module understands vlan interfaces with dot ' +
- 'notations. eg swp1.100. Vlan interfaces with any ' +
- 'other names need to have raw device and vlan id ' +
- 'attributes',
- 'attrs' : {
- 'vlan-raw-device' :
- {'help' : 'vlan raw device',
- 'validvals': ['<interface>']},
- 'vlan-id' :
- {'help' : 'vlan id',
- 'validrange' : ['0', '4096']},
- 'vlan-protocol' :
- {'help' : 'vlan protocol',
- 'default' : '802.1q',
- 'validvals': ['802.1q', '802.1ad'],
- 'example' : ['vlan-protocol 802.1q']},
- }}
-
+ _modinfo = {
+ "mhelp": "vlan module configures vlan interfaces. "
+ "This module understands vlan interfaces with dot "
+ "notations. eg swp1.100. Vlan interfaces with any "
+ "other names need to have raw device and vlan id attributes",
+ "attrs": {
+ "vlan-raw-device": {
+ "help": "vlan raw device",
+ "validvals": ["<interface>"]
+ },
+ "vlan-id": {
+ "help": "vlan id",
+ "validrange": ["0", "4096"]
+ },
+ "vlan-protocol": {
+ "help": "vlan protocol",
+ "default": "802.1q",
+ "validvals": ["802.1q", "802.1ad"],
+ "example": ["vlan-protocol 802.1q"]
+ },
+ }
+ }
def __init__(self, *args, **kargs):
+ Addon.__init__(self)
moduleBase.__init__(self, *args, **kargs)
- self.ipcmd = None
- def _is_vlan_device(self, ifaceobj):
+ @staticmethod
+ def _is_vlan_device(ifaceobj):
vlan_raw_device = ifaceobj.get_attr_value_first('vlan-raw-device')
if vlan_raw_device:
return True
return True
return False
- def _is_vlan_by_name(self, ifacename):
+ @staticmethod
+ def _is_vlan_by_name(ifacename):
return '.' in ifacename
- def _get_vlan_raw_device_from_ifacename(self, ifacename):
+ @staticmethod
+ def _get_vlan_raw_device_from_ifacename(ifacename):
""" Returns vlan raw device from ifname
Example:
Returns eth0 for ifname eth0.100
ifaceobj.link_kind |= ifaceLinkKind.VLAN
return [self._get_vlan_raw_device(ifaceobj)]
- def _bridge_vid_add_del(self, ifaceobj, bridgename, vlanid,
- add=True):
+ def _bridge_vid_add_del(self, bridgename, vlanid, add=True):
""" If the lower device is a vlan aware bridge, add/del the vlanid
to the bridge """
- if self.ipcmd.bridge_is_vlan_aware(bridgename):
- if add:
- netlink.link_add_bridge_vlan(bridgename, vlanid)
- else:
- netlink.link_del_bridge_vlan(bridgename, vlanid)
+ if self.cache.bridge_is_vlan_aware(bridgename):
+ if add:
+ self.netlink.link_add_bridge_vlan(bridgename, vlanid)
+ else:
+ self.netlink.link_del_bridge_vlan(bridgename, vlanid)
- def _bridge_vid_check(self, ifaceobj, ifaceobjcurr, bridgename, vlanid):
+ def _bridge_vid_check(self, ifaceobjcurr, bridgename, vlanid):
""" If the lower device is a vlan aware bridge, check if the vlanid
is configured on the bridge """
- if not self.ipcmd.bridge_is_vlan_aware(bridgename):
+ if not self.cache.bridge_is_vlan_aware(bridgename):
return
- vids = self.ipcmd.bridge_vlan_get_vids(bridgename)
+ _, vids = self.cache.get_pvid_and_vids(bridgename)
if not vids or vlanid not in vids:
ifaceobjcurr.status = ifaceStatus.ERROR
ifaceobjcurr.status_str = 'bridge vid error'
if not vlanrawdevice:
raise Exception('could not determine vlan raw device')
- vlan_protocol = ifaceobj.get_attr_value_first('vlan-protocol')
- cached_vlan_protocol = self.ipcmd.get_vlan_protocol(ifaceobj.name)
+ ifname = ifaceobj.name
+
+ if ifupdownflags.flags.PERFMODE:
+ cached_vlan_ifla_info_data = {}
+ else:
+ cached_vlan_ifla_info_data = self.cache.get_link_info_data(ifname)
+
+ vlan_protocol = ifaceobj.get_attr_value_first('vlan-protocol')
+ cached_vlan_protocol = cached_vlan_ifla_info_data.get(Link.IFLA_VLAN_PROTOCOL)
if not vlan_protocol:
vlan_protocol = self.get_attr_default_value('vlan-protocol')
if not ifupdownflags.flags.PERFMODE:
- vlan_exists = self.ipcmd.link_exists(ifaceobj.name)
+ vlan_exists = self.cache.link_exists(ifaceobj.name)
if vlan_exists:
user_vlan_raw_device = ifaceobj.get_attr_value_first('vlan-raw-device')
- cached_vlan_raw_device = self.ipcmd.cache_get('link', [ifaceobj.name, 'link'])
+ cached_vlan_raw_device = self.cache.get_lower_device_ifname(ifname)
if cached_vlan_raw_device and user_vlan_raw_device and cached_vlan_raw_device != user_vlan_raw_device:
raise Exception('%s: cannot change vlan-raw-device from %s to %s: operation not supported. '
'Please delete the device with \'ifdown %s\' and recreate it to apply the change.'
% (ifaceobj.name, cached_vlan_raw_device, user_vlan_raw_device, ifaceobj.name))
- if not self.ipcmd.link_exists(vlanrawdevice):
- raise Exception('rawdevice %s not present' %vlanrawdevice)
+ if not self.cache.link_exists(vlanrawdevice):
+ if ifupdownflags.flags.DRYRUN:
+ return
+ else:
+ raise Exception('rawdevice %s not present' % vlanrawdevice)
if vlan_exists:
- self._bridge_vid_add_del(ifaceobj, vlanrawdevice, vlanid)
+ self._bridge_vid_add_del(vlanrawdevice, vlanid)
return
- netlink.link_add_vlan(vlanrawdevice, ifaceobj.name, vlanid, vlan_protocol)
- self._bridge_vid_add_del(ifaceobj, vlanrawdevice, vlanid)
+ self.netlink.link_add_vlan(vlanrawdevice, ifaceobj.name, vlanid, vlan_protocol)
+ self._bridge_vid_add_del(vlanrawdevice, vlanid)
def _down(self, ifaceobj):
vlanid = self._get_vlan_id(ifaceobj)
vlanrawdevice = self._get_vlan_raw_device(ifaceobj)
if not vlanrawdevice:
raise Exception('could not determine vlan raw device')
- if (not ifupdownflags.flags.PERFMODE and
- not self.ipcmd.link_exists(ifaceobj.name)):
- return
+ if not ifupdownflags.flags.PERFMODE and not self.cache.link_exists(ifaceobj.name):
+ return
try:
- netlink.link_del(ifaceobj.name)
- self._bridge_vid_add_del(ifaceobj, vlanrawdevice, vlanid, add=False)
+ self.netlink.link_del(ifaceobj.name)
+ self._bridge_vid_add_del(vlanrawdevice, vlanid, add=False)
except Exception, e:
self.log_warn(str(e))
def _query_check(self, ifaceobj, ifaceobjcurr):
- if not self.ipcmd.link_exists(ifaceobj.name):
- return
- if not '.' in ifaceobj.name:
+ if not self.cache.link_exists(ifaceobj.name):
+ return
+ if '.' not in ifaceobj.name:
# if vlan name is not in the dot format, check its running state
- (vlanrawdev, vlanid, protocol) = self.ipcmd.get_vlandev_attrs(ifaceobj.name)
- if vlanrawdev != ifaceobj.get_attr_value_first('vlan-raw-device'):
- ifaceobjcurr.update_config_with_status('vlan-raw-device',
- vlanrawdev, 1)
- else:
- ifaceobjcurr.update_config_with_status('vlan-raw-device',
- vlanrawdev, 0)
+
+ ifname = ifaceobj.name
+ cached_vlan_raw_device = self.cache.get_lower_device_ifname(ifname)
+
+ #
+ # vlan-raw-device
+ #
+ ifaceobjcurr.update_config_with_status(
+ 'vlan-raw-device',
+ cached_vlan_raw_device,
+ cached_vlan_raw_device != ifaceobj.get_attr_value_first('vlan-raw-device')
+ )
+
+ cached_vlan_info_data = self.cache.get_link_info_data(ifname)
+
+ #
+ # vlan-id
+ #
vlanid_config = ifaceobj.get_attr_value_first('vlan-id')
if not vlanid_config:
vlanid_config = str(self._get_vlan_id(ifaceobj))
- if vlanid != vlanid_config:
- ifaceobjcurr.update_config_with_status('vlan-id', vlanid, 1)
- else:
- ifaceobjcurr.update_config_with_status('vlan-id', vlanid, 0)
+
+ cached_vlan_id = cached_vlan_info_data.get(Link.IFLA_VLAN_ID)
+ cached_vlan_id_str = str(cached_vlan_id)
+ ifaceobjcurr.update_config_with_status('vlan-id', cached_vlan_id_str, vlanid_config != cached_vlan_id_str)
+
+ #
+ # vlan-protocol
+ #
protocol_config = ifaceobj.get_attr_value_first('vlan-protocol')
if protocol_config:
- if protocol_config.upper() != protocol.upper():
- ifaceobjcurr.update_config_with_status('vlan-protocol',
- protocol, 1)
+
+ cached_vlan_protocol = cached_vlan_info_data.get(Link.IFLA_VLAN_PROTOCOL)
+
+ if protocol_config.upper() != cached_vlan_protocol.upper():
+ ifaceobjcurr.update_config_with_status(
+ 'vlan-protocol',
+ cached_vlan_protocol,
+ 1
+ )
else:
- ifaceobjcurr.update_config_with_status('vlan-protocol',
- protocol, 0)
- self._bridge_vid_check(ifaceobj, ifaceobjcurr, vlanrawdev, int(vlanid))
+ ifaceobjcurr.update_config_with_status(
+ 'vlan-protocol',
+ protocol_config,
+ 0
+ )
+
+ self._bridge_vid_check(ifaceobjcurr, cached_vlan_raw_device, cached_vlan_id)
def _query_running(self, ifaceobjrunning):
- if not self.ipcmd.link_exists(ifaceobjrunning.name):
+ ifname = ifaceobjrunning.name
+
+ if not self.cache.link_exists(ifname):
return
- (vlanrawdev, vlanid, protocol) = self.ipcmd.get_vlandev_attrs(ifaceobjrunning.name)
- if not vlanid:
+
+ if not self.cache.get_link_kind(ifname) == 'vlan':
return
+
# If vlan name is not in the dot format, get the
# vlan dev and vlan id
- if not '.' in ifaceobjrunning.name:
- ifaceobjrunning.update_config_dict({k: [v] for k, v in
- {'vlan-raw-device' : vlanrawdev,
- 'vlan-id' : vlanid,
- 'vlan-protocol' : protocol}.items()
- if v})
-
- _run_ops = {'pre-up' : _up,
- 'post-down' : _down,
- 'query-checkcurr' : _query_check,
- 'query-running' : _query_running}
+ if '.' in ifname:
+ return
+
+ cached_vlan_info_data = self.cache.get_link_info_data(ifname)
+
+ for attr_name, nl_attr in (
+ ('vlan-id', Link.IFLA_VLAN_ID),
+ ('vlan-protocol', Link.IFLA_VLAN_PROTOCOL)
+ ):
+ ifaceobjrunning.update_config(attr_name, str(cached_vlan_info_data.get(nl_attr)))
+
+ ifaceobjrunning.update_config('vlan-raw-device', self.cache.get_lower_device_ifname(ifname))
+
+ _run_ops = {
+ "pre-up": _up,
+ "post-down": _down,
+ "query-checkcurr": _query_check,
+ "query-running": _query_running
+ }
def get_ops(self):
""" returns list of ops supported by this module """
return self._run_ops.keys()
- def _init_command_handlers(self):
- if not self.ipcmd:
- self.ipcmd = LinkUtils()
-
def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
""" run vlan configuration on the interface object passed as argument
if (operation != 'query-running' and
not self._is_vlan_device(ifaceobj)):
return
- self._init_command_handlers()
if operation == 'query-checkcurr':
op_handler(self, ifaceobj, query_ifaceobj)
else:
from sets import Set
try:
+ from ifupdown2.lib.addon import Addon
+
import ifupdown2.ifupdown.policymanager as policymanager
import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
from ifupdown2.ifupdown.statemanager import statemanager_api as statemanager
from ifupdown2.ifupdown.iface import *
from ifupdown2.ifupdown.utils import utils
- from ifupdown2.ifupdown.netlink import netlink
+
+ from ifupdown2.nlmanager.nlmanager import Link
from ifupdown2.ifupdownaddons.dhclient import dhclient
from ifupdown2.ifupdownaddons.utilsbase import *
- from ifupdown2.ifupdownaddons.LinkUtils import LinkUtils
from ifupdown2.ifupdownaddons.modulebase import moduleBase
except ImportError:
+ from lib.addon import Addon
+
import ifupdown.policymanager as policymanager
import ifupdown.ifupdownflags as ifupdownflags
from ifupdown.statemanager import statemanager_api as statemanager
from ifupdown.iface import *
from ifupdown.utils import utils
- from ifupdown.netlink import netlink
+
+ from nlmanager.nlmanager import Link
from ifupdownaddons.dhclient import dhclient
from ifupdownaddons.utilsbase import *
- from ifupdownaddons.LinkUtils import LinkUtils
from ifupdownaddons.modulebase import moduleBase
class vrfPrivFlags:
PROCESSED = 0x1
-class vrf(moduleBase):
+
+class vrf(Addon, moduleBase):
""" ifupdown2 addon module to configure vrfs """
- _modinfo = { 'mhelp' : 'vrf configuration module',
- 'attrs' : {
- 'vrf-table':
- {'help' : 'vrf device routing table id. key to ' +
- 'creating a vrf device. ' +
- 'Table id is either \'auto\' or '+
- '\'valid routing table id\'',
- 'validvals': ['auto', '<number>'],
- 'example': ['vrf-table auto', 'vrf-table 1001']},
- 'vrf':
- {'help' : 'vrf the interface is part of.',
- 'validvals': ['<text>'],
- 'example': ['vrf blue']}}}
-
- iproute2_vrf_filename = '/etc/iproute2/rt_tables.d/ifupdown2_vrf_map.conf'
- iproute2_vrf_filehdr = '# This file is autogenerated by ifupdown2.\n' + \
- '# It contains the vrf name to table mapping.\n' + \
- '# Reserved table range %s %s\n'
+
+ _modinfo = {
+ "mhelp": "vrf configuration module",
+ "attrs": {
+ "vrf-table": {
+ "help": "vrf device routing table id. key to creating a vrf device. "
+ "Table id is either 'auto' or 'valid routing table id'",
+ "validvals": ["auto", "<number>"],
+ "example": ["vrf-table auto", "vrf-table 1001"]
+ },
+ "vrf": {
+ "help": "vrf the interface is part of",
+ "validvals": ["<text>"],
+ "example": ["vrf blue"]
+ }
+ }
+ }
+
+ iproute2_vrf_filename = "/etc/iproute2/rt_tables.d/ifupdown2_vrf_map.conf"
+ iproute2_vrf_filehdr = "# This file is autogenerated by ifupdown2.\n" \
+ "# It contains the vrf name to table mapping.\n" \
+ "# Reserved table range %s %s\n"
VRF_TABLE_START = 1001
VRF_TABLE_END = 5000
- system_reserved_rt_tables = {'255' : 'local', '254' : 'main',
- '253' : 'default', '0' : 'unspec'}
+ system_reserved_rt_tables = {
+ "255": "local",
+ "254": "main",
+ "253": "default",
+ "0": "unspec"
+ }
def __init__(self, *args, **kargs):
+ Addon.__init__(self)
moduleBase.__init__(self, *args, **kargs)
- self.ipcmd = None
- self.bondcmd = None
self.dhclientcmd = None
self.name = self.__class__.__name__
- self.vrf_mgmt_devname = policymanager.policymanager_api.get_module_globals(module_name=self.__class__.__name__, attr='vrf-mgmt-devname')
+ self.vrf_mgmt_devname = policymanager.policymanager_api.get_module_globals(
+ module_name=self.__class__.__name__,
+ attr="vrf-mgmt-devname"
+ )
+
+ self.at_exit = False
self.user_reserved_vrf_table = []
self.l3mdev_checked = True
self._iproute2_vrf_map_initialized = False
self.iproute2_vrf_map = {}
- self.iproute2_vrf_map_fd = None
self.iproute2_vrf_map_sync_to_disk = False
self.vrf_table_id_start = policymanager.policymanager_api.get_module_globals(module_name=self.__class__.__name__, attr='vrf-table-id-start')
iproute2_vrf_map_force_rewrite = False
# read or create /etc/iproute2/rt_tables.d/ifupdown2.vrf_map
if os.path.exists(self.iproute2_vrf_filename):
- with open(self.iproute2_vrf_filename, 'r+') as vrf_map_fd:
+ with open(self.iproute2_vrf_filename, "r+" if writetodisk else "r") as vrf_map_fd:
lines = vrf_map_fd.readlines()
for l in lines:
l = l.strip()
self.logger.info('vrf: iproute2_vrf_map: unable to parse %s (%s)' %(l, str(e)))
pass
- vrfs = self.ipcmd.link_get_vrfs()
- running_vrf_map = {}
- if vrfs:
- for v, lattrs in vrfs.iteritems():
- table = lattrs.get('table', None)
- if table:
- running_vrf_map[int(table)] = v
+ running_vrf_map = self.cache.get_vrf_table_map()
if (not running_vrf_map or (running_vrf_map != self.iproute2_vrf_map)):
self.iproute2_vrf_map = running_vrf_map
iproute2_vrf_map_force_rewrite = True
- self.iproute2_vrf_map_fd = None
if writetodisk:
if iproute2_vrf_map_force_rewrite:
# reopen the file and rewrite the map
self._iproute2_vrf_map_open(False, True)
self.iproute2_vrf_map_sync_to_disk = False
- atexit.register(self._iproute2_vrf_map_sync_to_disk)
+ self.at_exit = True
+ #atexit.register(self._iproute2_vrf_map_sync_to_disk)
self.logger.info("vrf: dumping iproute2_vrf_map")
self.logger.info(self.iproute2_vrf_map)
if ifupdownflags.flags.DRYRUN:
return
fmode = 'a+' if append else 'w'
- try:
- self.iproute2_vrf_map_fd = open(self.iproute2_vrf_filename,
- '%s' %fmode)
- fcntl.fcntl(self.iproute2_vrf_map_fd, fcntl.F_SETFD, fcntl.FD_CLOEXEC)
- except Exception, e:
- self._iproute2_map_warn(str(e))
- return
-
if not append:
# write file header
- self.iproute2_vrf_map_fd.write(self.iproute2_vrf_filehdr
- %(self.vrf_table_id_start,
- self.vrf_table_id_end))
- for t, v in self.iproute2_vrf_map.iteritems():
- self.iproute2_vrf_map_fd.write('%s %s\n' %(t, v))
- self.iproute2_vrf_map_fd.flush()
+ with open(self.iproute2_vrf_filename, fmode) as vrf_map_fd:
+ vrf_map_fd.write(self.iproute2_vrf_filehdr
+ %(self.vrf_table_id_start,
+ self.vrf_table_id_end))
+ for t, v in self.iproute2_vrf_map.iteritems():
+ vrf_map_fd.write('%s %s\n' %(t, v))
+ vrf_map_fd.flush()
def _is_vrf(self, ifaceobj):
if ifaceobj.get_attr_value_first('vrf-table'):
old_vrf_name = self.iproute2_vrf_map.get(int(table_id))
if not old_vrf_name:
self.iproute2_vrf_map[int(table_id)] = vrfifaceobj.name
- if self.iproute2_vrf_map_fd:
- self.iproute2_vrf_map_fd.write('%s %s\n'
- %(table_id, vrfifaceobj.name))
- self.iproute2_vrf_map_fd.flush()
+ with open(self.iproute2_vrf_filename, "a+") as vrf_map_fd:
+ vrf_map_fd.write('%s %s\n'
+ % (table_id, vrfifaceobj.name))
+ vrf_map_fd.flush()
self.vrf_count += 1
return
if old_vrf_name != vrfifaceobj.name:
break
self._handle_existing_connections(ifaceobj, vrfname)
self.enable_ipv6_if_prev_brport(ifacename)
- self.ipcmd.link_set(ifacename, 'master', vrfname)
+ self.netlink.link_set_master(ifacename, vrfname)
return
def enable_ipv6_if_prev_brport(self, ifname):
If the intf was previously enslaved to a bridge it is possible ipv6 is still disabled.
"""
try:
- if os.path.exists("/sys/class/net/%s/brport" % ifname):
- self.write_file("/proc/sys/net/ipv6/conf/%s/disable_ipv6" % ifname, "0")
+ for ifaceobj in statemanager.get_ifaceobjs(ifname) or []:
+ if ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT:
+ self.write_file("/proc/sys/net/ipv6/conf/%s/disable_ipv6" % ifname, "0")
+ return
except Exception, e:
self.logger.info(str(e))
try:
dhclient_cmd_prefix = None
if (vrfname and self.vrf_exec_cmd_prefix and
- self.ipcmd.link_exists(vrfname)):
+ self.cache.link_exists(vrfname)):
dhclient_cmd_prefix = '%s %s' %(self.vrf_exec_cmd_prefix,
vrfname)
self.dhclientcmd.release(ifaceobj.name, dhclient_cmd_prefix)
def _handle_existing_connections(self, ifaceobj, vrfname):
if not ifaceobj or ifupdownflags.flags.PERFMODE:
return
- if (self.vrf_mgmt_devname and
- self.vrf_mgmt_devname == vrfname):
- self._kill_ssh_connections(ifaceobj.name)
+ # XXX: re-evaluate kill_ssh_sessions
+ if (self.vrf_mgmt_devname and self.vrf_mgmt_devname == vrfname):
+ self._kill_ssh_connections(ifaceobj.name, ifaceobj)
+ self._close_sockets(ifaceobj.name)
if self._is_dhcp_slave(ifaceobj):
self._down_dhcp_slave(ifaceobj, vrfname)
ifaceobj_getfunc=None, vrf_exists=False):
try:
master_exists = True
- if vrf_exists or self.ipcmd.link_exists(vrfname):
- uppers = self.ipcmd.link_get_uppers(ifacename)
+ if vrf_exists or self.cache.link_exists(vrfname):
+ uppers = self.sysfs.link_get_uppers(ifacename)
if not uppers or vrfname not in uppers:
self._handle_existing_connections(ifaceobj, vrfname)
self.enable_ipv6_if_prev_brport(ifacename)
- self.ipcmd.link_set(ifacename, 'master', vrfname)
+ self.netlink.link_set_master(ifacename, vrfname)
elif ifaceobj:
vrf_master_objs = ifaceobj_getfunc(vrfname)
if not vrf_master_objs:
# but user has not provided a vrf interface.
# people expect you to warn them but go ahead with the
# rest of the config on that interface
- netlink.link_set_updown(ifacename, "up")
+ self.netlink.link_up(ifacename)
self.log_error('vrf master ifaceobj %s not found'
%vrfname)
return
master_exists = False
if master_exists:
if not ifaceobj.link_privflags & ifaceLinkPrivFlags.KEEP_LINK_DOWN:
- netlink.link_set_updown(ifacename, "up")
+ self.netlink.link_up(ifacename)
else:
self.log_error('vrf %s not around, skipping vrf config'
%(vrfname), ifaceobj)
# - check if it is also a macvlan device of the
# format <vrf_slave>-v<int> created by the
# address virtual module
- vrfslave_lowers = self.ipcmd.link_get_lowers(vrfslave)
+ vrfslave_lowers = self.sysfs.link_get_lowers(vrfslave)
if vrfslave_lowers:
if vrfslave_lowers[0] in config_vrfslaves:
return True
return False
def _add_vrf_slaves(self, ifaceobj, ifaceobj_getfunc=None):
- running_slaves = self.ipcmd.link_get_lowers(ifaceobj.name)
+ running_slaves = self.sysfs.link_get_lowers(ifaceobj.name)
config_slaves = ifaceobj.lowerifaces
if not config_slaves and not running_slaves:
return
if add_slaves:
for s in add_slaves:
try:
- if not self.ipcmd.link_exists(s):
+ if not self.cache.link_exists(s):
continue
sobj = None
if ifaceobj_getfunc:
for slave_ifaceobj in ifaceobj_getfunc(s) or []:
if slave_ifaceobj.link_privflags & ifaceLinkPrivFlags.KEEP_LINK_DOWN:
raise Exception("link-down yes: keeping VRF slave down")
- netlink.link_set_updown(s, "up")
+ self.netlink.link_up(s)
except Exception, e:
self.logger.debug("%s: %s" % (s, str(e)))
pass
return False
def _create_vrf_dev(self, ifaceobj, vrf_table):
- if not self.ipcmd.link_exists(ifaceobj.name):
+ if not self.cache.link_exists(ifaceobj.name):
self._check_vrf_system_reserved_names(ifaceobj)
if self.vrf_count == self.vrf_max_count:
self.vrf_table_id_start,
self.vrf_table_id_end), ifaceobj)
try:
- self.ipcmd.link_create(ifaceobj.name, 'vrf',
- {'table' : '%s' %vrf_table})
+ self.netlink.link_add_vrf(ifaceobj.name, vrf_table)
except Exception, e:
self.log_error('create failed (%s)\n' % str(e), ifaceobj)
if vrf_table != 'auto':
self.log_error('unable to get vrf table id', ifaceobj)
# if the device exists, check if table id is same
- vrfdev_attrs = self.ipcmd.link_get_linkinfo_attrs(ifaceobj.name)
- if vrfdev_attrs:
- running_table = vrfdev_attrs.get('table', None)
- if vrf_table != running_table:
- self.log_error('cannot change vrf table id,running table id'
- ' %s is different from config id %s'
- % (running_table, vrf_table), ifaceobj)
+ running_table = self.cache.get_link_info_data_attribute(ifaceobj.name, Link.IFLA_VRF_TABLE)
+
+ if running_table is not None and vrf_table != str(running_table):
+ self.log_error('cannot change vrf table id,running table id'
+ ' %s is different from config id %s'
+ % (running_table, vrf_table), ifaceobj)
return vrf_table
def _up_vrf_helper(self, ifaceobj, vrf_table):
self._set_vrf_dev_processed_flag(ifaceobj)
if not ifaceobj.link_privflags & ifaceLinkPrivFlags.KEEP_LINK_DOWN:
- netlink.link_set_updown(ifaceobj.name, "up")
+ self.netlink.link_up(ifaceobj.name)
except Exception, e:
self.log_error('%s: %s' %(ifaceobj.name, str(e)), ifaceobj)
- def _kill_ssh_connections(self, ifacename):
+ def _kill_ssh_connections(self, ifacename, ifaceobj):
try:
- runningaddrsdict = self.ipcmd.get_running_addrs(None, ifacename)
- if not runningaddrsdict:
+ running_addrs_list = [str(ip) for ip in self.cache.get_ifupdown2_addresses_list(
+ ifaceobj_list=[ifaceobj],
+ ifname=ifacename,
+ )]
+
+ if not running_addrs_list:
return
- iplist = [i.split('/', 1)[0] for i in runningaddrsdict.keys()]
+
+ iplist = [i.split('/', 1)[0] for i in running_addrs_list]
+
if not iplist:
return
proc=[]
else:
vrf = ifaceobj.get_attr_value_first('vrf')
if vrf:
+ if not self.cache.link_exists(ifaceobj.name):
+ self.logger.warning("%s: device not found - please check your configuration" % ifaceobj.name)
+ return
+
self._iproute2_vrf_map_initialize()
# This is a vrf slave
self._up_vrf_slave(ifaceobj.name, vrf, ifaceobj,
ifaceobj_getfunc)
elif not ifupdownflags.flags.PERFMODE:
# check if we were a slave before
- master = self.ipcmd.link_get_master(ifaceobj.name)
+ master = self.cache.get_master(ifaceobj.name)
if master:
self._iproute2_vrf_map_initialize()
if self._is_vrf_dev(master):
vrf_table,
mode))
- def _close_sockets(self, ifaceobj, ifindex):
+ def _close_sockets(self, ifacename):
if not self.vrf_close_socks_on_down:
return
+ try:
+ ifindex = self.cache.get_ifindex(ifacename)
+ except Exception as e:
+ self.logger.debug("%s: vrf: close sockets error: %s" % str(e))
+ ifindex = 0
+
+ if not ifindex:
+ return
+
try:
utils.exec_command('%s -aK \"dev == %s\"'
%(utils.ss_cmd, ifindex))
except Exception, e:
self.logger.info('%s: closing socks using ss'
- ' failed (%s)\n' %(ifaceobj.name, str(e)))
+ ' failed (%s)\n' %(ifacename, str(e)))
pass
def _down_vrf_dev(self, ifaceobj, vrf_table, ifaceobj_getfunc=None):
- if not self.ipcmd.link_exists(ifaceobj.name):
+ if not self.cache.link_exists(ifaceobj.name):
return
if vrf_table == 'auto':
vrf_table = self._get_iproute2_vrf_table(ifaceobj.name)
- running_slaves = self.ipcmd.link_get_lowers(ifaceobj.name)
+ running_slaves = self.sysfs.link_get_lowers(ifaceobj.name)
if running_slaves:
for s in running_slaves:
if ifaceobj_getfunc:
self.logger.info('%s: %s' %(ifaceobj.name, str(e)))
pass
try:
- self.ipcmd.addr_flush(s)
- netlink.link_set_updown(s, "down")
+ self.netlink.addr_flush(s)
+ self.netlink.link_down(s)
except Exception, e:
- self.logger.info('%s: %s' %(ifaceobj.name, str(e)))
+ self.logger.info('%s: %s' %(s, str(e)))
pass
try:
self.logger.info('%s: %s' %(ifaceobj.name, str(e)))
pass
- ifindex = self.ipcmd.link_get_ifindex(ifaceobj.name)
+ self._close_sockets(ifaceobj.name)
- if ifindex:
- try:
- self.ipcmd.link_delete(ifaceobj.name)
- except Exception, e:
- self.logger.info('%s: %s' %(ifaceobj.name, str(e)))
- pass
-
- self._close_sockets(ifaceobj, ifindex)
+ try:
+ self.netlink.link_del(ifaceobj.name)
+ except Exception, e:
+ self.logger.info('%s: %s' %(ifaceobj.name, str(e)))
+ pass
try:
self._iproute2_vrf_table_entry_del(vrf_table)
def _down_vrf_slave(self, ifacename, ifaceobj=None, vrfname=None):
try:
self._handle_existing_connections(ifaceobj, vrfname)
- self.ipcmd.link_set(ifacename, 'nomaster')
+ self.netlink.link_set_nomaster(ifacename)
# Down this slave only if it is a slave ifupdown2 manages.
# we dont want to down slaves that maybe up'ed by
# somebody else. One such example is a macvlan device
# which ifupdown2 addressvirtual addon module auto creates
if ifaceobj:
- netlink.link_set_updown(ifacename, "down")
+ self.netlink.link_down(ifacename)
except Exception, e:
self.logger.warn('%s: %s' %(ifacename, str(e)))
def _query_check_vrf_slave(self, ifaceobj, ifaceobjcurr, vrf):
try:
- master = self.ipcmd.link_get_master(ifaceobj.name)
+ master = self.cache.get_master(ifaceobj.name)
if not master or master != vrf:
ifaceobjcurr.update_config_with_status('vrf', str(master), 1)
else:
def _query_check_vrf_dev(self, ifaceobj, ifaceobjcurr, vrf_table):
try:
- if not self.ipcmd.link_exists(ifaceobj.name):
+ if not self.cache.link_exists(ifaceobj.name):
self.logger.info('%s: vrf: does not exist' %(ifaceobj.name))
return
if vrf_table == 'auto':
- config_table = self._get_iproute2_vrf_table(ifaceobj.name)
+ config_table = str(self._get_iproute2_vrf_table(ifaceobj.name) or 0)
else:
config_table = vrf_table
- vrfdev_attrs = self.ipcmd.link_get_linkinfo_attrs(ifaceobj.name)
- if not vrfdev_attrs:
- ifaceobjcurr.update_config_with_status('vrf-table', 'None', 1)
- return
- running_table = vrfdev_attrs.get('table')
- if not running_table:
- ifaceobjcurr.update_config_with_status('vrf-table', 'None', 1)
- return
- if config_table != running_table:
- ifaceobjcurr.update_config_with_status('vrf-table',
- running_table, 1)
- else:
- ifaceobjcurr.update_config_with_status('vrf-table',
- running_table, 0)
+
+ running_vrf_table = str(self.cache.get_link_info_data_attribute(ifaceobj.name, Link.IFLA_VRF_TABLE))
+
+ ifaceobjcurr.update_config_with_status('vrf-table', running_vrf_table, config_table != running_vrf_table)
+
if not ifupdownflags.flags.WITHDEFAULTS:
return
if self.vrf_helper:
def _query_running(self, ifaceobjrunning, ifaceobj_getfunc=None):
try:
- kind = self.ipcmd.link_get_kind(ifaceobjrunning.name)
+ kind = self.cache.get_link_kind(ifaceobjrunning.name)
if kind == 'vrf':
- vrfdev_attrs = self.ipcmd.link_get_linkinfo_attrs(ifaceobjrunning.name)
- if vrfdev_attrs:
- running_table = vrfdev_attrs.get('table')
- if running_table:
- ifaceobjrunning.update_config('vrf-table',
- running_table)
- return
- slave_kind = self.ipcmd.link_get_slave_kind(ifaceobjrunning.name)
+ running_table = self.cache.get_link_info_data_attribute(ifaceobjrunning.name, Link.IFLA_VRF_TABLE)
+
+ if running_table is not None:
+ ifaceobjrunning.update_config('vrf-table', str(running_table))
+ return
+
+ slave_kind = self.cache.get_link_slave_kind(ifaceobjrunning.name)
if slave_kind == 'vrf_slave':
- vrf = self.ipcmd.link_get_master(ifaceobjrunning.name)
+ vrf = self.cache.get_master(ifaceobjrunning.name)
if vrf:
ifaceobjrunning.update_config('vrf', vrf)
except Exception, e:
ifaceobj.update_config('vrf-helper', '%s %s' %(self.vrf_helper,
ifaceobj.name))
- _run_ops = {'pre-up' : _up,
- 'post-down' : _down,
- 'query-running' : _query_running,
- 'query-checkcurr' : _query_check,
- 'query' : _query}
+ _run_ops = {
+ "pre-up": _up,
+ "post-down": _down,
+ "query-running": _query_running,
+ "query-checkcurr": _query_check,
+ "query": _query
+ }
def get_ops(self):
""" returns list of ops supported by this module """
return self._run_ops.keys()
def _init_command_handlers(self):
- if not self.ipcmd:
- self.ipcmd = self.bondcmd = LinkUtils()
if not self.dhclientcmd:
self.dhclientcmd = dhclient()
op_handler(self, ifaceobj, query_ifaceobj)
else:
op_handler(self, ifaceobj, ifaceobj_getfunc=ifaceobj_getfunc)
+ if self.at_exit:
+ self._iproute2_vrf_map_sync_to_disk()
+ self.at_exit = False
from sets import Set
-from ipaddr import IPNetwork, IPv4Address, IPv4Network, AddressValueError
+from ipaddr import IPNetwork, IPAddress, IPv4Address, IPv4Network, AddressValueError
try:
import ifupdown2.ifupdown.policymanager as policymanager
import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
+ from ifupdown2.lib.addon import Addon
+ from ifupdown2.lib.nlcache import NetlinkCacheIfnameNotFoundError
+
from ifupdown2.nlmanager.nlmanager import Link
from ifupdown2.ifupdown.iface import *
from ifupdown2.ifupdown.utils import utils
- from ifupdown2.ifupdown.netlink import netlink
from ifupdown2.ifupdownaddons.cache import *
- from ifupdown2.ifupdownaddons.LinkUtils import LinkUtils
from ifupdown2.ifupdownaddons.modulebase import moduleBase
except ImportError:
import ifupdown.policymanager as policymanager
import ifupdown.ifupdownflags as ifupdownflags
+ from lib.addon import Addon
+ from lib.nlcache import NetlinkCacheIfnameNotFoundError
+
from nlmanager.nlmanager import Link
from ifupdown.iface import *
from ifupdown.utils import utils
- from ifupdown.netlink import netlink
from ifupdownaddons.cache import *
- from ifupdownaddons.LinkUtils import LinkUtils
from ifupdownaddons.modulebase import moduleBase
-class vxlan(moduleBase):
- _modinfo = {'mhelp' : 'vxlan module configures vxlan interfaces.',
- 'attrs' : {
- 'vxlan-id' :
- {'help' : 'vxlan id',
- 'validrange' : ['1', '16777214'],
- 'required' : True,
- 'example': ['vxlan-id 100']},
- 'vxlan-local-tunnelip' :
- {'help' : 'vxlan local tunnel ip',
- 'validvals' : ['<ipv4>'],
- 'example': ['vxlan-local-tunnelip 172.16.20.103']},
- 'vxlan-svcnodeip' :
- {'help' : 'vxlan id',
- 'validvals' : ['<ipv4>'],
- 'example': ['vxlan-svcnodeip 172.16.22.125']},
- 'vxlan-remoteip' :
- {'help' : 'vxlan remote ip',
- 'validvals' : ['<ipv4>'],
- 'example': ['vxlan-remoteip 172.16.22.127'],
- 'multiline': True},
- 'vxlan-learning' :
- {'help' : 'vxlan learning yes/no',
- 'validvals' : ['yes', 'no', 'on', 'off'],
- 'example': ['vxlan-learning no'],
- 'default': 'yes'},
- 'vxlan-ageing' :
- {'help' : 'vxlan aging timer',
- 'validrange' : ['0', '4096'],
- 'example': ['vxlan-ageing 300'],
- 'default': '300'},
- 'vxlan-purge-remotes' :
- {'help' : 'vxlan purge existing remote entries',
- 'validvals' : ['yes', 'no'],
- 'example': ['vxlan-purge-remotes yes'],},
- 'vxlan-port': {
- 'help': 'vxlan UDP port (transmitted to vxlan driver)',
- 'example': ['vxlan-port 4789'],
- 'validrange': ['1', '65536'],
- 'default': '4789',
- },
- 'vxlan-physdev':
- {'help': 'vxlan physical device',
- 'example': ['vxlan-physdev eth1']},
- "vxlan-ttl": {
- "help": "specifies the TTL value to use in outgoing packets (range 1..255)",
- "validvals": ['<number>', 'auto'],
- "example": ['vxlan-ttl 42'],
- }
- }}
- _clagd_vxlan_anycast_ip = ""
- _vxlan_local_tunnelip = None
+class vxlan(Addon, moduleBase):
+ _modinfo = {
+ "mhelp": "vxlan module configures vxlan interfaces.",
+ "attrs": {
+ "vxlan-id": {
+ "help": "vxlan id",
+ "validrange": ["1", "16777214"],
+ "required": True,
+ "example": ["vxlan-id 100"]
+ },
+ "vxlan-local-tunnelip": {
+ "help": "vxlan local tunnel ip",
+ "validvals": ["<ipv4>"],
+ "example": ["vxlan-local-tunnelip 172.16.20.103"]
+ },
+ "vxlan-svcnodeip": {
+ "help": "vxlan id",
+ "validvals": ["<ipv4>"],
+ "example": ["vxlan-svcnodeip 172.16.22.125"]
+ },
+ "vxlan-remoteip": {
+ "help": "vxlan remote ip",
+ "validvals": ["<ipv4>"],
+ "example": ["vxlan-remoteip 172.16.22.127"],
+ "multiline": True
+ },
+ "vxlan-learning": {
+ "help": "vxlan learning yes/no",
+ "validvals": ["yes", "no", "on", "off"],
+ "example": ["vxlan-learning no"],
+ "default": "yes"
+ },
+ "vxlan-ageing": {
+ "help": "vxlan aging timer",
+ "validrange": ["0", "4096"],
+ "example": ["vxlan-ageing 300"],
+ "default": "300"
+ },
+ "vxlan-purge-remotes": {
+ "help": "vxlan purge existing remote entries",
+ "validvals": ["yes", "no"],
+ "example": ["vxlan-purge-remotes yes"],
+ },
+ "vxlan-port": {
+ "help": "vxlan UDP port (transmitted to vxlan driver)",
+ "example": ["vxlan-port 4789"],
+ "validrange": ["1", "65536"],
+ "default": "4789",
+ },
+ "vxlan-physdev": {
+ "help": "vxlan physical device",
+ "example": ["vxlan-physdev eth1"]
+ },
+ "vxlan-ttl": {
+ "help": "specifies the TTL value to use in outgoing packets "
+ "(range 0..255), 0=auto",
+ "default": "0",
+ "validvals": ["0", "255"],
+ "example": ['vxlan-ttl 42'],
+ },
+ "vxlan-mcastgrp": {
+ "help": "vxlan multicast group",
+ "validvals": ["<ip>"],
+ "example": ["vxlan-mcastgrp 172.16.22.127"],
+ }
+ }
+ }
+
+ VXLAN_PHYSDEV_MCASTGRP_DEFAULT = "ipmr-lo"
def __init__(self, *args, **kargs):
+ Addon.__init__(self)
moduleBase.__init__(self, *args, **kargs)
- self.ipcmd = None
- purge_remotes = policymanager.policymanager_api.get_module_globals(module_name=self.__class__.__name__, attr='vxlan-purge-remotes')
- if purge_remotes:
- self._purge_remotes = utils.get_boolean_from_string(purge_remotes)
- else:
- self._purge_remotes = False
+
+ self._vxlan_purge_remotes = utils.get_boolean_from_string(
+ policymanager.policymanager_api.get_module_globals(
+ module_name=self.__class__.__name__,
+ attr="vxlan-purge-remotes"
+ )
+ )
+ self._vxlan_local_tunnelip = None
+ self._clagd_vxlan_anycast_ip = ""
+
+ # If mcastgrp is specified we need to rely on a user-configred device (via physdev)
+ # or via a policy variable "vxlan-physdev_mcastgrp". If the device doesn't exist we
+ # create it as a dummy device. We need to keep track of the user configuration to
+ # know when to delete this dummy device (when user remove mcastgrp from it's config)
+ self.vxlan_mcastgrp_ref = False
+ self.vxlan_physdev_mcast = policymanager.policymanager_api.get_module_globals(
+ module_name=self.__class__.__name__,
+ attr="vxlan-physdev-mcastgrp"
+ ) or self.VXLAN_PHYSDEV_MCASTGRP_DEFAULT
+
+ def reset(self):
+ # in daemon mode we need to reset mcastgrp_ref for every new command
+ # this variable has to be set in get_dependent_ifacenames
+ self.vxlan_mcastgrp_ref = False
def syntax_check(self, ifaceobj, ifaceobj_getfunc):
if self._is_vxlan_device(ifaceobj):
- if not ifaceobj.get_attr_value_first('vxlan-local-tunnelip') and not vxlan._vxlan_local_tunnelip:
+ if not ifaceobj.get_attr_value_first('vxlan-local-tunnelip') and not self._vxlan_local_tunnelip:
self.logger.warning('%s: missing vxlan-local-tunnelip' % ifaceobj.name)
return False
return self.syntax_check_localip_anycastip_equal(
ifaceobj.name,
- ifaceobj.get_attr_value_first('vxlan-local-tunnelip') or vxlan._vxlan_local_tunnelip,
- vxlan._clagd_vxlan_anycast_ip
+ ifaceobj.get_attr_value_first('vxlan-local-tunnelip') or self._vxlan_local_tunnelip,
+ self._clagd_vxlan_anycast_ip
)
return True
def syntax_check_localip_anycastip_equal(self, ifname, local_ip, anycast_ip):
try:
- if IPNetwork(local_ip) == IPNetwork(anycast_ip):
+ if local_ip and anycast_ip and IPNetwork(local_ip) == IPNetwork(anycast_ip):
self.logger.warning('%s: vxlan-local-tunnelip and clagd-vxlan-anycast-ip are identical (%s)'
% (ifname, local_ip))
return False
if self._is_vxlan_device(ifaceobj):
ifaceobj.link_kind |= ifaceLinkKind.VXLAN
self._set_global_local_ip(ifaceobj)
+
+ # if we detect a vxlan we check if mcastgrp is set (if so we set vxlan_mcastgrp_ref)
+ # to know when to delete this device.
+ if not self.vxlan_mcastgrp_ref and ifaceobj.get_attr_value("vxlan-mcastgrp"):
+ self.vxlan_mcastgrp_ref = True
+
elif ifaceobj.name == 'lo':
clagd_vxlan_list = ifaceobj.get_attr_value('clagd-vxlan-anycast-ip')
if clagd_vxlan_list:
if len(clagd_vxlan_list) != 1:
self.log_warn('%s: multiple clagd-vxlan-anycast-ip lines, using first one'
% (ifaceobj.name,))
- vxlan._clagd_vxlan_anycast_ip = clagd_vxlan_list[0]
+ self._clagd_vxlan_anycast_ip = clagd_vxlan_list[0]
self._set_global_local_ip(ifaceobj)
def _set_global_local_ip(self, ifaceobj):
vxlan_local_tunnel_ip = ifaceobj.get_attr_value_first('vxlan-local-tunnelip')
- if vxlan_local_tunnel_ip and not vxlan._vxlan_local_tunnelip:
- vxlan._vxlan_local_tunnelip = vxlan_local_tunnel_ip
+ if vxlan_local_tunnel_ip and not self._vxlan_local_tunnelip:
+ self._vxlan_local_tunnelip = vxlan_local_tunnel_ip
- def _is_vxlan_device(self, ifaceobj):
- if ifaceobj.get_attr_value_first('vxlan-id'):
- return True
- return False
+ @staticmethod
+ def _is_vxlan_device(ifaceobj):
+ return ifaceobj.link_kind & ifaceLinkKind.VXLAN or ifaceobj.get_attr_value_first('vxlan-id')
- def _get_purge_remotes(self, ifaceobj):
+ def __get_vlxan_purge_remotes(self, ifaceobj):
if not ifaceobj:
- return self._purge_remotes
+ return self._vxlan_purge_remotes
purge_remotes = ifaceobj.get_attr_value_first('vxlan-purge-remotes')
if purge_remotes:
purge_remotes = utils.get_boolean_from_string(purge_remotes)
else:
- purge_remotes = self._purge_remotes
+ purge_remotes = self._vxlan_purge_remotes
return purge_remotes
- def should_create_set_vxlan(self, link_exists, ifname, vxlan_id, local, learning, ageing, group, ttl):
- """
- should we issue a netlink: ip link add dev %ifname type vxlan ...?
- checking each attribute against the cache
- """
- if not link_exists:
- return True
-
- try:
- if ageing:
- ageing = int(ageing)
- except:
- pass
-
- if ttl is not None and not self.ipcmd.cache_check((ifname, 'linkinfo', Link.IFLA_VXLAN_TTL), ttl):
- return True
-
- for attr_list, value in (
- ((ifname, 'linkinfo', Link.IFLA_VXLAN_ID), vxlan_id),
- ((ifname, 'linkinfo', Link.IFLA_VXLAN_AGEING), ageing),
- ((ifname, 'linkinfo', Link.IFLA_VXLAN_LOCAL), local),
- ((ifname, 'linkinfo', Link.IFLA_VXLAN_LEARNING), learning),
- ((ifname, 'linkinfo', Link.IFLA_VXLAN_GROUP), group),
- ):
- if value and not self.ipcmd.cache_check(attr_list, value):
- return True
- return False
-
def get_vxlan_ttl_from_string(self, ttl_config):
ttl = 0
if ttl_config:
ttl = int(ttl_config)
return ttl
- def _vxlan_create(self, ifaceobj):
- vxlanid = ifaceobj.get_attr_value_first('vxlan-id')
- if vxlanid:
- ifname = ifaceobj.name
- anycastip = self._clagd_vxlan_anycast_ip
- group = ifaceobj.get_attr_value_first('vxlan-svcnodeip')
+ def __config_vxlan_id(self, ifname, ifaceobj, vxlan_id_str, user_request_vxlan_info_data, cached_vxlan_ifla_info_data):
+ """
+ Get vxlan-id user config and check it's value before inserting it in our netlink dictionary
+ :param ifname:
+ :param ifaceobj:
+ :param vxlan_id_str:
+ :param user_request_vxlan_info_data:
+ :param cached_vxlan_ifla_info_data:
+ :return:
+ """
+ try:
+ vxlan_id = int(vxlan_id_str)
+ cached_vxlan_id = cached_vxlan_ifla_info_data.get(Link.IFLA_VXLAN_ID)
+
+ if cached_vxlan_id and cached_vxlan_id != vxlan_id:
+ self.log_error(
+ "%s: Cannot change running vxlan id (%s): Operation not supported"
+ % (ifname, cached_vxlan_id),
+ ifaceobj
+ )
+ user_request_vxlan_info_data[Link.IFLA_VXLAN_ID] = vxlan_id
+ except ValueError:
+ self.log_error("%s: invalid vxlan-id '%s'" % (ifname, vxlan_id_str), ifaceobj)
+
+ def __get_vxlan_ageing_int(self, ifname, ifaceobj, link_exists):
+ """
+ Get vxlan-ageing user config or via policy, return integer value, None or raise on error
+ :param ifname:
+ :param ifaceobj:
+ :param link_exists:
+ :return:
+ """
+ vxlan_ageing_str = ifaceobj.get_attr_value_first("vxlan-ageing")
+ try:
+ if vxlan_ageing_str:
+ return int(vxlan_ageing_str)
+
+ vxlan_ageing_str = policymanager.policymanager_api.get_attr_default(
+ module_name=self.__class__.__name__,
+ attr="vxlan-ageing"
+ )
+
+ if not vxlan_ageing_str and link_exists:
+ # if link doesn't exist we let the kernel define ageing
+ vxlan_ageing_str = self.get_attr_default_value("vxlan-ageing")
+
+ if vxlan_ageing_str:
+ return int(vxlan_ageing_str)
+ except:
+ self.log_error("%s: invalid vxlan-ageing '%s'" % (ifname, vxlan_ageing_str), ifaceobj)
- local = ifaceobj.get_attr_value_first('vxlan-local-tunnelip')
- if not local and vxlan._vxlan_local_tunnelip:
- local = vxlan._vxlan_local_tunnelip
+ def __config_vxlan_ageing(self, ifname, ifaceobj, link_exists, user_request_vxlan_info_data, cached_vxlan_ifla_info_data):
+ """
+ Check user config vxlan-ageing and insert it in our netlink dictionary if needed
+ """
+ vxlan_ageing = self.__get_vxlan_ageing_int(ifname, ifaceobj, link_exists)
+
+ if not vxlan_ageing or (link_exists and vxlan_ageing == cached_vxlan_ifla_info_data.get(Link.IFLA_VXLAN_AGEING)):
+ return
+
+ self.logger.info("%s: set vxlan-ageing %s" % (ifname, vxlan_ageing))
+ user_request_vxlan_info_data[Link.IFLA_VXLAN_AGEING] = vxlan_ageing
+
+ def __config_vxlan_port(self, ifname, ifaceobj, link_exists, user_request_vxlan_info_data, cached_vxlan_ifla_info_data):
+ """
+ Check vxlan-port user config, validate the integer value and insert it in the netlink dictionary if needed
+ :param ifname:
+ :param ifaceobj:
+ :param link_exists:
+ :param user_request_vxlan_info_data:
+ :param cached_vxlan_ifla_info_data:
+ :return:
+ """
+ vxlan_port_str = ifaceobj.get_attr_value_first("vxlan-port")
+ try:
+ if not vxlan_port_str:
+ vxlan_port_str = policymanager.policymanager_api.get_attr_default(
+ module_name=self.__class__.__name__,
+ attr="vxlan-port"
+ )
- ttl_config = ifaceobj.get_attr_value_first('vxlan-ttl')
try:
- if ttl_config:
- ttl = self.get_vxlan_ttl_from_string(ttl_config)
- else:
- ttl = self.get_vxlan_ttl_from_string(
- policymanager.policymanager_api.get_attr_default(
- module_name=self.__class__.__name__,
- attr='vxlan-ttl'
- )
+ vxlan_port = int(vxlan_port_str)
+ except TypeError:
+ # TypeError means vxlan_port was None
+ # ie: not provided by the user or the policy
+ vxlan_port = self.netlink.VXLAN_UDP_PORT
+ except ValueError as e:
+ self.logger.warning(
+ "%s: vxlan-port: using default %s: invalid configured value %s"
+ % (ifname, self.netlink.VXLAN_UDP_PORT, str(e))
+ )
+ vxlan_port = self.netlink.VXLAN_UDP_PORT
+
+ cached_vxlan_port = cached_vxlan_ifla_info_data.get(Link.IFLA_VXLAN_PORT)
+
+ if link_exists:
+ if vxlan_port != cached_vxlan_port:
+ self.logger.warning(
+ "%s: vxlan-port (%s) cannot be changed - to apply the desired change please run: ifdown %s && ifup %s"
+ % (ifname, cached_vxlan_port, ifname, ifname)
)
- except:
- self.log_error('%s: invalid vxlan-ttl \'%s\'' % (ifname, ttl_config), ifaceobj)
return
- self.syntax_check_localip_anycastip_equal(ifname, local, anycastip)
- # if both local-ip and anycast-ip are identical the function prints a warning
+ self.logger.info("%s: set vxlan-port %s" % (ifname, vxlan_port))
+ user_request_vxlan_info_data[Link.IFLA_VXLAN_PORT] = vxlan_port
+ except:
+ self.log_error("%s: invalid vxlan-port '%s'" % (ifname, vxlan_port_str), ifaceobj)
+
+ def __config_vxlan_ttl(self, ifname, ifaceobj, user_request_vxlan_info_data, cached_vxlan_ifla_info_data):
+ """
+ Get vxlan-ttl from user config or policy, validate integer value and insert in netlink dict
+ :param ifname:
+ :param ifaceobj:
+ :param user_request_vxlan_info_data:
+ :param cached_vxlan_ifla_info_data:
+ :return:
+ """
+ vxlan_ttl_str = ifaceobj.get_attr_value_first("vxlan-ttl")
+ try:
+ if vxlan_ttl_str:
+ vxlan_ttl = self.get_vxlan_ttl_from_string(vxlan_ttl_str)
+ else:
+ vxlan_ttl = self.get_vxlan_ttl_from_string(
+ policymanager.policymanager_api.get_attr_default(
+ module_name=self.__class__.__name__,
+ attr="vxlan-ttl"
+ )
+ )
+
+ cached_ifla_vxlan_ttl = cached_vxlan_ifla_info_data.get(Link.IFLA_VXLAN_TTL)
+ if vxlan_ttl != cached_ifla_vxlan_ttl:
+
+ if cached_ifla_vxlan_ttl is not None:
+ self.logger.info("%s: set vxlan-ttl %s (cache %s)" % (ifname, vxlan_ttl_str if vxlan_ttl_str else vxlan_ttl, cached_ifla_vxlan_ttl))
+ else:
+ self.logger.info("%s: set vxlan-ttl %s" % (ifname, vxlan_ttl_str if vxlan_ttl_str else vxlan_ttl))
+
+ user_request_vxlan_info_data[Link.IFLA_VXLAN_TTL] = vxlan_ttl
+ except:
+ self.log_error("%s: invalid vxlan-ttl '%s'" % (ifname, vxlan_ttl_str), ifaceobj)
+
+ def __config_vxlan_local_tunnelip(self, ifname, ifaceobj, link_exists, user_request_vxlan_info_data, cached_vxlan_ifla_info_data):
+ """
+ Get vxlan-local-tunnelip user config or policy, validate ip address format and insert in netlink dict
+ :param ifname:
+ :param ifaceobj:
+ :param link_exists:
+ :param user_request_vxlan_info_data:
+ :param cached_vxlan_ifla_info_data:
+ :return:
+ """
+ local = ifaceobj.get_attr_value_first("vxlan-local-tunnelip")
+
+ if not local and self._vxlan_local_tunnelip:
+ local = self._vxlan_local_tunnelip
+
+ if link_exists:
+ # on ifreload do not overwrite anycast_ip to individual ip
+ # if clagd has modified
+ running_localtunnelip = cached_vxlan_ifla_info_data.get(Link.IFLA_VXLAN_LOCAL)
+
+ if self._clagd_vxlan_anycast_ip and running_localtunnelip:
+ anycastip = IPAddress(self._clagd_vxlan_anycast_ip)
+ if anycastip == running_localtunnelip:
+ local = running_localtunnelip
+
+ if not local:
+ local = policymanager.policymanager_api.get_attr_default(
+ module_name=self.__class__.__name__,
+ attr="vxlan-local-tunnelip"
+ )
+
+ if local:
+ try:
+ local = IPv4Address(local)
+ except AddressValueError:
+ try:
+ local_ip = IPv4Network(local).ip
+ self.logger.warning("%s: vxlan-local-tunnelip %s: netmask ignored" % (ifname, local))
+ local = local_ip
+ except:
+ raise Exception("%s: invalid vxlan-local-tunnelip %s: must be in ipv4 format" % (ifname, local))
+
+ cached_ifla_vxlan_local = cached_vxlan_ifla_info_data.get(Link.IFLA_VXLAN_LOCAL)
+
+ if local:
+ if local != cached_ifla_vxlan_local:
+ self.logger.info("%s: set vxlan-local-tunnelip %s" % (ifname, local))
+ user_request_vxlan_info_data[Link.IFLA_VXLAN_LOCAL] = local
+
+ # if both local-ip and anycast-ip are identical the function prints a warning
+ self.syntax_check_localip_anycastip_equal(ifname, local, self._clagd_vxlan_anycast_ip)
+ elif cached_ifla_vxlan_local:
+ self.logger.info("%s: removing vxlan-local-tunnelip (cache %s)" % (ifname, cached_ifla_vxlan_local))
+ user_request_vxlan_info_data[Link.IFLA_VXLAN_LOCAL] = None
+
+ return local
+
+ def __get_vxlan_mcast_grp(self, ifaceobj):
+ """
+ Get vxlan-mcastgrp user config or policy
+ :param ifaceobj:
+ :return:
+ """
+ vxlan_mcast_grp = ifaceobj.get_attr_value_first("vxlan-mcastgrp")
+
+ if not vxlan_mcast_grp:
+ vxlan_mcast_grp = policymanager.policymanager_api.get_attr_default(
+ module_name=self.__class__.__name__,
+ attr="vxlan-mcastgrp"
+ )
+
+ return vxlan_mcast_grp
+
+ def __get_vxlan_svcnodeip(self, ifaceobj):
+ """
+ Get vxlan-svcnodeip user config or policy
+ :param ifaceobj:
+ :return:
+ """
+ vxlan_svcnodeip = ifaceobj.get_attr_value_first('vxlan-svcnodeip')
- ageing = ifaceobj.get_attr_value_first('vxlan-ageing')
- vxlan_port = ifaceobj.get_attr_value_first('vxlan-port')
- physdev = ifaceobj.get_attr_value_first('vxlan-physdev')
- purge_remotes = self._get_purge_remotes(ifaceobj)
+ if not vxlan_svcnodeip:
+ vxlan_svcnodeip = policymanager.policymanager_api.get_attr_default(
+ module_name=self.__class__.__name__,
+ attr="vxlan-svcnodeip"
+ )
- link_exists = self.ipcmd.link_exists(ifname)
+ return vxlan_svcnodeip
- if (not link_exists or
- not ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT):
- vxlan_learning = ifaceobj.get_attr_value_first('vxlan-learning')
- if not vxlan_learning:
- vxlan_learning = self.get_attr_default_value('vxlan-learning')
- learning = utils.get_boolean_from_string(vxlan_learning)
+ def __config_vxlan_group(self, ifname, ifaceobj, link_exists, mcast_grp, group, physdev, user_request_vxlan_info_data, cached_vxlan_ifla_info_data):
+ """
+ vxlan-mcastgrp and vxlan-svcnodeip are mutually exclusive
+ this function validates ip format for both attribute and tries to understand
+ what the user really want (remote or group option).
+
+ :param ifname:
+ :param ifaceobj:
+ :param mcast_grp:
+ :param group:
+ :param physdev:
+ :param user_request_vxlan_info_data:
+ :param cached_vxlan_ifla_info_data:
+ :return:
+ """
+ if mcast_grp and group:
+ self.log_error("%s: both group (vxlan-mcastgrp %s) and "
+ "remote (vxlan-svcnodeip %s) cannot be specified"
+ % (ifname, mcast_grp, group), ifaceobj)
+
+ attribute_name = "vxlan-svcnodeip"
+ multicast_group_change = False
+
+ if group:
+ try:
+ group = IPv4Address(group)
+ except AddressValueError:
+ try:
+ group_ip = IPv4Network(group).ip
+ self.logger.warning("%s: vxlan-svcnodeip %s: netmask ignored" % (ifname, group))
+ group = group_ip
+ except:
+ raise Exception("%s: invalid vxlan-svcnodeip %s: must be in ipv4 format" % (ifname, group))
+
+ if group.is_multicast:
+ self.logger.warning("%s: vxlan-svcnodeip %s: invalid group address, "
+ "for multicast IP please use attribute \"vxlan-mcastgrp\"" % (ifname, group))
+ # if svcnodeip is used instead of mcastgrp we warn the user
+ # if mcast_grp is not provided by the user we can instead
+ # use the svcnodeip value
+ if not physdev:
+ self.log_error("%s: vxlan: 'group' (vxlan-mcastgrp) requires 'vxlan-physdev' to be specified" % (ifname))
+
+ elif mcast_grp:
+ try:
+ mcast_grp = IPv4Address(mcast_grp)
+ except AddressValueError:
+ try:
+ group_ip = IPv4Network(mcast_grp).ip
+ self.logger.warning("%s: vxlan-mcastgrp %s: netmask ignored" % (ifname, mcast_grp))
+ mcast_grp = group_ip
+ except:
+ raise Exception("%s: invalid vxlan-mcastgrp %s: must be in ipv4 format" % (ifname, mcast_grp))
+
+ if not mcast_grp.is_multicast:
+ self.logger.warning("%s: vxlan-mcastgrp %s: invalid group address, "
+ "for non-multicast IP please use attribute \"vxlan-svcnodeip\""
+ % (ifname, mcast_grp))
+ # if mcastgrp is specified with a non-multicast address
+ # we warn the user. If the svcnodeip wasn't specified by
+ # the user we can use the mcastgrp value as svcnodeip
+ if not group:
+ group = mcast_grp
+ mcast_grp = None
else:
- learning = utils.get_boolean_from_string(
- self.ipcmd.get_vxlandev_learning(ifname))
+ attribute_name = "vxlan-mcastgrp"
+
+ if mcast_grp:
+ group = mcast_grp
+
+ if not physdev:
+ self.log_error("%s: vxlan: 'group' (vxlan-mcastgrp) requires 'vxlan-physdev' to be specified" % (ifname))
+
+ cached_ifla_vxlan_group = cached_vxlan_ifla_info_data.get(Link.IFLA_VXLAN_GROUP)
+
+ if group != cached_ifla_vxlan_group:
+
+ if not group:
+ group = IPAddress("0.0.0.0")
+ attribute_name = "vxlan-svcnodeip/vxlan-mcastgrp"
+
+ self.logger.info("%s: set %s %s" % (ifname, attribute_name, group))
+ user_request_vxlan_info_data[Link.IFLA_VXLAN_GROUP] = group
+
+ # if the mcastgrp address is changed we need to signal this to the upper function
+ # in this case vxlan needs to be down before applying changes then up'd
+ multicast_group_change = True
if link_exists:
- vxlanattrs = self.ipcmd.get_vxlandev_attrs(ifname)
- # on ifreload do not overwrite anycast_ip to individual ip
- # if clagd has modified
- if vxlanattrs:
- running_localtunnelip = vxlanattrs.get('local')
- if (anycastip and running_localtunnelip and
- anycastip == running_localtunnelip):
- local = running_localtunnelip
- if vxlanattrs.get('vxlanid') != vxlanid:
- self.log_error('%s: Cannot change running vxlan id: '
- 'Operation not supported' % ifname, ifaceobj)
+ if cached_ifla_vxlan_group:
+ self.logger.info(
+ "%s: vxlan-mcastgrp configuration changed (cache %s): flapping vxlan device required"
+ % (ifname, cached_ifla_vxlan_group)
+ )
else:
- device_link_kind = self.ipcmd.link_get_kind(ifname)
- if not device_link_kind:
- self.logger.error("%s: device already exists and is not a vxlan" % ifname)
- ifaceobj.set_status(ifaceStatus.ERROR)
- return
- elif device_link_kind != "vxlan":
- self.logger.error("%s: device already exists and is not a vxlan (type %s)" % (ifname, device_link_kind))
- ifaceobj.set_status(ifaceStatus.ERROR)
- return
+ self.logger.info(
+ "%s: vxlan-mcastgrp configuration changed: flapping vxlan device required" % ifname
+ )
- try:
- vxlanid = int(vxlanid)
- except:
- self.log_error('%s: invalid vxlan-id \'%s\'' % (ifname, vxlanid), ifaceobj)
+ return group, multicast_group_change
- if not group:
- group = policymanager.policymanager_api.get_attr_default(
- module_name=self.__class__.__name__,
- attr='vxlan-svcnodeip'
- )
+ def __config_vxlan_learning(self, ifaceobj, link_exists, user_request_vxlan_info_data, cached_vxlan_ifla_info_data):
+ if not link_exists or not ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT:
+ vxlan_learning = ifaceobj.get_attr_value_first('vxlan-learning')
+ if not vxlan_learning:
+ vxlan_learning = self.get_attr_default_value('vxlan-learning')
+ vxlan_learning = utils.get_boolean_from_string(vxlan_learning)
+ else:
+ vxlan_learning = cached_vxlan_ifla_info_data.get(Link.IFLA_VXLAN_LEARNING)
- if group:
- try:
- group = IPv4Address(group)
- except AddressValueError:
- try:
- group_ip = IPv4Network(group).ip
- self.logger.warning('%s: vxlan-svcnodeip %s: netmask ignored' % (ifname, group))
- group = group_ip
- except:
- raise Exception('%s: invalid vxlan-svcnodeip %s: must be in ipv4 format' % (ifname, group))
-
- if not local:
- local = policymanager.policymanager_api.get_attr_default(
- module_name=self.__class__.__name__,
- attr='vxlan-local-tunnelip'
- )
+ if vxlan_learning != cached_vxlan_ifla_info_data.get(Link.IFLA_VXLAN_LEARNING):
+ self.logger.info("%s: set vxlan-learning %s" % (ifaceobj.name, "on" if vxlan_learning else "off"))
+ user_request_vxlan_info_data[Link.IFLA_VXLAN_LEARNING] = vxlan_learning
+
+ def __get_vxlan_physdev(self, ifaceobj, mcastgrp):
+ """
+ vxlan-physdev wrapper, special handling is required for mcastgrp is provided
+ the vxlan needs to use a dummy or real device for tunnel endpoint communication
+ This wrapper will get the physdev from user config or policy. IF the device
+ doesnt exists we create a dummy device.
+
+ :param ifaceobj:
+ :param mcastgrp:
+ :return physdev:
+ """
+ physdev = ifaceobj.get_attr_value_first("vxlan-physdev")
- if local:
+ # if the user provided a physdev we need to honor his config
+ # or if mcastgrp wasn't specified we don't need to go further
+ if physdev or not mcastgrp:
+ return physdev
+
+ physdev = self.vxlan_physdev_mcast
+
+ if not self.cache.link_exists(physdev):
+ self.logger.info("%s: needs a dummy device (%s) to use for "
+ "multicast termination (vxlan-mcastgrp %s)"
+ % (ifaceobj.name, physdev, mcastgrp))
+ self.netlink.link_add_with_attributes(ifname=physdev, kind="dummy", ifla={Link.IFLA_MTU: 16000, Link.IFLA_LINKMODE: 1})
+ self.netlink.link_up(physdev)
+
+ return physdev
+
+ def __config_vxlan_physdev(self, link_exists, ifaceobj, vxlan_physdev, user_request_vxlan_info_data, cached_vxlan_ifla_info_data):
+ if vxlan_physdev:
+ try:
+ vxlan_physdev_ifindex = self.cache.get_ifindex(vxlan_physdev)
+ except NetlinkCacheIfnameNotFoundError:
try:
- local = IPv4Address(local)
- except AddressValueError:
- try:
- local_ip = IPv4Network(local).ip
- self.logger.warning('%s: vxlan-local-tunnelip %s: netmask ignored' % (ifname, local))
- local = local_ip
- except:
- raise Exception('%s: invalid vxlan-local-tunnelip %s: must be in ipv4 format' % (ifname, local))
-
- if not ageing:
- ageing = policymanager.policymanager_api.get_attr_default(
- module_name=self.__class__.__name__,
- attr='vxlan-ageing'
- )
+ vxlan_physdev_ifindex = int(self.sysfs.read_file_oneline("/sys/class/net/%s/ifindex" % vxlan_physdev))
+ except:
+ self.logger.error("%s: physdev %s doesn't exists" % (ifaceobj.name, vxlan_physdev))
+ return
- if not ageing and link_exists:
- # if link doesn't exist we let the kernel define ageing
- ageing = self.get_attr_default_value('vxlan-ageing')
+ if vxlan_physdev_ifindex != cached_vxlan_ifla_info_data.get(Link.IFLA_VXLAN_LINK):
+ self.logger.info("%s: set vxlan-physdev %s" % (ifaceobj.name, vxlan_physdev))
+ user_request_vxlan_info_data[Link.IFLA_VXLAN_LINK] = vxlan_physdev_ifindex
- if not vxlan_port:
- vxlan_port = policymanager.policymanager_api.get_attr_default(
- module_name=self.__class__.__name__,
- attr='vxlan-port'
+ # if the vxlan exists we need to return True, meaning that the vxlan
+ # needs to be flapped because we detected a vxlan-physdev change
+ if link_exists:
+ self.logger.info("%s: vxlan-physdev configuration changed: flapping vxlan device required" % ifaceobj.name)
+ return True
+
+ return False
+
+ def _up(self, ifaceobj):
+ vxlan_id_str = ifaceobj.get_attr_value_first("vxlan-id")
+
+ if not vxlan_id_str:
+ return
+
+ ifname = ifaceobj.name
+ link_exists = self.cache.link_exists(ifname)
+
+ if link_exists:
+ # if link already exists make sure this is a vxlan
+ device_link_kind = self.cache.get_link_kind(ifname)
+
+ if device_link_kind != "vxlan":
+ self.logger.error(
+ "%s: device already exists and is not a vxlan (type %s)"
+ % (ifname, device_link_kind)
)
+ ifaceobj.set_status(ifaceStatus.ERROR)
+ return
- try:
- vxlan_port = int(vxlan_port)
- except TypeError:
- # TypeError means vxlan_port was None
- # ie: not provided by the user or the policy
- vxlan_port = netlink.VXLAN_UDP_PORT
- except ValueError as e:
- self.logger.warning('%s: vxlan-port: using default %s: invalid configured value %s' % (ifname, netlink.VXLAN_UDP_PORT, str(e)))
- vxlan_port = netlink.VXLAN_UDP_PORT
+ # get vxlan running attributes
+ cached_vxlan_ifla_info_data = self.cache.get_link_info_data(ifname)
+ else:
+ cached_vxlan_ifla_info_data = {}
- if link_exists and vxlanattrs and not ifupdownflags.flags.DRYRUN:
- cache_port = vxlanattrs.get(Link.IFLA_VXLAN_PORT)
- if vxlan_port != cache_port:
- self.logger.warning('%s: vxlan-port (%s) cannot be changed - to apply the desired change please run: ifdown %s && ifup %s'
- % (ifname, cache_port, ifname, ifname))
- vxlan_port = cache_port
+ user_request_vxlan_info_data = {}
- if self.should_create_set_vxlan(link_exists, ifname, vxlanid, local, learning, ageing, group, ttl):
+ self.__config_vxlan_id(ifname, ifaceobj, vxlan_id_str, user_request_vxlan_info_data, cached_vxlan_ifla_info_data)
+ self.__config_vxlan_learning(ifaceobj, link_exists, user_request_vxlan_info_data, cached_vxlan_ifla_info_data)
+ self.__config_vxlan_ageing(ifname, ifaceobj, link_exists, user_request_vxlan_info_data, cached_vxlan_ifla_info_data)
+ self.__config_vxlan_port(ifname, ifaceobj, link_exists, user_request_vxlan_info_data, cached_vxlan_ifla_info_data)
+ self.__config_vxlan_ttl(ifname, ifaceobj, user_request_vxlan_info_data, cached_vxlan_ifla_info_data)
+ local = self.__config_vxlan_local_tunnelip(ifname, ifaceobj, link_exists, user_request_vxlan_info_data, cached_vxlan_ifla_info_data)
+
+ vxlan_mcast_grp = self.__get_vxlan_mcast_grp(ifaceobj)
+ vxlan_svcnodeip = self.__get_vxlan_svcnodeip(ifaceobj)
+ vxlan_physdev = self.__get_vxlan_physdev(ifaceobj, vxlan_mcast_grp)
+
+ vxlan_physdev_changed = self.__config_vxlan_physdev(
+ link_exists,
+ ifaceobj,
+ vxlan_physdev,
+ user_request_vxlan_info_data,
+ cached_vxlan_ifla_info_data
+ )
+
+ group, multicast_group_changed = self.__config_vxlan_group(
+ ifname,
+ ifaceobj,
+ link_exists,
+ vxlan_mcast_grp,
+ vxlan_svcnodeip,
+ vxlan_physdev,
+ user_request_vxlan_info_data,
+ cached_vxlan_ifla_info_data
+ )
+
+ flap_vxlan_device = link_exists and (multicast_group_changed or vxlan_physdev_changed)
+
+ if user_request_vxlan_info_data:
+
+ if link_exists and not len(user_request_vxlan_info_data) > 1:
+ # if the vxlan already exists it's already cached
+ # user_request_vxlan_info_data always contains at least one
+ # element: vxlan-id
+ self.logger.info('%s: vxlan already exists - no change detected' % ifname)
+ else:
try:
- netlink.link_add_vxlan(ifname, vxlanid,
- local=local,
- learning=learning,
- ageing=ageing,
- group=group,
- dstport=vxlan_port,
- physdev=physdev,
- ttl=ttl)
- except Exception as e_netlink:
- self.logger.debug('%s: vxlan netlink: %s' % (ifname, str(e_netlink)))
- try:
- self.ipcmd.link_create_vxlan(ifname, vxlanid,
- localtunnelip=local,
- svcnodeip=group,
- remoteips=ifaceobj.get_attr_value('vxlan-remoteip'),
- learning='on' if learning else 'off',
- ageing=ageing,
- ttl=ttl)
- except Exception as e_iproute2:
- self.logger.warning('%s: vxlan add/set failed: %s' % (ifname, str(e_iproute2)))
- return
+ if flap_vxlan_device:
+ self.netlink.link_down_force(ifname)
+
+ self.netlink.link_add_vxlan_with_info_data(ifname, user_request_vxlan_info_data)
+
+ if flap_vxlan_device:
+ self.netlink.link_up_force(ifname)
+ except Exception as e:
+ if link_exists:
+ self.log_error("%s: applying vxlan change failed: %s" % (ifname, str(e)), ifaceobj)
+ else:
+ self.log_error("%s: vxlan creation failed: %s" % (ifname, str(e)), ifaceobj)
+ return
+
+ vxlan_purge_remotes = self.__get_vlxan_purge_remotes(ifaceobj)
+
+ remoteips = ifaceobj.get_attr_value('vxlan-remoteip')
+ if remoteips:
+ try:
+ for remoteip in remoteips:
+ IPv4Address(remoteip)
+ except Exception as e:
+ self.log_error('%s: vxlan-remoteip: %s' % (ifaceobj.name, str(e)))
+
+ if vxlan_purge_remotes or remoteips:
+ # figure out the diff for remotes and do the bridge fdb updates
+ # only if provisioned by user and not by an vxlan external
+ # controller.
+ peers = self.iproute2.get_vxlan_peers(ifaceobj.name, group)
+ if local and remoteips and local in remoteips:
+ remoteips.remove(local)
+ cur_peers = set(peers)
+ if remoteips:
+ new_peers = set(remoteips)
+ del_list = cur_peers.difference(new_peers)
+ add_list = new_peers.difference(cur_peers)
+ else:
+ del_list = cur_peers
+ add_list = []
+ for addr in del_list:
try:
- # manually adding an entry to the caching after creating/updating the vxlan
- if not ifname in linkCache.links:
- linkCache.links[ifname] = {'linkinfo': {}}
- linkCache.links[ifname]['linkinfo'].update({
- 'learning': learning,
- Link.IFLA_VXLAN_LEARNING: learning,
- 'vxlanid': str(vxlanid),
- Link.IFLA_VXLAN_ID: vxlanid
- })
- if ageing:
- linkCache.links[ifname]['linkinfo'].update({
- 'ageing': ageing,
- Link.IFLA_VXLAN_AGEING: int(ageing)
- })
+ self.iproute2.bridge_fdb_del(
+ ifaceobj.name,
+ "00:00:00:00:00:00",
+ None, True, addr
+ )
except:
pass
- else:
- self.logger.info('%s: vxlan already exists' % ifname)
- # if the vxlan already exists it's already cached
- remoteips = ifaceobj.get_attr_value('vxlan-remoteip')
- if remoteips:
+ for addr in add_list:
try:
- for remoteip in remoteips:
- IPv4Address(remoteip)
- except Exception as e:
- self.log_error('%s: vxlan-remoteip: %s' %(ifaceobj.name, str(e)))
-
- if purge_remotes or remoteips:
- # figure out the diff for remotes and do the bridge fdb updates
- # only if provisioned by user and not by an vxlan external
- # controller.
- peers = self.ipcmd.get_vxlan_peers(ifaceobj.name, group)
- if local and remoteips and local in remoteips:
- remoteips.remove(local)
- cur_peers = set(peers)
- if remoteips:
- new_peers = set(remoteips)
- del_list = cur_peers.difference(new_peers)
- add_list = new_peers.difference(cur_peers)
- else:
- del_list = cur_peers
- add_list = []
-
- for addr in del_list:
- try:
- self.ipcmd.bridge_fdb_del(ifaceobj.name,
- '00:00:00:00:00:00',
- None, True, addr)
- except:
- pass
-
- for addr in add_list:
- try:
- self.ipcmd.bridge_fdb_append(ifaceobj.name,
- '00:00:00:00:00:00',
- None, True, addr)
- except:
- pass
-
- def _up(self, ifaceobj):
- self._vxlan_create(ifaceobj)
+ self.iproute2.bridge_fdb_append(
+ ifaceobj.name,
+ "00:00:00:00:00:00",
+ None, True, addr
+ )
+ except:
+ pass
def _down(self, ifaceobj):
try:
- self.ipcmd.link_delete(ifaceobj.name)
+ self.netlink.link_del(ifaceobj.name)
except Exception, e:
self.log_warn(str(e))
- def _query_check_n_update(self, ifaceobj, ifaceobjcurr, attrname, attrval,
- running_attrval):
+ @staticmethod
+ def _query_check_n_update(ifaceobj, ifaceobjcurr, attrname, attrval, running_attrval):
if not ifaceobj.get_attr_value_first(attrname):
return
if running_attrval and attrval == running_attrval:
- ifaceobjcurr.update_config_with_status(attrname, attrval, 0)
+ ifaceobjcurr.update_config_with_status(attrname, attrval, 0)
else:
- ifaceobjcurr.update_config_with_status(attrname, running_attrval, 1)
+ ifaceobjcurr.update_config_with_status(attrname, running_attrval, 1)
- def _query_check_n_update_addresses(self, ifaceobjcurr, attrname,
- addresses, running_addresses):
+ @staticmethod
+ def _query_check_n_update_addresses(ifaceobjcurr, attrname, addresses, running_addresses):
if addresses:
for a in addresses:
if a in running_addresses:
ifaceobjcurr.update_config_with_status(attrname, a, 1)
running_addresses = Set(running_addresses).difference(
Set(addresses))
- [ifaceobjcurr.update_config_with_status(attrname, a, 1)
- for a in running_addresses]
+ [ifaceobjcurr.update_config_with_status(attrname, a, 1) for a in running_addresses]
def _query_check(self, ifaceobj, ifaceobjcurr):
- if not self.ipcmd.link_exists(ifaceobj.name):
- return
- # Update vxlan object
- vxlanattrs = self.ipcmd.get_vxlandev_attrs(ifaceobj.name)
- if not vxlanattrs:
- ifaceobjcurr.check_n_update_config_with_status_many(ifaceobj,
- self.get_mod_attrs(), -1)
+ ifname = ifaceobj.name
+
+ if not self.cache.link_exists(ifname):
return
- self._query_check_n_update(ifaceobj, ifaceobjcurr, 'vxlan-id',
- ifaceobj.get_attr_value_first('vxlan-id'),
- vxlanattrs.get('vxlanid'))
- self._query_check_n_update(
- ifaceobj,
- ifaceobjcurr,
- 'vxlan-port',
- ifaceobj.get_attr_value_first('vxlan-port'),
- str(vxlanattrs.get(Link.IFLA_VXLAN_PORT))
- )
+ cached_vxlan_ifla_info_data = self.cache.get_link_info_data(ifname)
+
+ if not cached_vxlan_ifla_info_data:
+ ifaceobjcurr.check_n_update_config_with_status_many(ifaceobj, self.get_mod_attrs(), -1)
+ return
+
+ for vxlan_attr_str, vxlan_attr_nl, callable_type in (
+ ('vxlan-id', Link.IFLA_VXLAN_ID, int),
+ ('vxlan-ttl', Link.IFLA_VXLAN_TTL, int),
+ ('vxlan-port', Link.IFLA_VXLAN_PORT, int),
+ ('vxlan-ageing', Link.IFLA_VXLAN_AGEING, int),
+ ('vxlan-mcastgrp', Link.IFLA_VXLAN_GROUP, IPv4Address),
+ ('vxlan-svcnodeip', Link.IFLA_VXLAN_GROUP, IPv4Address),
+ ('vxlan-physdev', Link.IFLA_VXLAN_LINK, lambda x: self.cache.get_ifindex(x)),
+ ('vxlan-learning', Link.IFLA_VXLAN_LEARNING, lambda boolean_str: utils.get_boolean_from_string(boolean_str)),
+ ):
+ vxlan_attr_value = ifaceobj.get_attr_value_first(vxlan_attr_str)
- running_attrval = vxlanattrs.get('local')
+ if not vxlan_attr_value:
+ continue
+
+ cached_vxlan_attr_value = cached_vxlan_ifla_info_data.get(vxlan_attr_nl)
+
+ try:
+ vxlan_attr_value_nl = callable_type(vxlan_attr_value)
+ except Exception as e:
+ self.logger.warning('%s: %s: %s' % (ifname, vxlan_attr_str, str(e)))
+ ifaceobjcurr.update_config_with_status(vxlan_attr_str, cached_vxlan_attr_value or 'None', 1)
+ continue
+
+ if vxlan_attr_value_nl == cached_vxlan_attr_value:
+ ifaceobjcurr.update_config_with_status(vxlan_attr_str, vxlan_attr_value, 0)
+ else:
+ ifaceobjcurr.update_config_with_status(vxlan_attr_str, cached_vxlan_attr_value or 'None', 1)
+
+ #
+ # vxlan-local-tunnelip
+ #
+ running_attrval = cached_vxlan_ifla_info_data.get(Link.IFLA_VXLAN_LOCAL)
attrval = ifaceobj.get_attr_value_first('vxlan-local-tunnelip')
if not attrval:
- attrval = vxlan._vxlan_local_tunnelip
+ attrval = self._vxlan_local_tunnelip
+ # TODO: vxlan._vxlan_local_tunnelip should be a IPNetwork obj
ifaceobj.update_config('vxlan-local-tunnelip', attrval)
- if running_attrval == self._clagd_vxlan_anycast_ip:
+ if str(running_attrval) == self._clagd_vxlan_anycast_ip:
# if local ip is anycast_ip, then let query_check to go through
attrval = self._clagd_vxlan_anycast_ip
- self._query_check_n_update(ifaceobj, ifaceobjcurr, 'vxlan-local-tunnelip',
- attrval, running_attrval)
- self._query_check_n_update(ifaceobj, ifaceobjcurr, 'vxlan-svcnodeip',
- ifaceobj.get_attr_value_first('vxlan-svcnodeip'),
- vxlanattrs.get('svcnode'))
+ self._query_check_n_update(
+ ifaceobj,
+ ifaceobjcurr,
+ 'vxlan-local-tunnelip',
+ str(attrval),
+ str(running_attrval)
+ )
- purge_remotes = self._get_purge_remotes(ifaceobj)
+ #
+ # vxlan-remoteip
+ #
+ purge_remotes = self.__get_vlxan_purge_remotes(ifaceobj)
if purge_remotes or ifaceobj.get_attr_value('vxlan-remoteip'):
# If purge remotes or if vxlan-remoteip's are set
# in the config file, we are owners of the installed
# remote-ip's, lets check and report any remote ips we don't
# understand
- self._query_check_n_update_addresses(ifaceobjcurr, 'vxlan-remoteip',
- ifaceobj.get_attr_value('vxlan-remoteip'),
- self.ipcmd.get_vxlan_peers(ifaceobj.name, vxlanattrs.get('svcnode')))
-
- learning = ifaceobj.get_attr_value_first('vxlan-learning')
- if learning:
- running_learning = vxlanattrs.get('learning')
- if learning == 'yes' and running_learning == 'on':
- running_learning = 'yes'
- elif learning == 'no' and running_learning == 'off':
- running_learning = 'no'
- if learning == running_learning:
- ifaceobjcurr.update_config_with_status('vxlan-learning',
- running_learning, 0)
- else:
- ifaceobjcurr.update_config_with_status('vxlan-learning',
- running_learning, 1)
- ageing = ifaceobj.get_attr_value_first('vxlan-ageing')
- if not ageing:
- ageing = self.get_mod_subattr('vxlan-ageing', 'default')
- self._query_check_n_update(ifaceobj, ifaceobjcurr, 'vxlan-ageing',
- ageing, vxlanattrs.get('ageing'))
+ cached_svcnode = cached_vxlan_ifla_info_data.get(Link.IFLA_VXLAN_GROUP)
- physdev = ifaceobj.get_attr_value_first('vxlan-physdev')
+ self._query_check_n_update_addresses(
+ ifaceobjcurr,
+ 'vxlan-remoteip',
+ ifaceobj.get_attr_value('vxlan-remoteip'),
+ self.iproute2.get_vxlan_peers(ifaceobj.name, str(cached_svcnode))
+ )
- if physdev:
- ifla_vxlan_link = vxlanattrs.get(Link.IFLA_VXLAN_LINK)
-
- if ifla_vxlan_link:
- self._query_check_n_update(
- ifaceobj,
- ifaceobjcurr,
- 'vxlan-physdev',
- physdev,
- netlink.get_iface_name(ifla_vxlan_link)
- )
- else:
- ifaceobjcurr.update_config_with_status('vxlan-physdev', physdev, 1)
+ def _query_running(self, ifaceobjrunning):
+ ifname = ifaceobjrunning.name
+ if not self.cache.link_exists(ifname):
+ return
- def _query_running(self, ifaceobjrunning):
- vxlanattrs = self.ipcmd.get_vxlandev_attrs(ifaceobjrunning.name)
- if not vxlanattrs:
+ if not self.cache.get_link_kind(ifname) == 'vxlan':
return
- attrval = vxlanattrs.get('vxlanid')
- if attrval:
- ifaceobjrunning.update_config('vxlan-id', vxlanattrs.get('vxlanid'))
- else:
- # if there is no vxlan id, this is not a vxlan port
+
+ cached_vxlan_ifla_info_data = self.cache.get_link_info_data(ifname)
+
+ if not cached_vxlan_ifla_info_data:
return
- ifaceobjrunning.update_config('vxlan-port', vxlanattrs.get(Link.IFLA_VXLAN_PORT))
+ #
+ # vxlan-id
+ #
+ vxlan_id = cached_vxlan_ifla_info_data.get(Link.IFLA_VXLAN_ID)
+
+ if not vxlan_id:
+ # no vxlan id, meaning this not a vxlan
+ return
+
+ ifaceobjrunning.update_config('vxlan-id', str(vxlan_id))
+
+ #
+ # vxlan-port
+ #
+ vxlan_port = cached_vxlan_ifla_info_data.get(Link.IFLA_VXLAN_PORT)
+
+ if vxlan_port:
+ ifaceobjrunning.update_config('vxlan-port', vxlan_port)
+
+ #
+ # vxlan-svcnode
+ #
+ vxlan_svcnode_value = cached_vxlan_ifla_info_data.get(Link.IFLA_VXLAN_GROUP)
+
+ if vxlan_svcnode_value:
+ vxlan_svcnode_value = str(vxlan_svcnode_value)
+ ifaceobjrunning.update_config('vxlan-svcnode', vxlan_svcnode_value)
- attrval = vxlanattrs.get('local')
- if attrval:
- ifaceobjrunning.update_config('vxlan-local-tunnelip', attrval)
- attrval = vxlanattrs.get('svcnode')
- if attrval:
- ifaceobjrunning.update_config('vxlan-svcnode', attrval)
- purge_remotes = self._get_purge_remotes(None)
+ #
+ # vxlan-remoteip
+ #
+ purge_remotes = self.__get_vlxan_purge_remotes(None)
if purge_remotes:
# if purge_remotes is on, it means we own the
# remote ips. Query them and add it to the running config
- attrval = self.ipcmd.get_vxlan_peers(ifaceobjrunning.name, vxlanattrs.get('svcnode'))
+ attrval = self.iproute2.get_vxlan_peers(ifname, vxlan_svcnode_value)
if attrval:
- [ifaceobjrunning.update_config('vxlan-remoteip', a)
- for a in attrval]
- attrval = vxlanattrs.get('learning')
- if attrval and attrval == 'on':
- ifaceobjrunning.update_config('vxlan-learning', 'on')
- attrval = vxlanattrs.get('ageing')
- if attrval:
- ifaceobjrunning.update_config('vxlan-ageing', vxlanattrs.get('ageing'))
-
- ifla_vxlan_link = vxlanattrs.get(Link.IFLA_VXLAN_LINK)
- if ifla_vxlan_link:
- ifaceobjrunning.update_config(
- 'vxlan-physdev',
- netlink.get_iface_name(ifla_vxlan_link)
- )
+ [ifaceobjrunning.update_config('vxlan-remoteip', a) for a in attrval]
+
+ #
+ # vxlan-link
+ # vxlan-ageing
+ # vxlan-learning
+ # vxlan-local-tunnelip
+ #
+ for vxlan_attr_name, vxlan_attr_nl, callable_netlink_value_to_string in (
+ ('vxlan-physdev', Link.IFLA_VXLAN_LINK, self._get_ifname_for_ifindex),
+ ('vxlan-ageing', Link.IFLA_VXLAN_AGEING, str),
+ ('vxlan-learning', Link.IFLA_VXLAN_LEARNING, lambda value: 'on' if value else 'off'),
+ ('vxlan-local-tunnelip', Link.IFLA_VXLAN_LOCAL, str),
+ ):
+ vxlan_attr_value = cached_vxlan_ifla_info_data.get(vxlan_attr_nl)
+
+ if vxlan_attr_value is not None:
+ vxlan_attr_value_str = callable_netlink_value_to_string(vxlan_attr_nl)
+
+ if vxlan_attr_value:
+ ifaceobjrunning.update_config(vxlan_attr_name, vxlan_attr_value_str)
+
+ def _get_ifname_for_ifindex(self, ifindex):
+ """
+ we need this middle-man function to query the cache
+ cache.get_ifname can raise KeyError, we need to catch
+ it and return None
+ """
+ try:
+ return self.cache.get_ifname(ifindex)
+ except KeyError:
+ return None
- _run_ops = {'pre-up' : _up,
- 'post-down' : _down,
- 'query-checkcurr' : _query_check,
- 'query-running' : _query_running}
+ _run_ops = {
+ "pre-up": _up,
+ "post-down": _down,
+ "query-running": _query_running,
+ "query-checkcurr": _query_check
+ }
def get_ops(self):
return self._run_ops.keys()
- def _init_command_handlers(self):
- if not self.ipcmd:
- self.ipcmd = LinkUtils()
-
def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
op_handler = self._run_ops.get(operation)
if not op_handler:
return
- if (operation != 'query-running' and
- not self._is_vxlan_device(ifaceobj)):
- return
- self._init_command_handlers()
+
+ if operation != 'query-running':
+ if not self._is_vxlan_device(ifaceobj):
+ return
+
+ if not self.vxlan_mcastgrp_ref \
+ and self.vxlan_physdev_mcast \
+ and self.cache.link_exists(self.vxlan_physdev_mcast):
+ self.netlink.link_del(self.vxlan_physdev_mcast)
+ self.reset()
+
if operation == 'query-checkcurr':
op_handler(self, ifaceobj, query_ifaceobj)
else:
from ipaddr import IPNetwork, IPv6Network
try:
+ from ifupdown2.lib.addon import Addon
+
from ifupdown2.ifupdown.iface import *
from ifupdown2.ifupdown.utils import utils
- from ifupdown2.ifupdown.netlink import netlink
- from ifupdown2.ifupdownaddons.LinkUtils import LinkUtils
+ from ifupdown2.nlmanager.nlpacket import Link
+
from ifupdown2.ifupdownaddons.modulebase import moduleBase
import ifupdown2.ifupdown.statemanager as statemanager
import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
import ifupdown2.ifupdown.ifupdownconfig as ifupdownconfig
except ImportError:
+ from lib.addon import Addon
+
from ifupdown.iface import *
from ifupdown.utils import utils
- from ifupdown.netlink import netlink
- from ifupdownaddons.LinkUtils import LinkUtils
+ from nlmanager.nlpacket import Link
+
from ifupdownaddons.modulebase import moduleBase
import ifupdown.statemanager as statemanager
import ifupdown.ifupdownconfig as ifupdownconfig
-class xfrm(moduleBase):
+class xfrm(Addon, moduleBase):
""" ifupdown2 addon module to create a xfrm interface """
- _modinfo = {'mhelp' : 'xfrm module creates a xfrm interface for',
- 'attrs' : {
- 'xfrm-id' :
- { 'help' : 'xfrm id',
- 'validrange' : ['1', '65535'],
- 'example': ['xfrm-id 1']
- },
- 'xfrm-physdev':
- {'help': 'xfrm physical device',
- 'example': ['xfrm-physdev lo']
- },
- },
- }
-
+ _modinfo = {
+ 'mhelp': 'xfrm module creates a xfrm interface for',
+ 'attrs': {
+ 'xfrm-id': {
+ 'help': 'xfrm id',
+ 'validrange': ['1', '65535'],
+ 'example': ['xfrm-id 1']
+ },
+ 'xfrm-physdev': {
+ 'help': 'xfrm physical device',
+ 'example': ['xfrm-physdev lo']
+ },
+ },
+ }
def __init__(self, *args, **kargs):
+ Addon.__init__(self)
moduleBase.__init__(self, *args, **kargs)
- self.ipcmd = None
def get_dependent_ifacenames(self, ifaceobj, ifacenames_all=None):
xfrm_ifacename = self._get_xfrm_name(ifaceobj)
physdev = self._get_parent_ifacename(ifaceobj)
xfrmid = self._get_xfrmid(ifaceobj)
- if not self.ipcmd.link_exists(xfrm_ifacename):
- try:
- netlink.link_add_xfrm(physdev, xfrm_ifacename, xfrmid)
- except:
- self.ipcmd.link_add_xfrm(physdev, xfrm_ifacename, xfrmid)
- link_created = True
+ if not self.cache.link_exists(xfrm_ifacename):
+ self.iproute2.link_add_xfrm(physdev, xfrm_ifacename, xfrmid)
else:
- current_attrs = self.ipcmd.link_get_linkinfo_attrs(ifaceobj.name)
- xfrmid_cur = current_attrs.get('xfrm-id', None)
- physdev_cur = current_attrs.get('xfrm-physdev', None)
+ xfrmid_cur = str(
+ self.cache.get_link_info_data_attribute(
+ xfrm_ifacename,
+ Link.IFLA_XFRM_IF_ID,
+ 0
+ )
+ )
+ physdev_cur = self.cache.get_ifname(
+ self.cache.get_link_info_data_attribute(
+ xfrm_ifacename,
+ Link.IFLA_XFRM_LINK,
+ 0
+ )
+ )
+
# Check XFRM Values
if xfrmid != xfrmid_cur or physdev != physdev_cur:
# Delete and recreate
- self.ipcmd.link_delete(xfrm_ifacename)
- try:
- netlink.link_add_xfrm(physdev, xfrm_ifacename, xfrmid)
- except:
- self.ipcmd.link_add_xfrm(physdev, xfrm_ifacename, xfrmid)
- link_created = True
+ self.netlink.link_del(xfrm_ifacename)
+ self.iproute2.link_add_xfrm(physdev, xfrm_ifacename, xfrmid)
def _down(self, ifaceobj, ifaceobj_getfunc=None):
"""
"""
try:
xfrm_ifacename = self._get_xfrm_name(ifaceobj)
- self.ipcmd.link_delete(xfrm_ifacename)
- except Exception, e:
+ self.netlink.link_del(xfrm_ifacename)
+ except Exception as e:
self.log_warn(str(e))
def _query_check(self, ifaceobj, ifaceobjcurr):
- if not self.ipcmd.link_exists(ifaceobj.name):
+ if not self.cache.link_exists(ifaceobj.name):
return
ifaceobjcurr.status = ifaceStatus.SUCCESS
def _query_running(self, ifaceobjrunning):
- if not self.ipcmd.link_exists(ifaceobjrunning.name):
+ if not self.cache.link_exists(ifaceobjrunning.name):
return
# Operations supported by this addon (yet).
def get_ops(self):
return self._run_ops.keys()
- def _init_command_handlers(self):
- if not self.ipcmd:
- self.ipcmd = LinkUtils()
-
def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
op_handler = self._run_ops.get(operation)
if operation != 'query-running' and not self._is_my_interface(ifaceobj):
return
- self._init_command_handlers()
if operation == 'query-checkcurr':
op_handler(self, ifaceobj, query_ifaceobj)
else:
try:
from ifupdown2.ifupdown.utils import utils
- from ifupdown2.ifupdown.exceptions import ArgvParseError
+ from ifupdown2.ifupdown.exceptions import ArgvParseError, ArgvParseHelp
except:
from ifupdown.utils import utils
- from ifupdown.exceptions import ArgvParseError
+ from ifupdown.exceptions import ArgvParseError, ArgvParseHelp
class VersionAction(argparse.Action):
self.update_ifquery_argparser(argparser)
self.update_common_argparser(argparser)
argcomplete.autocomplete(argparser)
- self.args = argparser.parse_args(self.argv)
+
+ try:
+ self.args = argparser.parse_args(self.argv)
+ except SystemExit as e:
+ # on "--help" parse_args will raise SystemExit.
+ # We need to catch this behavior and raise a custom
+ # exception to return 0 properly
+ #raise ArgvParseHelp()
+ for help_str in ('-h', '--help'):
+ if help_str in argv:
+ raise ArgvParseHelp()
+ raise
def validate(self):
if self.op == 'query' and (self.args.syntaxhelp or self.args.list):
for key, value in self.valid_ops.iteritems():
if self.executable_name.endswith(key):
return value
+ raise ArgvParseError("Unexpected executable. Should be '%s'" % "' or '".join(self.valid_ops.keys()))
except:
- raise ArgvParseError("Unexpected executable. Should be 'ifup' or 'ifdown' or 'ifquery'")
+ raise ArgvParseError("Unexpected executable. Should be '%s'" % "' or '".join(self.valid_ops.keys()))
def get_args(self):
return self.args
def update_ifupdown_argparser(self, argparser):
""" common arg parser for ifup and ifdown """
argparser.add_argument('-f', '--force', dest='force', action='store_true', help='force run all operations')
- argparser.add_argument('-l', '--syslog', dest='syslog', action='store_true', help=argparse.SUPPRESS)
+ argparser.add_argument('-l', '--syslog', dest='syslog', action='store_true')
group = argparser.add_mutually_exclusive_group(required=False)
group.add_argument('-n', '--no-act', dest='noact', action='store_true',
help="print out what would happen, but don't do it")
'With this option ifreload will only look at the current interfaces file. '
'Useful when your state file is corrupted or you want down to use the latest '
'from the interfaces file')
- argparser.add_argument('-l', '--syslog', dest='syslog', action='store_true', help=argparse.SUPPRESS)
+ argparser.add_argument('-l', '--syslog', dest='syslog', action='store_true')
argparser.add_argument('-f', '--force', dest='force', action='store_true', help='force run all operations')
argparser.add_argument('-s', '--syntax-check', dest='syntaxcheck', action='store_true',
help='Only run the interfaces file parser')
--- /dev/null
+# Copyright (C) 2017, 2018, 2019 Cumulus Networks, Inc. all rights reserved
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; version 2.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# https://www.gnu.org/licenses/gpl-2.0-standalone.html
+#
+# Author:
+# Julien Fortin, julien@cumulusnetworks.com
+#
+# ifupdown2 client-side
+#
+
+import struct
+import pickle
+
+import SocketServer
+
+import logging
+import logging.handlers
+
+import os
+import re
+import sys
+import json
+import socket
+import signal
+
+try:
+ from ifupdown2.lib.io import SocketIO
+ from ifupdown2.lib.status import Status
+ from ifupdown2.lib.log import LogManager, root_logger
+ from ifupdown2.lib.exceptions import ExitWithStatus, ExitWithStatusAndError
+
+ from ifupdown2.ifupdown.argv import Parse
+except:
+ from lib.status import Status
+ from lib.io import SocketIO
+ from lib.log import LogManager, root_logger
+ from lib.exceptions import ExitWithStatus, ExitWithStatusAndError
+
+ from ifupdown.argv import Parse
+
+
+class LogRecordStreamHandler(SocketServer.StreamRequestHandler):
+ """
+ Handler for a streaming logging request.
+ This basically logs the record using whatever logging policy is configured
+ locally.
+ """
+
+ def handle(self):
+ """
+ Handle multiple requests - each expected to be a 4-byte length,
+ followed by the LogRecord in pickle format.
+ """
+ while True:
+ chunk = self.connection.recv(4)
+ if len(chunk) < 4:
+ break
+ slen = struct.unpack(">L", chunk)[0]
+ chunk = self.connection.recv(slen)
+
+ while len(chunk) < slen:
+ chunk = chunk + self.connection.recv(slen - len(chunk))
+
+ record = logging.makeLogRecord(pickle.loads(chunk))
+ logging.getLogger(record.name).handle(record)
+
+
+class LogRecordSocketReceiver(SocketServer.TCPServer):
+ """
+ Simple TCP socket-based logging receiver. In ifupdown2d context, the running
+ daemon is the "sender" and the client is the "receiver". The TCPServer is
+ setup on the client/receiver side, the daemon will connect to the server to
+ transmit and stream LogRecord to a socket.
+ """
+ allow_reuse_address = True
+
+ def __init__(
+ self,
+ host="localhost",
+ handler=LogRecordStreamHandler,
+ port=LogManager.DEFAULT_TCP_LOGGING_PORT
+ ):
+ SocketServer.TCPServer.__init__(self, (host, port), handler)
+
+
+class Client(SocketIO):
+ def __init__(self, argv):
+ SocketIO.__init__(self)
+
+ # we setup our log receiver which reads LogRecord from a socket
+ # thus handing the logging-handling to the logging module and it's
+ # dedicated classes.
+ self.socket_receiver = LogRecordSocketReceiver()
+
+ self.stdin = None
+ self.argv = argv
+
+ # First we need to set the correct log level for the client.
+ # Unfortunately the only reliable way to do this is to use our main
+ # argument parser. We can't simply have a parse to catch -v and -d, a
+ # simple command like "ifup -av" wouldn't be recognized...
+ # Ideally it would be great to be able to send the Namespace returned by
+ # parse_args, and send it on the socket in pickle format. Unfortunately
+ # this might be a serious security issue. It needs to be studied and
+ # evaluated a bit more, that way we would save time and resources only
+ # parsing argv once.
+ args_parse = Parse(argv)
+ args_parse.validate()
+ # store the args namespace to send it to the daemon, we don't want
+ # the daemon to spend time to parsing argv again...
+ self.args = args_parse.get_args()
+
+ LogManager.get_instance().start_client_logging(self.args)
+
+ root_logger.info("starting ifupdown2 client...")
+
+ self.uds = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ try:
+ self.uds.connect("/var/run/ifupdown2d/uds")
+ except socket.error:
+ self.__shutdown()
+ sys.stderr.write("""
+ ERROR: %s could not connect to ifupdown2 daemon
+
+ Try starting ifupdown2 daemon with:
+ sudo systemctl start ifupdown2
+
+ To configure ifupdown2d to start when the box boots:
+ sudo systemctl enable ifupdown2\n\n""" % argv[0])
+ raise ExitWithStatus(status=Status.Client.STATUS_COULD_NOT_CONNECT)
+
+ signal.signal(signal.SIGINT, self.__signal_handler)
+ signal.signal(signal.SIGTERM, self.__signal_handler)
+ signal.signal(signal.SIGQUIT, self.__signal_handler)
+
+ try:
+ self.SO_PEERCRED = socket.SO_PEERCRED
+ except AttributeError:
+ # powerpc is the only non-generic we care about. alpha, mips,
+ # sparc, and parisc also have non-generic values.
+ machine = os.uname()[4]
+ if re.search(r"^(ppc|powerpc)", machine):
+ self.SO_PASSCRED = 20
+ self.SO_PEERCRED = 21
+ else:
+ self.SO_PASSCRED = 16
+ self.SO_PEERCRED = 17
+ try:
+ self.uds.setsockopt(socket.SOL_SOCKET, self.SO_PASSCRED, 1)
+ except Exception as e:
+ self.__shutdown()
+ raise Exception("setsockopt: %s" % str(e))
+
+ self.daemon_pid, _, _ = self.get_socket_peer_cred(self.uds)
+
+ if self.daemon_pid < 0:
+ self.__shutdown()
+ raise ExitWithStatusAndError(
+ status=Status.Client.STATUS_NO_PID,
+ message="could not get ifupdown2 daemon PID"
+ )
+
+ root_logger.info("connection to ifupdown2d successful (server pid %s)" % self.daemon_pid)
+
+ def __shutdown(self):
+ try:
+ self.uds.close()
+ self.uds = None
+ except:
+ pass
+ try:
+ self.socket_receiver.server_close()
+ self.socket_receiver = None
+ except:
+ pass
+
+ def __signal_handler(self, sig, frame):
+ """ Forward all signals to daemon """
+ if self.daemon_pid > 0:
+ os.kill(self.daemon_pid, sig)
+
+ def __get_stdin(self):
+ """
+ If stdin data is provided we need to store it to forward it to the
+ daemon
+ """
+ if hasattr(self.args, "interfacesfile") and self.args.interfacesfile == "-":
+ return sys.stdin.read()
+
+ def run(self):
+ try:
+ # First we need to send the user request to the daemon (argv + stdin)
+ self.tx_data(self.uds, json.dumps({
+ "argv": self.argv,
+ "stdin": self.__get_stdin()
+ }))
+
+ # Then "handle_request" will block until the daemon closes
+ # the channel, meaning that the request was processed.
+ self.socket_receiver.handle_request()
+ self.socket_receiver.server_close()
+
+ # Next the daemon should send us a dictionary containing stdout and
+ # stderr buffers as well as the request's exit status. We print those
+ # buffers in the correct channel and exit with the request status.
+ response = self.rx_json_packet(self.uds)
+
+ if response:
+ sys.stdout.write(response.get("stdout", ""))
+ sys.stderr.write(response.get("stderr", ""))
+
+ status = response.get("status", Status.Client.STATUS_EMPTY)
+ else:
+ status = Status.Client.STATUS_EMPTY
+
+ return status
+ finally:
+ self.__shutdown()
-#!/usr/bin/python
-#
# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
# Authors:
# Roopa Prabhu, roopa@cumulusnetworks.com
# exceptions
#
-try:
- from ifupdown2.ifupdown.log import log
-except:
- from ifupdown.log import log
+import logging
+
+log = logging.getLogger()
class Error(Exception):
pass
+class ArgvParseHelp(Error):
+ """
+ When ifupdown2 is called with --help argparse raise SystemExit
+ we need to catch this to properly print the help and exit 0 not 1
+ """
+ pass
+
+
class ifaceNotFoundError(Error):
pass
"""
import json
+import logging
from collections import OrderedDict
+log = logging.getLogger()
+
class ifaceStatusUserStrs():
""" This class declares strings user can see during an ifquery --check
bond have an ifaceobj.role attribute of SLAVE and the bridge or
bond itself has ifaceobj.role of MASTER.
"""
- UNKNOWN = 0x0000000
- BRIDGE = 0x0000001
- BOND = 0x0000010
- VLAN = 0x0000100
- VXLAN = 0x0001000
- VRF = 0x0010000
- BATMAN_ADV = 0x0100000
+ UNKNOWN = 0x000000
+ BRIDGE = 0x000001
+ BOND = 0x000010
+ VLAN = 0x000100
+ VXLAN = 0x001000
+ VRF = 0x010000
+ BATMAN_ADV = 0x0100000
# to indicate logical interface created by an external entity.
# the 'kind' of which ifupdown2 does not really understand
- OTHER = 0x1000000
+ OTHER = 0x100000
@classmethod
def to_str(cls, kind):
return "vxlan"
elif kind == cls.VRF:
return "vrf"
+ else:
+ return "OTHER"
class ifaceLinkPrivFlags():
""" This corresponds to kernel netdev->priv_flags
@classmethod
def get_str(cls, flag):
- if flag == cls.UNKNOWN:
- return 'unknown'
- elif flag == cls.BRIDGE_PORT:
- return 'bridge port'
- elif flag == cls.BOND_SLAVE:
- return 'bond slave'
- elif flag == cls.VRF_SLAVE:
- return 'vrf slave'
- elif flag == cls.BRIDGE_VLAN_AWARE:
- return 'vlan aware bridge'
- elif flag == cls.BRIDGE_VXLAN:
- return 'vxlan bridge'
+ string_list = []
+
+ if flag & cls.BRIDGE_PORT:
+ string_list.append("bridge port")
+
+ if flag & cls.BOND_SLAVE:
+ string_list.append("bond slave")
+
+ if flag & cls.VRF_SLAVE:
+ string_list.append("vrf slave")
+
+ if flag & cls.BRIDGE_VLAN_AWARE:
+ string_list.append("vlan aware bridge")
+
+ if flag & cls.BRIDGE_VXLAN:
+ string_list.append("vxlan bridge")
+
+ if flag & cls.ADDRESS_VIRTUAL_SLAVE:
+ string_list.append("address virtual slave")
+
+ if flag & cls.LOOPBACK:
+ string_list.append("loopback")
+
+ if flag & cls.KEEP_LINK_DOWN:
+ string_list.append("keep ling down")
+
+ return ", ".join(string_list)
- @classmethod
- def get_all_str(cls, flags):
- str = ''
- if flags & cls.BRIDGE_PORT:
- str += 'bridgeport '
- if flags & cls.BOND_SLAVE:
- str += 'bondslave '
- if flags & cls.VRF_SLAVE:
- str += 'vrfslave '
- if flags & cls.BRIDGE_VLAN_AWARE:
- str += 'vlanawarebridge '
- if flags & cls.BRIDGE_VXLAN:
- str += 'vxlanbridge '
- return str
class ifaceLinkType():
LINK_UNKNOWN = 0x0
del odict['env']
del odict['link_type']
del odict['link_kind']
- del odict['link_privflags']
+ #del odict['link_privflags']
del odict['role']
del odict['dependency_type']
del odict['blacklisted']
return odict
def __setstate__(self, dict):
- self.__dict__.update(dict)
self._config_status = {}
self.state = ifaceState.NEW
self.status = ifaceStatus.UNKNOWN
self.link_privflags = ifaceLinkPrivFlags.UNKNOWN
self.dependency_type = ifaceDependencyType.UNKNOWN
self.blacklisted = False
+ self.__dict__.update(dict)
def dump_raw(self, logger):
indent = ' '
else:
logger.info(indent + 'upperdevs: None')
+ logger.info("%srole: %s" % (indent, {
+ ifaceRole.UNKNOWN: "UNKNOWN",
+ ifaceRole.SLAVE: "SLAVE",
+ ifaceRole.MASTER: "MASTER"}.get(self.role)))
+
+ logger.info("%stype: %s" % (indent, {
+ ifaceType.UNKNOWN: "UNKNOWN",
+ ifaceType.IFACE: "IFACE",
+ ifaceType.BRIDGE_VLAN: "BRIDGE_VLAN"}.get(self.type)))
+
+ logger.info("%slink_kind: %s" % (indent, ifaceLinkKind.to_str(self.link_kind)))
+
+ logger.info("%slink_privflags: %s" % (indent, ifaceLinkPrivFlags.get_str(self.link_privflags)))
+
+ if self.priv_flags:
+ if self.priv_flags.BUILTIN:
+ logger.info("%spriv_flags: BUILTIN" % indent)
+
logger.info(indent + 'config: ')
config = self.config
if config:
outbuf += (indent + '{0:55} {1:>10}'.format(
'%s %s' %(cname, cv), status_str)) + '\n'
else:
- outbuf += indent + '%s %s\n' %(cname, cv)
+ if cv:
+ outbuf += indent + '%s %s\n' % (cname, cv)
idx += 1
if with_status:
outbuf = (outbuf.encode('utf8')
+++ /dev/null
-#!/usr/bin/env python
-#
-# Copyright 2014-2017 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
+++ /dev/null
-#!/usr/bin/python
-#
-# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
-# Author: Roopa Prabhu, roopa@cumulusnetworks.com
-#
-# ifupdownBase --
-# base object for various ifupdown objects
-#
-
-import re
-import os
-import logging
-import traceback
-
-try:
- from ifupdown2.ifupdown.netlink import netlink
-
- import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
-except ImportError:
- from ifupdown.netlink import netlink
-
- import ifupdown.ifupdownflags as ifupdownflags
-
-
-class ifupdownBase(object):
-
- def __init__(self):
- modulename = self.__class__.__name__
- self.logger = logging.getLogger('ifupdown.' + modulename)
-
- def ignore_error(self, errmsg):
- if (ifupdownflags.flags.FORCE == True or re.search(r'exists', errmsg,
- re.IGNORECASE | re.MULTILINE) is not None):
- return True
- return False
-
- def log_warn(self, str):
- if self.ignore_error(str) == False:
- if self.logger.getEffectiveLevel() == logging.DEBUG:
- traceback.print_stack()
- traceback.print_exc()
- self.logger.warn(str)
- pass
-
- def log_error(self, str):
- if self.ignore_error(str) == False:
- raise Exception(str)
- else:
- pass
-
- def link_exists(self, ifacename):
- return os.path.exists('/sys/class/net/%s' %ifacename)
-
- def link_up(self, ifacename):
- netlink.link_set_updown(ifacename, "up")
-
- def link_down(self, ifacename):
- netlink.link_set_updown(ifacename, "down")
# ifupdown main module
#
+import re
+import os
+import logging
+import traceback
import pprint
from collections import OrderedDict
from ipaddr import IPNetwork, IPv4Network, IPv6Network, IPAddress, IPv4Address, IPv6Address
try:
- import ifupdown2.ifupdownaddons.cache
- import ifupdown2.ifupdownaddons.LinkUtils
+ import ifupdown2.lib.nlcache as nlcache
+
import ifupdown2.ifupdownaddons.mstpctlutil
import ifupdown2.ifupdown.policymanager
- import ifupdown2.ifupdown.ifupdownflags
import ifupdown2.ifupdown.statemanager as statemanager
import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
import ifupdown2.ifupdown.ifupdownconfig as ifupdownConfig
from ifupdown2.ifupdown.networkinterfaces import *
from ifupdown2.ifupdown.config import ADDON_MODULES_DIR, ADDONS_CONF_PATH, IFUPDOWN2_ADDON_DROPIN_FOLDER
except ImportError:
- import ifupdownaddons.cache
- import ifupdownaddons.LinkUtils
+ import lib.nlcache as nlcache
+
import ifupdownaddons.mstpctlutil
import ifupdown.ifupdownflags
self.BUILTIN = builtin
self.NOCONFIG = noconfig
-class ifupdownMain(ifupdownBase):
+class ifupdownMain:
""" ifupdown2 main class """
scripts_dir = '/etc/network'
if self._keep_link_down(ifaceobj):
return
try:
- self.link_up(ifaceobj.name)
+ self.netlink.link_up(ifaceobj.name)
except:
if ifaceobj.addr_method == 'manual':
pass
# user has asked to explicitly keep the link down,
# so, force link down
self.logger.info('%s: keeping link down due to user config' %ifaceobj.name)
- self.link_down(ifaceobj.name)
+ self.netlink.link_down(ifaceobj.name)
return True
return False
if not self.link_exists(ifaceobj.name):
return
try:
- self.link_down(ifaceobj.name)
+ if not ifaceobj.link_privflags & ifaceLinkPrivFlags.LOOPBACK:
+ # set intf down (except loopback)
+ self.netlink.link_down(ifaceobj.name)
+ else:
+ self.logger.info("%s: ifupdown2 cannot bring loopback interface down" % ifaceobj.name)
except:
if ifaceobj.addr_method == 'manual':
pass
sched_hooks = {'posthook' : run_sched_ifaceobj_posthook}
def reset_ifupdown2(self):
+ self.modules = OrderedDict({})
+ self.module_attrs = {}
+
ifaceScheduler.reset()
+ try:
+ ifupdown2.ifupdown.statemanager.reset()
+ ifupdown2.ifupdown.policymanager.reset()
+ ifupdown2.ifupdown.ifupdownflags.reset()
+ ifupdownConfig.reset()
+ ifupdown2.ifupdownaddons.mstpctlutil.mstpctlutil.reset()
+ except:
+ try:
+ ifupdown.statemanager.reset()
+ ifupdown.policymanager.reset()
+ ifupdown.ifupdownflags.reset()
+ ifupdownConfig.reset()
+ ifupdownaddons.mstpctlutil.mstpctlutil.reset()
+ except:
+ pass
+
+ def ignore_error(self, errmsg):
+ if (ifupdownflags.flags.FORCE == True or re.search(r'exists', errmsg,
+ re.IGNORECASE | re.MULTILINE) is not None):
+ return True
+ return False
- ifupdown2.ifupdown.statemanager.reset()
- ifupdown2.ifupdown.policymanager.reset()
- ifupdown2.ifupdown.ifupdownflags.reset()
- ifupdownConfig.reset()
- ifupdown2.ifupdownaddons.mstpctlutil.mstpctlutil.reset()
- ifupdown2.ifupdownaddons.LinkUtils.LinkUtils.reset()
+ def log_warn(self, str):
+ if self.ignore_error(str) == False:
+ if self.logger.getEffectiveLevel() == logging.DEBUG:
+ traceback.print_stack()
+ traceback.print_exc()
+ self.logger.warn(str)
+ pass
+
+ def log_error(self, str):
+ if self.ignore_error(str) == False:
+ raise Exception(str)
+ else:
+ pass
- ifupdown2.ifupdownaddons.cache.linkCache.reset()
- ifupdown2.ifupdownaddons.cache.MSTPAttrsCache.invalidate()
+ def link_exists(self, ifacename):
+ return os.path.exists('/sys/class/net/%s' %ifacename)
def __init__(self, config={},
daemon=False, force=False, dryrun=False, nowait=False,
Raises:
AttributeError, KeyError """
+ modulename = self.__class__.__name__
+ self.logger = logging.getLogger('ifupdown.' + modulename)
+
if daemon:
self.reset_ifupdown2()
+ else:
+ # init nlcache with appropriate log level
+ nlcache.NetlinkListenerWithCache.init(logging.root.level)
+
+ # start netlink listener and cache link/addr/netconf dumps
+ nlcache.NetlinkListenerWithCache.get_instance().start()
+
+ # save reference to nlcache
+ self.netlink = nlcache.NetlinkListenerWithCache.get_instance()
+ self.netlink.reset_errorq()
# iface dictionary in the below format:
# { '<ifacename>' : [<ifaceobject1>, <ifaceobject2> ..] }
else:
return ifaceobjlist[idx]
- def get_ifaceobjrunning(self, ifacename):
- return self.ifaceobjrunningdict.get(ifacename)
-
def get_iface_refcnt(self, ifacename):
""" Return iface ref count """
max = 0
(role == ifaceRole.SLAVE) and (upperifaceobj.role & ifaceRole.MASTER)):
self.logger.error("misconfig..? %s %s is enslaved to multiple interfaces %s"
%(ifaceobj.name,
- ifaceLinkPrivFlags.get_all_str(ifaceobj.link_privflags), str(ifaceobj.upperifaces)))
+ ifaceLinkPrivFlags.get_str(ifaceobj.link_privflags), str(ifaceobj.upperifaces)))
ifaceobj.set_status(ifaceStatus.ERROR)
return
ifaceobj.role = role
def _keyword_mac_ip_prefixlen_list(self, value, validrange=None):
"""
- <mac> <ip> [<ip> ...]
+ MAC address followed by optional list of ip addresses
+ <mac> [<ip> <ip> ...]
ex: address-virtual 00:11:22:33:44:01 11.0.1.1/24 11.0.1.2/24
"""
try:
res = value.split()
- if len(res) < 2:
- return False
if not self._keyword_mac(res[0]):
return False
for ip in res[1:]:
continue
return ret
- def read_iface_config(self):
+ def read_iface_config(self, raw=False):
""" Reads default network interface config /etc/network/interfaces. """
ret = True
nifaces = networkInterfaces(self.interfacesfile,
self.interfacesfileformat,
template_enable=self.config.get('template_enable', 0),
template_engine=self.config.get('template_engine'),
- template_lookuppath=self.config.get('template_lookuppath'))
+ template_lookuppath=self.config.get('template_lookuppath'),
+ raw=raw)
if self._ifaceobj_squash or self._ifaceobj_squash_internal:
nifaces.subscribe('iface_found', self._save_iface_squash)
else:
script_override = minstance.get_overrides_ifupdown_scripts()
self.overridden_ifupdown_scripts.extend(script_override)
except moduleNotSupported, e:
- self.logger.info('module %s not loaded (%s)\n'
+ self.logger.info('module %s not loaded (%s)'
%(mname, str(e)))
continue
except:
if not self._delay_admin_state_iface_queue:
return
if op == 'up':
- func = self.link_up
+ func = self.netlink.link_up
elif op == 'down':
- func = self.link_down
+ func = self.netlink.link_down
else:
return
for i in self._delay_admin_state_iface_queue:
self.logger.warn(str(e))
pass
+ def _get_iface_exclude_companion(self, ifacename):
+ try:
+ return ifupdown2.ifupdown.policymanager.policymanager_api.get_iface_default(
+ module_name='main', ifname=ifacename,
+ attr='exclude-companion')
+ except:
+ return ifupdown.policymanager.policymanager_api.get_iface_default(
+ module_name='main', ifname=ifacename,
+ attr='exclude-companion')
+
+ def _preprocess_excludepats(self, excludepats):
+ new_excludepats = excludepats
+ for e in excludepats:
+ ifaceobjs = self.get_ifaceobjs(e)
+ for iobj in ifaceobjs or []:
+ ec = iobj.get_attr_value_first('exclude-companion')
+ if not ec:
+ ec = self._get_iface_exclude_companion(e)
+ if not ec:
+ continue
+ else:
+ ec = ec.encode('ascii','ignore')
+ for ee in ec.split():
+ if ee in new_excludepats:
+ continue
+ if self.get_ifaceobjs(ee):
+ # if we know the object add it to the new
+ # excludepats list
+ new_excludepats.append(ee)
+ self.logger.info('excludepats after processing companions [%s]' %' '.join(new_excludepats))
+ return new_excludepats
+
def up(self, ops, auto=False, allow_classes=None, ifacenames=None,
excludepats=None, printdependency=None, syntaxcheck=False,
type=None, skipupperifaces=False):
except Exception:
raise
+ if excludepats:
+ excludepats = self._preprocess_excludepats(excludepats)
+
filtered_ifacenames = None
if ifacenames:
ifacenames = self._preprocess_ifacenames(ifacenames)
if not iface_read_ret or not ret:
raise Exception()
+ self.check_running_configuration(filtered_ifacenames)
+
+ def check_running_configuration(self, filtered_ifacenames, all=False):
+ """
+ Print warning and better info message when we don't recognize an interface
+ AKA when the interface wasn't created.
+
+ :param filtered_ifacenames:
+ :param all:
+ :return:
+ """
+ if not filtered_ifacenames:
+ filtered_ifacenames = []
+
+ for ifname, ifaceobj_list in self.ifaceobjdict.iteritems():
+
+ if not all and ifname not in filtered_ifacenames:
+ continue
+
+ auto = True
+
+ for ifaceobj in ifaceobj_list:
+ if not ifaceobj.auto:
+ auto = False
+ break
+
+ if auto and not os.path.exists("/sys/class/net/%s" % ifname):
+ self.logger.warning("%s: interface not recognized - please check interface configuration" % ifname)
+
def _get_filtered_ifacenames_with_classes(self, auto, allow_classes, excludepats, ifacenames):
# if user has specified ifacelist and allow_classes
# append the allow_classes interfaces to user
self.read_iface_config()
except Exception, e:
raise Exception('error reading iface config (%s)' %str(e))
+
+ if excludepats:
+ excludepats = self._preprocess_excludepats(excludepats)
+
filtered_ifacenames = None
if ifacenames:
# If iface list is given by the caller, always check if iface
ifacePrivFlags(False, True)), ifacenames)
else:
try:
- iface_read_ret = self.read_iface_config()
+ iface_read_ret = self.read_iface_config(raw=ops[0] == "query-raw")
except Exception:
raise
if ops[0] == 'query' and not ifupdownflags.flags.WITHDEFAULTS:
return self.print_ifaceobjs_pretty(filtered_ifacenames, format)
elif ops[0] == 'query-raw':
- return self.print_ifaceobjs_raw(filtered_ifacenames)
+ return self.print_ifaceobjs_raw(filtered_ifacenames, format)
ret = self._sched_ifaces(filtered_ifacenames, ops,
followdependents=True
new_ifaceobjdict = self.ifaceobjdict
new_dependency_graph = self.dependency_graph
+ if excludepats:
+ excludepats = self._preprocess_excludepats(excludepats)
+
if op == 'reload' and ifacenames:
ifacenames = self.ifaceobjdict.keys()
old_filtered_ifacenames = [i for i in ifacenames
else:
self._reload_default(*args, **kargs)
+ self.check_running_configuration([], all=True)
+
def _any_iface_errors(self, ifacenames):
for i in ifacenames:
ifaceobjs = self.get_ifaceobjs(i)
for i in ifacenames:
print i
- def print_ifaceobjs_raw(self, ifacenames):
+ def print_ifaceobjs_raw(self, ifacenames, format=None):
""" prints raw lines for ifaces from config file """
+ if format == "json":
+ self.print_ifaceobjs_pretty(ifacenames, format)
+ return
+
for i in ifacenames:
for ifaceobj in self.get_ifaceobjs(i):
if self.is_ifaceobj_builtin(ifaceobj):
if not ifaceobjs: return
if format == 'json':
print json.dumps(ifaceobjs, cls=ifaceJsonEncoder,
- indent=4, separators=(',', ': '))
+ indent=2, separators=(',', ': '))
else:
expand = int(self.config.get('ifquery_ifacename_expand_range', '0'))
for i in ifaceobjs:
+++ /dev/null
-#!/usr/bin/env python
-#
-# Copyright 2016-2017 Cumulus Networks, Inc. All rights reserved.
-# Author: Julien Fortin, julien@cumulusnetworks.com
-#
-
-import sys
-import json
-import struct
-import select
-import logging
-import logging.handlers
-
-from cStringIO import StringIO
-
-
-class Log:
- LOGGER_NAME = sys.argv[0].split('/')[-1]
-
- def __init__(self):
- """
- - On start the daemon will log on syslog.
- - For each client commands we might need to adjust the target
- (stderr/stdout):
- if -v --verbose or -d --debug are provided we override
- sys.stdout and sys.stderr with string buffers to be able to send
- back the content of these buffer on the UNIX socket back to the
- client.
- if -l or --syslog we make sure to use syslog.
- """
-
- self.stdout_buffer = None
- self.stderr_buffer = None
-
- self.root = logging.getLogger()
- self.root.name = Log.LOGGER_NAME
- self.root.setLevel(logging.INFO)
-
- self.root_info = self.root.info
- self.root_debug = self.root.debug
- self.root_error = self.root.error
- self.root_warning = self.root.warning
- self.root_critical = self.root.critical
-
- self.root.info = self.info
- self.root.debug = self.debug
- self.root.error = self.error
- self.root.warning = self.warning
- self.root.critical = self.critical
-
- logging.addLevelName(logging.CRITICAL, 'critical')
- logging.addLevelName(logging.WARNING, 'warning')
- logging.addLevelName(logging.ERROR, 'error')
- logging.addLevelName(logging.DEBUG, 'debug')
- logging.addLevelName(logging.INFO, 'info')
-
- self.syslog = True
- self.socket = None
-
- # syslog
- facility = logging.handlers.SysLogHandler.LOG_DAEMON
- address = '/dev/log'
- format = '%(name)s: %(levelname)s: %(message)s'
-
- try:
- self.syslog_handler = logging.handlers.SysLogHandler(address=address, facility=facility)
- self.syslog_handler.setFormatter(logging.Formatter(format))
- except Exception as e:
- sys.stderr.write("warning: syslogs: %s\n" % str(e))
- self.syslog_handler = None
-
- # console
- format = '%(levelname)s: %(message)s'
- self.console_handler = logging.StreamHandler(sys.stderr)
- self.console_handler.setFormatter(logging.Formatter(format))
-
- if self.syslog_handler and self.LOGGER_NAME[-1] == 'd':
- self.update_current_logger(syslog=True, verbose=True, debug=False)
- else:
- self.update_current_logger(syslog=False, verbose=False, debug=False)
-
- def update_current_logger(self, syslog, verbose, debug):
- self.syslog = syslog
- self.root.setLevel(self.get_log_level(verbose=verbose, debug=debug))
- self.root.handlers = [self.syslog_handler if self.syslog and self.syslog_handler else self.console_handler]
- self.flush()
-
- def flush(self):
- if self.socket:
- result = dict()
- stdout = self._flush_buffer('stdout', self.stdout_buffer, result)
- stderr = self._flush_buffer('stderr', self.stderr_buffer, result)
- if stdout or stderr:
- try:
- self.tx_data(json.dumps(result))
- self.redirect_stdouput()
- except select.error as e:
- # haven't seen the case yet
- self.socket = None
- self.update_current_logger(syslog=True, verbose=True)
- self.critical(str(e))
- exit(84)
- self.console_handler.flush()
-
- if self.syslog_handler:
- self.syslog_handler.flush()
-
- def tx_data(self, data, socket=None):
- socket_obj = socket if socket else self.socket
- ready = select.select([], [socket_obj], [])
- if ready and ready[1] and ready[1][0] == socket_obj:
- frmt = "=%ds" % len(data)
- packed_msg = struct.pack(frmt, data)
- packed_hdr = struct.pack('=I', len(packed_msg))
- socket_obj.sendall(packed_hdr)
- socket_obj.sendall(packed_msg)
-
- def set_socket(self, socket):
- self.socket = socket
- self.redirect_stdouput()
-
- def redirect_stdouput(self):
- self.stdout_buffer = sys.stdout = StringIO()
- self.stderr_buffer = self.console_handler.stream = sys.stderr = StringIO()
-
- def error(self, msg, *args, **kwargs):
- self.root_error(msg, *args, **kwargs)
- self.flush()
-
- def critical(self, msg, *args, **kwargs):
- self.root_critical(msg, *args, **kwargs)
- self.flush()
-
- def warning(self, msg, *args, **kwargs):
- self.root_warning(msg, *args, **kwargs)
- self.flush()
-
- def info(self, msg, *args, **kwargs):
- self.root_info(msg, *args, **kwargs)
- self.flush()
-
- def debug(self, msg, *args, **kwargs):
- self.root_debug(msg, *args, **kwargs)
- self.flush()
-
- def get_current_log_level(self):
- return self.root.level
-
- def is_syslog(self): return self.syslog
-
- @staticmethod
- def get_log_level(verbose=False, debug=False):
- log_level = logging.WARNING
- if debug:
- log_level = logging.DEBUG
- elif verbose:
- log_level = logging.INFO
- return log_level
-
- @staticmethod
- def _flush_buffer(stream, buff, dictionary):
- if buff:
- data = buff.getvalue()
- if data:
- dictionary[stream] = data
- return True
-
-
-log = Log()
#!/usr/bin/python
#
-# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
+# Copyright 2014-2019 Cumulus Networks, Inc. All rights reserved.
# Authors:
# Roopa Prabhu, roopa@cumulusnetworks.com
# Julien Fortin, julien@cumulusnetworks.com
import os
import sys
-import signal
+import logging
import StringIO
import ConfigParser
try:
- from ifupdown2.ifupdown.log import log
from ifupdown2.ifupdown.argv import Parse
from ifupdown2.ifupdown.config import IFUPDOWN2_CONF_PATH
from ifupdown2.ifupdown.ifupdownmain import ifupdownMain
+
+ from ifupdown2.lib.dry_run import DryRunManager
+
except ImportError:
- from ifupdown.log import log
from ifupdown.argv import Parse
from ifupdown.config import IFUPDOWN2_CONF_PATH
from ifupdown.ifupdownmain import ifupdownMain
+ from lib.dry_run import DryRunManager
-_SIGINT = signal.getsignal(signal.SIGINT)
-_SIGTERM = signal.getsignal(signal.SIGTERM)
-_SIGQUIT = signal.getsignal(signal.SIGQUIT)
+log = logging.getLogger()
configmap_g = None
self.args = args_parse.get_args()
self.op = args_parse.get_op()
- def update_logger(self, socket=None):
- syslog = self.args.syslog if hasattr(self.args, 'syslog') else False
- log.update_current_logger(syslog=syslog,
- verbose=self.args.verbose,
- debug=self.args.debug)
- if socket:
- log.set_socket(socket)
-
def main(self, stdin_buffer=None):
if self.op != 'query' and self.uid != 0:
raise Exception('must be root to run this command')
raise
# else:
if log:
- log.error(str(e))
+ log.error('main exception: ' + str(e))
else:
print str(e)
# if args and not args.debug:
return 0
def init(self, stdin_buffer):
+ ##############
+ # dry run mode
+ ##############
+ dry_run_mode_on = DryRunManager.get_instance().is_dry_mode_on()
+
+ if hasattr(self.args, 'noact'):
+ if self.args.noact and not dry_run_mode_on:
+ DryRunManager.get_instance().dry_run_mode_on()
+ elif not self.args.noact and dry_run_mode_on:
+ DryRunManager.get_instance().dry_run_mode_off()
+ elif dry_run_mode_on:
+ # if noact is not in self.args we are probably in
+ # ifquery mode so we need to turn off dry run mode.
+ DryRunManager.get_instance().dry_run_mode_off()
+
+ ###
+
if hasattr(self.args, 'interfacesfile') and self.args.interfacesfile != None:
# Check to see if -i option is allowed by config file
# But for ifquery, we will not check this
currentlyup=args.currentlyup)
except:
raise
-
- @staticmethod
- def set_signal_handlers():
- signal.signal(signal.SIGQUIT, _SIGQUIT)
- signal.signal(signal.SIGTERM, _SIGTERM)
- signal.signal(signal.SIGINT, _SIGINT)
+++ /dev/null
-#!/usr/bin/python
-#
-# Copyright 2016-2017 Cumulus Networks, Inc. All rights reserved.
-# Author: Julien Fortin, julien@cumulusnetworks.com
-#
-
-import sys
-import socket
-import logging
-
-from collections import OrderedDict
-
-try:
- import ifupdown2.nlmanager.nlpacket
- import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
-
- from ifupdown2.ifupdownaddons.cache import *
- from ifupdown2.ifupdownaddons.utilsbase import utilsBase
-
- from ifupdown2.nlmanager.nlmanager import Link, Address, Route, NetlinkPacket
-except ImportError:
- import nlmanager.nlpacket
- import ifupdown.ifupdownflags as ifupdownflags
-
- from ifupdownaddons.cache import *
- from ifupdownaddons.utilsbase import utilsBase
-
- from nlmanager.nlmanager import Link, Address, Route, NetlinkPacket
-
-
-class Netlink(utilsBase):
- VXLAN_UDP_PORT = 4789
-
- def __init__(self, *args, **kargs):
- utilsBase.__init__(self, *args, **kargs)
- try:
- sys.path.insert(0, '/usr/share/ifupdown2/')
- try:
- from ifupdown2.nlmanager.nlmanager import NetlinkManager
- # Override the nlmanager's mac_int_to_str function to print the MACs
- # like xx:xx:xx:xx:xx:xx instead of xxxx.xxxx.xxxx
- ifupdown2.nlmanager.nlpacket.mac_int_to_str = self.mac_int_to_str
- except ImportError:
- from nlmanager.nlmanager import NetlinkManager
- # Override the nlmanager's mac_int_to_str function to print the MACs
- # like xx:xx:xx:xx:xx:xx instead of xxxx.xxxx.xxxx
- nlmanager.nlpacket.mac_int_to_str = self.mac_int_to_str
-
- # this should force the use of the local nlmanager
- self._nlmanager_api = NetlinkManager(log_level=logging.WARNING)
-
- self.link_kind_handlers = {
- 'vlan': self._link_dump_info_data_vlan,
- 'vrf': self._link_dump_info_data_vrf,
- 'vxlan': self._link_dump_info_data_vxlan,
- 'bond': self._link_dump_info_data_bond,
- 'bridge': self._link_dump_info_data_bridge,
- 'gre': self._link_dump_info_data_gre_tunnel,
- 'gretap': self._link_dump_info_data_gre_tunnel,
- "ip6gre": self._link_dump_info_data_gre_tunnel,
- "ip6gretap": self._link_dump_info_data_gre_tunnel,
- "ip6erspan": self._link_dump_info_data_gre_tunnel,
- 'ipip': self._link_dump_info_data_iptun_tunnel,
- 'sit': self._link_dump_info_data_iptun_tunnel,
- 'ip6tnl': self._link_dump_info_data_iptun_tunnel,
- 'vti': self._link_dump_info_data_vti_tunnel,
- 'vti6': self._link_dump_info_data_vti_tunnel,
- 'xfrm': self._link_dump_info_data_xfrm
- }
-
- except Exception as e:
- self.logger.error('cannot initialize ifupdown2\'s '
- 'netlink manager: %s' % str(e))
- raise
-
- @staticmethod
- def IN_MULTICAST(a):
- """
- /include/uapi/linux/in.h
-
- #define IN_CLASSD(a) ((((long int) (a)) & 0xf0000000) == 0xe0000000)
- #define IN_MULTICAST(a) IN_CLASSD(a)
- """
- return (int(a) & 0xf0000000) == 0xe0000000
-
- @staticmethod
- def mac_int_to_str(mac_int):
- """
- Return an integer in MAC string format: xx:xx:xx:xx:xx:xx
- """
- return ':'.join(("%012x" % mac_int)[i:i + 2] for i in range(0, 12, 2))
-
- def get_iface_index(self, ifacename):
- if ifupdownflags.flags.DRYRUN: return
- try:
- return self._nlmanager_api.get_iface_index(ifacename)
- except Exception as e:
- raise Exception('%s: netlink: %s: cannot get ifindex: %s'
- % (ifacename, ifacename, str(e)))
-
- def get_iface_name(self, ifindex):
- if ifupdownflags.flags.DRYRUN: return
- try:
- return self._nlmanager_api.get_iface_name(ifindex)
- except Exception as e:
- raise Exception('netlink: cannot get ifname for index %s: %s' % (ifindex, str(e)))
-
- def get_bridge_vlan(self, ifname):
- self.logger.info('%s: netlink: /sbin/bridge -d -c -json vlan show' % ifname)
- if ifupdownflags.flags.DRYRUN: return
- try:
- return self._nlmanager_api.vlan_get()
- except Exception as e:
- raise Exception('netlink: get bridge vlan: %s' % str(e))
-
- def bridge_set_vlan_filtering(self, ifname, vlan_filtering):
- self.logger.info('%s: netlink: ip link set dev %s type bridge vlan_filtering %s'
- % (ifname, ifname, vlan_filtering))
- if ifupdownflags.flags.DRYRUN: return
- try:
- ifla_info_data = {Link.IFLA_BR_VLAN_FILTERING: int(vlan_filtering)}
- return self._nlmanager_api.link_set_attrs(ifname, 'bridge', ifla_info_data=ifla_info_data)
- except Exception as e:
- raise Exception('%s: cannot set %s vlan_filtering %s' % (ifname, ifname, vlan_filtering))
-
- def link_add_set(self,
- ifname=None, ifindex=0,
- kind=None, slave_kind=None,
- ifla={},
- ifla_info_data={},
- ifla_info_slave_data={},
- link_exists=False):
- action = 'set' if ifindex or link_exists else 'add'
-
- if slave_kind:
- self.logger.info('%s: netlink: ip link set dev %s: %s slave attributes' % (ifname, ifname, slave_kind))
- else:
- self.logger.info('%s: netlink: ip link %s %s type %s with attributes' % (ifname, action, ifname, kind))
- if ifla:
- self.logger.debug('%s: ifla attributes a %s' % (ifname, ifla))
- if ifla_info_data:
- self.logger.debug('%s: ifla_info_data %s' % (ifname, ifla_info_data))
- if ifla_info_slave_data:
- self.logger.debug('%s: ifla_info_slave_data %s' % (ifname, ifla_info_slave_data))
-
- if ifupdownflags.flags.DRYRUN: return
- try:
- self._nlmanager_api.link_add_set(ifname=ifname,
- ifindex=ifindex,
- kind=kind,
- slave_kind=slave_kind,
- ifla=ifla,
- ifla_info_data=ifla_info_data,
- ifla_info_slave_data=ifla_info_slave_data)
- except Exception as e:
- if kind and not slave_kind:
- kind_str = kind
- elif kind and slave_kind:
- kind_str = '%s (%s slave)' % (kind, slave_kind)
- else:
- kind_str = '(%s slave)' % slave_kind
-
- raise Exception('netlink: cannot %s %s %s with options: %s' % (action, kind_str, ifname, str(e)))
-
- def link_del(self, ifname):
- self.logger.info('%s: netlink: ip link del %s' % (ifname, ifname))
- if ifupdownflags.flags.DRYRUN: return
- try:
- self._nlmanager_api.link_del(ifname=ifname)
- except Exception as e:
- raise Exception('netlink: cannot delete link %s: %s' % (ifname, str(e)))
-
- def link_set_master(self, ifacename, master_dev, state=None):
- self.logger.info('%s: netlink: ip link set dev %s master %s %s'
- % (ifacename, ifacename, master_dev,
- state if state else ''))
- if ifupdownflags.flags.DRYRUN: return
- try:
- master = 0 if not master_dev else self.get_iface_index(master_dev)
- return self._nlmanager_api.link_set_master(ifacename,
- master_ifindex=master,
- state=state)
- except Exception as e:
- raise Exception('netlink: %s: cannot set %s master %s: %s'
- % (ifacename, ifacename, master_dev, str(e)))
-
- def link_set_nomaster(self, ifacename, state=None):
- self.logger.info('%s: netlink: ip link set dev %s nomaster %s'
- % (ifacename, ifacename, state if state else ''))
- if ifupdownflags.flags.DRYRUN: return
- try:
- return self._nlmanager_api.link_set_master(ifacename,
- master_ifindex=0,
- state=state)
- except Exception as e:
- raise Exception('netlink: %s: cannot set %s nomaster: %s'
- % (ifacename, ifacename, str(e)))
-
- def link_add_vlan(self, vlanrawdevice, ifacename, vlanid, vlan_protocol):
- if vlan_protocol:
- self.logger.info('%s: netlink: ip link add link %s name %s type vlan id %s protocol %s'
- % (ifacename, vlanrawdevice, ifacename, vlanid, vlan_protocol))
-
- else:
- self.logger.info('%s: netlink: ip link add link %s name %s type vlan id %s'
- % (ifacename, vlanrawdevice, ifacename, vlanid))
- if ifupdownflags.flags.DRYRUN: return
- ifindex = self.get_iface_index(vlanrawdevice)
- try:
- return self._nlmanager_api.link_add_vlan(ifindex, ifacename, vlanid, vlan_protocol)
- except Exception as e:
- raise Exception('netlink: %s: cannot create vlan %s: %s'
- % (vlanrawdevice, vlanid, str(e)))
-
- def link_add_macvlan(self, ifacename, macvlan_ifacename):
- self.logger.info('%s: netlink: ip link add link %s name %s type macvlan mode private'
- % (ifacename, ifacename, macvlan_ifacename))
- if ifupdownflags.flags.DRYRUN: return
- ifindex = self.get_iface_index(ifacename)
- try:
- return self._nlmanager_api.link_add_macvlan(ifindex, macvlan_ifacename)
- except Exception as e:
- raise Exception('netlink: %s: cannot create macvlan %s: %s'
- % (ifacename, macvlan_ifacename, str(e)))
-
- def link_add_xfrm(self, ifacename, xfrm_ifacename, xfrm_id):
- self.logger.info('%s: netlink: ip link add %s type xfrm dev %s if_id %s'
- % (xfrm_ifacename, xfrm_ifacename, ifacename, xfrm_id))
- if ifupdownflags.flags.DRYRUN: return
- ifindex = self.get_iface_index(ifacename)
- try:
- return self._nlmanager_api.link_add_xfrm(ifindex, xfrm_ifacename, xfrm_id)
- except Exception as e:
- raise Exception('netlink: %s: cannot create xfrm %s id %s: %s'
- % (ifacename, xfrm_ifacename, xfrm_id, str(e)))
-
- def link_set_updown(self, ifacename, state):
- self.logger.info('%s: netlink: ip link set dev %s %s'
- % (ifacename, ifacename, state))
- if ifupdownflags.flags.DRYRUN: return
- try:
- return self._nlmanager_api.link_set_updown(ifacename, state)
- except Exception as e:
- raise Exception('netlink: cannot set link %s %s: %s'
- % (ifacename, state, str(e)))
-
- def link_set_protodown(self, ifacename, state):
- self.logger.info('%s: netlink: set link %s protodown %s'
- % (ifacename, ifacename, state))
- if ifupdownflags.flags.DRYRUN: return
- try:
- return self._nlmanager_api.link_set_protodown(ifacename, state)
- except Exception as e:
- raise Exception('netlink: cannot set link %s protodown %s: %s'
- % (ifacename, state, str(e)))
-
- def link_add_bridge(self, ifname, mtu=None):
- self.logger.info('%s: netlink: ip link add %s type bridge' % (ifname, ifname))
- if ifupdownflags.flags.DRYRUN: return
- try:
- return self._nlmanager_api.link_add_bridge(ifname, mtu=mtu)
- except Exception as e:
- raise Exception('netlink: cannot create bridge %s: %s' % (ifname, str(e)))
-
- def link_add_bridge_vlan(self, ifacename, vlanid):
- self.logger.info('%s: netlink: bridge vlan add vid %s dev %s'
- % (ifacename, vlanid, ifacename))
- if ifupdownflags.flags.DRYRUN: return
- ifindex = self.get_iface_index(ifacename)
- try:
- return self._nlmanager_api.link_add_bridge_vlan(ifindex, vlanid)
- except Exception as e:
- raise Exception('netlink: %s: cannot create bridge vlan %s: %s'
- % (ifacename, vlanid, str(e)))
-
- def link_del_bridge_vlan(self, ifacename, vlanid):
- self.logger.info('%s: netlink: bridge vlan del vid %s dev %s'
- % (ifacename, vlanid, ifacename))
- if ifupdownflags.flags.DRYRUN: return
- ifindex = self.get_iface_index(ifacename)
- try:
- return self._nlmanager_api.link_del_bridge_vlan(ifindex, vlanid)
- except Exception as e:
- raise Exception('netlink: %s: cannot remove bridge vlan %s: %s'
- % (ifacename, vlanid, str(e)))
-
- def link_add_vxlan(self, ifacename, vxlanid, local=None, dstport=VXLAN_UDP_PORT,
- group=None, learning=True, ageing=None, physdev=None, ttl=None):
- cmd = 'ip link add %s type vxlan id %s dstport %s' % (ifacename,
- vxlanid,
- dstport)
- cmd += ' local %s' % local if local else ''
- cmd += ' ageing %s' % ageing if ageing else ''
- cmd += ' remote %s' % group if group else ' noremote'
- cmd += ' nolearning' if not learning else ''
- cmd += ' dev %s' % physdev if physdev else ''
-
- if ttl is not None:
- cmd += ' ttl %s' % ttl
-
- self.logger.info('%s: netlink: %s' % (ifacename, cmd))
- if ifupdownflags.flags.DRYRUN: return
- try:
- if physdev:
- physdev = self.get_iface_index(physdev)
- return self._nlmanager_api.link_add_vxlan(ifacename,
- vxlanid,
- dstport=dstport,
- local=local,
- group=group,
- learning=learning,
- ageing=ageing,
- physdev=physdev,
- ttl=ttl)
- except Exception as e:
- raise Exception('netlink: %s: cannot create vxlan %s: %s'
- % (ifacename, vxlanid, str(e)))
-
- @staticmethod
- def _link_dump_attr(link, ifla_attributes, dump):
- for obj in ifla_attributes:
- attr = link.attributes.get(obj['attr'])
- if attr:
- dump[obj['name']] = attr.get_pretty_value(obj=obj.get('func'))
-
- @staticmethod
- def _link_dump_linkdata_attr(linkdata, ifla_linkdata_attr, dump):
- for obj in ifla_linkdata_attr:
- attr = obj['attr']
- if attr in linkdata:
- func = obj.get('func')
- value = linkdata.get(attr)
-
- if func:
- value = func(value)
-
- if value or obj['accept_none']:
- dump[obj['name']] = value
-
- ifla_attributes = [
- {
- 'attr': Link.IFLA_LINK,
- 'name': 'link',
- 'func': lambda x: netlink.get_iface_name(x) if x > 0 else None
- },
- {
- 'attr': Link.IFLA_MASTER,
- 'name': 'master',
- 'func': lambda x: netlink.get_iface_name(x) if x > 0 else None
- },
- {
- 'attr': Link.IFLA_IFNAME,
- 'name': 'ifname',
- 'func': str,
- },
- {
- 'attr': Link.IFLA_MTU,
- 'name': 'mtu',
- 'func': str
- },
- {
- 'attr': Link.IFLA_OPERSTATE,
- 'name': 'state',
- 'func': lambda x: '0%x' % int(x) if x > len(Link.oper_to_string) else Link.oper_to_string[x][8:]
- },
- {
- 'attr': Link.IFLA_AF_SPEC,
- 'name': 'af_spec',
- 'func': dict
- }
- ]
-
- ifla_address = {'attr': Link.IFLA_ADDRESS, 'name': 'hwaddress', 'func': str}
-
- ifla_vxlan_attributes = [
- {
- 'attr': Link.IFLA_VXLAN_LOCAL,
- 'name': 'local',
- 'func': str,
- 'accept_none': True
- },
- {
- 'attr': Link.IFLA_VXLAN_LOCAL6,
- 'name': 'local',
- 'func': str,
- 'accept_none': True
- },
- {
- 'attr': Link.IFLA_VXLAN_GROUP,
- 'name': 'svcnode',
- 'func': lambda x: str(x) if not Netlink.IN_MULTICAST(x) else None,
- 'accept_none': False
- },
- {
- 'attr': Link.IFLA_VXLAN_GROUP6,
- 'name': 'svcnode',
- 'func': lambda x: str(x) if not Netlink.IN_MULTICAST(x) else None,
- 'accept_none': False
- },
- {
- 'attr': Link.IFLA_VXLAN_LEARNING,
- 'name': 'learning',
- 'func': lambda x: 'on' if x else 'off',
- 'accept_none': True
- }
- ]
-
- def _link_dump_info_data_vlan(self, ifname, linkdata):
- return {
- 'vlanid': str(linkdata.get(Link.IFLA_VLAN_ID, '')),
- 'vlan_protocol': linkdata.get(Link.IFLA_VLAN_PROTOCOL)
- }
-
- def _link_dump_info_data_vrf(self, ifname, linkdata):
- vrf_info = {'table': str(linkdata.get(Link.IFLA_VRF_TABLE, ''))}
-
- # to remove later when moved to a true netlink cache
- linkCache.vrfs[ifname] = vrf_info
- return vrf_info
-
- def _link_dump_info_data_vxlan(self, ifname, linkdata):
- for attr, value in (
- ('learning', 'on'),
- ('svcnode', None),
- ('vxlanid', str(linkdata.get(Link.IFLA_VXLAN_ID, ''))),
- ('ageing', str(linkdata.get(Link.IFLA_VXLAN_AGEING, ''))),
- (Link.IFLA_VXLAN_PORT, linkdata.get(Link.IFLA_VXLAN_PORT))
- ):
- linkdata[attr] = value
- self._link_dump_linkdata_attr(linkdata, self.ifla_vxlan_attributes, linkdata)
- return linkdata
-
- ifla_bond_attributes = (
- Link.IFLA_BOND_MODE,
- Link.IFLA_BOND_MIIMON,
- Link.IFLA_BOND_USE_CARRIER,
- Link.IFLA_BOND_AD_LACP_RATE,
- Link.IFLA_BOND_XMIT_HASH_POLICY,
- Link.IFLA_BOND_MIN_LINKS,
- Link.IFLA_BOND_NUM_PEER_NOTIF,
- Link.IFLA_BOND_AD_ACTOR_SYSTEM,
- Link.IFLA_BOND_AD_ACTOR_SYS_PRIO,
- Link.IFLA_BOND_AD_LACP_BYPASS,
- Link.IFLA_BOND_UPDELAY,
- Link.IFLA_BOND_DOWNDELAY,
- )
-
- def _link_dump_info_data_bond(self, ifname, linkdata):
- linkinfo = {}
- for nl_attr in self.ifla_bond_attributes:
- try:
- linkinfo[nl_attr] = linkdata.get(nl_attr)
- except Exception as e:
- self.logger.debug('%s: parsing bond IFLA_INFO_DATA (%s): %s'
- % (ifname, nl_attr, str(e)))
- return linkinfo
-
- # this dict contains the netlink attribute, cache key,
- # and a callable to translate the netlink value into
- # whatever value we need to store in the old cache to
- # make sure we don't break anything
- ifla_bridge_attributes = (
- (Link.IFLA_BR_UNSPEC, Link.IFLA_BR_UNSPEC, None),
- (Link.IFLA_BR_FORWARD_DELAY, "fd", lambda x: str(x / 100)),
- (Link.IFLA_BR_HELLO_TIME, "hello", lambda x: str(x / 100)),
- (Link.IFLA_BR_MAX_AGE, "maxage", lambda x: str(x / 100)),
- (Link.IFLA_BR_AGEING_TIME, "ageing", lambda x: str(x / 100)),
- (Link.IFLA_BR_STP_STATE, "stp", lambda x: 'yes' if x else 'no'),
- (Link.IFLA_BR_PRIORITY, "bridgeprio", str),
- (Link.IFLA_BR_VLAN_FILTERING, 'vlan_filtering', str),
- (Link.IFLA_BR_VLAN_PROTOCOL, "vlan-protocol", str),
- (Link.IFLA_BR_GROUP_FWD_MASK, Link.IFLA_BR_GROUP_FWD_MASK, None),
- (Link.IFLA_BR_ROOT_ID, Link.IFLA_BR_ROOT_ID, None),
- (Link.IFLA_BR_BRIDGE_ID, Link.IFLA_BR_BRIDGE_ID, None),
- (Link.IFLA_BR_ROOT_PORT, Link.IFLA_BR_ROOT_PORT, None),
- (Link.IFLA_BR_ROOT_PATH_COST, Link.IFLA_BR_ROOT_PATH_COST, None),
- (Link.IFLA_BR_TOPOLOGY_CHANGE, Link.IFLA_BR_TOPOLOGY_CHANGE, None),
- (Link.IFLA_BR_TOPOLOGY_CHANGE_DETECTED, Link.IFLA_BR_TOPOLOGY_CHANGE_DETECTED, None),
- (Link.IFLA_BR_HELLO_TIMER, Link.IFLA_BR_HELLO_TIMER, None),
- (Link.IFLA_BR_TCN_TIMER, Link.IFLA_BR_TCN_TIMER, None),
- (Link.IFLA_BR_TOPOLOGY_CHANGE_TIMER, Link.IFLA_BR_TOPOLOGY_CHANGE_TIMER, None),
- (Link.IFLA_BR_GC_TIMER, Link.IFLA_BR_GC_TIMER, None),
- (Link.IFLA_BR_GROUP_ADDR, Link.IFLA_BR_GROUP_ADDR, None),
- (Link.IFLA_BR_FDB_FLUSH, Link.IFLA_BR_FDB_FLUSH, None),
- (Link.IFLA_BR_MCAST_ROUTER, "mcrouter", str),
- (Link.IFLA_BR_MCAST_SNOOPING, "mcsnoop", str),
- (Link.IFLA_BR_MCAST_QUERY_USE_IFADDR, "mcqifaddr", str),
- (Link.IFLA_BR_MCAST_QUERIER, "mcquerier", str),
- (Link.IFLA_BR_MCAST_HASH_ELASTICITY, "hashel", str),
- (Link.IFLA_BR_MCAST_HASH_MAX, "hashmax", str),
- (Link.IFLA_BR_MCAST_LAST_MEMBER_CNT, "mclmc", str),
- (Link.IFLA_BR_MCAST_STARTUP_QUERY_CNT, "mcsqc", str),
- (Link.IFLA_BR_MCAST_LAST_MEMBER_INTVL, "mclmi", lambda x: str(x / 100)),
- (Link.IFLA_BR_MCAST_MEMBERSHIP_INTVL, "mcmi", lambda x: str(x / 100)),
- (Link.IFLA_BR_MCAST_QUERIER_INTVL, "mcqpi", lambda x: str(x / 100)),
- (Link.IFLA_BR_MCAST_QUERY_INTVL, "mcqi", lambda x: str(x / 100)),
- (Link.IFLA_BR_MCAST_QUERY_RESPONSE_INTVL, "mcqri", lambda x: str(x / 100)),
- (Link.IFLA_BR_MCAST_STARTUP_QUERY_INTVL, "mcsqi", lambda x: str(x / 100)),
- (Link.IFLA_BR_NF_CALL_IPTABLES, Link.IFLA_BR_NF_CALL_IPTABLES, None),
- (Link.IFLA_BR_NF_CALL_IP6TABLES, Link.IFLA_BR_NF_CALL_IP6TABLES, None),
- (Link.IFLA_BR_NF_CALL_ARPTABLES, Link.IFLA_BR_NF_CALL_ARPTABLES, None),
- (Link.IFLA_BR_VLAN_DEFAULT_PVID, Link.IFLA_BR_VLAN_DEFAULT_PVID, None),
- (Link.IFLA_BR_PAD, Link.IFLA_BR_PAD, None),
- (Link.IFLA_BR_VLAN_STATS_ENABLED, "vlan-stats", str),
- (Link.IFLA_BR_MCAST_STATS_ENABLED, "mcstats", str),
- (Link.IFLA_BR_MCAST_IGMP_VERSION, "igmp-version", str),
- (Link.IFLA_BR_MCAST_MLD_VERSION, "mld-version", str)
- )
-
- def _link_dump_info_data_bridge(self, ifname, linkdata):
- linkinfo = {}
- for nl_attr, cache_key, func in self.ifla_bridge_attributes:
- try:
- if func:
- linkinfo[cache_key] = func(linkdata.get(nl_attr))
- else:
- linkinfo[cache_key] = linkdata.get(nl_attr)
-
- # we also store the value in pure netlink,
- # to make the transition easier in the future
- linkinfo[nl_attr] = linkdata.get(nl_attr)
- except Exception as e:
- self.logger.error('%s: parsing birdge IFLA_INFO_DATA %s: %s'
- % (ifname, nl_attr, str(e)))
- return linkinfo
-
- def _link_dump_info_slave_data_bridge(self, ifname, info_slave_data):
- return info_slave_data
-
- def _link_dump_info_data_gre_tunnel(self, ifname, info_slave_data):
- tunnel_link_ifindex = info_slave_data.get(Link.IFLA_GRE_LINK)
-
- return {
- "endpoint": str(info_slave_data.get(Link.IFLA_GRE_REMOTE)),
- "local": str(info_slave_data.get(Link.IFLA_GRE_LOCAL)),
- "ttl": str(info_slave_data.get(Link.IFLA_GRE_TTL)),
- "tunnel-physdev": self.get_iface_name(tunnel_link_ifindex) if tunnel_link_ifindex else ""
- }
-
- def _link_dump_info_data_iptun_tunnel(self, ifname, info_slave_data):
- tunnel_link_ifindex = info_slave_data.get(Link.IFLA_IPTUN_LINK)
-
- return {
- "endpoint": str(info_slave_data.get(Link.IFLA_IPTUN_REMOTE)),
- "local": str(info_slave_data.get(Link.IFLA_IPTUN_LOCAL)),
- "ttl": str(info_slave_data.get(Link.IFLA_IPTUN_TTL)),
- "tunnel-physdev": self.get_iface_name(tunnel_link_ifindex) if tunnel_link_ifindex else ""
- }
-
- def _link_dump_info_data_vti_tunnel(self, ifname, info_slave_data):
- tunnel_link_ifindex = info_slave_data.get(Link.IFLA_VTI_LINK)
-
- return {
- "endpoint": str(info_slave_data.get(Link.IFLA_VTI_REMOTE)),
- "local": str(info_slave_data.get(Link.IFLA_VTI_LOCAL)),
- "tunnel-physdev": self.get_iface_name(tunnel_link_ifindex) if tunnel_link_ifindex else ""
- }
-
- def _link_dump_info_data_xfrm(self, ifname, linkdata):
- xfrm_physdev_link_ifindex = linkdata.get(Link.IFLA_XFRM_LINK)
-
- return {
- 'xfrm-id': str(linkdata.get(Link.IFLA_XFRM_IF_ID, '')),
- 'xfrm-physdev': self.get_iface_name(xfrm_physdev_link_ifindex) if xfrm_physdev_link_ifindex else ""
- }
-
- def _link_dump_linkinfo(self, link, dump):
- linkinfo = link.attributes[Link.IFLA_LINKINFO].get_pretty_value(dict)
-
- if linkinfo:
- info_kind = linkinfo.get(Link.IFLA_INFO_KIND)
- info_data = linkinfo.get(Link.IFLA_INFO_DATA)
-
- info_slave_kind = linkinfo.get(Link.IFLA_INFO_SLAVE_KIND)
- info_slave_data = linkinfo.get(Link.IFLA_INFO_SLAVE_DATA)
-
- dump['kind'] = info_kind
- dump['slave_kind'] = info_slave_kind
-
- if info_data:
- link_kind_handler = self.link_kind_handlers.get(info_kind)
- if callable(link_kind_handler):
- dump['linkinfo'] = link_kind_handler(dump['ifname'], info_data)
-
- if info_slave_data:
- dump['info_slave_data'] = info_slave_data
-
- def link_dump(self, ifname=None):
- if ifname:
- self.logger.info('netlink: ip link show dev %s' % ifname)
- else:
- self.logger.info('netlink: ip link show')
-
- if ifupdownflags.flags.DRYRUN: return {}
-
- links = dict()
-
- try:
- links_dump = self._nlmanager_api.link_dump(ifname)
- except Exception as e:
- raise Exception('netlink: link dump failed: %s' % str(e))
-
- for link in links_dump:
- try:
- dump = dict()
-
- flags = []
- for flag, string in Link.flag_to_string.items():
- if link.flags & flag:
- flags.append(string[4:])
-
- dump['flags'] = flags
- dump['ifflag'] = 'UP' if 'UP' in flags else 'DOWN'
- dump['ifindex'] = str(link.ifindex)
-
- if link.device_type == Link.ARPHRD_ETHER:
- self._link_dump_attr(link, [self.ifla_address], dump)
-
- self._link_dump_attr(link, self.ifla_attributes, dump)
-
- if Link.IFLA_LINKINFO in link.attributes:
- self._link_dump_linkinfo(link, dump)
-
- links[dump['ifname']] = dump
- except Exception as e:
- self.logger.warning('netlink: ip link show: %s' % str(e))
- return links
-
- def _addr_dump_extract_ifname(self, addr_packet):
- addr_ifname_attr = addr_packet.attributes.get(Address.IFA_LABEL)
-
- if addr_ifname_attr:
- return addr_ifname_attr.get_pretty_value(str)
- else:
- return self.get_iface_name(addr_packet.ifindex)
-
- @staticmethod
- def _addr_filter(addr_ifname, addr):
- return addr_ifname == 'lo' and addr in ['127.0.0.1/8', '::1/128', '0.0.0.0']
-
- def _addr_dump_entry(self, ifaces, addr_packet, addr_ifname, ifa_attr):
- attribute = addr_packet.attributes.get(ifa_attr)
-
- if attribute:
- address = attribute.get_pretty_value(str)
-
- if hasattr(addr_packet, 'prefixlen'):
- address = '%s/%d' % (address, addr_packet.prefixlen)
-
- if self._addr_filter(addr_ifname, address):
- return
-
- addr_family = NetlinkPacket.af_family_to_string.get(addr_packet.family)
- if not addr_family:
- return
-
- ifaces[addr_ifname]['addrs'][address] = {
- 'type': addr_family,
- 'scope': addr_packet.scope
- }
-
- ifa_address_attributes = [
- Address.IFA_ADDRESS,
- Address.IFA_LOCAL,
- Address.IFA_BROADCAST,
- Address.IFA_ANYCAST,
- Address.IFA_MULTICAST
- ]
-
- def addr_dump(self, ifname=None):
- if ifname:
- self.logger.info('netlink: ip addr show dev %s' % ifname)
- else:
- self.logger.info('netlink: ip addr show')
-
- ifaces = dict()
- addr_dump = self._nlmanager_api.addr_dump()
-
- for addr_packet in addr_dump:
- addr_ifname = self._addr_dump_extract_ifname(addr_packet)
-
- if addr_packet.family not in [socket.AF_INET, socket.AF_INET6]:
- continue
-
- if ifname and ifname != addr_ifname:
- continue
-
- if addr_ifname not in ifaces:
- ifaces[addr_ifname] = {'addrs': OrderedDict({})}
-
- for ifa_attr in self.ifa_address_attributes:
- self._addr_dump_entry(ifaces, addr_packet, addr_ifname, ifa_attr)
-
- if ifname:
- return {ifname: ifaces.get(ifname, {})}
-
- return ifaces
-
-
-netlink = Netlink()
_addrfams = {'inet' : ['static', 'manual', 'loopback', 'dhcp', 'dhcp6', 'ppp', 'tunnel'],
'inet6' : ['static', 'manual', 'loopback', 'dhcp', 'dhcp6', 'ppp', 'tunnel']}
+ # tunnel is part of the address family for backward compatibility but is not required.
def __init__(self, interfacesfile='/etc/network/interfaces',
interfacesfileiobuf=None, interfacesfileformat='native',
template_enable='0', template_engine=None,
- template_lookuppath=None):
+ template_lookuppath=None, raw=False):
"""This member function initializes the networkinterfaces parser object.
Kwargs:
self.auto_ifaces = []
self.callbacks = {}
self.auto_all = False
-
+ self.raw = raw
self.logger = logging.getLogger('ifupdown.' +
self.__class__.__name__)
self.callbacks = {'iface_found' : None,
self._parse_warn(self._currentfile, lineno,
'%s: unexpected characters in interface name' %ifacename)
- ifaceobj.raw_config.append(iface_line)
+ if self.raw:
+ ifaceobj.raw_config.append(iface_line)
iface_config = collections.OrderedDict()
for line_idx in range(cur_idx + 1, len(lines)):
l = lines[line_idx].strip(whitespaces)
if self.ignore_line(l) == 1:
- ifaceobj.raw_config.append(l)
+ if self.raw:
+ ifaceobj.raw_config.append(l)
continue
attrs = re.split(self._ws_split_regex, l, 1)
if self._is_keyword(attrs[0]):
self._parse_error(self._currentfile, line_idx,
'iface %s: invalid syntax \'%s\'' %(ifacename, l))
continue
- ifaceobj.raw_config.append(l)
+ if self.raw:
+ ifaceobj.raw_config.append(l)
attrname = attrs[0]
# preprocess vars (XXX: only preprocesses $IFACE for now)
attrval = re.sub(r'\$IFACE', ifacename, attrs[1])
self.logger = logging.getLogger('ifupdown.' +
self.__class__.__name__)
+ self.logger.info("policymanager init")
+
# we grab the json files from a known location and make sure that
# the defaults_policy is checked first
user_files = glob.glob('/etc/network/ifupdown2/policy.d/*.json')
self.logger.debug("policymanager: merging system module %s policy with file %s" % (module, filename))
self.system_policy_array[module].update(system_array[module])
else:
- self.system_policy_array[module] = system_array[module]
+ json_dict = system_array[module]
+
+ if isinstance(json_dict, dict):
+ self.system_policy_array[module] = system_array[module]
+ elif module != "README":
+ self.logger.warning(
+ "file %s contains an invalid policy schema, key "
+ "\"%s\" contains %s when a dictionary is expected" %
+ (filename, module, type(json_dict))
+ )
# take care of user defined policy defaults
self.user_policy_array = {}
try:
from ifupdown2.ifupdown.graph import *
- from ifupdown2.ifupdown.ifupdownbase import *
-
from ifupdown2.ifupdown.iface import *
from ifupdown2.ifupdown.utils import utils
from ifupdown2.ifupdown.statemanager import *
+ import ifupdown2.ifupdown.policymanager as policymanager
import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
except ImportError:
from ifupdown.graph import *
- from ifupdown.ifupdownbase import *
-
from ifupdown.iface import *
from ifupdown.utils import utils
from ifupdown.statemanager import *
import ifupdown.ifupdownflags as ifupdownflags
+ import ifupdown.policymanager as policymanager
class ifaceSchedulerFlags():
_SCHED_STATUS = True
+ VRF_MGMT_DEVNAME = policymanager.policymanager_api.get_module_globals(
+ module_name="vrf",
+ attr="vrf-mgmt-devname"
+ )
+
@classmethod
def reset(cls):
cls._STATE_CHECK = True
ifaceobj_getfunc=ifupdownobj.get_ifaceobjs)
except Exception, e:
if not ifupdownobj.ignore_error(str(e)):
- err = 1
- ifupdownobj.logger.error(str(e))
+ err = 1
+ #import traceback
+ #traceback.print_exc()
+ ifupdownobj.logger.error(str(e))
# Continue with rest of the modules
pass
finally:
# if interface exists in the system
ifacename = ifaceobjs[0].name
ifupdownobj.logger.info('%s: running ops ...' %ifacename)
-
if ('down' in ops[0] and
ifaceobjs[0].type != ifaceType.BRIDGE_VLAN and
ifaceobjs[0].addr_method != 'ppp' and
# Run lowerifaces or dependents
dlist = ifaceobj.lowerifaces
if dlist:
+
+ if ifaceobj.link_kind == ifaceLinkKind.VRF:
+ # remove non-auto lowerifaces from 'dlist'
+ for lower_ifname in list(dlist):
+ for lower_ifaceobj in ifupdownobj.get_ifaceobjs(lower_ifname) or []:
+ if lower_ifaceobj and not lower_ifaceobj.auto and ifaceobj.name == cls.VRF_MGMT_DEVNAME:
+ dlist.remove(lower_ifname)
+
ifupdownobj.logger.debug('%s: found dependents %s'
%(ifacename, str(dlist)))
try:
"""
- __DEFAULT_STATE_DIR = "/run/network/"
+ __DEFAULT_STATE_DIR = "/var/tmp/network/"
state_filename = 'ifstatenew'
"""name of the satefile """
self.ifaceobjdict = OrderedDict()
self.logger = logging.getLogger('ifupdown.' +
self.__class__.__name__)
+ self.logger.info("stateManager init")
def init(self):
self.state_dir = ifupdownConfig.config.get("state_dir")
return
if ifaceobj.status != ifaceStatus.SUCCESS:
return
+ # ifupdown2 prevents user from bringing the loopback interface
+ # down - to avoid any issue (like wrong error messages) we
+ # shouldn't remove lo ifaceobj from the statemanager
+ if ifaceobj.link_privflags & ifaceLinkPrivFlags.LOOPBACK:
+ return
# If it matches any of the object, return
oidx = 0
for o in old_ifaceobjs:
import logging
import subprocess
+from string import maketrans
from functools import partial
from ipaddr import IPNetwork, IPAddress
systemctl_cmd = '/bin/systemctl'
dpkg_cmd = '/usr/bin/dpkg'
+ logger.info("utils init command paths")
for cmd in ['bridge',
'ip',
'brctl',
else:
logger.debug('warning: path %s not found: %s won\'t be usable' % (path + cmd, cmd))
+ mac_translate_tab = maketrans(":.-,", " ")
+
+ @classmethod
+ def mac_str_to_int(cls, hw_address):
+ mac = 0
+ if hw_address:
+ for i in hw_address.translate(cls.mac_translate_tab).split():
+ mac = mac << 8
+ mac += int(i, 16)
+ return mac
+
@staticmethod
def get_onff_from_onezero(value):
if value in utils._onoff_onezero:
+++ /dev/null
-#!/usr/bin/python
-#
-# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
-# Author: Roopa Prabhu, roopa@cumulusnetworks.com
-# Julien Fortin, julien@cumulusnetworks.com
-#
-
-import os
-import re
-import glob
-import shlex
-import signal
-import socket
-import subprocess
-
-from string import maketrans
-from ipaddr import IPNetwork, IPv6Network
-
-try:
- import ifupdown2.ifupdown.statemanager as statemanager
- import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
-
- from ifupdown2.nlmanager.nlmanager import Link, Route
-
- from ifupdown2.ifupdown.iface import *
- from ifupdown2.ifupdown.utils import utils
- from ifupdown2.ifupdown.netlink import netlink
-
- from ifupdown2.ifupdownaddons.utilsbase import utilsBase
- from ifupdown2.ifupdownaddons.cache import linkCache, MSTPAttrsCache
-except ImportError:
- import ifupdown.ifupdownflags as ifupdownflags
- import ifupdown.statemanager as statemanager
-
- from nlmanager.nlmanager import Link, Route
-
- from ifupdown.iface import *
- from ifupdown.utils import utils
- from ifupdown.netlink import netlink
-
- from ifupdownaddons.utilsbase import utilsBase
- from ifupdownaddons.cache import linkCache, MSTPAttrsCache
-
-
-class LinkUtils(utilsBase):
- """
- This class contains helper methods to cache and manipulate interfaces through
- non-netlink APIs (sysfs, iproute2, brctl...)
- """
- _CACHE_FILL_DONE = False
- VXLAN_UDP_PORT = 4789
-
- ipbatchbuf = ''
- ipbatch = False
- ipbatch_pause = False
-
- bridge_utils_is_installed = os.path.exists(utils.brctl_cmd)
- bridge_utils_missing_warning = True
-
- DEFAULT_IP_METRIC = 1024
- ADDR_METRIC_SUPPORT = None
-
- mac_translate_tab = maketrans(":.-,", " ")
-
- def __init__(self, *args, **kargs):
- utilsBase.__init__(self, *args, **kargs)
-
- self.supported_command = {
- '%s -c -json vlan show' % utils.bridge_cmd: True,
- 'showmcqv4src': True
- }
- self.bridge_vlan_cache = {}
- self.bridge_vlan_cache_fill_done = False
-
- if not ifupdownflags.flags.PERFMODE and not LinkUtils._CACHE_FILL_DONE:
- self._fill_cache()
-
- if LinkUtils.ADDR_METRIC_SUPPORT is None:
- try:
- cmd = [utils.ip_cmd, 'addr', 'help']
- self.logger.info('executing %s addr help' % utils.ip_cmd)
-
- process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- stdout, stderr = process.communicate()
- LinkUtils.ADDR_METRIC_SUPPORT = '[ metric METRIC ]' in stderr or ''
- self.logger.info('address metric support: %s' % ('OK' if LinkUtils.ADDR_METRIC_SUPPORT else 'KO'))
- except Exception:
- LinkUtils.ADDR_METRIC_SUPPORT = False
- self.logger.info('address metric support: KO')
-
- @classmethod
- def mac_str_to_int(cls, mac):
- mac_int = 0
- if mac:
- for n in mac.translate(cls.mac_translate_tab).split():
- mac_int += int(n, 16)
- return mac_int
-
- @classmethod
- def addr_metric_support(cls):
- return cls.ADDR_METRIC_SUPPORT
-
- @classmethod
- def get_default_ip_metric(cls):
- return cls.DEFAULT_IP_METRIC
-
- @classmethod
- def reset(cls):
- LinkUtils._CACHE_FILL_DONE = False
- LinkUtils.ipbatchbuf = ''
- LinkUtils.ipbatch = False
- LinkUtils.ipbatch_pause = False
-
- def _fill_cache(self):
- if not LinkUtils._CACHE_FILL_DONE:
- self._link_fill()
- self._addr_fill()
- LinkUtils._CACHE_FILL_DONE = True
- return True
- return False
-
- @staticmethod
- def _get_vland_id(citems, i, warn):
- try:
- sub = citems[i:]
- index = sub.index('id')
- int(sub[index + 1])
- return sub[index + 1]
- except:
- if warn:
- raise Exception('invalid use of \'vlan\' keyword')
- return None
-
- def _link_fill(self, ifacename=None, refresh=False):
- """ fills cache with link information
-
- if ifacename argument given, fill cache for ifacename, else
- fill cache for all interfaces in the system
- """
-
- if LinkUtils._CACHE_FILL_DONE and not refresh:
- return
- try:
- # if ifacename already present, return
- if (ifacename and not refresh and
- linkCache.get_attr([ifacename, 'ifflag'])):
- return
- except:
- pass
-
- if True:
- try:
- [linkCache.update_attrdict([ifname], linkattrs)
- for ifname, linkattrs in netlink.link_dump(ifacename).items()]
- except Exception as e:
- self.logger.info('%s' % str(e))
- # this netlink call replaces the call to _link_fill_iproute2_cmd()
- # We shouldn't have netlink calls in the iproute2 module, this will
- # be removed in the future. We plan to release, a flexible backend
- # (netlink+iproute2) by default we will use netlink backend but with
- # a CLI arg we can switch to iproute2 backend.
- # Until we decide to create this "backend" switch capability,
- # we have to put the netlink call inside the iproute2 module.
- else:
- self._link_fill_iproute2_cmd(ifacename, refresh)
-
- self._fill_bond_info(ifacename)
- self._fill_bridge_info(ifacename)
-
- def _fill_bridge_info(self, ifacename):
-
- if True: # netlink
- brports = {}
-
- if ifacename:
- cache_dict = {ifacename: linkCache.links.get(ifacename, {})}
- else:
- cache_dict = linkCache.links
-
- for ifname, obj in cache_dict.items():
- slave_kind = obj.get('slave_kind')
- if not slave_kind and slave_kind != 'bridge':
- continue
-
- info_slave_data = obj.get('info_slave_data')
- if not info_slave_data:
- continue
-
- ifla_master = obj.get('master')
- if not ifla_master:
- raise Exception('No master associated with bridge port %s' % ifname)
-
- for nl_attr in [
- Link.IFLA_BRPORT_STATE,
- Link.IFLA_BRPORT_COST,
- Link.IFLA_BRPORT_PRIORITY,
- ]:
- if nl_attr not in info_slave_data and LinkUtils.bridge_utils_is_installed:
- self._fill_bridge_info_brctl()
- return
-
- brport_attrs = {
- 'pathcost': str(info_slave_data.get(Link.IFLA_BRPORT_COST, 0)),
- 'fdelay': format(float(info_slave_data.get(Link.IFLA_BRPORT_FORWARD_DELAY_TIMER, 0) / 100), '.2f'),
- 'portmcrouter': str(info_slave_data.get(Link.IFLA_BRPORT_MULTICAST_ROUTER, 0)),
- 'portmcfl': str(info_slave_data.get(Link.IFLA_BRPORT_FAST_LEAVE, 0)),
- 'portprio': str(info_slave_data.get(Link.IFLA_BRPORT_PRIORITY, 0)),
- 'unicast-flood': str(info_slave_data.get(Link.IFLA_BRPORT_UNICAST_FLOOD, 0)),
- 'multicast-flood': str(info_slave_data.get(Link.IFLA_BRPORT_MCAST_FLOOD, 0)),
- 'learning': str(info_slave_data.get(Link.IFLA_BRPORT_LEARNING, 0)),
- 'arp-nd-suppress': str(info_slave_data.get(Link.IFLA_BRPORT_ARP_SUPPRESS, 0))
- }
-
- if ifla_master in brports:
- brports[ifla_master][ifname] = brport_attrs
- else:
- brports[ifla_master] = {ifname: brport_attrs}
-
- linkCache.update_attrdict([ifla_master, 'linkinfo', 'ports'], brports[ifla_master])
- else:
- if LinkUtils.bridge_utils_is_installed:
- self._fill_bridge_info_brctl()
-
- def _fill_bridge_info_brctl(self):
- brctlout = utils.exec_command('%s show' % utils.brctl_cmd)
- if not brctlout:
- return
-
- for bline in brctlout.splitlines()[1:]:
- bitems = bline.split()
- if len(bitems) < 2:
- continue
- try:
- linkCache.update_attrdict([bitems[0], 'linkinfo'],
- {'stp': bitems[2]})
- except KeyError:
- linkCache.update_attrdict([bitems[0]],
- {'linkinfo': {'stp': bitems[2]}})
- self._bridge_attrs_fill(bitems[0])
-
- def _bridge_attrs_fill(self, bridgename):
- battrs = {}
- bports = {}
-
- try:
- # Get all bridge attributes
- # battrs['pathcost'] = broutlines[3].split('path cost')[1].strip()
-
- try:
- battrs['maxage'] = self.read_file_oneline(
- '/sys/class/net/%s/bridge/max_age' % bridgename)
- except:
- pass
-
-
- try:
- battrs['hello'] = self.read_file_oneline(
- '/sys/class/net/%s/bridge/hello_time' % bridgename)
- except:
- pass
-
- try:
- battrs['fd'] = self.read_file_oneline(
- '/sys/class/net/%s/bridge/forward_delay' % bridgename)
- except:
- pass
-
- try:
- battrs['ageing'] = self.read_file_oneline(
- '/sys/class/net/%s/bridge/ageing_time' % bridgename)
- except:
- pass
-
- try:
- battrs['mcrouter'] = self.read_file_oneline(
- '/sys/class/net/%s/bridge/multicast_router' % bridgename)
- except:
- pass
-
- try:
- battrs['bridgeprio'] = self.read_file_oneline(
- '/sys/class/net/%s/bridge/priority' % bridgename)
- except:
- pass
-
- try:
- battrs['vlan-protocol'] = VlanProtocols.ID_TO_ETHERTYPES[
- self.read_file_oneline(
- '/sys/class/net/%s/bridge/vlan_protocol' % bridgename)]
- except:
- pass
-
- try:
- battrs.update(self._bridge_get_mcattrs_from_sysfs(bridgename))
- except:
- pass
-
- # XXX: comment this out until mc attributes become available
- # with brctl again
-
- # battrs['mciqc'] = broutlines[11].split('mc init query count')[1].strip()
- # battrs['mclmt'] = broutlines[13].split('mc last member timer')[1].split()[0].strip()
- except Exception, e:
- self.logger.warn('%s: error while processing bridge attributes: %s' % (bridgename, str(e)))
- pass
-
- linkCache.update_attrdict([bridgename, 'linkinfo'], battrs)
-
- names = [os.path.basename(x) for x in glob.glob("/sys/class/net/%s/brif/*" % bridgename)]
- for pname in names:
- bportattrs = {}
- try:
-
- bportattrs['pathcost'] = self.read_file_oneline(
- '/sys/class/net/%s/brport/path_cost' % pname)
- bportattrs['fdelay'] = self.read_file_oneline(
- '/sys/class/net/%s/brport/forward_delay_timer' % pname)
- bportattrs['portmcrouter'] = self.read_file_oneline(
- '/sys/class/net/%s/brport/multicast_router' % pname)
- bportattrs['portmcfl'] = self.read_file_oneline(
- '/sys/class/net/%s/brport/multicast_fast_leave' % pname)
- bportattrs['portprio'] = self.read_file_oneline(
- '/sys/class/net/%s/brport/priority' % pname)
- bportattrs['unicast-flood'] = self.read_file_oneline(
- '/sys/class/net/%s/brport/unicast_flood' % pname)
- bportattrs['multicast-flood'] = self.read_file_oneline(
- '/sys/class/net/%s/brport/multicast_flood' % pname)
- bportattrs['learning'] = self.read_file_oneline(
- '/sys/class/net/%s/brport/learning' % pname)
- bportattrs['arp-nd-suppress'] = self.read_file_oneline(
- '/sys/class/net/%s/brport/neigh_suppress' % pname)
-
- #bportattrs['mcrouters'] = self.read_file_oneline(
- # '/sys/class/net/%s/brport/multicast_router' % pname)
- #bportattrs['mc fast leave'] = self.read_file_oneline(
- # '/sys/class/net/%s/brport/multicast_fast_leave' % pname)
-
- except Exception, e:
- self.logger.warn('%s: error while processing bridge attributes: %s' % (bridgename, str(e)))
- bports[pname] = bportattrs
- linkCache.update_attrdict([bridgename, 'linkinfo', 'ports'], bports)
-
- _bridge_sysfs_mcattrs = {
- 'mclmc': 'multicast_last_member_count',
- 'mcrouter': 'multicast_router',
- 'mcsnoop': 'multicast_snooping',
- 'mcsqc': 'multicast_startup_query_count',
- 'mcqifaddr': 'multicast_query_use_ifaddr',
- 'mcquerier': 'multicast_querier',
- 'hashel': 'hash_elasticity',
- 'hashmax': 'hash_max',
- 'mclmi': 'multicast_last_member_interval',
- 'mcmi': 'multicast_membership_interval',
- 'mcqpi': 'multicast_querier_interval',
- 'mcqi': 'multicast_query_interval',
- 'mcqri': 'multicast_query_response_interval',
- 'mcsqi': 'multicast_startup_query_interval',
- 'igmp-version': 'multicast_igmp_version',
- 'mld-version': 'multicast_mld_version',
- 'vlan-stats': 'vlan_stats_enabled',
- 'mcstats': 'multicast_stats_enabled',
- }
-
- def _bridge_get_mcattrs_from_sysfs(self, bridgename):
- mcattrsdivby100 = ['mclmi', 'mcmi', 'mcqpi', 'mcqi', 'mcqri', 'mcsqi']
- mcattrs = {}
-
- for m, s in self._bridge_sysfs_mcattrs.items():
- n = self.read_file_oneline('/sys/class/net/%s/bridge/%s' % (bridgename, s))
- if m in mcattrsdivby100:
- try:
- v = int(n) / 100
- mcattrs[m] = str(v)
- except Exception, e:
- self.logger.warn('error getting mc attr %s (%s)' % (m, str(e)))
- pass
- else:
- mcattrs[m] = n
- return mcattrs
-
- def _fill_bond_info(self, ifacename):
- bonding_masters = self.read_file_oneline('/sys/class/net/bonding_masters')
- if not bonding_masters:
- return
-
- bond_masters_list = bonding_masters.split()
-
- if ifacename:
- if ifacename in bond_masters_list:
- bond_masters_list = [ifacename]
- else:
- # we want to refresh this interface only if it's a bond master
- return
-
- for bondname in bond_masters_list:
- try:
- if bondname not in linkCache.links:
- linkCache.set_attr([bondname], {'linkinfo': {}})
- linkCache.set_attr([bondname, 'linkinfo', 'slaves'],
- self.read_file_oneline('/sys/class/net/%s/bonding/slaves'
- % bondname).split())
- try:
- # if some attribute are missing we try to get the bond attributes via sysfs
- bond_linkinfo = linkCache.links[bondname]['linkinfo']
- for attr in [Link.IFLA_BOND_MODE, Link.IFLA_BOND_XMIT_HASH_POLICY, Link.IFLA_BOND_MIN_LINKS]:
- if attr not in bond_linkinfo:
- self._fill_bond_info_sysfs(bondname)
- # after we fill in the cache we can continue to the next bond
- break
- except:
- self._fill_bond_info_sysfs(bondname)
-
- except Exception as e:
- self.logger.debug('LinkUtils: bond cache error: %s' % str(e))
-
- def _fill_bond_info_sysfs(self, bondname):
- try:
- linkCache.set_attr([bondname, 'linkinfo', Link.IFLA_BOND_MIN_LINKS],
- self.read_file_oneline(
- '/sys/class/net/%s/bonding/min_links'
- % bondname))
- except Exception as e:
- self.logger.debug(str(e))
-
- try:
- linkCache.set_attr([bondname, 'linkinfo', Link.IFLA_BOND_MODE],
- self.read_file_oneline('/sys/class/net/%s/bonding/mode'
- % bondname).split()[0])
- except Exception as e:
- self.logger.debug(str(e))
- try:
- linkCache.set_attr([bondname, 'linkinfo', Link.IFLA_BOND_XMIT_HASH_POLICY],
- self.read_file_oneline(
- '/sys/class/net/%s/bonding/xmit_hash_policy'
- % bondname).split()[0])
- except Exception as e:
- self.logger.debug(str(e))
- try:
- linkCache.set_attr([bondname, 'linkinfo', Link.IFLA_BOND_AD_LACP_RATE],
- self.read_file_oneline('/sys/class/net/%s/bonding/lacp_rate'
- % bondname).split()[1])
- except Exception as e:
- self.logger.debug(str(e))
- try:
- linkCache.set_attr([bondname, 'linkinfo', Link.IFLA_BOND_AD_ACTOR_SYS_PRIO],
- self.read_file_oneline('/sys/class/net/%s/bonding/ad_actor_sys_prio'
- % bondname))
- except Exception as e:
- self.logger.debug(str(e))
- try:
- linkCache.set_attr([bondname, 'linkinfo', Link.IFLA_BOND_AD_ACTOR_SYSTEM],
- self.read_file_oneline('/sys/class/net/%s/bonding/ad_actor_system'
- % bondname))
- except Exception as e:
- self.logger.debug(str(e))
- try:
- linkCache.set_attr([bondname, 'linkinfo', Link.IFLA_BOND_AD_LACP_BYPASS],
- self.read_file_oneline('/sys/class/net/%s/bonding/lacp_bypass'
- % bondname).split()[1])
- except Exception as e:
- self.logger.debug(str(e))
- try:
- linkCache.set_attr([bondname, 'linkinfo', Link.IFLA_BOND_UPDELAY],
- self.read_file_oneline('/sys/class/net/%s/bonding/updelay'
- % bondname))
- except Exception as e:
- self.logger.debug(str(e))
- try:
- linkCache.set_attr([bondname, 'linkinfo', Link.IFLA_BOND_DOWNDELAY],
- self.read_file_oneline('/sys/class/net/%s/bonding/downdelay'
- % bondname))
- except Exception as e:
- self.logger.debug(str(e))
-
- try:
- linkCache.set_attr([bondname, 'linkinfo', Link.IFLA_BOND_USE_CARRIER],
- self.read_file_oneline('/sys/class/net/%s/bonding/use_carrier' % bondname))
- except Exception as e:
- self.logger.debug(str(e))
-
- try:
- linkCache.set_attr([bondname, 'linkinfo', Link.IFLA_BOND_MIIMON],
- self.read_file_oneline('/sys/class/net/%s/bonding/miimon' % bondname))
- except Exception as e:
- self.logger.debug(str(e))
-
- try:
- linkCache.set_attr([bondname, 'linkinfo', Link.IFLA_BOND_NUM_PEER_NOTIF],
- self.read_file_oneline('/sys/class/net/%s/bonding/num_unsol_na' % bondname))
- except Exception as e:
- self.logger.debug(str(e))
-
- try:
- linkCache.set_attr([bondname, 'linkinfo', Link.IFLA_BOND_NUM_PEER_NOTIF],
- self.read_file_oneline('/sys/class/net/%s/bonding/num_grat_arp' % bondname))
- except Exception as e:
- self.logger.debug(str(e))
-
-
- def _link_fill_iproute2_cmd(self, ifacename=None, refresh=False):
- warn = True
- linkout = {}
- if LinkUtils._CACHE_FILL_DONE and not refresh:
- return
- try:
- # if ifacename already present, return
- if (ifacename and not refresh and
- linkCache.get_attr([ifacename, 'ifflag'])):
- return
- except:
- pass
- cmdout = self.link_show(ifacename=ifacename)
- if not cmdout:
- return
- for c in cmdout.splitlines():
- citems = c.split()
- ifnamenlink = citems[1].split('@')
- if len(ifnamenlink) > 1:
- ifname = ifnamenlink[0]
- iflink = ifnamenlink[1].strip(':')
- else:
- ifname = ifnamenlink[0].strip(':')
- iflink = None
- linkattrs = dict()
- linkattrs['link'] = iflink
- linkattrs['ifindex'] = citems[0].strip(':')
- flags = citems[2].strip('<>').split(',')
- linkattrs['flags'] = flags
- linkattrs['ifflag'] = 'UP' if 'UP' in flags else 'DOWN'
- for i in range(0, len(citems)):
- try:
- if citems[i] == 'mtu':
- linkattrs['mtu'] = citems[i + 1]
- elif citems[i] == 'state':
- linkattrs['state'] = citems[i + 1]
- elif citems[i] == 'link/ether':
- linkattrs['hwaddress'] = citems[i + 1]
- elif citems[i] in ['link/gre', 'link/ipip', 'link/sit', 'link/gre6', 'link/tunnel6', 'gretap']:
- linkattrs['kind'] = 'tunnel'
- tunattrs = {'mode': citems[i].split('/')[-1],
- 'endpoint' : None,
- 'local' : None,
- 'ttl' : None,
- 'physdev' : None}
- for j in range(i, len(citems)):
- if citems[j] == 'local':
- tunattrs['local'] = citems[j + 1]
- elif citems[j] == 'remote':
- tunattrs['endpoint'] = citems[j + 1]
- elif citems[j] == 'ttl':
- tunattrs['ttl'] = citems[j + 1]
- elif citems[j] == 'dev':
- tunattrs['physdev'] = citems[j + 1]
- elif citems[j] in ['vti', 'vti6', 'ip6gre', 'ipip6', 'ip6ip6']:
- tunattrs['mode'] = citems[j]
- linkattrs['linkinfo'] = tunattrs
- break
- elif citems[i] == 'link/ppp':
- linkattrs['kind'] = 'ppp'
- elif citems[i] == 'vlan':
- vlanid = self._get_vland_id(citems, i, warn)
- if vlanid:
- linkattrs['linkinfo'] = {'vlanid': vlanid}
- linkattrs['kind'] = 'vlan'
- elif citems[i] == 'dummy':
- linkattrs['kind'] = 'dummy'
- elif citems[i] == 'vxlan' and citems[i + 1] == 'id':
- linkattrs['kind'] = 'vxlan'
- vattrs = {'vxlanid': citems[i + 2],
- 'svcnode': None,
- 'remote': [],
- 'ageing': citems[i + 2],
- 'learning': 'on'}
- for j in range(i + 2, len(citems)):
- if citems[j] == 'local':
- vattrs['local'] = citems[j + 1]
- elif citems[j] == 'remote':
- vattrs['svcnode'] = citems[j + 1]
- elif citems[j] == 'ageing':
- vattrs['ageing'] = citems[j + 1]
- elif citems[j] == 'nolearning':
- vattrs['learning'] = 'off'
- elif citems[j] == 'dev':
- vattrs['physdev'] = citems[j + 1]
- linkattrs['linkinfo'] = vattrs
- break
- elif citems[i] == 'vrf' and citems[i + 1] == 'table':
- vattrs = {'table': citems[i + 2]}
- linkattrs['linkinfo'] = vattrs
- linkattrs['kind'] = 'vrf'
- linkCache.vrfs[ifname] = vattrs
- break
- elif citems[i] == 'veth':
- linkattrs['kind'] = 'veth'
- elif citems[i] == 'vrf_slave':
- linkattrs['slave_kind'] = 'vrf_slave'
- break
- elif citems[i] == 'macvlan' and citems[i + 1] == 'mode':
- linkattrs['kind'] = 'macvlan'
- elif citems[i] == 'xfrm':
- linkattrs['kind'] = 'xfrm'
- except Exception as e:
- if warn:
- self.logger.debug('%s: parsing error: id, mtu, state, '
- 'link/ether, vlan, dummy, vxlan, local, '
- 'remote, ageing, nolearning, vrf, table, '
- 'vrf_slave are reserved keywords: %s' %
- (ifname, str(e)))
- warn = False
- # linkattrs['alias'] = self.read_file_oneline(
- # '/sys/class/net/%s/ifalias' %ifname)
- linkout[ifname] = linkattrs
- [linkCache.update_attrdict([ifname], linkattrs)
- for ifname, linkattrs in linkout.items()]
-
- @staticmethod
- def _addr_filter(ifname, addr, scope=None):
- default_addrs = ['127.0.0.1/8', '::1/128', '0.0.0.0']
- if ifname == 'lo' and addr in default_addrs:
- return True
- if scope and scope == 'link':
- return True
- return False
-
- def _addr_fill(self, ifacename=None, refresh=False):
- """ fills cache with address information
-
- if ifacename argument given, fill cache for ifacename, else
- fill cache for all interfaces in the system
- """
- if LinkUtils._CACHE_FILL_DONE and not refresh:
- return
- try:
- # Check if ifacename is already full, in which case, return
- if ifacename and not refresh:
- linkCache.get_attr([ifacename, 'addrs'])
- return
- except:
- pass
-
- if True:
- try:
- [linkCache.update_attrdict([ifname], linkattrs)
- for ifname, linkattrs in netlink.addr_dump(ifname=ifacename).items()]
- except Exception as e:
- self.logger.info(str(e))
-
- # this netlink call replaces the call to _addr_fill_iproute2_cmd()
- # We shouldn't have netlink calls in the iproute2 module, this will
- # be removed in the future. We plan to release, a flexible backend
- # (netlink+iproute2) by default we will use netlink backend but with
- # a CLI arg we can switch to iproute2 backend.
- # Until we decide to create this "backend" switch capability,
- # we have to put the netlink call inside the iproute2 module.
-
- else:
- self._addr_fill_iproute2_cmd(ifacename, refresh)
-
- def _addr_fill_iproute2_cmd(self, ifacename=None, refresh=False):
- """ fills cache with address information
-
- if ifacename argument given, fill cache for ifacename, else
- fill cache for all interfaces in the system
- """
- linkout = {}
- if LinkUtils._CACHE_FILL_DONE and not refresh:
- return
- try:
- # Check if ifacename is already full, in which case, return
- if ifacename and not refresh:
- linkCache.get_attr([ifacename, 'addrs'])
- return
- except:
- pass
- cmdout = self.addr_show(ifacename=ifacename)
- if not cmdout:
- return
- for c in cmdout.splitlines():
- citems = c.split()
- ifnamenlink = citems[1].split('@')
- if len(ifnamenlink) > 1:
- ifname = ifnamenlink[0]
- else:
- ifname = ifnamenlink[0].strip(':')
- if not linkout.get(ifname):
- linkattrs = dict()
- linkattrs['addrs'] = OrderedDict({})
- try:
- linkout[ifname].update(linkattrs)
- except KeyError:
- linkout[ifname] = linkattrs
- if citems[2] == 'inet':
- if self._addr_filter(ifname, citems[3], scope=citems[5]):
- continue
- addrattrs = dict()
- addrattrs['scope'] = citems[5]
- addrattrs['type'] = 'inet'
- linkout[ifname]['addrs'][citems[3]] = addrattrs
- elif citems[2] == 'inet6':
- if self._addr_filter(ifname, citems[3], scope=citems[5]):
- continue
- if citems[5] == 'link':
- continue # skip 'link' addresses
- addrattrs = dict()
- addrattrs['scope'] = citems[5]
- addrattrs['type'] = 'inet6'
- linkout[ifname]['addrs'][citems[3]] = addrattrs
- [linkCache.update_attrdict([ifname], linkattrs)
- for ifname, linkattrs in linkout.items()]
-
- def del_cache_entry(self, ifname):
- try:
- del linkCache.links[ifname]
- except:
- pass
-
- def cache_get(self, t, attrlist, refresh=False):
- return self._cache_get(t, attrlist, refresh)
-
- def _cache_get(self, t, attrlist, refresh=False):
- try:
- if ifupdownflags.flags.DRYRUN:
- return False
- if ifupdownflags.flags.CACHE:
- if self._fill_cache():
- # if we filled the cache, return new data
- return linkCache.get_attr(attrlist)
- if not refresh:
- return linkCache.get_attr(attrlist)
- if t == 'link':
- self._link_fill(attrlist[0], refresh)
- elif t == 'addr':
- self._addr_fill(attrlist[0], refresh)
- else:
- self._link_fill(attrlist[0], refresh)
- self._addr_fill(attrlist[0], refresh)
- return linkCache.get_attr(attrlist)
- except Exception, e:
- self.logger.debug('_cache_get(%s) : [%s]' % (str(attrlist), str(e)))
- return None
-
- def cache_check(self, attrlist, value, refresh=False):
- return self._cache_check('link', attrlist, value, refresh=refresh)
-
- def _cache_check(self, t, attrlist, value, refresh=False):
- try:
- return self._cache_get(t, attrlist, refresh) == value
- except Exception, e:
- self.logger.debug('_cache_check(%s) : [%s]'
- % (str(attrlist), str(e)))
- return False
-
- def cache_update(self, attrlist, value):
- return self._cache_update(attrlist, value)
-
- @staticmethod
- def _cache_update(attrlist, value):
- if ifupdownflags.flags.DRYRUN:
- return
- try:
- if attrlist[-1] == 'slaves':
- linkCache.append_to_attrlist(attrlist, value)
- return
- linkCache.set_attr(attrlist, value)
- except:
- pass
-
- @staticmethod
- def _cache_delete(attrlist, value=None):
- if ifupdownflags.flags.DRYRUN:
- return
- try:
- if value:
- linkCache.remove_from_attrlist(attrlist, value)
- else:
- linkCache.del_attr(attrlist)
- except:
- pass
-
- @staticmethod
- def _cache_invalidate():
- linkCache.invalidate()
- LinkUtils._CACHE_FILL_DONE = False
-
- @staticmethod
- def batch_start():
- LinkUtils.ipbatcbuf = ''
- LinkUtils.ipbatch = True
- LinkUtils.ipbatch_pause = False
-
- @staticmethod
- def add_to_batch(cmd):
- LinkUtils.ipbatchbuf += cmd + '\n'
-
- @staticmethod
- def batch_pause():
- LinkUtils.ipbatch_pause = True
-
- @staticmethod
- def batch_resume():
- LinkUtils.ipbatch_pause = False
-
- def batch_commit(self):
- if not LinkUtils.ipbatchbuf:
- LinkUtils.ipbatchbuf = ''
- LinkUtils.ipbatch = False
- LinkUtils.ipbatch_pause = False
- return
- try:
- utils.exec_command('%s -force -batch -' % utils.ip_cmd,
- stdin=self.ipbatchbuf)
- except:
- raise
- finally:
- LinkUtils.ipbatchbuf = ''
- LinkUtils.ipbatch = False
- LinkUtils.ipbatch_pause = False
-
- def bridge_batch_commit(self):
- if not LinkUtils.ipbatchbuf:
- LinkUtils.ipbatchbuf = ''
- LinkUtils.ipbatch = False
- LinkUtils.ipbatch_pause = False
- return
- try:
- utils.exec_command('%s -force -batch -'
- % utils.bridge_cmd, stdin=self.ipbatchbuf)
- except:
- raise
- finally:
- LinkUtils.ipbatchbuf = ''
- LinkUtils.ipbatch = False
- LinkUtils.ipbatch_pause = False
-
- def addr_show(self, ifacename=None):
- if ifacename:
- if not self.link_exists(ifacename):
- return
- return utils.exec_commandl([utils.ip_cmd,
- '-o', 'addr', 'show', 'dev', ifacename])
- else:
- return utils.exec_commandl([utils.ip_cmd,
- '-o', 'addr', 'show'])
-
- @staticmethod
- def link_show(ifacename=None):
- if ifacename:
- return utils.exec_commandl([utils.ip_cmd,
- '-o', '-d', 'link', 'show', 'dev', ifacename])
- else:
- return utils.exec_commandl([utils.ip_cmd,
- '-o', '-d', 'link', 'show'])
-
- def addr_add(self, ifacename, address, broadcast=None,
- peer=None, scope=None, preferred_lifetime=None, metric=None):
- if not address:
- return
- cmd = 'addr add %s' % address
- if broadcast:
- cmd += ' broadcast %s' % broadcast
- if peer:
- cmd += ' peer %s' % peer
- if scope:
- cmd += ' scope %s' % scope
- if preferred_lifetime:
- cmd += ' preferred_lft %s' % preferred_lifetime
- cmd += ' dev %s' % ifacename
-
- if metric:
- cmd += ' metric %s' % metric
-
- if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
- self.add_to_batch(cmd)
- else:
- utils.exec_command('%s %s' % (utils.ip_cmd, cmd))
- self._cache_update([ifacename, 'addrs', address], {})
-
- def addr_del(self, ifacename, address, broadcast=None,
- peer=None, scope=None):
- """ Delete ipv4 address """
- if not address:
- return
- if not self._cache_get('addr', [ifacename, 'addrs', address]):
- return
- cmd = 'addr del %s' % address
- if broadcast:
- cmd += ' broadcast %s' % broadcast
- if peer:
- cmd += ' peer %s' % peer
- if scope:
- cmd += ' scope %s' % scope
- cmd += ' dev %s' % ifacename
- utils.exec_command('%s %s' % (utils.ip_cmd, cmd))
- self._cache_delete([ifacename, 'addrs', address])
-
- def addr_flush(self, ifacename):
- cmd = 'addr flush dev %s' % ifacename
- if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
- self.add_to_batch(cmd)
- else:
- utils.exec_command('%s %s' % (utils.ip_cmd, cmd))
- self._cache_delete([ifacename, 'addrs'])
-
- def del_addr_all(self, ifacename, skip_addrs=[]):
- if not skip_addrs:
- skip_addrs = []
- runningaddrsdict = self.get_running_addrs(ifname=ifacename)
- try:
- # XXX: ignore errors. Fix this to delete secondary addresses
- # first
- [self.addr_del(ifacename, a) for a in
- set(runningaddrsdict.keys()).difference(skip_addrs)]
- except:
- # ignore errors
- pass
-
- def addr_get(self, ifacename, details=True, refresh=False):
- addrs = self._cache_get('addr', [ifacename, 'addrs'], refresh=refresh)
- if not addrs:
- return None
- if details:
- return addrs
- return addrs.keys()
-
- def get_running_addrs(self, ifaceobj=None, ifname=None, details=True, addr_virtual_ifaceobj=None):
- """
- We now support addr with link scope. Since the kernel may add it's
- own link address to some interfaces we need to filter them out and
- make sure we only deal with the addresses set by ifupdown2.
-
- To do so we look at the previous configuration made by ifupdown2
- (with the help of the statemanager) together with the addresses
- specified by the user in /etc/network/interfaces, these addresses
- are then compared to the running state of the intf (ip addr show)
- made via a netlink addr dump.
- For each configured addresses of scope link, we check if it was
- previously configured by ifupdown2 to create a final set of the
- addresses watched by ifupdown2
- """
- if not ifaceobj and not ifname:
- return None
-
- config_addrs = set()
-
- if ifaceobj:
- interface_name = ifaceobj.name
- else:
- interface_name = ifname
-
- if addr_virtual_ifaceobj:
- for attr_name in ["address-virtual", "vrrp"]:
- for virtual in addr_virtual_ifaceobj.get_attr_value(attr_name) or []:
- for ip in virtual.split():
- try:
- IPNetwork(ip)
- config_addrs.add(ip)
- except:
- pass
-
- saved_ifaceobjs = statemanager.statemanager_api.get_ifaceobjs(addr_virtual_ifaceobj.name)
- for saved_ifaceobj in saved_ifaceobjs or []:
- for virtual in saved_ifaceobj.get_attr_value(attr_name) or []:
- for ip in virtual.split():
- try:
- IPNetwork(ip)
- config_addrs.add(ip)
- except:
- pass
- else:
- if ifaceobj:
- for addr in ifaceobj.get_attr_value('address') or []:
- config_addrs.add(addr)
-
- saved_ifaceobjs = statemanager.statemanager_api.get_ifaceobjs(interface_name)
- for saved_ifaceobj in saved_ifaceobjs or []:
- for addr in saved_ifaceobj.get_attr_value('address') or []:
- config_addrs.add(addr)
-
- running_addrs = OrderedDict()
- cached_addrs = self.addr_get(interface_name)
- if cached_addrs:
- for addr, addr_details in cached_addrs.items():
- try:
- scope = int(addr_details['scope'])
- except Exception:
- try:
- d = {}
- addr_obj = IPNetwork(addr)
- if isinstance(addr_obj, IPv6Network):
- d['family'] = 'inet6'
- else:
- d['family'] = 'inet'
- running_addrs[addr] = d
- except:
- running_addrs[addr] = {}
- continue
- if (scope & Route.RT_SCOPE_LINK and addr in config_addrs) or not scope & Route.RT_SCOPE_LINK:
- running_addrs[addr] = addr_details
- else:
- return None
-
- if details:
- return running_addrs
- return running_addrs.keys()
-
- @staticmethod
- def compare_user_config_vs_running_state(running_addrs, user_addrs):
- ip4 = []
- ip6 = []
-
- for ip in user_addrs or []:
- obj = IPNetwork(ip)
-
- if type(obj) == IPv6Network:
- ip6.append(str(obj))
- else:
- ip4.append(str(obj))
-
- running_ipobj = []
- for ip in running_addrs or []:
- running_ipobj.append(str(IPNetwork(ip)))
-
- return running_ipobj == (ip4 + ip6)
-
- def addr_add_multiple(self, ifaceobj, ifacename, addrs, purge_existing=False, metric=None):
- # purges address
- if purge_existing:
- # if perfmode is not set and also if iface has no sibling
- # objects, purge addresses that are not present in the new
- # config
- runningaddrs = self.get_running_addrs(
- ifname=ifacename,
- details=False,
- addr_virtual_ifaceobj=ifaceobj
- )
- addrs = utils.get_normalized_ip_addr(ifacename, addrs)
-
- if self.compare_user_config_vs_running_state(runningaddrs, addrs):
- return
- try:
- # if primary address is not same, there is no need to keep any.
- # reset all addresses
- if (addrs and runningaddrs and
- (addrs[0] != runningaddrs[0])):
- self.del_addr_all(ifacename)
- else:
- self.del_addr_all(ifacename, addrs)
- except Exception, e:
- self.logger.warning('%s: %s' % (ifacename, str(e)))
- for a in addrs:
- try:
- self.addr_add(ifacename, a, metric=metric)
- except Exception, e:
- self.logger.error(str(e))
-
- def _link_set_ifflag(self, ifacename, value):
- # Dont look at the cache, the cache may have stale value
- # because link status can be changed by external
- # entity (One such entity is ifupdown main program)
- cmd = 'link set dev %s %s' % (ifacename, value.lower())
- if LinkUtils.ipbatch:
- self.add_to_batch(cmd)
- else:
- utils.exec_command('%s %s' % (utils.ip_cmd, cmd))
-
- def link_up(self, ifacename):
- self._link_set_ifflag(ifacename, 'UP')
-
- def link_down(self, ifacename):
- self._link_set_ifflag(ifacename, 'DOWN')
-
- def link_set(self, ifacename, key, value=None,
- force=False, t=None, state=None):
- if not force:
- if (key not in ['master', 'nomaster'] and
- self._cache_check('link', [ifacename, key], value)):
- return
- cmd = 'link set dev %s' % ifacename
- if t:
- cmd += ' type %s' % t
- cmd += ' %s' % key
- if value:
- cmd += ' %s' % value
- if state:
- cmd += ' %s' % state
- if LinkUtils.ipbatch:
- self.add_to_batch(cmd)
- else:
- utils.exec_command('%s %s' % (utils.ip_cmd, cmd))
- if key not in ['master', 'nomaster']:
- self._cache_update([ifacename, key], value)
-
- def link_set_hwaddress(self, ifacename, hwaddress, force=False, keep_down=False):
- if not force:
- link_hwaddress = self.link_get_hwaddress(ifacename)
-
- if self.mac_str_to_int(link_hwaddress) == self.mac_str_to_int(hwaddress):
- return False
-
- self.link_down(ifacename)
- cmd = 'link set dev %s address %s' % (ifacename, hwaddress)
- if LinkUtils.ipbatch:
- self.add_to_batch(cmd)
- else:
- utils.exec_command('%s %s' % (utils.ip_cmd, cmd))
-
- if not keep_down:
- self.link_up(ifacename)
- self._cache_update([ifacename, 'hwaddress'], hwaddress)
- return True
-
- def link_set_mtu(self, ifacename, mtu):
- if ifupdownflags.flags.DRYRUN:
- return True
- if not mtu or not ifacename: return
- self.write_file('/sys/class/net/%s/mtu' % ifacename, mtu)
- self._cache_update([ifacename, 'mtu'], mtu)
-
- def link_set_alias(self, ifacename, alias):
- self.write_file('/sys/class/net/%s/ifalias' % ifacename,
- '\n' if not alias else alias)
-
- def link_get_alias(self, ifacename):
- return self.read_file_oneline('/sys/class/net/%s/ifalias'
- % ifacename)
-
- def link_isloopback(self, ifacename):
- flags = self._cache_get('link', [ifacename, 'flags'])
- if not flags:
- return
- if 'LOOPBACK' in flags:
- return True
- return False
-
- def link_get_status(self, ifacename):
- return self._cache_get('link', [ifacename, 'ifflag'], refresh=True)
-
- @staticmethod
- def route_add_gateway(ifacename, gateway, vrf=None, metric=None, onlink=True):
- if not gateway:
- return
- if not vrf:
- cmd = '%s route add default via %s proto kernel' % (utils.ip_cmd,
- gateway)
- else:
- cmd = ('%s route add table %s default via %s proto kernel' %
- (utils.ip_cmd, vrf, gateway))
- # Add metric
- if metric:
- cmd += ' metric %s' % metric
- cmd += ' dev %s' % ifacename
-
- if onlink:
- cmd += " onlink"
-
- utils.exec_command(cmd)
-
- @staticmethod
- def route_del_gateway(ifacename, gateway, vrf=None, metric=None):
- # delete default gw
- if not gateway:
- return
- if not vrf:
- cmd = ('%s route del default via %s proto kernel' %
- (utils.ip_cmd, gateway))
- else:
- cmd = ('%s route del table %s default via %s proto kernel' %
- (utils.ip_cmd, vrf, gateway))
- if metric:
- cmd += ' metric %s' % metric
- cmd += ' dev %s' % ifacename
- utils.exec_command(cmd)
-
- @staticmethod
- def _get_vrf_id(ifacename):
- try:
- return linkCache.vrfs[ifacename]['table']
- except KeyError:
- dump = netlink.link_dump(ifacename)
-
- [linkCache.update_attrdict([ifname], linkattrs)
- for ifname, linkattrs in dump.items()]
-
- if dump and dump.get(ifacename, {}).get('kind') == 'vrf':
- vrf_table = dump.get(ifacename, {}).get('linkinfo', {}).get('table')
- linkCache.vrfs[ifacename] = {'table': vrf_table}
- return vrf_table
-
- return None
-
- def fix_ipv6_route_metric(self, ifaceobj, macvlan_ifacename, ips):
- vrf_table = None
-
- if ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE:
- try:
- for upper_iface in ifaceobj.upperifaces:
- vrf_table = self._get_vrf_id(upper_iface)
- if vrf_table:
- break
- except:
- pass
-
- ip_route_del = []
- for ip in ips:
- ip_network_obj = IPNetwork(ip)
-
- if type(ip_network_obj) == IPv6Network:
- route_prefix = '%s/%d' % (ip_network_obj.network, ip_network_obj.prefixlen)
-
- if vrf_table:
- if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
- LinkUtils.add_to_batch('route del %s table %s dev %s' % (route_prefix, vrf_table, macvlan_ifacename))
- else:
- utils.exec_commandl([utils.ip_cmd, 'route', 'del', route_prefix, 'table', vrf_table, 'dev', macvlan_ifacename])
- else:
- if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
- LinkUtils.add_to_batch('route del %s dev %s' % (route_prefix, macvlan_ifacename))
- else:
- utils.exec_commandl([utils.ip_cmd, 'route', 'del', route_prefix, 'dev', macvlan_ifacename])
- ip_route_del.append((route_prefix, vrf_table))
-
- for ip, vrf_table in ip_route_del:
- if vrf_table:
- if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
- LinkUtils.add_to_batch('route add %s table %s dev %s proto kernel metric 9999' % (ip, vrf_table, macvlan_ifacename))
- else:
- utils.exec_commandl([utils.ip_cmd, 'route', 'add', ip, 'table', vrf_table, 'dev', macvlan_ifacename, 'proto', 'kernel' 'metric', '9999'])
- else:
- if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
- LinkUtils.add_to_batch('route add %s dev %s proto kernel metric 9999' % (ip, macvlan_ifacename))
- else:
- utils.exec_commandl([utils.ip_cmd, 'route', 'add', ip, 'dev', macvlan_ifacename, 'proto', 'kernel' 'metric', '9999'])
-
- def link_create_vlan(self, vlan_device_name, vlan_raw_device, vlanid):
- if self.link_exists(vlan_device_name):
- return
- utils.exec_command('%s link add link %s name %s type vlan id %d' %
- (utils.ip_cmd,
- vlan_raw_device, vlan_device_name, vlanid))
- self._cache_update([vlan_device_name], {})
-
- def link_create_vlan_from_name(self, vlan_device_name):
- v = vlan_device_name.split('.')
- if len(v) != 2:
- self.logger.warn('invalid vlan device name %s' % vlan_device_name)
- return
- self.link_create_vlan(vlan_device_name, v[0], v[1])
-
- def link_create_macvlan(self, name, linkdev, mode='private'):
- if self.link_exists(name):
- return
- cmd = ('link add link %s' % linkdev +
- ' name %s' % name +
- ' type macvlan mode %s' % mode)
- if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
- self.add_to_batch(cmd)
- else:
- utils.exec_command('%s %s' % (utils.ip_cmd, cmd))
- self._cache_update([name], {})
-
- def get_vxlan_peers(self, dev, svcnodeip):
- cmd = '%s fdb show brport %s' % (utils.bridge_cmd,
- dev)
- cur_peers = []
- try:
- ps = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE, close_fds=False)
- utils.enable_subprocess_signal_forwarding(ps, signal.SIGINT)
- output = subprocess.check_output(('grep', '00:00:00:00:00:00'), stdin=ps.stdout)
- ps.wait()
- utils.disable_subprocess_signal_forwarding(signal.SIGINT)
- try:
- ppat = re.compile('\s+dst\s+(\d+.\d+.\d+.\d+)\s+')
- for l in output.split('\n'):
- m = ppat.search(l)
- if m and m.group(1) != svcnodeip:
- cur_peers.append(m.group(1))
- except:
- self.logger.warn('error parsing ip link output')
- except subprocess.CalledProcessError as e:
- if e.returncode != 1:
- self.logger.error(str(e))
- finally:
- utils.disable_subprocess_signal_forwarding(signal.SIGINT)
-
- return cur_peers
-
- def tunnel_create(self, tunnelname, mode, attrs={}):
- """ generic link_create function """
- if self.link_exists(tunnelname):
- return
-
- cmd = ''
- if '6' in mode:
- cmd = ' -6'
-
- if mode in ['gretap']:
- cmd += ' link add %s type %s' % (tunnelname, mode)
- else:
- cmd += ' tunnel add %s mode %s' % (tunnelname, mode)
-
- if attrs:
- for k, v in attrs.iteritems():
- cmd += ' %s' % k
- if v:
- cmd += ' %s' % v
- if self.ipbatch and not self.ipbatch_pause:
- self.add_to_batch(cmd)
- else:
- utils.exec_command('ip %s' % cmd)
- self._cache_update([tunnelname], {})
-
- def tunnel_change(self, tunnelname, attrs={}):
- """ tunnel change function """
- if not self.link_exists(tunnelname):
- return
- cmd = 'tunnel change'
- cmd += ' %s' %(tunnelname)
- if attrs:
- for k, v in attrs.iteritems():
- cmd += ' %s' %k
- if v:
- cmd += ' %s' %v
- if self.ipbatch and not self.ipbatch_pause:
- self.add_to_batch(cmd)
- else:
- utils.exec_command('ip %s' % cmd)
-
- def link_create_vxlan(self, name, vxlanid,
- localtunnelip=None,
- svcnodeip=None,
- remoteips=None,
- learning='on',
- ageing=None,
- anycastip=None,
- ttl=None):
- if svcnodeip and remoteips:
- raise Exception("svcnodeip and remoteip is mutually exclusive")
- args = ''
- if svcnodeip:
- args += ' remote %s' % svcnodeip
- if ageing:
- args += ' ageing %s' % ageing
- if learning == 'off':
- args += ' nolearning'
- if ttl is not None:
- args += ' ttl %s' % ttl
-
- if self.link_exists(name):
- cmd = 'link set dev %s type vxlan dstport %d' % (name, LinkUtils.VXLAN_UDP_PORT)
- vxlanattrs = self.get_vxlandev_attrs(name)
- # on ifreload do not overwrite anycast_ip to individual ip if clagd
- # has modified
- if vxlanattrs:
- running_localtunnelip = vxlanattrs.get('local')
- if anycastip and running_localtunnelip and anycastip == running_localtunnelip:
- localtunnelip = running_localtunnelip
- running_svcnode = vxlanattrs.get('svcnode')
- if running_svcnode and not svcnodeip:
- args += ' noremote'
- else:
- cmd = 'link add dev %s type vxlan id %s dstport %d' % (name, vxlanid, LinkUtils.VXLAN_UDP_PORT)
-
- if localtunnelip:
- args += ' local %s' % localtunnelip
- cmd += args
-
- if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
- self.add_to_batch(cmd)
- else:
- utils.exec_command('%s %s' % (utils.ip_cmd, cmd))
-
- # XXX: update linkinfo correctly
- #self._cache_update([name], {})
-
- @staticmethod
- def link_exists(ifacename):
- if ifupdownflags.flags.DRYRUN:
- return True
- return os.path.exists('/sys/class/net/%s' % ifacename)
-
- @staticmethod
- def link_exists_nodryrun(ifname):
- return os.path.exists('/sys/class/net/%s' % ifname)
-
- def link_get_ifindex(self, ifacename):
- if ifupdownflags.flags.DRYRUN:
- return True
- return self.read_file_oneline('/sys/class/net/%s/ifindex' % ifacename)
-
- def is_vlan_device_by_name(self, ifacename):
- if re.search(r'\.', ifacename):
- return True
- return False
-
- @staticmethod
- def link_add_macvlan(ifname, macvlan_ifacename, mode):
- utils.exec_commandl(['ip', 'link', 'add', 'link', ifname, 'name', macvlan_ifacename, 'type', 'macvlan', 'mode', mode])
-
- @staticmethod
- def link_add_xfrm(ifname, xfrm_name, xfrm_id):
- utils.exec_commandl(['ip', 'link', 'add', xfrm_name, 'type', 'xfrm', 'dev', ifname, 'if_id', xfrm_id])
-
- @staticmethod
- def route_add(route):
- utils.exec_command('%s route add %s' % (utils.ip_cmd,
- route))
-
- @staticmethod
- def route6_add(route):
- utils.exec_command('%s -6 route add %s' % (utils.ip_cmd,
- route))
-
- def get_vlandev_attrs(self, ifacename):
- return (self._cache_get('link', [ifacename, 'link']),
- self._cache_get('link', [ifacename, 'linkinfo', 'vlanid']),
- self._cache_get('link', [ifacename, 'linkinfo', 'vlan_protocol']))
-
- def get_vlan_protocol(self, ifacename):
- return self._cache_get('link', [ifacename, 'linkinfo', 'vlan_protocol'])
-
- def get_vxlandev_attrs(self, ifacename):
- return self._cache_get('link', [ifacename, 'linkinfo'])
-
- def get_vxlandev_learning(self, ifacename):
- return self._cache_get('link', [ifacename, 'linkinfo', Link.IFLA_VXLAN_LEARNING])
-
- def set_vxlandev_learning(self, ifacename, learn):
- if learn == 'on':
- utils.exec_command('%s link set dev %s type vxlan learning' %
- (utils.ip_cmd, ifacename))
- self._cache_update([ifacename, 'linkinfo', 'learning'], 'on')
- else:
- utils.exec_command('%s link set dev %s type vxlan nolearning' %
- (utils.ip_cmd, ifacename))
- self._cache_update([ifacename, 'linkinfo', 'learning'], 'off')
-
- def link_get_linkinfo_attrs(self, ifacename):
- return self._cache_get('link', [ifacename, 'linkinfo'])
-
- def link_get_mtu(self, ifacename, refresh=False):
- return self._cache_get('link', [ifacename, 'mtu'], refresh=refresh)
-
- def link_get_mtu_sysfs(self, ifacename):
- return self.read_file_oneline('/sys/class/net/%s/mtu'
- % ifacename)
-
- def link_get_kind(self, ifacename):
- return self._cache_get('link', [ifacename, 'kind'])
-
- def link_get_slave_kind(self, ifacename):
- return self._cache_get('link', [ifacename, 'slave_kind'])
-
- def link_get_hwaddress(self, ifacename):
- address = self._cache_get('link', [ifacename, 'hwaddress'])
- # newly created logical interface addresses dont end up in the cache
- # read hwaddress from sysfs file for these interfaces
- if not address:
- address = self.read_file_oneline('/sys/class/net/%s/address'
- % ifacename)
- return address
-
- def link_create(self, ifacename, t, attrs={}):
- """ generic link_create function """
- if self.link_exists(ifacename):
- return
- cmd = 'link add'
- cmd += ' name %s type %s' % (ifacename, t)
- if attrs:
- for k, v in attrs.iteritems():
- cmd += ' %s' % k
- if v:
- cmd += ' %s' % v
- if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
- self.add_to_batch(cmd)
- else:
- utils.exec_command('%s %s' % (utils.ip_cmd, cmd))
- self._cache_update([ifacename], {})
-
- def link_delete(self, ifacename):
- if not self.link_exists(ifacename):
- return
- cmd = 'link del %s' % ifacename
- if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
- self.add_to_batch(cmd)
- else:
- utils.exec_command('%s %s' % (utils.ip_cmd, cmd))
- self._cache_invalidate()
-
- def link_get_master(self, ifacename):
- sysfs_master_path = '/sys/class/net/%s/master' % ifacename
- if os.path.exists(sysfs_master_path):
- link_path = os.readlink(sysfs_master_path)
- if link_path:
- return os.path.basename(link_path)
- else:
- return None
- else:
- return self._cache_get('link', [ifacename, 'master'])
-
- def get_brport_peer_link(self, bridgename):
- try:
- return self._cache_get('link', [bridgename, 'info_slave_data', Link.IFLA_BRPORT_PEER_LINK])
- except:
- return None
-
- @staticmethod
- def bridge_port_vids_add(bridgeportname, vids):
- [utils.exec_command('%s vlan add vid %s dev %s' %
- (utils.bridge_cmd,
- v, bridgeportname)) for v in vids]
-
- @staticmethod
- def bridge_port_vids_del(bridgeportname, vids):
- if not vids:
- return
- [utils.exec_command('%s vlan del vid %s dev %s' %
- (utils.bridge_cmd,
- v, bridgeportname)) for v in vids]
-
- @staticmethod
- def bridge_port_vids_flush(bridgeportname, vid):
- utils.exec_command('%s vlan del vid %s dev %s' %
- (utils.bridge_cmd,
- vid, bridgeportname))
-
- @staticmethod
- def bridge_port_vids_get(bridgeportname):
- bridgeout = utils.exec_command('%s vlan show dev %s' %
- (utils.bridge_cmd,
- bridgeportname))
- if not bridgeout:
- return []
- brvlanlines = bridgeout.readlines()[2:]
- vids = [l.strip() for l in brvlanlines]
- return [v for v in vids if v]
-
- @staticmethod
- def bridge_port_vids_get_all():
- brvlaninfo = {}
- bridgeout = utils.exec_command('%s -c vlan show'
- % utils.bridge_cmd)
- if not bridgeout:
- return brvlaninfo
- brvlanlines = bridgeout.splitlines()
- brportname = None
- for l in brvlanlines[1:]:
- if l and not l.startswith(' ') and not l.startswith('\t'):
- attrs = l.split()
- brportname = attrs[0].strip()
- brvlaninfo[brportname] = {'pvid': None, 'vlan': []}
- l = ' '.join(attrs[1:])
- if not brportname or not l:
- continue
- l = l.strip()
- if 'PVID' in l:
- brvlaninfo[brportname]['pvid'] = l.split()[0]
- elif 'Egress Untagged' not in l:
- brvlaninfo[brportname]['vlan'].append(l)
- return brvlaninfo
-
- def bridge_port_vids_get_all_json(self):
- if not self.supported_command['%s -c -json vlan show'
- % utils.bridge_cmd]:
- return {}
- brvlaninfo = {}
- try:
- bridgeout = utils.exec_command('%s -c -json vlan show'
- % utils.bridge_cmd)
- except:
- self.supported_command['%s -c -json vlan show'
- % utils.bridge_cmd] = False
- self.logger.info('%s -c -json vlan show: skipping unsupported command'
- % utils.bridge_cmd)
- try:
- return self.get_bridge_vlan_nojson()
- except Exception as e:
- self.logger.info('bridge: get_bridge_vlan_nojson: %s' % str(e))
- return {}
-
- if not bridgeout: return brvlaninfo
- try:
- vlan_json = json.loads(bridgeout, encoding="utf-8")
- except Exception, e:
- self.logger.info('json loads failed with (%s)' % str(e))
- return {}
-
- try:
- if isinstance(vlan_json, list):
- # newer iproute2 version changed the bridge vlan show output
- # ifupdown2 relies on the previous format, we have the convert
- # data into old format
- bridge_port_vids = dict()
-
- for intf in vlan_json:
- bridge_port_vids[intf["ifname"]] = intf["vlans"]
-
- return bridge_port_vids
- else:
- # older iproute2 version have different ways to dump vlans
- # ifupdown2 prefers the following syntax:
- # {
- # "vx-1002": [{
- # "vlan": 1002,
- # "flags": ["PVID", "Egress Untagged"]
- # }
- # ],
- # "vx-1004": [{
- # "vlan": 1004,
- # "flags": ["PVID", "Egress Untagged"]
- # }]
- # }
- return vlan_json
- except Exception as e:
- self.logger.debug("bridge vlan show: Unknown json output: %s" % str(e))
- return vlan_json
-
- @staticmethod
- def get_bridge_vlan_nojson():
- vlan_json = {}
- bridgeout = utils.exec_commandl([utils.bridge_cmd, '-c', 'vlan', 'show'])
- if bridgeout:
- output = [line.split('\n') for line in bridgeout.split('\n\n')]
- output[0] = output[0][1:]
- for line in output:
- current_swp = None
- if not line:
- continue
- for entry in line:
- if not entry:
- continue
- prefix, vlan = entry.split('\t')
- if prefix:
- current_swp = prefix
- vlan_json[prefix] = []
- v = {}
- vlan = vlan[1:]
- try:
- v['vlan'] = int(vlan)
- except:
- try:
- if '-' in vlan:
- start, end = vlan.split('-')
- if ' ' in end:
- end = end[0:end.index(' ')]
- v['vlan'] = int(start)
- v['vlanEnd'] = int(end)
- else:
- v['vlan'] = int(vlan[0:vlan.index(' ')])
- flags = []
- if 'PVID' in vlan:
- flags.append('PVID')
- if 'Egress Untagged' in vlan:
- flags.append('Egress Untagged')
- v['flags'] = flags
- except:
- continue
- vlan_json[current_swp].append(v)
- return vlan_json
-
- def bridge_vlan_cache_get(self, ifacename, refresh=False):
- if not self.bridge_vlan_cache_fill_done or refresh:
- self.bridge_vlan_cache = self.bridge_port_vids_get_all_json()
- self.bridge_vlan_cache_fill_done = True
- return self.bridge_vlan_cache.get(ifacename, {})
-
- def bridge_vlan_get_pvid(self, ifacename, refresh=False):
- pvid = 0
-
- for vinfo in self.bridge_vlan_cache_get(ifacename, refresh):
- v = vinfo.get('vlan')
- pvid = v if 'PVID' in vinfo.get('flags', []) else 0
- if pvid:
- return pvid
- return pvid
-
- def bridge_vlan_get_vids(self, ifacename, refresh=False):
- vids = []
-
- for vinfo in self.bridge_vlan_cache_get(ifacename, refresh):
- v = vinfo.get('vlan')
- ispvid = True if 'PVID' in vinfo.get('flags', []) else False
- if ispvid:
- pvid = v if 'PVID' in vinfo.get('flags', []) else 0
- if pvid == 1:
- continue
- vEnd = vinfo.get('vlanEnd')
- if vEnd:
- vids.extend(range(v, vEnd + 1))
- else:
- vids.append(v)
- return vids
-
- def bridge_vlan_get_vids_n_pvid(self, ifacename, refresh=False):
- vids = []
- pvid = 0
-
- for vinfo in self.bridge_vlan_cache_get(ifacename, refresh):
- v = vinfo.get('vlan')
- ispvid = True if 'PVID' in vinfo.get('flags', []) else False
- if ispvid:
- pvid = v if 'PVID' in vinfo.get('flags', []) else 0
- vEnd = vinfo.get('vlanEnd')
- if vEnd:
- vids.extend(range(v, vEnd + 1))
- else:
- vids.append(v)
- return vids, pvid
-
- def bridge_port_pvid_add(self, bridgeportname, pvid):
- if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
- self.add_to_batch('vlan add vid %s untagged pvid dev %s' %
- (pvid, bridgeportname))
- else:
- utils.exec_command('%s vlan add vid %s untagged pvid dev %s' %
- (utils.bridge_cmd,
- pvid, bridgeportname))
-
- def bridge_port_pvid_del(self, bridgeportname, pvid):
- if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
- self.add_to_batch('vlan del vid %s untagged pvid dev %s' %
- (pvid, bridgeportname))
- else:
- utils.exec_command('%s vlan del vid %s untagged pvid dev %s' %
- (utils.bridge_cmd,
- pvid, bridgeportname))
-
- def bridge_port_pvids_get(self, bridgeportname):
- return self.read_file_oneline('/sys/class/net/%s/brport/pvid'
- % bridgeportname)
-
- def bridge_vids_add(self, bridgeportname, vids, bridge=True):
- target = 'self' if bridge else ''
- if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
- [self.add_to_batch('vlan add vid %s dev %s %s' %
- (v, bridgeportname, target)) for v in vids]
- else:
- [utils.exec_command('%s vlan add vid %s dev %s %s' %
- (utils.bridge_cmd,
- v, bridgeportname, target)) for v in vids]
-
- def bridge_vids_del(self, bridgeportname, vids, bridge=True):
- target = 'self' if bridge else ''
- if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
- [self.add_to_batch('vlan del vid %s dev %s %s' %
- (v, bridgeportname, target)) for v in vids]
- else:
- [utils.exec_command('%s vlan del vid %s dev %s %s' %
- (utils.bridge_cmd,
- v, bridgeportname, target)) for v in vids]
-
- @staticmethod
- def bridge_fdb_add(dev, address, vlan=None, bridge=True, remote=None):
- target = 'self' if bridge else ''
- vlan_str = ''
- if vlan:
- vlan_str = 'vlan %s ' % vlan
-
- dst_str = ''
- if remote:
- dst_str = 'dst %s ' % remote
-
- utils.exec_command('%s fdb replace %s dev %s %s %s %s' %
- (utils.bridge_cmd,
- address, dev, vlan_str, target, dst_str))
-
- @staticmethod
- def bridge_fdb_append(dev, address, vlan=None, bridge=True, remote=None):
- target = 'self' if bridge else ''
- vlan_str = ''
- if vlan:
- vlan_str = 'vlan %s ' % vlan
-
- dst_str = ''
- if remote:
- dst_str = 'dst %s ' % remote
-
- utils.exec_command('%s fdb append %s dev %s %s %s %s' %
- (utils.bridge_cmd,
- address, dev, vlan_str, target, dst_str))
-
- @staticmethod
- def bridge_fdb_del(dev, address, vlan=None, bridge=True, remote=None):
- target = 'self' if bridge else ''
- vlan_str = ''
- if vlan:
- vlan_str = 'vlan %s ' % vlan
-
- dst_str = ''
- if remote:
- dst_str = 'dst %s ' % remote
- utils.exec_command('%s fdb del %s dev %s %s %s %s' %
- (utils.bridge_cmd,
- address, dev, vlan_str, target, dst_str))
-
- def bridge_is_vlan_aware(self, bridgename):
- filename = '/sys/class/net/%s/bridge/vlan_filtering' % bridgename
- if os.path.exists(filename) and self.read_file_oneline(filename) == '1':
- return True
- return False
-
- @staticmethod
- def bridge_port_get_bridge_name(bridgeport):
- filename = '/sys/class/net/%s/brport/bridge' % bridgeport
- try:
- return os.path.basename(os.readlink(filename))
- except:
- return None
-
- @staticmethod
- def bridge_port_exists(bridge, bridgeportname):
- try:
- return os.path.exists('/sys/class/net/%s/brif/%s'
- % (bridge, bridgeportname))
- except Exception:
- return False
-
- def bridge_fdb_show_dev(self, dev):
- try:
- fdbs = {}
- output = utils.exec_command('%s fdb show dev %s'
- % (utils.bridge_cmd, dev))
- if output:
- for fdb_entry in output.splitlines():
- try:
- entries = fdb_entry.split()
- fdbs.setdefault(entries[2], []).append(entries[0])
- except:
- self.logger.debug('%s: invalid fdb line \'%s\''
- % (dev, fdb_entry))
- return fdbs
- except Exception:
- return None
-
- @staticmethod
- def is_bridge(bridge):
- return os.path.exists('/sys/class/net/%s/bridge' % bridge)
-
- def is_link_up(self, ifacename):
- ret = False
- try:
- flags = self.read_file_oneline('/sys/class/net/%s/flags' % ifacename)
- iflags = int(flags, 16)
- if iflags & 0x0001:
- ret = True
- except:
- ret = False
- return ret
-
- def ip_route_get_dev(self, prefix, vrf_master=None):
- try:
- if vrf_master:
- cmd = '%s route get %s vrf %s' % (utils.ip_cmd, prefix, vrf_master)
- else:
- cmd = '%s route get %s' % (utils.ip_cmd, prefix)
-
- output = utils.exec_command(cmd)
- if output:
- rline = output.splitlines()[0]
- if rline:
- rattrs = rline.split()
- return rattrs[rattrs.index('dev') + 1]
- except Exception, e:
- self.logger.debug('ip_route_get_dev: failed .. %s' % str(e))
- return None
-
- @staticmethod
- def link_get_lowers(ifacename):
- try:
- lowers = glob.glob("/sys/class/net/%s/lower_*" % ifacename)
- if not lowers:
- return []
- return [os.path.basename(l)[6:] for l in lowers]
- except:
- return []
-
- @staticmethod
- def link_get_uppers(ifacename):
- try:
- uppers = glob.glob("/sys/class/net/%s/upper_*" % ifacename)
- if not uppers:
- return None
- return [os.path.basename(u)[6:] for u in uppers]
- except Exception:
- return None
-
- def link_get_vrfs(self):
- if not LinkUtils._CACHE_FILL_DONE:
- self._fill_cache()
- return linkCache.vrfs
-
- @staticmethod
- def cache_get_info_slave(attrlist):
- try:
- return linkCache.get_attr(attrlist)
- except:
- return None
-
- def get_brport_learning(self, ifacename):
- learn = self.read_file_oneline('/sys/class/net/%s/brport/learning'
- % ifacename)
- if learn and learn == '1':
- return 'on'
- else:
- return 'off'
-
- def get_brport_learning_bool(self, ifacename):
- return utils.get_boolean_from_string(self.read_file_oneline('/sys/class/net/%s/brport/learning' % ifacename))
-
- def set_brport_learning(self, ifacename, learn):
- if learn == 'off':
- return self.write_file('/sys/class/net/%s/brport/learning'
- % ifacename, '0')
- else:
- return self.write_file('/sys/class/net/%s/brport/learning'
- % ifacename, '1')
-
- #################################################################################
- ################################### BOND UTILS ##################################
- #################################################################################
-
- def _link_cache_get(self, attrlist, refresh=False):
- return self._cache_get('link', attrlist, refresh)
-
- def cache_delete(self, attrlist, value=None):
- return self._cache_delete(attrlist, value)
-
- def link_cache_get(self, attrlist, refresh=False):
- return self._link_cache_get(attrlist, refresh)
-
- def link_cache_check(self, attrlist, value, refresh=False):
- return self._link_cache_check(attrlist, value, refresh)
-
- def _link_cache_check(self, attrlist, value, refresh=False):
- try:
- return self._link_cache_get(attrlist, refresh) == value
- except Exception, e:
- self.logger.debug('_cache_check(%s) : [%s]'
- % (str(attrlist), str(e)))
- pass
- return False
-
- bondcmd_attrmap = {
- Link.IFLA_BOND_MODE: 'mode',
- Link.IFLA_BOND_MIIMON: 'miimon',
- Link.IFLA_BOND_USE_CARRIER: 'use_carrier',
- Link.IFLA_BOND_AD_LACP_RATE: 'lacp_rate',
- Link.IFLA_BOND_XMIT_HASH_POLICY: 'xmit_hash_policy',
- Link.IFLA_BOND_MIN_LINKS: 'min_links',
- Link.IFLA_BOND_NUM_PEER_NOTIF: 'num_grat_arp',
- Link.IFLA_BOND_AD_ACTOR_SYSTEM: 'ad_actor_system',
- Link.IFLA_BOND_AD_ACTOR_SYS_PRIO: 'ad_actor_sys_prio',
- Link.IFLA_BOND_AD_LACP_BYPASS: 'lacp_bypass',
- Link.IFLA_BOND_UPDELAY: 'updelay',
- Link.IFLA_BOND_DOWNDELAY: 'downdelay',
- }
-
- def bond_set_attrs_nl(self, bondname, ifla_info_data):
- bond_attr_name = 'None' # for log purpose (in case an exception raised)
- for nl_attr, value in ifla_info_data.items():
- try:
- bond_attr_name = self.bondcmd_attrmap[nl_attr]
- file_path = '/sys/class/net/%s/bonding/%s' % (bondname, bond_attr_name)
- if os.path.exists(file_path):
- self.write_file(file_path, str(value))
- except Exception as e:
- exception_str = '%s: %s %s: %s' % (bondname, bond_attr_name, value, str(e))
- if ifupdownflags.flags.FORCE:
- self.logger.warning(exception_str)
- else:
- self.logger.debug(exception_str)
-
- def bond_set_attrs(self, bondname, attrdict, prehook):
- for attrname, attrval in attrdict.items():
- if (self._link_cache_check([bondname, 'linkinfo',
- attrname], attrval)):
- continue
- if (attrname == 'mode'
- or attrname == 'xmit_hash_policy'
- or attrname == 'lacp_rate' or attrname == 'min_links'):
- if prehook:
- prehook(bondname)
- try:
- if ((attrname not in ['lacp_rate',
- 'lacp_bypass']) or
- self._link_cache_check([bondname, 'linkinfo', 'mode'], '802.3ad',
- True)):
- self.write_file('/sys/class/net/%s/bonding/%s'
- % (bondname, attrname), attrval)
- except Exception, e:
- if ifupdownflags.flags.FORCE:
- self.logger.warn(str(e))
- pass
- else:
- raise
-
- def bond_set_use_carrier(self, bondname, use_carrier):
- if not use_carrier or (use_carrier != '0' and use_carrier != '1'):
- return
- if (self._link_cache_check([bondname, 'linkinfo', 'use_carrier'],
- use_carrier)):
- return
- self.write_file('/sys/class/net/%s' % bondname +
- '/bonding/use_carrier', use_carrier)
- self._cache_update([bondname, 'linkinfo',
- 'use_carrier'], use_carrier)
-
- def bond_get_use_carrier(self, bondname):
- return self._link_cache_get([bondname, 'linkinfo', 'use_carrier'])
-
- def bond_get_use_carrier_nl(self, bondname):
- return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_USE_CARRIER])
-
- def bond_set_xmit_hash_policy(self, bondname, hash_policy, prehook=None):
- valid_values = ['layer2', 'layer3+4', 'layer2+3']
- if not hash_policy:
- return
- if hash_policy not in valid_values:
- raise Exception('invalid hash policy value %s' % hash_policy)
- if (self._link_cache_check([bondname, 'linkinfo', 'xmit_hash_policy'],
- hash_policy)):
- return
- if prehook:
- prehook(bondname)
- self.write_file('/sys/class/net/%s' % bondname +
- '/bonding/xmit_hash_policy', hash_policy)
- self._cache_update([bondname, 'linkinfo', 'xmit_hash_policy'],
- hash_policy)
-
- def bond_get_xmit_hash_policy(self, bondname):
- return self._link_cache_get([bondname, 'linkinfo', 'xmit_hash_policy'])
-
- def bond_get_xmit_hash_policy_nl(self, bondname):
- return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_XMIT_HASH_POLICY])
-
- def bond_set_miimon(self, bondname, miimon):
- if (self._link_cache_check([bondname, 'linkinfo', 'miimon'],
- miimon)):
- return
- self.write_file('/sys/class/net/%s' % bondname +
- '/bonding/miimon', miimon)
- self._cache_update([bondname, 'linkinfo', 'miimon'], miimon)
-
- def bond_get_miimon(self, bondname):
- return self._link_cache_get([bondname, 'linkinfo', 'miimon'])
-
- def bond_get_miimon_nl(self, bondname):
- return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_MIIMON])
-
- def bond_set_mode(self, bondname, mode, prehook=None):
- valid_modes = ['balance-rr', 'active-backup', 'balance-xor',
- 'broadcast', '802.3ad', 'balance-tlb', 'balance-alb']
- if not mode:
- return
- if mode not in valid_modes:
- raise Exception('invalid mode %s' % mode)
- if (self._link_cache_check([bondname, 'linkinfo', 'mode'],
- mode)):
- return
- if prehook:
- prehook(bondname)
- self.write_file('/sys/class/net/%s' % bondname + '/bonding/mode', mode)
- self._cache_update([bondname, 'linkinfo', 'mode'], mode)
-
- def bond_get_mode(self, bondname):
- return self._link_cache_get([bondname, 'linkinfo', 'mode'])
-
- def bond_get_mode_nl(self, bondname):
- return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_MODE])
-
- def bond_set_lacp_rate(self, bondname, lacp_rate, prehook=None, posthook=None):
- if not lacp_rate or (lacp_rate != '0' and lacp_rate != '1'):
- return
- if (self._link_cache_check([bondname, 'linkinfo', 'lacp_rate'],
- lacp_rate)):
- return
- if prehook:
- prehook(bondname)
- try:
- self.write_file('/sys/class/net/%s' % bondname +
- '/bonding/lacp_rate', lacp_rate)
- except:
- raise
- finally:
- if posthook:
- prehook(bondname)
- self._cache_update([bondname, 'linkinfo',
- 'lacp_rate'], lacp_rate)
-
- def bond_get_lacp_rate(self, bondname):
- return self._link_cache_get([bondname, 'linkinfo', 'lacp_rate'])
-
- def bond_get_lacp_rate_nl(self, bondname):
- return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_AD_LACP_RATE])
-
- def bond_set_lacp_bypass_allow(self, bondname, allow, prehook=None, posthook=None):
- if self._link_cache_check([bondname, 'linkinfo', 'lacp_bypass'], allow):
- return
- if prehook:
- prehook(bondname)
- try:
- self.write_file('/sys/class/net/%s' % bondname +
- '/bonding/lacp_bypass', allow)
- except:
- raise
- finally:
- if posthook:
- posthook(bondname)
- self._cache_update([bondname, 'linkinfo',
- 'lacp_bypass'], allow)
-
- def bond_get_lacp_bypass_allow(self, bondname):
- return self._link_cache_get([bondname, 'linkinfo', 'lacp_bypass'])
-
- def bond_get_lacp_bypass_allow_nl(self, bondname):
- return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_AD_LACP_BYPASS])
-
- def bond_set_min_links(self, bondname, min_links, prehook=None):
- if (self._link_cache_check([bondname, 'linkinfo', 'min_links'],
- min_links)):
- return
- if prehook:
- prehook(bondname)
- self.write_file('/sys/class/net/%s/bonding/min_links' % bondname,
- min_links)
- self._cache_update([bondname, 'linkinfo', 'min_links'], min_links)
-
- def bond_get_min_links(self, bondname):
- return self._link_cache_get([bondname, 'linkinfo', 'min_links'])
-
- def get_min_links_nl(self, bondname):
- return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_MIN_LINKS])
-
- def bond_get_ad_actor_system(self, bondname):
- return self._link_cache_get([bondname, 'linkinfo', 'ad_actor_system'])
-
- def bond_get_ad_actor_system_nl(self, bondname):
- return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_AD_ACTOR_SYSTEM])
-
- def bond_get_ad_actor_sys_prio(self, bondname):
- return self._link_cache_get([bondname, 'linkinfo', 'ad_actor_sys_prio'])
-
- def bond_get_ad_actor_sys_prio_nl(self, bondname):
- return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_AD_ACTOR_SYS_PRIO])
-
- def bond_get_num_unsol_na(self, bondname):
- return self._link_cache_get([bondname, 'linkinfo', 'num_unsol_na'])
-
- def bond_get_num_unsol_na_nl(self, bondname):
- return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_NUM_PEER_NOTIF])
-
- def bond_get_num_grat_arp(self, bondname):
- return self._link_cache_get([bondname, 'linkinfo', 'num_grat_arp'])
-
- def bond_get_num_grat_arp_nl(self, bondname):
- return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_NUM_PEER_NOTIF])
-
- def bond_get_updelay(self, bondname):
- return self._link_cache_get([bondname, 'linkinfo', 'updelay'])
-
- def bond_get_updelay_nl(self, bondname):
- return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_UPDELAY])
-
- def bond_get_downdelay(self, bondname):
- return self._link_cache_get([bondname, 'linkinfo', 'downdelay'])
-
- def bond_get_downdelay_nl(self, bondname):
- return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_DOWNDELAY])
-
- def bond_enslave_slave(self, bondname, slave, prehook=None, posthook=None):
- slaves = self._link_cache_get([bondname, 'linkinfo', 'slaves'])
- if slaves and slave in slaves:
- return
- if prehook:
- prehook(slave)
- self.write_file('/sys/class/net/%s' % bondname +
- '/bonding/slaves', '+' + slave)
- if posthook:
- posthook(slave)
- self._cache_update([bondname, 'linkinfo', 'slaves'], slave)
-
- def bond_remove_slave(self, bondname, slave):
- slaves = self._link_cache_get([bondname, 'linkinfo', 'slaves'])
- if not slaves or slave not in slaves:
- return
- sysfs_bond_path = ('/sys/class/net/%s' % bondname +
- '/bonding/slaves')
- if not os.path.exists(sysfs_bond_path):
- return
- self.write_file(sysfs_bond_path, '-' + slave)
- self._cache_delete([bondname, 'linkinfo', 'slaves'], slave)
-
- def bond_remove_slaves_all(self, bondname):
- if not self._link_cache_get([bondname, 'linkinfo', 'slaves']):
- return
- slaves = None
- sysfs_bond_path = ('/sys/class/net/%s' % bondname +
- '/bonding/slaves')
- try:
- with open(sysfs_bond_path, 'r') as f:
- slaves = f.readline().strip().split()
- except IOError, e:
- raise Exception('error reading slaves of bond %s (%s)' % (bondname, str(e)))
- for slave in slaves:
- self.link_down(slave)
- try:
- self.bond_remove_slave(bondname, slave)
- except Exception, e:
- if not ifupdownflags.flags.FORCE:
- raise Exception('error removing slave %s from bond %s (%s)' % (slave, bondname, str(e)))
- else:
- pass
- self._cache_delete([bondname, 'linkinfo', 'slaves'])
-
- @staticmethod
- def bond_load_bonding_module():
- return utils.exec_command('%s -q bonding' % utils.modprobe_cmd)
-
- def create_bond(self, bondname):
- if self.bond_exists(bondname):
- return
- # load_bonding_module() has already been run
- self.write_file('/sys/class/net/bonding_masters', '+' + bondname)
- self._cache_update([bondname], {})
-
- def delete_bond(self, bondname):
- if not os.path.exists('/sys/class/net/%s' % bondname):
- return
- self.write_file('/sys/class/net/bonding_masters', '-' + bondname)
- self._cache_delete([bondname])
-
- def bond_get_slaves(self, bondname):
- slaves = self._link_cache_get([bondname, 'linkinfo', 'slaves'])
- if slaves:
- return list(slaves)
- slavefile = '/sys/class/net/%s/bonding/slaves' % bondname
- if os.path.exists(slavefile):
- buf = self.read_file_oneline(slavefile)
- if buf:
- slaves = buf.split()
- if not slaves:
- return []
- self._cache_update([bondname, 'linkinfo', 'slaves'], slaves)
- return list(slaves)
-
- def bond_slave_exists(self, bond, slave):
- slaves = self.bond_get_slaves(bond)
- if not slaves:
- return False
- return slave in slaves
-
- @staticmethod
- def bond_exists(bondname):
- return os.path.exists('/sys/class/net/%s/bonding' % bondname)
-
- #################################################################################
- ################################## BRIDGE UTILS #################################
- #################################################################################
-
- def create_bridge(self, bridgename):
- if not LinkUtils.bridge_utils_is_installed:
- return
- if self.bridge_exists(bridgename):
- return
- utils.exec_command('%s addbr %s' % (utils.brctl_cmd, bridgename))
- self._cache_update([bridgename], {})
-
- def delete_bridge(self, bridgename):
- if not LinkUtils.bridge_utils_is_installed:
- return
- if not self.bridge_exists(bridgename):
- return
- utils.exec_command('%s delbr %s' % (utils.brctl_cmd, bridgename))
- self._cache_invalidate()
-
- def add_bridge_port(self, bridgename, bridgeportname):
- """ Add port to bridge """
- if not LinkUtils.bridge_utils_is_installed:
- return
- ports = self._link_cache_get([bridgename, 'linkinfo', 'ports'])
- if ports and ports.get(bridgeportname):
- return
- utils.exec_command('%s addif %s %s' % (utils.brctl_cmd, bridgename, bridgeportname))
- self._cache_update([bridgename, 'linkinfo', 'ports', bridgeportname], {})
-
- def delete_bridge_port(self, bridgename, bridgeportname):
- """ Delete port from bridge """
- if not LinkUtils.bridge_utils_is_installed:
- return
- ports = self._link_cache_get([bridgename, 'linkinfo', 'ports'])
- if not ports or not ports.get(bridgeportname):
- return
- utils.exec_command('%s delif %s %s' % (utils.brctl_cmd, bridgename, bridgeportname))
- self._cache_delete([bridgename, 'linkinfo', 'ports', 'bridgeportname'])
-
- def set_bridgeport_attrs(self, bridgename, bridgeportname, attrdict):
- portattrs = self._link_cache_get([bridgename, 'linkinfo', 'ports', bridgeportname])
- if portattrs == None:
- portattrs = {}
- for k, v in attrdict.iteritems():
- if ifupdownflags.flags.CACHE:
- curval = portattrs.get(k)
- if curval and curval == v:
- continue
- if k == 'unicast-flood':
- self.write_file('/sys/class/net/%s/brport/unicast_flood' % bridgeportname, v)
- elif k == 'multicast-flood':
- self.write_file('/sys/class/net/%s/brport/multicast_flood' % bridgeportname, v)
- elif k == 'learning':
- self.write_file('/sys/class/net/%s/brport/learning' % bridgeportname, v)
- elif k == 'arp-nd-suppress':
- self.write_file('/sys/class/net/%s/brport/neigh_suppress' % bridgeportname, v)
- else:
- if not LinkUtils.bridge_utils_is_installed:
- continue
- utils.exec_command('%s set%s %s %s %s' % (utils.brctl_cmd, k, bridgename, bridgeportname, v))
-
- def set_bridgeport_attr(self, bridgename, bridgeportname,
- attrname, attrval):
- if not LinkUtils.bridge_utils_is_installed:
- return
- if self._link_cache_check([bridgename, 'linkinfo', 'ports', bridgeportname, attrname], attrval):
- return
- utils.exec_command('%s set%s %s %s %s' %
- (utils.brctl_cmd,
- attrname,
- bridgename,
- bridgeportname,
- attrval))
-
- def set_bridge_attrs(self, bridgename, attrdict):
- for k, v in attrdict.iteritems():
- if not v:
- continue
- if self._link_cache_check([bridgename, 'linkinfo', k], v):
- continue
- try:
- if k == 'igmp-version':
- self.write_file('/sys/class/net/%s/bridge/'
- 'multicast_igmp_version' % bridgename, v)
- elif k == 'mld-version':
- self.write_file('/sys/class/net/%s/bridge/'
- 'multicast_mld_version' % bridgename, v)
- elif k == 'vlan-protocol':
- self.write_file('/sys/class/net/%s/bridge/'
- 'vlan_protocol' % bridgename,
- VlanProtocols.ETHERTYPES_TO_ID.get(v.upper(),
- None))
- elif k == 'vlan-stats':
- self.write_file('/sys/class/net/%s/bridge/'
- 'vlan_stats_enabled' % bridgename, v)
- elif k == 'mcstats':
- self.write_file('/sys/class/net/%s/bridge/'
- 'multicast_stats_enabled' % bridgename, v)
- else:
- if not LinkUtils.bridge_utils_is_installed:
- continue
- cmd = ('%s set%s %s %s' %
- (utils.brctl_cmd, k, bridgename, v))
- utils.exec_command(cmd)
- except Exception, e:
- self.logger.warn('%s: %s' % (bridgename, str(e)))
- pass
-
- def set_bridge_attr(self, bridgename, attrname, attrval):
- if self._link_cache_check([bridgename, 'linkinfo', attrname], attrval):
- return
- if attrname == 'igmp-version':
- self.write_file('/sys/class/net/%s/bridge/multicast_igmp_version'
- % bridgename, attrval)
- elif attrname == 'mld-version':
- self.write_file('/sys/class/net/%s/bridge/multicast_mld_version'
- % bridgename, attrval)
- elif attrname == 'vlan-protocol':
- self.write_file('/sys/class/net/%s/bridge/vlan_protocol'
- % bridgename, VlanProtocols.ETHERTYPES_TO_ID[attrval.upper()])
- elif attrname == 'vlan-stats':
- self.write_file('/sys/class/net/%s/bridge/vlan_stats_enabled'
- % bridgename, attrval)
- elif attrname == 'mcstats':
- self.write_file('/sys/class/net/%s/bridge/multicast_stats_enabled'
- % bridgename, attrval)
- else:
- if not LinkUtils.bridge_utils_is_installed:
- return
- cmd = '%s set%s %s %s' % (utils.brctl_cmd,
- attrname, bridgename, attrval)
- utils.exec_command(cmd)
-
- def get_bridge_attrs(self, bridgename):
- attrs = self._link_cache_get([bridgename, 'linkinfo'])
- no_ints_attrs = {}
- for key, value in attrs.items():
- if type(key) == str:
- no_ints_attrs[key] = value
- return no_ints_attrs
-
- def get_bridgeport_attrs(self, bridgename, bridgeportname):
- return self._link_cache_get([bridgename, 'linkinfo', 'ports',
- bridgeportname])
-
- def get_bridgeport_attr(self, bridgename, bridgeportname, attrname):
- return self._link_cache_get([bridgename, 'linkinfo', 'ports',
- bridgeportname, attrname])
-
- @staticmethod
- def bridge_set_stp(bridge, stp_state):
- if not LinkUtils.bridge_utils_is_installed:
- return
- utils.exec_command('%s stp %s %s' % (utils.brctl_cmd, bridge, stp_state))
-
- def bridge_get_stp(self, bridge):
- sysfs_stpstate = '/sys/class/net/%s/bridge/stp_state' % bridge
- if not os.path.exists(sysfs_stpstate):
- return 'error'
- stpstate = self.read_file_oneline(sysfs_stpstate)
- if not stpstate:
- return 'error'
- try:
- if int(stpstate) > 0:
- return 'yes'
- elif int(stpstate) == 0:
- return 'no'
- except:
- return 'unknown'
-
- @staticmethod
- def _conv_value_to_user(s):
- try:
- ret = int(s) / 100
- return '%d' % ret
- except:
- return None
-
- def read_value_from_sysfs(self, filename, preprocess_func):
- value = self.read_file_oneline(filename)
- if not value:
- return None
- return preprocess_func(value)
-
- @staticmethod
- def bridge_set_ageing(bridge, ageing):
- if not LinkUtils.bridge_utils_is_installed:
- return
- utils.exec_command('%s setageing %s %s' % (utils.brctl_cmd, bridge, ageing))
-
- def bridge_get_ageing(self, bridge):
- return self.read_value_from_sysfs('/sys/class/net/%s/bridge/ageing_time'
- % bridge, self._conv_value_to_user)
-
- @staticmethod
- def set_bridgeprio(bridge, prio):
- if not LinkUtils.bridge_utils_is_installed:
- return
- utils.exec_command('%s setbridgeprio %s %s' % (utils.brctl_cmd, bridge, prio))
-
- def get_bridgeprio(self, bridge):
- return self.read_file_oneline(
- '/sys/class/net/%s/bridge/priority' % bridge)
-
- @staticmethod
- def bridge_set_fd(bridge, fd):
- if not LinkUtils.bridge_utils_is_installed:
- return
- utils.exec_command('%s setfd %s %s' % (utils.brctl_cmd, bridge, fd))
-
- def bridge_get_fd(self, bridge):
- return self.read_value_from_sysfs(
- '/sys/class/net/%s/bridge/forward_delay'
- % bridge, self._conv_value_to_user)
-
- def bridge_set_gcint(self, bridge, gcint):
- raise Exception('set_gcint not implemented')
-
- @staticmethod
- def bridge_set_hello(bridge, hello):
- if not LinkUtils.bridge_utils_is_installed:
- return
- utils.exec_command('%s sethello %s %s' % (utils.brctl_cmd, bridge, hello))
-
- def bridge_get_hello(self, bridge):
- return self.read_value_from_sysfs('/sys/class/net/%s/bridge/hello_time'
- % bridge, self._conv_value_to_user)
-
- @staticmethod
- def bridge_set_maxage(bridge, maxage):
- if not LinkUtils.bridge_utils_is_installed:
- return
- utils.exec_command('%s setmaxage %s %s' % (utils.brctl_cmd, bridge, maxage))
-
- def bridge_get_maxage(self, bridge):
- return self.read_value_from_sysfs('/sys/class/net/%s/bridge/max_age'
- % bridge, self._conv_value_to_user)
-
- @staticmethod
- def bridge_set_pathcost(bridge, port, pathcost):
- if not LinkUtils.bridge_utils_is_installed:
- return
- utils.exec_command('%s setpathcost %s %s %s' % (utils.brctl_cmd, bridge, port, pathcost))
-
- def bridge_get_pathcost(self, bridge, port):
- return self.read_file_oneline('/sys/class/net/%s/brport/path_cost'
- % port)
-
- @staticmethod
- def bridge_set_portprio(bridge, port, prio):
- if not LinkUtils.bridge_utils_is_installed:
- return
- utils.exec_command('%s setportprio %s %s %s' % (utils.brctl_cmd, bridge, port, prio))
-
- def bridge_get_portprio(self, bridge, port):
- return self.read_file_oneline('/sys/class/net/%s/brport/priority'
- % port)
-
- @staticmethod
- def bridge_set_hashmax(bridge, hashmax):
- if not LinkUtils.bridge_utils_is_installed:
- return
- utils.exec_command('%s sethashmax %s %s' % (utils.brctl_cmd, bridge, hashmax))
-
- def bridge_get_hashmax(self, bridge):
- return self.read_file_oneline('/sys/class/net/%s/bridge/hash_max'
- % bridge)
-
- @staticmethod
- def bridge_set_hashel(bridge, hashel):
- if not LinkUtils.bridge_utils_is_installed:
- return
- utils.exec_command('%s sethashel %s %s' % (utils.brctl_cmd, bridge, hashel))
-
- def bridge_get_hashel(self, bridge):
- return self.read_file_oneline('/sys/class/net/%s/bridge/hash_elasticity'
- % bridge)
-
- @staticmethod
- def bridge_set_mclmc(bridge, mclmc):
- if not LinkUtils.bridge_utils_is_installed:
- return
- utils.exec_command('%s setmclmc %s %s' % (utils.brctl_cmd, bridge, mclmc))
-
- def bridge_get_mclmc(self, bridge):
- return self.read_file_oneline(
- '/sys/class/net/%s/bridge/multicast_last_member_count'
- % bridge)
-
- @staticmethod
- def bridge_set_mcrouter(bridge, mcrouter):
- if not LinkUtils.bridge_utils_is_installed:
- return
- utils.exec_command('%s setmcrouter %s %s' % (utils.brctl_cmd, bridge, mcrouter))
-
- def bridge_get_mcrouter(self, bridge):
- return self.read_file_oneline(
- '/sys/class/net/%s/bridge/multicast_router' % bridge)
-
- @staticmethod
- def bridge_set_mcsnoop(bridge, mcsnoop):
- if not LinkUtils.bridge_utils_is_installed:
- return
- utils.exec_command('%s setmcsnoop %s %s' % (utils.brctl_cmd, bridge, mcsnoop))
-
- def bridge_get_mcsnoop(self, bridge):
- return self.read_file_oneline(
- '/sys/class/net/%s/bridge/multicast_snooping' % bridge)
-
- @staticmethod
- def bridge_set_mcsqc(bridge, mcsqc):
- if not LinkUtils.bridge_utils_is_installed:
- return
- utils.exec_command('%s setmcsqc %s %s' % (utils.brctl_cmd, bridge, mcsqc))
-
- def bridge_get_mcsqc(self, bridge):
- return self.read_file_oneline(
- '/sys/class/net/%s/bridge/multicast_startup_query_count'
- % bridge)
-
- @staticmethod
- def bridge_set_mcqifaddr(bridge, mcqifaddr):
- if not LinkUtils.bridge_utils_is_installed:
- return
- utils.exec_command('%s setmcqifaddr %s %s' % (utils.brctl_cmd, bridge, mcqifaddr))
-
- def bridge_get_mcqifaddr(self, bridge):
- return self.read_file_oneline(
- '/sys/class/net/%s/bridge/multicast_startup_query_use_ifaddr'
- % bridge)
-
- @staticmethod
- def bridge_set_mcquerier(bridge, mcquerier):
- if not LinkUtils.bridge_utils_is_installed:
- return
- utils.exec_command('%s setmcquerier %s %s' % (utils.brctl_cmd, bridge, mcquerier))
-
- def bridge_get_mcquerier(self, bridge):
- return self.read_file_oneline(
- '/sys/class/net/%s/bridge/multicast_querier' % bridge)
-
- def bridge_set_mcqv4src(self, bridge, vlan, mcquerier):
- try:
- vlan = int(vlan)
- except:
- self.logger.info('%s: set mcqv4src vlan: invalid parameter %s: %s' %(bridge, vlan, str(e)))
- return
- if vlan == 0 or vlan > 4095:
- self.logger.warn('mcqv4src vlan \'%d\' invalid range' % vlan)
- return
-
- ip = mcquerier.split('.')
- if len(ip) != 4:
- self.logger.warn('mcqv4src \'%s\' invalid IPv4 address' % mcquerier)
- return
- for k in ip:
- if not k.isdigit() or int(k, 10) < 0 or int(k, 10) > 255:
- self.logger.warn('mcqv4src \'%s\' invalid IPv4 address' % mcquerier)
- return
-
- if not LinkUtils.bridge_utils_is_installed:
- return
-
- utils.exec_command('%s setmcqv4src %s %d %s' %
- (utils.brctl_cmd, bridge, vlan, mcquerier))
-
- def bridge_del_mcqv4src(self, bridge, vlan):
- if not LinkUtils.bridge_utils_is_installed:
- return
- try:
- vlan = int(vlan)
- except:
- self.logger.info('%s: del mcqv4src vlan: invalid parameter %s: %s' %(bridge, vlan, str(e)))
- return
- utils.exec_command('%s delmcqv4src %s %d' % (utils.brctl_cmd, bridge, vlan))
-
- def bridge_get_mcqv4src(self, bridge, vlan=None):
- if not LinkUtils.bridge_utils_is_installed:
- return {}
- if not self.supported_command['showmcqv4src']:
- return {}
- mcqv4src = {}
- try:
- mcqout = utils.exec_command('%s showmcqv4src %s' %
- (utils.brctl_cmd, bridge))
- except Exception as e:
- s = str(e).lower()
- if 'never heard' in s:
- msg = ('%s showmcqv4src: skipping unsupported command'
- % utils.brctl_cmd)
- self.logger.info(msg)
- self.supported_command['showmcqv4src'] = False
- return {}
- raise
- if not mcqout:
- return {}
- mcqlines = mcqout.splitlines()
- for l in mcqlines[1:]:
- l = l.strip()
- k, d, v = l.split('\t')
- if not k or not v:
- continue
- mcqv4src[k] = v
- if vlan:
- return mcqv4src.get(vlan)
- return mcqv4src
-
- def bridge_get_mcqv4src_sysfs(self, bridge, vlan=None):
- if not LinkUtils.bridge_utils_is_installed:
- return {}
- if not self.supported_command['showmcqv4src']:
- return {}
- if ifupdownflags.flags.PERFMODE:
- return {}
- mcqv4src = {}
- try:
- filename = '/sys/class/net/%s/bridge/multicast_v4_queriers' % bridge
- if os.path.exists(filename):
- for line in self.read_file(filename) or []:
- vlan_id, ip = line.split('=')
- mcqv4src[vlan_id] = ip.strip()
- except Exception as e:
- s = str(e).lower()
- msg = ('%s showmcqv4src: skipping unsupported command'
- % utils.brctl_cmd)
- self.logger.info(msg)
- self.supported_command['showmcqv4src'] = False
- return {}
- if vlan:
- return mcqv4src.get(vlan)
- return mcqv4src
-
- @staticmethod
- def bridge_set_mclmi(bridge, mclmi):
- if not LinkUtils.bridge_utils_is_installed:
- return
- utils.exec_command('%s setmclmi %s %s' % (utils.brctl_cmd, bridge, mclmi))
-
- def bridge_get_mclmi(self, bridge):
- return self.read_file_oneline(
- '/sys/class/net/%s/bridge/multicast_last_member_interval'
- % bridge)
-
- @staticmethod
- def bridge_set_mcmi(bridge, mcmi):
- if not LinkUtils.bridge_utils_is_installed:
- return
- utils.exec_command('%s setmcmi %s %s' % (utils.brctl_cmd, bridge, mcmi))
-
- def bridge_get_mcmi(self, bridge):
- return self.read_file_oneline(
- '/sys/class/net/%s/bridge/multicast_membership_interval'
- % bridge)
-
- @staticmethod
- def bridge_exists(bridge):
- return os.path.exists('/sys/class/net/%s/bridge' % bridge)
-
- @staticmethod
- def is_bridge_port(ifacename):
- return os.path.exists('/sys/class/net/%s/brport' % ifacename)
-
- @staticmethod
- def bridge_port_exists(bridge, bridgeportname):
- try:
- return os.path.exists('/sys/class/net/%s/brif/%s' % (bridge, bridgeportname))
- except:
- return False
-
- @staticmethod
- def get_bridge_ports(bridgename):
- try:
- return os.listdir('/sys/class/net/%s/brif/' % bridgename)
- except:
- return []
-
- def reset_addr_cache(self, ifname):
- try:
- linkCache.links[ifname]['addrs'] = {}
- self.logger.debug('%s: reset address cache' % ifname)
- except:
- pass
-
- def get_ipv6_addrgen_mode(self, ifname):
- try:
- return self._cache_get('link', [ifname, 'af_spec', socket.AF_INET6])[Link.IFLA_INET6_ADDR_GEN_MODE]
- except:
- # default to 0 (eui64)
- return 0
-
- def ipv6_addrgen(self, ifname, addrgen, link_created):
- try:
- # IFLA_INET6_ADDR_GEN_MODE values:
- # 0 = eui64
- # 1 = none
- if self._link_cache_get([ifname, 'af_spec', socket.AF_INET6])[Link.IFLA_INET6_ADDR_GEN_MODE] == addrgen:
- self.logger.debug('%s: ipv6 addrgen already %s' % (ifname, 'off' if addrgen else 'on'))
- return
-
- disabled_ipv6 = self.read_file_oneline('/proc/sys/net/ipv6/conf/%s/disable_ipv6' % ifname)
- if not disabled_ipv6 or int(disabled_ipv6) == 1:
- self.logger.info('%s: cannot set addrgen: ipv6 is disabled on this device' % ifname)
- return
-
- if int(self._link_cache_get([ifname, 'mtu'])) < 1280:
- self.logger.info('%s: ipv6 addrgen is disabled on device with MTU '
- 'lower than 1280: cannot set addrgen %s' % (ifname, 'off' if addrgen else 'on'))
- return
- except (KeyError, TypeError):
- self.logger.debug('%s: ipv6 addrgen probably not supported or disabled on this device' % ifname)
- return
- except Exception:
- pass
-
- if not link_created:
- # When setting addrgenmode it is necessary to flap the macvlan
- # device. After flapping the device we also need to re-add all
- # the user configuration. The best way to add the user config
- # is to flush our internal address cache
- self.reset_addr_cache(ifname)
-
- cmd = 'link set dev %s addrgenmode %s' % (ifname, Link.ifla_inet6_addr_gen_mode_dict.get(addrgen))
-
- is_link_up = self.is_link_up(ifname)
-
- if is_link_up:
- self.link_down(ifname)
-
- #if LinkUtils.ipbatch:
- # self.add_to_batch(cmd)
- #else:
- # because this command might fail on older kernel its better to not batch it
- utils.exec_command('%s %s' % (utils.ip_cmd, cmd))
-
- if is_link_up:
- self.link_up(ifname)
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
-import pprint
-
class MSTPAttrsCache():
bridges = {}
@classmethod
def invalidate(cls):
MSTPAttrsCache.bridges = {}
-
-
-class linkCache():
- """ This class contains methods and instance variables to cache
- link info """
-
- """ { <ifacename> : { 'ifindex': <index>,
- 'mtu': <mtu>,
- 'state' : <state>',
- 'flags' : <flags>,
- 'kind' : <kind: bridge, bond, vlan>,
- 'linkinfo' : {<attr1> : <attrval1>,
- <attr2> : <attrval2>,
- <ports> : {
- } """
- links = {}
- vrfs = {}
-
- @classmethod
- def get_attr(cls, mapList):
- return reduce(lambda d, k: d[k], mapList, linkCache.links)
-
- @classmethod
- def set_attr(cls, mapList, value):
- cls.get_attr(mapList[:-1])[mapList[-1]] = value
-
- @classmethod
- def del_attr(cls, mapList):
- try:
- del cls.get_attr(mapList[:-1])[mapList[-1]]
- except:
- pass
-
- @classmethod
- def update_attrdict(cls, mapList, valuedict):
- try:
- cls.get_attr(mapList[:-1])[mapList[-1]].update(valuedict)
- except:
- cls.get_attr(mapList[:-1])[mapList[-1]] = valuedict
- pass
-
- @classmethod
- def append_to_attrlist(cls, mapList, value):
- cls.get_attr(mapList[:-1])[mapList[-1]].append(value)
-
- @classmethod
- def remove_from_attrlist(cls, mapList, value):
- try:
- cls.get_attr(mapList[:-1])[mapList[-1]].remove(value)
- except:
- pass
-
- @classmethod
- def check_attr(cls, attrlist, value=None):
- try:
- cachedvalue = cls.get_attr(attrlist)
- if value:
- if cachedvalue == value:
- return True
- else:
- return False
- elif cachedvalue:
- return True
- else:
- return False
- except:
- return False
-
- @classmethod
- def invalidate(cls):
- cls.links = {}
-
- @classmethod
- def reset(cls):
- cls.invalidate()
- cls.vrfs = {}
-
- @classmethod
- def dump(cls):
- print 'Dumping link cache'
- pp = pprint.PrettyPrinter(indent=4)
- pp.pprint(cls.links)
-
- @classmethod
- def dump_link(cls, linkname):
- print 'Dumping link %s' % linkname
- pp = pprint.PrettyPrinter(indent=4)
- pp.pprint(cls.links.get(linkname))
#
import os
+import errno
try:
from ifupdown2.ifupdown.utils import utils
def _pid_exists(self, pidfilename):
if os.path.exists(pidfilename):
- pid = self.read_file_oneline(pidfilename)
- if not os.path.exists('/proc/%s' %pid):
+ try:
+ return os.readlink(
+ "/proc/%s/exe" % self.read_file_oneline(pidfilename)
+ ).endswith("dhclient")
+ except OSError as e:
+ try:
+ if e.errno == errno.EACCES:
+ return os.path.exists("/proc/%s" % self.read_file_oneline(pidfilename))
+ except:
+ return False
+ except:
return False
- else:
- return False
- return True
+ return False
def is_running(self, ifacename):
return self._pid_exists('/run/dhclient.%s.pid' %ifacename)
def __init__(self, *args, **kargs):
utilsBase.__init__(self, *args, **kargs)
+ self.__batch = []
+ self.__batch_mode = False
+
+ def __add_to_batch(self, cmd):
+ self.__batch.append(cmd)
+
+ def __execute_or_batch(self, cmd):
+ if self.__batch_mode:
+ self.__add_to_batch(cmd)
+ else:
+ utils.exec_command("%s %s" % (utils.mstpctl_cmd, cmd))
+
+ def __execute_or_batch_dry_run(self, cmd):
+ """
+ The batch function has it's own dryrun handler so we only handle
+ dryrun for non-batch mode. Which will be removed once the "utils"
+ module has it's own dryrun handlers
+ """
+ if self.__batch_mode:
+ self.__add_to_batch(cmd)
+ else:
+ self.logger.info("DRY-RUN: executing: %s %s" % (utils.mstpctl_cmd, cmd))
+
+ def batch_start(self):
+ if not self.__batch_mode:
+ self.__batch_mode = True
+ self.__batch = []
+
+ def batch_commit(self):
+ if not self.__batch_mode or not self.__batch:
+ return
+ try:
+ utils.exec_command(
+ "%s batch -" % utils.mstpctl_cmd,
+ stdin="\n".join(self.__batch)
+ )
+ except:
+ raise
+ finally:
+ self.__batch_mode = False
+ del self.__batch
+ self.__batch = None
+
+ ###############################################################################
+ ###############################################################################
+ ###############################################################################
+
@classmethod
def reset(cls):
cls._cache_fill_done = False
except Exception as e:
self.logger.info(str(e))
return mstpctl_bridgeport_attrs_dict
+ portname = bridgename # assigning portname to avoid an exception, in the exception handler
try:
mstpctl_bridge_cache = json.loads(output.strip('\n'))
for portname in mstpctl_bridge_cache.keys():
mstpctl_bridgeport_attrs_dict[portname][jsonAttr] = str(jsonVal)
MSTPAttrsCache.set(bridgename, mstpctl_bridgeport_attrs_dict)
except Exception as e:
- self.logger.info('%s: cannot fetch mstpctl bridge port attributes: %s' % str(e))
+ self.logger.info('%s: cannot fetch mstpctl bridge port attributes: %s' % (portname, str(e)))
mstpctl_bridge_attrs_dict = {}
try:
del mstpctl_bridge_attrs_dict['bridgeId']
MSTPAttrsCache.bridges[bridgename].update(mstpctl_bridge_attrs_dict)
except Exception as e:
- self.logger.info('%s: cannot fetch mstpctl bridge attributes: %s' % str(e))
+ self.logger.info('%s: cannot fetch mstpctl bridge attributes: %s' % (bridgename, str(e)))
return MSTPAttrsCache.get(bridgename)
def get_bridge_ports_attrs(self, bridgename):
if cache_value and cache_value == value:
return
if attrname == 'treeportcost' or attrname == 'treeportprio':
- utils.exec_commandl([utils.mstpctl_cmd, 'set%s' % attrname,
- bridgename, portname, '0', value])
+ self.__execute_or_batch("set%s %s %s 0 %s" % (attrname, bridgename, portname, value))
else:
- utils.exec_commandl([utils.mstpctl_cmd, 'set%s' % attrname,
- bridgename, portname, value])
+ self.__execute_or_batch("set%s %s %s %s" % (attrname, bridgename, portname, value))
if json_attr:
self.update_bridge_port_cache(bridgename, portname, json_attr, value)
self._bridge_jsonAttr_map[attrname])
if attrvalue_curr and attrvalue_curr == attrvalue:
return
+
if attrname == 'treeprio':
- utils.exec_commandl([utils.mstpctl_cmd, 'set%s' % attrname,
- '%s' % bridgename, '0', '%s' % attrvalue], stderr=None)
+ self.__execute_or_batch("set%s %s 0 %s" % (attrname, bridgename, attrvalue))
self.update_bridge_cache(bridgename, attrname, str(attrvalue))
else:
- utils.exec_commandl([utils.mstpctl_cmd, 'set%s' % attrname,
- '%s' % bridgename, '%s' % attrvalue], stderr=None)
+ self.__execute_or_batch("set%s %s %s" % (attrname, bridgename, attrvalue))
self.update_bridge_cache(bridgename,
self._bridge_jsonAttr_map[attrname],
str(attrvalue))
attrvalue_curr = self.get_bridge_treeprio(bridgename)
if attrvalue_curr and attrvalue_curr == attrvalue:
return
- utils.exec_commandl([utils.mstpctl_cmd,
- 'settreeprio', bridgename, '0',
- str(attrvalue)])
+ self.__execute_or_batch("settreeprio %s 0 %s" % (bridgename, str(attrvalue)))
+
self.update_bridge_cache(bridgename, 'treeprio', str(attrvalue))
def showbridge(self, bridgename=None):
--- /dev/null
+# Copyright (C) 2017, 2018 Cumulus Networks, Inc. all rights reserved
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; version 2.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# https://www.gnu.org/licenses/gpl-2.0-standalone.html
+#
+# Author:
+# Julien Fortin, julien@cumulusnetworks.com
+#
+# addon -- Addon base class
+#
+
+import logging
+
+try:
+ from ifupdown2.lib.io import IO
+ from ifupdown2.lib.sysfs import Sysfs
+ from ifupdown2.lib.iproute2 import IPRoute2
+ from ifupdown2.lib.base_objects import Netlink, Cache, Requirements
+except ImportError:
+ from lib.io import IO
+ from lib.sysfs import Sysfs
+ from lib.iproute2 import IPRoute2
+ from lib.base_objects import Netlink, Cache, Requirements
+
+
+class Addon(Netlink, Cache):
+ """
+ Base class for ifupdown2 addon modules
+ Provides common infrastructure methods for all addon modules
+ """
+
+ def __init__(self):
+ Netlink.__init__(self)
+ Cache.__init__(self)
+
+ self.logger = logging.getLogger("ifupdown2.addons.%s" % self.__class__.__name__)
+
+ self.io = IO()
+ self.sysfs = Sysfs
+ self.iproute2 = IPRoute2()
+ self.requirements = Requirements()
--- /dev/null
+# Copyright (C) 2017, 2018 Cumulus Networks, Inc. all rights reserved
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; version 2.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# https://www.gnu.org/licenses/gpl-2.0-standalone.html
+#
+# Author:
+# Julien Fortin, julien@cumulusnetworks.com
+#
+# base_objects -- Base classes used by higher level classes
+#
+
+import os
+import logging
+
+try:
+ from ifupdown2.lib.dry_run import DryRun
+ from ifupdown2.ifupdown.utils import utils
+except ImportError:
+ from lib.dry_run import DryRun
+ from ifupdown.utils import utils
+
+
+class BaseObject(DryRun):
+ """
+ BaseObject should be the parent of any ifupdown2 object that wishes to
+ implement any "dry run" specific code and have a default logger.
+ More classes can inherit BaseObject and add features like Addon, FileIO or Sysfs...
+ """
+
+ def __init__(self):
+ DryRun.__init__(self)
+ self.logger = logging.getLogger("ifupdown2.%s" % self.__class__.__name__)
+
+
+def _import_NetlinkListenerWithCache():
+ try:
+ from ifupdown2.lib.nlcache import NetlinkListenerWithCache
+ except ImportError:
+ from lib.nlcache import NetlinkListenerWithCache
+ return NetlinkListenerWithCache
+
+
+class Cache(BaseObject):
+ def __init__(self):
+ BaseObject.__init__(self)
+ self.cache = _import_NetlinkListenerWithCache().get_instance().cache
+
+
+class Netlink(BaseObject):
+ def __init__(self):
+ BaseObject.__init__(self)
+ self.netlink = _import_NetlinkListenerWithCache().get_instance()
+
+
+class Requirements(BaseObject):
+ bridge_utils_is_installed = os.path.exists(utils.brctl_cmd)
--- /dev/null
+#!/usr/bin/python
+# Copyright (C) 2019 Cumulus Networks, Inc. all rights reserved
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; version 2.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# https://www.gnu.org/licenses/gpl-2.0-standalone.html
+#
+# Author:
+# Julien Fortin, julien@cumulusnetworks.com
+#
+# ifupdown2 -- dry_run module
+#
+#
+# __WeakMethodBound and __WeakMethodFree classes as well as the WeakMethod
+# function were inspired by the implementation of ActiveState recipes 81253
+# weakmethod.
+# This code solves an important issue here. You can't have weakrefs on bound
+# methods. Here is quote from the recipie:
+#
+# "Normal weakref.refs to bound methods don't quite work the way one expects,
+# because bound methods are first-class objects; weakrefs to bound methods are
+# dead-on-arrival unless some other strong reference to the same bound method
+# exists."
+#
+
+import logging
+import inspect
+import weakref
+
+
+class __WeakMethodBound:
+ """ ActiveState recipes 81253-weakmethod """
+
+ def __init__(self, f):
+ self.f = f.im_func
+ self.c = weakref.ref(f.im_self)
+
+ def __call__(self, *arg, **kwargs):
+ if not self.c():
+ raise TypeError("Method called on dead object")
+ apply(self.f, (self.c(),) + arg, kwargs)
+
+
+class __WeakMethodFree:
+ """ ActiveState recipes 81253-weakmethod """
+
+ def __init__(self, f):
+ self.f = weakref.ref(f)
+
+ def __call__(self, *arg, **kwargs):
+ if not self.f():
+ raise TypeError("Function no longer exist")
+ apply(self.f(), arg, kwargs)
+
+
+def WeakMethod(f):
+ """ ActiveState recipes 81253-weakmethod """
+ try:
+ f.im_func
+ except AttributeError:
+ return __WeakMethodFree(f)
+ return __WeakMethodBound(f)
+
+
+def _weakref_call_back_delete(reference):
+ try:
+ DryRunManager.get_instance().unregister_dry_run_handler_weakref_callback(reference)
+ except:
+ pass
+
+
+class DryRun(object):
+ """
+ Detect dry_run functions and save the associated handler
+ """
+ __DRY_RUN_PREFIX = "DRY-RUN"
+
+ def __init__(self):
+ self.logger = logging.getLogger("ifupdown2.%s" % self.__class__.__name__)
+
+ for attr_name in dir(self):
+ try:
+ # We need to iterate through the object attribute
+ # to find dryrun methods
+ if attr_name.lower().endswith("_dry_run"):
+ attr_value = getattr(self, attr_name)
+
+ # When we find a dryrun attribute we need to make sure
+ # it is a callable function or method.
+ if not self.__is_method_or_function(attr_value):
+ continue
+
+ base_attr_name = attr_name[:-8]
+ base_attr_value = getattr(self, base_attr_name)
+ # We try infere the base method/function name
+ # then make sure its a function or method
+ if not self.__is_method_or_function(base_attr_value):
+ continue
+
+ # now we are pretty sure we have want we want:
+ # - the base function
+ # - the associated dry_run code
+ # we will now register this couple in the DryRunManager
+ DryRunManager.get_instance().register_dry_run_handler(
+ weakref.ref(self, _weakref_call_back_delete),
+ handler_name=base_attr_name,
+ handler_code_weakref=WeakMethod(base_attr_value),
+ dry_run_code_weakref=WeakMethod(attr_value)
+ )
+ except:
+ pass
+
+ def log_info_ifname_dry_run(self, ifname, string):
+ self.logger.info("DRY-RUN: %s: %s" % (ifname, string))
+
+ def log_info_dry_run(self, string):
+ self.logger.info("DRY-RUN: %s" % string)
+
+ @staticmethod
+ def __is_method_or_function(obj):
+ return callable(obj) and (inspect.ismethod(obj) or inspect.isfunction(obj))
+
+
+class _DryRunEntry(object):
+ def __init__(self, target_module_weakref, handler_name, handler_code_weakref, dry_run_code_weakref):
+ self.target_module_weakref = target_module_weakref
+ self.handler_name = handler_name
+ self.handler_code_weakref = handler_code_weakref
+ self.dry_run_code_weakref = dry_run_code_weakref
+ self.__status = False
+
+ def set(self):
+ target_module_ref = self.target_module_weakref()
+
+ if target_module_ref:
+ if self.dry_run_code_weakref:
+ target_module_ref.__dict__[self.handler_name] = self.dry_run_code_weakref
+ self.__status = True
+ else:
+ # if the reference is dead we need to unregister it
+ DryRunManager.get_instance().unregister_dry_run_handler_weakref_callback(self.target_module_weakref)
+
+ def unset(self):
+ target_module_ref = self.target_module_weakref()
+
+ if target_module_ref:
+ if self.handler_code_weakref:
+ target_module_ref.__dict__[self.handler_name] = self.handler_code_weakref
+ self.__status = False
+ else:
+ # if the reference is dead we need to unregister it
+ DryRunManager.get_instance().unregister_dry_run_handler_weakref_callback(self.target_module_weakref)
+
+ def get_status(self):
+ return self.__status
+
+
+class DryRunManager(object):
+ __instance = None
+
+ @staticmethod
+ def get_instance():
+ if not DryRunManager.__instance:
+ DryRunManager.__instance = DryRunManager()
+ return DryRunManager.__instance
+
+ def __init__(self):
+ if DryRunManager.__instance:
+ raise RuntimeError("DryRunManager: invalid access. Please use DryRunManager.getInstance()")
+ else:
+ DryRunManager.__instance = self
+
+ self.__entries = dict()
+ self.__is_on = False
+
+ def register_dry_run_handler(self, module_weakref, handler_name, handler_code_weakref, dry_run_code_weakref):
+ """
+ Register the dry run handler only using weakrefs - we don't want to mess up with garbage collection
+ :param module_weakref:
+ :param handler_name:
+ :param handler_code_weakref:
+ :param dry_run_code_weakref:
+ :return:
+ """
+ dry_run_entry = _DryRunEntry(
+ target_module_weakref=module_weakref,
+ handler_name=handler_name,
+ handler_code_weakref=handler_code_weakref,
+ dry_run_code_weakref=dry_run_code_weakref
+ )
+ if self.__is_on:
+ dry_run_entry.set()
+
+ if module_weakref in self.__entries:
+ self.__entries[module_weakref].append(dry_run_entry)
+ else:
+ self.__entries[module_weakref] = [dry_run_entry]
+
+ def unregister_dry_run_handler_weakref_callback(self, reference):
+ """
+ If we detect a dead reference, we should remove this reference from our
+ internal data structure
+ """
+ try:
+ del self.__entries[reference]
+ except:
+ pass
+
+ def dry_run_mode_on(self):
+ """
+ Enable the dry run mode
+ WARNING: not thread-safe
+ """
+ for entries in self.__entries.itervalues():
+ for entry in entries:
+ entry.set()
+ self.__is_on = True
+
+ def dry_run_mode_off(self):
+ """
+ Disable the dry run mode
+ WARNING: not thread-safe
+ """
+ for entries in self.__entries.itervalues():
+ for entry in entries:
+ entry.unset()
+ self.__is_on = False
+
+ def dump_entries_stdout(self):
+ print "== DryRunManager dump =="
+ print " MODULE: HANDLER STATUS"
+ for entries in self.__entries.itervalues():
+ for entry in entries:
+ print " %s: %s() %s" % (repr(entry.target_module_weakref), entry.handler_name, "ON" if entry.get_status() else "OFF")
+ print "========================"
+
+ def is_dry_mode_on(self):
+ return self.__is_on
--- /dev/null
+# Copyright (C) 2017, 2018, 2019 Cumulus Networks, Inc. all rights reserved
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; version 2.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# https://www.gnu.org/licenses/gpl-2.0-standalone.html
+#
+# Author:
+# Julien Fortin, julien@cumulusnetworks.com
+#
+# ifupdown2 custom exceptions
+#
+
+
+class Ifupdown2Exception(Exception):
+ pass
+
+
+class ExitWithStatus(Ifupdown2Exception):
+
+ def __init__(self, status):
+ Ifupdown2Exception.__init__(self)
+ self.status = status
+
+ def get_status(self):
+ return self.status
+
+
+class ExitWithStatusAndError(ExitWithStatus):
+ def __init__(self, status, message):
+ ExitWithStatus.__init__(self, status)
+ self.message = message
--- /dev/null
+# Copyright (C) 2017, 2018, 2019 Cumulus Networks, Inc. all rights reserved
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; version 2.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# https://www.gnu.org/licenses/gpl-2.0-standalone.html
+#
+# Author:
+# Julien Fortin, julien@cumulusnetworks.com
+#
+# io -- all io (file) handlers
+#
+
+import json
+import struct
+import socket
+import select
+
+try:
+ from ifupdown2.lib.base_objects import BaseObject
+except ImportError:
+ from lib.base_objects import BaseObject
+
+
+class IO(BaseObject):
+ def __init__(self):
+ BaseObject.__init__(self)
+
+ def write_to_file(self, path, string):
+ try:
+ self.logger.info("writing \"%s\" to file %s" % (string, path))
+ with open(path, "w") as f:
+ f.write(string)
+ return True
+ except IOError, e:
+ self.logger.warn("error while writing to file %s: %s" % (path, str(e)))
+ return False
+
+ def write_to_file_dry_run(self, path, string):
+ self.log_info_dry_run("writing \"%s\" to file %s" % (string, path))
+ return True
+
+ def read_file_oneline(self, path):
+ try:
+ self.logger.info("reading '%s'" % path)
+ with open(path, "r") as f:
+ return f.readline().strip("\n")
+ except:
+ return None
+
+ def read_file_oneline_dry_run(self, path):
+ self.log_info_dry_run("reading \"%s\"" % path)
+ return None
+
+ def read_file(self, path):
+ """ read file and return lines from the file """
+ try:
+ self.logger.info("reading '%s'" % path)
+ with open(path, "r") as f:
+ return f.readlines()
+ except:
+ return None
+
+
+class SocketIO(object):
+ """
+ Helper class to provide common TX/RX methods for socket
+ communication to both client and daemon.
+ """
+
+ @staticmethod
+ def tx_data(_socket, data):
+ """
+ We don't send raw data over the socket, we pack it with the length
+ (first 4 bytes) then with the data. That way the the transfer is more
+ reliable
+ """
+ ready = select.select([], [_socket], [])
+ if ready and ready[1] and ready[1][0] == _socket:
+ frmt = "=%ds" % len(data)
+ packed_msg = struct.pack(frmt, data)
+ packed_hdr = struct.pack("=I", len(packed_msg))
+ _socket.sendall(packed_hdr + packed_msg)
+
+ @staticmethod
+ def rx_json_packet(_socket):
+ """
+ Reading data from socket. Unpacking the packets sent by "tx_data"
+ first 4 bytes are the length of the following data. The data should
+ be in json format
+ """
+ ready = select.select([_socket], [], [])
+
+ if ready and ready[0] and ready[0][0] == _socket:
+
+ header_data = _socket.recv(4)
+
+ if not header_data:
+ raise Exception("rx_json_packet: socket closed")
+ if len(header_data) < 4:
+ raise Exception("rx_json_packet: invalid data received")
+
+ data_len = struct.unpack("=I", header_data)[0]
+ data = _socket.recv(data_len)
+
+ while len(data) < data_len:
+ data = data + _socket.recv(data_len - len(data))
+
+ return json.loads(data)
+
+ return None
+
+ def get_socket_peer_cred(self, _socket):
+ """
+ Returns tuple of (pid, uid, gid) of connected AF_UNIX stream socket
+ :param _socket:
+ :return:
+ """
+ return struct.unpack("3i", _socket.getsockopt(socket.SOL_SOCKET, self.SO_PEERCRED, struct.calcsize("3i")))
--- /dev/null
+# Copyright (C) 2017, 2018, 2019 Cumulus Networks, Inc. all rights reserved
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; version 2.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# https://www.gnu.org/licenses/gpl-2.0-standalone.html
+#
+# Author:
+# Julien Fortin, julien@cumulusnetworks.com
+#
+# iproute2 -- contains all iproute2 related operation
+#
+
+import re
+import shlex
+import signal
+import subprocess
+
+from ipaddr import IPNetwork
+
+try:
+ from ifupdown2.lib.sysfs import Sysfs
+ from ifupdown2.lib.base_objects import Cache, Requirements
+
+ from ifupdown2.ifupdown.utils import utils
+ from ifupdown2.ifupdown.iface import ifaceLinkPrivFlags
+ from ifupdown2.nlmanager.nlpacket import Link
+except ImportError:
+ from lib.sysfs import Sysfs
+ from lib.base_objects import Cache, Requirements
+
+ from ifupdown.utils import utils
+ from ifupdown.iface import ifaceLinkPrivFlags
+ from nlmanager.nlpacket import Link
+
+# WORK AROUND - Tunnel creation should be done via netlink and not iproute2 ####
+import struct #
+import socket #
+ #
+try: #
+ import ifupdown2.nlmanager.nlpacket as nlpacket #
+except: #
+ import nlmanager.nlpacket as nlpacket #
+################################################################################
+
+
+class IPRoute2(Cache, Requirements):
+
+ VXLAN_UDP_PORT = 4789
+ VXLAN_PEER_REGEX_PATTERN = re.compile("\s+dst\s+(\d+.\d+.\d+.\d+)\s+")
+
+ def __init__(self):
+ Cache.__init__(self)
+ Requirements.__init__(self)
+
+ self.sysfs = Sysfs
+
+ self.__batch = {}
+ self.__batch_mode = False
+
+ # if bridge utils is not installed overrrides specific functions to
+ # avoid constantly checking bridge_utils_is_installed
+ if not Requirements.bridge_utils_is_installed:
+ self.bridge_set_stp = lambda _, __: None
+ self.bridge_del_mcqv4src = lambda _, __: None
+ self.bridge_set_mcqv4src = lambda _, __, ___: None
+
+ ############################################################################
+ # WORK-AROUND
+ ############################################################################
+
+ def __update_cache_after_link_creation(self, ifname, kind):
+ """
+ WORK AROUND - when creating tunnel via iproute2 we still need to fill
+ our internal cache to keep track of this interface until we receive the
+ NEWLINK notification. This code is a copy-paste from:
+ nlcache.tx_nlpacket_get_response_with_error_and_cache_on_ack
+
+ :param ifname:
+ :param kind:
+ :return:
+ """
+ packet = nlpacket.Link(nlpacket.RTM_NEWLINK, False, use_color=False)
+ packet.flags = nlpacket.NLM_F_CREATE | nlpacket.NLM_F_REQUEST | nlpacket.NLM_F_ACK
+ packet.body = struct.pack('Bxxxiii', socket.AF_UNSPEC, 0, 0, 0)
+ packet.add_attribute(nlpacket.Link.IFLA_IFNAME, ifname)
+ packet.add_attribute(nlpacket.Link.IFLA_LINKINFO, {
+ nlpacket.Link.IFLA_INFO_KIND: kind,
+ nlpacket.Link.IFLA_INFO_DATA: {}
+ })
+ packet.build_message(0, 0)
+ # When creating a new link via netlink, we don't always wait for the kernel
+ # NEWLINK notification to be cached to continue. If our request is ACKed by
+ # the OS we assume that the link was successfully created. Since we aren't
+ # waiting for the kernel notification to continue we need to manually fill
+ # our cache with the packet we just TX'ed. Once the NEWLINK notification
+ # is received it will simply override the previous entry.
+ # We need to keep track of those manually cached packets. We set a private
+ # flag on the objects via the attribute priv_flags
+ packet.priv_flags |= nlpacket.NLM_F_REQUEST
+ try:
+ # we need to decode the service header so all the attribute are properly
+ # filled in the packet object that we are about to store in cache.
+ # i.e.: packet.flags shouldn't contain NLM_F_* values but IFF_* (in case of Link object)
+ # otherwise call to cache.link_is_up() will probably return True
+ packet.decode_service_header()
+ except:
+ # we can ignore all errors
+ pass
+
+ # Then we can use our normal "add_link" API call to cache the packet
+ # and fill up our additional internal data structures.
+ self.cache.add_link(packet)
+
+ ############################################################################
+ # BATCH
+ ############################################################################
+
+ def __add_to_batch(self, prefix, cmd):
+ if prefix in self.__batch:
+ self.__batch[prefix].append(cmd)
+ else:
+ self.__batch[prefix] = [cmd]
+
+ def __execute_or_batch(self, prefix, cmd):
+ if self.__batch_mode:
+ self.__add_to_batch(prefix, cmd)
+ else:
+ utils.exec_command("%s %s" % (prefix, cmd))
+
+ def __execute_or_batch_dry_run(self, prefix, cmd):
+ """
+ The batch function has it's own dryrun handler so we only handle
+ dryrun for non-batch mode. Which will be removed once the "utils"
+ module has it's own dryrun handlers
+ """
+ if self.__batch_mode:
+ self.__add_to_batch(prefix, cmd)
+ else:
+ self.log_info_dry_run("executing: %s %s" % (prefix, cmd))
+
+ def batch_start(self):
+ if not self.__batch_mode:
+ self.__batch_mode = True
+ self.__batch = {}
+
+ def batch_commit(self):
+ try:
+ if not self.__batch_mode or not self.__batch:
+ return
+ for prefix, commands in self.__batch.iteritems():
+ utils.exec_command(
+ "%s -force -batch -" % prefix,
+ stdin="\n".join(commands)
+ )
+ except:
+ raise
+ finally:
+ self.__batch_mode = False
+ del self.__batch
+ self.__batch = None
+
+ ############################################################################
+ # LINK
+ ############################################################################
+
+ def link_up(self, ifname):
+ if not self.cache.link_is_up(ifname):
+ self.link_up_force(ifname)
+
+ def link_down(self, ifname):
+ if self.cache.link_is_up(ifname):
+ self.link_down_force(ifname)
+
+ def link_up_dry_run(self, ifname):
+ self.link_up_force(ifname)
+
+ def link_down_dry_run(self, ifname):
+ self.link_down_force(ifname)
+
+ def link_up_force(self, ifname):
+ self.__execute_or_batch(utils.ip_cmd, "link set dev %s up" % ifname)
+
+ def link_down_force(self, ifname):
+ self.__execute_or_batch(utils.ip_cmd, "link set dev %s down" % ifname)
+
+ ###
+
+ def link_set_master(self, ifname, master):
+ if master != self.cache.get_master(ifname):
+ self.__execute_or_batch(
+ utils.ip_cmd,
+ "link set dev %s master %s" % (ifname, master)
+ )
+
+ def link_set_master_dry_run(self, ifname, master):
+ self.__execute_or_batch(
+ utils.ip_cmd,
+ "link set dev %s master %s" % (ifname, master)
+ )
+
+ ###
+
+ def link_set_address(self, ifname, address):
+ if utils.mac_str_to_int(address) != self.cache.get_link_address_raw(ifname):
+ self.link_down(ifname)
+ self.__execute_or_batch(
+ utils.ip_cmd,
+ "link set dev %s address %s" % (ifname, address)
+ )
+ self.link_up(ifname)
+
+ def link_set_address_dry_run(self, ifname, address):
+ self.link_down(ifname)
+ self.__execute_or_batch(
+ utils.ip_cmd,
+ "link set dev %s address %s" % (ifname, address)
+ )
+ self.link_up(ifname)
+
+ def link_set_address_and_keep_down(self, ifname, address, keep_down=False):
+ if utils.mac_str_to_int(address) != self.cache.get_link_address_raw(ifname):
+ self.link_down(ifname)
+ self.__execute_or_batch(
+ utils.ip_cmd,
+ "link set dev %s address %s" % (ifname, address)
+ )
+ if not keep_down:
+ self.link_up(ifname)
+
+ def link_set_address_and_keep_down_dry_run(self, ifname, address, keep_down=False):
+ self.link_down(ifname)
+ self.__execute_or_batch(
+ utils.ip_cmd,
+ "link set dev %s address %s" % (ifname, address)
+ )
+ if not keep_down:
+ self.link_up(ifname)
+
+ ###
+
+ def link_add_macvlan(self, ifname, macvlan_ifname, macvlan_mode):
+ utils.exec_command(
+ "%s link add link %s name %s type macvlan mode %s"
+ % (utils.ip_cmd, ifname, macvlan_ifname, macvlan_mode)
+ )
+
+ def link_add_macvlan_dry_run(self, ifname, macvlan_ifname, macvlan_mode):
+ # this dryrun method can be removed once dryrun handlers
+ # are added to the utils module
+ self.log_info_ifname_dry_run(ifname, "executing %s link add link %s name %s type macvlan mode %s"
+ % (utils.ip_cmd, ifname, macvlan_ifname, macvlan_mode)
+ )
+
+ ###
+
+ def link_create_vxlan(self, name, vxlanid, localtunnelip=None, svcnodeip=None,
+ remoteips=None, learning='on', ageing=None, ttl=None, physdev=None):
+ if svcnodeip and remoteips:
+ raise Exception("svcnodeip and remoteip are mutually exclusive")
+
+ if self.cache.link_exists(name):
+ cmd = [
+ "link set dev %s type vxlan dstport %d"
+ % (name, self.VXLAN_UDP_PORT)
+ ]
+ else:
+ cmd = [
+ "link add dev %s type vxlan id %s dstport %d"
+ % (name, vxlanid, self.VXLAN_UDP_PORT)
+ ]
+
+ if svcnodeip:
+ if svcnodeip.is_multicast:
+ cmd.append("group %s" % svcnodeip)
+ else:
+ cmd.append("remote %s" % svcnodeip)
+
+ if ageing:
+ cmd.append("ageing %s" % ageing)
+
+ if learning == 'off':
+ cmd.append("nolearning")
+
+ if ttl is not None:
+ cmd.append("ttl %s" % ttl)
+
+ if physdev:
+ cmd.append("dev %s" % physdev)
+
+ if localtunnelip:
+ cmd.append("local %s" % localtunnelip)
+
+ self.__execute_or_batch(utils.ip_cmd, " ".join(cmd))
+
+ def get_vxlan_peers(self, dev, svcnodeip):
+ cmd = "%s fdb show brport %s" % (utils.bridge_cmd, dev)
+ cur_peers = []
+ try:
+ ps = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE, close_fds=False)
+ utils.enable_subprocess_signal_forwarding(ps, signal.SIGINT)
+ output = subprocess.check_output(("grep", "00:00:00:00:00:00"), stdin=ps.stdout)
+ ps.wait()
+ utils.disable_subprocess_signal_forwarding(signal.SIGINT)
+ try:
+ for l in output.split('\n'):
+ m = self.VXLAN_PEER_REGEX_PATTERN.search(l)
+ if m and m.group(1) != svcnodeip:
+ cur_peers.append(m.group(1))
+ except:
+ self.logger.warn('error parsing ip link output')
+ except subprocess.CalledProcessError as e:
+ if e.returncode != 1:
+ self.logger.error(str(e))
+ finally:
+ utils.disable_subprocess_signal_forwarding(signal.SIGINT)
+
+ return cur_peers
+
+ ###
+
+ @staticmethod
+ def link_add_xfrm(ifname, xfrm_name, xfrm_id):
+ utils.exec_commandl(['ip', 'link', 'add', xfrm_name, 'type', 'xfrm', 'dev', ifname, 'if_id', xfrm_id])
+
+ ############################################################################
+ # TUNNEL
+ ############################################################################
+
+ def tunnel_create(self, tunnelname, mode, attrs=None):
+ if self.cache.link_exists(tunnelname):
+ return
+
+ cmd = []
+ if "6" in mode:
+ cmd.append("-6")
+
+ if mode in ["gretap"]:
+ cmd.append("link add %s type %s" % (tunnelname, mode))
+ else:
+ cmd.append("tunnel add %s mode %s" % (tunnelname, mode))
+
+ if attrs:
+ for k, v in attrs.iteritems():
+ cmd.append(k)
+ if v:
+ cmd.append(v)
+
+ utils.exec_command("%s %s" % (utils.ip_cmd, " ".join(cmd)))
+ self.__update_cache_after_link_creation(tunnelname, mode)
+
+ def tunnel_change(self, tunnelname, attrs=None):
+ """ tunnel change function """
+ if not self.cache.link_exists(tunnelname):
+ return
+ cmd = ["tunnel change %s" % tunnelname]
+ if attrs:
+ for k, v in attrs.iteritems():
+ cmd.append(k)
+ if v:
+ cmd.append(v)
+ self.__execute_or_batch(utils.ip_cmd, " ".join(cmd))
+
+ ############################################################################
+ # ADDRESS
+ ############################################################################
+
+ def addr_flush(self, ifname):
+ if self.cache.link_has_ip(ifname):
+ self.__execute_or_batch(utils.ip_cmd, "addr flush dev %s" % ifname)
+
+ def link_set_ipv6_addrgen_dry_run(self, ifname, addrgen, link_created):
+ addrgen_str = "none" if addrgen else "eui64"
+ self.link_down(ifname)
+ self.__execute_or_batch(utils.ip_cmd, "link set dev %s addrgenmode %s" % (ifname, addrgen_str))
+ self.link_up(ifname)
+
+ def link_set_ipv6_addrgen(self, ifname, addrgen, link_created):
+ """
+ IFLA_INET6_ADDR_GEN_MODE values:
+ 0 = eui64
+ 1 = none
+
+ :param ifname:
+ :param addrgen:
+ :param link_created:
+ :return:
+ """
+ cached_ipv6_addr_gen_mode = self.cache.get_link_ipv6_addrgen_mode(ifname)
+
+ if cached_ipv6_addr_gen_mode == addrgen:
+ return True
+
+ disabled_ipv6 = self.sysfs.get_ipv6_conf_disable_ipv6(ifname)
+
+ if disabled_ipv6:
+ self.logger.info("%s: cannot set addrgen: ipv6 is disabled on this device" % ifname)
+ return False
+
+ if link_created:
+ link_mtu = self.sysfs.link_get_mtu(ifname)
+ else:
+ link_mtu = self.cache.get_link_mtu(ifname)
+
+ if link_mtu < 1280:
+ self.logger.info("%s: ipv6 addrgen is disabled on device with MTU "
+ "lower than 1280 (current mtu %s): cannot set addrgen %s"
+ % (ifname, link_mtu, "off" if addrgen else "on"))
+ return False
+
+ if not link_created:
+ # When setting addrgenmode it is necessary to flap the macvlan
+ # device. After flapping the device we also need to re-add all
+ # the user configuration. The best way to add the user config
+ # is to flush our internal address cache
+ self.cache.address_flush_link(ifname)
+
+ is_link_up = self.cache.link_is_up(ifname)
+
+ if is_link_up:
+ self.link_down_force(ifname)
+
+ self.__execute_or_batch(
+ utils.ip_cmd,
+ "link set dev %s addrgenmode %s" % (ifname, Link.ifla_inet6_addr_gen_mode_dict.get(addrgen))
+ )
+
+ if is_link_up:
+ self.link_up_force(ifname)
+
+ return True
+
+ @staticmethod
+ def __compare_user_config_vs_running_state(running_addrs, user_addrs):
+ ip4 = []
+ ip6 = []
+
+ for ip in user_addrs or []:
+ obj = IPNetwork(ip)
+
+ if obj.version == 6:
+ ip6.append(str(obj))
+ else:
+ ip4.append(str(obj))
+
+ running_ipobj = []
+ for ip in running_addrs or []:
+ running_ipobj.append(str(ip))
+
+ return running_ipobj == (ip4 + ip6)
+
+ def add_addresses(self, ifacobj, ifname, address_list, purge_existing=False, metric=None, with_address_virtual=False):
+ if purge_existing:
+ running_address_list = self.cache.get_ifupdown2_addresses_list(
+ [ifacobj],
+ ifname,
+ with_address_virtual=with_address_virtual
+ )
+ address_list = utils.get_normalized_ip_addr(ifname, address_list)
+
+ if self.__compare_user_config_vs_running_state(running_address_list, address_list):
+ return
+
+ try:
+ self.__execute_or_batch(utils.ip_cmd, "addr flush dev %s" % ifname)
+ except Exception, e:
+ self.logger.warning("%s: flushing all ip address failed: %s" % (ifname, str(e)))
+ for addr in address_list:
+ try:
+ if metric:
+ self.__execute_or_batch(utils.ip_cmd, "addr add %s dev %s metric %s" % (addr, ifname, metric))
+ else:
+ self.__execute_or_batch(utils.ip_cmd, "addr add %s dev %s" % (addr, ifname))
+ except Exception as e:
+ self.logger.error("%s: add_address: %s" % (ifname, str(e)))
+
+ ############################################################################
+ # BRIDGE
+ ############################################################################
+
+ @staticmethod
+ def bridge_set_stp(bridge, stp_state):
+ utils.exec_command("%s stp %s %s" % (utils.brctl_cmd, bridge, stp_state))
+
+ @staticmethod
+ def bridge_fdb_show_dev(dev):
+ try:
+ fdbs = {}
+ output = utils.exec_command("%s fdb show dev %s" % (utils.bridge_cmd, dev))
+ if output:
+ for fdb_entry in output.splitlines():
+ try:
+ entries = fdb_entry.split()
+ fdbs.setdefault(entries[2], []).append(entries[0])
+ except:
+ pass
+ return fdbs
+ except Exception:
+ return None
+
+ @staticmethod
+ def bridge_fdb_add(dev, address, vlan=None, bridge=True, remote=None):
+ target = "self" if bridge else ""
+ vlan_str = "vlan %s " % vlan if vlan else ""
+ dst_str = "dst %s " % remote if remote else ""
+
+ utils.exec_command(
+ "%s fdb replace %s dev %s %s %s %s"
+ % (
+ utils.bridge_cmd,
+ address,
+ dev,
+ vlan_str,
+ target,
+ dst_str
+ )
+ )
+
+ @staticmethod
+ def bridge_fdb_append(dev, address, vlan=None, bridge=True, remote=None):
+ target = "self" if bridge else ""
+ vlan_str = "vlan %s " % vlan if vlan else ""
+ dst_str = "dst %s " % remote if remote else ""
+
+ utils.exec_command(
+ "%s fdb append %s dev %s %s %s %s"
+ % (
+ utils.bridge_cmd,
+ address,
+ dev,
+ vlan_str,
+ target,
+ dst_str
+ )
+ )
+
+ @staticmethod
+ def bridge_fdb_del(dev, address, vlan=None, bridge=True, remote=None):
+ target = "self" if bridge else ""
+ vlan_str = "vlan %s " % vlan if vlan else ""
+ dst_str = "dst %s " % remote if remote else ""
+
+ utils.exec_command(
+ "%s fdb del %s dev %s %s %s %s"
+ % (
+ utils.bridge_cmd,
+ address,
+ dev,
+ vlan_str,
+ target,
+ dst_str
+ )
+ )
+
+ @staticmethod
+ def bridge_vlan_del_vid_list(ifname, vids):
+ if not vids:
+ return
+ for v in vids:
+ utils.exec_command(
+ "%s vlan del vid %s dev %s" % (utils.bridge_cmd, v, ifname)
+ )
+
+ def bridge_vlan_del_vid_list_self(self, ifname, vids, is_bridge=True):
+ target = "self" if is_bridge else ""
+ for v in vids:
+ self.__execute_or_batch(
+ utils.bridge_cmd,
+ "vlan del vid %s dev %s %s" % (v, ifname, target)
+ )
+
+ @staticmethod
+ def bridge_vlan_add_vid_list(ifname, vids):
+ for v in vids:
+ utils.exec_command(
+ "%s vlan add vid %s dev %s" % (utils.bridge_cmd, v, ifname)
+ )
+
+ def bridge_vlan_add_vid_list_self(self, ifname, vids, is_bridge=True):
+ target = "self" if is_bridge else ""
+ for v in vids:
+ self.__execute_or_batch(
+ utils.bridge_cmd,
+ "vlan add vid %s dev %s %s" % (v, ifname, target)
+ )
+
+ def bridge_vlan_del_pvid(self, ifname, pvid):
+ self.__execute_or_batch(
+ utils.bridge_cmd,
+ "vlan del vid %s untagged pvid dev %s" % (pvid, ifname)
+ )
+
+ def bridge_vlan_add_pvid(self, ifname, pvid):
+ self.__execute_or_batch(
+ utils.bridge_cmd,
+ "vlan add vid %s untagged pvid dev %s" % (pvid, ifname)
+ )
+
+ def bridge_del_mcqv4src(self, bridge, vlan):
+ try:
+ vlan = int(vlan)
+ except Exception as e:
+ self.logger.info("%s: del mcqv4src vlan: invalid parameter %s: %s"
+ % (bridge, vlan, str(e)))
+ return
+ utils.exec_command("%s delmcqv4src %s %d" % (utils.brctl_cmd, bridge, vlan))
+
+ def bridge_set_mcqv4src(self, bridge, vlan, mcquerier):
+ try:
+ vlan = int(vlan)
+ except Exception as e:
+ self.logger.info("%s: set mcqv4src vlan: invalid parameter %s: %s" % (bridge, vlan, str(e)))
+ return
+ if vlan == 0 or vlan > 4095:
+ self.logger.warn("mcqv4src vlan '%d' invalid range" % vlan)
+ return
+
+ ip = mcquerier.split(".")
+ if len(ip) != 4:
+ self.logger.warn("mcqv4src '%s' invalid IPv4 address" % mcquerier)
+ return
+ for k in ip:
+ if not k.isdigit() or int(k, 10) < 0 or int(k, 10) > 255:
+ self.logger.warn("mcqv4src '%s' invalid IPv4 address" % mcquerier)
+ return
+
+ utils.exec_command("%s setmcqv4src %s %d %s" % (utils.brctl_cmd, bridge, vlan, mcquerier))
+
+ ############################################################################
+ # ROUTE
+ ############################################################################
+
+ @staticmethod
+ def route_add_gateway(ifname, gateway, vrf=None, metric=None, onlink=True):
+ if not gateway:
+ return
+
+ if not vrf:
+ cmd = "%s route add default via %s proto kernel" % (utils.ip_cmd, gateway)
+ else:
+ cmd = "%s route add table %s default via %s proto kernel" % (utils.ip_cmd, vrf, gateway)
+
+ if metric:
+ cmd += " metric %s" % metric
+
+ cmd += " dev %s" % ifname
+
+ if onlink:
+ cmd += " onlink"
+
+ utils.exec_command(cmd)
+
+ @staticmethod
+ def route_del_gateway(ifname, gateway, vrf=None, metric=None):
+ """
+ delete default gw
+ we don't need a DRYRUN handler here as utils.exec_command should have one
+ """
+ if not gateway:
+ return
+
+ if not vrf:
+ cmd = "%s route del default via %s proto kernel" % (utils.ip_cmd, gateway)
+ else:
+ cmd = "%s route del table %s default via %s proto kernel" % (utils.ip_cmd, vrf, gateway)
+
+ if metric:
+ cmd += " metric %s" % metric
+
+ cmd += " dev %s" % ifname
+ utils.exec_command(cmd)
+
+ def fix_ipv6_route_metric(self, ifaceobj, macvlan_ifacename, ips):
+ vrf_table = None
+
+ if ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE:
+ try:
+ for upper_iface in ifaceobj.upperifaces:
+ vrf_table = self.cache.get_vrf_table(upper_iface)
+ if vrf_table:
+ break
+ except:
+ pass
+
+ ip_route_del = []
+ for ip in ips:
+ ip_network_obj = IPNetwork(ip)
+
+ if ip_network_obj.version == 6:
+ route_prefix = '%s/%d' % (ip_network_obj.network, ip_network_obj.prefixlen)
+
+ if vrf_table:
+ self.__execute_or_batch(
+ utils.ip_cmd,
+ "route del %s table %s dev %s" % (route_prefix, vrf_table, macvlan_ifacename)
+ )
+ else:
+ self.__execute_or_batch(
+ utils.ip_cmd,
+ "route del %s dev %s" % (route_prefix, macvlan_ifacename)
+ )
+
+ ip_route_del.append((route_prefix, vrf_table))
+
+ for ip, vrf_table in ip_route_del:
+ if vrf_table:
+ self.__execute_or_batch(
+ utils.ip_cmd,
+ "route add %s table %s dev %s proto kernel metric 9999" % (ip, vrf_table, macvlan_ifacename)
+ )
+ else:
+ self.__execute_or_batch(
+ utils.ip_cmd,
+ "route add %s dev %s proto kernel metric 9999" % (ip, macvlan_ifacename)
+ )
+
+ def ip_route_get_dev(self, prefix, vrf_master=None):
+ try:
+ if vrf_master:
+ cmd = "%s route get %s vrf %s" % (utils.ip_cmd, prefix, vrf_master)
+ else:
+ cmd = "%s route get %s" % (utils.ip_cmd, prefix)
+
+ output = utils.exec_command(cmd)
+ if output:
+ rline = output.splitlines()[0]
+ if rline:
+ rattrs = rline.split()
+ return rattrs[rattrs.index("dev") + 1]
+ except Exception, e:
+ self.logger.debug("ip_route_get_dev: failed .. %s" % str(e))
+ return None
--- /dev/null
+# Copyright (C) 2016, 2017, 2018, 2019 Cumulus Networks, Inc. all rights reserved
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; version 2.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# https://www.gnu.org/licenses/gpl-2.0-standalone.html
+#
+# Author:
+# Julien Fortin, julien@cumulusnetworks.com
+#
+
+import os
+import sys
+import traceback
+
+import logging
+import logging.handlers
+
+root_logger = logging.getLogger()
+
+
+class LogManager:
+ LOGGER_NAME = "ifupdown2"
+ LOGGER_NAME_DAEMON = "ifupdown2d"
+
+ DEFAULT_TCP_LOGGING_PORT = 42422
+ DEFAULT_LOGGING_LEVEL_DAEMON = logging.INFO
+ DEFAULT_LOGGING_LEVEL_NORMAL = logging.WARNING
+
+ __instance = None
+
+ @staticmethod
+ def get_instance():
+ if not LogManager.__instance:
+ try:
+ LogManager.__instance = LogManager()
+ except Exception as e:
+ sys.stderr.write("warning: ifupdown2.Log: %s\n" % str(e))
+ traceback.print_exc()
+ return LogManager.__instance
+
+ def __init__(self):
+ """
+ Setup root logger and console handler (stderr). To enable daemon, client
+ or standalone logging please call the proper function, see:
+ "start_(daemon|client|standlone)_logging"
+ """
+ if LogManager.__instance:
+ raise RuntimeError("Log: invalid access. Please use Log.getInstance()")
+ else:
+ LogManager.__instance = self
+
+ self.__fmt = "%(levelname)s: %(message)s"
+
+ self.__debug_fmt = "%(asctime)s: %(threadName)s: %(name)s: " \
+ "%(filename)s:%(lineno)d:%(funcName)s(): " \
+ "%(levelname)s: %(message)s"
+
+ self.__root_logger = logging.getLogger()
+ self.__root_logger.name = self.LOGGER_NAME
+
+ self.__socket_handler = None
+ self.__syslog_handler = None
+ self.__console_handler = None
+
+ self.daemon = None
+
+ # by default we attach a console handler that logs on stderr
+ # the daemon can manually remove this handler on startup
+ self.__console_handler = logging.StreamHandler(sys.stderr)
+ self.__console_handler.setFormatter(logging.Formatter(self.__fmt))
+ self.__root_logger.addHandler(self.__console_handler)
+
+ if os.path.exists("/dev/log"):
+ try:
+ self.__syslog_handler = logging.handlers.SysLogHandler(
+ address="/dev/log",
+ facility=logging.handlers.SysLogHandler.LOG_DAEMON
+ )
+ self.__syslog_handler.setFormatter(logging.Formatter(self.__fmt))
+ except Exception as e:
+ sys.stderr.write("warning: syslog: %s\n" % str(e))
+ self.__syslog_handler = None
+
+ logging.addLevelName(logging.CRITICAL, "critical")
+ logging.addLevelName(logging.WARNING, "warning")
+ logging.addLevelName(logging.ERROR, "error")
+ logging.addLevelName(logging.DEBUG, "debug")
+ logging.addLevelName(logging.INFO, "info")
+
+ def set_level(self, default, error=False, warning=False, info=False, debug=False):
+ """
+ Set root handler logging level
+ :param default:
+ :param error:
+ :param warning:
+ :param info:
+ :param debug:
+ """
+ if debug:
+ log_level = logging.DEBUG
+ elif info:
+ log_level = logging.INFO
+ elif warning:
+ log_level = logging.WARNING
+ elif error:
+ log_level = logging.ERROR
+ else:
+ log_level = default
+
+ for handler in self.__root_logger.handlers:
+ handler.setLevel(log_level)
+ self.__root_logger.setLevel(log_level)
+
+ def enable_console(self):
+ """ Add console handler to root logger """
+ self.__root_logger.addHandler(self.__console_handler)
+
+ def disable_console(self):
+ """ Remove console handler from root logger """
+ self.__root_logger.removeHandler(self.__console_handler)
+
+ def enable_syslog(self):
+ """ Add syslog handler to root logger """
+ if self.__syslog_handler:
+ self.__root_logger.addHandler(self.__syslog_handler)
+
+ def disable_syslog(self):
+ """ Remove syslog handler from root logger """
+ if self.__syslog_handler:
+ self.__root_logger.removeHandler(self.__syslog_handler)
+
+ def close_log_stream(self):
+ """ Close socket to disconnect client.
+ We first have to perform this little hack: it seems like the socket is
+ not opened until data (LogRecord) are transmitted. In our most basic use
+ case (client sends "ifup -a") the daemon doesn't send back any LogRecord
+ but we can't predict that in the client. The client is already in a
+ blocking-select waiting for data on it's socket handler
+ (StreamRequestHandler). For this special case we need to manually call
+ "createSocket" to open the channel to the client so that we can properly
+ close it. That way the client can exit cleanly.
+ """
+ self.__root_logger.removeHandler(self.__socket_handler)
+ self.__socket_handler.acquire()
+ self.__socket_handler.retryTime = None
+ try:
+ if not self.__socket_handler.sock:
+ self.__socket_handler.createSocket()
+ finally:
+ self.__socket_handler.close()
+ self.__socket_handler.release()
+
+ def start_stream(self):
+ self.__root_logger.addHandler(self.__socket_handler)
+
+ def set_daemon_logging_level(self, args):
+ self.set_level(self.DEFAULT_LOGGING_LEVEL_DAEMON, info=args.verbose, debug=args.debug)
+
+ def set_request_logging_level(self, args):
+ if not hasattr(args, "syslog") or not args.syslog:
+ self.disable_syslog()
+ else:
+ self.__root_logger.removeHandler(self.__socket_handler)
+ self.set_level(self.DEFAULT_LOGGING_LEVEL_NORMAL, info=args.verbose, debug=args.debug)
+
+ def start_client_logging(self, args):
+ """ Setup root logger name and client log level
+ syslog is handled by the daemon directly
+ """
+ self.__root_logger.name = self.LOGGER_NAME
+
+ if hasattr(args, "syslog") and args.syslog:
+ self.enable_syslog()
+ self.disable_console()
+
+ self.set_level(self.DEFAULT_LOGGING_LEVEL_NORMAL, info=args.verbose, debug=args.debug)
+
+ def start_standalone_logging(self, args):
+ self.__root_logger.name = self.LOGGER_NAME
+
+ if hasattr(args, "syslog") and args.syslog:
+ self.enable_syslog()
+ self.disable_console()
+
+ self.__root_logger.removeHandler(self.__console_handler)
+
+ self.set_level(self.DEFAULT_LOGGING_LEVEL_NORMAL, info=args.verbose, debug=args.debug)
+
+ def start_daemon_logging(self, args):
+ """
+ Daemon mode initialize a socket handler to transmit logging to the
+ client, we can also do syslog logging and/or console logging (probably
+ just for debugging purpose)
+ :param args:
+ :return:
+ """
+ self.__root_logger.name = self.LOGGER_NAME_DAEMON
+ self.daemon = True
+
+ self.enable_syslog()
+
+ # Create SocketHandler for daemon-client communication
+ self.__socket_handler = logging.handlers.SocketHandler(
+ "localhost",
+ port=self.DEFAULT_TCP_LOGGING_PORT
+ )
+ self.__root_logger.addHandler(self.__socket_handler)
+
+ if not args.console:
+ self.disable_console()
+
+ self.set_daemon_logging_level(args)
--- /dev/null
+#!/usr/bin/env python
+#
+# Copyright (C) 2017, 2018 Cumulus Networks, Inc. all rights reserved
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; version 2.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# https://www.gnu.org/licenses/gpl-2.0-standalone.html
+#
+# Author:
+# Julien Fortin, julien@cumulusnetworks.com
+#
+# Netlink cache --
+#
+
+import os
+import socket
+import struct
+import signal
+import inspect
+import logging
+import threading
+import traceback
+
+from ipaddr import IPNetwork
+from logging import DEBUG, WARNING
+from collections import OrderedDict
+
+try:
+ from ifupdown2.lib.sysfs import Sysfs
+ from ifupdown2.lib.base_objects import BaseObject
+
+ from ifupdown2.nlmanager.nlpacket import \
+ Address, \
+ Netconf, \
+ Link, \
+ Route, \
+ AF_MPLS, \
+ NetlinkPacket, \
+ NLM_F_REQUEST, \
+ RTM_NEWLINK, \
+ RTM_SETLINK, \
+ RTM_DELLINK, \
+ RTM_NEWADDR, \
+ RTM_DELADDR, \
+ RTMGRP_ALL, \
+ NLMSG_DONE, \
+ NLM_F_REQUEST, \
+ NLM_F_CREATE, \
+ NLM_F_ACK, \
+ RT_SCOPES, \
+ INFINITY_LIFE_TIME
+
+ import ifupdown2.nlmanager.nlpacket as nlpacket
+ import ifupdown2.nlmanager.nllistener as nllistener
+ import ifupdown2.nlmanager.nlmanager as nlmanager
+ import ifupdown2.ifupdown.statemanager as statemanager
+except:
+ from lib.sysfs import Sysfs
+ from lib.base_objects import BaseObject
+
+ from nlmanager.nlpacket import \
+ Address, \
+ Netconf, \
+ Link, \
+ Route, \
+ AF_MPLS, \
+ NetlinkPacket, \
+ NLM_F_REQUEST, \
+ RTM_NEWLINK, \
+ RTM_SETLINK, \
+ RTM_DELLINK, \
+ RTM_NEWADDR, \
+ RTM_DELADDR, \
+ RTMGRP_ALL, \
+ NLMSG_DONE, \
+ NLM_F_REQUEST, \
+ NLM_F_CREATE, \
+ NLM_F_ACK, \
+ RT_SCOPES, \
+ INFINITY_LIFE_TIME
+
+ import nlmanager.nlpacket as nlpacket
+ import nlmanager.nllistener as nllistener
+ import nlmanager.nlmanager as nlmanager
+ import ifupdown.statemanager as statemanager
+
+
+log = logging.getLogger()
+
+
+class NetlinkListenerWithCacheErrorNotInitialized(Exception):
+ """
+ If NetlinkListenerWithCache fails on __init__() or / start()
+ we need to raise this custom exception.
+ """
+ pass
+
+
+class NetlinkError(Exception):
+ def __init__(self, exception, prefix=None, ifname=None):
+ netlink_exception_message = ['netlink']
+
+ if ifname:
+ netlink_exception_message.append(ifname)
+
+ if prefix:
+ netlink_exception_message.append(prefix)
+
+ netlink_exception_message.append(str(exception))
+ super(NetlinkError, self).__init__(": ".join(netlink_exception_message))
+
+
+class NetlinkCacheError(Exception):
+ pass
+
+
+class NetlinkCacheIfnameNotFoundError(NetlinkCacheError):
+ pass
+
+
+class NetlinkCacheIfindexNotFoundError(NetlinkCacheError):
+ pass
+
+
+class _NetlinkCache:
+ """ Netlink Cache Class """
+
+ # we need to store these attributes in a static list to be able to iterate
+ # through it when comparing Address objects in add_address()
+ # we ignore IFA_CACHEINFO and IFA_FLAGS
+ _ifa_attributes = (
+ Address.IFA_ADDRESS,
+ Address.IFA_LOCAL,
+ Address.IFA_LABEL,
+ Address.IFA_BROADCAST,
+ Address.IFA_ANYCAST,
+ # Address.IFA_CACHEINFO,
+ Address.IFA_MULTICAST,
+ # Address.IFA_FLAGS
+ )
+
+ def __init__(self):
+ # sysfs API
+ self.__sysfs = Sysfs
+ self.__sysfs.cache = self
+
+ self._link_cache = {}
+ self._addr_cache = {}
+ self._bridge_vlan_cache = {}
+
+ # helper dictionaries
+ # ifindex: ifname
+ # ifname: ifindex
+ self._ifname_by_ifindex = {}
+ self._ifindex_by_ifname = {}
+
+ self._ifname_by_ifindex_sysfs = {}
+ self._ifindex_by_ifname_sysfs = {}
+
+ # master/slave(s) dictionary
+ # master_ifname: [slave_ifname, slave_ifname]
+ self._masters_and_slaves = {}
+
+ # slave/master dictionary
+ # slave_ifname: master_ifname
+ self._slaves_master = {}
+
+ # netconf cache data-structure schema:
+ # {
+ # family: {
+ # ifindex: obj
+ # }
+ # }
+ self._netconf_cache = {
+ socket.AF_INET: {},
+ socket.AF_INET6: {},
+ AF_MPLS: {}
+ }
+ # custom lock mechanism for netconf cache
+ self._netconf_cache_lock = threading.Lock()
+
+ # RLock is needed because we don't want to have separate handling in
+ # get_ifname, get_ifindex and all the API function
+ self._cache_lock = threading.RLock()
+
+ # After sending a RTM_DELLINK request (ip link del DEV) we don't
+ # automatically receive an RTM_DELLINK notification but instead we
+ # have 3 to 5 RTM_NEWLINK notifications (first the device goes
+ # admin-down then, goes through other steps that send notifications...
+ # Because of this behavior the cache is out of sync and may cause
+ # issues. To work-around this behavior we can ignore RTM_NEWLINK for a
+ # given ifname until we receive the RTM_DELLINK. That way our cache is
+ # not stale. When deleting a link, ifupdown2 uses:
+ # - NetlinkListenerWithCache:link_del(ifname)
+ # Before sending the RTM_DELLINK netlink packet we:
+ # - register the ifname in the _ignore_rtm_newlinkq
+ # - force purge the cache because we are not notified right away
+ # - for every RTM_NEWLINK notification we check _ignore_rtm_newlinkq
+ # to see if we need to ignore that packet
+ # - for every RTM_DELLINK notification we check if we have a
+ # corresponding entry in _ignore_rtm_newlinkq and remove it
+ self._ignore_rtm_newlinkq = list()
+ self._ignore_rtm_newlinkq_lock = threading.Lock()
+
+ # After sending a no master request (IFLA_MASTER=0) the kernels send
+ # 2 or 3 notifications (with IFLA_MASTER) before sending the final
+ # notification where IFLA_MASTER is removed. For performance purposes
+ # we don't wait for those notifications, we simply update the cache
+ # to reflect the change (if we got an ACK on the nomaster request).
+ # Those extra notification re-add the former slave to it's master
+ # (in our internal data-structures at least). ifupdown2 relies on
+ # the cache to get accurate information, this puts the cache in an
+ # unreliable state. We can detected this bad state and avoid it. Afer
+ # a nomaster request we "register" the device as "nomaster", meaning
+ # that we will manually remove the IFLA_MASTER attribute from any
+ # subsequent packet, until the final packet arrives - then unregister
+ # the device from the nomasterq.
+ # We need an extra data-structure and lock mechanism for this:
+ self._rtm_newlink_nomasterq = list()
+ self._rtm_newlink_nomasterq_lock = threading.Lock()
+
+ # In the scenario of NetlinkListenerWithCache, the listener thread
+ # decode netlink packets and perform caching operation based on their
+ # respective msgtype add_link for RTM_NEWLINK, remove_link for DELLINK
+ # In some cases the main thread is creating a new device with:
+ # NetlinkListenerWithCache.link_add()
+ # the request is sent and the cache won't have any knowledge of this
+ # new link until we receive a NEWLINK notification on the listener
+ # socket meanwhile the main thread keeps going. The main thread may
+ # query the cache for the newly created device but the cache might not
+ # know about it yet thus creating unexpected situation in the main
+ # thread operations. We need to provide a mechanism to block the main
+ # thread until the desired notification is processed. The main thread
+ # can call:
+ # register_wait_event(ifname, netlink_msgtype)
+ # to register an event for device name 'ifname' and netlink msgtype.
+ # The main thread should then call wait_event to sleep until the
+ # notification is received the NetlinkListenerWithCache provides the
+ # following API:
+ # tx_nlpacket_get_response_with_error_and_wait_for_cache(ifname, nl_packet)
+ # to handle both packet transmission, error handling and cache event
+ self._wait_event = None
+ self._wait_event_alarm = threading.Event()
+
+ def __handle_type_error(self, func_name, data, exception, return_value):
+ """
+ TypeError shouldn't happen but if it does, we are prepared to log and recover
+ """
+ log.debug('nlcache: %s: %s: TypeError: %s' % (func_name, data, str(exception)))
+ return return_value
+
+ def __unslave_nolock(self, slave, master=None):
+ """
+ WARNING: LOCK SHOULD BE ACQUIRED BEFORE CALLING THIS FUNCTION
+
+ When unslaving a device we need to manually clear and update our internal
+ data structures to avoid keeping stale information before receiving a proper
+ netlink notification.
+
+ Dictionaries:
+ - master_and_slaves
+ - slaves_master
+ - bridge_vlan_cache
+
+ :param master:
+ :param slave:
+ :return:
+ """
+ try:
+ del self._link_cache[slave].attributes[Link.IFLA_MASTER]
+ except:
+ pass
+
+ try:
+ if not master:
+ master = self._slaves_master[slave]
+
+ self._masters_and_slaves[master].remove(slave)
+ except (KeyError, ValueError):
+ for master, slaves_set in self._masters_and_slaves.iteritems():
+ if slave in slaves_set:
+ slaves_set.remove(slave)
+ break
+
+ try:
+ del self._slaves_master[slave]
+ except KeyError:
+ pass
+
+ try:
+ del self._bridge_vlan_cache[slave]
+ except KeyError:
+ pass
+
+ def append_to_ignore_rtm_newlinkq(self, ifname):
+ """
+ Register device 'ifname' to the ignore_rtm_newlinkq list pending
+ RTM_DELLINK (see comments above _ignore_rtm_newlinkq declaration)
+ """
+ with self._ignore_rtm_newlinkq_lock:
+ self._ignore_rtm_newlinkq.append(ifname)
+
+ def remove_from_ignore_rtm_newlinkq(self, ifname):
+ """ Unregister ifname from ignore_newlinkq list """
+ try:
+ with self._ignore_rtm_newlinkq_lock:
+ self._ignore_rtm_newlinkq.remove(ifname)
+ except ValueError:
+ pass
+
+ def append_to_rtm_newlink_nomasterq(self, ifname):
+ """ Register device 'ifname' to the _ignore_rtm_newlink_nomasterq """
+ with self._rtm_newlink_nomasterq_lock:
+ self._rtm_newlink_nomasterq.append(ifname)
+
+ def remove_from_rtm_newlink_nomasterq(self, ifname):
+ """ Unregister ifname from _ignore_rtm_newlink_nomasterq list """
+ try:
+ with self._rtm_newlink_nomasterq_lock:
+ self._rtm_newlink_nomasterq.remove(ifname)
+ except ValueError:
+ pass
+
+ def register_wait_event(self, ifname, msgtype):
+ """
+ Register a cache "wait event" for device named 'ifname' and packet
+ type msgtype
+
+ We only one wait_event to be registered. Currently we don't support
+ multi-threaded application so we need to had a strict check. In the
+ future we could have a wait_event queue for multiple thread could
+ register wait event.
+ :param ifname: target device
+ :param msgtype: netlink message type (RTM_NEWLINK, RTM_DELLINK etc.)
+ :return: boolean: did we successfully register a wait_event?
+ """
+ with self._cache_lock:
+ if self._wait_event:
+ return False
+ self._wait_event = (ifname, msgtype)
+ return True
+
+ def wait_event(self):
+ """
+ Sleep until cache event happened in netlinkq thread or timeout expired
+ :return: None
+
+ We set an arbitrary timeout at 1sec in case the kernel doesn't send
+ out a notification for the event we want to wait for.
+ """
+ if not self._wait_event_alarm.wait(1):
+ log.debug('nlcache: wait event alarm timeout expired for device "%s" and netlink packet type: %s'
+ % (self._wait_event[0], NetlinkPacket.type_to_string.get(self._wait_event[1], str(self._wait_event[1]))))
+ with self._cache_lock:
+ self._wait_event = None
+ self._wait_event_alarm.clear()
+
+ def unregister_wait_event(self):
+ """
+ Clear current wait event (cache can only handle one at once)
+ :return:
+ """
+ with self._cache_lock:
+ self._wait_event = None
+ self._wait_event_alarm.clear()
+
+ def override_link_flag(self, ifname, flags):
+ # TODO: dont override all the flags just turn on/off IFF_UP
+ try:
+ with self._cache_lock:
+ self._link_cache[ifname].flags = flags
+ except:
+ pass
+
+ def override_link_mtu(self, ifname, mtu):
+ """
+ Manually override link mtu and ignore any failures
+ :param ifname:
+ :param mtu:
+ :return:
+ """
+ try:
+ with self._cache_lock:
+ self._link_cache[ifname].attributes[Link.IFLA_MTU].value = mtu
+ except:
+ pass
+
+ def override_cache_unslave_link(self, slave, master):
+ """
+ Manually update the cache unslaving SLAVE from MASTER
+
+ When calling link_set_nomaster, we don't want to wait for the RTM_GETLINK
+ notification - if the operation return with NL_SUCCESS we can manually
+ update our cache and move on.
+
+ :param master:
+ :param slave:
+ :return:
+ """
+ with self._cache_lock:
+ self.__unslave_nolock(slave, master)
+
+ def DEBUG_IFNAME(self, ifname, with_addresses=False):
+ """
+ A very useful function to use while debugging, it dumps the netlink
+ packet with debug and color output.
+ """
+ import logging
+ root = logging.getLogger()
+
+ level = root.level
+
+ try:
+ root.setLevel(DEBUG)
+ for handler in root.handlers:
+ handler.setLevel(DEBUG)
+
+ nllistener.log.setLevel(DEBUG)
+ nlpacket.log.setLevel(DEBUG)
+ nlmanager.log.setLevel(DEBUG)
+ with self._cache_lock:
+ obj = self._link_cache[ifname]
+ save_debug = obj.debug
+ obj.debug = True
+ obj.dump()
+ obj.debug = save_debug
+
+ #if with_addresses:
+ # addrs = self._addr_cache.get(ifname, [])
+ # log.error('ADDRESSES=%s' % addrs)
+ # for addr in addrs:
+ # save_debug = addr.debug
+ # addr.debug = True
+ # addr.dump()
+ # addr.debug = save_debug
+ # log.error('-----------')
+ # log.error('-----------')
+ # log.error('-----------')
+ except:
+ traceback.print_exc()
+ # TODO: save log_level at entry and re-apply it after the dump
+ nllistener.log.setLevel(WARNING)
+ nlpacket.log.setLevel(WARNING)
+ nlmanager.log.setLevel(WARNING)
+
+ root.setLevel(level)
+ for handler in root.handlers:
+ handler.setLevel(level)
+
+ def DEBUG_MSG(self, msg):
+ import logging
+ root = logging.getLogger()
+ level = root.level
+
+ try:
+ root.setLevel(DEBUG)
+ for handler in root.handlers:
+ handler.setLevel(DEBUG)
+
+ nllistener.log.setLevel(DEBUG)
+ nlpacket.log.setLevel(DEBUG)
+ nlmanager.log.setLevel(DEBUG)
+
+ save_debug = msg.debug
+ msg.debug = True
+ msg.dump()
+ msg.debug = save_debug
+ except:
+ traceback.print_exc()
+ # TODO: save log_level at entry and re-apply it after the dump
+ nllistener.log.setLevel(WARNING)
+ nlpacket.log.setLevel(WARNING)
+ nlmanager.log.setLevel(WARNING)
+
+ root.setLevel(level)
+ for handler in root.handlers:
+ handler.setLevel(level)
+
+ def _populate_sysfs_ifname_ifindex_dicts(self):
+ ifname_by_ifindex_dict = {}
+ ifindex_by_ifname_dict = {}
+ try:
+ for dir_name in os.listdir('/sys/class/net/'):
+ try:
+ with open('/sys/class/net/%s/ifindex' % dir_name) as f:
+ ifindex = int(f.readline())
+ ifname_by_ifindex_dict[ifindex] = dir_name
+ ifindex_by_ifname_dict[dir_name] = ifindex
+ except (IOError, ValueError):
+ pass
+ except OSError:
+ pass
+ with self._cache_lock:
+ self._ifname_by_ifindex_sysfs = ifname_by_ifindex_dict
+ self._ifindex_by_ifname_sysfs = ifindex_by_ifname_dict
+
+ def get_ifindex(self, ifname):
+ """
+ Return device index or raise NetlinkCacheIfnameNotFoundError
+ :param ifname:
+ :return: int
+ :raise: NetlinkCacheIfnameNotFoundError(NetlinkCacheError)
+ """
+ try:
+ with self._cache_lock:
+ return self._ifindex_by_ifname[ifname]
+ except KeyError:
+ # We assume that if the user requested a valid device ifindex but
+ # for some reason we don't find any trace of it in our cache, we
+ # then use sysfs to make sure that this device exists and fill our
+ # internal help dictionaries.
+ with self._cache_lock:
+ ifindex = self._ifindex_by_ifname_sysfs.get(ifname)
+
+ if ifindex:
+ return ifindex
+ self._populate_sysfs_ifname_ifindex_dicts()
+ try:
+ return self._ifindex_by_ifname_sysfs[ifname]
+ except KeyError:
+ # if we still haven't found any trace of the requested device
+ # we raise a custom exception
+ raise NetlinkCacheIfnameNotFoundError('ifname %s not present in cache' % ifname)
+
+ def get_ifname(self, ifindex):
+ """
+ Return device name or raise NetlinkCacheIfindexNotFoundError
+ :param ifindex:
+ :return: str
+ :raise: NetlinkCacheIfindexNotFoundError (NetlinkCacheError)
+ """
+ try:
+ with self._cache_lock:
+ return self._ifname_by_ifindex[ifindex]
+ except KeyError:
+ # We assume that if the user requested a valid device ifname but
+ # for some reason we don't find any trace of it in our cache, we
+ # then use sysfs to make sure that this device exists and fill our
+ # internal help dictionaries.
+ with self._cache_lock:
+ ifname = self._ifname_by_ifindex_sysfs.get(ifindex)
+
+ if ifname:
+ return ifname
+ self._populate_sysfs_ifname_ifindex_dicts()
+ try:
+ return self._ifname_by_ifindex_sysfs[ifindex]
+ except KeyError:
+ # if we still haven't found any trace of the requested device
+ # we raise a custom exception
+ raise NetlinkCacheIfindexNotFoundError('ifindex %s not present in cache' % ifindex)
+
+ def link_exists(self, ifname):
+ """
+ Check if we have a cache entry for device 'ifname'
+ :param ifname: device name
+ :return: boolean
+ """
+ with self._cache_lock:
+ return ifname in self._link_cache
+
+ def link_is_up(self, ifname):
+ """
+ Check if device 'ifname' has IFF_UP flag
+ :param ifname:
+ :return: boolean
+ """
+ try:
+ with self._cache_lock:
+ return self._link_cache[ifname].flags & Link.IFF_UP
+ except (KeyError, TypeError):
+ # ifname is not present in the cache
+ return False
+ except TypeError as e:
+ return self.__handle_type_error(inspect.currentframe().f_code.co_name, ifname, str(e), return_value=False)
+
+ def link_is_loopback(self, ifname):
+ """
+ Check if device has IFF_LOOPBACK flag
+ :param ifname:
+ :return: boolean
+ """
+ try:
+ with self._cache_lock:
+ return self._link_cache[ifname].flags & Link.IFF_LOOPBACK
+ # IFF_LOOPBACK should be enough, otherwise we can also check for
+ # link.device_type & Link.ARPHRD_LOOPBACK
+ except (KeyError, AttributeError):
+ return False
+ except TypeError as e:
+ return self.__handle_type_error(inspect.currentframe().f_code.co_name, ifname, str(e), return_value=False)
+
+ def link_exists_and_up(self, ifname):
+ """
+ Check if device exists and has IFF_UP flag set
+ :param ifname:
+ :return: tuple (boolean, boolean) -> (link_exists, link_is_up)
+ """
+ try:
+ with self._cache_lock:
+ return True, self._link_cache[ifname].flags & Link.IFF_UP
+ except KeyError:
+ # ifname is not present in the cache
+ return False, False
+ except TypeError as e:
+ return self.__handle_type_error(inspect.currentframe().f_code.co_name, ifname, str(e), return_value=(False, False))
+
+ def link_is_bridge(self, ifname):
+ return self.get_link_kind(ifname) == 'bridge'
+
+ def get_link_kind(self, ifname):
+ """
+ Return link IFLA_INFO_KIND
+ :param ifname:
+ :return: string
+ """
+ try:
+ with self._cache_lock:
+ return self._link_cache[ifname].attributes[Link.IFLA_LINKINFO].value[Link.IFLA_INFO_KIND]
+ except (KeyError, AttributeError):
+ return None
+ except TypeError as e:
+ return self.__handle_type_error(inspect.currentframe().f_code.co_name, ifname, str(e), return_value=None)
+
+ def get_link_mtu(self, ifname):
+ """
+ Return link IFLA_MTU
+ :param ifname:
+ :return: int
+ """
+ return self.get_link_attribute(ifname, Link.IFLA_MTU, default=0)
+
+ def get_link_mtu_str(self, ifname):
+ """
+ Return link IFLA_MTU as string
+ :param ifname:
+ :return: str
+ """
+ return str(self.get_link_mtu(ifname))
+
+ def get_link_address(self, ifname):
+ """
+ Return link IFLA_ADDRESS
+ :param ifname:
+ :return: str
+ """
+ packet = None
+ default_value = ""
+ try:
+ with self._cache_lock:
+ packet = self._link_cache[ifname]
+ return packet.attributes[Link.IFLA_ADDRESS].value.lower()
+ except (KeyError, AttributeError):
+ # KeyError will be raised if:
+ # - ifname is missing from the cache (but link_exists should be called prior this call)
+ # - IFLA_ADDRESS is missing
+ # AttributeError can also be raised if attributes[IFLA_ADDRESS] returns None
+ # If the packet is tagged as a REQUEST packet (priv_flags) we should query sysfs
+ # otherwise default_value is returned.
+ if packet and packet.priv_flags & NLM_F_REQUEST:
+ return self.__sysfs.get_link_address(ifname)
+ else:
+ return default_value
+ except TypeError as e:
+ return self.__handle_type_error(inspect.currentframe().f_code.co_name, ifname, str(e), default_value)
+
+ def get_link_address_raw(self, ifname):
+ """
+ Return link IFLA_ADDRESS as integer
+ :param ifname:
+ :return: int
+ """
+ return self.get_link_attribute_raw(ifname, Link.IFLA_ADDRESS, default=0)
+
+ def get_link_alias(self, ifname):
+ """
+ Return link IFLA_IFALIAS
+ :param ifname:
+ :return: str
+ """
+ return self.get_link_attribute(ifname, Link.IFLA_IFALIAS)
+
+ def get_link_attribute(self, ifname, attr, default=None):
+ """
+ Return link attribute 'attr'.value
+ :param ifname:
+ :param attr:
+ :param default:
+ :return:
+ """
+ try:
+ with self._cache_lock:
+ return self._link_cache[ifname].attributes[attr].value
+ except (KeyError, AttributeError):
+ return default
+ except TypeError as e:
+ return self.__handle_type_error(inspect.currentframe().f_code.co_name, ifname, str(e), return_value=default)
+
+ def get_link_attribute_raw(self, ifname, attr, default=None):
+ """
+ Return link attribute 'attr'.raw
+ :param ifname:
+ :param attr:
+ :param default:
+ :return:
+ """
+ try:
+ with self._cache_lock:
+ return self._link_cache[ifname].attributes[attr].raw
+ except (KeyError, AttributeError):
+ return default
+ except TypeError as e:
+ return self.__handle_type_error(inspect.currentframe().f_code.co_name, ifname, str(e), return_value=default)
+
+ def get_link_slave_kind(self, ifname):
+ """
+ Return device slave kind
+ :param ifname:
+ :return: str
+ """
+ try:
+ with self._cache_lock:
+ return self._link_cache[ifname].attributes[Link.IFLA_LINKINFO].value[Link.IFLA_INFO_SLAVE_KIND]
+ except (KeyError, AttributeError):
+ return None
+ except TypeError as e:
+ return self.__handle_type_error(inspect.currentframe().f_code.co_name, ifname, str(e), return_value=None)
+
+ def get_link_info_data_attribute(self, ifname, info_data_attribute, default=None):
+ """
+ Return device linkinfo:info_data attribute or default value
+ :param ifname:
+ :param info_data_attribute:
+ :param default:
+ :return:
+ """
+ try:
+ with self._cache_lock:
+ return self._link_cache[ifname].attributes[Link.IFLA_LINKINFO].value[Link.IFLA_INFO_DATA][info_data_attribute]
+ except (KeyError, AttributeError):
+ return default
+ except TypeError as e:
+ return self.__handle_type_error(inspect.currentframe().f_code.co_name, ifname, str(e), return_value=default)
+
+ def get_link_info_data(self, ifname):
+ """
+ Return device linkinfo:info_data attribute or default value
+ :param ifname:
+ :param info_data_attribute:
+ :param default:
+ :return:
+ """
+ try:
+ with self._cache_lock:
+ return self._link_cache[ifname].attributes[Link.IFLA_LINKINFO].value[Link.IFLA_INFO_DATA]
+ except (KeyError, AttributeError):
+ return {}
+ except TypeError as e:
+ return self.__handle_type_error(inspect.currentframe().f_code.co_name, ifname, str(e), return_value={})
+
+ def get_link_info_slave_data_attribute(self, ifname, info_slave_data_attribute, default=None):
+ """
+ Return device linkinfo:info_slave_data attribute or default value
+ :param ifname:
+ :param info_data_attribute:
+ :param default:
+ :return:
+ """
+ try:
+ with self._cache_lock:
+ return self._link_cache[ifname].attributes[Link.IFLA_LINKINFO].value[Link.IFLA_INFO_SLAVE_DATA][info_slave_data_attribute]
+ except (KeyError, AttributeError):
+ return default
+ except TypeError as e:
+ return self.__handle_type_error(inspect.currentframe().f_code.co_name, ifname, str(e), return_value=default)
+
+ ################
+ # MASTER & SLAVE
+ ################
+ def get_master(self, ifname):
+ """
+ Return device master's ifname
+ :param ifname:
+ :return: str
+ """
+ try:
+ with self._cache_lock:
+ return self._slaves_master[ifname]
+ except (KeyError, AttributeError):
+ return None
+ except TypeError as e:
+ return self.__handle_type_error(inspect.currentframe().f_code.co_name, ifname, str(e), return_value=None)
+
+ def get_slaves(self, master):
+ """
+ Return all devices ifname enslaved to master device
+ :param master:
+ :return: list of string
+ """
+ try:
+ with self._cache_lock:
+ return list(self._masters_and_slaves[master])
+ except KeyError:
+ return []
+
+ def is_link_enslaved_to(self, slave, master):
+ """
+ Return bool if SLAVE is enslaved to MASTER
+ :param slave:
+ :param master:
+ :return:
+ """
+ try:
+ with self._cache_lock:
+ return self._slaves_master[slave] == master
+ except KeyError:
+ return False
+
+ def get_lower_device_ifname(self, ifname):
+ """
+ Return the lower-device (IFLA_LINK) name or raise KeyError
+ :param ifname:
+ :return: string
+ """
+ try:
+ with self._cache_lock:
+ return self.get_ifname(self._link_cache[ifname].attributes[Link.IFLA_LINK].value)
+ except (NetlinkCacheIfnameNotFoundError, AttributeError, KeyError):
+ return None
+ except TypeError as e:
+ return self.__handle_type_error(inspect.currentframe().f_code.co_name, ifname, str(e), return_value=None)
+
+ ##########################################################################
+ # VRF ####################################################################
+ ##########################################################################
+
+ def get_vrf_table_map(self):
+ vrf_table_map = {}
+ try:
+ with self._cache_lock:
+ for ifname, obj in self._link_cache.iteritems():
+ linkinfo = obj.attributes.get(Link.IFLA_LINKINFO)
+
+ if linkinfo and linkinfo.value.get(Link.IFLA_INFO_KIND) == "vrf":
+ vrf_table_map[linkinfo.value[Link.IFLA_INFO_DATA][Link.IFLA_VRF_TABLE]] = ifname
+ except Exception as e:
+ log.debug("get_vrf_table_map: %s" % str(e))
+ return vrf_table_map
+
+ def get_vrf_table(self, ifname):
+ try:
+ with self._cache_lock:
+ return self._link_cache[ifname].attributes[Link.IFLA_LINKINFO].value[Link.IFLA_INFO_DATA][Link.IFLA_VRF_TABLE]
+ except (KeyError, AttributeError):
+ return 0
+
+ ##########################################################################
+ # BOND ###################################################################
+ ##########################################################################
+
+ def bond_exists(self, ifname):
+ """
+ Check if bond 'ifname' exists
+ :param ifname: bond name
+ :return: boolean
+ """
+ try:
+ with self._cache_lock:
+ return self._link_cache[ifname].attributes[nlpacket.Link.IFLA_LINKINFO].value[nlpacket.Link.IFLA_INFO_KIND] == 'bond'
+ except (KeyError, AttributeError):
+ return False
+ except TypeError as e:
+ return self.__handle_type_error(inspect.currentframe().f_code.co_name, ifname, str(e), return_value=False)
+
+ ##########################################################################
+ # BRIDGE PORT ############################################################
+ ##########################################################################
+
+ def get_bridge_port_multicast_router(self, ifname):
+ """
+ Get bridge port multicast_router value - defaults to 1
+
+ :param ifname:
+ :return:
+ """
+ default_value = 1
+ try:
+ with self._cache_lock:
+ return self._link_cache[ifname].attributes[Link.IFLA_LINKINFO].value[Link.IFLA_INFO_SLAVE_DATA][Link.IFLA_BRPORT_MULTICAST_ROUTER]
+ except (KeyError, AttributeError):
+ # KeyError will be raised if:
+ # - ifname is missing from the cache (but link_exists should be called prior this call)
+ # - IFLA_BRPORT_MULTICAST_ROUTER is missing
+ # AttributeError can also be raised if IFLA_LINKINFO is missing (None.value)
+ # default_value is returned.
+ return default_value
+ except TypeError as e:
+ return self.__handle_type_error(
+ inspect.currentframe().f_code.co_name,
+ ifname,
+ str(e),
+ return_value=default_value
+ )
+
+ ##########################################################################
+ # BRIDGE #################################################################
+ ##########################################################################
+
+ def get_bridge_multicast_snooping(self, ifname):
+ """
+ Get bridge multicast_snooping value - defaults to 1
+
+ :param ifname:
+ :return:
+ """
+ default_value = 1
+ try:
+ with self._cache_lock:
+ return self._link_cache[ifname].attributes[Link.IFLA_LINKINFO].value[Link.IFLA_INFO_DATA][Link.IFLA_BR_MCAST_SNOOPING]
+ except (KeyError, AttributeError):
+ # KeyError will be raised if:
+ # - ifname is missing from the cache (but link_exists should be called prior this call)
+ # - IFLA_BR_MCAST_SNOOPING is missing
+ # AttributeError can also be raised if IFLA_LINKINFO is missing (None.value)
+ # default_value is returned.
+ return default_value
+ except TypeError as e:
+ return self.__handle_type_error(inspect.currentframe().f_code.co_name, ifname, str(e), return_value=default_value)
+
+ def get_bridge_stp(self, ifname):
+ """
+ WARNING: ifname should be a bridge
+ """
+ try:
+ with self._cache_lock:
+ return self._link_cache[ifname].attributes[Link.IFLA_LINKINFO].value[Link.IFLA_INFO_DATA][Link.IFLA_BR_STP_STATE]
+ except (KeyError, AttributeError):
+ return 0
+ except TypeError as e:
+ return self.__handle_type_error(inspect.currentframe().f_code.co_name, ifname, str(e), return_value=0)
+
+ def get_brport_cost(self, ifname):
+ try:
+ with self._cache_lock:
+ return self._link_cache[ifname].attributes[Link.IFLA_LINKINFO].value[Link.IFLA_INFO_DATA][Link.IFLA_BRPORT_COST]
+ except (KeyError, AttributeError):
+ return None
+ except TypeError as e:
+ return self.__handle_type_error(inspect.currentframe().f_code.co_name, ifname, str(e), return_value=None)
+
+ def get_brport_priority(self, ifname):
+ try:
+ with self._cache_lock:
+ return self._link_cache[ifname].attributes[Link.IFLA_LINKINFO].value[Link.IFLA_INFO_DATA][Link.IFLA_BRPORT_PRIORITY]
+ except (KeyError, AttributeError):
+ return None
+ except TypeError as e:
+ return self.__handle_type_error(inspect.currentframe().f_code.co_name, ifname, str(e), return_value=None)
+
+ def get_brport_unicast_flood(self, ifname):
+ try:
+ with self._cache_lock:
+ return self._link_cache[ifname].attributes[Link.IFLA_LINKINFO].value[Link.IFLA_INFO_DATA][Link.IFLA_BRPORT_UNICAST_FLOOD]
+ except (KeyError, AttributeError):
+ return 0
+ except TypeError as e:
+ return self.__handle_type_error(inspect.currentframe().f_code.co_name, ifname, str(e), return_value=0)
+
+ def get_brport_multicast_flood(self, ifname):
+ try:
+ with self._cache_lock:
+ return self._link_cache[ifname].attributes[Link.IFLA_LINKINFO].value[Link.IFLA_INFO_DATA][Link.IFLA_BRPORT_MCAST_FLOOD]
+ except (KeyError, AttributeError):
+ return 0
+ except TypeError as e:
+ return self.__handle_type_error(inspect.currentframe().f_code.co_name, ifname, str(e), return_value=0)
+
+ def get_brport_broadcast_flood(self, ifname):
+ try:
+ with self._cache_lock:
+ return self._link_cache[ifname].attributes[Link.IFLA_LINKINFO].value[Link.IFLA_INFO_DATA][Link.IFLA_BRPORT_BCAST_FLOOD]
+ except (KeyError, AttributeError):
+ return 0
+ except TypeError as e:
+ return self.__handle_type_error(inspect.currentframe().f_code.co_name, ifname, str(e), return_value=0)
+
+ def get_brport_neigh_suppress(self, ifname):
+ try:
+ with self._cache_lock:
+ return self._link_cache[ifname].attributes[Link.IFLA_LINKINFO].value[Link.IFLA_INFO_DATA][Link.IFLA_BRPORT_NEIGH_SUPPRESS]
+ except (KeyError, AttributeError):
+ return 0
+ except TypeError as e:
+ return self.__handle_type_error(inspect.currentframe().f_code.co_name, ifname, str(e), return_value=0)
+
+ def get_brport_learning(self, ifname):
+ try:
+ with self._cache_lock:
+ return self._link_cache[ifname].attributes[Link.IFLA_LINKINFO].value[Link.IFLA_INFO_SLAVE_DATA][Link.IFLA_BRPORT_LEARNING]
+ except (KeyError, AttributeError):
+ return 0
+
+ def get_pvid_and_vids(self, ifname):
+ """
+ vlan-identifiers are stored in:
+
+ self._bridge_vlan_cache = {
+ ifname: [(vlan, flag), (vlan, flag), ...]
+ }
+
+ Those vlans are stored in compressed format (RTEXT_FILTER_BRVLAN_COMPRESSED)
+ We only uncompress the vlan when the user request it.
+
+ :param ifname:
+ :return tuple: pvid, vids = int, [int, ]
+ """
+ pvid = None
+ vlans = []
+ try:
+ range_begin_vlan_id = None
+ range_flag = None
+
+ with self._cache_lock:
+ bridge_vlans_tuples = self._bridge_vlan_cache.get(ifname)
+
+ if bridge_vlans_tuples:
+ for (vlan_id, vlan_flag) in sorted(bridge_vlans_tuples):
+
+ if vlan_flag & Link.BRIDGE_VLAN_INFO_PVID:
+ pvid = vlan_id
+
+ if vlan_flag & Link.BRIDGE_VLAN_INFO_RANGE_BEGIN:
+ range_begin_vlan_id = vlan_id
+ range_flag = vlan_flag
+
+ elif vlan_flag & Link.BRIDGE_VLAN_INFO_RANGE_END:
+ range_flag |= vlan_flag
+
+ if not range_begin_vlan_id:
+ log.warning("BRIDGE_VLAN_INFO_RANGE_END is %d but we never "
+ "saw a BRIDGE_VLAN_INFO_RANGE_BEGIN" % vlan_id)
+ range_begin_vlan_id = vlan_id
+
+ for x in xrange(range_begin_vlan_id, vlan_id + 1):
+ vlans.append(x)
+
+ range_begin_vlan_id = None
+ range_flag = None
+
+ else:
+ vlans.append(vlan_id)
+ except:
+ log.exception("get_bridge_vids")
+ return pvid, vlans
+
+ def get_pvid(self, ifname):
+ """
+ Get Port VLAN ID for device 'ifname'
+
+ :param ifname:
+ :return:
+ """
+ pvid = None
+ try:
+ with self._cache_lock:
+ bridge_vlans_tuples = self._bridge_vlan_cache.get(ifname)
+
+ if bridge_vlans_tuples:
+
+ for (vlan_id, vlan_flag) in sorted(bridge_vlans_tuples):
+
+ if vlan_flag & Link.BRIDGE_VLAN_INFO_PVID:
+ return vlan_id
+ except:
+ log.exception("get_pvid")
+ return pvid
+
+ def bridge_exists(self, ifname):
+ """
+ Check if cached device is a bridge
+ """
+ try:
+ with self._cache_lock:
+ return self._link_cache[ifname].attributes[Link.IFLA_LINKINFO].value[Link.IFLA_INFO_KIND] == "bridge"
+ except (KeyError, AttributeError):
+ return False
+ except TypeError as e:
+ return self.__handle_type_error(inspect.currentframe().f_code.co_name, ifname, str(e), return_value=False)
+
+ def bridge_is_vlan_aware(self, ifname):
+ """
+ Return IFLA_BR_VLAN_FILTERING value
+ :param ifname:
+ :return: boolean
+ """
+ try:
+ with self._cache_lock:
+ return self._link_cache[ifname].attributes[Link.IFLA_LINKINFO].value[Link.IFLA_INFO_DATA][Link.IFLA_BR_VLAN_FILTERING]
+ except (KeyError, AttributeError):
+ return False
+ except TypeError as e:
+ return self.__handle_type_error(inspect.currentframe().f_code.co_name, ifname, str(e), return_value=False)
+
+ def link_is_bridge_port(self, ifname):
+ try:
+ with self._cache_lock:
+ return self._link_cache[ifname].attributes[Link.IFLA_LINKINFO].value[Link.IFLA_INFO_SLAVE_KIND] == "bridge"
+ except (KeyError, AttributeError):
+ return False
+ except TypeError as e:
+ return self.__handle_type_error(inspect.currentframe().f_code.co_name, ifname, str(e), return_value=False)
+
+ def bridge_port_exists(self, bridge_name, brport_name):
+ try:
+ with self._cache_lock:
+ # we are assuming that bridge_name is a valid bridge?
+ return self._slaves_master[brport_name] == bridge_name
+ except (KeyError, AttributeError):
+ return False
+ except TypeError as e:
+ return self.__handle_type_error(inspect.currentframe().f_code.co_name, bridge_name, str(e), return_value=False)
+
+ def get_bridge_name_from_port(self, bridge_port_name):
+ bridge_name = self.get_master(bridge_port_name)
+ # now that we have the master's name we just need to double check
+ # if the master is really a bridge
+ return bridge_name if self.link_is_bridge(bridge_name) else None
+
+ #def is_link_slave_kind(self, ifname, _type):
+ # try:
+ # with self._cache_lock:
+ # return self._link_cache[ifname].attributes[Link.IFLA_LINKINFO].value[Link.IFLA_INFO_SLAVE_KIND] == _type
+ # except (KeyError, AttributeError):
+ # return False
+
+ ########################################
+
+ def get_link_ipv6_addrgen_mode(self, ifname):
+ try:
+ with self._cache_lock:
+ return self._link_cache[ifname].attributes[Link.IFLA_AF_SPEC].value[socket.AF_INET6][Link.IFLA_INET6_ADDR_GEN_MODE]
+ except (KeyError, AttributeError):
+ # default to 0 (eui64)
+ return 0
+ except TypeError as e:
+ return self.__handle_type_error(inspect.currentframe().f_code.co_name, ifname, str(e), return_value=0)
+
+ #####################################################
+ #####################################################
+ #####################################################
+ #####################################################
+ #####################################################
+
+ def add_link(self, link):
+ """
+ Cache RTM_NEWLINK packet
+ :param link:
+ :return:
+ """
+ ifindex = link.ifindex
+ ifname = link.get_attribute_value(Link.IFLA_IFNAME)
+
+ # check if this device is registered in the ignore list
+ with self._ignore_rtm_newlinkq_lock:
+ if ifname in self._ignore_rtm_newlinkq:
+ return
+ # check if this device is registered in the nomaster list:
+ # if so we need to remove IFLA_MASTER attribute (if it fails
+ # it means we've received the final notification and we should
+ # unregister the device from our list.
+ with self._rtm_newlink_nomasterq_lock:
+ if ifname in self._rtm_newlink_nomasterq:
+ try:
+ del link.attributes[Link.IFLA_MASTER]
+ except:
+ self._rtm_newlink_nomasterq.remove(ifname)
+
+ # we need to check if the device was previously enslaved
+ # so we can update the _masters_and_slaves and _slaves_master
+ # dictionaries if the master has changed or was un-enslaved.
+ old_ifla_master = None
+
+ with self._cache_lock:
+
+ # do we have a wait event registered for RTM_NEWLINK this ifname
+ if self._wait_event and self._wait_event == (ifname, RTM_NEWLINK):
+ self._wait_event_alarm.set()
+
+ try:
+ ifla_master_attr = self._link_cache[ifname].attributes.get(Link.IFLA_MASTER)
+
+ if ifla_master_attr:
+ old_ifla_master = ifla_master_attr.get_pretty_value()
+ except KeyError:
+ # link is not present in the cache
+ pass
+ except AttributeError:
+ # if this code is ever reached, this is very concerning and
+ # should never happen as _link_cache should always contains
+ # nlpacket.NetlinkPacket... maybe have some extra handling
+ # here just in case?
+ pass
+
+ self._link_cache[ifname] = link
+
+ ######################################################
+ # update helper dictionaries and handle link renamed #
+ ######################################################
+ if ifindex:
+ # ifindex can be None for packet added on ACK, it means
+ # that we are caching the request packet and not the
+ # notification coming from the kernel. We can leave
+ # those data-strctures empty and rely on our try/excepts
+ # in get_ifname/get_ifindex/get_master to do the work.
+
+ self._ifindex_by_ifname[ifname] = ifindex
+
+ rename_detected = False
+ old_ifname_entry_for_ifindex = self._ifname_by_ifindex.get(ifindex)
+
+ if old_ifname_entry_for_ifindex and old_ifname_entry_for_ifindex != ifname:
+ # The ifindex was reused for a new interface before we got the
+ # RTM_DELLINK notification or the device using that ifindex was
+ # renamed. We need to update the cache accordingly.
+ rename_detected = True
+
+ self._ifname_by_ifindex[ifindex] = ifname
+
+ if rename_detected:
+ # in this case we detected a rename... It should'nt happen has we should get a RTM_DELLINK before that.
+ # if we still detect a rename the opti is to get rid of the stale value directly
+ try:
+ del self._ifindex_by_ifname[old_ifname_entry_for_ifindex]
+ except KeyError:
+ log.debug('update_helper_dicts: del _ifindex_by_ifname[%s]: KeyError ifname: %s'
+ % (old_ifname_entry_for_ifindex, old_ifname_entry_for_ifindex))
+ try:
+ del self._link_cache[old_ifname_entry_for_ifindex]
+ except KeyError:
+ log.debug('update_helper_dicts: del _link_cache[%s]: KeyError ifname: %s'
+ % (old_ifname_entry_for_ifindex, old_ifname_entry_for_ifindex))
+ ######################################################
+ ######################################################
+
+ link_ifla_master_attr = link.attributes.get(Link.IFLA_MASTER)
+ if link_ifla_master_attr:
+ link_ifla_master = link_ifla_master_attr.get_pretty_value()
+ else:
+ link_ifla_master = None
+
+ # if the link has a master we need to store it in an helper dictionary, where
+ # the key is the master ifla_ifname and the value is a list of slaves, example:
+ # _masters_slaves_dict = {
+ # 'bond0': ['swp21', 'swp42']
+ # }
+ # this will be useful in the case we need to iterate on all slaves of a specific link
+
+ if old_ifla_master:
+ if old_ifla_master != link_ifla_master:
+ # the link was previously enslaved but master is now unset on this device
+ # we need to reflect that on the _masters_and_slaves and _slaves_master dictionaries
+ try:
+ self.__unslave_nolock(slave=ifname)
+ except NetlinkCacheIfindexNotFoundError:
+ pass
+ else:
+ # the master status didn't change we can assume that our internal
+ # masters_slaves dictionary is up to date and return here
+ return
+
+ if not link_ifla_master:
+ return
+
+ master_ifname = self._ifname_by_ifindex.get(link_ifla_master)
+
+ if not master_ifname:
+ # in this case we have a link object with IFLA_MASTER set to a ifindex
+ # but this ifindex is not in our _ifname_by_ifindex dictionary thus it's
+ # not in the _link_cache yet. This situation may happen when getting the
+ # very first link dump. The kernel dumps device in the "ifindex" order.
+ #
+ # So let's say you have a box with 4 ports (lo, eth0, swp1, swp2), then
+ # manually create a bond (bond0) and enslave swp1 and swp2, bond0 will
+ # have ifindex 5 but when getting the link dump swp1 will be handled first
+ # so at this point the cache has no idea if ifindex 5 is valid or not.
+ # But since we've made it this far we can assume that this is probably a
+ # valid device and will use sysfs to confirm.
+ master_device_path = '/sys/class/net/%s/master' % ifname
+
+ if os.path.exists(master_device_path):
+ # this check is necessary because realpath doesn't return None on error
+ # it returns it's input argument...
+ # >>> os.path.realpath('/sys/class/net/device_not_found')
+ # '/sys/class/net/device_not_found'
+ # >>>
+ master_ifname = os.path.basename(os.path.realpath(master_device_path))
+
+ if master_ifname in self._masters_and_slaves:
+ self._masters_and_slaves[master_ifname].add(ifname)
+ else:
+ self._masters_and_slaves[master_ifname] = set([ifname])
+
+ self._slaves_master[ifname] = master_ifname
+
+ def update_link_info_data(self, ifname, ifla_info_data):
+ """
+ Update specific IFLA_INFO_DATA attributes of an existing cached device
+ ignore all errors
+ """
+ try:
+ with self._cache_lock:
+ self._link_cache[ifname].attributes[Link.IFLA_LINKINFO].value[Link.IFLA_INFO_DATA].update(ifla_info_data)
+ except:
+ pass
+
+ def add_bridge_vlan(self, msg):
+ """
+ Process AF_BRIDGE family packets (AF_BRIDGE family should be check
+ before calling this function).
+
+ Extract VLAN_INFO (vlan id and flag) and store it in cache.
+
+ :param link:
+ :return:
+ """
+ vlans_list = []
+
+ with self._cache_lock:
+ ifla_af_spec = msg.get_attribute_value(Link.IFLA_AF_SPEC)
+ ifname = msg.get_attribute_value(Link.IFLA_IFNAME)
+
+ if not ifla_af_spec:
+ return
+
+ try:
+ # We need to check if this object is still in cache, after a bridge
+ # is removed we still receive AF_BRIDGE notifications for it's slave
+ # those notifications should be ignored.
+ ifla_master = msg.get_attribute_value(Link.IFLA_MASTER)
+
+ if not ifla_master or not ifla_master in self._ifname_by_ifindex:
+ return
+ except:
+ pass
+
+ # Example IFLA_AF_SPEC
+ # 20: 0x1c001a00 .... Length 0x001c (28), Type 0x001a (26) IFLA_AF_SPEC
+ # 21: 0x08000200 .... Nested Attribute - Length 0x0008 (8), Type 0x0002 (2) IFLA_BRIDGE_VLAN_INFO
+ # 22: 0x00000a00 ....
+ # 23: 0x08000200 .... Nested Attribute - Length 0x0008 (8), Type 0x0002 (2) IFLA_BRIDGE_VLAN_INFO
+ # 24: 0x00001000 ....
+ # 25: 0x08000200 .... Nested Attribute - Length 0x0008 (8), Type 0x0002 (2) IFLA_BRIDGE_VLAN_INFO
+ # 26: 0x00001400 ....
+ for x_type, x_value in ifla_af_spec.iteritems():
+ if x_type == Link.IFLA_BRIDGE_VLAN_INFO:
+ for vlan_flag, vlan_id in x_value:
+ # We store these in the tuple as (vlan, flag) instead
+ # (flag, vlan) so that we can sort the list of tuples
+ vlans_list.append((vlan_id, vlan_flag))
+
+ self._bridge_vlan_cache.update({ifname: vlans_list})
+
+ def force_add_slave(self, master, slave):
+ """
+ When calling link_set_master, we don't want to wait for the RTM_GETLINK
+ notification - if the operation return with NL_SUCCESS we can manually
+ update our cache and move on
+ :param master:
+ :param slave:
+ :return:
+ """
+ try:
+ with self._cache_lock:
+ master_slaves = self._masters_and_slaves.get(master)
+
+ if not master_slaves:
+ self._masters_and_slaves[master] = {slave}
+ else:
+ master_slaves.add(slave)
+
+ # if the slave is already enslaved to another device we should
+ # make sure to remove it from the _masters_and_slaves data
+ # structure as well.
+ old_master = self._slaves_master.get(slave)
+
+ if old_master:
+ try:
+ self._masters_and_slaves.get(old_master, []).remove(slave)
+ except:
+ pass
+
+ self._slaves_master[slave] = master
+ except:
+ # since this is an optimization function we can ignore all error
+ pass
+
+ def force_add_slave_list(self, master, slave_list):
+ """
+ When calling link_set_master, we don't want to wait for the RTM_GETLINK
+ notification - if the operation return with NL_SUCCESS we can manually
+ update our cache and move on
+ :param master:
+ :param slave:
+ :return:
+ """
+ try:
+ with self._cache_lock:
+ master_slaves = self._masters_and_slaves.get(master)
+
+ if not master_slaves:
+ self._masters_and_slaves[master] = set(slave_list)
+ else:
+ master_slaves.update(slave_list)
+
+ for slave in slave_list:
+ self._slaves_master[slave] = master
+ except:
+ # since this is an optimization function we can ignore all error
+ pass
+
+ def force_remove_link(self, ifname):
+ """
+ When calling link_del (RTM_DELLINK) we need to manually remove the
+ associated cache entry - the RTM_DELLINK notification isn't received
+ instantaneously - we don't want to keep stale value in our cache
+ :param ifname:
+ :return:
+ """
+ try:
+ ifindex = self.get_ifindex(ifname)
+ except (KeyError, NetlinkCacheIfnameNotFoundError):
+ ifindex = None
+ self.remove_link(None, link_ifname=ifname, link_ifindex=ifindex)
+
+ def remove_link(self, link, link_ifname=None, link_ifindex=None):
+ """ Process RTM_DELLINK packet and purge the cache accordingly """
+ if link:
+ ifindex = link.ifindex
+ ifname = link.get_attribute_value(Link.IFLA_IFNAME)
+ try:
+ # RTM_DELLINK received - we can now remove ifname from the
+ # ignore_rtm_newlinkq list. We don't bother checkin if the
+ # if name is present in the list (because it's likely in)
+ with self._ignore_rtm_newlinkq_lock:
+ self._ignore_rtm_newlinkq.remove(ifname)
+ except ValueError:
+ pass
+ else:
+ ifname = link_ifname
+ ifindex = link_ifindex
+
+ link_ifla_master = None
+ # when an enslaved device is removed we receive the RTM_DELLINK
+ # notification without the IFLA_MASTER attribute, we need to
+ # get the previous cached value in order to correctly update the
+ # _masters_and_slaves dictionary
+
+ with self._cache_lock:
+ try:
+ try:
+ ifla_master_attr = self._link_cache[ifname].attributes.get(Link.IFLA_MASTER)
+ if ifla_master_attr:
+ link_ifla_master = ifla_master_attr.get_pretty_value()
+ except KeyError:
+ # link is not present in the cache
+ pass
+ except AttributeError:
+ # if this code is ever reached this is very concerning and
+ # should never happen as _link_cache should always contains
+ # nlpacket.NetlinkPacket maybe have some extra handling here
+ # just in case?
+ pass
+ finally:
+ del self._link_cache[ifname]
+ except KeyError:
+ # KeyError means that the link doesn't exists in the cache
+ log.debug('del _link_cache: KeyError ifname: %s' % ifname)
+
+ try:
+ # like in __unslave_nolock() we need to make sure that all deleted link
+ # have their bridge-vlans and _slaves_master entries cleared.
+ for slave in list(self._masters_and_slaves[ifname]):
+ self.__unslave_nolock(slave, master=ifname)
+ except:
+ pass
+
+ try:
+ del self._bridge_vlan_cache[ifname]
+ except:
+ pass
+
+ try:
+ del self._ifname_by_ifindex[ifindex]
+ except KeyError:
+ log.debug('del _ifname_by_ifindex: KeyError ifindex: %s' % ifindex)
+
+ try:
+ del self._ifindex_by_ifname[ifname]
+ except KeyError:
+ log.debug('del _ifindex_by_ifname: KeyError ifname: %s' % ifname)
+
+ try:
+ del self._addr_cache[ifname]
+ except KeyError:
+ log.debug('del _addr_cache: KeyError ifname: %s' % ifname)
+
+ try:
+ del self._masters_and_slaves[ifname]
+ except KeyError:
+ log.debug('del _masters_and_slaves: KeyError ifname: %s' % ifname)
+
+ # if the device was enslaved to another device we need to remove
+ # it's entry from our _masters_and_slaves dictionary
+ if link_ifla_master > 0:
+ try:
+ self.__unslave_nolock(slave=ifname)
+ except NetlinkCacheIfindexNotFoundError as e:
+ log.debug('cache: remove_link: %s: %s' % (ifname, str(e)))
+ except KeyError:
+ log.debug('_masters_and_slaves[if%s].remove(%s): KeyError' % (link_ifla_master, ifname))
+
+ def _address_get_ifname_and_ifindex(self, addr):
+ ifindex = addr.ifindex
+ label = addr.get_attribute_value(Address.IFA_LABEL)
+
+ if not label:
+ try:
+ label = self.get_ifname(ifindex)
+ except NetlinkCacheIfindexNotFoundError:
+ pass
+
+ return label, ifindex
+
+ def __check_and_replace_address(self, address_list, new_addr):
+ """
+ Check if new_addr is in address_list, if found we replace the occurrence
+ with the new and update object "new_addr"
+
+ address_list should be a valid list (check before calling to improve perf)
+ :param address_list:
+ :param new_addr:
+ :return:
+ """
+ ip_with_prefix = new_addr.get_attribute_value(Address.IFA_ADDRESS).with_prefixlen
+
+ for index, addr in enumerate(address_list):
+ if addr.get_attribute_value(Address.IFA_ADDRESS).with_prefixlen == ip_with_prefix:
+ address_list[index] = new_addr
+ return True
+
+ return False
+
+ def add_address(self, addr):
+ ifname, ifindex = self._address_get_ifname_and_ifindex(addr)
+
+ if not ifname:
+ log.debug('nlcache: add_address: cannot cache addr for ifindex %s' % ifindex)
+ return
+
+ ip_version = addr.get_attribute_value(Address.IFA_ADDRESS).version
+
+ with self._cache_lock:
+
+ if ifname in self._addr_cache:
+ address_list = self._addr_cache[ifname][ip_version]
+ # First check if the address is already cached, if so
+ # we need to update it's entry with the new obj
+ if not address_list or not self.__check_and_replace_address(address_list, addr):
+ address_list.append(addr)
+ else:
+ self._addr_cache[ifname] = {
+ 4: [],
+ 6: [],
+ ip_version: [addr]
+ }
+
+ def force_address_flush_family(self, ifname, family):
+ try:
+ with self._cache_lock:
+ self._addr_cache[ifname][family] = []
+ except:
+ pass
+
+ def address_flush_link(self, ifname):
+ """
+ Flush address cache for link 'ifname'
+ :param ifname:
+ :return:
+ """
+ try:
+ with self._cache_lock:
+ self._addr_cache[ifname] = {4: [], 6: []}
+ except:
+ pass
+
+ def force_remove_addr(self, ifname, addr):
+ """
+ When calling addr_del (RTM_DELADDR) we need to manually remove the
+ associated cache entry - the RTM_DELADDR notification isn't received
+ instantaneously - we don't want to keep stale value in our cache
+ :param ifname:
+ :param addr:
+ """
+ try:
+ with self._cache_lock:
+ # iterate through the interface addresses
+ # to find which one to remove from the cache
+ obj_to_remove = None
+
+ for cache_addr in self._addr_cache[ifname][addr.version]:
+ try:
+ if cache_addr.attributes[Address.IFA_ADDRESS].value.with_prefixlen == addr.with_prefixlen:
+ obj_to_remove = cache_addr
+ except:
+ try:
+ if cache_addr.attributes[Address.IFA_LOCAL].value.with_prefixlen == addr.with_prefixlen:
+ obj_to_remove = cache_addr
+ except:
+ return
+ if obj_to_remove:
+ self._addr_cache[ifname][addr.version].remove(obj_to_remove)
+ except:
+ pass
+
+ def remove_address(self, addr_to_remove):
+ ifname, _ = self._address_get_ifname_and_ifindex(addr_to_remove)
+
+ with self._cache_lock:
+ # iterate through the interface addresses
+ # to find which one to remove from the cache
+ try:
+ ip_version = addr_to_remove.get_attribute_value(Address.IFA_ADDRESS).version
+ except:
+ try:
+ ip_version = addr_to_remove.get_attribute_value(Address.IFA_LOCAL).version
+ except:
+ # print debug error
+ return
+
+ addrs_for_interface = self._addr_cache.get(ifname, {}).get(ip_version)
+
+ if not addrs_for_interface:
+ return
+
+ list_addr_to_remove = []
+
+ for addr in addrs_for_interface:
+ # compare each object attribute to see if they match
+ addr_match = False
+
+ for ifa_attr in self._ifa_attributes:
+ if addr.get_attribute_value(ifa_attr) != addr_to_remove.get_attribute_value(ifa_attr):
+ addr_match = False
+ break
+ addr_match = True
+ # if the address attribute matches we need to remove this one
+
+ if addr_match:
+ list_addr_to_remove.append(addr)
+
+ for addr in list_addr_to_remove:
+ try:
+ addrs_for_interface.remove(addr)
+ except ValueError as e:
+ log.debug('nlcache: remove_address: exception: %s' % e)
+
+ def get_addresses_list(self, ifname):
+ addresses = []
+ try:
+ with self._cache_lock:
+ intf_addresses = self._addr_cache[ifname]
+ for addr in intf_addresses.get(4, []):
+ addresses.append(addr.attributes[Address.IFA_ADDRESS].value)
+ for addr in intf_addresses.get(6, []):
+ addresses.append(addr.attributes[Address.IFA_ADDRESS].value)
+ return addresses
+ except (KeyError, AttributeError):
+ return addresses
+
+ def get_addresses_objects_list(self, ifname):
+ addresses = []
+ try:
+ with self._cache_lock:
+ intf_addresses = self._addr_cache[ifname]
+ for addr in intf_addresses.get(4, []):
+ addresses.append(addr)
+ for addr in intf_addresses.get(6, []):
+ addresses.append(addr)
+ return addresses
+ except (KeyError, AttributeError):
+ return addresses
+
+ def link_has_ip(self, ifname):
+ try:
+ with self._cache_lock:
+ intf_addresses = self._addr_cache[ifname]
+ return bool(intf_addresses.get(4, None) or intf_addresses.get(6, None))
+ except:
+ return False
+
+ ############################################################################
+ ############################################################################
+ ############################################################################
+
+ def add_netconf(self, msg):
+ """
+ cache RTM_NEWNETCONF objects
+ {
+ family: {
+ ifindex: RTM_NEWNETCONF
+ }
+ }
+ we currently only support AF_INET, AF_INET6 and AF_MPLS family.
+ """
+ try:
+ with self._netconf_cache_lock:
+ self._netconf_cache[msg.family][msg.get_attribute_value(msg.NETCONFA_IFINDEX)] = msg
+ except:
+ pass
+
+ def remove_netconf(self, msg):
+ """
+ Process RTM_DELNETCONF, remove associated entry in our _netconf_cache
+ """
+ try:
+ with self._netconf_cache_lock:
+ del self._netconf_cache[msg.family][msg.get_attribute_value(msg.NETCONFA_IFINDEX)]
+ except:
+ pass
+
+ def get_netconf_forwarding(self, family, ifname):
+ """
+ Return netconf device forwarding value
+ """
+ try:
+ with self._netconf_cache_lock:
+ return self._netconf_cache[family][self.get_ifindex(ifname)].get_attribute_value(Netconf.NETCONFA_FORWARDING)
+ except:
+ # if KeyError and family == AF_INET6: ipv6 is probably disabled on this device
+ return None
+
+ def get_netconf_mpls_input(self, ifname):
+ """
+ Return netconf device MPLS input value
+ """
+ try:
+ with self._netconf_cache_lock:
+ return self._netconf_cache[AF_MPLS][self.get_ifindex(ifname)].get_attribute_value(Netconf.NETCONFA_INPUT)
+ except:
+ return None
+
+ ############################################################################
+ ############################################################################
+ ############################################################################
+
+ def get_ifupdown2_addresses_list(self, ifaceobj_list, ifname, with_address_virtual=False):
+ """
+ With the new live cache, we store every intf's addresses even if they
+ werent configured by ifupdown2. We need to filter those out to avoid
+ problems
+
+ To do so we look at the previous configuration made by ifupdown2
+ (with the help of the statemanager) together with the addresses
+ specified by the user in /etc/network/interfaces, these addresses
+ are then compared to the running state of the intf
+ """
+ if not ifaceobj_list:
+ ifaceobj_list = []
+
+ config_addrs = set(
+ self.get_user_config_ip_addrs_with_attrs_in_ipnetwork_format(
+ ifaceobj_list,
+ with_address_virtual=with_address_virtual,
+ details=False
+ )
+ )
+
+ for previous_state_addr in self.get_user_config_ip_addrs_with_attrs_in_ipnetwork_format(
+ statemanager.statemanager_api.get_ifaceobjs(ifname),
+ with_address_virtual=with_address_virtual,
+ details=False
+ ):
+ config_addrs.add(previous_state_addr)
+
+ ifupdown2_addresses = []
+
+ for addr in self.get_addresses_objects_list(ifname):
+ ip_addr = addr.attributes[Address.IFA_ADDRESS].value
+ if ip_addr in config_addrs:
+ ifupdown2_addresses.append(ip_addr)
+ elif not addr.scope & Route.RT_SCOPE_LINK:
+ ifupdown2_addresses.append(ip_addr)
+
+ return ifupdown2_addresses
+
+ def get_user_config_ip_addrs_with_attrs_in_ipnetwork_format(self, ifaceobj_list, with_address_virtual=False, details=True):
+ """
+ if details=True:
+ This function will return a OrderedDict of user addresses (from /e/n/i)
+ An OrderedDict is necessary because the addresses order is important (primary etc)
+
+ if details=False:
+ Function will return an ordered list of ip4 followed by ip6 as configured in /e/n/i.
+
+ all of the IP object were created by IPNetwork.
+ """
+ if not ifaceobj_list:
+ return {} if details else []
+
+ ip4 = []
+ ip6 = []
+
+ for ifaceobj in ifaceobj_list:
+ addresses = ifaceobj.get_attr_value('address')
+
+ if addresses:
+ for addr_index, addr in enumerate(addresses):
+ if '/' in addr:
+ ip_network_obj = IPNetwork(addr)
+ else:
+ # if netmask is specified under the stanza we need to use to
+ # create the IPNetwork objects, otherwise let IPNetwork figure
+ # out the correct netmask for ip4 & ip6
+ netmask = ifaceobj.get_attr_value_n('netmask', addr_index)
+
+ if netmask:
+ ip_network_obj = IPNetwork('%s/%s' % (addr, netmask))
+ else:
+ ip_network_obj = IPNetwork(addr)
+
+ if not details:
+ # if no details=False we don't need to go further and our lists
+ # will only store the IPNetwork object and nothing else
+ if ip_network_obj.version == 6:
+ ip6.append(ip_network_obj)
+ else:
+ ip4.append(ip_network_obj)
+ continue
+
+ addr_attributes = {}
+
+ for attr in ['broadcast', 'pointopoint', 'scope', 'preferred-lifetime']:
+ attr_value = ifaceobj.get_attr_value_n(attr, addr_index)
+
+ if attr_value:
+ addr_attributes[attr] = attr_value
+
+ if ip_network_obj.version == 6:
+ ip6.append((ip_network_obj, addr_attributes))
+ else:
+ ip4.append((ip_network_obj, addr_attributes))
+
+ if not with_address_virtual:
+ continue
+ #
+ # address-virtual and vrrp ips also needs to be accounted for
+ #
+ addresses_virtual = ifaceobj.get_attr_value('address-virtual')
+ vrrp = ifaceobj.get_attr_value('vrrp')
+
+ for attr_config in (addresses_virtual, vrrp):
+ for addr_virtual_entry in attr_config or []:
+ for addr in addr_virtual_entry.split():
+ try:
+ ip_network_obj = IPNetwork(addr)
+
+ if ip_network_obj.version == 6:
+ if not details:
+ ip6.append(ip_network_obj)
+ else:
+ ip6.append((ip_network_obj, {}))
+ else:
+ if not details:
+ ip4.append(ip_network_obj)
+ else:
+ ip4.append((ip_network_obj, {}))
+ except:
+ continue
+
+ # always return ip4 first, followed by ip6
+ if not details:
+ return ip4 + ip6
+ else:
+ user_config_addresses = OrderedDict()
+
+ for addr, addr_details in ip4:
+ user_config_addresses[addr] = addr_details
+
+ for addr, addr_details in ip6:
+ user_config_addresses[addr] = addr_details
+
+ return user_config_addresses
+ ############################################################################
+ ############################################################################
+ ############################################################################
+
+ def addr_is_cached(self, ifname, addr):
+ """
+ return True if addr is in cache
+
+ We might need to check if metric/peer and other attribute are also correctly cached.
+ We might also need to add a "force" attribute to skip the cache check
+ :param ifname:
+ :param ifindex:
+ :return:
+ """
+ try:
+ with self._cache_lock:
+ for cache_addr in self._addr_cache[ifname][addr.version]:
+ try:
+ ifa_address = cache_addr.attributes[Address.IFA_ADDRESS].value
+ if ifa_address.ip == addr.ip and ifa_address.prefixlen == addr.prefixlen:
+ return True
+ except:
+ try:
+ ifa_local = cache_addr.attributes[Address.IFA_LOCAL].value
+ return ifa_local.ip == addr.ip and ifa_local.prefixlen == addr.prefixlen
+ except:
+ pass
+ except (KeyError, AttributeError):
+ pass
+ return False
+
+ # old
+
+ def get_link_obj(self, ifname):
+ try:
+ with self._cache_lock:
+ return self._link_cache[ifname]
+ except KeyError:
+ return None
+
+ def get_link_info_slave_data(self, ifname):
+ try:
+ with self._cache_lock:
+ return self._link_cache[ifname].attributes[Link.IFLA_LINKINFO].value[Link.IFLA_INFO_SLAVE_DATA]
+ except (KeyError, AttributeError):
+ return {}
+
+ def is_link_kind(self, ifname, _type):
+ try:
+ with self._cache_lock:
+ return self._link_cache[ifname].attributes[Link.IFLA_LINKINFO].value[Link.IFLA_INFO_KIND] == _type
+ except (KeyError, AttributeError):
+ return False
+
+ def is_link_slave_kind(self, ifname, _type):
+ try:
+ with self._cache_lock:
+ return self._link_cache[ifname].attributes[Link.IFLA_LINKINFO].value[Link.IFLA_INFO_SLAVE_KIND] == _type
+ except (KeyError, AttributeError):
+ return False
+
+
+class NetlinkListenerWithCache(nllistener.NetlinkManagerWithListener, BaseObject):
+
+ __instance = None
+ VXLAN_UDP_PORT = 4789
+
+ @staticmethod
+ def init(log_level):
+ """
+ Create the singleton via this init function
+ Following calls should use get_instance()
+ :param log_level:
+ :return:
+ """
+ if not NetlinkListenerWithCache.__instance:
+ try:
+ NetlinkListenerWithCache.__instance = NetlinkListenerWithCache(log_level=log_level)
+ except Exception as e:
+ log.error('NetlinkListenerWithCache: init: %s' % e)
+ traceback.print_exc()
+
+ @staticmethod
+ def get_instance():
+ """
+ Use this function to retrieve the active reference to the
+ NetlinkListenerWithCache, make sure you called .init() first
+ :return:
+ """
+ if not NetlinkListenerWithCache.__instance:
+ raise NetlinkListenerWithCacheErrorNotInitialized("NetlinkListenerWithCache not initialized")
+ return NetlinkListenerWithCache.__instance
+
+ def __init__(self, log_level):
+ """
+
+ :param log_level:
+ """
+ if NetlinkListenerWithCache.__instance:
+ raise RuntimeError("NetlinkListenerWithCache: invalid access. Please use NetlinkListenerWithCache.getInstance()")
+ else:
+ NetlinkListenerWithCache.__instance = self
+
+ nllistener.NetlinkManagerWithListener.__init__(
+ self,
+ groups=(
+ nlpacket.RTMGRP_LINK
+ | nlpacket.RTMGRP_IPV4_IFADDR
+ | nlpacket.RTMGRP_IPV6_IFADDR
+ | nlpacket.RTNLGRP_IPV4_NETCONF
+ | nlpacket.RTNLGRP_IPV6_NETCONF
+ | nlpacket.RTNLGRP_MPLS_NETCONF
+ ),
+ start_listener=False,
+ error_notification=True
+ )
+
+ BaseObject.__init__(self)
+
+ signal.signal(signal.SIGTERM, self.signal_term_handler)
+ signal.signal(signal.SIGINT, self.signal_int_handler)
+
+ self.cache = _NetlinkCache()
+
+ # set specific log level to lower-level API
+ nllistener.log.setLevel(log_level)
+ nlpacket.log.setLevel(log_level)
+ nlmanager.log.setLevel(log_level)
+
+ self.IPNetwork_version_to_family = {4: socket.AF_INET, 6: socket.AF_INET6}
+
+ nlpacket.mac_int_to_str = lambda mac_int: ':'.join(('%012x' % mac_int)[i:i + 2] for i in range(0, 12, 2))
+ # Override the nlmanager's mac_int_to_str function
+ # Return an integer in MAC string format: xx:xx:xx:xx:xx:xx instead of xxxx.xxxx.xxxx
+
+ self.workq_handler = {
+ self.WORKQ_SERVICE_NETLINK_QUEUE: self.service_netlinkq,
+ }
+
+ # NetlinkListenerWithCache first dumps links and addresses then start
+ # a worker thread before returning. The worker thread processes the
+ # workq mainly to service (process) the netlinkq which contains our
+ # netlink packet (notification coming from the Kernel).
+ # When the main thread is making netlin requests (i.e. bridge add etc
+ # ...) the main thread will sleep (thread.event.wait) until we notify
+ # it when receiving an ack associated with the request. The request
+ # may fail and the kernel won't return an ACK but instead return a
+ # NLMSG_ERROR packet. We need to store those packet separatly because:
+ # - we could have several NLMSG_ERROR for different requests from
+ # different threads (in a multi-threaded ifupdown2 case)
+ # - we want to decode the packet and tell the user/log or even raise
+ # an exception with the appropriate message.
+ # User must check the return value of it's netlink requests and
+ # catch any exceptions, for that purpose please use API:
+ # - tx_nlpacket_get_response_with_error
+ self.errorq = list()
+ self.errorq_lock = threading.Lock()
+ self.errorq_enabled = True
+
+ # when ifupdown2 starts, we need to fill the netlink cache
+ # GET_LINK/ADDR request are asynchronous, we need to block
+ # and wait for the cache to be filled. We are using this one
+ # time netlinkq_notify_event to wait for the cache completion event
+ self.netlinkq_notify_event = None
+
+ # another threading event to make sure that the netlinkq worker thread is ready
+ self.is_ready = threading.Event()
+
+ self.worker = None
+
+ def __str__(self):
+ return "NetlinkListenerWithCache"
+
+ def start(self):
+ """
+ Start NetlinkListener -
+ cache all links, bridges, addresses and netconfs
+ :return:
+ """
+ self.restart_listener()
+
+ # set ifupdown2 specific supported and ignore messages
+ self.listener.supported_messages = (
+ nlpacket.RTM_NEWLINK,
+ nlpacket.RTM_DELLINK,
+ nlpacket.RTM_NEWADDR,
+ nlpacket.RTM_DELADDR,
+ nlpacket.RTM_NEWNETCONF,
+ nlpacket.RTM_DELNETCONF
+ )
+ self.listener.ignore_messages = (
+ nlpacket.RTM_GETLINK,
+ nlpacket.RTM_GETADDR,
+ nlpacket.RTM_GETNEIGH,
+ nlpacket.RTM_GETROUTE,
+ nlpacket.RTM_GETQDISC,
+ nlpacket.RTM_NEWNEIGH,
+ nlpacket.RTM_DELNEIGH,
+ nlpacket.RTM_NEWROUTE,
+ nlpacket.RTM_DELROUTE,
+ nlpacket.RTM_DELNETCONF,
+ nlpacket.RTM_NEWQDISC,
+ nlpacket.RTM_DELQDISC,
+ nlpacket.RTM_GETQDISC,
+ nlpacket.NLMSG_ERROR, # should be in supported_messages ?
+ nlpacket.NLMSG_DONE # should be in supported_messages ?
+ )
+
+ # get all links and wait for the cache to be filled
+ self.get_all_links_wait_netlinkq()
+
+ # get all addresses and wait for cache to be filled
+ self.get_all_addresses_wait_netlinkq()
+
+ # get a netconf dump and wait for the cached to be filled
+ self.get_all_netconf_wait_netlinkq()
+
+ # TODO: on ifquery we shoudn't start any thread (including listener in NetlinkListener)
+ # only for standalone code.
+ #import sys
+ #for arg in sys.argv:
+ # if 'ifquery' in arg:
+ # self.worker = None
+ # return
+
+ # start the netlinkq worker thread
+ self.worker = threading.Thread(target=self.main, name='NetlinkListenerWithCache')
+ self.worker.start()
+ self.is_ready.wait()
+
+ def cleanup(self):
+ if not self.__instance:
+ return
+
+ # passing 0, 0 to the handler so it doesn't log.info
+ self.signal_term_handler(0, 0)
+
+ if self.worker:
+ self.worker.join()
+
+ def main(self):
+ self.is_ready.set()
+
+ # This loop has two jobs:
+ # - process items on our workq
+ # - process netlink messages on our netlinkq, messages are placed there via our NetlinkListener
+ try:
+ while True:
+ # Sleep until our alarm goes off...NetlinkListener will set the alarm once it
+ # has placed a NetlinkPacket object on our netlinkq. If someone places an item on
+ # our workq they should also set our alarm...if they don't it is not the end of
+ # the world as we will wake up in 1s anyway to check to see if our shutdown_event
+ # has been set.
+ self.alarm.wait(0.1)
+ # when ifupdown2 is not running we could change the timeout to 1 sec or more (daemon mode)
+ # the daemon can also put a hook (pyinotify) on /etc/network/interfaces
+ # if we detect changes to that file it probably means that ifupdown2 will be called very soon
+ # then we can scale up our ops (or maybe unpause some of them)
+ # lets study the use cases
+ self.alarm.clear()
+ if self.shutdown_event.is_set():
+ break
+
+ while not self.workq.empty():
+ (event, options) = self.workq.get()
+
+ if event == self.WORKQ_SERVICE_NETLINK_QUEUE:
+ self.service_netlinkq(self.netlinkq_notify_event)
+ elif event == self.WORKQ_SERVICE_ERROR:
+ self.logger.error('NetlinkListenerWithCache: WORKQ_SERVICE_ERROR')
+ else:
+ raise Exception("Unsupported workq event %s" % event)
+ except:
+ raise
+ finally:
+ # il faut surement mettre un try/except autour de la boucle au dessus
+ # car s'il y a une exception on ne quitte pas le listener thread
+ self.listener.shutdown_event.set()
+ self.listener.join()
+
+ def reset_errorq(self):
+ with self.errorq_lock:
+ self.logger.debug("nlcache: reset errorq")
+ self.errorq = []
+
+ def rx_rtm_newaddr(self, rxed_addr_packet):
+ super(NetlinkListenerWithCache, self).rx_rtm_newaddr(rxed_addr_packet)
+ self.cache.add_address(rxed_addr_packet)
+
+ def rx_rtm_dellink(self, link):
+ # cache only supports AF_UNSPEC for now
+ if link.family != socket.AF_UNSPEC:
+ return
+ super(NetlinkListenerWithCache, self).rx_rtm_dellink(link)
+ self.cache.remove_link(link)
+
+ def rx_rtm_deladdr(self, addr):
+ super(NetlinkListenerWithCache, self).rx_rtm_deladdr(addr)
+ self.cache.remove_address(addr)
+
+ def rx_rtm_newlink(self, rxed_link_packet):
+ # cache only supports AF_UNSPEC for now
+ # we can modify the cache to support more family:
+ # cache {
+ # intf_name: {
+ # AF_UNSPEC: NetlinkObj,
+ # AF_BRIDGE: NetlinkObj
+ # },
+ # }
+ if rxed_link_packet.family != socket.AF_UNSPEC:
+ # special handling for AF_BRIDGE packets
+ if rxed_link_packet.family == socket.AF_BRIDGE:
+ self.cache.add_bridge_vlan(rxed_link_packet)
+ return
+
+ super(NetlinkListenerWithCache, self).rx_rtm_newlink(rxed_link_packet)
+ self.cache.add_link(rxed_link_packet)
+
+ def rx_rtm_newnetconf(self, msg):
+ super(NetlinkListenerWithCache, self).rx_rtm_newnetconf(msg)
+ self.cache.add_netconf(msg)
+
+ def rx_rtm_delnetconf(self, msg):
+ super(NetlinkListenerWithCache, self).rx_rtm_delnetconf(msg)
+ self.cache.remove_netconf(msg)
+
+ def tx_nlpacket_get_response_with_error(self, nl_packet):
+ """
+ After getting an ACK we need to check if this ACK was in fact an
+ error (NLMSG_ERROR). This function go through the .errorq list to
+ find the error packet associated with our request.
+ If found, we process it and raise an exception with the appropriate
+ information/message.
+
+ :param nl_packet:
+ :return:
+ """
+ self.tx_nlpacket_get_response(nl_packet)
+
+ error_packet = None
+ index = 0
+
+ with self.errorq_lock:
+ for error in self.errorq:
+ if error.seq == nl_packet.seq and error.pid == nl_packet.pid:
+ error_packet = error
+ break
+ index += 1
+
+ if error_packet:
+ del self.errorq[index]
+
+ if not error_packet:
+ return True
+
+ error_code = abs(error_packet.negative_errno)
+
+ if error_packet.msgtype == NLMSG_DONE or not error_code:
+ # code NLE_SUCCESS...this is an ACK
+ return True
+
+ if self.debug:
+ error_packet.dump()
+
+ try:
+ # os.strerror might raise ValueError
+ strerror = os.strerror(error_code)
+
+ if strerror:
+ error_str = "operation failed with '%s' (%s)" % (strerror, error_code)
+ else:
+ error_str = "operation failed with code %s" % error_code
+
+ except ValueError:
+ error_str = "operation failed with code %s" % error_code
+
+ raise Exception(error_str)
+
+ def tx_nlpacket_get_response_with_error_and_cache_on_ack(self, packet):
+ """
+ TX packet and manually cache the object
+ """
+ self.tx_nlpacket_get_response_with_error(packet)
+ # When creating a new link via netlink, we don't always wait for the kernel
+ # NEWLINK notification to be cached to continue. If our request is ACKed by
+ # the OS we assume that the link was successfully created. Since we aren't
+ # waiting for the kernel notification to continue we need to manually fill
+ # our cache with the packet we just TX'ed. Once the NEWLINK notification
+ # is received it will simply override the previous entry.
+ # We need to keep track of those manually cached packets. We set a private
+ # flag on the objects via the attribute priv_flags
+ packet.priv_flags |= NLM_F_REQUEST
+ try:
+ # we need to decode the service header so all the attribute are properly
+ # filled in the packet object that we are about to store in cache.
+ # i.e.: packet.flags shouldn't contain NLM_F_* values but IFF_* (in case of Link object)
+ # otherwise call to cache.link_is_up() will probably return True
+ packet.decode_service_header()
+ except:
+ # we can ignore all errors
+ pass
+
+ # Then we can use our normal "add_link" API call to cache the packet
+ # and fill up our additional internal data structures.
+ self.cache.add_link(packet)
+
+ def tx_nlpacket_get_response_with_error_and_wait_for_cache(self, ifname, nl_packet):
+ """
+ The netlink request are asynchronus, but sometimes the main thread/user
+ would like to wait until the result of the request is cached. To do so
+ a cache event for ifname and nl_packet.msgtype is registered. Then the
+ netlink packet is TXed, errors are checked then we sleep until the
+ cache event is set (or we reach the timeout). This allows us to reliably
+ make sure is up to date with newly created/removed devices or addresses.
+ :param nl_packet:
+ :return:
+ """
+ wait_event_registered = self.cache.register_wait_event(ifname, nl_packet.msgtype)
+
+ try:
+ result = self.tx_nlpacket_get_response_with_error(nl_packet)
+ except:
+ # an error was caught, we need to unregister the event and raise again
+ self.cache.unregister_wait_event()
+ raise
+
+ if wait_event_registered:
+ self.cache.wait_event()
+
+ return result
+
+ def get_all_links_wait_netlinkq(self):
+ self.logger.info("requesting link dump")
+ # create netlinkq notify event so we can wait until the links are cached
+ self.netlinkq_notify_event = threading.Event()
+ self.get_all_links()
+ # we also need a dump of all existing bridge vlans
+ self.get_all_br_links(compress_vlans=True)
+ # block until the netlinkq was serviced and cached
+ self.service_netlinkq(self.netlinkq_notify_event)
+ self.netlinkq_notify_event.wait()
+ self.netlinkq_notify_event.clear()
+
+ def get_all_addresses_wait_netlinkq(self):
+ self.logger.info("requesting address dump")
+ self.netlinkq_notify_event = threading.Event()
+ self.get_all_addresses()
+ # block until the netlinkq was serviced and cached
+ self.service_netlinkq(self.netlinkq_notify_event)
+ self.netlinkq_notify_event.wait()
+ self.netlinkq_notify_event.clear()
+ self.netlinkq_notify_event = False
+
+ def get_all_netconf_wait_netlinkq(self):
+ self.logger.info("requesting netconf dump")
+ self.netlinkq_notify_event = threading.Event()
+ self.netconf_dump()
+ # block until the netlinkq was serviced and cached
+ self.service_netlinkq(self.netlinkq_notify_event)
+ self.netlinkq_notify_event.wait()
+ self.netlinkq_notify_event.clear()
+ self.netlinkq_notify_event = False
+
+ def vlan_modify(self, msgtype, ifindex, vlanid_start, vlanid_end=None, bridge_self=False, bridge_master=False, pvid=False, untagged=False):
+ """
+ iproute2 bridge/vlan.c vlan_modify()
+ """
+ assert msgtype in (RTM_SETLINK, RTM_DELLINK), "Invalid msgtype %s, must be RTM_SETLINK or RTM_DELLINK" % msgtype
+ assert vlanid_start >= 1 and vlanid_start <= 4096, "Invalid VLAN start %s" % vlanid_start
+
+ if vlanid_end is None:
+ vlanid_end = vlanid_start
+
+ assert vlanid_end >= 1 and vlanid_end <= 4096, "Invalid VLAN end %s" % vlanid_end
+ assert vlanid_start <= vlanid_end, "Invalid VLAN range %s-%s, start must be <= end" % (vlanid_start, vlanid_end)
+
+ debug = msgtype in self.debug
+ bridge_flags = 0
+ vlan_info_flags = 0
+
+ link = Link(msgtype, debug, use_color=self.use_color)
+ link.flags = NLM_F_REQUEST | NLM_F_ACK
+ link.body = struct.pack('Bxxxiii', socket.AF_BRIDGE, ifindex, 0, 0)
+
+ if bridge_self:
+ bridge_flags |= Link.BRIDGE_FLAGS_SELF
+
+ if bridge_master:
+ bridge_flags |= Link.BRIDGE_FLAGS_MASTER
+
+ if pvid:
+ vlan_info_flags |= Link.BRIDGE_VLAN_INFO_PVID
+
+ if untagged:
+ vlan_info_flags |= Link.BRIDGE_VLAN_INFO_UNTAGGED
+
+ ifla_af_spec = OrderedDict()
+
+ if bridge_flags:
+ ifla_af_spec[Link.IFLA_BRIDGE_FLAGS] = bridge_flags
+
+ # just one VLAN
+ if vlanid_start == vlanid_end:
+ ifla_af_spec[Link.IFLA_BRIDGE_VLAN_INFO] = [(vlan_info_flags, vlanid_start), ]
+
+ # a range of VLANs
+ else:
+ ifla_af_spec[Link.IFLA_BRIDGE_VLAN_INFO] = [
+ (vlan_info_flags | Link.BRIDGE_VLAN_INFO_RANGE_BEGIN, vlanid_start),
+ (vlan_info_flags | Link.BRIDGE_VLAN_INFO_RANGE_END, vlanid_end)
+ ]
+
+ link.add_attribute(Link.IFLA_AF_SPEC, ifla_af_spec)
+ link.build_message(self.sequence.next(), self.pid)
+ return self.tx_nlpacket_get_response_with_error(link)
+
+ #############################################################################################################
+ # Netlink API ###############################################################################################
+ #############################################################################################################
+
+ def link_add(self, ifname, kind):
+ self.link_add_with_attributes(ifname, kind, {})
+
+ def link_add_with_attributes(self, ifname, kind, ifla):
+ """
+ Build and TX a RTM_NEWLINK message to add the desired interface
+ """
+ if ifla:
+ self.logger.info("%s: netlink: ip link add dev %s type %s (with attributes)" % (ifname, ifname, kind))
+ self.logger.debug("attributes: %s" % ifla)
+ else:
+ self.logger.info("%s: netlink: ip link add dev %s type %s" % (ifname, ifname, kind))
+ try:
+ debug = RTM_NEWLINK in self.debug
+
+ link = Link(RTM_NEWLINK, debug, use_color=self.use_color)
+ link.flags = NLM_F_CREATE | NLM_F_REQUEST | NLM_F_ACK
+ link.body = struct.pack('Bxxxiii', socket.AF_UNSPEC, 0, 0, 0)
+
+ for nl_attr, value in ifla.items():
+ link.add_attribute(nl_attr, value)
+
+ link.add_attribute(Link.IFLA_IFNAME, ifname)
+ link.add_attribute(Link.IFLA_LINKINFO, {
+ Link.IFLA_INFO_KIND: kind
+ })
+ link.build_message(self.sequence.next(), self.pid)
+ return self.tx_nlpacket_get_response_with_error_and_cache_on_ack(link)
+ except Exception as e:
+ raise Exception("%s: cannot create link %s type %s" % (ifname, ifname, kind))
+
+ def link_add_with_attributes_dry_run(self, ifname, kind, ifla):
+ self.log_info_ifname_dry_run(ifname, "netlink: ip link add dev %s type %s" % (ifname, kind))
+ self.logger.debug("attributes: %s" % ifla)
+
+ ###
+
+ def __link_set_flag(self, ifname, flags):
+ """
+ Bring interface 'ifname' up (raises on error)
+ :param ifname:
+ :return:
+ """
+ try:
+ link = Link(RTM_NEWLINK, RTM_NEWLINK in self.debug, use_color=self.use_color)
+ link.flags = NLM_F_REQUEST | NLM_F_ACK
+ link.body = struct.pack("=BxxxiLL", socket.AF_UNSPEC, 0, flags, Link.IFF_UP)
+ link.add_attribute(Link.IFLA_IFNAME, ifname)
+ link.build_message(self.sequence.next(), self.pid)
+ result = self.tx_nlpacket_get_response_with_error(link)
+ # if we reach this code it means the operation went through
+ # without exception we can update the cache value this is
+ # needed for the following case (and probably others):
+ #
+ # ifdown bond0 ; ip link set dev bond_slave down
+ # ifup bond0
+ # at the beginning the slaves are admin down
+ # ifupdownmain:run_up link up the slave
+ # the bond addon check if the slave is up or down
+ # and admin down the slave before enslavement
+ # but the cache didn't process the UP notification yet
+ # so the cache has a stale value and we try to enslave
+ # a port, that is admin up, to a bond resulting
+ # in an unexpected failure
+ self.cache.override_link_flag(ifname, flags)
+ return result
+ except Exception as e:
+ raise NetlinkError(e, "ip link set dev %s %s" % (ifname, "up" if flags == Link.IFF_UP else "down"), ifname=ifname)
+
+ def link_up(self, ifname):
+ if not self.cache.link_is_up(ifname):
+ self.logger.info("%s: netlink: ip link set dev %s up" % (ifname, ifname))
+ self.__link_set_flag(ifname, flags=Link.IFF_UP)
+
+ def link_up_force(self, ifname):
+ self.logger.info("%s: netlink: ip link set dev %s up" % (ifname, ifname))
+ self.__link_set_flag(ifname, flags=Link.IFF_UP)
+
+ def link_down(self, ifname):
+ if self.cache.link_is_up(ifname):
+ self.logger.info("%s: netlink: ip link set dev %s down" % (ifname, ifname))
+ self.__link_set_flag(ifname, flags=0)
+
+ def link_down_force(self, ifname):
+ self.logger.info("%s: netlink: ip link set dev %s down" % (ifname, ifname))
+ self.__link_set_flag(ifname, flags=0)
+
+ def link_up_dry_run(self, ifname):
+ self.log_info_ifname_dry_run(ifname, "netlink: ip link set dev %s up" % ifname)
+
+ def link_down_dry_run(self, ifname):
+ self.log_info_ifname_dry_run(ifname, "netlink: ip link set dev %s down" % ifname)
+
+ def link_down_force_dry_run(self, ifname):
+ self.link_down_dry_run(ifname)
+
+ ###
+
+ def __link_set_protodown(self, ifname, state):
+ debug = RTM_NEWLINK in self.debug
+ link = Link(RTM_NEWLINK, debug, use_color=self.use_color)
+ link.flags = NLM_F_REQUEST | NLM_F_ACK
+ link.body = struct.pack("=BxxxiLL", socket.AF_UNSPEC, 0, 0, 0)
+ link.add_attribute(Link.IFLA_IFNAME, ifname)
+ link.add_attribute(Link.IFLA_PROTO_DOWN, state)
+ link.build_message(self.sequence.next(), self.pid)
+ return self.tx_nlpacket_get_response_with_error(link)
+
+ def link_set_protodown_on(self, ifname):
+ """
+ Bring ifname up by setting IFLA_PROTO_DOWN on
+ """
+ self.logger.info("%s: netlink: set link %s protodown on" % (ifname, ifname))
+ try:
+ self.__link_set_protodown(ifname, 1)
+ except Exception as e:
+ raise NetlinkError(e, "cannot set link %s protodown on" % ifname, ifname=ifname)
+
+ def link_set_protodown_off(self, ifname):
+ """
+ Take ifname down by setting IFLA_PROTO_DOWN off
+ """
+ self.logger.info("%s: netlink: set link %s protodown off" % (ifname, ifname))
+ try:
+ self.__link_set_protodown(ifname, 0)
+ except Exception as e:
+ raise NetlinkError(e, "cannot set link %s protodown off" % ifname, ifname=ifname)
+
+ def link_set_protodown_on_dry_run(self, ifname):
+ self.log_info_ifname_dry_run(ifname, "netlink: set link %s protodown on" % ifname)
+
+ def link_set_protodown_off_dry_run(self, ifname):
+ self.log_info_ifname_dry_run(ifname, "netlink: set link %s protodown off" % ifname)
+
+ ###
+
+ def link_del(self, ifname):
+ """
+ Send RTM_DELLINK request
+ :param ifname:
+ :return:
+ """
+ self.logger.info("%s: netlink: ip link del %s" % (ifname, ifname))
+ try:
+ ifindex = self.cache.get_ifindex(ifname)
+ debug = RTM_DELLINK in self.debug
+
+ link = Link(RTM_DELLINK, debug, use_color=self.use_color)
+ link.flags = NLM_F_REQUEST | NLM_F_ACK
+ link.body = struct.pack("Bxxxiii", socket.AF_UNSPEC, ifindex, 0, 0)
+ link.build_message(self.sequence.next(), self.pid)
+
+ try:
+ # We need to register this ifname so the cache can ignore and discard
+ # any further RTM_NEWLINK packet until we receive the associated
+ # RTM_DELLINK notification
+ self.cache.append_to_ignore_rtm_newlinkq(ifname)
+
+ result = self.tx_nlpacket_get_response_with_error(link)
+
+ # Manually purge the cache entry for ifname to make sure we don't have
+ # any stale value in our cache
+ self.cache.force_remove_link(ifname)
+ return result
+ except:
+ # Something went wrong while sending the RTM_DELLINK request
+ # we need to clear ifname from the ignore_rtm_newlinkq list
+ self.cache.remove_from_ignore_rtm_newlinkq(ifname)
+ raise
+ except Exception as e:
+ raise NetlinkError(e, "cannot delete link %s" % ifname, ifname=ifname)
+
+ def link_del_dry_run(self, ifname):
+ self.log_info_ifname_dry_run(ifname, "netlink: ip link del %s" % ifname)
+
+ ###
+
+ def __link_set_master(self, ifname, master_ifindex, master_ifname=None):
+ debug = RTM_NEWLINK in self.debug
+ link = Link(RTM_NEWLINK, debug, use_color=self.use_color)
+ link.flags = NLM_F_REQUEST | NLM_F_ACK
+ link.body = struct.pack("=BxxxiLL", socket.AF_UNSPEC, 0, 0, 0)
+ link.add_attribute(Link.IFLA_IFNAME, ifname)
+ link.add_attribute(Link.IFLA_MASTER, master_ifindex)
+ link.build_message(self.sequence.next(), self.pid)
+ result = self.tx_nlpacket_get_response_with_error(link)
+ # opti:
+ # if we reach this code it means the slave/unslave opreation went through
+ # we can manually update our cache to reflect the change without having
+ # to wait for the netlink notification
+ if master_ifindex:
+ self.cache.force_add_slave(master_ifname, ifname)
+ else:
+ self.cache.override_cache_unslave_link(slave=ifname, master=master_ifname)
+ return result
+
+ def link_set_master(self, ifname, master_ifname):
+ self.logger.info("%s: netlink: ip link set dev %s master %s" % (ifname, ifname, master_ifname))
+ try:
+ self.__link_set_master(ifname, self.cache.get_ifindex(master_ifname), master_ifname=master_ifname)
+ except Exception as e:
+ raise NetlinkError(e, "cannot enslave link %s to %s" % (ifname, master_ifname), ifname=ifname)
+
+ def link_set_nomaster(self, ifname):
+ self.logger.info("%s: netlink: ip link set dev %s nomaster" % (ifname, ifname))
+ try:
+ self.cache.append_to_rtm_newlink_nomasterq(ifname)
+ self.__link_set_master(ifname, 0)
+ except Exception as e:
+ self.cache.remove_from_rtm_newlink_nomasterq(ifname)
+ raise NetlinkError(e, "cannot un-enslave link %s" % ifname, ifname=ifname)
+
+ def link_set_master_dry_run(self, ifname, master_dev):
+ self.log_info_ifname_dry_run(ifname, "netlink: ip link set dev %s master %s" % (ifname, master_dev))
+
+ def link_set_nomaster_dry_run(self, ifname):
+ self.log_info_ifname_dry_run(ifname, "netlink: ip link set dev %s nomaster" % ifname)
+
+ ###
+
+ def link_set_address_dry_run(self, ifname, hw_address):
+ self.log_info_ifname_dry_run(ifname, "netlink: ip link set dev %s address %s" % (ifname, hw_address))
+
+ def link_set_address(self, ifname, hw_address):
+ is_link_up = self.cache.link_is_up(ifname)
+ # check if the link is already up or not if the link is
+ # up we need to down it then make sure we up it again
+ try:
+ if is_link_up:
+ self.link_down_force(ifname)
+
+ self.logger.info("%s: netlink: ip link set dev %s address %s" % (ifname, ifname, hw_address))
+ debug = RTM_NEWLINK in self.debug
+ link = Link(RTM_NEWLINK, debug, use_color=self.use_color)
+ link.flags = NLM_F_REQUEST | NLM_F_ACK
+ link.body = struct.pack('Bxxxiii', socket.AF_UNSPEC, 0, 0, 0)
+
+ link.add_attribute(Link.IFLA_IFNAME, ifname)
+ link.add_attribute(Link.IFLA_ADDRESS, hw_address)
+
+ link.build_message(self.sequence.next(), self.pid)
+ return self.tx_nlpacket_get_response_with_error(link)
+ except Exception as e:
+ raise NetlinkError(e, "cannot set dev %s address %s" % (ifname, hw_address), ifname=ifname)
+ finally:
+ if is_link_up:
+ self.link_up_force(ifname)
+
+ ###
+
+ __macvlan_mode = {
+ "private": Link.MACVLAN_MODE_PRIVATE,
+ "vepa": Link.MACVLAN_MODE_VEPA,
+ "bridge": Link.MACVLAN_MODE_BRIDGE,
+ "passthru": Link.MACVLAN_MODE_PASSTHRU,
+ "source": Link.MACVLAN_MODE_SOURCE
+ }
+
+ def link_add_macvlan(self, ifname, macvlan_ifname, macvlan_mode=None):
+ self.logger.info(
+ "%s: netlink: ip link add link %s name %s type macvlan mode %s"
+ % (ifname, ifname, macvlan_ifname, macvlan_mode if macvlan_mode else "private")
+ )
+ try:
+ ifindex = self.cache.get_ifindex(ifname)
+ debug = RTM_NEWLINK in self.debug
+
+ link = Link(RTM_NEWLINK, debug, use_color=self.use_color)
+ link.flags = NLM_F_CREATE | NLM_F_REQUEST | NLM_F_ACK
+ link.body = struct.pack("Bxxxiii", socket.AF_UNSPEC, 0, 0, 0)
+
+ link.add_attribute(Link.IFLA_IFNAME, ifname)
+
+ if ifindex:
+ link.add_attribute(Link.IFLA_LINK, ifindex)
+
+ link.add_attribute(Link.IFLA_LINKINFO, {
+ Link.IFLA_INFO_KIND: "macvlan",
+ Link.IFLA_INFO_DATA: {
+ Link.IFLA_MACVLAN_MODE: self.__macvlan_mode.get(
+ macvlan_mode,
+ Link.MACVLAN_MODE_PRIVATE
+ )
+ }
+ })
+ link.build_message(self.sequence.next(), self.pid)
+ return self.tx_nlpacket_get_response_with_error_and_cache_on_ack(link)
+
+ except Exception as e:
+ raise Exception(
+ "netlink: %s: cannot create macvlan %s: %s"
+ % (ifname, macvlan_ifname, str(e))
+ )
+
+ def link_add_macvlan_dry_run(self, ifname, macvlan_ifame, macvlan_mode=None):
+ self.log_info_ifname_dry_run(
+ ifname,
+ "netlink: ip link add link %s name %s type macvlan mode %s"
+ % (ifname, macvlan_ifame, macvlan_mode if macvlan_mode else "private")
+ )
+ return True
+
+ ###
+
+ def link_add_vrf(self, ifname, vrf_table):
+ self.logger.info("%s: netlink: ip link add dev %s type vrf table %s" % (ifname, ifname, vrf_table))
+
+ debug = RTM_NEWLINK in self.debug
+
+ link = Link(RTM_NEWLINK, debug, use_color=self.use_color)
+ link.flags = NLM_F_CREATE | NLM_F_REQUEST | NLM_F_ACK
+ link.body = struct.pack('Bxxxiii', socket.AF_UNSPEC, 0, 0, 0)
+ link.add_attribute(Link.IFLA_IFNAME, ifname)
+ link.add_attribute(Link.IFLA_LINKINFO, {
+ Link.IFLA_INFO_KIND: "vrf",
+ Link.IFLA_INFO_DATA: {
+ Link.IFLA_VRF_TABLE: int(vrf_table)
+ }
+ })
+ link.build_message(self.sequence.next(), self.pid)
+ return self.tx_nlpacket_get_response_with_error_and_cache_on_ack(link)
+
+ def link_add_vrf_dry_run(self, ifname, vrf_table):
+ self.log_info_ifname_dry_run(ifname, "netlink: ip link add dev %s type vrf table %s" % (ifname, vrf_table))
+ return True
+
+ ###
+
+ def link_add_bridge(self, ifname, mtu=None):
+ self.logger.info("%s: netlink: ip link add dev %s type bridge" % (ifname, ifname))
+
+ debug = RTM_NEWLINK in self.debug
+
+ link = Link(RTM_NEWLINK, debug, use_color=self.use_color)
+ link.flags = NLM_F_CREATE | NLM_F_REQUEST | NLM_F_ACK
+ link.body = struct.pack('Bxxxiii', socket.AF_UNSPEC, 0, 0, 0)
+ link.add_attribute(Link.IFLA_IFNAME, ifname)
+
+ if mtu:
+ self.logger.info("%s: netlink: set bridge mtu %s" % (ifname, mtu))
+ link.add_attribute(Link.IFLA_MTU, mtu)
+
+ link.add_attribute(Link.IFLA_LINKINFO, {
+ Link.IFLA_INFO_KIND: "bridge",
+ })
+ link.build_message(self.sequence.next(), self.pid)
+ return self.tx_nlpacket_get_response_with_error_and_cache_on_ack(link)
+
+ def link_add_bridge_dry_run(self, ifname):
+ self.log_info_ifname_dry_run(ifname, "netlink: ip link add dev %s type bridge" % ifname)
+ return True
+
+ def link_set_bridge_info_data(self, ifname, ifla_info_data, link_just_created):
+ self.logger.info(
+ "%s: netlink: ip link set dev %s type bridge (with attributes)"
+ % (ifname, ifname)
+ )
+ self.logger.debug("attributes: %s" % ifla_info_data)
+
+ try:
+ debug = RTM_NEWLINK in self.debug
+ link = Link(RTM_NEWLINK, debug, use_color=self.use_color)
+ link.flags = NLM_F_CREATE | NLM_F_REQUEST | NLM_F_ACK
+ link.body = struct.pack('Bxxxiii', socket.AF_UNSPEC, 0, 0, 0)
+ link.add_attribute(Link.IFLA_IFNAME, ifname)
+ link.add_attribute(Link.IFLA_LINKINFO, {
+ Link.IFLA_INFO_KIND: "bridge",
+ Link.IFLA_INFO_DATA: ifla_info_data
+ })
+ link.build_message(self.sequence.next(), self.pid)
+ result = self.tx_nlpacket_get_response_with_error(link)
+
+ if link_just_created:
+ self.cache.update_link_info_data(ifname, ifla_info_data)
+
+ return result
+ except Exception as e:
+ raise Exception("%s: netlink: cannot create bridge or set attributes: %s" % (ifname, str(e)))
+
+ def link_set_bridge_info_data_dry_run(self, ifname, ifla_info_data):
+ self.log_info_ifname_dry_run(ifname, "netlink: ip link add dev %s type bridge (with attributes)" % ifname)
+ self.logger.debug("attributes: %s" % ifla_info_data)
+
+ ###
+
+ def link_add_bridge_vlan(self, ifname, vlan_id):
+ """
+ Add VLAN(s) to a bridge interface
+ """
+ self.logger.info("%s: netlink: bridge vlan add vid %s dev %s" % (ifname, vlan_id, ifname))
+ try:
+ ifindex = self.cache.get_ifindex(ifname)
+ self.vlan_modify(RTM_SETLINK, ifindex, vlan_id, bridge_self=True)
+ # TODO: we should probably fill our internal cache when when the ACK is received.
+ except Exception as e:
+ raise NetlinkError(e, "cannot add bridge vlan %s" % vlan_id, ifname=ifname)
+
+ def link_del_bridge_vlan(self, ifname, vlan_id):
+ """
+ Delete VLAN(s) from a bridge interface
+ """
+ self.logger.info("%s: netlink: bridge vlan del vid %s dev %s" % (ifname, vlan_id, ifname))
+ try:
+ ifindex = self.cache.get_ifindex(ifname)
+ self.vlan_modify(RTM_DELLINK, ifindex, vlan_id, bridge_self=True)
+ except Exception as e:
+ raise NetlinkError(e, "cannot remove bridge vlan %s" % vlan_id, ifname=ifname)
+
+ def link_add_bridge_vlan_dry_run(self, ifname, vlan_id):
+ self.log_info_ifname_dry_run(ifname, "netlink: bridge vlan add vid %s dev %s" % (vlan_id, ifname))
+
+ def link_del_bridge_vlan_dry_run(self, ifname, vlan_id):
+ self.log_info_ifname_dry_run(ifname, "netlink: bridge vlan del vid %s dev %s" % (vlan_id, ifname))
+
+ ###
+
+ def link_add_vlan(self, vlan_raw_device, ifname, vlan_id, vlan_protocol=None):
+ """
+ ifindex is the index of the parent interface that this sub-interface
+ is being added to
+
+ If you name an interface swp2.17 but assign it to vlan 12, the kernel
+ will return a very misleading NLE_MSG_OVERFLOW error. It only does
+ this check if the ifname uses dot notation.
+
+ Do this check here so we can provide a more intuitive error
+ """
+ try:
+ if vlan_protocol:
+ self.logger.info("%s: netlink: ip link add link %s name %s type vlan id %s protocol %s"
+ % (ifname, vlan_raw_device, ifname, vlan_id, vlan_protocol))
+
+ else:
+ self.logger.info("%s: netlink: ip link add link %s name %s type vlan id %s"
+ % (ifname, vlan_raw_device, ifname, vlan_id))
+
+ if "." in ifname:
+ ifname_vlanid = int(ifname.split(".")[-1])
+
+ if ifname_vlanid != vlan_id:
+ raise Exception(
+ "Interface %s must belong to VLAN %d (VLAN %d was requested)"
+ % (ifname, ifname_vlanid, vlan_id)
+ )
+
+ ifindex = self.cache.get_ifindex(vlan_raw_device)
+
+ ifla_info_data = {Link.IFLA_VLAN_ID: vlan_id}
+
+ if vlan_protocol:
+ ifla_info_data[Link.IFLA_VLAN_PROTOCOL] = vlan_protocol
+
+ debug = RTM_NEWLINK in self.debug
+
+ link = Link(RTM_NEWLINK, debug, use_color=self.use_color)
+ link.flags = NLM_F_CREATE | NLM_F_REQUEST | NLM_F_ACK
+ link.body = struct.pack('Bxxxiii', socket.AF_UNSPEC, 0, 0, 0)
+
+ link.add_attribute(Link.IFLA_IFNAME, ifname)
+ link.add_attribute(Link.IFLA_LINK, ifindex)
+ link.add_attribute(Link.IFLA_LINKINFO, {
+ Link.IFLA_INFO_KIND: "vlan",
+ Link.IFLA_INFO_DATA: ifla_info_data
+ })
+ link.build_message(self.sequence.next(), self.pid)
+ return self.tx_nlpacket_get_response_with_error_and_cache_on_ack(link)
+ except Exception as e:
+ raise NetlinkError(e, "cannot create vlan %s %s" % (ifname, vlan_id), ifname=ifname)
+
+ def link_add_vlan_dry_run(self, vlan_raw_device, ifname, vlan_id, vlan_protocol=None):
+ """
+ ifindex is the index of the parent interface that this sub-interface
+ is being added to
+
+ If you name an interface swp2.17 but assign it to vlan 12, the kernel
+ will return a very misleading NLE_MSG_OVERFLOW error. It only does
+ this check if the ifname uses dot notation.
+
+ Do this check here so we can provide a more intuitive error
+ """
+ if vlan_protocol:
+ self.log_info_ifname_dry_run(
+ ifname,
+ "netlink: ip link add link %s name %s type vlan id %s protocol %s"
+ % (vlan_raw_device, ifname, vlan_id, vlan_protocol)
+ )
+
+ else:
+ self.log_info_ifname_dry_run(
+ ifname,
+ "netlink: ip link add link %s name %s type vlan id %s"
+ % (vlan_raw_device, ifname, vlan_id)
+ )
+
+ ###
+
+ def link_add_vxlan_with_info_data(self, ifname, info_data):
+ """
+ cmd = ["ip link add %s type vxlan id %s" % (ifname, id)]
+
+ if port:
+ cmd.append("dstport %s" % port)
+ info_data[nlpacket.Link.IFLA_VXLAN_PORT] = int(port)
+
+ if local:
+ cmd.append("local %s" % local)
+ info_data[nlpacket.Link.IFLA_VXLAN_LOCAL] = local
+
+ if ageing:
+ cmd.append("ageing %s" % ageing)
+ info_data[nlpacket.Link.IFLA_VXLAN_AGEING] = int(ageing)
+
+ if group:
+ if group.is_multicast:
+ cmd.append("group %s" % group)
+ else:
+ cmd.append("remote %s" % group)
+ info_data[nlpacket.Link.IFLA_VXLAN_GROUP] = group
+ else:
+ cmd.append("noremote")
+
+ if not learning:
+ cmd.append("nolearning")
+ info_data[nlpacket.Link.IFLA_VXLAN_LEARNING] = int(learning)
+
+ if physdev:
+ cmd.append("dev %s" % physdev)
+ info_data[nlpacket.Link.IFLA_VXLAN_LINK] = self.cache.get_ifindex(physdev)
+
+ if ttl:
+ cmd.append("ttl %s" % ttl)
+ info_data[nlpacket.Link.IFLA_VXLAN_TTL] = ttl
+
+ self.logger.info('%s: netlink: %s' % (ifname, " ".join(cmd)))
+
+ :param ifname:
+ :param info_data:
+ :return:
+ """
+ self.logger.info(
+ "%s: netlink: ip link add dev %s type vxlan id %s (with attributes)"
+ % (ifname, ifname, info_data.get(Link.IFLA_VXLAN_ID))
+ )
+ self.logger.debug("attributes: %s" % info_data)
+
+ debug = RTM_NEWLINK in self.debug
+ link = Link(RTM_NEWLINK, debug, use_color=self.use_color)
+ link.flags = NLM_F_CREATE | NLM_F_REQUEST | NLM_F_ACK
+ link.body = struct.pack('Bxxxiii', socket.AF_UNSPEC, 0, 0, 0)
+ link.add_attribute(Link.IFLA_IFNAME, ifname)
+ link.add_attribute(Link.IFLA_LINKINFO, {
+ Link.IFLA_INFO_KIND: "vxlan",
+ Link.IFLA_INFO_DATA: info_data
+ })
+ link.build_message(self.sequence.next(), self.pid)
+ return self.tx_nlpacket_get_response_with_error_and_cache_on_ack(link)
+
+ def link_add_vxlan_with_info_data_dry_run(self, ifname, info_data):
+ self.log_info_ifname_dry_run(
+ ifname,
+ "netlink: ip link add dev %s type vxlan id %s (with attributes)"
+ % (ifname, info_data.get(Link.IFLA_VXLAN_ID))
+ )
+ self.logger.debug("attributes: %s" % info_data)
+ return True
+
+ ###
+
+ def link_add_bond_with_info_data(self, ifname, ifla_info_data):
+ self.logger.info(
+ "%s: netlink: ip link add dev %s type bond (with attributes)"
+ % (ifname, ifname)
+ )
+ self.logger.debug("attributes: %s" % ifla_info_data)
+
+ try:
+ debug = RTM_NEWLINK in self.debug
+ link = Link(RTM_NEWLINK, debug, use_color=self.use_color)
+ link.flags = NLM_F_CREATE | NLM_F_REQUEST | NLM_F_ACK
+ link.body = struct.pack('Bxxxiii', socket.AF_UNSPEC, 0, 0, 0)
+ link.add_attribute(Link.IFLA_IFNAME, ifname)
+ link.add_attribute(Link.IFLA_LINKINFO, {
+ Link.IFLA_INFO_KIND: "bond",
+ Link.IFLA_INFO_DATA: ifla_info_data
+ })
+ link.build_message(self.sequence.next(), self.pid)
+ return self.tx_nlpacket_get_response_with_error_and_cache_on_ack(link)
+ except Exception as e:
+ raise Exception("%s: netlink: cannot create bond with attributes: %s" % (ifname, str(e)))
+
+ def link_add_bond_with_info_data_dry_run(self, ifname, ifla_info_data):
+ self.log_info_ifname_dry_run(ifname, "netlink: ip link add dev %s type bond (with attributes)" % ifname)
+ self.logger.debug("attributes: %s" % ifla_info_data)
+
+ ###
+
+ def link_set_brport_with_info_slave_data(self, ifname, kind, ifla_info_data, ifla_info_slave_data):
+ """
+ Build and TX a RTM_NEWLINK message to add the desired interface
+ """
+ self.logger.info("%s: netlink: ip link set dev %s: bridge port attributes" % (ifname, ifname))
+ self.logger.debug("attributes: %s" % ifla_info_slave_data)
+
+ try:
+ debug = RTM_NEWLINK in self.debug
+
+ link = Link(RTM_NEWLINK, debug, use_color=self.use_color)
+ link.flags = NLM_F_CREATE | NLM_F_REQUEST | NLM_F_ACK
+ link.body = struct.pack("Bxxxiii", socket.AF_UNSPEC, 0, 0, 0)
+
+ if ifname:
+ link.add_attribute(Link.IFLA_IFNAME, ifname)
+
+ linkinfo = dict()
+
+ if kind:
+ linkinfo[Link.IFLA_INFO_KIND] = kind
+ linkinfo[Link.IFLA_INFO_DATA] = ifla_info_data
+
+ linkinfo[Link.IFLA_INFO_SLAVE_KIND] = "bridge"
+ linkinfo[Link.IFLA_INFO_SLAVE_DATA] = ifla_info_slave_data
+
+ link.add_attribute(Link.IFLA_LINKINFO, linkinfo)
+ link.build_message(self.sequence.next(), self.pid)
+
+ # the brport already exists and is cached - after this operation we most
+ # likely don't need to do anything about the brport so we don't need to
+ # wait for the new notification to be cached.
+ return self.tx_nlpacket_get_response_with_error(link)
+ except Exception as e:
+ raise Exception("netlink: %s: cannot set %s (bridge slave) with options: %s" % (kind, ifname, str(e)))
+
+ def link_set_brport_with_info_slave_data_dry_run(self, ifname, _, __, ifla_info_slave_data):
+ self.log_info_ifname_dry_run(ifname, "netlink: ip link set dev %s: bridge port attributes" % ifname)
+ self.logger.debug("attributes: %s" % ifla_info_slave_data)
+
+ ############################################################################
+ # ADDRESS
+ ############################################################################
+
+ def addr_add_dry_run(self, ifname, addr, broadcast=None, peer=None, scope=None, preferred_lifetime=None, metric=None):
+ log_msg = ["netlink: ip addr add %s dev %s" % (addr, ifname)]
+
+ if scope:
+ log_msg.append("scope %s" % scope)
+
+ if broadcast:
+ log_msg.append("broadcast %s" % broadcast)
+
+ if preferred_lifetime:
+ log_msg.append("preferred_lft %s" % preferred_lifetime)
+
+ if peer:
+ log_msg.append("peer %s" % peer)
+
+ if metric:
+ log_msg.append("metric %s" % metric)
+
+ self.log_info_ifname_dry_run(ifname, " ".join(log_msg))
+
+ def addr_add(self, ifname, addr, broadcast=None, peer=None, scope=None, preferred_lifetime=None, metric=None):
+ log_msg = ["%s: netlink: ip addr add %s dev %s" % (ifname, addr, ifname)]
+ log_msg_displayed = False
+ try:
+ # We might need to check if metric/peer and other attribute are also
+ # correctly cached.
+ # We might also need to add a "force" attribute to skip the cache check
+ if self.cache.addr_is_cached(ifname, addr):
+ return
+
+ if scope:
+ log_msg.append("scope %s" % scope)
+ scope_value = RT_SCOPES.get(scope, 0)
+ else:
+ scope_value = 0
+
+ debug = RTM_NEWADDR in self.debug
+
+ packet = Address(RTM_NEWADDR, debug, use_color=self.use_color)
+ packet.flags = NLM_F_CREATE | NLM_F_REQUEST | NLM_F_ACK
+ packet.family = self.IPNetwork_version_to_family.get(addr.version)
+
+ packet.add_attribute(Address.IFA_ADDRESS, addr)
+ packet.add_attribute(Address.IFA_LOCAL, addr)
+
+ if broadcast:
+ log_msg.append("broadcast %s" % broadcast)
+ packet.add_attribute(Address.IFA_BROADCAST, broadcast)
+
+ if preferred_lifetime:
+ # struct ifa_cacheinfo {
+ # __u32 ifa_prefered;
+ # __u32 ifa_valid;
+ # __u32 cstamp; /* created timestamp, hundredths of seconds */
+ # __u32 tstamp; /* updated timestamp, hundredths of seconds */
+ # };
+ log_msg.append("preferred_lft %s" % preferred_lifetime)
+
+ if preferred_lifetime.lower() == "forever":
+ preferred_lifetime = INFINITY_LIFE_TIME
+
+ packet.add_attribute(Address.IFA_CACHEINFO, (int(preferred_lifetime), INFINITY_LIFE_TIME, 0, 0))
+
+ if metric:
+ log_msg.append("metric %s" % metric)
+ packet.add_attribute(Address.IFA_RT_PRIORITY, int(metric))
+
+ if peer:
+ log_msg.append("peer %s" % peer)
+ packet.add_attribute(Address.IFA_ADDRESS, peer)
+ packet_prefixlen = peer.prefixlen
+ else:
+ packet_prefixlen = addr.prefixlen
+
+ self.logger.info(" ".join(log_msg))
+ log_msg_displayed = True
+
+ packet.body = struct.pack("=4Bi", packet.family, packet_prefixlen, 0, scope_value, self.cache.get_ifindex(ifname))
+ packet.build_message(self.sequence.next(), self.pid)
+ return self.tx_nlpacket_get_response_with_error(packet)
+ except Exception as e:
+ if not log_msg_displayed:
+ # just in case we get an exception before we reach the log.info
+ # we should display it before we raise the exception
+ log.info(" ".join(log_msg))
+ raise NetlinkError(e, "cannot add address %s dev %s" % (addr, ifname), ifname=ifname)
+
+ ###
+
+ def addr_del_dry_run(self, ifname, addr):
+ self.log_info_ifname_dry_run(ifname, "netlink: ip addr del %s dev %s" % (addr, ifname))
+
+ def addr_del(self, ifname, addr):
+ if not self.cache.addr_is_cached(ifname, addr):
+ return
+ self.logger.info("%s: netlink: ip addr del %s dev %s" % (ifname, addr, ifname))
+ try:
+ debug = RTM_DELADDR in self.debug
+
+ packet = Address(RTM_DELADDR, debug, use_color=self.use_color)
+ packet.flags = NLM_F_REQUEST | NLM_F_ACK
+ packet.family = self.IPNetwork_version_to_family.get(addr.version)
+ packet.body = struct.pack("=4Bi", packet.family, addr.prefixlen, 0, 0, self.cache.get_ifindex(ifname))
+
+ packet.add_attribute(Address.IFA_LOCAL, addr)
+
+ packet.build_message(self.sequence.next(), self.pid)
+ result = self.tx_nlpacket_get_response_with_error(packet)
+
+ # RTM_DELADDR successful, we need to update our cache
+ # to make sure we don't have any stale ip addr cached
+ self.cache.force_remove_addr(ifname, addr)
+
+ return result
+ except Exception as e:
+ raise NetlinkError(e, "cannot delete address %s dev %s" % (addr, ifname), ifname=ifname)
+
+ def addr_flush(self, ifname):
+ """
+ From iproute2/ip/ipaddress.c
+ /*
+ * Note that the kernel may delete multiple addresses for one
+ * delete request (e.g. if ipv4 address promotion is disabled).
+ * Since a flush operation is really a series of delete requests
+ * its possible that we may request an address delete that has
+ * already been done by the kernel. Therefore, ignore EADDRNOTAVAIL
+ * errors returned from a flush request
+ */
+ """
+ for addr in self.cache.get_addresses_list(ifname):
+ try:
+ self.addr_del(ifname, addr)
+ except:
+ pass
+
+ ########################
+ # TEMPORARY DEBUG CODE #
+ ########################
+
+ def DEBUG_ON(self):
+ self.debug_link(True)
+ self.debug_address(True)
+ nllistener.log.setLevel(DEBUG)
+ nlpacket.log.setLevel(DEBUG)
+ nlmanager.log.setLevel(DEBUG)
+
+ def DEBUG_OFF(self):
+ self.debug_address(False)
+ self.debug_link(False)
+ nllistener.log.setLevel(WARNING)
+ nlpacket.log.setLevel(WARNING)
+ nlmanager.log.setLevel(WARNING)
--- /dev/null
+# Copyright (C) 2019 Cumulus Networks, Inc. all rights reserved
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; version 2.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# https://www.gnu.org/licenses/gpl-2.0-standalone.html
+#
+# Author:
+# Julien Fortin, julien@cumulusnetworks.com
+#
+
+
+class Status(object):
+ """
+ Defining client and daemon exit status to better identify
+ client and daemon issue and exceptions.
+ 80 > unknown > 90 > client status > 100 > daemon status
+ """
+
+ class Client(object):
+ STATUS_SUCCESS = 0
+ STATUS_INIT = 91
+ STATUS_COULD_NOT_CONNECT = 92
+ STATUS_NO_PID = 93
+ STATUS_EMPTY = 94
+ STATUS_KEYBOARD_INTERRUPT = 95
+ STATUS_NLERROR = 96
+ STATUS_EXCEPTION_MAIN = 99
+
+ class Daemon(object):
+ STATUS_SUCCESS = 0
+ STATUS_INIT = 101
+ STATUS_UNKNOWN = 102
+ STATUS_SOCKET_ERROR = 103
+ STATUS_PROCESS_REQUEST = 104
+ STATUS_KEYBOARD_INTERRUPT = 105
+ STATUS_NLERROR = 106
+
+ STATUS_REQUEST_PARSE_ERROR = 106
+ STATUS_REQUEST_EXCEPTION = 107
+ STATUS_REQUEST_BASE_EXCEPTION = 108
--- /dev/null
+# Copyright (C) 2017, 2018 Cumulus Networks, Inc. all rights reserved
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; version 2.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# https://www.gnu.org/licenses/gpl-2.0-standalone.html
+#
+# Author:
+# Julien Fortin, julien@cumulusnetworks.com
+#
+# sysfs -- contains all sysfs related operation
+#
+
+import os
+import glob
+
+try:
+ from ifupdown2.lib.io import IO
+ from ifupdown2.lib.base_objects import Requirements
+
+ from ifupdown2.ifupdown.utils import utils
+
+ from ifupdown2.nlmanager.nlpacket import Link
+except ImportError:
+ from lib.io import IO
+ from lib.base_objects import Requirements
+
+ from ifupdown.utils import utils
+
+ from nlmanager.nlpacket import Link
+
+
+class __Sysfs(IO, Requirements):
+
+ __bond_netlink_to_sysfs_attr_map = {
+ Link.IFLA_BOND_MODE: "mode",
+ Link.IFLA_BOND_MIIMON: "miimon",
+ Link.IFLA_BOND_USE_CARRIER: "use_carrier",
+ Link.IFLA_BOND_AD_LACP_RATE: "lacp_rate",
+ Link.IFLA_BOND_XMIT_HASH_POLICY: "xmit_hash_policy",
+ Link.IFLA_BOND_MIN_LINKS: "min_links",
+ Link.IFLA_BOND_NUM_PEER_NOTIF: "num_grat_arp",
+ Link.IFLA_BOND_AD_ACTOR_SYSTEM: "ad_actor_system",
+ Link.IFLA_BOND_AD_ACTOR_SYS_PRIO: "ad_actor_sys_prio",
+ Link.IFLA_BOND_AD_LACP_BYPASS: "lacp_bypass",
+ Link.IFLA_BOND_UPDELAY: "updelay",
+ Link.IFLA_BOND_DOWNDELAY: "downdelay",
+ Link.IFLA_BOND_PRIMARY: "primary",
+ }
+
+ def __init__(self):
+ IO.__init__(self)
+ Requirements.__init__(self)
+
+ # Temporary work around to solve the circular dependency with nlcache.
+ # Once nlcache is created it will populate sysfs.cache
+ self.cache = None
+
+ # if bridge utils is not installed overrrides specific functions to
+ # avoid constantly checking bridge_utils_is_installed
+ if not Requirements.bridge_utils_is_installed:
+ self.bridge_get_mcqv4src = self.bridge_get_mcqv4src_dry_run
+
+ @staticmethod
+ def link_get_uppers(ifname):
+ try:
+ uppers = glob.glob("/sys/class/net/%s/upper_*" % ifname)
+ if not uppers:
+ return []
+ return [os.path.basename(u)[6:] for u in uppers]
+ except:
+ return []
+
+ @staticmethod
+ def link_get_lowers(ifname):
+ try:
+ lowers = glob.glob("/sys/class/net/%s/lower_*" % ifname)
+ if not lowers:
+ return []
+ return [os.path.basename(l)[6:] for l in lowers]
+ except:
+ return []
+
+ def link_is_up(self, ifname):
+ """
+ Read sysfs operstate file
+ """
+ return "up" == self.read_file_oneline("/sys/class/net/%s/operstate" % ifname)
+
+ def get_link_address(self, ifname):
+ """
+ Read MAC hardware address from sysfs
+ """
+ return self.read_file_oneline("/sys/class/net/%s/address" % ifname)
+
+ #
+ # MTU
+ #
+
+ def link_get_mtu(self, ifname):
+ return int(self.read_file_oneline("/sys/class/net/%s/mtu" % ifname) or 0)
+
+ def link_set_mtu(self, ifname, mtu_str, mtu_int):
+ if self.cache.get_link_mtu(ifname) != mtu_int:
+ if self.write_to_file('/sys/class/net/%s/mtu' % ifname, mtu_str):
+ self.cache.override_link_mtu(ifname, mtu_int)
+
+ def link_set_mtu_dry_run(self, ifname, mtu_str, mtu_int):
+ # we can remove the cache check in DRYRUN mode
+ self.write_to_file('/sys/class/net/%s/mtu' % ifname, mtu_str)
+
+ #
+ # ALIAS
+ #
+
+ def link_set_alias(self, ifname, alias):
+ cached_alias = self.cache.get_link_alias(ifname)
+
+ if cached_alias == alias:
+ return
+
+ if not alias:
+ alias = "\n"
+
+ if self.write_to_file("/sys/class/net/%s/ifalias" % ifname, alias):
+ pass # self.cache.override_link_mtu(ifname, mtu_int)
+
+ def link_set_alias_dry_run(self, ifname, alias):
+ # we can remove the cache check in DRYRUN mode
+ if not alias:
+ alias = ""
+ self.write_to_file("/sys/class/net/%s/ifalias" % ifname, alias)
+
+ ############################################################################
+ # BRIDGE
+ ############################################################################
+
+ def bridge_port_pvids_get(self, bridge_port_name):
+ return self.read_file_oneline("/sys/class/net/%s/brport/pvid" % bridge_port_name)
+
+ def bridge_get_stp(self, bridge):
+ stp_state_path = "/sys/class/net/%s/bridge/stp_state" % bridge
+
+ if not os.path.exists(stp_state_path):
+ return "error"
+
+ stp_state = self.read_file_oneline(stp_state_path)
+
+ if not stp_state:
+ return "error"
+
+ try:
+ stp_state_int = int(stp_state)
+ return "yes" if stp_state_int > 0 else "no"
+ except:
+ return "unknown"
+
+ def bridge_get_mcqv4src(self, bridge):
+ mcqv4src = {}
+ try:
+ filename = "/sys/class/net/%s/bridge/multicast_v4_queriers" % bridge
+ if os.path.exists(filename):
+ for line in self.read_file(filename) or []:
+ vlan_id, ip = line.split('=')
+ mcqv4src[vlan_id] = ip.strip()
+ return mcqv4src
+ except Exception as e:
+ self.logger.info("%s showmcqv4src: skipping unsupported command" % utils.brctl_cmd)
+ self.bridge_get_mcqv4src = self.bridge_get_mcqv4src_dry_run
+ return {}
+
+ @staticmethod
+ def bridge_get_mcqv4src_dry_run(bridge):
+ return {}
+
+ ############################################################################
+ # BOND
+ ############################################################################
+
+ def bond_remove_slave(self, bond_name, slave_name):
+ if self.cache.is_link_enslaved_to(slave_name, bond_name):
+ if self.write_to_file("/sys/class/net/%s/bonding/slaves" % bond_name, "-%s" % slave_name):
+ # success we can manually update our cache to make sure we stay up-to-date
+ self.cache.override_cache_unslave_link(slave=slave_name, master=bond_name)
+
+ def bond_remove_slave_dry_run(self, bond_name, slave_name):
+ self.write_to_file("/sys/class/net/%s/bonding/slaves" % bond_name, "-%s" % slave_name)
+
+ ###
+
+ def bond_create(self, bond_name):
+ if self.cache.bond_exists(bond_name):
+ return
+ self.write_to_file("/sys/class/net/bonding_masters", "+%s" % bond_name)
+
+ def bond_create_dry_run(self, bond_name):
+ self.write_to_file("/sys/class/net/bonding_masters", "+%s" % bond_name)
+
+ ###
+
+ def bond_set_attrs_nl(self, bond_name, ifla_info_data):
+ """
+ bond_set_attrs_nl doesn't need a _dry_run handler because each
+ entry in ifla_info_data was checked against the cache already.
+ Here write_to_file already has a dry_run handler.
+ :param bond_name:
+ :param ifla_info_data:
+ :return:
+ """
+ bond_attr_name = 'None' # for log purpose (in case an exception raised)
+
+ for nl_attr, value in ifla_info_data.items():
+ try:
+ bond_attr_name = self.__bond_netlink_to_sysfs_attr_map.get(nl_attr)
+
+ if bond_attr_name is None:
+ self.logger.warning(
+ "%s: sysfs configuration: unknown bond attribute %s (value %s)"
+ % (bond_name, nl_attr, value)
+ )
+ continue
+
+ file_path = "/sys/class/net/%s/bonding/%s" % (bond_name, bond_attr_name)
+ if os.path.exists(file_path):
+ self.write_to_file(file_path, str(value))
+ except Exception as e:
+ self.logger.warning("%s: %s %s: %s" % (bond_name, bond_attr_name, value, str(e)))
+
+ ############################################################################
+ # /proc/sys/ipv6/conf
+ ############################################################################
+
+ def get_ipv6_conf_disable_ipv6(self, ifname):
+ return int(self.read_file_oneline("/proc/sys/net/ipv6/conf/%s/disable_ipv6" % ifname) or 0)
+
+
+Sysfs = __Sysfs()
-p, --print-dependency {list,dot}
print iface dependency in list or dot format
- --admin-state, --no-scripts
+ -m, --admin-state, --no-scripts
don't run any addon modules/scripts. Only bring
the interface administratively up/down
-p, --print-dependency {list,dot}
print iface dependency in list or dot format
- --admin-state, --no-scripts
+ -m, --admin-state, --no-scripts
don't run any addon modules/scripts. Only bring
the interface administratively up/down
#!/usr/bin/env python
#
-# Copyright (C) 2015, 2017 Cumulus Networks, Inc. all rights reserved
+# Copyright (C) 2015-2020 Cumulus Networks, Inc. all rights reserved
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
from threading import Thread, Event, Lock
from Queue import Queue
import logging
+import signal
import socket
import errno
+import os
log = logging.getLogger(__name__)
class NetlinkListener(Thread):
+ # As defined in asm/socket.h
+ _SO_ATTACH_FILTER = 26
- def __init__(self, manager, groups, pid_offset=1, error_notification=False, rcvbuf_sz=10000000):
+ RECV_BUFFER = 4096 # 1024 * 1024
+
+ def __init__(self, manager, groups, pid_offset=1, error_notification=False, rcvbuf_sz=10000000, bpf_filter=None):
"""
groups controls what types of messages we are interested in hearing
To get everything pass:
RTMGRP_IPV6_IFADDR | \
RTMGRP_IPV6_ROUTE
"""
- Thread.__init__(self)
+ Thread.__init__(self, name='NetlinkListener')
self.manager = manager
self.shutdown_event = Event()
self.groups = groups
self.pid_offset = pid_offset
self.rcvbuf_sz = rcvbuf_sz
+ self.bpf_filter = bpf_filter
+ self.rx_socket = None
+ self.rx_socket_prev_seq = {}
# if the app has requested for error notification socket errors will
# be sent via the SERVICE_ERROR event
self.supported_messages = [RTM_NEWLINK, RTM_DELLINK, RTM_NEWADDR,
RTM_DELADDR, RTM_NEWNEIGH, RTM_DELNEIGH,
- RTM_NEWROUTE, RTM_DELROUTE]
+ RTM_NEWROUTE, RTM_DELROUTE,
+ RTM_NEWMDB, RTM_DELMDB, RTM_GETMDB]
self.ignore_messages = [RTM_GETLINK, RTM_GETADDR, RTM_GETNEIGH,
RTM_GETROUTE, RTM_GETQDISC, NLMSG_ERROR, NLMSG_DONE]
if msgtype not in self.ignore_messages:
self.ignore_messages.append(msgtype)
+ def __bind_rx_socket(self, pid):
+ """
+ bind rx_socket and retry mechanism in case of failure and collision
+ i.e.: [Errno 98] Address already in use
+
+ We will retry NLMANAGER_BIND_RETRY times (defaults to 4242)
+
+ :param pid:
+ :return:
+ """
+ pid_offset = self.pid_offset
+ for i in xrange(0, int(os.getenv("NLMANAGER_BIND_RETRY", 4242))):
+ try:
+ pid_offset += i
+ self.rx_socket.bind((pid | (pid_offset << 22), self.groups))
+ self.pid_offset = pid_offset
+ return
+ except:
+ pass
+ # if we reach this line it means we've reach NLMANAGER_BIND_RETRY limit
+ # and couldn't successfully bind the rx_socket... We will try one more
+ # time but without catching the related exception.
+ self.rx_socket.bind((pid | (self.pid_offset << 22), self.groups))
+
def run(self):
manager = self.manager
- header_PACK = 'IHHII'
- header_LEN = calcsize(header_PACK)
-
- # The RX socket is used to listen to all netlink messages that fly by
- # as things change in the kernel. We need a very large SO_RCVBUF here
- # else we tend to miss messages.
- # PID_MAX_LIMIT is 2^22 allowing 1024 sockets per-pid. We default to
- # use 2 in the upper space (top 10 bits) instead of 0 to avoid conflicts
- # with the netlink manager which always attempts to bind with the pid.
- self.rx_socket = socket.socket(socket.AF_NETLINK, socket.SOCK_RAW, 0)
- _SO_RCVBUFFORCE = socket.SO_RCVBUFFORCE if hasattr(socket, 'SO_RCVBUFFORCE') else 33
- self.rx_socket.setsockopt(socket.SOL_SOCKET, _SO_RCVBUFFORCE, self.rcvbuf_sz)
- self.rx_socket.bind((manager.pid | (self.pid_offset << 22), self.groups))
- self.rx_socket_prev_seq = {}
+ try:
+ header_PACK = 'IHHII'
+ header_LEN = calcsize(header_PACK)
+
+ # The RX socket is used to listen to all netlink messages that fly by
+ # as things change in the kernel. We need a very large SO_RCVBUF here
+ # else we tend to miss messages.
+ # PID_MAX_LIMIT is 2^22 allowing 1024 sockets per-pid. We default to
+ # use 2 in the upper space (top 10 bits) instead of 0 to avoid conflicts
+ # with the netlink manager which always attempts to bind with the pid.
+ self.rx_socket = socket.socket(socket.AF_NETLINK, socket.SOCK_RAW, 0)
+ try:
+ self.rx_socket.setsockopt(
+ socket.SOL_SOCKET,
+ socket.SO_RCVBUFFORCE if hasattr(socket, 'SO_RCVBUFFORCE') else 33,
+ self.rcvbuf_sz
+ )
+ if self.bpf_filter is not None:
+ self.rx_socket.setsockopt(
+ socket.SOL_SOCKET,
+ NetlinkListener._SO_ATTACH_FILTER,
+ self.bpf_filter
+ )
+ except Exception as e:
+ log.debug("nllistener: rx socket: setsockopt: %s" % str(e))
- manager.target_lock.acquire()
- if not manager.tx_socket:
- manager.tx_socket_allocate()
- manager.target_lock.release()
+ self.__bind_rx_socket(manager.pid)
- my_sockets = (manager.tx_socket, self.rx_socket)
+ with manager.target_lock:
+ if not manager.tx_socket:
+ manager.tx_socket_allocate()
- socket_string = {
- manager.tx_socket: "TX",
- self.rx_socket: "RX"
- }
+ my_sockets = (manager.tx_socket, self.rx_socket)
+
+ socket_string = {
+ manager.tx_socket: "TX",
+ self.rx_socket: "RX"
+ }
+ except Exception as e:
+ if self.rx_socket:
+ self.rx_socket.close()
+ self.rx_socket = None
+
+ # before notifying the main thread we need to set
+ # manager.listener_ready properly to signal the failure
+ manager.listener_ready = False
+ manager.listener_event_ready.set()
+
+ if logging.root.level == logging.DEBUG:
+ # in debug mode we raise the exception so it can be displayed
+ # in the terminal: "Exception in thread NetlinkListener..."
+ raise
+ else:
+ log.error("netlink: listener thread: rx socket: %s" % str(e))
+ return
+
+ # Notify main thread that the NetlinkListener thread
+ # has started and is ready to start processing data
+ manager.listener_ready = True
+ manager.listener_event_ready.set()
while True:
# Only block for 1 second so we can wake up to see if shutdown_event is set
try:
- (readable, writeable, exceptional) = select(my_sockets, [], my_sockets, 1)
+ (readable, writeable, exceptional) = select(my_sockets, [], my_sockets, 0.1)
+ # when ifupdown2 is not running we could change the timeout to 1 sec or more
except Exception as e:
log.error('select() error: ' + str(e))
continue
data = []
try:
- data = s.recv(4096)
+ data = s.recv(self.RECV_BUFFER)
except socket.error, e:
log.error('recv() error: ' + str(e))
data = []
# Extract the length, etc from the header
(length, msgtype, flags, seq, pid) = unpack(header_PACK, data[:header_LEN])
+ msgtype_str = NetlinkPacket.type_to_string.get(msgtype)
+
+ if not msgtype_str:
+ data = data[length:]
+ log.debug('%s %s: RXed unknown/unsupported msg type %s skipping netlink message...' % (self, socket_string[s], msgtype))
+ continue
+
log.debug('%s %s: RXed %s seq %d, pid %d, %d bytes (%d total)' %
- (self, socket_string[s], NetlinkPacket.type_to_string[msgtype],
+ (self, socket_string[s], msgtype_str,
seq, pid, length, total_length))
possible_ack = False
msg.decode_packet(length, flags, seq, pid, data)
if error_code:
- log.debug("%s %s: RXed NLMSG_ERROR code %s (%d)" % (self, socket_string[s], msg.error_to_string.get(error_code), error_code))
+ log.debug("%s %s: RXed NLMSG_ERROR code %s (%d): %s" % (self, socket_string[s], msg.error_to_string.get(error_code), error_code, msg.error_to_human_readable_string.get(error_code)))
+ else:
+ log.debug("%s %s: RXed NLMSG_ERROR code %s (%d): %s... this is an ACK" % (self, socket_string[s], msg.error_to_string.get(error_code), error_code, msg.error_to_human_readable_string.get(error_code)))
+
+ if manager.errorq_enabled:
+ with manager.errorq_lock:
+ manager.errorq.append(msg)
if possible_ack and seq == manager.target_seq and pid == manager.target_pid:
log.debug("%s %s: Setting RXed ACK alarm for seq %d, pid %d" %
data = data[length:]
if set_tx_socket_rxed_ack_alarm:
- manager.target_lock.acquire()
- manager.target_seq = None
- manager.target_pid = None
- manager.target_lock.release()
+ with manager.target_lock:
+ manager.target_seq = None
+ manager.target_pid = None
manager.tx_socket_rxed_ack.set()
if set_alarm:
- manager.workq.put(('SERVICE_NETLINK_QUEUE', None))
+ manager.workq.put((manager.WORKQ_SERVICE_NETLINK_QUEUE, None))
if set_overrun:
- manager.workq.put(('SERVICE_ERROR', "OVERFLOW"))
+ manager.workq.put((manager.WORKQ_SERVICE_ERROR, "OVERFLOW"))
if set_alarm or set_overrun:
manager.alarm.set()
class NetlinkManagerWithListener(NetlinkManager):
- def __init__(self, groups, start_listener=True, use_color=True, pid_offset=0, error_notification=False, rcvbuf_sz=10000000):
+ WORKQ_SERVICE_NETLINK_QUEUE = 1
+ WORKQ_SERVICE_ERROR = 2
+
+ def __init__(self, groups, start_listener=True, use_color=True, pid_offset=0, error_notification=False, rcvbuf_sz=10000000, bpf_filter=None):
NetlinkManager.__init__(self, use_color=use_color, pid_offset=pid_offset)
self.groups = groups
self.workq = Queue()
self.rcvbuf_sz = rcvbuf_sz
self.error_notification = error_notification
self.pid_offset = pid_offset
+ self.bpf_filter = bpf_filter
+
+ self.errorq = None
+ self.errorq_lock = None
+ self.errorq_enabled = False
+
+ self.listener_event_ready = None
+ self.listener_ready = None
# Listen to netlink messages
if start_listener:
return 'NetlinkManagerWithListener'
def restart_listener(self):
- self.listener = NetlinkListener(self, self.groups, self.pid_offset+1, self.error_notification, self.rcvbuf_sz)
+ """
+ (re)Start Netlink listener thread and make sure to wait until
+ the newly created thread is ready.
+ :return:
+ """
+ self.listener_event_ready = Event()
+ self.listener_ready = False
+
+ self.listener = NetlinkListener(self, self.groups, self.pid_offset + 1, self.error_notification, self.rcvbuf_sz, self.bpf_filter)
self.listener.start()
- def signal_term_handler(self, signal, frame):
- log.info("NetlinkManagerWithListener: Caught SIGTERM")
+ self.listener_event_ready.wait()
+ if not self.listener_ready:
+ self.listener.join()
+ # TODO: add custom exception (easier to ignore and recognize)
+ raise Exception()
+
+ def signal_term_handler(self, sig, frame):
+ if sig == signal.SIGTERM:
+ log.info("NetlinkManagerWithListener: Caught SIGTERM")
if self.listener:
self.listener.shutdown_event.set()
self.alarm.set()
def tx_nlpacket_get_response(self, nlpacket):
+ # WARNING: having multiple threads waiting for ACKs might result in
+ # undefined behavior. To make this work we should probably have a
+ # (thread-safe) list of all the target SEQs and PIDs along side a
+ # reference to their alarms (thead.Event) to notify the right thread
+ # of the RXed ACK.
"""
TX the message and wait for an ack
"""
# NetlinkListener looks at the manager's target_seq and target_pid
# to know when we've RXed the ack that we want
- self.target_lock.acquire()
- self.target_seq = nlpacket.seq
- self.target_pid = nlpacket.pid
+ with self.target_lock:
+ self.target_seq = nlpacket.seq
+ self.target_pid = nlpacket.pid
- if not self.tx_socket:
- self.tx_socket_allocate()
- self.target_lock.release()
+ if not self.tx_socket:
+ self.tx_socket_allocate()
log.debug('%s TX: TXed %s seq %d, pid %d, %d bytes' %
(self, NetlinkPacket.type_to_string[nlpacket.msgtype],
log.debug("RXed RTM_DELLINK seq %d, pid %d, %d bytes, for %s, state %s" %
(msg.seq, msg.pid, msg.length, msg.get_attribute_value(msg.IFLA_IFNAME), "up" if msg.is_up() else "down"))
+ def rx_rtm_newnetconf(self, msg):
+ ifindex = msg.get_attribute_value(msg.NETCONFA_IFINDEX)
+ ifname = self.ifname_by_index.get(ifindex)
+
+ if ifname:
+ log.debug("RXed RTM_NEWNETCONF seq %d, pid %d, %d bytes on ifname %s" % (msg.seq, msg.pid, msg.length, ifname))
+ else:
+ log.debug("RXed RTM_NEWNETCONF seq %d, pid %d, %d bytes on ifindex %s" % (msg.seq, msg.pid, msg.length, ifindex))
+
+ def rx_rtm_delnetconf(self, msg):
+ ifindex = msg.get_attribute_value(msg.NETCONFA_IFINDEX)
+ ifname = self.ifname_by_index.get(ifindex)
+
+ if ifname:
+ log.debug("RXed RTM_DELNETCONF seq %d, pid %d, %d bytes on ifname %s" % (msg.seq, msg.pid, msg.length, ifname))
+ else:
+ log.debug("RXed RTM_DELNETCONF seq %d, pid %d, %d bytes on ifindex %s" % (msg.seq, msg.pid, msg.length, ifindex))
+
def rx_rtm_newaddr(self, msg):
- log.debug("RXed RTM_NEWADDR seq %d, pid %d, %d bytes, for %s/%d on %s" %
- (msg.seq, msg.pid, msg.length, msg.get_attribute_value(msg.IFA_ADDRESS), msg.prefixlen, self.ifname_by_index.get(msg.ifindex)))
+ log.debug("RXed RTM_NEWADDR seq %d, pid %d, %d bytes, for %s on %s" % (msg.seq, msg.pid, msg.length, msg.get_attribute_value(msg.IFA_ADDRESS), self.ifname_by_index.get(msg.ifindex)))
def rx_rtm_deladdr(self, msg):
- log.debug("RXed RTM_DELADDR seq %d, pid %d, %d bytes, for %s/%d on %s" %
- (msg.seq, msg.pid, msg.length, msg.get_attribute_value(msg.IFA_ADDRESS), msg.prefixlen, self.ifname_by_index.get(msg.ifindex)))
+ log.debug("RXed RTM_DELADDR seq %d, pid %d, %d bytes, for %s on %s" % (msg.seq, msg.pid, msg.length, msg.get_attribute_value(msg.IFA_ADDRESS), self.ifname_by_index.get(msg.ifindex)))
def rx_rtm_newneigh(self, msg):
log.debug("RXed RTM_NEWNEIGH seq %d, pid %d, %d bytes, for %s on %s" %
log.debug("RXed RTM_DELROUTE seq %d, pid %d, %d bytes, for %s%s" %
(msg.seq, msg.pid, msg.length, msg.get_prefix_string(), msg.get_nexthops_string(self.ifname_by_index)))
+ def rx_rtm_newmdb(self, msg):
+ log.debug("RXed RTM_NEWMDB")
+
+ def rx_rtm_delmdb(self, msg):
+ log.debug("RXed RTM_DELMDB")
+
def rx_nlmsg_done(self, msg):
log.debug("RXed NLMSG_DONE seq %d, pid %d, %d bytes" % (msg.seq, msg.pid, msg.length))
def filter_by_nested_attribute(self, add, filter_type, msgtype, attr_filter):
self._filter_update(add, filter_type, msgtype, ('NESTED_ATTRIBUTE', attr_filter))
- def service_netlinkq(self):
+ def service_netlinkq(self, notify_event=None):
msg_count = {}
processed = 0
elif msgtype == RTM_NEWROUTE or msgtype == RTM_DELROUTE:
msg = Route(msgtype, debug, use_color=self.use_color)
+ elif msgtype in (RTM_GETNETCONF, RTM_NEWNETCONF, RTM_DELNETCONF):
+ msg = Netconf(msgtype, debug, use_color=self.use_color)
+
+ elif msgtype == RTM_NEWMDB or msgtype == RTM_DELMDB:
+ msg = MDB(msgtype, debug, use_color=self.use_color)
+
elif msgtype == NLMSG_DONE:
msg = Done(msgtype, debug, use_color=self.use_color)
elif msg.msgtype == RTM_DELROUTE:
self.rx_rtm_delroute(msg)
+ elif msg.msgtype == RTM_NEWNETCONF:
+ self.rx_rtm_newnetconf(msg)
+
+ elif msg.msgtype == RTM_DELNETCONF:
+ self.rx_rtm_delnetconf(msg)
+
+ elif msg.msgtype == RTM_NEWMDB:
+ self.rx_rtm_newmdb(msg)
+
+ elif msg.msgtype == RTM_DELMDB:
+ self.rx_rtm_delmdb(msg)
+
elif msg.msgtype == NLMSG_DONE:
self.rx_nlmsg_done(msg)
if processed:
self.netlinkq = self.netlinkq[processed:]
+ if notify_event:
+ notify_event.set()
+
# too chatty
# for msgtype in msg_count:
# log.debug('RXed %d %s messages' % (msg_count[msgtype], NetlinkPacket.type_to_string[msgtype]))
#!/usr/bin/env python
#
-# Copyright (C) 2015, 2017 Cumulus Networks, Inc. all rights reserved
+# Copyright (C) 2015-2020 Cumulus Networks, Inc. all rights reserved
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
self._debug_set_clear((RTM_NEWROUTE, RTM_DELROUTE, RTM_GETROUTE), enabled)
def debug_netconf(self, enabled):
- self._debug_set_clear((RTM_GETNETCONF, RTM_NEWNETCONF), enabled)
+ self._debug_set_clear((RTM_GETNETCONF, RTM_NEWNETCONF, RTM_DELNETCONF), enabled)
+
+ def debug_mdb(self, enabled):
+ self._debug_set_clear((RTM_GETMDB, RTM_NEWMDB, RTM_DELMDB), enabled)
def debug_this_packet(self, mtype):
if mtype in self.debug:
elif msgtype in (RTM_GETNETCONF, RTM_NEWNETCONF):
msg = Netconf(msgtype, nlpacket.debug, use_color=self.use_color)
+ elif msgtype in (RTM_GETMDB, RTM_NEWMDB, RTM_DELMDB):
+ msg = MDB(msgtype, nlpacket.debug, use_color=self.use_color)
+
else:
raise Exception("RXed unknown netlink message type %s" % msgtype)
msg = Route(rtm_type, debug, use_color=self.use_color)
msg.body = pack('Bxxxii', family, 0, 0)
+ elif rtm_type == RTM_GETMDB:
+ msg = MDB(rtm_type, debug, use_color=self.use_color)
+ msg.body = pack('Bxxxii', family, 0, 0)
+
else:
log.error("request_dump RTM_GET %s is not supported" % rtm_type)
return None
return self._link_add(ifindex, ifname, 'vlan', ifla_info_data)
- def link_add_macvlan(self, ifindex, ifname):
+ def link_add_macvlan(self, ifindex, ifname, macvlan_mode):
"""
ifindex is the index of the parent interface that this sub-interface
is being added to
"""
- return self._link_add(ifindex, ifname, 'macvlan', {Link.IFLA_MACVLAN_MODE: Link.MACVLAN_MODE_PRIVATE})
-
- def link_add_xfrm(self, physdev, xfrm_ifname, xfrm_id):
- """
- ifindex is the index of the parent interface that this sub-interface
- is being added to
- """
- ifla_info_data = {
- Link.IFLA_XFRM_IF_ID: int(xfrm_id),
- Link.IFLA_XFRM_LINK: int(physdev)
- }
-
- return self._link_add(ifindex=None, ifname=xfrm_ifname, kind='xfrm', ifla_info_data=ifla_info_data)
+ return self._link_add(
+ ifindex,
+ ifname,
+ 'macvlan',
+ {
+ Link.IFLA_MACVLAN_MODE: {
+ "private": Link.MACVLAN_MODE_PRIVATE,
+ "vepa": Link.MACVLAN_MODE_VEPA,
+ "bridge": Link.MACVLAN_MODE_BRIDGE,
+ "passthru": Link.MACVLAN_MODE_PASSTHRU
+ }.get(macvlan_mode, Link.MACVLAN_MODE_PRIVATE)
+ }
+ )
def vlan_get(self, filter_ifindex=None, filter_vlanid=None, compress_vlans=True):
"""
msg.flags = NLM_F_REQUEST | NLM_F_DUMP | NLM_F_ACK
msg.build_message(self.sequence.next(), self.pid)
return self.tx_nlpacket_get_response(msg)
+
+ # ===
+ # MDB
+ # ===
+ def mdb_dump(self):
+ debug = RTM_GETMDB in self.debug
+ msg = MDB(RTM_GETMDB, debug, use_color=self.use_color)
+ msg.body = pack('Bxxxiii', socket.AF_BRIDGE, 0, 0, 0)
+ msg.flags = NLM_F_REQUEST | NLM_F_DUMP | NLM_F_ACK
+ msg.build_message(self.sequence.next(), self.pid)
+ return self.tx_nlpacket_get_response(msg)
# Copyright (c) 2009-2013, Exa Networks Limited
# Copyright (c) 2009-2013, Thomas Mangin
-# Copyright (c) 2015-2017 Cumulus Networks, Inc.
+# Copyright (c) 2015-2020 Cumulus Networks, Inc.
#
# All rights reserved.
# Redistribution and use in source and binary forms, with or without
import logging
import struct
-from ipaddr import IPv4Address, IPv6Address, IPAddress
+from ipaddr import IPNetwork, IPv4Address, IPv6Address, IPAddress
from binascii import hexlify
from pprint import pformat
from socket import AF_UNSPEC, AF_INET, AF_INET6, AF_BRIDGE, htons
log = logging.getLogger(__name__)
SYSLOG_EXTRA_DEBUG = 5
+ETH_P_IP = 0x0800
+ETH_P_IPV6 = 0x86DD
+
+INFINITY_LIFE_TIME = 0xFFFFFFFF
# Interface name buffer size #define IFNAMSIZ 16 (kernel source)
IF_NAME_SIZE = 15 # 15 because python doesn't have \0
RTM_GETQDISC = 0x26
RTM_NEWNETCONF = 80
+RTM_DELNETCONF = 81
RTM_GETNETCONF = 82
+RTM_NEWMDB = 84
+RTM_DELMDB = 85
+RTM_GETMDB = 86
+
# Netlink message flags
NLM_F_REQUEST = 0x01 # It is query message.
NLM_F_MULTI = 0x02 # Multipart message, terminated by NLMSG_DONE
RTMGRP_DECnet_IFADDR = 0x1000
RTMGRP_DECnet_ROUTE = 0x4000
RTMGRP_IPV6_PREFIX = 0x20000
+RTNLGRP_MDB = 0x1A
+
+
+def nl_mgrp(group):
+ """
+ The api is a reimplementation of "nl_mgrp" function from
+ iproute2/include/utils.h
+ """
+ if group > 31:
+ raise Exception("%d Invalid Group" % group)
+ else:
+ group = (1 << (group - 1)) if group else 0
+ return group
+
+
+RTNLGRP_IPV4_NETCONF = nl_mgrp(24)
+RTNLGRP_IPV6_NETCONF = nl_mgrp(25)
+RTNLGRP_MPLS_NETCONF = nl_mgrp(29)
+
RTMGRP_ALL = (RTMGRP_LINK | RTMGRP_NOTIFY | RTMGRP_NEIGH | RTMGRP_TC |
RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_MROUTE | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_RULE |
RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_MROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFINFO |
- RTMGRP_DECnet_IFADDR | RTMGRP_DECnet_ROUTE |
- RTMGRP_IPV6_PREFIX)
+ RTMGRP_DECnet_IFADDR | RTMGRP_DECnet_ROUTE | nl_mgrp(RTNLGRP_MDB) |
+ RTMGRP_IPV6_PREFIX | RTNLGRP_IPV4_NETCONF | RTNLGRP_IPV6_NETCONF | RTNLGRP_MPLS_NETCONF)
+
+# /etc/iproute2/rt_scopes
+RT_SCOPES = {
+ "global": 0,
+ "universe": 0,
+ "nowhere": 255,
+ "host": 254,
+ "link": 253,
+ "site": 200
+}
AF_MPLS = 28
return int((length + 3) / 4) * 4
-class Attribute(object):
+class NetlinkPacket_IFLA_LINKINFO_Attributes:
- def __init__(self, atype, string, logger):
- self.atype = atype
- self.string = string
- self.HEADER_PACK = '=HH'
- self.HEADER_LEN = calcsize(self.HEADER_PACK)
- self.PACK = None
- self.LEN = None
- self.value = None
- self.nested = False
- self.net_byteorder = False
- self.log = logger
+ # =========================================
+ # IFLA_LINKINFO attributes
+ # =========================================
+ IFLA_INFO_UNSPEC = 0
+ IFLA_INFO_KIND = 1
+ IFLA_INFO_DATA = 2
+ IFLA_INFO_XSTATS = 3
+ IFLA_INFO_SLAVE_KIND = 4
+ IFLA_INFO_SLAVE_DATA = 5
+ IFLA_INFO_MAX = 6
- def __str__(self):
- return self.string
+ ifla_info_to_string = {
+ IFLA_INFO_UNSPEC : 'IFLA_INFO_UNSPEC',
+ IFLA_INFO_KIND : 'IFLA_INFO_KIND',
+ IFLA_INFO_DATA : 'IFLA_INFO_DATA',
+ IFLA_INFO_XSTATS : 'IFLA_INFO_XSTATS',
+ IFLA_INFO_SLAVE_KIND : 'IFLA_INFO_SLAVE_KIND',
+ IFLA_INFO_SLAVE_DATA : 'IFLA_INFO_SLAVE_DATA',
+ IFLA_INFO_MAX : 'IFLA_INFO_MAX'
+ }
- def set_value(self, value):
- self.value = value
+ # =========================================
+ # IFLA_INFO_DATA attributes for vlan
+ # =========================================
+ IFLA_VLAN_UNSPEC = 0
+ IFLA_VLAN_ID = 1
+ IFLA_VLAN_FLAGS = 2
+ IFLA_VLAN_EGRESS_QOS = 3
+ IFLA_VLAN_INGRESS_QOS = 4
+ IFLA_VLAN_PROTOCOL = 5
- def set_nested(self, nested):
- self.nested = nested
+ ifla_vlan_to_string = {
+ IFLA_VLAN_UNSPEC : 'IFLA_VLAN_UNSPEC',
+ IFLA_VLAN_ID : 'IFLA_VLAN_ID',
+ IFLA_VLAN_FLAGS : 'IFLA_VLAN_FLAGS',
+ IFLA_VLAN_EGRESS_QOS : 'IFLA_VLAN_EGRESS_QOS',
+ IFLA_VLAN_INGRESS_QOS : 'IFLA_VLAN_INGRESS_QOS',
+ IFLA_VLAN_PROTOCOL : 'IFLA_VLAN_PROTOCOL'
+ }
- def set_net_byteorder(self, net_byteorder):
- self.net_byteorder = net_byteorder
+ ifla_vlan_protocol_dict = {
+ '802.1Q': 0x8100,
+ '802.1q': 0x8100,
- def pad_bytes_needed(self, length):
- """
- Return the number of bytes that should be added to align on a 4-byte boundry
- """
- remainder = length % 4
+ '802.1ad': 0x88A8,
+ '802.1AD': 0x88A8,
+ '802.1Ad': 0x88A8,
+ '802.1aD': 0x88A8,
- if remainder:
- return 4 - remainder
+ 0x8100: '802.1Q',
+ 0x88A8: '802.1ad'
+ }
- return 0
+ # =========================================
+ # IFLA_INFO_DATA attributes for macvlan
+ # =========================================
+ IFLA_MACVLAN_UNSPEC = 0
+ IFLA_MACVLAN_MODE = 1
- def pad(self, length, raw):
- pad = self.pad_bytes_needed(length)
+ ifla_macvlan_to_string = {
+ IFLA_MACVLAN_UNSPEC : 'IFLA_MACVLAN_UNSPEC',
+ IFLA_MACVLAN_MODE : 'IFLA_MACVLAN_MODE'
+ }
- if pad:
- raw += '\0' * pad
+ # enum macvlan_mode
+ MACVLAN_MODE_PRIVATE = 1 # don't talk to other macvlans */
+ MACVLAN_MODE_VEPA = 2 # talk to other ports through ext bridge */
+ MACVLAN_MODE_BRIDGE = 4 # talk to bridge ports directly */
+ MACVLAN_MODE_PASSTHRU = 8 # take over the underlying device */
+ MACVLAN_MODE_SOURCE = 16 # use source MAC address list to assign */
- return raw
+ macvlan_mode_to_string = {
+ MACVLAN_MODE_PRIVATE : 'MACVLAN_MODE_PRIVATE',
+ MACVLAN_MODE_VEPA : 'MACVLAN_MODE_VEPA',
+ MACVLAN_MODE_BRIDGE : 'MACVLAN_MODE_BRIDGE',
+ MACVLAN_MODE_PASSTHRU : 'MACVLAN_MODE_PASSTHRU',
+ MACVLAN_MODE_SOURCE : 'MACVLAN_MODE_SOURCE'
+ }
- def encode(self):
+ # =========================================
+ # IFLA_INFO_DATA attributes for xfrm
+ # =========================================
+ IFLA_XFRM_UNSPEC = 0
+ IFLA_XFRM_LINK = 1
+ IFLA_XFRM_IF_ID = 2
- if not self.LEN:
- raise Exception('Please define an encode() method in your child attribute class, or do not use AttributeGeneric')
+ ifla_xfrm_to_string = {
+ IFLA_XFRM_UNSPEC: 'IFLA_XFRM_UNSPEC',
+ IFLA_XFRM_LINK : 'IFLA_XFRM_LINK',
+ IFLA_XFRM_IF_ID : 'IFLA_XFRM_IF_ID'
+ }
- length = self.HEADER_LEN + self.LEN
- attr_type_with_flags = self.atype
+ # =========================================
+ # IFLA_INFO_DATA attributes for vxlan
+ # =========================================
+ IFLA_VXLAN_UNSPEC = 0
+ IFLA_VXLAN_ID = 1
+ IFLA_VXLAN_GROUP = 2
+ IFLA_VXLAN_LINK = 3
+ IFLA_VXLAN_LOCAL = 4
+ IFLA_VXLAN_TTL = 5
+ IFLA_VXLAN_TOS = 6
+ IFLA_VXLAN_LEARNING = 7
+ IFLA_VXLAN_AGEING = 8
+ IFLA_VXLAN_LIMIT = 9
+ IFLA_VXLAN_PORT_RANGE = 10
+ IFLA_VXLAN_PROXY = 11
+ IFLA_VXLAN_RSC = 12
+ IFLA_VXLAN_L2MISS = 13
+ IFLA_VXLAN_L3MISS = 14
+ IFLA_VXLAN_PORT = 15
+ IFLA_VXLAN_GROUP6 = 16
+ IFLA_VXLAN_LOCAL6 = 17
+ IFLA_VXLAN_UDP_CSUM = 18
+ IFLA_VXLAN_UDP_ZERO_CSUM6_TX = 19
+ IFLA_VXLAN_UDP_ZERO_CSUM6_RX = 20
+ IFLA_VXLAN_REMCSUM_TX = 21
+ IFLA_VXLAN_REMCSUM_RX = 22
+ IFLA_VXLAN_GBP = 23
+ IFLA_VXLAN_REMCSUM_NOPARTIAL = 24
+ IFLA_VXLAN_COLLECT_METADATA = 25
+ IFLA_VXLAN_REPLICATION_NODE = 253
+ IFLA_VXLAN_REPLICATION_TYPE = 254
- if self.nested:
- attr_type_with_flags = attr_type_with_flags | NLA_F_NESTED
+ ifla_vxlan_to_string = {
+ IFLA_VXLAN_UNSPEC : 'IFLA_VXLAN_UNSPEC',
+ IFLA_VXLAN_ID : 'IFLA_VXLAN_ID',
+ IFLA_VXLAN_GROUP : 'IFLA_VXLAN_GROUP',
+ IFLA_VXLAN_LINK : 'IFLA_VXLAN_LINK',
+ IFLA_VXLAN_LOCAL : 'IFLA_VXLAN_LOCAL',
+ IFLA_VXLAN_TTL : 'IFLA_VXLAN_TTL',
+ IFLA_VXLAN_TOS : 'IFLA_VXLAN_TOS',
+ IFLA_VXLAN_LEARNING : 'IFLA_VXLAN_LEARNING',
+ IFLA_VXLAN_AGEING : 'IFLA_VXLAN_AGEING',
+ IFLA_VXLAN_LIMIT : 'IFLA_VXLAN_LIMIT',
+ IFLA_VXLAN_PORT_RANGE : 'IFLA_VXLAN_PORT_RANGE',
+ IFLA_VXLAN_PROXY : 'IFLA_VXLAN_PROXY',
+ IFLA_VXLAN_RSC : 'IFLA_VXLAN_RSC',
+ IFLA_VXLAN_L2MISS : 'IFLA_VXLAN_L2MISS',
+ IFLA_VXLAN_L3MISS : 'IFLA_VXLAN_L3MISS',
+ IFLA_VXLAN_PORT : 'IFLA_VXLAN_PORT',
+ IFLA_VXLAN_GROUP6 : 'IFLA_VXLAN_GROUP6',
+ IFLA_VXLAN_LOCAL6 : 'IFLA_VXLAN_LOCAL6',
+ IFLA_VXLAN_UDP_CSUM : 'IFLA_VXLAN_UDP_CSUM',
+ IFLA_VXLAN_UDP_ZERO_CSUM6_TX : 'IFLA_VXLAN_UDP_ZERO_CSUM6_TX',
+ IFLA_VXLAN_UDP_ZERO_CSUM6_RX : 'IFLA_VXLAN_UDP_ZERO_CSUM6_RX',
+ IFLA_VXLAN_REMCSUM_TX : 'IFLA_VXLAN_REMCSUM_TX',
+ IFLA_VXLAN_REMCSUM_RX : 'IFLA_VXLAN_REMCSUM_RX',
+ IFLA_VXLAN_GBP : 'IFLA_VXLAN_GBP',
+ IFLA_VXLAN_REMCSUM_NOPARTIAL : 'IFLA_VXLAN_REMCSUM_NOPARTIAL',
+ IFLA_VXLAN_COLLECT_METADATA : 'IFLA_VXLAN_COLLECT_METADATA',
+ IFLA_VXLAN_REPLICATION_NODE : 'IFLA_VXLAN_REPLICATION_NODE',
+ IFLA_VXLAN_REPLICATION_TYPE : 'IFLA_VXLAN_REPLICATION_TYPE'
+ }
- if self.net_byteorder:
- attr_type_with_flags = attr_type_with_flags | NLA_F_NET_BYTEORDER
+ # =========================================
+ # IFLA_INFO_DATA attributes for bonds
+ # =========================================
+ IFLA_BOND_UNSPEC = 0
+ IFLA_BOND_MODE = 1
+ IFLA_BOND_ACTIVE_SLAVE = 2
+ IFLA_BOND_MIIMON = 3
+ IFLA_BOND_UPDELAY = 4
+ IFLA_BOND_DOWNDELAY = 5
+ IFLA_BOND_USE_CARRIER = 6
+ IFLA_BOND_ARP_INTERVAL = 7
+ IFLA_BOND_ARP_IP_TARGET = 8
+ IFLA_BOND_ARP_VALIDATE = 9
+ IFLA_BOND_ARP_ALL_TARGETS = 10
+ IFLA_BOND_PRIMARY = 11
+ IFLA_BOND_PRIMARY_RESELECT = 12
+ IFLA_BOND_FAIL_OVER_MAC = 13
+ IFLA_BOND_XMIT_HASH_POLICY = 14
+ IFLA_BOND_RESEND_IGMP = 15
+ IFLA_BOND_NUM_PEER_NOTIF = 16
+ IFLA_BOND_ALL_SLAVES_ACTIVE = 17
+ IFLA_BOND_MIN_LINKS = 18
+ IFLA_BOND_LP_INTERVAL = 19
+ IFLA_BOND_PACKETS_PER_SLAVE = 20
+ IFLA_BOND_AD_LACP_RATE = 21
+ IFLA_BOND_AD_SELECT = 22
+ IFLA_BOND_AD_INFO = 23
+ IFLA_BOND_AD_ACTOR_SYS_PRIO = 24
+ IFLA_BOND_AD_USER_PORT_KEY = 25
+ IFLA_BOND_AD_ACTOR_SYSTEM = 26
+ IFLA_BOND_CL_START = 60
+ IFLA_BOND_AD_LACP_BYPASS = IFLA_BOND_CL_START
- raw = pack(self.HEADER_PACK, length, attr_type_with_flags) + pack(self.PACK, self.value)
- raw = self.pad(length, raw)
- return raw
- def decode_length_type(self, data):
- """
- The first two bytes of an attribute are the length, the next two bytes are the type
- """
- self.data = data
- prev_atype = self.atype
- (data1, data2) = unpack(self.HEADER_PACK, data[:self.HEADER_LEN])
- self.length = int(data1)
- self.atype = int(data2)
- self.attr_end = padded_length(self.length)
+ ifla_bond_to_string = {
+ IFLA_BOND_UNSPEC : 'IFLA_BOND_UNSPEC',
+ IFLA_BOND_MODE : 'IFLA_BOND_MODE',
+ IFLA_BOND_ACTIVE_SLAVE : 'IFLA_BOND_ACTIVE_SLAVE',
+ IFLA_BOND_MIIMON : 'IFLA_BOND_MIIMON',
+ IFLA_BOND_UPDELAY : 'IFLA_BOND_UPDELAY',
+ IFLA_BOND_DOWNDELAY : 'IFLA_BOND_DOWNDELAY',
+ IFLA_BOND_USE_CARRIER : 'IFLA_BOND_USE_CARRIER',
+ IFLA_BOND_ARP_INTERVAL : 'IFLA_BOND_ARP_INTERVAL',
+ IFLA_BOND_ARP_IP_TARGET : 'IFLA_BOND_ARP_IP_TARGET',
+ IFLA_BOND_ARP_VALIDATE : 'IFLA_BOND_ARP_VALIDATE',
+ IFLA_BOND_ARP_ALL_TARGETS : 'IFLA_BOND_ARP_ALL_TARGETS',
+ IFLA_BOND_PRIMARY : 'IFLA_BOND_PRIMARY',
+ IFLA_BOND_PRIMARY_RESELECT : 'IFLA_BOND_PRIMARY_RESELECT',
+ IFLA_BOND_FAIL_OVER_MAC : 'IFLA_BOND_FAIL_OVER_MAC',
+ IFLA_BOND_XMIT_HASH_POLICY : 'IFLA_BOND_XMIT_HASH_POLICY',
+ IFLA_BOND_RESEND_IGMP : 'IFLA_BOND_RESEND_IGMP',
+ IFLA_BOND_NUM_PEER_NOTIF : 'IFLA_BOND_NUM_PEER_NOTIF',
+ IFLA_BOND_ALL_SLAVES_ACTIVE : 'IFLA_BOND_ALL_SLAVES_ACTIVE',
+ IFLA_BOND_MIN_LINKS : 'IFLA_BOND_MIN_LINKS',
+ IFLA_BOND_LP_INTERVAL : 'IFLA_BOND_LP_INTERVAL',
+ IFLA_BOND_PACKETS_PER_SLAVE : 'IFLA_BOND_PACKETS_PER_SLAVE',
+ IFLA_BOND_AD_LACP_RATE : 'IFLA_BOND_AD_LACP_RATE',
+ IFLA_BOND_AD_SELECT : 'IFLA_BOND_AD_SELECT',
+ IFLA_BOND_AD_INFO : 'IFLA_BOND_AD_INFO',
+ IFLA_BOND_AD_ACTOR_SYS_PRIO : 'IFLA_BOND_AD_ACTOR_SYS_PRIO',
+ IFLA_BOND_AD_USER_PORT_KEY : 'IFLA_BOND_AD_USER_PORT_KEY',
+ IFLA_BOND_AD_ACTOR_SYSTEM : 'IFLA_BOND_AD_ACTOR_SYSTEM',
+ IFLA_BOND_CL_START : 'IFLA_BOND_CL_START',
+ IFLA_BOND_AD_LACP_BYPASS : 'IFLA_BOND_AD_LACP_BYPASS'
+ }
- self.nested = True if self.atype & NLA_F_NESTED else False
- self.net_byteorder = True if self.atype & NLA_F_NET_BYTEORDER else False
- self.atype = self.atype & NLA_TYPE_MASK
-
- # Should never happen
- assert self.atype == prev_atype, "This object changes attribute type from %d to %d, this is bad" % (prev_atype, self.atype)
+ IFLA_BOND_AD_INFO_UNSPEC = 0
+ IFLA_BOND_AD_INFO_AGGREGATOR = 1
+ IFLA_BOND_AD_INFO_NUM_PORTS = 2
+ IFLA_BOND_AD_INFO_ACTOR_KEY = 3
+ IFLA_BOND_AD_INFO_PARTNER_KEY = 4
+ IFLA_BOND_AD_INFO_PARTNER_MAC = 5
- def dump_first_line(self, dump_buffer, line_number, color):
- """
- Add the "Length....Type..." line to the dump buffer
- """
- if self.attr_end == self.length:
- padded_to = ', '
- else:
- padded_to = ' padded to %d, ' % self.attr_end
+ ifla_bond_ad_to_string = {
+ IFLA_BOND_AD_INFO_UNSPEC : 'IFLA_BOND_AD_INFO_UNSPEC',
+ IFLA_BOND_AD_INFO_AGGREGATOR : 'IFLA_BOND_AD_INFO_AGGREGATOR',
+ IFLA_BOND_AD_INFO_NUM_PORTS : 'IFLA_BOND_AD_INFO_NUM_PORTS',
+ IFLA_BOND_AD_INFO_ACTOR_KEY : 'IFLA_BOND_AD_INFO_ACTOR_KEY',
+ IFLA_BOND_AD_INFO_PARTNER_KEY : 'IFLA_BOND_AD_INFO_PARTNER_KEY',
+ IFLA_BOND_AD_INFO_PARTNER_MAC : 'IFLA_BOND_AD_INFO_PARTNER_MAC'
+ }
- extra = 'Length %s (%d)%sType %s%s%s (%d) %s' % \
- (zfilled_hex(self.length, 4), self.length,
- padded_to,
- zfilled_hex(self.atype, 4),
- " (NLA_F_NESTED set)" if self.nested else "",
- " (NLA_F_NET_BYTEORDER set)" if self.net_byteorder else "",
- self.atype,
- self)
+ ifla_bond_mode_tbl = {
+ 'balance-rr': 0,
+ 'active-backup': 1,
+ 'balance-xor': 2,
+ 'broadcast': 3,
+ '802.3ad': 4,
+ 'balance-tlb': 5,
+ 'balance-alb': 6,
+ '0': 0,
+ '1': 1,
+ '2': 2,
+ '3': 3,
+ '4': 4,
+ '5': 5,
+ '6': 6,
+ 0: 0,
+ 1: 1,
+ 2: 2,
+ 3: 3,
+ 4: 4,
+ 5: 5,
+ 6: 6
+ }
- dump_buffer.append(data_to_color_text(line_number, color, self.data[0:4], extra))
- return line_number + 1
+ ifla_bond_mode_pretty_tbl = {
+ 0: 'balance-rr',
+ 1: 'active-backup',
+ 2: 'balance-xor',
+ 3: 'broadcast',
+ 4: '802.3ad',
+ 5: 'balance-tlb',
+ 6: 'balance-alb'
+ }
- def dump_lines(self, dump_buffer, line_number, color):
- line_number = self.dump_first_line(dump_buffer, line_number, color)
+ ifla_bond_xmit_hash_policy_tbl = {
+ 'layer2': 0,
+ 'layer3+4': 1,
+ 'layer2+3': 2,
+ 'encap2+3': 3,
+ 'encap3+4': 4,
+ '0': 0,
+ '1': 1,
+ '2': 2,
+ '3': 3,
+ '4': 4,
+ 0: 0,
+ 1: 1,
+ 2: 2,
+ 3: 3,
+ 4: 4
+ }
- for x in xrange(1, self.attr_end/4):
- start = x * 4
- end = start + 4
- dump_buffer.append(data_to_color_text(line_number, color, self.data[start:end], ''))
- line_number += 1
+ ifla_bond_xmit_hash_policy_pretty_tbl = {
+ 0: 'layer2',
+ 1: 'layer3+4',
+ 2: 'layer2+3',
+ 3: 'encap2+3',
+ 4: 'encap3+4',
+ }
- return line_number
+ # =========================================
+ # IFLA_INFO_SLAVE_DATA attributes for bonds
+ # =========================================
+ IFLA_BOND_SLAVE_UNSPEC = 0
+ IFLA_BOND_SLAVE_STATE = 1
+ IFLA_BOND_SLAVE_MII_STATUS = 2
+ IFLA_BOND_SLAVE_LINK_FAILURE_COUNT = 3
+ IFLA_BOND_SLAVE_PERM_HWADDR = 4
+ IFLA_BOND_SLAVE_QUEUE_ID = 5
+ IFLA_BOND_SLAVE_AD_AGGREGATOR_ID = 6
+ IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE = 7
+ IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE = 8
+ IFLA_BOND_SLAVE_CL_START = 50
+ IFLA_BOND_SLAVE_AD_RX_BYPASS = IFLA_BOND_SLAVE_CL_START
- def get_pretty_value(self, obj=None):
- if obj and callable(obj):
- return obj(self.value)
- return self.value
+ ifla_bond_slave_to_string = {
+ IFLA_BOND_SLAVE_UNSPEC : 'IFLA_BOND_SLAVE_UNSPEC',
+ IFLA_BOND_SLAVE_STATE : 'IFLA_BOND_SLAVE_STATE',
+ IFLA_BOND_SLAVE_MII_STATUS : 'IFLA_BOND_SLAVE_MII_STATUS',
+ IFLA_BOND_SLAVE_LINK_FAILURE_COUNT : 'IFLA_BOND_SLAVE_LINK_FAILURE_COUNT',
+ IFLA_BOND_SLAVE_PERM_HWADDR : 'IFLA_BOND_SLAVE_PERM_HWADDR',
+ IFLA_BOND_SLAVE_QUEUE_ID : 'IFLA_BOND_SLAVE_QUEUE_ID',
+ IFLA_BOND_SLAVE_AD_AGGREGATOR_ID : 'IFLA_BOND_SLAVE_AD_AGGREGATOR_ID',
+ IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE : 'IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE',
+ IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE : 'IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE',
+ IFLA_BOND_SLAVE_CL_START : 'IFLA_BOND_SLAVE_CL_START',
+ IFLA_BOND_SLAVE_AD_RX_BYPASS : 'IFLA_BOND_SLAVE_AD_RX_BYPASS'
+ }
+ # =========================================
+ # IFLA_PROTINFO attributes for bridge ports
+ # =========================================
+ IFLA_BRPORT_UNSPEC = 0
+ IFLA_BRPORT_STATE = 1
+ IFLA_BRPORT_PRIORITY = 2
+ IFLA_BRPORT_COST = 3
+ IFLA_BRPORT_MODE = 4
+ IFLA_BRPORT_GUARD = 5
+ IFLA_BRPORT_PROTECT = 6
+ IFLA_BRPORT_FAST_LEAVE = 7
+ IFLA_BRPORT_LEARNING = 8
+ IFLA_BRPORT_UNICAST_FLOOD = 9
+ IFLA_BRPORT_PROXYARP = 10
+ IFLA_BRPORT_LEARNING_SYNC = 11
+ IFLA_BRPORT_PROXYARP_WIFI = 12
+ IFLA_BRPORT_ROOT_ID = 13
+ IFLA_BRPORT_BRIDGE_ID = 14
+ IFLA_BRPORT_DESIGNATED_PORT = 15
+ IFLA_BRPORT_DESIGNATED_COST = 16
+ IFLA_BRPORT_ID = 17
+ IFLA_BRPORT_NO = 18
+ IFLA_BRPORT_TOPOLOGY_CHANGE_ACK = 19
+ IFLA_BRPORT_CONFIG_PENDING = 20
+ IFLA_BRPORT_MESSAGE_AGE_TIMER = 21
+ IFLA_BRPORT_FORWARD_DELAY_TIMER = 22
+ IFLA_BRPORT_HOLD_TIMER = 23
+ IFLA_BRPORT_FLUSH = 24
+ IFLA_BRPORT_MULTICAST_ROUTER = 25
+ IFLA_BRPORT_PAD = 26
+ IFLA_BRPORT_MCAST_FLOOD = 27
+ IFLA_BRPORT_MCAST_TO_UCAST = 28
+ IFLA_BRPORT_VLAN_TUNNEL = 29
+ IFLA_BRPORT_BCAST_FLOOD = 30
+ IFLA_BRPORT_GROUP_FWD_MASK = 31
+ IFLA_BRPORT_NEIGH_SUPPRESS = 32
+ IFLA_BRPORT_ISOLATED = 33
+ IFLA_BRPORT_BACKUP_PORT = 34
-class AttributeFourByteList(Attribute):
+ IFLA_BRPORT_PEER_LINK = 60
+ IFLA_BRPORT_DUAL_LINK = 61
+ IFLA_BRPORT_GROUP_FWD_MASKHI = 62
- def __init__(self, atype, string, family, logger):
- Attribute.__init__(self, atype, string, logger)
+ ifla_brport_to_string = {
+ IFLA_BRPORT_UNSPEC : 'IFLA_BRPORT_UNSPEC',
+ IFLA_BRPORT_STATE : 'IFLA_BRPORT_STATE',
+ IFLA_BRPORT_PRIORITY : 'IFLA_BRPORT_PRIORITY',
+ IFLA_BRPORT_COST : 'IFLA_BRPORT_COST',
+ IFLA_BRPORT_MODE : 'IFLA_BRPORT_MODE',
+ IFLA_BRPORT_GUARD : 'IFLA_BRPORT_GUARD',
+ IFLA_BRPORT_PROTECT : 'IFLA_BRPORT_PROTECT',
+ IFLA_BRPORT_FAST_LEAVE : 'IFLA_BRPORT_FAST_LEAVE',
+ IFLA_BRPORT_LEARNING : 'IFLA_BRPORT_LEARNING',
+ IFLA_BRPORT_UNICAST_FLOOD : 'IFLA_BRPORT_UNICAST_FLOOD',
+ IFLA_BRPORT_PROXYARP : 'IFLA_BRPORT_PROXYARP',
+ IFLA_BRPORT_LEARNING_SYNC : 'IFLA_BRPORT_LEARNING_SYNC',
+ IFLA_BRPORT_PROXYARP_WIFI : 'IFLA_BRPORT_PROXYARP_WIFI',
+ IFLA_BRPORT_ROOT_ID : 'IFLA_BRPORT_ROOT_ID',
+ IFLA_BRPORT_BRIDGE_ID : 'IFLA_BRPORT_BRIDGE_ID',
+ IFLA_BRPORT_DESIGNATED_PORT : 'IFLA_BRPORT_DESIGNATED_PORT',
+ IFLA_BRPORT_DESIGNATED_COST : 'IFLA_BRPORT_DESIGNATED_COST',
+ IFLA_BRPORT_ID : 'IFLA_BRPORT_ID',
+ IFLA_BRPORT_NO : 'IFLA_BRPORT_NO',
+ IFLA_BRPORT_TOPOLOGY_CHANGE_ACK : 'IFLA_BRPORT_TOPOLOGY_CHANGE_ACK',
+ IFLA_BRPORT_CONFIG_PENDING : 'IFLA_BRPORT_CONFIG_PENDING',
+ IFLA_BRPORT_MESSAGE_AGE_TIMER : 'IFLA_BRPORT_MESSAGE_AGE_TIMER',
+ IFLA_BRPORT_FORWARD_DELAY_TIMER : 'IFLA_BRPORT_FORWARD_DELAY_TIMER',
+ IFLA_BRPORT_HOLD_TIMER : 'IFLA_BRPORT_HOLD_TIMER',
+ IFLA_BRPORT_FLUSH : 'IFLA_BRPORT_FLUSH',
+ IFLA_BRPORT_MULTICAST_ROUTER : 'IFLA_BRPORT_MULTICAST_ROUTER',
+ IFLA_BRPORT_PAD : 'IFLA_BRPORT_PAD',
+ IFLA_BRPORT_MCAST_FLOOD : 'IFLA_BRPORT_MCAST_FLOOD',
+ IFLA_BRPORT_MCAST_TO_UCAST : 'IFLA_BRPORT_MCAST_TO_UCAST',
+ IFLA_BRPORT_VLAN_TUNNEL : 'IFLA_BRPORT_VLAN_TUNNEL',
+ IFLA_BRPORT_BCAST_FLOOD : 'IFLA_BRPORT_BCAST_FLOOD',
+ IFLA_BRPORT_GROUP_FWD_MASK : 'IFLA_BRPORT_GROUP_FWD_MASK',
+ IFLA_BRPORT_NEIGH_SUPPRESS : 'IFLA_BRPORT_NEIGH_SUPPRESS',
+ IFLA_BRPORT_ISOLATED : 'IFLA_BRPORT_ISOLATED',
+ IFLA_BRPORT_BACKUP_PORT : 'IFLA_BRPORT_BACKUP_PORT',
+ IFLA_BRPORT_PEER_LINK : 'IFLA_BRPORT_PEER_LINK',
+ IFLA_BRPORT_DUAL_LINK : 'IFLA_BRPORT_DUAL_LINK',
+ IFLA_BRPORT_GROUP_FWD_MASKHI : 'IFLA_BRPORT_GROUP_FWD_MASKHI'
+ }
- def decode(self, parent_msg, data):
- self.decode_length_type(data)
- wordcount = (self.attr_end - 4)/4
- self.PACK = '=%dL' % wordcount
- self.LEN = calcsize(self.PACK)
+ IFLA_BR_UNSPEC = 0
+ IFLA_BR_FORWARD_DELAY = 1
+ IFLA_BR_HELLO_TIME = 2
+ IFLA_BR_MAX_AGE = 3
+ IFLA_BR_AGEING_TIME = 4
+ IFLA_BR_STP_STATE = 5
+ IFLA_BR_PRIORITY = 6
+ IFLA_BR_VLAN_FILTERING = 7
+ IFLA_BR_VLAN_PROTOCOL = 8
+ IFLA_BR_GROUP_FWD_MASK = 9
+ IFLA_BR_ROOT_ID = 10
+ IFLA_BR_BRIDGE_ID = 11
+ IFLA_BR_ROOT_PORT = 12
+ IFLA_BR_ROOT_PATH_COST = 13
+ IFLA_BR_TOPOLOGY_CHANGE = 14
+ IFLA_BR_TOPOLOGY_CHANGE_DETECTED = 15
+ IFLA_BR_HELLO_TIMER = 16
+ IFLA_BR_TCN_TIMER = 17
+ IFLA_BR_TOPOLOGY_CHANGE_TIMER = 18
+ IFLA_BR_GC_TIMER = 19
+ IFLA_BR_GROUP_ADDR = 20
+ IFLA_BR_FDB_FLUSH = 21
+ IFLA_BR_MCAST_ROUTER = 22
+ IFLA_BR_MCAST_SNOOPING = 23
+ IFLA_BR_MCAST_QUERY_USE_IFADDR = 24
+ IFLA_BR_MCAST_QUERIER = 25
+ IFLA_BR_MCAST_HASH_ELASTICITY = 26
+ IFLA_BR_MCAST_HASH_MAX = 27
+ IFLA_BR_MCAST_LAST_MEMBER_CNT = 28
+ IFLA_BR_MCAST_STARTUP_QUERY_CNT = 29
+ IFLA_BR_MCAST_LAST_MEMBER_INTVL = 30
+ IFLA_BR_MCAST_MEMBERSHIP_INTVL = 31
+ IFLA_BR_MCAST_QUERIER_INTVL = 32
+ IFLA_BR_MCAST_QUERY_INTVL = 33
+ IFLA_BR_MCAST_QUERY_RESPONSE_INTVL = 34
+ IFLA_BR_MCAST_STARTUP_QUERY_INTVL = 35
+ IFLA_BR_NF_CALL_IPTABLES = 36
+ IFLA_BR_NF_CALL_IP6TABLES = 37
+ IFLA_BR_NF_CALL_ARPTABLES = 38
+ IFLA_BR_VLAN_DEFAULT_PVID = 39
+ IFLA_BR_PAD = 40
+ IFLA_BR_VLAN_STATS_ENABLED = 41
+ IFLA_BR_MCAST_STATS_ENABLED = 42
+ IFLA_BR_MCAST_IGMP_VERSION = 43
+ IFLA_BR_MCAST_MLD_VERSION = 44
- try:
- self.value = unpack(self.PACK, self.data[4:])
- except struct.error:
- self.log.error("%s unpack of %s failed, data 0x%s" % (self, self.PACK, hexlify(self.data[4:])))
- raise
+ ifla_br_to_string = {
+ IFLA_BR_UNSPEC : 'IFLA_BR_UNSPEC',
+ IFLA_BR_FORWARD_DELAY : 'IFLA_BR_FORWARD_DELAY',
+ IFLA_BR_HELLO_TIME : 'IFLA_BR_HELLO_TIME',
+ IFLA_BR_MAX_AGE : 'IFLA_BR_MAX_AGE',
+ IFLA_BR_AGEING_TIME : 'IFLA_BR_AGEING_TIME',
+ IFLA_BR_STP_STATE : 'IFLA_BR_STP_STATE',
+ IFLA_BR_PRIORITY : 'IFLA_BR_PRIORITY',
+ IFLA_BR_VLAN_FILTERING : 'IFLA_BR_VLAN_FILTERING',
+ IFLA_BR_VLAN_PROTOCOL : 'IFLA_BR_VLAN_PROTOCOL',
+ IFLA_BR_GROUP_FWD_MASK : 'IFLA_BR_GROUP_FWD_MASK',
+ IFLA_BR_ROOT_ID : 'IFLA_BR_ROOT_ID',
+ IFLA_BR_BRIDGE_ID : 'IFLA_BR_BRIDGE_ID',
+ IFLA_BR_ROOT_PORT : 'IFLA_BR_ROOT_PORT',
+ IFLA_BR_ROOT_PATH_COST : 'IFLA_BR_ROOT_PATH_COST',
+ IFLA_BR_TOPOLOGY_CHANGE : 'IFLA_BR_TOPOLOGY_CHANGE',
+ IFLA_BR_TOPOLOGY_CHANGE_DETECTED : 'IFLA_BR_TOPOLOGY_CHANGE_DETECTED',
+ IFLA_BR_HELLO_TIMER : 'IFLA_BR_HELLO_TIMER',
+ IFLA_BR_TCN_TIMER : 'IFLA_BR_TCN_TIMER',
+ IFLA_BR_TOPOLOGY_CHANGE_TIMER : 'IFLA_BR_TOPOLOGY_CHANGE_TIMER',
+ IFLA_BR_GC_TIMER : 'IFLA_BR_GC_TIMER',
+ IFLA_BR_GROUP_ADDR : 'IFLA_BR_GROUP_ADDR',
+ IFLA_BR_FDB_FLUSH : 'IFLA_BR_FDB_FLUSH',
+ IFLA_BR_MCAST_ROUTER : 'IFLA_BR_MCAST_ROUTER',
+ IFLA_BR_MCAST_SNOOPING : 'IFLA_BR_MCAST_SNOOPING',
+ IFLA_BR_MCAST_QUERY_USE_IFADDR : 'IFLA_BR_MCAST_QUERY_USE_IFADDR',
+ IFLA_BR_MCAST_QUERIER : 'IFLA_BR_MCAST_QUERIER',
+ IFLA_BR_MCAST_HASH_ELASTICITY : 'IFLA_BR_MCAST_HASH_ELASTICITY',
+ IFLA_BR_MCAST_HASH_MAX : 'IFLA_BR_MCAST_HASH_MAX',
+ IFLA_BR_MCAST_LAST_MEMBER_CNT : 'IFLA_BR_MCAST_LAST_MEMBER_CNT',
+ IFLA_BR_MCAST_STARTUP_QUERY_CNT : 'IFLA_BR_MCAST_STARTUP_QUERY_CNT',
+ IFLA_BR_MCAST_LAST_MEMBER_INTVL : 'IFLA_BR_MCAST_LAST_MEMBER_INTVL',
+ IFLA_BR_MCAST_MEMBERSHIP_INTVL : 'IFLA_BR_MCAST_MEMBERSHIP_INTVL',
+ IFLA_BR_MCAST_QUERIER_INTVL : 'IFLA_BR_MCAST_QUERIER_INTVL',
+ IFLA_BR_MCAST_QUERY_INTVL : 'IFLA_BR_MCAST_QUERY_INTVL',
+ IFLA_BR_MCAST_QUERY_RESPONSE_INTVL : 'IFLA_BR_MCAST_QUERY_RESPONSE_INTVL',
+ IFLA_BR_MCAST_STARTUP_QUERY_INTVL : 'IFLA_BR_MCAST_STARTUP_QUERY_INTVL',
+ IFLA_BR_NF_CALL_IPTABLES : 'IFLA_BR_NF_CALL_IPTABLES',
+ IFLA_BR_NF_CALL_IP6TABLES : 'IFLA_BR_NF_CALL_IP6TABLES',
+ IFLA_BR_NF_CALL_ARPTABLES : 'IFLA_BR_NF_CALL_ARPTABLES',
+ IFLA_BR_VLAN_DEFAULT_PVID : 'IFLA_BR_VLAN_DEFAULT_PVID',
+ IFLA_BR_PAD : 'IFLA_BR_PAD',
+ IFLA_BR_VLAN_STATS_ENABLED : 'IFLA_BR_VLAN_STATS_ENABLED',
+ IFLA_BR_MCAST_STATS_ENABLED : 'IFLA_BR_MCAST_STATS_ENABLED',
+ IFLA_BR_MCAST_IGMP_VERSION : 'IFLA_BR_MCAST_IGMP_VERSION',
+ IFLA_BR_MCAST_MLD_VERSION : 'IFLA_BR_MCAST_MLD_VERSION'
+ }
- def dump_lines(self, dump_buffer, line_number, color):
- line_number = self.dump_first_line(dump_buffer, line_number, color)
- idx = 1
- for val in self.value:
- dump_buffer.append(data_to_color_text(line_number, color, self.data[4*idx:4*(idx+1)], val))
- line_number += 1
- idx += 1
- return line_number
+ # =========================================
+ # IFLA_INFO_DATA attributes for vrfs
+ # =========================================
+ IFLA_VRF_UNSPEC = 0
+ IFLA_VRF_TABLE = 1
+ ifla_vrf_to_string = {
+ IFLA_VRF_UNSPEC : 'IFLA_VRF_UNSPEC',
+ IFLA_VRF_TABLE : 'IFLA_VRF_TABLE'
+ }
-class AttributeFourByteValue(Attribute):
+ # ================================================================
+ # IFLA_INFO_DATA attributes for (ip6)gre, (ip6)gretap, (ip6)erspan
+ # ================================================================
+ IFLA_GRE_UNSPEC = 0
+ IFLA_GRE_LINK = 1
+ IFLA_GRE_IFLAGS = 2
+ IFLA_GRE_OFLAGS = 3
+ IFLA_GRE_IKEY = 4
+ IFLA_GRE_OKEY = 5
+ IFLA_GRE_LOCAL = 6
+ IFLA_GRE_REMOTE = 7
+ IFLA_GRE_TTL = 8
+ IFLA_GRE_TOS = 9
+ IFLA_GRE_PMTUDISC = 10
+ IFLA_GRE_ENCAP_LIMIT = 11
+ IFLA_GRE_FLOWINFO = 12
+ IFLA_GRE_FLAGS = 13
+ IFLA_GRE_ENCAP_TYPE = 14
+ IFLA_GRE_ENCAP_FLAGS = 15
+ IFLA_GRE_ENCAP_SPORT = 16
+ IFLA_GRE_ENCAP_DPORT = 17
+ IFLA_GRE_COLLECT_METADATA = 18
+ IFLA_GRE_IGNORE_DF = 19
+ IFLA_GRE_FWMARK = 20
+ IFLA_GRE_ERSPAN_INDEX = 21
+ IFLA_GRE_ERSPAN_VER = 22
+ IFLA_GRE_ERSPAN_DIR = 23
+ IFLA_GRE_ERSPAN_HWID = 24
- def __init__(self, atype, string, family, logger):
- Attribute.__init__(self, atype, string, logger)
- self.PACK = '=L'
- self.LEN = calcsize(self.PACK)
+ ifla_gre_to_string = {
+ IFLA_GRE_UNSPEC : "IFLA_GRE_UNSPEC",
+ IFLA_GRE_LINK : "IFLA_GRE_LINK",
+ IFLA_GRE_IFLAGS : "IFLA_GRE_IFLAGS",
+ IFLA_GRE_OFLAGS : "IFLA_GRE_OFLAGS",
+ IFLA_GRE_IKEY : "IFLA_GRE_IKEY",
+ IFLA_GRE_OKEY : "IFLA_GRE_OKEY",
+ IFLA_GRE_LOCAL : "IFLA_GRE_LOCAL",
+ IFLA_GRE_REMOTE : "IFLA_GRE_REMOTE",
+ IFLA_GRE_TTL : "IFLA_GRE_TTL",
+ IFLA_GRE_TOS : "IFLA_GRE_TOS",
+ IFLA_GRE_PMTUDISC : "IFLA_GRE_PMTUDISC",
+ IFLA_GRE_ENCAP_LIMIT : "IFLA_GRE_ENCAP_LIMIT",
+ IFLA_GRE_FLOWINFO : "IFLA_GRE_FLOWINFO",
+ IFLA_GRE_FLAGS : "IFLA_GRE_FLAGS",
+ IFLA_GRE_ENCAP_TYPE : "IFLA_GRE_ENCAP_TYPE",
+ IFLA_GRE_ENCAP_FLAGS : "IFLA_GRE_ENCAP_FLAGS",
+ IFLA_GRE_ENCAP_SPORT : "IFLA_GRE_ENCAP_SPORT",
+ IFLA_GRE_ENCAP_DPORT : "IFLA_GRE_ENCAP_DPORT",
+ IFLA_GRE_COLLECT_METADATA : "IFLA_GRE_COLLECT_METADATA",
+ IFLA_GRE_IGNORE_DF : "IFLA_GRE_IGNORE_DF",
+ IFLA_GRE_FWMARK : "IFLA_GRE_FWMARK",
+ IFLA_GRE_ERSPAN_INDEX : "IFLA_GRE_ERSPAN_INDEX",
+ IFLA_GRE_ERSPAN_VER : "IFLA_GRE_ERSPAN_VER",
+ IFLA_GRE_ERSPAN_DIR : "IFLA_GRE_ERSPAN_DIR",
+ IFLA_GRE_ERSPAN_HWID : "IFLA_GRE_ERSPAN_HWID",
+ }
- def decode(self, parent_msg, data):
- self.decode_length_type(data)
- assert self.attr_end == 8, "Attribute length for %s must be 8, it is %d" % (self, self.attr_end)
+ # ===============================================
+ # IFLA_INFO_DATA attributes for ipip, sit, ip6tnl
+ # ===============================================
+ IFLA_IPTUN_UNSPEC = 0
+ IFLA_IPTUN_LINK = 1
+ IFLA_IPTUN_LOCAL = 2
+ IFLA_IPTUN_REMOTE = 3
+ IFLA_IPTUN_TTL = 4
+ IFLA_IPTUN_TOS = 5
+ IFLA_IPTUN_ENCAP_LIMIT = 6
+ IFLA_IPTUN_FLOWINFO = 7
+ IFLA_IPTUN_FLAGS = 8
+ IFLA_IPTUN_PROTO = 9
+ IFLA_IPTUN_PMTUDISC = 10
+ IFLA_IPTUN_6RD_PREFIX = 11
+ IFLA_IPTUN_6RD_RELAY_PREFIX = 12
+ IFLA_IPTUN_6RD_PREFIXLEN = 13
+ IFLA_IPTUN_6RD_RELAY_PREFIXLEN = 14
+ IFLA_IPTUN_ENCAP_TYPE = 15
+ IFLA_IPTUN_ENCAP_FLAGS = 16
+ IFLA_IPTUN_ENCAP_SPORT = 17
+ IFLA_IPTUN_ENCAP_DPORT = 18
+ IFLA_IPTUN_COLLECT_METADATA = 19
+ IFLA_IPTUN_FWMARK = 20
- try:
- self.value = int(unpack(self.PACK, self.data[4:])[0])
- except struct.error:
- self.log.error("%s unpack of %s failed, data 0x%s" % (self, self.PACK, hexlify(self.data[4:])))
- raise
+ ifla_iptun_to_string = {
+ IFLA_IPTUN_UNSPEC : "IFLA_IPTUN_UNSPEC",
+ IFLA_IPTUN_LINK : "IFLA_IPTUN_LINK",
+ IFLA_IPTUN_LOCAL : "IFLA_IPTUN_LOCAL",
+ IFLA_IPTUN_REMOTE : "IFLA_IPTUN_REMOTE",
+ IFLA_IPTUN_TTL : "IFLA_IPTUN_TTL",
+ IFLA_IPTUN_TOS : "IFLA_IPTUN_TOS",
+ IFLA_IPTUN_ENCAP_LIMIT : "IFLA_IPTUN_ENCAP_LIMIT",
+ IFLA_IPTUN_FLOWINFO : "IFLA_IPTUN_FLOWINFO",
+ IFLA_IPTUN_FLAGS : "IFLA_IPTUN_FLAGS",
+ IFLA_IPTUN_PROTO : "IFLA_IPTUN_PROTO",
+ IFLA_IPTUN_PMTUDISC : "IFLA_IPTUN_PMTUDISC",
+ IFLA_IPTUN_6RD_PREFIX : "IFLA_IPTUN_6RD_PREFIX",
+ IFLA_IPTUN_6RD_RELAY_PREFIX : "IFLA_IPTUN_6RD_RELAY_PREFIX",
+ IFLA_IPTUN_6RD_PREFIXLEN : "IFLA_IPTUN_6RD_PREFIXLEN",
+ IFLA_IPTUN_6RD_RELAY_PREFIXLEN : "IFLA_IPTUN_6RD_RELAY_PREFIXLEN",
+ IFLA_IPTUN_ENCAP_TYPE : "IFLA_IPTUN_ENCAP_TYPE",
+ IFLA_IPTUN_ENCAP_FLAGS : "IFLA_IPTUN_ENCAP_FLAGS",
+ IFLA_IPTUN_ENCAP_SPORT : "IFLA_IPTUN_ENCAP_SPORT",
+ IFLA_IPTUN_ENCAP_DPORT : "IFLA_IPTUN_ENCAP_DPORT",
+ IFLA_IPTUN_COLLECT_METADATA : "IFLA_IPTUN_COLLECT_METADATA",
+ IFLA_IPTUN_FWMARK : "IFLA_IPTUN_FWMARK",
+ }
- def dump_lines(self, dump_buffer, line_number, color):
- line_number = self.dump_first_line(dump_buffer, line_number, color)
- dump_buffer.append(data_to_color_text(line_number, color, self.data[4:8], self.value))
- return line_number + 1
+ # =========================================
+ # IFLA_INFO_DATA attributes for vti, vti6
+ # =========================================
+ IFLA_VTI_UNSPEC = 0
+ IFLA_VTI_LINK = 1
+ IFLA_VTI_IKEY = 2
+ IFLA_VTI_OKEY = 3
+ IFLA_VTI_LOCAL = 4
+ IFLA_VTI_REMOTE = 5
+ IFLA_VTI_FWMARK = 6
+ ifla_vti_to_string = {
+ IFLA_VTI_UNSPEC : "IFLA_VTI_UNSPEC",
+ IFLA_VTI_LINK : "IFLA_VTI_LINK",
+ IFLA_VTI_IKEY : "IFLA_VTI_IKEY",
+ IFLA_VTI_OKEY : "IFLA_VTI_OKEY",
+ IFLA_VTI_LOCAL : "IFLA_VTI_LOCAL",
+ IFLA_VTI_REMOTE : "IFLA_VTI_REMOTE",
+ IFLA_VTI_FWMARK : "IFLA_VTI_FWMARK",
+ }
-class AttributeTwoByteValue(Attribute):
- def __init__(self, atype, string, family, logger):
- Attribute.__init__(self, atype, string, logger)
- self.PACK = '=Hxx'
- self.LEN = calcsize(self.PACK)
+class Attribute(object):
- def decode(self, parent_msg, data):
- self.decode_length_type(data)
- assert self.attr_end == 8, "Attribute length for %s must be 8, it is %d" % (self, self.attr_end)
+ def __init__(self, atype, string, logger):
+ self.atype = atype
+ self.string = string
+ self.HEADER_PACK = '=HH'
+ self.HEADER_LEN = calcsize(self.HEADER_PACK)
+ self.PACK = None
+ self.LEN = None
+ self.raw = None # raw value (i.e. int for mac address)
+ self.value = None
+ self.nested = False
+ self.net_byteorder = False
+ self.log = logger
- try:
- self.value = int(unpack(self.PACK, self.data[4:8])[0])
- except struct.error:
- self.log.error("%s unpack of %s failed, data 0x%s" % (self, self.PACK, hexlify(self.data[4:6])))
- raise
+ def __str__(self):
+ return self.string
- def encode(self):
- length = self.HEADER_LEN + self.LEN
- raw = pack(self.HEADER_PACK, length-2, self.atype) + pack(self.PACK, self.value)
- raw = self.pad(length, raw)
- return raw
+ def set_value(self, value):
+ self.value = value
- def dump_lines(self, dump_buffer, line_number, color):
- line_number = self.dump_first_line(dump_buffer, line_number, color)
- dump_buffer.append(data_to_color_text(line_number, color, self.data[4:8], self.value))
- return line_number + 1
+ def set_nested(self, nested):
+ self.nested = nested
+ def set_net_byteorder(self, net_byteorder):
+ self.net_byteorder = net_byteorder
-class AttributeString(Attribute):
+ @staticmethod
+ def pad_bytes_needed(length):
+ """
+ Return the number of bytes that should be added to align on a 4-byte boundry
+ """
+ remainder = length % 4
- def __init__(self, atype, string, family, logger):
- Attribute.__init__(self, atype, string, logger)
- self.PACK = None
- self.LEN = None
+ if remainder:
+ return 4 - remainder
+
+ return 0
+
+ def pad(self, length, raw):
+ pad = self.pad_bytes_needed(length)
+
+ if pad:
+ raw += '\0' * pad
+
+ return raw
+
+ def encode(self):
+
+ if not self.LEN:
+ raise Exception('Please define an encode() method in your child attribute class, or do not use AttributeGeneric')
+
+ length = self.HEADER_LEN + self.LEN
+ attr_type_with_flags = self.atype
+
+ if self.nested:
+ attr_type_with_flags = attr_type_with_flags | NLA_F_NESTED
+
+ if self.net_byteorder:
+ attr_type_with_flags = attr_type_with_flags | NLA_F_NET_BYTEORDER
+
+ raw = pack(self.HEADER_PACK, length, attr_type_with_flags) + pack(self.PACK, self.value)
+ raw = self.pad(length, raw)
+ return raw
+
+ def decode_length_type(self, data):
+ """
+ The first two bytes of an attribute are the length, the next two bytes are the type
+ """
+ self.data = data
+ prev_atype = self.atype
+ (data1, data2) = unpack(self.HEADER_PACK, data[:self.HEADER_LEN])
+ self.length = int(data1)
+ self.atype = int(data2)
+ self.attr_end = padded_length(self.length)
+
+ self.nested = True if self.atype & NLA_F_NESTED else False
+ self.net_byteorder = True if self.atype & NLA_F_NET_BYTEORDER else False
+ self.atype = self.atype & NLA_TYPE_MASK
+
+ # Should never happen
+ assert self.atype == prev_atype, "This object changes attribute type from %d to %d, this is bad" % (prev_atype, self.atype)
+
+ def dump_first_line(self, dump_buffer, line_number, color):
+ """
+ Add the "Length....Type..." line to the dump buffer
+ """
+ if self.attr_end == self.length:
+ padded_to = ', '
+ else:
+ padded_to = ' padded to %d, ' % self.attr_end
+
+ extra = 'Length %s (%d)%sType %s%s%s (%d) %s' % \
+ (zfilled_hex(self.length, 4), self.length,
+ padded_to,
+ zfilled_hex(self.atype, 4),
+ " (NLA_F_NESTED set)" if self.nested else "",
+ " (NLA_F_NET_BYTEORDER set)" if self.net_byteorder else "",
+ self.atype,
+ self)
+
+ dump_buffer.append(data_to_color_text(line_number, color, self.data[0:4], extra))
+ return line_number + 1
+
+ def dump_lines(self, dump_buffer, line_number, color):
+ line_number = self.dump_first_line(dump_buffer, line_number, color)
+
+ for x in xrange(1, self.attr_end/4):
+ start = x * 4
+ end = start + 4
+ dump_buffer.append(data_to_color_text(line_number, color, self.data[start:end], ''))
+ line_number += 1
+
+ return line_number
+
+ def get_pretty_value(self, obj=None):
+ if obj and callable(obj):
+ return obj(self.value)
+ return self.value
+
+ @staticmethod
+ def decode_one_byte_attribute(data, _=None):
+ return unpack("=B", data[4])[0]
+
+ @staticmethod
+ def decode_two_bytes_attribute(data, _=None):
+ return unpack("=H", data[4:6])[0]
+
+ @staticmethod
+ def decode_two_bytes_network_byte_order_attribute(data, _=None):
+ # The form '!' is available for those poor souls who claim they can't
+ # remember whether network byte order is big-endian or little-endian.
+ return unpack("!H", data[4:6])[0]
+
+ @staticmethod
+ def decode_four_bytes_attribute(data, _=None):
+ return unpack("=L", data[4:8])[0]
+
+ @staticmethod
+ def decode_eight_bytes_attribute(data, _=None):
+ return unpack("=Q", data[4:12])[0]
+
+ @staticmethod
+ def decode_mac_address_attribute(data, _=None):
+ (data1, data2) = unpack(">LHxx", data[4:12])
+ return mac_int_to_str(data1 << 16 | data2)
+
+ @staticmethod
+ def decode_ipv4_address_attribute(data, _=None):
+ return IPv4Address(unpack(">L", data[4:8])[0])
+
+ @staticmethod
+ def decode_ipv6_address_attribute(data, _=None):
+ (data1, data2) = unpack(">QQ", data[4:20])
+ return IPv6Address(data1 << 64 | data2)
+
+ @staticmethod
+ def decode_bond_ad_info_attribute(data, info_data_end):
+ ifla_bond_ad_info = {}
+ ad_attr_data = data[4:info_data_end]
+
+ while ad_attr_data:
+ (ad_data_length, ad_data_type) = unpack("=HH", ad_attr_data[:4])
+ ad_data_end = padded_length(ad_data_length)
+
+ if ad_data_type == Link.IFLA_BOND_AD_INFO_PARTNER_MAC:
+ (data1, data2) = unpack(">LHxx", ad_attr_data[4:12])
+ ifla_bond_ad_info[ad_data_type] = mac_int_to_str(data1 << 16 | data2)
+
+ ad_attr_data = ad_attr_data[ad_data_end:]
+
+ return ifla_bond_ad_info
+
+ @staticmethod
+ def decode_vlan_protocol_attribute(data, _=None):
+ return Link.ifla_vlan_protocol_dict.get(int("0x%s" % data[4:6].encode("hex"), base=16))
+
+ ############################################################################
+ # encode methods
+ ############################################################################
+
+ @staticmethod
+ def encode_one_byte_attribute(sub_attr_pack_layout, sub_attr_payload, info_data_type, info_data_value):
+ sub_attr_pack_layout.append("HH")
+ sub_attr_payload.append(5) # length
+ sub_attr_payload.append(info_data_type)
+
+ sub_attr_pack_layout.append("B")
+ sub_attr_payload.append(info_data_value)
+
+ # pad 3 bytes
+ sub_attr_pack_layout.extend("xxx")
+
+ @staticmethod
+ def encode_one_byte_attribute_from_string_boolean(sub_attr_pack_layout, sub_attr_payload, info_data_type, info_data_value):
+ return Attribute.encode_one_byte_attribute(
+ sub_attr_pack_layout, sub_attr_payload, info_data_type, value_to_bool_dict.get(info_data_value)
+ )
+
+ @staticmethod
+ def encode_bond_xmit_hash_policy_attribute(sub_attr_pack_layout, sub_attr_payload, info_data_type, info_data_value):
+ return Attribute.encode_one_byte_attribute(
+ sub_attr_pack_layout,
+ sub_attr_payload,
+ info_data_type,
+ Link.ifla_bond_xmit_hash_policy_tbl.get(info_data_value, 0),
+ )
+
+ @staticmethod
+ def encode_bond_mode_attribute(sub_attr_pack_layout, sub_attr_payload, info_data_type, info_data_value):
+ return Attribute.encode_one_byte_attribute(
+ sub_attr_pack_layout,
+ sub_attr_payload,
+ info_data_type,
+ Link.ifla_bond_mode_tbl.get(info_data_value, 0),
+ )
+
+ @staticmethod
+ def encode_two_bytes_attribute(sub_attr_pack_layout, sub_attr_payload, info_data_type, info_data_value):
+ sub_attr_pack_layout.append("HH")
+ sub_attr_payload.append(6) # length
+ sub_attr_payload.append(info_data_type)
+
+ sub_attr_pack_layout.append("H")
+ sub_attr_payload.append(info_data_value)
+
+ # pad 2 bytes
+ sub_attr_pack_layout.extend("xx")
+
+ @staticmethod
+ def encode_four_bytes_attribute(sub_attr_pack_layout, sub_attr_payload, info_data_type, info_data_value):
+ sub_attr_pack_layout.append("HH")
+ sub_attr_payload.append(8) # length
+ sub_attr_payload.append(info_data_type)
+
+ sub_attr_pack_layout.append("L")
+ sub_attr_payload.append(info_data_value)
+
+ @staticmethod
+ def encode_eight_bytes_attribute(sub_attr_pack_layout, sub_attr_payload, info_data_type, info_data_value):
+ sub_attr_pack_layout.append("HH")
+ sub_attr_payload.append(12) # length
+ sub_attr_payload.append(info_data_type)
+
+ sub_attr_pack_layout.append("Q")
+ sub_attr_payload.append(info_data_value)
+
+ @staticmethod
+ def encode_ipv4_attribute(sub_attr_pack_layout, sub_attr_payload, info_data_type, info_data_value):
+ sub_attr_pack_layout.append("HH")
+ sub_attr_payload.append(8) # length
+ sub_attr_payload.append(info_data_type)
+
+ sub_attr_pack_layout.append("L")
+
+ if info_data_value:
+ reorder = unpack("<L", IPv4Address(info_data_value).packed)[0]
+ sub_attr_payload.append(IPv4Address(reorder))
+ else:
+ sub_attr_payload.append(0)
+
+ @staticmethod
+ def encode_ipv6_attribute(sub_attr_pack_layout, sub_attr_payload, info_data_type, info_data_value):
+ raise NotImplementedError("ipv6 tunnel local and remote not supported yet")
+
+ @staticmethod
+ def encode_vlan_protocol_attribute(sub_attr_pack_layout, sub_attr_payload, info_data_type, info_data_value):
+ sub_attr_pack_layout.append("HH")
+ sub_attr_payload.append(6) # length
+ sub_attr_payload.append(info_data_type)
+
+ # vlan protocol
+ vlan_protocol = NetlinkPacket_IFLA_LINKINFO_Attributes.ifla_vlan_protocol_dict.get(info_data_value)
+ if not vlan_protocol:
+ raise NotImplementedError('vlan protocol %s not implemented' % info_data_value)
+
+ sub_attr_pack_layout.append("H")
+ sub_attr_payload.append(htons(vlan_protocol))
+
+ # pad 2 bytes
+ sub_attr_pack_layout.extend("xx")
+
+ @staticmethod
+ def encode_vxlan_port_attribute(sub_attr_pack_layout, sub_attr_payload, info_data_type, info_data_value):
+ sub_attr_pack_layout.append("HH")
+ sub_attr_payload.append(6)
+ sub_attr_payload.append(info_data_type)
+
+ sub_attr_pack_layout.append("H")
+
+ # byte swap
+ swaped = pack(">H", info_data_value)
+ sub_attr_payload.append(unpack("<H", swaped)[0])
+
+ # pad 2 bytes
+ sub_attr_pack_layout.extend("xx")
+
+ @staticmethod
+ def encode_mac_address_attribute(sub_attr_pack_layout, sub_attr_payload, info_data_type, info_data_value):
+ sub_attr_pack_layout.append("HH")
+ sub_attr_payload.append(10) # length
+ sub_attr_payload.append(info_data_type)
+
+ sub_attr_pack_layout.append("6B")
+ for mbyte in info_data_value.replace(".", " ").replace(":", " ").split():
+ sub_attr_payload.append(int(mbyte, 16))
+
+ # pad 2 bytes
+ sub_attr_pack_layout.extend('xx')
+
+
+class AttributeCACHEINFO(Attribute):
+ """
+ struct ifa_cacheinfo {
+ __u32 ifa_prefered;
+ __u32 ifa_valid;
+ __u32 cstamp; /* created timestamp, hundredths of seconds */
+ __u32 tstamp; /* updated timestamp, hundredths of seconds */
+ };
+ """
+ def __init__(self, atype, string, family, logger):
+ Attribute.__init__(self, atype, string, logger)
+ self.PACK = "=IIII"
+ self.LEN = calcsize(self.PACK)
+
+ def encode(self):
+ ifa_prefered, ifa_valid, cstamp, tstamp = self.value
+ return pack(self.HEADER_PACK, self.HEADER_LEN + self.LEN , self.atype) + pack(self.PACK, ifa_prefered, ifa_valid, cstamp, tstamp)
+
+ def decode(self, parent_msg, data):
+ self.decode_length_type(data)
+ try:
+ self.value = unpack(self.PACK, self.data[4:])
+ except struct.error:
+ self.log.error("%s unpack of %s failed, data 0x%s" % (self, self.PACK, hexlify(self.data[4:])))
+
+
+class AttributeFourByteList(Attribute):
+
+ def __init__(self, atype, string, family, logger):
+ Attribute.__init__(self, atype, string, logger)
+
+ def decode(self, parent_msg, data):
+ self.decode_length_type(data)
+ wordcount = (self.attr_end - 4)/4
+ self.PACK = '=%dL' % wordcount
+ self.LEN = calcsize(self.PACK)
+
+ try:
+ self.value = unpack(self.PACK, self.data[4:])
+ except struct.error:
+ self.log.error("%s unpack of %s failed, data 0x%s" % (self, self.PACK, hexlify(self.data[4:])))
+ raise
+
+ def dump_lines(self, dump_buffer, line_number, color):
+ line_number = self.dump_first_line(dump_buffer, line_number, color)
+ idx = 1
+ for val in self.value:
+ dump_buffer.append(data_to_color_text(line_number, color, self.data[4*idx:4*(idx+1)], val))
+ line_number += 1
+ idx += 1
+ return line_number
+
+
+class AttributeFourByteValue(Attribute):
+
+ def __init__(self, atype, string, family, logger):
+ Attribute.__init__(self, atype, string, logger)
+ self.PACK = '=L'
+ self.LEN = calcsize(self.PACK)
+
+ def decode(self, parent_msg, data):
+ self.decode_length_type(data)
+ assert self.attr_end == 8, "Attribute length for %s must be 8, it is %d" % (self, self.attr_end)
+
+ try:
+ self.value = int(unpack(self.PACK, self.data[4:])[0])
+ except struct.error:
+ self.log.error("%s unpack of %s failed, data 0x%s" % (self, self.PACK, hexlify(self.data[4:])))
+ raise
+
+ def dump_lines(self, dump_buffer, line_number, color):
+ line_number = self.dump_first_line(dump_buffer, line_number, color)
+ dump_buffer.append(data_to_color_text(line_number, color, self.data[4:8], self.value))
+ return line_number + 1
+
+
+class AttributeTwoByteValue(Attribute):
+
+ def __init__(self, atype, string, family, logger):
+ Attribute.__init__(self, atype, string, logger)
+ self.PACK = '=Hxx'
+ self.LEN = calcsize(self.PACK)
+
+ def decode(self, parent_msg, data):
+ self.decode_length_type(data)
+ assert self.attr_end == 8, "Attribute length for %s must be 8, it is %d" % (self, self.attr_end)
+
+ try:
+ self.value = int(unpack(self.PACK, self.data[4:8])[0])
+ except struct.error:
+ self.log.error("%s unpack of %s failed, data 0x%s" % (self, self.PACK, hexlify(self.data[4:6])))
+ raise
+
+ def encode(self):
+ length = self.HEADER_LEN + self.LEN
+ raw = pack(self.HEADER_PACK, length-2, self.atype) + pack(self.PACK, self.value)
+ raw = self.pad(length, raw)
+ return raw
+
+ def dump_lines(self, dump_buffer, line_number, color):
+ line_number = self.dump_first_line(dump_buffer, line_number, color)
+ dump_buffer.append(data_to_color_text(line_number, color, self.data[4:8], self.value))
+ return line_number + 1
+
+
+class AttributeString(Attribute):
+
+ def __init__(self, atype, string, family, logger):
+ Attribute.__init__(self, atype, string, logger)
+ self.PACK = None
+ self.LEN = None
def encode(self):
# some interface names come from JSON as unicode strings
self.LEN = calcsize(self.PACK)
try:
- self.value = remove_trailing_null(unpack(self.PACK, self.data[4:self.length])[0])
+ self.value = str(remove_trailing_null(unpack(self.PACK, self.data[4:self.length])[0]))
except struct.error:
self.log.error("%s unpack of %s failed, data 0x%s" % (self, self.PACK, hexlify(self.data[4:self.length])))
raise
if value is None:
self.value = None
else:
- self.value = IPAddress(value)
+ self.value = IPNetwork(value)
def decode(self, parent_msg, data):
self.decode_length_type(data)
try:
- if self.family == AF_INET:
+ if self.family in (AF_INET, AF_BRIDGE):
self.value = IPv4Address(unpack(self.PACK, self.data[4:])[0])
elif self.family == AF_INET6:
(data1, data2) = unpack(self.PACK, self.data[4:])
self.value = IPv6Address(data1 << 64 | data2)
- elif self.family == AF_BRIDGE:
- self.value = IPv4Address(unpack(self.PACK, self.data[4:])[0])
+ if isinstance(parent_msg, Route):
+ if self.atype == Route.RTA_SRC:
+ self.value = IPNetwork('%s/%s' % (self.value, parent_msg.src_len))
+ elif self.atype == Route.RTA_DST:
+ self.value = IPNetwork('%s/%s' % (self.value, parent_msg.dst_len))
+ else:
+ try:
+ self.value = IPNetwork('%s/%s' % (self.value, parent_msg.prefixlen))
+ except AttributeError:
+ self.value = IPNetwork('%s' % self.value)
self.value_int = int(self.value)
self.value_int_str = str(self.value_int)
def decode(self, parent_msg, data):
self.decode_length_type(data)
-
+
# IFLA_ADDRESS and IFLA_BROADCAST attributes for all interfaces has been a
- # 6-byte MAC address. But the GRE interface uses a 4-byte IP address and
+ # 6-byte MAC address. But the GRE interface uses a 4-byte IP address and
# GREv6 uses a 16-byte IPv6 address for this attribute.
try:
# GRE interface uses a 4-byte IP address for this attribute
self.value = IPv4Address(unpack('>L', self.data[4:])[0])
self.value_int = int(self.value)
self.value_int_str = str(self.value_int)
- # MAC Address
+ # MAC Address
elif self.length == 10:
(data1, data2) = unpack(self.PACK, self.data[4:])
- self.value = mac_int_to_str(data1 << 16 | data2)
- # GREv6 interface uses a 16-byte IP address for this attribute
+ self.raw = data1 << 16 | data2
+ self.value = mac_int_to_str(self.raw)
+ # GREv6 interface uses a 16-byte IP address for this attribute
elif self.length == 20:
self.value = IPv6Address(unpack('>L', self.data[16:])[0])
self.value_int = int(self.value)
}
}
"""
+ decode_ifla_info_nested_data_handlers = {
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_INFO_DATA: {
+ "bridge": {
+ # 1 byte attributes ############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_VLAN_FILTERING: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_TOPOLOGY_CHANGE: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_TOPOLOGY_CHANGE_DETECTED: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_MCAST_ROUTER: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_MCAST_SNOOPING: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_MCAST_QUERY_USE_IFADDR: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_MCAST_QUERIER: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_NF_CALL_IPTABLES: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_NF_CALL_IP6TABLES: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_NF_CALL_ARPTABLES: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_VLAN_STATS_ENABLED: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_MCAST_STATS_ENABLED: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_MCAST_IGMP_VERSION: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_MCAST_MLD_VERSION: Attribute.decode_one_byte_attribute,
+
+ # 2 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_PRIORITY: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_GROUP_FWD_MASK: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_ROOT_PORT: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_VLAN_DEFAULT_PVID: Attribute.decode_two_bytes_attribute,
+
+ # 4 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_AGEING_TIME: Attribute.decode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_FORWARD_DELAY: Attribute.decode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_HELLO_TIME: Attribute.decode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_MAX_AGE: Attribute.decode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_STP_STATE: Attribute.decode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_ROOT_PATH_COST: Attribute.decode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_MCAST_HASH_ELASTICITY: Attribute.decode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_MCAST_HASH_MAX: Attribute.decode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_MCAST_LAST_MEMBER_CNT: Attribute.decode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_MCAST_STARTUP_QUERY_CNT: Attribute.decode_four_bytes_attribute,
+
+ # 8 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_MCAST_MEMBERSHIP_INTVL: Attribute.decode_eight_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_MCAST_QUERIER_INTVL: Attribute.decode_eight_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_MCAST_LAST_MEMBER_INTVL: Attribute.decode_eight_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_MCAST_QUERY_INTVL: Attribute.decode_eight_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_MCAST_QUERY_RESPONSE_INTVL: Attribute.decode_eight_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_MCAST_STARTUP_QUERY_INTVL: Attribute.decode_eight_bytes_attribute,
+
+ # vlan-protocol attribute ######################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_VLAN_PROTOCOL: Attribute.decode_vlan_protocol_attribute
+ },
+ "bond": {
+ # 1 byte attributes ############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BOND_MODE: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BOND_USE_CARRIER: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BOND_AD_LACP_RATE: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BOND_AD_LACP_BYPASS: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BOND_XMIT_HASH_POLICY: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BOND_NUM_PEER_NOTIF: Attribute.decode_one_byte_attribute,
+
+ # 2 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BOND_AD_ACTOR_SYS_PRIO: Attribute.decode_two_bytes_attribute,
+
+ # 4 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BOND_MIIMON: Attribute.decode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BOND_UPDELAY: Attribute.decode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BOND_DOWNDELAY: Attribute.decode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BOND_MIN_LINKS: Attribute.decode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BOND_PRIMARY: Attribute.decode_four_bytes_attribute,
+
+ # mac address attributes #######################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BOND_AD_ACTOR_SYSTEM: Attribute.decode_mac_address_attribute,
+
+ # bond ad info attribute #######################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BOND_AD_INFO: Attribute.decode_bond_ad_info_attribute,
+ },
+ "vlan": {
+ # 2 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VLAN_ID: Attribute.decode_two_bytes_attribute,
+
+ # vlan-protocol attribute ######################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VLAN_PROTOCOL: Attribute.decode_vlan_protocol_attribute
+ },
+ "macvlan": {
+ # 4 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_MACVLAN_MODE: Attribute.decode_four_bytes_attribute,
+ },
+ "vxlan": {
+ # 1 byte attributes ############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_TTL: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_TOS: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_LEARNING: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_PROXY: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_RSC: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_L2MISS: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_L3MISS: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_UDP_CSUM: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_UDP_ZERO_CSUM6_TX: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_UDP_ZERO_CSUM6_RX: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_REMCSUM_TX: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_REMCSUM_RX: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_REPLICATION_TYPE: Attribute.decode_one_byte_attribute,
+
+ # 2 bytes network byte order attributes ########################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_PORT: Attribute.decode_two_bytes_network_byte_order_attribute,
+
+ # 4 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_ID: Attribute.decode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_LINK: Attribute.decode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_AGEING: Attribute.decode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_LIMIT: Attribute.decode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_PORT_RANGE: Attribute.decode_four_bytes_attribute,
+
+ # ipv4 attributes ##############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_GROUP: Attribute.decode_ipv4_address_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_LOCAL: Attribute.decode_ipv4_address_attribute,
+ },
+ "vrf": {
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VRF_TABLE: Attribute.decode_four_bytes_attribute
+ },
+ "xfrm": {
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_XFRM_IF_ID: Attribute.decode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_XFRM_LINK: Attribute.decode_four_bytes_attribute
+ },
+
+ # Tunnels:
+ # There's is a lot of copy paste here because most of the tunnels
+ # share the same attribute key / attribute index value, but ipv6
+ # tunnels needs special handling for their ipv6 attributes.
+ #
+ # "gre", "gretap", "erspan", "ip6gre", "ip6gretap", "ip6erspan" are
+ # identical as well with special handling for LOCAL and REMOTE for
+ # the ipv6 tunnels
+ "gre": {
+ # 1 byte attributes ############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_TTL: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_TOS: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_PMTUDISC: Attribute.decode_one_byte_attribute,
+
+ # 2 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_IFLAGS: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_OFLAGS: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_TYPE: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_SPORT: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_DPORT: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_FLAGS: Attribute.decode_two_bytes_attribute,
+
+ # 4 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_LINK: Attribute.decode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_IKEY: Attribute.decode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_OKEY: Attribute.decode_four_bytes_attribute,
+
+ # ipv4 attributes ##############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_LOCAL: Attribute.decode_ipv4_address_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_REMOTE: Attribute.decode_ipv4_address_attribute
+ },
+ "gretap": {
+ # 1 byte attributes ############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_TTL: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_TOS: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_PMTUDISC: Attribute.decode_one_byte_attribute,
+
+ # 2 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_IFLAGS: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_OFLAGS: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_TYPE: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_SPORT: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_DPORT: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_FLAGS: Attribute.decode_two_bytes_attribute,
+
+ # 4 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_LINK: Attribute.decode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_IKEY: Attribute.decode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_OKEY: Attribute.decode_four_bytes_attribute,
+
+ # ipv4 attributes ##############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_LOCAL: Attribute.decode_ipv4_address_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_REMOTE: Attribute.decode_ipv4_address_attribute
+ },
+ "erspan": {
+ # 1 byte attributes ############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_TTL: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_TOS: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_PMTUDISC: Attribute.decode_one_byte_attribute,
+
+ # 2 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_IFLAGS: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_OFLAGS: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_TYPE: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_SPORT: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_DPORT: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_FLAGS: Attribute.decode_two_bytes_attribute,
+
+ # 4 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_LINK: Attribute.decode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_IKEY: Attribute.decode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_OKEY: Attribute.decode_four_bytes_attribute,
+
+ # ipv4 attributes ##############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_LOCAL: Attribute.decode_ipv4_address_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_REMOTE: Attribute.decode_ipv4_address_attribute
+ },
+ "ip6gre": {
+ # 1 byte attributes ############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_TTL: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_TOS: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_PMTUDISC: Attribute.decode_one_byte_attribute,
+
+ # 2 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_IFLAGS: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_OFLAGS: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_TYPE: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_SPORT: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_DPORT: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_FLAGS: Attribute.decode_two_bytes_attribute,
+
+ # 4 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_LINK: Attribute.decode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_IKEY: Attribute.decode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_OKEY: Attribute.decode_four_bytes_attribute,
+
+ # ipv6 attributes ##############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_LOCAL: Attribute.decode_ipv6_address_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_REMOTE: Attribute.decode_ipv6_address_attribute
+ },
+ "ip6gretap": {
+ # 1 byte attributes ############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_TTL: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_TOS: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_PMTUDISC: Attribute.decode_one_byte_attribute,
+
+ # 2 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_IFLAGS: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_OFLAGS: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_TYPE: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_SPORT: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_DPORT: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_FLAGS: Attribute.decode_two_bytes_attribute,
+
+ # 4 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_LINK: Attribute.decode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_IKEY: Attribute.decode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_OKEY: Attribute.decode_four_bytes_attribute,
+
+ # ipv6 attributes ##############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_LOCAL: Attribute.decode_ipv6_address_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_REMOTE: Attribute.decode_ipv6_address_attribute
+ },
+ "ip6erspan": {
+ # 1 byte attributes ############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_TTL: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_TOS: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_PMTUDISC: Attribute.decode_one_byte_attribute,
+
+ # 2 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_IFLAGS: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_OFLAGS: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_TYPE: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_SPORT: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_DPORT: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_FLAGS: Attribute.decode_two_bytes_attribute,
+
+ # 4 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_LINK: Attribute.decode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_IKEY: Attribute.decode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_OKEY: Attribute.decode_four_bytes_attribute,
+
+ # ipv6 attributes ##############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_LOCAL: Attribute.decode_ipv6_address_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_REMOTE: Attribute.decode_ipv6_address_attribute
+ },
+
+ # "ipip", "sit", "ip6tnl" are identical as well except for some
+ # special ipv6 handling for LOCAL and REMOTE.
+ "ipip": {
+ # 1 byte attributes ############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_IPTUN_TTL: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_IPTUN_TOS: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_IPTUN_PMTUDISC: Attribute.decode_one_byte_attribute,
+
+ # 2 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_IPTUN_ENCAP_TYPE: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_IPTUN_ENCAP_SPORT: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_IPTUN_ENCAP_DPORT: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_IPTUN_ENCAP_FLAGS: Attribute.decode_two_bytes_attribute,
+
+ # 4 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_IPTUN_LINK: Attribute.decode_four_bytes_attribute,
+
+ # ipv4 attributes ##############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_IPTUN_LOCAL: Attribute.decode_ipv4_address_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_IPTUN_REMOTE: Attribute.decode_ipv4_address_attribute,
+ },
+ "sit": {
+ # 1 byte attributes ############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_IPTUN_TTL: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_IPTUN_TOS: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_IPTUN_PMTUDISC: Attribute.decode_one_byte_attribute,
+
+ # 2 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_IPTUN_ENCAP_TYPE: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_IPTUN_ENCAP_SPORT: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_IPTUN_ENCAP_DPORT: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_IPTUN_ENCAP_FLAGS: Attribute.decode_two_bytes_attribute,
+
+ # 4 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_IPTUN_LINK: Attribute.decode_four_bytes_attribute,
+
+ # ipv4 attributes ##############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_IPTUN_LOCAL: Attribute.decode_ipv4_address_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_IPTUN_REMOTE: Attribute.decode_ipv4_address_attribute,
+ },
+ "ip6tnl": {
+ # 1 byte attributes ############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_IPTUN_TTL: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_IPTUN_TOS: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_IPTUN_PMTUDISC: Attribute.decode_one_byte_attribute,
+
+ # 2 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_IPTUN_ENCAP_TYPE: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_IPTUN_ENCAP_SPORT: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_IPTUN_ENCAP_DPORT: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_IPTUN_ENCAP_FLAGS: Attribute.decode_two_bytes_attribute,
+
+ # 4 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_IPTUN_LINK: Attribute.decode_four_bytes_attribute,
+
+ # ipv6 attributes ##############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_IPTUN_LOCAL: Attribute.decode_ipv6_address_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_IPTUN_REMOTE: Attribute.decode_ipv6_address_attribute,
+ },
+
+ # Same story with "vti", "vti6"...
+ "vti": {
+ # 4 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VTI_LINK: Attribute.decode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VTI_IKEY: Attribute.decode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VTI_OKEY: Attribute.decode_four_bytes_attribute,
+
+ # ipv4 attributes ##############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VTI_LOCAL: Attribute.decode_ipv4_address_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VTI_REMOTE: Attribute.decode_ipv4_address_attribute
+ },
+ "vti6": {
+ # 4 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VTI_LINK: Attribute.decode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VTI_IKEY: Attribute.decode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VTI_OKEY: Attribute.decode_four_bytes_attribute,
+
+ # ipv6 attributes ##############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VTI_LOCAL: Attribute.decode_ipv6_address_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VTI_REMOTE: Attribute.decode_ipv6_address_attribute
+ }
+ },
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_INFO_SLAVE_DATA: {
+ "bridge": {
+ # 1 byte attributes ############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_STATE: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_MODE: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_GUARD: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_PROTECT: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_FAST_LEAVE: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_LEARNING: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_UNICAST_FLOOD: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_PROXYARP: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_LEARNING_SYNC: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_PROXYARP_WIFI: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_TOPOLOGY_CHANGE_ACK: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_CONFIG_PENDING: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_MULTICAST_ROUTER: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_MCAST_FLOOD: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_BCAST_FLOOD: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_MCAST_TO_UCAST: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_VLAN_TUNNEL: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_PEER_LINK: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_DUAL_LINK: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_NEIGH_SUPPRESS: Attribute.decode_one_byte_attribute,
+
+ # 2 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_PRIORITY: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_DESIGNATED_PORT: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_DESIGNATED_COST: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_ID: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_NO: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_GROUP_FWD_MASK: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_GROUP_FWD_MASKHI: Attribute.decode_two_bytes_attribute,
+
+ # 4 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_COST: Attribute.decode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_BACKUP_PORT: Attribute.decode_four_bytes_attribute,
+ },
+ "bond": {
+ # 1 byte attributes ############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BOND_SLAVE_STATE: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BOND_SLAVE_MII_STATUS: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE: Attribute.decode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BOND_SLAVE_AD_RX_BYPASS: Attribute.decode_one_byte_attribute,
+
+ # 2 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BOND_SLAVE_QUEUE_ID: Attribute.decode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BOND_SLAVE_AD_AGGREGATOR_ID: Attribute.decode_two_bytes_attribute,
+
+ # 4 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BOND_SLAVE_PERM_HWADDR: Attribute.decode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BOND_SLAVE_LINK_FAILURE_COUNT: Attribute.decode_four_bytes_attribute,
+ }
+ }
+ }
+
+ encode_ifla_info_nested_data_handlers = {
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_INFO_DATA: {
+ "vlan": {
+ # 2 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VLAN_ID: Attribute.encode_two_bytes_attribute,
+
+ # vlan-protocol attribute ######################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VLAN_PROTOCOL: Attribute.encode_vlan_protocol_attribute,
+ },
+ "macvlan": {
+ # 4 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_MACVLAN_MODE: Attribute.encode_four_bytes_attribute,
+ },
+ "vxlan": {
+ # 1 byte attributes ############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_TTL: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_TOS: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_LEARNING: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_PROXY: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_RSC: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_L2MISS: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_L3MISS: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_UDP_CSUM: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_UDP_ZERO_CSUM6_TX: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_UDP_ZERO_CSUM6_RX: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_REMCSUM_TX: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_REMCSUM_RX: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_REPLICATION_TYPE: Attribute.encode_one_byte_attribute,
+
+ # 4 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_ID: Attribute.encode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_LINK: Attribute.encode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_AGEING: Attribute.encode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_LIMIT: Attribute.encode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_PORT_RANGE: Attribute.encode_four_bytes_attribute,
+
+ # ipv4 attributes ##############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_GROUP: Attribute.encode_ipv4_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_LOCAL: Attribute.encode_ipv4_attribute,
+
+ # vxlan-port attribute #########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_PORT: Attribute.encode_vxlan_port_attribute,
+ },
+ "bond": {
+ # 1 byte attributes ############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BOND_NUM_PEER_NOTIF: Attribute.encode_one_byte_attribute,
+
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BOND_USE_CARRIER: Attribute.encode_one_byte_attribute_from_string_boolean,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BOND_AD_LACP_BYPASS: Attribute.encode_one_byte_attribute_from_string_boolean,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BOND_AD_LACP_RATE: Attribute.encode_one_byte_attribute_from_string_boolean,
+
+ # bond-mode attribute ##########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BOND_MODE: Attribute.encode_bond_mode_attribute,
+
+ # bond-xmit-hash-policy attribute ##############################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BOND_XMIT_HASH_POLICY: Attribute.encode_bond_xmit_hash_policy_attribute,
+
+ # 2 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BOND_AD_ACTOR_SYS_PRIO: Attribute.encode_two_bytes_attribute,
+
+ # 4 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BOND_MIIMON: Attribute.encode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BOND_UPDELAY: Attribute.encode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BOND_DOWNDELAY: Attribute.encode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BOND_MIN_LINKS: Attribute.encode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BOND_PRIMARY: Attribute.encode_four_bytes_attribute,
+
+ # mac address attribute ########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BOND_AD_ACTOR_SYSTEM: Attribute.encode_mac_address_attribute
+ },
+ "vrf": {
+ # 4 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VRF_TABLE: Attribute.encode_four_bytes_attribute
+ },
+ "bridge": {
+ # 1 byte attributes ############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_VLAN_FILTERING: Attribute.encode_one_byte_attribute_from_string_boolean,
+
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_TOPOLOGY_CHANGE: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_TOPOLOGY_CHANGE_DETECTED: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_MCAST_ROUTER: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_MCAST_SNOOPING: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_MCAST_QUERY_USE_IFADDR: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_MCAST_QUERIER: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_NF_CALL_IPTABLES: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_NF_CALL_IP6TABLES: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_NF_CALL_ARPTABLES: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_VLAN_STATS_ENABLED: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_MCAST_STATS_ENABLED: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_MCAST_IGMP_VERSION: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_MCAST_MLD_VERSION: Attribute.encode_one_byte_attribute,
+
+ # 2 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_PRIORITY: Attribute.encode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_GROUP_FWD_MASK: Attribute.encode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_ROOT_PORT: Attribute.encode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_VLAN_DEFAULT_PVID: Attribute.encode_two_bytes_attribute,
+
+ # 4 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_FORWARD_DELAY: Attribute.encode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_HELLO_TIME: Attribute.encode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_MAX_AGE: Attribute.encode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_AGEING_TIME: Attribute.encode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_STP_STATE: Attribute.encode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_ROOT_PATH_COST: Attribute.encode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_MCAST_HASH_ELASTICITY: Attribute.encode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_MCAST_HASH_MAX: Attribute.encode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_MCAST_LAST_MEMBER_CNT: Attribute.encode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_MCAST_STARTUP_QUERY_CNT: Attribute.encode_four_bytes_attribute,
+
+ # 8 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_MCAST_LAST_MEMBER_INTVL: Attribute.encode_eight_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_MCAST_MEMBERSHIP_INTVL: Attribute.encode_eight_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_MCAST_QUERIER_INTVL: Attribute.encode_eight_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_MCAST_QUERY_INTVL: Attribute.encode_eight_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_MCAST_QUERY_RESPONSE_INTVL: Attribute.encode_eight_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_MCAST_STARTUP_QUERY_INTVL: Attribute.encode_eight_bytes_attribute,
+
+ # vlan-protocol attribute ######################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BR_VLAN_PROTOCOL: Attribute.encode_vlan_protocol_attribute
+ },
+ # Tunnels:
+ # There's is a lot of copy paste here because most of the tunnels
+ # share the same attribute key / attribute index value, but ipv6
+ # tunnels needs special handling for their ipv6 attributes.
+ #
+ # "gre", "gretap", "erspan", "ip6gre", "ip6gretap", "ip6erspan" are
+ # identical as well with special handling for LOCAL and REMOTE for
+ # the ipv6 tunnels
+ "gre": { # == ("gre", "gretap", "erspan")
+ # 1 byte attributes ############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_TTL: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_TOS: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_PMTUDISC: Attribute.encode_one_byte_attribute,
+
+ # 2 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_IFLAGS: Attribute.encode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_OFLAGS: Attribute.encode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_TYPE: Attribute.encode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_SPORT: Attribute.encode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_DPORT: Attribute.encode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_FLAGS: Attribute.encode_two_bytes_attribute,
+
+ # 4 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_LINK: Attribute.encode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_IKEY: Attribute.encode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_OKEY: Attribute.encode_four_bytes_attribute,
+
+ # ipv4 attributes ##############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_LOCAL: Attribute.encode_ipv4_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_REMOTE: Attribute.encode_ipv4_attribute,
+ },
+ "gretap": { # == ("gre", "gretap", "erspan")
+ # 1 byte attributes ############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_TTL: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_TOS: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_PMTUDISC: Attribute.encode_one_byte_attribute,
+
+ # 2 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_IFLAGS: Attribute.encode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_OFLAGS: Attribute.encode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_TYPE: Attribute.encode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_SPORT: Attribute.encode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_DPORT: Attribute.encode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_FLAGS: Attribute.encode_two_bytes_attribute,
+
+ # 4 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_LINK: Attribute.encode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_IKEY: Attribute.encode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_OKEY: Attribute.encode_four_bytes_attribute,
+
+ # ipv4 attributes ##############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_LOCAL: Attribute.encode_ipv4_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_REMOTE: Attribute.encode_ipv4_attribute,
+ },
+ "erspan": { # == ("gre", "gretap", "erspan")
+ # 1 byte attributes ############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_TTL: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_TOS: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_PMTUDISC: Attribute.encode_one_byte_attribute,
+
+ # 2 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_IFLAGS: Attribute.encode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_OFLAGS: Attribute.encode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_TYPE: Attribute.encode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_SPORT: Attribute.encode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_DPORT: Attribute.encode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_FLAGS: Attribute.encode_two_bytes_attribute,
+
+ # 4 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_LINK: Attribute.encode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_IKEY: Attribute.encode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_OKEY: Attribute.encode_four_bytes_attribute,
+
+ # ipv4 attributes ##############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_LOCAL: Attribute.encode_ipv4_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_REMOTE: Attribute.encode_ipv4_attribute,
+ },
+ "ip6gre": { # == ("ip6gre", "ip6gretap", "ip6erspan")
+ # 1 byte attributes ############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_TTL: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_TOS: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_PMTUDISC: Attribute.encode_one_byte_attribute,
+
+ # 2 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_IFLAGS: Attribute.encode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_OFLAGS: Attribute.encode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_TYPE: Attribute.encode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_SPORT: Attribute.encode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_DPORT: Attribute.encode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_FLAGS: Attribute.encode_two_bytes_attribute,
+
+ # 4 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_LINK: Attribute.encode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_IKEY: Attribute.encode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_OKEY: Attribute.encode_four_bytes_attribute,
+
+ # ipv6 attributes ##############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_LOCAL: Attribute.encode_ipv6_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_REMOTE: Attribute.encode_ipv6_attribute,
+ },
+ "ip6gretap": { # == ("ip6gre", "ip6gretap", "ip6erspan")
+ # 1 byte attributes ############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_TTL: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_TOS: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_PMTUDISC: Attribute.encode_one_byte_attribute,
+
+ # 2 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_IFLAGS: Attribute.encode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_OFLAGS: Attribute.encode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_TYPE: Attribute.encode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_SPORT: Attribute.encode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_DPORT: Attribute.encode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_FLAGS: Attribute.encode_two_bytes_attribute,
+
+ # 4 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_LINK: Attribute.encode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_IKEY: Attribute.encode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_OKEY: Attribute.encode_four_bytes_attribute,
+
+ # ipv6 attributes ##############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_LOCAL: Attribute.encode_ipv6_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_REMOTE: Attribute.encode_ipv6_attribute,
+ },
+ "ip6erspan": { # == ("ip6gre", "ip6gretap", "ip6erspan")
+ # 1 byte attributes ############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_TTL: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_TOS: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_PMTUDISC: Attribute.encode_one_byte_attribute,
+
+ # 2 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_IFLAGS: Attribute.encode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_OFLAGS: Attribute.encode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_TYPE: Attribute.encode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_SPORT: Attribute.encode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_DPORT: Attribute.encode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_ENCAP_FLAGS: Attribute.encode_two_bytes_attribute,
+
+ # 4 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_LINK: Attribute.encode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_IKEY: Attribute.encode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_OKEY: Attribute.encode_four_bytes_attribute,
+
+ # ipv6 attributes ##############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_LOCAL: Attribute.encode_ipv6_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_GRE_REMOTE: Attribute.encode_ipv6_attribute,
+ }
+ },
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_INFO_SLAVE_DATA: {
+ "bridge": {
+ # 1 byte attributes ############################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_STATE: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_MODE: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_GUARD: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_PROTECT: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_FAST_LEAVE: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_LEARNING: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_UNICAST_FLOOD: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_PROXYARP: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_LEARNING_SYNC: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_PROXYARP_WIFI: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_TOPOLOGY_CHANGE_ACK: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_CONFIG_PENDING: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_MULTICAST_ROUTER: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_MCAST_FLOOD: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_MCAST_TO_UCAST: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_VLAN_TUNNEL: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_BCAST_FLOOD: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_PEER_LINK: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_DUAL_LINK: Attribute.encode_one_byte_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_NEIGH_SUPPRESS: Attribute.encode_one_byte_attribute,
+
+ # 2 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_PRIORITY: Attribute.encode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_DESIGNATED_PORT: Attribute.encode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_DESIGNATED_COST: Attribute.encode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_ID: Attribute.encode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_NO: Attribute.encode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_GROUP_FWD_MASK: Attribute.encode_two_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_GROUP_FWD_MASKHI: Attribute.encode_two_bytes_attribute,
+
+ # 4 bytes attributes ###########################################
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_COST: Attribute.encode_four_bytes_attribute,
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_BRPORT_BACKUP_PORT: Attribute.encode_four_bytes_attribute,
+ },
+ }
+ }
+
+ ifla_info_nested_data_attributes_to_string_dict = {
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_INFO_DATA: {
+ "bond": NetlinkPacket_IFLA_LINKINFO_Attributes.ifla_bond_to_string,
+ "vlan": NetlinkPacket_IFLA_LINKINFO_Attributes.ifla_vlan_to_string,
+ "vxlan": NetlinkPacket_IFLA_LINKINFO_Attributes.ifla_vxlan_to_string,
+ "bridge": NetlinkPacket_IFLA_LINKINFO_Attributes.ifla_br_to_string,
+ "macvlan": NetlinkPacket_IFLA_LINKINFO_Attributes.ifla_macvlan_to_string,
+ "vrf": NetlinkPacket_IFLA_LINKINFO_Attributes.ifla_vrf_to_string,
+ "gre": NetlinkPacket_IFLA_LINKINFO_Attributes.ifla_gre_to_string,
+ "gretap": NetlinkPacket_IFLA_LINKINFO_Attributes.ifla_gre_to_string,
+ "erspan": NetlinkPacket_IFLA_LINKINFO_Attributes.ifla_gre_to_string,
+ "ip6gre": NetlinkPacket_IFLA_LINKINFO_Attributes.ifla_gre_to_string,
+ "ip6gretap": NetlinkPacket_IFLA_LINKINFO_Attributes.ifla_gre_to_string,
+ "ip6erspan": NetlinkPacket_IFLA_LINKINFO_Attributes.ifla_gre_to_string,
+ "vti": NetlinkPacket_IFLA_LINKINFO_Attributes.ifla_vti_to_string,
+ "vti6": NetlinkPacket_IFLA_LINKINFO_Attributes.ifla_vti_to_string,
+ "ipip": NetlinkPacket_IFLA_LINKINFO_Attributes.ifla_iptun_to_string,
+ "sit": NetlinkPacket_IFLA_LINKINFO_Attributes.ifla_iptun_to_string,
+ "ip6tnl": NetlinkPacket_IFLA_LINKINFO_Attributes.ifla_iptun_to_string
+ },
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_INFO_SLAVE_DATA: {
+ "bridge": NetlinkPacket_IFLA_LINKINFO_Attributes.ifla_brport_to_string,
+ "bond": NetlinkPacket_IFLA_LINKINFO_Attributes.ifla_bond_slave_to_string
+ }
+ }
+
def __init__(self, atype, string, family, logger):
Attribute.__init__(self, atype, string, logger)
+ def encode_ifla_info_nested_data(self, sub_attr_pack_layout, sub_attr_type, sub_attr_type_string, sub_attr_value, encode_handlers, ifla_info_nested_attr_to_str_dict, kind):
+ sub_attr_payload = [0, sub_attr_type | NLA_F_NESTED]
+
+ if not encode_handlers:
+ self.log.log(
+ SYSLOG_EXTRA_DEBUG,
+ "Add support for encoding %s for %s link kind" % (sub_attr_type_string, kind)
+ )
+ else:
+ for (info_data_type, info_data_value) in sub_attr_value.iteritems():
+ encode_handler = encode_handlers.get(info_data_type)
+
+ if encode_handler:
+ encode_handler(sub_attr_pack_layout, sub_attr_payload, info_data_type, info_data_value)
+ else:
+ self.log.log(
+ SYSLOG_EXTRA_DEBUG,
+ "Add support for encoding %s %s sub-attribute %s (%d)"
+ % (
+ sub_attr_type_string,
+ kind,
+ ifla_info_nested_attr_to_str_dict.get(info_data_type),
+ info_data_type
+ )
+ )
+
+ return sub_attr_payload
+
def encode(self):
pack_layout = [self.HEADER_PACK]
payload = [0, self.atype | NLA_F_NESTED]
kind = self.value.get(Link.IFLA_INFO_KIND)
slave_kind = self.value.get(Link.IFLA_INFO_SLAVE_KIND)
- if not slave_kind and kind not in ('vlan', 'macvlan', 'vxlan', 'bond', 'bridge', 'xfrm'):
- raise Exception('Unsupported IFLA_INFO_KIND %s' % kind)
+ if not slave_kind and kind not in (
+ "vrf",
+ "vlan",
+ "vxlan",
+ "bond",
+ "dummy",
+ "bridge",
+ "macvlan",
+ ):
+ self.log.debug('Unsupported IFLA_INFO_KIND %s' % kind)
+ return
+
elif not kind and slave_kind != 'bridge':
# only support brport for now.
raise Exception('Unsupported IFLA_INFO_SLAVE_KIND %s' % slave_kind)
# order (=). If a field is added that needs to be packed via network
# order (>) then some smarts will need to be added to split the pack_layout
# string at the >, split the payload and make the needed pack() calls.
- #
# Until we cross that bridge though we will keep things nice and simple and
# pack everything via a single pack() call.
+
for (sub_attr_type, sub_attr_value) in self.value.iteritems():
sub_attr_pack_layout = ['=', 'HH']
sub_attr_payload = [0, sub_attr_type]
sub_attr_length_index = 0
- if sub_attr_type == Link.IFLA_INFO_KIND:
+ if sub_attr_type in (Link.IFLA_INFO_KIND, Link.IFLA_INFO_SLAVE_KIND):
sub_attr_pack_layout.append('%ds' % len(sub_attr_value))
sub_attr_payload.append(sub_attr_value)
elif sub_attr_type == Link.IFLA_INFO_DATA:
+ sub_attr_payload = self.encode_ifla_info_nested_data(
+ sub_attr_pack_layout,
+ sub_attr_type,
+ "IFLA_INFO_DATA",
+ sub_attr_value,
+ self.encode_ifla_info_nested_data_handlers.get(Link.IFLA_INFO_DATA, {}).get(kind),
+ self.ifla_info_nested_data_attributes_to_string_dict.get(Link.IFLA_INFO_DATA, {}).get(kind),
+ kind
+ )
- sub_attr_payload = [0, sub_attr_type | NLA_F_NESTED]
+ elif sub_attr_type == Link.IFLA_INFO_SLAVE_DATA:
+ sub_attr_payload = self.encode_ifla_info_nested_data(
+ sub_attr_pack_layout,
+ sub_attr_type,
+ "IFLA_INFO_SLAVE_DATA",
+ sub_attr_value,
+ self.encode_ifla_info_nested_data_handlers.get(Link.IFLA_INFO_SLAVE_DATA, {}).get(slave_kind),
+ self.ifla_info_nested_data_attributes_to_string_dict.get(Link.IFLA_INFO_SLAVE_DATA, {}).get(slave_kind),
+ slave_kind
+ )
- for (info_data_type, info_data_value) in sub_attr_value.iteritems():
+ else:
+ self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for encoding IFLA_LINKINFO sub-attribute type %d' % sub_attr_type)
+ continue
- if kind == 'vlan':
- if info_data_type == Link.IFLA_VLAN_ID:
- sub_attr_pack_layout.append('HH')
- sub_attr_payload.append(6) # length
- sub_attr_payload.append(info_data_type)
+ sub_attr_length = calcsize(''.join(sub_attr_pack_layout))
+ sub_attr_payload[sub_attr_length_index] = sub_attr_length
- # The vlan-id
- sub_attr_pack_layout.append('H')
- sub_attr_payload.append(info_data_value)
+ # add padding
+ for x in xrange(self.pad_bytes_needed(sub_attr_length)):
+ sub_attr_pack_layout.append('x')
- # pad 2 bytes
- sub_attr_pack_layout.extend('xx')
+ # The [1:] is to remove the leading = so that when we do the ''.join() later
+ # we do not end up with an = in the middle of the pack layout string. There
+ # will be an = at the beginning via self.HEADER_PACK
+ sub_attr_pack_layout = sub_attr_pack_layout[1:]
- elif info_data_type == Link.IFLA_VLAN_PROTOCOL:
- sub_attr_pack_layout.append('HH')
- sub_attr_payload.append(6) # length
- sub_attr_payload.append(info_data_type)
+ # Now extend the ovarall attribute pack_layout/payload to include this sub-attribute
+ pack_layout.extend(sub_attr_pack_layout)
+ payload.extend(sub_attr_payload)
- # vlan protocol
- vlan_protocol = Link.ifla_vlan_protocol_dict.get(info_data_value)
- if not vlan_protocol:
- raise NotImplementedError('vlan protocol %s not implemented' % info_data_value)
+ pack_layout = ''.join(pack_layout)
- sub_attr_pack_layout.append('H')
- sub_attr_payload.append(htons(vlan_protocol))
+ # Fill in the length field
+ length = calcsize(pack_layout)
+ payload[attr_length_index] = length
- # pad 2 bytes
- sub_attr_pack_layout.extend('xx')
- else:
- self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for encoding IFLA_INFO_DATA vlan sub-attribute type %d' % info_data_type)
-
- elif kind == 'macvlan':
- if info_data_type == Link.IFLA_MACVLAN_MODE:
- sub_attr_pack_layout.append('HH')
- sub_attr_payload.append(8) # length
- sub_attr_payload.append(info_data_type)
-
- # macvlan mode
- sub_attr_pack_layout.append('L')
- sub_attr_payload.append(info_data_value)
-
- else:
- self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for encoding IFLA_INFO_DATA macvlan sub-attribute type %d' % info_data_type)
-
- elif kind == 'xfrm':
- if info_data_type in (Link.IFLA_XFRM_IF_ID, Link.IFLA_XFRM_LINK):
- sub_attr_pack_layout.append('HH')
- sub_attr_payload.append(8) # length
- sub_attr_payload.append(info_data_type)
-
- sub_attr_pack_layout.append('L')
- sub_attr_payload.append(info_data_value)
-
- elif kind == 'vxlan':
- if info_data_type in (Link.IFLA_VXLAN_ID,
- Link.IFLA_VXLAN_LINK,
- Link.IFLA_VXLAN_AGEING,
- Link.IFLA_VXLAN_LIMIT,
- Link.IFLA_VXLAN_PORT_RANGE):
- sub_attr_pack_layout.append('HH')
- sub_attr_payload.append(8) # length
- sub_attr_payload.append(info_data_type)
-
- sub_attr_pack_layout.append('L')
- sub_attr_payload.append(info_data_value)
-
- elif info_data_type in (Link.IFLA_VXLAN_GROUP,
- Link.IFLA_VXLAN_LOCAL):
- sub_attr_pack_layout.append('HH')
- sub_attr_payload.append(8) # length
- sub_attr_payload.append(info_data_type)
-
- sub_attr_pack_layout.append('L')
-
- reorder = unpack('<L', IPv4Address(info_data_value).packed)[0]
- sub_attr_payload.append(IPv4Address(reorder))
-
- elif info_data_type in (Link.IFLA_VXLAN_PORT,):
- sub_attr_pack_layout.append('HH')
- sub_attr_payload.append(6)
- sub_attr_payload.append(info_data_type)
-
- sub_attr_pack_layout.append('H')
-
- # byte swap
- swaped = pack(">H", info_data_value)
- sub_attr_payload.append(unpack("<H", swaped)[0])
-
- sub_attr_pack_layout.extend('xx')
-
- elif info_data_type in (Link.IFLA_VXLAN_TTL,
- Link.IFLA_VXLAN_TOS,
- Link.IFLA_VXLAN_LEARNING,
- Link.IFLA_VXLAN_PROXY,
- Link.IFLA_VXLAN_RSC,
- Link.IFLA_VXLAN_L2MISS,
- Link.IFLA_VXLAN_L3MISS,
- Link.IFLA_VXLAN_UDP_CSUM,
- Link.IFLA_VXLAN_UDP_ZERO_CSUM6_TX,
- Link.IFLA_VXLAN_UDP_ZERO_CSUM6_RX,
- Link.IFLA_VXLAN_REMCSUM_TX,
- Link.IFLA_VXLAN_REMCSUM_RX,
- Link.IFLA_VXLAN_REPLICATION_TYPE):
- sub_attr_pack_layout.append('HH')
- sub_attr_payload.append(5)
- sub_attr_payload.append(info_data_type)
-
- sub_attr_pack_layout.append('B')
- sub_attr_payload.append(info_data_value)
- sub_attr_pack_layout.extend('xxx')
-
- else:
- self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for encoding IFLA_INFO_DATA vxlan sub-attribute type %d' % info_data_type)
-
- elif kind == 'bond':
- if info_data_type in (Link.IFLA_BOND_AD_ACTOR_SYSTEM, ):
- sub_attr_pack_layout.append('HH')
- sub_attr_payload.append(10) # length
- sub_attr_payload.append(info_data_type)
-
- sub_attr_pack_layout.append('6B')
- for mbyte in info_data_value.replace('.', ' ').replace(':', ' ').split():
- sub_attr_payload.append(int(mbyte, 16))
- sub_attr_pack_layout.extend('xx')
-
- elif info_data_type == Link.IFLA_BOND_AD_ACTOR_SYS_PRIO:
- sub_attr_pack_layout.append('HH')
- sub_attr_payload.append(6) # length
- sub_attr_payload.append(info_data_type)
-
- # 2 bytes
- sub_attr_pack_layout.append('H')
- sub_attr_payload.append(int(info_data_value))
-
- # pad 2 bytes
- sub_attr_pack_layout.extend('xx')
-
- elif info_data_type == Link.IFLA_BOND_NUM_PEER_NOTIF:
- sub_attr_pack_layout.append('HH')
- sub_attr_payload.append(5) # length
- sub_attr_payload.append(info_data_type)
-
- # 1 byte
- sub_attr_pack_layout.append('B')
- sub_attr_payload.append(int(info_data_value))
-
- # pad 3 bytes
- sub_attr_pack_layout.extend('xxx')
-
-
- elif info_data_type in (Link.IFLA_BOND_AD_LACP_RATE,
- Link.IFLA_BOND_AD_LACP_BYPASS,
- Link.IFLA_BOND_USE_CARRIER):
- # converts yes/no/on/off/0/1 strings to boolean value
- bool_value = self.get_bool_value(info_data_value)
-
- sub_attr_pack_layout.append('HH')
- sub_attr_payload.append(5) # length
- sub_attr_payload.append(info_data_type)
-
- # 1 byte
- sub_attr_pack_layout.append('B')
- sub_attr_payload.append(bool_value)
-
- # pad 3 bytes
- sub_attr_pack_layout.extend('xxx')
-
- elif info_data_type == Link.IFLA_BOND_XMIT_HASH_POLICY:
- index = self.get_index(Link.ifla_bond_xmit_hash_policy_tbl,
- 'bond xmit hash policy',
- info_data_value)
-
- sub_attr_pack_layout.append('HH')
- sub_attr_payload.append(5) # length
- sub_attr_payload.append(info_data_type)
-
- # 1 byte
- sub_attr_pack_layout.append('B')
- sub_attr_payload.append(index)
-
- # pad 3 bytes
- sub_attr_pack_layout.extend('xxx')
-
- elif info_data_type == Link.IFLA_BOND_MODE:
- index = self.get_index(Link.ifla_bond_mode_tbl,
- 'bond mode',
- info_data_value)
-
- sub_attr_pack_layout.append('HH')
- sub_attr_payload.append(5) # length
- sub_attr_payload.append(info_data_type)
-
- # 1 byte
- sub_attr_pack_layout.append('B')
- sub_attr_payload.append(index)
-
- # pad 3 bytes
- sub_attr_pack_layout.extend('xxx')
-
- elif info_data_type in (Link.IFLA_BOND_MIIMON,
- Link.IFLA_BOND_UPDELAY,
- Link.IFLA_BOND_DOWNDELAY,
- Link.IFLA_BOND_MIN_LINKS):
- sub_attr_pack_layout.append('HH')
- sub_attr_payload.append(8) # length
- sub_attr_payload.append(info_data_type)
-
- sub_attr_pack_layout.append('L')
- sub_attr_payload.append(int(info_data_value))
-
- else:
- self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for encoding IFLA_INFO_DATA bond sub-attribute type %d' % info_data_type)
-
- elif kind == 'bridge':
- if info_data_type == Link.IFLA_BR_VLAN_PROTOCOL:
- sub_attr_pack_layout.append('HH')
- sub_attr_payload.append(6) # length
- sub_attr_payload.append(info_data_type)
-
- # vlan protocol
- vlan_protocol = Link.ifla_vlan_protocol_dict.get(info_data_value)
- if not vlan_protocol:
- raise NotImplementedError('vlan protocol %s not implemented' % info_data_value)
-
- sub_attr_pack_layout.append('H')
- sub_attr_payload.append(htons(vlan_protocol))
-
- # pad 2 bytes
- sub_attr_pack_layout.extend('xx')
-
- # 1 byte
- elif info_data_type in (Link.IFLA_BR_VLAN_FILTERING,
- Link.IFLA_BR_TOPOLOGY_CHANGE,
- Link.IFLA_BR_TOPOLOGY_CHANGE_DETECTED,
- Link.IFLA_BR_MCAST_ROUTER,
- Link.IFLA_BR_MCAST_SNOOPING,
- Link.IFLA_BR_MCAST_QUERY_USE_IFADDR,
- Link.IFLA_BR_MCAST_QUERIER,
- Link.IFLA_BR_NF_CALL_IPTABLES,
- Link.IFLA_BR_NF_CALL_IP6TABLES,
- Link.IFLA_BR_NF_CALL_ARPTABLES,
- Link.IFLA_BR_VLAN_STATS_ENABLED,
- Link.IFLA_BR_MCAST_STATS_ENABLED,
- Link.IFLA_BR_MCAST_IGMP_VERSION,
- Link.IFLA_BR_MCAST_MLD_VERSION):
- sub_attr_pack_layout.append('HH')
- sub_attr_payload.append(5) # length
- sub_attr_payload.append(info_data_type)
-
- # 1 byte
- sub_attr_pack_layout.append('B')
- sub_attr_payload.append(int(info_data_value))
-
- # pad 3 bytes
- sub_attr_pack_layout.extend('xxx')
-
- # 2 bytes
- elif info_data_type in (Link.IFLA_BR_PRIORITY,
- Link.IFLA_BR_GROUP_FWD_MASK,
- Link.IFLA_BR_ROOT_PORT,
- Link.IFLA_BR_VLAN_DEFAULT_PVID):
- sub_attr_pack_layout.append('HH')
- sub_attr_payload.append(6) # length
- sub_attr_payload.append(info_data_type)
-
- # 2 bytes
- sub_attr_pack_layout.append('H')
- sub_attr_payload.append(int(info_data_value))
-
- # pad 2 bytes
- sub_attr_pack_layout.extend('xx')
-
- # 4 bytes
- elif info_data_type in (Link.IFLA_BR_FORWARD_DELAY,
- Link.IFLA_BR_HELLO_TIME,
- Link.IFLA_BR_MAX_AGE,
- Link.IFLA_BR_AGEING_TIME,
- Link.IFLA_BR_STP_STATE,
- Link.IFLA_BR_ROOT_PATH_COST,
- Link.IFLA_BR_MCAST_QUERIER,
- Link.IFLA_BR_MCAST_HASH_ELASTICITY,
- Link.IFLA_BR_MCAST_HASH_MAX,
- Link.IFLA_BR_MCAST_LAST_MEMBER_CNT,
- Link.IFLA_BR_MCAST_STARTUP_QUERY_CNT):
- sub_attr_pack_layout.append('HH')
- sub_attr_payload.append(8) # length
- sub_attr_payload.append(info_data_type)
-
- sub_attr_pack_layout.append('L')
- sub_attr_payload.append(int(info_data_value))
-
- # 8 bytes
- elif info_data_type in (Link.IFLA_BR_MCAST_LAST_MEMBER_INTVL,
- Link.IFLA_BR_MCAST_MEMBERSHIP_INTVL,
- Link.IFLA_BR_MCAST_QUERIER_INTVL,
- Link.IFLA_BR_MCAST_QUERY_INTVL,
- Link.IFLA_BR_MCAST_QUERY_RESPONSE_INTVL,
- Link.IFLA_BR_MCAST_STARTUP_QUERY_INTVL):
- sub_attr_pack_layout.append('HH')
- sub_attr_payload.append(12) # length
- sub_attr_payload.append(info_data_type)
-
- sub_attr_pack_layout.append('Q')
- sub_attr_payload.append(int(info_data_value))
-
- else:
- self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for encoding IFLA_INFO_DATA bridge sub-attribute type %d' % info_data_type)
-
- elif sub_attr_type == Link.IFLA_INFO_SLAVE_DATA:
-
- sub_attr_payload = [0, sub_attr_type | NLA_F_NESTED]
-
- for (info_slave_data_type, info_slave_data_value) in sub_attr_value.iteritems():
-
- if slave_kind == 'bridge':
-
- # 1 byte
- if info_slave_data_type in (Link.IFLA_BRPORT_STATE,
- Link.IFLA_BRPORT_MODE,
- Link.IFLA_BRPORT_GUARD,
- Link.IFLA_BRPORT_PROTECT,
- Link.IFLA_BRPORT_FAST_LEAVE,
- Link.IFLA_BRPORT_LEARNING,
- Link.IFLA_BRPORT_UNICAST_FLOOD,
- Link.IFLA_BRPORT_PROXYARP,
- Link.IFLA_BRPORT_LEARNING_SYNC,
- Link.IFLA_BRPORT_PROXYARP_WIFI,
- Link.IFLA_BRPORT_TOPOLOGY_CHANGE_ACK,
- Link.IFLA_BRPORT_CONFIG_PENDING,
- Link.IFLA_BRPORT_MULTICAST_ROUTER,
- Link.IFLA_BRPORT_MCAST_FLOOD,
- Link.IFLA_BRPORT_MCAST_TO_UCAST,
- Link.IFLA_BRPORT_VLAN_TUNNEL,
- Link.IFLA_BRPORT_BCAST_FLOOD,
- Link.IFLA_BRPORT_PEER_LINK,
- Link.IFLA_BRPORT_DUAL_LINK,
- Link.IFLA_BRPORT_ARP_SUPPRESS,
- Link.IFLA_BRPORT_DOWN_PEERLINK_REDIRECT):
- sub_attr_pack_layout.append('HH')
- sub_attr_payload.append(5) # length
- sub_attr_payload.append(info_slave_data_type)
-
- # 1 byte
- sub_attr_pack_layout.append('B')
- sub_attr_payload.append(int(info_slave_data_value))
-
- # pad 3 bytes
- sub_attr_pack_layout.extend('xxx')
-
- # 2 bytes
- elif info_slave_data_type in (Link.IFLA_BRPORT_PRIORITY,
- Link.IFLA_BRPORT_DESIGNATED_PORT,
- Link.IFLA_BRPORT_DESIGNATED_COST,
- Link.IFLA_BRPORT_ID,
- Link.IFLA_BRPORT_NO,
- Link.IFLA_BRPORT_GROUP_FWD_MASK,
- Link.IFLA_BRPORT_GROUP_FWD_MASKHI):
- sub_attr_pack_layout.append('HH')
- sub_attr_payload.append(6) # length
- sub_attr_payload.append(info_slave_data_type)
-
- # 2 bytes
- sub_attr_pack_layout.append('H')
- sub_attr_payload.append(int(info_slave_data_value))
-
- # pad 2 bytes
- sub_attr_pack_layout.extend('xx')
-
- # 4 bytes
- elif info_slave_data_type == Link.IFLA_BRPORT_COST:
- sub_attr_pack_layout.append('HH')
- sub_attr_payload.append(8) # length
- sub_attr_payload.append(info_slave_data_type)
-
- sub_attr_pack_layout.append('L')
- sub_attr_payload.append(int(info_slave_data_value))
-
- else:
- self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for encoding IFLA_INFO_SLAVE_DATA bond sub-attribute type %d' % info_slave_data_type)
-
- else:
- self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for encoding IFLA_LINKINFO kind %s' % slave_kind)
-
- else:
- self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for encoding IFLA_LINKINFO sub-attribute type %d' % sub_attr_type)
- continue
-
- sub_attr_length = calcsize(''.join(sub_attr_pack_layout))
- sub_attr_payload[sub_attr_length_index] = sub_attr_length
-
- # add padding
- for x in xrange(self.pad_bytes_needed(sub_attr_length)):
- sub_attr_pack_layout.append('x')
-
- # The [1:] is to remove the leading = so that when we do the ''.join() later
- # we do not end up with an = in the middle of the pack layout string. There
- # will be an = at the beginning via self.HEADER_PACK
- sub_attr_pack_layout = sub_attr_pack_layout[1:]
-
- # Now extend the ovarall attribute pack_layout/payload to include this sub-attribute
- pack_layout.extend(sub_attr_pack_layout)
- payload.extend(sub_attr_payload)
-
- pack_layout = ''.join(pack_layout)
-
- # Fill in the length field
- length = calcsize(pack_layout)
- payload[attr_length_index] = length
-
- raw = pack(pack_layout, *payload)
- raw = self.pad(length, raw)
- return raw
+ raw = pack(pack_layout, *payload)
+ raw = self.pad(length, raw)
+ return raw
def get_bool_value(self, value, default=None):
try:
self.log.debug('unsupported %s value %s (%s)' % (attr, value, tbl.keys()))
return default
+ def decode_ifla_info_nested_data(self, kind, ifla_info_nested_kind_str, sub_attr_type, sub_attr_type_str, data, sub_attr_end):
+ sub_attr_data = data[4:sub_attr_end]
+ ifla_info_nested_data = {}
+
+ if not kind:
+ self.log.warning("%s is not known...we cannot parse %s" % (ifla_info_nested_kind_str, sub_attr_type_str))
+ else:
+ ifla_info_nested_data_handlers = self.decode_ifla_info_nested_data_handlers.get(sub_attr_type, {}).get(kind)
+ ifla_info_nested_attr_to_str_dict = self.ifla_info_nested_data_attributes_to_string_dict.get(sub_attr_type, {}).get(kind)
+
+ if not ifla_info_nested_data_handlers or not ifla_info_nested_attr_to_str_dict:
+ self.log.log(SYSLOG_EXTRA_DEBUG, "%s: decode: unsupported %s %s" % (sub_attr_type_str, ifla_info_nested_kind_str, kind))
+ else:
+ while sub_attr_data:
+ (info_nested_data_length, info_nested_data_type) = unpack("=HH", sub_attr_data[:4])
+ info_nested_data_end = padded_length(info_nested_data_length)
+ handler = ifla_info_nested_data_handlers.get(info_nested_data_type)
+ try:
+ if handler:
+ ifla_info_nested_data[info_nested_data_type] = handler(sub_attr_data, info_nested_data_end)
+ else:
+ self.log.log(
+ SYSLOG_EXTRA_DEBUG,
+ "Add support for decoding %s %s, attribute %s (%s)"
+ % (
+ ifla_info_nested_kind_str,
+ kind,
+ ifla_info_nested_attr_to_str_dict.get(info_nested_data_type, "UNKNOWN"),
+ info_nested_data_type
+ )
+ )
+ except Exception as e:
+ self.log.warning(
+ "%s: %s: attribute %s: %s (%s)"
+ % (
+ ifla_info_nested_kind_str,
+ kind,
+ ifla_info_nested_attr_to_str_dict.get(info_nested_data_type, "UNKNOWN"),
+ info_nested_data_type,
+ str(e)
+ )
+ )
+
+ sub_attr_data = sub_attr_data[info_nested_data_end:]
+
+ return ifla_info_nested_data
+
def decode(self, parent_msg, data):
"""
value is a dictionary such as:
(sub_attr_length, sub_attr_type) = unpack('=HH', data[:4])
sub_attr_end = padded_length(sub_attr_length)
+ if sub_attr_type & NLA_F_NESTED:
+ sub_attr_type ^= NLA_F_NESTED
+
if not sub_attr_length:
self.log.error('parsed a zero length sub-attr')
return
if sub_attr_type in (Link.IFLA_INFO_KIND, Link.IFLA_INFO_SLAVE_KIND):
self.value[sub_attr_type] = remove_trailing_null(unpack('%ds' % (sub_attr_length - 4), data[4:sub_attr_length])[0])
- elif sub_attr_type == Link.IFLA_INFO_SLAVE_DATA:
- sub_attr_data = data[4:sub_attr_end]
-
- ifla_info_slave_data = dict()
- ifla_info_slave_kind = self.value.get(Link.IFLA_INFO_SLAVE_KIND)
-
- if not ifla_info_slave_kind:
- self.log.warning('IFLA_INFO_SLAVE_KIND is not known...we cannot parse IFLA_INFO_SLAVE_DATA')
- else:
- while sub_attr_data:
- (info_data_length, info_data_type) = unpack('=HH', sub_attr_data[:4])
- info_data_end = padded_length(info_data_length)
- try:
- if ifla_info_slave_kind == 'bridge':
- # 1 byte
- if info_data_type in (Link.IFLA_BRPORT_STATE,
- Link.IFLA_BRPORT_MODE,
- Link.IFLA_BRPORT_GUARD,
- Link.IFLA_BRPORT_PROTECT,
- Link.IFLA_BRPORT_FAST_LEAVE,
- Link.IFLA_BRPORT_LEARNING,
- Link.IFLA_BRPORT_UNICAST_FLOOD,
- Link.IFLA_BRPORT_PROXYARP,
- Link.IFLA_BRPORT_LEARNING_SYNC,
- Link.IFLA_BRPORT_PROXYARP_WIFI,
- Link.IFLA_BRPORT_TOPOLOGY_CHANGE_ACK,
- Link.IFLA_BRPORT_CONFIG_PENDING,
- Link.IFLA_BRPORT_MULTICAST_ROUTER,
- Link.IFLA_BRPORT_MCAST_FLOOD,
- Link.IFLA_BRPORT_MCAST_TO_UCAST,
- Link.IFLA_BRPORT_VLAN_TUNNEL,
- Link.IFLA_BRPORT_PEER_LINK,
- Link.IFLA_BRPORT_DUAL_LINK,
- Link.IFLA_BRPORT_ARP_SUPPRESS,
- Link.IFLA_BRPORT_DOWN_PEERLINK_REDIRECT):
- ifla_info_slave_data[info_data_type] = unpack('=B', sub_attr_data[4])[0]
-
- # 2 bytes
- elif info_data_type in (Link.IFLA_BRPORT_PRIORITY,
- Link.IFLA_BRPORT_DESIGNATED_PORT,
- Link.IFLA_BRPORT_DESIGNATED_COST,
- Link.IFLA_BRPORT_ID,
- Link.IFLA_BRPORT_NO,
- Link.IFLA_BRPORT_GROUP_FWD_MASK,
- Link.IFLA_BRPORT_GROUP_FWD_MASKHI):
- ifla_info_slave_data[info_data_type] = unpack('=H', sub_attr_data[4:6])[0]
-
- # 4 bytes
- elif info_data_type == Link.IFLA_BRPORT_COST:
- ifla_info_slave_data[info_data_type] = unpack('=L', sub_attr_data[4:8])[0]
-
- elif ifla_info_slave_kind == 'bond':
-
- # 1 byte
- if info_data_type in (
- Link.IFLA_BOND_SLAVE_STATE,
- Link.IFLA_BOND_SLAVE_MII_STATUS,
- Link.IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE,
- Link.IFLA_BOND_SLAVE_AD_RX_BYPASS,
- ):
- ifla_info_slave_data[info_data_type] = unpack('=B', sub_attr_data[4])[0]
-
- # 2 bytes
- elif info_data_type in (
- Link.IFLA_BOND_SLAVE_QUEUE_ID,
- Link.IFLA_BOND_SLAVE_AD_AGGREGATOR_ID
- ):
- ifla_info_slave_data[info_data_type] = unpack('=H', sub_attr_data[4:6])[0]
-
- # 4 bytes
- elif info_data_type == (
- Link.IFLA_BOND_SLAVE_PERM_HWADDR,
- Link.IFLA_BOND_SLAVE_LINK_FAILURE_COUNT
- ):
- ifla_info_slave_data[info_data_type] = unpack('=L', sub_attr_data[4:8])[0]
-
- except Exception as e:
- self.log.debug('%s: attribute %s: %s'
- % (self.value[Link.IFLA_INFO_SLAVE_KIND],
- info_data_type,
- str(e)))
- sub_attr_data = sub_attr_data[info_data_end:]
-
- self.value[Link.IFLA_INFO_SLAVE_DATA] = ifla_info_slave_data
-
elif sub_attr_type == Link.IFLA_INFO_DATA:
- sub_attr_data = data[4:sub_attr_end]
- self.value[Link.IFLA_INFO_DATA] = {}
-
- ifla_info_kind = self.value.get(Link.IFLA_INFO_KIND)
- if not ifla_info_kind:
- self.log.warning('IFLA_INFO_KIND is not known...we cannot parse IFLA_INFO_DATA')
- else:
- while sub_attr_data:
- (info_data_length, info_data_type) = unpack('=HH', sub_attr_data[:4])
- info_data_end = padded_length(info_data_length)
- try:
- if ifla_info_kind == 'vlan':
- if info_data_type == Link.IFLA_VLAN_ID:
- self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=H', sub_attr_data[4:6])[0]
-
- elif info_data_type == Link.IFLA_VLAN_PROTOCOL:
- hex_value = '0x%s' % sub_attr_data[4:6].encode('hex')
- vlan_protocol = Link.ifla_vlan_protocol_dict.get(int(hex_value, base=16))
-
- if vlan_protocol:
- self.value[Link.IFLA_INFO_DATA][info_data_type] = vlan_protocol
- else:
- self.log.warning('IFLA_VLAN_PROTOCOL: cannot decode vlan protocol %s' % hex_value)
-
- else:
- self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for decoding IFLA_INFO_KIND vlan type %s (%d), length %d, padded to %d' %
- (parent_msg.get_ifla_vlan_string(info_data_type), info_data_type, info_data_length, info_data_end))
-
- elif ifla_info_kind == 'macvlan':
- if info_data_type == Link.IFLA_MACVLAN_MODE:
- self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=L', sub_attr_data[4:8])[0]
- else:
- self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for decoding IFLA_INFO_KIND macvlan type %s (%d), length %d, padded to %d' %
- (parent_msg.get_ifla_macvlan_string(info_data_type), info_data_type, info_data_length, info_data_end))
-
- elif ifla_info_kind == 'xfrm':
- # 4-byte int
- if info_data_type in (Link.IFLA_XFRM_IF_ID, Link.IFLA_XFRM_LINK):
- self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=L', sub_attr_data[4:8])[0]
-
- elif ifla_info_kind == 'vxlan':
-
- # IPv4Address
- if info_data_type in (Link.IFLA_VXLAN_GROUP,
- Link.IFLA_VXLAN_LOCAL):
- self.value[Link.IFLA_INFO_DATA][info_data_type] = IPv4Address(unpack('>L', sub_attr_data[4:8])[0])
-
- # 4-byte int
- elif info_data_type in (Link.IFLA_VXLAN_ID,
- Link.IFLA_VXLAN_LINK,
- Link.IFLA_VXLAN_AGEING,
- Link.IFLA_VXLAN_LIMIT,
- Link.IFLA_VXLAN_PORT_RANGE):
- self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=L', sub_attr_data[4:8])[0]
-
- # 2-byte int
- elif info_data_type in (Link.IFLA_VXLAN_PORT, ):
- self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('!H', sub_attr_data[4:6])[0]
- # The form '!' is available for those poor souls who claim they can't
- # remember whether network byte order is big-endian or little-endian.
-
- # 1-byte int
- elif info_data_type in (Link.IFLA_VXLAN_TTL,
- Link.IFLA_VXLAN_TOS,
- Link.IFLA_VXLAN_LEARNING,
- Link.IFLA_VXLAN_PROXY,
- Link.IFLA_VXLAN_RSC,
- Link.IFLA_VXLAN_L2MISS,
- Link.IFLA_VXLAN_L3MISS,
- Link.IFLA_VXLAN_UDP_CSUM,
- Link.IFLA_VXLAN_UDP_ZERO_CSUM6_TX,
- Link.IFLA_VXLAN_UDP_ZERO_CSUM6_RX,
- Link.IFLA_VXLAN_REMCSUM_TX,
- Link.IFLA_VXLAN_REMCSUM_RX,
- Link.IFLA_VXLAN_REPLICATION_TYPE):
- self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=B', sub_attr_data[4])[0]
-
- else:
- # sub_attr_end = padded_length(sub_attr_length)
- self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for decoding IFLA_INFO_KIND vxlan type %s (%d), length %d, padded to %d' %
- (parent_msg.get_ifla_vxlan_string(info_data_type), info_data_type, info_data_length, info_data_end))
-
- elif ifla_info_kind == 'bond':
-
- if info_data_type in (Link.IFLA_BOND_AD_INFO, ):
- ad_attr_data = sub_attr_data[4:info_data_end]
- self.value[Link.IFLA_INFO_DATA][Link.IFLA_BOND_AD_INFO] = {}
-
- while ad_attr_data:
- (ad_data_length, ad_data_type) = unpack('=HH', ad_attr_data[:4])
- ad_data_end = padded_length(ad_data_length)
-
- if ad_data_type in (Link.IFLA_BOND_AD_INFO_PARTNER_MAC,):
- (data1, data2) = unpack('>LHxx', ad_attr_data[4:12])
- self.value[Link.IFLA_INFO_DATA][Link.IFLA_BOND_AD_INFO][ad_data_type] = mac_int_to_str(data1 << 16 | data2)
-
- ad_attr_data = ad_attr_data[ad_data_end:]
-
- # 1-byte int
- elif info_data_type in (Link.IFLA_BOND_MODE,
- Link.IFLA_BOND_USE_CARRIER,
- Link.IFLA_BOND_AD_LACP_RATE,
- Link.IFLA_BOND_AD_LACP_BYPASS,
- Link.IFLA_BOND_XMIT_HASH_POLICY,
- Link.IFLA_BOND_NUM_PEER_NOTIF):
- self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=B', sub_attr_data[4])[0]
-
- # 2-bytes int
- elif info_data_type == Link.IFLA_BOND_AD_ACTOR_SYS_PRIO:
- self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=H', sub_attr_data[4:6])[0]
-
- # 4-bytes int
- elif info_data_type in (Link.IFLA_BOND_MIIMON,
- Link.IFLA_BOND_UPDELAY,
- Link.IFLA_BOND_DOWNDELAY,
- Link.IFLA_BOND_MIN_LINKS):
- self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=L', sub_attr_data[4:8])[0]
-
- # mac address
- elif info_data_type in (Link.IFLA_BOND_AD_ACTOR_SYSTEM, ):
- (data1, data2) = unpack('>LHxx', sub_attr_data[4:12])
- self.value[Link.IFLA_INFO_DATA][info_data_type] = mac_int_to_str(data1 << 16 | data2)
-
- else:
- self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for decoding IFLA_INFO_KIND bond type %s (%d), length %d, padded to %d' %
- (parent_msg.get_ifla_bond_string(info_data_type), info_data_type, info_data_length, info_data_end))
-
- elif ifla_info_kind == 'bridge':
- # 4 bytes
- if info_data_type in (Link.IFLA_BR_AGEING_TIME,
- Link.IFLA_BR_FORWARD_DELAY,
- Link.IFLA_BR_HELLO_TIME,
- Link.IFLA_BR_MAX_AGE,
- Link.IFLA_BR_STP_STATE,
- Link.IFLA_BR_ROOT_PATH_COST,
- Link.IFLA_BR_MCAST_HASH_ELASTICITY,
- Link.IFLA_BR_MCAST_HASH_MAX,
- Link.IFLA_BR_MCAST_LAST_MEMBER_CNT,
- Link.IFLA_BR_MCAST_STARTUP_QUERY_CNT):
- self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=L', sub_attr_data[4:8])[0]
-
- # 2 bytes
- elif info_data_type in (Link.IFLA_BR_PRIORITY,
- Link.IFLA_BR_GROUP_FWD_MASK,
- Link.IFLA_BR_ROOT_PORT,
- Link.IFLA_BR_VLAN_DEFAULT_PVID):
- self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=H', sub_attr_data[4:6])[0]
-
- elif info_data_type == Link.IFLA_BR_VLAN_PROTOCOL:
- hex_value = '0x%s' % sub_attr_data[4:6].encode('hex')
- vlan_protocol = Link.ifla_vlan_protocol_dict.get(int(hex_value, base=16))
-
- if vlan_protocol:
- self.value[Link.IFLA_INFO_DATA][info_data_type] = vlan_protocol
- else:
- self.log.warning('IFLA_VLAN_PROTOCOL: cannot decode vlan protocol %s' % hex_value)
-
- # 8 bytes
- elif info_data_type in (Link.IFLA_BR_MCAST_MEMBERSHIP_INTVL,
- Link.IFLA_BR_MCAST_QUERIER_INTVL,
- Link.IFLA_BR_MCAST_LAST_MEMBER_INTVL,
- Link.IFLA_BR_MCAST_MEMBERSHIP_INTVL,
- Link.IFLA_BR_MCAST_QUERIER_INTVL,
- Link.IFLA_BR_MCAST_QUERY_INTVL,
- Link.IFLA_BR_MCAST_QUERY_RESPONSE_INTVL,
- Link.IFLA_BR_MCAST_STARTUP_QUERY_INTVL):
- self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=Q', sub_attr_data[4:12])[0]
-
- # 1 bytes
- elif info_data_type in (Link.IFLA_BR_VLAN_FILTERING,
- Link.IFLA_BR_TOPOLOGY_CHANGE,
- Link.IFLA_BR_TOPOLOGY_CHANGE_DETECTED,
- Link.IFLA_BR_MCAST_ROUTER,
- Link.IFLA_BR_MCAST_SNOOPING,
- Link.IFLA_BR_MCAST_QUERY_USE_IFADDR,
- Link.IFLA_BR_MCAST_QUERIER,
- Link.IFLA_BR_NF_CALL_IPTABLES,
- Link.IFLA_BR_NF_CALL_IP6TABLES,
- Link.IFLA_BR_NF_CALL_ARPTABLES,
- Link.IFLA_BR_VLAN_STATS_ENABLED,
- Link.IFLA_BR_MCAST_STATS_ENABLED,
- Link.IFLA_BR_MCAST_IGMP_VERSION,
- Link.IFLA_BR_MCAST_MLD_VERSION):
- self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=B', sub_attr_data[4])[0]
- else:
- self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for decoding IFLA_INFO_KIND bridge type %s (%d), length %d, padded to %d' %
- (parent_msg.get_ifla_br_string(info_data_type), info_data_type, info_data_length, info_data_end))
-
- elif ifla_info_kind == 'vrf':
-
- if info_data_type in (Link.IFLA_VRF_TABLE,):
- self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=L', sub_attr_data[4:8])[0]
-
- elif ifla_info_kind in ("gre", "gretap", "erspan", "ip6gre", "ip6gretap", "ip6erspan"):
-
- # 1-byte
- if info_data_type in (Link.IFLA_GRE_TTL, Link.IFLA_GRE_TOS, Link.IFLA_GRE_PMTUDISC):
- self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=B', sub_attr_data[4])[0]
-
- # 2-bytes
- elif info_data_type in (
- Link.IFLA_GRE_IFLAGS,
- Link.IFLA_GRE_OFLAGS,
- Link.IFLA_GRE_ENCAP_TYPE,
- Link.IFLA_GRE_ENCAP_SPORT,
- Link.IFLA_GRE_ENCAP_DPORT,
- Link.IFLA_GRE_ENCAP_FLAGS
- ):
- self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=H', sub_attr_data[4:6])[0]
-
- # 4 bytes
- elif info_data_type in (Link.IFLA_GRE_LINK, Link.IFLA_GRE_IKEY, Link.IFLA_GRE_OKEY):
- self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=L', sub_attr_data[4:8])[0]
-
- # ip addr
- elif info_data_type in (Link.IFLA_GRE_LOCAL, Link.IFLA_GRE_REMOTE):
- if ifla_info_kind in ("ip6gre", "ip6gretap", "ip6erspan"):
- (data1, data2) = unpack(">QQ", sub_attr_data[4:20])
- self.value[Link.IFLA_INFO_DATA][info_data_type] = IPv6Address(data1 << 64 | data2)
- else:
- self.value[Link.IFLA_INFO_DATA][info_data_type] = IPv4Address(unpack(">L", sub_attr_data[4:8])[0])
-
- else:
- self.log.log(SYSLOG_EXTRA_DEBUG,
- 'Add support for decoding IFLA_INFO_KIND %s type %s (%d), length %d, padded to %d' %
- (ifla_info_kind, parent_msg.get_ifla_gre_string(info_data_type), info_data_type,
- info_data_length, info_data_end))
-
- elif ifla_info_kind in ("ipip", "sit", "ip6tnl"):
-
- # 1-byte
- if info_data_type in (Link.IFLA_IPTUN_TTL, Link.IFLA_IPTUN_TOS, Link.IFLA_IPTUN_PMTUDISC):
- self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=B', sub_attr_data[4])[0]
-
- # 2-bytes
- elif info_data_type in (Link.IFLA_IPTUN_ENCAP_TYPE, Link.IFLA_IPTUN_ENCAP_SPORT, Link.IFLA_IPTUN_ENCAP_DPORT, Link.IFLA_IPTUN_ENCAP_FLAGS):
- self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=H', sub_attr_data[4:6])[
- 0]
-
- # 4 bytes
- elif info_data_type == Link.IFLA_IPTUN_LINK:
- self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=L', sub_attr_data[4:8])[
- 0]
-
- # ip addr
- elif info_data_type in (Link.IFLA_IPTUN_LOCAL, Link.IFLA_IPTUN_REMOTE):
- if ifla_info_kind == "ip6tnl":
- (data1, data2) = unpack(">QQ", sub_attr_data[4:20])
- self.value[Link.IFLA_INFO_DATA][info_data_type] = IPv6Address(data1 << 64 | data2)
- else:
- self.value[Link.IFLA_INFO_DATA][info_data_type] = IPv4Address(unpack(">L", sub_attr_data[4:8])[0])
-
- else:
- self.log.log(SYSLOG_EXTRA_DEBUG,
- 'Add support for decoding IFLA_INFO_KIND %s type %s (%d), length %d, padded to %d' %
- (ifla_info_kind, parent_msg.get_ifla_iptun_string(info_data_type), info_data_type,
- info_data_length, info_data_end))
-
- elif ifla_info_kind in ("vti", "vti6"):
- # 4 bytes
- if info_data_type in (Link.IFLA_VTI_LINK, Link.IFLA_VTI_IKEY, Link.IFLA_VTI_OKEY):
- self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=L', sub_attr_data[4:8])[0]
-
- # ip addr
- elif info_data_type in (Link.IFLA_VTI_LOCAL, Link.IFLA_VTI_REMOTE):
- if ifla_info_kind == "vti6":
- (data1, data2) = unpack(">QQ", sub_attr_data[4:20])
- self.value[Link.IFLA_INFO_DATA][info_data_type] = IPv6Address(data1 << 64 | data2)
- else:
- self.value[Link.IFLA_INFO_DATA][info_data_type] = IPv4Address(unpack(">L", sub_attr_data[4:8])[0])
-
- else:
- self.log.log(SYSLOG_EXTRA_DEBUG,
- 'Add support for decoding IFLA_INFO_KIND %s type %s (%d), length %d, padded to %d' %
- (ifla_info_kind, parent_msg.get_ifla_vti_string(info_data_type), info_data_type,
- info_data_length, info_data_end))
+ self.value[Link.IFLA_INFO_DATA] = self.decode_ifla_info_nested_data(
+ self.value.get(Link.IFLA_INFO_KIND), "IFLA_INFO_KIND",
+ Link.IFLA_INFO_DATA, "IFLA_INFO_DATA",
+ data, sub_attr_end,
+ )
- else:
- self.log.log(SYSLOG_EXTRA_DEBUG, "Add support for decoding IFLA_INFO_KIND %s (%d), length %d, padded to %d" %
- (ifla_info_kind, info_data_type, info_data_length, info_data_end))
-
- except Exception as e:
- self.log.debug('%s: attribute %s: %s'
- % (self.value[Link.IFLA_INFO_KIND],
- info_data_type,
- str(e)))
- sub_attr_data = sub_attr_data[info_data_end:]
+ elif sub_attr_type == Link.IFLA_INFO_SLAVE_DATA:
+ self.value[Link.IFLA_INFO_SLAVE_DATA] = self.decode_ifla_info_nested_data(
+ self.value.get(Link.IFLA_INFO_SLAVE_KIND), "IFLA_INFO_SLAVE_KIND",
+ Link.IFLA_INFO_SLAVE_DATA, "IFLA_INFO_SLAVE_DATA",
+ data, sub_attr_end,
+ )
else:
- self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for decoding IFLA_LINKINFO sub-attribute type %s (%d), length %d, padded to %d' %
- (parent_msg.get_ifla_info_string(sub_attr_type), sub_attr_type, sub_attr_length, sub_attr_end))
+ self.log.log(
+ SYSLOG_EXTRA_DEBUG,
+ 'Add support for decoding IFLA_LINKINFO sub-attribute type %s (%d), length %d, padded to %d'
+ % (parent_msg.get_ifla_info_string(sub_attr_type), sub_attr_type, sub_attr_length, sub_attr_end)
+ )
data = data[sub_attr_end:]
- # self.log.info('IFLA_LINKINFO values %s' % pformat(self.value))
-
def dump_lines(self, dump_buffer, line_number, color):
line_number = self.dump_first_line(dump_buffer, line_number, color)
extra = ''
else:
padded_to = ' padded to %d, ' % sub_attr_end
- extra = 'Nested Attribute - Length %s (%d)%s Type %s (%d) %s' % \
+ if sub_attr_type & NLA_F_NESTED:
+ sub_attr_type ^= NLA_F_NESTED
+
+ extra = 'Nested Attribute - Length %s (%d)%s Type %s (%d) %s (%s)' % \
(zfilled_hex(sub_attr_length, 4), sub_attr_length,
padded_to,
zfilled_hex(sub_attr_type, 4), sub_attr_type,
- Link.ifla_info_to_string.get(sub_attr_type))
+ Link.ifla_info_to_string.get(sub_attr_type), sub_attr_type)
else:
extra = ''
ifla_info_kind = self.value.get(Link.IFLA_INFO_KIND)
ifla_info_slave_kind = self.value.get(Link.IFLA_INFO_SLAVE_KIND)
- kind_dict = dict()
-
- # We do this so we can print a more human readable dictionary
- # with the names of the nested keys instead of their numbers
-
- # Most of these are placeholders...we need to add support
- # for more human readable dictionaries for bond, bridge, etc
- kind_dict[Link.IFLA_INFO_DATA] = {
- 'bond': Link.ifla_bond_to_string,
- 'vlan': Link.ifla_vlan_to_string,
- 'vxlan': Link.ifla_vxlan_to_string,
- 'bridge': Link.ifla_br_to_string,
- 'macvlan': Link.ifla_macvlan_to_string,
- 'gre': Link.ifla_gre_to_string,
- 'gretap': Link.ifla_gre_to_string,
- 'erspan': Link.ifla_gre_to_string,
- 'ip6gre': Link.ifla_gre_to_string,
- 'ip6gretap': Link.ifla_gre_to_string,
- 'ip6erspan': Link.ifla_gre_to_string,
- 'vti': Link.ifla_vti_to_string,
- 'vti6': Link.ifla_vti_to_string,
- 'ipip': Link.ifla_iptun_to_string,
- 'sit': Link.ifla_iptun_to_string,
- 'ip6tnl': Link.ifla_iptun_to_string,
- 'xfrm': Link.ifla_xfrm_to_string
- }.get(ifla_info_kind, {})
-
- kind_dict[Link.IFLA_INFO_SLAVE_DATA] = {
- 'bridge': Link.ifla_brport_to_string,
- 'bond': Link.ifla_bond_slave_to_string
- }.get(ifla_info_slave_kind, {})
-
+ kind_dict = {
+ Link.IFLA_INFO_DATA: self.ifla_info_nested_data_attributes_to_string_dict.get(Link.IFLA_INFO_DATA, {}).get(ifla_info_kind),
+ Link.IFLA_INFO_SLAVE_DATA: self.ifla_info_nested_data_attributes_to_string_dict.get(Link.IFLA_INFO_SLAVE_DATA, {}).get(ifla_info_slave_kind)
+ }
if ifla_info_kind or ifla_info_slave_kind:
value_pretty = {}
Link.IFLA_BRPORT_MULTICAST_ROUTER,
Link.IFLA_BRPORT_PEER_LINK,
Link.IFLA_BRPORT_DUAL_LINK,
- Link.IFLA_BRPORT_ARP_SUPPRESS,
- Link.IFLA_BRPORT_DOWN_PEERLINK_REDIRECT):
+ Link.IFLA_BRPORT_NEIGH_SUPPRESS):
sub_attr_pack_layout.append('B')
sub_attr_payload.append(sub_attr_value)
- sub_attr_pack_layout.extend('xxx')
# 2 Byte attributes
elif sub_attr_type in (Link.IFLA_BRPORT_PRIORITY,
Link.IFLA_BRPORT_NO):
sub_attr_pack_layout.append('H')
sub_attr_payload.append(sub_attr_value)
- sub_attr_pack_layout.extend('xx')
# 4 Byte attributes
- elif sub_attr_type in (Link.IFLA_BRPORT_COST,):
+ elif sub_attr_type in (Link.IFLA_BRPORT_COST, Link.IFLA_BRPORT_BACKUP_PORT):
sub_attr_pack_layout.append('L')
sub_attr_payload.append(sub_attr_value)
Link.IFLA_BRPORT_MULTICAST_ROUTER,
Link.IFLA_BRPORT_PEER_LINK,
Link.IFLA_BRPORT_DUAL_LINK,
- Link.IFLA_BRPORT_ARP_SUPPRESS,
- Link.IFLA_BRPORT_DOWN_PEERLINK_REDIRECT):
+ Link.IFLA_BRPORT_NEIGH_SUPPRESS):
self.value[sub_attr_type] = unpack('=B', data[4])[0]
# 2 Byte attributes
self.value[sub_attr_type] = unpack('=H', data[4:6])[0]
# 4 Byte attributes
- elif sub_attr_type in (Link.IFLA_BRPORT_COST,):
+ elif sub_attr_type in (Link.IFLA_BRPORT_COST, Link.IFLA_BRPORT_BACKUP_PORT):
self.value[sub_attr_type] = unpack('=L', data[4:8])[0]
# 8 Byte attributes
RTM_DELQDISC : 'RTM_DELQDISC',
RTM_GETQDISC : 'RTM_GETQDISC',
RTM_NEWNETCONF: 'RTM_NEWNETCONF',
- RTM_GETNETCONF: 'RTM_GETNETCONF'
+ RTM_GETNETCONF: 'RTM_GETNETCONF',
+ RTM_DELNETCONF: 'RTM_DELNETCONF',
+ RTM_NEWMDB : 'RTM_NEWMDB',
+ RTM_DELMDB : 'RTM_DELMDB',
+ RTM_GETMDB : 'RTM_GETMDB'
}
af_family_to_string = {
AF_INET6 : 'inet6'
}
- def __init__(self, msgtype, debug, owner_logger=None, use_color=True):
+ def __init__(self, msgtype, debug, owner_logger=None, use_color=True, rx=False, tx=False):
self.msgtype = msgtype
self.attributes = {}
self.dump_buffer = ['']
self.message = None
self.use_color = use_color
self.family = None
+ self.rx = rx
+ self.tx = tx
+ self.priv_flags = 0
if owner_logger:
self.log = owner_logger
foo.append('NLM_F_ECHO')
# Modifiers to GET query
- if msg_type in (RTM_GETLINK, RTM_GETADDR, RTM_GETNEIGH, RTM_GETROUTE, RTM_GETQDISC, RTM_GETNETCONF):
+ if msg_type in (RTM_GETLINK, RTM_GETADDR, RTM_GETNEIGH, RTM_GETROUTE, RTM_GETQDISC, RTM_GETNETCONF, RTM_GETMDB):
if flags & NLM_F_DUMP:
foo.append('NLM_F_DUMP')
else:
foo.append('NLM_F_ATOMIC')
# Modifiers to NEW query
- elif msg_type in (RTM_NEWLINK, RTM_NEWADDR, RTM_NEWNEIGH, RTM_NEWROUTE, RTM_NEWQDISC):
+ elif msg_type in (RTM_NEWLINK, RTM_NEWADDR, RTM_NEWNEIGH, RTM_NEWROUTE, RTM_NEWQDISC, RTM_NEWMDB):
if flags & NLM_F_REPLACE:
foo.append('NLM_F_REPLACE')
take the family into account. For now we'll handle this as a special case for
MPLS but long term we may need to make key a tuple of the attr_type and family.
'''
- if self.msgtype not in (RTM_NEWNETCONF, RTM_GETNETCONF) and attr_type == Route.RTA_DST and self.family == AF_MPLS:
+ if self.msgtype not in (RTM_NEWNETCONF, RTM_GETNETCONF, RTM_DELNETCONF) and attr_type == Route.RTA_DST and self.family == AF_MPLS:
attr_string = 'RTA_DST'
attr_class = AttributeMplsLabel
IFA_CACHEINFO = 0x06
IFA_MULTICAST = 0x07
IFA_FLAGS = 0x08
+ IFA_RT_PRIORITY = 0x09 # 32, priority / metricfor prefix route
attribute_to_class = {
IFA_UNSPEC : ('IFA_UNSPEC', AttributeGeneric),
IFA_LABEL : ('IFA_LABEL', AttributeString),
IFA_BROADCAST : ('IFA_BROADCAST', AttributeIPAddress),
IFA_ANYCAST : ('IFA_ANYCAST', AttributeIPAddress),
- IFA_CACHEINFO : ('IFA_CACHEINFO', AttributeGeneric),
+ IFA_CACHEINFO : ('IFA_CACHEINFO', AttributeCACHEINFO),
IFA_MULTICAST : ('IFA_MULTICAST', AttributeIPAddress),
- IFA_FLAGS : ('IFA_FLAGS', AttributeGeneric)
+ IFA_FLAGS : ('IFA_FLAGS', AttributeGeneric),
+ IFA_RT_PRIORITY : ('IFA_RT_PRIORITY', AttributeFourByteValue)
}
# Address flags
NLE_NODEV = 0x1F
NLE_IMMUTABLE = 0x20
NLE_DUMP_INTR = 0x21
+ NLE_ATTRSIZE = 0x22
error_to_string = {
NLE_SUCCESS : 'NLE_SUCCESS',
NLE_PARSE_ERR : 'NLE_PARSE_ERR',
NLE_NODEV : 'NLE_NODEV',
NLE_IMMUTABLE : 'NLE_IMMUTABLE',
- NLE_DUMP_INTR : 'NLE_DUMP_INTR'
+ NLE_DUMP_INTR : 'NLE_DUMP_INTR',
+ NLE_ATTRSIZE : 'NLE_ATTRSIZE'
+ }
+
+ error_to_human_readable_string = {
+ NLE_SUCCESS: "Success",
+ NLE_FAILURE: "Unspecific failure",
+ NLE_INTR: "Interrupted system call",
+ NLE_BAD_SOCK: "Bad socket",
+ NLE_AGAIN: "Try again",
+ NLE_NOMEM: "Out of memory",
+ NLE_EXIST: "Object exists",
+ NLE_INVAL: "Invalid input data or parameter",
+ NLE_RANGE: "Input data out of range",
+ NLE_MSGSIZE: "Message size not sufficient",
+ NLE_OPNOTSUPP: "Operation not supported",
+ NLE_AF_NOSUPPORT: "Address family not supported",
+ NLE_OBJ_NOTFOUND: "Object not found",
+ NLE_NOATTR: "Attribute not available",
+ NLE_MISSING_ATTR: "Missing attribute",
+ NLE_AF_MISMATCH: "Address family mismatch",
+ NLE_SEQ_MISMATCH: "Message sequence number mismatch",
+ NLE_MSG_OVERFLOW: "Kernel reported message overflow",
+ NLE_MSG_TRUNC: "Kernel reported truncated message",
+ NLE_NOADDR: "Invalid address for specified address family",
+ NLE_SRCRT_NOSUPPORT: "Source based routing not supported",
+ NLE_MSG_TOOSHORT: "Netlink message is too short",
+ NLE_MSGTYPE_NOSUPPORT: "Netlink message type is not supported",
+ NLE_OBJ_MISMATCH: "Object type does not match cache",
+ NLE_NOCACHE: "Unknown or invalid cache type",
+ NLE_BUSY: "Object busy",
+ NLE_PROTO_MISMATCH: "Protocol mismatch",
+ NLE_NOACCESS: "No Access",
+ NLE_PERM: "Operation not permitted",
+ NLE_PKTLOC_FILE: "Unable to open packet location file",
+ NLE_PARSE_ERR: "Unable to parse object",
+ NLE_NODEV: "No such device",
+ NLE_IMMUTABLE: "Immutable attribute",
+ NLE_DUMP_INTR: "Dump inconsistency detected, interrupted",
+ NLE_ATTRSIZE: "Attribute max length exceeded",
}
def __init__(self, msgtype, debug=False, logger=None, use_color=True):
for x in range(0, self.LEN/4):
if self.line_number == 5:
- extra = "Error Number %s is %s" % (self.negative_errno, self.error_to_string.get(abs(self.negative_errno)))
+ error_number = abs(self.negative_errno)
+ extra = "Error Number %s is %s (%s)" % (self.negative_errno, self.error_to_string.get(error_number), self.error_to_human_readable_string.get(error_number))
# zfilled_hex(self.negative_errno, 2)
elif self.line_number == 6:
self.line_number += 1
-class Link(NetlinkPacket):
+class Link(NetlinkPacket, NetlinkPacket_IFLA_LINKINFO_Attributes):
"""
Service Header
IFLA_PROTO_DOWN = 39
IFLA_GSO_MAX_SEGS = 40
IFLA_GSO_MAX_SIZE = 41
+ IFLA_PAD = 42
+ IFLA_XDP = 43
+ IFLA_EVENT = 44
+ IFLA_NEW_NETNSID = 45
+ IFLA_IF_NETNSID = 46
+ IFLA_CARRIER_UP_COUNT = 47
+ IFLA_CARRIER_DOWN_COUNT = 48
+ IFLA_NEW_IFINDEX = 49
+ IFLA_MIN_MTU = 50
+ IFLA_MAX_MTU = 51
attribute_to_class = {
IFLA_UNSPEC : ('IFLA_UNSPEC', AttributeGeneric),
IFLA_LINKMODE : ('IFLA_LINKMODE', AttributeOneByteValue),
IFLA_LINKINFO : ('IFLA_LINKINFO', AttributeIFLA_LINKINFO),
IFLA_NET_NS_PID : ('IFLA_NET_NS_PID', AttributeGeneric),
- IFLA_IFALIAS : ('IFLA_IFALIAS', AttributeGeneric),
+ IFLA_IFALIAS : ('IFLA_IFALIAS', AttributeString),
IFLA_NUM_VF : ('IFLA_NUM_VF', AttributeGeneric),
IFLA_VFINFO_LIST : ('IFLA_VFINFO_LIST', AttributeGeneric),
IFLA_STATS64 : ('IFLA_STATS64', AttributeGeneric),
IFLA_PHYS_PORT_NAME : ('IFLA_PHYS_PORT_NAME', AttributeGeneric),
IFLA_PROTO_DOWN : ('IFLA_PROTO_DOWN', AttributeOneByteValue),
IFLA_GSO_MAX_SEGS : ('IFLA_GSO_MAX_SEGS', AttributeFourByteValue),
- IFLA_GSO_MAX_SIZE : ('IFLA_GSO_MAX_SIZE', AttributeFourByteValue)
+ IFLA_GSO_MAX_SIZE : ('IFLA_GSO_MAX_SIZE', AttributeFourByteValue),
+ IFLA_PAD : ('IFLA_PAD', AttributeGeneric),
+ IFLA_XDP : ('IFLA_XDP', AttributeGeneric),
+ IFLA_EVENT : ('IFLA_EVENT', AttributeFourByteValue),
+ IFLA_NEW_NETNSID : ('IFLA_NEW_NETNSID', AttributeFourByteValue),
+ IFLA_IF_NETNSID : ('IFLA_IF_NETNSID', AttributeFourByteValue),
+ IFLA_CARRIER_UP_COUNT : ('IFLA_CARRIER_UP_COUNT', AttributeFourByteValue),
+ IFLA_CARRIER_DOWN_COUNT : ('IFLA_CARRIER_DOWN_COUNT', AttributeFourByteValue),
+ IFLA_NEW_IFINDEX : ('IFLA_NEW_IFINDEX', AttributeFourByteValue),
+ IFLA_MIN_MTU : ('IFLA_MIN_MTU', AttributeFourByteValue),
+ IFLA_MAX_MTU : ('IFLA_MAX_MTU', AttributeFourByteValue),
}
# Link flags
ARPHRD_NONE = 0xFFFE # zero header length
link_type_to_string = {
- ARPHRD_NETROM : 'ARPHRD_NETROM',
- ARPHRD_ETHER : 'ARPHRD_ETHER',
- ARPHRD_EETHER : 'ARPHRD_EETHER',
- ARPHRD_AX25 : 'ARPHRD_AX25',
- ARPHRD_PRONET : 'ARPHRD_PRONET',
- ARPHRD_CHAOS : 'ARPHRD_CHAOS',
- ARPHRD_IEEE802 : 'ARPHRD_IEEE802',
- ARPHRD_ARCNET : 'ARPHRD_ARCNET',
- ARPHRD_APPLETLK : 'ARPHRD_APPLETLK',
- ARPHRD_DLCI : 'ARPHRD_DLCI',
- ARPHRD_ATM : 'ARPHRD_ATM',
- ARPHRD_METRICOM : 'ARPHRD_METRICOM',
- ARPHRD_IEEE1394 : 'ARPHRD_IEEE1394',
- ARPHRD_EUI64 : 'ARPHRD_EUI64',
- ARPHRD_INFINIBAND : 'ARPHRD_INFINIBAND',
- ARPHRD_SLIP : 'ARPHRD_SLIP',
- ARPHRD_CSLIP : 'ARPHRD_CSLIP',
- ARPHRD_SLIP6 : 'ARPHRD_SLIP6',
- ARPHRD_CSLIP6 : 'ARPHRD_CSLIP6',
- ARPHRD_RSRVD : 'ARPHRD_RSRVD',
- ARPHRD_ADAPT : 'ARPHRD_ADAPT',
- ARPHRD_ROSE : 'ARPHRD_ROSE',
- ARPHRD_X25 : 'ARPHRD_X25',
- ARPHRD_HWX25 : 'ARPHRD_HWX25',
- ARPHRD_CAN : 'ARPHRD_CAN',
- ARPHRD_PPP : 'ARPHRD_PPP',
- ARPHRD_CISCO : 'ARPHRD_CISCO',
- ARPHRD_HDLC : 'ARPHRD_HDLC',
- ARPHRD_LAPB : 'ARPHRD_LAPB',
- ARPHRD_DDCMP : 'ARPHRD_DDCMP',
- ARPHRD_RAWHDLC : 'ARPHRD_RAWHDLC',
- ARPHRD_TUNNEL : 'ARPHRD_TUNNEL',
- ARPHRD_TUNNEL6 : 'ARPHRD_TUNNEL6',
- ARPHRD_FRAD : 'ARPHRD_FRAD',
- ARPHRD_SKIP : 'ARPHRD_SKIP',
- ARPHRD_LOOPBACK : 'ARPHRD_LOOPBACK',
- ARPHRD_LOCALTLK : 'ARPHRD_LOCALTLK',
- ARPHRD_FDDI : 'ARPHRD_FDDI',
- ARPHRD_BIF : 'ARPHRD_BIF',
- ARPHRD_SIT : 'ARPHRD_SIT',
- ARPHRD_IPDDP : 'ARPHRD_IPDDP',
- ARPHRD_IPGRE : 'ARPHRD_IPGRE',
- ARPHRD_PIMREG : 'ARPHRD_PIMREG',
- ARPHRD_HIPPI : 'ARPHRD_HIPPI',
- ARPHRD_ASH : 'ARPHRD_ASH',
- ARPHRD_ECONET : 'ARPHRD_ECONET',
- ARPHRD_IRDA : 'ARPHRD_IRDA',
- ARPHRD_FCPP : 'ARPHRD_FCPP',
- ARPHRD_FCAL : 'ARPHRD_FCAL',
- ARPHRD_FCPL : 'ARPHRD_FCPL',
- ARPHRD_FCFABRIC : 'ARPHRD_FCFABRIC',
- ARPHRD_IEEE802_TR : 'ARPHRD_IEEE802_TR',
- ARPHRD_IEEE80211 : 'ARPHRD_IEEE80211',
- ARPHRD_IEEE80211_PRISM : 'ARPHRD_IEEE80211_PRISM',
- ARPHRD_IEEE80211_RADIOTAP : 'ARPHRD_IEEE80211_RADIOTAP',
- ARPHRD_IEEE802154 : 'ARPHRD_IEEE802154',
- ARPHRD_PHONET : 'ARPHRD_PHONET',
- ARPHRD_PHONET_PIPE : 'ARPHRD_PHONET_PIPE',
- ARPHRD_CAIF : 'ARPHRD_CAIF',
- ARPHRD_VOID : 'ARPHRD_VOID',
- ARPHRD_NONE : 'ARPHRD_NONE'
- }
-
- # =========================================
- # IFLA_LINKINFO attributes
- # =========================================
- IFLA_INFO_UNSPEC = 0
- IFLA_INFO_KIND = 1
- IFLA_INFO_DATA = 2
- IFLA_INFO_XSTATS = 3
- IFLA_INFO_SLAVE_KIND = 4
- IFLA_INFO_SLAVE_DATA = 5
- IFLA_INFO_MAX = 6
-
- ifla_info_to_string = {
- IFLA_INFO_UNSPEC : 'IFLA_INFO_UNSPEC',
- IFLA_INFO_KIND : 'IFLA_INFO_KIND',
- IFLA_INFO_DATA : 'IFLA_INFO_DATA',
- IFLA_INFO_XSTATS : 'IFLA_INFO_XSTATS',
- IFLA_INFO_SLAVE_KIND : 'IFLA_INFO_SLAVE_KIND',
- IFLA_INFO_SLAVE_DATA : 'IFLA_INFO_SLAVE_DATA',
- IFLA_INFO_MAX : 'IFLA_INFO_MAX'
- }
-
- # =========================================
- # IFLA_INFO_DATA attributes for vlan
- # =========================================
- IFLA_VLAN_UNSPEC = 0
- IFLA_VLAN_ID = 1
- IFLA_VLAN_FLAGS = 2
- IFLA_VLAN_EGRESS_QOS = 3
- IFLA_VLAN_INGRESS_QOS = 4
- IFLA_VLAN_PROTOCOL = 5
-
- ifla_vlan_to_string = {
- IFLA_VLAN_UNSPEC : 'IFLA_VLAN_UNSPEC',
- IFLA_VLAN_ID : 'IFLA_VLAN_ID',
- IFLA_VLAN_FLAGS : 'IFLA_VLAN_FLAGS',
- IFLA_VLAN_EGRESS_QOS : 'IFLA_VLAN_EGRESS_QOS',
- IFLA_VLAN_INGRESS_QOS : 'IFLA_VLAN_INGRESS_QOS',
- IFLA_VLAN_PROTOCOL : 'IFLA_VLAN_PROTOCOL'
- }
-
- ifla_vlan_protocol_dict = {
- '802.1Q': 0x8100,
- '802.1q': 0x8100,
-
- '802.1ad': 0x88A8,
- '802.1AD': 0x88A8,
- '802.1Ad': 0x88A8,
- '802.1aD': 0x88A8,
-
- 0x8100: '802.1Q',
- 0x88A8: '802.1ad'
- }
-
- # =========================================
- # IFLA_INFO_DATA attributes for macvlan
- # =========================================
- IFLA_MACVLAN_UNSPEC = 0
- IFLA_MACVLAN_MODE = 1
-
- ifla_macvlan_to_string = {
- IFLA_MACVLAN_UNSPEC : 'IFLA_MACVLAN_UNSPEC',
- IFLA_MACVLAN_MODE : 'IFLA_MACVLAN_MODE'
- }
-
- # macvlan modes
- MACVLAN_MODE_PRIVATE = 1
- MACVLAN_MODE_VEPA = 2
- MACVLAN_MODE_BRIDGE = 3
- MACVLAN_MODE_PASSTHRU = 4
-
- macvlan_mode_to_string = {
- MACVLAN_MODE_PRIVATE : 'MACVLAN_MODE_PRIVATE',
- MACVLAN_MODE_VEPA : 'MACVLAN_MODE_VEPA',
- MACVLAN_MODE_BRIDGE : 'MACVLAN_MODE_BRIDGE',
- MACVLAN_MODE_PASSTHRU : 'MACVLAN_MODE_PASSTHRU'
- }
-
- # =========================================
- # IFLA_INFO_DATA attributes for xfrm
- # =========================================
- IFLA_XFRM_UNSPEC = 0
- IFLA_XFRM_LINK = 1
- IFLA_XFRM_IF_ID = 2
-
- ifla_xfrm_to_string = {
- IFLA_XFRM_UNSPEC : 'IFLA_XFRM_UNSPEC',
- IFLA_XFRM_LINK : 'IFLA_XFRM_LINK',
- IFLA_XFRM_IF_ID : 'IFLA_XFRM_IF_ID'
- }
-
- # =========================================
- # IFLA_INFO_DATA attributes for vxlan
- # =========================================
- IFLA_VXLAN_UNSPEC = 0
- IFLA_VXLAN_ID = 1
- IFLA_VXLAN_GROUP = 2
- IFLA_VXLAN_LINK = 3
- IFLA_VXLAN_LOCAL = 4
- IFLA_VXLAN_TTL = 5
- IFLA_VXLAN_TOS = 6
- IFLA_VXLAN_LEARNING = 7
- IFLA_VXLAN_AGEING = 8
- IFLA_VXLAN_LIMIT = 9
- IFLA_VXLAN_PORT_RANGE = 10
- IFLA_VXLAN_PROXY = 11
- IFLA_VXLAN_RSC = 12
- IFLA_VXLAN_L2MISS = 13
- IFLA_VXLAN_L3MISS = 14
- IFLA_VXLAN_PORT = 15
- IFLA_VXLAN_GROUP6 = 16
- IFLA_VXLAN_LOCAL6 = 17
- IFLA_VXLAN_UDP_CSUM = 18
- IFLA_VXLAN_UDP_ZERO_CSUM6_TX = 19
- IFLA_VXLAN_UDP_ZERO_CSUM6_RX = 20
- IFLA_VXLAN_REMCSUM_TX = 21
- IFLA_VXLAN_REMCSUM_RX = 22
- IFLA_VXLAN_GBP = 23
- IFLA_VXLAN_REMCSUM_NOPARTIAL = 24
- IFLA_VXLAN_COLLECT_METADATA = 25
- IFLA_VXLAN_REPLICATION_NODE = 253
- IFLA_VXLAN_REPLICATION_TYPE = 254
-
- ifla_vxlan_to_string = {
- IFLA_VXLAN_UNSPEC : 'IFLA_VXLAN_UNSPEC',
- IFLA_VXLAN_ID : 'IFLA_VXLAN_ID',
- IFLA_VXLAN_GROUP : 'IFLA_VXLAN_GROUP',
- IFLA_VXLAN_LINK : 'IFLA_VXLAN_LINK',
- IFLA_VXLAN_LOCAL : 'IFLA_VXLAN_LOCAL',
- IFLA_VXLAN_TTL : 'IFLA_VXLAN_TTL',
- IFLA_VXLAN_TOS : 'IFLA_VXLAN_TOS',
- IFLA_VXLAN_LEARNING : 'IFLA_VXLAN_LEARNING',
- IFLA_VXLAN_AGEING : 'IFLA_VXLAN_AGEING',
- IFLA_VXLAN_LIMIT : 'IFLA_VXLAN_LIMIT',
- IFLA_VXLAN_PORT_RANGE : 'IFLA_VXLAN_PORT_RANGE',
- IFLA_VXLAN_PROXY : 'IFLA_VXLAN_PROXY',
- IFLA_VXLAN_RSC : 'IFLA_VXLAN_RSC',
- IFLA_VXLAN_L2MISS : 'IFLA_VXLAN_L2MISS',
- IFLA_VXLAN_L3MISS : 'IFLA_VXLAN_L3MISS',
- IFLA_VXLAN_PORT : 'IFLA_VXLAN_PORT',
- IFLA_VXLAN_GROUP6 : 'IFLA_VXLAN_GROUP6',
- IFLA_VXLAN_LOCAL6 : 'IFLA_VXLAN_LOCAL6',
- IFLA_VXLAN_UDP_CSUM : 'IFLA_VXLAN_UDP_CSUM',
- IFLA_VXLAN_UDP_ZERO_CSUM6_TX : 'IFLA_VXLAN_UDP_ZERO_CSUM6_TX',
- IFLA_VXLAN_UDP_ZERO_CSUM6_RX : 'IFLA_VXLAN_UDP_ZERO_CSUM6_RX',
- IFLA_VXLAN_REMCSUM_TX : 'IFLA_VXLAN_REMCSUM_TX',
- IFLA_VXLAN_REMCSUM_RX : 'IFLA_VXLAN_REMCSUM_RX',
- IFLA_VXLAN_GBP : 'IFLA_VXLAN_GBP',
- IFLA_VXLAN_REMCSUM_NOPARTIAL : 'IFLA_VXLAN_REMCSUM_NOPARTIAL',
- IFLA_VXLAN_COLLECT_METADATA : 'IFLA_VXLAN_COLLECT_METADATA',
- IFLA_VXLAN_REPLICATION_NODE : 'IFLA_VXLAN_REPLICATION_NODE',
- IFLA_VXLAN_REPLICATION_TYPE : 'IFLA_VXLAN_REPLICATION_TYPE'
- }
-
- # =========================================
- # IFLA_INFO_DATA attributes for bonds
- # =========================================
- IFLA_BOND_UNSPEC = 0
- IFLA_BOND_MODE = 1
- IFLA_BOND_ACTIVE_SLAVE = 2
- IFLA_BOND_MIIMON = 3
- IFLA_BOND_UPDELAY = 4
- IFLA_BOND_DOWNDELAY = 5
- IFLA_BOND_USE_CARRIER = 6
- IFLA_BOND_ARP_INTERVAL = 7
- IFLA_BOND_ARP_IP_TARGET = 8
- IFLA_BOND_ARP_VALIDATE = 9
- IFLA_BOND_ARP_ALL_TARGETS = 10
- IFLA_BOND_PRIMARY = 11
- IFLA_BOND_PRIMARY_RESELECT = 12
- IFLA_BOND_FAIL_OVER_MAC = 13
- IFLA_BOND_XMIT_HASH_POLICY = 14
- IFLA_BOND_RESEND_IGMP = 15
- IFLA_BOND_NUM_PEER_NOTIF = 16
- IFLA_BOND_ALL_SLAVES_ACTIVE = 17
- IFLA_BOND_MIN_LINKS = 18
- IFLA_BOND_LP_INTERVAL = 19
- IFLA_BOND_PACKETS_PER_SLAVE = 20
- IFLA_BOND_AD_LACP_RATE = 21
- IFLA_BOND_AD_SELECT = 22
- IFLA_BOND_AD_INFO = 23
- IFLA_BOND_AD_ACTOR_SYS_PRIO = 24
- IFLA_BOND_AD_USER_PORT_KEY = 25
- IFLA_BOND_AD_ACTOR_SYSTEM = 26
- IFLA_BOND_AD_LACP_BYPASS = 100
-
- ifla_bond_to_string = {
- IFLA_BOND_UNSPEC : 'IFLA_BOND_UNSPEC',
- IFLA_BOND_MODE : 'IFLA_BOND_MODE',
- IFLA_BOND_ACTIVE_SLAVE : 'IFLA_BOND_ACTIVE_SLAVE',
- IFLA_BOND_MIIMON : 'IFLA_BOND_MIIMON',
- IFLA_BOND_UPDELAY : 'IFLA_BOND_UPDELAY',
- IFLA_BOND_DOWNDELAY : 'IFLA_BOND_DOWNDELAY',
- IFLA_BOND_USE_CARRIER : 'IFLA_BOND_USE_CARRIER',
- IFLA_BOND_ARP_INTERVAL : 'IFLA_BOND_ARP_INTERVAL',
- IFLA_BOND_ARP_IP_TARGET : 'IFLA_BOND_ARP_IP_TARGET',
- IFLA_BOND_ARP_VALIDATE : 'IFLA_BOND_ARP_VALIDATE',
- IFLA_BOND_ARP_ALL_TARGETS : 'IFLA_BOND_ARP_ALL_TARGETS',
- IFLA_BOND_PRIMARY : 'IFLA_BOND_PRIMARY',
- IFLA_BOND_PRIMARY_RESELECT : 'IFLA_BOND_PRIMARY_RESELECT',
- IFLA_BOND_FAIL_OVER_MAC : 'IFLA_BOND_FAIL_OVER_MAC',
- IFLA_BOND_XMIT_HASH_POLICY : 'IFLA_BOND_XMIT_HASH_POLICY',
- IFLA_BOND_RESEND_IGMP : 'IFLA_BOND_RESEND_IGMP',
- IFLA_BOND_NUM_PEER_NOTIF : 'IFLA_BOND_NUM_PEER_NOTIF',
- IFLA_BOND_ALL_SLAVES_ACTIVE : 'IFLA_BOND_ALL_SLAVES_ACTIVE',
- IFLA_BOND_MIN_LINKS : 'IFLA_BOND_MIN_LINKS',
- IFLA_BOND_LP_INTERVAL : 'IFLA_BOND_LP_INTERVAL',
- IFLA_BOND_PACKETS_PER_SLAVE : 'IFLA_BOND_PACKETS_PER_SLAVE',
- IFLA_BOND_AD_LACP_RATE : 'IFLA_BOND_AD_LACP_RATE',
- IFLA_BOND_AD_SELECT : 'IFLA_BOND_AD_SELECT',
- IFLA_BOND_AD_INFO : 'IFLA_BOND_AD_INFO',
- IFLA_BOND_AD_ACTOR_SYS_PRIO : 'IFLA_BOND_AD_ACTOR_SYS_PRIO',
- IFLA_BOND_AD_USER_PORT_KEY : 'IFLA_BOND_AD_USER_PORT_KEY',
- IFLA_BOND_AD_ACTOR_SYSTEM : 'IFLA_BOND_AD_ACTOR_SYSTEM',
- IFLA_BOND_AD_LACP_BYPASS : 'IFLA_BOND_AD_LACP_BYPASS'
- }
-
- IFLA_BOND_AD_INFO_UNSPEC = 0
- IFLA_BOND_AD_INFO_AGGREGATOR = 1
- IFLA_BOND_AD_INFO_NUM_PORTS = 2
- IFLA_BOND_AD_INFO_ACTOR_KEY = 3
- IFLA_BOND_AD_INFO_PARTNER_KEY = 4
- IFLA_BOND_AD_INFO_PARTNER_MAC = 5
-
- ifla_bond_ad_to_string = {
- IFLA_BOND_AD_INFO_UNSPEC : 'IFLA_BOND_AD_INFO_UNSPEC',
- IFLA_BOND_AD_INFO_AGGREGATOR : 'IFLA_BOND_AD_INFO_AGGREGATOR',
- IFLA_BOND_AD_INFO_NUM_PORTS : 'IFLA_BOND_AD_INFO_NUM_PORTS',
- IFLA_BOND_AD_INFO_ACTOR_KEY : 'IFLA_BOND_AD_INFO_ACTOR_KEY',
- IFLA_BOND_AD_INFO_PARTNER_KEY : 'IFLA_BOND_AD_INFO_PARTNER_KEY',
- IFLA_BOND_AD_INFO_PARTNER_MAC : 'IFLA_BOND_AD_INFO_PARTNER_MAC'
- }
-
- ifla_bond_mode_tbl = {
- 'balance-rr': 0,
- 'active-backup': 1,
- 'balance-xor': 2,
- 'broadcast': 3,
- '802.3ad': 4,
- 'balance-tlb': 5,
- 'balance-alb': 6,
- '0': 0,
- '1': 1,
- '2': 2,
- '3': 3,
- '4': 4,
- '5': 5,
- '6': 6,
- 0: 0,
- 1: 1,
- 2: 2,
- 3: 3,
- 4: 4,
- 5: 5,
- 6: 6
- }
-
- ifla_bond_mode_pretty_tbl = {
- 0: 'balance-rr',
- 1: 'active-backup',
- 2: 'balance-xor',
- 3: 'broadcast',
- 4: '802.3ad',
- 5: 'balance-tlb',
- 6: 'balance-alb'
- }
-
- ifla_bond_xmit_hash_policy_tbl = {
- 'layer2': 0,
- 'layer3+4': 1,
- 'layer2+3': 2,
- 'encap2+3': 3,
- 'encap3+4': 4,
- '0': 0,
- '1': 1,
- '2': 2,
- '3': 3,
- '4': 4,
- 0: 0,
- 1: 1,
- 2: 2,
- 3: 3,
- 4: 4
- }
-
- ifla_bond_xmit_hash_policy_pretty_tbl = {
- 0: 'layer2',
- 1: 'layer3+4',
- 2: 'layer2+3',
- 3: 'encap2+3',
- 4: 'encap3+4',
- }
-
- # =========================================
- # IFLA_INFO_SLAVE_DATA attributes for bonds
- # =========================================
- IFLA_BOND_SLAVE_UNSPEC = 0
- IFLA_BOND_SLAVE_STATE = 1
- IFLA_BOND_SLAVE_MII_STATUS = 2
- IFLA_BOND_SLAVE_LINK_FAILURE_COUNT = 3
- IFLA_BOND_SLAVE_PERM_HWADDR = 4
- IFLA_BOND_SLAVE_QUEUE_ID = 5
- IFLA_BOND_SLAVE_AD_AGGREGATOR_ID = 6
- IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE = 7
- IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE = 8
- IFLA_BOND_SLAVE_CL_START = 50
- IFLA_BOND_SLAVE_AD_RX_BYPASS = IFLA_BOND_SLAVE_CL_START
-
- ifla_bond_slave_to_string = {
- IFLA_BOND_SLAVE_UNSPEC : 'IFLA_BOND_SLAVE_UNSPEC',
- IFLA_BOND_SLAVE_STATE : 'IFLA_BOND_SLAVE_STATE',
- IFLA_BOND_SLAVE_MII_STATUS : 'IFLA_BOND_SLAVE_MII_STATUS',
- IFLA_BOND_SLAVE_LINK_FAILURE_COUNT : 'IFLA_BOND_SLAVE_LINK_FAILURE_COUNT',
- IFLA_BOND_SLAVE_PERM_HWADDR : 'IFLA_BOND_SLAVE_PERM_HWADDR',
- IFLA_BOND_SLAVE_QUEUE_ID : 'IFLA_BOND_SLAVE_QUEUE_ID',
- IFLA_BOND_SLAVE_AD_AGGREGATOR_ID : 'IFLA_BOND_SLAVE_AD_AGGREGATOR_ID',
- IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE : 'IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE',
- IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE : 'IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE',
- IFLA_BOND_SLAVE_CL_START : 'IFLA_BOND_SLAVE_CL_START',
- IFLA_BOND_SLAVE_AD_RX_BYPASS : 'IFLA_BOND_SLAVE_AD_RX_BYPASS'
- }
-
- # =========================================
- # IFLA_PROTINFO attributes for bridge ports
- # =========================================
- IFLA_BRPORT_UNSPEC = 0
- IFLA_BRPORT_STATE = 1
- IFLA_BRPORT_PRIORITY = 2
- IFLA_BRPORT_COST = 3
- IFLA_BRPORT_MODE = 4
- IFLA_BRPORT_GUARD = 5
- IFLA_BRPORT_PROTECT = 6
- IFLA_BRPORT_FAST_LEAVE = 7
- IFLA_BRPORT_LEARNING = 8
- IFLA_BRPORT_UNICAST_FLOOD = 9
- IFLA_BRPORT_PROXYARP = 10
- IFLA_BRPORT_LEARNING_SYNC = 11
- IFLA_BRPORT_PROXYARP_WIFI = 12
- IFLA_BRPORT_ROOT_ID = 13
- IFLA_BRPORT_BRIDGE_ID = 14
- IFLA_BRPORT_DESIGNATED_PORT = 15
- IFLA_BRPORT_DESIGNATED_COST = 16
- IFLA_BRPORT_ID = 17
- IFLA_BRPORT_NO = 18
- IFLA_BRPORT_TOPOLOGY_CHANGE_ACK = 19
- IFLA_BRPORT_CONFIG_PENDING = 20
- IFLA_BRPORT_MESSAGE_AGE_TIMER = 21
- IFLA_BRPORT_FORWARD_DELAY_TIMER = 22
- IFLA_BRPORT_HOLD_TIMER = 23
- IFLA_BRPORT_FLUSH = 24
- IFLA_BRPORT_MULTICAST_ROUTER = 25
- IFLA_BRPORT_PAD = 26
- IFLA_BRPORT_MCAST_FLOOD = 27
- IFLA_BRPORT_MCAST_TO_UCAST = 28
- IFLA_BRPORT_VLAN_TUNNEL = 29
- IFLA_BRPORT_BCAST_FLOOD = 30
- IFLA_BRPORT_GROUP_FWD_MASK = 31
- IFLA_BRPORT_ARP_SUPPRESS = 32
- IFLA_BRPORT_PEER_LINK = 150
- IFLA_BRPORT_DUAL_LINK = 151
- IFLA_BRPORT_GROUP_FWD_MASKHI = 153
- IFLA_BRPORT_DOWN_PEERLINK_REDIRECT = 154
-
- ifla_brport_to_string = {
- IFLA_BRPORT_UNSPEC : 'IFLA_BRPORT_UNSPEC',
- IFLA_BRPORT_STATE : 'IFLA_BRPORT_STATE',
- IFLA_BRPORT_PRIORITY : 'IFLA_BRPORT_PRIORITY',
- IFLA_BRPORT_COST : 'IFLA_BRPORT_COST',
- IFLA_BRPORT_MODE : 'IFLA_BRPORT_MODE',
- IFLA_BRPORT_GUARD : 'IFLA_BRPORT_GUARD',
- IFLA_BRPORT_PROTECT : 'IFLA_BRPORT_PROTECT',
- IFLA_BRPORT_FAST_LEAVE : 'IFLA_BRPORT_FAST_LEAVE',
- IFLA_BRPORT_LEARNING : 'IFLA_BRPORT_LEARNING',
- IFLA_BRPORT_UNICAST_FLOOD : 'IFLA_BRPORT_UNICAST_FLOOD',
- IFLA_BRPORT_PROXYARP : 'IFLA_BRPORT_PROXYARP',
- IFLA_BRPORT_LEARNING_SYNC : 'IFLA_BRPORT_LEARNING_SYNC',
- IFLA_BRPORT_PROXYARP_WIFI : 'IFLA_BRPORT_PROXYARP_WIFI',
- IFLA_BRPORT_ROOT_ID : 'IFLA_BRPORT_ROOT_ID',
- IFLA_BRPORT_BRIDGE_ID : 'IFLA_BRPORT_BRIDGE_ID',
- IFLA_BRPORT_DESIGNATED_PORT : 'IFLA_BRPORT_DESIGNATED_PORT',
- IFLA_BRPORT_DESIGNATED_COST : 'IFLA_BRPORT_DESIGNATED_COST',
- IFLA_BRPORT_ID : 'IFLA_BRPORT_ID',
- IFLA_BRPORT_NO : 'IFLA_BRPORT_NO',
- IFLA_BRPORT_TOPOLOGY_CHANGE_ACK : 'IFLA_BRPORT_TOPOLOGY_CHANGE_ACK',
- IFLA_BRPORT_CONFIG_PENDING : 'IFLA_BRPORT_CONFIG_PENDING',
- IFLA_BRPORT_MESSAGE_AGE_TIMER : 'IFLA_BRPORT_MESSAGE_AGE_TIMER',
- IFLA_BRPORT_FORWARD_DELAY_TIMER : 'IFLA_BRPORT_FORWARD_DELAY_TIMER',
- IFLA_BRPORT_HOLD_TIMER : 'IFLA_BRPORT_HOLD_TIMER',
- IFLA_BRPORT_FLUSH : 'IFLA_BRPORT_FLUSH',
- IFLA_BRPORT_MULTICAST_ROUTER : 'IFLA_BRPORT_MULTICAST_ROUTER',
- IFLA_BRPORT_PAD : 'IFLA_BRPORT_PAD',
- IFLA_BRPORT_MCAST_FLOOD : 'IFLA_BRPORT_MCAST_FLOOD',
- IFLA_BRPORT_MCAST_TO_UCAST : 'IFLA_BRPORT_MCAST_TO_UCAST',
- IFLA_BRPORT_VLAN_TUNNEL : 'IFLA_BRPORT_VLAN_TUNNEL',
- IFLA_BRPORT_BCAST_FLOOD : 'IFLA_BRPORT_BCAST_FLOOD',
- IFLA_BRPORT_GROUP_FWD_MASK : 'IFLA_BRPORT_GROUP_FWD_MASK',
- IFLA_BRPORT_PEER_LINK : 'IFLA_BRPORT_PEER_LINK',
- IFLA_BRPORT_DUAL_LINK : 'IFLA_BRPORT_DUAL_LINK',
- IFLA_BRPORT_ARP_SUPPRESS : 'IFLA_BRPORT_ARP_SUPPRESS',
- IFLA_BRPORT_GROUP_FWD_MASKHI : 'IFLA_BRPORT_GROUP_FWD_MASKHI',
- IFLA_BRPORT_DOWN_PEERLINK_REDIRECT : 'IFLA_BRPORT_DOWN_PEERLINK_REDIRECT'
+ ARPHRD_NETROM : 'ARPHRD_NETROM',
+ ARPHRD_ETHER : 'ARPHRD_ETHER',
+ ARPHRD_EETHER : 'ARPHRD_EETHER',
+ ARPHRD_AX25 : 'ARPHRD_AX25',
+ ARPHRD_PRONET : 'ARPHRD_PRONET',
+ ARPHRD_CHAOS : 'ARPHRD_CHAOS',
+ ARPHRD_IEEE802 : 'ARPHRD_IEEE802',
+ ARPHRD_ARCNET : 'ARPHRD_ARCNET',
+ ARPHRD_APPLETLK : 'ARPHRD_APPLETLK',
+ ARPHRD_DLCI : 'ARPHRD_DLCI',
+ ARPHRD_ATM : 'ARPHRD_ATM',
+ ARPHRD_METRICOM : 'ARPHRD_METRICOM',
+ ARPHRD_IEEE1394 : 'ARPHRD_IEEE1394',
+ ARPHRD_EUI64 : 'ARPHRD_EUI64',
+ ARPHRD_INFINIBAND : 'ARPHRD_INFINIBAND',
+ ARPHRD_SLIP : 'ARPHRD_SLIP',
+ ARPHRD_CSLIP : 'ARPHRD_CSLIP',
+ ARPHRD_SLIP6 : 'ARPHRD_SLIP6',
+ ARPHRD_CSLIP6 : 'ARPHRD_CSLIP6',
+ ARPHRD_RSRVD : 'ARPHRD_RSRVD',
+ ARPHRD_ADAPT : 'ARPHRD_ADAPT',
+ ARPHRD_ROSE : 'ARPHRD_ROSE',
+ ARPHRD_X25 : 'ARPHRD_X25',
+ ARPHRD_HWX25 : 'ARPHRD_HWX25',
+ ARPHRD_CAN : 'ARPHRD_CAN',
+ ARPHRD_PPP : 'ARPHRD_PPP',
+ ARPHRD_CISCO : 'ARPHRD_CISCO',
+ ARPHRD_HDLC : 'ARPHRD_HDLC',
+ ARPHRD_LAPB : 'ARPHRD_LAPB',
+ ARPHRD_DDCMP : 'ARPHRD_DDCMP',
+ ARPHRD_RAWHDLC : 'ARPHRD_RAWHDLC',
+ ARPHRD_TUNNEL : 'ARPHRD_TUNNEL',
+ ARPHRD_TUNNEL6 : 'ARPHRD_TUNNEL6',
+ ARPHRD_FRAD : 'ARPHRD_FRAD',
+ ARPHRD_SKIP : 'ARPHRD_SKIP',
+ ARPHRD_LOOPBACK : 'ARPHRD_LOOPBACK',
+ ARPHRD_LOCALTLK : 'ARPHRD_LOCALTLK',
+ ARPHRD_FDDI : 'ARPHRD_FDDI',
+ ARPHRD_BIF : 'ARPHRD_BIF',
+ ARPHRD_SIT : 'ARPHRD_SIT',
+ ARPHRD_IPDDP : 'ARPHRD_IPDDP',
+ ARPHRD_IPGRE : 'ARPHRD_IPGRE',
+ ARPHRD_PIMREG : 'ARPHRD_PIMREG',
+ ARPHRD_HIPPI : 'ARPHRD_HIPPI',
+ ARPHRD_ASH : 'ARPHRD_ASH',
+ ARPHRD_ECONET : 'ARPHRD_ECONET',
+ ARPHRD_IRDA : 'ARPHRD_IRDA',
+ ARPHRD_FCPP : 'ARPHRD_FCPP',
+ ARPHRD_FCAL : 'ARPHRD_FCAL',
+ ARPHRD_FCPL : 'ARPHRD_FCPL',
+ ARPHRD_FCFABRIC : 'ARPHRD_FCFABRIC',
+ ARPHRD_IEEE802_TR : 'ARPHRD_IEEE802_TR',
+ ARPHRD_IEEE80211 : 'ARPHRD_IEEE80211',
+ ARPHRD_IEEE80211_PRISM : 'ARPHRD_IEEE80211_PRISM',
+ ARPHRD_IEEE80211_RADIOTAP : 'ARPHRD_IEEE80211_RADIOTAP',
+ ARPHRD_IEEE802154 : 'ARPHRD_IEEE802154',
+ ARPHRD_PHONET : 'ARPHRD_PHONET',
+ ARPHRD_PHONET_PIPE : 'ARPHRD_PHONET_PIPE',
+ ARPHRD_CAIF : 'ARPHRD_CAIF',
+ ARPHRD_VOID : 'ARPHRD_VOID',
+ ARPHRD_NONE : 'ARPHRD_NONE'
}
# Subtype attributes for IFLA_AF_SPEC
IN6_ADDR_GEN_MODE_NONE: "none",
IN6_ADDR_GEN_MODE_STABLE_PRIVACY: "stable_secret",
IN6_ADDR_GEN_MODE_RANDOM: "random"
- }
-
- # Subtype attrbutes AF_INET
- IFLA_INET_UNSPEC = 0
- IFLA_INET_CONF = 1
- __IFLA_INET_MAX = 2
-
- ifla_inet_af_spec_to_string = {
- IFLA_INET_UNSPEC : 'IFLA_INET_UNSPEC',
- IFLA_INET_CONF : 'IFLA_INET_CONF',
- }
-
- # BRIDGE IFLA_AF_SPEC attributes
- IFLA_BRIDGE_FLAGS = 0
- IFLA_BRIDGE_MODE = 1
- IFLA_BRIDGE_VLAN_INFO = 2
-
- ifla_bridge_af_spec_to_string = {
- IFLA_BRIDGE_FLAGS : 'IFLA_BRIDGE_FLAGS',
- IFLA_BRIDGE_MODE : 'IFLA_BRIDGE_MODE',
- IFLA_BRIDGE_VLAN_INFO : 'IFLA_BRIDGE_VLAN_INFO'
- }
-
- # BRIDGE_VLAN_INFO flags
- BRIDGE_VLAN_INFO_MASTER = 1 << 0 # Operate on Bridge device as well
- BRIDGE_VLAN_INFO_PVID = 1 << 1 # VLAN is PVID, ingress untagged
- BRIDGE_VLAN_INFO_UNTAGGED = 1 << 2 # VLAN egresses untagged
- BRIDGE_VLAN_INFO_RANGE_BEGIN = 1 << 3 # VLAN is start of vlan range
- BRIDGE_VLAN_INFO_RANGE_END = 1 << 4 # VLAN is end of vlan range
- BRIDGE_VLAN_INFO_BRENTRY = 1 << 5 # Global bridge VLAN entry
-
- bridge_vlan_to_string = {
- BRIDGE_VLAN_INFO_MASTER : 'BRIDGE_VLAN_INFO_MASTER',
- BRIDGE_VLAN_INFO_PVID : 'BRIDGE_VLAN_INFO_PVID',
- BRIDGE_VLAN_INFO_UNTAGGED : 'BRIDGE_VLAN_INFO_UNTAGGED',
- BRIDGE_VLAN_INFO_RANGE_BEGIN : 'BRIDGE_VLAN_INFO_RANGE_BEGIN',
- BRIDGE_VLAN_INFO_RANGE_END : 'BRIDGE_VLAN_INFO_RANGE_END',
- BRIDGE_VLAN_INFO_BRENTRY : 'BRIDGE_VLAN_INFO_BRENTRY'
- }
-
- # Bridge flags
- BRIDGE_FLAGS_MASTER = 1
- BRIDGE_FLAGS_SELF = 2
-
- bridge_flags_to_string = {
- BRIDGE_FLAGS_MASTER : 'BRIDGE_FLAGS_MASTER',
- BRIDGE_FLAGS_SELF : 'BRIDGE_FLAGS_SELF'
- }
-
- # filters for IFLA_EXT_MASK
- RTEXT_FILTER_VF = 1 << 0
- RTEXT_FILTER_BRVLAN = 1 << 1
- RTEXT_FILTER_BRVLAN_COMPRESSED = 1 << 2
- RTEXT_FILTER_SKIP_STATS = 1 << 3
-
- rtext_to_string = {
- RTEXT_FILTER_VF : 'RTEXT_FILTER_VF',
- RTEXT_FILTER_BRVLAN : 'RTEXT_FILTER_BRVLAN',
- RTEXT_FILTER_BRVLAN_COMPRESSED : 'RTEXT_FILTER_BRVLAN_COMPRESSED',
- RTEXT_FILTER_SKIP_STATS : 'RTEXT_FILTER_SKIP_STATS'
- }
-
- IFLA_BR_UNSPEC = 0
- IFLA_BR_FORWARD_DELAY = 1
- IFLA_BR_HELLO_TIME = 2
- IFLA_BR_MAX_AGE = 3
- IFLA_BR_AGEING_TIME = 4
- IFLA_BR_STP_STATE = 5
- IFLA_BR_PRIORITY = 6
- IFLA_BR_VLAN_FILTERING = 7
- IFLA_BR_VLAN_PROTOCOL = 8
- IFLA_BR_GROUP_FWD_MASK = 9
- IFLA_BR_ROOT_ID = 10
- IFLA_BR_BRIDGE_ID = 11
- IFLA_BR_ROOT_PORT = 12
- IFLA_BR_ROOT_PATH_COST = 13
- IFLA_BR_TOPOLOGY_CHANGE = 14
- IFLA_BR_TOPOLOGY_CHANGE_DETECTED = 15
- IFLA_BR_HELLO_TIMER = 16
- IFLA_BR_TCN_TIMER = 17
- IFLA_BR_TOPOLOGY_CHANGE_TIMER = 18
- IFLA_BR_GC_TIMER = 19
- IFLA_BR_GROUP_ADDR = 20
- IFLA_BR_FDB_FLUSH = 21
- IFLA_BR_MCAST_ROUTER = 22
- IFLA_BR_MCAST_SNOOPING = 23
- IFLA_BR_MCAST_QUERY_USE_IFADDR = 24
- IFLA_BR_MCAST_QUERIER = 25
- IFLA_BR_MCAST_HASH_ELASTICITY = 26
- IFLA_BR_MCAST_HASH_MAX = 27
- IFLA_BR_MCAST_LAST_MEMBER_CNT = 28
- IFLA_BR_MCAST_STARTUP_QUERY_CNT = 29
- IFLA_BR_MCAST_LAST_MEMBER_INTVL = 30
- IFLA_BR_MCAST_MEMBERSHIP_INTVL = 31
- IFLA_BR_MCAST_QUERIER_INTVL = 32
- IFLA_BR_MCAST_QUERY_INTVL = 33
- IFLA_BR_MCAST_QUERY_RESPONSE_INTVL = 34
- IFLA_BR_MCAST_STARTUP_QUERY_INTVL = 35
- IFLA_BR_NF_CALL_IPTABLES = 36
- IFLA_BR_NF_CALL_IP6TABLES = 37
- IFLA_BR_NF_CALL_ARPTABLES = 38
- IFLA_BR_VLAN_DEFAULT_PVID = 39
- IFLA_BR_PAD = 40
- IFLA_BR_VLAN_STATS_ENABLED = 41
- IFLA_BR_MCAST_STATS_ENABLED = 42
- IFLA_BR_MCAST_IGMP_VERSION = 43
- IFLA_BR_MCAST_MLD_VERSION = 44
-
- ifla_br_to_string = {
- IFLA_BR_UNSPEC : 'IFLA_BR_UNSPEC',
- IFLA_BR_FORWARD_DELAY : 'IFLA_BR_FORWARD_DELAY',
- IFLA_BR_HELLO_TIME : 'IFLA_BR_HELLO_TIME',
- IFLA_BR_MAX_AGE : 'IFLA_BR_MAX_AGE',
- IFLA_BR_AGEING_TIME : 'IFLA_BR_AGEING_TIME',
- IFLA_BR_STP_STATE : 'IFLA_BR_STP_STATE',
- IFLA_BR_PRIORITY : 'IFLA_BR_PRIORITY',
- IFLA_BR_VLAN_FILTERING : 'IFLA_BR_VLAN_FILTERING',
- IFLA_BR_VLAN_PROTOCOL : 'IFLA_BR_VLAN_PROTOCOL',
- IFLA_BR_GROUP_FWD_MASK : 'IFLA_BR_GROUP_FWD_MASK',
- IFLA_BR_ROOT_ID : 'IFLA_BR_ROOT_ID',
- IFLA_BR_BRIDGE_ID : 'IFLA_BR_BRIDGE_ID',
- IFLA_BR_ROOT_PORT : 'IFLA_BR_ROOT_PORT',
- IFLA_BR_ROOT_PATH_COST : 'IFLA_BR_ROOT_PATH_COST',
- IFLA_BR_TOPOLOGY_CHANGE : 'IFLA_BR_TOPOLOGY_CHANGE',
- IFLA_BR_TOPOLOGY_CHANGE_DETECTED : 'IFLA_BR_TOPOLOGY_CHANGE_DETECTED',
- IFLA_BR_HELLO_TIMER : 'IFLA_BR_HELLO_TIMER',
- IFLA_BR_TCN_TIMER : 'IFLA_BR_TCN_TIMER',
- IFLA_BR_TOPOLOGY_CHANGE_TIMER : 'IFLA_BR_TOPOLOGY_CHANGE_TIMER',
- IFLA_BR_GC_TIMER : 'IFLA_BR_GC_TIMER',
- IFLA_BR_GROUP_ADDR : 'IFLA_BR_GROUP_ADDR',
- IFLA_BR_FDB_FLUSH : 'IFLA_BR_FDB_FLUSH',
- IFLA_BR_MCAST_ROUTER : 'IFLA_BR_MCAST_ROUTER',
- IFLA_BR_MCAST_SNOOPING : 'IFLA_BR_MCAST_SNOOPING',
- IFLA_BR_MCAST_QUERY_USE_IFADDR : 'IFLA_BR_MCAST_QUERY_USE_IFADDR',
- IFLA_BR_MCAST_QUERIER : 'IFLA_BR_MCAST_QUERIER',
- IFLA_BR_MCAST_HASH_ELASTICITY : 'IFLA_BR_MCAST_HASH_ELASTICITY',
- IFLA_BR_MCAST_HASH_MAX : 'IFLA_BR_MCAST_HASH_MAX',
- IFLA_BR_MCAST_LAST_MEMBER_CNT : 'IFLA_BR_MCAST_LAST_MEMBER_CNT',
- IFLA_BR_MCAST_STARTUP_QUERY_CNT : 'IFLA_BR_MCAST_STARTUP_QUERY_CNT',
- IFLA_BR_MCAST_LAST_MEMBER_INTVL : 'IFLA_BR_MCAST_LAST_MEMBER_INTVL',
- IFLA_BR_MCAST_MEMBERSHIP_INTVL : 'IFLA_BR_MCAST_MEMBERSHIP_INTVL',
- IFLA_BR_MCAST_QUERIER_INTVL : 'IFLA_BR_MCAST_QUERIER_INTVL',
- IFLA_BR_MCAST_QUERY_INTVL : 'IFLA_BR_MCAST_QUERY_INTVL',
- IFLA_BR_MCAST_QUERY_RESPONSE_INTVL : 'IFLA_BR_MCAST_QUERY_RESPONSE_INTVL',
- IFLA_BR_MCAST_STARTUP_QUERY_INTVL : 'IFLA_BR_MCAST_STARTUP_QUERY_INTVL',
- IFLA_BR_NF_CALL_IPTABLES : 'IFLA_BR_NF_CALL_IPTABLES',
- IFLA_BR_NF_CALL_IP6TABLES : 'IFLA_BR_NF_CALL_IP6TABLES',
- IFLA_BR_NF_CALL_ARPTABLES : 'IFLA_BR_NF_CALL_ARPTABLES',
- IFLA_BR_VLAN_DEFAULT_PVID : 'IFLA_BR_VLAN_DEFAULT_PVID',
- IFLA_BR_PAD : 'IFLA_BR_PAD',
- IFLA_BR_VLAN_STATS_ENABLED : 'IFLA_BR_VLAN_STATS_ENABLED',
- IFLA_BR_MCAST_STATS_ENABLED : 'IFLA_BR_MCAST_STATS_ENABLED',
- IFLA_BR_MCAST_IGMP_VERSION : 'IFLA_BR_MCAST_IGMP_VERSION',
- IFLA_BR_MCAST_MLD_VERSION : 'IFLA_BR_MCAST_MLD_VERSION'
- }
-
- # =========================================
- # IFLA_INFO_DATA attributes for vrfs
- # =========================================
- IFLA_VRF_UNSPEC = 0
- IFLA_VRF_TABLE = 1
-
- ifla_vrf_to_string = {
- IFLA_VRF_UNSPEC : 'IFLA_VRF_UNSPEC',
- IFLA_VRF_TABLE : 'IFLA_VRF_TABLE'
- }
-
- # ================================================================
- # IFLA_INFO_DATA attributes for (ip6)gre, (ip6)gretap, (ip6)erspan
- # ================================================================
- IFLA_GRE_UNSPEC = 0
- IFLA_GRE_LINK = 1
- IFLA_GRE_IFLAGS = 2
- IFLA_GRE_OFLAGS = 3
- IFLA_GRE_IKEY = 4
- IFLA_GRE_OKEY = 5
- IFLA_GRE_LOCAL = 6
- IFLA_GRE_REMOTE = 7
- IFLA_GRE_TTL = 8
- IFLA_GRE_TOS = 9
- IFLA_GRE_PMTUDISC = 10
- IFLA_GRE_ENCAP_LIMIT = 11
- IFLA_GRE_FLOWINFO = 12
- IFLA_GRE_FLAGS = 13
- IFLA_GRE_ENCAP_TYPE = 14
- IFLA_GRE_ENCAP_FLAGS = 15
- IFLA_GRE_ENCAP_SPORT = 16
- IFLA_GRE_ENCAP_DPORT = 17
- IFLA_GRE_COLLECT_METADATA = 18
- IFLA_GRE_IGNORE_DF = 19
- IFLA_GRE_FWMARK = 20
- IFLA_GRE_ERSPAN_INDEX = 21
- IFLA_GRE_ERSPAN_VER = 22
- IFLA_GRE_ERSPAN_DIR = 23
- IFLA_GRE_ERSPAN_HWID = 24
+ }
- ifla_gre_to_string = {
- IFLA_GRE_UNSPEC : "IFLA_GRE_UNSPEC",
- IFLA_GRE_LINK : "IFLA_GRE_LINK",
- IFLA_GRE_IFLAGS : "IFLA_GRE_IFLAGS",
- IFLA_GRE_OFLAGS : "IFLA_GRE_OFLAGS",
- IFLA_GRE_IKEY : "IFLA_GRE_IKEY",
- IFLA_GRE_OKEY : "IFLA_GRE_OKEY",
- IFLA_GRE_LOCAL : "IFLA_GRE_LOCAL",
- IFLA_GRE_REMOTE : "IFLA_GRE_REMOTE",
- IFLA_GRE_TTL : "IFLA_GRE_TTL",
- IFLA_GRE_TOS : "IFLA_GRE_TOS",
- IFLA_GRE_PMTUDISC : "IFLA_GRE_PMTUDISC",
- IFLA_GRE_ENCAP_LIMIT : "IFLA_GRE_ENCAP_LIMIT",
- IFLA_GRE_FLOWINFO : "IFLA_GRE_FLOWINFO",
- IFLA_GRE_FLAGS : "IFLA_GRE_FLAGS",
- IFLA_GRE_ENCAP_TYPE : "IFLA_GRE_ENCAP_TYPE",
- IFLA_GRE_ENCAP_FLAGS : "IFLA_GRE_ENCAP_FLAGS",
- IFLA_GRE_ENCAP_SPORT : "IFLA_GRE_ENCAP_SPORT",
- IFLA_GRE_ENCAP_DPORT : "IFLA_GRE_ENCAP_DPORT",
- IFLA_GRE_COLLECT_METADATA : "IFLA_GRE_COLLECT_METADATA",
- IFLA_GRE_IGNORE_DF : "IFLA_GRE_IGNORE_DF",
- IFLA_GRE_FWMARK : "IFLA_GRE_FWMARK",
- IFLA_GRE_ERSPAN_INDEX : "IFLA_GRE_ERSPAN_INDEX",
- IFLA_GRE_ERSPAN_VER : "IFLA_GRE_ERSPAN_VER",
- IFLA_GRE_ERSPAN_DIR : "IFLA_GRE_ERSPAN_DIR",
- IFLA_GRE_ERSPAN_HWID : "IFLA_GRE_ERSPAN_HWID",
+ # Subtype attrbutes AF_INET
+ IFLA_INET_UNSPEC = 0
+ IFLA_INET_CONF = 1
+ __IFLA_INET_MAX = 2
+
+ ifla_inet_af_spec_to_string = {
+ IFLA_INET_UNSPEC : 'IFLA_INET_UNSPEC',
+ IFLA_INET_CONF : 'IFLA_INET_CONF',
}
- # ===============================================
- # IFLA_INFO_DATA attributes for ipip, sit, ip6tnl
- # ===============================================
- IFLA_IPTUN_UNSPEC = 0
- IFLA_IPTUN_LINK = 1
- IFLA_IPTUN_LOCAL = 2
- IFLA_IPTUN_REMOTE = 3
- IFLA_IPTUN_TTL = 4
- IFLA_IPTUN_TOS = 5
- IFLA_IPTUN_ENCAP_LIMIT = 6
- IFLA_IPTUN_FLOWINFO = 7
- IFLA_IPTUN_FLAGS = 8
- IFLA_IPTUN_PROTO = 9
- IFLA_IPTUN_PMTUDISC = 10
- IFLA_IPTUN_6RD_PREFIX = 11
- IFLA_IPTUN_6RD_RELAY_PREFIX = 12
- IFLA_IPTUN_6RD_PREFIXLEN = 13
- IFLA_IPTUN_6RD_RELAY_PREFIXLEN = 14
- IFLA_IPTUN_ENCAP_TYPE = 15
- IFLA_IPTUN_ENCAP_FLAGS = 16
- IFLA_IPTUN_ENCAP_SPORT = 17
- IFLA_IPTUN_ENCAP_DPORT = 18
- IFLA_IPTUN_COLLECT_METADATA = 19
- IFLA_IPTUN_FWMARK = 20
+ # BRIDGE IFLA_AF_SPEC attributes
+ IFLA_BRIDGE_FLAGS = 0
+ IFLA_BRIDGE_MODE = 1
+ IFLA_BRIDGE_VLAN_INFO = 2
- ifla_iptun_to_string = {
- IFLA_IPTUN_UNSPEC : "IFLA_IPTUN_UNSPEC",
- IFLA_IPTUN_LINK : "IFLA_IPTUN_LINK",
- IFLA_IPTUN_LOCAL : "IFLA_IPTUN_LOCAL",
- IFLA_IPTUN_REMOTE : "IFLA_IPTUN_REMOTE",
- IFLA_IPTUN_TTL : "IFLA_IPTUN_TTL",
- IFLA_IPTUN_TOS : "IFLA_IPTUN_TOS",
- IFLA_IPTUN_ENCAP_LIMIT : "IFLA_IPTUN_ENCAP_LIMIT",
- IFLA_IPTUN_FLOWINFO : "IFLA_IPTUN_FLOWINFO",
- IFLA_IPTUN_FLAGS : "IFLA_IPTUN_FLAGS",
- IFLA_IPTUN_PROTO : "IFLA_IPTUN_PROTO",
- IFLA_IPTUN_PMTUDISC : "IFLA_IPTUN_PMTUDISC",
- IFLA_IPTUN_6RD_PREFIX : "IFLA_IPTUN_6RD_PREFIX",
- IFLA_IPTUN_6RD_RELAY_PREFIX : "IFLA_IPTUN_6RD_RELAY_PREFIX",
- IFLA_IPTUN_6RD_PREFIXLEN : "IFLA_IPTUN_6RD_PREFIXLEN",
- IFLA_IPTUN_6RD_RELAY_PREFIXLEN : "IFLA_IPTUN_6RD_RELAY_PREFIXLEN",
- IFLA_IPTUN_ENCAP_TYPE : "IFLA_IPTUN_ENCAP_TYPE",
- IFLA_IPTUN_ENCAP_FLAGS : "IFLA_IPTUN_ENCAP_FLAGS",
- IFLA_IPTUN_ENCAP_SPORT : "IFLA_IPTUN_ENCAP_SPORT",
- IFLA_IPTUN_ENCAP_DPORT : "IFLA_IPTUN_ENCAP_DPORT",
- IFLA_IPTUN_COLLECT_METADATA : "IFLA_IPTUN_COLLECT_METADATA",
- IFLA_IPTUN_FWMARK : "IFLA_IPTUN_FWMARK",
+ ifla_bridge_af_spec_to_string = {
+ IFLA_BRIDGE_FLAGS : 'IFLA_BRIDGE_FLAGS',
+ IFLA_BRIDGE_MODE : 'IFLA_BRIDGE_MODE',
+ IFLA_BRIDGE_VLAN_INFO : 'IFLA_BRIDGE_VLAN_INFO'
}
- # =========================================
- # IFLA_INFO_DATA attributes for vti, vti6
- # =========================================
- IFLA_VTI_UNSPEC = 0
- IFLA_VTI_LINK = 1
- IFLA_VTI_IKEY = 2
- IFLA_VTI_OKEY = 3
- IFLA_VTI_LOCAL = 4
- IFLA_VTI_REMOTE = 5
- IFLA_VTI_FWMARK = 6
+ # BRIDGE_VLAN_INFO flags
+ BRIDGE_VLAN_INFO_MASTER = 1 << 0 # Operate on Bridge device as well
+ BRIDGE_VLAN_INFO_PVID = 1 << 1 # VLAN is PVID, ingress untagged
+ BRIDGE_VLAN_INFO_UNTAGGED = 1 << 2 # VLAN egresses untagged
+ BRIDGE_VLAN_INFO_RANGE_BEGIN = 1 << 3 # VLAN is start of vlan range
+ BRIDGE_VLAN_INFO_RANGE_END = 1 << 4 # VLAN is end of vlan range
+ BRIDGE_VLAN_INFO_BRENTRY = 1 << 5 # Global bridge VLAN entry
- ifla_vti_to_string = {
- IFLA_VTI_UNSPEC : "IFLA_VTI_UNSPEC",
- IFLA_VTI_LINK : "IFLA_VTI_LINK",
- IFLA_VTI_IKEY : "IFLA_VTI_IKEY",
- IFLA_VTI_OKEY : "IFLA_VTI_OKEY",
- IFLA_VTI_LOCAL : "IFLA_VTI_LOCAL",
- IFLA_VTI_REMOTE : "IFLA_VTI_REMOTE",
- IFLA_VTI_FWMARK : "IFLA_VTI_FWMARK",
+ bridge_vlan_to_string = {
+ BRIDGE_VLAN_INFO_MASTER : 'BRIDGE_VLAN_INFO_MASTER',
+ BRIDGE_VLAN_INFO_PVID : 'BRIDGE_VLAN_INFO_PVID',
+ BRIDGE_VLAN_INFO_UNTAGGED : 'BRIDGE_VLAN_INFO_UNTAGGED',
+ BRIDGE_VLAN_INFO_RANGE_BEGIN : 'BRIDGE_VLAN_INFO_RANGE_BEGIN',
+ BRIDGE_VLAN_INFO_RANGE_END : 'BRIDGE_VLAN_INFO_RANGE_END',
+ BRIDGE_VLAN_INFO_BRENTRY : 'BRIDGE_VLAN_INFO_BRENTRY'
+ }
+
+ # Bridge flags
+ BRIDGE_FLAGS_MASTER = 1
+ BRIDGE_FLAGS_SELF = 2
+
+ bridge_flags_to_string = {
+ BRIDGE_FLAGS_MASTER : 'BRIDGE_FLAGS_MASTER',
+ BRIDGE_FLAGS_SELF : 'BRIDGE_FLAGS_SELF'
+ }
+
+ # filters for IFLA_EXT_MASK
+ RTEXT_FILTER_VF = 1 << 0
+ RTEXT_FILTER_BRVLAN = 1 << 1
+ RTEXT_FILTER_BRVLAN_COMPRESSED = 1 << 2
+ RTEXT_FILTER_SKIP_STATS = 1 << 3
+
+ rtext_to_string = {
+ RTEXT_FILTER_VF : 'RTEXT_FILTER_VF',
+ RTEXT_FILTER_BRVLAN : 'RTEXT_FILTER_BRVLAN',
+ RTEXT_FILTER_BRVLAN_COMPRESSED : 'RTEXT_FILTER_BRVLAN_COMPRESSED',
+ RTEXT_FILTER_SKIP_STATS : 'RTEXT_FILTER_SKIP_STATS'
}
def __init__(self, msgtype, debug=False, logger=None, use_color=True):
def get_ifla_vxlan_string(self, index):
return self.get_string(self.ifla_vxlan_to_string, index)
+ def get_ifla_vrf_string(self, index):
+ return self.get_string(self.ifla_vrf_to_string, index)
+
+ def get_ifla_bond_slave_string(self, index):
+ return self.get_string(self.ifla_bond_slave_to_string, index)
+
def get_ifla_macvlan_string(self, index):
return self.get_string(self.ifla_macvlan_to_string, index)
- def get_ifla_xfrm_string(self, index):
- return self.get_string(self.ifla_xfrm_to_string, index)
-
def get_macvlan_mode_string(self, index):
return self.get_string(self.macvlan_mode_to_string, index)
return False
+class AttributeMDBA_MDB(Attribute):
+ """
+ /* Bridge multicast database attributes
+ * [MDBA_MDB] = {
+ * [MDBA_MDB_ENTRY] = {
+ * [MDBA_MDB_ENTRY_INFO] {
+ * struct br_mdb_entry
+ * [MDBA_MDB_EATTR attributes]
+ * }
+ * }
+ * }
+ """
+ """
+ Current we support only MDB Dump and no MDB_GET.
+ The code has been written to handle multiple entries in a single msg.
+ data -- alignment
+ MDBA_MDB ===> data[0:4]
+ MDBA_MDB_ENTRY ===> data[4:8]
+ MDBA_MDB_ENTRY_INFO ===> data[8:12]
+ br_mdb_entry -- ===> ifindex data[12:16]
+ -- ===> state,flags,vide data[16:20]
+ -- ===> ip_addr data[20:36]
+ -- ===> proto data[36:40]
+ -- ===> MDB_MDB_EATTR_TIMER data[40:44]
+ -- Timer Value data[44:48]
+ """
+
+ def __init__(self, atype, string, family, logger):
+ Attribute.__init__(self, atype, string, logger)
+
+ def decode(self, parent_msg, data):
+ self.decode_length_type(data)
+
+ data = self.data[4:]
+ if parent_msg.msgtype == RTM_GETMDB:
+ self.value = []
+ while data:
+ (sub_attr_length, sub_attr_type) = unpack('=HH', data[:4])
+ sub_attr_end = padded_length(sub_attr_length)
+ sub_attr_data = data[4:sub_attr_end]
+
+ mdb_entry = {}
+ mdb_entry[MDB.MDBA_MDB_ENTRY] = []
+ if not sub_attr_length:
+ self.log.error('parsed a zero length sub-attr')
+ return
+
+ if sub_attr_type == MDB.MDBA_MDB_ENTRY:
+ while sub_attr_data:
+ nested_mdb_entry = {}
+ (nested_attr_length,nested_attr_type) = unpack('=HH',sub_attr_data[:4])
+ nested_attr_end = padded_length(nested_attr_length)
+ if nested_attr_type == MDB.MDBA_MDB_ENTRY_INFO:
+ (ifindex, state, flags, vid) = unpack('=LBBH',sub_attr_data[4:12])
+ info = [ifindex,state,flags,vid]
+ proto = unpack('=H',sub_attr_data[28:30])[0]
+ if proto == htons(ETH_P_IP):
+ ip_addr = IPv4Address(unpack('>L', sub_attr_data[12:16])[0])
+ else:
+ (data1, data2) = unpack('>QQ',sub_attr_data[12:28])
+ ip_addr = IPv6Address(data1 << 64 | data2)
+
+ info.append(ip_addr)
+
+ try:
+ (timer_attr_length,timer_attr_type) = unpack('=HH',sub_attr_data[32:36])
+ if(timer_attr_type ) == MDB.MDBA_MDB_EATTR_TIMER:
+ info.append({MDB.MDBA_MDB_EATTR_TIMER: (unpack('=I',sub_attr_data[36:40])[0])*0.01})
+ except struct.error:
+ self.log.error('No TimerAttribute')
+ nested_mdb_entry[MDB.MDBA_MDB_ENTRY] = info
+ mdb_entry[MDB.MDBA_MDB_ENTRY].append(nested_mdb_entry)
+ sub_attr_data = sub_attr_data[nested_attr_end:]
+ self.value.append(mdb_entry)
+ data = data[sub_attr_end:]
+
+ else:
+ self.value = {}
+ while data:
+ (sub_attr_length, sub_attr_type) = unpack('=HH', data[:4])
+ sub_attr_end = padded_length(sub_attr_length)
+ sub_attr_data = data[4:]
+ if not sub_attr_length:
+ self.log.error('parsed a zero length sub-attr')
+ return
+
+ if sub_attr_type == MDB.MDBA_MDB_ENTRY:
+ (nested_attr_length,nested_attr_type) = unpack('=HH',sub_attr_data[:4])
+ if nested_attr_type == MDB.MDBA_MDB_ENTRY_INFO:
+ self.value[MDB.MDBA_MDB_ENTRY] = {}
+ (ifindex,state,flags,vid) = unpack('=LBBH',sub_attr_data[4:12])
+ info = (ifindex,state,flags,vid)
+ info = list(info)
+ proto = unpack('=H',sub_attr_data[28:30])[0]
+ if proto == 8:
+ ip_addr = IPv4Address(unpack('>L', sub_attr_data[12:16])[0])
+ else:
+ (data1, data2) = unpack('>QQ',sub_attr_data[12:28])
+ ip_addr = IPv6Address(data1 << 64 | data2)
+
+ info.append(ip_addr)
+ self.value[MDB.MDBA_MDB_ENTRY][MDB.MDBA_MDB_ENTRY_INFO] = info
+ data = data[sub_attr_end:]
+
+ def dump_lines(self, dump_buffer, line_number, color):
+ line_number = self.dump_first_line(dump_buffer, line_number, color)
+
+ dump_buffer.append(data_to_color_text(line_number, color, self.data[0:4], self.value))
+ return line_number + 1
+
+
+
+class AttributeMDBA_ROUTER(Attribute):
+ """
+ /*
+ * [MDBA_ROUTER] = {
+ * [MDBA_ROUTER_PORT] = {
+ * u32 ifindex
+ * [MDBA_ROUTER_PATTR attributes]
+ * }
+ * }
+ */
+ """
+
+ def __init__(self, atype, string, family, logger):
+ Attribute.__init__(self, atype, string, logger)
+
+ def decode(self, parent_msg, data):
+ self.decode_length_type(data)
+ data = self.data[4:]
+ if parent_msg.msgtype == RTM_GETMDB:
+ self.value = []
+ while data:
+ (sub_attr_length, sub_attr_type) = unpack('=HH', data[:4])
+ sub_attr_end = padded_length(sub_attr_length)
+ sub_attr_data = data[4:sub_attr_end]
+ router_entry = {}
+
+ if not sub_attr_length:
+ self.log.error('parsed a zero length sub-attr')
+ return
+
+ if sub_attr_type == MDB.MDBA_ROUTER_PORT:
+ ifindex = unpack('=I',sub_attr_data[:4])[0]
+ sub_attr_data = sub_attr_data[4:]
+ timer_info = {}
+ type_info = {}
+ while sub_attr_data:
+ (nested_sub_attr_length, nested_sub_attr_type) = unpack('=HH',sub_attr_data[:4])
+ nested_sub_attr_data = sub_attr_data[4:]
+ nested_sub_attr_end = padded_length(nested_sub_attr_length)
+ if nested_sub_attr_type == MDB.MDBA_ROUTER_PATTR_TIMER:
+ timer_info[MDB.MDBA_ROUTER_PATTR_TIMER] = (unpack('=L',nested_sub_attr_data[ :4])[0])*0.01
+ elif nested_sub_attr_type == MDB.MDBA_ROUTER_PATTR_TYPE:
+ type_info[MDB.MDBA_ROUTER_PATTR_TYPE] = unpack('=B',nested_sub_attr_data[:1])[0]
+ else:
+ raise Exception("Invalid Router Port Attribute")
+ sub_attr_data = sub_attr_data[nested_sub_attr_end:]
+ router_entry[MDB.MDBA_ROUTER_PORT] = [ifindex,timer_info,type_info]
+
+ self.value.append(router_entry)
+ data = data[sub_attr_end:]
+
+ else:
+ self.value = {}
+ while data:
+ (sub_attr_length, sub_attr_type) = unpack('=HH', data[:4])
+ sub_attr_end = padded_length(sub_attr_length)
+ sub_attr_data = data[4:]
+
+ if not sub_attr_length:
+ self.log.error('parsed a zero length sub-attr')
+ return
+
+ if sub_attr_type == MDB.MDBA_ROUTER_PORT:
+ ifindex = unpack('=L',sub_attr_data[:4])[0]
+ self.value[MDB.MDBA_ROUTER_PORT] = ifindex
+ data = data[sub_attr_end:]
+
+ def dump_lines(self, dump_buffer, line_number, color):
+ line_number = self.dump_first_line(dump_buffer, line_number, color)
+
+ dump_buffer.append(data_to_color_text(line_number, color, self.data[0:4], self.value))
+ return line_number + 1
+
+
+class AttributeMDBA_SET_ENTRY(Attribute):
+
+ def __init__(self, atype, string, family, logger):
+ Attribute.__init__(self, atype, string, logger)
+ self.PACK = None
+ self.LEN = None
+
+ def set_value(self, value):
+ self.value = value
+
+
+ def encode(self):
+ if self.value:
+ (ifindex, flags, state,vid, ip, proto) = self.value
+ if proto == htons(ETH_P_IP):
+ self.PACK = '=IBBHLxxxxxxxxxxxxHxx'
+ reorder = unpack('<L', ip.packed)[0]
+ ip = IPv4Address(reorder)
+
+ self.LEN = calcsize(self.PACK)
+ length = self.HEADER_LEN + self.LEN
+ #TODO Please check the encoding for Ipv6
+ raw = pack(self.HEADER_PACK, length, self.atype) + pack(self.PACK, ifindex, flags, state, vid, ip, proto)
+ elif proto == htons(ETH_P_IPV6):
+ self.PACK = '=IBBHQQHxx'
+ (data1, data2) = unpack('<QQ', ip.packed)
+ self.LEN = calcsize(self.PACK)
+ length = self.HEADER_LEN + self.LEN
+ raw = pack(self.HEADER_PACK, length, self.atype) + pack(self.PACK, ifindex, flags, state, vid, data1,data2, proto)
+
+ else:
+ raise Exception("%d Invalid Proto" % proto)
+ raw = self.pad(length, raw)
+ return raw
+
+
+ def decode(self, parent_msg, data):
+ self.decode_length_type(data)
+ if self.length == 32:
+ proto = unpack('=H', data[28:30])[0]
+ if proto == htons(ETH_P_IP):
+ self.PACK = '=IBBHLxxxxxxxxxxxxHxx'
+ (ifindex, flags, state,vid, ip, proto) = unpack(self.PACK, self.data[4:])
+ elif proto == htons(ETH_P_IPV6):
+ self.PACK = '=IBBHQQHxx'
+ (ifindex, flags, state,vid, data1,data2, proto) = unpack(self.PACK, self.data[4:])
+ ip = IPv6Address(data1 << 64 | data2)
+ else:
+ raise Exception("%d Invalid Proto" % proto)
+ self.LEN = calcsize(self.PACK)
+ self.value = (ifindex, flags, state,vid, ip, proto)
+ else:
+ raise Exception("Invalid Attribute Length")
+
+
+
+class MDB(NetlinkPacket):
+ """
+ Service Header
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Family | Reserved1 | Reserved2 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Interface Index |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ struct br_port_msg {
+ __u8 family;
+ __u32 ifindex;
+ };
+
+ RTM_GETMDB - Service Header
+
+ /* Bridge multicast database attributes
+ * [MDBA_MDB] = {
+ * [MDBA_MDB_ENTRY] = {
+ * [MDBA_MDB_ENTRY_INFO] {
+ * struct br_mdb_entry
+ * [MDBA_MDB_EATTR attributes]
+ * }
+ * }
+ * }
+ * [MDBA_ROUTER] = {
+ * [MDBA_ROUTER_PORT] = {
+ * u32 ifindex
+ * [MDBA_ROUTER_PATTR attributes]
+ * }
+ * }
+ */
+
+ struct br_mdb_entry {
+ __u32 ifindex;
+ #define MDB_TEMPORARY 0
+ #define MDB_PERMANENT 1
+ __u8 state;
+ #define MDB_FLAGS_OFFLOAD (1 << 0)
+ #define MDB_FLAGS_FAST_LEAVE (1 << 1)
+ __u8 flags;
+ __u16 vid;
+ struct {
+ union {
+ __be32 ip4;
+ struct in6_addr ip6;
+ } u;
+ __be16 proto;
+ } addr;
+ };
+ """
+ MDBA_UNSPEC = 0
+ MDBA_MDB = 1
+ MDBA_ROUTER = 2
+ __MDBA_MAX = 3
+ MDBA_MAX = (__MDBA_MAX - 1)
+
+ #MDBA Set Attributes
+ MDBA_SET_ENTRY_UNSPEC = 0
+ MDBA_SET_ENTRY = 1
+ __MDBA_SET_ENTRY_MAX = 2
+ MDBA_SET_ENTRY_MAX = (__MDBA_SET_ENTRY_MAX - 1)
+
+ #MDBA flags
+ MDB_FLAGS_OFFLOAD = 1 << 0
+ MDB_FLAGS_FAST_LEAVE = 1 << 1
+
+ #MDBA Attributes
+ MDBA_MDB_UNSPEC = 0
+ MDBA_MDB_ENTRY = 1
+ __MDBA_MDB_MAX = 2
+ MDBA_MDB_MAX = (__MDBA_MDB_MAX - 1)
+
+ MDBA_MDB_ENTRY_UNSPEC = 0
+ MDBA_MDB_ENTRY_INFO = 1
+ __MDBA_MDB_ENTRY_MAX = 2
+ MDBA_MDB_ENTRY_MAX = (__MDBA_MDB_ENTRY_MAX - 1)
+
+ MDBA_MDB_EATTR_UNSPEC = 0
+ MDBA_MDB_EATTR_TIMER = 1
+ __MDBA_MDB_EATTR_MAX = 2
+ MDBA_MDB_ENTRY_MAX = (__MDBA_MDB_EATTR_MAX -1)
+
+ # router port attributes
+ MDBA_ROUTER_UNSPEC = 0
+ MDBA_ROUTER_PORT = 1
+ __MDBA_ROUTER_MAX = 2
+ MDBA_ROUTER_MAX = (__MDBA_ROUTER_MAX - 1)
+
+
+ MDBA_ROUTER_PATTR_UNSPEC = 0
+ MDBA_ROUTER_PATTR_TIMER = 1
+ MDBA_ROUTER_PATTR_TYPE = 2
+ __MDBA_ROUTER_PATTR_MAX = 3
+ MDBA_ROUTER_PATTR_MAX = (__MDBA_ROUTER_PATTR_MAX - 1)
+
+ MDB_RTR_TYPE_DISABLED = 0
+ MDB_RTR_TYPE_TEMP_QUERY = 1
+ MDB_RTR_TYPE_PERM = 2
+ MDB_RTR_TYPE_TEMP = 3
+
+
+ def __init__(self, msgtype, debug=False, logger=None, use_color=True, rx=False, tx=False):
+ NetlinkPacket.__init__(self, msgtype, debug, logger, use_color, rx, tx)
+ if self.tx and msgtype in (RTM_NEWMDB, RTM_DELMDB):
+ self.attribute_to_class = {
+ self.MDBA_UNSPEC: ('MDBA_SET_ENTRY_UNSPEC', AttributeGeneric),
+ self.MDBA_SET_ENTRY: ('MDBA_SET_ENTRY', AttributeMDBA_SET_ENTRY),
+ }
+ else:
+ self.attribute_to_class = {
+ self.MDBA_UNSPEC: ('MDBA_UNSPEC', AttributeGeneric),
+ self.MDBA_MDB: ('MDBA_MDB', AttributeMDBA_MDB),
+ self.MDBA_ROUTER: ('MDBA_ROUTER', AttributeMDBA_ROUTER),
+ }
+
+ self.PACK = 'Bxxxi'
+ self.LEN = calcsize(self.PACK)
+
+ def decode_service_header(self):
+ # Nothing to do if the message did not contain a service header
+ if self.length == self.header_LEN:
+ return
+
+ (self.family,self.ifindex) = unpack(self.PACK, self.msg_data[:self.LEN])
+ if self.debug:
+ color = yellow if self.use_color else None
+ color_start = "\033[%dm" % color if color else ""
+ color_end = "\033[0m" if color else ""
+ self.dump_buffer.append(" %sService Header%s" % (color_start, color_end))
+ self.dump_buffer.append(self.msg_data)
+ self.dump_buffer.append(data_to_color_text(1, color, bytearray(struct.pack('!I', self.family)),
+ "Family %s (%d)" % (zfilled_hex(self.family, 2), self.family)))
+ self.dump_buffer.append(data_to_color_text(2, color, bytearray(struct.pack('i', self.ifindex)),
+ "Ifindex %s (%d)" % (zfilled_hex(self.ifindex, 8), self.ifindex)))
+
class Netconf(Link):
"""
RTM_NEWNETCONF - Service Header
NETCONFA_PROXY_NEIGH = 5
NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN = 6
NETCONFA_INPUT = 7
- __NETCONFA_MAX = 8
+ NETCONFA_BC_FORWARDING = 8
+ __NETCONFA_MAX = 9
NETCONFA_MAX = (__NETCONFA_MAX - 1)
NETCONFA_PROXY_NEIGH : ('NETCONFA_PROXY_NEIGH', AttributeFourByteValue),
NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN : ('NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN', AttributeFourByteValue),
NETCONFA_INPUT : ('NETCONFA_INPUT', AttributeFourByteValue),
+ NETCONFA_BC_FORWARDING : ('NETCONFA_BC_FORWARDING', AttributeFourByteValue),
}
def __init__(self, msgtype, debug=False, logger=None, use_color=True):
if msgtype == RTM_GETNETCONF: # same as RTM_GETLINK
self.PACK = 'BxHiII'
self.LEN = calcsize(self.PACK)
- elif msgtype == RTM_NEWNETCONF:
+ else:
+ # RTM_NEWNETCONF
+ # RTM_DELNETCONF
self.PACK = 'Bxxx'
self.LEN = calcsize(self.PACK)
if self.msgtype == RTM_GETNETCONF:
super(Netconf, self).decode_service_header()
- elif self.msgtype == RTM_NEWNETCONF:
+ else:
+ # RTM_NEWNETCONF
+ # RTM_DELNETCONF
(self.family,) = unpack(self.PACK, self.msg_data[:self.LEN])
if self.debug:
self.dump_buffer.append(data_to_color_text(self.line_number, color, self.msg_data[start:end], extra))
self.line_number += 1
+
class Done(NetlinkPacket):
"""
NLMSG_DONE
+++ /dev/null
-#!/usr/bin/python
-#
-# Copyright 2017 Cumulus Networks, Inc. All rights reserved.
-# Authors:
-# Roopa Prabhu, roopa@cumulusnetworks.com
-# Julien Fortin, julien@cumulusnetworks.com
-#
-# ifupdown2 --
-# tool to configure network interfaces
-#
-
-import os
-import re
-import json
-import fcntl
-import struct
-import signal
-import socket
-import daemon
-import select
-import datetime
-import threading
-
-try:
- import ifupdown2.ifupdown.argv
-
- from ifupdown2.ifupdown.log import log
- from ifupdown2.ifupdown.main import Ifupdown2
-except ImportError:
- import ifupdown.argv
-
- from ifupdown.log import log
- from ifupdown.main import Ifupdown2
-
-
-class Daemon:
- shutdown_event = threading.Event()
-
- def __init__(self):
- self.uds = None
- self.context = None
- self.working_directory = '/var/run/ifupdown2d/'
- self.server_address = '/var/run/ifupdown2d/uds'
-
- if not os.path.exists(self.working_directory):
- log.info('creating %s' % self.working_directory)
- os.makedirs(self.working_directory, mode=0755)
-
- if os.path.exists(self.server_address):
- log.info('removing uds %s' % self.server_address)
- os.remove(self.server_address)
-
- self.context = daemon.DaemonContext(
- working_directory=self.working_directory,
- signal_map={
- signal.SIGINT: self.signal_handler,
- signal.SIGTERM: self.signal_handler,
- signal.SIGQUIT: self.signal_handler,
- },
- umask=0o22
- )
-
- try:
- self.SO_PEERCRED = socket.SO_PEERCRED
- except AttributeError:
- # powerpc is the only non-generic we care about. alpha, mips,
- # sparc, and parisc also have non-generic values.
- machine = os.uname()[4]
- if re.search(r'^(ppc|powerpc)', machine):
- self.SO_PASSCRED = 20
- self.SO_PEERCRED = 21
- else:
- self.SO_PASSCRED = 16
- self.SO_PEERCRED = 17
-
- log.info('daemonizing ifupdown2d...')
- self.context.open()
-
- log.info('preloading all necessary modules')
- self.preload_imports()
-
- try:
- log.info('opening UNIX socket')
- self.uds = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
- fcntl.fcntl(self.uds.fileno(), fcntl.F_SETFD, fcntl.FD_CLOEXEC)
- except Exception as e:
- raise Exception('socket: %s' % str(e))
- try:
- self.uds.bind(self.server_address)
- except Exception as e:
- raise Exception('bind: %s' % str(e))
- try:
- self.uds.setsockopt(socket.SOL_SOCKET, self.SO_PASSCRED, 1)
- except Exception as e:
- raise Exception('setsockopt: %s' % str(e))
- try:
- self.uds.listen(1)
- except Exception as e:
- raise Exception('listen: %s' % str(e))
- os.chmod(self.server_address, 0777)
-
- def __del__(self):
- if self.context:
- self.context.close()
- if self.uds:
- self.uds.close()
-
- @staticmethod
- def preload_imports():
- """
- preloading all the necessary modules
- at first will increase performances
- """
- try:
- import io
- import pdb
- import imp
- import sets
- import json
- import glob
- import time
- import copy
- import errno
- import pprint
- import atexit
- import ipaddr
- import cPickle
- import logging
- import argparse
- import StringIO
- import datetime
- import traceback
- import itertools
- import subprocess
- import argcomplete
- import collections
- import ConfigParser
- import pkg_resources
-
- import ifupdown2.ifupdown.exceptions
- import ifupdown2.ifupdown.graph
- import ifupdown2.ifupdown.iface
- import ifupdown2.ifupdown.iff
- import ifupdown2.ifupdown.ifupdownbase
- import ifupdown2.ifupdown.ifupdownbase
- import ifupdown2.ifupdown.ifupdownconfig
- import ifupdown2.ifupdown.ifupdownflags
- import ifupdown2.ifupdown.ifupdownmain
- import ifupdown2.ifupdown.netlink
- import ifupdown2.ifupdown.networkinterfaces
- import ifupdown2.ifupdown.policymanager
- import ifupdown2.ifupdown.scheduler
- import ifupdown2.ifupdown.statemanager
- import ifupdown2.ifupdown.template
- import ifupdown2.ifupdown.utils
-
- import ifupdown2.ifupdownaddons.cache
- import ifupdown2.ifupdownaddons.dhclient
- import ifupdown2.ifupdownaddons.mstpctlutil
- import ifupdown2.ifupdownaddons.LinkUtils
- import ifupdown2.ifupdownaddons.modulebase
- import ifupdown2.ifupdownaddons.systemutils
- import ifupdown2.ifupdownaddons.utilsbase
- except ImportError, e:
- raise ImportError('%s - required module not found' % str(e))
-
- @staticmethod
- def signal_handler(sig, frame):
- log.info('received %s' % 'SIGINT' if sig == signal.SIGINT else 'SIGTERM')
- Daemon.shutdown_event.set()
-
- @staticmethod
- def user_waiting_for_reply():
- return not log.is_syslog()
-
- def run(self):
- try:
- while True:
- if Daemon.shutdown_event.is_set():
- log.info("shutdown signal RXed, breaking out loop")
- break
-
- try:
- (client_socket, client_address) = self.uds.accept()
- except socket.error as e:
- log.error(str(e))
- break
-
- pid = os.fork()
- if pid == 0:
- exit(self.ifupdown2(client_socket))
- else:
- log.tx_data(json.dumps({'pid': pid}), socket=client_socket)
-
- start = datetime.datetime.now()
- status = os.WEXITSTATUS(os.waitpid(pid, 0)[1])
- end = datetime.datetime.now()
-
- log.tx_data(json.dumps({'status': status}), socket=client_socket)
- client_socket.close()
-
- log.info('exit status %d - in %ssecs'
- % (status, (end - start).total_seconds()))
-
- except Exception as e:
- log.error(e)
- self.uds.close()
-
- def get_client_uid(self, client_socket):
- creds = client_socket.getsockopt(socket.SOL_SOCKET, self.SO_PEERCRED, struct.calcsize('3i'))
- (pid, uid, gid) = struct.unpack('3i', creds)
- log.debug('client uid %d' % uid)
- return uid
-
- @staticmethod
- def get_client_request(client_socket):
- """
- This function handles requests of any length.
-
- if the received json is longer than 65k it will be truncated
- several calls to recv will be needed, we store the data until
- we can decode them with the json library.
- """
- data = []
- while True:
- log.debug('waiting for request on client socket')
- ready = select.select([client_socket], [], [])
-
- if ready and ready[0] and ready[0][0] == client_socket:
- # data available start reading
- raw_data = client_socket.recv(65536)
-
- try:
- return json.loads(raw_data)
- except ValueError:
- # the json is incomplete
- data.append(raw_data)
-
- if len(data) > 1:
- try:
- return json.loads(''.join(data))
- except ValueError:
- pass
-
- def ifupdown2(self, client_socket):
- try:
- fcntl.fcntl(client_socket.fileno(), fcntl.F_SETFD, fcntl.FD_CLOEXEC)
-
- ifupdown2 = Ifupdown2(daemon=True, uid=self.get_client_uid(client_socket))
- ifupdown2.set_signal_handlers()
-
- request = self.get_client_request(client_socket)
- log.info('request: %s' % request['argv'])
-
- ifupdown2.parse_argv(request['argv'])
- # adjust the logger with argv
- ifupdown2.update_logger(socket=client_socket)
-
- try:
- status = ifupdown2.main(request['stdin'])
- except Exception as e:
- log.error(str(e))
- status = 1
-
- except ifupdown2.ifupdown.argv.ArgvParseError as e:
- log.update_current_logger(syslog=False, verbose=True, debug=False)
- log.set_socket(client_socket)
- e.log_error()
- status = 1
- except Exception as e:
- log.error(e)
- status = 1
-
- log.flush()
- log.set_socket(None)
- client_socket.close()
- return status
-
-
-if __name__ == '__main__':
- try:
- Daemon().run()
- except Exception as e:
- print e
- log.error(str(e))
- import traceback
- log.error(traceback.format_exc())
- exit(1)
+++ /dev/null
-#!/bin/bash
-
-# This replaces the old init.d script, and is run from the networking.service
-# Only has start, stop, reload, because that's all systemd has.
-# restart is implemented in systemd by stop then start.
-
-RUN_DIR="/run/network"
-IFSTATE_LOCKFILE="${RUN_DIR}/ifstatelock"
-
-STATE_DIR="/var/tmp/network"
-IFSTATE_FILE="${STATE_DIR}/ifstatenew"
-
-NAME=networking
-
-[ -x /sbin/ifup ] || exit 0
-[ -x /sbin/ifdown ] || exit 0
-
-CONFIGURE_INTERFACES=yes
-
-EXTRA_ARGS=
-
-[ -f /etc/default/networking ] && . /etc/default/networking
-
-[ "$VERBOSE" = yes ] && EXTRA_ARGS=-v
-[ "$DEBUG" = yes ] && EXTRA_ARGS="$EXTRA_ARGS -d"
-[ "$SYSLOG" = yes ] && EXTRA_ARGS="$EXTRA_ARGS --syslog"
-
-perf_options() {
- # At bootup lets set perfmode
- [ -f ${IFSTATE_LOCKFILE} ] && echo -n "" && return
-
- echo -n "--perfmode"
-}
-
-process_exclusions() {
- set -- $EXCLUDE_INTERFACES
- exclusions=""
- for d
- do
- exclusions="-X $d $exclusions"
- done
- echo $exclusions
-}
-
-check_network_file_systems() {
- [ -e /proc/mounts ] || return 0
-
- if [ -e /etc/iscsi/iscsi.initramfs ]; then
- echo ${NAME}':' "not deconfiguring network interfaces: iSCSI root is mounted."
- exit 0
- fi
-
- while read DEV MTPT FSTYPE REST; do
- case $DEV in
- /dev/nbd*|/dev/nd[a-z]*|/dev/etherd/e*)
- echo ${NAME}':' "not deconfiguring network interfaces: network devices still mounted."
- exit 0
- ;;
- esac
- case $FSTYPE in
- nfs|nfs4|smbfs|ncp|ncpfs|cifs|coda|ocfs2|gfs|pvfs|pvfs2|fuse.httpfs|fuse.curlftpfs)
- echo ${NAME}':' "not deconfiguring network interfaces: network file systems still mounted."
- exit 0
- ;;
- esac
- done < /proc/mounts
-}
-
-check_network_swap() {
- [ -e /proc/swaps ] || return 0
-
- while read DEV MTPT FSTYPE REST; do
- case $DEV in
- /dev/nbd*|/dev/nd[a-z]*|/dev/etherd/e*)
- echo ${NAME}':' "not deconfiguring network interfaces: network swap still mounted."
- exit 0
- ;;
- esac
- done < /proc/swaps
-}
-
-ifup_hotplug () {
- if [ -d /sys/class/net ]
- then
- ifaces=$(for iface in $(ifquery --list --allow=hotplug 2>/dev/null)
- do
- link=${iface##:*}
- link=${link##.*}
- if [ -e "/sys/class/net/$link" ]
- then
- echo "$iface"
- fi
- done)
- if [ -n "$ifaces" ]
- then
- ifup $ifaces "$@" || true
- fi
- fi
-}
-
-ifup_mgmt () {
- ifaces=$(ifquery --list --allow=mgmt 2>/dev/null)
- if [ -n "$ifaces" ]; then
- echo "bringing up mgmt class interfaces"
- ifup --allow=mgmt
- fi
-}
-
-ifupdown_init() {
- # remove state file at boot
- [ ! -e ${IFSTATE_LOCKFILE} ] && rm -f ${IFSTATE_FILE}
-
- [ ! -e /run/network ] && mkdir -p /run/network &>/dev/null
- [ ! -e /etc/network/run ] && \
- ln -sf /run/network /etc/network/run &>/dev/null
-}
-
-case "$1" in
-start)
- ifupdown_init
- if [ "$CONFIGURE_INTERFACES" = no ]
- then
- echo ${NAME}':' "Not configuring network interfaces, see /etc/default/networking"
- exit 0
- fi
- set -f
- exclusions=$(process_exclusions)
- perfoptions=$(perf_options)
- echo ${NAME}':' "Configuring network interfaces"
- ifup_mgmt
- ifup -a $EXTRA_ARGS $exclusions $perfoptions
- ifup_hotplug $HOTPLUG_ARGS $EXTRA_ARGS $exclusions
- ;;
-stop)
- if [ "$SKIP_DOWN_AT_SYSRESET" = "yes" ]; then
- SYSRESET=0
- systemctl list-jobs | egrep -q '(shutdown|reboot|halt|poweroff)\.target'
- [ $? -eq 0 ] && SYSRESET=1
- if [ $SYSRESET -eq 1 ]; then
- echo ${NAME}':' "Skipping deconfiguring network interfaces"
- exit 0
- fi
- fi
- ifupdown_init
- check_network_file_systems
- check_network_swap
- exclusions=$(process_exclusions)
-
- echo ${NAME}':' "Deconfiguring network interfaces"
- ifdown -a $EXTRA_ARGS $exclusions
- ;;
-
-reload)
-
- ifupdown_init
- exclusions=$(process_exclusions)
-
- echo ${NAME}':' "Reloading network interfaces configuration"
- ifreload -a $EXTRA_ARGS $exclusions
- ;;
-
-*)
- echo ${NAME}':' "Usage: $0 {start|stop|reload}"
- exit 1
- ;;
-esac
-
-exit 0
]
DATA_FILES = [
- ('/etc/default/', ['etc/default/networking']),
('/etc/network/ifupdown2/', ['etc/network/ifupdown2/addons.conf']),
('/etc/network/ifupdown2/', ['etc/network/ifupdown2/ifupdown2.conf']),
]
def build_deb_package():
try:
return sys.argv[sys.argv.index('--root') + 1].endswith('/debian/ifupdown2')
- except:
- return False
+ except Exception:
+ pass
+ return False
-if build_deb_package():
- DATA_FILES.append(('/usr/share/ifupdown2/sbin/', ['ifupdown2/sbin/start-networking']))
-else:
+if not build_deb_package():
ENTRY_POINTS = {
'console_scripts': [
'ifup = ifupdown2.__main__:main',
}
setup(
- author='Roopa Prabhu',
- author_email='roopa@cumulusnetworks.com',
+ author='Julien Fortin',
+ author_email='julien@cumulusnetworks.com',
maintainer='Julien Fortin',
maintainer_email='julien@cumulusnetworks.com',
classifiers=[
name='ifupdown2',
packages=find_packages(),
url='https://github.com/CumulusNetworks/ifupdown2',
- version='1.2.9',
+ version='2.0.0',
data_files=DATA_FILES,
setup_requires=['setuptools'],
scripts=SCRIPTS,