cnat: Support offloaded check sums 49/31449/14
authorNathan Skrzypczak <nathan.skrzypczak@gmail.com>
Thu, 25 Feb 2021 18:13:19 +0000 (19:13 +0100)
committerNathan Skrzypczak <nathan.skrzypczak@gmail.com>
Mon, 7 Aug 2023 09:34:48 +0000 (11:34 +0200)
This patch removes zero checks for new_addr, new_port
meaning sessions with zero values will rewrite the packet
with a 0 value instead of leaving it in place. This allows
to reduce branchiness in the code, and sessions are fully
resolved at creation time anyway.

This also adds support for checksum offloads:
- IP checksum offload : we always compute the checksum to
avoid issues with drivers. We'll revert this if we realize
cost gets too important.
- TCP/UDP checksum offload : we add the implementation for
pseudo header checksum computation. This is needed for the
drivers that do not re-compute this pseudo-checksum before
the packet is TX-ed (e.g. a few DPDK drivers).

Type: improvement

Change-Id: I6543f3aec8c120ec50f4219108609138283620ef
Signed-off-by: Nathan Skrzypczak <nathan.skrzypczak@gmail.com>
src/plugins/cnat/cnat_node.h
src/plugins/cnat/cnat_node_feature.c
src/plugins/cnat/cnat_node_snat.c
src/plugins/cnat/cnat_node_vip.c

index c304c5c..75c1b4a 100644 (file)
@@ -19,6 +19,7 @@
 #include <vlibmemory/api.h>
 #include <vnet/dpo/load_balance.h>
 #include <vnet/dpo/load_balance_map.h>
+#include <vnet/ip/ip_psh_cksum.h>
 
 #include <cnat/cnat_session.h>
 #include <cnat/cnat_client.h>
@@ -169,60 +170,46 @@ cmp_ip6_address (const ip6_address_t * a1, const ip6_address_t * a2)
  * Inline translation functions
  */
 
-static_always_inline u8
-has_ip6_address (ip6_address_t * a)
+static_always_inline u16
+ip4_pseudo_header_cksum2 (ip4_header_t *ip4, ip4_address_t address[VLIB_N_DIR])
 {
-  return ((0 != a->as_u64[0]) || (0 != a->as_u64[1]));
+  ip4_psh_t psh = { 0 };
+  psh.src = address[VLIB_RX];
+  psh.dst = address[VLIB_TX];
+  psh.proto = ip4->protocol;
+  psh.l4len = clib_host_to_net_u16 (clib_net_to_host_u16 (ip4->length) -
+                                   sizeof (ip4_header_t));
+  return ~(clib_ip_csum ((u8 *) &psh, sizeof (ip4_psh_t)));
 }
 
 static_always_inline void
-cnat_ip4_translate_l4 (ip4_header_t * ip4, udp_header_t * udp,
-                      ip_csum_t * sum,
+cnat_ip4_translate_l4 (ip4_header_t *ip4, udp_header_t *udp, ip_csum_t *sum,
                       ip4_address_t new_addr[VLIB_N_DIR],
-                      u16 new_port[VLIB_N_DIR])
+                      u16 new_port[VLIB_N_DIR], u32 oflags)
 {
   u16 old_port[VLIB_N_DIR];
-  ip4_address_t old_addr[VLIB_N_DIR];
+  old_port[VLIB_TX] = udp->dst_port;
+  old_port[VLIB_RX] = udp->src_port;
 
-  /* Fastpath no checksum */
-  if (PREDICT_TRUE (0 == *sum))
+  udp->dst_port = new_port[VLIB_TX];
+  udp->src_port = new_port[VLIB_RX];
+
+  if (oflags &
+      (VNET_BUFFER_OFFLOAD_F_TCP_CKSUM | VNET_BUFFER_OFFLOAD_F_UDP_CKSUM))
     {
-      udp->dst_port = new_port[VLIB_TX];
-      udp->src_port = new_port[VLIB_RX];
+      *sum = ip4_pseudo_header_cksum2 (ip4, new_addr);
       return;
     }
 
-  old_port[VLIB_TX] = udp->dst_port;
-  old_port[VLIB_RX] = udp->src_port;
-  old_addr[VLIB_TX] = ip4->dst_address;
-  old_addr[VLIB_RX] = ip4->src_address;
+  *sum = ip_csum_update (*sum, ip4->dst_address.as_u32,
+                        new_addr[VLIB_TX].as_u32, ip4_header_t, dst_address);
+  *sum = ip_csum_update (*sum, ip4->src_address.as_u32,
+                        new_addr[VLIB_RX].as_u32, ip4_header_t, src_address);
 
-  if (new_addr[VLIB_TX].as_u32)
-    {
-      *sum =
-       ip_csum_update (*sum, old_addr[VLIB_TX].as_u32,
-                       new_addr[VLIB_TX].as_u32, ip4_header_t, dst_address);
-    }
-  if (new_port[VLIB_TX])
-    {
-      udp->dst_port = new_port[VLIB_TX];
-      *sum = ip_csum_update (*sum, old_port[VLIB_TX], new_port[VLIB_TX],
-                            ip4_header_t /* cheat */ ,
-                            length /* changed member */ );
-    }
-  if (new_addr[VLIB_RX].as_u32)
-    {
-      *sum =
-       ip_csum_update (*sum, old_addr[VLIB_RX].as_u32,
-                       new_addr[VLIB_RX].as_u32, ip4_header_t, src_address);
-    }
-  if (new_port[VLIB_RX])
-    {
-      udp->src_port = new_port[VLIB_RX];
-      *sum = ip_csum_update (*sum, old_port[VLIB_RX], new_port[VLIB_RX],
-                            ip4_header_t /* cheat */ ,
-                            length /* changed member */ );
-    }
+  *sum = ip_csum_update (*sum, old_port[VLIB_TX], new_port[VLIB_TX],
+                        udp_header_t, dst_port);
+  *sum = ip_csum_update (*sum, old_port[VLIB_RX], new_port[VLIB_RX],
+                        udp_header_t, src_port);
 }
 
 static_always_inline void
@@ -249,29 +236,26 @@ cnat_ip4_translate_sctp (ip4_header_t *ip4, sctp_header_t *sctp,
 }
 
 static_always_inline void
-cnat_ip4_translate_l3 (ip4_header_t * ip4, ip4_address_t new_addr[VLIB_N_DIR])
+cnat_ip4_translate_l3 (ip4_header_t *ip4, ip4_address_t new_addr[VLIB_N_DIR],
+                      u32 oflags)
 {
   ip4_address_t old_addr[VLIB_N_DIR];
   ip_csum_t sum;
-
   old_addr[VLIB_TX] = ip4->dst_address;
   old_addr[VLIB_RX] = ip4->src_address;
 
+  ip4->dst_address = new_addr[VLIB_TX];
+  ip4->src_address = new_addr[VLIB_RX];
+
+  // We always compute the IP checksum even if oflags &
+  // VNET_BUFFER_OFFLOAD_F_IP_CKSUM is set as this is relatively inexpensive
+  // and will allow avoiding issues in driver that do not behave properly
+  // downstream.
   sum = ip4->checksum;
-  if (new_addr[VLIB_TX].as_u32)
-    {
-      ip4->dst_address = new_addr[VLIB_TX];
-      sum =
-       ip_csum_update (sum, old_addr[VLIB_TX].as_u32,
+  sum = ip_csum_update (sum, old_addr[VLIB_TX].as_u32,
                        new_addr[VLIB_TX].as_u32, ip4_header_t, dst_address);
-    }
-  if (new_addr[VLIB_RX].as_u32)
-    {
-      ip4->src_address = new_addr[VLIB_RX];
-      sum =
-       ip_csum_update (sum, old_addr[VLIB_RX].as_u32,
+  sum = ip_csum_update (sum, old_addr[VLIB_RX].as_u32,
                        new_addr[VLIB_RX].as_u32, ip4_header_t, src_address);
-    }
   ip4->checksum = ip_csum_fold (sum);
 }
 
@@ -280,48 +264,40 @@ cnat_tcp_update_session_lifetime (tcp_header_t * tcp, u32 index)
 {
   cnat_main_t *cm = &cnat_main;
   if (PREDICT_FALSE (tcp_fin (tcp)))
-    {
-      cnat_timestamp_set_lifetime (index, CNAT_DEFAULT_TCP_RST_TIMEOUT);
-    }
+    cnat_timestamp_set_lifetime (index, CNAT_DEFAULT_TCP_RST_TIMEOUT);
 
   if (PREDICT_FALSE (tcp_rst (tcp)))
-    {
-      cnat_timestamp_set_lifetime (index, CNAT_DEFAULT_TCP_RST_TIMEOUT);
-    }
+    cnat_timestamp_set_lifetime (index, CNAT_DEFAULT_TCP_RST_TIMEOUT);
 
   if (PREDICT_FALSE (tcp_syn (tcp) && tcp_ack (tcp)))
-    {
-      cnat_timestamp_set_lifetime (index, cm->tcp_max_age);
-    }
+    cnat_timestamp_set_lifetime (index, cm->tcp_max_age);
 }
 
 static_always_inline void
-cnat_translation_icmp4_echo (ip4_header_t * ip4, icmp46_header_t * icmp,
+cnat_translation_icmp4_echo (ip4_header_t *ip4, icmp46_header_t *icmp,
                             ip4_address_t new_addr[VLIB_N_DIR],
-                            u16 new_port[VLIB_N_DIR])
+                            u16 new_port[VLIB_N_DIR], u32 oflags)
 {
   ip_csum_t sum;
   u16 old_port;
   cnat_echo_header_t *echo = (cnat_echo_header_t *) (icmp + 1);
 
-  cnat_ip4_translate_l3 (ip4, new_addr);
+  cnat_ip4_translate_l3 (ip4, new_addr, oflags);
   old_port = echo->identifier;
   echo->identifier = new_port[VLIB_RX];
 
   sum = icmp->checksum;
-  sum = ip_csum_update (sum, old_port, new_port[VLIB_RX],
-                       ip4_header_t /* cheat */ ,
-                       length /* changed member */ );
+  sum =
+    ip_csum_update (sum, old_port, new_port[VLIB_RX], udp_header_t, src_port);
 
   icmp->checksum = ip_csum_fold (sum);
 }
 
 static_always_inline void
-cnat_translation_icmp4_error (ip4_header_t * outer_ip4,
-                             icmp46_header_t * icmp,
+cnat_translation_icmp4_error (ip4_header_t *outer_ip4, icmp46_header_t *icmp,
                              ip4_address_t outer_new_addr[VLIB_N_DIR],
-                             u16 outer_new_port[VLIB_N_DIR],
-                             u8 snat_outer_ip)
+                             u16 outer_new_port[VLIB_N_DIR], u8 snat_outer_ip,
+                             u32 oflags)
 {
   ip4_address_t new_addr[VLIB_N_DIR];
   ip4_address_t old_addr[VLIB_N_DIR];
@@ -350,18 +326,20 @@ cnat_translation_icmp4_error (ip4_header_t * outer_ip4,
   /* translate outer ip. */
   if (!snat_outer_ip)
     outer_new_addr[VLIB_RX] = outer_ip4->src_address;
-  cnat_ip4_translate_l3 (outer_ip4, outer_new_addr);
+  cnat_ip4_translate_l3 (outer_ip4, outer_new_addr, oflags);
 
   if (ip4->protocol == IP_PROTOCOL_TCP)
     {
       inner_l4_old_sum = inner_l4_sum = tcp->checksum;
-      cnat_ip4_translate_l4 (ip4, udp, &inner_l4_sum, new_addr, new_port);
+      cnat_ip4_translate_l4 (ip4, udp, &inner_l4_sum, new_addr, new_port,
+                            0 /* flags */);
       tcp->checksum = ip_csum_fold (inner_l4_sum);
     }
   else if (ip4->protocol == IP_PROTOCOL_UDP)
     {
       inner_l4_old_sum = inner_l4_sum = udp->checksum;
-      cnat_ip4_translate_l4 (ip4, udp, &inner_l4_sum, new_addr, new_port);
+      cnat_ip4_translate_l4 (ip4, udp, &inner_l4_sum, new_addr, new_port,
+                            0 /* flags */);
       udp->checksum = ip_csum_fold (inner_l4_sum);
     }
   else
@@ -374,37 +352,30 @@ cnat_translation_icmp4_error (ip4_header_t * outer_ip4,
   /* UDP/TCP Ports changed */
   if (old_port[VLIB_TX] && new_port[VLIB_TX])
     sum = ip_csum_update (sum, old_port[VLIB_TX], new_port[VLIB_TX],
-                         ip4_header_t /* cheat */ ,
-                         length /* changed member */ );
+                         udp_header_t, dst_port);
 
   if (old_port[VLIB_RX] && new_port[VLIB_RX])
     sum = ip_csum_update (sum, old_port[VLIB_RX], new_port[VLIB_RX],
-                         ip4_header_t /* cheat */ ,
-                         length /* changed member */ );
-
+                         udp_header_t, src_port);
 
-  cnat_ip4_translate_l3 (ip4, new_addr);
+  cnat_ip4_translate_l3 (ip4, new_addr, 0 /* oflags */);
   ip_csum_t new_ip_sum = ip4->checksum;
   /* IP checksum changed */
   sum = ip_csum_update (sum, old_ip_sum, new_ip_sum, ip4_header_t, checksum);
 
   /* IP src/dst addr changed */
-  if (new_addr[VLIB_TX].as_u32)
-    sum =
-      ip_csum_update (sum, old_addr[VLIB_TX].as_u32, new_addr[VLIB_TX].as_u32,
-                     ip4_header_t, dst_address);
+  sum = ip_csum_update (sum, old_addr[VLIB_TX].as_u32,
+                       new_addr[VLIB_TX].as_u32, ip4_header_t, dst_address);
 
-  if (new_addr[VLIB_RX].as_u32)
-    sum =
-      ip_csum_update (sum, old_addr[VLIB_RX].as_u32, new_addr[VLIB_RX].as_u32,
-                     ip4_header_t, src_address);
+  sum = ip_csum_update (sum, old_addr[VLIB_RX].as_u32,
+                       new_addr[VLIB_RX].as_u32, ip4_header_t, src_address);
 
   icmp->checksum = ip_csum_fold (sum);
 }
 
 static_always_inline void
-cnat_translation_ip4 (const cnat_session_t * session,
-                     ip4_header_t * ip4, udp_header_t * udp)
+cnat_translation_ip4 (const cnat_session_t *session, ip4_header_t *ip4,
+                     udp_header_t *udp, u32 oflags)
 {
   tcp_header_t *tcp = (tcp_header_t *) udp;
   ip4_address_t new_addr[VLIB_N_DIR];
@@ -418,23 +389,23 @@ cnat_translation_ip4 (const cnat_session_t * session,
   if (ip4->protocol == IP_PROTOCOL_TCP)
     {
       ip_csum_t sum = tcp->checksum;
-      cnat_ip4_translate_l4 (ip4, udp, &sum, new_addr, new_port);
+      cnat_ip4_translate_l4 (ip4, udp, &sum, new_addr, new_port, oflags);
       tcp->checksum = ip_csum_fold (sum);
-      cnat_ip4_translate_l3 (ip4, new_addr);
+      cnat_ip4_translate_l3 (ip4, new_addr, oflags);
       cnat_tcp_update_session_lifetime (tcp, session->value.cs_ts_index);
     }
   else if (ip4->protocol == IP_PROTOCOL_UDP)
     {
       ip_csum_t sum = udp->checksum;
-      cnat_ip4_translate_l4 (ip4, udp, &sum, new_addr, new_port);
+      cnat_ip4_translate_l4 (ip4, udp, &sum, new_addr, new_port, oflags);
       udp->checksum = ip_csum_fold (sum);
-      cnat_ip4_translate_l3 (ip4, new_addr);
+      cnat_ip4_translate_l3 (ip4, new_addr, oflags);
     }
   else if (ip4->protocol == IP_PROTOCOL_SCTP)
     {
       sctp_header_t *sctp = (sctp_header_t *) udp;
       cnat_ip4_translate_sctp (ip4, sctp, new_port);
-      cnat_ip4_translate_l3 (ip4, new_addr);
+      cnat_ip4_translate_l3 (ip4, new_addr, oflags);
     }
   else if (ip4->protocol == IP_PROTOCOL_ICMP)
     {
@@ -446,74 +417,65 @@ cnat_translation_ip4 (const cnat_session_t * session,
            (ip4->src_address.as_u32 ==
             session->key.cs_ip[VLIB_RX].ip4.as_u32);
          cnat_translation_icmp4_error (ip4, icmp, new_addr, new_port,
-                                       snat_outer_ip);
+                                       snat_outer_ip, oflags);
        }
       else if (icmp_type_is_echo (icmp->type))
-       cnat_translation_icmp4_echo (ip4, icmp, new_addr, new_port);
+       cnat_translation_icmp4_echo (ip4, icmp, new_addr, new_port, oflags);
     }
 }
 
 static_always_inline void
 cnat_ip6_translate_l3 (ip6_header_t * ip6, ip6_address_t new_addr[VLIB_N_DIR])
 {
-  if (has_ip6_address (&new_addr[VLIB_TX]))
-    ip6_address_copy (&ip6->dst_address, &new_addr[VLIB_TX]);
-  if (has_ip6_address (&new_addr[VLIB_RX]))
-    ip6_address_copy (&ip6->src_address, &new_addr[VLIB_RX]);
+  ip6_address_copy (&ip6->dst_address, &new_addr[VLIB_TX]);
+  ip6_address_copy (&ip6->src_address, &new_addr[VLIB_RX]);
+}
+
+static_always_inline u16
+ip6_pseudo_header_cksum2 (ip6_header_t *ip6, ip6_address_t address[VLIB_N_DIR])
+{
+  ip6_psh_t psh = { 0 };
+  psh.src = address[VLIB_RX];
+  psh.dst = address[VLIB_TX];
+  psh.l4len = ip6->payload_length;
+  psh.proto = clib_host_to_net_u32 ((u32) ip6->protocol);
+  return ~(clib_ip_csum ((u8 *) &psh, sizeof (ip6_psh_t)));
 }
 
 static_always_inline void
-cnat_ip6_translate_l4 (ip6_header_t * ip6, udp_header_t * udp,
-                      ip_csum_t * sum,
+cnat_ip6_translate_l4 (ip6_header_t *ip6, udp_header_t *udp, ip_csum_t *sum,
                       ip6_address_t new_addr[VLIB_N_DIR],
-                      u16 new_port[VLIB_N_DIR])
+                      u16 new_port[VLIB_N_DIR], u32 oflags)
 {
   u16 old_port[VLIB_N_DIR];
-  ip6_address_t old_addr[VLIB_N_DIR];
+  old_port[VLIB_TX] = udp->dst_port;
+  old_port[VLIB_RX] = udp->src_port;
 
-  /* Fastpath no checksum */
-  if (PREDICT_TRUE (0 == *sum))
+  udp->dst_port = new_port[VLIB_TX];
+  udp->src_port = new_port[VLIB_RX];
+
+  if (oflags &
+      (VNET_BUFFER_OFFLOAD_F_TCP_CKSUM | VNET_BUFFER_OFFLOAD_F_UDP_CKSUM))
     {
-      udp->dst_port = new_port[VLIB_TX];
-      udp->src_port = new_port[VLIB_RX];
+      *sum = ip6_pseudo_header_cksum2 (ip6, new_addr);
       return;
     }
 
-  old_port[VLIB_TX] = udp->dst_port;
-  old_port[VLIB_RX] = udp->src_port;
-  ip6_address_copy (&old_addr[VLIB_TX], &ip6->dst_address);
-  ip6_address_copy (&old_addr[VLIB_RX], &ip6->src_address);
+  *sum = ip_csum_add_even (*sum, new_addr[VLIB_TX].as_u64[0]);
+  *sum = ip_csum_add_even (*sum, new_addr[VLIB_TX].as_u64[1]);
+  *sum = ip_csum_sub_even (*sum, ip6->dst_address.as_u64[0]);
+  *sum = ip_csum_sub_even (*sum, ip6->dst_address.as_u64[1]);
 
-  if (has_ip6_address (&new_addr[VLIB_TX]))
-    {
-      *sum = ip_csum_add_even (*sum, new_addr[VLIB_TX].as_u64[0]);
-      *sum = ip_csum_add_even (*sum, new_addr[VLIB_TX].as_u64[1]);
-      *sum = ip_csum_sub_even (*sum, old_addr[VLIB_TX].as_u64[0]);
-      *sum = ip_csum_sub_even (*sum, old_addr[VLIB_TX].as_u64[1]);
-    }
+  *sum = ip_csum_add_even (*sum, new_addr[VLIB_RX].as_u64[0]);
+  *sum = ip_csum_add_even (*sum, new_addr[VLIB_RX].as_u64[1]);
+  *sum = ip_csum_sub_even (*sum, ip6->src_address.as_u64[0]);
+  *sum = ip_csum_sub_even (*sum, ip6->src_address.as_u64[1]);
 
-  if (new_port[VLIB_TX])
-    {
-      udp->dst_port = new_port[VLIB_TX];
-      *sum = ip_csum_update (*sum, old_port[VLIB_TX], new_port[VLIB_TX],
-                            ip4_header_t /* cheat */ ,
-                            length /* changed member */ );
-    }
-  if (has_ip6_address (&new_addr[VLIB_RX]))
-    {
-      *sum = ip_csum_add_even (*sum, new_addr[VLIB_RX].as_u64[0]);
-      *sum = ip_csum_add_even (*sum, new_addr[VLIB_RX].as_u64[1]);
-      *sum = ip_csum_sub_even (*sum, old_addr[VLIB_RX].as_u64[0]);
-      *sum = ip_csum_sub_even (*sum, old_addr[VLIB_RX].as_u64[1]);
-    }
+  *sum = ip_csum_update (*sum, old_port[VLIB_TX], new_port[VLIB_TX],
+                        udp_header_t, dst_port);
 
-  if (new_port[VLIB_RX])
-    {
-      udp->src_port = new_port[VLIB_RX];
-      *sum = ip_csum_update (*sum, old_port[VLIB_RX], new_port[VLIB_RX],
-                            ip4_header_t /* cheat */ ,
-                            length /* changed member */ );
-    }
+  *sum = ip_csum_update (*sum, old_port[VLIB_RX], new_port[VLIB_RX],
+                        udp_header_t, src_port);
 }
 
 static_always_inline void
@@ -532,26 +494,20 @@ cnat_translation_icmp6_echo (ip6_header_t * ip6, icmp46_header_t * icmp,
   sum = icmp->checksum;
 
   cnat_ip6_translate_l3 (ip6, new_addr);
-  if (has_ip6_address (&new_addr[VLIB_TX]))
-    {
-      sum = ip_csum_add_even (sum, new_addr[VLIB_TX].as_u64[0]);
-      sum = ip_csum_add_even (sum, new_addr[VLIB_TX].as_u64[1]);
-      sum = ip_csum_sub_even (sum, old_addr[VLIB_TX].as_u64[0]);
-      sum = ip_csum_sub_even (sum, old_addr[VLIB_TX].as_u64[1]);
-    }
 
-  if (has_ip6_address (&new_addr[VLIB_RX]))
-    {
-      sum = ip_csum_add_even (sum, new_addr[VLIB_RX].as_u64[0]);
-      sum = ip_csum_add_even (sum, new_addr[VLIB_RX].as_u64[1]);
-      sum = ip_csum_sub_even (sum, old_addr[VLIB_RX].as_u64[0]);
-      sum = ip_csum_sub_even (sum, old_addr[VLIB_RX].as_u64[1]);
-    }
+  sum = ip_csum_add_even (sum, new_addr[VLIB_TX].as_u64[0]);
+  sum = ip_csum_add_even (sum, new_addr[VLIB_TX].as_u64[1]);
+  sum = ip_csum_sub_even (sum, old_addr[VLIB_TX].as_u64[0]);
+  sum = ip_csum_sub_even (sum, old_addr[VLIB_TX].as_u64[1]);
+
+  sum = ip_csum_add_even (sum, new_addr[VLIB_RX].as_u64[0]);
+  sum = ip_csum_add_even (sum, new_addr[VLIB_RX].as_u64[1]);
+  sum = ip_csum_sub_even (sum, old_addr[VLIB_RX].as_u64[0]);
+  sum = ip_csum_sub_even (sum, old_addr[VLIB_RX].as_u64[1]);
 
   echo->identifier = new_port[VLIB_RX];
-  sum = ip_csum_update (sum, old_port, new_port[VLIB_RX],
-                       ip4_header_t /* cheat */ ,
-                       length /* changed member */ );
+  sum =
+    ip_csum_update (sum, old_port, new_port[VLIB_RX], udp_header_t, src_port);
 
   icmp->checksum = ip_csum_fold (sum);
 }
@@ -595,79 +551,64 @@ cnat_translation_icmp6_error (ip6_header_t * outer_ip6,
   if (!snat_outer_ip)
     ip6_address_copy (&outer_new_addr[VLIB_RX], &outer_ip6->src_address);
   cnat_ip6_translate_l3 (outer_ip6, outer_new_addr);
-  if (has_ip6_address (&outer_new_addr[VLIB_TX]))
-    {
-      sum = ip_csum_add_even (sum, outer_new_addr[VLIB_TX].as_u64[0]);
-      sum = ip_csum_add_even (sum, outer_new_addr[VLIB_TX].as_u64[1]);
-      sum = ip_csum_sub_even (sum, outer_old_addr[VLIB_TX].as_u64[0]);
-      sum = ip_csum_sub_even (sum, outer_old_addr[VLIB_TX].as_u64[1]);
-    }
 
-  if (has_ip6_address (&outer_new_addr[VLIB_RX]))
-    {
-      sum = ip_csum_add_even (sum, outer_new_addr[VLIB_RX].as_u64[0]);
-      sum = ip_csum_add_even (sum, outer_new_addr[VLIB_RX].as_u64[1]);
-      sum = ip_csum_sub_even (sum, outer_old_addr[VLIB_RX].as_u64[0]);
-      sum = ip_csum_sub_even (sum, outer_old_addr[VLIB_RX].as_u64[1]);
-    }
+  sum = ip_csum_add_even (sum, outer_new_addr[VLIB_TX].as_u64[0]);
+  sum = ip_csum_add_even (sum, outer_new_addr[VLIB_TX].as_u64[1]);
+  sum = ip_csum_sub_even (sum, outer_old_addr[VLIB_TX].as_u64[0]);
+  sum = ip_csum_sub_even (sum, outer_old_addr[VLIB_TX].as_u64[1]);
+
+  sum = ip_csum_add_even (sum, outer_new_addr[VLIB_RX].as_u64[0]);
+  sum = ip_csum_add_even (sum, outer_new_addr[VLIB_RX].as_u64[1]);
+  sum = ip_csum_sub_even (sum, outer_old_addr[VLIB_RX].as_u64[0]);
+  sum = ip_csum_sub_even (sum, outer_old_addr[VLIB_RX].as_u64[1]);
 
   /* Translate inner TCP / UDP */
   if (ip6->protocol == IP_PROTOCOL_TCP)
     {
       inner_l4_old_sum = inner_l4_sum = tcp->checksum;
-      cnat_ip6_translate_l4 (ip6, udp, &inner_l4_sum, new_addr, new_port);
+      cnat_ip6_translate_l4 (ip6, udp, &inner_l4_sum, new_addr, new_port,
+                            0 /* oflags */);
       tcp->checksum = ip_csum_fold (inner_l4_sum);
     }
   else if (ip6->protocol == IP_PROTOCOL_UDP)
     {
       inner_l4_old_sum = inner_l4_sum = udp->checksum;
-      cnat_ip6_translate_l4 (ip6, udp, &inner_l4_sum, new_addr, new_port);
+      cnat_ip6_translate_l4 (ip6, udp, &inner_l4_sum, new_addr, new_port,
+                            0 /* oflags */);
       udp->checksum = ip_csum_fold (inner_l4_sum);
     }
   else
     return;
 
   /* UDP/TCP checksum changed */
-  sum = ip_csum_update (sum, inner_l4_old_sum, inner_l4_sum,
-                       ip4_header_t /* cheat */ ,
+  sum = ip_csum_update (sum, inner_l4_old_sum, inner_l4_sum, ip4_header_t,
                        checksum);
 
   /* UDP/TCP Ports changed */
-  if (old_port[VLIB_TX] && new_port[VLIB_TX])
-    sum = ip_csum_update (sum, old_port[VLIB_TX], new_port[VLIB_TX],
-                         ip4_header_t /* cheat */ ,
-                         length /* changed member */ );
-
-  if (old_port[VLIB_RX] && new_port[VLIB_RX])
-    sum = ip_csum_update (sum, old_port[VLIB_RX], new_port[VLIB_RX],
-                         ip4_header_t /* cheat */ ,
-                         length /* changed member */ );
+  sum = ip_csum_update (sum, old_port[VLIB_TX], new_port[VLIB_TX],
+                       udp_header_t, dst_port);
 
+  sum = ip_csum_update (sum, old_port[VLIB_RX], new_port[VLIB_RX],
+                       udp_header_t, src_port);
 
   cnat_ip6_translate_l3 (ip6, new_addr);
   /* IP src/dst addr changed */
-  if (has_ip6_address (&new_addr[VLIB_TX]))
-    {
-      sum = ip_csum_add_even (sum, new_addr[VLIB_TX].as_u64[0]);
-      sum = ip_csum_add_even (sum, new_addr[VLIB_TX].as_u64[1]);
-      sum = ip_csum_sub_even (sum, old_addr[VLIB_TX].as_u64[0]);
-      sum = ip_csum_sub_even (sum, old_addr[VLIB_TX].as_u64[1]);
-    }
+  sum = ip_csum_add_even (sum, new_addr[VLIB_TX].as_u64[0]);
+  sum = ip_csum_add_even (sum, new_addr[VLIB_TX].as_u64[1]);
+  sum = ip_csum_sub_even (sum, old_addr[VLIB_TX].as_u64[0]);
+  sum = ip_csum_sub_even (sum, old_addr[VLIB_TX].as_u64[1]);
 
-  if (has_ip6_address (&new_addr[VLIB_RX]))
-    {
-      sum = ip_csum_add_even (sum, new_addr[VLIB_RX].as_u64[0]);
-      sum = ip_csum_add_even (sum, new_addr[VLIB_RX].as_u64[1]);
-      sum = ip_csum_sub_even (sum, old_addr[VLIB_RX].as_u64[0]);
-      sum = ip_csum_sub_even (sum, old_addr[VLIB_RX].as_u64[1]);
-    }
+  sum = ip_csum_add_even (sum, new_addr[VLIB_RX].as_u64[0]);
+  sum = ip_csum_add_even (sum, new_addr[VLIB_RX].as_u64[1]);
+  sum = ip_csum_sub_even (sum, old_addr[VLIB_RX].as_u64[0]);
+  sum = ip_csum_sub_even (sum, old_addr[VLIB_RX].as_u64[1]);
 
   icmp->checksum = ip_csum_fold (sum);
 }
 
 static_always_inline void
-cnat_translation_ip6 (const cnat_session_t * session,
-                     ip6_header_t * ip6, udp_header_t * udp)
+cnat_translation_ip6 (const cnat_session_t *session, ip6_header_t *ip6,
+                     udp_header_t *udp, u32 oflags)
 {
   tcp_header_t *tcp = (tcp_header_t *) udp;
   ip6_address_t new_addr[VLIB_N_DIR];
@@ -681,7 +622,7 @@ cnat_translation_ip6 (const cnat_session_t * session,
   if (ip6->protocol == IP_PROTOCOL_TCP)
     {
       ip_csum_t sum = tcp->checksum;
-      cnat_ip6_translate_l4 (ip6, udp, &sum, new_addr, new_port);
+      cnat_ip6_translate_l4 (ip6, udp, &sum, new_addr, new_port, oflags);
       tcp->checksum = ip_csum_fold (sum);
       cnat_ip6_translate_l3 (ip6, new_addr);
       cnat_tcp_update_session_lifetime (tcp, session->value.cs_ts_index);
@@ -689,7 +630,7 @@ cnat_translation_ip6 (const cnat_session_t * session,
   else if (ip6->protocol == IP_PROTOCOL_UDP)
     {
       ip_csum_t sum = udp->checksum;
-      cnat_ip6_translate_l4 (ip6, udp, &sum, new_addr, new_port);
+      cnat_ip6_translate_l4 (ip6, udp, &sum, new_addr, new_port, oflags);
       udp->checksum = ip_csum_fold (sum);
       cnat_ip6_translate_l3 (ip6, new_addr);
     }
index 76aa893..2ab5cb2 100644 (file)
@@ -156,9 +156,9 @@ cnat_input_feature_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
     }
 
   if (AF_IP4 == ctx->af)
-    cnat_translation_ip4 (session, ip4, udp0);
+    cnat_translation_ip4 (session, ip4, udp0, vnet_buffer (b)->oflags);
   else
-    cnat_translation_ip6 (session, ip6, udp0);
+    cnat_translation_ip6 (session, ip6, udp0, vnet_buffer (b)->oflags);
 
   if (NULL != ct)
     {
@@ -326,9 +326,9 @@ cnat_output_feature_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
     }
 
   if (AF_IP4 == ctx->af)
-    cnat_translation_ip4 (session, ip4, udp0);
+    cnat_translation_ip4 (session, ip4, udp0, vnet_buffer (b)->oflags);
   else
-    cnat_translation_ip6 (session, ip6, udp0);
+    cnat_translation_ip6 (session, ip6, udp0, vnet_buffer (b)->oflags);
 
 trace:
   if (PREDICT_FALSE (ctx->do_trace))
index 9212d67..f5c8a20 100644 (file)
@@ -133,11 +133,10 @@ cnat_snat_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
                           CNAT_SESSION_FLAG_HAS_SNAT);
     }
 
-
   if (AF_IP4 == ctx->af)
-    cnat_translation_ip4 (session, ip4, udp0);
+    cnat_translation_ip4 (session, ip4, udp0, vnet_buffer (b)->oflags);
   else
-    cnat_translation_ip6 (session, ip6, udp0);
+    cnat_translation_ip6 (session, ip6, udp0, vnet_buffer (b)->oflags);
 
 trace:
   if (PREDICT_FALSE (b->flags & VLIB_BUFFER_IS_TRACED))
index f166bd4..5db19d2 100644 (file)
@@ -176,9 +176,9 @@ cnat_vip_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_buffer_t *b,
     }
 
   if (AF_IP4 == ctx->af)
-    cnat_translation_ip4 (session, ip4, udp0);
+    cnat_translation_ip4 (session, ip4, udp0, vnet_buffer (b)->oflags);
   else
-    cnat_translation_ip6 (session, ip6, udp0);
+    cnat_translation_ip6 (session, ip6, udp0, vnet_buffer (b)->oflags);
 
   if (NULL != ct)
     {