Sfoglia il codice sorgente

Closes #4814: Allow nested LAG interfaces

Jeremy Stretch 5 anni fa
parent
commit
f37997ac54

+ 1 - 1
docs/models/dcim/interface.md

@@ -4,7 +4,7 @@ Interfaces in NetBox represent network interfaces used to exchange data with con
 
 Interfaces may be physical or virtual in nature, but only physical interfaces may be connected via cables. Cables can connect interfaces to pass-through ports, circuit terminations, or other interfaces.
 
-Physical interfaces may be arranged into a link aggregation group (LAG) and associated with a parent LAG (virtual) interface. Like all virtual interfaces, LAG interfaces cannot be connected physically.
+Physical interfaces may be arranged into a link aggregation group (LAG) and associated with a parent LAG (virtual) interface. LAG interfaces can be recursively nested to model bonding of trunk groups. Like all virtual interfaces, LAG interfaces cannot be connected physically.
 
 IP addresses can be assigned to interfaces. VLANs can also be assigned to each interface as either tagged or untagged. (An interface may have only one untagged VLAN.)
 

+ 1 - 0
docs/release-notes/version-2.9.md

@@ -5,6 +5,7 @@
 ### Enhancements
 
 * [#4540](https://github.com/netbox-community/netbox/issues/4540) - Add IP address status type for SLAAC
+* [#4814](https://github.com/netbox-community/netbox/issues/4814) - Allow nested LAG interfaces
 * [#4991](https://github.com/netbox-community/netbox/issues/4991) - Add Python and NetBox versions to error page
 
 ---

+ 4 - 1
netbox/dcim/forms.py

@@ -2686,7 +2686,10 @@ class InterfaceForm(InterfaceCommonForm, BootstrapMixin, forms.ModelForm):
         device_query = Q(device=device)
         if device.virtual_chassis:
             device_query |= Q(device__virtual_chassis=device.virtual_chassis)
-        self.fields['lag'].queryset = Interface.objects.filter(device_query, type=InterfaceTypeChoices.TYPE_LAG)
+        self.fields['lag'].queryset = Interface.objects.filter(
+            device_query,
+            type=InterfaceTypeChoices.TYPE_LAG
+        ).exclude(pk=self.instance.pk)
 
         # Add current site to VLANs query params
         self.fields['untagged_vlan'].widget.add_query_param('site_id', device.site.pk)

+ 5 - 11
netbox/dcim/models/device_components.py

@@ -702,18 +702,12 @@ class Interface(CableTermination, ComponentModel, BaseInterface):
                 })
 
         # A virtual interface cannot have a parent LAG
-        if self.type in NONCONNECTABLE_IFACE_TYPES and self.lag is not None:
-            raise ValidationError({
-                'lag': "{} interfaces cannot have a parent LAG interface.".format(self.get_type_display())
-            })
+        if self.type == InterfaceTypeChoices.TYPE_VIRTUAL and self.lag is not None:
+            raise ValidationError({'lag': "Virtual interfaces cannot have a parent LAG interface."})
 
-        # Only a LAG can have LAG members
-        if self.type != InterfaceTypeChoices.TYPE_LAG and self.member_interfaces.exists():
-            raise ValidationError({
-                'type': "Cannot change interface type; it has LAG members ({}).".format(
-                    ", ".join([iface.name for iface in self.member_interfaces.all()])
-                )
-            })
+        # A LAG interface cannot be its own parent
+        if self.pk and self.lag_id == self.pk:
+            raise ValidationError({'lag': "A LAG interface cannot be its own parent."})
 
         # Validate untagged VLAN
         if self.untagged_vlan and self.untagged_vlan.site not in [self.parent.site, None]: