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