TetherController: attach/detach tether bpf program to upstream interface

Test: build, atest

Manual test steps:
1. Connect to FarEastone mobile
2. Enable WiFi hotspot
3. Get the upstream interface via logcat
   I netd    : ipfwdAddInterfaceForward("wlan1", "rmnet_data1")
4. Check the tether BPF program attaching on upstream interface
   $ adb shell tc filter show dev rmnet_data1 ingress
   filter protocol ipv6 pref 1 bpf
   filter protocol ipv6 pref 1 bpf handle 0x1
   prog_offload_schedcls_ingress_tether_rawip:[*fsobj] direct-action
5. Disable WiFi hotspot
6. Check the tether BPF program detaching on upstream interface by
   logcat

Change-Id: I2acca0220a660fbaa235f8863237d526828c2af8
diff --git a/server/TetherController.cpp b/server/TetherController.cpp
index b56480a..a62d774 100644
--- a/server/TetherController.cpp
+++ b/server/TetherController.cpp
@@ -42,6 +42,7 @@
 #include <android-base/unique_fd.h>
 #include <cutils/properties.h>
 #include <log/log.h>
+#include <net/if.h>
 #include <netdutils/DumpWriter.h>
 #include <netdutils/StatusOr.h>
 
@@ -50,6 +51,7 @@
 #include "InterfaceController.h"
 #include "NetdConstants.h"
 #include "NetworkController.h"
+#include "OffloadUtils.h"
 #include "Permission.h"
 #include "TetherController.h"
 
@@ -598,6 +600,7 @@
         return -ENODEV;
     }
 
+    maybeStartBpf(extIface);
     return 0;
 }
 
@@ -784,6 +787,8 @@
     if (!isAnyForwardingPairEnabled()) {
         setDefaults();
     }
+
+    maybeStopBpf(extIface);
     return 0;
 }
 
@@ -922,6 +927,50 @@
     return statsList;
 }
 
+void TetherController::maybeStartBpf(const char* extIface) {
+    // TODO: perhaps ignore IPv4-only interface because IPv4 traffic downstream is not supported.
+    int ifIndex = if_nametoindex(extIface);
+    if (!ifIndex) {
+        ALOGE("Fail to get index for interface %s", extIface);
+        return;
+    }
+
+    auto isEthernet = android::net::isEthernet(extIface);
+    if (!isEthernet.ok()) {
+        ALOGE("isEthernet(%s[%d]) failure: %s", extIface, ifIndex,
+              isEthernet.error().message().c_str());
+        return;
+    }
+
+    int rv = getTetherIngressProgFd(isEthernet.value());
+    if (rv < 0) {
+        ALOGE("getTetherIngressProgFd(%d) failure: %s", isEthernet.value(), strerror(-rv));
+        return;
+    }
+    unique_fd tetherProgFd(rv);
+
+    rv = tcFilterAddDevIngressTether(ifIndex, tetherProgFd, isEthernet.value());
+    if (rv) {
+        ALOGE("tcFilterAddDevIngressTether(%d[%s], %d) failure: %s", ifIndex, extIface,
+              isEthernet.value(), strerror(-rv));
+        return;
+    }
+}
+
+void TetherController::maybeStopBpf(const char* extIface) {
+    // TODO: perhaps ignore IPv4-only interface because IPv4 traffic downstream is not supported.
+    int ifIndex = if_nametoindex(extIface);
+    if (!ifIndex) {
+        ALOGE("Fail to get index for interface %s", extIface);
+        return;
+    }
+
+    int rv = tcFilterDelDevIngressTether(ifIndex);
+    if (rv < 0) {
+        ALOGE("tcFilterDelDevIngressTether(%d[%s]) failure: %s", ifIndex, extIface, strerror(-rv));
+    }
+}
+
 void TetherController::dumpIfaces(DumpWriter& dw) {
     dw.println("Interface pairs:");