Populate the key destination mac address

Required because XDP offload needs input interface mac address
to be a part of the key. The mac address is used for checking
packets which are received from exceped input interface.

Test: atest TetheringCoverageTests, TetheringPrivilegedTests
Change-Id: Ied159454b516c0d70efe0a85744d1bb606892f2d
diff --git a/Tethering/apishim/30/com/android/networkstack/tethering/apishim/api30/BpfCoordinatorShimImpl.java b/Tethering/apishim/30/com/android/networkstack/tethering/apishim/api30/BpfCoordinatorShimImpl.java
index ce71f45..e310fb6 100644
--- a/Tethering/apishim/30/com/android/networkstack/tethering/apishim/api30/BpfCoordinatorShimImpl.java
+++ b/Tethering/apishim/30/com/android/networkstack/tethering/apishim/api30/BpfCoordinatorShimImpl.java
@@ -80,12 +80,14 @@
 
     @Override
     public boolean startUpstreamIpv6Forwarding(int downstreamIfindex, int upstreamIfindex,
-            MacAddress srcMac, MacAddress dstMac, int mtu) {
+            @NonNull MacAddress inDstMac, @NonNull MacAddress outSrcMac,
+            @NonNull MacAddress outDstMac, int mtu) {
         return true;
     }
 
     @Override
-    public boolean stopUpstreamIpv6Forwarding(int downstreamIfindex, int upstreamIfindex) {
+    public boolean stopUpstreamIpv6Forwarding(int downstreamIfindex,
+            int upstreamIfindex, @NonNull MacAddress inDstMac) {
         return true;
     }
 
diff --git a/Tethering/apishim/31/com/android/networkstack/tethering/apishim/api31/BpfCoordinatorShimImpl.java b/Tethering/apishim/31/com/android/networkstack/tethering/apishim/api31/BpfCoordinatorShimImpl.java
index 2bb9fd7..d7ce139 100644
--- a/Tethering/apishim/31/com/android/networkstack/tethering/apishim/api31/BpfCoordinatorShimImpl.java
+++ b/Tethering/apishim/31/com/android/networkstack/tethering/apishim/api31/BpfCoordinatorShimImpl.java
@@ -184,12 +184,13 @@
 
     @Override
     public boolean startUpstreamIpv6Forwarding(int downstreamIfindex, int upstreamIfindex,
-            MacAddress srcMac, MacAddress dstMac, int mtu) {
+            @NonNull MacAddress inDstMac, @NonNull MacAddress outSrcMac,
+            @NonNull MacAddress outDstMac, int mtu) {
         if (!isInitialized()) return false;
 
-        final TetherUpstream6Key key = new TetherUpstream6Key(downstreamIfindex);
-        final Tether6Value value = new Tether6Value(upstreamIfindex, srcMac,
-                dstMac, OsConstants.ETH_P_IPV6, mtu);
+        final TetherUpstream6Key key = new TetherUpstream6Key(downstreamIfindex, inDstMac);
+        final Tether6Value value = new Tether6Value(upstreamIfindex, outSrcMac,
+                outDstMac, OsConstants.ETH_P_IPV6, mtu);
         try {
             mBpfUpstream6Map.insertEntry(key, value);
         } catch (ErrnoException | IllegalStateException e) {
@@ -200,10 +201,11 @@
     }
 
     @Override
-    public boolean stopUpstreamIpv6Forwarding(int downstreamIfindex, int upstreamIfindex) {
+    public boolean stopUpstreamIpv6Forwarding(int downstreamIfindex, int upstreamIfindex,
+            @NonNull MacAddress inDstMac) {
         if (!isInitialized()) return false;
 
-        final TetherUpstream6Key key = new TetherUpstream6Key(downstreamIfindex);
+        final TetherUpstream6Key key = new TetherUpstream6Key(downstreamIfindex, inDstMac);
         try {
             mBpfUpstream6Map.deleteEntry(key);
         } catch (ErrnoException e) {
diff --git a/Tethering/apishim/common/com/android/networkstack/tethering/apishim/common/BpfCoordinatorShim.java b/Tethering/apishim/common/com/android/networkstack/tethering/apishim/common/BpfCoordinatorShim.java
index ccdf78c..79a628b 100644
--- a/Tethering/apishim/common/com/android/networkstack/tethering/apishim/common/BpfCoordinatorShim.java
+++ b/Tethering/apishim/common/com/android/networkstack/tethering/apishim/common/BpfCoordinatorShim.java
@@ -78,21 +78,25 @@
 
      * @param downstreamIfindex the downstream interface index
      * @param upstreamIfindex the upstream interface index
-     * @param srcMac the source MAC address to use for packets
-     * @oaram dstMac the destination MAC address to use for packets
+     * @param inDstMac the destination MAC address to use for XDP
+     * @param outSrcMac the source MAC address to use for packets
+     * @param outDstMac the destination MAC address to use for packets
      * @return true if operation succeeded or was a no-op, false otherwise
      */
     public abstract boolean startUpstreamIpv6Forwarding(int downstreamIfindex, int upstreamIfindex,
-            MacAddress srcMac, MacAddress dstMac, int mtu);
+            @NonNull MacAddress inDstMac, @NonNull MacAddress outSrcMac,
+            @NonNull MacAddress outDstMac, int mtu);
 
     /**
      * Stops IPv6 forwarding between the specified interfaces.
 
      * @param downstreamIfindex the downstream interface index
      * @param upstreamIfindex the upstream interface index
+     * @param inDstMac the destination MAC address to use for XDP
      * @return true if operation succeeded or was a no-op, false otherwise
      */
-    public abstract boolean stopUpstreamIpv6Forwarding(int downstreamIfindex, int upstreamIfindex);
+    public abstract boolean stopUpstreamIpv6Forwarding(int downstreamIfindex,
+            int upstreamIfindex, @NonNull MacAddress inDstMac);
 
     /**
      * Return BPF tethering offload statistics.
diff --git a/Tethering/bpf_progs/bpf_tethering.h b/Tethering/bpf_progs/bpf_tethering.h
index efda228..5fdf8cd 100644
--- a/Tethering/bpf_progs/bpf_tethering.h
+++ b/Tethering/bpf_progs/bpf_tethering.h
@@ -107,11 +107,12 @@
 // Ethernet) have 6-byte MAC addresses.
 
 typedef struct {
-    uint32_t iif;            // The input interface index
-                             // TODO: extend this to include dstMac
-    struct in6_addr neigh6;  // The destination IPv6 address
+    uint32_t iif;              // The input interface index
+    uint8_t dstMac[ETH_ALEN];  // destination ethernet mac address (zeroed iff rawip ingress)
+    uint8_t zero[2];           // zero pad for 8 byte alignment
+    struct in6_addr neigh6;    // The destination IPv6 address
 } TetherDownstream6Key;
-STRUCT_SIZE(TetherDownstream6Key, 4 + 16);  // 20
+STRUCT_SIZE(TetherDownstream6Key, 4 + 6 + 2 + 16);  // 28
 
 typedef struct {
     uint32_t oif;             // The output interface to redirect to
@@ -154,10 +155,12 @@
 #define TETHER_UPSTREAM6_MAP_PATH BPF_PATH_TETHER "map_offload_tether_upstream6_map"
 
 typedef struct {
-    uint32_t iif;  // The input interface index
-                   // TODO: extend this to include dstMac and src ip /64 subnet
+    uint32_t iif;              // The input interface index
+    uint8_t dstMac[ETH_ALEN];  // destination ethernet mac address (zeroed iff rawip ingress)
+    uint8_t zero[2];           // zero pad for 8 byte alignment
+                               // TODO: extend this to include src ip /64 subnet
 } TetherUpstream6Key;
-STRUCT_SIZE(TetherUpstream6Key, 4);
+STRUCT_SIZE(TetherUpstream6Key, 12);
 
 #define TETHER_DOWNSTREAM4_TC_PROG_RAWIP_NAME "prog_offload_schedcls_tether_downstream4_rawip"
 #define TETHER_DOWNSTREAM4_TC_PROG_ETHER_NAME "prog_offload_schedcls_tether_downstream4_ether"
diff --git a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
index 6f54d10..27fb581 100644
--- a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
+++ b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
@@ -485,7 +485,7 @@
             final int upstream = rule.upstreamIfindex;
             // TODO: support upstream forwarding on non-point-to-point interfaces.
             // TODO: get the MTU from LinkProperties and update the rules when it changes.
-            if (!mBpfCoordinatorShim.startUpstreamIpv6Forwarding(downstream, upstream,
+            if (!mBpfCoordinatorShim.startUpstreamIpv6Forwarding(downstream, upstream, rule.srcMac,
                     NULL_MAC_ADDRESS, NULL_MAC_ADDRESS, NetworkStackConstants.ETHER_MTU)) {
                 mLog.e("Failed to enable upstream IPv6 forwarding from "
                         + mInterfaceNames.get(downstream) + " to " + mInterfaceNames.get(upstream));
@@ -526,7 +526,8 @@
         if (!isAnyRuleFromDownstreamToUpstream(rule.downstreamIfindex, rule.upstreamIfindex)) {
             final int downstream = rule.downstreamIfindex;
             final int upstream = rule.upstreamIfindex;
-            if (!mBpfCoordinatorShim.stopUpstreamIpv6Forwarding(downstream, upstream)) {
+            if (!mBpfCoordinatorShim.stopUpstreamIpv6Forwarding(downstream, upstream,
+                    rule.srcMac)) {
                 mLog.e("Failed to disable upstream IPv6 forwarding from "
                         + mInterfaceNames.get(downstream) + " to " + mInterfaceNames.get(upstream));
             }
@@ -795,8 +796,8 @@
     }
 
     private String ipv6UpstreamRuletoString(TetherUpstream6Key key, Tether6Value value) {
-        return String.format("%d(%s) -> %d(%s) %04x %s %s",
-                key.iif, getIfName(key.iif), value.oif, getIfName(value.oif),
+        return String.format("%d(%s) %s -> %d(%s) %04x %s %s",
+                key.iif, getIfName(key.iif), key.dstMac, value.oif, getIfName(value.oif),
                 value.ethProto, value.ethSrcMac, value.ethDstMac);
     }
 
@@ -885,6 +886,62 @@
 
     /** IPv6 forwarding rule class. */
     public static class Ipv6ForwardingRule {
+        // The upstream6 and downstream6 rules are built as the following tables. Only raw ip
+        // upstream interface is supported.
+        // TODO: support ether ip upstream interface.
+        //
+        // NAT network topology:
+        //
+        //         public network (rawip)                 private network
+        //                   |                 UE                |
+        // +------------+    V    +------------+------------+    V    +------------+
+        // |   Sever    +---------+  Upstream  | Downstream +---------+   Client   |
+        // +------------+         +------------+------------+         +------------+
+        //
+        // upstream6 key and value:
+        //
+        // +------+-------------+
+        // | TetherUpstream6Key |
+        // +------+------+------+
+        // |field |iif   |dstMac|
+        // |      |      |      |
+        // +------+------+------+
+        // |value |downst|downst|
+        // |      |ream  |ream  |
+        // +------+------+------+
+        //
+        // +------+----------------------------------+
+        // |      |Tether6Value                      |
+        // +------+------+------+------+------+------+
+        // |field |oif   |ethDst|ethSrc|ethPro|pmtu  |
+        // |      |      |mac   |mac   |to    |      |
+        // +------+------+------+------+------+------+
+        // |value |upstre|--    |--    |ETH_P_|1500  |
+        // |      |am    |      |      |IP    |      |
+        // +------+------+------+------+------+------+
+        //
+        // downstream6 key and value:
+        //
+        // +------+--------------------+
+        // |      |TetherDownstream6Key|
+        // +------+------+------+------+
+        // |field |iif   |dstMac|neigh6|
+        // |      |      |      |      |
+        // +------+------+------+------+
+        // |value |upstre|--    |client|
+        // |      |am    |      |      |
+        // +------+------+------+------+
+        //
+        // +------+----------------------------------+
+        // |      |Tether6Value                      |
+        // +------+------+------+------+------+------+
+        // |field |oif   |ethDst|ethSrc|ethPro|pmtu  |
+        // |      |      |mac   |mac   |to    |      |
+        // +------+------+------+------+------+------+
+        // |value |downst|client|downst|ETH_P_|1500  |
+        // |      |ream  |      |ream  |IP    |      |
+        // +------+------+------+------+------+------+
+        //
         public final int upstreamIfindex;
         public final int downstreamIfindex;
 
@@ -934,7 +991,8 @@
          */
         @NonNull
         public TetherDownstream6Key makeTetherDownstream6Key() {
-            return new TetherDownstream6Key(upstreamIfindex, address.getAddress());
+            return new TetherDownstream6Key(upstreamIfindex, NULL_MAC_ADDRESS,
+                    address.getAddress());
         }
 
         /**
diff --git a/Tethering/src/com/android/networkstack/tethering/TetherDownstream6Key.java b/Tethering/src/com/android/networkstack/tethering/TetherDownstream6Key.java
index 3860cba..a08ad4a 100644
--- a/Tethering/src/com/android/networkstack/tethering/TetherDownstream6Key.java
+++ b/Tethering/src/com/android/networkstack/tethering/TetherDownstream6Key.java
@@ -16,6 +16,10 @@
 
 package com.android.networkstack.tethering;
 
+import android.net.MacAddress;
+
+import androidx.annotation.NonNull;
+
 import com.android.net.module.util.Struct;
 import com.android.net.module.util.Struct.Field;
 import com.android.net.module.util.Struct.Type;
@@ -24,16 +28,23 @@
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.Arrays;
+import java.util.Objects;
 
 /** The key of BpfMap which is used for bpf offload. */
 public class TetherDownstream6Key extends Struct {
     @Field(order = 0, type = Type.U32)
     public final long iif; // The input interface index.
 
-    @Field(order = 1, type = Type.ByteArray, arraysize = 16)
+    @Field(order = 1, type = Type.EUI48, padding = 2)
+    public final MacAddress dstMac; // Destination ethernet mac address (zeroed iff rawip ingress).
+
+    @Field(order = 2, type = Type.ByteArray, arraysize = 16)
     public final byte[] neigh6; // The destination IPv6 address.
 
-    public TetherDownstream6Key(final long iif, final byte[] neigh6) {
+    public TetherDownstream6Key(final long iif, @NonNull final MacAddress dstMac,
+            final byte[] neigh6) {
+        Objects.requireNonNull(dstMac);
+
         try {
             final Inet6Address unused = (Inet6Address) InetAddress.getByAddress(neigh6);
         } catch (ClassCastException | UnknownHostException e) {
@@ -41,29 +52,15 @@
                     + Arrays.toString(neigh6));
         }
         this.iif = iif;
+        this.dstMac = dstMac;
         this.neigh6 = neigh6;
     }
 
     @Override
-    public boolean equals(Object obj) {
-        if (this == obj) return true;
-
-        if (!(obj instanceof TetherDownstream6Key)) return false;
-
-        final TetherDownstream6Key that = (TetherDownstream6Key) obj;
-
-        return iif == that.iif && Arrays.equals(neigh6, that.neigh6);
-    }
-
-    @Override
-    public int hashCode() {
-        return Long.hashCode(iif) ^ Arrays.hashCode(neigh6);
-    }
-
-    @Override
     public String toString() {
         try {
-            return String.format("iif: %d, neigh: %s", iif, Inet6Address.getByAddress(neigh6));
+            return String.format("iif: %d, dstMac: %s, neigh: %s", iif, dstMac,
+                    Inet6Address.getByAddress(neigh6));
         } catch (UnknownHostException e) {
             // Should not happen because construtor already verify neigh6.
             throw new IllegalStateException("Invalid TetherDownstream6Key");
diff --git a/Tethering/src/com/android/networkstack/tethering/TetherUpstream6Key.java b/Tethering/src/com/android/networkstack/tethering/TetherUpstream6Key.java
index c736f2a..5893885 100644
--- a/Tethering/src/com/android/networkstack/tethering/TetherUpstream6Key.java
+++ b/Tethering/src/com/android/networkstack/tethering/TetherUpstream6Key.java
@@ -16,14 +16,26 @@
 
 package com.android.networkstack.tethering;
 
+import android.net.MacAddress;
+
+import androidx.annotation.NonNull;
+
 import com.android.net.module.util.Struct;
 
+import java.util.Objects;
+
 /** Key type for upstream IPv6 forwarding map. */
 public class TetherUpstream6Key extends Struct {
     @Field(order = 0, type = Type.S32)
     public final int iif; // The input interface index.
 
-    public TetherUpstream6Key(int iif) {
+    @Field(order = 1, type = Type.EUI48, padding = 2)
+    public final MacAddress dstMac; // Destination ethernet mac address (zeroed iff rawip ingress).
+
+    public TetherUpstream6Key(int iif, @NonNull final MacAddress dstMac) {
+        Objects.requireNonNull(dstMac);
+
         this.iif = iif;
+        this.dstMac = dstMac;
     }
 }
diff --git a/Tethering/tests/privileged/src/com/android/networkstack/tethering/BpfMapTest.java b/Tethering/tests/privileged/src/com/android/networkstack/tethering/BpfMapTest.java
index 62302c3..2e79739 100644
--- a/Tethering/tests/privileged/src/com/android/networkstack/tethering/BpfMapTest.java
+++ b/Tethering/tests/privileged/src/com/android/networkstack/tethering/BpfMapTest.java
@@ -65,13 +65,13 @@
     @Before
     public void setUp() throws Exception {
         mTestData = new ArrayMap<>();
-        mTestData.put(createTetherDownstream6Key(101, "2001:db8::1"),
+        mTestData.put(createTetherDownstream6Key(101, "00:00:00:00:00:aa", "2001:db8::1"),
                 createTether6Value(11, "00:00:00:00:00:0a", "11:11:11:00:00:0b",
                 ETH_P_IPV6, 1280));
-        mTestData.put(createTetherDownstream6Key(102, "2001:db8::2"),
+        mTestData.put(createTetherDownstream6Key(102, "00:00:00:00:00:bb", "2001:db8::2"),
                 createTether6Value(22, "00:00:00:00:00:0c", "22:22:22:00:00:0d",
                 ETH_P_IPV6, 1400));
-        mTestData.put(createTetherDownstream6Key(103, "2001:db8::3"),
+        mTestData.put(createTetherDownstream6Key(103, "00:00:00:00:00:cc", "2001:db8::3"),
                 createTether6Value(33, "00:00:00:00:00:0e", "33:33:33:00:00:0f",
                 ETH_P_IPV6, 1500));
 
@@ -94,11 +94,12 @@
         assertTrue(mTestMap.isEmpty());
     }
 
-    private TetherDownstream6Key createTetherDownstream6Key(long iif, String address)
-            throws Exception {
+    private TetherDownstream6Key createTetherDownstream6Key(long iif, String mac,
+            String address) throws Exception {
+        final MacAddress dstMac = MacAddress.fromString(mac);
         final InetAddress ipv6Address = InetAddress.getByName(address);
 
-        return new TetherDownstream6Key(iif, ipv6Address.getAddress());
+        return new TetherDownstream6Key(iif, dstMac, ipv6Address.getAddress());
     }
 
     private Tether6Value createTether6Value(int oif, String src, String dst, int proto, int pmtu) {
@@ -164,7 +165,7 @@
     public void testGetNextKey() throws Exception {
         // [1] If the passed-in key is not found on empty map, return null.
         final TetherDownstream6Key nonexistentKey =
-                createTetherDownstream6Key(1234, "2001:db8::10");
+                createTetherDownstream6Key(1234, "00:00:00:00:00:01", "2001:db8::10");
         assertNull(mTestMap.getNextKey(nonexistentKey));
 
         // [2] If the passed-in key is null on empty map, throw NullPointerException.
@@ -344,7 +345,8 @@
 
         // Build test data for TEST_MAP_SIZE + 1 entries.
         for (int i = 1; i <= TEST_MAP_SIZE + 1; i++) {
-            testData.put(createTetherDownstream6Key(i, "2001:db8::1"),
+            testData.put(
+                    createTetherDownstream6Key(i, "00:00:00:00:00:01", "2001:db8::1"),
                     createTether6Value(100, "de:ad:be:ef:00:01", "de:ad:be:ef:00:02",
                     ETH_P_IPV6, 1500));
         }
diff --git a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
index 1380bbf..435cab5 100644
--- a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
+++ b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
@@ -838,8 +838,8 @@
 
     @NonNull
     private static TetherDownstream6Key makeDownstream6Key(int upstreamIfindex,
-            @NonNull final InetAddress dst) {
-        return new TetherDownstream6Key(upstreamIfindex, dst.getAddress());
+            @NonNull MacAddress upstreamMac, @NonNull final InetAddress dst) {
+        return new TetherDownstream6Key(upstreamIfindex, upstreamMac, dst.getAddress());
     }
 
     @NonNull
@@ -857,10 +857,12 @@
     }
 
     private void verifyTetherOffloadRuleAdd(@Nullable InOrder inOrder, int upstreamIfindex,
-            @NonNull final InetAddress dst, @NonNull final MacAddress dstMac) throws Exception {
+            @NonNull MacAddress upstreamMac, @NonNull final InetAddress dst,
+            @NonNull final MacAddress dstMac) throws Exception {
         if (mBpfDeps.isAtLeastS()) {
             verifyWithOrder(inOrder, mBpfDownstream6Map).updateEntry(
-                    makeDownstream6Key(upstreamIfindex, dst), makeDownstream6Value(dstMac));
+                    makeDownstream6Key(upstreamIfindex, upstreamMac, dst),
+                    makeDownstream6Value(dstMac));
         } else {
             verifyWithOrder(inOrder, mNetd).tetherOffloadRuleAdd(matches(upstreamIfindex, dst,
                     dstMac));
@@ -868,10 +870,11 @@
     }
 
     private void verifyNeverTetherOffloadRuleAdd(int upstreamIfindex,
-            @NonNull final InetAddress dst, @NonNull final MacAddress dstMac) throws Exception {
+            @NonNull MacAddress upstreamMac, @NonNull final InetAddress dst,
+            @NonNull final MacAddress dstMac) throws Exception {
         if (mBpfDeps.isAtLeastS()) {
             verify(mBpfDownstream6Map, never()).updateEntry(
-                    makeDownstream6Key(upstreamIfindex, dst),
+                    makeDownstream6Key(upstreamIfindex, upstreamMac, dst),
                     makeDownstream6Value(dstMac));
         } else {
             verify(mNetd, never()).tetherOffloadRuleAdd(matches(upstreamIfindex, dst, dstMac));
@@ -887,10 +890,11 @@
     }
 
     private void verifyTetherOffloadRuleRemove(@Nullable InOrder inOrder, int upstreamIfindex,
-            @NonNull final InetAddress dst, @NonNull final MacAddress dstMac) throws Exception {
+            @NonNull MacAddress upstreamMac, @NonNull final InetAddress dst,
+            @NonNull final MacAddress dstMac) throws Exception {
         if (mBpfDeps.isAtLeastS()) {
             verifyWithOrder(inOrder, mBpfDownstream6Map).deleteEntry(makeDownstream6Key(
-                    upstreamIfindex, dst));
+                    upstreamIfindex, upstreamMac, dst));
         } else {
             // |dstMac| is not required for deleting rules. Used bacause tetherOffloadRuleRemove
             // uses a whole rule to be a argument.
@@ -911,7 +915,8 @@
     private void verifyStartUpstreamIpv6Forwarding(@Nullable InOrder inOrder, int upstreamIfindex)
             throws Exception {
         if (!mBpfDeps.isAtLeastS()) return;
-        final TetherUpstream6Key key = new TetherUpstream6Key(TEST_IFACE_PARAMS.index);
+        final TetherUpstream6Key key = new TetherUpstream6Key(TEST_IFACE_PARAMS.index,
+                TEST_IFACE_PARAMS.macAddr);
         final Tether6Value value = new Tether6Value(upstreamIfindex,
                 MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS,
                 ETH_P_IPV6, NetworkStackConstants.ETHER_MTU);
@@ -921,7 +926,8 @@
     private void verifyStopUpstreamIpv6Forwarding(@Nullable InOrder inOrder)
             throws Exception {
         if (!mBpfDeps.isAtLeastS()) return;
-        final TetherUpstream6Key key = new TetherUpstream6Key(TEST_IFACE_PARAMS.index);
+        final TetherUpstream6Key key = new TetherUpstream6Key(TEST_IFACE_PARAMS.index,
+                TEST_IFACE_PARAMS.macAddr);
         verifyWithOrder(inOrder, mBpfUpstream6Map).deleteEntry(key);
     }
 
@@ -991,14 +997,16 @@
         recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA);
         verify(mBpfCoordinator).tetherOffloadRuleAdd(
                 mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighA, macA));
-        verifyTetherOffloadRuleAdd(null, UPSTREAM_IFINDEX, neighA, macA);
+        verifyTetherOffloadRuleAdd(null,
+                UPSTREAM_IFINDEX, UPSTREAM_IFACE_PARAMS.macAddr, neighA, macA);
         verifyStartUpstreamIpv6Forwarding(null, UPSTREAM_IFINDEX);
         resetNetdBpfMapAndCoordinator();
 
         recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB);
         verify(mBpfCoordinator).tetherOffloadRuleAdd(
                 mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighB, macB));
-        verifyTetherOffloadRuleAdd(null, UPSTREAM_IFINDEX, neighB, macB);
+        verifyTetherOffloadRuleAdd(null,
+                UPSTREAM_IFINDEX, UPSTREAM_IFACE_PARAMS.macAddr, neighB, macB);
         verifyNoUpstreamIpv6ForwardingChange(null);
         resetNetdBpfMapAndCoordinator();
 
@@ -1013,7 +1021,8 @@
         recvNewNeigh(myIfindex, neighA, NUD_FAILED, null);
         verify(mBpfCoordinator).tetherOffloadRuleRemove(
                 mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighA, macNull));
-        verifyTetherOffloadRuleRemove(null, UPSTREAM_IFINDEX, neighA, macNull);
+        verifyTetherOffloadRuleRemove(null,
+                UPSTREAM_IFINDEX, UPSTREAM_IFACE_PARAMS.macAddr, neighA, macNull);
         verifyNoUpstreamIpv6ForwardingChange(null);
         resetNetdBpfMapAndCoordinator();
 
@@ -1021,7 +1030,8 @@
         recvDelNeigh(myIfindex, neighB, NUD_STALE, macB);
         verify(mBpfCoordinator).tetherOffloadRuleRemove(
                 mIpServer,  makeForwardingRule(UPSTREAM_IFINDEX, neighB, macNull));
-        verifyTetherOffloadRuleRemove(null, UPSTREAM_IFINDEX, neighB, macNull);
+        verifyTetherOffloadRuleRemove(null,
+                UPSTREAM_IFINDEX, UPSTREAM_IFACE_PARAMS.macAddr, neighB, macNull);
         verifyStopUpstreamIpv6Forwarding(null);
         resetNetdBpfMapAndCoordinator();
 
@@ -1036,12 +1046,16 @@
         lp.setInterfaceName(UPSTREAM_IFACE2);
         dispatchTetherConnectionChanged(UPSTREAM_IFACE2, lp, -1);
         verify(mBpfCoordinator).tetherOffloadRuleUpdate(mIpServer, UPSTREAM_IFINDEX2);
-        verifyTetherOffloadRuleRemove(inOrder, UPSTREAM_IFINDEX, neighA, macA);
-        verifyTetherOffloadRuleRemove(inOrder, UPSTREAM_IFINDEX, neighB, macB);
+        verifyTetherOffloadRuleRemove(inOrder,
+                UPSTREAM_IFINDEX, UPSTREAM_IFACE_PARAMS.macAddr, neighA, macA);
+        verifyTetherOffloadRuleRemove(inOrder,
+                UPSTREAM_IFINDEX, UPSTREAM_IFACE_PARAMS.macAddr, neighB, macB);
         verifyStopUpstreamIpv6Forwarding(inOrder);
-        verifyTetherOffloadRuleAdd(inOrder, UPSTREAM_IFINDEX2, neighA, macA);
+        verifyTetherOffloadRuleAdd(inOrder,
+                UPSTREAM_IFINDEX2, UPSTREAM_IFACE_PARAMS2.macAddr, neighA, macA);
         verifyStartUpstreamIpv6Forwarding(inOrder, UPSTREAM_IFINDEX2);
-        verifyTetherOffloadRuleAdd(inOrder, UPSTREAM_IFINDEX2, neighB, macB);
+        verifyTetherOffloadRuleAdd(inOrder,
+                UPSTREAM_IFINDEX2, UPSTREAM_IFACE_PARAMS2.macAddr, neighB, macB);
         verifyNoUpstreamIpv6ForwardingChange(inOrder);
         resetNetdBpfMapAndCoordinator();
 
@@ -1052,8 +1066,10 @@
         // - processMessage CMD_IPV6_TETHER_UPDATE for the IPv6 upstream is lost.
         // See dispatchTetherConnectionChanged.
         verify(mBpfCoordinator, times(2)).tetherOffloadRuleClear(mIpServer);
-        verifyTetherOffloadRuleRemove(null, UPSTREAM_IFINDEX2, neighA, macA);
-        verifyTetherOffloadRuleRemove(null, UPSTREAM_IFINDEX2, neighB, macB);
+        verifyTetherOffloadRuleRemove(null,
+                UPSTREAM_IFINDEX2, UPSTREAM_IFACE_PARAMS2.macAddr, neighA, macA);
+        verifyTetherOffloadRuleRemove(null,
+                UPSTREAM_IFINDEX2, UPSTREAM_IFACE_PARAMS2.macAddr, neighB, macB);
         verifyStopUpstreamIpv6Forwarding(inOrder);
         resetNetdBpfMapAndCoordinator();
 
@@ -1072,17 +1088,20 @@
         recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB);
         verify(mBpfCoordinator).tetherOffloadRuleAdd(
                 mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighB, macB));
-        verifyTetherOffloadRuleAdd(null, UPSTREAM_IFINDEX, neighB, macB);
+        verifyTetherOffloadRuleAdd(null,
+                UPSTREAM_IFINDEX, UPSTREAM_IFACE_PARAMS.macAddr, neighB, macB);
         verifyStartUpstreamIpv6Forwarding(null, UPSTREAM_IFINDEX);
         verify(mBpfCoordinator, never()).tetherOffloadRuleAdd(
                 mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighA, macA));
-        verifyNeverTetherOffloadRuleAdd(UPSTREAM_IFINDEX, neighA, macA);
+        verifyNeverTetherOffloadRuleAdd(
+                UPSTREAM_IFINDEX, UPSTREAM_IFACE_PARAMS.macAddr, neighA, macA);
 
         // If upstream IPv6 connectivity is lost, rules are removed.
         resetNetdBpfMapAndCoordinator();
         dispatchTetherConnectionChanged(UPSTREAM_IFACE, null, 0);
         verify(mBpfCoordinator).tetherOffloadRuleClear(mIpServer);
-        verifyTetherOffloadRuleRemove(null, UPSTREAM_IFINDEX, neighB, macB);
+        verifyTetherOffloadRuleRemove(null,
+                UPSTREAM_IFINDEX, UPSTREAM_IFACE_PARAMS.macAddr, neighB, macB);
         verifyStopUpstreamIpv6Forwarding(null);
 
         // When the interface goes down, rules are removed.
@@ -1092,18 +1111,22 @@
         recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB);
         verify(mBpfCoordinator).tetherOffloadRuleAdd(
                 mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighA, macA));
-        verifyTetherOffloadRuleAdd(null, UPSTREAM_IFINDEX, neighA, macA);
+        verifyTetherOffloadRuleAdd(null,
+                UPSTREAM_IFINDEX, UPSTREAM_IFACE_PARAMS.macAddr, neighA, macA);
         verifyStartUpstreamIpv6Forwarding(null, UPSTREAM_IFINDEX);
         verify(mBpfCoordinator).tetherOffloadRuleAdd(
                 mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighB, macB));
-        verifyTetherOffloadRuleAdd(null, UPSTREAM_IFINDEX, neighB, macB);
+        verifyTetherOffloadRuleAdd(null,
+                UPSTREAM_IFINDEX, UPSTREAM_IFACE_PARAMS.macAddr, neighB, macB);
         resetNetdBpfMapAndCoordinator();
 
         mIpServer.stop();
         mLooper.dispatchAll();
         verify(mBpfCoordinator).tetherOffloadRuleClear(mIpServer);
-        verifyTetherOffloadRuleRemove(null, UPSTREAM_IFINDEX, neighA, macA);
-        verifyTetherOffloadRuleRemove(null, UPSTREAM_IFINDEX, neighB, macB);
+        verifyTetherOffloadRuleRemove(null,
+                UPSTREAM_IFINDEX, UPSTREAM_IFACE_PARAMS.macAddr, neighA, macA);
+        verifyTetherOffloadRuleRemove(null,
+                UPSTREAM_IFINDEX, UPSTREAM_IFACE_PARAMS.macAddr, neighB, macB);
         verifyStopUpstreamIpv6Forwarding(null);
         verify(mIpNeighborMonitor).stop();
         resetNetdBpfMapAndCoordinator();
@@ -1132,14 +1155,16 @@
         recvNewNeigh(myIfindex, neigh, NUD_REACHABLE, macA);
         verify(mBpfCoordinator).tetherOffloadRuleAdd(
                 mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neigh, macA));
-        verifyTetherOffloadRuleAdd(null, UPSTREAM_IFINDEX, neigh, macA);
+        verifyTetherOffloadRuleAdd(null,
+                UPSTREAM_IFINDEX, UPSTREAM_IFACE_PARAMS.macAddr, neigh, macA);
         verifyStartUpstreamIpv6Forwarding(null, UPSTREAM_IFINDEX);
         resetNetdBpfMapAndCoordinator();
 
         recvDelNeigh(myIfindex, neigh, NUD_STALE, macA);
         verify(mBpfCoordinator).tetherOffloadRuleRemove(
                 mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neigh, macNull));
-        verifyTetherOffloadRuleRemove(null, UPSTREAM_IFINDEX, neigh, macNull);
+        verifyTetherOffloadRuleRemove(null,
+                UPSTREAM_IFINDEX, UPSTREAM_IFACE_PARAMS.macAddr, neigh, macNull);
         verifyStopUpstreamIpv6Forwarding(null);
         resetNetdBpfMapAndCoordinator();
 
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java
index 293d0df..27fdac5 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java
@@ -109,7 +109,7 @@
     public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule();
 
     private static final int DOWNSTREAM_IFINDEX = 10;
-    private static final MacAddress DOWNSTREAM_MAC = MacAddress.ALL_ZEROS_ADDRESS;
+    private static final MacAddress DOWNSTREAM_MAC = MacAddress.fromString("12:34:56:78:90:ab");
     private static final InetAddress NEIGH_A = InetAddresses.parseNumericAddress("2001:db8::1");
     private static final InetAddress NEIGH_B = InetAddresses.parseNumericAddress("2001:db8::2");
     private static final MacAddress MAC_A = MacAddress.fromString("00:00:00:00:00:0a");
@@ -383,19 +383,20 @@
     }
 
     private void verifyStartUpstreamIpv6Forwarding(@Nullable InOrder inOrder, int downstreamIfIndex,
-            int upstreamIfindex) throws Exception {
+            MacAddress downstreamMac, int upstreamIfindex) throws Exception {
         if (!mDeps.isAtLeastS()) return;
-        final TetherUpstream6Key key = new TetherUpstream6Key(downstreamIfIndex);
+        final TetherUpstream6Key key = new TetherUpstream6Key(downstreamIfIndex, downstreamMac);
         final Tether6Value value = new Tether6Value(upstreamIfindex,
                 MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS,
                 ETH_P_IPV6, NetworkStackConstants.ETHER_MTU);
         verifyWithOrder(inOrder, mBpfUpstream6Map).insertEntry(key, value);
     }
 
-    private void verifyStopUpstreamIpv6Forwarding(@Nullable InOrder inOrder, int downstreamIfIndex)
+    private void verifyStopUpstreamIpv6Forwarding(@Nullable InOrder inOrder, int downstreamIfIndex,
+            MacAddress downstreamMac)
             throws Exception {
         if (!mDeps.isAtLeastS()) return;
-        final TetherUpstream6Key key = new TetherUpstream6Key(downstreamIfIndex);
+        final TetherUpstream6Key key = new TetherUpstream6Key(downstreamIfIndex, downstreamMac);
         verifyWithOrder(inOrder, mBpfUpstream6Map).deleteEntry(key);
     }
 
@@ -732,9 +733,10 @@
 
         final TetherDownstream6Key key = rule.makeTetherDownstream6Key();
         assertEquals(key.iif, (long) mobileIfIndex);
+        assertEquals(key.dstMac, MacAddress.ALL_ZEROS_ADDRESS);  // rawip upstream
         assertTrue(Arrays.equals(key.neigh6, NEIGH_A.getAddress()));
-        // iif (4) + neigh6 (16) = 20.
-        assertEquals(20, key.writeToBytes().length);
+        // iif (4) + dstMac(6) + padding(2) + neigh6 (16) = 28.
+        assertEquals(28, key.writeToBytes().length);
     }
 
     @Test
@@ -875,7 +877,7 @@
         verifyTetherOffloadRuleAdd(inOrder, ethernetRuleA);
         verifyTetherOffloadSetInterfaceQuota(inOrder, ethIfIndex, QUOTA_UNLIMITED,
                 true /* isInit */);
-        verifyStartUpstreamIpv6Forwarding(inOrder, DOWNSTREAM_IFINDEX, ethIfIndex);
+        verifyStartUpstreamIpv6Forwarding(inOrder, DOWNSTREAM_IFINDEX, DOWNSTREAM_MAC, ethIfIndex);
         coordinator.tetherOffloadRuleAdd(mIpServer, ethernetRuleB);
         verifyTetherOffloadRuleAdd(inOrder, ethernetRuleB);
 
@@ -892,12 +894,13 @@
         coordinator.tetherOffloadRuleUpdate(mIpServer, mobileIfIndex);
         verifyTetherOffloadRuleRemove(inOrder, ethernetRuleA);
         verifyTetherOffloadRuleRemove(inOrder, ethernetRuleB);
-        verifyStopUpstreamIpv6Forwarding(inOrder, DOWNSTREAM_IFINDEX);
+        verifyStopUpstreamIpv6Forwarding(inOrder, DOWNSTREAM_IFINDEX, DOWNSTREAM_MAC);
         verifyTetherOffloadGetAndClearStats(inOrder, ethIfIndex);
         verifyTetherOffloadRuleAdd(inOrder, mobileRuleA);
         verifyTetherOffloadSetInterfaceQuota(inOrder, mobileIfIndex, QUOTA_UNLIMITED,
                 true /* isInit */);
-        verifyStartUpstreamIpv6Forwarding(inOrder, DOWNSTREAM_IFINDEX, mobileIfIndex);
+        verifyStartUpstreamIpv6Forwarding(inOrder, DOWNSTREAM_IFINDEX, DOWNSTREAM_MAC,
+                mobileIfIndex);
         verifyTetherOffloadRuleAdd(inOrder, mobileRuleB);
 
         // [3] Clear all rules for a given IpServer.
@@ -906,7 +909,7 @@
         coordinator.tetherOffloadRuleClear(mIpServer);
         verifyTetherOffloadRuleRemove(inOrder, mobileRuleA);
         verifyTetherOffloadRuleRemove(inOrder, mobileRuleB);
-        verifyStopUpstreamIpv6Forwarding(inOrder, DOWNSTREAM_IFINDEX);
+        verifyStopUpstreamIpv6Forwarding(inOrder, DOWNSTREAM_IFINDEX, DOWNSTREAM_MAC);
         verifyTetherOffloadGetAndClearStats(inOrder, mobileIfIndex);
 
         // [4] Force pushing stats update to verify that the last diff of stats is reported on all