@@ -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 {
@@ -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;
@@ -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;
@@ -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;
}
@@ -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);
}
}