validators: Allow uppercase iface names
[ta/cm-plugins.git] / validators / src / NetworkProfilesValidation.py
1 #! /usr/bin/python
2 # Copyright 2019 Nokia
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 #    http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15
16 import json
17 import re
18
19 from cmdatahandlers.api import validation
20 from cmframework.apis import cmvalidator
21 from cmdatahandlers.api import utils
22
23
24 class NetworkProfilesValidation(cmvalidator.CMValidator):
25     SUBSCRIPTION = r'^cloud\.network_profiles|cloud\.networking$'
26     DOMAIN = 'cloud.network_profiles'
27     NETWORKING = 'cloud.networking'
28
29     MAX_IFACE_NAME_LEN = 15
30     IFACE_NAME_MATCH = r'^[a-z][\da-z]+$'
31     BOND_NAME_MATCH = r'^bond[\d]+$'
32
33     INTERFACE_NET_MAPPING = 'interface_net_mapping'
34     PROVIDER_NETWORK_INTERFACES = 'provider_network_interfaces'
35     PROVIDER_NETWORKS = 'provider_networks'
36     SRIOV_PROVIDER_NETWORKS = 'sriov_provider_networks'
37     INTERFACES = 'interfaces'
38     TRUSTED = 'trusted'
39     VF_COUNT = 'vf_count'
40     TYPE = 'type'
41     DPDK_MAX_RX_QUEUES = 'dpdk_max_rx_queues'
42     BONDING_INTERFACES = 'bonding_interfaces'
43     LINUX_BONDING_OPTIONS = 'linux_bonding_options'
44     OVS_BONDING_OPTIONS = 'ovs_bonding_options'
45
46     TYPE_CAAS = 'caas'
47     TYPE_OPENSTACK = 'openstack'
48     TYPE_OVS = 'ovs'
49     TYPE_OVS_DPDK = 'ovs-dpdk'
50     TYPE_OVS_OFFLOAD_SRIOV = "ovs-offload-sriov"
51     TYPE_OVS_OFFLOAD_VIRTIO = "ovs-offload-virtio"
52     VALID_PROVIDER_TYPES = [TYPE_CAAS,
53                             TYPE_OVS,
54                             TYPE_OVS_DPDK,
55                             TYPE_OVS_OFFLOAD_SRIOV,
56                             TYPE_OVS_OFFLOAD_VIRTIO]
57     SINGLE_NIC_UNSUPPORTED_TYPES = [TYPE_CAAS, TYPE_OVS_DPDK]
58     VALID_SRIOV_TYPES = [TYPE_CAAS, TYPE_OPENSTACK]
59
60     MODE_LACP = 'mode=lacp'
61     MODE_LACP_LAYER34 = 'mode=lacp-layer34'
62     MODE_AB = 'mode=active-backup'
63     VALID_BONDING_OPTIONS = [MODE_LACP, MODE_LACP_LAYER34, MODE_AB]
64
65     VLAN_RANGES = 'vlan_ranges'
66     VLAN = 'vlan'
67     MTU = 'mtu'
68     DEFAULT_MTU = 1500
69     NETWORK_DOMAINS = 'network_domains'
70
71     UNTAGGED = 'untagged'
72
73     INPUT_ERR_CONTEXT = 'validate_set() input'
74     ERR_INPUT_NOT_DICT = 'Invalid %s, not a dictionary' % INPUT_ERR_CONTEXT
75
76     ERR_MISSING = 'Missing {1} configuration in {0}'
77     ERR_NOT_DICT = 'Invalid {1} value in {0}: Empty or not a dictionary'
78     ERR_NOT_LIST = 'Invalid {1} value in {0}: Empty, contains duplicates or not a list'
79     ERR_NOT_STR = 'Invalid {1} value in {0}: Not a string'
80     ERR_NOT_INT = 'Invalid {1} value in {0}: Not an integer'
81     ERR_NOT_BOOL = 'Invalid {1} value in {0}: Not a boolean value'
82
83     ERR_INVALID_IFACE_NAME = 'Invalid interface name in {}'
84     ERR_IFACE_NAME_LEN = 'Too long interface name in {}, max %s chars' % MAX_IFACE_NAME_LEN
85     ERR_IFACE_VLAN = 'Interface in {0} cannot be vlan interface: {1}'
86     ERR_IFACE_BOND = 'Interface in {0} cannot be bond interface: {1}'
87     ERR_IFACE_NOT_BOND = 'Invalid bonding interface name {1} in {0}'
88     ERR_NET_MAPPING_CONFLICT = 'Network {1} mapped to multiple interfaces in {0}'
89     ERR_UNTAGGED_INFRA_CONFLICT = 'Multiple untagged networks on interface {1} in {0}'
90     ERR_UNTAGGED_MTU_SIZE = 'Untagged network {1} in {0} has too small MTU, ' + \
91                             'VLAN tagged networks with bigger MTU exists on the same interface'
92
93     ERR_INVALID_PROVIDER_TYPE = \
94         'Invalid provider network type for interface {}, valid types: %s' % \
95         VALID_PROVIDER_TYPES
96     ERR_INVALID_SRIOV_TYPE = \
97         'Invalid sr-iov network type for network {}, valid types: %s' % \
98         VALID_SRIOV_TYPES
99
100     ERR_DPDK_MAX_RX_QUEUES = 'Invalid %s value {}, must be positive integer' % DPDK_MAX_RX_QUEUES
101     ERR_MISSPLACED_MTU = 'Missplaced MTU inside %s interface {}' % PROVIDER_NETWORK_INTERFACES
102     ERR_OVS_TYPE_CONFLICT = 'Cannot have both %s and %s types of provider networks in {}' % \
103         (TYPE_OVS, TYPE_OVS_DPDK)
104     ERR_DPDK_SRIOV_CONFLICT = 'Cannot have both %s and sr-iov on same interface in {}' % \
105         TYPE_OVS_DPDK
106     ERR_OFFLOAD_SRIOV_CONFLICT = 'Cannot have both %s and sr-iov on same profile in {}' % \
107         TYPE_OVS_OFFLOAD_SRIOV
108     ERR_OFFLOAD_DPDK_CONFLICT = 'Cannot have both %s and %s types of provider networks in {}' % \
109         (TYPE_OVS_OFFLOAD_SRIOV, TYPE_OVS_DPDK)
110
111     ERR_INVALID_BONDING_OPTIONS = 'Invalid {1} in {0}, valid options: %s' % VALID_BONDING_OPTIONS
112     ERR_MISSING_BOND = 'Missing bonding interface definition for {1} in {0}'
113     ERR_LACP_SLAVE_COUNT = 'Invalid bonding slave interface count for {1} in {0} ' + \
114         'at least two interfaces required with %s' % MODE_LACP
115     ERR_AB_SLAVE_COUNT = 'Invalid bonding slave interface count for {1} in {0}, ' + \
116         'exactly two interfaces required with %s' % MODE_AB
117     ERR_SLAVE_CONFLICT = 'Same interface mapped to multiple bond interfaces in {}'
118     ERR_SLAVE_IN_NET = 'Network physical interface {1} mapped also as part of bond in {0}'
119
120     ERR_SRIOV_MTU_SIZE = 'SR-IOV network {0} MTU {1} cannot be greater than interface {2} MTU {3}'
121     ERR_SRIOV_INFRA_VLAN_CONFLICT = \
122         'SR-IOV network {} vlan range is conflicting with infra network vlan'
123     ERR_SRIOV_PROVIDER_VLAN_CONFLICT = \
124         'SR-IOV network {} vlan range is conflicting with other provider network vlan'
125     ERR_SINGLE_NIC_VIOLATION = \
126         'Provider and infra networks on the same interface in {}: ' + \
127         'Supported only if all networks on the same interface'
128     ERR_SINGLE_NIC_PROVIDER_TYPE = \
129         'Provider and infra networks on the same interface in {0}: ' + \
130         'Not supported for {1} type of provider networks'
131     ERR_INFRA_PROVIDER_VLAN_CONFLICT = \
132         'Provider network {} vlan range is conflicting with infra network vlan'
133     ERR_INFRA_PROVIDER_UNTAGGED_CONFLICT = \
134         'Sharing untagged infra and provider network {} not supported'
135     ERR_SRIOV_LACP_CONFLICT = 'Bonding mode %s not supported with SR-IOV networks' % MODE_LACP
136     ERR_SRIOV_IFACE_CONFLICT = 'Same interface mapped to multiple SR-IOV networks in {}'
137     ERR_VF_COUNT = 'SR-IOV network {} %s must be positive integer' % VF_COUNT
138
139     ERR_PROVIDER_VLAN_CONFLICT = 'Provider network vlan ranges conflicting on interface {}'
140
141     @staticmethod
142     def err_input_not_dict():
143         err = NetworkProfilesValidation.ERR_INPUT_NOT_DICT
144         raise validation.ValidationError(err)
145
146     @staticmethod
147     def err_missing(context, key):
148         err = NetworkProfilesValidation.ERR_MISSING.format(context, key)
149         raise validation.ValidationError(err)
150
151     @staticmethod
152     def err_not_dict(context, key):
153         err = NetworkProfilesValidation.ERR_NOT_DICT.format(context, key)
154         raise validation.ValidationError(err)
155
156     @staticmethod
157     def err_not_list(context, key):
158         err = NetworkProfilesValidation.ERR_NOT_LIST.format(context, key)
159         raise validation.ValidationError(err)
160
161     @staticmethod
162     def err_not_str(context, key):
163         raise validation.ValidationError(NetworkProfilesValidation.ERR_NOT_STR.format(context, key))
164
165     @staticmethod
166     def err_not_int(context, key):
167         raise validation.ValidationError(NetworkProfilesValidation.ERR_NOT_INT.format(context, key))
168
169     @staticmethod
170     def err_not_bool(context, key):
171         err = NetworkProfilesValidation.ERR_NOT_BOOL.format(context, key)
172         raise validation.ValidationError(err)
173
174     @staticmethod
175     def err_invalid_iface_name(context):
176         err = NetworkProfilesValidation.ERR_INVALID_IFACE_NAME.format(context)
177         raise validation.ValidationError(err)
178
179     @staticmethod
180     def err_iface_name_len(context):
181         err = NetworkProfilesValidation.ERR_IFACE_NAME_LEN.format(context)
182         raise validation.ValidationError(err)
183
184     @staticmethod
185     def err_iface_vlan(context, iface):
186         err = NetworkProfilesValidation.ERR_IFACE_VLAN.format(context, iface)
187         raise validation.ValidationError(err)
188
189     @staticmethod
190     def err_iface_bond(context, iface):
191         err = NetworkProfilesValidation.ERR_IFACE_BOND.format(context, iface)
192         raise validation.ValidationError(err)
193
194     @staticmethod
195     def err_provnet_type(iface):
196         err = NetworkProfilesValidation.ERR_INVALID_PROVIDER_TYPE.format(iface)
197         raise validation.ValidationError(err)
198
199     @staticmethod
200     def err_sriov_type(network):
201         err = NetworkProfilesValidation.ERR_INVALID_SRIOV_TYPE.format(network)
202         raise validation.ValidationError(err)
203
204     @staticmethod
205     def err_dpdk_max_rx_queues(value):
206         err = NetworkProfilesValidation.ERR_DPDK_MAX_RX_QUEUES.format(value)
207         raise validation.ValidationError(err)
208
209     @staticmethod
210     def err_missplaced_mtu(iface):
211         err = NetworkProfilesValidation.ERR_MISSPLACED_MTU.format(iface)
212         raise validation.ValidationError(err)
213
214     @staticmethod
215     def err_iface_not_bond(context, iface):
216         err = NetworkProfilesValidation.ERR_IFACE_NOT_BOND.format(context, iface)
217         raise validation.ValidationError(err)
218
219     @staticmethod
220     def err_bonding_options(profile, options_type):
221         err = NetworkProfilesValidation.ERR_INVALID_BONDING_OPTIONS.format(profile, options_type)
222         raise validation.ValidationError(err)
223
224     @staticmethod
225     def err_missing_bond_def(profile, iface):
226         err = NetworkProfilesValidation.ERR_MISSING_BOND.format(profile, iface)
227         raise validation.ValidationError(err)
228
229     @staticmethod
230     def err_lacp_slave_count(profile, iface):
231         err = NetworkProfilesValidation.ERR_LACP_SLAVE_COUNT.format(profile, iface)
232         raise validation.ValidationError(err)
233
234     @staticmethod
235     def err_ab_slave_count(profile, iface):
236         err = NetworkProfilesValidation.ERR_AB_SLAVE_COUNT.format(profile, iface)
237         raise validation.ValidationError(err)
238
239     @staticmethod
240     def err_slave_conflict(profile):
241         err = NetworkProfilesValidation.ERR_SLAVE_CONFLICT.format(profile)
242         raise validation.ValidationError(err)
243
244     @staticmethod
245     def err_slave_in_net(profile, iface):
246         err = NetworkProfilesValidation.ERR_SLAVE_IN_NET.format(profile, iface)
247         raise validation.ValidationError(err)
248
249     @staticmethod
250     def err_ovs_type_conflict(profile):
251         err = NetworkProfilesValidation.ERR_OVS_TYPE_CONFLICT.format(profile)
252         raise validation.ValidationError(err)
253
254     @staticmethod
255     def err_offload_dpdk_conflict(profile):
256         err = NetworkProfilesValidation.ERR_OFFLOAD_DPDK_CONFLICT.format(profile)
257         raise validation.ValidationError(err)
258
259     @staticmethod
260     def err_dpdk_sriov_conflict(profile):
261         err = NetworkProfilesValidation.ERR_DPDK_SRIOV_CONFLICT.format(profile)
262         raise validation.ValidationError(err)
263
264     @staticmethod
265     def err_offload_sriov_conflict(profile):
266         err = NetworkProfilesValidation.ERR_OFFLOAD_SRIOV_CONFLICT.format(profile)
267         raise validation.ValidationError(err)
268
269     @staticmethod
270     def err_net_mapping_conflict(profile, network):
271         err = NetworkProfilesValidation.ERR_NET_MAPPING_CONFLICT.format(profile, network)
272         raise validation.ValidationError(err)
273
274     @staticmethod
275     def err_untagged_infra_conflict(profile, iface):
276         err = NetworkProfilesValidation.ERR_UNTAGGED_INFRA_CONFLICT.format(profile, iface)
277         raise validation.ValidationError(err)
278
279     @staticmethod
280     def err_untagged_mtu_size(context, network):
281         err = NetworkProfilesValidation.ERR_UNTAGGED_MTU_SIZE.format(context, network)
282         raise validation.ValidationError(err)
283
284     @staticmethod
285     def err_sriov_mtu_size(sriov_net, sriov_mtu, phys_iface, iface_mtu):
286         err = NetworkProfilesValidation.ERR_SRIOV_MTU_SIZE.format(sriov_net, sriov_mtu,
287                                                                   phys_iface, iface_mtu)
288         raise validation.ValidationError(err)
289
290     @staticmethod
291     def err_sriov_infra_vlan_conflict(network):
292         err = NetworkProfilesValidation.ERR_SRIOV_INFRA_VLAN_CONFLICT.format(network)
293         raise validation.ValidationError(err)
294
295     @staticmethod
296     def err_sriov_provider_vlan_conflict(network):
297         err = NetworkProfilesValidation.ERR_SRIOV_PROVIDER_VLAN_CONFLICT.format(network)
298         raise validation.ValidationError(err)
299
300     @staticmethod
301     def err_single_nic_violation(profile):
302         err = NetworkProfilesValidation.ERR_SINGLE_NIC_VIOLATION.format(profile)
303         raise validation.ValidationError(err)
304
305     @staticmethod
306     def err_single_nic_provider_type(profile, provider_type):
307         err = NetworkProfilesValidation.ERR_SINGLE_NIC_PROVIDER_TYPE.format(profile, provider_type)
308         raise validation.ValidationError(err)
309
310     @staticmethod
311     def err_infra_provider_vlan_conflict(network):
312         err = NetworkProfilesValidation.ERR_INFRA_PROVIDER_VLAN_CONFLICT.format(network)
313         raise validation.ValidationError(err)
314
315     @staticmethod
316     def err_infra_provider_untagged_conflict(network):
317         err = NetworkProfilesValidation.ERR_INFRA_PROVIDER_UNTAGGED_CONFLICT.format(network)
318         raise validation.ValidationError(err)
319
320     @staticmethod
321     def err_sriov_lacp_conflict():
322         err = NetworkProfilesValidation.ERR_SRIOV_LACP_CONFLICT
323         raise validation.ValidationError(err)
324
325     @staticmethod
326     def err_sriov_iface_conflict():
327         err = NetworkProfilesValidation.ERR_SRIOV_IFACE_CONFLICT
328         raise validation.ValidationError(err)
329
330     @staticmethod
331     def err_vf_count(network):
332         err = NetworkProfilesValidation.ERR_VF_COUNT.format(network)
333         raise validation.ValidationError(err)
334
335     @staticmethod
336     def err_provider_vlan_conflict(iface):
337         err = NetworkProfilesValidation.ERR_PROVIDER_VLAN_CONFLICT.format(iface)
338         raise validation.ValidationError(err)
339
340     @staticmethod
341     def is_dict(conf):
342         return isinstance(conf, dict)
343
344     @staticmethod
345     def is_bond_iface(iface):
346         return re.match(NetworkProfilesValidation.BOND_NAME_MATCH, iface)
347
348     @staticmethod
349     def is_non_empty_dict(conf):
350         return isinstance(conf, dict) and len(conf) > 0
351
352     @staticmethod
353     def key_exists(conf_dict, key):
354         return key in conf_dict
355
356     @staticmethod
357     def val_is_int(conf_dict, key):
358         return isinstance(conf_dict[key], (int, long))
359
360     @staticmethod
361     def val_is_bool(conf_dict, key):
362         return isinstance(conf_dict[key], bool)
363
364     @staticmethod
365     def val_is_str(conf_dict, key):
366         return isinstance(conf_dict[key], basestring)
367
368     @staticmethod
369     def val_is_non_empty_list(conf_dict, key):
370         return (isinstance(conf_dict[key], list) and
371                 len(conf_dict[key]) > 0 and
372                 len(conf_dict[key]) == len(set(conf_dict[key])))
373
374     @staticmethod
375     def val_is_non_empty_dict(conf_dict, key):
376         return NetworkProfilesValidation.is_non_empty_dict(conf_dict[key])
377
378     @staticmethod
379     def key_must_exist(conf_dict, entry, key):
380         if not NetworkProfilesValidation.key_exists(conf_dict[entry], key):
381             NetworkProfilesValidation.err_missing(entry, key)
382
383     @staticmethod
384     def must_be_str(conf_dict, entry, key):
385         NetworkProfilesValidation.key_must_exist(conf_dict, entry, key)
386         if not NetworkProfilesValidation.val_is_str(conf_dict[entry], key):
387             NetworkProfilesValidation.err_not_str(entry, key)
388
389     @staticmethod
390     def must_be_list(conf_dict, entry, key):
391         NetworkProfilesValidation.key_must_exist(conf_dict, entry, key)
392         if not NetworkProfilesValidation.val_is_non_empty_list(conf_dict[entry], key):
393             NetworkProfilesValidation.err_not_list(entry, key)
394
395     @staticmethod
396     def must_be_dict(conf_dict, entry, key):
397         NetworkProfilesValidation.key_must_exist(conf_dict, entry, key)
398         if not NetworkProfilesValidation.val_is_non_empty_dict(conf_dict[entry], key):
399             NetworkProfilesValidation.err_not_dict(entry, key)
400
401     @staticmethod
402     def exists_as_dict(conf_dict, entry, key):
403         if not NetworkProfilesValidation.key_exists(conf_dict[entry], key):
404             return False
405         if not NetworkProfilesValidation.val_is_non_empty_dict(conf_dict[entry], key):
406             NetworkProfilesValidation.err_not_dict(entry, key)
407         return True
408
409     @staticmethod
410     def exists_as_int(conf_dict, entry, key):
411         if not NetworkProfilesValidation.key_exists(conf_dict[entry], key):
412             return False
413         if not NetworkProfilesValidation.val_is_int(conf_dict[entry], key):
414             NetworkProfilesValidation.err_not_int(entry, key)
415         return True
416
417     @staticmethod
418     def are_overlapping(ranges1, ranges2):
419         for range1 in ranges1:
420             for range2 in ranges2:
421                 if not (range1[0] > range2[1] or range1[1] < range2[0]):
422                     return True
423         return False
424
425     def __init__(self):
426         cmvalidator.CMValidator.__init__(self)
427         self.conf = None
428         self.networking = None
429
430     def get_subscription_info(self):
431         return self.SUBSCRIPTION
432
433     def validate_set(self, props):
434         if not self.is_dict(props):
435             self.err_input_not_dict()
436
437         if not (self.key_exists(props, self.DOMAIN) or
438                 self.key_exists(props, self.NETWORKING)):
439             self.err_missing(self.INPUT_ERR_CONTEXT,
440                              '{} or {}'.format(self.DOMAIN, self.NETWORKING))
441
442         if self.key_exists(props, self.DOMAIN):
443             if not props[self.DOMAIN]:
444                 self.err_not_dict(self.INPUT_ERR_CONTEXT, self.DOMAIN)
445             self.conf = json.loads(props[self.DOMAIN])
446         else:
447             self.conf = json.loads(self.get_plugin_client().get_property(self.DOMAIN))
448
449         if not self.is_non_empty_dict(self.conf):
450             self.err_not_dict(self.INPUT_ERR_CONTEXT, self.DOMAIN)
451
452         if self.key_exists(props, self.NETWORKING):
453             if not props[self.NETWORKING]:
454                 self.err_not_dict(self.INPUT_ERR_CONTEXT, self.NETWORKING)
455             self.networking = json.loads(props[self.NETWORKING])
456         else:
457             self.networking = json.loads(self.get_plugin_client().get_property(self.NETWORKING))
458
459         if not self.is_non_empty_dict(self.networking):
460             self.err_not_dict(self.INPUT_ERR_CONTEXT, self.NETWORKING)
461
462         self.validate()
463
464     def validate(self):
465         for profile_name in self.conf:
466             if not self.val_is_non_empty_dict(self.conf, profile_name):
467                 self.err_not_dict(self.DOMAIN, profile_name)
468             self.validate_network_profile(profile_name)
469
470     def validate_network_profile(self, profile_name):
471         self.validate_interface_net_mapping(profile_name)
472         self.validate_bonding_interfaces(profile_name)
473         self.validate_bonding_options(profile_name)
474         self.validate_provider_net_ifaces(profile_name)
475         self.validate_network_integrity(profile_name)
476         self.validate_sriov_provider_networks(profile_name)
477         self.validate_provider_networks(profile_name)
478
479     def validate_interface_net_mapping(self, profile_name):
480         self.must_be_dict(self.conf, profile_name, self.INTERFACE_NET_MAPPING)
481         networks = []
482         for iface in self.conf[profile_name][self.INTERFACE_NET_MAPPING]:
483             self.validate_iface_name(self.INTERFACE_NET_MAPPING, iface)
484             self.validate_not_vlan(self.INTERFACE_NET_MAPPING, iface)
485             self.must_be_list(self.conf[profile_name], self.INTERFACE_NET_MAPPING, iface)
486             iface_nets = self.conf[profile_name][self.INTERFACE_NET_MAPPING][iface]
487             self.validate_used_infra_networks_defined(iface_nets)
488             for domain in self.get_network_domains(iface_nets):
489                 self.validate_untagged_infra_integrity(iface_nets, iface, profile_name, domain)
490             networks.extend(iface_nets)
491         self.validate_networks_mapped_only_once(profile_name, networks)
492
493     def validate_used_infra_networks_defined(self, networks):
494         for net in networks:
495             if not self.key_exists(self.networking, net):
496                 self.err_missing(self.NETWORKING, net)
497             self.must_be_dict(self.networking, net, self.NETWORK_DOMAINS)
498             for domain in self.networking[net][self.NETWORK_DOMAINS]:
499                 self.must_be_dict(self.networking[net], self.NETWORK_DOMAINS, domain)
500
501     def get_network_domains(self, networks):
502         domains = set()
503         for net in networks:
504             domains.update(self.networking[net][self.NETWORK_DOMAINS].keys())
505         return domains
506
507     def validate_untagged_infra_integrity(self, iface_nets, iface, profile_name, network_domain):
508         untagged_infras = []
509         untagged_mtu = None
510         max_vlan_mtu = 0
511         default_mtu = self.get_default_mtu()
512
513         for net in iface_nets:
514             if self.key_exists(self.networking[net][self.NETWORK_DOMAINS], network_domain):
515                 if not self.key_exists(self.networking[net][self.NETWORK_DOMAINS][network_domain],
516                                        self.VLAN):
517                     untagged_infras.append(net)
518                     if self.exists_as_int(self.networking, net, self.MTU):
519                         untagged_mtu = self.networking[net][self.MTU]
520                     else:
521                         untagged_mtu = default_mtu
522                 else:
523                     if self.exists_as_int(self.networking, net, self.MTU):
524                         mtu = self.networking[net][self.MTU]
525                     else:
526                         mtu = default_mtu
527                     if mtu > max_vlan_mtu:
528                         max_vlan_mtu = mtu
529
530         if not utils.is_virtualized():
531             if len(untagged_infras) > 1:
532                 self.err_untagged_infra_conflict(profile_name, iface)
533
534         if untagged_mtu and untagged_mtu < max_vlan_mtu:
535             self.err_untagged_mtu_size(self.NETWORKING, untagged_infras[0])
536
537     def validate_bonding_interfaces(self, profile_name):
538         slaves = []
539         if self.exists_as_dict(self.conf, profile_name, self.BONDING_INTERFACES):
540             for iface in self.conf[profile_name][self.BONDING_INTERFACES]:
541                 self.validate_iface_name(self.BONDING_INTERFACES, iface)
542                 if not self.is_bond_iface(iface):
543                     self.err_iface_not_bond(self.BONDING_INTERFACES, iface)
544                 self.must_be_list(self.conf[profile_name], self.BONDING_INTERFACES, iface)
545                 for slave in self.conf[profile_name][self.BONDING_INTERFACES][iface]:
546                     self.validate_bond_slave(iface, slave)
547                     slaves.append(slave)
548             if len(slaves) != len(set(slaves)):
549                 self.err_slave_conflict(profile_name)
550
551     def validate_bond_slave(self, iface, slave):
552         self.validate_iface_name(iface, slave)
553         self.validate_not_vlan(iface, slave)
554         self.validate_not_bond(iface, slave)
555
556     def validate_not_bond(self, context, iface):
557         if 'bond' in iface:
558             self.err_iface_bond(context, iface)
559
560     def validate_bonding_options(self, profile_name):
561         self.validate_bonding_option(profile_name, self.LINUX_BONDING_OPTIONS)
562         self.validate_bonding_option(profile_name, self.OVS_BONDING_OPTIONS)
563
564     def validate_bonding_option(self, profile_name, options_type):
565         if self.key_exists(self.conf[profile_name], options_type):
566             if self.conf[profile_name][options_type] not in self.VALID_BONDING_OPTIONS:
567                 self.err_bonding_options(profile_name, options_type)
568
569     def validate_provider_net_ifaces(self, profile_name):
570         if self.exists_as_dict(self.conf, profile_name, self.PROVIDER_NETWORK_INTERFACES):
571             types = set()
572             networks = []
573             for iface in self.conf[profile_name][self.PROVIDER_NETWORK_INTERFACES]:
574                 self.validate_iface_name(self.PROVIDER_NETWORK_INTERFACES, iface)
575                 self.validate_not_vlan(self.PROVIDER_NETWORK_INTERFACES, iface)
576                 provnet_ifaces_conf = self.conf[profile_name][self.PROVIDER_NETWORK_INTERFACES]
577                 self.validate_provider_net_type(provnet_ifaces_conf, iface)
578                 self.validate_provider_net_vf_count(provnet_ifaces_conf, iface)
579                 self.validate_dpdk_max_rx_queues(provnet_ifaces_conf, iface)
580                 self.validate_no_mtu(provnet_ifaces_conf, iface)
581                 self.must_be_list(provnet_ifaces_conf, iface, self.PROVIDER_NETWORKS)
582                 types.add(provnet_ifaces_conf[iface][self.TYPE])
583                 networks.extend(provnet_ifaces_conf[iface][self.PROVIDER_NETWORKS])
584             if self.TYPE_OVS_DPDK in types and self.TYPE_OVS in types:
585                 self.err_ovs_type_conflict(profile_name)
586             if self.TYPE_OVS_DPDK in types and self.TYPE_OVS_OFFLOAD_SRIOV in types:
587                 self.err_offload_dpdk_conflict(profile_name)
588             self.validate_networks_mapped_only_once(profile_name, networks)
589             self.validate_used_provider_networks_defined(networks)
590
591     def validate_sriov_provider_networks(self, profile_name):
592         if self.exists_as_dict(self.conf, profile_name, self.SRIOV_PROVIDER_NETWORKS):
593             networks = self.conf[profile_name][self.SRIOV_PROVIDER_NETWORKS]
594             self.validate_used_provider_networks_defined(networks)
595             sriov_ifaces = []
596             for network in networks:
597                 if (self.exists_as_int(networks, network, self.VF_COUNT) and
598                         networks[network][self.VF_COUNT] < 1):
599                     self.err_vf_count(network)
600                 if (self.key_exists(networks[network], self.TRUSTED) and
601                         not self.val_is_bool(networks[network], self.TRUSTED)):
602                     self.err_not_bool(network, self.TRUSTED)
603                 if (self.key_exists(networks[network], self.TYPE) and
604                         networks[network][self.TYPE] not in self.VALID_SRIOV_TYPES):
605                     self.err_sriov_type(network)
606                 self.must_be_list(networks, network, self.INTERFACES)
607                 for iface in networks[network][self.INTERFACES]:
608                     sriov_ifaces.append(iface)
609                     self.validate_iface_name(network, iface)
610                     self.validate_not_vlan(network, iface)
611                     self.validate_not_bond(network, iface)
612                     self.validate_not_part_of_lacp(self.conf[profile_name], iface)
613                     infra_info = self.get_iface_infra_info(self.conf[profile_name], iface)
614                     if infra_info is not None:
615                         self.validate_shared_sriov_infra(network, iface, infra_info)
616                     provider_info = self.get_iface_provider_info(self.conf[profile_name], iface)
617                     if provider_info[self.TYPE] == self.TYPE_OVS_DPDK:
618                         self.err_dpdk_sriov_conflict(profile_name)
619                     if provider_info[self.TYPE] == self.TYPE_OVS_OFFLOAD_SRIOV:
620                         self.err_offload_sriov_conflict(profile_name)
621                     if provider_info[self.VLAN_RANGES]:
622                         self.validate_shared_sriov_provider(network,
623                                                             provider_info[self.VLAN_RANGES])
624             if len(sriov_ifaces) != len(set(sriov_ifaces)):
625                 self.err_sriov_iface_conflict()
626
627     def validate_provider_networks(self, profile_name):
628         if self.key_exists(self.conf[profile_name], self.PROVIDER_NETWORK_INTERFACES):
629             for iface in self.conf[profile_name][self.PROVIDER_NETWORK_INTERFACES]:
630                 iface_info = self.conf[profile_name][self.PROVIDER_NETWORK_INTERFACES][iface]
631                 vlan_ranges_list = []
632                 for network in iface_info[self.PROVIDER_NETWORKS]:
633                     vlan_ranges = self.get_vlan_ranges(network)
634                     vlan_ranges_list.append(vlan_ranges)
635                     infra_info = self.get_iface_infra_info(self.conf[profile_name], iface)
636                     if infra_info is not None:
637                         if (len(self.conf[profile_name][self.PROVIDER_NETWORK_INTERFACES]) > 1 or
638                                 len(self.conf[profile_name][self.INTERFACE_NET_MAPPING]) > 1):
639                             self.err_single_nic_violation(profile_name)
640                         if iface_info[self.TYPE] in self.SINGLE_NIC_UNSUPPORTED_TYPES:
641                             self.err_single_nic_provider_type(profile_name, iface_info[self.TYPE])
642                         self.validate_shared_infra_provider(network, infra_info, vlan_ranges)
643                 for idx, ranges1 in enumerate(vlan_ranges_list):
644                     for ranges2 in vlan_ranges_list[(idx+1):]:
645                         if self.are_overlapping(ranges1, ranges2):
646                             self.err_provider_vlan_conflict(iface)
647
648     def validate_not_part_of_lacp(self, profile_conf, iface):
649         if self.key_exists(profile_conf, self.PROVIDER_NETWORK_INTERFACES):
650             for prov_iface, prov in profile_conf[self.PROVIDER_NETWORK_INTERFACES].iteritems():
651                 if self.is_bond_iface(prov_iface):
652                     if iface in profile_conf[self.BONDING_INTERFACES][prov_iface]:
653                         bonding_type = self.OVS_BONDING_OPTIONS \
654                             if prov[self.TYPE] != self.TYPE_CAAS else self.LINUX_BONDING_OPTIONS
655                         if profile_conf[bonding_type] == self.MODE_LACP:
656                             self.err_sriov_lacp_conflict()
657                         # part of ovs bonding
658                         # do not check linux bonding options even if shared with infra networks
659                         return
660         for infra_iface in profile_conf[self.INTERFACE_NET_MAPPING]:
661             if self.is_bond_iface(infra_iface):
662                 if iface in profile_conf[self.BONDING_INTERFACES][infra_iface]:
663                     if profile_conf[self.LINUX_BONDING_OPTIONS] == self.MODE_LACP:
664                         self.err_sriov_lacp_conflict()
665                     break
666
667     def validate_shared_sriov_infra(self, sriov_net, iface, infra_info):
668         sriov_info = self.get_sriov_info(sriov_net)
669         if sriov_info[self.MTU] > infra_info[self.MTU]:
670             self.err_sriov_mtu_size(sriov_net, sriov_info[self.MTU], iface, infra_info[self.MTU])
671         for vlan_range in sriov_info[self.VLAN_RANGES]:
672             for infra_vlan in infra_info[self.VLAN]:
673                 if not (infra_vlan < vlan_range[0] or infra_vlan > vlan_range[1]):
674                     self.err_sriov_infra_vlan_conflict(sriov_net)
675
676     def validate_shared_sriov_provider(self, sriov_net, ovs_vlan_ranges):
677         sriov_vlan_ranges = self.get_vlan_ranges(sriov_net)
678         if self.are_overlapping(sriov_vlan_ranges, ovs_vlan_ranges):
679             self.err_sriov_provider_vlan_conflict(sriov_net)
680
681     def validate_shared_infra_provider(self, provider_net, infra_info, vlan_ranges):
682         if infra_info[self.UNTAGGED]:
683             self.err_infra_provider_untagged_conflict(provider_net)
684         for vlan in infra_info[self.VLAN]:
685             for vlan_range in vlan_ranges:
686                 if not (vlan_range[0] > vlan or vlan_range[1] < vlan):
687                     self.err_infra_provider_vlan_conflict(provider_net)
688
689     def get_iface_infra_info(self, profile_conf, iface):
690         infra_info = {self.VLAN: [], self.MTU: 0, self.UNTAGGED: False}
691         default_mtu = self.get_default_mtu()
692         infra_iface = self.get_master_iface(profile_conf, iface)
693
694         if self.key_exists(profile_conf[self.INTERFACE_NET_MAPPING], infra_iface):
695             for infra in profile_conf[self.INTERFACE_NET_MAPPING][infra_iface]:
696                 for domain in self.networking[infra][self.NETWORK_DOMAINS].itervalues():
697                     if self.key_exists(domain, self.VLAN):
698                         infra_info[self.VLAN].append(domain[self.VLAN])
699                     else:
700                         infra_info[self.UNTAGGED] = True
701                 if self.exists_as_int(self.networking, infra, self.MTU):
702                     mtu = self.networking[infra][self.MTU]
703                 else:
704                     mtu = default_mtu
705                 if mtu > infra_info[self.MTU]:
706                     infra_info[self.MTU] = mtu
707
708         if infra_info[self.MTU] == 0:
709             return None
710
711         return infra_info
712
713     def get_iface_provider_info(self, profile_conf, iface):
714         provider_info = {self.TYPE: None, self.VLAN_RANGES: []}
715         provider_iface = self.get_master_iface(profile_conf, iface)
716
717         if self.key_exists(profile_conf, self.PROVIDER_NETWORK_INTERFACES):
718             if self.key_exists(profile_conf[self.PROVIDER_NETWORK_INTERFACES], provider_iface):
719                 iface_info = profile_conf[self.PROVIDER_NETWORK_INTERFACES][provider_iface]
720                 provider_info[self.TYPE] = iface_info[self.TYPE]
721                 for network in iface_info[self.PROVIDER_NETWORKS]:
722                     provider_info[self.VLAN_RANGES].extend(self.get_vlan_ranges(network))
723
724         return provider_info
725
726     def get_master_iface(self, profile_conf, slave_iface):
727         if self.key_exists(profile_conf, self.BONDING_INTERFACES):
728             for bond in profile_conf[self.BONDING_INTERFACES]:
729                 if slave_iface in profile_conf[self.BONDING_INTERFACES][bond]:
730                     return bond
731         return slave_iface
732
733     def get_sriov_info(self, network):
734         sriov_info = {self.VLAN_RANGES: []}
735         if self.exists_as_int(self.networking[self.PROVIDER_NETWORKS], network, self.MTU):
736             sriov_info[self.MTU] = self.networking[self.PROVIDER_NETWORKS][network][self.MTU]
737         else:
738             sriov_info[self.MTU] = self.get_default_mtu()
739         sriov_info[self.VLAN_RANGES] = self.get_vlan_ranges(network)
740         return sriov_info
741
742     def get_vlan_ranges(self, network):
743         vlan_ranges = []
744         networks = self.networking[self.PROVIDER_NETWORKS]
745         self.must_be_str(networks, network, self.VLAN_RANGES)
746         for vlan_range in networks[network][self.VLAN_RANGES].split(','):
747             vids = vlan_range.split(':')
748             if len(vids) != 2:
749                 break
750             try:
751                 start = int(vids[0])
752                 end = int(vids[1])
753             except ValueError:
754                 break
755             if end >= start:
756                 vlan_ranges.append([start, end])
757         return vlan_ranges
758
759     def get_default_mtu(self):
760         if (self.key_exists(self.networking, self.MTU) and
761                 self.val_is_int(self.networking, self.MTU)):
762             return self.networking[self.MTU]
763         return self.DEFAULT_MTU
764
765     def validate_iface_name(self, context, iface):
766         if not isinstance(iface, basestring) or not re.match(self.IFACE_NAME_MATCH, iface, re.IGNORECASE):
767             self.err_invalid_iface_name(context)
768         if len(iface) > self.MAX_IFACE_NAME_LEN:
769             self.err_iface_name_len(context)
770
771     def validate_not_vlan(self, context, iface):
772         if 'vlan' in iface:
773             self.err_iface_vlan(context, iface)
774
775     def validate_provider_net_type(self, provnet_ifaces_conf, iface):
776         self.must_be_str(provnet_ifaces_conf, iface, self.TYPE)
777         if provnet_ifaces_conf[iface][self.TYPE] not in self.VALID_PROVIDER_TYPES:
778             self.err_provnet_type(iface)
779
780     def validate_provider_net_vf_count(self, provnet_ifaces_conf, iface):
781         if self.exists_as_int(provnet_ifaces_conf, iface, self.VF_COUNT):
782             value = provnet_ifaces_conf[iface][self.VF_COUNT]
783             if value < 1:
784                 self.err_vf_count(iface)
785
786     def validate_dpdk_max_rx_queues(self, provnet_ifaces_conf, iface):
787         if self.exists_as_int(provnet_ifaces_conf, iface, self.DPDK_MAX_RX_QUEUES):
788             value = provnet_ifaces_conf[iface][self.DPDK_MAX_RX_QUEUES]
789             if value < 1:
790                 self.err_dpdk_max_rx_queues(value)
791
792     def validate_no_mtu(self, provnet_ifaces_conf, iface):
793         if self.key_exists(provnet_ifaces_conf[iface], self.MTU):
794             self.err_missplaced_mtu(iface)
795
796     def validate_networks_mapped_only_once(self, profile_name, networks):
797         prev_net = None
798         for net in sorted(networks):
799             if net == prev_net:
800                 self.err_net_mapping_conflict(profile_name, net)
801             prev_net = net
802
803     def validate_used_provider_networks_defined(self, networks):
804         for net in networks:
805             self.key_must_exist(self.networking, self.PROVIDER_NETWORKS, net)
806
807     def validate_network_integrity(self, profile_name):
808         provider_ifaces = []
809         if self.key_exists(self.conf[profile_name], self.PROVIDER_NETWORK_INTERFACES):
810             for iface in self.conf[profile_name][self.PROVIDER_NETWORK_INTERFACES]:
811                 iface_data = self.conf[profile_name][self.PROVIDER_NETWORK_INTERFACES][iface]
812                 bonding_type = self.OVS_BONDING_OPTIONS \
813                     if iface_data[self.TYPE] != self.TYPE_CAAS else self.LINUX_BONDING_OPTIONS
814                 self.validate_net_iface_integrity(profile_name, iface, bonding_type)
815                 provider_ifaces.append(iface)
816         for iface in self.conf[profile_name][self.INTERFACE_NET_MAPPING]:
817             if iface not in provider_ifaces:
818                 self.validate_net_iface_integrity(profile_name, iface, self.LINUX_BONDING_OPTIONS)
819
820     def validate_net_iface_integrity(self, profile_name, iface, bonding_type):
821         if self.is_bond_iface(iface):
822             if (not self.key_exists(self.conf[profile_name], self.BONDING_INTERFACES) or
823                     iface not in self.conf[profile_name][self.BONDING_INTERFACES]):
824                 self.err_missing_bond_def(profile_name, iface)
825             self.key_must_exist(self.conf, profile_name, bonding_type)
826             self.validate_bond_slave_count(profile_name, iface,
827                                            self.conf[profile_name][bonding_type])
828         elif self.key_exists(self.conf[profile_name], self.BONDING_INTERFACES):
829             for bond in self.conf[profile_name][self.BONDING_INTERFACES]:
830                 for slave in self.conf[profile_name][self.BONDING_INTERFACES][bond]:
831                     if iface == slave:
832                         self.err_slave_in_net(profile_name, iface)
833
834     def validate_bond_slave_count(self, profile_name, iface, bonding_mode):
835         slave_count = len(self.conf[profile_name][self.BONDING_INTERFACES][iface])
836         if bonding_mode == self.MODE_AB and slave_count != 2:
837             self.err_ab_slave_count(profile_name, iface)
838         elif bonding_mode == self.MODE_LACP and slave_count < 2:
839             self.err_lacp_slave_count(profile_name, iface)