aboutgitcodebugslistschat
diff options
context:
space:
mode:
-rw-r--r--flow.c35
-rw-r--r--flow.h19
-rw-r--r--flow_table.h3
-rw-r--r--tcp.c61
4 files changed, 65 insertions, 53 deletions
diff --git a/flow.c b/flow.c
index 71c44d2..e70e3cb 100644
--- a/flow.c
+++ b/flow.c
@@ -116,9 +116,9 @@ static struct timespec flow_timer_run;
* @faddr: Forwarding address (pointer to in_addr or in6_addr)
* @fport: Forwarding port
*/
-static void flowside_from_af(struct flowside *side, sa_family_t af,
- const void *eaddr, in_port_t eport,
- const void *faddr, in_port_t fport)
+void flowside_from_af(struct flowside *side, sa_family_t af,
+ const void *eaddr, in_port_t eport,
+ const void *faddr, in_port_t fport)
{
if (faddr)
inany_from_af(&side->faddr, af, faddr);
@@ -402,6 +402,35 @@ void flow_alloc_cancel(union flow *flow)
}
/**
+ * flow_hash() - Calculate hash value for one side of a flow
+ * @c: Execution context
+ * @proto: Protocol of this flow (IP L4 protocol number)
+ * @pif: pif of the side to hash
+ * @side: Flowside (must not have unspecified parts)
+ *
+ * Return: hash value
+ */
+uint64_t flow_hash(const struct ctx *c, uint8_t proto, uint8_t pif,
+ const struct flowside *side)
+{
+ struct siphash_state state = SIPHASH_INIT(c->hash_secret);
+
+ /* For the hash table to work, we need complete endpoint information,
+ * and at least a forwarding port.
+ */
+ ASSERT(pif != PIF_NONE && !inany_is_unspecified(&side->eaddr) &&
+ side->eport != 0 && side->fport != 0);
+
+ inany_siphash_feed(&state, &side->faddr);
+ inany_siphash_feed(&state, &side->eaddr);
+
+ return siphash_final(&state, 38, (uint64_t)proto << 40 |
+ (uint64_t)pif << 32 |
+ (uint64_t)side->fport << 16 |
+ (uint64_t)side->eport);
+}
+
+/**
* flow_defer_handler() - Handler for per-flow deferred and timed tasks
* @c: Execution context
* @now: Current timestamp
diff --git a/flow.h b/flow.h
index 8c6ba60..a0550dc 100644
--- a/flow.h
+++ b/flow.h
@@ -150,6 +150,25 @@ struct flowside {
};
/**
+ * flowside_eq() - Check if two flowsides are equal
+ * @left, @right: Flowsides to compare
+ *
+ * Return: true if equal, false otherwise
+ */
+static inline bool flowside_eq(const struct flowside *left,
+ const struct flowside *right)
+{
+ return inany_equals(&left->eaddr, &right->eaddr) &&
+ left->eport == right->eport &&
+ inany_equals(&left->faddr, &right->faddr) &&
+ left->fport == right->fport;
+}
+
+void flowside_from_af(struct flowside *side, sa_family_t af,
+ const void *eaddr, in_port_t eport,
+ const void *faddr, in_port_t fport);
+
+/**
* struct flow_common - Common fields for packet flows
* @state: State of the flow table entry
* @type: Type of packet flow
diff --git a/flow_table.h b/flow_table.h
index aabdbb7..b3cb546 100644
--- a/flow_table.h
+++ b/flow_table.h
@@ -146,4 +146,7 @@ void flow_activate(struct flow_common *f);
#define FLOW_ACTIVATE(flow_) \
(flow_activate(&(flow_)->f))
+uint64_t flow_hash(const struct ctx *c, uint8_t proto, uint8_t pif,
+ const struct flowside *side);
+
#endif /* FLOW_TABLE_H */
diff --git a/tcp.c b/tcp.c
index b4c4f77..5c8c8d1 100644
--- a/tcp.c
+++ b/tcp.c
@@ -377,7 +377,7 @@ bool peek_offset_cap;
/* sendmsg() to socket */
static struct iovec tcp_iov [UIO_MAXIOV];
-/* Table for lookup from remote address, local port, remote port */
+/* Table for lookup from flowside information */
static flow_sidx_t tc_hash[TCP_HASH_TABLE_SIZE];
static_assert(ARRAY_SIZE(tc_hash) >= FLOW_MAX,
@@ -853,46 +853,6 @@ static int tcp_opt_get(const char *opts, size_t len, uint8_t type_find,
}
/**
- * tcp_hash_match() - Check if a connection entry matches address and ports
- * @conn: Connection entry to match against
- * @faddr: Guest side forwarding address
- * @eport: Guest side endpoint port
- * @fport: Guest side forwarding port
- *
- * Return: 1 on match, 0 otherwise
- */
-static int tcp_hash_match(const struct tcp_tap_conn *conn,
- const union inany_addr *faddr,
- in_port_t eport, in_port_t fport)
-{
- const struct flowside *tapside = TAPFLOW(conn);
-
- if (inany_equals(&tapside->faddr, faddr) &&
- tapside->eport == eport && tapside->fport == fport)
- return 1;
-
- return 0;
-}
-
-/**
- * tcp_hash() - Calculate hash value for connection given address and ports
- * @c: Execution context
- * @faddr: Guest side forwarding address
- * @eport: Guest side endpoint port
- * @fport: Guest side forwarding port
- *
- * Return: hash value, needs to be adjusted for table size
- */
-static uint64_t tcp_hash(const struct ctx *c, const union inany_addr *faddr,
- in_port_t eport, in_port_t fport)
-{
- struct siphash_state state = SIPHASH_INIT(c->hash_secret);
-
- inany_siphash_feed(&state, faddr);
- return siphash_final(&state, 20, (uint64_t)eport << 16 | fport);
-}
-
-/**
* tcp_conn_hash() - Calculate hash bucket of an existing connection
* @c: Execution context
* @conn: Connection
@@ -904,8 +864,7 @@ static uint64_t tcp_conn_hash(const struct ctx *c,
{
const struct flowside *tapside = TAPFLOW(conn);
- return tcp_hash(c, &tapside->faddr, tapside->eport,
- tapside->fport);
+ return flow_hash(c, IPPROTO_TCP, conn->f.pif[TAPSIDE(conn)], tapside);
}
/**
@@ -979,25 +938,26 @@ static void tcp_hash_remove(const struct ctx *c,
* tcp_hash_lookup() - Look up connection given remote address and ports
* @c: Execution context
* @af: Address family, AF_INET or AF_INET6
+ * @eaddr: Guest side endpoint address (guest local address)
* @faddr: Guest side forwarding address (guest remote address)
* @eport: Guest side endpoint port (guest local port)
* @fport: Guest side forwarding port (guest remote port)
*
* Return: connection pointer, if found, -ENOENT otherwise
*/
-static struct tcp_tap_conn *tcp_hash_lookup(const struct ctx *c,
- sa_family_t af, const void *faddr,
+static struct tcp_tap_conn *tcp_hash_lookup(const struct ctx *c, sa_family_t af,
+ const void *eaddr, const void *faddr,
in_port_t eport, in_port_t fport)
{
- union inany_addr aany;
+ struct flowside side;
union flow *flow;
unsigned b;
- inany_from_af(&aany, af, faddr);
+ flowside_from_af(&side, af, eaddr, eport, faddr, fport);
- b = tcp_hash(c, &aany, eport, fport) % TCP_HASH_TABLE_SIZE;
+ b = flow_hash(c, IPPROTO_TCP, PIF_TAP, &side) % TCP_HASH_TABLE_SIZE;
while ((flow = flow_at_sidx(tc_hash[b])) &&
- !tcp_hash_match(&flow->tcp, &aany, eport, fport))
+ !flowside_eq(&flow->f.side[TAPSIDE(flow)], &side))
b = mod_sub(b, 1, TCP_HASH_TABLE_SIZE);
return &flow->tcp;
@@ -2102,7 +2062,8 @@ int tcp_tap_handler(struct ctx *c, uint8_t pif, sa_family_t af,
optlen = MIN(optlen, ((1UL << 4) /* from doff width */ - 6) * 4UL);
opts = packet_get(p, idx, sizeof(*th), optlen, NULL);
- conn = tcp_hash_lookup(c, af, daddr, ntohs(th->source), ntohs(th->dest));
+ conn = tcp_hash_lookup(c, af, saddr, daddr,
+ ntohs(th->source), ntohs(th->dest));
/* New connection from tap */
if (!conn) {