meta/saiserialize.c (1,019 lines of code) (raw):
/**
* Copyright (c) 2014 Microsoft Open Technologies, Inc.
*
* 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
*
* THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
* LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS
* FOR A PARTICULAR PURPOSE, MERCHANTABILITY OR NON-INFRINGEMENT.
*
* See the Apache Version 2.0 License for specific language governing
* permissions and limitations under the License.
*
* Microsoft would like to thank the following companies for their review and
* assistance with these files: Intel Corporation, Mellanox Technologies Ltd,
* Dell Products, L.P., Facebook, Inc., Marvell International Ltd.
*
* @file saiserialize.c
*
* @brief This module defines SAI Metadata Serialize
*/
#include <arpa/inet.h>
#include <byteswap.h>
#include <ctype.h>
#include <errno.h>
#include <inttypes.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sai.h>
#include "saimetadatautils.h"
#include "saimetadata.h"
#include "saiserialize.h"
#define PRIMITIVE_BUFFER_SIZE 128
#define MAX_CHARS_PRINT 25
/* Expect macros */
#define EXPECT(x) { \
if (strncmp(buf, x, sizeof(x) - 1) == 0) { buf += sizeof(x) - 1; } \
else { \
SAI_META_LOG_WARN("expected '%s' but got '%.*s...'", x, (int)sizeof(x), buf); \
return SAI_SERIALIZE_ERROR; } }
#define EXPECT_KEY(k) EXPECT("\"" k "\":")
#define EXPECT_NEXT_KEY(k) { EXPECT(","); EXPECT_KEY(k); }
#define EXPECT_CHECK(expr, suffix) { \
ret = (expr); \
if (ret < 0) { \
SAI_META_LOG_WARN("failed to deserialize " #suffix ""); \
return SAI_SERIALIZE_ERROR; } \
buf += ret; }
#define EXPECT_QUOTE_CHECK(expr, suffix) {\
EXPECT("\""); EXPECT_CHECK(expr, suffix); EXPECT("\""); }
bool sai_serialize_is_char_allowed(
_In_ char c)
{
/*
* When we will perform deserialize, we allow buffer string to be
* terminated not only by zero, but also with json characters like:
*
* - end of quote
* - comma, next item in array
* - end of array
*
* This will be handy when performing deserialize.
*/
return c == 0 || c == '"' || c == ',' || c == ']' || c == '}';
}
int sai_serialize_bool(
_Out_ char *buffer,
_In_ bool flag)
{
return sprintf(buffer, "%s", flag ? "true" : "false");
}
#define SAI_TRUE_LENGTH 4
#define SAI_FALSE_LENGTH 5
int sai_deserialize_bool(
_In_ const char *buffer,
_Out_ bool *flag)
{
if (strncmp(buffer, "true", SAI_TRUE_LENGTH) == 0 &&
sai_serialize_is_char_allowed(buffer[SAI_TRUE_LENGTH]))
{
*flag = true;
return SAI_TRUE_LENGTH;
}
if (strncmp(buffer, "false", SAI_FALSE_LENGTH) == 0 &&
sai_serialize_is_char_allowed(buffer[SAI_FALSE_LENGTH]))
{
*flag = false;
return SAI_FALSE_LENGTH;
}
/*
* Limit printf to maximum "false" length + 1 if there is invalid character
* after "false" string.
*/
SAI_META_LOG_WARN("failed to deserialize '%.*s' as bool",
SAI_FALSE_LENGTH + 1,
buffer);
return SAI_SERIALIZE_ERROR;
}
int sai_serialize_chardata(
_Out_ char *buffer,
_In_ const char data[SAI_CHARDATA_LENGTH])
{
int idx;
for (idx = 0; idx < SAI_CHARDATA_LENGTH; ++idx)
{
char c = data[idx];
if (c == 0)
{
break;
}
if (isprint(c) && c != '\\' && c != '"')
{
buffer[idx] = c;
continue;
}
SAI_META_LOG_WARN("invalid character 0x%x in chardata", c);
return SAI_SERIALIZE_ERROR;
}
buffer[idx] = 0;
return idx;
}
int sai_deserialize_chardata(
_In_ const char *buffer,
_Out_ char data[SAI_CHARDATA_LENGTH])
{
int idx;
memset(data, 0, SAI_CHARDATA_LENGTH);
for (idx = 0; idx < SAI_CHARDATA_LENGTH; ++idx)
{
char c = buffer[idx];
if (isprint(c) && c != '\\' && c != '"')
{
data[idx] = c;
continue;
}
if (c == 0)
{
break;
}
if (c == '"')
{
/*
* We allow quote as last char since chardata will be serialized in
* quotes.
*/
break;
}
SAI_META_LOG_WARN("invalid character 0x%x in chardata", c);
return SAI_SERIALIZE_ERROR;
}
if (sai_serialize_is_char_allowed(buffer[idx]))
{
return idx;
}
SAI_META_LOG_WARN("invalid character 0x%x in chardata", buffer[idx]);
return SAI_SERIALIZE_ERROR;
}
int sai_serialize_uint8(
_Out_ char *buffer,
_In_ uint8_t u8)
{
return sprintf(buffer, "%u", u8);
}
int sai_deserialize_uint8(
_In_ const char *buffer,
_Out_ uint8_t *u8)
{
uint64_t u64;
int res = sai_deserialize_uint64(buffer, &u64);
if (res > 0 && u64 <= UCHAR_MAX)
{
*u8 = (uint8_t)u64;
return res;
}
SAI_META_LOG_WARN("failed to deserialize '%.*s' as uint8", MAX_CHARS_PRINT, buffer);
return SAI_SERIALIZE_ERROR;
}
int sai_serialize_int8(
_Out_ char *buffer,
_In_ int8_t u8)
{
return sprintf(buffer, "%d", u8);
}
int sai_deserialize_int8(
_In_ const char *buffer,
_Out_ int8_t *s8)
{
int64_t s64;
int res = sai_deserialize_int64(buffer, &s64);
if (res > 0 && s64 >= CHAR_MIN && s64 <= CHAR_MAX)
{
*s8 = (int8_t)s64;
return res;
}
SAI_META_LOG_WARN("failed to deserialize '%.*s' as int8", MAX_CHARS_PRINT, buffer);
return SAI_SERIALIZE_ERROR;
}
int sai_serialize_uint16(
_Out_ char *buffer,
_In_ uint16_t u16)
{
return sprintf(buffer, "%u", u16);
}
int sai_deserialize_uint16(
_In_ const char *buffer,
_Out_ uint16_t *u16)
{
uint64_t u64;
int res = sai_deserialize_uint64(buffer, &u64);
if (res > 0 && u64 <= USHRT_MAX)
{
*u16 = (uint16_t)u64;
return res;
}
SAI_META_LOG_WARN("failed to deserialize '%.*s' as uint16", MAX_CHARS_PRINT, buffer);
return SAI_SERIALIZE_ERROR;
}
int sai_serialize_int16(
_Out_ char *buffer,
_In_ int16_t s16)
{
return sprintf(buffer, "%d", s16);
}
int sai_deserialize_int16(
_In_ const char *buffer,
_Out_ int16_t *s16)
{
int64_t s64;
int res = sai_deserialize_int64(buffer, &s64);
if (res > 0 && s64 >= SHRT_MIN && s64 <= SHRT_MAX)
{
*s16 = (int16_t)s64;
return res;
}
SAI_META_LOG_WARN("failed to deserialize '%.*s' as int16", MAX_CHARS_PRINT, buffer);
return SAI_SERIALIZE_ERROR;
}
int sai_serialize_uint32(
_Out_ char *buffer,
_In_ uint32_t u32)
{
return sprintf(buffer, "%u", u32);
}
int sai_deserialize_uint32(
_In_ const char *buffer,
_Out_ uint32_t *u32)
{
uint64_t u64;
int res = sai_deserialize_uint64(buffer, &u64);
if (res > 0 && u64 <= UINT_MAX)
{
*u32 = (uint32_t)u64;
return res;
}
SAI_META_LOG_WARN("failed to deserialize '%.*s' as uint32", MAX_CHARS_PRINT, buffer);
return SAI_SERIALIZE_ERROR;
}
int sai_serialize_int32(
_Out_ char *buffer,
_In_ int32_t s32)
{
return sprintf(buffer, "%d", s32);
}
int sai_deserialize_int32(
_In_ const char *buffer,
_Out_ int32_t *s32)
{
int64_t s64;
int res = sai_deserialize_int64(buffer, &s64);
if (res > 0 && s64 >= INT_MIN && s64 <= INT_MAX)
{
*s32 = (int32_t)s64;
return res;
}
SAI_META_LOG_WARN("failed to deserialize '%.*s' as int32", MAX_CHARS_PRINT, buffer);
return SAI_SERIALIZE_ERROR;
}
int sai_serialize_uint64(
_Out_ char *buffer,
_In_ uint64_t u64)
{
return sprintf(buffer, "%"PRIu64, u64);
}
#define SAI_BASE_10 10
int sai_deserialize_uint64(
_In_ const char *buffer,
_Out_ uint64_t *u64)
{
int idx = 0;
uint64_t result = 0;
while (isdigit(buffer[idx]))
{
char c = (char)(buffer[idx] - '0');
/*
* Base is 10 we can check, that if result is greater than (2^64-1)/10)
* then next multiplication with 10 will cause overflow.
*/
if (result > (ULONG_MAX/SAI_BASE_10) ||
((result == ULONG_MAX/SAI_BASE_10) && (c > (char)(ULONG_MAX % SAI_BASE_10))))
{
idx = 0;
break;
}
result = result * 10 + (uint64_t)(c);
idx++;
}
if (idx > 0 && sai_serialize_is_char_allowed(buffer[idx]))
{
*u64 = result;
return idx;
}
SAI_META_LOG_WARN("failed to deserialize '%.*s...' as uint64", MAX_CHARS_PRINT, buffer);
return SAI_SERIALIZE_ERROR;
}
int sai_serialize_int64(
_Out_ char *buffer,
_In_ int64_t s64)
{
return sprintf(buffer, "%"PRId64, s64);
}
int sai_deserialize_int64(
_In_ const char *buffer,
_Out_ int64_t *s64)
{
uint64_t result = 0;
bool negative = 0;
if (*buffer == '-')
{
buffer++;
negative = true;
}
int res = sai_deserialize_uint64(buffer, &result);
if (res > 0)
{
if (negative)
{
if (result <= (uint64_t)(LONG_MIN))
{
*s64 = -(int64_t)result;
return res + 1;
}
}
else
{
if (result <= LONG_MAX)
{
*s64 = (int64_t)result;
return res;
}
}
}
SAI_META_LOG_WARN("failed to deserialize '%.*s' as int64", MAX_CHARS_PRINT, buffer);
return SAI_SERIALIZE_ERROR;
}
int sai_serialize_size(
_Out_ char *buffer,
_In_ sai_size_t size)
{
return sprintf(buffer, "%zu", size);
}
int sai_deserialize_size(
_In_ const char *buffer,
_Out_ sai_size_t *size)
{
uint64_t u64;
int res = sai_deserialize_uint64(buffer, &u64);
if (res > 0)
{
*size = (sai_size_t)u64;
return res;
}
SAI_META_LOG_WARN("failed to deserialize '%.*s...' as sai_size_t", MAX_CHARS_PRINT, buffer);
return SAI_SERIALIZE_ERROR;
}
int sai_serialize_object_id(
_Out_ char *buffer,
_In_ sai_object_id_t oid)
{
return sprintf(buffer, "oid:0x%"PRIx64, oid);
}
int sai_deserialize_object_id(
_In_ const char *buffer,
_Out_ sai_object_id_t *oid)
{
int read;
int n = sscanf(buffer, "oid:0x%16"PRIx64"%n", oid, &read);
if (n == 1 && sai_serialize_is_char_allowed(buffer[read]))
{
return read;
}
SAI_META_LOG_WARN("failed to deserialize '%.*s' as oid", MAX_CHARS_PRINT, buffer);
return SAI_SERIALIZE_ERROR;
}
int sai_serialize_mac(
_Out_ char *buffer,
_In_ const sai_mac_t mac)
{
return sprintf(buffer, "%02X:%02X:%02X:%02X:%02X:%02X",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}
#define SAI_MAC_ADDRESS_LENGTH 17
int sai_deserialize_mac(
_In_ const char *buffer,
_Out_ sai_mac_t mac)
{
int arr[6];
int read;
int n = sscanf(buffer, "%2X:%2X:%2X:%2X:%2X:%2X%n",
&arr[0], &arr[1], &arr[2], &arr[3], &arr[4], &arr[5], &read);
if (n == 6 && read == SAI_MAC_ADDRESS_LENGTH && sai_serialize_is_char_allowed(buffer[read]))
{
for (n = 0; n < 6; n++)
{
mac[n] = (uint8_t)arr[n];
}
return SAI_MAC_ADDRESS_LENGTH;
}
SAI_META_LOG_WARN("failed to deserialize '%.*s' as mac address", MAX_CHARS_PRINT, buffer);
return SAI_SERIALIZE_ERROR;
}
int sai_serialize_encrypt_key(
_Out_ char *buffer,
_In_ const sai_encrypt_key_t sak)
{
return sprintf(buffer, "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:\
%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:\
%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:\
%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X",
sak[0], sak[1], sak[2], sak[3], sak[4], sak[5],sak[6], sak[7],
sak[8], sak[9], sak[10], sak[11], sak[12], sak[13],sak[14], sak[15],
sak[16], sak[17], sak[18], sak[19], sak[20], sak[21],sak[22], sak[23],
sak[24], sak[25], sak[26], sak[27], sak[28], sak[29],sak[30], sak[31]);
}
int sai_deserialize_encrypt_key(
_In_ const char *buffer,
_Out_ sai_encrypt_key_t sak)
{
int arr[32];
int read;
int n = sscanf(buffer, "%2X:%2X:%2X:%2X:%2X:%2X:%2X:%2X:%2X:%2X:%2X:%2X:%2X:%2X:%2X:%2X:\
%2X:%2X:%2X:%2X:%2X:%2X:%2X:%2X:%2X:%2X:%2X:%2X:%2X:%2X:%2X:%2X%n",
&arr[0], &arr[1], &arr[2], &arr[3],
&arr[4], &arr[5], &arr[6], &arr[7],
&arr[8], &arr[9], &arr[10], &arr[11],
&arr[12], &arr[13], &arr[14], &arr[15],
&arr[16], &arr[17], &arr[18], &arr[19],
&arr[20], &arr[21], &arr[22], &arr[23],
&arr[24], &arr[25], &arr[26], &arr[27],
&arr[28], &arr[29], &arr[30], &arr[31], &read);
if (n == 32 && read == (32*3-1) && sai_serialize_is_char_allowed(buffer[read]))
{
for (n = 0; n < 32; n++)
{
sak[n] = (uint8_t)arr[n];
}
return read;
}
SAI_META_LOG_WARN("failed to deserialize '%.*s' as encrypt_key", MAX_CHARS_PRINT, buffer);
return SAI_SERIALIZE_ERROR;
}
int sai_serialize_auth_key(
_Out_ char *buffer,
_In_ const sai_auth_key_t auth)
{
return sprintf(buffer, "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:\
%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X",
auth[0], auth[1], auth[2], auth[3], auth[4], auth[5],auth[6], auth[7],
auth[8], auth[9], auth[10], auth[11], auth[12], auth[13],auth[14], auth[15]);
}
int sai_deserialize_auth_key(
_In_ const char *buffer,
_Out_ sai_auth_key_t auth)
{
int arr[16];
int read;
int n = sscanf(buffer, "%2X:%2X:%2X:%2X:%2X:%2X:%2X:%2X:%2X:%2X:%2X:%2X:%2X:%2X:%2X:%2X%n",
&arr[0], &arr[1], &arr[2], &arr[3],
&arr[4], &arr[5], &arr[6], &arr[7],
&arr[8], &arr[9], &arr[10], &arr[11],
&arr[12], &arr[13], &arr[14], &arr[15], &read);
if (n == 16 && read == (16*3-1) && sai_serialize_is_char_allowed(buffer[read]))
{
for (n = 0; n < 16; n++)
{
auth[n] = (uint8_t)arr[n];
}
return read;
}
SAI_META_LOG_WARN("failed to deserialize '%.*s' as auth_key", MAX_CHARS_PRINT, buffer);
return SAI_SERIALIZE_ERROR;
}
int sai_serialize_macsec_sak(
_Out_ char *buffer,
_In_ const sai_macsec_sak_t sak)
{
return sai_serialize_encrypt_key(buffer, sak);
}
int sai_deserialize_macsec_sak(
_In_ const char *buffer,
_Out_ sai_macsec_sak_t sak)
{
return sai_deserialize_encrypt_key(buffer, sak);
}
int sai_serialize_macsec_auth_key(
_Out_ char *buffer,
_In_ const sai_macsec_auth_key_t auth)
{
return sai_serialize_auth_key(buffer, auth);
}
int sai_deserialize_macsec_auth_key(
_In_ const char *buffer,
_Out_ sai_macsec_auth_key_t auth)
{
return sai_deserialize_auth_key(buffer, auth);
}
int sai_serialize_macsec_salt(
_Out_ char *buffer,
_In_ const sai_macsec_salt_t salt)
{
return sprintf(buffer, "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X",
salt[0], salt[1], salt[2], salt[3], salt[4], salt[5],salt[6], salt[7],
salt[8], salt[9], salt[10], salt[11]);
}
int sai_deserialize_macsec_salt(
_In_ const char *buffer,
_Out_ sai_macsec_salt_t salt)
{
int arr[32];
int read;
int n = sscanf(buffer, "%2X:%2X:%2X:%2X:%2X:%2X:%2X:%2X:%2X:%2X:%2X:%2X%n",
&arr[0], &arr[1], &arr[2], &arr[3],
&arr[4], &arr[5], &arr[6], &arr[7],
&arr[8], &arr[9], &arr[10], &arr[11],
&read);
if (n == 12 && read == (12*3-1) && sai_serialize_is_char_allowed(buffer[read]))
{
for (n = 0; n < 12; n++)
{
salt[n] = (uint8_t)arr[n];
}
return read;
}
SAI_META_LOG_WARN("failed to deserialize '%.*s' as macsec_salt", MAX_CHARS_PRINT, buffer);
return SAI_SERIALIZE_ERROR;
}
int sai_serialize_enum(
_Out_ char *buffer,
_In_ const sai_enum_metadata_t *meta,
_In_ int32_t value)
{
if (meta == NULL)
{
return sai_serialize_int32(buffer, value);
}
size_t i = 0;
for (; i < meta->valuescount; ++i)
{
if (meta->values[i] == value)
{
return sprintf(buffer, "%s", meta->valuesnames[i]);
}
}
SAI_META_LOG_WARN("enum value %d not found in enum %s", value, meta->name);
return sai_serialize_int32(buffer, value);
}
int sai_deserialize_enum(
_In_ const char *buffer,
_In_ const sai_enum_metadata_t *meta,
_Out_ int32_t *value)
{
if (meta == NULL)
{
return sai_deserialize_int32(buffer, value);
}
size_t idx = 0;
for (; idx < meta->valuescount; ++idx)
{
size_t len = strlen(meta->valuesnames[idx]);
if (strncmp(meta->valuesnames[idx], buffer, len) == 0 &&
sai_serialize_is_char_allowed(buffer[len]))
{
*value = meta->values[idx];
return (int)len;
}
}
SAI_META_LOG_WARN("enum value '%.*s' not found in enum %s", MAX_CHARS_PRINT, buffer, meta->name);
return sai_deserialize_int32(buffer, value);
}
static int sai_deserialize_ip(
_In_ const char *buffer,
_In_ int inet,
_Out_ uint8_t *ip)
{
/*
* Since we want relaxed version of deserialize, after ip address there
* may be '"' (quote), but inet_pton expects '\0' at the end, so copy at
* most INET6 characters to local buffer.
*/
char local[INET6_ADDRSTRLEN + 1];
int idx;
for (idx = 0; idx < INET6_ADDRSTRLEN; idx++)
{
char c = buffer[idx];
if (isxdigit(c) || c == ':' || c == '.')
{
local[idx] = c;
continue;
}
break;
}
local[idx] = 0;
if (inet_pton(inet, local, ip) != 1)
{
/*
* We should not warn here, since we will use this method to
* deserialize ip4 and ip6 and we will need to guess which one.
*/
return SAI_SERIALIZE_ERROR;
}
if (sai_serialize_is_char_allowed(buffer[idx]) || buffer[idx] == '/')
{
return idx;
}
SAI_META_LOG_WARN("invalid char 0x%x at end of ip address", buffer[idx]);
return SAI_SERIALIZE_ERROR;
}
int sai_serialize_ip4(
_Out_ char *buffer,
_In_ sai_ip4_t ip4)
{
if (inet_ntop(AF_INET, &ip4, buffer, INET_ADDRSTRLEN) == NULL)
{
SAI_META_LOG_WARN("failed to convert ipv4 address, errno: %s", strerror(errno));
return SAI_SERIALIZE_ERROR;
}
return (int)strlen(buffer);
}
int sai_deserialize_ip4(
_In_ const char *buffer,
_Out_ sai_ip4_t *ip4)
{
return sai_deserialize_ip(buffer, AF_INET, (uint8_t*)ip4);
}
int sai_serialize_ip6(
_Out_ char *buffer,
_In_ const sai_ip6_t ip6)
{
if (inet_ntop(AF_INET6, ip6, buffer, INET6_ADDRSTRLEN) == NULL)
{
SAI_META_LOG_WARN("failed to convert ipv6 address, errno: %s", strerror(errno));
return SAI_SERIALIZE_ERROR;
}
return (int)strlen(buffer);
}
int sai_deserialize_ip6(
_In_ const char *buffer,
_Out_ sai_ip6_t ip6)
{
return sai_deserialize_ip(buffer, AF_INET6, ip6);
}
int sai_serialize_ip_address(
_Out_ char *buffer,
_In_ const sai_ip_address_t *ip_address)
{
switch (ip_address->addr_family)
{
case SAI_IP_ADDR_FAMILY_IPV4:
return sai_serialize_ip4(buffer, ip_address->addr.ip4);
case SAI_IP_ADDR_FAMILY_IPV6:
return sai_serialize_ip6(buffer, ip_address->addr.ip6);
default:
SAI_META_LOG_WARN("invalid ip address family: %d", ip_address->addr_family);
return SAI_SERIALIZE_ERROR;
}
}
int sai_deserialize_ip_address(
_In_ const char *buffer,
_Out_ sai_ip_address_t *ip_address)
{
int res;
/* try first deserialize ip4 then ip6 */
res = sai_deserialize_ip(buffer, AF_INET, (uint8_t*)&ip_address->addr.ip4);
if (res > 0)
{
ip_address->addr_family = SAI_IP_ADDR_FAMILY_IPV4;
return res;
}
res = sai_deserialize_ip(buffer, AF_INET6, ip_address->addr.ip6);
if (res > 0)
{
ip_address->addr_family = SAI_IP_ADDR_FAMILY_IPV6;
return res;
}
SAI_META_LOG_WARN("failed to deserialize '%.*s' as ip address",
INET6_ADDRSTRLEN, buffer);
return SAI_SERIALIZE_ERROR;
}
int sai_serialize_ip_prefix(
_Out_ char *buffer,
_In_ const sai_ip_prefix_t *ip_prefix)
{
int ret = 0;
char addr[PRIMITIVE_BUFFER_SIZE];
char mask[PRIMITIVE_BUFFER_SIZE];
switch (ip_prefix->addr_family)
{
case SAI_IP_ADDR_FAMILY_IPV4:
ret |= sai_serialize_ip4(addr, ip_prefix->addr.ip4);
ret |= sai_serialize_ip4_mask(mask, ip_prefix->mask.ip4);
if (ret < 0)
{
SAI_META_LOG_WARN("failed to serialize ipv4");
return SAI_SERIALIZE_ERROR;
}
break;
case SAI_IP_ADDR_FAMILY_IPV6:
ret |= sai_serialize_ip6(addr, ip_prefix->addr.ip6);
ret |= sai_serialize_ip6_mask(mask, ip_prefix->mask.ip6);
if (ret < 0)
{
SAI_META_LOG_WARN("failed to serialize ipv6");
return SAI_SERIALIZE_ERROR;
}
break;
default:
SAI_META_LOG_WARN("invalid ip address family: %d", ip_prefix->addr_family);
return SAI_SERIALIZE_ERROR;
}
return sprintf(buffer, "%s/%s", addr, mask);
}
int sai_deserialize_ip_prefix(
_In_ const char *buffer,
_Out_ sai_ip_prefix_t *ip_prefix)
{
/* try first deserialize ip4 then ip6 */
int res, n;
while (true)
{
res = sai_deserialize_ip(buffer, AF_INET, (uint8_t*)&ip_prefix->addr.ip4);
if (res > 0)
{
ip_prefix->addr_family = SAI_IP_ADDR_FAMILY_IPV4;
if (buffer[res++] != '/')
{
break;
}
n = sai_deserialize_ip4_mask(buffer + res, &ip_prefix->mask.ip4);
if (n > 0)
{
return res + n;
}
break;
}
res = sai_deserialize_ip(buffer, AF_INET6, ip_prefix->addr.ip6);
if (res > 0)
{
if (buffer[res++] != '/')
{
break;
}
ip_prefix->addr_family = SAI_IP_ADDR_FAMILY_IPV6;
n = sai_deserialize_ip6_mask(buffer + res, (uint8_t*)&ip_prefix->mask.ip6);
if (n > 0)
{
return res + n;
}
}
break;
}
SAI_META_LOG_WARN("failed to deserialize '%.*s' as ip prefix", MAX_CHARS_PRINT, buffer);
return SAI_SERIALIZE_ERROR;
}
int sai_serialize_ip4_mask(
_Out_ char *buffer,
_In_ sai_ip4_t mask)
{
uint32_t n = 32;
uint32_t tmp = 0xFFFFFFFF;
mask = __builtin_bswap32(mask);
for (; (tmp != mask) && tmp; tmp <<= 1, n--);
if (tmp == mask)
{
return sai_serialize_uint32(buffer, n);
}
SAI_META_LOG_WARN("ipv4 mask 0x%X has holes", htonl(mask));
return SAI_SERIALIZE_ERROR;
}
int sai_deserialize_ip4_mask(
_In_ const char *buffer,
_Out_ sai_ip4_t *mask)
{
uint32_t value;
int res = sai_deserialize_uint32(buffer, &value);
if (res < 0 || value > 32)
{
SAI_META_LOG_WARN("failed to deserialize '%.*s' as ip4 mask", MAX_CHARS_PRINT, buffer);
return SAI_SERIALIZE_ERROR;
}
if (value == 0)
{
/* mask is all zeros */
}
else if (value == 32)
{
value = 0xFFFFFFFF;
}
else
{
value = 0xFFFFFFFF << (32 - value);
}
*mask = __builtin_bswap32(value);
return res;
}
int sai_serialize_ip6_mask(
_Out_ char *buffer,
_In_ const sai_ip6_t mask)
{
uint32_t n = 64;
uint64_t tmp = UINT64_C(0xFFFFFFFFFFFFFFFF);
uint64_t high;
uint64_t low;
memcpy(&high, (const uint8_t*)mask, sizeof(uint64_t));
memcpy(&low, ((const uint8_t*)mask + sizeof(uint64_t)), sizeof(uint64_t));
high = __builtin_bswap64(high);
low = __builtin_bswap64(low);
if (high == tmp)
{
for (; (tmp != low) && tmp; tmp <<= 1, n--);
if (tmp == low)
{
return sai_serialize_uint32(buffer, 64 + n);
}
}
else if (low == 0)
{
for (; (tmp != high) && tmp; tmp <<= 1, n--);
if (tmp == high)
{
return sai_serialize_uint32(buffer, n);
}
}
char buf[PRIMITIVE_BUFFER_SIZE];
sai_serialize_ip6(buf, mask);
SAI_META_LOG_WARN("ipv6 mask %s has holes", buf);
return SAI_SERIALIZE_ERROR;
}
int sai_deserialize_ip6_mask(
_In_ const char *buffer,
_Out_ sai_ip6_t mask)
{
uint64_t value;
int res = sai_deserialize_uint64(buffer, &value);
if (res < 0 || value > 128)
{
SAI_META_LOG_WARN("failed to deserialize '%.*s' as ip6 mask", MAX_CHARS_PRINT, buffer);
return SAI_SERIALIZE_ERROR;
}
uint64_t high = UINT64_C(0xFFFFFFFFFFFFFFFF);
uint64_t low = UINT64_C(0xFFFFFFFFFFFFFFFF);
uint64_t tmp;
if (value == 128)
{
/* mask is all ones */
}
else if (value == 64)
{
low = 0;
}
else if (value == 0)
{
low = 0;
high = 0;
}
else if (value > 64)
{
low = low << (128 - value);
}
else
{
high = high << (64 - value);
low = 0;
}
tmp = __builtin_bswap64(high);
memcpy((uint8_t*)mask, &tmp, sizeof(uint64_t));
tmp = __builtin_bswap64(low);
memcpy(((uint8_t*)mask + sizeof(uint64_t)), &tmp, sizeof(uint64_t));
return res;
}
int sai_serialize_pointer(
_Out_ char *buffer,
_In_ const sai_pointer_t pointer)
{
return sprintf(buffer, "ptr:%p", pointer);
}
int sai_deserialize_pointer(
_In_ const char *buffer,
_Out_ sai_pointer_t *pointer)
{
int read;
int n = sscanf(buffer, "ptr:%p%n", pointer, &read);
if (n == 1 && sai_serialize_is_char_allowed(buffer[read]))
{
return read;
}
SAI_META_LOG_WARN("failed to deserialize '%.*s' as pointer", MAX_CHARS_PRINT, buffer);
return SAI_SERIALIZE_ERROR;
}
int sai_serialize_enum_list(
_Out_ char *buf,
_In_ const sai_enum_metadata_t *meta,
_In_ const sai_s32_list_t *list)
{
if (meta == NULL)
{
return sai_serialize_s32_list(buf, list);
}
char *begin_buf = buf;
int ret;
buf += sprintf(buf, "{");
buf += sprintf(buf, "\"count\":");
buf += sprintf(buf, "%d", list->count);
buf += sprintf(buf, ",\"list\":");
if (list->list == NULL || list->count == 0)
{
buf += sprintf(buf, "null");
}
else
{
buf += sprintf(buf, "[");
uint32_t idx;
for (idx = 0; idx < list->count; idx++)
{
if (idx != 0)
{
buf += sprintf(buf, ",");
}
buf += sprintf(buf, "\"");
ret = sai_serialize_enum(buf, meta, list->list[idx]);
if (ret < 0)
{
SAI_META_LOG_WARN("failed to serialize enum_list");
return SAI_SERIALIZE_ERROR;
}
buf += ret;
buf += sprintf(buf, "\"");
}
buf += sprintf(buf, "]");
}
buf += sprintf(buf, "}");
return (int)(buf - begin_buf);
}
int sai_deserialize_enum_list(
_In_ const char *buffer,
_In_ const sai_enum_metadata_t *meta,
_Out_ sai_s32_list_t *list)
{
if (meta == NULL)
{
return sai_deserialize_s32_list(buffer, list);
}
const char *buf = buffer;
int ret;
uint32_t idx;
EXPECT("{");
EXPECT_KEY("count");
EXPECT_CHECK(sai_deserialize_uint32(buf, &list->count), uint32);
EXPECT_NEXT_KEY("list");
if (strncmp(buf, "null", 4) == 0)
{
list->list = NULL;
buf += 4;
}
else
{
list->list = calloc((list->count), sizeof(uint32_t));
EXPECT("[");
for (idx = 0; idx < list->count; idx++)
{
if (idx != 0)
{
EXPECT(",");
}
EXPECT_QUOTE_CHECK(sai_deserialize_enum(buf, meta, &list->list[idx]), enum);
}
EXPECT("]");
}
EXPECT("}");
return (int)(buf - buffer);
}
int sai_serialize_attr_id(
_Out_ char *buf,
_In_ const sai_attr_metadata_t *meta,
_In_ sai_attr_id_t attr_id)
{
if (meta != NULL)
{
strcpy(buf, meta->attridname);
return (int)strlen(buf);
}
SAI_META_LOG_WARN("failed to serialize attr_id");
return SAI_SERIALIZE_ERROR;
}
int sai_deserialize_attr_id(
_In_ const char *buffer,
_Out_ sai_attr_id_t *attr_id)
{
const sai_attr_metadata_t *meta;
meta = sai_metadata_get_attr_metadata_by_attr_id_name_ext(buffer);
if (meta != NULL)
{
*attr_id = meta->attrid;
return (int)strlen(meta->attridname);
}
SAI_META_LOG_WARN("failed to deserialize attr_id");
return SAI_SERIALIZE_ERROR;
}
int sai_serialize_attribute(
_Out_ char *buf,
_In_ const sai_attr_metadata_t *meta,
_In_ const sai_attribute_t *attribute)
{
char *begin_buf = buf;
int ret;
/* can be auto generated */
buf += sprintf(buf, "{");
buf += sprintf(buf, "\"id\":");
buf += sprintf(buf, "\"");
ret = sai_serialize_attr_id(buf, meta, attribute->id);
if (ret < 0)
{
SAI_META_LOG_WARN("failed to serialize attr id");
return SAI_SERIALIZE_ERROR;
}
buf += ret;
buf += sprintf(buf, "\",");
buf += sprintf(buf, "\"value\":");
ret = sai_serialize_attribute_value(buf, meta, &attribute->value);
if (ret < 0)
{
SAI_META_LOG_WARN("failed to serialize attribute value");
return SAI_SERIALIZE_ERROR;
}
buf += ret;
buf += sprintf(buf, "}");
return (int)(buf - begin_buf);
}
int sai_deserialize_attribute(
_In_ const char *buffer,
_Out_ sai_attribute_t *attribute)
{
const char *buf = buffer;
const sai_attr_metadata_t *meta;
size_t len;
int ret;
EXPECT("{");
EXPECT_KEY("id");
EXPECT("\"");
meta = sai_metadata_get_attr_metadata_by_attr_id_name_ext(buf);
if (meta != NULL)
{
len = strlen(meta->attridname);
attribute->id = meta->attrid;
buf += len;
}
else
{
SAI_META_LOG_WARN("Failed deserialize attribute id");
return SAI_SERIALIZE_ERROR;
}
EXPECT("\"");
EXPECT_NEXT_KEY("value");
EXPECT_CHECK(sai_deserialize_attribute_value(buf, meta, &attribute->value), "attr_value");
EXPECT("}");
return (int)(buf - buffer);
}