colo-compare: track connection and enqueue packet

In this patch we use kernel jhash table to track
connection, and then enqueue net packet like this:

+ CompareState ++
|               |
+---------------+   +---------------+         +---------------+
|conn list      +--->conn           +--------->conn           |
+---------------+   +---------------+         +---------------+
|               |     |           |             |          |
+---------------+ +---v----+  +---v----+    +---v----+ +---v----+
                  |primary |  |secondary    |primary | |secondary
                  |packet  |  |packet  +    |packet  | |packet  +
                  +--------+  +--------+    +--------+ +--------+
                      |           |             |          |
                  +---v----+  +---v----+    +---v----+ +---v----+
                  |primary |  |secondary    |primary | |secondary
                  |packet  |  |packet  +    |packet  | |packet  +
                  +--------+  +--------+    +--------+ +--------+
                      |           |             |          |
                  +---v----+  +---v----+    +---v----+ +---v----+
                  |primary |  |secondary    |primary | |secondary
                  |packet  |  |packet  +    |packet  | |packet  +
                  +--------+  +--------+    +--------+ +--------+

We use conn_list to record connection info.
When we want to enqueue a packet, firstly get the
connection from connection_track_table. then push
the packet to g_queue(pri/sec) in it's own conn.

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:
Zhang Chen 2016-09-27 10:22:29 +08:00 committed by Jason Wang
parent ccf0426c09
commit b6540d403d
3 changed files with 190 additions and 10 deletions

View file

@ -16,6 +16,29 @@
#include "trace.h"
#include "net/colo.h"
uint32_t connection_key_hash(const void *opaque)
{
const ConnectionKey *key = opaque;
uint32_t a, b, c;
/* Jenkins hash */
a = b = c = JHASH_INITVAL + sizeof(*key);
a += key->src.s_addr;
b += key->dst.s_addr;
c += (key->src_port | key->dst_port << 16);
__jhash_mix(a, b, c);
a += key->ip_proto;
__jhash_final(a, b, c);
return c;
}
int connection_key_equal(const void *key1, const void *key2)
{
return memcmp(key1, key2, sizeof(ConnectionKey)) == 0;
}
int parse_packet_early(Packet *pkt)
{
int network_length;
@ -59,6 +82,61 @@ int parse_packet_early(Packet *pkt)
return 0;
}
void fill_connection_key(Packet *pkt, ConnectionKey *key)
{
uint32_t tmp_ports;
memset(key, 0, sizeof(*key));
key->ip_proto = pkt->ip->ip_p;
switch (key->ip_proto) {
case IPPROTO_TCP:
case IPPROTO_UDP:
case IPPROTO_DCCP:
case IPPROTO_ESP:
case IPPROTO_SCTP:
case IPPROTO_UDPLITE:
tmp_ports = *(uint32_t *)(pkt->transport_header);
key->src = pkt->ip->ip_src;
key->dst = pkt->ip->ip_dst;
key->src_port = ntohs(tmp_ports & 0xffff);
key->dst_port = ntohs(tmp_ports >> 16);
break;
case IPPROTO_AH:
tmp_ports = *(uint32_t *)(pkt->transport_header + 4);
key->src = pkt->ip->ip_src;
key->dst = pkt->ip->ip_dst;
key->src_port = ntohs(tmp_ports & 0xffff);
key->dst_port = ntohs(tmp_ports >> 16);
break;
default:
break;
}
}
Connection *connection_new(ConnectionKey *key)
{
Connection *conn = g_slice_new(Connection);
conn->ip_proto = key->ip_proto;
conn->processing = false;
g_queue_init(&conn->primary_list);
g_queue_init(&conn->secondary_list);
return conn;
}
void connection_destroy(void *opaque)
{
Connection *conn = opaque;
g_queue_foreach(&conn->primary_list, packet_destroy, NULL);
g_queue_free(&conn->primary_list);
g_queue_foreach(&conn->secondary_list, packet_destroy, NULL);
g_queue_free(&conn->secondary_list);
g_slice_free(Connection, conn);
}
Packet *packet_new(const void *data, int size)
{
Packet *pkt = g_slice_new(Packet);
@ -84,3 +162,33 @@ void connection_hashtable_reset(GHashTable *connection_track_table)
{
g_hash_table_remove_all(connection_track_table);
}
/* if not found, create a new connection and add to hash table */
Connection *connection_get(GHashTable *connection_track_table,
ConnectionKey *key,
GQueue *conn_list)
{
Connection *conn = g_hash_table_lookup(connection_track_table, key);
if (conn == NULL) {
ConnectionKey *new_key = g_memdup(key, sizeof(*key));
conn = connection_new(key);
if (g_hash_table_size(connection_track_table) > HASHTABLE_MAX_SIZE) {
trace_colo_proxy_main("colo proxy connection hashtable full,"
" clear it");
connection_hashtable_reset(connection_track_table);
/*
* clear the conn_list
*/
while (!g_queue_is_empty(conn_list)) {
connection_destroy(g_queue_pop_head(conn_list));
}
}
g_hash_table_insert(connection_track_table, new_key, conn);
}
return conn;
}