1 /*
2 * Copyright (C) 2022 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
17 #include <jni.h>
18 #include <nativehelper/JNIHelp.h>
19 #include <nativehelper/scoped_utf_chars.h>
20 #include <tcutils/tcutils.h>
21
22 #define BPF_FD_JUST_USE_INT
23 #include "BpfSyscallWrappers.h"
24
25 namespace android {
26
throwIOException(JNIEnv * env,const char * msg,int error)27 static void throwIOException(JNIEnv *env, const char *msg, int error) {
28 jniThrowExceptionFmt(env, "java/io/IOException", "%s: %s", msg,
29 strerror(error));
30 }
31
com_android_net_module_util_TcUtils_isEthernet(JNIEnv * env,jclass clazz,jstring iface)32 static jboolean com_android_net_module_util_TcUtils_isEthernet(JNIEnv *env,
33 jclass clazz,
34 jstring iface) {
35 ScopedUtfChars interface(env, iface);
36 bool result = false;
37 int error = isEthernet(interface.c_str(), result);
38 if (error) {
39 throwIOException(
40 env, "com_android_net_module_util_TcUtils_isEthernet error: ", -error);
41 }
42 // result is not touched when error is returned; leave false.
43 return result;
44 }
45
46 // tc filter add dev .. in/egress prio 1 protocol ipv6/ip bpf object-pinned
47 // /sys/fs/bpf/... direct-action
com_android_net_module_util_TcUtils_tcFilterAddDevBpf(JNIEnv * env,jclass clazz,jint ifIndex,jboolean ingress,jshort prio,jshort proto,jstring bpfProgPath)48 static void com_android_net_module_util_TcUtils_tcFilterAddDevBpf(
49 JNIEnv *env, jclass clazz, jint ifIndex, jboolean ingress, jshort prio,
50 jshort proto, jstring bpfProgPath) {
51 ScopedUtfChars pathname(env, bpfProgPath);
52 int error = tcAddBpfFilter(ifIndex, ingress, prio, proto, pathname.c_str());
53 if (error) {
54 throwIOException(
55 env,
56 "com_android_net_module_util_TcUtils_tcFilterAddDevBpf error: ", -error);
57 }
58 }
59
60 // tc filter add dev .. ingress prio .. protocol .. matchall \
61 // action police rate .. burst .. conform-exceed pipe/continue \
62 // action bpf object-pinned .. \
63 // drop
com_android_net_module_util_TcUtils_tcFilterAddDevIngressPolice(JNIEnv * env,jclass clazz,jint ifIndex,jshort prio,jshort proto,jint rateInBytesPerSec,jstring bpfProgPath)64 static void com_android_net_module_util_TcUtils_tcFilterAddDevIngressPolice(
65 JNIEnv *env, jclass clazz, jint ifIndex, jshort prio, jshort proto,
66 jint rateInBytesPerSec, jstring bpfProgPath) {
67 ScopedUtfChars pathname(env, bpfProgPath);
68 int error = tcAddIngressPoliceFilter(ifIndex, prio, proto, rateInBytesPerSec,
69 pathname.c_str());
70 if (error) {
71 throwIOException(env,
72 "com_android_net_module_util_TcUtils_"
73 "tcFilterAddDevIngressPolice error: ",
74 -error);
75 }
76 }
77
78 // tc filter del dev .. in/egress prio .. protocol ..
com_android_net_module_util_TcUtils_tcFilterDelDev(JNIEnv * env,jclass clazz,jint ifIndex,jboolean ingress,jshort prio,jshort proto)79 static void com_android_net_module_util_TcUtils_tcFilterDelDev(
80 JNIEnv *env, jclass clazz, jint ifIndex, jboolean ingress, jshort prio,
81 jshort proto) {
82 int error = tcDeleteFilter(ifIndex, ingress, prio, proto);
83 if (error) {
84 throwIOException(
85 env,
86 "com_android_net_module_util_TcUtils_tcFilterDelDev error: ", -error);
87 }
88 }
89
90 // tc qdisc add dev .. clsact
com_android_net_module_util_TcUtils_tcQdiscAddDevClsact(JNIEnv * env,jclass clazz,jint ifIndex)91 static void com_android_net_module_util_TcUtils_tcQdiscAddDevClsact(JNIEnv *env,
92 jclass clazz,
93 jint ifIndex) {
94 int error = tcAddQdiscClsact(ifIndex);
95 if (error) {
96 throwIOException(
97 env,
98 "com_android_net_module_util_TcUtils_tcQdiscAddDevClsact error: ", -error);
99 }
100 }
101
com_android_net_module_util_TcUtils_isBpfProgramUsable(JNIEnv * env,jclass clazz,jstring bpfProgPath)102 static jboolean com_android_net_module_util_TcUtils_isBpfProgramUsable(JNIEnv *env,
103 jclass clazz,
104 jstring bpfProgPath) {
105 ScopedUtfChars pathname(env, bpfProgPath);
106 return bpf::usableProgram(pathname.c_str());
107 }
108
109
110 /*
111 * JNI registration.
112 */
113 static const JNINativeMethod gMethods[] = {
114 /* name, signature, funcPtr */
115 {"isEthernet", "(Ljava/lang/String;)Z",
116 (void *)com_android_net_module_util_TcUtils_isEthernet},
117 {"tcFilterAddDevBpf", "(IZSSLjava/lang/String;)V",
118 (void *)com_android_net_module_util_TcUtils_tcFilterAddDevBpf},
119 {"tcFilterAddDevIngressPolice", "(ISSILjava/lang/String;)V",
120 (void *)com_android_net_module_util_TcUtils_tcFilterAddDevIngressPolice},
121 {"tcFilterDelDev", "(IZSS)V",
122 (void *)com_android_net_module_util_TcUtils_tcFilterDelDev},
123 {"tcQdiscAddDevClsact", "(I)V",
124 (void *)com_android_net_module_util_TcUtils_tcQdiscAddDevClsact},
125 {"isBpfProgramUsable", "(Ljava/lang/String;)Z",
126 (void *)com_android_net_module_util_TcUtils_isBpfProgramUsable},
127 };
128
register_com_android_net_module_util_TcUtils(JNIEnv * env,char const * class_name)129 int register_com_android_net_module_util_TcUtils(JNIEnv *env,
130 char const *class_name) {
131 return jniRegisterNativeMethods(env, class_name, gMethods, NELEM(gMethods));
132 }
133
134 }; // namespace android
135