filter-rewriter: rewrite tcp packet to keep secondary connection
We will rewrite tcp packet secondary received and sent. When colo guest is a tcp server. Firstly, client start a tcp handshake. the packet's seq=client_seq, ack=0,flag=SYN. COLO primary guest get this pkt and mirror(filter-mirror) to secondary guest, secondary get it use filter-redirector. Then,primary guest response pkt (seq=primary_seq,ack=client_seq+1,flag=ACK|SYN). secondary guest response pkt (seq=secondary_seq,ack=client_seq+1,flag=ACK|SYN). In here,we use filter-rewriter save the secondary_seq to it's tcp connection. Finally handshake,client send pkt (seq=client_seq+1,ack=primary_seq+1,flag=ACK). Here,filter-rewriter can get primary_seq, and rewrite ack from primary_seq+1 to secondary_seq+1, recalculate checksum. So the secondary tcp connection kept good. When we send/recv packet. client send pkt(seq=client_seq+1+data_len,ack=primary_seq+1,flag=ACK|PSH). filter-rewriter rewrite ack and send to secondary guest. primary guest response pkt (seq=primary_seq+1,ack=client_seq+1+data_len,flag=ACK) secondary guest response pkt (seq=secondary_seq+1,ack=client_seq+1+data_len,flag=ACK) we rewrite secondary guest seq from secondary_seq+1 to primary_seq+1. So tcp connection kept good. In code We use offset( = secondary_seq - primary_seq ) to rewrite seq or ack. handle_primary_tcp_pkt: tcp_pkt->th_ack += offset; handle_secondary_tcp_pkt: tcp_pkt->th_seq -= offset; Signed-off-by: Zhang Chen <zhangchen.fnst@cn.fujitsu.com> Signed-off-by: Li Zhijian <lizhijian@cn.fujitsu.com> Signed-off-by: Wen Congyang <wency@cn.fujitsu.com> Signed-off-by: Jason Wang <jasowang@redhat.com>
This commit is contained in:
		
							parent
							
								
									afe4612409
								
							
						
					
					
						commit
						30656b097e
					
				| 
						 | 
					@ -134,6 +134,8 @@ Connection *connection_new(ConnectionKey *key)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    conn->ip_proto = key->ip_proto;
 | 
					    conn->ip_proto = key->ip_proto;
 | 
				
			||||||
    conn->processing = false;
 | 
					    conn->processing = false;
 | 
				
			||||||
 | 
					    conn->offset = 0;
 | 
				
			||||||
 | 
					    conn->syn_flag = 0;
 | 
				
			||||||
    g_queue_init(&conn->primary_list);
 | 
					    g_queue_init(&conn->primary_list);
 | 
				
			||||||
    g_queue_init(&conn->secondary_list);
 | 
					    g_queue_init(&conn->secondary_list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -62,6 +62,13 @@ typedef struct Connection {
 | 
				
			||||||
    /* flag to enqueue unprocessed_connections */
 | 
					    /* flag to enqueue unprocessed_connections */
 | 
				
			||||||
    bool processing;
 | 
					    bool processing;
 | 
				
			||||||
    uint8_t ip_proto;
 | 
					    uint8_t ip_proto;
 | 
				
			||||||
 | 
					    /* offset = secondary_seq - primary_seq */
 | 
				
			||||||
 | 
					    tcp_seq  offset;
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * we use this flag update offset func
 | 
				
			||||||
 | 
					     * run once in independent tcp connection
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    int syn_flag;
 | 
				
			||||||
} Connection;
 | 
					} Connection;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uint32_t connection_key_hash(const void *opaque);
 | 
					uint32_t connection_key_hash(const void *opaque);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,6 +10,7 @@
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "qemu/osdep.h"
 | 
					#include "qemu/osdep.h"
 | 
				
			||||||
 | 
					#include "trace.h"
 | 
				
			||||||
#include "net/colo.h"
 | 
					#include "net/colo.h"
 | 
				
			||||||
#include "net/filter.h"
 | 
					#include "net/filter.h"
 | 
				
			||||||
#include "net/net.h"
 | 
					#include "net/net.h"
 | 
				
			||||||
| 
						 | 
					@ -58,6 +59,93 @@ static int is_tcp_packet(Packet *pkt)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* handle tcp packet from primary guest */
 | 
				
			||||||
 | 
					static int handle_primary_tcp_pkt(NetFilterState *nf,
 | 
				
			||||||
 | 
					                                  Connection *conn,
 | 
				
			||||||
 | 
					                                  Packet *pkt)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct tcphdr *tcp_pkt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tcp_pkt = (struct tcphdr *)pkt->transport_header;
 | 
				
			||||||
 | 
					    if (trace_event_get_state(TRACE_COLO_FILTER_REWRITER_DEBUG)) {
 | 
				
			||||||
 | 
					        char *sdebug, *ddebug;
 | 
				
			||||||
 | 
					        sdebug = strdup(inet_ntoa(pkt->ip->ip_src));
 | 
				
			||||||
 | 
					        ddebug = strdup(inet_ntoa(pkt->ip->ip_dst));
 | 
				
			||||||
 | 
					        trace_colo_filter_rewriter_pkt_info(__func__, sdebug, ddebug,
 | 
				
			||||||
 | 
					                    ntohl(tcp_pkt->th_seq), ntohl(tcp_pkt->th_ack),
 | 
				
			||||||
 | 
					                    tcp_pkt->th_flags);
 | 
				
			||||||
 | 
					        trace_colo_filter_rewriter_conn_offset(conn->offset);
 | 
				
			||||||
 | 
					        g_free(sdebug);
 | 
				
			||||||
 | 
					        g_free(ddebug);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (((tcp_pkt->th_flags & (TH_ACK | TH_SYN)) == TH_SYN)) {
 | 
				
			||||||
 | 
					        /*
 | 
				
			||||||
 | 
					         * we use this flag update offset func
 | 
				
			||||||
 | 
					         * run once in independent tcp connection
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        conn->syn_flag = 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (((tcp_pkt->th_flags & (TH_ACK | TH_SYN)) == TH_ACK)) {
 | 
				
			||||||
 | 
					        if (conn->syn_flag) {
 | 
				
			||||||
 | 
					            /*
 | 
				
			||||||
 | 
					             * offset = secondary_seq - primary seq
 | 
				
			||||||
 | 
					             * ack packet sent by guest from primary node,
 | 
				
			||||||
 | 
					             * so we use th_ack - 1 get primary_seq
 | 
				
			||||||
 | 
					             */
 | 
				
			||||||
 | 
					            conn->offset -= (ntohl(tcp_pkt->th_ack) - 1);
 | 
				
			||||||
 | 
					            conn->syn_flag = 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        /* handle packets to the secondary from the primary */
 | 
				
			||||||
 | 
					        tcp_pkt->th_ack = htonl(ntohl(tcp_pkt->th_ack) + conn->offset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        net_checksum_calculate((uint8_t *)pkt->data, pkt->size);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* handle tcp packet from secondary guest */
 | 
				
			||||||
 | 
					static int handle_secondary_tcp_pkt(NetFilterState *nf,
 | 
				
			||||||
 | 
					                                    Connection *conn,
 | 
				
			||||||
 | 
					                                    Packet *pkt)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct tcphdr *tcp_pkt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tcp_pkt = (struct tcphdr *)pkt->transport_header;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (trace_event_get_state(TRACE_COLO_FILTER_REWRITER_DEBUG)) {
 | 
				
			||||||
 | 
					        char *sdebug, *ddebug;
 | 
				
			||||||
 | 
					        sdebug = strdup(inet_ntoa(pkt->ip->ip_src));
 | 
				
			||||||
 | 
					        ddebug = strdup(inet_ntoa(pkt->ip->ip_dst));
 | 
				
			||||||
 | 
					        trace_colo_filter_rewriter_pkt_info(__func__, sdebug, ddebug,
 | 
				
			||||||
 | 
					                    ntohl(tcp_pkt->th_seq), ntohl(tcp_pkt->th_ack),
 | 
				
			||||||
 | 
					                    tcp_pkt->th_flags);
 | 
				
			||||||
 | 
					        trace_colo_filter_rewriter_conn_offset(conn->offset);
 | 
				
			||||||
 | 
					        g_free(sdebug);
 | 
				
			||||||
 | 
					        g_free(ddebug);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (((tcp_pkt->th_flags & (TH_ACK | TH_SYN)) == (TH_ACK | TH_SYN))) {
 | 
				
			||||||
 | 
					        /*
 | 
				
			||||||
 | 
					         * save offset = secondary_seq and then
 | 
				
			||||||
 | 
					         * in handle_primary_tcp_pkt make offset
 | 
				
			||||||
 | 
					         * = secondary_seq - primary_seq
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        conn->offset = ntohl(tcp_pkt->th_seq);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ((tcp_pkt->th_flags & (TH_ACK | TH_SYN)) == TH_ACK) {
 | 
				
			||||||
 | 
					        /* handle packets to the primary from the secondary*/
 | 
				
			||||||
 | 
					        tcp_pkt->th_seq = htonl(ntohl(tcp_pkt->th_seq) - conn->offset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        net_checksum_calculate((uint8_t *)pkt->data, pkt->size);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static ssize_t colo_rewriter_receive_iov(NetFilterState *nf,
 | 
					static ssize_t colo_rewriter_receive_iov(NetFilterState *nf,
 | 
				
			||||||
                                         NetClientState *sender,
 | 
					                                         NetClientState *sender,
 | 
				
			||||||
                                         unsigned flags,
 | 
					                                         unsigned flags,
 | 
				
			||||||
| 
						 | 
					@ -97,10 +185,30 @@ static ssize_t colo_rewriter_receive_iov(NetFilterState *nf,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (sender == nf->netdev) {
 | 
					        if (sender == nf->netdev) {
 | 
				
			||||||
            /* NET_FILTER_DIRECTION_TX */
 | 
					            /* NET_FILTER_DIRECTION_TX */
 | 
				
			||||||
            /* handle_primary_tcp_pkt */
 | 
					            if (!handle_primary_tcp_pkt(nf, conn, pkt)) {
 | 
				
			||||||
 | 
					                qemu_net_queue_send(s->incoming_queue, sender, 0,
 | 
				
			||||||
 | 
					                (const uint8_t *)pkt->data, pkt->size, NULL);
 | 
				
			||||||
 | 
					                packet_destroy(pkt, NULL);
 | 
				
			||||||
 | 
					                pkt = NULL;
 | 
				
			||||||
 | 
					                /*
 | 
				
			||||||
 | 
					                 * We block the packet here,after rewrite pkt
 | 
				
			||||||
 | 
					                 * and will send it
 | 
				
			||||||
 | 
					                 */
 | 
				
			||||||
 | 
					                return 1;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            /* NET_FILTER_DIRECTION_RX */
 | 
					            /* NET_FILTER_DIRECTION_RX */
 | 
				
			||||||
            /* handle_secondary_tcp_pkt */
 | 
					            if (!handle_secondary_tcp_pkt(nf, conn, pkt)) {
 | 
				
			||||||
 | 
					                qemu_net_queue_send(s->incoming_queue, sender, 0,
 | 
				
			||||||
 | 
					                (const uint8_t *)pkt->data, pkt->size, NULL);
 | 
				
			||||||
 | 
					                packet_destroy(pkt, NULL);
 | 
				
			||||||
 | 
					                pkt = NULL;
 | 
				
			||||||
 | 
					                /*
 | 
				
			||||||
 | 
					                 * We block the packet here,after rewrite pkt
 | 
				
			||||||
 | 
					                 * and will send it
 | 
				
			||||||
 | 
					                 */
 | 
				
			||||||
 | 
					                return 1;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -150,6 +150,11 @@ colo_compare_ip_info(int psize, const char *sta, const char *stb, int ssize, con
 | 
				
			||||||
colo_old_packet_check_found(int64_t old_time) "%" PRId64
 | 
					colo_old_packet_check_found(int64_t old_time) "%" PRId64
 | 
				
			||||||
colo_compare_miscompare(void) ""
 | 
					colo_compare_miscompare(void) ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# net/filter-rewriter.c
 | 
				
			||||||
 | 
					colo_filter_rewriter_debug(void) ""
 | 
				
			||||||
 | 
					colo_filter_rewriter_pkt_info(const char *func, const char *src, const char *dst, uint32_t seq, uint32_t ack, uint32_t flag) "%s: src/dst: %s/%s p: seq/ack=%u/%u  flags=%x\n"
 | 
				
			||||||
 | 
					colo_filter_rewriter_conn_offset(uint32_t offset) ": offset=%u\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Guest events, keep at bottom
 | 
					### Guest events, keep at bottom
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# @vaddr: Access' virtual address.
 | 
					# @vaddr: Access' virtual address.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue