blob: 6e230d0d6a3cdc7ee9abb9e626ad4bcc16f1dc69 [file] [log] [blame]
Hungming Chen8ebdb6f2022-01-16 14:44:11 +08001/*
2 * Copyright 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * main.c - main function
17 */
18#define LOG_TAG "bpfhelper"
19
20#include "libclat/bpfhelper.h"
21
22#include <android-base/unique_fd.h>
23#include <log/log.h>
24
25#include "bpf/BpfMap.h"
26#include "libclat/TcUtils.h"
27
28#define DEVICEPREFIX "v4-"
29
30using android::base::unique_fd;
31using android::net::RAWIP;
32using android::net::getClatEgress4MapFd;
33using android::net::getClatIngress6MapFd;
34using android::net::getClatEgress4ProgFd;
35using android::net::getClatIngress6ProgFd;
36using android::net::tcQdiscAddDevClsact;
37using android::net::tcFilterAddDevEgressClatIpv4;
38using android::net::tcFilterAddDevIngressClatIpv6;
39using android::net::tcFilterDelDevEgressClatIpv4;
40using android::net::tcFilterDelDevIngressClatIpv6;
41using android::bpf::BpfMap;
42
43BpfMap<ClatEgress4Key, ClatEgress4Value> mClatEgress4Map;
44BpfMap<ClatIngress6Key, ClatIngress6Value> mClatIngress6Map;
45
46namespace android {
47namespace net {
48namespace clat {
49
50// TODO: have a clearMap function to remove all stubs while system server crash.
51// For long term, move bpf access into java and map initialization should live
52// ClatCoordinator constructor.
53int initMaps(void) {
54 int rv = getClatEgress4MapFd();
55 if (rv < 0) {
56 ALOGE("getClatEgress4MapFd() failure: %s", strerror(-rv));
57 return -rv;
58 }
59 mClatEgress4Map.reset(rv);
60
61 rv = getClatIngress6MapFd();
62 if (rv < 0) {
63 ALOGE("getClatIngress6MapFd() failure: %s", strerror(-rv));
64 mClatEgress4Map.reset(-1);
65 return -rv;
66 }
67 mClatIngress6Map.reset(rv);
68
69 return 0;
70}
71
72void maybeStartBpf(const ClatdTracker& tracker) {
73 auto isEthernet = android::net::isEthernet(tracker.iface);
74 if (!isEthernet.ok()) {
75 ALOGE("isEthernet(%s[%d]) failure: %s", tracker.iface, tracker.ifIndex,
76 isEthernet.error().message().c_str());
77 return;
78 }
79
80 // This program will be attached to the v4-* interface which is a TUN and thus always rawip.
81 int rv = getClatEgress4ProgFd(RAWIP);
82 if (rv < 0) {
83 ALOGE("getClatEgress4ProgFd(RAWIP) failure: %s", strerror(-rv));
84 return;
85 }
86 unique_fd txRawIpProgFd(rv);
87
88 rv = getClatIngress6ProgFd(isEthernet.value());
89 if (rv < 0) {
90 ALOGE("getClatIngress6ProgFd(%d) failure: %s", isEthernet.value(), strerror(-rv));
91 return;
92 }
93 unique_fd rxProgFd(rv);
94
95 ClatEgress4Key txKey = {
96 .iif = tracker.v4ifIndex,
97 .local4 = tracker.v4,
98 };
99 ClatEgress4Value txValue = {
100 .oif = tracker.ifIndex,
101 .local6 = tracker.v6,
102 .pfx96 = tracker.pfx96,
103 .oifIsEthernet = isEthernet.value(),
104 };
105
106 auto ret = mClatEgress4Map.writeValue(txKey, txValue, BPF_ANY);
107 if (!ret.ok()) {
108 ALOGE("mClatEgress4Map.writeValue failure: %s", strerror(ret.error().code()));
109 return;
110 }
111
112 ClatIngress6Key rxKey = {
113 .iif = tracker.ifIndex,
114 .pfx96 = tracker.pfx96,
115 .local6 = tracker.v6,
116 };
117 ClatIngress6Value rxValue = {
118 // TODO: move all the clat code to eBPF and remove the tun interface entirely.
119 .oif = tracker.v4ifIndex,
120 .local4 = tracker.v4,
121 };
122
123 ret = mClatIngress6Map.writeValue(rxKey, rxValue, BPF_ANY);
124 if (!ret.ok()) {
125 ALOGE("mClatIngress6Map.writeValue failure: %s", strerror(ret.error().code()));
126 ret = mClatEgress4Map.deleteValue(txKey);
127 if (!ret.ok())
128 ALOGE("mClatEgress4Map.deleteValue failure: %s", strerror(ret.error().code()));
129 return;
130 }
131
132 // We do tc setup *after* populating the maps, so scanning through them
133 // can always be used to tell us what needs cleanup.
134
135 // Usually the clsact will be added in RouteController::addInterfaceToPhysicalNetwork.
136 // But clat is started before the v4- interface is added to the network. The clat startup have
137 // to add clsact of v4- tun interface first for adding bpf filter in maybeStartBpf.
138 // TODO: move "qdisc add clsact" of v4- tun interface out from ClatdController.
139 rv = tcQdiscAddDevClsact(tracker.v4ifIndex);
140 if (rv) {
141 ALOGE("tcQdiscAddDevClsact(%d[%s]) failure: %s", tracker.v4ifIndex, tracker.v4iface,
142 strerror(-rv));
143 ret = mClatEgress4Map.deleteValue(txKey);
144 if (!ret.ok())
145 ALOGE("mClatEgress4Map.deleteValue failure: %s", strerror(ret.error().code()));
146 ret = mClatIngress6Map.deleteValue(rxKey);
147 if (!ret.ok())
148 ALOGE("mClatIngress6Map.deleteValue failure: %s", strerror(ret.error().code()));
149 return;
150 }
151
152 rv = tcFilterAddDevEgressClatIpv4(tracker.v4ifIndex, txRawIpProgFd, RAWIP);
153 if (rv) {
154 ALOGE("tcFilterAddDevEgressClatIpv4(%d[%s], RAWIP) failure: %s", tracker.v4ifIndex,
155 tracker.v4iface, strerror(-rv));
156
157 // The v4- interface clsact is not deleted for unwinding error because once it is created
158 // with interface addition, the lifetime is till interface deletion. Moreover, the clsact
159 // has no clat filter now. It should not break anything.
160
161 ret = mClatEgress4Map.deleteValue(txKey);
162 if (!ret.ok())
163 ALOGE("mClatEgress4Map.deleteValue failure: %s", strerror(ret.error().code()));
164 ret = mClatIngress6Map.deleteValue(rxKey);
165 if (!ret.ok())
166 ALOGE("mClatIngress6Map.deleteValue failure: %s", strerror(ret.error().code()));
167 return;
168 }
169
170 rv = tcFilterAddDevIngressClatIpv6(tracker.ifIndex, rxProgFd, isEthernet.value());
171 if (rv) {
172 ALOGE("tcFilterAddDevIngressClatIpv6(%d[%s], %d) failure: %s", tracker.ifIndex,
173 tracker.iface, isEthernet.value(), strerror(-rv));
174 rv = tcFilterDelDevEgressClatIpv4(tracker.v4ifIndex);
175 if (rv) {
176 ALOGE("tcFilterDelDevEgressClatIpv4(%d[%s]) failure: %s", tracker.v4ifIndex,
177 tracker.v4iface, strerror(-rv));
178 }
179
180 // The v4- interface clsact is not deleted. See the reason in the error unwinding code of
181 // the egress filter attaching of v4- tun interface.
182
183 ret = mClatEgress4Map.deleteValue(txKey);
184 if (!ret.ok())
185 ALOGE("mClatEgress4Map.deleteValue failure: %s", strerror(ret.error().code()));
186 ret = mClatIngress6Map.deleteValue(rxKey);
187 if (!ret.ok())
188 ALOGE("mClatIngress6Map.deleteValue failure: %s", strerror(ret.error().code()));
189 return;
190 }
191
192 // success
193}
194
195void maybeStopBpf(const ClatdTracker& tracker) {
196 int rv = tcFilterDelDevIngressClatIpv6(tracker.ifIndex);
197 if (rv < 0) {
198 ALOGE("tcFilterDelDevIngressClatIpv6(%d[%s]) failure: %s", tracker.ifIndex, tracker.iface,
199 strerror(-rv));
200 }
201
202 rv = tcFilterDelDevEgressClatIpv4(tracker.v4ifIndex);
203 if (rv < 0) {
204 ALOGE("tcFilterDelDevEgressClatIpv4(%d[%s]) failure: %s", tracker.v4ifIndex,
205 tracker.v4iface, strerror(-rv));
206 }
207
208 // We cleanup the maps last, so scanning through them can be used to
209 // determine what still needs cleanup.
210
211 ClatEgress4Key txKey = {
212 .iif = tracker.v4ifIndex,
213 .local4 = tracker.v4,
214 };
215
216 auto ret = mClatEgress4Map.deleteValue(txKey);
217 if (!ret.ok()) ALOGE("mClatEgress4Map.deleteValue failure: %s", strerror(ret.error().code()));
218
219 ClatIngress6Key rxKey = {
220 .iif = tracker.ifIndex,
221 .pfx96 = tracker.pfx96,
222 .local6 = tracker.v6,
223 };
224
225 ret = mClatIngress6Map.deleteValue(rxKey);
226 if (!ret.ok()) ALOGE("mClatIngress6Map.deleteValue failure: %s", strerror(ret.error().code()));
227}
228
229} // namespace clat
230} // namespace net
231} // namespace android