colo.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. /*
  2. * COarse-grain LOck-stepping Virtual Machines for Non-stop Service (COLO)
  3. * (a.k.a. Fault Tolerance or Continuous Replication)
  4. *
  5. * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
  6. * Copyright (c) 2016 FUJITSU LIMITED
  7. * Copyright (c) 2016 Intel Corporation
  8. *
  9. * Author: Zhang Chen <zhangchen.fnst@cn.fujitsu.com>
  10. *
  11. * This work is licensed under the terms of the GNU GPL, version 2 or
  12. * later. See the COPYING file in the top-level directory.
  13. */
  14. #include "qemu/osdep.h"
  15. #include "trace.h"
  16. #include "colo.h"
  17. #include "util.h"
  18. uint32_t connection_key_hash(const void *opaque)
  19. {
  20. const ConnectionKey *key = opaque;
  21. uint32_t a, b, c;
  22. /* Jenkins hash */
  23. a = b = c = JHASH_INITVAL + sizeof(*key);
  24. a += key->src.s_addr;
  25. b += key->dst.s_addr;
  26. c += (key->src_port | key->dst_port << 16);
  27. __jhash_mix(a, b, c);
  28. a += key->ip_proto;
  29. __jhash_final(a, b, c);
  30. return c;
  31. }
  32. int connection_key_equal(const void *key1, const void *key2)
  33. {
  34. return memcmp(key1, key2, sizeof(ConnectionKey)) == 0;
  35. }
  36. int parse_packet_early(Packet *pkt)
  37. {
  38. int network_length;
  39. static const uint8_t vlan[] = {0x81, 0x00};
  40. uint8_t *data = pkt->data + pkt->vnet_hdr_len;
  41. uint16_t l3_proto;
  42. ssize_t l2hdr_len = eth_get_l2_hdr_length(data);
  43. if (pkt->size < ETH_HLEN + pkt->vnet_hdr_len) {
  44. trace_colo_proxy_main("pkt->size < ETH_HLEN");
  45. return 1;
  46. }
  47. /*
  48. * TODO: support vlan.
  49. */
  50. if (!memcmp(&data[12], vlan, sizeof(vlan))) {
  51. trace_colo_proxy_main("COLO-proxy don't support vlan");
  52. return 1;
  53. }
  54. pkt->network_header = data + l2hdr_len;
  55. const struct iovec l2vec = {
  56. .iov_base = (void *) data,
  57. .iov_len = l2hdr_len
  58. };
  59. l3_proto = eth_get_l3_proto(&l2vec, 1, l2hdr_len);
  60. if (l3_proto != ETH_P_IP) {
  61. return 1;
  62. }
  63. network_length = pkt->ip->ip_hl * 4;
  64. if (pkt->size < l2hdr_len + network_length + pkt->vnet_hdr_len) {
  65. trace_colo_proxy_main("pkt->size < network_header + network_length");
  66. return 1;
  67. }
  68. pkt->transport_header = pkt->network_header + network_length;
  69. return 0;
  70. }
  71. void extract_ip_and_port(uint32_t tmp_ports, ConnectionKey *key, Packet *pkt)
  72. {
  73. key->src = pkt->ip->ip_src;
  74. key->dst = pkt->ip->ip_dst;
  75. key->src_port = ntohs(tmp_ports >> 16);
  76. key->dst_port = ntohs(tmp_ports & 0xffff);
  77. }
  78. void fill_connection_key(Packet *pkt, ConnectionKey *key)
  79. {
  80. uint32_t tmp_ports;
  81. memset(key, 0, sizeof(*key));
  82. key->ip_proto = pkt->ip->ip_p;
  83. switch (key->ip_proto) {
  84. case IPPROTO_TCP:
  85. case IPPROTO_UDP:
  86. case IPPROTO_DCCP:
  87. case IPPROTO_ESP:
  88. case IPPROTO_SCTP:
  89. case IPPROTO_UDPLITE:
  90. tmp_ports = *(uint32_t *)(pkt->transport_header);
  91. extract_ip_and_port(tmp_ports, key, pkt);
  92. break;
  93. case IPPROTO_AH:
  94. tmp_ports = *(uint32_t *)(pkt->transport_header + 4);
  95. extract_ip_and_port(tmp_ports, key, pkt);
  96. break;
  97. default:
  98. break;
  99. }
  100. }
  101. void reverse_connection_key(ConnectionKey *key)
  102. {
  103. struct in_addr tmp_ip;
  104. uint16_t tmp_port;
  105. tmp_ip = key->src;
  106. key->src = key->dst;
  107. key->dst = tmp_ip;
  108. tmp_port = key->src_port;
  109. key->src_port = key->dst_port;
  110. key->dst_port = tmp_port;
  111. }
  112. Connection *connection_new(ConnectionKey *key)
  113. {
  114. Connection *conn = g_slice_new(Connection);
  115. conn->ip_proto = key->ip_proto;
  116. conn->processing = false;
  117. conn->offset = 0;
  118. conn->tcp_state = TCPS_CLOSED;
  119. conn->pack = 0;
  120. conn->sack = 0;
  121. g_queue_init(&conn->primary_list);
  122. g_queue_init(&conn->secondary_list);
  123. return conn;
  124. }
  125. void connection_destroy(void *opaque)
  126. {
  127. Connection *conn = opaque;
  128. g_queue_foreach(&conn->primary_list, packet_destroy, NULL);
  129. g_queue_clear(&conn->primary_list);
  130. g_queue_foreach(&conn->secondary_list, packet_destroy, NULL);
  131. g_queue_clear(&conn->secondary_list);
  132. g_slice_free(Connection, conn);
  133. }
  134. Packet *packet_new(const void *data, int size, int vnet_hdr_len)
  135. {
  136. Packet *pkt = g_slice_new(Packet);
  137. pkt->data = g_memdup(data, size);
  138. pkt->size = size;
  139. pkt->creation_ms = qemu_clock_get_ms(QEMU_CLOCK_HOST);
  140. pkt->vnet_hdr_len = vnet_hdr_len;
  141. pkt->tcp_seq = 0;
  142. pkt->tcp_ack = 0;
  143. pkt->seq_end = 0;
  144. pkt->header_size = 0;
  145. pkt->payload_size = 0;
  146. pkt->offset = 0;
  147. pkt->flags = 0;
  148. return pkt;
  149. }
  150. void packet_destroy(void *opaque, void *user_data)
  151. {
  152. Packet *pkt = opaque;
  153. g_free(pkt->data);
  154. g_slice_free(Packet, pkt);
  155. }
  156. void packet_destroy_partial(void *opaque, void *user_data)
  157. {
  158. Packet *pkt = opaque;
  159. g_slice_free(Packet, pkt);
  160. }
  161. /*
  162. * Clear hashtable, stop this hash growing really huge
  163. */
  164. void connection_hashtable_reset(GHashTable *connection_track_table)
  165. {
  166. g_hash_table_remove_all(connection_track_table);
  167. }
  168. /* if not found, create a new connection and add to hash table */
  169. Connection *connection_get(GHashTable *connection_track_table,
  170. ConnectionKey *key,
  171. GQueue *conn_list)
  172. {
  173. Connection *conn = g_hash_table_lookup(connection_track_table, key);
  174. if (conn == NULL) {
  175. ConnectionKey *new_key = g_memdup(key, sizeof(*key));
  176. conn = connection_new(key);
  177. if (g_hash_table_size(connection_track_table) > HASHTABLE_MAX_SIZE) {
  178. trace_colo_proxy_main("colo proxy connection hashtable full,"
  179. " clear it");
  180. connection_hashtable_reset(connection_track_table);
  181. /*
  182. * clear the conn_list
  183. */
  184. while (!g_queue_is_empty(conn_list)) {
  185. connection_destroy(g_queue_pop_head(conn_list));
  186. }
  187. }
  188. g_hash_table_insert(connection_track_table, new_key, conn);
  189. }
  190. return conn;
  191. }
  192. bool connection_has_tracked(GHashTable *connection_track_table,
  193. ConnectionKey *key)
  194. {
  195. Connection *conn = g_hash_table_lookup(connection_track_table, key);
  196. return conn ? true : false;
  197. }