summaryrefslogtreecommitdiff
path: root/Tethering/src/com/android/networkstack/tethering/BpfUtils.java
blob: 3d2dfaa8dbaa840b565c47685fdd933b598cf749 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.networkstack.tethering;

import static android.system.OsConstants.ETH_P_IP;
import static android.system.OsConstants.ETH_P_IPV6;

import static com.android.networkstack.tethering.util.TetheringUtils.getTetheringJniLibraryName;

import androidx.annotation.NonNull;

import com.android.net.module.util.InterfaceParams;
import com.android.net.module.util.TcUtils;

import java.io.IOException;

/**
 * The classes and the methods for BPF utilization.
 *
 * {@hide}
 */
public class BpfUtils {
    static {
        System.loadLibrary(getTetheringJniLibraryName());
    }

    // For better code clarity when used for 'bool ingress' parameter.
    static final boolean EGRESS = false;
    static final boolean INGRESS = true;

    // For better code clarify when used for 'bool downstream' parameter.
    //
    // This is talking about the direction of travel of the offloaded packets.
    //
    // Upstream means packets heading towards the internet/uplink (upload),
    // thus for tethering this is attached to ingress on the downstream interface,
    // while for clat this is attached to egress on the v4-* clat interface.
    //
    // Downstream means packets coming from the internet/uplink (download), thus
    // for both clat and tethering this is attached to ingress on the upstream interface.
    static final boolean DOWNSTREAM = true;
    static final boolean UPSTREAM = false;

    // The priority of tether hooks - smaller is higher priority.
    // TC tether is higher priority then TC clat to match XDP winning over TC.
    // Sync from system/netd/server/TcUtils.h.
    static final short PRIO_TETHER6 = 2;
    static final short PRIO_TETHER4 = 3;
    // note that the above must be lower than PRIO_CLAT from netd's OffloadUtils.cpp

    private static String makeProgPath(boolean downstream, int ipVersion, boolean ether) {
        String path = "/sys/fs/bpf/tethering/prog_offload_schedcls_tether_"
                + (downstream ? "downstream" : "upstream")
                + ipVersion + "_"
                + (ether ? "ether" : "rawip");
        return path;
    }

    /**
     * Attach BPF program
     *
     * TODO: use interface index to replace interface name.
     */
    public static void attachProgram(@NonNull String iface, boolean downstream)
            throws IOException {
        final InterfaceParams params = InterfaceParams.getByName(iface);
        if (params == null) {
            throw new IOException("Fail to get interface params for interface " + iface);
        }

        boolean ether;
        try {
            ether = TcUtils.isEthernet(iface);
        } catch (IOException e) {
            throw new IOException("isEthernet(" + params.index + "[" + iface + "]) failure: " + e);
        }

        try {
            // tc filter add dev .. ingress prio 1 protocol ipv6 bpf object-pinned /sys/fs/bpf/...
            // direct-action
            TcUtils.tcFilterAddDevBpf(params.index, INGRESS, PRIO_TETHER6, (short) ETH_P_IPV6,
                    makeProgPath(downstream, 6, ether));
        } catch (IOException e) {
            throw new IOException("tc filter add dev (" + params.index + "[" + iface
                    + "]) ingress prio PRIO_TETHER6 protocol ipv6 failure: " + e);
        }

        try {
            // tc filter add dev .. ingress prio 2 protocol ip bpf object-pinned /sys/fs/bpf/...
            // direct-action
            TcUtils.tcFilterAddDevBpf(params.index, INGRESS, PRIO_TETHER4, (short) ETH_P_IP,
                    makeProgPath(downstream, 4, ether));
        } catch (IOException e) {
            throw new IOException("tc filter add dev (" + params.index + "[" + iface
                    + "]) ingress prio PRIO_TETHER4 protocol ip failure: " + e);
        }
    }

    /**
     * Detach BPF program
     *
     * TODO: use interface index to replace interface name.
     */
    public static void detachProgram(@NonNull String iface) throws IOException {
        final InterfaceParams params = InterfaceParams.getByName(iface);
        if (params == null) {
            throw new IOException("Fail to get interface params for interface " + iface);
        }

        try {
            // tc filter del dev .. ingress prio 1 protocol ipv6
            TcUtils.tcFilterDelDev(params.index, INGRESS, PRIO_TETHER6, (short) ETH_P_IPV6);
        } catch (IOException e) {
            throw new IOException("tc filter del dev (" + params.index + "[" + iface
                    + "]) ingress prio PRIO_TETHER6 protocol ipv6 failure: " + e);
        }

        try {
            // tc filter del dev .. ingress prio 2 protocol ip
            TcUtils.tcFilterDelDev(params.index, INGRESS, PRIO_TETHER4, (short) ETH_P_IP);
        } catch (IOException e) {
            throw new IOException("tc filter del dev (" + params.index + "[" + iface
                    + "]) ingress prio PRIO_TETHER4 protocol ip failure: " + e);
        }
    }
}