diff mbox

[ovs-dev,patch_v8,1/9] dpdk: Parse NAT netlink for userspace datapath.

Message ID 1496166573-90065-2-git-send-email-dlu998@gmail.com
State Accepted
Headers show

Commit Message

Darrell Ball May 30, 2017, 5:49 p.m. UTC
Signed-off-by: Darrell Ball <dlu998@gmail.com>
Acked-by: Flavio Leitner <fbl@sysclose.org>
Acked-by: Daniele Di Proietto <diproiettod@ovn.org>
---
 lib/conntrack-private.h |  9 ------
 lib/conntrack.c         |  3 +-
 lib/conntrack.h         | 38 +++++++++++++++++++---
 lib/dpif-netdev.c       | 85 +++++++++++++++++++++++++++++++++++++++++++++++--
 tests/test-conntrack.c  |  9 +++---
 5 files changed, 122 insertions(+), 22 deletions(-)
diff mbox

Patch

diff --git a/lib/conntrack-private.h b/lib/conntrack-private.h
index 013f19f..493865f 100644
--- a/lib/conntrack-private.h
+++ b/lib/conntrack-private.h
@@ -29,15 +29,6 @@ 
 #include "packets.h"
 #include "unaligned.h"
 
-struct ct_addr {
-    union {
-        ovs_16aligned_be32 ipv4;
-        union ovs_16aligned_in6_addr ipv6;
-        ovs_be32 ipv4_aligned;
-        struct in6_addr ipv6_aligned;
-    };
-};
-
 struct ct_endpoint {
     struct ct_addr addr;
     union {
diff --git a/lib/conntrack.c b/lib/conntrack.c
index cb30ac7..ecc6177 100644
--- a/lib/conntrack.c
+++ b/lib/conntrack.c
@@ -313,7 +313,8 @@  conntrack_execute(struct conntrack *ct, struct dp_packet_batch *pkt_batch,
                   ovs_be16 dl_type, bool force, bool commit, uint16_t zone,
                   const uint32_t *setmark,
                   const struct ovs_key_ct_labels *setlabel,
-                  const char *helper)
+                  const char *helper,
+                  const struct nat_action_info_t *nat_action_info OVS_UNUSED)
 {
     struct dp_packet **pkts = pkt_batch->packets;
     size_t cnt = pkt_batch->count;
diff --git a/lib/conntrack.h b/lib/conntrack.h
index 0437cd3..21c516b 100644
--- a/lib/conntrack.h
+++ b/lib/conntrack.h
@@ -26,6 +26,8 @@ 
 #include "openvswitch/thread.h"
 #include "openvswitch/types.h"
 #include "ovs-atomic.h"
+#include "ovs-thread.h"
+#include "packets.h"
 
 /* Userspace connection tracker
  * ============================
@@ -61,14 +63,40 @@  struct dp_packet_batch;
 
 struct conntrack;
 
+struct ct_addr {
+    union {
+        ovs_16aligned_be32 ipv4;
+        union ovs_16aligned_in6_addr ipv6;
+        ovs_be32 ipv4_aligned;
+        struct in6_addr ipv6_aligned;
+    };
+};
+
+enum nat_action_e {
+    NAT_ACTION_SRC = 1 << 0,
+    NAT_ACTION_SRC_PORT = 1 << 1,
+    NAT_ACTION_DST = 1 << 2,
+    NAT_ACTION_DST_PORT = 1 << 3,
+};
+
+struct nat_action_info_t {
+    struct ct_addr min_addr;
+    struct ct_addr max_addr;
+    uint16_t min_port;
+    uint16_t max_port;
+    uint16_t nat_action;
+};
+
 void conntrack_init(struct conntrack *);
 void conntrack_destroy(struct conntrack *);
 
-int conntrack_execute(struct conntrack *, struct dp_packet_batch *,
-                      ovs_be16 dl_type, bool force, bool commit,
-                      uint16_t zone, const uint32_t *setmark,
-                      const struct ovs_key_ct_labels *setlabel,
-                      const char *helper);
+int
+conntrack_execute(struct conntrack *, struct dp_packet_batch *,
+                  ovs_be16 dl_type, bool force, bool commit,
+                  uint16_t zone, const uint32_t *setmark,
+                  const struct ovs_key_ct_labels *setlabel,
+                  const char *helper,
+                  const struct nat_action_info_t *nat_action_info OVS_UNUSED);
 
 struct conntrack_dump {
     struct conntrack *ct;
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index b50164b..e68ae1a 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -100,7 +100,8 @@  static struct shash dp_netdevs OVS_GUARDED_BY(dp_netdev_mutex)
 static struct vlog_rate_limit upcall_rl = VLOG_RATE_LIMIT_INIT(600, 600);
 
 #define DP_NETDEV_CS_SUPPORTED_MASK (CS_NEW | CS_ESTABLISHED | CS_RELATED \
-                                     | CS_INVALID | CS_REPLY_DIR | CS_TRACKED)
+                                     | CS_INVALID | CS_REPLY_DIR | CS_TRACKED \
+                                     | CS_SRC_NAT | CS_DST_NAT)
 #define DP_NETDEV_CS_UNSUPPORTED_MASK (~(uint32_t)DP_NETDEV_CS_SUPPORTED_MASK)
 
 static struct odp_support dp_netdev_support = {
@@ -5166,6 +5167,9 @@  dp_execute_cb(void *aux_, struct dp_packet_batch *packets_,
         const char *helper = NULL;
         const uint32_t *setmark = NULL;
         const struct ovs_key_ct_labels *setlabel = NULL;
+        struct nat_action_info_t nat_action_info;
+        struct nat_action_info_t *nat_action_info_ref = NULL;
+        bool nat_config = false;
 
         NL_ATTR_FOR_EACH_UNSAFE (b, left, nl_attr_get(a),
                                  nl_attr_get_size(a)) {
@@ -5194,15 +5198,90 @@  dp_execute_cb(void *aux_, struct dp_packet_batch *packets_,
                 /* Silently ignored, as userspace datapath does not generate
                  * netlink events. */
                 break;
-            case OVS_CT_ATTR_NAT:
+            case OVS_CT_ATTR_NAT: {
+                const struct nlattr *b_nest;
+                unsigned int left_nest;
+                bool ip_min_specified = false;
+                bool proto_num_min_specified = false;
+                bool ip_max_specified = false;
+                bool proto_num_max_specified = false;
+                memset(&nat_action_info, 0, sizeof nat_action_info);
+                nat_action_info_ref = &nat_action_info;
+
+                NL_NESTED_FOR_EACH_UNSAFE (b_nest, left_nest, b) {
+                    enum ovs_nat_attr sub_type_nest = nl_attr_type(b_nest);
+
+                    switch(sub_type_nest) {
+                    case OVS_NAT_ATTR_SRC:
+                    case OVS_NAT_ATTR_DST:
+                        nat_config = true;
+                        nat_action_info.nat_action |=
+                            ((sub_type_nest == OVS_NAT_ATTR_SRC)
+                                ? NAT_ACTION_SRC : NAT_ACTION_DST);
+                        break;
+                    case OVS_NAT_ATTR_IP_MIN:
+                        memcpy(&nat_action_info.min_addr,
+                               nl_attr_get(b_nest),
+                               nl_attr_get_size(b_nest));
+                        ip_min_specified = true;
+                        break;
+                    case OVS_NAT_ATTR_IP_MAX:
+                        memcpy(&nat_action_info.max_addr,
+                               nl_attr_get(b_nest),
+                               nl_attr_get_size(b_nest));
+                        ip_max_specified = true;
+                        break;
+                    case OVS_NAT_ATTR_PROTO_MIN:
+                        nat_action_info.min_port =
+                            nl_attr_get_u16(b_nest);
+                        proto_num_min_specified = true;
+                        break;
+                    case OVS_NAT_ATTR_PROTO_MAX:
+                        nat_action_info.max_port =
+                            nl_attr_get_u16(b_nest);
+                        proto_num_max_specified = true;
+                        break;
+                    case OVS_NAT_ATTR_PERSISTENT:
+                    case OVS_NAT_ATTR_PROTO_HASH:
+                    case OVS_NAT_ATTR_PROTO_RANDOM:
+                        break;
+                    case OVS_NAT_ATTR_UNSPEC:
+                    case __OVS_NAT_ATTR_MAX:
+                        OVS_NOT_REACHED();
+                    }
+                }
+
+                if (ip_min_specified && !ip_max_specified) {
+                    nat_action_info.max_addr = nat_action_info.min_addr;
+                }
+                if (proto_num_min_specified && !proto_num_max_specified) {
+                    nat_action_info.max_port = nat_action_info.min_port;
+                }
+                if (proto_num_min_specified || proto_num_max_specified) {
+                    if (nat_action_info.nat_action & NAT_ACTION_SRC) {
+                        nat_action_info.nat_action |= NAT_ACTION_SRC_PORT;
+                    } else if (nat_action_info.nat_action & NAT_ACTION_DST) {
+                        nat_action_info.nat_action |= NAT_ACTION_DST_PORT;
+                    }
+                }
+                break;
+            }
             case OVS_CT_ATTR_UNSPEC:
             case __OVS_CT_ATTR_MAX:
                 OVS_NOT_REACHED();
             }
         }
 
+        /* We won't be able to function properly in this case, hence
+         * complain loudly. */
+        if (nat_config && !commit) {
+            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5);
+            VLOG_WARN_RL(&rl, "NAT specified without commit.");
+        }
+
         conntrack_execute(&dp->conntrack, packets_, aux->flow->dl_type, force,
-                          commit, zone, setmark, setlabel, helper);
+                          commit, zone, setmark, setlabel, helper,
+                          nat_action_info_ref);
         break;
     }
 
diff --git a/tests/test-conntrack.c b/tests/test-conntrack.c
index 4213f5c..96bc1e5 100644
--- a/tests/test-conntrack.c
+++ b/tests/test-conntrack.c
@@ -89,7 +89,7 @@  ct_thread_main(void *aux_)
     ovs_barrier_block(&barrier);
     for (i = 0; i < n_pkts; i += batch_size) {
         conntrack_execute(&ct, pkt_batch, dl_type, false, true, 0, NULL, NULL,
-                          NULL);
+                          NULL, NULL);
     }
     ovs_barrier_block(&barrier);
     destroy_packets(pkt_batch);
@@ -171,15 +171,16 @@  pcap_batch_execute_conntrack(struct conntrack *ct,
         }
 
         if (flow.dl_type != dl_type) {
-            conntrack_execute(ct, &new_batch, dl_type, false, true, 0, NULL,
-                              NULL, NULL);
+            conntrack_execute(ct, &new_batch, dl_type, false, true, 0,
+                              NULL, NULL, NULL, NULL);
             dp_packet_batch_init(&new_batch);
         }
         new_batch.packets[new_batch.count++] = packet;;
     }
 
     if (!dp_packet_batch_is_empty(&new_batch)) {
-        conntrack_execute(ct, &new_batch, dl_type, false, true, 0, NULL, NULL, NULL);
+        conntrack_execute(ct, &new_batch, dl_type, false, true, 0, NULL, NULL,
+                          NULL, NULL);
     }
 
 }