From: Zhang Chen <chen.zh...@intel.com> Currently, we just use guest's TCP/UDP source port as the key to bypass certain network traffic.
Signed-off-by: Zhang Chen <chen.zh...@intel.com> --- net/colo-compare.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++ net/colo-compare.h | 2 ++ net/net.c | 27 +++++++++++++++++++++++++ 3 files changed, 78 insertions(+) diff --git a/net/colo-compare.c b/net/colo-compare.c index 337025b44f..11a32caa9b 100644 --- a/net/colo-compare.c +++ b/net/colo-compare.c @@ -46,6 +46,9 @@ static QTAILQ_HEAD(, CompareState) net_compares = static NotifierList colo_compare_notifiers = NOTIFIER_LIST_INITIALIZER(colo_compare_notifiers); +static QLIST_HEAD(, PassthroughEntry) passthroughlist = + QLIST_HEAD_INITIALIZER(passthroughlist); + #define COMPARE_READ_LEN_MAX NET_BUFSIZE #define MAX_QUEUE_SIZE 1024 @@ -103,6 +106,12 @@ typedef struct SendEntry { uint8_t *buf; } SendEntry; +typedef struct PassthroughEntry { + bool is_tcp; + uint16_t port; + QLIST_ENTRY(PassthroughEntry) node; +} PassthroughEntry; + struct CompareState { Object parent; @@ -247,6 +256,7 @@ static int packet_enqueue(CompareState *s, int mode, Connection **con) ConnectionKey key; Packet *pkt = NULL; Connection *conn; + PassthroughEntry *bypass, *next; int ret; if (mode == PRIMARY_IN) { @@ -264,8 +274,23 @@ static int packet_enqueue(CompareState *s, int mode, Connection **con) pkt = NULL; return -1; } + fill_connection_key(pkt, &key); + /* Check COLO passthrough connenction */ + if (!QLIST_EMPTY(&passthroughlist)) { + QLIST_FOREACH_SAFE(bypass, &passthroughlist, node, next) { + if (((key.ip_proto == IPPROTO_TCP) && bypass->is_tcp) || + ((key.ip_proto == IPPROTO_UDP) && !bypass->is_tcp)) { + if (bypass->port == key.src_port) { + packet_destroy(pkt, NULL); + pkt = NULL; + return -1; + } + } + } + } + conn = connection_get(s->connection_track_table, &key, &s->conn_list); @@ -1373,6 +1398,30 @@ static void colo_flush_packets(void *opaque, void *user_data) } } +void colo_compare_passthrough_add(bool is_tcp, const uint16_t port) +{ + PassthroughEntry *bypass = NULL; + + bypass = g_new0(PassthroughEntry, 1); + bypass->is_tcp = is_tcp; + bypass->port = port; + QLIST_INSERT_HEAD(&passthroughlist, bypass, node); +} + +void colo_compare_passthrough_del(bool is_tcp, const uint16_t port) +{ + PassthroughEntry *bypass = NULL, *next = NULL; + + if (!QLIST_EMPTY(&passthroughlist)) { + QLIST_FOREACH_SAFE(bypass, &passthroughlist, node, next) { + if ((bypass->is_tcp == is_tcp) && (bypass->port == port)) { + QLIST_REMOVE(bypass, node); + g_free(bypass); + } + } + } +} + static void colo_compare_class_init(ObjectClass *oc, void *data) { UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); diff --git a/net/colo-compare.h b/net/colo-compare.h index 22ddd512e2..1fa026c85e 100644 --- a/net/colo-compare.h +++ b/net/colo-compare.h @@ -20,5 +20,7 @@ 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); +void colo_compare_passthrough_add(bool is_tcp, const uint16_t port); +void colo_compare_passthrough_del(bool is_tcp, const uint16_t port); #endif /* QEMU_COLO_COMPARE_H */ diff --git a/net/net.c b/net/net.c index eac7a92618..1f303e8309 100644 --- a/net/net.c +++ b/net/net.c @@ -55,6 +55,7 @@ #include "sysemu/sysemu.h" #include "net/filter.h" #include "qapi/string-output-visitor.h" +#include "net/colo-compare.h" /* Net bridge is currently not supported for W32. */ #if !defined(_WIN32) @@ -1155,12 +1156,38 @@ void qmp_colo_passthrough_add(const char *prot, const uint32_t port, Error **errp) { /* Setup passthrough connection */ + if (port > 65536) { + error_setg(errp, "COLO pass through get wrong port"); + return; + } + + if (!strcmp(prot, "tcp") || !strcmp(prot, "TCP")) { + colo_compare_passthrough_add(true, (uint16_t)port); + } else if (!strcmp(prot, "udp") || !strcmp(prot, "UDP")) { + colo_compare_passthrough_add(false, (uint16_t)port); + } else { + error_setg(errp, "COLO pass through just support tcp or udp protocol"); + return; + } } void qmp_colo_passthrough_del(const char *prot, const uint32_t port, Error **errp) { /* Delete passthrough connection */ + if (port > 65536) { + error_setg(errp, "COLO pass through get wrong port"); + return; + } + + if (!strcmp(prot, "tcp") || !strcmp(prot, "TCP")) { + colo_compare_passthrough_del(true, (uint16_t)port); + } else if (!strcmp(prot, "udp") || !strcmp(prot, "UDP")) { + colo_compare_passthrough_del(false, (uint16_t)port); + } else { + error_setg(errp, "COLO pass through just support tcp or udp protocol"); + return; + } } static void netfilter_print_info(Monitor *mon, NetFilterState *nf) -- 2.17.1