vpp中gtpu封装报文和解封装报文的代码怎么写?
时间: 2024-01-16 07:03:19 浏览: 52
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));
```