4 # Copyright 2017 RIFT.IO Inc
6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License.
8 # You may obtain 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,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 # See the License for the specific language governing permissions and
16 # limitations under the License.
19 gi
.require_version('RwcalYang', '1.0')
20 from gi
.repository
import RwcalYang
21 import neutronclient
.common
.exceptions
as NeutronException
24 class NetworkUtils(object):
26 Utility class for network operations
28 def __init__(self
, driver
):
32 driver: object of OpenstackDriver()
41 def _parse_cp(self
, cp_info
):
43 Parse the port_info dictionary returned by neutronclient
45 cp_info: A dictionary object representing port attributes
48 Protobuf GI oject of type RwcalYang.YangData_RwProject_Project_VnfResources_VirtualLinkInfoList_ConnectionPoints()
50 cp
= RwcalYang
.YangData_RwProject_Project_VnfResources_VirtualLinkInfoList_ConnectionPoints()
51 if 'name' in cp_info
and cp_info
['name']:
52 cp
.name
= cp_info
['name']
54 if 'id' in cp_info
and cp_info
['id']:
55 cp
.connection_point_id
= cp_info
['id']
57 if ('fixed_ips' in cp_info
) and (len(cp_info
['fixed_ips']) >= 1):
58 if 'ip_address' in cp_info
['fixed_ips'][0]:
59 cp
.ip_address
= cp_info
['fixed_ips'][0]['ip_address']
61 if 'mac_address' in cp_info
and cp_info
['mac_address']:
62 cp
.mac_addr
= cp_info
['mac_address']
64 if cp_info
['status'] == 'ACTIVE':
69 if 'network_id' in cp_info
and cp_info
['network_id']:
70 cp
.virtual_link_id
= cp_info
['network_id']
72 if 'device_id' in cp_info
and cp_info
['device_id']:
73 cp
.vdu_id
= cp_info
['device_id']
75 if 'allowed_address_pairs' in cp_info
and cp_info
['allowed_address_pairs']:
76 for vcp
in cp_info
['allowed_address_pairs']:
77 vcp_info
= cp
.virtual_cp_info
.add()
78 if 'ip_address' in vcp
and vcp
['ip_address']:
79 vcp_info
.ip_address
= vcp
['ip_address']
80 if 'mac_address' in vcp
and vcp
['mac_address']:
81 vcp_info
.mac_address
= vcp
['mac_address']
84 def _parse_virtual_cp(self
, cp_info
):
86 Parse the port_info dictionary returned by neutronclient
88 cp_info: A dictionary object representing port attributes
91 Protobuf GI oject of type RwcalYang.YangData_RwProject_Project_VnfResources_VirtualLinkInfoList_VirtualConnectionPoints()
93 cp
= RwcalYang
.YangData_RwProject_Project_VnfResources_VirtualLinkInfoList_VirtualConnectionPoints()
95 if 'id' in cp_info
and cp_info
['id']:
96 cp
.connection_point_id
= cp_info
['id']
98 if 'name' in cp_info
and cp_info
['name']:
99 cp
.name
= cp_info
['name']
101 if ('fixed_ips' in cp_info
) and (len(cp_info
['fixed_ips']) >= 1):
102 if 'ip_address' in cp_info
['fixed_ips'][0]:
103 cp
.ip_address
= cp_info
['fixed_ips'][0]['ip_address']
105 if 'mac_address' in cp_info
and cp_info
['mac_address']:
106 cp
.mac_address
= cp_info
['mac_address']
110 def parse_cloud_virtual_link_info(self
, vlink_info
, port_list
, subnet
):
112 Parse vlink_info dictionary (return by python-client) and put values in GI object for Virtual Link
115 vlink_info : A dictionary object return by neutronclient library listing network attributes
118 Protobuf GI Object of type RwcalYang.YangData_RwProject_Project_VnfResources_VirtualLinkInfoList()
120 link
= RwcalYang
.YangData_RwProject_Project_VnfResources_VirtualLinkInfoList()
121 link
.name
= vlink_info
['name']
122 if 'status' in vlink_info
and vlink_info
['status'] == 'ACTIVE':
123 link
.state
= 'active'
125 link
.state
= 'inactive'
127 link
.virtual_link_id
= vlink_info
['id']
128 for port
in port_list
:
129 if ('device_owner' in port
) and (port
['device_owner'] in ['compute:nova', 'compute:None']):
130 link
.connection_points
.append(self
._parse
_cp
(port
))
131 if ('device_owner' in port
) and (port
['device_owner'] == ''):
132 link
.virtual_connection_points
.append(self
._parse
_virtual
_cp
(port
))
134 if subnet
is not None:
135 link
.subnet
= subnet
['cidr']
137 if ('provider:network_type' in vlink_info
) and (vlink_info
['provider:network_type'] != None):
138 link
.provider_network
.overlay_type
= vlink_info
['provider:network_type'].upper()
139 if ('provider:segmentation_id' in vlink_info
) and (vlink_info
['provider:segmentation_id']):
140 link
.provider_network
.segmentation_id
= vlink_info
['provider:segmentation_id']
141 if ('provider:physical_network' in vlink_info
) and (vlink_info
['provider:physical_network']):
142 link
.provider_network
.physical_network
= vlink_info
['provider:physical_network'].upper()
146 def setup_vdu_networking(self
, vdu_params
):
148 This function validates the networking/connectivity setup.
151 vdu_params: object of RwcalYang.YangData_RwProject_Project_VduInitParams()
154 A list of port_ids and network_ids for VDU
161 # Sorting Connection Points by given 'port_order'. If 'port_order' is not given then sorting by name.
162 # Please note that the GI Object (vdu_params.connection_points) has been converted into a dictionary object for sorting purposes.
164 sorted_connection_points
= []
165 if vdu_params
.has_field('connection_points'):
166 sorted_connection_points
= sorted(vdu_params
.as_dict().get('connection_points'), key
=lambda k
: ("port_order" not in k
,
167 k
.get("port_order", None), k
['name']))
169 if vdu_params
.mgmt_network
is not None:
170 # Setting the mgmt network as found in vdu params.
171 mgmt_network
= self
.driver
.neutron_drv
.network_get(network_name
=vdu_params
.mgmt_network
)['id']
173 mgmt_network
= self
.driver
._mgmt
_network
_id
175 for cp
in sorted_connection_points
:
176 if cp
['virtual_link_id'] == mgmt_network
:
177 ### Remove mgmt_network_id from net_ids
179 port_args
.append(self
._create
_cp
_args
(cp
))
181 network_ids
.append(mgmt_network
)
183 ### Create ports and collect port ids
185 port_ids
= self
.driver
.neutron_multi_port_create(port_args
)
188 return port_ids
, network_ids
191 def _create_cp_args(self
, cp
):
193 Creates a request dictionary for port create call
195 cp: Object of Python Dictionary
197 dict() of request params
200 args
['name'] = cp
['name']
202 args
['network_id'] = cp
['virtual_link_id']
203 args
['admin_state_up'] = True
205 if cp
['type_yang'] in ['VIRTIO', 'E1000', 'VPORT']:
206 args
['binding:vnic_type'] = 'normal'
207 elif cp
['type_yang'] == 'SR_IOV':
208 args
['binding:vnic_type'] = 'direct'
210 raise NotImplementedError("Port Type: %s not supported" %(cp
['type_yang']))
213 if cp
['static_ip_address']:
214 args
["fixed_ips"] = [{"ip_address" : cp
['static_ip_address']}]
215 except Exception as e
:
218 if 'port_security_enabled' in cp
:
219 args
['port_security_enabled'] = cp
['port_security_enabled']
221 if 'security_group' in cp
:
222 if self
.driver
._neutron
_security
_groups
:
223 gid
= self
.driver
._neutron
_security
_groups
[0]['id']
224 args
['security_groups'] = [ gid
]
226 if 'virtual_cps' in cp
:
227 args
['allowed_address_pairs'] = [ {'ip_address': vcp
['ip_address'],
228 'mac_address': vcp
['mac_address']}
229 for vcp
in cp
['virtual_cps'] ]
233 def make_virtual_link_args(self
, link_params
):
235 Function to create kwargs required for neutron_network_create API
238 link_params: Protobuf GI object RwcalYang.YangData_RwProject_Project_VirtualLinkReqParams()
241 A kwargs dictionary for network operation
244 kwargs
['name'] = link_params
.name
245 kwargs
['admin_state_up'] = True
246 kwargs
['external_router'] = False
247 kwargs
['shared'] = False
249 if link_params
.has_field('provider_network'):
250 if link_params
.provider_network
.has_field('physical_network'):
251 kwargs
['physical_network'] = link_params
.provider_network
.physical_network
252 if link_params
.provider_network
.has_field('overlay_type'):
253 kwargs
['network_type'] = link_params
.provider_network
.overlay_type
.lower()
254 if link_params
.provider_network
.has_field('segmentation_id'):
255 kwargs
['segmentation_id'] = link_params
.provider_network
.segmentation_id
259 def make_subnet_args(self
, link_params
, network_id
):
261 Function to create kwargs required for neutron_subnet_create API
264 link_params: Protobuf GI object RwcalYang.YangData_RwProject_Project_VirtualLinkReqParams()
267 A kwargs dictionary for subnet operation
269 kwargs
= {'network_id' : network_id
,
270 'dhcp_params': {'enable_dhcp': True},
271 'gateway_ip' : None,}
273 if link_params
.ip_profile_params
.has_field('ip_version'):
274 kwargs
['ip_version'] = 6 if link_params
.ip_profile_params
.ip_version
== 'ipv6' else 4
276 kwargs
['ip_version'] = 4
278 if link_params
.ip_profile_params
.has_field('subnet_address'):
279 kwargs
['cidr'] = link_params
.ip_profile_params
.subnet_address
280 elif link_params
.ip_profile_params
.has_field('subnet_prefix_pool'):
281 name
= link_params
.ip_profile_params
.subnet_prefix_pool
282 pools
= [ p
['id'] for p
in self
.driver
._neutron
_subnet
_prefix
_pool
if p
['name'] == name
]
284 self
.log
.error("Could not find subnet pool with name :%s to be used for network: %s",
285 link_params
.ip_profile_params
.subnet_prefix_pool
,
287 raise NeutronException
.NotFound("SubnetPool with name %s not found"%(link_params
.ip_profile_params
.subnet_prefix_pool
))
289 kwargs
['subnetpool_id'] = pools
[0]
291 elif link_params
.has_field('subnet'):
292 kwargs
['cidr'] = link_params
.subnet
294 raise NeutronException
.NeutronException("No IP Prefix or Pool name specified")
296 if link_params
.ip_profile_params
.has_field('dhcp_params'):
297 if link_params
.ip_profile_params
.dhcp_params
.has_field('enabled'):
298 kwargs
['dhcp_params']['enable_dhcp'] = link_params
.ip_profile_params
.dhcp_params
.enabled
299 if link_params
.ip_profile_params
.dhcp_params
.has_field('start_address'):
300 kwargs
['dhcp_params']['start_address'] = link_params
.ip_profile_params
.dhcp_params
.start_address
301 if link_params
.ip_profile_params
.dhcp_params
.has_field('count'):
302 kwargs
['dhcp_params']['count'] = link_params
.ip_profile_params
.dhcp_params
.count
304 if link_params
.ip_profile_params
.has_field('dns_server'):
305 kwargs
['dns_server'] = []
306 for server
in link_params
.ip_profile_params
.dns_server
:
307 kwargs
['dns_server'].append(server
.address
)
309 if link_params
.ip_profile_params
.has_field('gateway_address'):
310 kwargs
['gateway_ip'] = link_params
.ip_profile_params
.gateway_address
314 def prepare_virtual_link(self
, link_params
, network_id
):
316 Function to create additional resources in the network during
317 network-creation process. It involves following steps
319 - Create any virtual ports in network
322 link_params: Protobuf GI object RwcalYang.YangData_RwProject_Project_VirtualLinkReqParams()
329 kwargs
= self
.make_subnet_args(link_params
, network_id
)
330 self
.driver
.neutron_subnet_create(**kwargs
)
332 ### Create Virtual connection point
333 if link_params
.has_field('virtual_cps'):
335 for vcp
in link_params
.virtual_cps
:
336 cp
= RwcalYang
.YangData_RwProject_Project_VduInitParams_ConnectionPoints()
337 cp
.from_dict({k
:v
for k
,v
in vcp
.as_dict().items()
338 if k
in ['name','security_group', 'port_security_enabled', 'static_ip_address', 'type_yang']})
339 cp
.virtual_link_id
= network_id
340 port_args
.append(self
._create
_cp
_args
(cp
.as_dict()))
343 self
.driver
.neutron_multi_port_create(port_args
)