xref: /qemu/net/filter-rewriter.c (revision afe461240940077e7ea8313e9c547a4898263cd2)
1e6eee8abSZhang Chen /*
2e6eee8abSZhang Chen  * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
3e6eee8abSZhang Chen  * Copyright (c) 2016 FUJITSU LIMITED
4e6eee8abSZhang Chen  * Copyright (c) 2016 Intel Corporation
5e6eee8abSZhang Chen  *
6e6eee8abSZhang Chen  * Author: Zhang Chen <zhangchen.fnst@cn.fujitsu.com>
7e6eee8abSZhang Chen  *
8e6eee8abSZhang Chen  * This work is licensed under the terms of the GNU GPL, version 2 or
9e6eee8abSZhang Chen  * later.  See the COPYING file in the top-level directory.
10e6eee8abSZhang Chen  */
11e6eee8abSZhang Chen 
12e6eee8abSZhang Chen #include "qemu/osdep.h"
13e6eee8abSZhang Chen #include "net/colo.h"
14e6eee8abSZhang Chen #include "net/filter.h"
15e6eee8abSZhang Chen #include "net/net.h"
16e6eee8abSZhang Chen #include "qemu-common.h"
17e6eee8abSZhang Chen #include "qapi/error.h"
18e6eee8abSZhang Chen #include "qapi/qmp/qerror.h"
19e6eee8abSZhang Chen #include "qapi-visit.h"
20e6eee8abSZhang Chen #include "qom/object.h"
21e6eee8abSZhang Chen #include "qemu/main-loop.h"
22e6eee8abSZhang Chen #include "qemu/iov.h"
23e6eee8abSZhang Chen #include "net/checksum.h"
24e6eee8abSZhang Chen 
25e6eee8abSZhang Chen #define FILTER_COLO_REWRITER(obj) \
26e6eee8abSZhang Chen     OBJECT_CHECK(RewriterState, (obj), TYPE_FILTER_REWRITER)
27e6eee8abSZhang Chen 
28e6eee8abSZhang Chen #define TYPE_FILTER_REWRITER "filter-rewriter"
29e6eee8abSZhang Chen 
30e6eee8abSZhang Chen typedef struct RewriterState {
31e6eee8abSZhang Chen     NetFilterState parent_obj;
32e6eee8abSZhang Chen     NetQueue *incoming_queue;
33e6eee8abSZhang Chen     /* hashtable to save connection */
34e6eee8abSZhang Chen     GHashTable *connection_track_table;
35e6eee8abSZhang Chen } RewriterState;
36e6eee8abSZhang Chen 
37e6eee8abSZhang Chen static void filter_rewriter_flush(NetFilterState *nf)
38e6eee8abSZhang Chen {
39e6eee8abSZhang Chen     RewriterState *s = FILTER_COLO_REWRITER(nf);
40e6eee8abSZhang Chen 
41e6eee8abSZhang Chen     if (!qemu_net_queue_flush(s->incoming_queue)) {
42e6eee8abSZhang Chen         /* Unable to empty the queue, purge remaining packets */
43e6eee8abSZhang Chen         qemu_net_queue_purge(s->incoming_queue, nf->netdev);
44e6eee8abSZhang Chen     }
45e6eee8abSZhang Chen }
46e6eee8abSZhang Chen 
47*afe46124SZhang Chen /*
48*afe46124SZhang Chen  * Return 1 on success, if return 0 means the pkt
49*afe46124SZhang Chen  * is not TCP packet
50*afe46124SZhang Chen  */
51*afe46124SZhang Chen static int is_tcp_packet(Packet *pkt)
52*afe46124SZhang Chen {
53*afe46124SZhang Chen     if (!parse_packet_early(pkt) &&
54*afe46124SZhang Chen         pkt->ip->ip_p == IPPROTO_TCP) {
55*afe46124SZhang Chen         return 1;
56*afe46124SZhang Chen     } else {
57*afe46124SZhang Chen         return 0;
58*afe46124SZhang Chen     }
59*afe46124SZhang Chen }
60*afe46124SZhang Chen 
61e6eee8abSZhang Chen static ssize_t colo_rewriter_receive_iov(NetFilterState *nf,
62e6eee8abSZhang Chen                                          NetClientState *sender,
63e6eee8abSZhang Chen                                          unsigned flags,
64e6eee8abSZhang Chen                                          const struct iovec *iov,
65e6eee8abSZhang Chen                                          int iovcnt,
66e6eee8abSZhang Chen                                          NetPacketSent *sent_cb)
67e6eee8abSZhang Chen {
68*afe46124SZhang Chen     RewriterState *s = FILTER_COLO_REWRITER(nf);
69*afe46124SZhang Chen     Connection *conn;
70*afe46124SZhang Chen     ConnectionKey key;
71*afe46124SZhang Chen     Packet *pkt;
72*afe46124SZhang Chen     ssize_t size = iov_size(iov, iovcnt);
73*afe46124SZhang Chen     char *buf = g_malloc0(size);
74*afe46124SZhang Chen 
75*afe46124SZhang Chen     iov_to_buf(iov, iovcnt, 0, buf, size);
76*afe46124SZhang Chen     pkt = packet_new(buf, size);
77*afe46124SZhang Chen 
78e6eee8abSZhang Chen     /*
79e6eee8abSZhang Chen      * if we get tcp packet
80e6eee8abSZhang Chen      * we will rewrite it to make secondary guest's
81e6eee8abSZhang Chen      * connection established successfully
82e6eee8abSZhang Chen      */
83*afe46124SZhang Chen     if (pkt && is_tcp_packet(pkt)) {
84*afe46124SZhang Chen 
85*afe46124SZhang Chen         fill_connection_key(pkt, &key);
86*afe46124SZhang Chen 
87*afe46124SZhang Chen         if (sender == nf->netdev) {
88*afe46124SZhang Chen             /*
89*afe46124SZhang Chen              * We need make tcp TX and RX packet
90*afe46124SZhang Chen              * into one connection.
91*afe46124SZhang Chen              */
92*afe46124SZhang Chen             reverse_connection_key(&key);
93*afe46124SZhang Chen         }
94*afe46124SZhang Chen         conn = connection_get(s->connection_track_table,
95*afe46124SZhang Chen                               &key,
96*afe46124SZhang Chen                               NULL);
97*afe46124SZhang Chen 
98*afe46124SZhang Chen         if (sender == nf->netdev) {
99*afe46124SZhang Chen             /* NET_FILTER_DIRECTION_TX */
100*afe46124SZhang Chen             /* handle_primary_tcp_pkt */
101*afe46124SZhang Chen         } else {
102*afe46124SZhang Chen             /* NET_FILTER_DIRECTION_RX */
103*afe46124SZhang Chen             /* handle_secondary_tcp_pkt */
104*afe46124SZhang Chen         }
105*afe46124SZhang Chen     }
106*afe46124SZhang Chen 
107*afe46124SZhang Chen     packet_destroy(pkt, NULL);
108*afe46124SZhang Chen     pkt = NULL;
109e6eee8abSZhang Chen     return 0;
110e6eee8abSZhang Chen }
111e6eee8abSZhang Chen 
112e6eee8abSZhang Chen static void colo_rewriter_cleanup(NetFilterState *nf)
113e6eee8abSZhang Chen {
114e6eee8abSZhang Chen     RewriterState *s = FILTER_COLO_REWRITER(nf);
115e6eee8abSZhang Chen 
116e6eee8abSZhang Chen     /* flush packets */
117e6eee8abSZhang Chen     if (s->incoming_queue) {
118e6eee8abSZhang Chen         filter_rewriter_flush(nf);
119e6eee8abSZhang Chen         g_free(s->incoming_queue);
120e6eee8abSZhang Chen     }
121e6eee8abSZhang Chen }
122e6eee8abSZhang Chen 
123e6eee8abSZhang Chen static void colo_rewriter_setup(NetFilterState *nf, Error **errp)
124e6eee8abSZhang Chen {
125e6eee8abSZhang Chen     RewriterState *s = FILTER_COLO_REWRITER(nf);
126e6eee8abSZhang Chen 
127e6eee8abSZhang Chen     s->connection_track_table = g_hash_table_new_full(connection_key_hash,
128e6eee8abSZhang Chen                                                       connection_key_equal,
129e6eee8abSZhang Chen                                                       g_free,
130e6eee8abSZhang Chen                                                       connection_destroy);
131e6eee8abSZhang Chen     s->incoming_queue = qemu_new_net_queue(qemu_netfilter_pass_to_next, nf);
132e6eee8abSZhang Chen }
133e6eee8abSZhang Chen 
134e6eee8abSZhang Chen static void colo_rewriter_class_init(ObjectClass *oc, void *data)
135e6eee8abSZhang Chen {
136e6eee8abSZhang Chen     NetFilterClass *nfc = NETFILTER_CLASS(oc);
137e6eee8abSZhang Chen 
138e6eee8abSZhang Chen     nfc->setup = colo_rewriter_setup;
139e6eee8abSZhang Chen     nfc->cleanup = colo_rewriter_cleanup;
140e6eee8abSZhang Chen     nfc->receive_iov = colo_rewriter_receive_iov;
141e6eee8abSZhang Chen }
142e6eee8abSZhang Chen 
143e6eee8abSZhang Chen static const TypeInfo colo_rewriter_info = {
144e6eee8abSZhang Chen     .name = TYPE_FILTER_REWRITER,
145e6eee8abSZhang Chen     .parent = TYPE_NETFILTER,
146e6eee8abSZhang Chen     .class_init = colo_rewriter_class_init,
147e6eee8abSZhang Chen     .instance_size = sizeof(RewriterState),
148e6eee8abSZhang Chen };
149e6eee8abSZhang Chen 
150e6eee8abSZhang Chen static void register_types(void)
151e6eee8abSZhang Chen {
152e6eee8abSZhang Chen     type_register_static(&colo_rewriter_info);
153e6eee8abSZhang Chen }
154e6eee8abSZhang Chen 
155e6eee8abSZhang Chen type_init(register_types);
156