summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorPravin B Shelar <pshelar@ovn.org>2016-05-23 20:27:14 -0700
committerPravin B Shelar <pshelar@ovn.org>2016-05-23 20:27:14 -0700
commit4975aa3ee6a8e5643b12e8d8d66facb705d11367 (patch)
treed4ba07aa8428bb9c15ba4af90550b05a33969575 /lib
parentb803e6ac63f03b53bc5d0c52634ea88f783d506f (diff)
downloadopenvswitch-4975aa3ee6a8e5643b12e8d8d66facb705d11367.tar.gz
netdev-native-tnl: Introduce ip_build_header()
The native tunneling build tunnel header code is spread across two different modules, it makes pretty hard to follow the code. Following patch refactors the code to move all code to netdev-ative-tnl module. Signed-off-by: Pravin B Shelar <pshelar@ovn.org> Acked-by: Jesse Gross <jesse@kernel.org>
Diffstat (limited to 'lib')
-rw-r--r--lib/netdev-native-tnl.c132
-rw-r--r--lib/netdev-native-tnl.h14
-rw-r--r--lib/netdev-provider.h7
-rw-r--r--lib/netdev.c22
-rw-r--r--lib/netdev.h20
5 files changed, 131 insertions, 64 deletions
diff --git a/lib/netdev-native-tnl.c b/lib/netdev-native-tnl.c
index 123f3b2e2..ba87835b2 100644
--- a/lib/netdev-native-tnl.c
+++ b/lib/netdev-native-tnl.c
@@ -245,41 +245,83 @@ netdev_tnl_push_udp_header(struct dp_packet *packet,
}
static void *
-udp_build_header(struct netdev_tunnel_config *tnl_cfg,
- const struct flow *tnl_flow,
- struct ovs_action_push_tnl *data,
- unsigned int *hlen)
+eth_build_header(struct ovs_action_push_tnl *data,
+ const struct netdev_tnl_build_header_params *params)
{
- struct ip_header *ip;
- struct ovs_16aligned_ip6_hdr *ip6;
- struct udp_header *udp;
- bool is_ipv6;
+ uint16_t eth_proto = params->is_ipv6 ? ETH_TYPE_IPV6 : ETH_TYPE_IP;
+ struct eth_header *eth;
- *hlen = sizeof(struct eth_header);
+ memset(data->header, 0, sizeof data->header);
- is_ipv6 = netdev_tnl_is_header_ipv6(data->header);
+ eth = (struct eth_header *)data->header;
+ eth->eth_dst = params->dmac;
+ eth->eth_src = params->smac;
+ eth->eth_type = htons(eth_proto);
+ data->header_len = sizeof(struct eth_header);
+ return eth + 1;
+}
- if (is_ipv6) {
- ip6 = netdev_tnl_ipv6_hdr(data->header);
- ip6->ip6_nxt = IPPROTO_UDP;
- udp = (struct udp_header *) (ip6 + 1);
- *hlen += IPV6_HEADER_LEN;
+void *
+netdev_tnl_ip_build_header(struct ovs_action_push_tnl *data,
+ const struct netdev_tnl_build_header_params *params,
+ uint8_t next_proto)
+{
+ void *l3;
+
+ l3 = eth_build_header(data, params);
+ if (!params->is_ipv6) {
+ ovs_be32 ip_src = in6_addr_get_mapped_ipv4(params->s_ip);
+ struct ip_header *ip;
+
+ ip = (struct ip_header *) l3;
+
+ ip->ip_ihl_ver = IP_IHL_VER(5, 4);
+ ip->ip_tos = params->flow->tunnel.ip_tos;
+ ip->ip_ttl = params->flow->tunnel.ip_ttl;
+ ip->ip_proto = next_proto;
+ put_16aligned_be32(&ip->ip_src, ip_src);
+ put_16aligned_be32(&ip->ip_dst, params->flow->tunnel.ip_dst);
+
+ ip->ip_frag_off = (params->flow->tunnel.flags & FLOW_TNL_F_DONT_FRAGMENT) ?
+ htons(IP_DF) : 0;
+
+ ip->ip_csum = csum(ip, sizeof *ip);
+
+ data->header_len += IP_HEADER_LEN;
+ return ip + 1;
} else {
- ip = netdev_tnl_ip_hdr(data->header);
- ip->ip_proto = IPPROTO_UDP;
- udp = (struct udp_header *) (ip + 1);
- *hlen += IP_HEADER_LEN;
+ struct ovs_16aligned_ip6_hdr *ip6;
+
+ ip6 = (struct ovs_16aligned_ip6_hdr *) l3;
+
+ ip6->ip6_vfc = 0x60;
+ ip6->ip6_hlim = params->flow->tunnel.ip_ttl;
+ ip6->ip6_nxt = next_proto;
+ memcpy(&ip6->ip6_src, params->s_ip, sizeof(ovs_be32[4]));
+ memcpy(&ip6->ip6_dst, &params->flow->tunnel.ipv6_dst, sizeof(ovs_be32[4]));
+
+ data->header_len += IPV6_HEADER_LEN;
+ return ip6 + 1;
}
+}
+
+static void *
+udp_build_header(struct netdev_tunnel_config *tnl_cfg,
+ struct ovs_action_push_tnl *data,
+ const struct netdev_tnl_build_header_params *params)
+{
+ struct udp_header *udp;
+ udp = netdev_tnl_ip_build_header(data, params, IPPROTO_UDP);
udp->udp_dst = tnl_cfg->dst_port;
- if (is_ipv6 || tnl_flow->tunnel.flags & FLOW_TNL_F_CSUM) {
+ if (params->is_ipv6 || params->flow->tunnel.flags & FLOW_TNL_F_CSUM) {
/* Write a value in now to mark that we should compute the checksum
* later. 0xffff is handy because it is transparent to the
* calculation. */
udp->udp_csum = htons(0xffff);
}
-
+ data->header_len += sizeof *udp;
return udp + 1;
}
@@ -400,38 +442,25 @@ netdev_gre_push_header(struct dp_packet *packet,
int
netdev_gre_build_header(const struct netdev *netdev,
struct ovs_action_push_tnl *data,
- const struct flow *tnl_flow)
+ const struct netdev_tnl_build_header_params *params)
{
struct netdev_vport *dev = netdev_vport_cast(netdev);
struct netdev_tunnel_config *tnl_cfg;
- struct ip_header *ip;
- struct ovs_16aligned_ip6_hdr *ip6;
struct gre_base_hdr *greh;
ovs_16aligned_be32 *options;
- int hlen;
- bool is_ipv6;
-
- is_ipv6 = netdev_tnl_is_header_ipv6(data->header);
+ unsigned int hlen;
/* XXX: RCUfy tnl_cfg. */
ovs_mutex_lock(&dev->mutex);
tnl_cfg = &dev->tnl_cfg;
- if (is_ipv6) {
- ip6 = netdev_tnl_ipv6_hdr(data->header);
- ip6->ip6_nxt = IPPROTO_GRE;
- greh = (struct gre_base_hdr *) (ip6 + 1);
- } else {
- ip = netdev_tnl_ip_hdr(data->header);
- ip->ip_proto = IPPROTO_GRE;
- greh = (struct gre_base_hdr *) (ip + 1);
- }
+ greh = netdev_tnl_ip_build_header(data, params, IPPROTO_GRE);
greh->protocol = htons(ETH_TYPE_TEB);
greh->flags = 0;
options = (ovs_16aligned_be32 *) (greh + 1);
- if (tnl_flow->tunnel.flags & FLOW_TNL_F_CSUM) {
+ if (params->flow->tunnel.flags & FLOW_TNL_F_CSUM) {
greh->flags |= htons(GRE_CSUM);
put_16aligned_be32(options, 0);
options++;
@@ -440,7 +469,7 @@ netdev_gre_build_header(const struct netdev *netdev,
if (tnl_cfg->out_key_present) {
greh->flags |= htons(GRE_KEY);
put_16aligned_be32(options, (OVS_FORCE ovs_be32)
- ((OVS_FORCE uint64_t) tnl_flow->tunnel.tun_id >> 32));
+ ((OVS_FORCE uint64_t) params->flow->tunnel.tun_id >> 32));
options++;
}
@@ -448,8 +477,7 @@ netdev_gre_build_header(const struct netdev *netdev,
hlen = (uint8_t *) options - (uint8_t *) greh;
- data->header_len = sizeof(struct eth_header) + hlen +
- (is_ipv6 ? IPV6_HEADER_LEN : IP_HEADER_LEN);
+ data->header_len += hlen;
data->tnl_type = OVS_VPORT_TYPE_GRE;
return 0;
}
@@ -493,24 +521,23 @@ err:
int
netdev_vxlan_build_header(const struct netdev *netdev,
struct ovs_action_push_tnl *data,
- const struct flow *tnl_flow)
+ const struct netdev_tnl_build_header_params *params)
{
struct netdev_vport *dev = netdev_vport_cast(netdev);
struct netdev_tunnel_config *tnl_cfg;
struct vxlanhdr *vxh;
- unsigned int hlen;
/* XXX: RCUfy tnl_cfg. */
ovs_mutex_lock(&dev->mutex);
tnl_cfg = &dev->tnl_cfg;
- vxh = udp_build_header(tnl_cfg, tnl_flow, data, &hlen);
+ vxh = udp_build_header(tnl_cfg, data, params);
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(params->flow->tunnel.tun_id) << 8));
ovs_mutex_unlock(&dev->mutex);
- data->header_len = hlen + VXLAN_HLEN;
+ data->header_len += sizeof *vxh;
data->tnl_type = OVS_VPORT_TYPE_VXLAN;
return 0;
}
@@ -573,34 +600,33 @@ err:
int
netdev_geneve_build_header(const struct netdev *netdev,
struct ovs_action_push_tnl *data,
- const struct flow *tnl_flow)
+ const struct netdev_tnl_build_header_params *params)
{
struct netdev_vport *dev = netdev_vport_cast(netdev);
struct netdev_tunnel_config *tnl_cfg;
struct genevehdr *gnh;
int opt_len;
bool crit_opt;
- unsigned int hlen;
/* XXX: RCUfy tnl_cfg. */
ovs_mutex_lock(&dev->mutex);
tnl_cfg = &dev->tnl_cfg;
- gnh = udp_build_header(tnl_cfg, tnl_flow, data, &hlen);
+ gnh = udp_build_header(tnl_cfg, data, params);
- put_16aligned_be32(&gnh->vni, htonl(ntohll(tnl_flow->tunnel.tun_id) << 8));
+ put_16aligned_be32(&gnh->vni, htonl(ntohll(params->flow->tunnel.tun_id) << 8));
ovs_mutex_unlock(&dev->mutex);
- opt_len = tun_metadata_to_geneve_header(&tnl_flow->tunnel,
+ opt_len = tun_metadata_to_geneve_header(&params->flow->tunnel,
gnh->options, &crit_opt);
gnh->opt_len = opt_len / 4;
- gnh->oam = !!(tnl_flow->tunnel.flags & FLOW_TNL_F_OAM);
+ gnh->oam = !!(params->flow->tunnel.flags & FLOW_TNL_F_OAM);
gnh->critical = crit_opt ? 1 : 0;
gnh->proto_type = htons(ETH_TYPE_TEB);
- data->header_len = hlen + GENEVE_BASE_HLEN + opt_len;
+ data->header_len += sizeof *gnh + opt_len;
data->tnl_type = OVS_VPORT_TYPE_GENEVE;
return 0;
}
diff --git a/lib/netdev-native-tnl.h b/lib/netdev-native-tnl.h
index e0d15fc44..ed81857ca 100644
--- a/lib/netdev-native-tnl.h
+++ b/lib/netdev-native-tnl.h
@@ -25,7 +25,8 @@
int
netdev_gre_build_header(const struct netdev *netdev,
struct ovs_action_push_tnl *data,
- const struct flow *tnl_flow);
+ const struct netdev_tnl_build_header_params *params);
+
void
netdev_gre_push_header(struct dp_packet *packet,
const struct ovs_action_push_tnl *data);
@@ -38,14 +39,16 @@ netdev_tnl_push_udp_header(struct dp_packet *packet,
int
netdev_geneve_build_header(const struct netdev *netdev,
struct ovs_action_push_tnl *data,
- const struct flow *tnl_flow);
+ const struct netdev_tnl_build_header_params *params);
+
struct dp_packet *
netdev_geneve_pop_header(struct dp_packet *packet);
int
netdev_vxlan_build_header(const struct netdev *netdev,
struct ovs_action_push_tnl *data,
- const struct flow *tnl_flow);
+ const struct netdev_tnl_build_header_params *params);
+
struct dp_packet *
netdev_vxlan_pop_header(struct dp_packet *packet);
@@ -69,6 +72,11 @@ netdev_tnl_ipv6_hdr(void *eth)
return (void *)((char *)eth + sizeof (struct eth_header));
}
+void *
+netdev_tnl_ip_build_header(struct ovs_action_push_tnl *data,
+ const struct netdev_tnl_build_header_params *params,
+ uint8_t next_proto);
+
extern uint16_t tnl_udp_port_min;
extern uint16_t tnl_udp_port_max;
diff --git a/lib/netdev-provider.h b/lib/netdev-provider.h
index be12e7cd7..5da377f99 100644
--- a/lib/netdev-provider.h
+++ b/lib/netdev-provider.h
@@ -32,6 +32,7 @@
extern "C" {
#endif
+struct netdev_tnl_build_header_params;
#define NETDEV_NUMA_UNSPEC OVS_NUMA_UNSPEC
/* A network device (e.g. an Ethernet device).
@@ -276,10 +277,10 @@ struct netdev_class {
const struct netdev_tunnel_config *
(*get_tunnel_config)(const struct netdev *netdev);
- /* Build Partial Tunnel header. Ethernet and ip header is already built,
- * build_header() is suppose build protocol specific part of header. */
+ /* Build Tunnel header. Ethernet and ip header parameters are passed to
+ * tunnel implementation to build entire outer header for given flow. */
int (*build_header)(const struct netdev *, struct ovs_action_push_tnl *data,
- const struct flow *tnl_flow);
+ const struct netdev_tnl_build_header_params *params);
/* build_header() can not build entire header for all packets for given
* flow. Push header is called for packet to build header specific to
diff --git a/lib/netdev.c b/lib/netdev.c
index 24e0f18f7..4be806d18 100644
--- a/lib/netdev.c
+++ b/lib/netdev.c
@@ -741,12 +741,26 @@ netdev_pop_header(struct netdev *netdev, struct dp_packet_batch *batch)
batch->count = n_cnt;
}
-int
-netdev_build_header(const struct netdev *netdev, struct ovs_action_push_tnl *data,
- const struct flow *tnl_flow)
+void
+netdev_init_tnl_build_header_params(struct netdev_tnl_build_header_params *params,
+ const struct flow *tnl_flow,
+ const struct in6_addr *src,
+ struct eth_addr dmac,
+ struct eth_addr smac)
+{
+ params->flow = tnl_flow;
+ params->dmac = dmac;
+ params->smac = smac;
+ params->s_ip = src;
+ params->is_ipv6 = !IN6_IS_ADDR_V4MAPPED(src);
+}
+
+int netdev_build_header(const struct netdev *netdev,
+ struct ovs_action_push_tnl *data,
+ const struct netdev_tnl_build_header_params *params)
{
if (netdev->netdev_class->build_header) {
- return netdev->netdev_class->build_header(netdev, data, tnl_flow);
+ return netdev->netdev_class->build_header(netdev, data, params);
}
return EOPNOTSUPP;
}
diff --git a/lib/netdev.h b/lib/netdev.h
index 6d6e4aba6..cdefcd532 100644
--- a/lib/netdev.h
+++ b/lib/netdev.h
@@ -152,8 +152,26 @@ int netdev_send(struct netdev *, int qid, struct dp_packet_batch *,
bool may_steal);
void netdev_send_wait(struct netdev *, int qid);
+/* native tunnel APIs */
+/* Structure to pass parameters required to build a tunnel header. */
+struct netdev_tnl_build_header_params {
+ const struct flow *flow;
+ const struct in6_addr *s_ip;
+ struct eth_addr dmac;
+ struct eth_addr smac;
+ bool is_ipv6;
+};
+
+void
+netdev_init_tnl_build_header_params(struct netdev_tnl_build_header_params *params,
+ const struct flow *tnl_flow,
+ const struct in6_addr *src,
+ struct eth_addr dmac,
+ struct eth_addr smac);
+
int netdev_build_header(const struct netdev *, struct ovs_action_push_tnl *data,
- const struct flow *tnl_flow);
+ const struct netdev_tnl_build_header_params *params);
+
int netdev_push_header(const struct netdev *netdev,
struct dp_packet_batch *,
const struct ovs_action_push_tnl *data);