1
# vim: tabstop=4 shiftwidth=4 softtabstop=4
3
# Copyright 2011 Nicira Networks, Inc
6
# Licensed under the Apache License, Version 2.0 (the "License"); you may
7
# not use this file except in compliance with the License. You may obtain
8
# a copy of the License at
10
# http://www.apache.org/licenses/LICENSE-2.0
12
# Unless required by applicable law or agreed to in writing, software
13
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15
# License for the specific language governing permissions and limitations
18
from netaddr import IPNetwork
21
from nova import exception
22
from nova import flags
23
from nova import log as logging
24
from nova.network.quantum import melange_connection
27
LOG = logging.getLogger("nova.network.quantum.melange_ipam_lib")
32
def get_ipam_lib(net_man):
33
return QuantumMelangeIPAMLib()
36
class QuantumMelangeIPAMLib(object):
37
"""Implements Quantum IP Address Management (IPAM) interface
38
using the Melange service, which is access using the Melange
43
"""Initialize class used to connect to Melange server"""
44
self.m_conn = melange_connection.MelangeConnection()
46
def create_subnet(self, context, label, project_id,
47
quantum_net_id, priority, cidr=None,
48
gateway_v6=None, cidr_v6=None,
49
dns1=None, dns2=None):
50
"""Contact Melange and create a subnet for any non-NULL
53
Also create a entry in the Nova networks DB, but only
54
to store values not represented in Melange or to
55
temporarily provide compatibility with Nova code that
56
accesses IPAM data directly via the DB (e.g., nova-api)
58
tenant_id = project_id or FLAGS.quantum_default_tenant_id
60
self.m_conn.create_block(quantum_net_id, cidr,
64
self.m_conn.create_block(quantum_net_id, cidr_v6,
68
net = {"uuid": quantum_net_id,
69
"project_id": project_id,
72
admin_context = context.elevated()
73
network = db.network_create_safe(admin_context, net)
75
def allocate_fixed_ip(self, context, project_id, quantum_net_id, vif_ref):
76
"""Pass call to allocate fixed IP on to Melange"""
77
tenant_id = project_id or FLAGS.quantum_default_tenant_id
78
self.m_conn.allocate_ip(quantum_net_id,
79
vif_ref['uuid'], project_id=tenant_id,
80
mac_address=vif_ref['address'])
82
def get_network_id_by_cidr(self, context, cidr, project_id):
83
"""Find the Quantum UUID associated with a IPv4 CIDR
84
address for the specified tenant.
86
tenant_id = project_id or FLAGS.quantum_default_tenant_id
87
all_blocks = self.m_conn.get_blocks(tenant_id)
88
for b in all_blocks['ip_blocks']:
90
return b['network_id']
91
raise exception.NotFound(_("No network found for cidr %s" % cidr))
93
def delete_subnets_by_net_id(self, context, net_id, project_id):
94
"""Find Melange block associated with the Quantum UUID,
95
then tell Melange to delete that block.
97
admin_context = context.elevated()
98
tenant_id = project_id or FLAGS.quantum_default_tenant_id
99
all_blocks = self.m_conn.get_blocks(tenant_id)
100
for b in all_blocks['ip_blocks']:
101
if b['network_id'] == net_id:
102
self.m_conn.delete_block(b['id'], tenant_id)
104
network = db.network_get_by_uuid(admin_context, net_id)
105
db.network_delete_safe(context, network['id'])
107
def get_project_and_global_net_ids(self, context, project_id):
108
"""Fetches all networks associated with this project, or
109
that are "global" (i.e., have no project set).
110
Returns list sorted by 'priority' (lowest integer value
111
is highest priority).
113
if project_id is None:
114
raise Exception(_("get_project_and_global_net_ids must be called"
115
" with a non-null project_id"))
117
admin_context = context.elevated()
119
# Decorate with priority
121
for tenant_id in (project_id, FLAGS.quantum_default_tenant_id):
122
blocks = self.m_conn.get_blocks(tenant_id)
123
for ip_block in blocks['ip_blocks']:
124
network_id = ip_block['network_id']
125
network = db.network_get_by_uuid(admin_context, network_id)
127
priority = network['priority']
128
priority_nets.append((priority, network_id, tenant_id))
134
return [(network_id, tenant_id)
135
for priority, network_id, tenant_id in priority_nets]
137
def get_subnets_by_net_id(self, context, project_id, net_id):
138
"""Returns information about the IPv4 and IPv6 subnets
139
associated with a Quantum Network UUID.
142
# FIXME(danwent): Melange actually returns the subnet info
143
# when we query for a particular interface. We may want to
144
# rework the ipam_manager python API to let us take advantage of
145
# this, as right now we have to get all blocks and cycle through
149
tenant_id = project_id or FLAGS.quantum_default_tenant_id
150
all_blocks = self.m_conn.get_blocks(tenant_id)
151
for b in all_blocks['ip_blocks']:
152
if b['network_id'] == net_id:
153
subnet = {'network_id': b['network_id'],
155
'gateway': b['gateway'],
156
'broadcast': b['broadcast'],
157
'netmask': b['netmask'],
161
if IPNetwork(b['cidr']).version == 6:
165
return (subnet_v4, subnet_v6)
167
def get_v4_ips_by_interface(self, context, net_id, vif_id, project_id):
168
"""Returns a list of IPv4 address strings associated with
169
the specified virtual interface.
171
return self._get_ips_by_interface(context, net_id, vif_id,
174
def get_v6_ips_by_interface(self, context, net_id, vif_id, project_id):
175
"""Returns a list of IPv6 address strings associated with
176
the specified virtual interface.
178
return self._get_ips_by_interface(context, net_id, vif_id,
181
def _get_ips_by_interface(self, context, net_id, vif_id, project_id,
183
"""Helper method to fetch v4 or v6 addresses for a particular
186
tenant_id = project_id or FLAGS.quantum_default_tenant_id
187
ip_list = self.m_conn.get_allocated_ips(net_id, vif_id, tenant_id)
188
return [ip['address'] for ip in ip_list
189
if IPNetwork(ip['address']).version == ip_version]
191
def verify_subnet_exists(self, context, project_id, quantum_net_id):
192
"""Confirms that a subnet exists that is associated with the
193
specified Quantum Network UUID.
195
tenant_id = project_id or FLAGS.quantum_default_tenant_id
196
v4_subnet, v6_subnet = self.get_subnets_by_net_id(context, tenant_id,
198
return v4_subnet is not None
200
def deallocate_ips_by_vif(self, context, project_id, net_id, vif_ref):
201
"""Deallocate all fixed IPs associated with the specified
204
tenant_id = project_id or FLAGS.quantum_default_tenant_id
205
self.m_conn.deallocate_ips(net_id, vif_ref['uuid'], tenant_id)