1 # Copyright (C) 2014 Nippon Telegraph and Telephone Corporation.
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
17 Module provides utilities for validation.
23 from ryu.lib import ip
26 def is_valid_mac(mac):
27 """Returns True if the given MAC address is valid.
29 The given MAC address should be a colon hexadecimal notation string.
32 - valid address: aa:bb:cc:dd:ee:ff, 11:22:33:44:55:66
33 - invalid address: aa:bb:cc:dd, 11-22-33-44-55-66, etc.
35 return bool(re.match(r'^' + r'[\:\-]'.join([r'([0-9a-f]{2})'] * 6)
39 def is_valid_ip_prefix(prefix, bits):
40 """Returns True if *prefix* is a valid IPv4 or IPv6 address prefix.
42 *prefix* should be a number between 0 to *bits* length.
45 # Prefix should be a number
50 # Prefix should be a number between 0 to *bits*
51 return 0 <= prefix <= bits
54 def is_valid_ipv4(ipv4):
55 """Returns True if given is a valid ipv4 address.
57 Given value should be a dot-decimal notation string.
60 - valid address: 10.0.0.1, 192.168.0.1
61 - invalid address: 11.0.0, 192:168:0:1, etc.
63 return ip.valid_ipv4(ipv4)
66 def is_valid_ipv4_prefix(ipv4_prefix):
67 """Returns True if *ipv4_prefix* is a valid prefix with mask.
70 - valid prefix: 1.1.1.0/32, 244.244.244.1/10
71 - invalid prefix: 255.2.2.2/2, 2.2.2/22, etc.
73 if not isinstance(ipv4_prefix, str):
76 tokens = ipv4_prefix.split('/')
80 # Validate address/mask and return
81 return is_valid_ipv4(tokens[0]) and is_valid_ip_prefix(tokens[1], 32)
84 def is_valid_ipv6(ipv6):
85 """Returns True if given `ipv6` is a valid IPv6 address
87 return ip.valid_ipv6(ipv6)
90 def is_valid_ipv6_prefix(ipv6_prefix):
91 """Returns True if given `ipv6_prefix` is a valid IPv6 prefix."""
94 if not isinstance(ipv6_prefix, str):
97 tokens = ipv6_prefix.split('/')
101 # Validate address/mask and return
102 return is_valid_ipv6(tokens[0]) and is_valid_ip_prefix(tokens[1], 128)
105 def is_valid_old_asn(asn):
106 """Returns True if the given AS number is Two Octet."""
107 return isinstance(asn, numbers.Integral) and 0 <= asn <= 0xffff
110 def is_valid_asn(asn):
111 """Returns True if the given AS number is Two or Four Octet."""
112 return isinstance(asn, numbers.Integral) and 0 <= asn <= 0xffffffff
115 def is_valid_vpnv4_prefix(prefix):
116 """Returns True if given prefix is a string represent vpnv4 prefix.
118 Vpnv4 prefix is made up of RD:Ipv4, where RD is represents route
119 distinguisher and Ipv4 represents valid dot-decimal ipv4 notation string.
121 if not isinstance(prefix, str):
124 # Split the prefix into route distinguisher and IP
125 tokens = prefix.split(':', 2)
129 # Validate route distinguisher
130 if not is_valid_route_dist(':'.join([tokens[0], tokens[1]])):
133 # Validate IPv4 prefix and return
134 return is_valid_ipv4_prefix(tokens[2])
137 def is_valid_vpnv6_prefix(prefix):
138 """Returns True if given prefix is a string represent vpnv6 prefix.
140 Vpnv6 prefix is made up of RD:Ipv6, where RD is represents route
141 distinguisher and Ipv6 represents valid colon hexadecimal notation string.
143 if not isinstance(prefix, str):
146 # Split the prefix into route distinguisher and IP
147 tokens = prefix.split(':', 2)
151 # Validate route distinguisher
152 if not is_valid_route_dist(':'.join([tokens[0], tokens[1]])):
155 # Validate IPv6 prefix and return
156 return is_valid_ipv6_prefix(tokens[2])
159 def is_valid_med(med):
160 """Returns True if value of *med* is valid as per RFC.
162 According to RFC MED is a four octet non-negative integer and
163 value '((2 ** 32) - 1) = 0xffffffff' denotes an "infinity" metric.
165 return isinstance(med, numbers.Integral) and 0 <= med <= 0xffffffff
168 def is_valid_mpls_label(label):
169 """Validates `label` according to MPLS label rules
173 A value of 0 represents the "IPv4 Explicit NULL Label".
174 A value of 1 represents the "Router Alert Label".
175 A value of 2 represents the "IPv6 Explicit NULL Label".
176 A value of 3 represents the "Implicit NULL Label".
177 Values 4-15 are reserved.
179 if (not isinstance(label, numbers.Integral) or
180 (4 <= label <= 15) or
181 (label < 0 or label > 2 ** 20)):
187 def is_valid_mpls_labels(labels):
188 """Returns True if the given value is a list of valid MPLS labels.
190 if not isinstance(labels, (list, tuple)):
194 if not is_valid_mpls_label(label):
200 def is_valid_route_dist(route_dist):
201 """Validates *route_dist* as string representation of route distinguisher.
203 Returns True if *route_dist* is as per our convention of RD, else False.
204 Our convention is to represent RD as a string in format:
205 *admin_sub_field:assigned_num_field* and *admin_sub_field* can be valid
206 IPv4 string representation.
207 Valid examples: '65000:222', '1.2.3.4:4432'.
208 Invalid examples: '1.11.1: 333'
210 # TODO(PH): Provide complete implementation.
211 return is_valid_ext_comm_attr(route_dist)
214 def is_valid_ext_comm_attr(attr):
215 """Validates *attr* as string representation of RT or SOO.
217 Returns True if *attr* is as per our convention of RT or SOO, else
218 False. Our convention is to represent RT/SOO is a string with format:
219 *global_admin_part:local_admin_path*
221 if not isinstance(attr, str):
224 tokens = attr.rsplit(':', 1)
230 if not is_valid_ipv4(tokens[0]):
235 except (ValueError, socket.error):
241 def is_valid_esi(esi):
242 """Returns True if the given EVPN Ethernet SegmentEthernet ID is valid."""
243 if isinstance(esi, numbers.Integral):
244 return 0 <= esi <= 0xffffffffffffffffff
245 return isinstance(esi, dict)
248 def is_valid_ethernet_tag_id(etag_id):
249 """Returns True if the given EVPN Ethernet Tag ID is valid.
251 Ethernet Tag ID should be a 32-bit field number.
253 return isinstance(etag_id, numbers.Integral) and 0 <= etag_id <= 0xffffffff
256 def is_valid_vni(vni):
257 """Returns True if the given Virtual Network Identifier for VXLAN
260 Virtual Network Identifier should be a 24-bit field number.
262 return isinstance(vni, numbers.Integral) and 0 <= vni <= 0xffffff