diff mbox

[ovs-dev,v4,09/17] dpif-netdev: Implement conntrack dump functions.

Message ID 1465598863-56688-10-git-send-email-diproiettod@vmware.com
State Changes Requested
Headers show

Commit Message

Daniele Di Proietto June 10, 2016, 10:47 p.m. UTC
New functions are implemented in the conntrack module to support this.

Signed-off-by: Daniele Di Proietto <diproiettod@vmware.com>
Acked-by: Flavio Leitner <fbl@sysclose.org>
---
 lib/conntrack-private.h |   3 ++
 lib/conntrack-tcp.c     |  34 +++++++++++++
 lib/conntrack.c         | 123 ++++++++++++++++++++++++++++++++++++++++++++++++
 lib/conntrack.h         |  15 ++++++
 lib/dpif-netdev.c       |  60 +++++++++++++++++++++--
 5 files changed, 232 insertions(+), 3 deletions(-)

Comments

Sairam Venugopal June 16, 2016, 10:57 p.m. UTC | #1
Hi Daniele,

I was trying to add conntrack dump support based on this patch and found a
discrepancy in
conntrack-tcp.c. 

Can you confirm if this is intended? I have inlined the comment.

Thanks,
Sairam



On 6/10/16, 3:47 PM, "Daniele Di Proietto" <diproiettod@vmware.com> wrote:

>New functions are implemented in the conntrack module to support this.
>
>Signed-off-by: Daniele Di Proietto <diproiettod@vmware.com>
>Acked-by: Flavio Leitner <fbl@sysclose.org>
>---
> lib/conntrack-private.h |   3 ++
> lib/conntrack-tcp.c     |  34 +++++++++++++
> lib/conntrack.c         | 123
>++++++++++++++++++++++++++++++++++++++++++++++++
> lib/conntrack.h         |  15 ++++++
> lib/dpif-netdev.c       |  60 +++++++++++++++++++++--
> 5 files changed, 232 insertions(+), 3 deletions(-)
>
>diff --git a/lib/conntrack-private.h b/lib/conntrack-private.h
>index 4743dc6..d5d5e52 100644
>--- a/lib/conntrack-private.h
>+++ b/lib/conntrack-private.h
>@@ -22,6 +22,7 @@
> #include <netinet/ip6.h>
> 
> #include "conntrack.h"
>+#include "ct-dpif.h"
> #include "hmap.h"
> #include "openvswitch/list.h"
> #include "openvswitch/types.h"
>@@ -75,6 +76,8 @@ struct ct_l4_proto {
>                                       struct conntrack_bucket *,
>                                       struct dp_packet *pkt, bool reply,
>                                       long long now);
>+    void (*conn_get_protoinfo)(const struct conn *,
>+                               struct ct_dpif_protoinfo *);
> };
> 
> extern struct ct_l4_proto ct_proto_tcp;
>diff --git a/lib/conntrack-tcp.c b/lib/conntrack-tcp.c
>index 71eadc1..947e1c9 100644
>--- a/lib/conntrack-tcp.c
>+++ b/lib/conntrack-tcp.c
>@@ -457,8 +457,42 @@ tcp_new_conn(struct conntrack_bucket *ctb, struct
>dp_packet *pkt,
>     return &newconn->up;
> }
> 
>+static uint8_t
>+tcp_peer_to_protoinfo_flags(const struct tcp_peer *peer)
>+{
>+    uint8_t res = 0;
>+
>+    if (peer->wscale & CT_WSCALE_FLAG) {
>+        res |= CT_DPIF_TCPF_WINDOW_SCALE;
>+    }
>+
>+    if (peer->wscale & CT_WSCALE_UNKNOWN) {
>+        res |= CT_DPIF_TCPF_BE_LIBERAL;
>+    }
>+
>+    return res;
>+}
>+
>+static void
>+tcp_conn_get_protoinfo(const struct conn *conn_,
>+                       struct ct_dpif_protoinfo *protoinfo)
>+{
>+    const struct conn_tcp *conn = conn_tcp_cast(conn_);
>+
>+    protoinfo->proto = IPPROTO_TCP;
>+    protoinfo->tcp.state_orig = conn->peer[0].state;
>+    protoinfo->tcp.state_reply = conn->peer[1].state;
>+
>+    protoinfo->tcp.wscale_orig = conn->peer[0].wscale & CT_WSCALE_MASK;
>+    protoinfo->tcp.wscale_reply = conn->peer[1].wscale & CT_WSCALE_MASK;
>+
>+    protoinfo->tcp.flags_orig =
>tcp_peer_to_protoinfo_flags(&conn->peer[0]);
>+    protoinfo->tcp.flags_reply =
>tcp_peer_to_protoinfo_flags(&conn->peer[0]);

Sai: Shouldn¹t the reply be tcp_peer_to_protoinfo_flags(&conn->peer[1]);


>+}
>+
> struct ct_l4_proto ct_proto_tcp = {
>     .new_conn = tcp_new_conn,
>     .valid_new = tcp_valid_new,
>     .conn_update = tcp_conn_update,
>+    .conn_get_protoinfo = tcp_conn_get_protoinfo,
> };
>diff --git a/lib/conntrack.c b/lib/conntrack.c
>index 5376550..6e59375 100644
>--- a/lib/conntrack.c
>+++ b/lib/conntrack.c
>@@ -26,6 +26,7 @@
> #include "conntrack-private.h"
> #include "coverage.h"
> #include "csum.h"
>+#include "ct-dpif.h"
> #include "dp-packet.h"
> #include "flow.h"
> #include "hmap.h"
>@@ -1048,3 +1049,125 @@ delete_conn(struct conn *conn)
> {
>     free(conn);
> }
>+?
>+static void
>+ct_endpoint_to_ct_dpif_inet_addr(const struct ct_addr *a,
>+                                 union ct_dpif_inet_addr *b,
>+                                 ovs_be16 dl_type)
>+{
>+    if (dl_type == htons(ETH_TYPE_IP)) {
>+        b->ip = a->ipv4_aligned;
>+    } else if (dl_type == htons(ETH_TYPE_IPV6)){
>+        b->in6 = a->ipv6_aligned;
>+    }
>+}
>+
>+static void
>+conn_key_to_tuple(const struct conn_key *key, struct ct_dpif_tuple
>*tuple)
>+{
>+    if (key->dl_type == htons(ETH_TYPE_IP)) {
>+        tuple->l3_type = AF_INET;
>+    } else if (key->dl_type == htons(ETH_TYPE_IPV6)) {
>+        tuple->l3_type = AF_INET6;
>+    }
>+    tuple->ip_proto = key->nw_proto;
>+    ct_endpoint_to_ct_dpif_inet_addr(&key->src.addr, &tuple->src,
>+                                     key->dl_type);
>+    ct_endpoint_to_ct_dpif_inet_addr(&key->dst.addr, &tuple->dst,
>+                                     key->dl_type);
>+
>+    if (key->nw_proto == IPPROTO_ICMP || key->nw_proto ==
>IPPROTO_ICMPV6) {
>+        tuple->icmp_id = key->src.port;
>+        /* ICMP type and code are not tracked */
>+        tuple->icmp_type = 0;
>+        tuple->icmp_code = 0;
>+    } else {
>+        tuple->src_port = key->src.port;
>+        tuple->dst_port = key->dst.port;
>+    }
>+}
>+
>+static void
>+conn_to_ct_dpif_entry(const struct conn *conn, struct ct_dpif_entry
>*entry,
>+                      long long now)
>+{
>+    struct ct_l4_proto *class;
>+    long long expiration;
>+    memset(entry, 0, sizeof *entry);
>+    conn_key_to_tuple(&conn->key, &entry->tuple_orig);
>+    conn_key_to_tuple(&conn->rev_key, &entry->tuple_reply);
>+
>+    entry->zone = conn->key.zone;
>+    entry->mark = conn->mark;
>+
>+    memcpy(&entry->labels, &conn->label, sizeof(entry->labels));
>+    /* Not implemented yet */
>+    entry->timestamp.start = 0;
>+    entry->timestamp.stop = 0;
>+
>+    expiration = conn->expiration - now;
>+    entry->timeout = (expiration > 0) ? expiration / 1000 : 0;
>+
>+    class = l4_protos[conn->key.nw_proto];
>+    if (class->conn_get_protoinfo) {
>+        class->conn_get_protoinfo(conn, &entry->protoinfo);
>+    }
>+}
>+
>+int
>+conntrack_dump_start(struct conntrack *ct, struct conntrack_dump *dump,
>+                     const uint16_t *pzone)
>+{
>+    memset(dump, 0, sizeof(*dump));
>+    if (pzone) {
>+        dump->zone = *pzone;
>+        dump->filter_zone = true;
>+    }
>+    dump->ct = ct;
>+
>+    return 0;
>+}
>+
>+int
>+conntrack_dump_next(struct conntrack_dump *dump, struct ct_dpif_entry
>*entry)
>+{
>+    struct conntrack *ct = dump->ct;
>+    long long now = time_msec();
>+
>+    while (dump->bucket < CONNTRACK_BUCKETS) {
>+        struct hmap_node *node;
>+
>+        ct_lock_lock(&ct->buckets[dump->bucket].lock);
>+        for (;;) {
>+            struct conn *conn;
>+
>+            node =
>hmap_at_position(&ct->buckets[dump->bucket].connections,
>+                                    &dump->bucket_pos);
>+            if (!node) {
>+                break;
>+            }
>+            INIT_CONTAINER(conn, node, node);
>+            if (!dump->filter_zone || conn->key.zone == dump->zone) {
>+                conn_to_ct_dpif_entry(conn, entry, now);
>+                break;
>+            }
>+            /* Else continue, until we find an entry in the appropriate
>zone
>+             * or the bucket has been scanned completely. */
>+        }
>+        ct_lock_unlock(&ct->buckets[dump->bucket].lock);
>+
>+        if (!node) {
>+            memset(&dump->bucket_pos, 0, sizeof dump->bucket_pos);
>+            dump->bucket++;
>+        } else {
>+            return 0;
>+        }
>+    }
>+    return EOF;
>+}
>+
>+int
>+conntrack_dump_done(struct conntrack_dump *dump OVS_UNUSED)
>+{
>+    return 0;
>+}
>diff --git a/lib/conntrack.h b/lib/conntrack.h
>index 29bf4b7..eba3ae9 100644
>--- a/lib/conntrack.h
>+++ b/lib/conntrack.h
>@@ -68,6 +68,21 @@ int conntrack_execute(struct conntrack *, struct
>dp_packet_batch *,
>                       bool commit, uint16_t zone, const uint32_t
>*setmark,
>                       const struct ovs_key_ct_labels *setlabel,
>                       const char *helper);
>+
>+struct conntrack_dump {
>+    struct conntrack *ct;
>+    unsigned bucket;
>+    struct hmap_position bucket_pos;
>+    bool filter_zone;
>+    uint16_t zone;
>+};
>+
>+struct ct_dpif_entry;
>+
>+int conntrack_dump_start(struct conntrack *, struct conntrack_dump *,
>+                         const uint16_t *pzone);
>+int conntrack_dump_next(struct conntrack_dump *, struct ct_dpif_entry *);
>+int conntrack_dump_done(struct conntrack_dump *);
> ?
> /* 'struct ct_lock' is a wrapper for an adaptive mutex.  It's useful to
>try
>  * different types of locks (e.g. spinlocks) */
>diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
>index 48ec987..910ada3 100644
>--- a/lib/dpif-netdev.c
>+++ b/lib/dpif-netdev.c
>@@ -35,6 +35,7 @@
> #include "cmap.h"
> #include "conntrack.h"
> #include "coverage.h"
>+#include "ct-dpif.h"
> #include "csum.h"
> #include "dp-packet.h"
> #include "dpif.h"
>@@ -4227,6 +4228,59 @@ dp_netdev_execute_actions(struct
>dp_netdev_pmd_thread *pmd,
>                         actions_len, dp_execute_cb);
> }
> 
>+struct dp_netdev_ct_dump {
>+    struct ct_dpif_dump_state up;
>+    struct conntrack_dump dump;
>+    struct conntrack *ct;
>+    struct dp_netdev *dp;
>+};
>+
>+static int
>+dpif_netdev_ct_dump_start(struct dpif *dpif, struct ct_dpif_dump_state
>**dump_,
>+                          const uint16_t *pzone)
>+{
>+    struct dp_netdev *dp = get_dp_netdev(dpif);
>+    struct dp_netdev_ct_dump *dump;
>+
>+    dump = xzalloc(sizeof *dump);
>+    dump->dp = dp;
>+    dump->ct = &dp->conntrack;
>+
>+    conntrack_dump_start(&dp->conntrack, &dump->dump, pzone);
>+
>+    *dump_ = &dump->up;
>+
>+    return 0;
>+}
>+
>+static int
>+dpif_netdev_ct_dump_next(struct dpif *dpif OVS_UNUSED,
>+                         struct ct_dpif_dump_state *dump_,
>+                         struct ct_dpif_entry *entry)
>+{
>+    struct dp_netdev_ct_dump *dump;
>+
>+    INIT_CONTAINER(dump, dump_, up);
>+
>+    return conntrack_dump_next(&dump->dump, entry);
>+}
>+
>+static int
>+dpif_netdev_ct_dump_done(struct dpif *dpif OVS_UNUSED,
>+                         struct ct_dpif_dump_state *dump_)
>+{
>+    struct dp_netdev_ct_dump *dump;
>+    int err;
>+
>+    INIT_CONTAINER(dump, dump_, up);
>+
>+    err = conntrack_dump_done(&dump->dump);
>+
>+    free(dump);
>+
>+    return err;
>+}
>+
> const struct dpif_class dpif_netdev_class = {
>     "netdev",
>     dpif_netdev_init,
>@@ -4267,9 +4321,9 @@ const struct dpif_class dpif_netdev_class = {
>     dpif_netdev_enable_upcall,
>     dpif_netdev_disable_upcall,
>     dpif_netdev_get_datapath_version,
>-    NULL,                       /* ct_dump_start */
>-    NULL,                       /* ct_dump_next */
>-    NULL,                       /* ct_dump_done */
>+    dpif_netdev_ct_dump_start,
>+    dpif_netdev_ct_dump_next,
>+    dpif_netdev_ct_dump_done,
>     NULL,                       /* ct_flush */
> };
> 
>-- 
>2.8.1
>
>_______________________________________________
>dev mailing list
>dev@openvswitch.org
>https://urldefense.proofpoint.com/v2/url?u=http-3A__openvswitch.org_mailma
>n_listinfo_dev&d=CwIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-YihVMNtXt-uEs&r=Dc
>ruz40PROJ40ROzSpxyQSLw6fcrOWpJgEcEmNR3JEQ&m=tNe8IQ972ivdkXYe_yHze175Gvfnc8
>nkzR8IOYekTsY&s=27fwP-jORLNBENHqlEC-4Ozf8gkYCcKr-5uxM9C3OBE&e=
Daniele Di Proietto June 18, 2016, 12:10 a.m. UTC | #2
Hi Sairam,

You're right, that should be tcp_peer_to_protoinfo_flags(&conn->peer[1])

Thanks for pointing that out!

Daniele


On 16/06/2016 15:57, "Sairam Venugopal" <vsairam@vmware.com> wrote:

>Hi Daniele,

>

>I was trying to add conntrack dump support based on this patch and found a

>discrepancy in

>conntrack-tcp.c. 

>

>Can you confirm if this is intended? I have inlined the comment.

>

>Thanks,

>Sairam

>

>

>

>On 6/10/16, 3:47 PM, "Daniele Di Proietto" <diproiettod@vmware.com> wrote:

>

>>New functions are implemented in the conntrack module to support this.

>>

>>Signed-off-by: Daniele Di Proietto <diproiettod@vmware.com>

>>Acked-by: Flavio Leitner <fbl@sysclose.org>

>>---

>> lib/conntrack-private.h |   3 ++

>> lib/conntrack-tcp.c     |  34 +++++++++++++

>> lib/conntrack.c         | 123

>>++++++++++++++++++++++++++++++++++++++++++++++++

>> lib/conntrack.h         |  15 ++++++

>> lib/dpif-netdev.c       |  60 +++++++++++++++++++++--

>> 5 files changed, 232 insertions(+), 3 deletions(-)

>>

>>diff --git a/lib/conntrack-private.h b/lib/conntrack-private.h

>>index 4743dc6..d5d5e52 100644

>>--- a/lib/conntrack-private.h

>>+++ b/lib/conntrack-private.h

>>@@ -22,6 +22,7 @@

>> #include <netinet/ip6.h>

>> 

>> #include "conntrack.h"

>>+#include "ct-dpif.h"

>> #include "hmap.h"

>> #include "openvswitch/list.h"

>> #include "openvswitch/types.h"

>>@@ -75,6 +76,8 @@ struct ct_l4_proto {

>>                                       struct conntrack_bucket *,

>>                                       struct dp_packet *pkt, bool reply,

>>                                       long long now);

>>+    void (*conn_get_protoinfo)(const struct conn *,

>>+                               struct ct_dpif_protoinfo *);

>> };

>> 

>> extern struct ct_l4_proto ct_proto_tcp;

>>diff --git a/lib/conntrack-tcp.c b/lib/conntrack-tcp.c

>>index 71eadc1..947e1c9 100644

>>--- a/lib/conntrack-tcp.c

>>+++ b/lib/conntrack-tcp.c

>>@@ -457,8 +457,42 @@ tcp_new_conn(struct conntrack_bucket *ctb, struct

>>dp_packet *pkt,

>>     return &newconn->up;

>> }

>> 

>>+static uint8_t

>>+tcp_peer_to_protoinfo_flags(const struct tcp_peer *peer)

>>+{

>>+    uint8_t res = 0;

>>+

>>+    if (peer->wscale & CT_WSCALE_FLAG) {

>>+        res |= CT_DPIF_TCPF_WINDOW_SCALE;

>>+    }

>>+

>>+    if (peer->wscale & CT_WSCALE_UNKNOWN) {

>>+        res |= CT_DPIF_TCPF_BE_LIBERAL;

>>+    }

>>+

>>+    return res;

>>+}

>>+

>>+static void

>>+tcp_conn_get_protoinfo(const struct conn *conn_,

>>+                       struct ct_dpif_protoinfo *protoinfo)

>>+{

>>+    const struct conn_tcp *conn = conn_tcp_cast(conn_);

>>+

>>+    protoinfo->proto = IPPROTO_TCP;

>>+    protoinfo->tcp.state_orig = conn->peer[0].state;

>>+    protoinfo->tcp.state_reply = conn->peer[1].state;

>>+

>>+    protoinfo->tcp.wscale_orig = conn->peer[0].wscale & CT_WSCALE_MASK;

>>+    protoinfo->tcp.wscale_reply = conn->peer[1].wscale & CT_WSCALE_MASK;

>>+

>>+    protoinfo->tcp.flags_orig =

>>tcp_peer_to_protoinfo_flags(&conn->peer[0]);

>>+    protoinfo->tcp.flags_reply =

>>tcp_peer_to_protoinfo_flags(&conn->peer[0]);

>

>Sai: Shouldn¹t the reply be tcp_peer_to_protoinfo_flags(&conn->peer[1]);

>

>

>>+}

>>+

>> struct ct_l4_proto ct_proto_tcp = {

>>     .new_conn = tcp_new_conn,

>>     .valid_new = tcp_valid_new,

>>     .conn_update = tcp_conn_update,

>>+    .conn_get_protoinfo = tcp_conn_get_protoinfo,

>> };

>>diff --git a/lib/conntrack.c b/lib/conntrack.c

>>index 5376550..6e59375 100644

>>--- a/lib/conntrack.c

>>+++ b/lib/conntrack.c

>>@@ -26,6 +26,7 @@

>> #include "conntrack-private.h"

>> #include "coverage.h"

>> #include "csum.h"

>>+#include "ct-dpif.h"

>> #include "dp-packet.h"

>> #include "flow.h"

>> #include "hmap.h"

>>@@ -1048,3 +1049,125 @@ delete_conn(struct conn *conn)

>> {

>>     free(conn);

>> }

>>+?

>>+static void

>>+ct_endpoint_to_ct_dpif_inet_addr(const struct ct_addr *a,

>>+                                 union ct_dpif_inet_addr *b,

>>+                                 ovs_be16 dl_type)

>>+{

>>+    if (dl_type == htons(ETH_TYPE_IP)) {

>>+        b->ip = a->ipv4_aligned;

>>+    } else if (dl_type == htons(ETH_TYPE_IPV6)){

>>+        b->in6 = a->ipv6_aligned;

>>+    }

>>+}

>>+

>>+static void

>>+conn_key_to_tuple(const struct conn_key *key, struct ct_dpif_tuple

>>*tuple)

>>+{

>>+    if (key->dl_type == htons(ETH_TYPE_IP)) {

>>+        tuple->l3_type = AF_INET;

>>+    } else if (key->dl_type == htons(ETH_TYPE_IPV6)) {

>>+        tuple->l3_type = AF_INET6;

>>+    }

>>+    tuple->ip_proto = key->nw_proto;

>>+    ct_endpoint_to_ct_dpif_inet_addr(&key->src.addr, &tuple->src,

>>+                                     key->dl_type);

>>+    ct_endpoint_to_ct_dpif_inet_addr(&key->dst.addr, &tuple->dst,

>>+                                     key->dl_type);

>>+

>>+    if (key->nw_proto == IPPROTO_ICMP || key->nw_proto ==

>>IPPROTO_ICMPV6) {

>>+        tuple->icmp_id = key->src.port;

>>+        /* ICMP type and code are not tracked */

>>+        tuple->icmp_type = 0;

>>+        tuple->icmp_code = 0;

>>+    } else {

>>+        tuple->src_port = key->src.port;

>>+        tuple->dst_port = key->dst.port;

>>+    }

>>+}

>>+

>>+static void

>>+conn_to_ct_dpif_entry(const struct conn *conn, struct ct_dpif_entry

>>*entry,

>>+                      long long now)

>>+{

>>+    struct ct_l4_proto *class;

>>+    long long expiration;

>>+    memset(entry, 0, sizeof *entry);

>>+    conn_key_to_tuple(&conn->key, &entry->tuple_orig);

>>+    conn_key_to_tuple(&conn->rev_key, &entry->tuple_reply);

>>+

>>+    entry->zone = conn->key.zone;

>>+    entry->mark = conn->mark;

>>+

>>+    memcpy(&entry->labels, &conn->label, sizeof(entry->labels));

>>+    /* Not implemented yet */

>>+    entry->timestamp.start = 0;

>>+    entry->timestamp.stop = 0;

>>+

>>+    expiration = conn->expiration - now;

>>+    entry->timeout = (expiration > 0) ? expiration / 1000 : 0;

>>+

>>+    class = l4_protos[conn->key.nw_proto];

>>+    if (class->conn_get_protoinfo) {

>>+        class->conn_get_protoinfo(conn, &entry->protoinfo);

>>+    }

>>+}

>>+

>>+int

>>+conntrack_dump_start(struct conntrack *ct, struct conntrack_dump *dump,

>>+                     const uint16_t *pzone)

>>+{

>>+    memset(dump, 0, sizeof(*dump));

>>+    if (pzone) {

>>+        dump->zone = *pzone;

>>+        dump->filter_zone = true;

>>+    }

>>+    dump->ct = ct;

>>+

>>+    return 0;

>>+}

>>+

>>+int

>>+conntrack_dump_next(struct conntrack_dump *dump, struct ct_dpif_entry

>>*entry)

>>+{

>>+    struct conntrack *ct = dump->ct;

>>+    long long now = time_msec();

>>+

>>+    while (dump->bucket < CONNTRACK_BUCKETS) {

>>+        struct hmap_node *node;

>>+

>>+        ct_lock_lock(&ct->buckets[dump->bucket].lock);

>>+        for (;;) {

>>+            struct conn *conn;

>>+

>>+            node =

>>hmap_at_position(&ct->buckets[dump->bucket].connections,

>>+                                    &dump->bucket_pos);

>>+            if (!node) {

>>+                break;

>>+            }

>>+            INIT_CONTAINER(conn, node, node);

>>+            if (!dump->filter_zone || conn->key.zone == dump->zone) {

>>+                conn_to_ct_dpif_entry(conn, entry, now);

>>+                break;

>>+            }

>>+            /* Else continue, until we find an entry in the appropriate

>>zone

>>+             * or the bucket has been scanned completely. */

>>+        }

>>+        ct_lock_unlock(&ct->buckets[dump->bucket].lock);

>>+

>>+        if (!node) {

>>+            memset(&dump->bucket_pos, 0, sizeof dump->bucket_pos);

>>+            dump->bucket++;

>>+        } else {

>>+            return 0;

>>+        }

>>+    }

>>+    return EOF;

>>+}

>>+

>>+int

>>+conntrack_dump_done(struct conntrack_dump *dump OVS_UNUSED)

>>+{

>>+    return 0;

>>+}

>>diff --git a/lib/conntrack.h b/lib/conntrack.h

>>index 29bf4b7..eba3ae9 100644

>>--- a/lib/conntrack.h

>>+++ b/lib/conntrack.h

>>@@ -68,6 +68,21 @@ int conntrack_execute(struct conntrack *, struct

>>dp_packet_batch *,

>>                       bool commit, uint16_t zone, const uint32_t

>>*setmark,

>>                       const struct ovs_key_ct_labels *setlabel,

>>                       const char *helper);

>>+

>>+struct conntrack_dump {

>>+    struct conntrack *ct;

>>+    unsigned bucket;

>>+    struct hmap_position bucket_pos;

>>+    bool filter_zone;

>>+    uint16_t zone;

>>+};

>>+

>>+struct ct_dpif_entry;

>>+

>>+int conntrack_dump_start(struct conntrack *, struct conntrack_dump *,

>>+                         const uint16_t *pzone);

>>+int conntrack_dump_next(struct conntrack_dump *, struct ct_dpif_entry *);

>>+int conntrack_dump_done(struct conntrack_dump *);

>> ?

>> /* 'struct ct_lock' is a wrapper for an adaptive mutex.  It's useful to

>>try

>>  * different types of locks (e.g. spinlocks) */

>>diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c

>>index 48ec987..910ada3 100644

>>--- a/lib/dpif-netdev.c

>>+++ b/lib/dpif-netdev.c

>>@@ -35,6 +35,7 @@

>> #include "cmap.h"

>> #include "conntrack.h"

>> #include "coverage.h"

>>+#include "ct-dpif.h"

>> #include "csum.h"

>> #include "dp-packet.h"

>> #include "dpif.h"

>>@@ -4227,6 +4228,59 @@ dp_netdev_execute_actions(struct

>>dp_netdev_pmd_thread *pmd,

>>                         actions_len, dp_execute_cb);

>> }

>> 

>>+struct dp_netdev_ct_dump {

>>+    struct ct_dpif_dump_state up;

>>+    struct conntrack_dump dump;

>>+    struct conntrack *ct;

>>+    struct dp_netdev *dp;

>>+};

>>+

>>+static int

>>+dpif_netdev_ct_dump_start(struct dpif *dpif, struct ct_dpif_dump_state

>>**dump_,

>>+                          const uint16_t *pzone)

>>+{

>>+    struct dp_netdev *dp = get_dp_netdev(dpif);

>>+    struct dp_netdev_ct_dump *dump;

>>+

>>+    dump = xzalloc(sizeof *dump);

>>+    dump->dp = dp;

>>+    dump->ct = &dp->conntrack;

>>+

>>+    conntrack_dump_start(&dp->conntrack, &dump->dump, pzone);

>>+

>>+    *dump_ = &dump->up;

>>+

>>+    return 0;

>>+}

>>+

>>+static int

>>+dpif_netdev_ct_dump_next(struct dpif *dpif OVS_UNUSED,

>>+                         struct ct_dpif_dump_state *dump_,

>>+                         struct ct_dpif_entry *entry)

>>+{

>>+    struct dp_netdev_ct_dump *dump;

>>+

>>+    INIT_CONTAINER(dump, dump_, up);

>>+

>>+    return conntrack_dump_next(&dump->dump, entry);

>>+}

>>+

>>+static int

>>+dpif_netdev_ct_dump_done(struct dpif *dpif OVS_UNUSED,

>>+                         struct ct_dpif_dump_state *dump_)

>>+{

>>+    struct dp_netdev_ct_dump *dump;

>>+    int err;

>>+

>>+    INIT_CONTAINER(dump, dump_, up);

>>+

>>+    err = conntrack_dump_done(&dump->dump);

>>+

>>+    free(dump);

>>+

>>+    return err;

>>+}

>>+

>> const struct dpif_class dpif_netdev_class = {

>>     "netdev",

>>     dpif_netdev_init,

>>@@ -4267,9 +4321,9 @@ const struct dpif_class dpif_netdev_class = {

>>     dpif_netdev_enable_upcall,

>>     dpif_netdev_disable_upcall,

>>     dpif_netdev_get_datapath_version,

>>-    NULL,                       /* ct_dump_start */

>>-    NULL,                       /* ct_dump_next */

>>-    NULL,                       /* ct_dump_done */

>>+    dpif_netdev_ct_dump_start,

>>+    dpif_netdev_ct_dump_next,

>>+    dpif_netdev_ct_dump_done,

>>     NULL,                       /* ct_flush */

>> };

>> 

>>-- 

>>2.8.1

>>

>>_______________________________________________

>>dev mailing list

>>dev@openvswitch.org

>>https://urldefense.proofpoint.com/v2/url?u=http-3A__openvswitch.org_mailma

>>n_listinfo_dev&d=CwIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-YihVMNtXt-uEs&r=Dc

>>ruz40PROJ40ROzSpxyQSLw6fcrOWpJgEcEmNR3JEQ&m=tNe8IQ972ivdkXYe_yHze175Gvfnc8

>>nkzR8IOYekTsY&s=27fwP-jORLNBENHqlEC-4Ozf8gkYCcKr-5uxM9C3OBE&e= 

>
diff mbox

Patch

diff --git a/lib/conntrack-private.h b/lib/conntrack-private.h
index 4743dc6..d5d5e52 100644
--- a/lib/conntrack-private.h
+++ b/lib/conntrack-private.h
@@ -22,6 +22,7 @@ 
 #include <netinet/ip6.h>
 
 #include "conntrack.h"
+#include "ct-dpif.h"
 #include "hmap.h"
 #include "openvswitch/list.h"
 #include "openvswitch/types.h"
@@ -75,6 +76,8 @@  struct ct_l4_proto {
                                       struct conntrack_bucket *,
                                       struct dp_packet *pkt, bool reply,
                                       long long now);
+    void (*conn_get_protoinfo)(const struct conn *,
+                               struct ct_dpif_protoinfo *);
 };
 
 extern struct ct_l4_proto ct_proto_tcp;
diff --git a/lib/conntrack-tcp.c b/lib/conntrack-tcp.c
index 71eadc1..947e1c9 100644
--- a/lib/conntrack-tcp.c
+++ b/lib/conntrack-tcp.c
@@ -457,8 +457,42 @@  tcp_new_conn(struct conntrack_bucket *ctb, struct dp_packet *pkt,
     return &newconn->up;
 }
 
+static uint8_t
+tcp_peer_to_protoinfo_flags(const struct tcp_peer *peer)
+{
+    uint8_t res = 0;
+
+    if (peer->wscale & CT_WSCALE_FLAG) {
+        res |= CT_DPIF_TCPF_WINDOW_SCALE;
+    }
+
+    if (peer->wscale & CT_WSCALE_UNKNOWN) {
+        res |= CT_DPIF_TCPF_BE_LIBERAL;
+    }
+
+    return res;
+}
+
+static void
+tcp_conn_get_protoinfo(const struct conn *conn_,
+                       struct ct_dpif_protoinfo *protoinfo)
+{
+    const struct conn_tcp *conn = conn_tcp_cast(conn_);
+
+    protoinfo->proto = IPPROTO_TCP;
+    protoinfo->tcp.state_orig = conn->peer[0].state;
+    protoinfo->tcp.state_reply = conn->peer[1].state;
+
+    protoinfo->tcp.wscale_orig = conn->peer[0].wscale & CT_WSCALE_MASK;
+    protoinfo->tcp.wscale_reply = conn->peer[1].wscale & CT_WSCALE_MASK;
+
+    protoinfo->tcp.flags_orig = tcp_peer_to_protoinfo_flags(&conn->peer[0]);
+    protoinfo->tcp.flags_reply = tcp_peer_to_protoinfo_flags(&conn->peer[0]);
+}
+
 struct ct_l4_proto ct_proto_tcp = {
     .new_conn = tcp_new_conn,
     .valid_new = tcp_valid_new,
     .conn_update = tcp_conn_update,
+    .conn_get_protoinfo = tcp_conn_get_protoinfo,
 };
diff --git a/lib/conntrack.c b/lib/conntrack.c
index 5376550..6e59375 100644
--- a/lib/conntrack.c
+++ b/lib/conntrack.c
@@ -26,6 +26,7 @@ 
 #include "conntrack-private.h"
 #include "coverage.h"
 #include "csum.h"
+#include "ct-dpif.h"
 #include "dp-packet.h"
 #include "flow.h"
 #include "hmap.h"
@@ -1048,3 +1049,125 @@  delete_conn(struct conn *conn)
 {
     free(conn);
 }
+
+static void
+ct_endpoint_to_ct_dpif_inet_addr(const struct ct_addr *a,
+                                 union ct_dpif_inet_addr *b,
+                                 ovs_be16 dl_type)
+{
+    if (dl_type == htons(ETH_TYPE_IP)) {
+        b->ip = a->ipv4_aligned;
+    } else if (dl_type == htons(ETH_TYPE_IPV6)){
+        b->in6 = a->ipv6_aligned;
+    }
+}
+
+static void
+conn_key_to_tuple(const struct conn_key *key, struct ct_dpif_tuple *tuple)
+{
+    if (key->dl_type == htons(ETH_TYPE_IP)) {
+        tuple->l3_type = AF_INET;
+    } else if (key->dl_type == htons(ETH_TYPE_IPV6)) {
+        tuple->l3_type = AF_INET6;
+    }
+    tuple->ip_proto = key->nw_proto;
+    ct_endpoint_to_ct_dpif_inet_addr(&key->src.addr, &tuple->src,
+                                     key->dl_type);
+    ct_endpoint_to_ct_dpif_inet_addr(&key->dst.addr, &tuple->dst,
+                                     key->dl_type);
+
+    if (key->nw_proto == IPPROTO_ICMP || key->nw_proto == IPPROTO_ICMPV6) {
+        tuple->icmp_id = key->src.port;
+        /* ICMP type and code are not tracked */
+        tuple->icmp_type = 0;
+        tuple->icmp_code = 0;
+    } else {
+        tuple->src_port = key->src.port;
+        tuple->dst_port = key->dst.port;
+    }
+}
+
+static void
+conn_to_ct_dpif_entry(const struct conn *conn, struct ct_dpif_entry *entry,
+                      long long now)
+{
+    struct ct_l4_proto *class;
+    long long expiration;
+    memset(entry, 0, sizeof *entry);
+    conn_key_to_tuple(&conn->key, &entry->tuple_orig);
+    conn_key_to_tuple(&conn->rev_key, &entry->tuple_reply);
+
+    entry->zone = conn->key.zone;
+    entry->mark = conn->mark;
+
+    memcpy(&entry->labels, &conn->label, sizeof(entry->labels));
+    /* Not implemented yet */
+    entry->timestamp.start = 0;
+    entry->timestamp.stop = 0;
+
+    expiration = conn->expiration - now;
+    entry->timeout = (expiration > 0) ? expiration / 1000 : 0;
+
+    class = l4_protos[conn->key.nw_proto];
+    if (class->conn_get_protoinfo) {
+        class->conn_get_protoinfo(conn, &entry->protoinfo);
+    }
+}
+
+int
+conntrack_dump_start(struct conntrack *ct, struct conntrack_dump *dump,
+                     const uint16_t *pzone)
+{
+    memset(dump, 0, sizeof(*dump));
+    if (pzone) {
+        dump->zone = *pzone;
+        dump->filter_zone = true;
+    }
+    dump->ct = ct;
+
+    return 0;
+}
+
+int
+conntrack_dump_next(struct conntrack_dump *dump, struct ct_dpif_entry *entry)
+{
+    struct conntrack *ct = dump->ct;
+    long long now = time_msec();
+
+    while (dump->bucket < CONNTRACK_BUCKETS) {
+        struct hmap_node *node;
+
+        ct_lock_lock(&ct->buckets[dump->bucket].lock);
+        for (;;) {
+            struct conn *conn;
+
+            node = hmap_at_position(&ct->buckets[dump->bucket].connections,
+                                    &dump->bucket_pos);
+            if (!node) {
+                break;
+            }
+            INIT_CONTAINER(conn, node, node);
+            if (!dump->filter_zone || conn->key.zone == dump->zone) {
+                conn_to_ct_dpif_entry(conn, entry, now);
+                break;
+            }
+            /* Else continue, until we find an entry in the appropriate zone
+             * or the bucket has been scanned completely. */
+        }
+        ct_lock_unlock(&ct->buckets[dump->bucket].lock);
+
+        if (!node) {
+            memset(&dump->bucket_pos, 0, sizeof dump->bucket_pos);
+            dump->bucket++;
+        } else {
+            return 0;
+        }
+    }
+    return EOF;
+}
+
+int
+conntrack_dump_done(struct conntrack_dump *dump OVS_UNUSED)
+{
+    return 0;
+}
diff --git a/lib/conntrack.h b/lib/conntrack.h
index 29bf4b7..eba3ae9 100644
--- a/lib/conntrack.h
+++ b/lib/conntrack.h
@@ -68,6 +68,21 @@  int conntrack_execute(struct conntrack *, struct dp_packet_batch *,
                       bool commit, uint16_t zone, const uint32_t *setmark,
                       const struct ovs_key_ct_labels *setlabel,
                       const char *helper);
+
+struct conntrack_dump {
+    struct conntrack *ct;
+    unsigned bucket;
+    struct hmap_position bucket_pos;
+    bool filter_zone;
+    uint16_t zone;
+};
+
+struct ct_dpif_entry;
+
+int conntrack_dump_start(struct conntrack *, struct conntrack_dump *,
+                         const uint16_t *pzone);
+int conntrack_dump_next(struct conntrack_dump *, struct ct_dpif_entry *);
+int conntrack_dump_done(struct conntrack_dump *);
 
 /* 'struct ct_lock' is a wrapper for an adaptive mutex.  It's useful to try
  * different types of locks (e.g. spinlocks) */
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 48ec987..910ada3 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -35,6 +35,7 @@ 
 #include "cmap.h"
 #include "conntrack.h"
 #include "coverage.h"
+#include "ct-dpif.h"
 #include "csum.h"
 #include "dp-packet.h"
 #include "dpif.h"
@@ -4227,6 +4228,59 @@  dp_netdev_execute_actions(struct dp_netdev_pmd_thread *pmd,
                         actions_len, dp_execute_cb);
 }
 
+struct dp_netdev_ct_dump {
+    struct ct_dpif_dump_state up;
+    struct conntrack_dump dump;
+    struct conntrack *ct;
+    struct dp_netdev *dp;
+};
+
+static int
+dpif_netdev_ct_dump_start(struct dpif *dpif, struct ct_dpif_dump_state **dump_,
+                          const uint16_t *pzone)
+{
+    struct dp_netdev *dp = get_dp_netdev(dpif);
+    struct dp_netdev_ct_dump *dump;
+
+    dump = xzalloc(sizeof *dump);
+    dump->dp = dp;
+    dump->ct = &dp->conntrack;
+
+    conntrack_dump_start(&dp->conntrack, &dump->dump, pzone);
+
+    *dump_ = &dump->up;
+
+    return 0;
+}
+
+static int
+dpif_netdev_ct_dump_next(struct dpif *dpif OVS_UNUSED,
+                         struct ct_dpif_dump_state *dump_,
+                         struct ct_dpif_entry *entry)
+{
+    struct dp_netdev_ct_dump *dump;
+
+    INIT_CONTAINER(dump, dump_, up);
+
+    return conntrack_dump_next(&dump->dump, entry);
+}
+
+static int
+dpif_netdev_ct_dump_done(struct dpif *dpif OVS_UNUSED,
+                         struct ct_dpif_dump_state *dump_)
+{
+    struct dp_netdev_ct_dump *dump;
+    int err;
+
+    INIT_CONTAINER(dump, dump_, up);
+
+    err = conntrack_dump_done(&dump->dump);
+
+    free(dump);
+
+    return err;
+}
+
 const struct dpif_class dpif_netdev_class = {
     "netdev",
     dpif_netdev_init,
@@ -4267,9 +4321,9 @@  const struct dpif_class dpif_netdev_class = {
     dpif_netdev_enable_upcall,
     dpif_netdev_disable_upcall,
     dpif_netdev_get_datapath_version,
-    NULL,                       /* ct_dump_start */
-    NULL,                       /* ct_dump_next */
-    NULL,                       /* ct_dump_done */
+    dpif_netdev_ct_dump_start,
+    dpif_netdev_ct_dump_next,
+    dpif_netdev_ct_dump_done,
     NULL,                       /* ct_flush */
 };