/* * Called from the compare thread on the primary * for compare icmp packet */ static int colo_packet_compare_icmp(Packet *spkt, Packet *ppkt) { int network_header_length = ppkt->ip->ip_hl * 4; trace_colo_compare_main("compare icmp"); /* * Because of ppkt and spkt are both in the same connection, * The ppkt's src ip, dst ip, src port, dst port, ip_proto all are * same with spkt. In addition, IP header's Identification is a random * field, we can handle it in IP fragmentation function later. * COLO just concern the response net packet payload from primary guest * and secondary guest are same or not, So we ignored all IP header include * other field like TOS,TTL,IP Checksum. we only need to compare * the ip payload here. */ if (colo_packet_compare_common(ppkt, spkt, network_header_length + ETH_HLEN, network_header_length + ETH_HLEN)) { trace_colo_compare_icmp_miscompare("primary pkt size", ppkt->size); trace_colo_compare_icmp_miscompare("Secondary pkt size", spkt->size); if (trace_event_get_state_backends(TRACE_COLO_COMPARE_MISCOMPARE)) { qemu_hexdump((char *)ppkt->data, stderr, "colo-compare pri pkt", ppkt->size); qemu_hexdump((char *)spkt->data, stderr, "colo-compare sec pkt", spkt->size); } return -1; } else { return 0; } }
static ssize_t etsec_receive(NetClientState *nc, const uint8_t *buf, size_t size) { eTSEC *etsec = qemu_get_nic_opaque(nc); #if defined(HEX_DUMP) fprintf(stderr, "%s receive size:%d\n", etsec->nic->nc.name, size); qemu_hexdump(buf, stderr, "", size); #endif etsec_rx_ring_write(etsec, buf, size); return size; }
void iov_hexdump(const struct iovec *iov, const unsigned int iov_cnt, FILE *fp, const char *prefix, size_t limit) { int v; size_t size = 0; char *buf; for (v = 0; v < iov_cnt; v++) { size += iov[v].iov_len; } size = size > limit ? limit : size; buf = g_malloc(size); iov_to_buf(iov, iov_cnt, 0, buf, size); qemu_hexdump(buf, fp, prefix, size); g_free(buf); }
static ssize_t etsec_receive(NetClientState *nc, const uint8_t *buf, size_t size) { ssize_t ret; eTSEC *etsec = qemu_get_nic_opaque(nc); #if defined(HEX_DUMP) fprintf(stderr, "%s receive size:%d\n", etsec->nic->nc.name, size); qemu_hexdump(buf, stderr, "", size); #endif /* Flush is unnecessary as are already in receiving path */ etsec->need_flush = false; ret = etsec_rx_ring_write(etsec, buf, size); if (ret == 0) { /* The packet will be queued, let's flush it when buffer is available * again. */ etsec->need_flush = true; } return ret; }
/* * Called from the compare thread on the primary * for compare tcp packet * compare_tcp copied from Dr. David Alan Gilbert's branch */ static int colo_packet_compare_tcp(Packet *spkt, Packet *ppkt) { struct tcphdr *ptcp, *stcp; int res; trace_colo_compare_main("compare tcp"); ptcp = (struct tcphdr *)ppkt->transport_header; stcp = (struct tcphdr *)spkt->transport_header; /* * The 'identification' field in the IP header is *very* random * it almost never matches. Fudge this by ignoring differences in * unfragmented packets; they'll normally sort themselves out if different * anyway, and it should recover at the TCP level. * An alternative would be to get both the primary and secondary to rewrite * somehow; but that would need some sync traffic to sync the state */ if (ntohs(ppkt->ip->ip_off) & IP_DF) { spkt->ip->ip_id = ppkt->ip->ip_id; /* and the sum will be different if the IDs were different */ spkt->ip->ip_sum = ppkt->ip->ip_sum; } /* * Check tcp header length for tcp option field. * th_off > 5 means this tcp packet have options field. * The tcp options maybe always different. * for example: * From RFC 7323. * TCP Timestamps option (TSopt): * Kind: 8 * * Length: 10 bytes * * +-------+-------+---------------------+---------------------+ * |Kind=8 | 10 | TS Value (TSval) |TS Echo Reply (TSecr)| * +-------+-------+---------------------+---------------------+ * 1 1 4 4 * * In this case the primary guest's timestamp always different with * the secondary guest's timestamp. COLO just focus on payload, * so we just need skip this field. */ if (ptcp->th_off > 5) { ptrdiff_t ptcp_offset, stcp_offset; ptcp_offset = ppkt->transport_header - (uint8_t *)ppkt->data + (ptcp->th_off * 4) - ppkt->vnet_hdr_len; stcp_offset = spkt->transport_header - (uint8_t *)spkt->data + (stcp->th_off * 4) - spkt->vnet_hdr_len; /* * When network is busy, some tcp options(like sack) will unpredictable * occur in primary side or secondary side. it will make packet size * not same, but the two packet's payload is identical. colo just * care about packet payload, so we skip the option field. */ res = colo_packet_compare_common(ppkt, spkt, ptcp_offset, stcp_offset); } else if (ptcp->th_sum == stcp->th_sum) { res = colo_packet_compare_common(ppkt, spkt, ETH_HLEN, ETH_HLEN); } else { res = -1; } if (res != 0 && trace_event_get_state_backends(TRACE_COLO_COMPARE_MISCOMPARE)) { char pri_ip_src[20], pri_ip_dst[20], sec_ip_src[20], sec_ip_dst[20]; strcpy(pri_ip_src, inet_ntoa(ppkt->ip->ip_src)); strcpy(pri_ip_dst, inet_ntoa(ppkt->ip->ip_dst)); strcpy(sec_ip_src, inet_ntoa(spkt->ip->ip_src)); strcpy(sec_ip_dst, inet_ntoa(spkt->ip->ip_dst)); trace_colo_compare_ip_info(ppkt->size, pri_ip_src, pri_ip_dst, spkt->size, sec_ip_src, sec_ip_dst); trace_colo_compare_tcp_info("pri tcp packet", ntohl(ptcp->th_seq), ntohl(ptcp->th_ack), res, ptcp->th_flags, ppkt->size); trace_colo_compare_tcp_info("sec tcp packet", ntohl(stcp->th_seq), ntohl(stcp->th_ack), res, stcp->th_flags, spkt->size); qemu_hexdump((char *)ppkt->data, stderr, "colo-compare ppkt", ppkt->size); qemu_hexdump((char *)spkt->data, stderr, "colo-compare spkt", spkt->size); } return res; }