X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=vnet%2Fvnet%2Flisp-cp%2Flisp_types.c;h=5ab4a5eb4496f4ffc2920f891ffb9635f130f0d4;hb=f3bd5716c1e2dfb1063a0abb0b2fdaf0bccf159f;hp=1234c7caf954b59ed748d020bfb517d691e4cd1d;hpb=02655bd425cc596960b7efc74d1fbad3b3406419;p=vpp.git diff --git a/vnet/vnet/lisp-cp/lisp_types.c b/vnet/vnet/lisp-cp/lisp_types.c index 1234c7caf95..5ab4a5eb449 100644 --- a/vnet/vnet/lisp-cp/lisp_types.c +++ b/vnet/vnet/lisp-cp/lisp_types.c @@ -15,35 +15,126 @@ #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 *); +static u16 gid_address_put_no_vni (u8 * b, gid_address_t * gid); +static u16 gid_address_size_to_put_no_vni (gid_address_t * gid); +static u16 fid_addr_size_to_write (fid_address_t * a); + +u32 mac_parse (u8 * offset, u8 * a); + +typedef u16 (*size_to_write_fct) (void *); +typedef void *(*cast_fct) (gid_address_t *); +typedef u16 (*serdes_fct) (u8 *, void *); +typedef u8 (*addr_len_fct) (void *); +typedef void (*copy_fct) (void *, void *); +typedef void (*free_fct) (void *); +typedef int (*cmp_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 }; + { ip_prefix_size_to_write, lcaf_size_to_write, mac_size_to_write, + sd_size_to_write +}; +serdes_fct write_fcts[GID_ADDR_TYPES] = + { ip_prefix_write, lcaf_write, mac_write, sd_write }; cast_fct cast_fcts[GID_ADDR_TYPES] = - { ip_prefix_cast }; + { ip_prefix_cast, lcaf_cast, mac_cast, sd_cast }; addr_len_fct addr_len_fcts[GID_ADDR_TYPES] = - { ip_prefix_length }; + { ip_prefix_length, lcaf_length, mac_length, sd_length }; copy_fct copy_fcts[GID_ADDR_TYPES] = - { ip_prefix_copy }; + { ip_prefix_copy, lcaf_copy, mac_copy, sd_copy }; + +#define foreach_lcaf_type \ + _(1, no_addr) \ + _(0, NULL) \ + _(1, vni) \ + _(0, NULL) \ + _(0, NULL) \ + _(0, NULL) \ + _(0, NULL) \ + _(0, NULL) \ + _(0, NULL) \ + _(0, NULL) \ + _(0, NULL) \ + _(0, NULL) \ + _(1, sd) + +#define _(cond, name) \ + u16 name ## _write (u8 * p, void * a); \ + u16 name ## _parse (u8 * p, void * a); \ + u16 name ## _size_to_write (void * a); \ + void name ## _free (void * a); \ + void name ## _copy (void * dst, void * src); \ + u8 name ## _length (void * a); \ + int name ## _cmp (void *, void *); +foreach_lcaf_type +#undef _ +#define CONCAT(a,b) a##_##b +#define IF(c, t, e) CONCAT(IF, c)(t, e) +#define IF_0(t, e) e +#define IF_1(t, e) t +#define EXPAND_FCN(cond, fcn) \ + IF(cond, fcn, NULL) + cmp_fct lcaf_cmp_fcts[LCAF_TYPES] = +{ +#define _(cond, name) \ + EXPAND_FCN(cond, name##_cmp), + foreach_lcaf_type +#undef _ +}; + +addr_len_fct lcaf_body_length_fcts[LCAF_TYPES] = { +#define _(cond, name) \ + EXPAND_FCN(cond, name##_length), + foreach_lcaf_type +#undef _ +}; + +copy_fct lcaf_copy_fcts[LCAF_TYPES] = { +#define _(cond, name) \ + EXPAND_FCN(cond, name##_copy), + foreach_lcaf_type +#undef _ +}; + +free_fct lcaf_free_fcts[LCAF_TYPES] = { +#define _(cond, name) \ + EXPAND_FCN(cond, name##_free), + foreach_lcaf_type +#undef _ +}; + +size_to_write_fct lcaf_size_to_write_fcts[LCAF_TYPES] = { +#define _(cond, name) \ + EXPAND_FCN(cond, name##_size_to_write), + foreach_lcaf_type +#undef _ +}; + +serdes_fct lcaf_write_fcts[LCAF_TYPES] = { +#define _(cond, name) \ + EXPAND_FCN(cond, name##_write), + foreach_lcaf_type +#undef _ +}; + +serdes_fct lcaf_parse_fcts[LCAF_TYPES] = { +#define _(cond, name) \ + EXPAND_FCN(cond, name##_parse), + foreach_lcaf_type +#undef _ +}; 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); + 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)); + 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)); + return format (s, "%U", format_ip6_address, &ip_addr_v6 (a)); } else { @@ -55,11 +146,13 @@ format_ip_address (u8 * s, va_list * args) 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; + ip_address_t *a = va_arg (*args, ip_address_t *); + + memset (a, 0, sizeof (*a)); + 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; @@ -68,56 +161,257 @@ unformat_ip_address (unformat_input_t * input, va_list * args) 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)); + 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)); + ip_prefix_t *a = va_arg (*args, ip_prefix_t *); + if (unformat (input, "%U/%d", unformat_ip_address, &ip_prefix_addr (a), + &ip_prefix_len (a))) + { + if ((ip_prefix_version (a) == IP4 && 32 < ip_prefix_len (a)) || + (ip_prefix_version (a) == IP6 && 128 < ip_prefix_length (a))) + { + clib_warning ("Prefix length to big: %d!", ip_prefix_len (a)); + return 0; + } + ip_prefix_normalize (a); + } + else + return 0; + return 1; +} + +uword +unformat_mac_address (unformat_input_t * input, va_list * args) +{ + u8 *a = va_arg (*args, u8 *); + return unformat (input, "%x:%x:%x:%x:%x:%x", &a[0], &a[1], &a[2], &a[3], + &a[4], &a[5]); +} + +u8 * +format_mac_address (u8 * s, va_list * args) +{ + u8 *a = va_arg (*args, u8 *); + return format (s, "%02x:%02x:%02x:%02x:%02x:%02x", + a[0], a[1], a[2], a[3], a[4], a[5]); +} + +u8 * +format_fid_address (u8 * s, va_list * args) +{ + fid_address_t *a = va_arg (*args, fid_address_t *); + + switch (fid_addr_type (a)) + { + case FID_ADDR_IP_PREF: + return format (s, "%U", format_ip_prefix, &fid_addr_ippref (a)); + + case FID_ADDR_MAC: + return format (s, "%U", format_mac_address, &fid_addr_mac (a)); + + default: + clib_warning ("Can't format fid address type %d!", fid_addr_type (a)); + return 0; + } + return 0; } 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); + 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)); + case GID_ADDR_IP_PREFIX: + return format (s, "[%d] %U", gid_address_vni (a), format_ip_prefix, + &gid_address_ippref (a)); + case GID_ADDR_SRC_DST: + return format (s, "[%d] %U|%U", gid_address_vni (a), + format_fid_address, &gid_address_sd_src (a), + format_fid_address, &gid_address_sd_dst (a)); + case GID_ADDR_MAC: + return format (s, "[%d] %U", gid_address_vni (a), format_mac_address, + &gid_address_mac (a)); default: - clib_warning("Can't format gid type %d", type); + clib_warning ("Can't format gid type %d", type); return 0; } + return 0; +} + +uword +unformat_fid_address (unformat_input_t * i, va_list * args) +{ + fid_address_t *a = va_arg (*args, fid_address_t *); + ip_prefix_t ippref; + u8 mac[6] = { 0 }; + + if (unformat (i, "%U", unformat_ip_prefix, &ippref)) + { + fid_addr_type (a) = FID_ADDR_IP_PREF; + ip_prefix_copy (&fid_addr_ippref (a), &ippref); + } + else if (unformat (i, "%U", unformat_mac_address, mac)) + { + fid_addr_type (a) = FID_ADDR_MAC; + mac_copy (fid_addr_mac (a), mac); + } + else + return 0; + + return 1; +} + +uword +unformat_hmac_key_id (unformat_input_t * input, va_list * args) +{ + u32 *key_id = va_arg (*args, u32 *); + u8 *s = 0; + + if (unformat (input, "%s", &s)) + { + if (!strcmp ((char *) s, "sha1")) + key_id[0] = HMAC_SHA_1_96; + else if (!strcmp ((char *) s, "sha256")) + key_id[0] = HMAC_SHA_256_128; + else + { + clib_warning ("invalid key_id: '%s'", s); + key_id[0] = HMAC_NO_KEY; + } + } + else + return 0; + + vec_free (s); + return 1; } 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; + gid_address_t *a = va_arg (*args, gid_address_t *); + u8 mac[6] = { 0 }; + ip_prefix_t ippref; + fid_address_t sim1, sim2; + + memset (&ippref, 0, sizeof (ippref)); + memset (&sim1, 0, sizeof (sim1)); + memset (&sim2, 0, sizeof (sim2)); + + if (unformat (input, "%U|%U", unformat_fid_address, &sim1, + unformat_fid_address, &sim2)) + { + gid_address_sd_src (a) = sim1; + gid_address_sd_dst (a) = sim2; + gid_address_type (a) = GID_ADDR_SRC_DST; + } + else if (unformat (input, "%U", unformat_ip_prefix, &ippref)) + { + ip_prefix_copy (&gid_address_ippref (a), &ippref); + gid_address_type (a) = GID_ADDR_IP_PREFIX; + } + else if (unformat (input, "%U", unformat_mac_address, mac)) + { + mac_copy (gid_address_mac (a), mac); + gid_address_type (a) = GID_ADDR_MAC; + } else return 0; + return 1; } +uword +unformat_negative_mapping_action (unformat_input_t * input, va_list * args) +{ + u32 *action = va_arg (*args, u32 *); + u8 *s = 0; + + if (unformat (input, "%s", &s)) + { + if (!strcmp ((char *) s, "no-action")) + action[0] = LISP_NO_ACTION; + else if (!strcmp ((char *) s, "natively-forward")) + action[0] = LISP_FORWARD_NATIVE; + else if (!strcmp ((char *) s, "send-map-request")) + action[0] = LISP_SEND_MAP_REQUEST; + else if (!strcmp ((char *) s, "drop")) + action[0] = LISP_DROP; + else + { + clib_warning ("invalid action: '%s'", s); + action[0] = LISP_DROP; + } + } + else + return 0; + + vec_free (s); + return 1; +} + +u8 * +format_hmac_key_id (u8 * s, va_list * args) +{ + lisp_key_type_t key_id = va_arg (*args, lisp_key_type_t); + + switch (key_id) + { + case HMAC_SHA_1_96: + return format (0, "sha1"); + case HMAC_SHA_256_128: + return format (0, "sha256"); + default: + return 0; + } + + return 0; +} + +u8 * +format_negative_mapping_action (u8 * s, va_list * args) +{ + lisp_action_e action = va_arg (*args, lisp_action_e); + + switch (action) + { + case LISP_NO_ACTION: + s = format (s, "no-action"); + break; + case LISP_FORWARD_NATIVE: + s = format (s, "natively-forward"); + break; + case LISP_SEND_MAP_REQUEST: + s = format (s, "send-map-request"); + break; + case LISP_DROP: + default: + s = format (s, "drop"); + break; + } + return (s); +} + u16 -ip_address_size (ip_address_t * a) +ip_address_size (const ip_address_t * a) { switch (ip_addr_version (a)) - { + { case IP4: - return sizeof(ip4_address_t); + return sizeof (ip4_address_t); break; case IP6: - return sizeof(ip6_address_t); + return sizeof (ip6_address_t); break; - } + } return 0; } @@ -125,14 +419,14 @@ u16 ip_version_to_size (u8 ver) { switch (ver) - { + { case IP4: - return sizeof(ip4_address_t); + return sizeof (ip4_address_t); break; case IP6: - return sizeof(ip6_address_t); + return sizeof (ip6_address_t); break; - } + } return 0; } @@ -140,14 +434,14 @@ u8 ip_version_to_max_plen (u8 ver) { switch (ver) - { + { case IP4: return 32; break; case IP6: return 128; break; - } + } return 0; } @@ -188,9 +482,9 @@ ip_address_size_to_write (ip_address_t * a) } u16 -ip_address_iana_afi(ip_address_t *a) +ip_address_iana_afi (ip_address_t * a) { - return ip_version_to_iana_afi(ip_addr_version(a)); + return ip_version_to_iana_afi (ip_addr_version (a)); } u8 @@ -216,47 +510,233 @@ ip6_address_size_to_put () u32 ip4_address_put (u8 * b, ip4_address_t * a) { - *(u16 *)b = clib_host_to_net_u16(ip_version_to_iana_afi(IP4)); + *(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(); + 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)); + *(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(); + 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); + *(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_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); +} + +u32 +lcaf_hdr_parse (void *offset, lcaf_t * lcaf) +{ + lcaf_hdr_t *lh = offset; + lcaf->type = lh->type; + + /* this is a bit of hack: since the LCAF Instance ID is the + only message that uses reserved2 field, we can set it here. + If any LCAF format starts using reserved2 field as well this needs + to be moved elsewhere */ + lcaf_vni_len (lcaf) = lh->reserved2; + + return sizeof (lh[0]); +} + +static u8 +iana_afi_to_fid_addr_type (u16 type) +{ + switch (type) + { + case LISP_AFI_IP: + case LISP_AFI_IP6: + return FID_ADDR_IP_PREF; + + case LISP_AFI_MAC: + return FID_ADDR_MAC; + } + return ~0; +} + +static u16 +fid_addr_parse (u8 * p, fid_address_t * a) +{ + u16 afi = clib_net_to_host_u16 (*(u16 *) p); + fid_addr_type (a) = iana_afi_to_fid_addr_type (afi); + ip_address_t *ip_addr = &ip_prefix_addr (&fid_addr_ippref (a)); + + switch (fid_addr_type (a)) + { + case FID_ADDR_MAC: + return mac_parse (p, fid_addr_mac (a)); + + case FID_ADDR_IP_PREF: + return ip_address_parse (p, afi, ip_addr); + } + return ~0; +} + +u16 +sd_parse (u8 * p, void *a) +{ + lcaf_src_dst_hdr_t *sd_hdr; + gid_address_t *g = a; + u16 size = 0; + fid_address_t *src = &gid_address_sd_src (g); + fid_address_t *dst = &gid_address_sd_dst (g); + + gid_address_type (g) = GID_ADDR_SRC_DST; + + sd_hdr = (lcaf_src_dst_hdr_t *) (p + size); + size += sizeof (sd_hdr[0]); + + size += fid_addr_parse (p + size, src); + size += fid_addr_parse (p + size, dst); + + if (fid_addr_type (src) == FID_ADDR_IP_PREF) + { + ip_prefix_t *ippref = &fid_addr_ippref (src); + ip_prefix_len (ippref) = LCAF_SD_SRC_ML (sd_hdr); + } + if (fid_addr_type (dst) == FID_ADDR_IP_PREF) + { + ip_prefix_t *ippref = &fid_addr_ippref (dst); + ip_prefix_len (ippref) = LCAF_SD_DST_ML (sd_hdr); + } + return size; +} + +u16 +try_parse_src_dst_lcaf (u8 * p, gid_address_t * a) +{ + lcaf_t lcaf; + u16 size = sizeof (u16); /* skip AFI */ + + size += lcaf_hdr_parse (p + size, &lcaf); + + if (LCAF_SOURCE_DEST != lcaf_type (&lcaf)) + return ~0; + + size += sd_parse (p + size, a); + return size; +} + +u16 +vni_parse (u8 * p, void *a) +{ + lcaf_t *lcaf = a; + gid_address_t *g = a; + u16 size = 0; + + gid_address_vni (g) = clib_net_to_host_u32 (*(u32 *) p); + size += sizeof (u32); + gid_address_vni_mask (g) = lcaf_vni_len (lcaf); + + /* nested LCAFs are not supported except of src/dst with vni - to handle + * such case look at the next AFI and process src/dest LCAF separately */ + u16 afi = clib_net_to_host_u16 (*((u16 *) (p + size))); + if (LISP_AFI_LCAF == afi) + { + u16 len = try_parse_src_dst_lcaf (p + size, g); + if ((u16) ~ 0 == len) + return ~0; + size += len; + } + else + size += gid_address_parse (p + size, g); + + return size; +} + +u16 +no_addr_parse (u8 * p, void *a) +{ + /* do nothing */ + return 0; +} + +u32 +lcaf_parse (void *offset, gid_address_t * addr) +{ + /* skip AFI type */ + offset += sizeof (u16); + lcaf_t *lcaf = &gid_address_lcaf (addr); + + u32 size = lcaf_hdr_parse (offset, lcaf); + u8 type = lcaf_type (lcaf); + + if (!lcaf_parse_fcts[type]) + { + clib_warning ("Unsupported LCAF type: %u", type); + return ~0; + } + size += (*lcaf_parse_fcts[type]) (offset + size, lcaf); + return sizeof (u16) + size; +} + +void +vni_free (void *a) +{ + vni_t *v = a; + gid_address_free (vni_gid (v)); + clib_mem_free (vni_gid (v)); +} + +void +no_addr_free (void *a) +{ + /* nothing to do */ +} + +void +sd_free (void *a) +{ + /* nothing */ +} + +void +gid_address_free (gid_address_t * a) +{ + if (gid_address_type (a) != GID_ADDR_LCAF) + return; + + lcaf_t *lcaf = &gid_address_lcaf (a); + u8 lcaf_type = lcaf_type (lcaf); + (*lcaf_free_fcts[lcaf_type]) (lcaf); +} + +void +gid_address_from_ip (gid_address_t * g, ip_address_t * ip) { - 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); + memset (g, 0, sizeof (g[0])); + ip_address_set (&gid_address_ip (g), ip, ip_addr_version (ip)); + gid_address_ippref_len (g) = 32; } int -ip_address_cmp (ip_address_t * ip1, ip_address_t * ip2) +ip_address_cmp (const ip_address_t * ip1, const ip_address_t * ip2) { int res = 0; - if (ip_addr_version (ip1) != ip_addr_version(ip2)) + 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)); + res = + memcmp (&ip_addr_addr (ip1), &ip_addr_addr (ip2), ip_address_size (ip1)); if (res < 0) res = 2; @@ -267,115 +747,572 @@ ip_address_cmp (ip_address_t * ip1, ip_address_t * ip2) } void -ip_address_copy (ip_address_t * dst , ip_address_t * src) +ip_address_copy (ip_address_t * dst, const ip_address_t * src) +{ + if (IP4 == ip_addr_version (src)) + { + /* don't copy any garbe from the union */ + memset (dst, 0, sizeof (*dst)); + dst->ip.v4 = src->ip.v4; + dst->version = IP4; + } + else + { + clib_memcpy (dst, src, sizeof (ip_address_t)); + } +} + +void +ip_address_copy_addr (void *dst, const ip_address_t * src) +{ + clib_memcpy (dst, src, ip_address_size (src)); +} + +void +ip_address_set (ip_address_t * dst, const void *src, u8 version) +{ + clib_memcpy (dst, src, ip_version_to_size (version)); + ip_addr_version (dst) = version; +} + +void +ip_address_to_46 (const ip_address_t * addr, + ip46_address_t * a, fib_protocol_t * proto) { - clib_memcpy (dst, src, sizeof (ip_address_t)); + *proto = (IP4 == ip_addr_version (addr) ? + FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6); + switch (*proto) + { + case FIB_PROTOCOL_IP4: + ip46_address_set_ip4 (a, &addr->ip.v4); + break; + case FIB_PROTOCOL_IP6: + a->ip6 = addr->ip.v6; + break; + default: + ASSERT (0); + break; + } +} + +static void +ip_prefix_normalize_ip4 (ip4_address_t * ip4, u8 preflen) +{ + u32 mask = ~0; + + ASSERT (ip4); + + if (32 <= preflen) + { + return; + } + + mask = pow2_mask (preflen) << (32 - preflen); + mask = clib_host_to_net_u32 (mask); + ip4->data_u32 &= mask; +} + +static void +ip_prefix_normalize_ip6 (ip6_address_t * ip6, u8 preflen) +{ + u8 mask_6[16]; + u32 *m; + u8 j, i0, i1; + + ASSERT (ip6); + + memset (mask_6, 0, sizeof (mask_6)); + + if (128 <= preflen) + { + return; + } + + i1 = preflen % 32; + i0 = preflen / 32; + m = (u32 *) & mask_6[0]; + + for (j = 0; j < i0; j++) + { + m[j] = ~0; + } + + if (i1) + { + m[i0] = clib_host_to_net_u32 (pow2_mask (i1) << (32 - i1)); + } + + for (j = 0; j < sizeof (mask_6); j++) + { + ip6->as_u8[j] &= mask_6[j]; + } } void -ip_address_copy_addr (void * dst , ip_address_t * src) +ip_prefix_normalize (ip_prefix_t * a) { - clib_memcpy (dst, src, ip_address_size(src)); + u8 preflen = ip_prefix_len (a); + + switch (ip_prefix_version (a)) + { + case IP4: + ip_prefix_normalize_ip4 (&ip_prefix_v4 (a), preflen); + break; + + case IP6: + ip_prefix_normalize_ip6 (&ip_prefix_v6 (a), preflen); + break; + + default: + ASSERT (0); + } } void * ip_prefix_cast (gid_address_t * a) { - return &gid_address_ippref(a); + return &gid_address_ippref (a); } u16 -ip_prefix_size_to_write (void * pref) +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_write (u8 * p, void *gid) { - ip_prefix_t *a = (ip_prefix_t *) pref; + gid_address_t *g = gid; + ip_prefix_t *a = &gid_address_ippref (g); + 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); + return ip_prefix_len ((ip_prefix_t *) a); } void -ip_prefix_copy (void * dst , void * src) +ip_prefix_copy (void *dst, void *src) { clib_memcpy (dst, src, sizeof (ip_prefix_t)); } +void +mac_copy (void *dst, void *src) +{ + clib_memcpy (dst, src, 6); +} + +void +sd_copy (void *dst, void *src) +{ + clib_memcpy (dst, src, sizeof (source_dest_t)); +} + int -ip_prefix_cmp(ip_prefix_t * p1, ip_prefix_t * p2) +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)); + + ip_prefix_normalize (p1); + ip_prefix_normalize (p2); + + 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; + 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; +} + +void +no_addr_copy (void *dst, void *src) +{ + /* nothing to do */ +} + +void +vni_copy (void *dst, void *src) +{ + vni_t *vd = dst; + vni_t *vs = src; + + clib_memcpy (vd, vs, sizeof (vd[0])); + vni_gid (vd) = clib_mem_alloc (sizeof (gid_address_t)); + gid_address_copy (vni_gid (vd), vni_gid (vs)); +} + +void +lcaf_copy (void *dst, void *src) +{ + lcaf_t *lcaf_dst = dst; + lcaf_t *lcaf_src = src; + + lcaf_type (lcaf_dst) = lcaf_type (lcaf_src); + (*lcaf_copy_fcts[lcaf_type (lcaf_src)]) (dst, src); +} + +u8 +lcaf_length (void *a) +{ + return 0; +} + +u8 +mac_length (void *a) +{ + return 0; +} + +u8 +sd_length (void *a) +{ + return 0; +} + +void * +lcaf_cast (gid_address_t * a) +{ + return &gid_address_lcaf (a); +} + +void * +mac_cast (gid_address_t * a) +{ + return &gid_address_mac (a); +} + +void * +sd_cast (gid_address_t * a) +{ + return &gid_address_sd (a); +} + +u8 +no_addr_length (void *a) +{ + return 0; +} + +u8 +vni_length (void *a) +{ + vni_t *v = a; + return (sizeof (u32) /* VNI size */ + + gid_address_size_to_put (vni_gid (v)) /* vni body size */ ); +} + +u16 +lcaf_write (u8 * p, void *a) +{ + u16 size = 0, len; + lcaf_t *lcaf = a; + u8 type = lcaf_type (lcaf); + lcaf_hdr_t _h, *h = &_h; + + *(u16 *) p = clib_host_to_net_u16 (LISP_AFI_LCAF); + size += sizeof (u16); + memset (h, 0, sizeof (h[0])); + LCAF_TYPE (h) = type; + u16 lcaf_len = (*lcaf_body_length_fcts[type]) (lcaf); + LCAF_LENGTH (h) = clib_host_to_net_u16 (lcaf_len); + + clib_memcpy (p + size, h, sizeof (h[0])); + size += sizeof (h[0]); + len = (*lcaf_write_fcts[type]) (p + size, lcaf); + + if ((u16) ~ 0 == len) + return ~0; + + return size + len; +} + +u16 +mac_write (u8 * p, void *a) +{ + *(u16 *) p = clib_host_to_net_u16 (LISP_AFI_MAC); + clib_memcpy (p + sizeof (u16), a, 6); + return mac_size_to_write (a); +} + +static u16 +fid_addr_write (u8 * p, fid_address_t * a) +{ + switch (fid_addr_type (a)) + { + case FID_ADDR_IP_PREF: + return ip_prefix_write (p, &fid_addr_ippref (a)); + + case FID_ADDR_MAC: + return mac_write (p, &fid_addr_mac (a)); + + default: + return ~0; } - else + return ~0; +} + +static u8 +fid_address_length (fid_address_t * a) +{ + switch (fid_addr_type (a)) { - if (ip_prefix_len(p1) > ip_prefix_len(p2)) - cmp = 2; + case FID_ADDR_IP_PREF: + return ip_prefix_length (&fid_addr_ippref (a)); + case FID_ADDR_MAC: + return 0; } - } - return cmp; + return 0; +} + +u16 +sd_write (u8 * p, void *a) +{ + source_dest_t *sd = a; + u16 size = 0; + lcaf_hdr_t _h, *h = &_h; + lcaf_src_dst_hdr_t sd_hdr; + + *(u16 *) p = clib_host_to_net_u16 (LISP_AFI_LCAF); + size += sizeof (u16); + memset (h, 0, sizeof (h[0])); + LCAF_TYPE (h) = LCAF_SOURCE_DEST; + u16 lcaf_len = sizeof (lcaf_src_dst_hdr_t) + + fid_addr_size_to_write (&sd_src (sd)) + + fid_addr_size_to_write (&sd_dst (sd)); + LCAF_LENGTH (h) = clib_host_to_net_u16 (lcaf_len); + + clib_memcpy (p + size, h, sizeof (h[0])); + size += sizeof (h[0]); + + memset (&sd_hdr, 0, sizeof (sd_hdr)); + LCAF_SD_SRC_ML (&sd_hdr) = fid_address_length (&sd_src (sd)); + LCAF_SD_DST_ML (&sd_hdr) = fid_address_length (&sd_dst (sd)); + clib_memcpy (p + size, &sd_hdr, sizeof (sd_hdr)); + size += sizeof (sd_hdr); + + u16 len = fid_addr_write (p + size, &sd_src (sd)); + if ((u16) ~ 0 == len) + return ~0; + size += len; + + len = fid_addr_write (p + size, &sd_dst (sd)); + if ((u16) ~ 0 == len) + return ~0; + size += len; + + return size; +} + +u16 +vni_write (u8 * p, void *a) +{ + lcaf_hdr_t _h, *h = &_h; + gid_address_t *g = a; + u16 size = 0, len; + + /* put lcaf header */ + *(u16 *) p = clib_host_to_net_u16 (LISP_AFI_LCAF); + size += sizeof (u16); + memset (h, 0, sizeof (h[0])); + LCAF_TYPE (h) = LCAF_INSTANCE_ID; + u16 lcaf_len = sizeof (u32) /* Instance ID size */ + + gid_address_size_to_put_no_vni (g); + LCAF_LENGTH (h) = clib_host_to_net_u16 (lcaf_len); + LCAF_RES2 (h) = gid_address_vni_mask (g); + + /* put vni header */ + clib_memcpy (p + size, h, sizeof (h[0])); + size += sizeof (h[0]); + + u32 *afip = (u32 *) (p + size); + afip[0] = clib_host_to_net_u32 (gid_address_vni (g)); + size += sizeof (u32); + + if (GID_ADDR_SRC_DST == gid_address_type (g)) + /* write src/dst LCAF */ + { + len = sd_write (p + size, g); + if ((u16) ~ 0 == len) + return ~0; + } + else + /* write the actual address */ + len = gid_address_put_no_vni (p + size, g); + + if ((u16) ~ 0 == len) + return ~0; + + return size + len; +} + +u16 +no_addr_write (u8 * p, void *a) +{ + /* do nothing; return AFI field size */ + return sizeof (u16); +} + +u16 +no_addr_size_to_write (void *a) +{ + return sizeof (u16); /* AFI field length */ +} + +static u16 +fid_addr_size_to_write (fid_address_t * a) +{ + switch (fid_addr_type (a)) + { + case FID_ADDR_IP_PREF: + return ip_prefix_size_to_write (a); + + case FID_ADDR_MAC: + return mac_size_to_write (a); + + default: + break; + } + return 0; +} + +u16 +vni_size_to_write (void *a) +{ + gid_address_t *g = a; + + u16 lcaf_size = sizeof (u32) + sizeof (u16) /* LCAF AFI field size */ + + sizeof (lcaf_hdr_t); + + if (gid_address_type (g) == GID_ADDR_SRC_DST) + /* special case where nested LCAF is supported */ + return lcaf_size + sd_size_to_write (g); + else + return lcaf_size + gid_address_size_to_put_no_vni (g); +} + +u16 +lcaf_size_to_write (void *a) +{ + lcaf_t *lcaf = (lcaf_t *) a; + u32 size = 0, len; + u8 type = lcaf_type (lcaf); + + size += sizeof (u16); /* AFI size */ + + len = (*lcaf_size_to_write_fcts[type]) (lcaf); + if (~0 == len) + return ~0; + + return size + len; +} + +u16 +sd_size_to_write (void *a) +{ + source_dest_t *sd = a; + return sizeof (u16) + + sizeof (lcaf_hdr_t) + + sizeof (lcaf_src_dst_hdr_t) + + fid_addr_size_to_write (&sd_src (sd)) + + fid_addr_size_to_write (&sd_dst (sd)); +} + +u16 +mac_size_to_write (void *a) +{ + return sizeof (u16) + 6; } u8 -gid_address_len (gid_address_t *a) +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)); + return (*addr_len_fcts[type]) ((*cast_fcts[type]) (a)); +} + +static u16 +gid_address_put_no_vni (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_put (u8 * b, gid_address_t * gid) +{ + if (0 != gid_address_vni (gid)) + return vni_write (b, gid); + + return gid_address_put_no_vni (b, gid); +} + +static u16 +gid_address_size_to_put_no_vni (gid_address_t * gid) { gid_address_type_t type = gid_address_type (gid); - return (*write_fcts[type])(b, (*cast_fcts[type])(gid)); + return (*size_to_write_fcts[type]) ((*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)); + if (0 != gid_address_vni (gid)) + return vni_size_to_write (gid); + + return gid_address_size_to_put_no_vni (gid); } void * gid_address_cast (gid_address_t * gid, gid_address_type_t type) { - return (*cast_fcts[type])(gid); + return (*cast_fcts[type]) (gid); } void -gid_address_copy(gid_address_t * dst, gid_address_t * src) +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; + 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; + gid_address_vni (dst) = gid_address_vni (src); + gid_address_vni_mask (dst) = gid_address_vni_mask (src); } u32 -gid_address_parse (u8 * offset, gid_address_t *a) +mac_parse (u8 * offset, u8 * a) +{ + /* skip AFI field */ + offset += sizeof (u16); + + clib_memcpy (a, offset, 6); + return sizeof (u16) + 6; +} + +u32 +gid_address_parse (u8 * offset, gid_address_t * a) { lisp_afi_e afi; int len = 0; @@ -383,34 +1320,108 @@ gid_address_parse (u8 * offset, gid_address_t *a) if (!a) return 0; + /* NOTE: since gid_address_parse may be called by vni_parse, we can't 0 + * the gid address here */ afi = clib_net_to_host_u16 (*((u16 *) offset)); switch (afi) { case LISP_AFI_NO_ADDR: - len = sizeof(u16); - gid_address_type(a) = NO_ADDRESS; + len = sizeof (u16); + gid_address_type (a) = GID_ADDR_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; + len = ip_address_parse (offset, afi, &gid_address_ip (a)); + gid_address_type (a) = GID_ADDR_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; + len = ip_address_parse (offset, afi, &gid_address_ip (a)); + gid_address_type (a) = GID_ADDR_IP_PREFIX; + /* this should be modified outside if needed */ + gid_address_ippref_len (a) = 128; break; case LISP_AFI_LCAF: + gid_address_type (a) = GID_ADDR_LCAF; + len = lcaf_parse (offset, a); + break; + case LISP_AFI_MAC: + len = mac_parse (offset, gid_address_mac (a)); + gid_address_type (a) = GID_ADDR_MAC; + break; default: - clib_warning("LISP AFI %d not supported!", afi); + clib_warning ("LISP AFI %d not supported!", afi); return ~0; } return len; } +void +gid_address_ip_set (gid_address_t * dst, void *src, u8 version) +{ + gid_address_ippref_len (dst) = ip_address_max_len (version); + ip_address_set (&gid_address_ip (dst), src, version); +} + +int +no_addr_cmp (void *a1, void *a2) +{ + return 0; +} + +int +vni_cmp (void *a1, void *a2) +{ + vni_t *v1 = a1; + vni_t *v2 = a2; + + if (vni_mask_len (v1) != vni_mask_len (v2)) + return -1; + if (vni_vni (v1) != vni_vni (v2)) + return -1; + return gid_address_cmp (vni_gid (v1), vni_gid (v2)); +} + +static int +mac_cmp (void *a1, void *a2) +{ + return memcmp (a1, a2, 6); +} + +static int +fid_addr_cmp (fid_address_t * a1, fid_address_t * a2) +{ + if (fid_addr_type (a1) != fid_addr_type (a2)) + return -1; + + switch (fid_addr_type (a1)) + { + case FID_ADDR_IP_PREF: + return ip_prefix_cmp (&fid_addr_ippref (a1), &fid_addr_ippref (a2)); + + case FID_ADDR_MAC: + return mac_cmp (fid_addr_mac (a1), fid_addr_mac (a2)); + + default: + return -1; + } + return -1; +} + +int +sd_cmp (void *a1, void *a2) +{ + source_dest_t *sd1 = a1; + source_dest_t *sd2 = a2; + + if (fid_addr_cmp (&sd_dst (sd1), &sd_dst (sd2))) + return -1; + if (fid_addr_cmp (&sd_src (sd1), &sd_src (sd2))) + return -1; + return 0; +} + /* Compare two gid_address_t. * Returns: * -1: If they are from different afi @@ -421,22 +1432,41 @@ gid_address_parse (u8 * offset, gid_address_t *a) int gid_address_cmp (gid_address_t * a1, gid_address_t * a2) { + lcaf_t *lcaf1, *lcaf2; int cmp = -1; if (!a1 || !a2) return -1; - if (gid_address_type(a1) != gid_address_type(a2)) + if (gid_address_type (a1) != gid_address_type (a2)) + return -1; + if (gid_address_vni (a1) != gid_address_vni (a2)) + return -1; + if (gid_address_vni_mask (a1) != gid_address_vni_mask (a2)) return -1; - switch (gid_address_type(a1)) + switch (gid_address_type (a1)) { - case NO_ADDRESS: + case GID_ADDR_NO_ADDRESS: if (a1 == a2) - cmp = 0; + cmp = 0; else - cmp = 2; + cmp = 2; + break; + case GID_ADDR_IP_PREFIX: + cmp = + ip_prefix_cmp (&gid_address_ippref (a1), &gid_address_ippref (a2)); break; - case IP_PREFIX: - cmp = ip_prefix_cmp (&gid_address_ippref(a1), &gid_address_ippref(a2)); + case GID_ADDR_LCAF: + lcaf1 = &gid_address_lcaf (a1); + lcaf2 = &gid_address_lcaf (a2); + if (lcaf_type (lcaf1) == lcaf_type (lcaf2)) + cmp = (*lcaf_cmp_fcts[lcaf_type (lcaf1)]) (lcaf1, lcaf2); + break; + case GID_ADDR_MAC: + cmp = mac_cmp (gid_address_mac (a1), gid_address_mac (a2)); + break; + + case GID_ADDR_SRC_DST: + cmp = sd_cmp (&gid_address_sd (a1), &gid_address_sd (a2)); break; default: break; @@ -445,37 +1475,38 @@ gid_address_cmp (gid_address_t * a1, gid_address_t * a2) return cmp; } - u32 -locator_parse (void * b, locator_t * loc) +locator_parse (void *b, locator_t * loc) { - locator_hdr_t * h; - u8 status = 1; /* locator up */ + locator_hdr_t *h; + u8 status = 1; /* locator up */ int len; h = b; - if (!LOC_REACHABLE(h) && LOC_LOCAL(h)) + if (!LOC_REACHABLE (h) && LOC_LOCAL (h)) status = 0; - len = gid_address_parse (LOC_ADDR(h), &loc->address); + 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); + 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; + 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)); + clib_memcpy (dst, src, sizeof (*dst)); + if (!src->local) + gid_address_copy (&dst->address, &src->address); } u32 @@ -495,3 +1526,49 @@ locator_cmp (locator_t * l1, locator_t * l2) return 1; return 0; } + +void +locator_free (locator_t * l) +{ + if (!l->local) + gid_address_free (&l->address); +} + +void +build_src_dst (gid_address_t * sd, gid_address_t * src, gid_address_t * dst) +{ + memset (sd, 0, sizeof (*sd)); + gid_address_type (sd) = GID_ADDR_SRC_DST; + gid_address_vni (sd) = gid_address_vni (dst); + gid_address_vni_mask (sd) = gid_address_vni_mask (dst); + + switch (gid_address_type (dst)) + { + case GID_ADDR_IP_PREFIX: + gid_address_sd_src_type (sd) = FID_ADDR_IP_PREF; + gid_address_sd_dst_type (sd) = FID_ADDR_IP_PREF; + ip_prefix_copy (&gid_address_sd_src_ippref (sd), + &gid_address_ippref (src)); + ip_prefix_copy (&gid_address_sd_dst_ippref (sd), + &gid_address_ippref (dst)); + break; + case GID_ADDR_MAC: + gid_address_sd_src_type (sd) = FID_ADDR_MAC; + gid_address_sd_dst_type (sd) = FID_ADDR_MAC; + mac_copy (gid_address_sd_src_mac (sd), gid_address_mac (src)); + mac_copy (gid_address_sd_dst_mac (sd), gid_address_mac (dst)); + break; + default: + clib_warning ("Unsupported gid type %d while conversion!", + gid_address_type (dst)); + break; + } +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */