TSG-17749 tsg-service-chaining-engine更改VXLAN Frame源端口的计算方式

This commit is contained in:
luwenpeng
2023-11-20 10:31:21 +08:00
parent 83f9880ff0
commit 134d2c82b7
14 changed files with 327 additions and 271 deletions

View File

@@ -1,67 +0,0 @@
#include <netinet/ip.h>
#include <netinet/ether.h>
#include "utils.h"
#include "g_vxlan.h"
void g_vxlan_set_packet_dir(struct g_vxlan *hdr, int dir_is_e2i)
{
hdr->dir_is_e2i = (!!dir_is_e2i);
}
void g_vxlan_set_sf_index(struct g_vxlan *hdr, int sf_index)
{
hdr->sf_index = (0x1f & sf_index);
}
void g_vxlan_set_traffic_type(struct g_vxlan *hdr, int traffic_is_decrypted)
{
hdr->traffic_is_decrypted = (!!traffic_is_decrypted);
}
int g_vxlan_get_packet_dir(struct g_vxlan *hdr)
{
return (!!hdr->dir_is_e2i);
}
int g_vxlan_get_sf_index(struct g_vxlan *hdr)
{
return hdr->sf_index;
}
int g_vxlan_get_traffic_type(struct g_vxlan *hdr)
{
return (!!hdr->traffic_is_decrypted);
}
// return 0 : success
// return -1 : error
int g_vxlan_decode(struct g_vxlan **g_vxlan_hdr, const char *raw_data, int raw_len)
{
if (raw_len <= (int)(sizeof(struct ethhdr) + sizeof(struct ip) + sizeof(struct udp_hdr) + sizeof(struct g_vxlan)))
{
return -1;
}
struct ethhdr *eth_hdr = (struct ethhdr *)raw_data;
if (eth_hdr->h_proto != htons(ETH_P_IP))
{
return -1;
}
struct ip *ip_hdr = (struct ip *)((char *)eth_hdr + sizeof(struct ethhdr));
if (ip_hdr->ip_p != IPPROTO_UDP)
{
return -1;
}
struct udp_hdr *udp_hdr = (struct udp_hdr *)((char *)ip_hdr + sizeof(struct ip));
if (udp_hdr->uh_dport != htons(4789))
{
return -1;
}
*g_vxlan_hdr = (struct g_vxlan *)((char *)udp_hdr + sizeof(struct udp_hdr));
return 0;
}

View File

@@ -4,6 +4,7 @@
#include <netinet/ip6.h>
#define __FAVOR_BSD 1
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <netinet/ether.h>
#include <linux/ppp_defs.h>
@@ -26,14 +27,6 @@
LOG_PACKET, (tag), (next_proto)); \
}
struct udp_hdr
{
uint16_t uh_sport; /* source port */
uint16_t uh_dport; /* destination port */
uint16_t uh_ulen; /* udp length */
uint16_t uh_sum; /* udp checksum */
} __attribute__((__packed__));
/******************************************************************************
* Static API
******************************************************************************/
@@ -349,7 +342,7 @@ static inline void set_four_tuple(const char *data, enum layer_type type, struct
const struct ip *ipv4 = NULL;
const struct ip6_hdr *ipv6 = NULL;
const struct tcphdr *tcp = NULL;
const struct udp_hdr *udp = NULL;
const struct udphdr *udp = NULL;
switch (type)
{
@@ -358,7 +351,7 @@ static inline void set_four_tuple(const char *data, enum layer_type type, struct
four_tuple_set_port(tuple, tcp->th_sport, tcp->th_dport);
break;
case LAYER_TYPE_UDP:
udp = (const struct udp_hdr *)data;
udp = (const struct udphdr *)data;
four_tuple_set_port(tuple, udp->uh_sport, udp->uh_dport);
break;
case LAYER_TYPE_IPV4:
@@ -856,7 +849,7 @@ static inline const char *parse_gre(struct packet *handler, const char *data, ui
static inline const char *parse_udp(struct packet *handler, const char *data, uint16_t len)
{
if (unlikely(len < sizeof(struct udp_hdr)))
if (unlikely(len < sizeof(struct udphdr)))
{
PACKET_LOG_DATA_INSUFFICIENCY(LAYER_TYPE_UDP);
return data;
@@ -867,8 +860,8 @@ static inline const char *parse_udp(struct packet *handler, const char *data, ui
{
return data;
}
struct udp_hdr *hdr = (struct udp_hdr *)data;
SET_LAYER(handler, layer, LAYER_TYPE_UDP, sizeof(struct udp_hdr), data, len);
struct udphdr *hdr = (struct udphdr *)data;
SET_LAYER(handler, layer, LAYER_TYPE_UDP, sizeof(struct udphdr), data, len);
switch (ntohs(hdr->uh_dport))
{

View File

@@ -153,79 +153,6 @@ void throughput_metrics_inc(struct throughput_metrics *iterm, uint64_t n_pkts, u
iterm->n_pkts += n_pkts;
}
/******************************************************************************
* protocol
******************************************************************************/
int checksum(uint16_t *addr, int len)
{
int sum = 0;
int nleft = len;
uint16_t ans = 0;
uint16_t *w = addr;
while (nleft > 1)
{
sum += *w++;
nleft -= 2;
}
if (nleft == 1)
{
*(char *)(&ans) = *(char *)w;
sum += ans;
}
return sum;
}
void build_udp_header(const char *l3_hdr, int l3_hdr_len, struct udp_hdr *udp_hdr, uint16_t udp_sport, uint16_t udp_dport, int payload_len)
{
memset(udp_hdr, 0, sizeof(struct udp_hdr));
int udp_hlen = sizeof(struct udp_hdr) + payload_len;
udp_hdr->uh_sport = htons(udp_sport);
udp_hdr->uh_dport = htons(udp_dport);
udp_hdr->uh_ulen = htons(udp_hlen);
udp_hdr->uh_sum = 0;
int sum = checksum((uint16_t *)l3_hdr, l3_hdr_len);
sum += ntohs(IPPROTO_UDP + udp_hlen);
sum += checksum((uint16_t *)udp_hdr, udp_hlen);
udp_hdr->uh_sum = CHECKSUM_CARRY(sum);
}
void build_ip_header(struct ip *ip_hdr, uint8_t next_protocol, uint16_t ipid, const in_addr_t src_ip, const in_addr_t dst_ip, uint16_t payload_len)
{
memset(ip_hdr, 0, sizeof(struct ip));
ip_hdr->ip_hl = 5; /* 20 byte header */
ip_hdr->ip_v = 4; /* version 4 */
ip_hdr->ip_tos = 0; /* IP tos */
ip_hdr->ip_id = htons(ipid); /* IP ID */
ip_hdr->ip_ttl = 80; /* time to live */
ip_hdr->ip_p = next_protocol; /* transport protocol */
ip_hdr->ip_src.s_addr = src_ip;
ip_hdr->ip_dst.s_addr = dst_ip;
ip_hdr->ip_len = htons(sizeof(struct ip) + payload_len); /* total length */
ip_hdr->ip_off = htons(0); /* fragmentation flags */
ip_hdr->ip_sum = 0; /* do this later */
int sum = checksum((uint16_t *)ip_hdr, 20);
ip_hdr->ip_sum = CHECKSUM_CARRY(sum);
}
// l3_protocol: ETH_P_IPV6/ETH_P_IP
void build_ether_header(struct ethhdr *eth_hdr, uint16_t next_protocol, const u_char src_mac[], const u_char dst_mac[])
{
memset(eth_hdr, 0, sizeof(struct ethhdr));
memcpy(eth_hdr->h_source, src_mac, ETH_ALEN);
memcpy(eth_hdr->h_dest, dst_mac, ETH_ALEN);
eth_hdr->h_proto = htons(next_protocol);
}
/******************************************************************************
* device
******************************************************************************/

169
common/src/vxlan.cpp Normal file
View File

@@ -0,0 +1,169 @@
#include <string.h>
#include <netinet/ip.h>
#include <netinet/in.h>
#include <netinet/ether.h>
#include "vxlan.h"
#define CHECKSUM_CARRY(x) (x = (x >> 16) + (x & 0xffff), (~(x + (x >> 16)) & 0xffff))
static inline int checksum(uint16_t *data, int len)
{
int sum = 0;
int nleft = len;
uint16_t ans = 0;
uint16_t *w = data;
while (nleft > 1)
{
sum += *w++;
nleft -= 2;
}
if (nleft == 1)
{
*(char *)(&ans) = *(char *)w;
sum += ans;
}
return sum;
}
static inline void eth_header_encode(struct ethhdr *eth_hdr, const u_char src_mac[], const u_char dst_mac[], uint16_t proto)
{
memcpy(eth_hdr->h_source, src_mac, ETH_ALEN);
memcpy(eth_hdr->h_dest, dst_mac, ETH_ALEN);
eth_hdr->h_proto = htons(proto);
}
static inline void ip_header_encode(struct ip *ip_hdr, const in_addr_t src_ip, const in_addr_t dst_ip, uint16_t ipid, uint8_t proto, uint16_t pld_len)
{
ip_hdr->ip_v = 4; /* version 4 */
ip_hdr->ip_hl = 5; /* 20 byte header */
ip_hdr->ip_tos = 0; /* IP tos */
ip_hdr->ip_len = htons(sizeof(struct ip) + pld_len); /* total length */
ip_hdr->ip_id = htons(ipid); /* IP ID */
ip_hdr->ip_off = htons(0); /* fragmentation flags */
ip_hdr->ip_ttl = 80; /* time to live */
ip_hdr->ip_p = proto; /* transport protocol */
ip_hdr->ip_sum = 0; /* do this later */
ip_hdr->ip_src.s_addr = src_ip;
ip_hdr->ip_dst.s_addr = dst_ip;
int sum = checksum((uint16_t *)ip_hdr, 20);
ip_hdr->ip_sum = CHECKSUM_CARRY(sum);
}
static inline void udp_header_encode(struct udphdr *udp_hdr, uint16_t udp_sport, uint16_t udp_dport, uint16_t pld_len)
{
int udp_hlen = sizeof(struct udphdr) + pld_len;
udp_hdr->uh_sport = htons(udp_sport);
udp_hdr->uh_dport = htons(udp_dport);
udp_hdr->uh_ulen = htons(udp_hlen);
/*
* UDP Checksum: It SHOULD be transmitted as zero
* https://datatracker.ietf.org/doc/html/rfc7348#section-5
*/
udp_hdr->uh_sum = 0;
}
void vxlan_set_opt(struct vxlan_hdr *hdr, enum vni_opt opt, uint8_t val)
{
switch (opt)
{
case VNI_OPT_DIR:
hdr->dir = (!!val);
break;
case VNI_OPT_TRAFFIC:
hdr->traffic = (!!val);
break;
case VNI_OPT_SFINDEX:
hdr->sf_index = (0x1f & val);
break;
default:
break;
}
}
uint8_t vxlan_get_opt(struct vxlan_hdr *hdr, enum vni_opt opt)
{
switch (opt)
{
case VNI_OPT_DIR:
return (!!hdr->dir);
case VNI_OPT_TRAFFIC:
return (!!hdr->traffic);
case VNI_OPT_SFINDEX:
return hdr->sf_index;
default:
return 0;
}
}
// return 0 : success
// return -1 : error
int vxlan_frame_decode(struct vxlan_hdr **vxlan_hdr, const char *data, uint16_t len)
{
if (len < VXLAN_FRAME_HDR_LEN)
{
return -1;
}
struct ethhdr *eth_hdr = (struct ethhdr *)data;
if (eth_hdr->h_proto != htons(ETH_P_IP))
{
return -1;
}
struct ip *ip_hdr = (struct ip *)((char *)eth_hdr + sizeof(struct ethhdr));
if (ip_hdr->ip_p != IPPROTO_UDP)
{
return -1;
}
struct udphdr *udp_hdr = (struct udphdr *)((char *)ip_hdr + sizeof(struct ip));
if (udp_hdr->uh_dport != htons(4789))
{
return -1;
}
*vxlan_hdr = (struct vxlan_hdr *)((char *)udp_hdr + sizeof(struct udphdr));
return 0;
}
void vxlan_frame_encode(char *buff,
const u_char eth_src_mac[], const u_char eth_dst_mac[],
const in_addr_t ip_src_addr, const in_addr_t ip_dst_addr, uint16_t ip_id,
uint16_t udp_src_port, uint16_t udp_pld_len,
uint8_t vni_opt_dir, uint8_t vni_opt_traffic, uint8_t vni_opt_sf_index)
{
struct ethhdr *eth_hdr = (struct ethhdr *)buff;
struct ip *ip_hdr = (struct ip *)((char *)eth_hdr + sizeof(struct ethhdr));
struct udphdr *udp_hdr = (struct udphdr *)((char *)ip_hdr + sizeof(struct ip));
struct vxlan_hdr *vxlan_hdr = (struct vxlan_hdr *)((char *)udp_hdr + sizeof(struct udphdr));
// MUST be set to zero
memset(vxlan_hdr, 0, sizeof(struct vxlan_hdr));
vxlan_hdr->flags = VXLAN_FLAGS;
vxlan_set_opt(vxlan_hdr, VNI_OPT_DIR, vni_opt_dir);
vxlan_set_opt(vxlan_hdr, VNI_OPT_TRAFFIC, vni_opt_traffic);
vxlan_set_opt(vxlan_hdr, VNI_OPT_SFINDEX, vni_opt_sf_index);
eth_header_encode(eth_hdr, eth_src_mac, eth_dst_mac, ETH_P_IP);
ip_header_encode(ip_hdr, ip_src_addr, ip_dst_addr, ip_id, IPPROTO_UDP, sizeof(struct udphdr) + sizeof(struct vxlan_hdr) + udp_pld_len);
udp_header_encode(udp_hdr, udp_src_port, VXLAN_DST_PORT, sizeof(struct vxlan_hdr) + udp_pld_len);
}
uint16_t calculate_vxlan_source_port(struct four_tuple *innermost_tuple4)
{
/*
* When calculating the UDP source port number in this manner, it
* is RECOMMENDED that the value be in the dynamic/private port
* range 49152-65535 [RFC6335].
*/
uint64_t hash = four_tuple_hash(innermost_tuple4);
uint16_t port = (uint16_t)(hash % (65535 - 49152) + 49152);
return port;
}