from ifupdown2.ifupdown.iface import *
from ifupdown2.nlmanager.nlmanager import Link
from ifupdown2.ifupdownaddons.modulebase import moduleBase
+ from ifupdown2.ifupdown.utils import utils
import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
+ import ifupdown2.ifupdown.policymanager as policymanager
except (ImportError, ModuleNotFoundError):
from lib.addon import Addon
from ifupdown.iface import *
from nlmanager.nlmanager import Link
from ifupdownaddons.modulebase import moduleBase
+ from ifupdown.utils import utils
import ifupdown.ifupdownflags as ifupdownflags
+ import ifupdown.policymanager as policymanager
class vlan(Addon, moduleBase):
"validvals": ["802.1q", "802.1ad"],
"example": ["vlan-protocol 802.1q"]
},
+ "vlan-bridge-binding": {
+ "help": "The link state of the vlan device may need to track only the state of the subset of ports "
+ "that are also members of the corresponding vlan, rather than that of all ports. Add a flag to "
+ "specify a vlan bridge binding mode, by which the link state is no longer automatically "
+ "transferred from the lower device, but is instead determined by the bridge ports that are "
+ "members of the vlan.",
+ "default": "off",
+ "validvals": ["on", "off"],
+ "example": ["vlan-bridge-binding on"]
+ }
}
}
else:
cached_vlan_ifla_info_data = self.cache.get_link_info_data(ifname)
+ vlan_bridge_binding = ifaceobj.get_attr_value_first("vlan-bridge-binding")
+
+ if not vlan_bridge_binding:
+ vlan_bridge_binding = policymanager.policymanager_api.get_attr_default(
+ self.__class__.__name__,
+ "vlan-bridge-binding"
+ ) or self.get_attr_default_value("vlan-bridge-binding")
+
+ bool_vlan_bridge_binding = utils.get_boolean_from_string(vlan_bridge_binding)
+
vlan_protocol = ifaceobj.get_attr_value_first('vlan-protocol')
cached_vlan_protocol = cached_vlan_ifla_info_data.get(Link.IFLA_VLAN_PROTOCOL)
else:
raise Exception('rawdevice %s not present' % vlanrawdevice)
if vlan_exists:
+
+ # vlan-bridge-binding has changed we need to update it
+ if vlan_bridge_binding is not None and bool_vlan_bridge_binding != cached_vlan_ifla_info_data.get(Link.IFLA_VLAN_FLAGS, {}).get(Link.VLAN_FLAG_BRIDGE_BINDING, False):
+ self.logger.info("%s: mismatch detected: resetting: vlan-bridge-binding %s" % (ifname, vlan_bridge_binding))
+ self.netlink.link_add_vlan(vlanrawdevice, ifaceobj.name, vlanid, vlan_protocol, bool_vlan_bridge_binding)
+
self._bridge_vid_add_del(vlanrawdevice, vlanid)
return
- self.netlink.link_add_vlan(vlanrawdevice, ifaceobj.name, vlanid, vlan_protocol)
+ self.netlink.link_add_vlan(vlanrawdevice, ifaceobj.name, vlanid, vlan_protocol, bool_vlan_bridge_binding if vlan_bridge_binding is not None else None)
self._bridge_vid_add_del(vlanrawdevice, vlanid)
def _down(self, ifaceobj):
0
)
+ #
+ # vlan-bridge-binding
+ #
+ vlan_bridge_binding = ifaceobj.get_attr_value_first("vlan-bridge-binding")
+ if vlan_bridge_binding:
+ cached_vlan_bridge_binding = cached_vlan_info_data.get(Link.IFLA_VLAN_FLAGS, {}).get(
+ Link.VLAN_FLAG_BRIDGE_BINDING, False)
+
+ ifaceobjcurr.update_config_with_status(
+ "vlan-bridge-binding",
+ "on" if cached_vlan_bridge_binding else "off",
+ cached_vlan_bridge_binding != utils.get_boolean_from_string(vlan_bridge_binding)
+ )
+
self._bridge_vid_check(ifaceobjcurr, cached_vlan_raw_device, cached_vlan_id)
def _query_running(self, ifaceobjrunning):
ifaceobjrunning.update_config('vlan-raw-device', self.cache.get_lower_device_ifname(ifname))
+ if cached_vlan_info_data.get(Link.IFLA_VLAN_FLAGS, {}).get(Link.VLAN_FLAG_BRIDGE_BINDING, False):
+ ifaceobjrunning.update_config("vlan-bridge-binding", "on")
+
_run_ops = {
"pre-up": _up,
"post-down": _down,
link.build_message(next(self.sequence), self.pid)
return self.tx_nlpacket_get_response_with_error(link)
+ def vlan_set_bridge_binding(self, ifname, bridge_binding=True):
+ """
+ Set VLAN_FLAG_BRIDGE_BINDING on vlan interface
+ :param ifname: the vlan interface
+ :param bridge_binding: True to set the flag, False to unset
+ """
+ self.logger.info("%s: netlink: ip link set dev %s type vlan bridge_binding %s" % (ifname, ifname, "on" if bridge_binding else "off"))
+
+ 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)
+ info_data = {Link.IFLA_VLAN_FLAGS: {Link.VLAN_FLAG_BRIDGE_BINDING: bridge_binding}}
+ link.add_attribute(Link.IFLA_LINKINFO, {
+ Link.IFLA_INFO_KIND: "vlan",
+ Link.IFLA_INFO_DATA: info_data
+ })
+
+ link.build_message(next(self.sequence), self.pid)
+ return self.tx_nlpacket_get_response_with_error(link)
+
#############################################################################################################
# Netlink API ###############################################################################################
#############################################################################################################
###
- def link_add_vlan(self, vlan_raw_device, ifname, vlan_id, vlan_protocol=None):
+ def link_add_vlan(self, vlan_raw_device, ifname, vlan_id, vlan_protocol=None, bridge_binding=None):
"""
ifindex is the index of the parent interface that this sub-interface
is being added to
Do this check here so we can provide a more intuitive error
"""
try:
+ vlan_iproute2_cmd = ["ip link add link %s name %s type vlan id %s" % (vlan_raw_device, ifname, vlan_id)]
+ ifla_info_data = {Link.IFLA_VLAN_ID: vlan_id}
+
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))
+ vlan_iproute2_cmd.append("protocol %s" % vlan_protocol)
+ ifla_info_data[Link.IFLA_VLAN_PROTOCOL] = 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 bridge_binding is not None:
+ vlan_iproute2_cmd.append("bridge_binding %s" % ("on" if bridge_binding else "off"))
+ ifla_info_data[Link.IFLA_VLAN_FLAGS] = {Link.VLAN_FLAG_BRIDGE_BINDING: bridge_binding}
+
+ self.logger.info("%s: netlink: %s" % (ifname, " ".join(vlan_iproute2_cmd)))
if "." in ifname:
ifname_vlanid = int(ifname.split(".")[-1])
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)
0x88A8: '802.1ad'
}
+ VLAN_FLAG_REORDER_HDR = 0x1
+ VLAN_FLAG_GVRP = 0x2
+ VLAN_FLAG_LOOSE_BINDING = 0x4
+ VLAN_FLAG_MVRP = 0x8
+ VLAN_FLAG_BRIDGE_BINDING = 0x10
+
+ vlan_flags_to_string = {
+ VLAN_FLAG_REORDER_HDR : "REORDER_HDR",
+ VLAN_FLAG_GVRP : "GVRP",
+ VLAN_FLAG_LOOSE_BINDING : "LOOSE_BINDING",
+ VLAN_FLAG_MVRP : "MVRP",
+ VLAN_FLAG_BRIDGE_BINDING : "BRIDGE_BINDING",
+ }
+
# =========================================
# IFLA_INFO_DATA attributes for macvlan
# =========================================
def decode_vlan_protocol_attribute(data, _=None):
return Link.ifla_vlan_protocol_dict.get(unpack(">H", data[4:6])[0])
+ @staticmethod
+ def decode_vlan_flags_attribute(data, _=None):
+ vlan_flags = unpack('=I', data[4:8])[0]
+ vlan_flags_dict = {}
+
+ # iterate over bits set to 1
+ def bits(n):
+ while n:
+ b = n & (~n + 1)
+ yield b
+ n ^= b
+
+ for vlan_flag in bits(vlan_flags):
+ if vlan_flag in Link.vlan_flags_to_string:
+ vlan_flags_dict[vlan_flag] = True
+ #else:
+ # self.log.warning('Unknown vlan flag %d in IFLA_VLAN_FLAGS' % vlan_flag)
+
+ return vlan_flags_dict
+
############################################################################
# encode methods
############################################################################
for mbyte in info_data_value.replace(".", " ").replace(":", " ").split():
sub_attr_payload.append(int(mbyte, 16))
+ @staticmethod
+ def encode_vlan_flags_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)
+ sub_attr_payload.append(info_data_type)
+
+ # vlan flags and mask
+ sub_attr_pack_layout.append('II')
+ vlan_flags = 0
+ vlan_flags_mask = 0
+
+ for (vlan_flag, flag_set) in info_data_value.items():
+ vlan_flags_mask |= vlan_flag
+ if flag_set:
+ vlan_flags |= vlan_flag
+
+ sub_attr_payload.append(vlan_flags)
+ sub_attr_payload.append(vlan_flags_mask)
+
class AttributeCACHEINFO(Attribute):
"""
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
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VLAN_PROTOCOL: Attribute.decode_vlan_protocol_attribute,
+
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VLAN_FLAGS: Attribute.decode_vlan_flags_attribute
},
"macvlan": {
# 4 bytes attributes ###########################################
# vlan-protocol attribute ######################################
NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VLAN_PROTOCOL: Attribute.encode_vlan_protocol_attribute,
+
+ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VLAN_FLAGS: Attribute.encode_vlan_flags_attribute,
},
"macvlan": {
# 4 bytes attributes ###########################################