summaryrefslogtreecommitdiff
path: root/lib/conntrack.c
diff options
context:
space:
mode:
authorDarrell Ball <dlu998@gmail.com>2017-05-30 10:49:28 -0700
committerBen Pfaff <blp@ovn.org>2017-06-02 16:40:00 -0700
commitedd1bef468c039dbea032bc0bcdcd8e4c1bf130d (patch)
tree65d8ffece04cdb503102fc7ee6c0497dc1c5c961 /lib/conntrack.c
parent286de27299550d1c4b2b4abb8048a189669962ef (diff)
downloadopenvswitch-edd1bef468c039dbea032bc0bcdcd8e4c1bf130d.tar.gz
dpdk: Add more ICMP Related NAT support.
This patch includes more complete support for icmp4 and icmp6 related NAT handling. Signed-off-by: Darrell Ball <dlu998@gmail.com> Acked-by: Daniele Di Proietto <diproiettod@ovn.org> Signed-off-by: Ben Pfaff <blp@ovn.org>
Diffstat (limited to 'lib/conntrack.c')
-rw-r--r--lib/conntrack.c98
1 files changed, 96 insertions, 2 deletions
diff --git a/lib/conntrack.c b/lib/conntrack.c
index 4fabcc353..005f2092f 100644
--- a/lib/conntrack.c
+++ b/lib/conntrack.c
@@ -324,6 +324,94 @@ un_pat_packet(struct dp_packet *pkt, const struct conn *conn)
}
static void
+reverse_pat_packet(struct dp_packet *pkt, const struct conn *conn)
+{
+ if (conn->nat_info->nat_action & NAT_ACTION_SRC) {
+ if (conn->key.nw_proto == IPPROTO_TCP) {
+ struct tcp_header *th_in = dp_packet_l4(pkt);
+ packet_set_tcp_port(pkt, conn->key.src.port,
+ th_in->tcp_dst);
+ } else if (conn->key.nw_proto == IPPROTO_UDP) {
+ struct udp_header *uh_in = dp_packet_l4(pkt);
+ packet_set_udp_port(pkt, conn->key.src.port,
+ uh_in->udp_dst);
+ }
+ } else if (conn->nat_info->nat_action & NAT_ACTION_DST) {
+ if (conn->key.nw_proto == IPPROTO_TCP) {
+ struct tcp_header *th_in = dp_packet_l4(pkt);
+ packet_set_tcp_port(pkt, th_in->tcp_src,
+ conn->key.dst.port);
+ } else if (conn->key.nw_proto == IPPROTO_UDP) {
+ struct udp_header *uh_in = dp_packet_l4(pkt);
+ packet_set_udp_port(pkt, uh_in->udp_src,
+ conn->key.dst.port);
+ }
+ }
+}
+
+static void
+reverse_nat_packet(struct dp_packet *pkt, const struct conn *conn)
+{
+ char *tail = dp_packet_tail(pkt);
+ char pad = dp_packet_l2_pad_size(pkt);
+ struct conn_key inner_key;
+ const char *inner_l4 = NULL;
+ uint16_t orig_l3_ofs = pkt->l3_ofs;
+ uint16_t orig_l4_ofs = pkt->l4_ofs;
+
+ if (conn->key.dl_type == htons(ETH_TYPE_IP)) {
+ struct ip_header *nh = dp_packet_l3(pkt);
+ struct icmp_header *icmp = dp_packet_l4(pkt);
+ struct ip_header *inner_l3 = (struct ip_header *) (icmp + 1);
+ extract_l3_ipv4(&inner_key, inner_l3, tail - ((char *)inner_l3)
+ -pad, &inner_l4, false);
+
+ pkt->l3_ofs += (char *) inner_l3 - (char *) nh;
+ pkt->l4_ofs += inner_l4 - (char *) icmp;
+
+ if (conn->nat_info->nat_action & NAT_ACTION_SRC) {
+ packet_set_ipv4_addr(pkt, &inner_l3->ip_src,
+ conn->key.src.addr.ipv4_aligned);
+ } else if (conn->nat_info->nat_action & NAT_ACTION_DST) {
+ packet_set_ipv4_addr(pkt, &inner_l3->ip_dst,
+ conn->key.dst.addr.ipv4_aligned);
+ }
+ reverse_pat_packet(pkt, conn);
+ icmp->icmp_csum = 0;
+ icmp->icmp_csum = csum(icmp, tail - (char *) icmp - pad);
+ } else {
+ struct ovs_16aligned_ip6_hdr *nh6 = dp_packet_l3(pkt);
+ struct icmp6_error_header *icmp6 = dp_packet_l4(pkt);
+ struct ovs_16aligned_ip6_hdr *inner_l3_6 =
+ (struct ovs_16aligned_ip6_hdr *) (icmp6 + 1);
+ extract_l3_ipv6(&inner_key, inner_l3_6,
+ tail - ((char *)inner_l3_6) - pad,
+ &inner_l4);
+ pkt->l3_ofs += (char *) inner_l3_6 - (char *) nh6;
+ pkt->l4_ofs += inner_l4 - (char *) icmp6;
+
+ if (conn->nat_info->nat_action & NAT_ACTION_SRC) {
+ packet_set_ipv6_addr(pkt, conn->key.nw_proto,
+ inner_l3_6->ip6_src.be32,
+ &conn->key.src.addr.ipv6_aligned,
+ true);
+ } else if (conn->nat_info->nat_action & NAT_ACTION_DST) {
+ packet_set_ipv6_addr(pkt, conn->key.nw_proto,
+ inner_l3_6->ip6_dst.be32,
+ &conn->key.dst.addr.ipv6_aligned,
+ true);
+ }
+ reverse_pat_packet(pkt, conn);
+ uint32_t icmp6_csum = packet_csum_pseudoheader6(nh6);
+ icmp6->icmp6_base.icmp6_cksum = 0;
+ icmp6->icmp6_base.icmp6_cksum = csum_finish(
+ csum_continue(icmp6_csum, icmp6, tail - (char *) icmp6 - pad));
+ }
+ pkt->l3_ofs = orig_l3_ofs;
+ pkt->l4_ofs = orig_l4_ofs;
+}
+
+static void
un_nat_packet(struct dp_packet *pkt, const struct conn *conn,
bool related)
{
@@ -339,7 +427,10 @@ un_nat_packet(struct dp_packet *pkt, const struct conn *conn,
nh6->ip6_dst.be32,
&conn->key.src.addr.ipv6_aligned, true);
}
- if (!related) {
+
+ if (OVS_UNLIKELY(related)) {
+ reverse_nat_packet(pkt, conn);
+ } else {
un_pat_packet(pkt, conn);
}
} else if (conn->nat_info->nat_action & NAT_ACTION_DST) {
@@ -354,7 +445,10 @@ un_nat_packet(struct dp_packet *pkt, const struct conn *conn,
nh6->ip6_src.be32,
&conn->key.dst.addr.ipv6_aligned, true);
}
- if (!related) {
+
+ if (OVS_UNLIKELY(related)) {
+ reverse_nat_packet(pkt, conn);
+ } else {
un_pat_packet(pkt, conn);
}
}