Improve BPF tethering counters. am: 72ec3ba88a

Original change: https://android-review.googlesource.com/c/platform/packages/modules/Connectivity/+/1580284

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: I43e2306bf134e2219b9f0a5bb59ad9c03f3aaa70
This commit is contained in:
Lorenzo Colitti
2021-02-09 06:27:17 +00:00
committed by Automerger Merge Worker
2 changed files with 22 additions and 18 deletions

View File

@@ -34,6 +34,7 @@
ERR(BELOW_IPV6_MTU) \ ERR(BELOW_IPV6_MTU) \
ERR(LIMIT_REACHED) \ ERR(LIMIT_REACHED) \
ERR(CHANGE_HEAD_FAILED) \ ERR(CHANGE_HEAD_FAILED) \
ERR(TOO_SHORT) \
ERR(_MAX) ERR(_MAX)
#define ERR(x) BPF_TETHER_ERR_ ##x, #define ERR(x) BPF_TETHER_ERR_ ##x,

View File

@@ -53,13 +53,16 @@ DEFINE_BPF_MAP_GRW(tether_upstream6_map, HASH, TetherUpstream6Key, Tether6Value,
DEFINE_BPF_MAP_GRW(tether_error_map, ARRAY, __u32, __u32, BPF_TETHER_ERR__MAX, DEFINE_BPF_MAP_GRW(tether_error_map, ARRAY, __u32, __u32, BPF_TETHER_ERR__MAX,
AID_NETWORK_STACK) AID_NETWORK_STACK)
#define ERROR_EXIT(error) do { \ #define COUNT_AND_RETURN(counter, ret) do { \
__u32 errcode = BPF_TETHER_ERR_ ## error; \ __u32 code = BPF_TETHER_ERR_ ## counter; \
__u32 *errcount = bpf_tether_error_map_lookup_elem(&errcode); \ __u32 *count = bpf_tether_error_map_lookup_elem(&code); \
if (errcount) __sync_fetch_and_add(errcount, 1); \ if (count) __sync_fetch_and_add(count, 1); \
return TC_ACT_OK; \ return ret; \
} while(0) } while(0)
#define DROP(counter) COUNT_AND_RETURN(counter, TC_ACT_SHOT)
#define PUNT(counter) COUNT_AND_RETURN(counter, TC_ACT_OK)
static inline __always_inline int do_forward6(struct __sk_buff* skb, const bool is_ethernet, static inline __always_inline int do_forward6(struct __sk_buff* skb, const bool is_ethernet,
const bool downstream) { const bool downstream) {
const int l2_header_size = is_ethernet ? sizeof(struct ethhdr) : 0; const int l2_header_size = is_ethernet ? sizeof(struct ethhdr) : 0;
@@ -81,11 +84,11 @@ static inline __always_inline int do_forward6(struct __sk_buff* skb, const bool
if (is_ethernet && (eth->h_proto != htons(ETH_P_IPV6))) return TC_ACT_OK; if (is_ethernet && (eth->h_proto != htons(ETH_P_IPV6))) return TC_ACT_OK;
// IP version must be 6 // IP version must be 6
if (ip6->version != 6) ERROR_EXIT(INVALID_IP_VERSION); if (ip6->version != 6) PUNT(INVALID_IP_VERSION);
// Cannot decrement during forward if already zero or would be zero, // Cannot decrement during forward if already zero or would be zero,
// Let the kernel's stack handle these cases and generate appropriate ICMP errors. // Let the kernel's stack handle these cases and generate appropriate ICMP errors.
if (ip6->hop_limit <= 1) ERROR_EXIT(LOW_TTL); if (ip6->hop_limit <= 1) PUNT(LOW_TTL);
// If hardware offload is running and programming flows based on conntrack entries, // If hardware offload is running and programming flows based on conntrack entries,
// try not to interfere with it. // try not to interfere with it.
@@ -94,27 +97,27 @@ static inline __always_inline int do_forward6(struct __sk_buff* skb, const bool
// Make sure we can get at the tcp header // Make sure we can get at the tcp header
if (data + l2_header_size + sizeof(*ip6) + sizeof(*tcph) > data_end) if (data + l2_header_size + sizeof(*ip6) + sizeof(*tcph) > data_end)
ERROR_EXIT(INVALID_TCP_HEADER); PUNT(INVALID_TCP_HEADER);
// Do not offload TCP packets with any one of the SYN/FIN/RST flags // Do not offload TCP packets with any one of the SYN/FIN/RST flags
if (tcph->syn || tcph->fin || tcph->rst) ERROR_EXIT(TCP_CONTROL_PACKET); if (tcph->syn || tcph->fin || tcph->rst) PUNT(TCP_CONTROL_PACKET);
} }
// Protect against forwarding packets sourced from ::1 or fe80::/64 or other weirdness. // Protect against forwarding packets sourced from ::1 or fe80::/64 or other weirdness.
__be32 src32 = ip6->saddr.s6_addr32[0]; __be32 src32 = ip6->saddr.s6_addr32[0];
if (src32 != htonl(0x0064ff9b) && // 64:ff9b:/32 incl. XLAT464 WKP if (src32 != htonl(0x0064ff9b) && // 64:ff9b:/32 incl. XLAT464 WKP
(src32 & htonl(0xe0000000)) != htonl(0x20000000)) // 2000::/3 Global Unicast (src32 & htonl(0xe0000000)) != htonl(0x20000000)) // 2000::/3 Global Unicast
ERROR_EXIT(NON_GLOBAL_SRC); PUNT(NON_GLOBAL_SRC);
// Protect against forwarding packets destined to ::1 or fe80::/64 or other weirdness. // Protect against forwarding packets destined to ::1 or fe80::/64 or other weirdness.
__be32 dst32 = ip6->daddr.s6_addr32[0]; __be32 dst32 = ip6->daddr.s6_addr32[0];
if (dst32 != htonl(0x0064ff9b) && // 64:ff9b:/32 incl. XLAT464 WKP if (dst32 != htonl(0x0064ff9b) && // 64:ff9b:/32 incl. XLAT464 WKP
(dst32 & htonl(0xe0000000)) != htonl(0x20000000)) // 2000::/3 Global Unicast (dst32 & htonl(0xe0000000)) != htonl(0x20000000)) // 2000::/3 Global Unicast
ERROR_EXIT(NON_GLOBAL_DST); PUNT(NON_GLOBAL_DST);
// In the upstream direction do not forward traffic within the same /64 subnet. // In the upstream direction do not forward traffic within the same /64 subnet.
if (!downstream && (src32 == dst32) && (ip6->saddr.s6_addr32[1] == ip6->daddr.s6_addr32[1])) if (!downstream && (src32 == dst32) && (ip6->saddr.s6_addr32[1] == ip6->daddr.s6_addr32[1]))
ERROR_EXIT(LOCAL_SRC_DST); PUNT(LOCAL_SRC_DST);
TetherDownstream6Key kd = { TetherDownstream6Key kd = {
.iif = skb->ifindex, .iif = skb->ifindex,
@@ -136,15 +139,15 @@ static inline __always_inline int do_forward6(struct __sk_buff* skb, const bool
TetherStatsValue* stat_v = bpf_tether_stats_map_lookup_elem(&stat_and_limit_k); TetherStatsValue* stat_v = bpf_tether_stats_map_lookup_elem(&stat_and_limit_k);
// If we don't have anywhere to put stats, then abort... // If we don't have anywhere to put stats, then abort...
if (!stat_v) ERROR_EXIT(NO_STATS_ENTRY); if (!stat_v) PUNT(NO_STATS_ENTRY);
uint64_t* limit_v = bpf_tether_limit_map_lookup_elem(&stat_and_limit_k); uint64_t* limit_v = bpf_tether_limit_map_lookup_elem(&stat_and_limit_k);
// If we don't have a limit, then abort... // If we don't have a limit, then abort...
if (!limit_v) ERROR_EXIT(NO_LIMIT_ENTRY); if (!limit_v) PUNT(NO_LIMIT_ENTRY);
// Required IPv6 minimum mtu is 1280, below that not clear what we should do, abort... // Required IPv6 minimum mtu is 1280, below that not clear what we should do, abort...
if (v->pmtu < IPV6_MIN_MTU) ERROR_EXIT(BELOW_IPV6_MTU); if (v->pmtu < IPV6_MIN_MTU) PUNT(BELOW_IPV6_MTU);
// Approximate handling of TCP/IPv6 overhead for incoming LRO/GRO packets: default // Approximate handling of TCP/IPv6 overhead for incoming LRO/GRO packets: default
// outbound path mtu of 1500 is not necessarily correct, but worst case we simply // outbound path mtu of 1500 is not necessarily correct, but worst case we simply
@@ -169,7 +172,7 @@ static inline __always_inline int do_forward6(struct __sk_buff* skb, const bool
// a packet we let the core stack deal with things. // a packet we let the core stack deal with things.
// (The core stack needs to handle limits correctly anyway, // (The core stack needs to handle limits correctly anyway,
// since we don't offload all traffic in both directions) // since we don't offload all traffic in both directions)
if (stat_v->rxBytes + stat_v->txBytes + bytes > *limit_v) ERROR_EXIT(LIMIT_REACHED); if (stat_v->rxBytes + stat_v->txBytes + bytes > *limit_v) PUNT(LIMIT_REACHED);
if (!is_ethernet) { if (!is_ethernet) {
// Try to inject an ethernet header, and simply return if we fail. // Try to inject an ethernet header, and simply return if we fail.
@@ -177,7 +180,7 @@ static inline __always_inline int do_forward6(struct __sk_buff* skb, const bool
// because this is easier and the kernel will strip extraneous ethernet header. // because this is easier and the kernel will strip extraneous ethernet header.
if (bpf_skb_change_head(skb, sizeof(struct ethhdr), /*flags*/ 0)) { if (bpf_skb_change_head(skb, sizeof(struct ethhdr), /*flags*/ 0)) {
__sync_fetch_and_add(downstream ? &stat_v->rxErrors : &stat_v->txErrors, 1); __sync_fetch_and_add(downstream ? &stat_v->rxErrors : &stat_v->txErrors, 1);
ERROR_EXIT(CHANGE_HEAD_FAILED); PUNT(CHANGE_HEAD_FAILED);
} }
// bpf_skb_change_head() invalidates all pointers - reload them // bpf_skb_change_head() invalidates all pointers - reload them
@@ -189,7 +192,7 @@ static inline __always_inline int do_forward6(struct __sk_buff* skb, const bool
// I do not believe this can ever happen, but keep the verifier happy... // I do not believe this can ever happen, but keep the verifier happy...
if (data + sizeof(struct ethhdr) + sizeof(*ip6) > data_end) { if (data + sizeof(struct ethhdr) + sizeof(*ip6) > data_end) {
__sync_fetch_and_add(downstream ? &stat_v->rxErrors : &stat_v->txErrors, 1); __sync_fetch_and_add(downstream ? &stat_v->rxErrors : &stat_v->txErrors, 1);
return TC_ACT_SHOT; DROP(TOO_SHORT);
} }
}; };