20
20
from netaddr .strategy import eui48
21
21
from neutron_lib .agent import constants as agent_consts
22
22
from neutron_lib .agent import topics
23
+ from neutron_lib .api import converters
23
24
from neutron_lib .api .definitions import address_group as addrgrp_def
24
25
from neutron_lib .api .definitions import address_scope
25
26
from neutron_lib .api .definitions import agent as agent_apidef
@@ -1563,11 +1564,36 @@ def _after_create_port(self, context, result, mech_context):
1563
1564
1564
1565
return bound_context .current
1565
1566
1566
- def allocate_ips_for_ports (self , context , ports ):
1567
+ def allocate_macs_and_ips_for_ports (self , context , ports ):
1568
+ macs = self ._generate_macs (len (ports ))
1569
+ network_cache = dict ()
1567
1570
for port in ports :
1568
1571
port ['port' ]['id' ] = (
1569
1572
port ['port' ].get ('id' ) or uuidutils .generate_uuid ())
1570
1573
1574
+ network_id = port ['port' ].get ('network_id' )
1575
+ if network_id not in network_cache :
1576
+ network = self .get_network (context , network_id )
1577
+ network_cache [network_id ] = network
1578
+
1579
+ raw_mac_address = port ['port' ].get ('mac_address' ,
1580
+ const .ATTR_NOT_SPECIFIED )
1581
+ if raw_mac_address is const .ATTR_NOT_SPECIFIED :
1582
+ raw_mac_address = macs .pop ()
1583
+ elif self ._is_mac_in_use (context , network_id , raw_mac_address ):
1584
+ raise exc .MacAddressInUse (net_id = network_id ,
1585
+ mac = raw_mac_address )
1586
+ eui_mac_address = converters .convert_to_sanitized_mac_address (
1587
+ raw_mac_address )
1588
+ # Create the Port object
1589
+ # Note: netaddr has an issue with using the correct dialect when
1590
+ # the input for EUI is another EUI object, see:
1591
+ # https://github.com/netaddr/netaddr/issues/250
1592
+ # TODO(lajoskatona): remove this once
1593
+ # https://review.opendev.org/c/openstack/neutron-lib/+/865517 is
1594
+ # released.
1595
+ port ['port' ]['mac_address' ] = str (eui_mac_address )
1596
+
1571
1597
# Call IPAM to allocate IP addresses
1572
1598
try :
1573
1599
port ['ipams' ] = self .ipam .allocate_ips_for_port (context , port )
@@ -1577,18 +1603,19 @@ def allocate_ips_for_ports(self, context, ports):
1577
1603
except ipam_exc .DeferIpam :
1578
1604
port ['ip_allocation' ] = (ipalloc_apidef .
1579
1605
IP_ALLOCATION_DEFERRED )
1580
- return ports
1606
+ return ports , network_cache
1581
1607
1582
1608
@utils .transaction_guard
1583
1609
def create_port_bulk (self , context , ports ):
1584
1610
port_list = ports .get ('ports' )
1585
1611
for port in port_list :
1586
1612
self ._before_create_port (context , port )
1587
1613
1588
- port_list = self .allocate_ips_for_ports (context , port_list )
1614
+ port_list , net_cache = self .allocate_macs_and_ips_for_ports (
1615
+ context , port_list )
1589
1616
1590
1617
try :
1591
- return self ._create_port_bulk (context , port_list )
1618
+ return self ._create_port_bulk (context , port_list , net_cache )
1592
1619
except Exception :
1593
1620
with excutils .save_and_reraise_exception ():
1594
1621
# If any issue happened allocated IP addresses needs to be
@@ -1598,17 +1625,16 @@ def create_port_bulk(self, context, ports):
1598
1625
context , port , port ['ipams' ])
1599
1626
1600
1627
@db_api .retry_if_session_inactive ()
1601
- def _create_port_bulk (self , context , port_list ):
1628
+ def _create_port_bulk (self , context , port_list , network_cache ):
1602
1629
# TODO(njohnston): Break this up into smaller functions.
1603
1630
port_data = []
1604
- network_cache = dict ()
1605
- macs = self ._generate_macs (len (port_list ))
1606
1631
with db_api .CONTEXT_WRITER .using (context ):
1607
1632
for port in port_list :
1608
1633
# Set up the port request dict
1609
1634
pdata = port .get ('port' )
1610
1635
project_id = pdata .get ('project_id' ) or pdata .get ('tenant_id' )
1611
1636
security_group_ids = pdata .get ('security_groups' )
1637
+ network_id = pdata .get ('network_id' )
1612
1638
if security_group_ids is const .ATTR_NOT_SPECIFIED :
1613
1639
security_group_ids = None
1614
1640
else :
@@ -1620,39 +1646,21 @@ def _create_port_bulk(self, context, port_list):
1620
1646
bulk_port_data = dict (
1621
1647
project_id = project_id ,
1622
1648
name = pdata .get ('name' ),
1623
- network_id = pdata . get ( ' network_id' ) ,
1649
+ network_id = network_id ,
1624
1650
admin_state_up = pdata .get ('admin_state_up' ),
1625
1651
status = pdata .get ('status' ,
1626
1652
const .PORT_STATUS_ACTIVE ),
1627
1653
device_id = pdata .get ('device_id' ),
1628
1654
device_owner = pdata .get ('device_owner' ),
1629
1655
description = pdata .get ('description' ))
1630
1656
1631
- # Ensure that the networks exist.
1632
- network_id = pdata .get ('network_id' )
1633
- if network_id not in network_cache :
1634
- network = self .get_network (context , network_id )
1635
- network_cache [network_id ] = network
1636
- else :
1637
- network = network_cache [network_id ]
1638
-
1639
- # Determine the MAC address
1640
- raw_mac_address = pdata .get ('mac_address' ,
1641
- const .ATTR_NOT_SPECIFIED )
1642
- if raw_mac_address is const .ATTR_NOT_SPECIFIED :
1643
- raw_mac_address = macs .pop ()
1644
- elif self ._is_mac_in_use (context , network_id , raw_mac_address ):
1645
- raise exc .MacAddressInUse (net_id = network_id ,
1646
- mac = raw_mac_address )
1647
- eui_mac_address = netaddr .EUI (raw_mac_address ,
1648
- dialect = eui48 .mac_unix_expanded )
1649
- port ['port' ]['mac_address' ] = str (eui_mac_address )
1650
-
1651
- # Create the Port object
1652
- db_port_obj = ports_obj .Port (context ,
1653
- mac_address = eui_mac_address ,
1654
- id = port ['port' ]['id' ],
1655
- ** bulk_port_data )
1657
+ network = network_cache [network_id ]
1658
+
1659
+ db_port_obj = ports_obj .Port (
1660
+ context ,
1661
+ mac_address = netaddr .EUI (port ['port' ]['mac_address' ],
1662
+ dialect = eui48 .mac_unix_expanded ),
1663
+ id = port ['port' ]['id' ], ** bulk_port_data )
1656
1664
db_port_obj .create ()
1657
1665
1658
1666
# Call IPAM to store allocated IP addresses
0 commit comments