示例#1
0
def _validate_allowed_address_pairs(address_pairs, valid_values=None):
    unique_check = {}
    for address_pair in address_pairs:
        # mac_address is optional, if not set we use the mac on the port
        if 'mac_address' in address_pair:
            msg = attr._validate_mac_address(address_pair['mac_address'])
            if msg:
                raise webob.exc.HTTPBadRequest(msg)
        if 'ip_address' not in address_pair:
            raise AllowedAddressPairsMissingIP()

        mac = address_pair.get('mac_address')
        ip_address = address_pair['ip_address']
        if (mac, ip_address) not in unique_check:
            unique_check[(mac, ip_address)] = None
        else:
            raise DuplicateAddressPairInRequest(mac_address=mac,
                                                ip_address=ip_address)

        invalid_attrs = set(address_pair.keys()) - set(['mac_address',
                                                        'ip_address'])
        if invalid_attrs:
            msg = (_("Unrecognized attribute(s) '%s'") %
                   ', '.join(set(address_pair.keys()) -
                             set(['mac_address', 'ip_address'])))
            raise webob.exc.HTTPBadRequest(msg)

        if '/' in ip_address:
            msg = attr._validate_subnet(ip_address)
        else:
            msg = attr._validate_ip_address(ip_address)
        if msg:
            raise webob.exc.HTTPBadRequest(msg)
示例#2
0
def _validate_gbproutes(data, valid_values=None):
    # Shamelessly copied from Neutron, will pass even if nexthop is valid
    if not isinstance(data, list):
        msg = _("Invalid data format for hostroute: '%s'") % data
        LOG.debug(msg)
        return msg

    expected_keys = ['destination', 'nexthop']
    hostroutes = []
    for hostroute in data:
        msg = attr._verify_dict_keys(expected_keys, hostroute)
        if msg:
            LOG.debug(msg)
            return msg
        msg = attr._validate_subnet(hostroute['destination'])
        if msg:
            LOG.debug(msg)
            return msg
        if hostroute['nexthop'] is not None:
            msg = attr._validate_ip_address(hostroute['nexthop'])
        if msg:
            LOG.debug(msg)
            return msg
        if hostroute in hostroutes:
            msg = _("Duplicate hostroute '%s'") % hostroute
            LOG.debug(msg)
            return msg
        hostroutes.append(hostroute)
示例#3
0
def _validate_allowed_address_pairs(address_pairs, valid_values=None):
    unique_check = {}
    for address_pair in address_pairs:
        # mac_address is optional, if not set we use the mac on the port
        if 'mac_address' in address_pair:
            msg = attr._validate_mac_address(address_pair['mac_address'])
            if msg:
                raise webob.exc.HTTPBadRequest(msg)
        if 'ip_address' not in address_pair:
            raise AllowedAddressPairsMissingIP()

        mac = address_pair.get('mac_address')
        ip_address = address_pair['ip_address']
        if (mac, ip_address) not in unique_check:
            unique_check[(mac, ip_address)] = None
        else:
            raise DuplicateAddressPairInRequest(mac_address=mac,
                                                ip_address=ip_address)

        invalid_attrs = set(address_pair.keys()) - set(
            ['mac_address', 'ip_address'])
        if invalid_attrs:
            msg = (_("Unrecognized attribute(s) '%s'") % ', '.join(
                set(address_pair.keys()) - set(['mac_address', 'ip_address'])))
            raise webob.exc.HTTPBadRequest(msg)

        if '/' in ip_address:
            msg = attr._validate_subnet(ip_address)
        else:
            msg = attr._validate_ip_address(ip_address)
        if msg:
            raise webob.exc.HTTPBadRequest(msg)
示例#4
0
def _validate_allowed_address_pairs(address_pairs, valid_values=None):
    unique_check = {}
    if len(address_pairs) > cfg.CONF.max_allowed_address_pair:
        raise AllowedAddressPairExhausted(quota=cfg.CONF.max_allowed_address_pair)

    for address_pair in address_pairs:
        # mac_address is optional, if not set we use the mac on the port
        if "mac_address" in address_pair:
            msg = attr._validate_mac_address(address_pair["mac_address"])
            if msg:
                raise webob.exc.HTTPBadRequest(msg)
        if "ip_address" not in address_pair:
            raise AllowedAddressPairsMissingIP()

        mac = address_pair.get("mac_address")
        ip_address = address_pair["ip_address"]
        if (mac, ip_address) not in unique_check:
            unique_check[(mac, ip_address)] = None
        else:
            raise DuplicateAddressPairInRequest(mac_address=mac, ip_address=ip_address)

        invalid_attrs = set(address_pair.keys()) - set(["mac_address", "ip_address"])
        if invalid_attrs:
            msg = _("Unrecognized attribute(s) '%s'") % ", ".join(
                set(address_pair.keys()) - set(["mac_address", "ip_address"])
            )
            raise webob.exc.HTTPBadRequest(msg)

        if "/" in ip_address:
            msg = attr._validate_subnet(ip_address)
        else:
            msg = attr._validate_ip_address(ip_address)
        if msg:
            raise webob.exc.HTTPBadRequest(msg)
def _validate_gbproutes(data, valid_values=None):
    # Shamelessly copied from Neutron, will pass even if nexthop is valid
    if not isinstance(data, list):
        msg = _("Invalid data format for hostroute: '%s'") % data
        LOG.debug(msg)
        return msg

    expected_keys = ['destination', 'nexthop']
    hostroutes = []
    for hostroute in data:
        msg = attr._verify_dict_keys(expected_keys, hostroute)
        if msg:
            LOG.debug(msg)
            return msg
        msg = attr._validate_subnet(hostroute['destination'])
        if msg:
            LOG.debug(msg)
            return msg
        if hostroute['nexthop']:
            msg = attr._validate_ip_address(hostroute['nexthop'])
        if msg:
            LOG.debug(msg)
            return msg
        if hostroute in hostroutes:
            msg = _("Duplicate hostroute '%s'") % hostroute
            LOG.debug(msg)
            return msg
        hostroutes.append(hostroute)
示例#6
0
    def test_validate_subnet(self):
        # Valid - IPv4
        cidr = "10.0.2.0/24"
        msg = attributes._validate_subnet(cidr, None)
        self.assertIsNone(msg)

        # Valid - IPv6 without final octets
        cidr = "fe80::/24"
        msg = attributes._validate_subnet(cidr, None)
        self.assertIsNone(msg)

        # Valid - IPv6 with final octets
        cidr = "fe80::/24"
        msg = attributes._validate_subnet(cidr, None)
        self.assertIsNone(msg)

        # Invalid - IPv4 missing mask
        cidr = "10.0.2.0"
        msg = attributes._validate_subnet(cidr, None)
        error = _("'%(data)s' isn't a recognized IP subnet cidr," " '%(cidr)s' is recommended") % {
            "data": cidr,
            "cidr": "10.0.2.0/32",
        }
        self.assertEqual(msg, error)

        # Invalid - IPv4 with final octets
        cidr = "192.168.1.1/24"
        msg = attributes._validate_subnet(cidr, None)
        error = _("'%(data)s' isn't a recognized IP subnet cidr," " '%(cidr)s' is recommended") % {
            "data": cidr,
            "cidr": "192.168.1.0/24",
        }
        self.assertEqual(msg, error)

        # Invalid - IPv6 without final octets, missing mask
        cidr = "fe80::"
        msg = attributes._validate_subnet(cidr, None)
        error = _("'%(data)s' isn't a recognized IP subnet cidr," " '%(cidr)s' is recommended") % {
            "data": cidr,
            "cidr": "fe80::/128",
        }
        self.assertEqual(msg, error)

        # Invalid - IPv6 with final octets, missing mask
        cidr = "fe80::0"
        msg = attributes._validate_subnet(cidr, None)
        error = _("'%(data)s' isn't a recognized IP subnet cidr," " '%(cidr)s' is recommended") % {
            "data": cidr,
            "cidr": "fe80::/128",
        }
        self.assertEqual(msg, error)

        # Invalid - Address format error
        cidr = "invalid"
        msg = attributes._validate_subnet(cidr, None)
        error = "'%s' is not a valid IP subnet" % cidr
        self.assertEqual(msg, error)
 def _validate_cidrs(self, cidrs):
     """Ensure valid IPv4/6 CIDRs."""
     for cidr in cidrs:
         msg = attributes._validate_subnet(cidr)
         if msg:
             raise vpnaas.InvalidEndpointInEndpointGroup(
                 group_type=constants.CIDR_ENDPOINT, endpoint=cidr,
                 why=_("Invalid CIDR"))
示例#8
0
 def _validate_cidrs(self, cidrs):
     """Ensure valid IPv4/6 CIDRs."""
     for cidr in cidrs:
         msg = attributes._validate_subnet(cidr)
         if msg:
             raise vpnaas.InvalidEndpointInEndpointGroup(
                 group_type=constants.CIDR_ENDPOINT,
                 endpoint=cidr,
                 why=_("Invalid CIDR"))
示例#9
0
def _validate_ip_or_subnet_or_none(data, valid_values=None):
    if data is None:
        return None
    msg_ip = attr._validate_ip_address(data, valid_values)
    if not msg_ip:
        return
    msg_subnet = attr._validate_subnet(data, valid_values)
    if not msg_subnet:
        return
    return _("%(msg_ip)s and %(msg_subnet)s") % {"msg_ip": msg_ip, "msg_subnet": msg_subnet}
示例#10
0
def _validate_ip_or_subnet_or_none(data, valid_values=None):
    if data is None:
        return None
    msg_ip = attr._validate_ip_address(data, valid_values)
    if not msg_ip:
        return
    msg_subnet = attr._validate_subnet(data, valid_values)
    if not msg_subnet:
        return
    return _("%(msg_ip)s and %(msg_subnet)s") % {'msg_ip': msg_ip,
                                                 'msg_subnet': msg_subnet}
def _validate_ip_or_subnet_or_none(data, valid_values=None):
    if data is None:
        return None
    msg_ip = attributes._validate_ip_address(data, valid_values)
    if not msg_ip:
        return None
    msg_subnet = attributes._validate_subnet(data, valid_values)
    if not msg_subnet:
        return None
    return _("%(msg_ip)s and %(msg_subnet)s") % {'msg_ip': msg_ip,
                                                 'msg_subnet': msg_subnet}
示例#12
0
def convert_to_valid_router_rules(data):
    """
    Validates and converts router rules to the appropriate data structure
    Example argument = [{'source': 'any', 'destination': 'any',
                         'action':'deny'},
                        {'source': '1.1.1.1/32', 'destination': 'external',
                         'action':'permit',
                         'nexthops': ['1.1.1.254', '1.1.1.253']}
                       ]
    """
    V4ANY = '0.0.0.0/0'
    CIDRALL = ['any', 'external']
    if not isinstance(data, list):
        emsg = _("Invalid data format for router rule: '%s'") % data
        LOG.debug(emsg)
        raise nexception.InvalidInput(error_message=emsg)
    _validate_uniquerules(data)
    rules = []
    expected_keys = ['source', 'destination', 'action']
    for rule in data:
        rule['nexthops'] = rule.get('nexthops', [])
        if not isinstance(rule['nexthops'], list):
            rule['nexthops'] = rule['nexthops'].split('+')

        src = V4ANY if rule['source'] in CIDRALL else rule['source']
        dst = V4ANY if rule['destination'] in CIDRALL else rule['destination']

        errors = [
            attr._verify_dict_keys(expected_keys, rule, False),
            attr._validate_subnet(dst),
            attr._validate_subnet(src),
            _validate_nexthops(rule['nexthops']),
            _validate_action(rule['action'])
        ]
        errors = [m for m in errors if m]
        if errors:
            LOG.debug(errors)
            raise nexception.InvalidInput(error_message=errors)
        rules.append(rule)
    return rules
示例#13
0
def convert_to_valid_router_rules(data):
    """
    Validates and converts router rules to the appropriate data structure
    Example argument = [{'source': 'any', 'destination': 'any',
                         'action':'deny'},
                        {'source': '1.1.1.1/32', 'destination': 'external',
                         'action':'permit',
                         'nexthops': ['1.1.1.254', '1.1.1.253']}
                       ]
    """
    V4ANY = '0.0.0.0/0'
    CIDRALL = ['any', 'external']
    if not isinstance(data, list):
        emsg = _("Invalid data format for router rule: '%s'") % data
        LOG.debug(emsg)
        raise qexception.InvalidInput(error_message=emsg)
    _validate_uniquerules(data)
    rules = []
    expected_keys = ['source', 'destination', 'action']
    for rule in data:
        rule['nexthops'] = rule.get('nexthops', [])
        if not isinstance(rule['nexthops'], list):
            rule['nexthops'] = rule['nexthops'].split('+')

        src = V4ANY if rule['source'] in CIDRALL else rule['source']
        dst = V4ANY if rule['destination'] in CIDRALL else rule['destination']

        errors = [attr._verify_dict_keys(expected_keys, rule, False),
                  attr._validate_subnet(dst),
                  attr._validate_subnet(src),
                  _validate_nexthops(rule['nexthops']),
                  _validate_action(rule['action'])]
        errors = [m for m in errors if m]
        if errors:
            LOG.debug(errors)
            raise qexception.InvalidInput(error_message=errors)
        rules.append(rule)
    return rules
示例#14
0
def _validate_pptp_cidr(data, valid_values=None):
    msg = attr._validate_subnet(data, valid_values)
    if msg:
        return msg
    try:
        net = netaddr.IPNetwork(data)
        if net.size < 4:
            msg = (_("The valid IP range defined by '%(data)s are too small") %
                   {"data": data})
        elif net.size > 256:
            msg = (_("The valid IP range defined by '%(data)s are too large") %
                   {"data": data})
    except Exception:
        msg = _("'%s' is not a valid IP subnet") % data
    return msg
示例#15
0
    def test_validate_subnet(self):
        # Valid - IPv4
        cidr = "10.0.2.0/24"
        msg = attributes._validate_subnet(cidr,
                                          None)
        self.assertIsNone(msg)

        # Valid - IPv6 without final octets
        cidr = "fe80::/24"
        msg = attributes._validate_subnet(cidr,
                                          None)
        self.assertIsNone(msg)

        # Valid - IPv6 with final octets
        cidr = "fe80::0/24"
        msg = attributes._validate_subnet(cidr,
                                          None)
        self.assertIsNone(msg)

        # Invalid - IPv4 missing mask
        cidr = "10.0.2.0"
        msg = attributes._validate_subnet(cidr,
                                          None)
        error = "'%s' is not a valid IP subnet" % cidr
        self.assertEqual(msg, error)

        # Invalid - IPv6 without final octets, missing mask
        cidr = "fe80::"
        msg = attributes._validate_subnet(cidr,
                                          None)
        error = "'%s' is not a valid IP subnet" % cidr
        self.assertEqual(msg, error)

        # Invalid - IPv6 with final octets, missing mask
        cidr = "fe80::0"
        msg = attributes._validate_subnet(cidr,
                                          None)
        error = "'%s' is not a valid IP subnet" % cidr
        self.assertEqual(msg, error)

        # Invalid - Address format error
        cidr = 'invalid'
        msg = attributes._validate_subnet(cidr,
                                          None)
        error = "'%s' is not a valid IP subnet" % cidr
        self.assertEqual(msg, error)
示例#16
0
def _validate_openvpn_cidr(data, valid_values=None):
    msg = attr._validate_subnet(data, valid_values)
    if msg:
        return msg
    try:
        net = netaddr.IPNetwork(data)
        if net.size < 4:
            msg = (_("The valid IP range defined by '%(data)s are too small") %
                   {
                       "data": data
                   })
        elif net.size > vpn_connstants.PEER_VPN_SIZE:
            msg = (_("The valid IP range defined by '%(data)s are too large") %
                   {
                       "data": data
                   })
    except Exception:
        msg = _("'%s' is not a valid IP subnet") % data
    return msg
示例#17
0
def _validate_allowed_address_pairs(address_pairs, valid_values=None):
    unique_check = {}
    if len(address_pairs) > cfg.CONF.max_allowed_address_pair:
        raise AllowedAddressPairExhausted(
            quota=cfg.CONF.max_allowed_address_pair)

    for address_pair in address_pairs:
        # mac_address is optional, if not set we use the mac on the port
        if 'mac_address' in address_pair:
            msg = attr._validate_mac_address(address_pair['mac_address'])
            if msg:
                raise webob.exc.HTTPBadRequest(msg)
        if 'ip_address' not in address_pair:
            raise AllowedAddressPairsMissingIP()

        mac = address_pair.get('mac_address')
        ip_address = address_pair['ip_address']
        if (mac, ip_address) not in unique_check:
            unique_check[(mac, ip_address)] = None
        else:
            raise DuplicateAddressPairInRequest(mac_address=mac,
                                                ip_address=ip_address)

        invalid_attrs = set(address_pair.keys()) - set(['mac_address',
                                                        'ip_address'])
        if invalid_attrs:
            msg = (_("Unrecognized attribute(s) '%s'") %
                   ', '.join(set(address_pair.keys()) -
                             set(['mac_address', 'ip_address'])))
            raise webob.exc.HTTPBadRequest(msg)

        if (netaddr.IPNetwork(ip_address).prefixlen == 0):
            raise AllowedAddressPairsZeroPrefixNotAllowed()
        elif '/' in ip_address:
            msg = attr._validate_subnet(ip_address)
        else:
            msg = attr._validate_ip_address(ip_address)
        if msg:
            raise webob.exc.HTTPBadRequest(msg)
示例#18
0
    def test_validate_subnet(self):
        # Valid - IPv4
        cidr = "10.0.2.0/24"
        msg = attributes._validate_subnet(cidr, None)
        self.assertIsNone(msg)

        # Valid - IPv6 without final octets
        cidr = "fe80::/24"
        msg = attributes._validate_subnet(cidr, None)
        self.assertIsNone(msg)

        # Valid - IPv6 with final octets
        cidr = "fe80::/24"
        msg = attributes._validate_subnet(cidr, None)
        self.assertIsNone(msg)

        # Valid - uncompressed ipv6 address
        cidr = "fe80:0:0:0:0:0:0:0/128"
        msg = attributes._validate_subnet(cidr, None)
        self.assertIsNone(msg)

        # Valid - ipv6 address with multiple consecutive zero
        cidr = "2001:0db8:0:0:1::1/128"
        msg = attributes._validate_subnet(cidr, None)
        self.assertIsNone(msg)

        # Valid - ipv6 address with multiple consecutive zero
        cidr = "2001:0db8::1:0:0:1/128"
        msg = attributes._validate_subnet(cidr, None)
        self.assertIsNone(msg)

        # Valid - ipv6 address with multiple consecutive zero
        cidr = "2001::0:1:0:0:1100/120"
        msg = attributes._validate_subnet(cidr, None)
        self.assertIsNone(msg)

        # Valid - abbreviated ipv4 address
        cidr = "10/24"
        msg = attributes._validate_subnet(cidr, None)
        self.assertIsNone(msg)

        # Invalid - IPv4 missing mask
        cidr = "10.0.2.0"
        msg = attributes._validate_subnet(cidr, None)
        error = _("'%(data)s' isn't a recognized IP subnet cidr,"
                  " '%(cidr)s' is recommended") % {
                      "data": cidr,
                      "cidr": "10.0.2.0/32"
                  }
        self.assertEqual(msg, error)

        # Invalid - IPv4 with final octets
        cidr = "192.168.1.1/24"
        msg = attributes._validate_subnet(cidr, None)
        error = _("'%(data)s' isn't a recognized IP subnet cidr,"
                  " '%(cidr)s' is recommended") % {
                      "data": cidr,
                      "cidr": "192.168.1.0/24"
                  }
        self.assertEqual(msg, error)

        # Invalid - IPv6 without final octets, missing mask
        cidr = "fe80::"
        msg = attributes._validate_subnet(cidr, None)
        error = _("'%(data)s' isn't a recognized IP subnet cidr,"
                  " '%(cidr)s' is recommended") % {
                      "data": cidr,
                      "cidr": "fe80::/128"
                  }
        self.assertEqual(msg, error)

        # Invalid - IPv6 with final octets, missing mask
        cidr = "fe80::0"
        msg = attributes._validate_subnet(cidr, None)
        error = _("'%(data)s' isn't a recognized IP subnet cidr,"
                  " '%(cidr)s' is recommended") % {
                      "data": cidr,
                      "cidr": "fe80::/128"
                  }
        self.assertEqual(msg, error)

        # Invalid - Address format error
        cidr = 'invalid'
        msg = attributes._validate_subnet(cidr, None)
        error = "'%s' is not a valid IP subnet" % cidr
        self.assertEqual(msg, error)
示例#19
0
    def test_validate_subnet(self):
        # Valid - IPv4
        cidr = "10.0.2.0/24"
        msg = attributes._validate_subnet(cidr, None)
        self.assertIsNone(msg)

        # Valid - IPv6 without final octets
        cidr = "fe80::/24"
        msg = attributes._validate_subnet(cidr, None)
        self.assertIsNone(msg)

        # Valid - IPv6 with final octets
        cidr = "fe80::/24"
        msg = attributes._validate_subnet(cidr, None)
        self.assertIsNone(msg)

        # Invalid - IPv4 missing mask
        cidr = "10.0.2.0"
        msg = attributes._validate_subnet(cidr, None)
        error = _("'%(data)s' isn't a recognized IP subnet cidr,"
                  " '%(cidr)s' is recommended") % {
                      "data": cidr,
                      "cidr": "10.0.2.0/32"
                  }
        self.assertEqual(msg, error)

        # Invalid - IPv4 with final octets
        cidr = "192.168.1.1/24"
        msg = attributes._validate_subnet(cidr, None)
        error = _("'%(data)s' isn't a recognized IP subnet cidr,"
                  " '%(cidr)s' is recommended") % {
                      "data": cidr,
                      "cidr": "192.168.1.0/24"
                  }
        self.assertEqual(msg, error)

        # Invalid - IPv6 without final octets, missing mask
        cidr = "fe80::"
        msg = attributes._validate_subnet(cidr, None)
        error = _("'%(data)s' isn't a recognized IP subnet cidr,"
                  " '%(cidr)s' is recommended") % {
                      "data": cidr,
                      "cidr": "fe80::/128"
                  }
        self.assertEqual(msg, error)

        # Invalid - IPv6 with final octets, missing mask
        cidr = "fe80::0"
        msg = attributes._validate_subnet(cidr, None)
        error = _("'%(data)s' isn't a recognized IP subnet cidr,"
                  " '%(cidr)s' is recommended") % {
                      "data": cidr,
                      "cidr": "fe80::/128"
                  }
        self.assertEqual(msg, error)

        # Invalid - Address format error
        cidr = 'invalid'
        msg = attributes._validate_subnet(cidr, None)
        error = "'%s' is not a valid IP subnet" % cidr
        self.assertEqual(msg, error)
示例#20
0
    def test_validate_subnet(self):
        # Valid - IPv4
        cidr = "10.0.2.0/24"
        msg = attributes._validate_subnet(cidr,
                                          None)
        self.assertIsNone(msg)

        # Valid - IPv6 without final octets
        cidr = "fe80::/24"
        msg = attributes._validate_subnet(cidr,
                                          None)
        self.assertIsNone(msg)

        # Valid - IPv6 with final octets
        cidr = "fe80::/24"
        msg = attributes._validate_subnet(cidr,
                                          None)
        self.assertIsNone(msg)

        # Valid - uncompressed ipv6 address
        cidr = "fe80:0:0:0:0:0:0:0/128"
        msg = attributes._validate_subnet(cidr,
                                          None)
        self.assertIsNone(msg)

        # Valid - ipv6 address with multiple consecutive zero
        cidr = "2001:0db8:0:0:1::1/128"
        msg = attributes._validate_subnet(cidr,
                                          None)
        self.assertIsNone(msg)

        # Valid - ipv6 address with multiple consecutive zero
        cidr = "2001:0db8::1:0:0:1/128"
        msg = attributes._validate_subnet(cidr,
                                          None)
        self.assertIsNone(msg)

        # Valid - ipv6 address with multiple consecutive zero
        cidr = "2001::0:1:0:0:1100/120"
        msg = attributes._validate_subnet(cidr,
                                          None)
        self.assertIsNone(msg)

        # Valid - abbreviated ipv4 address
        cidr = "10/24"
        msg = attributes._validate_subnet(cidr,
                                          None)
        self.assertIsNone(msg)

        # Invalid - IPv4 missing mask
        cidr = "10.0.2.0"
        msg = attributes._validate_subnet(cidr,
                                          None)
        error = _("'%(data)s' isn't a recognized IP subnet cidr,"
                  " '%(cidr)s' is recommended") % {"data": cidr,
                                                   "cidr": "10.0.2.0/32"}
        self.assertEqual(msg, error)

        # Invalid - IPv4 with final octets
        cidr = "192.168.1.1/24"
        msg = attributes._validate_subnet(cidr,
                                          None)
        error = _("'%(data)s' isn't a recognized IP subnet cidr,"
                  " '%(cidr)s' is recommended") % {"data": cidr,
                                                   "cidr": "192.168.1.0/24"}
        self.assertEqual(msg, error)

        # Invalid - IPv6 without final octets, missing mask
        cidr = "fe80::"
        msg = attributes._validate_subnet(cidr,
                                          None)
        error = _("'%(data)s' isn't a recognized IP subnet cidr,"
                  " '%(cidr)s' is recommended") % {"data": cidr,
                                                   "cidr": "fe80::/128"}
        self.assertEqual(msg, error)

        # Invalid - IPv6 with final octets, missing mask
        cidr = "fe80::0"
        msg = attributes._validate_subnet(cidr,
                                          None)
        error = _("'%(data)s' isn't a recognized IP subnet cidr,"
                  " '%(cidr)s' is recommended") % {"data": cidr,
                                                   "cidr": "fe80::/128"}
        self.assertEqual(msg, error)

        # Invalid - Address format error
        cidr = 'invalid'
        msg = attributes._validate_subnet(cidr,
                                          None)
        error = "'%s' is not a valid IP subnet" % cidr
        self.assertEqual(msg, error)