/* * Copyright (c) 2016 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include typedef u16 (*size_to_write_fct)(void *); typedef void * (*cast_fct)(gid_address_t *); typedef u16 (*write_fct)(u8 *, void *); typedef u8 (*addr_len_fct)(void *); typedef void (*copy_fct)(void *, void *); size_to_write_fct size_to_write_fcts[GID_ADDR_TYPES] = { ip_prefix_size_to_write }; write_fct write_fcts[GID_ADDR_TYPES] = { ip_prefix_write }; cast_fct cast_fcts[GID_ADDR_TYPES] = { ip_prefix_cast }; addr_len_fct addr_len_fcts[GID_ADDR_TYPES] = { ip_prefix_length }; copy_fct copy_fcts[GID_ADDR_TYPES] = { ip_prefix_copy }; u8 * format_ip_address (u8 * s, va_list * args) { ip_address_t * a = va_arg (*args, ip_address_t *); u8 ver = ip_addr_version(a); if (ver == IP4) { return format (s, "%U", format_ip4_address, &ip_addr_v4(a)); } else if (ver == IP6) { return format (s, "%U", format_ip6_address, &ip_addr_v6(a)); } else { clib_warning ("Can't format IP version %d!", ver); return 0; } } uword unformat_ip_address (unformat_input_t * input, va_list * args) { ip_address_t * a = va_arg(*args, ip_address_t *); if (unformat(input, "%U", unformat_ip4_address, &ip_addr_v4(a))) ip_addr_version(a) = IP4; else if (unformat_user (input, unformat_ip6_address, &ip_addr_v6(a))) ip_addr_version(a) = IP6; else return 0; return 1; } u8 * format_ip_prefix (u8 * s, va_list * args) { ip_prefix_t * a = va_arg (*args, ip_prefix_t *); return format (s, "%U/%d", format_ip_address, &ip_prefix_addr(a), ip_prefix_len(a)); } uword unformat_ip_prefix (unformat_input_t * input, va_list * args) { ip_prefix_t * a = va_arg(*args, ip_prefix_t *); return unformat (input, "%U/%d", unformat_ip_address, &ip_prefix_addr(a), &ip_prefix_len(a)); } u8 * format_gid_address (u8 * s, va_list * args) { gid_address_t * a = va_arg(*args, gid_address_t *); u8 type = gid_address_type(a); switch (type) { case IP_PREFIX: return format (s, "%U", format_ip_prefix, &gid_address_ippref(a)); default: clib_warning("Can't format gid type %d", type); return 0; } } uword unformat_gid_address (unformat_input_t * input, va_list * args) { gid_address_t * a = va_arg(*args, gid_address_t *); if (unformat (input, "%U", unformat_ip_prefix, &gid_address_ippref(a))) gid_address_type(a) = IP_PREFIX; else return 0; return 1; } u16 ip_address_size (ip_address_t * a) { switch (ip_addr_version (a)) { case IP4: return sizeof(ip4_address_t); break; case IP6: return sizeof(ip6_address_t); break; } return 0; } u16 ip_version_to_size (u8 ver) { switch (ver) { case IP4: return sizeof(ip4_address_t); break; case IP6: return sizeof(ip6_address_t); break; } return 0; } u8 ip_version_to_max_plen (u8 ver) { switch (ver) { case IP4: return 32; break; case IP6: return 128; break; } return 0; } always_inline lisp_afi_e ip_version_to_iana_afi (u16 version) { switch (version) { case IP4: return LISP_AFI_IP; case IP6: return LISP_AFI_IP6; default: return 0; } return 0; } always_inline u8 ip_iana_afi_to_version (lisp_afi_e afi) { switch (afi) { case LISP_AFI_IP: return IP4; case LISP_AFI_IP6: return IP6; default: return 0; } return 0; } u16 ip_address_size_to_write (ip_address_t * a) { return ip_address_size (a) + sizeof (u16); } u16 ip_address_iana_afi(ip_address_t *a) { return ip_version_to_iana_afi(ip_addr_version(a)); } u8 ip_address_max_len (u8 version) { return version == IP4 ? 32 : 128; } u16 ip4_address_size_to_put () { // return sizeof(u16) + sizeof (ip4_address_t); return 6; } u16 ip6_address_size_to_put () { //return sizeof(u16) + sizeof (ip6_address_t); return 18; } u32 ip4_address_put (u8 * b, ip4_address_t * a) { *(u16 *)b = clib_host_to_net_u16(ip_version_to_iana_afi(IP4)); u8 *p = b + sizeof (u16); clib_memcpy (p, a, sizeof(*a)); return ip4_address_size_to_put(); } u32 ip6_address_put (u8 * b, ip6_address_t * a) { *(u16 *)b = clib_host_to_net_u16(ip_version_to_iana_afi(IP6)); u8 *p = b + sizeof (u16); clib_memcpy (p, a, sizeof(*a)); return ip6_address_size_to_put(); } u32 ip_address_put (u8 * b, ip_address_t * a) { u32 len = ip_address_size (a); *(u16 *) b = clib_host_to_net_u16(ip_address_iana_afi (a)); u8 * p = b + sizeof (u16); clib_memcpy (p, &ip_addr_addr (a), len); return (len + sizeof (u16)); } u32 ip_address_parse(void * offset, u16 iana_afi, ip_address_t *dst) { ip_addr_version(dst) = ip_iana_afi_to_version (iana_afi); u8 size = ip_version_to_size (ip_addr_version(dst)); clib_memcpy (&ip_addr_addr(dst), offset + sizeof(u16), size); return(sizeof(u16) + size); } int ip_address_cmp (ip_address_t * ip1, ip_address_t * ip2) { int res = 0; if (ip_addr_version (ip1) != ip_addr_version(ip2)) return -1; res = memcmp (&ip_addr_addr(ip1), &ip_addr_addr(ip2), ip_address_size (ip1)); if (res < 0) res = 2; else if (res > 0) res = 1; return res; } void * ip_prefix_cast (gid_address_t * a) { return &gid_address_ippref(a); } u16 ip_prefix_size_to_write (void * pref) { ip_prefix_t *a = (ip_prefix_t *) pref; return ip_address_size_to_write (&ip_prefix_addr (a)); } u16 ip_prefix_write (u8 * p, void * pref) { ip_prefix_t *a = (ip_prefix_t *) pref; switch (ip_prefix_version (a)) { case IP4: return ip4_address_put (p, &ip_prefix_v4 (a)); break; case IP6: return ip6_address_put (p, &ip_prefix_v6 (a)); break; } return 0; } u8 ip_prefix_length (void *a) { return ip_prefix_len((ip_prefix_t *) a); } void ip_prefix_copy (void * dst , void * src) { clib_memcpy (dst, src, sizeof (ip_prefix_t)); } int ip_prefix_cmp(ip_prefix_t * p1, ip_prefix_t * p2) { int cmp = 0; cmp = ip_address_cmp (&ip_prefix_addr(p1), &ip_prefix_addr(p2)); if (cmp == 0) { if (ip_prefix_len(p1) < ip_prefix_len(p2)) { cmp = 1; } else { if (ip_prefix_len(p1) > ip_prefix_len(p2)) cmp = 2; } } return cmp; } u8 gid_address_len (gid_address_t *a) { gid_address_type_t type = gid_address_type (a); return (*addr_len_fcts[type])((*cast_fcts[type])(a)); } u16 gid_address_put (u8 * b, gid_address_t * gid) { gid_address_type_t type = gid_address_type (gid); return (*write_fcts[type])(b, (*cast_fcts[type])(gid)); } u16 gid_address_size_to_put (gid_address_t * gid) { gid_address_type_t type = gid_address_type (gid); return (*size_to_write_fcts[type])((*cast_fcts[type])(gid)); } void * gid_address_cast (gid_address_t * gid, gid_address_type_t type) { return (*cast_fcts[type])(gid); } void gid_address_copy(gid_address_t * dst, gid_address_t * src) { gid_address_type_t type = gid_address_type(src); (*copy_fcts[type])((*cast_fcts[type])(dst), (*cast_fcts[type])(src)); gid_address_type(dst) = type; } u32 gid_address_parse (u8 * offset, gid_address_t *a) { lisp_afi_e afi; int len = 0; if (!a) return 0; afi = clib_net_to_host_u16 (*((u16 *) offset)); switch (afi) { case LISP_AFI_NO_ADDR: len = sizeof(u16); gid_address_type(a) = NO_ADDRESS; break; case LISP_AFI_IP: len = ip_address_parse (offset, afi, &gid_address_ip(a)); gid_address_type(a) = IP_PREFIX; /* this should be modified outside if needed*/ gid_address_ippref_len(a) = 32; break; case LISP_AFI_IP6: len = ip_address_parse (offset, afi, &gid_address_ip(a)); gid_address_type(a) = IP_PREFIX; /* this should be modified outside if needed*/ gid_address_ippref_len(a) = 128; break; case LISP_AFI_LCAF: default: clib_warning("LISP AFI %d not supported!", afi); return ~0; } return len; } /* Compare two gid_address_t. * Returns: * -1: If they are from different afi * 0: Both address are the same * 1: Addr1 is bigger than addr2 * 2: Addr2 is bigger than addr1 */ int gid_address_cmp (gid_address_t * a1, gid_address_t * a2) { int cmp = -1; if (!a1 || !a2) return -1; if (gid_address_type(a1) != gid_address_type(a2)) return -1; switch (gid_address_type(a1)) { case NO_ADDRESS: if (a1 == a2) cmp = 0; else cmp = 2; break; case IP_PREFIX: cmp = ip_prefix_cmp (&gid_address_ippref(a1), &gid_address_ippref(a2)); break; default: break; } return cmp; } u32 locator_parse (void * b, locator_t * loc) { locator_hdr_t * h; u8 status = 1; /* locator up */ int len; h = b; if (!LOC_REACHABLE(h) && LOC_LOCAL(h)) status = 0; len = gid_address_parse (LOC_ADDR(h), &loc->address); if (len == ~0) return len; loc->state = status; loc->local = 0; loc->priority = LOC_PRIORITY(h); loc->weight = LOC_WEIGHT(h); loc->mpriority = LOC_MPRIORITY(h); loc->mweight = LOC_MWEIGHT(h); return sizeof(locator_hdr_t) + len; } void locator_copy (locator_t * dst, locator_t * src) { /* TODO if gid become more complex, this will need to be changed! */ clib_memcpy (dst, src, sizeof(*dst)); } u32 locator_cmp (locator_t * l1, locator_t * l2) { u32 ret = 0; if ((ret = gid_address_cmp (&l1->address, &l2->address)) != 0) return 1; if (l1->priority != l2->priority) return 1; if (l1->weight != l2->weight) return 1; if (l1->mpriority != l2->mpriority) return 1; if (l1->mweight != l2->mweight) return 1; return 0; }