处理字节序相关的头文件。比如IP地址 192.168.10.20 这个IP地址。
在X86 CPU中处理时,长这样: 0x140aa8c0
在网络上传输时,长这样:0xc0a80a14
由于网络传输是按照低地址代表most significant byte的语义。这个与x86 这类的CPU刚好相反。
所以软件中需要做相应的处理,实际上就是在内存中做字节交换。
#include <vppinfra/clib.h>
#if (__BYTE_ORDER__)==( __ORDER_LITTLE_ENDIAN__)
#define CLIB_ARCH_IS_BIG_ENDIAN (0)
#define CLIB_ARCH_IS_LITTLE_ENDIAN (1)
#else
/* Default is big endian. */
#define CLIB_ARCH_IS_BIG_ENDIAN (1)
#define CLIB_ARCH_IS_LITTLE_ENDIAN (0)
#endif
/* Big/little endian. */
#define clib_arch_is_big_endian CLIB_ARCH_IS_BIG_ENDIAN
#define clib_arch_is_little_endian CLIB_ARCH_IS_LITTLE_ENDIAN
当前CPU是大端结尾还是小端结尾,简称大端CPU,小端CPU。由编译选项决定。
如果编译的时候编译选项指定错误,则会出问题。
always_inline u16
clib_byte_swap_u16 (u16 x)
{
#if defined (__aarch64__)
if (!__builtin_constant_p (x))
{
__asm__ ("rev16 %w0, %w0":"+r" (x));
return x;
}
#endif
return (x >> 8) | (x << 8);
}
always_inline i16
clib_byte_swap_i16 (i16 x)
{
return clib_byte_swap_u16 (x);
}
交换16位数的2个字节的内容。
always_inline u32
clib_byte_swap_u32 (u32 x)
{
#if defined (i386) || defined (__x86_64__)
if (!__builtin_constant_p (x))
{
asm volatile ("bswap %0":"=r" (x):"0" (x));
return x;
}
#elif defined (__aarch64__)
if (!__builtin_constant_p (x))
{
__asm__ ("rev %w0, %w0":"+r" (x));
return x;
}
#endif
return ((x << 24) | ((x & 0xff00) << 8) | ((x >> 8) & 0xff00) | (x >> 24));
}
always_inline i32
clib_byte_swap_i32 (i32 x)
{
return clib_byte_swap_u32 (x);
}
交换32位数的4个字节的内容。依次对调。
always_inline u64
clib_byte_swap_u64 (u64 x)
{
#if defined (__x86_64__)
if (!__builtin_constant_p (x))
{
asm volatile ("bswapq %0":"=r" (x):"0" (x));
return x;
}
#elif defined (__aarch64__)
if (!__builtin_constant_p (x))
{
__asm__ ("rev %0, %0":"+r" (x));
return x;
}
#endif
#define _(x,n,i) \
((((x) >> (8*(i))) & 0xff) << (8*((n)-(i)-1)))
return (_(x, 8, 0) | _(x, 8, 1)
| _(x, 8, 2) | _(x, 8, 3)
| _(x, 8, 4) | _(x, 8, 5) | _(x, 8, 6) | _(x, 8, 7));
#undef _
}
always_inline i64
clib_byte_swap_i64 (i64 x)
{
return clib_byte_swap_u64 (x);
}
交换64位数的8个字节。
/* HOST -> SEX */ \
always_inline type \
clib_host_to_##sex##_##type (type x) \
{ \
if (! clib_arch_is_##sex##_endian) \
x = clib_byte_swap_##type (x); \
return x; \
} \
\
always_inline type \
clib_host_to_##sex##_mem_##type (type * x) \
{ \
type v = x[0]; \
return clib_host_to_##sex##_##type (v); \
} \
\
always_inline type \
clib_host_to_##sex##_unaligned_mem_##type (type * x) \
{ \
type v = clib_mem_unaligned (x, type); \
return clib_host_to_##sex##_##type (v); \
} \
CPU字节序转换成网络字节序。
/* SEX -> HOST */ \
always_inline type \
clib_##sex##_to_host_##type (type x) \
{ return clib_host_to_##sex##_##type (x); } \
\
always_inline type \
clib_##sex##_to_host_mem_##type (type * x) \
{ return clib_host_to_##sex##_mem_##type (x); } \
\
always_inline type \
clib_##sex##_to_host_unaligned_mem_##type (type * x) \
{ return clib_host_to_##sex##_unaligned_mem_##type (x); }
网络字节序转主机字节序
#ifndef __cplusplus
_(little, u16)
_(little, u32)
_(little, u64)
_(little, i16)
_(little, i32)
_(little, i64)
_(big, u16) _(big, u32) _(big, u64) _(big, i16) _(big, i32) _(big, i64)
#endif
#undef _
2种CPU结构下,各种长度的字节序转换宏封装。
/* Network "net" alias for "big". */
#define _(type) \
always_inline type \
clib_net_to_host_##type (type x) \
{ return clib_big_to_host_##type (x); } \
\
always_inline type \
clib_net_to_host_mem_##type (type * x) \
{ return clib_big_to_host_mem_##type (x); } \
\
always_inline type \
clib_net_to_host_unaligned_mem_##type (type * x) \
{ return clib_big_to_host_unaligned_mem_##type (x); } \
\
always_inline type \
clib_host_to_net_##type (type x) \
{ return clib_host_to_big_##type (x); } \
\
always_inline type \
clib_host_to_net_mem_##type (type * x) \
{ return clib_host_to_big_mem_##type (x); } \
\
always_inline type \
clib_host_to_net_unaligned_mem_##type (type * x) \
{ return clib_host_to_big_unaligned_mem_##type (x); }
#ifndef __cplusplus
_(u16);
_(i16);
_(u32);
_(i32);
_(u64);
_(i64);
#endif
#undef _
宏封装