kernel: add shortcut-fe support

This commit is contained in:
CN_SZTL 2020-07-13 23:19:38 +08:00
parent 9c8a3a44e0
commit 6e64d8c6c3
No known key found for this signature in database
GPG Key ID: 6850B6345C862176
29 changed files with 13103 additions and 0 deletions

View File

@ -0,0 +1,91 @@
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=fast-classifier
PKG_RELEASE:=1
include $(INCLUDE_DIR)/package.mk
define KernelPackage/$(PKG_NAME)/Default
SECTION:=kernel
CATEGORY:=Kernel modules
SUBMENU:=Network Support
DEPENDS:=+kmod-ipt-conntrack +kmod-shortcut-fe
TITLE:=Kernel driver for FAST Classifier
FILES:=$(PKG_BUILD_DIR)/fast-classifier.ko
KCONFIG:=CONFIG_NF_CONNTRACK_CHAIN_EVENTS=y CONFIG_NF_CONNTRACK_MARK=y
PROVIDES:=$(PKG_NAME)
endef
define KernelPackage/$(PKG_NAME)
$(call KernelPackage/$(PKG_NAME)/Default)
endef
define KernelPackage/$(PKG_NAME)-noload
$(call KernelPackage/$(PKG_NAME)/Default)
endef
define KernelPackage/$(PKG_NAME)/Default/description
FAST Classifier talks to SFE to make decisions about offloading connections
endef
define KernelPackage/$(PKG_NAME)/description
$(call KernelPackage/$(PKG_NAME)/Default/description)
endef
define KernelPackage/$(PKG_NAME)-noload/description
$(call KernelPackage/$(PKG_NAME)/Default/description)
This package does not load $(PKG_NAME) at boot by default
endef
define Package/fast-classifier-example
TITLE:=Example user space program for fast-classifier
DEPENDS:=+libnl +kmod-fast-classifier
endef
define Package/fast-classifier-example/description
Example user space program that communicates with fast
classifier kernel module
endef
SFE_MAKE_OPTS:=SFE_SUPPORT_IPV6=y
define Build/Compile/kmod
+$(MAKE) $(PKG_JOBS) -C "$(LINUX_DIR)" $(strip $(SFE_MAKE_OPTS)) \
$(KERNEL_MAKE_FLAGS) \
$(PKG_MAKE_FLAGS) \
M="$(PKG_BUILD_DIR)" \
CONFIG_FAST_CLASSIFIER=m \
EXTRA_CFLAGS="$(EXTRA_CFLAGS)" \
modules
endef
define Build/Compile/example
$(TARGET_CC) -o $(PKG_BUILD_DIR)/userspace_fast_classifier \
-I $(PKG_BUILD_DIR) \
-I$(STAGING_DIR)/usr/include/libnl \
-I$(STAGING_DIR)/usr/include/libnl3 \
-lnl-genl-3 -lnl-3 \
$(PKG_BUILD_DIR)/nl_classifier_test.c
endef
define Build/Compile
$(Build/Compile/kmod)
$(if $(CONFIG_PACKAGE_fast-classifier-example),$(Build/Compile/example))
endef
define Build/InstallDev
$(INSTALL_DIR) $(1)/usr/include
$(CP) $(PKG_BUILD_DIR)/fast-classifier.h $(1)/usr/include/
endef
define Package/fast-classifier-example/install
$(INSTALL_DIR) $(1)/sbin
$(CP) $(PKG_BUILD_DIR)/userspace_fast_classifier $(1)/sbin/
endef
$(eval $(call KernelPackage,$(PKG_NAME)))
$(eval $(call KernelPackage,$(PKG_NAME)-noload))
#$(eval $(call BuildPackage,fast-classifier-example))

View File

@ -0,0 +1,10 @@
obj-$(CONFIG_FAST_CLASSIFIER) += fast-classifier.o
ifeq ($(SFE_SUPPORT_IPV6),)
SFE_SUPPORT_IPV6=y
endif
ccflags-$(SFE_SUPPORT_IPV6) += -DSFE_SUPPORT_IPV6
ccflags-y += -I$(obj)/../shortcut-fe
obj ?= .

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,57 @@
/*
* User space header to send message to the fast classifier
*
* Copyright (c) 2013,2016 The Linux Foundation. All rights reserved.
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all copies.
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/if_ether.h>
#define FAST_CLASSIFIER_GENL_VERSION (1)
#define FAST_CLASSIFIER_GENL_NAME "FC"
#define FAST_CLASSIFIER_GENL_MCGRP "FC_MCGRP"
#define FAST_CLASSIFIER_GENL_HDRSIZE (0)
enum {
FAST_CLASSIFIER_A_UNSPEC,
FAST_CLASSIFIER_A_TUPLE,
__FAST_CLASSIFIER_A_MAX,
};
#define FAST_CLASSIFIER_A_MAX (__FAST_CLASSIFIER_A_MAX - 1)
enum {
FAST_CLASSIFIER_C_UNSPEC,
FAST_CLASSIFIER_C_OFFLOAD,
FAST_CLASSIFIER_C_OFFLOADED,
FAST_CLASSIFIER_C_DONE,
__FAST_CLASSIFIER_C_MAX,
};
#define FAST_CLASSIFIER_C_MAX (__FAST_CLASSIFIER_C_MAX - 1)
struct fast_classifier_tuple {
unsigned short ethertype;
unsigned char proto;
union {
struct in_addr in;
struct in6_addr in6;
} src_saddr;
union {
struct in_addr in;
struct in6_addr in6;
} dst_saddr;
unsigned short sport;
unsigned short dport;
unsigned char smac[ETH_ALEN];
unsigned char dmac[ETH_ALEN];
};

View File

@ -0,0 +1,281 @@
/*
* Copyright (c) 2016 The Linux Foundation. All rights reserved.
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all copies.
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <netlink/genl/genl.h>
#include <netlink/genl/ctrl.h>
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#include <arpa/inet.h>
#define NL_CLASSIFIER_GENL_VERSION 1
#define NL_CLASSIFIER_GENL_FAMILY "FC"
#define NL_CLASSIFIER_GENL_GROUP "FC_MCGRP"
#define NL_CLASSIFIER_GENL_HDRSIZE 0
enum NL_CLASSIFIER_CMD {
NL_CLASSIFIER_CMD_UNSPEC,
NL_CLASSIFIER_CMD_ACCEL,
NL_CLASSIFIER_CMD_ACCEL_OK,
NL_CLASSIFIER_CMD_CONNECTION_CLOSED,
NL_CLASSIFIER_CMD_MAX,
};
enum NL_CLASSIFIER_ATTR {
NL_CLASSIFIER_ATTR_UNSPEC,
NL_CLASSIFIER_ATTR_TUPLE,
NL_CLASSIFIER_ATTR_MAX,
};
union nl_classifier_tuple_ip {
struct in_addr in;
struct in6_addr in6;
};
struct nl_classifier_tuple {
unsigned short af;
unsigned char proto;
union nl_classifier_tuple_ip src_ip;
union nl_classifier_tuple_ip dst_ip;
unsigned short sport;
unsigned short dport;
unsigned char smac[6];
unsigned char dmac[6];
};
struct nl_classifier_instance {
struct nl_sock *sock;
int family_id;
int group_id;
int stop;
};
struct nl_classifier_instance nl_cls_inst;
static struct nla_policy nl_classifier_genl_policy[(NL_CLASSIFIER_ATTR_MAX+1)] = {
[NL_CLASSIFIER_ATTR_TUPLE] = { .type = NLA_UNSPEC },
};
void nl_classifier_dump_nl_tuple(struct nl_classifier_tuple *tuple)
{
char ip_str[64];
printf("protocol = %s\n", (tuple->proto == IPPROTO_UDP) ? "udp" : ((tuple->proto == IPPROTO_TCP) ? "tcp" : "unknown"));
printf("source ip = %s\n", inet_ntop(tuple->af, &tuple->src_ip, ip_str, sizeof(ip_str)));
printf("destination ip = %s\n", inet_ntop(tuple->af, &tuple->dst_ip, ip_str, sizeof(ip_str)));
printf("source port = %d\n", ntohs(tuple->sport));
printf("destination port = %d\n", ntohs(tuple->dport));
}
int nl_classifier_msg_recv(struct nl_msg *msg, void *arg)
{
struct nlmsghdr *nlh = nlmsg_hdr(msg);
struct genlmsghdr *gnlh = nlmsg_data(nlh);
struct nlattr *attrs[(NL_CLASSIFIER_ATTR_MAX+1)];
genlmsg_parse(nlh, NL_CLASSIFIER_GENL_HDRSIZE, attrs, NL_CLASSIFIER_ATTR_MAX, nl_classifier_genl_policy);
switch (gnlh->cmd) {
case NL_CLASSIFIER_CMD_ACCEL_OK:
printf("Acceleration successful:\n");
nl_classifier_dump_nl_tuple(nla_data(attrs[NL_CLASSIFIER_ATTR_TUPLE]));
return NL_OK;
case NL_CLASSIFIER_CMD_CONNECTION_CLOSED:
printf("Connection is closed:\n");
nl_classifier_dump_nl_tuple(nla_data(attrs[NL_CLASSIFIER_ATTR_TUPLE]));
return NL_OK;
default:
printf("nl classifier received unknow message %d\n", gnlh->cmd);
}
return NL_SKIP;
}
void nl_classifier_offload(struct nl_classifier_instance *inst,
unsigned char proto, unsigned long *src_saddr,
unsigned long *dst_saddr, unsigned short sport,
unsigned short dport, int af)
{
struct nl_msg *msg;
int ret;
struct nl_classifier_tuple classifier_msg;
memset(&classifier_msg, 0, sizeof(classifier_msg));
classifier_msg.af = af;
classifier_msg.proto = proto;
memcpy(&classifier_msg.src_ip, src_saddr, (af == AF_INET ? 4 : 16));
memcpy(&classifier_msg.dst_ip, dst_saddr, (af == AF_INET ? 4 : 16));
classifier_msg.sport = sport;
classifier_msg.dport = dport;
msg = nlmsg_alloc();
if (!msg) {
printf("Unable to allocate message\n");
return;
}
genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, inst->family_id,
NL_CLASSIFIER_GENL_HDRSIZE, NLM_F_REQUEST,
NL_CLASSIFIER_CMD_ACCEL, NL_CLASSIFIER_GENL_VERSION);
nla_put(msg, NL_CLASSIFIER_ATTR_TUPLE, sizeof(classifier_msg), &classifier_msg);
ret = nl_send_auto(inst->sock, msg);
if (ret < 0) {
printf("send netlink message failed.\n");
nlmsg_free(msg);
return;
}
nlmsg_free(msg);
printf("nl classifier offload connection successful\n");
}
int nl_classifier_init(struct nl_classifier_instance *inst)
{
int ret;
inst->sock = nl_socket_alloc();
if (!inst->sock) {
printf("Unable to allocation socket.\n");
return -1;
}
genl_connect(inst->sock);
inst->family_id = genl_ctrl_resolve(inst->sock, NL_CLASSIFIER_GENL_FAMILY);
if (inst->family_id < 0) {
printf("Unable to resolve family %s\n", NL_CLASSIFIER_GENL_FAMILY);
goto init_failed;
}
inst->group_id = genl_ctrl_resolve_grp(inst->sock, NL_CLASSIFIER_GENL_FAMILY, NL_CLASSIFIER_GENL_GROUP);
if (inst->group_id < 0) {
printf("Unable to resolve mcast group %s\n", NL_CLASSIFIER_GENL_GROUP);
goto init_failed;
}
ret = nl_socket_add_membership(inst->sock, inst->group_id);
if (ret < 0) {
printf("Unable to add membership\n");
goto init_failed;
}
nl_socket_disable_seq_check(inst->sock);
nl_socket_modify_cb(inst->sock, NL_CB_VALID, NL_CB_CUSTOM, nl_classifier_msg_recv, NULL);
printf("nl classifier init successful\n");
return 0;
init_failed:
if (inst->sock) {
nl_close(inst->sock);
nl_socket_free(inst->sock);
inst->sock = NULL;
}
return -1;
}
void nl_classifier_exit(struct nl_classifier_instance *inst)
{
if (inst->sock) {
nl_close(inst->sock);
nl_socket_free(inst->sock);
inst->sock = NULL;
}
printf("nl classifier exit successful\n");
}
int nl_classifier_parse_arg(int argc, char *argv[], unsigned char *proto, unsigned long *src_saddr,
unsigned long *dst_saddr, unsigned short *sport, unsigned short *dport, int *af)
{
int ret;
unsigned short port;
if (argc < 7) {
printf("help: nl_classifier <v4|v6> <udp|tcp> <source ip> <destination ip> <source port> <destination port>\n");
return -1;
}
if (0 == strncmp(argv[1], "v4", 2)) {
*af = AF_INET;
} else if (0 == strncmp(argv[1], "v6", 2)) {
*af = AF_INET6;
} else {
printf("Address family is not supported");
return -1;
}
if (0 == strncmp(argv[2], "udp", 3)) {
*proto = IPPROTO_UDP;
} else if (0 == strncmp(argv[2], "tcp", 3)) {
*proto = IPPROTO_TCP;
} else {
printf("Protocol is not supported");
return -1;
}
ret = inet_pton(*af, argv[3], src_saddr);
if (ret <= 0) {
printf("source ip has wrong format\n");
return -1;
}
ret = inet_pton(*af, argv[4], dst_saddr);
if (ret <= 0) {
printf("destination ip has wrong format\n");
return -1;
}
port = strtol(argv[5], NULL, 0);
*sport = htons(port);
port = strtol(argv[6], NULL, 0);
*dport = htons(port);
printf("nl classifier parse arguments successful\n");
return 0;
}
int main(int argc, char *argv[])
{
struct nl_classifier_instance *inst = &nl_cls_inst;
unsigned char proto;
unsigned long src_addr[4];
unsigned long dst_addr[4];
unsigned short sport;
unsigned short dport;
int af;
int ret;
ret = nl_classifier_parse_arg(argc, argv, &proto, src_addr, dst_addr, &sport, &dport, &af);
if (ret < 0) {
printf("Failed to parse arguments\n");
return ret;
}
ret = nl_classifier_init(inst);
if (ret < 0) {
printf("Unable to init generic netlink\n");
return ret;
}
nl_classifier_offload(inst, proto, src_addr, dst_addr, sport, dport, af);
/* main loop to listen on message */
while (!inst->stop) {
nl_recvmsgs_default(inst->sock);
}
nl_classifier_exit(inst);
return 0;
}

View File

@ -0,0 +1,232 @@
/*
* Copyright (c) 2013,2016 The Linux Foundation. All rights reserved.
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all copies.
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <netlink/genl/genl.h>
#include <netlink/genl/ctrl.h>
#include <errno.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <fast-classifier.h>
static struct nl_sock *sock;
static struct nl_sock *sock_event;
static int family;
static int grp_id;
static struct nla_policy fast_classifier_genl_policy[FAST_CLASSIFIER_A_MAX + 1] = {
[FAST_CLASSIFIER_A_TUPLE] = { .type = NLA_UNSPEC },
};
void dump_fc_tuple(struct fast_classifier_tuple *fc_msg)
{
char src_str[INET_ADDRSTRLEN];
char dst_str[INET_ADDRSTRLEN];
printf("TUPLE: %d, %s, %s, %d, %d"
" SMAC=%02x:%02x:%02x:%02x:%02x:%02x",
" DMAC=%02x:%02x:%02x:%02x:%02x:%02x\n",
fc_msg->proto,
inet_ntop(AF_INET,
&fc_msg->src_saddr.in.s_addr,
src_str,
INET_ADDRSTRLEN),
inet_ntop(AF_INET,
&fc_msg->dst_saddr.in.s_addr,
dst_str,
INET_ADDRSTRLEN),
fc_msg->sport, fc_msg->dport,
fc_msg->smac[0], fc_msg->smac[1], fc_msg->smac[2],
fc_msg->smac[3], fc_msg->smac[4], fc_msg->smac[5],
fc_msg->dmac[0], fc_msg->dmac[1], fc_msg->dmac[2],
fc_msg->dmac[3], fc_msg->dmac[4], fc_msg->dmac[5]);
}
static int parse_cb(struct nl_msg *msg, void *arg)
{
struct nlmsghdr *nlh = nlmsg_hdr(msg);
struct genlmsghdr *gnlh = nlmsg_data(nlh);
struct nlattr *attrs[FAST_CLASSIFIER_A_MAX];
genlmsg_parse(nlh, 0, attrs, FAST_CLASSIFIER_A_MAX, fast_classifier_genl_policy);
switch (gnlh->cmd) {
case FAST_CLASSIFIER_C_OFFLOADED:
printf("Got a offloaded message\n");
dump_fc_tuple(nla_data(attrs[FAST_CLASSIFIER_A_TUPLE]));
return NL_OK;
case FAST_CLASSIFIER_C_DONE:
printf("Got a done message\n");
dump_fc_tuple(nla_data(attrs[FAST_CLASSIFIER_A_TUPLE]));
return NL_OK;
}
return NL_SKIP;
}
int fast_classifier_init(void)
{
int err;
sock = nl_socket_alloc();
if (!sock) {
printf("Unable to allocation socket.\n");
return -1;
}
genl_connect(sock);
sock_event = nl_socket_alloc();
if (!sock_event) {
nl_close(sock);
nl_socket_free(sock);
printf("Unable to allocation socket.\n");
return -1;
}
genl_connect(sock_event);
family = genl_ctrl_resolve(sock, FAST_CLASSIFIER_GENL_NAME);
if (family < 0) {
nl_close(sock_event);
nl_close(sock);
nl_socket_free(sock);
nl_socket_free(sock_event);
printf("Unable to resolve family\n");
return -1;
}
grp_id = genl_ctrl_resolve_grp(sock, FAST_CLASSIFIER_GENL_NAME,
FAST_CLASSIFIER_GENL_MCGRP);
if (grp_id < 0) {
printf("Unable to resolve mcast group\n");
return -1;
}
err = nl_socket_add_membership(sock_event, grp_id);
if (err < 0) {
printf("Unable to add membership\n");
return -1;
}
nl_socket_disable_seq_check(sock_event);
nl_socket_modify_cb(sock_event, NL_CB_VALID, NL_CB_CUSTOM, parse_cb, NULL);
return 0;
}
void fast_classifier_close(void)
{
nl_close(sock_event);
nl_close(sock);
nl_socket_free(sock_event);
nl_socket_free(sock);
}
void fast_classifier_ipv4_offload(unsigned char proto, unsigned long src_saddr,
unsigned long dst_saddr, unsigned short sport,
unsigned short dport)
{
struct nl_msg *msg;
int ret;
#ifdef DEBUG
char src_str[INET_ADDRSTRLEN];
char dst_str[INET_ADDRSTRLEN];
#endif
struct fast_classifier_tuple fc_msg;
#ifdef DEBUG
printf("DEBUG: would offload: %d, %s, %s, %d, %d\n", proto,
inet_ntop(AF_INET, &src_saddr, src_str, INET_ADDRSTRLEN),
inet_ntop(AF_INET, &dst_saddr, dst_str, INET_ADDRSTRLEN),
sport, dport);
#endif
fc_msg.proto = proto;
fc_msg.src_saddr.in.s_addr = src_saddr;
fc_msg.dst_saddr.in.s_addr = dst_saddr;
fc_msg.sport = sport;
fc_msg.dport = dport;
fc_msg.smac[0] = 'a';
fc_msg.smac[1] = 'b';
fc_msg.smac[2] = 'c';
fc_msg.smac[3] = 'd';
fc_msg.smac[4] = 'e';
fc_msg.smac[5] = 'f';
fc_msg.dmac[0] = 'f';
fc_msg.dmac[1] = 'e';
fc_msg.dmac[2] = 'd';
fc_msg.dmac[3] = 'c';
fc_msg.dmac[4] = 'b';
fc_msg.dmac[5] = 'a';
if (fast_classifier_init() < 0) {
printf("Unable to init generic netlink\n");
exit(1);
}
msg = nlmsg_alloc();
if (!msg) {
nl_socket_free(sock);
printf("Unable to allocate message\n");
return;
}
genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family,
FAST_CLASSIFIER_GENL_HDRSIZE, NLM_F_REQUEST,
FAST_CLASSIFIER_C_OFFLOAD, FAST_CLASSIFIER_GENL_VERSION);
nla_put(msg, 1, sizeof(fc_msg), &fc_msg);
ret = nl_send_auto_complete(sock, msg);
nlmsg_free(msg);
if (ret < 0) {
printf("nlmsg_free failed");
nl_close(sock);
nl_socket_free(sock);
return;
}
ret = nl_wait_for_ack(sock);
if (ret < 0) {
printf("wait for ack failed");
nl_close(sock);
nl_socket_free(sock);
return;
}
}
void fast_classifier_listen_for_messages(void)
{
printf("waiting for netlink events\n");
while (1) {
nl_recvmsgs_default(sock_event);
}
}
int main(int argc, char *argv[])
{
if (fast_classifier_init() < 0) {
printf("Unable to init generic netlink\n");
exit(1);
}
fast_classifier_ipv4_offload('a', 0, 0, 0, 0);
/* this never returns */
fast_classifier_listen_for_messages();
fast_classifier_close();
return 0;
}

View File

@ -0,0 +1,17 @@
# Copyright (C) 2016 Openwrt.org
#
# This is free software, licensed under the Apache License, Version 2.0 .
#
include $(TOPDIR)/rules.mk
LUCI_TITLE:=LuCI support for Turbo ACC (SFE)
LUCI_DEPENDS:=+kmod-fast-classifier +pdnsd-alt +kmod-tcp-bbr
LUCI_PKGARCH:=all
PKG_VERSION:=1.0
PKG_RELEASE:=13
include $(TOPDIR)/feeds/luci/luci.mk
# call BuildPackage - OpenWrt buildroot signature

View File

@ -0,0 +1,44 @@
module("luci.controller.sfe", package.seeall)
function index()
if not nixio.fs.access("/etc/config/sfe") then
return
end
local page
page = entry({"admin", "network", "sfe"}, cbi("sfe"), _("Turbo ACC Center"), 100)
page.i18n = "sfe"
page.dependent = true
entry({"admin", "network", "sfe", "status"}, call("action_status"))
end
local function is_running()
return luci.sys.call("lsmod | grep fast_classifier >/dev/null") == 0
end
local function is_bbr()
return luci.sys.call("sysctl net.ipv4.tcp_congestion_control | grep bbr >/dev/null") == 0
end
local function is_fullcone()
return luci.sys.call("iptables -t nat -L -n --line-numbers | grep FULLCONENAT >/dev/null") == 0
end
local function is_dns()
return luci.sys.call("[ x$(uci get sfe.config.dnscache_enable 2>/dev/null) != x3 ] && pgrep dnscache >/dev/null || pgrep AdGuardHome >/dev/null") == 0
end
local function is_ad()
return luci.sys.call("pgrep AdGuardHome >/dev/null") == 0
end
function action_status()
luci.http.prepare_content("application/json")
luci.http.write_json({
run_state = is_running(),
down_state = is_bbr(),
up_state = is_fullcone(),
dns_state = is_dns(),
ad_state = is_ad()
})
end

View File

@ -0,0 +1,67 @@
local trport = 3001
local button = ""
if luci.sys.call("pidof AdGuardHome >/dev/null") == 0 then
button = "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<input type=\"button\" value=\" " .. translate("Open Web Interface") .. " \" onclick=\"window.open('http://'+window.location.hostname+':" .. trport .. "')\"/>"
end
m = Map("sfe")
m.title = translate("Turbo ACC Acceleration Settings")
m.description = translate("Opensource Qualcomm Shortcut FE driver (Fast Path)")
m:append(Template("sfe/status"))
s = m:section(TypedSection, "sfe", "")
s.addremove = false
s.anonymous = true
enable = s:option(Flag, "enabled", translate("Enable SFE Fast Path"))
enable.default = 0
enable.rmempty = false
enable.description = translate("Enable Fast Path offloading for connections. (decrease cpu load / increase routing throughput)")
wifi = s:option(Flag, "wifi", translate("Bridge Acceleration"))
wifi.default = 0
wifi.rmempty = false
wifi.description = translate("Enable Bridge Acceleration (may be functional conflict with bridge-mode VPN Server)")
wifi:depends("enabled", 1)
ipv6 = s:option(Flag, "ipv6", translate("IPv6 Acceleration"))
ipv6.default = 0
ipv6.rmempty = false
ipv6.description = translate("Enable IPv6 Acceleration")
ipv6:depends("enabled", 1)
bbr = s:option(Flag, "bbr", translate("Enable BBR"))
bbr.default = 0
bbr.rmempty = false
bbr.description = translate("Bottleneck Bandwidth and Round-trip propagation time (BBR)")
dns = s:option(Flag, "dns", translate("DNS Acceleration"))
dns.default = 0
dns.rmempty = false
dns.description = translate("Enable DNS Cache Acceleration and anti ISP DNS pollution")
o = s:option(ListValue, "dnscache_enable", translate("Resolve Dns Mode"), translate("AdGuardHome's login username/passwd: AdGuardHome, web console addr: IP:3001") .. button)
o:value("1", translate("Use Pdnsd query and cache"))
if nixio.fs.access("/usr/bin/dnsforwarder") then
o:value("2", translate("Use dnsforwarder query and cache"))
end
if nixio.fs.access("/usr/bin/AdGuardHome") then
o:value("3", translate("Use AdGuardHome query and cache"))
end
o.default = 1
o:depends("dns", 1)
o = s:option(Value, "dns_server", translate("Upsteam DNS Server"))
o.default = "114.114.114.114,114.114.115.115,223.5.5.5,223.6.6.6,180.76.76.76,119.29.29.29,119.28.28.28,1.2.4.8,210.2.4.8"
o.description = translate("Muitiple DNS server can saperate with ','")
o:depends("dnscache_enable", 1)
o:depends("dnscache_enable", 2)
o = s:option(Value, "ipv6dns_server", translate("Upsteam IPV6 DNS Server"))
o.default = "2001:4860:4860::8888,2001:4860:4860::8844,2001:2001::1111,2001:2001::1001,2400:da00::6666,240C::6666,240C::6644"
o.description = translate("Muitiple IPV6 DNS server can saperate with ','")
o:depends("dnscache_enable", 2)
return m

View File

@ -0,0 +1,27 @@
<fieldset class="cbi-section">
<legend><%:Running Status%></legend>
<table width="100%" cellspacing="10" id="_xlnetacc_status_table">
<tr><td width="33%">SFE 加速状态</td><td id="_run_state"><em><%:Collecting data...%></em></td></tr>
<tr><td width="33%">BBR 加速</td><td id="_down_state"><em><%:Collecting data...%></em></td></tr>
<tr><td width="33%">FULLCONE NAT加速</td><td id="_up_state"><em><%:Collecting data...%></em></td></tr>
<tr><td width="33%">DNS 加速</td><td id="_dns_state"><em><%:Collecting data...%></em></td></tr>
<tr><td width="33%">AdGuardHome 去广告</td><td id="_ad_state"><em><%:Collecting data...%></em></td></tr>
</table>
</fieldset>
<script type="text/javascript">//<![CDATA[
var run_state = document.getElementById('_run_state');
var down_state = document.getElementById('_down_state');
var up_state = document.getElementById('_up_state');
var dns_state = document.getElementById('_dns_state');
var ad_state = document.getElementById('_ad_state');
XHR.poll(5, '<%=luci.dispatcher.build_url("admin", "network", "sfe", "status")%>', null, function(x, status) {
if ( x && x.status == 200 ) {
run_state.innerHTML = status.run_state ? '<em><b><font color=green><%:RUNNING%></font></b></em>' : '<em><b><font color=red><%:NOT RUNNING%></font></b></em>';
down_state.innerHTML = status.down_state ? '<em><b><font color=green><%:RUNNING%></font></b></em>' : '<em><b><font color=red><%:NOT RUNNING%></font></b></em>';
up_state.innerHTML = status.up_state ? '<em><b><font color=green><%:RUNNING%></font></b></em>' : '<em><b><font color=red><%:NOT RUNNING%></font></b></em>';
dns_state.innerHTML = status.dns_state ? '<em><b><font color=green><%:RUNNING%></font></b></em>' : '<em><b><font color=red><%:NOT RUNNING%></font></b></em>';
ad_state.innerHTML = status.ad_state ? '<em><b><font color=green><%:RUNNING%></font></b></em>' : '<em><b><font color=red><%:NOT RUNNING%></font></b></em>';
}
});
//]]></script>

View File

@ -0,0 +1,81 @@
msgid "SFE Acceleration"
msgstr "SFE 转发加速"
msgid "Turbo ACC Center"
msgstr "Turbo ACC 网络加速"
msgid "Turbo ACC Acceleration Settings"
msgstr "Turbo ACC 网络加速设置"
msgid "Shortcut Forwarding Engine Acceleration Settings"
msgstr "SFE 转发加速引擎设置"
msgid "Opensource Qualcomm Shortcut FE driver (Fast Path)"
msgstr "来自高通开源的 Shortcut FE 转发加速引擎 (Fast Path)"
msgid "Enable"
msgstr "启用"
msgid "Enable SFE Fast Path"
msgstr "启用 SFE Fast Path 加速"
msgid "Enable Fast Path offloading for connections. (decrease cpu load / increase routing throughput)"
msgstr "开启 Fast Path 转发加速. (降低CPU占用 / 增强路由转发性能和多WAN或者QOS功能可能会冲突)"
msgid "Bridge Acceleration"
msgstr "桥接加速"
msgid "Enable Bridge Acceleration (may be functional conflict with bridge-mode VPN Server)"
msgstr "启用桥接加速 (可能会和路由器上桥接模式的VPN服务器冲突)"
msgid "IPv6 Acceleration"
msgstr "IPv6 加速"
msgid "Enable IPv6 Acceleration"
msgstr "开启IPv6加速"
msgid "Enable BBR"
msgstr "启用 BBR"
msgid "Bottleneck Bandwidth and Round-trip propagation time (BBR)"
msgstr "BBR拥塞控制算法可以加强TCP应用表现"
msgid "DNS Acceleration"
msgstr "DNS 加速"
msgid "Enable DNS Cache Acceleration and anti ISP DNS pollution"
msgstr "启用DNS多线程查询、缓存并防止ISP的DNS广告和域名劫持"
msgid "Resolve Dns Mode"
msgstr "DNS解析方式"
msgid "Enable dnsmasq killqqad"
msgstr "启用dnsmasq去广告"
msgid "dnsmasq killqqad"
msgstr "dnsmasq去广告"
msgid "Use Pdnsd query and cache"
msgstr "使用pdnsd解析"
msgid "Use dnsforwarder query and cache"
msgstr "使用dnsforwarder解析"
msgid "Use AdGuardHome query and cache"
msgstr "使用AdGuardHome解析去广告"
msgid "Upsteam DNS Server"
msgstr "上游 DNS 服务器(国内)"
msgid "Upsteam IPV6 DNS Server"
msgstr "上游 IPV6 DNS 服务器"
msgid "Muitiple DNS server can saperate with ','"
msgstr "支持多个上游DNS服务器用','分隔(注意用英文逗号).请填写您最快的DNS服务器"
msgid "Muitiple IPV6 DNS server can saperate with ','"
msgstr "支持dnsforwarder解析多个上游IPV6 DNS服务器用','分隔(注意用英文逗号).请填写您最快的DNS服务器"
msgid "AdGuardHome's login username/passwd: AdGuardHome, web console addr: IP:3001"
msgstr "AdGuardHome 网页控制台地址IP:3001 登录账号/密码AdGuardHome"

View File

@ -0,0 +1,11 @@
config sfe 'config'
option enabled '1'
option ipv6 '0'
option wifi '0'
option bbr '0'
option dns '0'
option dnscache_enable '1'
option dns_server '114.114.114.114,114.114.115.115,223.5.5.5,223.6.6.6,180.76.76.76,119.29.29.29,119.28.28.28,1.2.4.8,210.2.4.8'
option ipv6dns_server '240c::6666,240c::6644,2001:da8::666,2001:da8:202:10::36,2001:da8:8000:1:202:120:2:100'

View File

@ -0,0 +1,294 @@
#!/bin/sh /etc/rc.common
# Copyright (C) 2007-2012 OpenWrt.org
START=90
USE_PROCD=1
DNSMASQ_RESTART=N
DNS_SERVER="114.114.114.114,114.114.115.115,223.5.5.5,223.6.6.6,180.76.76.76,119.29.29.29,119.28.28.28,1.2.4.8,210.2.4.8"
IPV6DNS_SERVER="240c::6666,240c::6644,2001:da8::666,2001:da8:202:10::36,2001:da8:8000:1:202:120:2:100"
lan_addr=$(uci get network.lan.ipaddr)
start_pdnsd() {
DNS_SERVER=$(uci get sfe.config.dns_server 2>/dev/null)
cp -a /usr/sbin/pdnsd /usr/sbin/dnscache
sleep 1
[ -d /var/etc ] || mkdir -p /var/etc
if [ ! -f /var/dnscache/pdnsd.cache ]; then
mkdir -p /var/dnscache
echo -ne "pd13\000\000\000\000" > /var/dnscache/pdnsd.cache
chown -R nobody.nogroup /var/dnscache
fi
cat > /var/etc/dnscache.conf <<EOF
global {
perm_cache=1024; # dns缓存大小单位KB建议不要写的太大
cache_dir="/var/dnscache"; # 缓存文件的位置
pid_file = /var/run/dnscache.pid;
server_ip = 0.0.0.0; # pdnsd监听的网卡0.0.0.0是全部网卡
server_port=5333; # pdnsd监听的端口不要和别的服务冲突即可
status_ctl = on;
paranoid=on; # 二次请求模式如果请求主DNS服务器返回的是垃圾地址就向备用服务器请求
query_method=udp_only;
neg_domain_pol = off;
par_queries = 400; # 最多同时请求数
min_ttl = 1h; # DNS结果最短缓存时间
max_ttl = 1w; # DNS结果最长缓存时间
timeout = 10; # DNS请求超时时间单位秒
}
server {
label = "routine";
ip = $DNS_SERVER; # 这里为主要上级 dns 的 ip 地址建议填写一个当地最快的DNS地址
timeout = 5; # DNS请求超时时间
reject = 74.125.127.102, # 以下是脏IP也就是DNS污染一般会返回的结果如果收到如下DNS结果会触发二次请求TCP协议一般不会碰到脏IP
74.125.155.102,
74.125.39.102,
74.125.39.113,
209.85.229.138,
128.121.126.139,
159.106.121.75,
169.132.13.103,
192.67.198.6,
202.106.1.2,
202.181.7.85,
203.161.230.171,
203.98.7.65,
207.12.88.98,
208.56.31.43,
209.145.54.50,
209.220.30.174,
209.36.73.33,
211.94.66.147,
213.169.251.35,
216.221.188.182,
216.234.179.13,
243.185.187.39,
37.61.54.158,
4.36.66.178,
46.82.174.68,
59.24.3.173,
64.33.88.161,
64.33.99.47,
64.66.163.251,
65.104.202.252,
65.160.219.113,
66.45.252.237,
69.55.52.253,
72.14.205.104,
72.14.205.99,
78.16.49.15,
8.7.198.45,
93.46.8.89,
37.61.54.158,
243.185.187.39,
190.93.247.4,
190.93.246.4,
190.93.245.4,
190.93.244.4,
65.49.2.178,
189.163.17.5,
23.89.5.60,
49.2.123.56,
54.76.135.1,
77.4.7.92,
118.5.49.6,
159.24.3.173,
188.5.4.96,
197.4.4.12,
220.250.64.24,
243.185.187.30,
249.129.46.48,
253.157.14.165;
reject_policy = fail;
}
server {
label = "special"; # 这个随便写
ip = 208.67.222.222,208.67.220.220; # 这里为备用DNS服务器的 ip 地址
port = 5353; # 推荐使用53以外的端口DNS服务器必须支持
proxy_only = on;
timeout = 5;
}
source {
owner=localhost;
// serve_aliases=on;
file="/etc/hosts";
}
rr {
name=localhost;
reverse=on;
a=127.0.0.1;
owner=localhost;
soa=localhost,root.localhost,42,86400,900,86400,86400;
}
EOF
[ -d /var/sbin ] || mkdir -p /var/sbin
[ -f /var/sbin/dnscache ] || cp -a /usr/sbin/pdnsd /var/sbin/dnscache
/usr/sbin/dnscache -c /var/etc/dnscache.conf &
echo "Start DNS Cache"
}
start_dnsforwarder() {
DNS_SERVER=$(uci get sfe.config.dns_server 2>/dev/null)
IPV6DNS_SERVER=$(uci get sfe.config.ipv6dns_server 2>/dev/null)
dnscache_enable=$(uci get sfe.config.dnscache_enable 2>/dev/null)
if [ $dnscache_enable = "2" ]; then
localserver=0.0.0.0:5333
elif [ $dnscache_enable = "3" ]; then
localserver=0.0.0.0:5383
fi
cp -a /usr/bin/dnsforwarder /usr/sbin/dnscache
sleep 1
DNSCACHE_CONF=/var/run/dnscache/dnscache.conf
PID_PATH=/var/run/dnscache
PID_FILE=dns.pid
mkdir -p $PID_PATH
pid=`ps | awk '$5 ~ /\[dnscache\]/ {print $1}'`
cat > /var/run/dnscache/dnscache.conf <<EOF
LogOn false
LogFileThresholdLength 102400
LogFileFolder /var/run/dnscache
UDPLocal $localserver
UDPGroup $DNS_SERVER,$IPV6DNS_SERVER * on
GroupFile
BlockIP 243.185.187.39,46.82.174.68,37.61.54.158,93.46.8.89,59.24.3.173,203.98.7.65,8.7.198.45,78.16.49.15,159.106.121.75,69.63.187.12,31.13.76.8,31.13.64.49
IPSubstituting
BlockNegativeResponse false
Hosts
HostsUpdateInterval 18000
HostsDownloadPath
HostsScript
HostsRetryInterval 30
AppendHosts
BlockIpv6WhenIpv4Exists false
UseCache true
CacheSize 1048576
MemoryCache true
CacheFile
IgnoreTTL false
OverrideTTL -1
MultipleTTL 1
ReloadCache false
OverwriteCache false
DisabledType
DisabledDomain
DisabledList
DomainStatistic false
DomainStatisticTempletFile
StatisticUpdateInterval 29
EOF
dnscache -f $DNSCACHE_CONF &
echo "Start DNS Cache"
}
stop_dnscache() {
kill $(pidof AdGuardHome) >/dev/null 2>&1 || kill -9 $(ps | grep AdGuardHome | grep -v "grep" | awk '{print $1}') >/dev/null 2>&1
kill $(pidof dnscache) >/dev/null 2>&1 || kill -9 $(ps | grep dnscache | grep -v "grep" | awk '{print $1}') >/dev/null 2>&1
rm -rf /var/run/dnscache
rm -rf /var/dnscache
echo "Stop DNS Cache"
}
change_dns() {
uci delete dhcp.@dnsmasq[0].server >/dev/null 2>&1
uci add_list dhcp.@dnsmasq[0].server=127.0.0.1#5333
uci set dhcp.@dnsmasq[0].noresolv=1
uci commit dhcp
}
revert_dns() {
uci del_list dhcp.@dnsmasq[0].server=127.0.0.1#5333 >/dev/null 2>&1
uci set dhcp.@dnsmasq[0].resolvfile=/tmp/resolv.conf.auto
uci set dhcp.@dnsmasq[0].noresolv=0
uci commit dhcp
}
start_service() {
enable=$(uci get sfe.config.enabled 2>/dev/null)
wifi=$(uci get sfe.config.wifi)
ipv6=$(uci get sfe.config.ipv6)
dns=$(uci get sfe.config.dns 2>/dev/null)
dnscache_enable=$(uci get sfe.config.dnscache_enable 2>/dev/null)
bbr=$(uci get sfe.config.bbr 2>/dev/null)
if [ $enable -eq 1 ]; then
! (lsmod | grep fast_classifier >/dev/null) && (modprobe fast_classifier)
if [ $wifi -eq 1 ] ; then
echo 1 > /sys/fast_classifier/skip_to_bridge_ingress
else
echo 0 > /sys/fast_classifier/skip_to_bridge_ingress
fi
if [ $ipv6 -eq 1 ]; then
sfe_ipv6=$(cat /sys/sfe_ipv6/debug_dev)
[ ! -f /dev/sfe_ipv6 ] && mknod /dev/sfe_ipv6 c $sfe_ipv6 0
else
rm -f /dev/sfe_ipv6
fi
else
rmmod fast_classifier >/dev/null 2>&1
fi
if [ $dns -eq 1 ]; then
kill -9 $(ps | grep dnscache-while.sh | grep -v "grep" | awk '{print $1}') >/dev/null 2>&1
stop_dnscache
sleep 1
rm -f /var/log/dnscache.file
rm -f /etc/AdGuardHome/data/querylog.json*
if [ $dnscache_enable = "1" ]; then
start_pdnsd
elif [ $dnscache_enable = "2" ]; then
start_dnsforwarder
elif [ $dnscache_enable = "3" ]; then
AdGuardHome -c /etc/AdGuardHome/AdGuardHome.yaml -w /etc/AdGuardHome -h ${lan_addr} -p 3001 --no-check-update &
fi
change_dns
nohup /usr/share/dnscache/dnscache-while.sh > /var/log/dnscache.file 2>&1 &
else
stop_dnscache
revert_dns
kill -9 $(ps | grep dnscache-while.sh | grep -v "grep" | awk '{print $1}') >/dev/null 2>&1
fi
if [ $bbr -eq 1 ]; then
sysctl -w net.ipv4.tcp_congestion_control=bbr
else
sysctl -w net.ipv4.tcp_congestion_control=cubic
fi
if [ "$DNSMASQ_RESTART" = N ]; then
/etc/init.d/dnsmasq restart
fi
}
stop_service(){
enable=$(uci get sfe.config.enabled 2>/dev/null)
[ $enable -ne 1 ] && rmmod fast_classifier >/dev/null 2>&1
stop_dnscache
revert_dns
kill -9 $(ps | grep dnscache-while.sh | grep -v "grep" | awk '{print $1}') >/dev/null 2>&1
if [ "$DNSMASQ_RESTART" = N ]; then
/etc/init.d/dnsmasq restart
fi
}
restart(){
DNSMASQ_RESTART=Y
stop
start
/etc/init.d/dnsmasq restart && echo "DNSMASQ restart"
}

View File

@ -0,0 +1,14 @@
#!/bin/sh
uci -q batch <<-EOF >/dev/null
delete ucitrack.@sfe[-1]
add ucitrack sfe
set ucitrack.@sfe[-1].init=sfe
commit ucitrack
EOF
[ ! -f /usr/sbin/dnscache ] && ln /usr/sbin/pdnsd /usr/sbin/dnscache
/etc/init.d/sfe enable
rm -f /tmp/luci-indexcache
exit 0

View File

@ -0,0 +1,50 @@
#!/bin/sh
sleeptime=30
logfile="/var/log/dnscache.file"
adg_logfile="/etc/AdGuardHome/data/querylog.json"
dns_enable=$(uci get sfe.config.dns 2>/dev/null)
dnscache_enable=$(uci get sfe.config.dnscache_enable 2>/dev/null)
lan_addr=$(uci get network.lan.ipaddr)
clean_log(){
logrow=$(grep -c "" ${logfile})
if [ $logrow -ge 500 ];then
cat /dev/null > ${logfile}
echo "$curtime Log条数超限清空处理" >> ${logfile}
fi
if [ $dnscache_enable = "3" ];then
adg_logrow=$(grep -c "" ${adg_logfile})
if [ $adg_logrow -ge 500 ];then
cat /dev/null > ${adg_logfile}
echo "$curtime Log条数超限清空处理" >> ${adg_logfile}
fi
fi
}
while [ $dns_enable -eq 1 ];
do
curtime=`date "+%H:%M:%S"`
echo "$curtime online! "
if [ $dns_enable -eq 1 ]; then
if [ $dnscache_enable = "3" ]; then
if ! pidof AdGuardHome>/dev/null; then
AdGuardHome -c /etc/AdGuardHome/AdGuardHome.yaml -w /etc/AdGuardHome -h ${lan_addr} -p 3001 --no-check-update &
echo "$curtime 重启服务!" >> ${logfile}
fi
else
if ! pidof dnscache>/dev/null; then
if [ $dnscache_enable = "1" ]; then
/usr/sbin/dnscache -c /var/etc/dnscache.conf &
elif [ $dnscache_enable = "2" ]; then
dnscache -f /var/run/dnscache/dnscache.conf &
fi
echo "$curtime 重启服务!" >> ${logfile}
fi
fi
fi
sleep ${sleeptime}
continue
done

View File

@ -0,0 +1,81 @@
#
# Copyright (c) 2014 The Linux Foundation. All rights reserved.
# Permission to use, copy, modify, and/or distribute this software for
# any purpose with or without fee is hereby granted, provided that the
# above copyright notice and this permission notice appear in all copies.
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=shortcut-fe
PKG_RELEASE:=2
include $(INCLUDE_DIR)/package.mk
define KernelPackage/shortcut-fe
SECTION:=kernel
CATEGORY:=Kernel modules
SUBMENU:=Network Support
DEPENDS:=
TITLE:=Kernel driver for SFE
FILES:=$(PKG_BUILD_DIR)/shortcut-fe.ko $(PKG_BUILD_DIR)/shortcut-fe-ipv6.ko
KCONFIG:=CONFIG_NF_CONNTRACK_EVENTS=y \
CONFIG_NF_CONNTRACK_TIMEOUT=y \
CONFIG_SHORTCUT_FE=y \
CONFIG_XFRM=y
AUTOLOAD:=$(call AutoLoad,09,shortcut-fe shortcut-fe-ipv6)
endef
define KernelPackage/shortcut-fe/Description
Shortcut is an in-Linux-kernel IP packet forwarding engine.
endef
define KernelPackage/shortcut-fe/install
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./files/etc/init.d/shortcut-fe $(1)/etc/init.d
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) ./files/usr/bin/sfe_dump $(1)/usr/bin
endef
define KernelPackage/shortcut-fe-cm
SECTION:=kernel
CATEGORY:=Kernel modules
SUBMENU:=Network Support
DEPENDS:=+kmod-ipt-conntrack +kmod-shortcut-fe
TITLE:=Kernel driver for SFE
FILES:=$(PKG_BUILD_DIR)/shortcut-fe-cm.ko
KCONFIG:=CONFIG_NF_CONNTRACK_CHAIN_EVENTS=y
endef
define KernelPackage/shortcut-fe-cm/Description
Simple connection manager for the Shortcut forwarding engine.
endef
EXTRA_CFLAGS+=-DSFE_SUPPORT_IPV6
define Build/Compile
+$(MAKE) $(PKG_JOBS) -C "$(LINUX_DIR)" \
$(KERNEL_MAKE_FLAGS) \
$(PKG_MAKE_FLAGS) \
M="$(PKG_BUILD_DIR)" \
EXTRA_CFLAGS="$(EXTRA_CFLAGS)" \
SFE_SUPPORT_IPV6=1 \
modules
endef
ifneq ($(CONFIG_PACKAGE_kmod-shortcut-fe)$(CONFIG_PACKAGE_kmod-shortcut-fe-cm),)
define Build/InstallDev
$(INSTALL_DIR) $(1)/usr/include/shortcut-fe
$(CP) -rf $(PKG_BUILD_DIR)/sfe.h $(1)/usr/include/shortcut-fe
endef
endif
$(eval $(call KernelPackage,shortcut-fe))
$(eval $(call KernelPackage,shortcut-fe-cm))

View File

@ -0,0 +1,49 @@
#!/bin/sh /etc/rc.common
#
# Copyright (c) 2014-2015 The Linux Foundation. All rights reserved.
# Permission to use, copy, modify, and/or distribute this software for
# any purpose with or without fee is hereby granted, provided that the
# above copyright notice and this permission notice appear in all copies.
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
#SFE connection manager has a lower priority, it should be started after other connection manager
#to detect the existence of connection manager with higher priority
START=72
have_cm() {
[ -d "/sys/kernel/debug/ecm" ] && echo 1 && return
echo 0
}
#load shortcut-fe connection manager
load_sfe_cm() {
local kernel_version=$(uname -r)
#shortcut-fe-drv.ko is not needed because other connection manager is not enabled
[ -d "/sys/module/shortcut_fe_drv" ] && rmmod shortcut_fe_drv
[ -e "/lib/modules/$kernel_version/fast-classifier.ko" ] && {
[ -d /sys/module/fast_classifier ] || insmod /lib/modules/$kernel_version/fast-classifier.ko && return
}
[ -e "/lib/modules/$kernel_version/shortcut-fe-cm.ko" ] && {
[ -d /sys/module/shortcut_fe_cm ] || insmod /lib/modules/$kernel_version/shortcut-fe-cm.ko && return
}
}
start() {
[ "$(have_cm)" = "1" ] || load_sfe_cm
}
stop() {
[ -d /sys/module/shortcut_fe_cm ] && rmmod shortcut_fe_cm
[ -d /sys/module/fast_classifier ] && rmmod fast_classifier
}

View File

@ -0,0 +1,35 @@
#!/bin/sh
#
# Copyright (c) 2015 The Linux Foundation. All rights reserved.
# Permission to use, copy, modify, and/or distribute this software for
# any purpose with or without fee is hereby granted, provided that the
# above copyright notice and this permission notice appear in all copies.
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
#@sfe_dump
#@example : sfe_dump (ipv4|ipv6)
sfe_dump(){
[ -e "/dev/sfe_ipv4" ] || {
dev_num=$(cat /sys/sfe_ipv4/debug_dev)
mknod /dev/sfe_ipv4 c $dev_num 0
}
[ -e "/dev/sfe_ipv6" ] || {
dev_num=$(cat /sys/sfe_ipv6/debug_dev)
mknod /dev/sfe_ipv6 c $dev_num 0
}
cat /dev/sfe_$1
}
if [ -z "$1" ]; then
sfe_dump ipv4
sfe_dump ipv6
else
sfe_dump $1
fi

View File

@ -0,0 +1,14 @@
#
# Shortcut forwarding engine
#
config SHORTCUT_FE
tristate "Shortcut Forwarding Engine"
depends on NF_CONNTRACK
---help---
Shortcut is a fast in-kernel packet forwarding engine.
To compile this code as a module, choose M here: the module will be
called shortcut-fe.
If unsure, say N.

View File

@ -0,0 +1,23 @@
#
# Makefile for Shortcut FE.
#
obj-m += shortcut-fe.o
ifdef SFE_SUPPORT_IPV6
obj-m += shortcut-fe-ipv6.o
endif
obj-m += shortcut-fe-cm.o
shortcut-fe-objs := \
sfe_ipv4.o
ifdef SFE_SUPPORT_IPV6
shortcut-fe-ipv6-objs := \
sfe_ipv6.o
endif
shortcut-fe-cm-objs := \
sfe_cm.o

View File

@ -0,0 +1,114 @@
/*
* sfe.h
* Shortcut forwarding engine.
*
* Copyright (c) 2013-2017 The Linux Foundation. All rights reserved.
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all copies.
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* The following are debug macros used throughout the SFE.
*
* The DEBUG_LEVEL enables the followings based on its value,
* when dynamic debug option is disabled.
*
* 0 = OFF
* 1 = ASSERTS / ERRORS
* 2 = 1 + WARN
* 3 = 2 + INFO
* 4 = 3 + TRACE
*/
#define DEBUG_LEVEL 2
#if (DEBUG_LEVEL < 1)
#define DEBUG_ASSERT(s, ...)
#define DEBUG_ERROR(s, ...)
#else
#define DEBUG_ASSERT(c, s, ...) if (!(c)) { pr_emerg("ASSERT: %s:%d:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__); BUG(); }
#define DEBUG_ERROR(s, ...) pr_err("%s:%d:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#endif
#if defined(CONFIG_DYNAMIC_DEBUG)
/*
* Compile messages for dynamic enable/disable
*/
#define DEBUG_WARN(s, ...) pr_debug("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#define DEBUG_INFO(s, ...) pr_debug("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#define DEBUG_TRACE(s, ...) pr_debug("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#else
/*
* Statically compile messages at different levels
*/
#if (DEBUG_LEVEL < 2)
#define DEBUG_WARN(s, ...)
#else
#define DEBUG_WARN(s, ...) pr_warn("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#endif
#if (DEBUG_LEVEL < 3)
#define DEBUG_INFO(s, ...)
#else
#define DEBUG_INFO(s, ...) pr_notice("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#endif
#if (DEBUG_LEVEL < 4)
#define DEBUG_TRACE(s, ...)
#else
#define DEBUG_TRACE(s, ...) pr_info("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#endif
#endif
#ifdef CONFIG_NF_FLOW_COOKIE
typedef int (*flow_cookie_set_func_t)(u32 protocol, __be32 src_ip, __be16 src_port,
__be32 dst_ip, __be16 dst_port, u16 flow_cookie);
/*
* sfe_register_flow_cookie_cb
* register a function in SFE to let SFE use this function to configure flow cookie for a flow
*
* Hardware driver which support flow cookie should register a callback function in SFE. Then SFE
* can use this function to configure flow cookie for a flow.
* return: 0, success; !=0, fail
*/
int sfe_register_flow_cookie_cb(flow_cookie_set_func_t cb);
/*
* sfe_unregister_flow_cookie_cb
* unregister function which is used to configure flow cookie for a flow
*
* return: 0, success; !=0, fail
*/
int sfe_unregister_flow_cookie_cb(flow_cookie_set_func_t cb);
typedef int (*sfe_ipv6_flow_cookie_set_func_t)(u32 protocol, __be32 src_ip[4], __be16 src_port,
__be32 dst_ip[4], __be16 dst_port, u16 flow_cookie);
/*
* sfe_ipv6_register_flow_cookie_cb
* register a function in SFE to let SFE use this function to configure flow cookie for a flow
*
* Hardware driver which support flow cookie should register a callback function in SFE. Then SFE
* can use this function to configure flow cookie for a flow.
* return: 0, success; !=0, fail
*/
int sfe_ipv6_register_flow_cookie_cb(sfe_ipv6_flow_cookie_set_func_t cb);
/*
* sfe_ipv6_unregister_flow_cookie_cb
* unregister function which is used to configure flow cookie for a flow
*
* return: 0, success; !=0, fail
*/
int sfe_ipv6_unregister_flow_cookie_cb(sfe_ipv6_flow_cookie_set_func_t cb);
#endif /*CONFIG_NF_FLOW_COOKIE*/

View File

@ -0,0 +1,195 @@
/*
* sfe_backport.h
* Shortcut forwarding engine compatible header file.
*
* Copyright (c) 2014-2016 The Linux Foundation. All rights reserved.
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all copies.
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/version.h>
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
#include <net/netfilter/nf_conntrack_timeout.h>
#else
enum udp_conntrack {
UDP_CT_UNREPLIED,
UDP_CT_REPLIED,
UDP_CT_MAX
};
static inline unsigned int *
nf_ct_timeout_lookup(struct net *net, struct nf_conn *ct,
struct nf_conntrack_l4proto *l4proto)
{
#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
struct nf_conn_timeout *timeout_ext;
unsigned int *timeouts;
timeout_ext = nf_ct_timeout_find(ct);
if (timeout_ext)
timeouts = NF_CT_TIMEOUT_EXT_DATA(timeout_ext);
else
timeouts = l4proto->get_timeouts(net);
return timeouts;
#else
return l4proto->get_timeouts(net);
#endif /*CONFIG_NF_CONNTRACK_TIMEOUT*/
}
#endif /*KERNEL_VERSION(3, 7, 0)*/
#endif /*KERNEL_VERSION(3, 4, 0)*/
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
#define sfe_define_post_routing_hook(FN_NAME, HOOKNUM, OPS, SKB, UNUSED, OUT, OKFN) \
static unsigned int FN_NAME(void *priv, \
struct sk_buff *SKB, \
const struct nf_hook_state *state)
#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0))
#define sfe_define_post_routing_hook(FN_NAME, HOOKNUM, OPS, SKB, UNUSED, OUT, OKFN) \
static unsigned int FN_NAME(const struct nf_hook_ops *OPS, \
struct sk_buff *SKB, \
const struct net_device *UNUSED, \
const struct net_device *OUT, \
int (*OKFN)(struct sk_buff *))
#else
#define sfe_define_post_routing_hook(FN_NAME, HOOKNUM, OPS, SKB, UNUSED, OUT, OKFN) \
static unsigned int FN_NAME(unsigned int HOOKNUM, \
struct sk_buff *SKB, \
const struct net_device *UNUSED, \
const struct net_device *OUT, \
int (*OKFN)(struct sk_buff *))
#endif
#define sfe_cm_ipv4_post_routing_hook(HOOKNUM, OPS, SKB, UNUSED, OUT, OKFN) \
sfe_define_post_routing_hook(__sfe_cm_ipv4_post_routing_hook, HOOKNUM, OPS, SKB, UNUSED, OUT, OKFN)
#define sfe_cm_ipv6_post_routing_hook(HOOKNUM, OPS, SKB, UNUSED, OUT, OKFN) \
sfe_define_post_routing_hook(__sfe_cm_ipv6_post_routing_hook, HOOKNUM, OPS, SKB, UNUSED, OUT, OKFN)
#define fast_classifier_ipv4_post_routing_hook(HOOKNUM, OPS, SKB, UNUSED, OUT, OKFN) \
sfe_define_post_routing_hook(__fast_classifier_ipv4_post_routing_hook, HOOKNUM, OPS, SKB, UNUSED, OUT, OKFN)
#define fast_classifier_ipv6_post_routing_hook(HOOKNUM, OPS, SKB, UNUSED, OUT, OKFN) \
sfe_define_post_routing_hook(__fast_classifier_ipv6_post_routing_hook, HOOKNUM, OPS, SKB, UNUSED, OUT, OKFN)
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
#define SFE_IPV4_NF_POST_ROUTING_HOOK(fn) \
{ \
.hook = fn, \
.pf = NFPROTO_IPV4, \
.hooknum = NF_INET_POST_ROUTING, \
.priority = NF_IP_PRI_NAT_SRC + 1, \
}
#else
#define SFE_IPV4_NF_POST_ROUTING_HOOK(fn) \
{ \
.hook = fn, \
.owner = THIS_MODULE, \
.pf = NFPROTO_IPV4, \
.hooknum = NF_INET_POST_ROUTING, \
.priority = NF_IP_PRI_NAT_SRC + 1, \
}
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
#define SFE_IPV6_NF_POST_ROUTING_HOOK(fn) \
{ \
.hook = fn, \
.pf = NFPROTO_IPV6, \
.hooknum = NF_INET_POST_ROUTING, \
.priority = NF_IP_PRI_NAT_SRC + 1, \
}
#else
#define SFE_IPV6_NF_POST_ROUTING_HOOK(fn) \
{ \
.hook = fn, \
.owner = THIS_MODULE, \
.pf = NFPROTO_IPV6, \
.hooknum = NF_INET_POST_ROUTING, \
.priority = NF_IP6_PRI_NAT_SRC + 1, \
}
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0))
#define SFE_NF_CT_DEFAULT_ZONE (&nf_ct_zone_dflt)
#else
#define SFE_NF_CT_DEFAULT_ZONE NF_CT_DEFAULT_ZONE
#endif
/*
* sfe_dev_get_master
* get master of bridge port, and hold it
*/
static inline struct net_device *sfe_dev_get_master(struct net_device *dev)
{
struct net_device *master;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
rcu_read_lock();
master = netdev_master_upper_dev_get_rcu(dev);
if (master)
dev_hold(master);
rcu_read_unlock();
#else
master = dev->master;
if (master)
dev_hold(master);
#endif
return master;
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
#define SFE_DEV_EVENT_PTR(PTR) netdev_notifier_info_to_dev(PTR)
#else
#define SFE_DEV_EVENT_PTR(PTR) (struct net_device *)(PTR)
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0))
#define SFE_NF_CONN_ACCT(NM) struct nf_conn_acct *NM
#else
#define SFE_NF_CONN_ACCT(NM) struct nf_conn_counter *NM
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0))
#define SFE_ACCT_COUNTER(NM) ((NM)->counter)
#else
#define SFE_ACCT_COUNTER(NM) (NM)
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
#define sfe_hash_for_each_possible(name, obj, node, member, key) \
hash_for_each_possible(name, obj, member, key)
#else
#define sfe_hash_for_each_possible(name, obj, node, member, key) \
hash_for_each_possible(name, obj, node, member, key)
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
#define sfe_hash_for_each(name, bkt, node, obj, member) \
hash_for_each(name, bkt, obj, member)
#else
#define sfe_hash_for_each(name, bkt, node, obj, member) \
hash_for_each(name, bkt, node, obj, member)
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
#define sfe_dst_get_neighbour(dst, daddr) dst_neigh_lookup(dst, daddr)
#else
static inline struct neighbour *
sfe_dst_get_neighbour(struct dst_entry *dst, void *daddr)
{
struct neighbour *neigh = dst_get_neighbour_noref(dst);
if (neigh)
neigh_hold(neigh);
return neigh;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,259 @@
/*
* sfe_cm.h
* Shortcut forwarding engine.
*
* Copyright (c) 2013-2016 The Linux Foundation. All rights reserved.
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all copies.
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* connection flags.
*/
#define SFE_CREATE_FLAG_NO_SEQ_CHECK BIT(0)
/* Indicates that we should not check sequence numbers */
#define SFE_CREATE_FLAG_REMARK_PRIORITY BIT(1)
/* Indicates that we should remark priority of skb */
#define SFE_CREATE_FLAG_REMARK_DSCP BIT(2)
/* Indicates that we should remark DSCP of packet */
/*
* IPv6 address structure
*/
struct sfe_ipv6_addr {
__be32 addr[4];
};
typedef union {
__be32 ip;
struct sfe_ipv6_addr ip6[1];
} sfe_ip_addr_t;
/*
* connection creation structure.
*/
struct sfe_connection_create {
int protocol;
struct net_device *src_dev;
struct net_device *dest_dev;
u32 flags;
u32 src_mtu;
u32 dest_mtu;
sfe_ip_addr_t src_ip;
sfe_ip_addr_t src_ip_xlate;
sfe_ip_addr_t dest_ip;
sfe_ip_addr_t dest_ip_xlate;
__be16 src_port;
__be16 src_port_xlate;
__be16 dest_port;
__be16 dest_port_xlate;
u8 src_mac[ETH_ALEN];
u8 src_mac_xlate[ETH_ALEN];
u8 dest_mac[ETH_ALEN];
u8 dest_mac_xlate[ETH_ALEN];
u8 src_td_window_scale;
u32 src_td_max_window;
u32 src_td_end;
u32 src_td_max_end;
u8 dest_td_window_scale;
u32 dest_td_max_window;
u32 dest_td_end;
u32 dest_td_max_end;
u32 mark;
#ifdef CONFIG_XFRM
u32 original_accel;
u32 reply_accel;
#endif
u32 src_priority;
u32 dest_priority;
u32 src_dscp;
u32 dest_dscp;
};
/*
* connection destruction structure.
*/
struct sfe_connection_destroy {
int protocol;
sfe_ip_addr_t src_ip;
sfe_ip_addr_t dest_ip;
__be16 src_port;
__be16 dest_port;
};
typedef enum sfe_sync_reason {
SFE_SYNC_REASON_STATS, /* Sync is to synchronize stats */
SFE_SYNC_REASON_FLUSH, /* Sync is to flush a entry */
SFE_SYNC_REASON_DESTROY /* Sync is to destroy a entry(requested by connection manager) */
} sfe_sync_reason_t;
/*
* Structure used to sync connection stats/state back within the system.
*
* NOTE: The addresses here are NON-NAT addresses, i.e. the true endpoint addressing.
* 'src' is the creator of the connection.
*/
struct sfe_connection_sync {
struct net_device *src_dev;
struct net_device *dest_dev;
int is_v6; /* Is it for ipv6? */
int protocol; /* IP protocol number (IPPROTO_...) */
sfe_ip_addr_t src_ip; /* Non-NAT source address, i.e. the creator of the connection */
sfe_ip_addr_t src_ip_xlate; /* NATed source address */
__be16 src_port; /* Non-NAT source port */
__be16 src_port_xlate; /* NATed source port */
sfe_ip_addr_t dest_ip; /* Non-NAT destination address, i.e. to whom the connection was created */
sfe_ip_addr_t dest_ip_xlate; /* NATed destination address */
__be16 dest_port; /* Non-NAT destination port */
__be16 dest_port_xlate; /* NATed destination port */
u32 src_td_max_window;
u32 src_td_end;
u32 src_td_max_end;
u64 src_packet_count;
u64 src_byte_count;
u32 src_new_packet_count;
u32 src_new_byte_count;
u32 dest_td_max_window;
u32 dest_td_end;
u32 dest_td_max_end;
u64 dest_packet_count;
u64 dest_byte_count;
u32 dest_new_packet_count;
u32 dest_new_byte_count;
u32 reason; /* reason for stats sync message, i.e. destroy, flush, period sync */
u64 delta_jiffies; /* Time to be added to the current timeout to keep the connection alive */
};
/*
* connection mark structure
*/
struct sfe_connection_mark {
int protocol;
sfe_ip_addr_t src_ip;
sfe_ip_addr_t dest_ip;
__be16 src_port;
__be16 dest_port;
u32 mark;
};
/*
* Expose the hook for the receive processing.
*/
extern int (*athrs_fast_nat_recv)(struct sk_buff *skb);
/*
* Expose what should be a static flag in the TCP connection tracker.
*/
extern int nf_ct_tcp_no_window_check;
/*
* This callback will be called in a timer
* at 100 times per second to sync stats back to
* Linux connection track.
*
* A RCU lock is taken to prevent this callback
* from unregistering.
*/
typedef void (*sfe_sync_rule_callback_t)(struct sfe_connection_sync *);
/*
* IPv4 APIs used by connection manager
*/
int sfe_ipv4_recv(struct net_device *dev, struct sk_buff *skb);
int sfe_ipv4_create_rule(struct sfe_connection_create *sic);
void sfe_ipv4_destroy_rule(struct sfe_connection_destroy *sid);
void sfe_ipv4_destroy_all_rules_for_dev(struct net_device *dev);
void sfe_ipv4_register_sync_rule_callback(sfe_sync_rule_callback_t callback);
void sfe_ipv4_update_rule(struct sfe_connection_create *sic);
void sfe_ipv4_mark_rule(struct sfe_connection_mark *mark);
#ifdef SFE_SUPPORT_IPV6
/*
* IPv6 APIs used by connection manager
*/
int sfe_ipv6_recv(struct net_device *dev, struct sk_buff *skb);
int sfe_ipv6_create_rule(struct sfe_connection_create *sic);
void sfe_ipv6_destroy_rule(struct sfe_connection_destroy *sid);
void sfe_ipv6_destroy_all_rules_for_dev(struct net_device *dev);
void sfe_ipv6_register_sync_rule_callback(sfe_sync_rule_callback_t callback);
void sfe_ipv6_update_rule(struct sfe_connection_create *sic);
void sfe_ipv6_mark_rule(struct sfe_connection_mark *mark);
#else
static inline int sfe_ipv6_recv(struct net_device *dev, struct sk_buff *skb)
{
return 0;
}
static inline int sfe_ipv6_create_rule(struct sfe_connection_create *sic)
{
return 0;
}
static inline void sfe_ipv6_destroy_rule(struct sfe_connection_destroy *sid)
{
return;
}
static inline void sfe_ipv6_destroy_all_rules_for_dev(struct net_device *dev)
{
return;
}
static inline void sfe_ipv6_register_sync_rule_callback(sfe_sync_rule_callback_t callback)
{
return;
}
static inline void sfe_ipv6_update_rule(struct sfe_connection_create *sic)
{
return;
}
static inline void sfe_ipv6_mark_rule(struct sfe_connection_mark *mark)
{
return;
}
#endif
/*
* sfe_ipv6_addr_equal()
* compare ipv6 address
*
* return: 1, equal; 0, no equal
*/
static inline int sfe_ipv6_addr_equal(struct sfe_ipv6_addr *a,
struct sfe_ipv6_addr *b)
{
return a->addr[0] == b->addr[0] &&
a->addr[1] == b->addr[1] &&
a->addr[2] == b->addr[2] &&
a->addr[3] == b->addr[3];
}
/*
* sfe_ipv4_addr_equal()
* compare ipv4 address
*
* return: 1, equal; 0, no equal
*/
#define sfe_ipv4_addr_equal(a, b) ((u32)(a) == (u32)(b))
/*
* sfe_addr_equal()
* compare ipv4 or ipv6 address
*
* return: 1, equal; 0, no equal
*/
static inline int sfe_addr_equal(sfe_ip_addr_t *a,
sfe_ip_addr_t *b, int is_v4)
{
return is_v4 ? sfe_ipv4_addr_equal(a->ip, b->ip) : sfe_ipv6_addr_equal(a->ip6, b->ip6);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,236 @@
--- a/include/linux/skbuff.h 2019-01-16 20:16:08.325745306 +0800
+++ b/include/linux/skbuff.h 2019-01-16 20:31:47.288028493 +0800
@@ -783,6 +783,9 @@ struct sk_buff {
__u8 tc_from_ingress:1;
#endif
__u8 gro_skip:1;
+#ifdef CONFIG_SHORTCUT_FE
+ __u8 fast_forwarded:1;
+#endif
#ifdef CONFIG_NET_SCHED
__u16 tc_index; /* traffic control index */
--- a/include/linux/if_bridge.h 2019-01-16 20:51:47.871445535 +0800
+++ b/include/linux/if_bridge.h 2019-01-16 20:52:26.220269649 +0800
@@ -54,6 +54,8 @@ struct br_ip_list {
#define BR_DEFAULT_AGEING_TIME (300 * HZ)
extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void __user *));
+extern void br_dev_update_stats(struct net_device *dev,
+ struct rtnl_link_stats64 *nlstats);
typedef int br_should_route_hook_t(struct sk_buff *skb);
extern br_should_route_hook_t __rcu *br_should_route_hook;
--- a/include/linux/timer.h
+++ b/include/linux/timer.h
@@ -20,6 +20,9 @@ struct timer_list {
void (*function)(unsigned long);
unsigned long data;
u32 flags;
+#ifdef CONFIG_SHORTCUT_FE
+ unsigned long cust_data;
+#endif
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
--- a/net/Kconfig 2019-01-16 20:36:30.266465286 +0800
+++ b/net/Kconfig 2019-01-16 20:36:41.980609067 +0800
@@ -463,3 +463,6 @@ config HAVE_CBPF_JIT
# Extended BPF JIT (eBPF)
config HAVE_EBPF_JIT
bool
+
+config SHORTCUT_FE
+ bool "Enables kernel network stack path for Shortcut Forwarding Engine
--- a/net/core/dev.c 2019-01-16 20:38:37.274933833 +0800
+++ b/net/core/dev.c 2019-01-16 20:44:07.773594898 +0800
@@ -3005,8 +3005,17 @@ static int xmit_one(struct sk_buff *skb, struct net_device *dev,
!(skb->imq_flags & IMQ_F_ENQUEUE))
#else
if (!list_empty(&ptype_all) || !list_empty(&dev->ptype_all))
+#endif
+#ifdef CONFIG_SHORTCUT_FE
+ /* If this skb has been fast forwarded then we don't want it to
+ * go to any taps (by definition we're trying to bypass them).
+ */
+ if (!skb->fast_forwarded) {
#endif
dev_queue_xmit_nit(skb, dev);
+#ifdef CONFIG_SHORTCUT_FE
+ }
+#endif
#ifdef CONFIG_ETHERNET_PACKET_MANGLE
if (!dev->eth_mangle_tx ||
@@ -4315,6 +4324,11 @@ void netdev_rx_handler_unregister(struct
}
EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister);
+#ifdef CONFIG_SHORTCUT_FE
+int (*athrs_fast_nat_recv)(struct sk_buff *skb) __rcu __read_mostly;
+EXPORT_SYMBOL_GPL(athrs_fast_nat_recv);
+#endif
+
/*
* Limit the use of PFMEMALLOC reserves to those protocols that implement
* the special handling of PFMEMALLOC skbs.
@@ -4362,6 +4376,9 @@ static int __netif_receive_skb_core(stru
bool deliver_exact = false;
int ret = NET_RX_DROP;
__be16 type;
+#ifdef CONFIG_SHORTCUT_FE
+ int (*fast_recv)(struct sk_buff *skb);
+#endif
net_timestamp_check(!netdev_tstamp_prequeue, skb);
@@ -4388,6 +4405,16 @@ another_round:
goto out;
}
+#ifdef CONFIG_SHORTCUT_FE
+ fast_recv = rcu_dereference(athrs_fast_nat_recv);
+ if (fast_recv) {
+ if (fast_recv(skb)) {
+ ret = NET_RX_SUCCESS;
+ goto out;
+ }
+ }
+#endif
+
if (skb_skip_tc_classify(skb))
goto skip_classify;
--- a/net/netfilter/nf_conntrack_proto_tcp.c 2019-01-16 20:47:40.886993297 +0800
+++ b/net/netfilter/nf_conntrack_proto_tcp.c 2019-01-16 20:48:57.700570104 +0800
@@ -35,11 +35,17 @@
/* Do not check the TCP window for incoming packets */
static int nf_ct_tcp_no_window_check __read_mostly = 1;
+#ifdef CONFIG_SHORTCUT_FE
+EXPORT_SYMBOL_GPL(nf_ct_tcp_no_window_check);
+#endif
/* "Be conservative in what you do,
be liberal in what you accept from others."
If it's non-zero, we mark only out of window RST segments as INVALID. */
static int nf_ct_tcp_be_liberal __read_mostly = 0;
+#ifdef CONFIG_SHORTCUT_FE
+EXPORT_SYMBOL_GPL(nf_ct_tcp_be_liberal);
+#endif
/* If it is set to zero, we disable picking up already established
connections. */
--- a/net/bridge/br_if.c 2019-01-16 20:54:51.919367044 +0800
+++ b/net/bridge/br_if.c 2019-01-16 20:55:53.812401263 +0800
@@ -653,3 +653,26 @@ void br_port_flags_change(struct net_bri
if (mask & BR_AUTO_MASK)
nbp_update_port_count(br);
}
+
+/* Update bridge statistics for bridge packets processed by offload engines */
+void br_dev_update_stats(struct net_device *dev,
+ struct rtnl_link_stats64 *nlstats)
+{
+ struct net_bridge *br;
+ struct pcpu_sw_netstats *stats;
+
+ /* Is this a bridge? */
+ if (!(dev->priv_flags & IFF_EBRIDGE))
+ return;
+
+ br = netdev_priv(dev);
+ stats = this_cpu_ptr(br->stats);
+
+ u64_stats_update_begin(&stats->syncp);
+ stats->rx_packets += nlstats->rx_packets;
+ stats->rx_bytes += nlstats->rx_bytes;
+ stats->tx_packets += nlstats->tx_packets;
+ stats->tx_bytes += nlstats->tx_bytes;
+ u64_stats_update_end(&stats->syncp);
+}
+EXPORT_SYMBOL_GPL(br_dev_update_stats);
--- a/net/netfilter/Kconfig 2019-01-16 21:07:34.543460920 +0800
+++ b/net/netfilter/Kconfig 2019-01-16 21:08:14.739465937 +0800
@@ -146,6 +146,14 @@ config NF_CONNTRACK_TIMEOUT
If unsure, say `N'.
+config NF_CONNTRACK_CHAIN_EVENTS
+ bool "Register multiple callbacks to ct events"
+ depends on NF_CONNTRACK_EVENTS
+ help
+ Support multiple registrations.
+
+ If unsure, say `N'.
+
config NF_CONNTRACK_TIMESTAMP
bool 'Connection tracking timestamping'
depends on NETFILTER_ADVANCED
--- a/net/netfilter/nf_conntrack_ecache.c 2019-01-16 21:12:22.183462975 +0800
+++ b/net/netfilter/nf_conntrack_ecache.c 2019-01-16 21:26:10.379462031 +0800
@@ -122,13 +125,17 @@ int nf_conntrack_eventmask_report(unsign
{
int ret = 0;
struct net *net = nf_ct_net(ct);
+#ifndef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
struct nf_ct_event_notifier *notify;
+#endif
struct nf_conntrack_ecache *e;
rcu_read_lock();
+#ifndef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
notify = rcu_dereference(net->ct.nf_conntrack_event_cb);
if (!notify)
goto out_unlock;
+#endif
e = nf_ct_ecache_find(ct);
if (!e)
@@ -146,7 +153,12 @@ int nf_conntrack_eventmask_report(unsign
if (!((eventmask | missed) & e->ctmask))
goto out_unlock;
+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
+ ret = atomic_notifier_call_chain(&net->ct.nf_conntrack_chain,
+ eventmask | missed, &item);
+#else
ret = notify->fcn(eventmask | missed, &item);
+#endif
if (unlikely(ret < 0 || missed)) {
spin_lock_bh(&ct->lock);
if (ret < 0) {
@@ -179,15 +191,19 @@ void nf_ct_deliver_cached_events(struct
{
struct net *net = nf_ct_net(ct);
unsigned long events, missed;
+#ifndef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
struct nf_ct_event_notifier *notify;
+#endif
struct nf_conntrack_ecache *e;
struct nf_ct_event item;
int ret;
rcu_read_lock();
+#ifndef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
notify = rcu_dereference(net->ct.nf_conntrack_event_cb);
if (notify == NULL)
goto out_unlock;
+#endif
e = nf_ct_ecache_find(ct);
if (e == NULL)
@@ -210,7 +226,13 @@ void nf_ct_deliver_cached_events(struct
item.portid = 0;
item.report = 0;
+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
+ ret = atomic_notifier_call_chain(&net->ct.nf_conntrack_chain,
+ events | missed,
+ &item);
+#else
ret = notify->fcn(events | missed, &item);
+#endif
if (likely(ret == 0 && !missed))
goto out_unlock;

View File

@ -0,0 +1,236 @@
--- a/include/linux/skbuff.h 2019-01-16 20:16:08.325745306 +0800
+++ b/include/linux/skbuff.h 2019-01-16 20:31:47.288028493 +0800
@@ -783,6 +783,9 @@ struct sk_buff {
__u8 tc_from_ingress:1;
#endif
__u8 gro_skip:1;
+#ifdef CONFIG_SHORTCUT_FE
+ __u8 fast_forwarded:1;
+#endif
#ifdef CONFIG_NET_SCHED
__u16 tc_index; /* traffic control index */
--- a/include/linux/if_bridge.h 2019-01-16 20:51:47.871445535 +0800
+++ b/include/linux/if_bridge.h 2019-01-16 20:52:26.220269649 +0800
@@ -54,6 +54,8 @@ struct br_ip_list {
#define BR_DEFAULT_AGEING_TIME (300 * HZ)
extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void __user *));
+extern void br_dev_update_stats(struct net_device *dev,
+ struct rtnl_link_stats64 *nlstats);
typedef int br_should_route_hook_t(struct sk_buff *skb);
extern br_should_route_hook_t __rcu *br_should_route_hook;
--- a/include/linux/timer.h
+++ b/include/linux/timer.h
@@ -20,6 +20,9 @@ struct timer_list {
void (*function)(unsigned long);
unsigned long data;
u32 flags;
+#ifdef CONFIG_SHORTCUT_FE
+ unsigned long cust_data;
+#endif
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
--- a/net/Kconfig 2019-01-16 20:36:30.266465286 +0800
+++ b/net/Kconfig 2019-01-16 20:36:41.980609067 +0800
@@ -463,3 +463,6 @@ config HAVE_CBPF_JIT
# Extended BPF JIT (eBPF)
config HAVE_EBPF_JIT
bool
+
+config SHORTCUT_FE
+ bool "Enables kernel network stack path for Shortcut Forwarding Engine
--- a/net/core/dev.c 2019-01-16 20:38:37.274933833 +0800
+++ b/net/core/dev.c 2019-01-16 20:44:07.773594898 +0800
@@ -3256,8 +3256,17 @@ static int xmit_one(struct sk_buff *skb, struct net_device *dev,
!(skb->imq_flags & IMQ_F_ENQUEUE))
#else
if (!list_empty(&ptype_all) || !list_empty(&dev->ptype_all))
+#endif
+#ifdef CONFIG_SHORTCUT_FE
+ /* If this skb has been fast forwarded then we don't want it to
+ * go to any taps (by definition we're trying to bypass them).
+ */
+ if (!skb->fast_forwarded) {
#endif
dev_queue_xmit_nit(skb, dev);
+#ifdef CONFIG_SHORTCUT_FE
+ }
+#endif
#ifdef CONFIG_ETHERNET_PACKET_MANGLE
if (!dev->eth_mangle_tx ||
@@ -4315,6 +4324,11 @@ void netdev_rx_handler_unregister(struct
}
EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister);
+#ifdef CONFIG_SHORTCUT_FE
+int (*athrs_fast_nat_recv)(struct sk_buff *skb) __rcu __read_mostly;
+EXPORT_SYMBOL_GPL(athrs_fast_nat_recv);
+#endif
+
/*
* Limit the use of PFMEMALLOC reserves to those protocols that implement
* the special handling of PFMEMALLOC skbs.
@@ -4362,6 +4376,9 @@ static int __netif_receive_skb_core(stru
bool deliver_exact = false;
int ret = NET_RX_DROP;
__be16 type;
+#ifdef CONFIG_SHORTCUT_FE
+ int (*fast_recv)(struct sk_buff *skb);
+#endif
net_timestamp_check(!netdev_tstamp_prequeue, skb);
@@ -4388,6 +4405,16 @@ another_round:
goto out;
}
+#ifdef CONFIG_SHORTCUT_FE
+ fast_recv = rcu_dereference(athrs_fast_nat_recv);
+ if (fast_recv) {
+ if (fast_recv(skb)) {
+ ret = NET_RX_SUCCESS;
+ goto out;
+ }
+ }
+#endif
+
if (skb_skip_tc_classify(skb))
goto skip_classify;
--- a/net/netfilter/nf_conntrack_proto_tcp.c 2019-01-16 20:47:40.886993297 +0800
+++ b/net/netfilter/nf_conntrack_proto_tcp.c 2019-01-16 20:48:57.700570104 +0800
@@ -35,11 +35,17 @@
/* Do not check the TCP window for incoming packets */
static int nf_ct_tcp_no_window_check __read_mostly = 1;
+#ifdef CONFIG_SHORTCUT_FE
+EXPORT_SYMBOL_GPL(nf_ct_tcp_no_window_check);
+#endif
/* "Be conservative in what you do,
be liberal in what you accept from others."
If it's non-zero, we mark only out of window RST segments as INVALID. */
static int nf_ct_tcp_be_liberal __read_mostly = 0;
+#ifdef CONFIG_SHORTCUT_FE
+EXPORT_SYMBOL_GPL(nf_ct_tcp_be_liberal);
+#endif
/* If it is set to zero, we disable picking up already established
connections. */
--- a/net/bridge/br_if.c 2019-01-16 20:54:51.919367044 +0800
+++ b/net/bridge/br_if.c 2019-01-16 20:55:53.812401263 +0800
@@ -653,3 +653,26 @@ void br_port_flags_change(struct net_bri
if (mask & BR_AUTO_MASK)
nbp_update_port_count(br);
}
+
+/* Update bridge statistics for bridge packets processed by offload engines */
+void br_dev_update_stats(struct net_device *dev,
+ struct rtnl_link_stats64 *nlstats)
+{
+ struct net_bridge *br;
+ struct pcpu_sw_netstats *stats;
+
+ /* Is this a bridge? */
+ if (!(dev->priv_flags & IFF_EBRIDGE))
+ return;
+
+ br = netdev_priv(dev);
+ stats = this_cpu_ptr(br->stats);
+
+ u64_stats_update_begin(&stats->syncp);
+ stats->rx_packets += nlstats->rx_packets;
+ stats->rx_bytes += nlstats->rx_bytes;
+ stats->tx_packets += nlstats->tx_packets;
+ stats->tx_bytes += nlstats->tx_bytes;
+ u64_stats_update_end(&stats->syncp);
+}
+EXPORT_SYMBOL_GPL(br_dev_update_stats);
--- a/net/netfilter/Kconfig 2019-01-16 21:07:34.543460920 +0800
+++ b/net/netfilter/Kconfig 2019-01-16 21:08:14.739465937 +0800
@@ -146,6 +146,14 @@ config NF_CONNTRACK_TIMEOUT
If unsure, say `N'.
+config NF_CONNTRACK_CHAIN_EVENTS
+ bool "Register multiple callbacks to ct events"
+ depends on NF_CONNTRACK_EVENTS
+ help
+ Support multiple registrations.
+
+ If unsure, say `N'.
+
config NF_CONNTRACK_TIMESTAMP
bool 'Connection tracking timestamping'
depends on NETFILTER_ADVANCED
--- a/net/netfilter/nf_conntrack_ecache.c 2019-01-16 21:12:22.183462975 +0800
+++ b/net/netfilter/nf_conntrack_ecache.c 2019-01-16 21:26:10.379462031 +0800
@@ -122,13 +125,17 @@ int nf_conntrack_eventmask_report(unsign
{
int ret = 0;
struct net *net = nf_ct_net(ct);
+#ifndef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
struct nf_ct_event_notifier *notify;
+#endif
struct nf_conntrack_ecache *e;
rcu_read_lock();
+#ifndef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
notify = rcu_dereference(net->ct.nf_conntrack_event_cb);
if (!notify)
goto out_unlock;
+#endif
e = nf_ct_ecache_find(ct);
if (!e)
@@ -146,7 +153,12 @@ int nf_conntrack_eventmask_report(unsign
if (!((eventmask | missed) & e->ctmask))
goto out_unlock;
+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
+ ret = atomic_notifier_call_chain(&net->ct.nf_conntrack_chain,
+ eventmask | missed, &item);
+#else
ret = notify->fcn(eventmask | missed, &item);
+#endif
if (unlikely(ret < 0 || missed)) {
spin_lock_bh(&ct->lock);
if (ret < 0) {
@@ -179,15 +191,19 @@ void nf_ct_deliver_cached_events(struct
{
struct net *net = nf_ct_net(ct);
unsigned long events, missed;
+#ifndef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
struct nf_ct_event_notifier *notify;
+#endif
struct nf_conntrack_ecache *e;
struct nf_ct_event item;
int ret;
rcu_read_lock();
+#ifndef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
notify = rcu_dereference(net->ct.nf_conntrack_event_cb);
if (notify == NULL)
goto out_unlock;
+#endif
e = nf_ct_ecache_find(ct);
if (e == NULL)
@@ -210,7 +226,13 @@ void nf_ct_deliver_cached_events(struct
item.portid = 0;
item.report = 0;
+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
+ ret = atomic_notifier_call_chain(&net->ct.nf_conntrack_chain,
+ events | missed,
+ &item);
+#else
ret = notify->fcn(events | missed, &item);
+#endif
if (likely(ret == 0 && !missed))
goto out_unlock;

View File

@ -0,0 +1,228 @@
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -52,6 +52,9 @@ struct br_ip_list {
extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void __user *));
+extern void br_dev_update_stats(struct net_device *dev,
+ struct rtnl_link_stats64 *nlstats);
+
#if IS_ENABLED(CONFIG_BRIDGE) && IS_ENABLED(CONFIG_BRIDGE_IGMP_SNOOPING)
int br_multicast_list_adjacent(struct net_device *dev,
struct list_head *br_ip_list);
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -838,6 +838,10 @@ struct sk_buff {
#endif
__u8 gro_skip:1;
+#ifdef CONFIG_SHORTCUT_FE
+ __u8 fast_forwarded:1;
+#endif
+
#ifdef CONFIG_NET_SCHED
__u16 tc_index; /* traffic control index */
#endif
--- a/include/linux/timer.h
+++ b/include/linux/timer.h
@@ -18,6 +18,10 @@ struct timer_list {
void (*function)(struct timer_list *);
u32 flags;
+#ifdef CONFIG_SHORTCUT_FE
+ unsigned long cust_data;
+#endif
+
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -746,6 +746,28 @@ void br_port_flags_change(struct net_bri
br_recalculate_neigh_suppress_enabled(br);
}
+void br_dev_update_stats(struct net_device *dev,
+ struct rtnl_link_stats64 *nlstats)
+{
+ struct net_bridge *br;
+ struct pcpu_sw_netstats *stats;
+
+ /* Is this a bridge? */
+ if (!(dev->priv_flags & IFF_EBRIDGE))
+ return;
+
+ br = netdev_priv(dev);
+ stats = this_cpu_ptr(br->stats);
+
+ u64_stats_update_begin(&stats->syncp);
+ stats->rx_packets += nlstats->rx_packets;
+ stats->rx_bytes += nlstats->rx_bytes;
+ stats->tx_packets += nlstats->tx_packets;
+ stats->tx_bytes += nlstats->tx_bytes;
+ u64_stats_update_end(&stats->syncp);
+}
+EXPORT_SYMBOL_GPL(br_dev_update_stats);
+
bool br_port_flag_is_set(const struct net_device *dev, unsigned long flag)
{
struct net_bridge_port *p;
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3198,9 +3198,17 @@ static int xmit_one(struct sk_buff *skb,
if (!list_empty(&ptype_all) || !list_empty(&dev->ptype_all))
#endif
+#ifdef CONFIG_SHORTCUT_FE
+ /* If this skb has been fast forwarded then we don't want it to
+ * go to any taps (by definition we're trying to bypass them).
+ */
+ if (!skb->fast_forwarded) {
+#endif
if (dev_nit_active(dev))
dev_queue_xmit_nit(skb, dev);
-
+#ifdef CONFIG_SHORTCUT_FE
+ }
+#endif
#ifdef CONFIG_ETHERNET_PACKET_MANGLE
if (!dev->eth_mangle_tx ||
(skb = dev->eth_mangle_tx(dev, skb)) != NULL)
@@ -4694,6 +4702,11 @@ void netdev_rx_handler_unregister(struct
}
EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister);
+#ifdef CONFIG_SHORTCUT_FE
+int (*athrs_fast_nat_recv)(struct sk_buff *skb) __rcu __read_mostly;
+EXPORT_SYMBOL_GPL(athrs_fast_nat_recv);
+#endif
+
/*
* Limit the use of PFMEMALLOC reserves to those protocols that implement
* the special handling of PFMEMALLOC skbs.
@@ -4744,6 +4757,10 @@ static int __netif_receive_skb_core(stru
int ret = NET_RX_DROP;
__be16 type;
+#ifdef CONFIG_SHORTCUT_FE
+ int (*fast_recv)(struct sk_buff *skb);
+#endif
+
net_timestamp_check(!netdev_tstamp_prequeue, skb);
trace_netif_receive_skb(skb);
@@ -4783,6 +4800,16 @@ another_round:
goto out;
}
+#ifdef CONFIG_SHORTCUT_FE
+ fast_recv = rcu_dereference(athrs_fast_nat_recv);
+ if (fast_recv) {
+ if (fast_recv(skb)) {
+ ret = NET_RX_SUCCESS;
+ goto out;
+ }
+ }
+#endif
+
if (skb_skip_tc_classify(skb))
goto skip_classify;
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -473,3 +473,6 @@ config HAVE_CBPF_JIT
# Extended BPF JIT (eBPF)
config HAVE_EBPF_JIT
bool
+
+config SHORTCUT_FE
+ bool "Enables kernel network stack path for Shortcut Forwarding Engine
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -34,11 +34,19 @@
/* Do not check the TCP window for incoming packets */
static int nf_ct_tcp_no_window_check __read_mostly = 1;
+#ifdef CONFIG_SHORTCUT_FE
+EXPORT_SYMBOL_GPL(nf_ct_tcp_no_window_check);
+#endif
+
/* "Be conservative in what you do,
be liberal in what you accept from others."
If it's non-zero, we mark only out of window RST segments as INVALID. */
static int nf_ct_tcp_be_liberal __read_mostly = 0;
+#ifdef CONFIG_SHORTCUT_FE
+EXPORT_SYMBOL_GPL(nf_ct_tcp_be_liberal);
+#endif
+
/* If it is set to zero, we disable picking up already established
connections. */
static int nf_ct_tcp_loose __read_mostly = 1;
--- a/net/netfilter/nf_conntrack_ecache.c
+++ b/net/netfilter/nf_conntrack_ecache.c
@@ -153,13 +153,17 @@ int nf_conntrack_eventmask_report(unsign
{
int ret = 0;
struct net *net = nf_ct_net(ct);
+#ifndef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
struct nf_ct_event_notifier *notify;
+#endif
struct nf_conntrack_ecache *e;
rcu_read_lock();
+#ifndef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
notify = rcu_dereference(net->ct.nf_conntrack_event_cb);
if (!notify)
goto out_unlock;
+#endif
e = nf_ct_ecache_find(ct);
if (!e)
@@ -177,7 +181,12 @@ int nf_conntrack_eventmask_report(unsign
if (!((eventmask | missed) & e->ctmask))
goto out_unlock;
+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
+ ret = atomic_notifier_call_chain(&net->ct.nf_conntrack_chain,
+ eventmask | missed, &item);
+#else
ret = notify->fcn(eventmask | missed, &item);
+#endif
if (unlikely(ret < 0 || missed)) {
spin_lock_bh(&ct->lock);
if (ret < 0) {
@@ -252,15 +261,19 @@ void nf_ct_deliver_cached_events(struct
{
struct net *net = nf_ct_net(ct);
unsigned long events, missed;
+#ifndef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
struct nf_ct_event_notifier *notify;
+#endif
struct nf_conntrack_ecache *e;
struct nf_ct_event item;
int ret;
rcu_read_lock();
+#ifndef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
notify = rcu_dereference(net->ct.nf_conntrack_event_cb);
if (notify == NULL)
goto out_unlock;
+#endif
e = nf_ct_ecache_find(ct);
if (e == NULL)
@@ -283,7 +296,13 @@ void nf_ct_deliver_cached_events(struct
item.portid = 0;
item.report = 0;
+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
+ ret = atomic_notifier_call_chain(&net->ct.nf_conntrack_chain,
+ events | missed,
+ &item);
+#else
ret = notify->fcn(events | missed, &item);
+#endif
if (likely(ret == 0 && !missed))
goto out_unlock;