Skip to content

Commit

Permalink
tunneling: Factor out common UDP tunnel code.
Browse files Browse the repository at this point in the history
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 <[email protected]>
Acked-by: Pravin B Shelar <[email protected]>
  • Loading branch information
jessegross committed Apr 7, 2015
1 parent 83fbb69 commit e066f78
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 57 deletions.
105 changes: 63 additions & 42 deletions lib/netdev-vport.c
Original file line number Diff line number Diff line change
Expand Up @@ -876,6 +876,65 @@ push_ip_header(struct dp_packet *packet,
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
gre_header_len(ovs_be16 flags)
{
Expand Down Expand Up @@ -1068,19 +1127,17 @@ vxlan_extract_md(struct dp_packet *packet)
{
struct pkt_metadata *md = &packet->md;
struct flow_tnl *tnl = &md->tunnel;
struct udp_header *udp;
struct vxlanhdr *vxh;

memset(md, 0, sizeof *md);
if (VXLAN_HLEN > dp_packet_size(packet)) {
return;
}

udp = ip_extract_tnl_md(packet, tnl);
if (!udp) {
vxh = udp_extract_tnl_md(packet, tnl);
if (!vxh) {
return;
}
vxh = (struct vxlanhdr *) (udp + 1);

if (get_16aligned_be32(&vxh->vx_flags) != htonl(VXLAN_FLAGS) ||
(get_16aligned_be32(&vxh->vx_vni) & htonl(0xff))) {
Expand All @@ -1090,8 +1147,6 @@ vxlan_extract_md(struct dp_packet *packet)
reset_tnl_md(md);
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->flags |= FLOW_TNL_F_KEY;

Expand All @@ -1117,21 +1172,14 @@ netdev_vxlan_build_header(const struct netdev *netdev,
{
struct netdev_vport *dev = netdev_vport_cast(netdev);
struct netdev_tunnel_config *tnl_cfg;
struct ip_header *ip;
struct udp_header *udp;
struct vxlanhdr *vxh;

/* XXX: RCUfy tnl_cfg. */
ovs_mutex_lock(&dev->mutex);
tnl_cfg = &dev->tnl_cfg;

ip = ip_hdr(data->header);
ip->ip_proto = IPPROTO_UDP;
vxh = udp_build_header(tnl_cfg, data);

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_vni, htonl(ntohll(tnl_flow->tunnel.tun_id) << 8));

Expand All @@ -1141,32 +1189,6 @@ netdev_vxlan_build_header(const struct netdev *netdev,
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
netdev_vxlan_push_header(const struct netdev *netdev OVS_UNUSED,
struct dp_packet **packets, int cnt,
Expand All @@ -1175,8 +1197,7 @@ netdev_vxlan_push_header(const struct netdev *netdev OVS_UNUSED,
int i;

for (i = 0; i < cnt; i++) {
netdev_vxlan_push_header__(packets[i],
data->header, VXLAN_HLEN);
push_udp_header(packets[i], data->header, VXLAN_HLEN);
packets[i]->md = PKT_METADATA_INITIALIZER(u32_to_odp(data->out_port));
}
return 0;
Expand Down
37 changes: 22 additions & 15 deletions lib/odp-util.c
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,18 @@ format_odp_hash_action(struct ds *ds, const struct ovs_action_hash *hash_act)
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
format_odp_tnl_push_header(struct ds *ds, struct ovs_action_push_tnl *data)
{
Expand Down Expand Up @@ -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) {
const struct vxlanhdr *vxh;
const struct udp_header *udp;

/* 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));
vxh = format_udp_tnl_push_header(ds, ip);

/* VxLan */
vxh = (const struct vxlanhdr *) (udp + 1);
ds_put_format(ds, "vxlan(flags=0x%"PRIx32",vni=0x%"PRIx32")",
ntohl(get_16aligned_be32(&vxh->vx_flags)),
ntohl(get_16aligned_be32(&vxh->vx_vni)) >> 8);
Expand Down Expand Up @@ -887,24 +893,25 @@ ovs_parse_tnl_push(const char *s, struct ovs_action_push_tnl *data)
greh = (struct gre_base_hdr *) l4;
if (ovs_scan_len(s, &n, "udp(src=%"SCNi16",dst=%"SCNi16"),",
&udp_src, &udp_dst)) {
struct vxlanhdr *vxh;
uint32_t vx_flags, vx_vni;

udp->udp_src = htons(udp_src);
udp->udp_dst = htons(udp_dst);
udp->udp_len = 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)) {
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;
}
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")",
&greh->flags, &gre_proto)){

Expand Down

0 comments on commit e066f78

Please sign in to comment.