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