vpp gtpu怎样封装序列号?
时间: 2023-07-19 15:38:26 浏览: 142
在VPP GTPU中,序列号是通过GTP-U封装头部中的Sequence Number字段来实现的。封装头部的结构如下:
```
typedef struct {
u8 flags;
u8 type;
u16 length;
u32 teid;
u32 seq_num; /* sequence number */
u32 npdu_num;
u8 next_ext;
u8 data[0];
} gtpu_header_t;
```
其中,seq_num字段即为序列号。在将数据包封装为GTP-U报文时,将序列号填充到seq_num字段中,以便接收端可以正确地按序接收数据包。具体的封装过程可以参考VPP GTPU的源代码实现。
相关问题
vpp中gtpu封装报文和解封装报文的代码怎么写(报文包括序列号)?
VPP中GTP-U封装和解封装代码可以如下实现(包括序列号的处理):
封装:
```
/* 构建GTP-U报文头部 */
gtpu_header_t *gtpuh = vlib_buffer_push_uninit (b, sizeof (*gtpuh));
gtpuh->gtpu_flags = GTPU_FLAG_VER | GTPU_FLAG_PT | GTPU_FLAG_SEQ;
gtpuh->gtpu_msg_type = GTPU_MSG_GPDU;
gtpuh->gtpu_length = clib_host_to_net_u16 (len + sizeof(u32));
gtpuh->gtpu_teid = clib_host_to_net_u32 (teid);
/* 获取tunnel */
gtpu_tunnel_t *tun = gtpu_tunnel_lookup (gm, &key);
/* 计算序列号 */
u32 seq = clib_atomic_fetch_add (&tun->seq_num, 1);
/* 将序列号添加到GTP-U头部后面 */
u32 *seq_num = vlib_buffer_push_uninit (b, sizeof (u32));
*seq_num = clib_host_to_net_u32 (seq);
/* 将IP头部添加到报文之前 */
ip4_header_t *ip4h = vlib_buffer_push_uninit (b, sizeof (*ip4h));
ip4h->ip_version_and_header_length = 0x45;
ip4h->ttl = 254;
ip4h->protocol = IP_PROTOCOL_UDP;
ip4h->src_address.as_u32 = tun->src.ip4.as_u32;
ip4h->dst_address.as_u32 = tun->dst.ip4.as_u32;
ip4h->length = clib_host_to_net_u16 (len + sizeof (*ip4h) + sizeof (u32));
/* 添加UDP头部 */
udp_header_t *udph = (udp_header_t *) (ip4h + 1);
udph->src_port = clib_host_to_net_u16 (tun->src_port);
udph->dst_port = clib_host_to_net_u16 (tun->dst_port);
udph->length = clib_host_to_net_u16 (len + sizeof (*udph) + sizeof (u32));
udph->checksum = 0;
/* 更新UDP长度字段 */
ip_csum_t sum = ip4h->checksum;
sum = ip_csum_update (sum, 0, ip4h->length, ip4_header_t, length);
ip4h->checksum = ip_csum_fold (sum);
/* 更新UDP长度字段 */
sum = ip_csum_update (0, 0, udph->length, udp_header_t, length);
udph->checksum = ip_csum_fold (sum);
/* 更新GTP-U长度字段 */
sum = ip_csum_update (0, 0, gtpuh->gtpu_length, gtpu_header_t, length);
gtpuh->gtpu_checksum = ~ip_csum_fold (sum);
```
解封:
```
/* 从报文中获取GTP-U头部 */
gtpu_header_t *gtpuh = (gtpu_header_t *) (udp + 1);
/* 检验GTP-U头部 */
if ((gtpuh->gtpu_flags & GTPU_FLAG_VER) != GTPU_VERSION ||
gtpuh->gtpu_msg_type != GTPU_MSG_GPDU)
{
vlib_buffer_free_one (vm, b);
return;
}
/* 从GTP-U头部中获取TEID */
u32 teid = clib_net_to_host_u32 (gtpuh->gtpu_teid);
/* 从报文中获取IP头部 */
ip4_header_t *ip4h = vlib_buffer_get_current (b);
/* 从IP头部中获取源IP地址和目的IP地址 */
ip4_address_t src = ip4h->src_address;
ip4_address_t dst = ip4h->dst_address;
/* 从报文中获取UDP头部 */
udp_header_t *udph = (udp_header_t *) (ip4h + 1);
/* 从UDP头部中获取源端口和目的端口 */
u16 src_port = clib_net_to_host_u16 (udph->src_port);
u16 dst_port = clib_net_to_host_u16 (udph->dst_port);
/* 从报文中获取GTP-U数据 */
u8 *data = (u8 *) (gtpuh + 1);
u16 len = clib_net_to_host_u16 (gtpuh->gtpu_length) - sizeof (u32);
/* 从报文中获取序列号 */
u32 *seq_num = (u32 *) (data + len);
u32 seq = clib_net_to_host_u32 (*seq_num);
/* 构建tunnel_key_t结构体 */
tunnel_key_t key = {
.src = {
.ip4 = src,
.port = src_port,
},
.dst = {
.ip4 = dst,
.port = dst_port,
},
.teid = teid,
};
/* 获取tunnel */
gtpu_tunnel_t *tun = gtpu_tunnel_lookup (gm, &key);
/* 如果未找到tunnel,则释放报文并返回 */
if (!tun)
{
vlib_buffer_free_one (vm, b);
return;
}
/* 检查序列号是否正确 */
if (seq != tun->seq_num_expected)
{
vlib_buffer_free_one (vm, b);
return;
}
/* 更新tunnel的seq_num_expected字段 */
clib_atomic_fetch_add (&tun->seq_num_expected, 1);
/* 将tunnel信息写入buffer_metadata_t */
buffer_metadata_t *bm = gtpu_init_buffer_metadata (b);
bm->tun_index = tun - gm->tunnels;
bm->teid = teid;
bm->seq_num = seq;
/* 将GTP-U头部和序列号从报文中移除 */
vlib_buffer_advance (b, sizeof (*gtpuh) + sizeof (u32));
```
vpp中gtpu封装报文和解封装报文的代码怎么写?
VPP中的GTP-U封装和解封装代码可以用以下方式实现:
封装:
```
/* 构建GTP-U报文头部 */
gtpu_header_t *gtpuh = vlib_buffer_push_uninit (b, sizeof (*gtpuh));
gtpuh->gtpu_flags = GTPU_FLAG_VER | GTPU_FLAG_PT;
gtpuh->gtpu_msg_type = GTPU_MSG_GPDU;
gtpuh->gtpu_length = clib_host_to_net_u16 (len);
gtpuh->gtpu_teid = clib_host_to_net_u32 (teid);
/* 将IP头部添加到报文之前 */
ip4_header_t *ip4h = vlib_buffer_push_uninit (b, sizeof (*ip4h));
ip4h->ip_version_and_header_length = 0x45;
ip4h->ttl = 254;
ip4h->protocol = IP_PROTOCOL_UDP;
ip4h->src_address.as_u32 = tun->src.ip4.as_u32;
ip4h->dst_address.as_u32 = tun->dst.ip4.as_u32;
ip4h->length = clib_host_to_net_u16 (len + sizeof (*ip4h));
/* 添加UDP头部 */
udp_header_t *udph = (udp_header_t *) (ip4h + 1);
udph->src_port = clib_host_to_net_u16 (tun->src_port);
udph->dst_port = clib_host_to_net_u16 (tun->dst_port);
udph->length = clib_host_to_net_u16 (len + sizeof (*udph));
udph->checksum = 0;
/* 更新UDP长度字段 */
ip_csum_t sum = ip4h->checksum;
sum = ip_csum_update (sum, 0, ip4h->length, ip4_header_t, length);
ip4h->checksum = ip_csum_fold (sum);
/* 更新UDP长度字段 */
sum = ip_csum_update (0, 0, udph->length, udp_header_t, length);
udph->checksum = ip_csum_fold (sum);
/* 更新GTP-U长度字段 */
sum = ip_csum_update (0, 0, gtpuh->gtpu_length, gtpu_header_t, length);
gtpuh->gtpu_checksum = ~ip_csum_fold (sum);
```
解封:
```
/* 从报文中获取GTP-U头部 */
gtpu_header_t *gtpuh = (gtpu_header_t *) (udp + 1);
/* 检验GTP-U头部 */
if ((gtpuh->gtpu_flags & GTPU_FLAG_VER) != GTPU_VERSION ||
gtpuh->gtpu_msg_type != GTPU_MSG_GPDU)
{
vlib_buffer_free_one (vm, b);
return;
}
/* 从GTP-U头部中获取TEID */
u32 teid = clib_net_to_host_u32 (gtpuh->gtpu_teid);
/* 从报文中获取IP头部 */
ip4_header_t *ip4h = vlib_buffer_get_current (b);
/* 从IP头部中获取源IP地址和目的IP地址 */
ip4_address_t src = ip4h->src_address;
ip4_address_t dst = ip4h->dst_address;
/* 从报文中获取UDP头部 */
udp_header_t *udph = (udp_header_t *) (ip4h + 1);
/* 从UDP头部中获取源端口和目的端口 */
u16 src_port = clib_net_to_host_u16 (udph->src_port);
u16 dst_port = clib_net_to_host_u16 (udph->dst_port);
/* 从报文中获取GTP-U数据 */
u8 *data = (u8 *) (gtpuh + 1);
u16 len = clib_net_to_host_u16 (gtpuh->gtpu_length);
/* 构建tunnel_key_t结构体 */
tunnel_key_t key = {
.src = {
.ip4 = src,
.port = src_port,
},
.dst = {
.ip4 = dst,
.port = dst_port,
},
.teid = teid,
};
/* 获取tunnel */
gtpu_tunnel_t *tun = gtpu_tunnel_lookup (gm, &key);
/* 如果未找到tunnel,则释放报文并返回 */
if (!tun)
{
vlib_buffer_free_one (vm, b);
return;
}
/* 将tunnel信息写入buffer_metadata_t */
buffer_metadata_t *bm = gtpu_init_buffer_metadata (b);
bm->tun_index = tun - gm->tunnels;
bm->teid = teid;
/* 将GTP-U头部从报文中移除 */
vlib_buffer_advance (b, sizeof (*gtpuh));
```
阅读全文