tap: Fill the IPv6 flow label field to represent flow association
This isn't optional: TCP streams must carry a unique, hard-to-guess, non-zero label for each direction. Linux, probably among others, will otherwise refuse to associate packets in a given stream to the same connection. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
This commit is contained in:
parent
17765f8de0
commit
16b08367a5
5 changed files with 25 additions and 10 deletions
4
dhcpv6.c
4
dhcpv6.c
|
@ -520,7 +520,7 @@ int dhcpv6(struct ctx *c, struct ethhdr *eh, size_t len)
|
||||||
resp_not_on_link.hdr.xid = mh->xid;
|
resp_not_on_link.hdr.xid = mh->xid;
|
||||||
|
|
||||||
tap_ip_send(c, &c->gw6, IPPROTO_UDP,
|
tap_ip_send(c, &c->gw6, IPPROTO_UDP,
|
||||||
(char *)&resp_not_on_link, n);
|
(char *)&resp_not_on_link, n, mh->xid);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -569,7 +569,7 @@ int dhcpv6(struct ctx *c, struct ethhdr *eh, size_t len)
|
||||||
|
|
||||||
resp.hdr.xid = mh->xid;
|
resp.hdr.xid = mh->xid;
|
||||||
|
|
||||||
tap_ip_send(c, &c->gw6, IPPROTO_UDP, (char *)&resp, n);
|
tap_ip_send(c, &c->gw6, IPPROTO_UDP, (char *)&resp, n, mh->xid);
|
||||||
c->addr6_seen = c->addr6;
|
c->addr6_seen = c->addr6;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
4
icmp.c
4
icmp.c
|
@ -98,7 +98,7 @@ void icmp_sock_handler(struct ctx *c, union epoll_ref ref, uint32_t events,
|
||||||
icmp_id_map[V6][id].seq = seq;
|
icmp_id_map[V6][id].seq = seq;
|
||||||
}
|
}
|
||||||
|
|
||||||
tap_ip_send(c, &sr6->sin6_addr, IPPROTO_ICMPV6, buf, n);
|
tap_ip_send(c, &sr6->sin6_addr, IPPROTO_ICMPV6, buf, n, 0);
|
||||||
} else {
|
} else {
|
||||||
struct sockaddr_in *sr4 = (struct sockaddr_in *)&sr;
|
struct sockaddr_in *sr4 = (struct sockaddr_in *)&sr;
|
||||||
struct icmphdr *ih = (struct icmphdr *)buf;
|
struct icmphdr *ih = (struct icmphdr *)buf;
|
||||||
|
@ -115,7 +115,7 @@ void icmp_sock_handler(struct ctx *c, union epoll_ref ref, uint32_t events,
|
||||||
|
|
||||||
memcpy(&a6.s6_addr[12], &sr4->sin_addr, sizeof(sr4->sin_addr));
|
memcpy(&a6.s6_addr[12], &sr4->sin_addr, sizeof(sr4->sin_addr));
|
||||||
|
|
||||||
tap_ip_send(c, &a6, IPPROTO_ICMP, buf, n);
|
tap_ip_send(c, &a6, IPPROTO_ICMP, buf, n, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
18
tap.c
18
tap.c
|
@ -91,9 +91,10 @@ int tap_send(struct ctx *c, void *data, size_t len, int vnet_pre)
|
||||||
* @proto: L4 protocol number
|
* @proto: L4 protocol number
|
||||||
* @in: Payload
|
* @in: Payload
|
||||||
* @len: L4 payload length
|
* @len: L4 payload length
|
||||||
|
* @flow: Flow label for TCP over IPv6
|
||||||
*/
|
*/
|
||||||
void tap_ip_send(struct ctx *c, struct in6_addr *src, uint8_t proto,
|
void tap_ip_send(struct ctx *c, struct in6_addr *src, uint8_t proto,
|
||||||
char *in, size_t len)
|
char *in, size_t len, uint32_t flow)
|
||||||
{
|
{
|
||||||
char buf[USHRT_MAX];
|
char buf[USHRT_MAX];
|
||||||
char *pkt = buf + 4;
|
char *pkt = buf + 4;
|
||||||
|
@ -161,21 +162,30 @@ void tap_ip_send(struct ctx *c, struct in6_addr *src, uint8_t proto,
|
||||||
struct tcphdr *th = (struct tcphdr *)(ip6h + 1);
|
struct tcphdr *th = (struct tcphdr *)(ip6h + 1);
|
||||||
|
|
||||||
th->check = 0;
|
th->check = 0;
|
||||||
th->check = csum_ip4(ip6h, len + sizeof(*ip6h));
|
th->check = csum_unaligned(ip6h, len + sizeof(*ip6h),
|
||||||
|
0);
|
||||||
} else if (proto == IPPROTO_UDP) {
|
} else if (proto == IPPROTO_UDP) {
|
||||||
struct udphdr *uh = (struct udphdr *)(ip6h + 1);
|
struct udphdr *uh = (struct udphdr *)(ip6h + 1);
|
||||||
|
|
||||||
uh->check = 0;
|
uh->check = 0;
|
||||||
uh->check = csum_ip4(ip6h, len + sizeof(*ip6h));
|
uh->check = csum_unaligned(ip6h, len + sizeof(*ip6h),
|
||||||
|
0);
|
||||||
} else if (proto == IPPROTO_ICMPV6) {
|
} else if (proto == IPPROTO_ICMPV6) {
|
||||||
struct icmp6hdr *ih = (struct icmp6hdr *)(ip6h + 1);
|
struct icmp6hdr *ih = (struct icmp6hdr *)(ip6h + 1);
|
||||||
|
|
||||||
ih->icmp6_cksum = 0;
|
ih->icmp6_cksum = 0;
|
||||||
ih->icmp6_cksum = csum_ip4(ip6h, len + sizeof(*ip6h));
|
ih->icmp6_cksum = csum_unaligned(ip6h,
|
||||||
|
len + sizeof(*ip6h),
|
||||||
|
0);
|
||||||
}
|
}
|
||||||
ip6h->version = 6;
|
ip6h->version = 6;
|
||||||
ip6h->nexthdr = proto;
|
ip6h->nexthdr = proto;
|
||||||
ip6h->hop_limit = 255;
|
ip6h->hop_limit = 255;
|
||||||
|
if (flow) {
|
||||||
|
ip6h->flow_lbl[0] = (flow >> 16) & 0xf;
|
||||||
|
ip6h->flow_lbl[1] = (flow >> 8) & 0xff;
|
||||||
|
ip6h->flow_lbl[2] = (flow >> 0) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
tap_send(c, buf, len + sizeof(*ip6h) + sizeof(*eh), 1);
|
tap_send(c, buf, len + sizeof(*ip6h) + sizeof(*eh), 1);
|
||||||
}
|
}
|
||||||
|
|
2
tap.h
2
tap.h
|
@ -1,5 +1,5 @@
|
||||||
void tap_ip_send(struct ctx *c, struct in6_addr *src, uint8_t proto,
|
void tap_ip_send(struct ctx *c, struct in6_addr *src, uint8_t proto,
|
||||||
char *in, size_t len);
|
char *in, size_t len, uint32_t flow);
|
||||||
int tap_send(struct ctx *c, void *data, size_t len, int vnet_pre);
|
int tap_send(struct ctx *c, void *data, size_t len, int vnet_pre);
|
||||||
void tap_handler(struct ctx *c, uint32_t events, struct timespec *now);
|
void tap_handler(struct ctx *c, uint32_t events, struct timespec *now);
|
||||||
void tap_sock_init(struct ctx *c);
|
void tap_sock_init(struct ctx *c);
|
||||||
|
|
7
tcp.c
7
tcp.c
|
@ -469,6 +469,7 @@ struct tcp_tap_conn {
|
||||||
uint32_t seq_from_tap;
|
uint32_t seq_from_tap;
|
||||||
uint32_t seq_ack_to_tap;
|
uint32_t seq_ack_to_tap;
|
||||||
uint32_t seq_init_from_tap;
|
uint32_t seq_init_from_tap;
|
||||||
|
uint32_t seq_init_to_tap;
|
||||||
uint64_t tcpi_acked_last;
|
uint64_t tcpi_acked_last;
|
||||||
|
|
||||||
int ws_allowed;
|
int ws_allowed;
|
||||||
|
@ -934,7 +935,8 @@ static int tcp_send_to_tap(struct ctx *c, struct tcp_tap_conn *conn,
|
||||||
|
|
||||||
memcpy(data, in, len);
|
memcpy(data, in, len);
|
||||||
|
|
||||||
tap_ip_send(c, &conn->a.a6, IPPROTO_TCP, buf, th->doff * 4 + len);
|
tap_ip_send(c, &conn->a.a6, IPPROTO_TCP, buf, th->doff * 4 + len,
|
||||||
|
conn->seq_init_to_tap);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1116,6 +1118,7 @@ static void tcp_conn_from_tap(struct ctx *c, int af, void *addr,
|
||||||
conn->seq_ack_to_tap = conn->seq_from_tap;
|
conn->seq_ack_to_tap = conn->seq_from_tap;
|
||||||
|
|
||||||
conn->seq_to_tap = tcp_seq_init(c, af, addr, th->dest, th->source, now);
|
conn->seq_to_tap = tcp_seq_init(c, af, addr, th->dest, th->source, now);
|
||||||
|
conn->seq_init_to_tap = conn->seq_to_tap;
|
||||||
conn->seq_ack_from_tap = conn->seq_to_tap + 1;
|
conn->seq_ack_from_tap = conn->seq_to_tap + 1;
|
||||||
|
|
||||||
tcp_hash_insert(c, conn, af, addr);
|
tcp_hash_insert(c, conn, af, addr);
|
||||||
|
@ -1828,6 +1831,7 @@ static void tcp_conn_from_sock(struct ctx *c, union epoll_ref ref,
|
||||||
conn->sock_port,
|
conn->sock_port,
|
||||||
conn->tap_port,
|
conn->tap_port,
|
||||||
now);
|
now);
|
||||||
|
conn->seq_init_to_tap = conn->seq_to_tap;
|
||||||
|
|
||||||
tcp_hash_insert(c, conn, AF_INET6, &sa6->sin6_addr);
|
tcp_hash_insert(c, conn, AF_INET6, &sa6->sin6_addr);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1850,6 +1854,7 @@ static void tcp_conn_from_sock(struct ctx *c, union epoll_ref ref,
|
||||||
conn->sock_port,
|
conn->sock_port,
|
||||||
conn->tap_port,
|
conn->tap_port,
|
||||||
now);
|
now);
|
||||||
|
conn->seq_init_to_tap = conn->seq_to_tap;
|
||||||
|
|
||||||
tcp_hash_insert(c, conn, AF_INET, &sa4->sin_addr);
|
tcp_hash_insert(c, conn, AF_INET, &sa4->sin_addr);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue