Set mark on non-offloaded ingress clat traffic
As Maze@'s advice, we add a clat mark to clat packet in ingress bpf
and drop the duplicate packets in iptables via mark match.
Bug: 218407445
Test: manual test with unmerged aosp/1951099
0. Connect to IPv6-only wifi
1. Clatd test: ping 5 times and check that iptables drop 5 packets by
mark 0xdeadc1a7.
$ adb shell ping 8.8.8.8
..
64 bytes from 8.8.8.8: icmp_seq=4 ttl=120 time=14.3 ms
64 bytes from 8.8.8.8: icmp_seq=5 ttl=120 time=67.4 ms
$ adb shell ip6tables -t raw -L bw_raw_PREROUTING -v
Chain bw_raw_PREROUTING (1 references)
pkts bytes target prot opt in out source destination
5 520 DROP all any any anywhere anywhere mark match 0xdeadc1a7
0 0 RETURN all ipsec+ any anywhere anywhere
0 0 RETURN all any any anywhere anywhere policy match dir in pol ipsec
1661 1239K all any any anywhere anywhere match bpf pinned /sys/fs/bpf/prog_netd_skfilter_ingress_xtbpf
2. Bpf test: run iperf to an IPv4 server and iptables doesn't see
offloaded packet with mark 0xdeadc1a7. Drop packet count (5) is
unchanged.
$ adb shell iperf3 -4 -c 117.102.109.186 -t1
Connecting to host 117.102.109.186, port 5201
[ 5] local 192.0.0.4 port 56242 connected to 117.102.109.186 port 5201
[ ID] Interval Transfer Bitrate Retr Cwnd
[ 5] 0.00-1.00 sec 622 KBytes 5.09 Mbits/sec 0 44.0 KBytes
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bitrate Retr
[ 5] 0.00-1.00 sec 622 KBytes 5.09 Mbits/sec 0 sender
[ 5] 0.00-1.00 sec 201 KBytes 1.64 Mbits/sec receiver
$ adb shell ip6tables -t raw -L bw_raw_PREROUTING -v
Chain bw_raw_PREROUTING (1 references)
pkts bytes target prot opt in out source destination
5 520 DROP all any any anywhere anywhere mark match 0xdeadc1a7
0 0 RETURN all ipsec+ any anywhere anywhere
0 0 RETURN all any any anywhere anywhere policy match dir in pol ipsec
1804 1280K all any any anywhere anywhere match bpf pinned /sys/fs/bpf/prog_netd_skfilter_ingress_xtbpf
3. Enable USB tethering. Do ping and iperf on tethered client.
4. Clatd test: ping 5 times and check that iptables drop 5 packets
(count from 5 to 10) by mark 0xdeadc1a7.
$ ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
..
64 bytes from 8.8.8.8: icmp_seq=4 ttl=119 time=13.7 ms
64 bytes from 8.8.8.8: icmp_seq=5 ttl=119 time=15.9 ms
$ adb shell ip6tables -t raw -L bw_raw_PREROUTING -v
Chain bw_raw_PREROUTING (1 references)
pkts bytes target prot opt in out source destination
10 1040 DROP all any any anywhere anywhere mark match 0xdeadc1a7
0 0 RETURN all ipsec+ any anywhere anywhere
0 0 RETURN all any any anywhere anywhere policy match dir in pol ipsec
1900 1298K all any any anywhere anywhere match bpf pinned /sys/fs/bpf/prog_netd_skfilter_ingress_xtbpf
5. Bpf test: run iperf to an IPv4 server and iptables doesn't see
offloaded packet with mark 0xdeadc1a7. Drop packet count (10) is
unchanged.
$ iperf3 -4 -c 117.102.109.186 -t1
Connecting to host 117.102.109.186, port 5201
[ 5] local 192.168.235.233 port 41602 connected to 117.102.109.186 port 5201
[ ID] Interval Transfer Bitrate Retr Cwnd
[ 5] 0.00-1.00 sec 3.19 MBytes 26.8 Mbits/sec 0 369 KBytes
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bitrate Retr
[ 5] 0.00-1.00 sec 3.19 MBytes 26.8 Mbits/sec 0 sender
[ 5] 0.00-1.00 sec 2.58 MBytes 21.7 Mbits/sec receiver
$ adb shell ip6tables -t raw -L bw_raw_PREROUTING -v
Chain bw_raw_PREROUTING (1 references)
pkts bytes target prot opt in out source destination
10 1040 DROP all any any anywhere anywhere mark match 0xdeadc1a7
0 0 RETURN all ipsec+ any anywhere anywhere
0 0 RETURN all any any anywhere anywhere policy match dir in pol ipsec
1978 1320K all any any anywhere anywhere match bpf pinned /sys/fs/bpf/prog_netd_skfilter_ingress_xtbpf
Change-Id: I180206bb15a1362c678f42fb980b60dfed6ce1ab
diff --git a/bpf_progs/clatd.c b/bpf_progs/clatd.c
index dc646c3..55165b1 100644
--- a/bpf_progs/clatd.c
+++ b/bpf_progs/clatd.c
@@ -37,6 +37,12 @@
// From kernel:include/net/ip.h
#define IP_DF 0x4000 // Flag: "Don't Fragment"
+// Used for iptables drops ingress clat packet. Beware of clat mark change may break the device
+// which is using the old clat mark in netd platform code. The reason is that the clat mark is a
+// mainline constant since T+ but netd iptable rules (ex: bandwidth control, firewall, and so on)
+// are set in stone.
+#define CLAT_MARK 0xdeadc1a7
+
DEFINE_BPF_MAP_GRW(clat_ingress6_map, HASH, ClatIngress6Key, ClatIngress6Value, 16, AID_SYSTEM)
static inline __always_inline int nat64(struct __sk_buff* skb, bool is_ethernet) {
@@ -64,17 +70,6 @@
// Maximum IPv6 payload length that can be translated to IPv4
if (ntohs(ip6->payload_len) > 0xFFFF - sizeof(struct iphdr)) return TC_ACT_PIPE;
- switch (ip6->nexthdr) {
- case IPPROTO_TCP: // For TCP & UDP the checksum neutrality of the chosen IPv6
- case IPPROTO_UDP: // address means there is no need to update their checksums.
- case IPPROTO_GRE: // We do not need to bother looking at GRE/ESP headers,
- case IPPROTO_ESP: // since there is never a checksum to update.
- break;
-
- default: // do not know how to handle anything else
- return TC_ACT_PIPE;
- }
-
ClatIngress6Key k = {
.iif = skb->ifindex,
.pfx96.in6_u.u6_addr32 =
@@ -90,6 +85,21 @@
if (!v) return TC_ACT_PIPE;
+ switch (ip6->nexthdr) {
+ case IPPROTO_TCP: // For TCP & UDP the checksum neutrality of the chosen IPv6
+ case IPPROTO_UDP: // address means there is no need to update their checksums.
+ case IPPROTO_GRE: // We do not need to bother looking at GRE/ESP headers,
+ case IPPROTO_ESP: // since there is never a checksum to update.
+ break;
+
+ default: // do not know how to handle anything else
+ // Mark ingress non-offloaded clat packet for dropping in ip6tables bw_raw_PREROUTING.
+ // Non-offloaded clat packet is going to be handled by clat daemon and ip6tables. The
+ // duplicate one in ip6tables is not necessary.
+ skb->mark = CLAT_MARK;
+ return TC_ACT_PIPE;
+ }
+
struct ethhdr eth2; // used iff is_ethernet
if (is_ethernet) {
eth2 = *eth; // Copy over the ethernet header (src/dst mac)
@@ -132,7 +142,13 @@
// Packet mutations begin - point of no return, but if this first modification fails
// the packet is probably still pristine, so let clatd handle it.
- if (bpf_skb_change_proto(skb, htons(ETH_P_IP), 0)) return TC_ACT_PIPE;
+ if (bpf_skb_change_proto(skb, htons(ETH_P_IP), 0)) {
+ // Mark ingress non-offloaded clat packet for dropping in ip6tables bw_raw_PREROUTING.
+ // Non-offloaded clat packet is going to be handled by clat daemon and ip6tables. The
+ // duplicate one in ip6tables is not necessary.
+ skb->mark = CLAT_MARK;
+ return TC_ACT_PIPE;
+ }
// This takes care of updating the skb->csum field for a CHECKSUM_COMPLETE packet.
//