diff options
author | Darrell Ball <dlu998@gmail.com> | 2017-05-30 10:49:28 -0700 |
---|---|---|
committer | Ben Pfaff <blp@ovn.org> | 2017-06-02 16:40:00 -0700 |
commit | edd1bef468c039dbea032bc0bcdcd8e4c1bf130d (patch) | |
tree | 65d8ffece04cdb503102fc7ee6c0497dc1c5c961 /lib/conntrack.c | |
parent | 286de27299550d1c4b2b4abb8048a189669962ef (diff) | |
download | openvswitch-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.c | 98 |
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); } } |