2
0
mirror of https://github.com/openvswitch/ovs synced 2025-10-27 15:18:06 +00:00

tunneling: Factor out common UDP tunnel code.

Currently, the userspace VXLAN implementation contains the code
for generating and parsing both the UDP and VXLAN headers. This
pulls out the UDP portion for better layering and to make it
easier to support additional UDP based tunnels and features.

Signed-off-by: Jesse Gross <jesse@nicira.com>
Acked-by: Pravin B Shelar <pshelar@nicira.com>
This commit is contained in:
Jesse Gross
2015-03-26 12:07:02 -07:00
parent 83fbb69b50
commit e066f78fea
2 changed files with 85 additions and 57 deletions

View File

@@ -876,6 +876,65 @@ push_ip_header(struct dp_packet *packet,
return ip + 1; return ip + 1;
} }
static void *
udp_extract_tnl_md(struct dp_packet *packet, struct flow_tnl *tnl)
{
struct udp_header *udp;
udp = ip_extract_tnl_md(packet, tnl);
if (!udp) {
return NULL;
}
tnl->tp_src = udp->udp_src;
tnl->tp_dst = udp->udp_dst;
return udp + 1;
}
static ovs_be16
get_src_port(struct dp_packet *packet)
{
uint32_t hash;
hash = dp_packet_get_dp_hash(packet);
return htons((((uint64_t) hash * (tnl_udp_port_max - tnl_udp_port_min)) >> 32) +
tnl_udp_port_min);
}
static void *
push_udp_header(struct dp_packet *packet, const void *header, int size)
{
struct udp_header *udp;
int ip_tot_size;
udp = push_ip_header(packet, header, size, &ip_tot_size);
/* set udp src port */
udp->udp_src = get_src_port(packet);
udp->udp_len = htons(ip_tot_size - sizeof (struct ip_header));
/* udp_csum is zero */
return udp + 1;
}
static void *
udp_build_header(struct netdev_tunnel_config *tnl_cfg,
struct ovs_action_push_tnl *data)
{
struct ip_header *ip;
struct udp_header *udp;
ip = ip_hdr(data->header);
ip->ip_proto = IPPROTO_UDP;
udp = (struct udp_header *) (ip + 1);
udp->udp_dst = tnl_cfg->dst_port;
return udp + 1;
}
static int static int
gre_header_len(ovs_be16 flags) gre_header_len(ovs_be16 flags)
{ {
@@ -1068,7 +1127,6 @@ vxlan_extract_md(struct dp_packet *packet)
{ {
struct pkt_metadata *md = &packet->md; struct pkt_metadata *md = &packet->md;
struct flow_tnl *tnl = &md->tunnel; struct flow_tnl *tnl = &md->tunnel;
struct udp_header *udp;
struct vxlanhdr *vxh; struct vxlanhdr *vxh;
memset(md, 0, sizeof *md); memset(md, 0, sizeof *md);
@@ -1076,11 +1134,10 @@ vxlan_extract_md(struct dp_packet *packet)
return; return;
} }
udp = ip_extract_tnl_md(packet, tnl); vxh = udp_extract_tnl_md(packet, tnl);
if (!udp) { if (!vxh) {
return; return;
} }
vxh = (struct vxlanhdr *) (udp + 1);
if (get_16aligned_be32(&vxh->vx_flags) != htonl(VXLAN_FLAGS) || if (get_16aligned_be32(&vxh->vx_flags) != htonl(VXLAN_FLAGS) ||
(get_16aligned_be32(&vxh->vx_vni) & htonl(0xff))) { (get_16aligned_be32(&vxh->vx_vni) & htonl(0xff))) {
@@ -1090,8 +1147,6 @@ vxlan_extract_md(struct dp_packet *packet)
reset_tnl_md(md); reset_tnl_md(md);
return; return;
} }
tnl->tp_src = udp->udp_src;
tnl->tp_dst = udp->udp_dst;
tnl->tun_id = htonll(ntohl(get_16aligned_be32(&vxh->vx_vni)) >> 8); tnl->tun_id = htonll(ntohl(get_16aligned_be32(&vxh->vx_vni)) >> 8);
tnl->flags |= FLOW_TNL_F_KEY; tnl->flags |= FLOW_TNL_F_KEY;
@@ -1117,21 +1172,14 @@ netdev_vxlan_build_header(const struct netdev *netdev,
{ {
struct netdev_vport *dev = netdev_vport_cast(netdev); struct netdev_vport *dev = netdev_vport_cast(netdev);
struct netdev_tunnel_config *tnl_cfg; struct netdev_tunnel_config *tnl_cfg;
struct ip_header *ip;
struct udp_header *udp;
struct vxlanhdr *vxh; struct vxlanhdr *vxh;
/* XXX: RCUfy tnl_cfg. */ /* XXX: RCUfy tnl_cfg. */
ovs_mutex_lock(&dev->mutex); ovs_mutex_lock(&dev->mutex);
tnl_cfg = &dev->tnl_cfg; tnl_cfg = &dev->tnl_cfg;
ip = ip_hdr(data->header); vxh = udp_build_header(tnl_cfg, data);
ip->ip_proto = IPPROTO_UDP;
udp = (struct udp_header *) (ip + 1);
udp->udp_dst = tnl_cfg->dst_port;
vxh = (struct vxlanhdr *) (udp + 1);
put_16aligned_be32(&vxh->vx_flags, htonl(VXLAN_FLAGS)); put_16aligned_be32(&vxh->vx_flags, htonl(VXLAN_FLAGS));
put_16aligned_be32(&vxh->vx_vni, htonl(ntohll(tnl_flow->tunnel.tun_id) << 8)); put_16aligned_be32(&vxh->vx_vni, htonl(ntohll(tnl_flow->tunnel.tun_id) << 8));
@@ -1141,32 +1189,6 @@ netdev_vxlan_build_header(const struct netdev *netdev,
return 0; return 0;
} }
static ovs_be16
get_src_port(struct dp_packet *packet)
{
uint32_t hash;
hash = dp_packet_get_dp_hash(packet);
return htons((((uint64_t) hash * (tnl_udp_port_max - tnl_udp_port_min)) >> 32) +
tnl_udp_port_min);
}
static void
netdev_vxlan_push_header__(struct dp_packet *packet,
const void *header, int size)
{
struct udp_header *udp;
int ip_tot_size;
udp = push_ip_header(packet, header, size, &ip_tot_size);
/* set udp src port */
udp->udp_src = get_src_port(packet);
udp->udp_len = htons(ip_tot_size - sizeof (struct ip_header));
/* udp_csum is zero */
}
static int static int
netdev_vxlan_push_header(const struct netdev *netdev OVS_UNUSED, netdev_vxlan_push_header(const struct netdev *netdev OVS_UNUSED,
struct dp_packet **packets, int cnt, struct dp_packet **packets, int cnt,
@@ -1175,8 +1197,7 @@ netdev_vxlan_push_header(const struct netdev *netdev OVS_UNUSED,
int i; int i;
for (i = 0; i < cnt; i++) { for (i = 0; i < cnt; i++) {
netdev_vxlan_push_header__(packets[i], push_udp_header(packets[i], data->header, VXLAN_HLEN);
data->header, VXLAN_HLEN);
packets[i]->md = PKT_METADATA_INITIALIZER(u32_to_odp(data->out_port)); packets[i]->md = PKT_METADATA_INITIALIZER(u32_to_odp(data->out_port));
} }
return 0; return 0;

View File

@@ -510,6 +510,18 @@ format_odp_hash_action(struct ds *ds, const struct ovs_action_hash *hash_act)
ds_put_format(ds, ")"); ds_put_format(ds, ")");
} }
static const void *
format_udp_tnl_push_header(struct ds *ds, const struct ip_header *ip)
{
const struct udp_header *udp;
udp = (const struct udp_header *) (ip + 1);
ds_put_format(ds, "udp(src=%"PRIu16",dst=%"PRIu16"),",
ntohs(udp->udp_src), ntohs(udp->udp_dst));
return udp + 1;
}
static void static void
format_odp_tnl_push_header(struct ds *ds, struct ovs_action_push_tnl *data) format_odp_tnl_push_header(struct ds *ds, struct ovs_action_push_tnl *data)
{ {
@@ -541,15 +553,9 @@ format_odp_tnl_push_header(struct ds *ds, struct ovs_action_push_tnl *data)
if (data->tnl_type == OVS_VPORT_TYPE_VXLAN) { if (data->tnl_type == OVS_VPORT_TYPE_VXLAN) {
const struct vxlanhdr *vxh; const struct vxlanhdr *vxh;
const struct udp_header *udp;
/* UDP */ vxh = format_udp_tnl_push_header(ds, ip);
udp = (const struct udp_header *) (ip + 1);
ds_put_format(ds, "udp(src=%"PRIu16",dst=%"PRIu16"),",
ntohs(udp->udp_src), ntohs(udp->udp_dst));
/* VxLan */
vxh = (const struct vxlanhdr *) (udp + 1);
ds_put_format(ds, "vxlan(flags=0x%"PRIx32",vni=0x%"PRIx32")", ds_put_format(ds, "vxlan(flags=0x%"PRIx32",vni=0x%"PRIx32")",
ntohl(get_16aligned_be32(&vxh->vx_flags)), ntohl(get_16aligned_be32(&vxh->vx_flags)),
ntohl(get_16aligned_be32(&vxh->vx_vni)) >> 8); ntohl(get_16aligned_be32(&vxh->vx_vni)) >> 8);
@@ -887,7 +893,6 @@ ovs_parse_tnl_push(const char *s, struct ovs_action_push_tnl *data)
greh = (struct gre_base_hdr *) l4; greh = (struct gre_base_hdr *) l4;
if (ovs_scan_len(s, &n, "udp(src=%"SCNi16",dst=%"SCNi16"),", if (ovs_scan_len(s, &n, "udp(src=%"SCNi16",dst=%"SCNi16"),",
&udp_src, &udp_dst)) { &udp_src, &udp_dst)) {
struct vxlanhdr *vxh;
uint32_t vx_flags, vx_vni; uint32_t vx_flags, vx_vni;
udp->udp_src = htons(udp_src); udp->udp_src = htons(udp_src);
@@ -895,16 +900,18 @@ ovs_parse_tnl_push(const char *s, struct ovs_action_push_tnl *data)
udp->udp_len = 0; udp->udp_len = 0;
udp->udp_csum = 0; udp->udp_csum = 0;
vxh = (struct vxlanhdr *) (udp + 1); if (ovs_scan_len(s, &n, "vxlan(flags=0x%"SCNx32",vni=0x%"SCNx32"))",
if (!ovs_scan_len(s, &n, "vxlan(flags=0x%"SCNx32",vni=0x%"SCNx32"))",
&vx_flags, &vx_vni)) { &vx_flags, &vx_vni)) {
struct vxlanhdr *vxh = (struct vxlanhdr *) (udp + 1);
put_16aligned_be32(&vxh->vx_flags, htonl(vx_flags));
put_16aligned_be32(&vxh->vx_vni, htonl(vx_vni << 8));
tnl_type = OVS_VPORT_TYPE_VXLAN;
header_len = sizeof *eth + sizeof *ip +
sizeof *udp + sizeof *vxh;
} else {
return -EINVAL; return -EINVAL;
} }
put_16aligned_be32(&vxh->vx_flags, htonl(vx_flags));
put_16aligned_be32(&vxh->vx_vni, htonl(vx_vni << 8));
tnl_type = OVS_VPORT_TYPE_VXLAN;
header_len = sizeof *eth + sizeof *ip +
sizeof *udp + sizeof *vxh;
} else if (ovs_scan_len(s, &n, "gre((flags=0x%"SCNx16",proto=0x%"SCNx16")", } else if (ovs_scan_len(s, &n, "gre((flags=0x%"SCNx16",proto=0x%"SCNx16")",
&greh->flags, &gre_proto)){ &greh->flags, &gre_proto)){