1
+ from neutron .objects .trunk import SubPort
1
2
from neutron .services .trunk .drivers import base as trunk_base
3
+ from neutron_lib import exceptions as exc
2
4
from neutron_lib .api .definitions import portbindings
5
+ from neutron_lib .callbacks import events
6
+ from neutron_lib .callbacks import registry
7
+ from neutron_lib .callbacks import resources
3
8
from neutron_lib .services .trunk import constants as trunk_consts
4
9
from oslo_config import cfg
10
+ from oslo_log import log
11
+
12
+ from neutron_understack import config
13
+ from neutron_understack import utils
14
+ from neutron_understack .nautobot import Nautobot
15
+
16
+ config .register_ml2_understack_opts (cfg .CONF )
17
+
18
+ LOG = log .getLogger (__name__ )
5
19
6
20
SUPPORTED_INTERFACES = (portbindings .VIF_TYPE_OTHER ,)
7
21
8
22
SUPPORTED_SEGMENTATION_TYPES = (trunk_consts .SEGMENTATION_TYPE_VLAN ,)
9
23
10
24
25
+ class SubportSegmentationIDError (exc .NeutronException ):
26
+ message = (
27
+ "Segmentation ID: %(seg_id)s cannot be set to the Subport: "
28
+ "%(subport_id)s as there is already another Segmentation ID: "
29
+ "%(nb_seg_id)s in use by the Network: %(net_id)s that is "
30
+ "attached to the Subport. Please use %(nb_seg_id)s as "
31
+ "segmentation_id for this subport."
32
+ )
33
+
34
+
11
35
class UnderStackTrunkDriver (trunk_base .DriverBase ):
36
+ def __init__ (
37
+ self ,
38
+ name ,
39
+ interfaces ,
40
+ segmentation_types ,
41
+ agent_type = None ,
42
+ can_trunk_bound_port = False ,
43
+ ):
44
+ super ().__init__ (
45
+ name ,
46
+ interfaces ,
47
+ segmentation_types ,
48
+ agent_type = agent_type ,
49
+ can_trunk_bound_port = can_trunk_bound_port ,
50
+ )
51
+ conf = cfg .CONF .ml2_understack
52
+ self .nb = Nautobot (conf .nb_url , conf .nb_token )
53
+
12
54
@property
13
55
def is_loaded (self ):
14
56
try :
@@ -26,3 +68,63 @@ def create(cls, plugin_driver):
26
68
None ,
27
69
can_trunk_bound_port = True ,
28
70
)
71
+
72
+ @registry .receives (resources .TRUNK_PLUGIN , [events .AFTER_INIT ])
73
+ def register (self , resource , event , trigger , payload = None ):
74
+ super ().register (resource , event , trigger , payload = payload )
75
+
76
+ registry .subscribe (
77
+ self .subports_added ,
78
+ resources .SUBPORTS ,
79
+ events .AFTER_CREATE ,
80
+ cancellable = True ,
81
+ )
82
+ registry .subscribe (
83
+ self .trunk_created , resources .TRUNK , events .AFTER_CREATE , cancellable = True
84
+ )
85
+
86
+ def _configure_tenant_vlan_id (
87
+ self , tenant_vlan_id : int | None , ucvni_uuid : str , subport : SubPort
88
+ ) -> None :
89
+ subport_seg_id = subport .segmentation_id
90
+ if not tenant_vlan_id :
91
+ self .nb .add_tenant_vlan_tag_to_ucvni (
92
+ network_uuid = ucvni_uuid , vlan_tag = subport_seg_id
93
+ )
94
+ LOG .info (
95
+ "Segmentation ID: %(seg_id)s is now set on Nautobot's UCVNI "
96
+ "UUID: %(ucvni_uuid)s in the tenant_vlan_id custom field" ,
97
+ {"seg_id" : subport_seg_id , "ucvni_uuid" : ucvni_uuid },
98
+ )
99
+ elif tenant_vlan_id != subport_seg_id :
100
+ subport .delete ()
101
+ raise SubportSegmentationIDError (
102
+ seg_id = subport_seg_id ,
103
+ net_id = ucvni_uuid ,
104
+ nb_seg_id = tenant_vlan_id ,
105
+ subport_id = subport .port_id ,
106
+ )
107
+
108
+ def _subports_added (self , subports : list [SubPort ]) -> None :
109
+ for subport in subports :
110
+ subport_id = subport .port_id
111
+ subport_network_id = utils .fetch_subport_network_id (subport_id = subport_id )
112
+ ucvni_tenant_vlan_id = self .nb .fetch_ucvni_tenant_vlan_id (
113
+ network_id = subport_network_id
114
+ )
115
+
116
+ self ._configure_tenant_vlan_id (
117
+ tenant_vlan_id = ucvni_tenant_vlan_id ,
118
+ ucvni_uuid = subport_network_id ,
119
+ subport = subport ,
120
+ )
121
+
122
+ def subports_added (self , resource , event , trunk_plugin , payload ):
123
+ subports = payload .metadata ["subports" ]
124
+ self ._subports_added (subports )
125
+
126
+ def trunk_created (self , resource , event , trunk_plugin , payload ):
127
+ trunk = payload .states [0 ]
128
+ subports = trunk .sub_ports
129
+ if subports :
130
+ self ._subports_added (subports )
0 commit comments