blob: 00785ad817c59474a4281be7024c516b95112bd8 [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;
Hungming Chen8ebdb6f2022-01-16 14:44:11 +080031using android::bpf::BpfMap;
32
33BpfMap<ClatEgress4Key, ClatEgress4Value> mClatEgress4Map;
34BpfMap<ClatIngress6Key, ClatIngress6Value> mClatIngress6Map;
35
36namespace android {
37namespace net {
38namespace clat {
39
40// TODO: have a clearMap function to remove all stubs while system server crash.
41// For long term, move bpf access into java and map initialization should live
42// ClatCoordinator constructor.
43int initMaps(void) {
44 int rv = getClatEgress4MapFd();
45 if (rv < 0) {
46 ALOGE("getClatEgress4MapFd() failure: %s", strerror(-rv));
47 return -rv;
48 }
49 mClatEgress4Map.reset(rv);
50
51 rv = getClatIngress6MapFd();
52 if (rv < 0) {
53 ALOGE("getClatIngress6MapFd() failure: %s", strerror(-rv));
54 mClatEgress4Map.reset(-1);
55 return -rv;
56 }
57 mClatIngress6Map.reset(rv);
58
59 return 0;
60}
61
62void maybeStartBpf(const ClatdTracker& tracker) {
63 auto isEthernet = android::net::isEthernet(tracker.iface);
64 if (!isEthernet.ok()) {
65 ALOGE("isEthernet(%s[%d]) failure: %s", tracker.iface, tracker.ifIndex,
66 isEthernet.error().message().c_str());
67 return;
68 }
69
70 // This program will be attached to the v4-* interface which is a TUN and thus always rawip.
71 int rv = getClatEgress4ProgFd(RAWIP);
72 if (rv < 0) {
73 ALOGE("getClatEgress4ProgFd(RAWIP) failure: %s", strerror(-rv));
74 return;
75 }
76 unique_fd txRawIpProgFd(rv);
77
78 rv = getClatIngress6ProgFd(isEthernet.value());
79 if (rv < 0) {
80 ALOGE("getClatIngress6ProgFd(%d) failure: %s", isEthernet.value(), strerror(-rv));
81 return;
82 }
83 unique_fd rxProgFd(rv);
84
85 ClatEgress4Key txKey = {
86 .iif = tracker.v4ifIndex,
87 .local4 = tracker.v4,
88 };
89 ClatEgress4Value txValue = {
90 .oif = tracker.ifIndex,
91 .local6 = tracker.v6,
92 .pfx96 = tracker.pfx96,
93 .oifIsEthernet = isEthernet.value(),
94 };
95
96 auto ret = mClatEgress4Map.writeValue(txKey, txValue, BPF_ANY);
97 if (!ret.ok()) {
98 ALOGE("mClatEgress4Map.writeValue failure: %s", strerror(ret.error().code()));
99 return;
100 }
101
102 ClatIngress6Key rxKey = {
103 .iif = tracker.ifIndex,
104 .pfx96 = tracker.pfx96,
105 .local6 = tracker.v6,
106 };
107 ClatIngress6Value rxValue = {
108 // TODO: move all the clat code to eBPF and remove the tun interface entirely.
109 .oif = tracker.v4ifIndex,
110 .local4 = tracker.v4,
111 };
112
113 ret = mClatIngress6Map.writeValue(rxKey, rxValue, BPF_ANY);
114 if (!ret.ok()) {
115 ALOGE("mClatIngress6Map.writeValue failure: %s", strerror(ret.error().code()));
116 ret = mClatEgress4Map.deleteValue(txKey);
117 if (!ret.ok())
118 ALOGE("mClatEgress4Map.deleteValue failure: %s", strerror(ret.error().code()));
119 return;
120 }
121
122 // We do tc setup *after* populating the maps, so scanning through them
123 // can always be used to tell us what needs cleanup.
124
125 // Usually the clsact will be added in RouteController::addInterfaceToPhysicalNetwork.
126 // But clat is started before the v4- interface is added to the network. The clat startup have
127 // to add clsact of v4- tun interface first for adding bpf filter in maybeStartBpf.
128 // TODO: move "qdisc add clsact" of v4- tun interface out from ClatdController.
129 rv = tcQdiscAddDevClsact(tracker.v4ifIndex);
130 if (rv) {
131 ALOGE("tcQdiscAddDevClsact(%d[%s]) failure: %s", tracker.v4ifIndex, tracker.v4iface,
132 strerror(-rv));
133 ret = mClatEgress4Map.deleteValue(txKey);
134 if (!ret.ok())
135 ALOGE("mClatEgress4Map.deleteValue failure: %s", strerror(ret.error().code()));
136 ret = mClatIngress6Map.deleteValue(rxKey);
137 if (!ret.ok())
138 ALOGE("mClatIngress6Map.deleteValue failure: %s", strerror(ret.error().code()));
139 return;
140 }
141
142 rv = tcFilterAddDevEgressClatIpv4(tracker.v4ifIndex, txRawIpProgFd, RAWIP);
143 if (rv) {
144 ALOGE("tcFilterAddDevEgressClatIpv4(%d[%s], RAWIP) failure: %s", tracker.v4ifIndex,
145 tracker.v4iface, strerror(-rv));
146
147 // The v4- interface clsact is not deleted for unwinding error because once it is created
148 // with interface addition, the lifetime is till interface deletion. Moreover, the clsact
149 // has no clat filter now. It should not break anything.
150
151 ret = mClatEgress4Map.deleteValue(txKey);
152 if (!ret.ok())
153 ALOGE("mClatEgress4Map.deleteValue failure: %s", strerror(ret.error().code()));
154 ret = mClatIngress6Map.deleteValue(rxKey);
155 if (!ret.ok())
156 ALOGE("mClatIngress6Map.deleteValue failure: %s", strerror(ret.error().code()));
157 return;
158 }
159
160 rv = tcFilterAddDevIngressClatIpv6(tracker.ifIndex, rxProgFd, isEthernet.value());
161 if (rv) {
162 ALOGE("tcFilterAddDevIngressClatIpv6(%d[%s], %d) failure: %s", tracker.ifIndex,
163 tracker.iface, isEthernet.value(), strerror(-rv));
164 rv = tcFilterDelDevEgressClatIpv4(tracker.v4ifIndex);
165 if (rv) {
166 ALOGE("tcFilterDelDevEgressClatIpv4(%d[%s]) failure: %s", tracker.v4ifIndex,
167 tracker.v4iface, strerror(-rv));
168 }
169
170 // The v4- interface clsact is not deleted. See the reason in the error unwinding code of
171 // the egress filter attaching of v4- tun interface.
172
173 ret = mClatEgress4Map.deleteValue(txKey);
174 if (!ret.ok())
175 ALOGE("mClatEgress4Map.deleteValue failure: %s", strerror(ret.error().code()));
176 ret = mClatIngress6Map.deleteValue(rxKey);
177 if (!ret.ok())
178 ALOGE("mClatIngress6Map.deleteValue failure: %s", strerror(ret.error().code()));
179 return;
180 }
181
182 // success
183}
184
185void maybeStopBpf(const ClatdTracker& tracker) {
186 int rv = tcFilterDelDevIngressClatIpv6(tracker.ifIndex);
187 if (rv < 0) {
188 ALOGE("tcFilterDelDevIngressClatIpv6(%d[%s]) failure: %s", tracker.ifIndex, tracker.iface,
189 strerror(-rv));
190 }
191
192 rv = tcFilterDelDevEgressClatIpv4(tracker.v4ifIndex);
193 if (rv < 0) {
194 ALOGE("tcFilterDelDevEgressClatIpv4(%d[%s]) failure: %s", tracker.v4ifIndex,
195 tracker.v4iface, strerror(-rv));
196 }
197
198 // We cleanup the maps last, so scanning through them can be used to
199 // determine what still needs cleanup.
200
201 ClatEgress4Key txKey = {
202 .iif = tracker.v4ifIndex,
203 .local4 = tracker.v4,
204 };
205
206 auto ret = mClatEgress4Map.deleteValue(txKey);
207 if (!ret.ok()) ALOGE("mClatEgress4Map.deleteValue failure: %s", strerror(ret.error().code()));
208
209 ClatIngress6Key rxKey = {
210 .iif = tracker.ifIndex,
211 .pfx96 = tracker.pfx96,
212 .local6 = tracker.v6,
213 };
214
215 ret = mClatIngress6Map.deleteValue(rxKey);
216 if (!ret.ok()) ALOGE("mClatIngress6Map.deleteValue failure: %s", strerror(ret.error().code()));
217}
218
219} // namespace clat
220} // namespace net
221} // namespace android