QEMU-Devel Archive on lore.kernel.org
 help / color / Atom feed
* [PATCH V6 0/6] Passthrough specific network traffic in COLO
@ 2021-04-20 15:15 Zhang Chen
  2021-04-20 15:15 ` [PATCH V6 1/6] qapi/net: Add IPFlowSpec and QMP command for COLO passthrough Zhang Chen
                   ` (6 more replies)
  0 siblings, 7 replies; 13+ messages in thread
From: Zhang Chen @ 2021-04-20 15:15 UTC (permalink / raw)
  To: Jason Wang, qemu-dev, Eric Blake, Dr. David Alan Gilbert,
	Markus Armbruster, Daniel P. Berrangé,
	Gerd Hoffmann, Li Zhijian
  Cc: Zhang Chen, Lukas Straub, Zhang Chen

Due to some real user scenarios don't need to monitor all traffic.
And qemu net-filter also need function to more detailed flow control.
This series give user ability to passthrough kinds of COLO network stream.

For example, windows guest user want to enable windows remote desktop
to touch guest(UDP/TCP 3389), This case use UDP and TCP mixed, and the
tcp part payload always different caused by real desktop display
data(for guest time/ mouse display....).

Another case is some real user application will actively transmit information
include guest time part, primary guest send data with time 10:01.000,
At the same time secondary guest send data with time 10:01.001,
it will always trigger COLO checkpoint(live migrate) to drop guest performance.

  V6:
    - Change QAPI IPFlowSpec protocol from enum to str.
    - Use getprotobyname to handle the protocols.
    - Optimize code in net.

  V5:
    - Squash original 1-3 QAPI patches together.
    - Rename some data structures to avoid misunderstanding.
    - Reuse InetSocketAddressBase in IPFlowSpec.
    - Add new function in util/qemu-sockets.c to parse
      InetSocketAddressBase.
    - Update HMP command define to reuse current code.
    - Add more comments.

  V4:
    - Fix QAPI code conflict for V6.0 merged patches.
    - Note this feature for V6.1.

  V3:
    - Add COLO passthrough list lock.
    - Add usage demo and more comments.

  V2:
    - Add the n-tuple support.
    - Add some qapi definitions.
    - Support multi colo-compare objects.
    - Support setup each rules for each objects individually.
    - Clean up COLO compare definition to .h file.
    - Rebase HMP command for stable tree.
    - Add redundant rules check.


Zhang Chen (6):
  qapi/net: Add IPFlowSpec and QMP command for COLO passthrough
  util/qemu-sockets.c: Add inet_parse_base to handle
    InetSocketAddressBase
  hmp-commands: Add new HMP command for COLO passthrough
  net/colo-compare: Move data structure and define to .h file.
  net/colo-compare: Add passthrough list to CompareState
  net/net.c: Add handler for COLO passthrough connection

 hmp-commands.hx        |  26 +++++++
 include/monitor/hmp.h  |   2 +
 include/qemu/sockets.h |   1 +
 monitor/hmp-cmds.c     |  82 ++++++++++++++++++++
 net/colo-compare.c     | 162 +++++++++++-----------------------------
 net/colo-compare.h     | 118 +++++++++++++++++++++++++++++
 net/net.c              | 166 +++++++++++++++++++++++++++++++++++++++++
 qapi/net.json          |  68 +++++++++++++++++
 util/qemu-sockets.c    |  14 ++++
 9 files changed, 519 insertions(+), 120 deletions(-)

-- 
2.25.1



^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH V6 1/6] qapi/net: Add IPFlowSpec and QMP command for COLO passthrough
  2021-04-20 15:15 [PATCH V6 0/6] Passthrough specific network traffic in COLO Zhang Chen
@ 2021-04-20 15:15 ` Zhang Chen
  2021-05-17 20:34   ` Lukas Straub
  2021-04-20 15:15 ` [PATCH V6 2/6] util/qemu-sockets.c: Add inet_parse_base to handle InetSocketAddressBase Zhang Chen
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 13+ messages in thread
From: Zhang Chen @ 2021-04-20 15:15 UTC (permalink / raw)
  To: Jason Wang, qemu-dev, Eric Blake, Dr. David Alan Gilbert,
	Markus Armbruster, Daniel P. Berrangé,
	Gerd Hoffmann, Li Zhijian
  Cc: Zhang Chen, Lukas Straub, Zhang Chen

Since the real user scenario does not need COLO to monitor all traffic.
Add colo-passthrough-add and colo-passthrough-del to maintain
a COLO network passthrough list. Add IPFlowSpec struct for all QMP commands.
Except protocol field is necessary, other fields are optional.

Signed-off-by: Zhang Chen <chen.zhang@intel.com>
---
 net/net.c     | 10 ++++++++
 qapi/net.json | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 78 insertions(+)

diff --git a/net/net.c b/net/net.c
index edf9b95418..2a6e5f3886 100644
--- a/net/net.c
+++ b/net/net.c
@@ -1196,6 +1196,16 @@ void qmp_netdev_del(const char *id, Error **errp)
     }
 }
 
+void qmp_colo_passthrough_add(IPFlowSpec *spec, Error **errp)
+{
+    /* TODO implement setup passthrough rule */
+}
+
+void qmp_colo_passthrough_del(IPFlowSpec *spec, Error **errp)
+{
+    /* TODO implement delete passthrough rule */
+}
+
 static void netfilter_print_info(Monitor *mon, NetFilterState *nf)
 {
     char *str;
diff --git a/qapi/net.json b/qapi/net.json
index af3f5b0fda..f6e4e37526 100644
--- a/qapi/net.json
+++ b/qapi/net.json
@@ -7,6 +7,7 @@
 ##
 
 { 'include': 'common.json' }
+{ 'include': 'sockets.json' }
 
 ##
 # @set_link:
@@ -694,3 +695,70 @@
 ##
 { 'event': 'FAILOVER_NEGOTIATED',
   'data': {'device-id': 'str'} }
+
+##
+# @IPFlowSpec:
+#
+# IP flow specification.
+#
+# @protocol: Transport layer protocol like TCP/UDP...
+#
+# @object-name: Point out the IPflow spec effective range of object,
+#               If there is no such part, it means global spec.
+#
+# @source: Source address and port.
+#
+# @destination: Destination address and port.
+#
+# Since: 6.1
+##
+{ 'struct': 'IPFlowSpec',
+  'data': { 'protocol': 'str', '*object-name': 'str',
+    '*source': 'InetSocketAddressBase',
+    '*destination': 'InetSocketAddressBase' } }
+
+##
+# @colo-passthrough-add:
+#
+# Add passthrough entry according to user's needs in COLO-compare.
+# Source IP/port and destination IP/port both optional, If user just
+# input parts of infotmation, it will match all.
+#
+# Returns: Nothing on success
+#
+# Since: 6.1
+#
+# Example:
+#
+# -> { "execute": "colo-passthrough-add",
+#      "arguments": { "protocol": "tcp", "object-name": "object0",
+#      "source": {"host": "192.168.1.1", "port": "1234"},
+#      "destination": {"host": "192.168.1.2", "port": "4321"} } }
+# <- { "return": {} }
+#
+##
+{ 'command': 'colo-passthrough-add', 'boxed': true,
+     'data': 'IPFlowSpec' }
+
+##
+# @colo-passthrough-del:
+#
+# Delete passthrough entry according to user's needs in COLO-compare.
+# Source IP/port and destination IP/port both optional, If user just
+# input parts of infotmation, it will match all.
+#
+# Returns: Nothing on success
+#
+# Since: 6.1
+#
+# Example:
+#
+# -> { "execute": "colo-passthrough-del",
+#      "arguments": { "protocol": "tcp", "object-name": "object0",
+#      "source": {"host": "192.168.1.1", "port": "1234"},
+#      "destination": {"host": "192.168.1.2", "port": "4321"} } }
+# <- { "return": {} }
+#
+##
+{ 'command': 'colo-passthrough-del', 'boxed': true,
+     'data': 'IPFlowSpec' }
-- 
2.25.1



^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH V6 2/6] util/qemu-sockets.c: Add inet_parse_base to handle InetSocketAddressBase
  2021-04-20 15:15 [PATCH V6 0/6] Passthrough specific network traffic in COLO Zhang Chen
  2021-04-20 15:15 ` [PATCH V6 1/6] qapi/net: Add IPFlowSpec and QMP command for COLO passthrough Zhang Chen
@ 2021-04-20 15:15 ` Zhang Chen
  2021-04-20 15:15 ` [PATCH V6 3/6] hmp-commands: Add new HMP command for COLO passthrough Zhang Chen
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Zhang Chen @ 2021-04-20 15:15 UTC (permalink / raw)
  To: Jason Wang, qemu-dev, Eric Blake, Dr. David Alan Gilbert,
	Markus Armbruster, Daniel P. Berrangé,
	Gerd Hoffmann, Li Zhijian
  Cc: Zhang Chen, Lukas Straub, Zhang Chen

No need to carry the flag all the time in many scenarios.

Signed-off-by: Zhang Chen <chen.zhang@intel.com>
---
 include/qemu/sockets.h |  1 +
 util/qemu-sockets.c    | 14 ++++++++++++++
 2 files changed, 15 insertions(+)

diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h
index 7d1f813576..d5abc227eb 100644
--- a/include/qemu/sockets.h
+++ b/include/qemu/sockets.h
@@ -32,6 +32,7 @@ int socket_set_fast_reuse(int fd);
 int inet_ai_family_from_address(InetSocketAddress *addr,
                                 Error **errp);
 int inet_parse(InetSocketAddress *addr, const char *str, Error **errp);
+int inet_parse_base(InetSocketAddressBase *addr, const char *str, Error **errp);
 int inet_connect(const char *str, Error **errp);
 int inet_connect_saddr(InetSocketAddress *saddr, Error **errp);
 
diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c
index 8af0278f15..c16eba1917 100644
--- a/util/qemu-sockets.c
+++ b/util/qemu-sockets.c
@@ -690,6 +690,20 @@ int inet_parse(InetSocketAddress *addr, const char *str, Error **errp)
     return 0;
 }
 
+int inet_parse_base(InetSocketAddressBase *base, const char *str, Error **errp)
+{
+    InetSocketAddress *addr;
+    int ret = 0;
+
+    addr = g_new0(InetSocketAddress, 1);
+    ret = inet_parse(addr, str, errp);
+
+    base->host = addr->host;
+    base->port = addr->port;
+
+    g_free(addr);
+    return ret;
+}
 
 /**
  * Create a blocking socket and connect it to an address.
-- 
2.25.1



^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH V6 3/6] hmp-commands: Add new HMP command for COLO passthrough
  2021-04-20 15:15 [PATCH V6 0/6] Passthrough specific network traffic in COLO Zhang Chen
  2021-04-20 15:15 ` [PATCH V6 1/6] qapi/net: Add IPFlowSpec and QMP command for COLO passthrough Zhang Chen
  2021-04-20 15:15 ` [PATCH V6 2/6] util/qemu-sockets.c: Add inet_parse_base to handle InetSocketAddressBase Zhang Chen
@ 2021-04-20 15:15 ` Zhang Chen
  2021-04-20 15:15 ` [PATCH V6 4/6] net/colo-compare: Move data structure and define to .h file Zhang Chen
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Zhang Chen @ 2021-04-20 15:15 UTC (permalink / raw)
  To: Jason Wang, qemu-dev, Eric Blake, Dr. David Alan Gilbert,
	Markus Armbruster, Daniel P. Berrangé,
	Gerd Hoffmann, Li Zhijian
  Cc: Zhang Chen, Lukas Straub, Zhang Chen

Add hmp_colo_passthrough_add and hmp_colo_passthrough_del make user
can maintain COLO network passthrough list in human monitor

Signed-off-by: Zhang Chen <chen.zhang@intel.com>
---
 hmp-commands.hx       | 26 ++++++++++++++
 include/monitor/hmp.h |  2 ++
 monitor/hmp-cmds.c    | 82 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 110 insertions(+)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index 435c591a1c..cbb08623c7 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1290,6 +1290,32 @@ SRST
   Remove host network device.
 ERST
 
+    {
+        .name       = "colo_passthrough_add",
+        .args_type  = "protocol:s,object-name:s?,src:s?,dst:s?",
+        .params     = "protocol [object-name] [src] [dst]",
+        .help       = "Add network stream to colo passthrough list",
+        .cmd        = hmp_colo_passthrough_add,
+    },
+
+SRST
+``colo_passthrough_add``
+  Add network stream to colo passthrough list.
+ERST
+
+    {
+        .name       = "colo_passthrough_del",
+        .args_type  = "protocol:s,object-name:s?,src:s?,dst:s?",
+        .params     = "protocol [object-name] [src] [dst]",
+        .help       = "Delete network stream from colo passthrough list",
+        .cmd        = hmp_colo_passthrough_del,
+    },
+
+SRST
+``colo_passthrough_del``
+  Delete network stream from colo passthrough list.
+ERST
+
     {
         .name       = "object_add",
         .args_type  = "object:S",
diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h
index 605d57287a..a784f98531 100644
--- a/include/monitor/hmp.h
+++ b/include/monitor/hmp.h
@@ -77,6 +77,8 @@ void hmp_device_del(Monitor *mon, const QDict *qdict);
 void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict);
 void hmp_netdev_add(Monitor *mon, const QDict *qdict);
 void hmp_netdev_del(Monitor *mon, const QDict *qdict);
+void hmp_colo_passthrough_add(Monitor *mon, const QDict *qdict);
+void hmp_colo_passthrough_del(Monitor *mon, const QDict *qdict);
 void hmp_getfd(Monitor *mon, const QDict *qdict);
 void hmp_closefd(Monitor *mon, const QDict *qdict);
 void hmp_sendkey(Monitor *mon, const QDict *qdict);
diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
index 0ad5b77477..6991b03075 100644
--- a/monitor/hmp-cmds.c
+++ b/monitor/hmp-cmds.c
@@ -1634,6 +1634,88 @@ void hmp_netdev_del(Monitor *mon, const QDict *qdict)
     hmp_handle_error(mon, err);
 }
 
+void hmp_colo_passthrough_add(Monitor *mon, const QDict *qdict)
+{
+    IPFlowSpec *spec = g_new0(IPFlowSpec, 1);
+    char *src, *dst;
+    Error *err = NULL;
+
+    spec->protocol = g_strdup(qdict_get_try_str(qdict, "protocol"));
+    spec->object_name = g_strdup(qdict_get_try_str(qdict, "object-name"));
+
+    src = g_strdup(qdict_get_try_str(qdict, "src"));
+    if (src) {
+        spec->source = g_new0(InetSocketAddressBase, 1);
+
+        if (inet_parse_base(spec->source, src, NULL)) {
+            monitor_printf(mon, "bad colo passthrough src address");
+            goto out;
+        }
+    }
+
+    dst = g_strdup(qdict_get_try_str(qdict, "dst"));
+    if (dst) {
+        spec->destination = g_new0(InetSocketAddressBase, 1);
+
+        if (inet_parse_base(spec->destination, dst, NULL)) {
+            monitor_printf(mon, "bad colo passthrough dst address");
+            goto out;
+        }
+    }
+
+    qmp_colo_passthrough_add(spec, &err);
+
+out:
+    g_free(src);
+    src = NULL;
+
+    g_free(dst);
+    dst = NULL;
+
+    hmp_handle_error(mon, err);
+}
+
+void hmp_colo_passthrough_del(Monitor *mon, const QDict *qdict)
+{
+    IPFlowSpec *spec = g_new0(IPFlowSpec, 1);
+    char *src, *dst;
+    Error *err = NULL;
+
+    spec->protocol = g_strdup(qdict_get_try_str(qdict, "protocol"));
+    spec->object_name = g_strdup(qdict_get_try_str(qdict, "object-name"));
+
+    src = g_strdup(qdict_get_try_str(qdict, "src"));
+    if (src) {
+        spec->source = g_new0(InetSocketAddressBase, 1);
+
+        if (inet_parse_base(spec->source, src, NULL)) {
+            monitor_printf(mon, "bad colo passthrough src address");
+            goto out;
+        }
+    }
+
+    dst = g_strdup(qdict_get_try_str(qdict, "dst"));
+    if (dst) {
+        spec->destination = g_new0(InetSocketAddressBase, 1);
+
+        if (inet_parse_base(spec->destination, dst, NULL)) {
+            monitor_printf(mon, "bad colo passthrough dst address");
+            goto out;
+        }
+    }
+
+    qmp_colo_passthrough_del(spec, &err);
+
+out:
+    g_free(src);
+    src = NULL;
+
+    g_free(dst);
+    dst = NULL;
+
+    hmp_handle_error(mon, err);
+}
+
 void hmp_object_add(Monitor *mon, const QDict *qdict)
 {
     const char *options = qdict_get_str(qdict, "object");
-- 
2.25.1



^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH V6 4/6] net/colo-compare: Move data structure and define to .h file.
  2021-04-20 15:15 [PATCH V6 0/6] Passthrough specific network traffic in COLO Zhang Chen
                   ` (2 preceding siblings ...)
  2021-04-20 15:15 ` [PATCH V6 3/6] hmp-commands: Add new HMP command for COLO passthrough Zhang Chen
@ 2021-04-20 15:15 ` Zhang Chen
  2021-05-17 20:03   ` Lukas Straub
  2021-04-20 15:15 ` [PATCH V6 5/6] net/colo-compare: Add passthrough list to CompareState Zhang Chen
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 13+ messages in thread
From: Zhang Chen @ 2021-04-20 15:15 UTC (permalink / raw)
  To: Jason Wang, qemu-dev, Eric Blake, Dr. David Alan Gilbert,
	Markus Armbruster, Daniel P. Berrangé,
	Gerd Hoffmann, Li Zhijian
  Cc: Zhang Chen, Lukas Straub, Zhang Chen

Rename structure with COLO index and move it to .h file,
It make other modules can reuse COLO code.

Signed-off-by: Zhang Chen <chen.zhang@intel.com>
---
 net/colo-compare.c | 134 +++++----------------------------------------
 net/colo-compare.h | 106 +++++++++++++++++++++++++++++++++++
 2 files changed, 120 insertions(+), 120 deletions(-)

diff --git a/net/colo-compare.c b/net/colo-compare.c
index 9d1ad99941..b51b1437ef 100644
--- a/net/colo-compare.c
+++ b/net/colo-compare.c
@@ -17,44 +17,24 @@
 #include "qemu/error-report.h"
 #include "trace.h"
 #include "qapi/error.h"
-#include "net/net.h"
 #include "net/eth.h"
 #include "qom/object_interfaces.h"
 #include "qemu/iov.h"
 #include "qom/object.h"
 #include "net/queue.h"
-#include "chardev/char-fe.h"
 #include "qemu/sockets.h"
-#include "colo.h"
-#include "sysemu/iothread.h"
 #include "net/colo-compare.h"
-#include "migration/colo.h"
-#include "migration/migration.h"
 #include "util.h"
 
 #include "block/aio-wait.h"
 #include "qemu/coroutine.h"
 
-#define TYPE_COLO_COMPARE "colo-compare"
-typedef struct CompareState CompareState;
-DECLARE_INSTANCE_CHECKER(CompareState, COLO_COMPARE,
-                         TYPE_COLO_COMPARE)
-
 static QTAILQ_HEAD(, CompareState) net_compares =
        QTAILQ_HEAD_INITIALIZER(net_compares);
 
 static NotifierList colo_compare_notifiers =
     NOTIFIER_LIST_INITIALIZER(colo_compare_notifiers);
 
-#define COMPARE_READ_LEN_MAX NET_BUFSIZE
-#define MAX_QUEUE_SIZE 1024
-
-#define COLO_COMPARE_FREE_PRIMARY     0x01
-#define COLO_COMPARE_FREE_SECONDARY   0x02
-
-#define REGULAR_PACKET_CHECK_MS 1000
-#define DEFAULT_TIME_OUT_MS 3000
-
 /* #define DEBUG_COLO_PACKETS */
 
 static QemuMutex colo_compare_mutex;
@@ -64,92 +44,6 @@ static QemuCond event_complete_cond;
 static int event_unhandled_count;
 static uint32_t max_queue_size;
 
-/*
- *  + CompareState ++
- *  |               |
- *  +---------------+   +---------------+         +---------------+
- *  |   conn list   + - >      conn     + ------- >      conn     + -- > ......
- *  +---------------+   +---------------+         +---------------+
- *  |               |     |           |             |          |
- *  +---------------+ +---v----+  +---v----+    +---v----+ +---v----+
- *                    |primary |  |secondary    |primary | |secondary
- *                    |packet  |  |packet  +    |packet  | |packet  +
- *                    +--------+  +--------+    +--------+ +--------+
- *                        |           |             |          |
- *                    +---v----+  +---v----+    +---v----+ +---v----+
- *                    |primary |  |secondary    |primary | |secondary
- *                    |packet  |  |packet  +    |packet  | |packet  +
- *                    +--------+  +--------+    +--------+ +--------+
- *                        |           |             |          |
- *                    +---v----+  +---v----+    +---v----+ +---v----+
- *                    |primary |  |secondary    |primary | |secondary
- *                    |packet  |  |packet  +    |packet  | |packet  +
- *                    +--------+  +--------+    +--------+ +--------+
- */
-
-typedef struct SendCo {
-    Coroutine *co;
-    struct CompareState *s;
-    CharBackend *chr;
-    GQueue send_list;
-    bool notify_remote_frame;
-    bool done;
-    int ret;
-} SendCo;
-
-typedef struct SendEntry {
-    uint32_t size;
-    uint32_t vnet_hdr_len;
-    uint8_t *buf;
-} SendEntry;
-
-struct CompareState {
-    Object parent;
-
-    char *pri_indev;
-    char *sec_indev;
-    char *outdev;
-    char *notify_dev;
-    CharBackend chr_pri_in;
-    CharBackend chr_sec_in;
-    CharBackend chr_out;
-    CharBackend chr_notify_dev;
-    SocketReadState pri_rs;
-    SocketReadState sec_rs;
-    SocketReadState notify_rs;
-    SendCo out_sendco;
-    SendCo notify_sendco;
-    bool vnet_hdr;
-    uint64_t compare_timeout;
-    uint32_t expired_scan_cycle;
-
-    /*
-     * Record the connection that through the NIC
-     * Element type: Connection
-     */
-    GQueue conn_list;
-    /* Record the connection without repetition */
-    GHashTable *connection_track_table;
-
-    IOThread *iothread;
-    GMainContext *worker_context;
-    QEMUTimer *packet_check_timer;
-
-    QEMUBH *event_bh;
-    enum colo_event event;
-
-    QTAILQ_ENTRY(CompareState) next;
-};
-
-typedef struct CompareClass {
-    ObjectClass parent_class;
-} CompareClass;
-
-enum {
-    PRIMARY_IN = 0,
-    SECONDARY_IN,
-};
-
 static const char *colo_mode[] = {
     [PRIMARY_IN] = "primary",
     [SECONDARY_IN] = "secondary",
@@ -737,19 +631,19 @@ static void colo_compare_connection(void *opaque, void *user_data)
 
 static void coroutine_fn _compare_chr_send(void *opaque)
 {
-    SendCo *sendco = opaque;
+    COLOSendCo *sendco = opaque;
     CompareState *s = sendco->s;
     int ret = 0;
 
     while (!g_queue_is_empty(&sendco->send_list)) {
-        SendEntry *entry = g_queue_pop_tail(&sendco->send_list);
+        COLOSendEntry *entry = g_queue_pop_tail(&sendco->send_list);
         uint32_t len = htonl(entry->size);
 
         ret = qemu_chr_fe_write_all(sendco->chr, (uint8_t *)&len, sizeof(len));
 
         if (ret != sizeof(len)) {
             g_free(entry->buf);
-            g_slice_free(SendEntry, entry);
+            g_slice_free(COLOSendEntry, entry);
             goto err;
         }
 
@@ -766,7 +660,7 @@ static void coroutine_fn _compare_chr_send(void *opaque)
 
             if (ret != sizeof(len)) {
                 g_free(entry->buf);
-                g_slice_free(SendEntry, entry);
+                g_slice_free(COLOSendEntry, entry);
                 goto err;
             }
         }
@@ -777,12 +671,12 @@ static void coroutine_fn _compare_chr_send(void *opaque)
 
         if (ret != entry->size) {
             g_free(entry->buf);
-            g_slice_free(SendEntry, entry);
+            g_slice_free(COLOSendEntry, entry);
             goto err;
         }
 
         g_free(entry->buf);
-        g_slice_free(SendEntry, entry);
+        g_slice_free(COLOSendEntry, entry);
     }
 
     sendco->ret = 0;
@@ -790,9 +684,9 @@ static void coroutine_fn _compare_chr_send(void *opaque)
 
 err:
     while (!g_queue_is_empty(&sendco->send_list)) {
-        SendEntry *entry = g_queue_pop_tail(&sendco->send_list);
+        COLOSendEntry *entry = g_queue_pop_tail(&sendco->send_list);
         g_free(entry->buf);
-        g_slice_free(SendEntry, entry);
+        g_slice_free(COLOSendEntry, entry);
     }
     sendco->ret = ret < 0 ? ret : -EIO;
 out:
@@ -808,8 +702,8 @@ static int compare_chr_send(CompareState *s,
                             bool notify_remote_frame,
                             bool zero_copy)
 {
-    SendCo *sendco;
-    SendEntry *entry;
+    COLOSendCo *sendco;
+    COLOSendEntry *entry;
 
     if (notify_remote_frame) {
         sendco = &s->notify_sendco;
@@ -821,7 +715,7 @@ static int compare_chr_send(CompareState *s,
         return 0;
     }
 
-    entry = g_slice_new(SendEntry);
+    entry = g_slice_new(COLOSendEntry);
     entry->size = size;
     entry->vnet_hdr_len = vnet_hdr_len;
     if (zero_copy) {
@@ -1274,17 +1168,17 @@ static void colo_compare_complete(UserCreatable *uc, Error **errp)
 
     if (!s->compare_timeout) {
         /* Set default value to 3000 MS */
-        s->compare_timeout = DEFAULT_TIME_OUT_MS;
+        s->compare_timeout = COLO_DEFAULT_TIME_OUT_MS;
     }
 
     if (!s->expired_scan_cycle) {
         /* Set default value to 3000 MS */
-        s->expired_scan_cycle = REGULAR_PACKET_CHECK_MS;
+        s->expired_scan_cycle = COLO_REGULAR_PACKET_CHECK_MS;
     }
 
     if (!max_queue_size) {
         /* Set default queue size to 1024 */
-        max_queue_size = MAX_QUEUE_SIZE;
+        max_queue_size = MAX_COLO_QUEUE_SIZE;
     }
 
     if (find_and_check_chardev(&chr, s->pri_indev, errp) ||
diff --git a/net/colo-compare.h b/net/colo-compare.h
index 22ddd512e2..ab649c9dbe 100644
--- a/net/colo-compare.h
+++ b/net/colo-compare.h
@@ -17,6 +17,112 @@
 #ifndef QEMU_COLO_COMPARE_H
 #define QEMU_COLO_COMPARE_H
 
+#include "net/net.h"
+#include "chardev/char-fe.h"
+#include "migration/colo.h"
+#include "migration/migration.h"
+#include "sysemu/iothread.h"
+#include "colo.h"
+
+#define TYPE_COLO_COMPARE "colo-compare"
+typedef struct CompareState CompareState;
+DECLARE_INSTANCE_CHECKER(CompareState, COLO_COMPARE,
+                         TYPE_COLO_COMPARE)
+
+#define COMPARE_READ_LEN_MAX NET_BUFSIZE
+#define MAX_COLO_QUEUE_SIZE 1024
+
+#define COLO_COMPARE_FREE_PRIMARY     0x01
+#define COLO_COMPARE_FREE_SECONDARY   0x02
+
+#define COLO_REGULAR_PACKET_CHECK_MS 1000
+#define COLO_DEFAULT_TIME_OUT_MS 3000
+
+typedef struct COLOSendCo {
+    Coroutine *co;
+    struct CompareState *s;
+    CharBackend *chr;
+    GQueue send_list;
+    bool notify_remote_frame;
+    bool done;
+    int ret;
+} COLOSendCo;
+
+typedef struct COLOSendEntry {
+    uint32_t size;
+    uint32_t vnet_hdr_len;
+    uint8_t *buf;
+} COLOSendEntry;
+
+/*
+ *  + CompareState ++
+ *  |               |
+ *  +---------------+   +---------------+         +---------------+
+ *  |   conn list   + - >      conn     + ------- >      conn     + -- > ......
+ *  +---------------+   +---------------+         +---------------+
+ *  |               |     |           |             |          |
+ *  +---------------+ +---v----+  +---v----+    +---v----+ +---v----+
+ *                    |primary |  |secondary    |primary | |secondary
+ *                    |packet  |  |packet  +    |packet  | |packet  +
+ *                    +--------+  +--------+    +--------+ +--------+
+ *                        |           |             |          |
+ *                    +---v----+  +---v----+    +---v----+ +---v----+
+ *                    |primary |  |secondary    |primary | |secondary
+ *                    |packet  |  |packet  +    |packet  | |packet  +
+ *                    +--------+  +--------+    +--------+ +--------+
+ *                        |           |             |          |
+ *                    +---v----+  +---v----+    +---v----+ +---v----+
+ *                    |primary |  |secondary    |primary | |secondary
+ *                    |packet  |  |packet  +    |packet  | |packet  +
+ *                    +--------+  +--------+    +--------+ +--------+
+ */
+struct CompareState {
+    Object parent;
+
+    char *pri_indev;
+    char *sec_indev;
+    char *outdev;
+    char *notify_dev;
+    CharBackend chr_pri_in;
+    CharBackend chr_sec_in;
+    CharBackend chr_out;
+    CharBackend chr_notify_dev;
+    SocketReadState pri_rs;
+    SocketReadState sec_rs;
+    SocketReadState notify_rs;
+    COLOSendCo out_sendco;
+    COLOSendCo notify_sendco;
+    bool vnet_hdr;
+    uint64_t compare_timeout;
+    uint32_t expired_scan_cycle;
+
+    /*
+     * Record the connection that through the NIC
+     * Element type: Connection
+     */
+    GQueue conn_list;
+    /* Record the connection without repetition */
+    GHashTable *connection_track_table;
+
+    IOThread *iothread;
+    GMainContext *worker_context;
+    QEMUTimer *packet_check_timer;
+
+    QEMUBH *event_bh;
+    enum colo_event event;
+
+    QTAILQ_ENTRY(CompareState) next;
+};
+
+typedef struct CompareClass {
+    ObjectClass parent_class;
+} CompareClass;
+
+enum {
+    PRIMARY_IN = 0,
+    SECONDARY_IN,
+};
+
 void colo_notify_compares_event(void *opaque, int event, Error **errp);
 void colo_compare_register_notifier(Notifier *notify);
 void colo_compare_unregister_notifier(Notifier *notify);
-- 
2.25.1



^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH V6 5/6] net/colo-compare: Add passthrough list to CompareState
  2021-04-20 15:15 [PATCH V6 0/6] Passthrough specific network traffic in COLO Zhang Chen
                   ` (3 preceding siblings ...)
  2021-04-20 15:15 ` [PATCH V6 4/6] net/colo-compare: Move data structure and define to .h file Zhang Chen
@ 2021-04-20 15:15 ` Zhang Chen
  2021-05-17 20:07   ` Lukas Straub
  2021-04-20 15:15 ` [PATCH V6 6/6] net/net.c: Add handler for COLO passthrough connection Zhang Chen
  2021-04-28  3:26 ` [PATCH V6 0/6] Passthrough specific network traffic in COLO Zhang, Chen
  6 siblings, 1 reply; 13+ messages in thread
From: Zhang Chen @ 2021-04-20 15:15 UTC (permalink / raw)
  To: Jason Wang, qemu-dev, Eric Blake, Dr. David Alan Gilbert,
	Markus Armbruster, Daniel P. Berrangé,
	Gerd Hoffmann, Li Zhijian
  Cc: Zhang Chen, Lukas Straub, Zhang Chen

Add passthrough list for each CompareState.

Signed-off-by: Zhang Chen <chen.zhang@intel.com>
---
 net/colo-compare.c | 28 ++++++++++++++++++++++++++++
 net/colo-compare.h | 12 ++++++++++++
 2 files changed, 40 insertions(+)

diff --git a/net/colo-compare.c b/net/colo-compare.c
index b51b1437ef..7109e2ed30 100644
--- a/net/colo-compare.c
+++ b/net/colo-compare.c
@@ -141,6 +141,7 @@ static int packet_enqueue(CompareState *s, int mode, Connection **con)
     ConnectionKey key;
     Packet *pkt = NULL;
     Connection *conn;
+    COLOPassthroughEntry *pass, *next;
     int ret;
 
     if (mode == PRIMARY_IN) {
@@ -160,6 +161,31 @@ static int packet_enqueue(CompareState *s, int mode, Connection **con)
     }
     fill_connection_key(pkt, &key);
 
+    /* Check COLO passthrough specifications */
+    qemu_mutex_lock(&s->passthroughlist_mutex);
+    if (!QLIST_EMPTY(&s->passthroughlist)) {
+        QLIST_FOREACH_SAFE(pass, &s->passthroughlist, node, next) {
+            if (key.ip_proto == pass->l4_protocol->p_proto) {
+                if (pass->src_port == 0 || pass->src_port == key.dst_port) {
+                    if (pass->src_ip.s_addr == 0 ||
+                        pass->src_ip.s_addr == key.src.s_addr) {
+                        if (pass->dst_port == 0 ||
+                            pass->dst_port == key.src_port) {
+                            if (pass->dst_ip.s_addr == 0 ||
+                                pass->dst_ip.s_addr == key.dst.s_addr) {
+                                packet_destroy(pkt, NULL);
+                                pkt = NULL;
+                                qemu_mutex_unlock(&s->passthroughlist_mutex);
+                                return -1;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    qemu_mutex_unlock(&s->passthroughlist_mutex);
+
     conn = connection_get(s->connection_track_table,
                           &key,
                           &s->conn_list);
@@ -1225,6 +1251,7 @@ static void colo_compare_complete(UserCreatable *uc, Error **errp)
     }
 
     g_queue_init(&s->conn_list);
+    QLIST_INIT(&s->passthroughlist);
 
     s->connection_track_table = g_hash_table_new_full(connection_key_hash,
                                                       connection_key_equal,
@@ -1237,6 +1264,7 @@ static void colo_compare_complete(UserCreatable *uc, Error **errp)
     if (!colo_compare_active) {
         qemu_mutex_init(&event_mtx);
         qemu_cond_init(&event_complete_cond);
+        qemu_mutex_init(&s->passthroughlist_mutex);
         colo_compare_active = true;
     }
     QTAILQ_INSERT_TAIL(&net_compares, s, next);
diff --git a/net/colo-compare.h b/net/colo-compare.h
index ab649c9dbe..7ca74de840 100644
--- a/net/colo-compare.h
+++ b/net/colo-compare.h
@@ -23,6 +23,7 @@
 #include "migration/migration.h"
 #include "sysemu/iothread.h"
 #include "colo.h"
+#include <netdb.h>
 
 #define TYPE_COLO_COMPARE "colo-compare"
 typedef struct CompareState CompareState;
@@ -54,6 +55,15 @@ typedef struct COLOSendEntry {
     uint8_t *buf;
 } COLOSendEntry;
 
+typedef struct COLOPassthroughEntry {
+    struct protoent *l4_protocol;
+    int src_port;
+    int dst_port;
+    struct in_addr src_ip;
+    struct in_addr dst_ip;
+    QLIST_ENTRY(COLOPassthroughEntry) node;
+} COLOPassthroughEntry;
+
 /*
  *  + CompareState ++
  *  |               |
@@ -110,6 +120,8 @@ struct CompareState {
 
     QEMUBH *event_bh;
     enum colo_event event;
+    QLIST_HEAD(, COLOPassthroughEntry) passthroughlist;
+    QemuMutex passthroughlist_mutex;
 
     QTAILQ_ENTRY(CompareState) next;
 };
-- 
2.25.1



^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH V6 6/6] net/net.c: Add handler for COLO passthrough connection
  2021-04-20 15:15 [PATCH V6 0/6] Passthrough specific network traffic in COLO Zhang Chen
                   ` (4 preceding siblings ...)
  2021-04-20 15:15 ` [PATCH V6 5/6] net/colo-compare: Add passthrough list to CompareState Zhang Chen
@ 2021-04-20 15:15 ` Zhang Chen
  2021-05-17 20:38   ` Lukas Straub
  2021-04-28  3:26 ` [PATCH V6 0/6] Passthrough specific network traffic in COLO Zhang, Chen
  6 siblings, 1 reply; 13+ messages in thread
From: Zhang Chen @ 2021-04-20 15:15 UTC (permalink / raw)
  To: Jason Wang, qemu-dev, Eric Blake, Dr. David Alan Gilbert,
	Markus Armbruster, Daniel P. Berrangé,
	Gerd Hoffmann, Li Zhijian
  Cc: Zhang Chen, Lukas Straub, Zhang Chen

Use connection protocol,src port,dst port,src ip,dst ip as the key
to bypass certain network traffic in COLO compare.

Signed-off-by: Zhang Chen <chen.zhang@intel.com>
---
 net/net.c | 160 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 158 insertions(+), 2 deletions(-)

diff --git a/net/net.c b/net/net.c
index 2a6e5f3886..9b0de0f332 100644
--- a/net/net.c
+++ b/net/net.c
@@ -56,6 +56,8 @@
 #include "sysemu/sysemu.h"
 #include "net/filter.h"
 #include "qapi/string-output-visitor.h"
+#include "net/colo-compare.h"
+#include "qom/object_interfaces.h"
 
 /* Net bridge is currently not supported for W32. */
 #if !defined(_WIN32)
@@ -1196,14 +1198,168 @@ void qmp_netdev_del(const char *id, Error **errp)
     }
 }
 
+static CompareState *colo_passthrough_check(IPFlowSpec *spec, Error **errp)
+{
+    Object *container;
+    Object *obj;
+    CompareState *s;
+
+    if (!spec->object_name) {
+        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "object-name",
+                   "Need input colo-compare object name");
+        return NULL;
+    }
+
+    container = object_get_objects_root();
+    obj = object_resolve_path_component(container, spec->object_name);
+    if (!obj) {
+        error_setg(errp, "colo-compare '%s' not found", spec->object_name);
+        return NULL;
+    }
+
+    s = COLO_COMPARE(obj);
+
+    if (!getprotobyname(spec->protocol)) {
+        error_setg(errp, "COLO pass through get wrong protocol");
+        return NULL;
+    }
+
+    if ((spec->source->host && !qemu_isdigit(spec->source->host[0])) ||
+        (spec->destination->host &&
+        !qemu_isdigit(spec->destination->host[0]))) {
+        error_setg(errp, "COLO pass through get wrong IP");
+        return NULL;
+    }
+
+    if (atoi(spec->source->port) > 65536 || atoi(spec->source->port) < 0 ||
+        atoi(spec->destination->port) > 65536 ||
+        atoi(spec->destination->port) < 0) {
+        error_setg(errp, "COLO pass through get wrong port");
+        return NULL;
+    }
+
+    return s;
+}
+
+static void compare_passthrough_add(CompareState *s,
+                                    IPFlowSpec *spec,
+                                    Error **errp)
+{
+    COLOPassthroughEntry *pass = NULL, *next = NULL, *origin = NULL;
+
+    pass = g_new0(COLOPassthroughEntry, 1);
+
+    pass->l4_protocol = getprotobyname(spec->protocol);
+    pass->src_port = atoi(spec->source->port);
+    pass->dst_port = atoi(spec->destination->port);
+
+    if (!inet_aton(spec->source->host, &pass->src_ip)) {
+        pass->src_ip.s_addr = 0;
+    }
+
+    if (!inet_aton(spec->destination->host, &pass->dst_ip)) {
+        pass->dst_ip.s_addr = 0;
+    }
+
+    qemu_mutex_lock(&s->passthroughlist_mutex);
+    if (!QLIST_EMPTY(&s->passthroughlist)) {
+        QLIST_FOREACH_SAFE(origin, &s->passthroughlist, node, next) {
+            if ((pass->l4_protocol->p_proto == origin->l4_protocol->p_proto) &&
+                (pass->src_port == origin->src_port) &&
+                (pass->dst_port == origin->dst_port) &&
+                (pass->src_ip.s_addr == origin->src_ip.s_addr) &&
+                (pass->dst_ip.s_addr == origin->dst_ip.s_addr)) {
+                error_setg(errp, "The pass through connection already exists");
+                g_free(pass);
+                qemu_mutex_unlock(&s->passthroughlist_mutex);
+                return;
+            }
+        }
+    }
+
+    QLIST_INSERT_HEAD(&s->passthroughlist, pass, node);
+    qemu_mutex_unlock(&s->passthroughlist_mutex);
+}
+
+static void compare_passthrough_del(CompareState *s,
+                                    IPFlowSpec *spec,
+                                    Error **errp)
+{
+    COLOPassthroughEntry *pass = NULL, *next = NULL, *origin = NULL;
+
+    pass = g_new0(COLOPassthroughEntry, 1);
+
+    pass->l4_protocol = getprotobyname(spec->protocol);
+    pass->src_port = atoi(spec->source->port);
+    pass->dst_port = atoi(spec->destination->port);
+
+    if (!inet_aton(spec->source->host, &pass->src_ip)) {
+        pass->src_ip.s_addr = 0;
+    }
+
+    if (!inet_aton(spec->destination->host, &pass->dst_ip)) {
+        pass->dst_ip.s_addr = 0;
+    }
+
+    qemu_mutex_lock(&s->passthroughlist_mutex);
+    if (!QLIST_EMPTY(&s->passthroughlist)) {
+        QLIST_FOREACH_SAFE(origin, &s->passthroughlist, node, next) {
+            if ((pass->l4_protocol->p_proto == origin->l4_protocol->p_proto) &&
+                (pass->src_port == origin->src_port) &&
+                (pass->dst_port == origin->dst_port) &&
+                (pass->src_ip.s_addr == origin->src_ip.s_addr) &&
+                (pass->dst_ip.s_addr == origin->dst_ip.s_addr)) {
+                QLIST_REMOVE(origin, node);
+                g_free(origin);
+                g_free(pass);
+                qemu_mutex_unlock(&s->passthroughlist_mutex);
+                return;
+            }
+        }
+        error_setg(errp, "The pass through list can't find the connection");
+    } else {
+        error_setg(errp, "The pass through connection list is empty");
+    }
+
+    g_free(pass);
+    qemu_mutex_unlock(&s->passthroughlist_mutex);
+}
+
+
 void qmp_colo_passthrough_add(IPFlowSpec *spec, Error **errp)
 {
-    /* TODO implement setup passthrough rule */
+    CompareState *s;
+    Error *err = NULL;
+
+    s = colo_passthrough_check(spec, &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
+
+    compare_passthrough_add(s, spec, &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
 }
 
 void qmp_colo_passthrough_del(IPFlowSpec *spec, Error **errp)
 {
-    /* TODO implement delete passthrough rule */
+    CompareState *s;
+    Error *err = NULL;
+
+    s = colo_passthrough_check(spec, &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
+
+    compare_passthrough_del(s, spec, &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
 }
 
 static void netfilter_print_info(Monitor *mon, NetFilterState *nf)
-- 
2.25.1



^ permalink raw reply	[flat|nested] 13+ messages in thread

* RE: [PATCH V6 0/6] Passthrough specific network traffic in COLO
  2021-04-20 15:15 [PATCH V6 0/6] Passthrough specific network traffic in COLO Zhang Chen
                   ` (5 preceding siblings ...)
  2021-04-20 15:15 ` [PATCH V6 6/6] net/net.c: Add handler for COLO passthrough connection Zhang Chen
@ 2021-04-28  3:26 ` Zhang, Chen
  2021-05-12  7:05   ` Zhang, Chen
  6 siblings, 1 reply; 13+ messages in thread
From: Zhang, Chen @ 2021-04-28  3:26 UTC (permalink / raw)
  To: Jason Wang, qemu-dev, Eric Blake, Dr. David Alan Gilbert,
	Markus Armbruster, Daniel P. Berrangé,
	Gerd Hoffmann, Li Zhijian
  Cc: Lukas Straub, Zhang Chen

Please give me for comments for this series, Ping....

Thanks
Chen

> -----Original Message-----
> From: Zhang, Chen <chen.zhang@intel.com>
> Sent: Tuesday, April 20, 2021 11:16 PM
> To: Jason Wang <jasowang@redhat.com>; qemu-dev <qemu-
> devel@nongnu.org>; Eric Blake <eblake@redhat.com>; Dr. David Alan
> Gilbert <dgilbert@redhat.com>; Markus Armbruster <armbru@redhat.com>;
> Daniel P. Berrangé <berrange@redhat.com>; Gerd Hoffmann
> <kraxel@redhat.com>; Li Zhijian <lizhijian@cn.fujitsu.com>
> Cc: Zhang Chen <zhangckid@gmail.com>; Zhang, Chen
> <chen.zhang@intel.com>; Lukas Straub <lukasstraub2@web.de>
> Subject: [PATCH V6 0/6] Passthrough specific network traffic in COLO
> 
> Due to some real user scenarios don't need to monitor all traffic.
> And qemu net-filter also need function to more detailed flow control.
> This series give user ability to passthrough kinds of COLO network stream.
> 
> For example, windows guest user want to enable windows remote desktop
> to touch guest(UDP/TCP 3389), This case use UDP and TCP mixed, and the tcp
> part payload always different caused by real desktop display data(for guest
> time/ mouse display....).
> 
> Another case is some real user application will actively transmit information
> include guest time part, primary guest send data with time 10:01.000, At the
> same time secondary guest send data with time 10:01.001, it will always
> trigger COLO checkpoint(live migrate) to drop guest performance.
> 
>   V6:
>     - Change QAPI IPFlowSpec protocol from enum to str.
>     - Use getprotobyname to handle the protocols.
>     - Optimize code in net.
> 
>   V5:
>     - Squash original 1-3 QAPI patches together.
>     - Rename some data structures to avoid misunderstanding.
>     - Reuse InetSocketAddressBase in IPFlowSpec.
>     - Add new function in util/qemu-sockets.c to parse
>       InetSocketAddressBase.
>     - Update HMP command define to reuse current code.
>     - Add more comments.
> 
>   V4:
>     - Fix QAPI code conflict for V6.0 merged patches.
>     - Note this feature for V6.1.
> 
>   V3:
>     - Add COLO passthrough list lock.
>     - Add usage demo and more comments.
> 
>   V2:
>     - Add the n-tuple support.
>     - Add some qapi definitions.
>     - Support multi colo-compare objects.
>     - Support setup each rules for each objects individually.
>     - Clean up COLO compare definition to .h file.
>     - Rebase HMP command for stable tree.
>     - Add redundant rules check.
> 
> 
> Zhang Chen (6):
>   qapi/net: Add IPFlowSpec and QMP command for COLO passthrough
>   util/qemu-sockets.c: Add inet_parse_base to handle
>     InetSocketAddressBase
>   hmp-commands: Add new HMP command for COLO passthrough
>   net/colo-compare: Move data structure and define to .h file.
>   net/colo-compare: Add passthrough list to CompareState
>   net/net.c: Add handler for COLO passthrough connection
> 
>  hmp-commands.hx        |  26 +++++++
>  include/monitor/hmp.h  |   2 +
>  include/qemu/sockets.h |   1 +
>  monitor/hmp-cmds.c     |  82 ++++++++++++++++++++
>  net/colo-compare.c     | 162 +++++++++++-----------------------------
>  net/colo-compare.h     | 118 +++++++++++++++++++++++++++++
>  net/net.c              | 166 +++++++++++++++++++++++++++++++++++++++++
>  qapi/net.json          |  68 +++++++++++++++++
>  util/qemu-sockets.c    |  14 ++++
>  9 files changed, 519 insertions(+), 120 deletions(-)
> 
> --
> 2.25.1



^ permalink raw reply	[flat|nested] 13+ messages in thread

* RE: [PATCH V6 0/6] Passthrough specific network traffic in COLO
  2021-04-28  3:26 ` [PATCH V6 0/6] Passthrough specific network traffic in COLO Zhang, Chen
@ 2021-05-12  7:05   ` Zhang, Chen
  0 siblings, 0 replies; 13+ messages in thread
From: Zhang, Chen @ 2021-05-12  7:05 UTC (permalink / raw)
  To: Zhang, Chen, Jason Wang, qemu-dev, Eric Blake,
	Dr. David Alan Gilbert, Markus Armbruster,
	Daniel P. Berrangé,
	Gerd Hoffmann, Li Zhijian
  Cc: Lukas Straub, Zhang Chen

Hi Markus, Jason and Dave.

This series has been modified according to previous suggestions. 
Please review it again to make sure I fully understand comments.

Thanks
Chen

> -----Original Message-----
> From: Qemu-devel <qemu-devel-
> bounces+chen.zhang=intel.com@nongnu.org> On Behalf Of Zhang, Chen
> Sent: Wednesday, April 28, 2021 11:27 AM
> To: Jason Wang <jasowang@redhat.com>; qemu-dev <qemu-
> devel@nongnu.org>; Eric Blake <eblake@redhat.com>; Dr. David Alan
> Gilbert <dgilbert@redhat.com>; Markus Armbruster <armbru@redhat.com>;
> Daniel P. Berrangé <berrange@redhat.com>; Gerd Hoffmann
> <kraxel@redhat.com>; Li Zhijian <lizhijian@cn.fujitsu.com>
> Cc: Lukas Straub <lukasstraub2@web.de>; Zhang Chen
> <zhangckid@gmail.com>
> Subject: RE: [PATCH V6 0/6] Passthrough specific network traffic in COLO
> 
> Please give me for comments for this series, Ping....
> 
> Thanks
> Chen
> 
> > -----Original Message-----
> > From: Zhang, Chen <chen.zhang@intel.com>
> > Sent: Tuesday, April 20, 2021 11:16 PM
> > To: Jason Wang <jasowang@redhat.com>; qemu-dev <qemu-
> > devel@nongnu.org>; Eric Blake <eblake@redhat.com>; Dr. David Alan
> > Gilbert <dgilbert@redhat.com>; Markus Armbruster
> <armbru@redhat.com>;
> > Daniel P. Berrangé <berrange@redhat.com>; Gerd Hoffmann
> > <kraxel@redhat.com>; Li Zhijian <lizhijian@cn.fujitsu.com>
> > Cc: Zhang Chen <zhangckid@gmail.com>; Zhang, Chen
> > <chen.zhang@intel.com>; Lukas Straub <lukasstraub2@web.de>
> > Subject: [PATCH V6 0/6] Passthrough specific network traffic in COLO
> >
> > Due to some real user scenarios don't need to monitor all traffic.
> > And qemu net-filter also need function to more detailed flow control.
> > This series give user ability to passthrough kinds of COLO network stream.
> >
> > For example, windows guest user want to enable windows remote
> desktop
> > to touch guest(UDP/TCP 3389), This case use UDP and TCP mixed, and the
> > tcp part payload always different caused by real desktop display
> > data(for guest time/ mouse display....).
> >
> > Another case is some real user application will actively transmit
> > information include guest time part, primary guest send data with time
> > 10:01.000, At the same time secondary guest send data with time
> > 10:01.001, it will always trigger COLO checkpoint(live migrate) to drop guest
> performance.
> >
> >   V6:
> >     - Change QAPI IPFlowSpec protocol from enum to str.
> >     - Use getprotobyname to handle the protocols.
> >     - Optimize code in net.
> >
> >   V5:
> >     - Squash original 1-3 QAPI patches together.
> >     - Rename some data structures to avoid misunderstanding.
> >     - Reuse InetSocketAddressBase in IPFlowSpec.
> >     - Add new function in util/qemu-sockets.c to parse
> >       InetSocketAddressBase.
> >     - Update HMP command define to reuse current code.
> >     - Add more comments.
> >
> >   V4:
> >     - Fix QAPI code conflict for V6.0 merged patches.
> >     - Note this feature for V6.1.
> >
> >   V3:
> >     - Add COLO passthrough list lock.
> >     - Add usage demo and more comments.
> >
> >   V2:
> >     - Add the n-tuple support.
> >     - Add some qapi definitions.
> >     - Support multi colo-compare objects.
> >     - Support setup each rules for each objects individually.
> >     - Clean up COLO compare definition to .h file.
> >     - Rebase HMP command for stable tree.
> >     - Add redundant rules check.
> >
> >
> > Zhang Chen (6):
> >   qapi/net: Add IPFlowSpec and QMP command for COLO passthrough
> >   util/qemu-sockets.c: Add inet_parse_base to handle
> >     InetSocketAddressBase
> >   hmp-commands: Add new HMP command for COLO passthrough
> >   net/colo-compare: Move data structure and define to .h file.
> >   net/colo-compare: Add passthrough list to CompareState
> >   net/net.c: Add handler for COLO passthrough connection
> >
> >  hmp-commands.hx        |  26 +++++++
> >  include/monitor/hmp.h  |   2 +
> >  include/qemu/sockets.h |   1 +
> >  monitor/hmp-cmds.c     |  82 ++++++++++++++++++++
> >  net/colo-compare.c     | 162 +++++++++++-----------------------------
> >  net/colo-compare.h     | 118 +++++++++++++++++++++++++++++
> >  net/net.c              | 166
> +++++++++++++++++++++++++++++++++++++++++
> >  qapi/net.json          |  68 +++++++++++++++++
> >  util/qemu-sockets.c    |  14 ++++
> >  9 files changed, 519 insertions(+), 120 deletions(-)
> >
> > --
> > 2.25.1
> 



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH V6 4/6] net/colo-compare: Move data structure and define to .h file.
  2021-04-20 15:15 ` [PATCH V6 4/6] net/colo-compare: Move data structure and define to .h file Zhang Chen
@ 2021-05-17 20:03   ` Lukas Straub
  0 siblings, 0 replies; 13+ messages in thread
From: Lukas Straub @ 2021-05-17 20:03 UTC (permalink / raw)
  To: Zhang Chen
  Cc: Daniel P. Berrangé,
	Li Zhijian, Jason Wang, Markus Armbruster, qemu-dev,
	Gerd Hoffmann, Zhang Chen, Dr. David Alan Gilbert


[-- Attachment #1: Type: text/plain, Size: 13221 bytes --]

On Tue, 20 Apr 2021 23:15:35 +0800
Zhang Chen <chen.zhang@intel.com> wrote:

> Rename structure with COLO index and move it to .h file,
> It make other modules can reuse COLO code.

Hi,
There are some definitions that don't need to be moved into the header,
more comments below.

In general I think the new passthrough feature can be exclusive to
colo-compare for now and that everything can remain there. If other net
filters implement the feature, we can still move it outside of
colo-compare later.

> Signed-off-by: Zhang Chen <chen.zhang@intel.com>
> ---
>  net/colo-compare.c | 134 +++++----------------------------------------
>  net/colo-compare.h | 106 +++++++++++++++++++++++++++++++++++
>  2 files changed, 120 insertions(+), 120 deletions(-)
> 
> diff --git a/net/colo-compare.c b/net/colo-compare.c
> index 9d1ad99941..b51b1437ef 100644
> --- a/net/colo-compare.c
> +++ b/net/colo-compare.c
> @@ -17,44 +17,24 @@
>  #include "qemu/error-report.h"
>  #include "trace.h"
>  #include "qapi/error.h"
> -#include "net/net.h"
>  #include "net/eth.h"
>  #include "qom/object_interfaces.h"
>  #include "qemu/iov.h"
>  #include "qom/object.h"
>  #include "net/queue.h"
> -#include "chardev/char-fe.h"
>  #include "qemu/sockets.h"
> -#include "colo.h"
> -#include "sysemu/iothread.h"
>  #include "net/colo-compare.h"
> -#include "migration/colo.h"
> -#include "migration/migration.h"
>  #include "util.h"
>  
>  #include "block/aio-wait.h"
>  #include "qemu/coroutine.h"
>  
> -#define TYPE_COLO_COMPARE "colo-compare"
> -typedef struct CompareState CompareState;
> -DECLARE_INSTANCE_CHECKER(CompareState, COLO_COMPARE,
> -                         TYPE_COLO_COMPARE)
> -
>  static QTAILQ_HEAD(, CompareState) net_compares =
>         QTAILQ_HEAD_INITIALIZER(net_compares);
>  
>  static NotifierList colo_compare_notifiers =
>      NOTIFIER_LIST_INITIALIZER(colo_compare_notifiers);
>  
> -#define COMPARE_READ_LEN_MAX NET_BUFSIZE
> -#define MAX_QUEUE_SIZE 1024
> -
> -#define COLO_COMPARE_FREE_PRIMARY     0x01
> -#define COLO_COMPARE_FREE_SECONDARY   0x02
> -
> -#define REGULAR_PACKET_CHECK_MS 1000
> -#define DEFAULT_TIME_OUT_MS 3000
> -

These 6 defines should stay here.

>  /* #define DEBUG_COLO_PACKETS */
>  
>  static QemuMutex colo_compare_mutex;
> @@ -64,92 +44,6 @@ static QemuCond event_complete_cond;
>  static int event_unhandled_count;
>  static uint32_t max_queue_size;
>  
> -/*
> - *  + CompareState ++
> - *  |               |
> - *  +---------------+   +---------------+         +---------------+
> - *  |   conn list   + - >      conn     + ------- >      conn     + -- > ......
> - *  +---------------+   +---------------+         +---------------+
> - *  |               |     |           |             |          |
> - *  +---------------+ +---v----+  +---v----+    +---v----+ +---v----+
> - *                    |primary |  |secondary    |primary | |secondary
> - *                    |packet  |  |packet  +    |packet  | |packet  +
> - *                    +--------+  +--------+    +--------+ +--------+
> - *                        |           |             |          |
> - *                    +---v----+  +---v----+    +---v----+ +---v----+
> - *                    |primary |  |secondary    |primary | |secondary
> - *                    |packet  |  |packet  +    |packet  | |packet  +
> - *                    +--------+  +--------+    +--------+ +--------+
> - *                        |           |             |          |
> - *                    +---v----+  +---v----+    +---v----+ +---v----+
> - *                    |primary |  |secondary    |primary | |secondary
> - *                    |packet  |  |packet  +    |packet  | |packet  +
> - *                    +--------+  +--------+    +--------+ +--------+
> - */
> -
> -typedef struct SendCo {
> -    Coroutine *co;
> -    struct CompareState *s;
> -    CharBackend *chr;
> -    GQueue send_list;
> -    bool notify_remote_frame;
> -    bool done;
> -    int ret;
> -} SendCo;

This struct should stay here.

> -typedef struct SendEntry {
> -    uint32_t size;
> -    uint32_t vnet_hdr_len;
> -    uint8_t *buf;
> -} SendEntry;

This struct should stay here.

> -struct CompareState {
> -    Object parent;
> -
> -    char *pri_indev;
> -    char *sec_indev;
> -    char *outdev;
> -    char *notify_dev;
> -    CharBackend chr_pri_in;
> -    CharBackend chr_sec_in;
> -    CharBackend chr_out;
> -    CharBackend chr_notify_dev;
> -    SocketReadState pri_rs;
> -    SocketReadState sec_rs;
> -    SocketReadState notify_rs;
> -    SendCo out_sendco;
> -    SendCo notify_sendco;
> -    bool vnet_hdr;
> -    uint64_t compare_timeout;
> -    uint32_t expired_scan_cycle;
> -
> -    /*
> -     * Record the connection that through the NIC
> -     * Element type: Connection
> -     */
> -    GQueue conn_list;
> -    /* Record the connection without repetition */
> -    GHashTable *connection_track_table;
> -
> -    IOThread *iothread;
> -    GMainContext *worker_context;
> -    QEMUTimer *packet_check_timer;
> -
> -    QEMUBH *event_bh;
> -    enum colo_event event;
> -
> -    QTAILQ_ENTRY(CompareState) next;
> -};
> -
> -typedef struct CompareClass {
> -    ObjectClass parent_class;
> -} CompareClass;
> -
> -enum {
> -    PRIMARY_IN = 0,
> -    SECONDARY_IN,
> -};

The enum should stay here.

>  static const char *colo_mode[] = {
>      [PRIMARY_IN] = "primary",
>      [SECONDARY_IN] = "secondary",
> @@ -737,19 +631,19 @@ static void colo_compare_connection(void *opaque, void *user_data)
>  
>  static void coroutine_fn _compare_chr_send(void *opaque)
>  {
> -    SendCo *sendco = opaque;
> +    COLOSendCo *sendco = opaque;
>      CompareState *s = sendco->s;
>      int ret = 0;
>  
>      while (!g_queue_is_empty(&sendco->send_list)) {
> -        SendEntry *entry = g_queue_pop_tail(&sendco->send_list);
> +        COLOSendEntry *entry = g_queue_pop_tail(&sendco->send_list);
>          uint32_t len = htonl(entry->size);
>  
>          ret = qemu_chr_fe_write_all(sendco->chr, (uint8_t *)&len, sizeof(len));
>  
>          if (ret != sizeof(len)) {
>              g_free(entry->buf);
> -            g_slice_free(SendEntry, entry);
> +            g_slice_free(COLOSendEntry, entry);
>              goto err;
>          }
>  
> @@ -766,7 +660,7 @@ static void coroutine_fn _compare_chr_send(void *opaque)
>  
>              if (ret != sizeof(len)) {
>                  g_free(entry->buf);
> -                g_slice_free(SendEntry, entry);
> +                g_slice_free(COLOSendEntry, entry);
>                  goto err;
>              }
>          }
> @@ -777,12 +671,12 @@ static void coroutine_fn _compare_chr_send(void *opaque)
>  
>          if (ret != entry->size) {
>              g_free(entry->buf);
> -            g_slice_free(SendEntry, entry);
> +            g_slice_free(COLOSendEntry, entry);
>              goto err;
>          }
>  
>          g_free(entry->buf);
> -        g_slice_free(SendEntry, entry);
> +        g_slice_free(COLOSendEntry, entry);
>      }
>  
>      sendco->ret = 0;
> @@ -790,9 +684,9 @@ static void coroutine_fn _compare_chr_send(void *opaque)
>  
>  err:
>      while (!g_queue_is_empty(&sendco->send_list)) {
> -        SendEntry *entry = g_queue_pop_tail(&sendco->send_list);
> +        COLOSendEntry *entry = g_queue_pop_tail(&sendco->send_list);
>          g_free(entry->buf);
> -        g_slice_free(SendEntry, entry);
> +        g_slice_free(COLOSendEntry, entry);
>      }
>      sendco->ret = ret < 0 ? ret : -EIO;
>  out:
> @@ -808,8 +702,8 @@ static int compare_chr_send(CompareState *s,
>                              bool notify_remote_frame,
>                              bool zero_copy)
>  {
> -    SendCo *sendco;
> -    SendEntry *entry;
> +    COLOSendCo *sendco;
> +    COLOSendEntry *entry;
>  
>      if (notify_remote_frame) {
>          sendco = &s->notify_sendco;
> @@ -821,7 +715,7 @@ static int compare_chr_send(CompareState *s,
>          return 0;
>      }
>  
> -    entry = g_slice_new(SendEntry);
> +    entry = g_slice_new(COLOSendEntry);
>      entry->size = size;
>      entry->vnet_hdr_len = vnet_hdr_len;
>      if (zero_copy) {
> @@ -1274,17 +1168,17 @@ static void colo_compare_complete(UserCreatable *uc, Error **errp)
>  
>      if (!s->compare_timeout) {
>          /* Set default value to 3000 MS */
> -        s->compare_timeout = DEFAULT_TIME_OUT_MS;
> +        s->compare_timeout = COLO_DEFAULT_TIME_OUT_MS;
>      }
>  
>      if (!s->expired_scan_cycle) {
>          /* Set default value to 3000 MS */
> -        s->expired_scan_cycle = REGULAR_PACKET_CHECK_MS;
> +        s->expired_scan_cycle = COLO_REGULAR_PACKET_CHECK_MS;
>      }
>  
>      if (!max_queue_size) {
>          /* Set default queue size to 1024 */
> -        max_queue_size = MAX_QUEUE_SIZE;
> +        max_queue_size = MAX_COLO_QUEUE_SIZE;
>      }
>  
>      if (find_and_check_chardev(&chr, s->pri_indev, errp) ||
> diff --git a/net/colo-compare.h b/net/colo-compare.h
> index 22ddd512e2..ab649c9dbe 100644
> --- a/net/colo-compare.h
> +++ b/net/colo-compare.h
> @@ -17,6 +17,112 @@
>  #ifndef QEMU_COLO_COMPARE_H
>  #define QEMU_COLO_COMPARE_H
>  
> +#include "net/net.h"
> +#include "chardev/char-fe.h"
> +#include "migration/colo.h"
> +#include "migration/migration.h"
> +#include "sysemu/iothread.h"
> +#include "colo.h"
> +
> +#define TYPE_COLO_COMPARE "colo-compare"
> +typedef struct CompareState CompareState;
> +DECLARE_INSTANCE_CHECKER(CompareState, COLO_COMPARE,
> +                         TYPE_COLO_COMPARE)
> +
> +#define COMPARE_READ_LEN_MAX NET_BUFSIZE
> +#define MAX_COLO_QUEUE_SIZE 1024
> +
> +#define COLO_COMPARE_FREE_PRIMARY     0x01
> +#define COLO_COMPARE_FREE_SECONDARY   0x02
> +
> +#define COLO_REGULAR_PACKET_CHECK_MS 1000
> +#define COLO_DEFAULT_TIME_OUT_MS 3000
> +
> +typedef struct COLOSendCo {
> +    Coroutine *co;
> +    struct CompareState *s;
> +    CharBackend *chr;
> +    GQueue send_list;
> +    bool notify_remote_frame;
> +    bool done;
> +    int ret;
> +} COLOSendCo;
> +
> +typedef struct COLOSendEntry {
> +    uint32_t size;
> +    uint32_t vnet_hdr_len;
> +    uint8_t *buf;
> +} COLOSendEntry;
> +
> +/*
> + *  + CompareState ++
> + *  |               |
> + *  +---------------+   +---------------+         +---------------+
> + *  |   conn list   + - >      conn     + ------- >      conn     + -- > ......
> + *  +---------------+   +---------------+         +---------------+
> + *  |               |     |           |             |          |
> + *  +---------------+ +---v----+  +---v----+    +---v----+ +---v----+
> + *                    |primary |  |secondary    |primary | |secondary
> + *                    |packet  |  |packet  +    |packet  | |packet  +
> + *                    +--------+  +--------+    +--------+ +--------+
> + *                        |           |             |          |
> + *                    +---v----+  +---v----+    +---v----+ +---v----+
> + *                    |primary |  |secondary    |primary | |secondary
> + *                    |packet  |  |packet  +    |packet  | |packet  +
> + *                    +--------+  +--------+    +--------+ +--------+
> + *                        |           |             |          |
> + *                    +---v----+  +---v----+    +---v----+ +---v----+
> + *                    |primary |  |secondary    |primary | |secondary
> + *                    |packet  |  |packet  +    |packet  | |packet  +
> + *                    +--------+  +--------+    +--------+ +--------+
> + */
> +struct CompareState {
> +    Object parent;
> +
> +    char *pri_indev;
> +    char *sec_indev;
> +    char *outdev;
> +    char *notify_dev;
> +    CharBackend chr_pri_in;
> +    CharBackend chr_sec_in;
> +    CharBackend chr_out;
> +    CharBackend chr_notify_dev;
> +    SocketReadState pri_rs;
> +    SocketReadState sec_rs;
> +    SocketReadState notify_rs;
> +    COLOSendCo out_sendco;
> +    COLOSendCo notify_sendco;
> +    bool vnet_hdr;
> +    uint64_t compare_timeout;
> +    uint32_t expired_scan_cycle;
> +
> +    /*
> +     * Record the connection that through the NIC
> +     * Element type: Connection
> +     */
> +    GQueue conn_list;
> +    /* Record the connection without repetition */
> +    GHashTable *connection_track_table;
> +
> +    IOThread *iothread;
> +    GMainContext *worker_context;
> +    QEMUTimer *packet_check_timer;
> +
> +    QEMUBH *event_bh;
> +    enum colo_event event;
> +
> +    QTAILQ_ENTRY(CompareState) next;
> +};
> +
> +typedef struct CompareClass {
> +    ObjectClass parent_class;
> +} CompareClass;
> +
> +enum {
> +    PRIMARY_IN = 0,
> +    SECONDARY_IN,
> +};
> +
>  void colo_notify_compares_event(void *opaque, int event, Error **errp);
>  void colo_compare_register_notifier(Notifier *notify);
>  void colo_compare_unregister_notifier(Notifier *notify);



-- 


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH V6 5/6] net/colo-compare: Add passthrough list to CompareState
  2021-04-20 15:15 ` [PATCH V6 5/6] net/colo-compare: Add passthrough list to CompareState Zhang Chen
@ 2021-05-17 20:07   ` Lukas Straub
  0 siblings, 0 replies; 13+ messages in thread
From: Lukas Straub @ 2021-05-17 20:07 UTC (permalink / raw)
  To: Zhang Chen
  Cc: Daniel P. Berrangé,
	Li Zhijian, Jason Wang, Markus Armbruster, qemu-dev,
	Gerd Hoffmann, Zhang Chen, Dr. David Alan Gilbert


[-- Attachment #1: Type: text/plain, Size: 4244 bytes --]

On Tue, 20 Apr 2021 23:15:36 +0800
Zhang Chen <chen.zhang@intel.com> wrote:

> Add passthrough list for each CompareState.
> 
> Signed-off-by: Zhang Chen <chen.zhang@intel.com>
> ---
>  net/colo-compare.c | 28 ++++++++++++++++++++++++++++
>  net/colo-compare.h | 12 ++++++++++++
>  2 files changed, 40 insertions(+)
> 
> diff --git a/net/colo-compare.c b/net/colo-compare.c
> index b51b1437ef..7109e2ed30 100644
> --- a/net/colo-compare.c
> +++ b/net/colo-compare.c
> @@ -141,6 +141,7 @@ static int packet_enqueue(CompareState *s, int mode, Connection **con)
>      ConnectionKey key;
>      Packet *pkt = NULL;
>      Connection *conn;
> +    COLOPassthroughEntry *pass, *next;
>      int ret;
>  
>      if (mode == PRIMARY_IN) {
> @@ -160,6 +161,31 @@ static int packet_enqueue(CompareState *s, int mode, Connection **con)
>      }
>      fill_connection_key(pkt, &key);
>  
> +    /* Check COLO passthrough specifications */
> +    qemu_mutex_lock(&s->passthroughlist_mutex);
> +    if (!QLIST_EMPTY(&s->passthroughlist)) {
> +        QLIST_FOREACH_SAFE(pass, &s->passthroughlist, node, next) {
> +            if (key.ip_proto == pass->l4_protocol->p_proto) {
> +                if (pass->src_port == 0 || pass->src_port == key.dst_port) {
> +                    if (pass->src_ip.s_addr == 0 ||
> +                        pass->src_ip.s_addr == key.src.s_addr) {
> +                        if (pass->dst_port == 0 ||
> +                            pass->dst_port == key.src_port) {
> +                            if (pass->dst_ip.s_addr == 0 ||
> +                                pass->dst_ip.s_addr == key.dst.s_addr) {
> +                                packet_destroy(pkt, NULL);
> +                                pkt = NULL;
> +                                qemu_mutex_unlock(&s->passthroughlist_mutex);
> +                                return -1;
> +                            }
> +                        }
> +                    }
> +                }
> +            }
> +        }
> +    }
> +    qemu_mutex_unlock(&s->passthroughlist_mutex);
> +
>      conn = connection_get(s->connection_track_table,
>                            &key,
>                            &s->conn_list);
> @@ -1225,6 +1251,7 @@ static void colo_compare_complete(UserCreatable *uc, Error **errp)
>      }
>  
>      g_queue_init(&s->conn_list);
> +    QLIST_INIT(&s->passthroughlist);
>  
>      s->connection_track_table = g_hash_table_new_full(connection_key_hash,
>                                                        connection_key_equal,
> @@ -1237,6 +1264,7 @@ static void colo_compare_complete(UserCreatable *uc, Error **errp)
>      if (!colo_compare_active) {
>          qemu_mutex_init(&event_mtx);
>          qemu_cond_init(&event_complete_cond);
> +        qemu_mutex_init(&s->passthroughlist_mutex);

This initializes the mutex only for the first colo-compare object that is created. The mutex has to be initialized every time, as it separate for each
colo-compare object.

>          colo_compare_active = true;
>      }
>      QTAILQ_INSERT_TAIL(&net_compares, s, next);
> diff --git a/net/colo-compare.h b/net/colo-compare.h
> index ab649c9dbe..7ca74de840 100644
> --- a/net/colo-compare.h
> +++ b/net/colo-compare.h
> @@ -23,6 +23,7 @@
>  #include "migration/migration.h"
>  #include "sysemu/iothread.h"
>  #include "colo.h"
> +#include <netdb.h>
>  
>  #define TYPE_COLO_COMPARE "colo-compare"
>  typedef struct CompareState CompareState;
> @@ -54,6 +55,15 @@ typedef struct COLOSendEntry {
>      uint8_t *buf;
>  } COLOSendEntry;
>  
> +typedef struct COLOPassthroughEntry {
> +    struct protoent *l4_protocol;
> +    int src_port;
> +    int dst_port;
> +    struct in_addr src_ip;
> +    struct in_addr dst_ip;
> +    QLIST_ENTRY(COLOPassthroughEntry) node;
> +} COLOPassthroughEntry;
> +
>  /*
>   *  + CompareState ++
>   *  |               |
> @@ -110,6 +120,8 @@ struct CompareState {
>  
>      QEMUBH *event_bh;
>      enum colo_event event;
> +    QLIST_HEAD(, COLOPassthroughEntry) passthroughlist;
> +    QemuMutex passthroughlist_mutex;
>  
>      QTAILQ_ENTRY(CompareState) next;
>  };



-- 


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH V6 1/6] qapi/net: Add IPFlowSpec and QMP command for COLO passthrough
  2021-04-20 15:15 ` [PATCH V6 1/6] qapi/net: Add IPFlowSpec and QMP command for COLO passthrough Zhang Chen
@ 2021-05-17 20:34   ` Lukas Straub
  0 siblings, 0 replies; 13+ messages in thread
From: Lukas Straub @ 2021-05-17 20:34 UTC (permalink / raw)
  To: Zhang Chen
  Cc: Daniel P. Berrangé,
	Li Zhijian, Jason Wang, Markus Armbruster, qemu-dev,
	Gerd Hoffmann, Zhang Chen, Dr. David Alan Gilbert


[-- Attachment #1: Type: text/plain, Size: 4072 bytes --]

On Tue, 20 Apr 2021 23:15:32 +0800
Zhang Chen <chen.zhang@intel.com> wrote:

> Since the real user scenario does not need COLO to monitor all traffic.
> Add colo-passthrough-add and colo-passthrough-del to maintain
> a COLO network passthrough list. Add IPFlowSpec struct for all QMP commands.
> Except protocol field is necessary, other fields are optional.
> 
> Signed-off-by: Zhang Chen <chen.zhang@intel.com>
> ---
>  net/net.c     | 10 ++++++++
>  qapi/net.json | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 78 insertions(+)
> 
> diff --git a/net/net.c b/net/net.c
> index edf9b95418..2a6e5f3886 100644
> --- a/net/net.c
> +++ b/net/net.c
> @@ -1196,6 +1196,16 @@ void qmp_netdev_del(const char *id, Error **errp)
>      }
>  }
>  
> +void qmp_colo_passthrough_add(IPFlowSpec *spec, Error **errp)
> +{
> +    /* TODO implement setup passthrough rule */
> +}
> +
> +void qmp_colo_passthrough_del(IPFlowSpec *spec, Error **errp)
> +{
> +    /* TODO implement delete passthrough rule */
> +}
> +
>  static void netfilter_print_info(Monitor *mon, NetFilterState *nf)
>  {
>      char *str;
> diff --git a/qapi/net.json b/qapi/net.json
> index af3f5b0fda..f6e4e37526 100644
> --- a/qapi/net.json
> +++ b/qapi/net.json
> @@ -7,6 +7,7 @@
>  ##
>  
>  { 'include': 'common.json' }
> +{ 'include': 'sockets.json' }
>  
>  ##
>  # @set_link:
> @@ -694,3 +695,70 @@
>  ##
>  { 'event': 'FAILOVER_NEGOTIATED',
>    'data': {'device-id': 'str'} }
> +
> +##
> +# @IPFlowSpec:

I think something like "@IPFilterRule" is clearer.

> +# IP flow specification.

"IP filter rule specification"

> +# @protocol: Transport layer protocol like TCP/UDP...
> +#
> +# @object-name: Point out the IPflow spec effective range of object,
> +#               If there is no such part, it means global spec.

I think IPFlowSpec should be kept generic, so object-name should not be
part of it. It should move directly to 'colo-passthrough-add' and
'colo-passthrough-del'.

Also please use clearer wording. Proposal:
"@object-name: The id of the colo-compare object to add the filter to."

Again, if other net filters support the new feature in the future, the
wording can always be changed later.

> +# @source: Source address and port.
> +#
> +# @destination: Destination address and port.
> +#
> +# Since: 6.1
> +##
> +{ 'struct': 'IPFlowSpec',
> +  'data': { 'protocol': 'str', '*object-name': 'str',
> +    '*source': 'InetSocketAddressBase',
> +    '*destination': 'InetSocketAddressBase' } }

I think 'protocol' should be made optional too.

> +##
> +# @colo-passthrough-add:
> +#
> +# Add passthrough entry according to user's needs in COLO-compare.
> +# Source IP/port and destination IP/port both optional, If user just
> +# input parts of infotmation, it will match all.
> +#
> +# Returns: Nothing on success
> +#
> +# Since: 6.1
> +#
> +# Example:
> +#
> +# -> { "execute": "colo-passthrough-add",
> +#      "arguments": { "protocol": "tcp", "object-name": "object0",
> +#      "source": {"host": "192.168.1.1", "port": "1234"},
> +#      "destination": {"host": "192.168.1.2", "port": "4321"} } }
> +# <- { "return": {} }
> +#
> +##
> +{ 'command': 'colo-passthrough-add', 'boxed': true,
> +     'data': 'IPFlowSpec' }
> +
> +##
> +# @colo-passthrough-del:
> +#
> +# Delete passthrough entry according to user's needs in COLO-compare.
> +# Source IP/port and destination IP/port both optional, If user just
> +# input parts of infotmation, it will match all.
> +#
> +# Returns: Nothing on success
> +#
> +# Since: 6.1
> +#
> +# Example:
> +#
> +# -> { "execute": "colo-passthrough-del",
> +#      "arguments": { "protocol": "tcp", "object-name": "object0",
> +#      "source": {"host": "192.168.1.1", "port": "1234"},
> +#      "destination": {"host": "192.168.1.2", "port": "4321"} } }
> +# <- { "return": {} }
> +#
> +##
> +{ 'command': 'colo-passthrough-del', 'boxed': true,
> +     'data': 'IPFlowSpec' }



-- 


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH V6 6/6] net/net.c: Add handler for COLO passthrough connection
  2021-04-20 15:15 ` [PATCH V6 6/6] net/net.c: Add handler for COLO passthrough connection Zhang Chen
@ 2021-05-17 20:38   ` Lukas Straub
  0 siblings, 0 replies; 13+ messages in thread
From: Lukas Straub @ 2021-05-17 20:38 UTC (permalink / raw)
  To: Zhang Chen
  Cc: Daniel P. Berrangé,
	Li Zhijian, Jason Wang, Markus Armbruster, qemu-dev,
	Gerd Hoffmann, Zhang Chen, Dr. David Alan Gilbert


[-- Attachment #1: Type: text/plain, Size: 6862 bytes --]

On Tue, 20 Apr 2021 23:15:37 +0800
Zhang Chen <chen.zhang@intel.com> wrote:

> Use connection protocol,src port,dst port,src ip,dst ip as the key
> to bypass certain network traffic in COLO compare.
> 
> Signed-off-by: Zhang Chen <chen.zhang@intel.com>
> ---
>  net/net.c | 160 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 158 insertions(+), 2 deletions(-)
> 
> diff --git a/net/net.c b/net/net.c
> index 2a6e5f3886..9b0de0f332 100644
> --- a/net/net.c
> +++ b/net/net.c
> @@ -56,6 +56,8 @@
>  #include "sysemu/sysemu.h"
>  #include "net/filter.h"
>  #include "qapi/string-output-visitor.h"
> +#include "net/colo-compare.h"
> +#include "qom/object_interfaces.h"
>  
>  /* Net bridge is currently not supported for W32. */
>  #if !defined(_WIN32)
> @@ -1196,14 +1198,168 @@ void qmp_netdev_del(const char *id, Error **errp)
>      }
>  }
>  
> +static CompareState *colo_passthrough_check(IPFlowSpec *spec, Error **errp)
> +{
> +    Object *container;
> +    Object *obj;
> +    CompareState *s;
> +
> +    if (!spec->object_name) {
> +        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "object-name",
> +                   "Need input colo-compare object name");
> +        return NULL;
> +    }
> +
> +    container = object_get_objects_root();
> +    obj = object_resolve_path_component(container, spec->object_name);
> +    if (!obj) {
> +        error_setg(errp, "colo-compare '%s' not found", spec->object_name);
> +        return NULL;
> +    }
> +
> +    s = COLO_COMPARE(obj);
> +
> +    if (!getprotobyname(spec->protocol)) {
> +        error_setg(errp, "COLO pass through get wrong protocol");
> +        return NULL;
> +    }
> +
> +    if ((spec->source->host && !qemu_isdigit(spec->source->host[0])) ||
> +        (spec->destination->host &&
> +        !qemu_isdigit(spec->destination->host[0]))) {
> +        error_setg(errp, "COLO pass through get wrong IP");
> +        return NULL;
> +    }
> +
> +    if (atoi(spec->source->port) > 65536 || atoi(spec->source->port) < 0 ||
> +        atoi(spec->destination->port) > 65536 ||
> +        atoi(spec->destination->port) < 0) {
> +        error_setg(errp, "COLO pass through get wrong port");
> +        return NULL;
> +    }
> +
> +    return s;
> +}
> +
> +static void compare_passthrough_add(CompareState *s,
> +                                    IPFlowSpec *spec,
> +                                    Error **errp)
> +{
> +    COLOPassthroughEntry *pass = NULL, *next = NULL, *origin = NULL;
> +
> +    pass = g_new0(COLOPassthroughEntry, 1);
> +
> +    pass->l4_protocol = getprotobyname(spec->protocol);
> +    pass->src_port = atoi(spec->source->port);
> +    pass->dst_port = atoi(spec->destination->port);
> +
> +    if (!inet_aton(spec->source->host, &pass->src_ip)) {
> +        pass->src_ip.s_addr = 0;
> +    }
> +
> +    if (!inet_aton(spec->destination->host, &pass->dst_ip)) {
> +        pass->dst_ip.s_addr = 0;
> +    }
> +
> +    qemu_mutex_lock(&s->passthroughlist_mutex);
> +    if (!QLIST_EMPTY(&s->passthroughlist)) {
> +        QLIST_FOREACH_SAFE(origin, &s->passthroughlist, node, next) {
> +            if ((pass->l4_protocol->p_proto == origin->l4_protocol->p_proto) &&
> +                (pass->src_port == origin->src_port) &&
> +                (pass->dst_port == origin->dst_port) &&
> +                (pass->src_ip.s_addr == origin->src_ip.s_addr) &&
> +                (pass->dst_ip.s_addr == origin->dst_ip.s_addr)) {
> +                error_setg(errp, "The pass through connection already exists");
> +                g_free(pass);
> +                qemu_mutex_unlock(&s->passthroughlist_mutex);
> +                return;
> +            }
> +        }
> +    }

I think this searching for a existing passthrough rule should move into
a function. The function can then be used in compare_passthrough_del
too.

> +    QLIST_INSERT_HEAD(&s->passthroughlist, pass, node);
> +    qemu_mutex_unlock(&s->passthroughlist_mutex);
> +}
> +
> +static void compare_passthrough_del(CompareState *s,
> +                                    IPFlowSpec *spec,
> +                                    Error **errp)
> +{
> +    COLOPassthroughEntry *pass = NULL, *next = NULL, *origin = NULL;
> +
> +    pass = g_new0(COLOPassthroughEntry, 1);
> +
> +    pass->l4_protocol = getprotobyname(spec->protocol);
> +    pass->src_port = atoi(spec->source->port);
> +    pass->dst_port = atoi(spec->destination->port);
> +
> +    if (!inet_aton(spec->source->host, &pass->src_ip)) {
> +        pass->src_ip.s_addr = 0;
> +    }
> +
> +    if (!inet_aton(spec->destination->host, &pass->dst_ip)) {
> +        pass->dst_ip.s_addr = 0;
> +    }
> +
> +    qemu_mutex_lock(&s->passthroughlist_mutex);
> +    if (!QLIST_EMPTY(&s->passthroughlist)) {
> +        QLIST_FOREACH_SAFE(origin, &s->passthroughlist, node, next) {
> +            if ((pass->l4_protocol->p_proto == origin->l4_protocol->p_proto) &&
> +                (pass->src_port == origin->src_port) &&
> +                (pass->dst_port == origin->dst_port) &&
> +                (pass->src_ip.s_addr == origin->src_ip.s_addr) &&
> +                (pass->dst_ip.s_addr == origin->dst_ip.s_addr)) {
> +                QLIST_REMOVE(origin, node);
> +                g_free(origin);
> +                g_free(pass);
> +                qemu_mutex_unlock(&s->passthroughlist_mutex);
> +                return;
> +            }
> +        }
> +        error_setg(errp, "The pass through list can't find the connection");
> +    } else {
> +        error_setg(errp, "The pass through connection list is empty");
> +    }
> +
> +    g_free(pass);
> +    qemu_mutex_unlock(&s->passthroughlist_mutex);
> +}
> +
> +
>  void qmp_colo_passthrough_add(IPFlowSpec *spec, Error **errp)
>  {
> -    /* TODO implement setup passthrough rule */
> +    CompareState *s;
> +    Error *err = NULL;
> +
> +    s = colo_passthrough_check(spec, &err);
> +    if (err) {
> +        error_propagate(errp, err);
> +        return;
> +    }
> +
> +    compare_passthrough_add(s, spec, &err);
> +    if (err) {
> +        error_propagate(errp, err);
> +        return;
> +    }
>  }
>  
>  void qmp_colo_passthrough_del(IPFlowSpec *spec, Error **errp)
>  {
> -    /* TODO implement delete passthrough rule */
> +    CompareState *s;
> +    Error *err = NULL;
> +
> +    s = colo_passthrough_check(spec, &err);
> +    if (err) {
> +        error_propagate(errp, err);
> +        return;
> +    }
> +
> +    compare_passthrough_del(s, spec, &err);
> +    if (err) {
> +        error_propagate(errp, err);
> +        return;
> +    }
>  }
>  
>  static void netfilter_print_info(Monitor *mon, NetFilterState *nf)



-- 


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, back to index

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-04-20 15:15 [PATCH V6 0/6] Passthrough specific network traffic in COLO Zhang Chen
2021-04-20 15:15 ` [PATCH V6 1/6] qapi/net: Add IPFlowSpec and QMP command for COLO passthrough Zhang Chen
2021-05-17 20:34   ` Lukas Straub
2021-04-20 15:15 ` [PATCH V6 2/6] util/qemu-sockets.c: Add inet_parse_base to handle InetSocketAddressBase Zhang Chen
2021-04-20 15:15 ` [PATCH V6 3/6] hmp-commands: Add new HMP command for COLO passthrough Zhang Chen
2021-04-20 15:15 ` [PATCH V6 4/6] net/colo-compare: Move data structure and define to .h file Zhang Chen
2021-05-17 20:03   ` Lukas Straub
2021-04-20 15:15 ` [PATCH V6 5/6] net/colo-compare: Add passthrough list to CompareState Zhang Chen
2021-05-17 20:07   ` Lukas Straub
2021-04-20 15:15 ` [PATCH V6 6/6] net/net.c: Add handler for COLO passthrough connection Zhang Chen
2021-05-17 20:38   ` Lukas Straub
2021-04-28  3:26 ` [PATCH V6 0/6] Passthrough specific network traffic in COLO Zhang, Chen
2021-05-12  7:05   ` Zhang, Chen

QEMU-Devel Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/qemu-devel/0 qemu-devel/git/0.git
	git clone --mirror https://lore.kernel.org/qemu-devel/1 qemu-devel/git/1.git
	git clone --mirror https://lore.kernel.org/qemu-devel/2 qemu-devel/git/2.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 qemu-devel qemu-devel/ https://lore.kernel.org/qemu-devel \
		qemu-devel@nongnu.org
	public-inbox-index qemu-devel

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.nongnu.qemu-devel


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git