| /* |
| * Copyright (C) 2008 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. |
| */ |
| |
| #include <stdlib.h> |
| #include <errno.h> |
| #include <fcntl.h> |
| #include <string.h> |
| |
| #include <sys/socket.h> |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| #include <sys/wait.h> |
| |
| #include <linux/netlink.h> |
| #include <linux/rtnetlink.h> |
| #include <linux/pkt_sched.h> |
| |
| #define LOG_TAG "ThrottleController" |
| #include <cutils/log.h> |
| |
| |
| #include "ThrottleController.h" |
| #include "NetdConstants.h" |
| |
| extern "C" int system_nosh(const char *command); |
| extern "C" int ifc_init(void); |
| extern "C" int ifc_up(const char *name); |
| extern "C" int ifc_down(const char *name); |
| |
| int ThrottleController::runTcCmd(const char *cmd) { |
| char *buffer; |
| size_t len = strnlen(cmd, 255); |
| int res; |
| |
| if (len == 255) { |
| ALOGE("tc command too long"); |
| errno = E2BIG; |
| return -1; |
| } |
| |
| asprintf(&buffer, "%s %s", TC_PATH, cmd); |
| res = system_nosh(buffer); |
| free(buffer); |
| return res; |
| } |
| |
| int ThrottleController::setInterfaceThrottle(const char *iface, int rxKbps, int txKbps) { |
| char cmd[512]; |
| char ifn[65]; |
| int rc; |
| |
| memset(ifn, 0, sizeof(ifn)); |
| strncpy(ifn, iface, sizeof(ifn)-1); |
| |
| if (txKbps == -1) { |
| reset(ifn); |
| return 0; |
| } |
| |
| /* |
| * |
| * Target interface configuration |
| * |
| */ |
| |
| /* |
| * Add root qdisc for the interface |
| */ |
| sprintf(cmd, "qdisc add dev %s root handle 1: htb default 1 r2q 1000", ifn); |
| if (runTcCmd(cmd)) { |
| ALOGE("Failed to add root qdisc (%s)", strerror(errno)); |
| goto fail; |
| } |
| |
| /* |
| * Add our egress throttling class |
| */ |
| sprintf(cmd, "class add dev %s parent 1: classid 1:1 htb rate %dkbit", ifn, txKbps); |
| if (runTcCmd(cmd)) { |
| ALOGE("Failed to add egress throttling class (%s)", strerror(errno)); |
| goto fail; |
| } |
| |
| /* |
| * Bring up the IFD device |
| */ |
| ifc_init(); |
| if (ifc_up("ifb0")) { |
| ALOGE("Failed to up ifb0 (%s)", strerror(errno)); |
| goto fail; |
| } |
| |
| /* |
| * Add root qdisc for IFD |
| */ |
| sprintf(cmd, "qdisc add dev ifb0 root handle 1: htb default 1 r2q 1000"); |
| if (runTcCmd(cmd)) { |
| ALOGE("Failed to add root ifb qdisc (%s)", strerror(errno)); |
| goto fail; |
| } |
| |
| /* |
| * Add our ingress throttling class |
| */ |
| sprintf(cmd, "class add dev ifb0 parent 1: classid 1:1 htb rate %dkbit", rxKbps); |
| if (runTcCmd(cmd)) { |
| ALOGE("Failed to add ingress throttling class (%s)", strerror(errno)); |
| goto fail; |
| } |
| |
| /* |
| * Add ingress qdisc for pkt redirection |
| */ |
| sprintf(cmd, "qdisc add dev %s ingress", ifn); |
| if (runTcCmd(cmd)) { |
| ALOGE("Failed to add ingress qdisc (%s)", strerror(errno)); |
| goto fail; |
| } |
| |
| /* |
| * Add filter to link <ifn> -> ifb0 |
| */ |
| sprintf(cmd, "filter add dev %s parent ffff: protocol ip prio 10 u32 match " |
| "u32 0 0 flowid 1:1 action mirred egress redirect dev ifb0", ifn); |
| if (runTcCmd(cmd)) { |
| ALOGE("Failed to add ifb filter (%s)", strerror(errno)); |
| goto fail; |
| } |
| |
| return 0; |
| fail: |
| reset(ifn); |
| return -1; |
| } |
| |
| void ThrottleController::reset(const char *iface) { |
| char cmd[128]; |
| |
| sprintf(cmd, "qdisc del dev %s root", iface); |
| runTcCmd(cmd); |
| sprintf(cmd, "qdisc del dev %s ingress", iface); |
| runTcCmd(cmd); |
| |
| runTcCmd("qdisc del dev ifb0 root"); |
| } |
| |
| int ThrottleController::getInterfaceRxThrottle(const char *iface, int *rx) { |
| *rx = 0; |
| return 0; |
| } |
| |
| int ThrottleController::getInterfaceTxThrottle(const char *iface, int *tx) { |
| *tx = 0; |
| return 0; |
| } |