Signed-off-by: Darrell Ball <dlu...@gmail.com> Acked-by: Flavio Leitner <f...@sysclose.org> --- lib/conntrack-private.h | 9 ------ lib/conntrack.c | 3 +- lib/conntrack.h | 29 ++++++++++++++++- lib/dpif-netdev.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++-- tests/test-conntrack.c | 9 +++--- 5 files changed, 117 insertions(+), 18 deletions(-)
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 60a3972..4f490fb 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..46f4391 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,6 +63,30 @@ 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 *); @@ -68,7 +94,8 @@ 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 char *helper, + const struct nat_action_info_t *nat_action_info); struct conntrack_dump { struct conntrack *ct; diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index a14a2eb..aa67780 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 = { @@ -5128,6 +5129,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)) { @@ -5152,15 +5156,90 @@ dp_execute_cb(void *aux_, struct dp_packet_batch *packets_, case OVS_CT_ATTR_LABELS: setlabel = nl_attr_get(b); 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); } } -- 1.9.1 _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev