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" 1330656b09SZhang Chen #include "trace.h" 14f27f01dbSMichael S. Tsirkin #include "colo.h" 15e6eee8abSZhang Chen #include "net/filter.h" 16e6eee8abSZhang Chen #include "net/net.h" 17e6eee8abSZhang Chen #include "qemu-common.h" 184b39bdceSZhang Chen #include "qemu/error-report.h" 19e6eee8abSZhang Chen #include "qom/object.h" 20e6eee8abSZhang Chen #include "qemu/main-loop.h" 21e6eee8abSZhang Chen #include "qemu/iov.h" 22e6eee8abSZhang Chen #include "net/checksum.h" 23*24525e93SZhang Chen #include "net/colo.h" 24*24525e93SZhang Chen #include "migration/colo.h" 25e6eee8abSZhang Chen 26e6eee8abSZhang Chen #define FILTER_COLO_REWRITER(obj) \ 27e6eee8abSZhang Chen OBJECT_CHECK(RewriterState, (obj), TYPE_FILTER_REWRITER) 28e6eee8abSZhang Chen 29e6eee8abSZhang Chen #define TYPE_FILTER_REWRITER "filter-rewriter" 30*24525e93SZhang Chen #define FAILOVER_MODE_ON true 31*24525e93SZhang Chen #define FAILOVER_MODE_OFF false 32e6eee8abSZhang Chen 33e6eee8abSZhang Chen typedef struct RewriterState { 34e6eee8abSZhang Chen NetFilterState parent_obj; 35e6eee8abSZhang Chen NetQueue *incoming_queue; 36e6eee8abSZhang Chen /* hashtable to save connection */ 37e6eee8abSZhang Chen GHashTable *connection_track_table; 384b39bdceSZhang Chen bool vnet_hdr; 39*24525e93SZhang Chen bool failover_mode; 40e6eee8abSZhang Chen } RewriterState; 41e6eee8abSZhang Chen 42*24525e93SZhang Chen static void filter_rewriter_failover_mode(RewriterState *s) 43*24525e93SZhang Chen { 44*24525e93SZhang Chen s->failover_mode = FAILOVER_MODE_ON; 45*24525e93SZhang Chen } 46*24525e93SZhang Chen 47e6eee8abSZhang Chen static void filter_rewriter_flush(NetFilterState *nf) 48e6eee8abSZhang Chen { 49e6eee8abSZhang Chen RewriterState *s = FILTER_COLO_REWRITER(nf); 50e6eee8abSZhang Chen 51e6eee8abSZhang Chen if (!qemu_net_queue_flush(s->incoming_queue)) { 52e6eee8abSZhang Chen /* Unable to empty the queue, purge remaining packets */ 53e6eee8abSZhang Chen qemu_net_queue_purge(s->incoming_queue, nf->netdev); 54e6eee8abSZhang Chen } 55e6eee8abSZhang Chen } 56e6eee8abSZhang Chen 57afe46124SZhang Chen /* 58afe46124SZhang Chen * Return 1 on success, if return 0 means the pkt 59afe46124SZhang Chen * is not TCP packet 60afe46124SZhang Chen */ 61afe46124SZhang Chen static int is_tcp_packet(Packet *pkt) 62afe46124SZhang Chen { 63afe46124SZhang Chen if (!parse_packet_early(pkt) && 64afe46124SZhang Chen pkt->ip->ip_p == IPPROTO_TCP) { 65afe46124SZhang Chen return 1; 66afe46124SZhang Chen } else { 67afe46124SZhang Chen return 0; 68afe46124SZhang Chen } 69afe46124SZhang Chen } 70afe46124SZhang Chen 7130656b09SZhang Chen /* handle tcp packet from primary guest */ 726214231aSZhang Chen static int handle_primary_tcp_pkt(RewriterState *rf, 7330656b09SZhang Chen Connection *conn, 746214231aSZhang Chen Packet *pkt, ConnectionKey *key) 7530656b09SZhang Chen { 7630656b09SZhang Chen struct tcphdr *tcp_pkt; 7730656b09SZhang Chen 7830656b09SZhang Chen tcp_pkt = (struct tcphdr *)pkt->transport_header; 79d87aa138SStefan Hajnoczi if (trace_event_get_state_backends(TRACE_COLO_FILTER_REWRITER_DEBUG)) { 802061c14cSZhang Chen trace_colo_filter_rewriter_pkt_info(__func__, 812061c14cSZhang Chen inet_ntoa(pkt->ip->ip_src), inet_ntoa(pkt->ip->ip_dst), 8230656b09SZhang Chen ntohl(tcp_pkt->th_seq), ntohl(tcp_pkt->th_ack), 8330656b09SZhang Chen tcp_pkt->th_flags); 8430656b09SZhang Chen trace_colo_filter_rewriter_conn_offset(conn->offset); 8530656b09SZhang Chen } 8630656b09SZhang Chen 876214231aSZhang Chen if (((tcp_pkt->th_flags & (TH_ACK | TH_SYN)) == (TH_ACK | TH_SYN)) && 886214231aSZhang Chen conn->tcp_state == TCPS_SYN_SENT) { 896214231aSZhang Chen conn->tcp_state = TCPS_ESTABLISHED; 906214231aSZhang Chen } 916214231aSZhang Chen 9230656b09SZhang Chen if (((tcp_pkt->th_flags & (TH_ACK | TH_SYN)) == TH_SYN)) { 9330656b09SZhang Chen /* 9430656b09SZhang Chen * we use this flag update offset func 9530656b09SZhang Chen * run once in independent tcp connection 9630656b09SZhang Chen */ 976214231aSZhang Chen conn->tcp_state = TCPS_SYN_RECEIVED; 9830656b09SZhang Chen } 9930656b09SZhang Chen 10030656b09SZhang Chen if (((tcp_pkt->th_flags & (TH_ACK | TH_SYN)) == TH_ACK)) { 1016214231aSZhang Chen if (conn->tcp_state == TCPS_SYN_RECEIVED) { 10230656b09SZhang Chen /* 10330656b09SZhang Chen * offset = secondary_seq - primary seq 10430656b09SZhang Chen * ack packet sent by guest from primary node, 10530656b09SZhang Chen * so we use th_ack - 1 get primary_seq 10630656b09SZhang Chen */ 10730656b09SZhang Chen conn->offset -= (ntohl(tcp_pkt->th_ack) - 1); 1086214231aSZhang Chen conn->tcp_state = TCPS_ESTABLISHED; 10930656b09SZhang Chen } 110db0a762eSzhanghailiang if (conn->offset) { 11130656b09SZhang Chen /* handle packets to the secondary from the primary */ 11230656b09SZhang Chen tcp_pkt->th_ack = htonl(ntohl(tcp_pkt->th_ack) + conn->offset); 11330656b09SZhang Chen 1146ce310b5SZhang Chen net_checksum_calculate((uint8_t *)pkt->data + pkt->vnet_hdr_len, 1156ce310b5SZhang Chen pkt->size - pkt->vnet_hdr_len); 11630656b09SZhang Chen } 1176214231aSZhang Chen 1186214231aSZhang Chen /* 1196214231aSZhang Chen * Passive close step 3 1206214231aSZhang Chen */ 1216214231aSZhang Chen if ((conn->tcp_state == TCPS_LAST_ACK) && 1226214231aSZhang Chen (ntohl(tcp_pkt->th_ack) == (conn->fin_ack_seq + 1))) { 1236214231aSZhang Chen conn->tcp_state = TCPS_CLOSED; 1246214231aSZhang Chen g_hash_table_remove(rf->connection_track_table, key); 1256214231aSZhang Chen } 1266214231aSZhang Chen } 1276214231aSZhang Chen 1286214231aSZhang Chen if ((tcp_pkt->th_flags & TH_FIN) == TH_FIN) { 1296214231aSZhang Chen /* 1306214231aSZhang Chen * Passive close. 1316214231aSZhang Chen * Step 1: 1326214231aSZhang Chen * The *server* side of this connect is VM, *client* tries to close 1336214231aSZhang Chen * the connection. We will into CLOSE_WAIT status. 1346214231aSZhang Chen * 1356214231aSZhang Chen * Step 2: 1366214231aSZhang Chen * In this step we will into LAST_ACK status. 1376214231aSZhang Chen * 1386214231aSZhang Chen * We got 'fin=1, ack=1' packet from server side, we need to 1396214231aSZhang Chen * record the seq of 'fin=1, ack=1' packet. 1406214231aSZhang Chen * 1416214231aSZhang Chen * Step 3: 1426214231aSZhang Chen * We got 'ack=1' packets from client side, it acks 'fin=1, ack=1' 1436214231aSZhang Chen * packet from server side. From this point, we can ensure that there 1446214231aSZhang Chen * will be no packets in the connection, except that, some errors 1456214231aSZhang Chen * happen between the path of 'filter object' and vNIC, if this rare 1466214231aSZhang Chen * case really happen, we can still create a new connection, 1476214231aSZhang Chen * So it is safe to remove the connection from connection_track_table. 1486214231aSZhang Chen * 1496214231aSZhang Chen */ 1506214231aSZhang Chen if (conn->tcp_state == TCPS_ESTABLISHED) { 1516214231aSZhang Chen conn->tcp_state = TCPS_CLOSE_WAIT; 1526214231aSZhang Chen } 1536214231aSZhang Chen 1546214231aSZhang Chen /* 1556214231aSZhang Chen * Active close step 2. 1566214231aSZhang Chen */ 1576214231aSZhang Chen if (conn->tcp_state == TCPS_FIN_WAIT_1) { 1586214231aSZhang Chen conn->tcp_state = TCPS_TIME_WAIT; 1596214231aSZhang Chen /* 1606214231aSZhang Chen * For simplify implementation, we needn't wait 2MSL time 1616214231aSZhang Chen * in filter rewriter. Because guest kernel will track the 1626214231aSZhang Chen * TCP status and wait 2MSL time, if client resend the FIN 1636214231aSZhang Chen * packet, guest will apply the last ACK too. 1646214231aSZhang Chen */ 1656214231aSZhang Chen conn->tcp_state = TCPS_CLOSED; 1666214231aSZhang Chen g_hash_table_remove(rf->connection_track_table, key); 1676214231aSZhang Chen } 168db0a762eSzhanghailiang } 16930656b09SZhang Chen 17030656b09SZhang Chen return 0; 17130656b09SZhang Chen } 17230656b09SZhang Chen 17330656b09SZhang Chen /* handle tcp packet from secondary guest */ 1746214231aSZhang Chen static int handle_secondary_tcp_pkt(RewriterState *rf, 17530656b09SZhang Chen Connection *conn, 1766214231aSZhang Chen Packet *pkt, ConnectionKey *key) 17730656b09SZhang Chen { 17830656b09SZhang Chen struct tcphdr *tcp_pkt; 17930656b09SZhang Chen 18030656b09SZhang Chen tcp_pkt = (struct tcphdr *)pkt->transport_header; 18130656b09SZhang Chen 182d87aa138SStefan Hajnoczi if (trace_event_get_state_backends(TRACE_COLO_FILTER_REWRITER_DEBUG)) { 1832061c14cSZhang Chen trace_colo_filter_rewriter_pkt_info(__func__, 1842061c14cSZhang Chen inet_ntoa(pkt->ip->ip_src), inet_ntoa(pkt->ip->ip_dst), 18530656b09SZhang Chen ntohl(tcp_pkt->th_seq), ntohl(tcp_pkt->th_ack), 18630656b09SZhang Chen tcp_pkt->th_flags); 18730656b09SZhang Chen trace_colo_filter_rewriter_conn_offset(conn->offset); 18830656b09SZhang Chen } 18930656b09SZhang Chen 1906214231aSZhang Chen if (conn->tcp_state == TCPS_SYN_RECEIVED && 1916214231aSZhang Chen ((tcp_pkt->th_flags & (TH_ACK | TH_SYN)) == (TH_ACK | TH_SYN))) { 19230656b09SZhang Chen /* 19330656b09SZhang Chen * save offset = secondary_seq and then 19430656b09SZhang Chen * in handle_primary_tcp_pkt make offset 19530656b09SZhang Chen * = secondary_seq - primary_seq 19630656b09SZhang Chen */ 19730656b09SZhang Chen conn->offset = ntohl(tcp_pkt->th_seq); 19830656b09SZhang Chen } 19930656b09SZhang Chen 2006214231aSZhang Chen /* VM active connect */ 2016214231aSZhang Chen if (conn->tcp_state == TCPS_CLOSED && 2026214231aSZhang Chen ((tcp_pkt->th_flags & (TH_ACK | TH_SYN)) == TH_SYN)) { 2036214231aSZhang Chen conn->tcp_state = TCPS_SYN_SENT; 2046214231aSZhang Chen } 2056214231aSZhang Chen 20630656b09SZhang Chen if ((tcp_pkt->th_flags & (TH_ACK | TH_SYN)) == TH_ACK) { 207db0a762eSzhanghailiang /* Only need to adjust seq while offset is Non-zero */ 208db0a762eSzhanghailiang if (conn->offset) { 20930656b09SZhang Chen /* handle packets to the primary from the secondary*/ 21030656b09SZhang Chen tcp_pkt->th_seq = htonl(ntohl(tcp_pkt->th_seq) - conn->offset); 21130656b09SZhang Chen 2126ce310b5SZhang Chen net_checksum_calculate((uint8_t *)pkt->data + pkt->vnet_hdr_len, 2136ce310b5SZhang Chen pkt->size - pkt->vnet_hdr_len); 21430656b09SZhang Chen } 215db0a762eSzhanghailiang } 21630656b09SZhang Chen 2176214231aSZhang Chen /* 2186214231aSZhang Chen * Passive close step 2: 2196214231aSZhang Chen */ 2206214231aSZhang Chen if (conn->tcp_state == TCPS_CLOSE_WAIT && 2216214231aSZhang Chen (tcp_pkt->th_flags & (TH_ACK | TH_FIN)) == (TH_ACK | TH_FIN)) { 2226214231aSZhang Chen conn->fin_ack_seq = ntohl(tcp_pkt->th_seq); 2236214231aSZhang Chen conn->tcp_state = TCPS_LAST_ACK; 2246214231aSZhang Chen } 2256214231aSZhang Chen 2266214231aSZhang Chen /* 2276214231aSZhang Chen * Active close 2286214231aSZhang Chen * 2296214231aSZhang Chen * Step 1: 2306214231aSZhang Chen * The *server* side of this connect is VM, *server* tries to close 2316214231aSZhang Chen * the connection. 2326214231aSZhang Chen * 2336214231aSZhang Chen * Step 2: 2346214231aSZhang Chen * We will into CLOSE_WAIT status. 2356214231aSZhang Chen * We simplify the TCPS_FIN_WAIT_2, TCPS_TIME_WAIT and 2366214231aSZhang Chen * CLOSING status. 2376214231aSZhang Chen */ 2386214231aSZhang Chen if (conn->tcp_state == TCPS_ESTABLISHED && 2396214231aSZhang Chen (tcp_pkt->th_flags & (TH_ACK | TH_FIN)) == TH_FIN) { 2406214231aSZhang Chen conn->tcp_state = TCPS_FIN_WAIT_1; 2416214231aSZhang Chen } 2426214231aSZhang Chen 24330656b09SZhang Chen return 0; 24430656b09SZhang Chen } 24530656b09SZhang Chen 246e6eee8abSZhang Chen static ssize_t colo_rewriter_receive_iov(NetFilterState *nf, 247e6eee8abSZhang Chen NetClientState *sender, 248e6eee8abSZhang Chen unsigned flags, 249e6eee8abSZhang Chen const struct iovec *iov, 250e6eee8abSZhang Chen int iovcnt, 251e6eee8abSZhang Chen NetPacketSent *sent_cb) 252e6eee8abSZhang Chen { 253afe46124SZhang Chen RewriterState *s = FILTER_COLO_REWRITER(nf); 254afe46124SZhang Chen Connection *conn; 255afe46124SZhang Chen ConnectionKey key; 256afe46124SZhang Chen Packet *pkt; 257afe46124SZhang Chen ssize_t size = iov_size(iov, iovcnt); 2584b39bdceSZhang Chen ssize_t vnet_hdr_len = 0; 259afe46124SZhang Chen char *buf = g_malloc0(size); 260afe46124SZhang Chen 261afe46124SZhang Chen iov_to_buf(iov, iovcnt, 0, buf, size); 2624b39bdceSZhang Chen 2634b39bdceSZhang Chen if (s->vnet_hdr) { 2644b39bdceSZhang Chen vnet_hdr_len = nf->netdev->vnet_hdr_len; 2654b39bdceSZhang Chen } 2664b39bdceSZhang Chen 2674b39bdceSZhang Chen pkt = packet_new(buf, size, vnet_hdr_len); 2682061c14cSZhang Chen g_free(buf); 269afe46124SZhang Chen 270e6eee8abSZhang Chen /* 271e6eee8abSZhang Chen * if we get tcp packet 272e6eee8abSZhang Chen * we will rewrite it to make secondary guest's 273e6eee8abSZhang Chen * connection established successfully 274e6eee8abSZhang Chen */ 275afe46124SZhang Chen if (pkt && is_tcp_packet(pkt)) { 276afe46124SZhang Chen 277afe46124SZhang Chen fill_connection_key(pkt, &key); 278afe46124SZhang Chen 279afe46124SZhang Chen if (sender == nf->netdev) { 280afe46124SZhang Chen /* 281afe46124SZhang Chen * We need make tcp TX and RX packet 282afe46124SZhang Chen * into one connection. 283afe46124SZhang Chen */ 284afe46124SZhang Chen reverse_connection_key(&key); 285afe46124SZhang Chen } 286*24525e93SZhang Chen 287*24525e93SZhang Chen /* After failover we needn't change new TCP packet */ 288*24525e93SZhang Chen if (s->failover_mode && 289*24525e93SZhang Chen !connection_has_tracked(s->connection_track_table, &key)) { 290*24525e93SZhang Chen goto out; 291*24525e93SZhang Chen } 292*24525e93SZhang Chen 293afe46124SZhang Chen conn = connection_get(s->connection_track_table, 294afe46124SZhang Chen &key, 295afe46124SZhang Chen NULL); 296afe46124SZhang Chen 297afe46124SZhang Chen if (sender == nf->netdev) { 298afe46124SZhang Chen /* NET_FILTER_DIRECTION_TX */ 2996214231aSZhang Chen if (!handle_primary_tcp_pkt(s, conn, pkt, &key)) { 30030656b09SZhang Chen qemu_net_queue_send(s->incoming_queue, sender, 0, 30130656b09SZhang Chen (const uint8_t *)pkt->data, pkt->size, NULL); 30230656b09SZhang Chen packet_destroy(pkt, NULL); 30330656b09SZhang Chen pkt = NULL; 30430656b09SZhang Chen /* 30530656b09SZhang Chen * We block the packet here,after rewrite pkt 30630656b09SZhang Chen * and will send it 30730656b09SZhang Chen */ 30830656b09SZhang Chen return 1; 30930656b09SZhang Chen } 310afe46124SZhang Chen } else { 311afe46124SZhang Chen /* NET_FILTER_DIRECTION_RX */ 3126214231aSZhang Chen if (!handle_secondary_tcp_pkt(s, conn, pkt, &key)) { 31330656b09SZhang Chen qemu_net_queue_send(s->incoming_queue, sender, 0, 31430656b09SZhang Chen (const uint8_t *)pkt->data, pkt->size, NULL); 31530656b09SZhang Chen packet_destroy(pkt, NULL); 31630656b09SZhang Chen pkt = NULL; 31730656b09SZhang Chen /* 31830656b09SZhang Chen * We block the packet here,after rewrite pkt 31930656b09SZhang Chen * and will send it 32030656b09SZhang Chen */ 32130656b09SZhang Chen return 1; 32230656b09SZhang Chen } 323afe46124SZhang Chen } 324afe46124SZhang Chen } 325afe46124SZhang Chen 326*24525e93SZhang Chen out: 327afe46124SZhang Chen packet_destroy(pkt, NULL); 328afe46124SZhang Chen pkt = NULL; 329e6eee8abSZhang Chen return 0; 330e6eee8abSZhang Chen } 331e6eee8abSZhang Chen 332*24525e93SZhang Chen static void reset_seq_offset(gpointer key, gpointer value, gpointer user_data) 333*24525e93SZhang Chen { 334*24525e93SZhang Chen Connection *conn = (Connection *)value; 335*24525e93SZhang Chen 336*24525e93SZhang Chen conn->offset = 0; 337*24525e93SZhang Chen } 338*24525e93SZhang Chen 339*24525e93SZhang Chen static gboolean offset_is_nonzero(gpointer key, 340*24525e93SZhang Chen gpointer value, 341*24525e93SZhang Chen gpointer user_data) 342*24525e93SZhang Chen { 343*24525e93SZhang Chen Connection *conn = (Connection *)value; 344*24525e93SZhang Chen 345*24525e93SZhang Chen return conn->offset ? true : false; 346*24525e93SZhang Chen } 347*24525e93SZhang Chen 348*24525e93SZhang Chen static void colo_rewriter_handle_event(NetFilterState *nf, int event, 349*24525e93SZhang Chen Error **errp) 350*24525e93SZhang Chen { 351*24525e93SZhang Chen RewriterState *rs = FILTER_COLO_REWRITER(nf); 352*24525e93SZhang Chen 353*24525e93SZhang Chen switch (event) { 354*24525e93SZhang Chen case COLO_EVENT_CHECKPOINT: 355*24525e93SZhang Chen g_hash_table_foreach(rs->connection_track_table, 356*24525e93SZhang Chen reset_seq_offset, NULL); 357*24525e93SZhang Chen break; 358*24525e93SZhang Chen case COLO_EVENT_FAILOVER: 359*24525e93SZhang Chen if (!g_hash_table_find(rs->connection_track_table, 360*24525e93SZhang Chen offset_is_nonzero, NULL)) { 361*24525e93SZhang Chen filter_rewriter_failover_mode(rs); 362*24525e93SZhang Chen } 363*24525e93SZhang Chen break; 364*24525e93SZhang Chen default: 365*24525e93SZhang Chen break; 366*24525e93SZhang Chen } 367*24525e93SZhang Chen } 368*24525e93SZhang Chen 369e6eee8abSZhang Chen static void colo_rewriter_cleanup(NetFilterState *nf) 370e6eee8abSZhang Chen { 371e6eee8abSZhang Chen RewriterState *s = FILTER_COLO_REWRITER(nf); 372e6eee8abSZhang Chen 373e6eee8abSZhang Chen /* flush packets */ 374e6eee8abSZhang Chen if (s->incoming_queue) { 375e6eee8abSZhang Chen filter_rewriter_flush(nf); 376e6eee8abSZhang Chen g_free(s->incoming_queue); 377e6eee8abSZhang Chen } 378e6eee8abSZhang Chen } 379e6eee8abSZhang Chen 380e6eee8abSZhang Chen static void colo_rewriter_setup(NetFilterState *nf, Error **errp) 381e6eee8abSZhang Chen { 382e6eee8abSZhang Chen RewriterState *s = FILTER_COLO_REWRITER(nf); 383e6eee8abSZhang Chen 384e6eee8abSZhang Chen s->connection_track_table = g_hash_table_new_full(connection_key_hash, 385e6eee8abSZhang Chen connection_key_equal, 386e6eee8abSZhang Chen g_free, 387e6eee8abSZhang Chen connection_destroy); 388e6eee8abSZhang Chen s->incoming_queue = qemu_new_net_queue(qemu_netfilter_pass_to_next, nf); 389e6eee8abSZhang Chen } 390e6eee8abSZhang Chen 3914b39bdceSZhang Chen static bool filter_rewriter_get_vnet_hdr(Object *obj, Error **errp) 3924b39bdceSZhang Chen { 3934b39bdceSZhang Chen RewriterState *s = FILTER_COLO_REWRITER(obj); 3944b39bdceSZhang Chen 3954b39bdceSZhang Chen return s->vnet_hdr; 3964b39bdceSZhang Chen } 3974b39bdceSZhang Chen 3984b39bdceSZhang Chen static void filter_rewriter_set_vnet_hdr(Object *obj, 3994b39bdceSZhang Chen bool value, 4004b39bdceSZhang Chen Error **errp) 4014b39bdceSZhang Chen { 4024b39bdceSZhang Chen RewriterState *s = FILTER_COLO_REWRITER(obj); 4034b39bdceSZhang Chen 4044b39bdceSZhang Chen s->vnet_hdr = value; 4054b39bdceSZhang Chen } 4064b39bdceSZhang Chen 4074b39bdceSZhang Chen static void filter_rewriter_init(Object *obj) 4084b39bdceSZhang Chen { 4094b39bdceSZhang Chen RewriterState *s = FILTER_COLO_REWRITER(obj); 4104b39bdceSZhang Chen 4114b39bdceSZhang Chen s->vnet_hdr = false; 412*24525e93SZhang Chen s->failover_mode = FAILOVER_MODE_OFF; 4134b39bdceSZhang Chen object_property_add_bool(obj, "vnet_hdr_support", 4144b39bdceSZhang Chen filter_rewriter_get_vnet_hdr, 4154b39bdceSZhang Chen filter_rewriter_set_vnet_hdr, NULL); 4164b39bdceSZhang Chen } 4174b39bdceSZhang Chen 418e6eee8abSZhang Chen static void colo_rewriter_class_init(ObjectClass *oc, void *data) 419e6eee8abSZhang Chen { 420e6eee8abSZhang Chen NetFilterClass *nfc = NETFILTER_CLASS(oc); 421e6eee8abSZhang Chen 422e6eee8abSZhang Chen nfc->setup = colo_rewriter_setup; 423e6eee8abSZhang Chen nfc->cleanup = colo_rewriter_cleanup; 424e6eee8abSZhang Chen nfc->receive_iov = colo_rewriter_receive_iov; 425*24525e93SZhang Chen nfc->handle_event = colo_rewriter_handle_event; 426e6eee8abSZhang Chen } 427e6eee8abSZhang Chen 428e6eee8abSZhang Chen static const TypeInfo colo_rewriter_info = { 429e6eee8abSZhang Chen .name = TYPE_FILTER_REWRITER, 430e6eee8abSZhang Chen .parent = TYPE_NETFILTER, 431e6eee8abSZhang Chen .class_init = colo_rewriter_class_init, 4324b39bdceSZhang Chen .instance_init = filter_rewriter_init, 433e6eee8abSZhang Chen .instance_size = sizeof(RewriterState), 434e6eee8abSZhang Chen }; 435e6eee8abSZhang Chen 436e6eee8abSZhang Chen static void register_types(void) 437e6eee8abSZhang Chen { 438e6eee8abSZhang Chen type_register_static(&colo_rewriter_info); 439e6eee8abSZhang Chen } 440e6eee8abSZhang Chen 441e6eee8abSZhang Chen type_init(register_types); 442