diff --git a/bcm27xx-eeprom/Makefile b/bcm27xx-eeprom/Makefile index dec227d51..b114ee11a 100755 --- a/bcm27xx-eeprom/Makefile +++ b/bcm27xx-eeprom/Makefile @@ -1,12 +1,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=bcm27xx-eeprom -PKG_VERSION:=2fec47bd7f981c9cb21b0fb3fdd4fe07f23f9e3b -PKG_RELEASE:=4 +PKG_VERSION:=v2022.04.26-138a1 +PKG_RELEASE:=$(AUTORELEASE) PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/raspberrypi/rpi-eeprom/tar.gz/$(PKG_VERSION)? -PKG_HASH:=f54c26ec399801dee7d3d0cc0e969c28878b6f42c982e166c863edb91d2d2a21 +PKG_HASH:=7c54839e68f226c5853fb63c8a1539b729d84b2e6bac311a51766c601d10a413 PKG_LICENSE:=BSD-3-Clause Custom PKG_LICENSE_FILES:=LICENSE @@ -21,7 +21,7 @@ TAR_CMD=$(HOST_TAR) -C $(1) $(TAR_OPTIONS) define Package/bcm27xx-eeprom SECTION:=utils CATEGORY:=Utilities - DEPENDS:=bcm27xx-userland +blkid +pciutils +python3-light +coreutils +coreutils-od + DEPENDS:=bcm27xx-userland +blkid +coreutils +coreutils-od +pciutils +python3-light TITLE:=BCM27xx EEPROM tools endef @@ -43,6 +43,7 @@ define Package/bcm27xx-eeprom/install $(INSTALL_DIR) $(1)/usr/bin $(INSTALL_BIN) $(PKG_BUILD_DIR)/rpi-eeprom-config $(1)/usr/bin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/rpi-eeprom-digest $(1)/usr/bin $(INSTALL_BIN) $(PKG_BUILD_DIR)/rpi-eeprom-update $(1)/usr/bin $(INSTALL_DIR) $(1)/lib/firmware/raspberrypi/bootloader diff --git a/bcm27xx-eeprom/patches/0004-rpi-eeprom-update-chmod-silent-f-is-not-supported.patch b/bcm27xx-eeprom/patches/0004-rpi-eeprom-update-chmod-silent-f-is-not-supported.patch new file mode 100644 index 000000000..5872f12da --- /dev/null +++ b/bcm27xx-eeprom/patches/0004-rpi-eeprom-update-chmod-silent-f-is-not-supported.patch @@ -0,0 +1,33 @@ +From 8376ac74390af0ad736c88615e128b82a75eebc0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= +Date: Fri, 19 Feb 2021 10:54:23 +0100 +Subject: [PATCH] rpi-eeprom-update: chmod silent (-f) is not supported +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Álvaro Fernández Rojas +--- + rpi-eeprom-update | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/rpi-eeprom-update ++++ b/rpi-eeprom-update +@@ -200,7 +200,7 @@ applyRecoveryUpdate() + || die "Failed to copy ${TMP_EEPROM_IMAGE} to ${BOOTFS}" + + # For NFS mounts ensure that the files are readable to the TFTP user +- chmod -f go+r "${BOOTFS}/pieeprom.upd" "${BOOTFS}/pieeprom.sig" \ ++ chmod go+r "${BOOTFS}/pieeprom.upd" "${BOOTFS}/pieeprom.sig" \ + || die "Failed to set permissions on eeprom update files" + fi + +@@ -211,7 +211,7 @@ applyRecoveryUpdate() + || die "Failed to copy ${VL805_UPDATE_IMAGE} to ${BOOTFS}/vl805.bin" + + # For NFS mounts ensure that the files are readable to the TFTP user +- chmod -f go+r "${BOOTFS}/vl805.bin" "${BOOTFS}/vl805.sig" \ ++ chmod go+r "${BOOTFS}/vl805.bin" "${BOOTFS}/vl805.sig" \ + || die "Failed to set permissions on eeprom update files" + fi + diff --git a/bcm27xx-eeprom/patches/0004-rpi-eeprom-update-remove-chmod.patch b/bcm27xx-eeprom/patches/0004-rpi-eeprom-update-remove-chmod.patch deleted file mode 100755 index a79fa89b1..000000000 --- a/bcm27xx-eeprom/patches/0004-rpi-eeprom-update-remove-chmod.patch +++ /dev/null @@ -1,24 +0,0 @@ ---- a/rpi-eeprom-update 2020-11-05 21:58:02.247836497 +0100 -+++ b/rpi-eeprom-update 2020-11-05 21:58:36.911266307 +0100 -@@ -212,8 +212,8 @@ - || die "Failed to copy ${TMP_EEPROM_IMAGE} to ${BOOTFS}" - - # For NFS mounts ensure that the files are readable to the TFTP user -- chmod -f go+r "${BOOTFS}/pieeprom.upd" "${BOOTFS}/pieeprom.sig" \ -- || die "Failed to set permissions on eeprom update files" -+ #chmod -f go+r "${BOOTFS}/pieeprom.upd" "${BOOTFS}/pieeprom.sig" \ -+ # || die "Failed to set permissions on eeprom update files" - fi - - if [ -n "${VL805_UPDATE_IMAGE}" ]; then -@@ -224,8 +224,8 @@ - || die "Failed to copy ${VL805_UPDATE_IMAGE} to ${BOOTFS}/vl805.bin" - - # For NFS mounts ensure that the files are readable to the TFTP user -- chmod -f go+r "${BOOTFS}/vl805.bin" "${BOOTFS}/vl805.sig" \ -- || die "Failed to set permissions on eeprom update files" -+ #chmod -f go+r "${BOOTFS}/vl805.bin" "${BOOTFS}/vl805.sig" \ -+ # || die "Failed to set permissions on eeprom update files" - fi - - cp -f "${RECOVERY_BIN}" "${BOOTFS}/recovery.bin" \ diff --git a/bcm27xx-eeprom/patches/0005-rpi-eeprom-config-change-default-text-editor.patch b/bcm27xx-eeprom/patches/0005-rpi-eeprom-config-change-default-text-editor.patch new file mode 100644 index 000000000..6feb7602c --- /dev/null +++ b/bcm27xx-eeprom/patches/0005-rpi-eeprom-config-change-default-text-editor.patch @@ -0,0 +1,22 @@ +--- a/rpi-eeprom-config ++++ b/rpi-eeprom-config +@@ -166,8 +166,8 @@ def edit_config(eeprom=None): + """ + Implements something like 'git commit' for editing EEPROM configs. + """ +- # Default to nano if $EDITOR is not defined. +- editor = 'nano' ++ # Default to vi if $EDITOR is not defined. ++ editor = 'vi' + if 'EDITOR' in os.environ: + editor = os.environ['EDITOR'] + +@@ -428,7 +428,7 @@ Operating modes: + + To cancel the pending update run 'sudo rpi-eeprom-update -r' + +- The default text editor is nano and may be overridden by setting the 'EDITOR' ++ The default text editor is vi and may be overridden by setting the 'EDITOR' + environment variable and passing '-E' to 'sudo' to preserve the environment. + + 6. Signing the bootloader config file. diff --git a/contributors/ta264.md b/contributors/ta264.md new file mode 100644 index 000000000..06ed382e6 --- /dev/null +++ b/contributors/ta264.md @@ -0,0 +1,9 @@ +2022-08-26 + +I hereby agree to the terms of the "OpenMPTCProuter Individual Contributor License Agreement", with MD5 checksum bc827a07eb93611d793ddb7c75083c00. + +I furthermore declare that I am authorized and able to make this agreement and sign this declaration. + +Signed, + +ta264 https://github.com/ta264 diff --git a/fast-classifier/Makefile b/fast-classifier/Makefile old mode 100755 new mode 100644 index 757d60e52..58dd06e01 --- a/fast-classifier/Makefile +++ b/fast-classifier/Makefile @@ -1,109 +1,10 @@ -# -# Copyright (c) 2013-2018 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. -# +obj-$(CONFIG_FAST_CLASSIFIER) += fast-classifier.o -include $(TOPDIR)/rules.mk -include $(INCLUDE_DIR)/kernel.mk +ifeq ($(SFE_SUPPORT_IPV6),) +SFE_SUPPORT_IPV6=y +endif +ccflags-$(SFE_SUPPORT_IPV6) += -DSFE_SUPPORT_IPV6 -PKG_NAME:=fast-classifier -PKG_RELEASE:=3 +ccflags-y += -I$(obj)/../shortcut-fe -include $(INCLUDE_DIR)/package.mk - -define KernelPackage/fast-classifier/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_EVENTS=y \ - CONFIG_NF_CONNTRACK_CHAIN_EVENTS=y \ - CONFIG_NF_CONNTRACK_MARK=y \ - CONFIG_XFRM=y - CONFLICTS:=kmod-shortcut-fe-drv kmod-shortcut-fe-cm -endef - -define KernelPackage/fast-classifier - $(call KernelPackage/fast-classifier/Default) -endef - -define KernelPackage/fast-classifier-noload - $(call KernelPackage/fast-classifier/Default) -endef - -define KernelPackage/fast-classifier/Default/description -FAST Classifier talks to SFE to make decisions about offloading connections -endef - -define KernelPackage/fast-classifier/description -$(call KernelPackage/fast-classifier/Default/description) -endef - -define KernelPackage/fast-classifier-noload/description -$(call KernelPackage/fast-classifier/Default/description) - -This package does not load fast-classifier 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 - -HAVE_ECM:=$(CONFIG_PACKAGE_kmod-qca-nss-ecm-premium)$(CONFIG_PACKAGE_kmod-qca-nss-ecm-noload)$(CONFIG_PACKAGE_kmod-qca-nss-ecm-premium-noload)$(CONFIG_PACKAGE_kmod-qca-nss-ecm-standard) - -define Build/Compile/kmod - +$(MAKE) $(PKG_JOBS) -C "$(LINUX_DIR)" \ - $(KERNEL_MAKE_FLAGS) \ - $(PKG_MAKE_FLAGS) \ - M="$(PKG_BUILD_DIR)" \ - CONFIG_FAST_CLASSIFIER=m \ - EXTRA_CFLAGS+="-DSFE_SUPPORT_IPV6" \ - $(if $(HAVE_ECM),EXTRA_CFLAGS+="-DCONFIG_SFE_ECM" CONFIG_SFE_ECM=y,) \ - 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,fast-classifier)) -#$(eval $(call KernelPackage,fast-classifier-noload)) -#$(eval $(call BuildPackage,fast-classifier-example)) +obj ?= . diff --git a/fast-classifier/fast-classifier.c b/fast-classifier/fast-classifier.c new file mode 100644 index 000000000..d79404cba --- /dev/null +++ b/fast-classifier/fast-classifier.c @@ -0,0 +1,1892 @@ +/* + * fast-classifier.c + * Shortcut forwarding engine connection manager. + * fast-classifier + * + * Copyright (c) 2013-2018 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "fast-classifier.h" + +typedef enum fast_classifier_exception { + FAST_CL_EXCEPTION_PACKET_BROADCAST, + FAST_CL_EXCEPTION_PACKET_MULTICAST, + FAST_CL_EXCEPTION_NO_IIF, + FAST_CL_EXCEPTION_NO_CT, + FAST_CL_EXCEPTION_CT_NO_TRACK, + FAST_CL_EXCEPTION_CT_NO_CONFIRM, + FAST_CL_EXCEPTION_CT_IS_ALG, + FAST_CL_EXCEPTION_IS_IPV4_MCAST, + FAST_CL_EXCEPTION_IS_IPV6_MCAST, + FAST_CL_EXCEPTION_TCP_NOT_ASSURED, + FAST_CL_EXCEPTION_TCP_NOT_ESTABLISHED, + FAST_CL_EXCEPTION_UNKNOW_PROTOCOL, + FAST_CL_EXCEPTION_NO_SRC_DEV, + FAST_CL_EXCEPTION_NO_SRC_XLATE_DEV, + FAST_CL_EXCEPTION_NO_DEST_DEV, + FAST_CL_EXCEPTION_NO_DEST_XLATE_DEV, + FAST_CL_EXCEPTION_NO_BRIDGE, + FAST_CL_EXCEPTION_LOCAL_OUT, + FAST_CL_EXCEPTION_WAIT_FOR_ACCELERATION, + FAST_CL_EXCEPTION_UPDATE_PROTOCOL_FAIL, + FAST_CL_EXCEPTION_CT_DESTROY_MISS, + FAST_CL_EXCEPTION_MAX +} fast_classifier_exception_t; + +static char *fast_classifier_exception_events_string[FAST_CL_EXCEPTION_MAX] = { + "PACKET_BROADCAST", + "PACKET_MULTICAST", + "NO_IIF", + "NO_CT", + "CT_NO_TRACK", + "CT_NO_CONFIRM", + "CT_IS_ALG", + "IS_IPV4_MCAST", + "IS_IPV6_MCAST", + "TCP_NOT_ASSURED", + "TCP_NOT_ESTABLISHED", + "UNKNOW_PROTOCOL", + "NO_SRC_DEV", + "NO_SRC_XLATE_DEV", + "NO_DEST_DEV", + "NO_DEST_XLATE_DEV", + "NO_BRIDGE", + "LOCAL_OUT", + "WAIT_FOR_ACCELERATION", + "UPDATE_PROTOCOL_FAIL", + "CT_DESTROY_MISS", +}; + +/* + * Per-module structure. + */ +struct fast_classifier { + spinlock_t lock; /* Lock for SMP correctness */ + + /* + * Control state. + */ + struct kobject *sys_fast_classifier; /* sysfs linkage */ + + /* + * Callback notifiers. + */ + struct notifier_block dev_notifier; /* Device notifier */ + struct notifier_block inet_notifier; /* IPv4 notifier */ + struct notifier_block inet6_notifier; /* IPv6 notifier */ + u32 exceptions[FAST_CL_EXCEPTION_MAX]; +}; + +static struct fast_classifier __sc; + +static struct nla_policy fast_classifier_genl_policy[FAST_CLASSIFIER_A_MAX + 1] = { + [FAST_CLASSIFIER_A_TUPLE] = { + .type = NLA_UNSPEC, + .len = sizeof(struct fast_classifier_tuple) + }, +}; + +static struct genl_multicast_group fast_classifier_genl_mcgrp[] = { + { + .name = FAST_CLASSIFIER_GENL_MCGRP, + }, +}; + +static struct genl_family fast_classifier_gnl_family = { + .id = GENL_ID_GENERATE, + .hdrsize = FAST_CLASSIFIER_GENL_HDRSIZE, + .name = FAST_CLASSIFIER_GENL_NAME, + .version = FAST_CLASSIFIER_GENL_VERSION, + .maxattr = FAST_CLASSIFIER_A_MAX, +}; + +static int fast_classifier_offload_genl_msg(struct sk_buff *skb, struct genl_info *info); +static int fast_classifier_nl_genl_msg_DUMP(struct sk_buff *skb, struct netlink_callback *cb); + +static struct genl_ops fast_classifier_gnl_ops[] = { + { + .cmd = FAST_CLASSIFIER_C_OFFLOAD, + .flags = 0, + .policy = fast_classifier_genl_policy, + .doit = fast_classifier_offload_genl_msg, + .dumpit = NULL, + }, + { + .cmd = FAST_CLASSIFIER_C_OFFLOADED, + .flags = 0, + .policy = fast_classifier_genl_policy, + .doit = NULL, + .dumpit = fast_classifier_nl_genl_msg_DUMP, + }, + { + .cmd = FAST_CLASSIFIER_C_DONE, + .flags = 0, + .policy = fast_classifier_genl_policy, + .doit = NULL, + .dumpit = fast_classifier_nl_genl_msg_DUMP, + }, +}; + +static atomic_t offload_msgs = ATOMIC_INIT(0); +static atomic_t offload_no_match_msgs = ATOMIC_INIT(0); +static atomic_t offloaded_msgs = ATOMIC_INIT(0); +static atomic_t done_msgs = ATOMIC_INIT(0); + +static atomic_t offloaded_fail_msgs = ATOMIC_INIT(0); +static atomic_t done_fail_msgs = ATOMIC_INIT(0); + +/* + * Accelerate incoming packets destined for bridge device + * If a incoming packet is ultimatly destined for + * a bridge device we will first see the packet coming + * from the phyiscal device, we can skip straight to + * processing the packet like it came from the bridge + * for some more performance gains + * + * This only works when the hook is above the bridge. We + * only implement ingress for now, because for egress we + * want to have the bridge devices qdiscs be used. + */ +static bool skip_to_bridge_ingress; + +/* + * fast_classifier_incr_exceptions() + * increase an exception counter. + */ +static inline void fast_classifier_incr_exceptions(fast_classifier_exception_t except) +{ + struct fast_classifier *sc = &__sc; + + spin_lock_bh(&sc->lock); + sc->exceptions[except]++; + spin_unlock_bh(&sc->lock); +} + +/* + * fast_classifier_recv() + * Handle packet receives. + * + * Returns 1 if the packet is forwarded or 0 if it isn't. + */ +int fast_classifier_recv(struct sk_buff *skb) +{ + struct net_device *dev; + struct net_device *master_dev = NULL; + int ret = 0; + + /* + * We know that for the vast majority of packets we need the transport + * layer header so we may as well start to fetch it now! + */ + prefetch(skb->data + 32); + barrier(); + + dev = skb->dev; + + /* + * Process packet like it arrived on the bridge device + */ + if (skip_to_bridge_ingress && + (dev->priv_flags & IFF_BRIDGE_PORT)) { + master_dev = sfe_dev_get_master(dev); + if (!master_dev) { + DEBUG_WARN("master dev is NULL %s\n", dev->name); + goto rx_exit; + } + dev = master_dev; + } + + /* + * We're only interested in IPv4 and IPv6 packets. + */ + if (likely(htons(ETH_P_IP) == skb->protocol)) { + struct in_device *in_dev; + + /* + * Does our input device support IP processing? + */ + in_dev = (struct in_device *)dev->ip_ptr; + if (unlikely(!in_dev)) { + DEBUG_TRACE("no IP processing for device: %s\n", dev->name); + goto rx_exit; + } + + /* + * Does it have an IP address? If it doesn't then we can't do anything + * interesting here! + */ + if (unlikely(!in_dev->ifa_list)) { + DEBUG_TRACE("no IP address for device: %s\n", dev->name); + goto rx_exit; + } + + ret = sfe_ipv4_recv(dev, skb); + + } else if (likely(htons(ETH_P_IPV6) == skb->protocol)) { + struct inet6_dev *in_dev; + + /* + * Does our input device support IPv6 processing? + */ + in_dev = (struct inet6_dev *)dev->ip6_ptr; + if (unlikely(!in_dev)) { + DEBUG_TRACE("no IPv6 processing for device: %s\n", dev->name); + goto rx_exit; + } + + /* + * Does it have an IPv6 address? If it doesn't then we can't do anything + * interesting here! + */ + if (unlikely(list_empty(&in_dev->addr_list))) { + DEBUG_TRACE("no IPv6 address for device: %s\n", dev->name); + goto rx_exit; + } + + ret = sfe_ipv6_recv(dev, skb); + + } else { + DEBUG_TRACE("not IP packet\n"); + } + +rx_exit: + if (master_dev) { + dev_put(master_dev); + } + + return ret; +} + +/* + * fast_classifier_find_dev_and_mac_addr() + * Find the device and MAC address for a given IPv4 address. + * + * Returns true if we find the device and MAC address, otherwise false. + * + * We look up the rtable entry for the address and, from its neighbour + * structure, obtain the hardware address. This means this function also + * works if the neighbours are routers too. + */ +static bool fast_classifier_find_dev_and_mac_addr(sfe_ip_addr_t *addr, struct net_device **dev, u8 *mac_addr, bool is_v4) +{ + struct neighbour *neigh; + struct rtable *rt; + struct rt6_info *rt6; + struct dst_entry *dst; + struct net_device *mac_dev; + + /* + * Look up the rtable entry for the IP address then get the hardware + * address from its neighbour structure. This means this works when the + * neighbours are routers too. + */ + if (likely(is_v4)) { + rt = ip_route_output(&init_net, addr->ip, 0, 0, 0); + if (unlikely(IS_ERR(rt))) { + goto ret_fail; + } + + dst = (struct dst_entry *)rt; + } else { + rt6 = rt6_lookup(&init_net, (struct in6_addr *)addr->ip6, 0, 0, 0); + if (!rt6) { + goto ret_fail; + } + + dst = (struct dst_entry *)rt6; + } + + rcu_read_lock(); + neigh = sfe_dst_get_neighbour(dst, addr); + if (unlikely(!neigh)) { + rcu_read_unlock(); + dst_release(dst); + goto ret_fail; + } + + if (unlikely(!(neigh->nud_state & NUD_VALID))) { + rcu_read_unlock(); + neigh_release(neigh); + dst_release(dst); + goto ret_fail; + } + + mac_dev = neigh->dev; + if (!mac_dev) { + rcu_read_unlock(); + neigh_release(neigh); + dst_release(dst); + goto ret_fail; + } + + memcpy(mac_addr, neigh->ha, (size_t)mac_dev->addr_len); + + dev_hold(mac_dev); + *dev = mac_dev; + rcu_read_unlock(); + neigh_release(neigh); + dst_release(dst); + + return true; + +ret_fail: + if (is_v4) { + DEBUG_TRACE("failed to find MAC address for IP: %pI4\n", addr); + + } else { + DEBUG_TRACE("failed to find MAC address for IP: %pI6\n", addr); + } + + return false; +} + +static DEFINE_SPINLOCK(sfe_connections_lock); + +struct sfe_connection { + struct hlist_node hl; + struct sfe_connection_create *sic; + struct nf_conn *ct; + int hits; + int offload_permit; + int offloaded; + bool is_v4; + unsigned char smac[ETH_ALEN]; + unsigned char dmac[ETH_ALEN]; +}; + +static int sfe_connections_size; + +#define FC_CONN_HASH_ORDER 13 +static DEFINE_HASHTABLE(fc_conn_ht, FC_CONN_HASH_ORDER); + +static u32 fc_conn_hash(sfe_ip_addr_t *saddr, sfe_ip_addr_t *daddr, + unsigned short sport, unsigned short dport, bool is_v4) +{ + u32 idx, cnt = ((is_v4 ? sizeof(saddr->ip) : sizeof(saddr->ip6))/sizeof(u32)); + u32 hash = 0; + + for (idx = 0; idx < cnt; idx++) { + hash ^= ((u32 *)saddr)[idx] ^ ((u32 *)daddr)[idx]; + } + + return hash ^ (sport | (dport << 16)); +} + +/* + * fast_classifier_update_protocol() + * Update sfe_ipv4_create struct with new protocol information before we offload + */ +static int fast_classifier_update_protocol(struct sfe_connection_create *p_sic, struct nf_conn *ct) +{ + switch (p_sic->protocol) { + case IPPROTO_TCP: + p_sic->src_td_window_scale = ct->proto.tcp.seen[0].td_scale; + p_sic->src_td_max_window = ct->proto.tcp.seen[0].td_maxwin; + p_sic->src_td_end = ct->proto.tcp.seen[0].td_end; + p_sic->src_td_max_end = ct->proto.tcp.seen[0].td_maxend; + p_sic->dest_td_window_scale = ct->proto.tcp.seen[1].td_scale; + p_sic->dest_td_max_window = ct->proto.tcp.seen[1].td_maxwin; + p_sic->dest_td_end = ct->proto.tcp.seen[1].td_end; + p_sic->dest_td_max_end = ct->proto.tcp.seen[1].td_maxend; + + if (nf_ct_tcp_no_window_check + || (ct->proto.tcp.seen[0].flags & IP_CT_TCP_FLAG_BE_LIBERAL) + || (ct->proto.tcp.seen[1].flags & IP_CT_TCP_FLAG_BE_LIBERAL)) { + p_sic->flags |= SFE_CREATE_FLAG_NO_SEQ_CHECK; + } + + /* + * If the connection is shutting down do not manage it. + * state can not be SYN_SENT, SYN_RECV because connection is assured + * Not managed states: FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE. + */ + spin_lock(&ct->lock); + if (ct->proto.tcp.state != TCP_CONNTRACK_ESTABLISHED) { + spin_unlock(&ct->lock); + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_TCP_NOT_ESTABLISHED); + DEBUG_TRACE("connection in termination state: %#x, s: %pI4:%u, d: %pI4:%u\n", + ct->proto.tcp.state, &p_sic->src_ip, ntohs(p_sic->src_port), + &p_sic->dest_ip, ntohs(p_sic->dest_port)); + return 0; + } + spin_unlock(&ct->lock); + break; + + case IPPROTO_UDP: + break; + + default: + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_UNKNOW_PROTOCOL); + DEBUG_TRACE("unhandled protocol %d\n", p_sic->protocol); + return 0; + } + + return 1; +} + +/* fast_classifier_send_genl_msg() + * Function to send a generic netlink message + */ +static void fast_classifier_send_genl_msg(int msg, struct fast_classifier_tuple *fc_msg) +{ + struct sk_buff *skb; + int rc; + int buf_len; + int total_len; + void *msg_head; + + /* + * Calculate our packet payload size. + * Start with our family header. + */ + buf_len = fast_classifier_gnl_family.hdrsize; + + /* + * Add the nla_total_size of each attribute we're going to nla_put(). + */ + buf_len += nla_total_size(sizeof(*fc_msg)); + + /* + * Lastly we need to add space for the NL message header since + * genlmsg_new only accounts for the GENL header and not the + * outer NL header. To do this, we use a NL helper function which + * calculates the total size of a netlink message given a payload size. + * Note this value does not include the GENL header, but that's + * added automatically by genlmsg_new. + */ + total_len = nlmsg_total_size(buf_len); + skb = genlmsg_new(total_len, GFP_ATOMIC); + if (!skb) + return; + + msg_head = genlmsg_put(skb, 0, 0, &fast_classifier_gnl_family, 0, msg); + if (!msg_head) { + nlmsg_free(skb); + return; + } + + rc = nla_put(skb, FAST_CLASSIFIER_A_TUPLE, sizeof(struct fast_classifier_tuple), fc_msg); + if (rc != 0) { + genlmsg_cancel(skb, msg_head); + nlmsg_free(skb); + return; + } + +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 19 , 0)) + rc = genlmsg_end(skb, msg_head); + if (rc < 0) { + genlmsg_cancel(skb, msg_head); + nlmsg_free(skb); + return; + } +#else + genlmsg_end(skb, msg_head); + +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)) + rc = genlmsg_multicast(&fast_classifier_gnl_family, skb, 0, 0, GFP_ATOMIC); +#else + rc = genlmsg_multicast(skb, 0, fast_classifier_genl_mcgrp[0].id, GFP_ATOMIC); +#endif + switch (msg) { + case FAST_CLASSIFIER_C_OFFLOADED: + if (rc == 0) { + atomic_inc(&offloaded_msgs); + } else { + atomic_inc(&offloaded_fail_msgs); + } + break; + case FAST_CLASSIFIER_C_DONE: + if (rc == 0) { + atomic_inc(&done_msgs); + } else { + atomic_inc(&done_fail_msgs); + } + break; + default: + DEBUG_ERROR("fast-classifer: Unknown message type sent!\n"); + break; + } + + DEBUG_TRACE("Notify NL message %d ", msg); + if (fc_msg->ethertype == AF_INET) { + DEBUG_TRACE("sip=%pI4 dip=%pI4 ", &fc_msg->src_saddr, &fc_msg->dst_saddr); + } else { + DEBUG_TRACE("sip=%pI6 dip=%pI6 ", &fc_msg->src_saddr, &fc_msg->dst_saddr); + } + DEBUG_TRACE("protocol=%d sport=%d dport=%d smac=%pM dmac=%pM\n", + fc_msg->proto, fc_msg->sport, fc_msg->dport, fc_msg->smac, fc_msg->dmac); +} + +/* + * fast_classifier_find_conn() + * find a connection object in the hash table + * @pre the sfe_connection_lock must be held before calling this function + */ +static struct sfe_connection * +fast_classifier_find_conn(sfe_ip_addr_t *saddr, sfe_ip_addr_t *daddr, + unsigned short sport, unsigned short dport, + unsigned char proto, bool is_v4) +{ + struct sfe_connection_create *p_sic; + struct sfe_connection *conn; + u32 key; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)) + struct hlist_node *node; +#endif + + key = fc_conn_hash(saddr, daddr, sport, dport, is_v4); + + sfe_hash_for_each_possible(fc_conn_ht, conn, node, hl, key) { + if (conn->is_v4 != is_v4) { + continue; + } + + p_sic = conn->sic; + + if (p_sic->protocol == proto && + p_sic->src_port == sport && + p_sic->dest_port == dport && + sfe_addr_equal(&p_sic->src_ip, saddr, is_v4) && + sfe_addr_equal(&p_sic->dest_ip, daddr, is_v4)) { + return conn; + } + } + + DEBUG_TRACE("connection not found\n"); + return NULL; +} + +/* + * fast_classifier_sb_find_conn() + * find a connection object in the hash table according to information of packet + * if not found, reverse the tuple and try again. + * @pre the sfe_connection_lock must be held before calling this function + */ +static struct sfe_connection * +fast_classifier_sb_find_conn(sfe_ip_addr_t *saddr, sfe_ip_addr_t *daddr, + unsigned short sport, unsigned short dport, + unsigned char proto, bool is_v4) +{ + struct sfe_connection_create *p_sic; + struct sfe_connection *conn; + u32 key; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)) + struct hlist_node *node; +#endif + + key = fc_conn_hash(saddr, daddr, sport, dport, is_v4); + + sfe_hash_for_each_possible(fc_conn_ht, conn, node, hl, key) { + if (conn->is_v4 != is_v4) { + continue; + } + + p_sic = conn->sic; + + if (p_sic->protocol == proto && + p_sic->src_port == sport && + p_sic->dest_port_xlate == dport && + sfe_addr_equal(&p_sic->src_ip, saddr, is_v4) && + sfe_addr_equal(&p_sic->dest_ip_xlate, daddr, is_v4)) { + return conn; + } + } + + /* + * Reverse the tuple and try again + */ + key = fc_conn_hash(daddr, saddr, dport, sport, is_v4); + + sfe_hash_for_each_possible(fc_conn_ht, conn, node, hl, key) { + if (conn->is_v4 != is_v4) { + continue; + } + + p_sic = conn->sic; + + if (p_sic->protocol == proto && + p_sic->src_port == dport && + p_sic->dest_port_xlate == sport && + sfe_addr_equal(&p_sic->src_ip, daddr, is_v4) && + sfe_addr_equal(&p_sic->dest_ip_xlate, saddr, is_v4)) { + return conn; + } + } + + DEBUG_TRACE("connection not found\n"); + return NULL; +} + +/* + * fast_classifier_add_conn() + * add a connection object in the hash table if no duplicate + * @conn connection to add + * @return conn if successful, NULL if duplicate + */ +static struct sfe_connection * +fast_classifier_add_conn(struct sfe_connection *conn) +{ + struct sfe_connection_create *sic = conn->sic; + u32 key; + + spin_lock_bh(&sfe_connections_lock); + if (fast_classifier_find_conn(&sic->src_ip, &sic->dest_ip, sic->src_port, + sic->dest_port, sic->protocol, conn->is_v4)) { + spin_unlock_bh(&sfe_connections_lock); + return NULL; + } + + key = fc_conn_hash(&sic->src_ip, &sic->dest_ip, + sic->src_port, sic->dest_port, conn->is_v4); + + hash_add(fc_conn_ht, &conn->hl, key); + sfe_connections_size++; + spin_unlock_bh(&sfe_connections_lock); + + DEBUG_TRACE(" -> adding item to sfe_connections, new size: %d\n", sfe_connections_size); + + if (conn->is_v4) { + DEBUG_TRACE("new offloadable: key: %u proto: %d src_ip: %pI4 dst_ip: %pI4, src_port: %d, dst_port: %d\n", + key, sic->protocol, &(sic->src_ip), &(sic->dest_ip), sic->src_port, sic->dest_port); + } else { + DEBUG_TRACE("new offloadable: key: %u proto: %d src_ip: %pI6 dst_ip: %pI6, src_port: %d, dst_port: %d\n", + key, sic->protocol, &(sic->src_ip), &(sic->dest_ip), sic->src_port, sic->dest_port); + } + + return conn; +} + +/* + * fast_classifier_offload_genl_msg() + * Called from user space to offload a connection + */ +static int +fast_classifier_offload_genl_msg(struct sk_buff *skb, struct genl_info *info) +{ + struct nlattr *na; + struct fast_classifier_tuple *fc_msg; + struct sfe_connection *conn; + + na = info->attrs[FAST_CLASSIFIER_A_TUPLE]; + fc_msg = nla_data(na); + + if (fc_msg->ethertype == AF_INET) { + DEBUG_TRACE("want to offload: %d-%d, %pI4, %pI4, %d, %d SMAC=%pM DMAC=%pM\n", + fc_msg->ethertype, + fc_msg->proto, + &fc_msg->src_saddr, + &fc_msg->dst_saddr, + fc_msg->sport, + fc_msg->dport, + fc_msg->smac, + fc_msg->dmac); + } else { + DEBUG_TRACE("want to offload: %d-%d, %pI6, %pI6, %d, %d SMAC=%pM DMAC=%pM\n", + fc_msg->ethertype, + fc_msg->proto, + &fc_msg->src_saddr, + &fc_msg->dst_saddr, + fc_msg->sport, + fc_msg->dport, + fc_msg->smac, + fc_msg->dmac); + } + + spin_lock_bh(&sfe_connections_lock); + conn = fast_classifier_sb_find_conn((sfe_ip_addr_t *)&fc_msg->src_saddr, + (sfe_ip_addr_t *)&fc_msg->dst_saddr, + fc_msg->sport, + fc_msg->dport, + fc_msg->proto, + (fc_msg->ethertype == AF_INET)); + if (!conn) { + spin_unlock_bh(&sfe_connections_lock); + DEBUG_TRACE("REQUEST OFFLOAD NO MATCH\n"); + atomic_inc(&offload_no_match_msgs); + return 0; + } + + conn->offload_permit = 1; + spin_unlock_bh(&sfe_connections_lock); + atomic_inc(&offload_msgs); + + DEBUG_TRACE("INFO: calling sfe rule creation!\n"); + return 0; +} + +/* + * fast_classifier_nl_genl_msg_DUMP() + * ignore fast_classifier_messages OFFLOADED and DONE + */ +static int fast_classifier_nl_genl_msg_DUMP(struct sk_buff *skb, + struct netlink_callback *cb) +{ + return 0; +} + +/* auto offload connection once we have this many packets*/ +static int offload_at_pkts = 128; + +/* + * fast_classifier_post_routing() + * Called for packets about to leave the box - either locally generated or forwarded from another interface + */ +static unsigned int fast_classifier_post_routing(struct sk_buff *skb, bool is_v4) +{ + int ret; + struct sfe_connection_create sic; + struct sfe_connection_create *p_sic; + struct net_device *in; + struct nf_conn *ct; + enum ip_conntrack_info ctinfo; + struct net_device *dev; + struct net_device *src_dev; + struct net_device *dest_dev; + struct net_device *src_dev_tmp; + struct net_device *dest_dev_tmp; + struct net_device *src_br_dev = NULL; + struct net_device *dest_br_dev = NULL; + struct nf_conntrack_tuple orig_tuple; + struct nf_conntrack_tuple reply_tuple; + struct sfe_connection *conn; + + /* + * Don't process broadcast or multicast packets. + */ + if (unlikely(skb->pkt_type == PACKET_BROADCAST)) { + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_PACKET_BROADCAST); + DEBUG_TRACE("broadcast, ignoring\n"); + return NF_ACCEPT; + } + if (unlikely(skb->pkt_type == PACKET_MULTICAST)) { + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_PACKET_MULTICAST); + DEBUG_TRACE("multicast, ignoring\n"); + return NF_ACCEPT; + } + + /* + * Don't process packets that are not being forwarded. + */ + in = dev_get_by_index(&init_net, skb->skb_iif); + if (!in) { + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_NO_IIF); + DEBUG_TRACE("packet not forwarding\n"); + return NF_ACCEPT; + } + + dev_put(in); + + /* + * Don't process packets that aren't being tracked by conntrack. + */ + ct = nf_ct_get(skb, &ctinfo); + if (unlikely(!ct)) { + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_NO_CT); + DEBUG_TRACE("no conntrack connection, ignoring\n"); + return NF_ACCEPT; + } + + /* + * Don't process untracked connections. + */ + if (unlikely(nf_ct_is_untracked(ct))) { + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_CT_NO_TRACK); + DEBUG_TRACE("untracked connection\n"); + return NF_ACCEPT; + } + + /* + * Unconfirmed connection may be dropped by Linux at the final step, + * So we don't process unconfirmed connections. + */ + if (!nf_ct_is_confirmed(ct)) { + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_CT_NO_CONFIRM); + DEBUG_TRACE("unconfirmed connection\n"); + return NF_ACCEPT; + } + + /* + * Don't process connections that require support from a 'helper' (typically a NAT ALG). + */ + if (unlikely(nfct_help(ct))) { + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_CT_IS_ALG); + DEBUG_TRACE("connection has helper\n"); + return NF_ACCEPT; + } + + memset(&sic, 0, sizeof(sic)); + + /* + * Look up the details of our connection in conntrack. + * + * Note that the data we get from conntrack is for the "ORIGINAL" direction + * but our packet may actually be in the "REPLY" direction. + */ + orig_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; + reply_tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple; + sic.protocol = (s32)orig_tuple.dst.protonum; + + sic.flags = 0; + + /* + * Get addressing information, non-NAT first + */ + if (likely(is_v4)) { + u32 dscp; + + sic.src_ip.ip = (__be32)orig_tuple.src.u3.ip; + sic.dest_ip.ip = (__be32)orig_tuple.dst.u3.ip; + + if (ipv4_is_multicast(sic.src_ip.ip) || ipv4_is_multicast(sic.dest_ip.ip)) { + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_IS_IPV4_MCAST); + DEBUG_TRACE("multicast address\n"); + return NF_ACCEPT; + } + + /* + * NAT'ed addresses - note these are as seen from the 'reply' direction + * When NAT does not apply to this connection these will be identical to the above. + */ + sic.src_ip_xlate.ip = (__be32)reply_tuple.dst.u3.ip; + sic.dest_ip_xlate.ip = (__be32)reply_tuple.src.u3.ip; + + dscp = ipv4_get_dsfield(ip_hdr(skb)) >> XT_DSCP_SHIFT; + if (dscp) { + sic.dest_dscp = dscp; + sic.src_dscp = sic.dest_dscp; + sic.flags |= SFE_CREATE_FLAG_REMARK_DSCP; + } + } else { + u32 dscp; + + sic.src_ip.ip6[0] = *((struct sfe_ipv6_addr *)&orig_tuple.src.u3.in6); + sic.dest_ip.ip6[0] = *((struct sfe_ipv6_addr *)&orig_tuple.dst.u3.in6); + + if (ipv6_addr_is_multicast((struct in6_addr *)sic.src_ip.ip6) || + ipv6_addr_is_multicast((struct in6_addr *)sic.dest_ip.ip6)) { + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_IS_IPV6_MCAST); + DEBUG_TRACE("multicast address\n"); + return NF_ACCEPT; + } + + /* + * NAT'ed addresses - note these are as seen from the 'reply' direction + * When NAT does not apply to this connection these will be identical to the above. + */ + sic.src_ip_xlate.ip6[0] = *((struct sfe_ipv6_addr *)&reply_tuple.dst.u3.in6); + sic.dest_ip_xlate.ip6[0] = *((struct sfe_ipv6_addr *)&reply_tuple.src.u3.in6); + + dscp = ipv6_get_dsfield(ipv6_hdr(skb)) >> XT_DSCP_SHIFT; + if (dscp) { + sic.dest_dscp = dscp; + sic.src_dscp = sic.dest_dscp; + sic.flags |= SFE_CREATE_FLAG_REMARK_DSCP; + } + } + + switch (sic.protocol) { + case IPPROTO_TCP: + sic.src_port = orig_tuple.src.u.tcp.port; + sic.dest_port = orig_tuple.dst.u.tcp.port; + sic.src_port_xlate = reply_tuple.dst.u.tcp.port; + sic.dest_port_xlate = reply_tuple.src.u.tcp.port; + + /* + * Don't try to manage a non-established connection. + */ + if (!test_bit(IPS_ASSURED_BIT, &ct->status)) { + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_TCP_NOT_ASSURED); + DEBUG_TRACE("non-established connection\n"); + return NF_ACCEPT; + } + + break; + + case IPPROTO_UDP: + sic.src_port = orig_tuple.src.u.udp.port; + sic.dest_port = orig_tuple.dst.u.udp.port; + sic.src_port_xlate = reply_tuple.dst.u.udp.port; + sic.dest_port_xlate = reply_tuple.src.u.udp.port; + break; + + default: + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_UNKNOW_PROTOCOL); + DEBUG_TRACE("unhandled protocol %d\n", sic.protocol); + return NF_ACCEPT; + } + +#ifdef CONFIG_XFRM + sic.original_accel = 1; + sic.reply_accel = 1; +#endif + + /* + * Get QoS information + */ + if (skb->priority) { + sic.dest_priority = skb->priority; + sic.src_priority = sic.dest_priority; + sic.flags |= SFE_CREATE_FLAG_REMARK_PRIORITY; + } + + if (is_v4) { + DEBUG_TRACE("POST_ROUTE: checking new connection: %d src_ip: %pI4 dst_ip: %pI4, src_port: %d, dst_port: %d\n", + sic.protocol, &sic.src_ip, &sic.dest_ip, sic.src_port, sic.dest_port); + } else { + DEBUG_TRACE("POST_ROUTE: checking new connection: %d src_ip: %pI6 dst_ip: %pI6, src_port: %d, dst_port: %d\n", + sic.protocol, &sic.src_ip, &sic.dest_ip, sic.src_port, sic.dest_port); + } + + /* + * If we already have this connection in our list, skip it + * XXX: this may need to be optimized + */ + spin_lock_bh(&sfe_connections_lock); + + conn = fast_classifier_find_conn(&sic.src_ip, &sic.dest_ip, sic.src_port, sic.dest_port, sic.protocol, is_v4); + if (conn) { + conn->hits++; + + if (!conn->offloaded) { + if (conn->offload_permit || conn->hits >= offload_at_pkts) { + DEBUG_TRACE("OFFLOADING CONNECTION, TOO MANY HITS\n"); + + if (fast_classifier_update_protocol(conn->sic, conn->ct) == 0) { + spin_unlock_bh(&sfe_connections_lock); + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_UPDATE_PROTOCOL_FAIL); + DEBUG_TRACE("UNKNOWN PROTOCOL OR CONNECTION CLOSING, SKIPPING\n"); + return NF_ACCEPT; + } + + DEBUG_TRACE("INFO: calling sfe rule creation!\n"); + spin_unlock_bh(&sfe_connections_lock); + + ret = is_v4 ? sfe_ipv4_create_rule(conn->sic) : sfe_ipv6_create_rule(conn->sic); + if ((ret == 0) || (ret == -EADDRINUSE)) { + struct fast_classifier_tuple fc_msg; + + if (is_v4) { + fc_msg.ethertype = AF_INET; + fc_msg.src_saddr.in = *((struct in_addr *)&sic.src_ip); + fc_msg.dst_saddr.in = *((struct in_addr *)&sic.dest_ip_xlate); + } else { + fc_msg.ethertype = AF_INET6; + fc_msg.src_saddr.in6 = *((struct in6_addr *)&sic.src_ip); + fc_msg.dst_saddr.in6 = *((struct in6_addr *)&sic.dest_ip_xlate); + } + + fc_msg.proto = sic.protocol; + fc_msg.sport = sic.src_port; + fc_msg.dport = sic.dest_port_xlate; + memcpy(fc_msg.smac, conn->smac, ETH_ALEN); + memcpy(fc_msg.dmac, conn->dmac, ETH_ALEN); + fast_classifier_send_genl_msg(FAST_CLASSIFIER_C_OFFLOADED, &fc_msg); + conn->offloaded = 1; + } + + return NF_ACCEPT; + } + } + + spin_unlock_bh(&sfe_connections_lock); + if (conn->offloaded) { + is_v4 ? sfe_ipv4_update_rule(conn->sic) : sfe_ipv6_update_rule(conn->sic); + } + + DEBUG_TRACE("FOUND, SKIPPING\n"); + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_WAIT_FOR_ACCELERATION); + return NF_ACCEPT; + } + + spin_unlock_bh(&sfe_connections_lock); + + /* + * Get the net device and MAC addresses that correspond to the various source and + * destination host addresses. + */ + if (!fast_classifier_find_dev_and_mac_addr(&sic.src_ip, &src_dev_tmp, sic.src_mac, is_v4)) { + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_NO_SRC_DEV); + return NF_ACCEPT; + } + src_dev = src_dev_tmp; + + if (!fast_classifier_find_dev_and_mac_addr(&sic.src_ip_xlate, &dev, sic.src_mac_xlate, is_v4)) { + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_NO_SRC_XLATE_DEV); + goto done1; + } + dev_put(dev); + + if (!fast_classifier_find_dev_and_mac_addr(&sic.dest_ip, &dev, sic.dest_mac, is_v4)) { + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_NO_DEST_DEV); + goto done1; + } + dev_put(dev); + + if (!fast_classifier_find_dev_and_mac_addr(&sic.dest_ip_xlate, &dest_dev_tmp, sic.dest_mac_xlate, is_v4)) { + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_NO_DEST_XLATE_DEV); + goto done1; + } + dest_dev = dest_dev_tmp; + + /* + * Our devices may actually be part of a bridge interface. If that's + * the case then find the bridge interface instead. + */ + if (src_dev->priv_flags & IFF_BRIDGE_PORT) { + src_br_dev = sfe_dev_get_master(src_dev); + if (!src_br_dev) { + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_NO_BRIDGE); + DEBUG_TRACE("no bridge found for: %s\n", src_dev->name); + goto done2; + } + src_dev = src_br_dev; + } + + if (dest_dev->priv_flags & IFF_BRIDGE_PORT) { + dest_br_dev = sfe_dev_get_master(dest_dev); + if (!dest_br_dev) { + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_NO_BRIDGE); + DEBUG_TRACE("no bridge found for: %s\n", dest_dev->name); + goto done3; + } + dest_dev = dest_br_dev; + } + + sic.src_dev = src_dev; + sic.dest_dev = dest_dev; + + sic.src_mtu = src_dev->mtu; + sic.dest_mtu = dest_dev->mtu; + + if (skb->mark) { + DEBUG_TRACE("SKB MARK NON ZERO %x\n", skb->mark); + } + sic.mark = skb->mark; + + conn = kmalloc(sizeof(*conn), GFP_ATOMIC); + if (!conn) { + printk(KERN_CRIT "ERROR: no memory for sfe\n"); + goto done4; + } + conn->hits = 0; + conn->offload_permit = 0; + conn->offloaded = 0; + conn->is_v4 = is_v4; + DEBUG_TRACE("Source MAC=%pM\n", sic.src_mac); + memcpy(conn->smac, sic.src_mac, ETH_ALEN); + memcpy(conn->dmac, sic.dest_mac_xlate, ETH_ALEN); + + p_sic = kmalloc(sizeof(*p_sic), GFP_ATOMIC); + if (!p_sic) { + printk(KERN_CRIT "ERROR: no memory for sfe\n"); + kfree(conn); + goto done4; + } + + memcpy(p_sic, &sic, sizeof(sic)); + conn->sic = p_sic; + conn->ct = ct; + + if (!fast_classifier_add_conn(conn)) { + kfree(conn->sic); + kfree(conn); + } + + /* + * If we had bridge ports then release them too. + */ +done4: + if (dest_br_dev) { + dev_put(dest_br_dev); + } +done3: + if (src_br_dev) { + dev_put(src_br_dev); + } +done2: + dev_put(dest_dev_tmp); +done1: + dev_put(src_dev_tmp); + + return NF_ACCEPT; +} + +/* + * fast_classifier_ipv4_post_routing_hook() + * Called for packets about to leave the box - either locally generated or forwarded from another interface + */ +fast_classifier_ipv4_post_routing_hook(hooknum, ops, skb, in_unused, out, okfn) +{ + return fast_classifier_post_routing(skb, true); +} + +/* + * fast_classifier_ipv6_post_routing_hook() + * Called for packets about to leave the box - either locally generated or forwarded from another interface + */ +fast_classifier_ipv6_post_routing_hook(hooknum, ops, skb, in_unused, out, okfn) +{ + return fast_classifier_post_routing(skb, false); +} + +/* + * fast_classifier_update_mark() + * updates the mark for a fast-classifier connection + */ +static void fast_classifier_update_mark(struct sfe_connection_mark *mark, bool is_v4) +{ + struct sfe_connection *conn; + + spin_lock_bh(&sfe_connections_lock); + + conn = fast_classifier_find_conn(&mark->src_ip, &mark->dest_ip, + mark->src_port, mark->dest_port, + mark->protocol, is_v4); + if (conn) { + conn->sic->mark = mark->mark; + } + + spin_unlock_bh(&sfe_connections_lock); +} + +#ifdef CONFIG_NF_CONNTRACK_EVENTS +/* + * fast_classifier_conntrack_event() + * Callback event invoked when a conntrack connection's state changes. + */ +#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS +static int fast_classifier_conntrack_event(struct notifier_block *this, + unsigned long events, void *ptr) +#else +static int fast_classifier_conntrack_event(unsigned int events, struct nf_ct_event *item) +#endif +{ +#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS + struct nf_ct_event *item = ptr; +#endif + struct sfe_connection_destroy sid; + struct nf_conn *ct = item->ct; + struct nf_conntrack_tuple orig_tuple; + struct sfe_connection *conn; + struct fast_classifier_tuple fc_msg; + int offloaded = 0; + bool is_v4; + + /* + * If we don't have a conntrack entry then we're done. + */ + if (unlikely(!ct)) { + DEBUG_WARN("no ct in conntrack event callback\n"); + return NOTIFY_DONE; + } + + /* + * If this is an untracked connection then we can't have any state either. + */ + if (unlikely(nf_ct_is_untracked(ct))) { + DEBUG_TRACE("ignoring untracked conn\n"); + return NOTIFY_DONE; + } + + orig_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; + sid.protocol = (s32)orig_tuple.dst.protonum; + + /* + * Extract information from the conntrack connection. We're only interested + * in nominal connection information (i.e. we're ignoring any NAT information). + */ + if (likely(nf_ct_l3num(ct) == AF_INET)) { + sid.src_ip.ip = (__be32)orig_tuple.src.u3.ip; + sid.dest_ip.ip = (__be32)orig_tuple.dst.u3.ip; + is_v4 = true; + } else if (likely(nf_ct_l3num(ct) == AF_INET6)) { + sid.src_ip.ip6[0] = *((struct sfe_ipv6_addr *)&orig_tuple.src.u3.in6); + sid.dest_ip.ip6[0] = *((struct sfe_ipv6_addr *)&orig_tuple.dst.u3.in6); + is_v4 = false; + } else { + DEBUG_TRACE("ignoring non-IPv4 and non-IPv6 connection\n"); + return NOTIFY_DONE; + } + + switch (sid.protocol) { + case IPPROTO_TCP: + sid.src_port = orig_tuple.src.u.tcp.port; + sid.dest_port = orig_tuple.dst.u.tcp.port; + break; + + case IPPROTO_UDP: + sid.src_port = orig_tuple.src.u.udp.port; + sid.dest_port = orig_tuple.dst.u.udp.port; + break; + + default: + DEBUG_TRACE("unhandled protocol: %d\n", sid.protocol); + return NOTIFY_DONE; + } + + /* + * Check for an updated mark + */ + if ((events & (1 << IPCT_MARK)) && (ct->mark != 0)) { + struct sfe_connection_mark mark; + + mark.protocol = sid.protocol; + mark.src_ip = sid.src_ip; + mark.dest_ip = sid.dest_ip; + mark.src_port = sid.src_port; + mark.dest_port = sid.dest_port; + mark.mark = ct->mark; + + is_v4 ? sfe_ipv4_mark_rule(&mark) : sfe_ipv6_mark_rule(&mark); + fast_classifier_update_mark(&mark, is_v4); + } + + /* + * We're only interested in destroy events at this point + */ + if (unlikely(!(events & (1 << IPCT_DESTROY)))) { + DEBUG_TRACE("ignoring non-destroy event\n"); + return NOTIFY_DONE; + } + + if (is_v4) { + DEBUG_TRACE("Try to clean up: proto: %d src_ip: %pI4 dst_ip: %pI4, src_port: %d, dst_port: %d\n", + sid.protocol, &sid.src_ip, &sid.dest_ip, sid.src_port, sid.dest_port); + } else { + DEBUG_TRACE("Try to clean up: proto: %d src_ip: %pI6 dst_ip: %pI6, src_port: %d, dst_port: %d\n", + sid.protocol, &sid.src_ip, &sid.dest_ip, sid.src_port, sid.dest_port); + } + + spin_lock_bh(&sfe_connections_lock); + + conn = fast_classifier_find_conn(&sid.src_ip, &sid.dest_ip, sid.src_port, sid.dest_port, sid.protocol, is_v4); + if (conn && conn->offloaded) { + if (is_v4) { + fc_msg.ethertype = AF_INET; + fc_msg.src_saddr.in = *((struct in_addr *)&conn->sic->src_ip); + fc_msg.dst_saddr.in = *((struct in_addr *)&conn->sic->dest_ip_xlate); + } else { + fc_msg.ethertype = AF_INET6; + fc_msg.src_saddr.in6 = *((struct in6_addr *)&conn->sic->src_ip); + fc_msg.dst_saddr.in6 = *((struct in6_addr *)&conn->sic->dest_ip_xlate); + } + + fc_msg.proto = conn->sic->protocol; + fc_msg.sport = conn->sic->src_port; + fc_msg.dport = conn->sic->dest_port_xlate; + memcpy(fc_msg.smac, conn->smac, ETH_ALEN); + memcpy(fc_msg.dmac, conn->dmac, ETH_ALEN); + offloaded = 1; + } + + if (conn) { + DEBUG_TRACE("Free connection\n"); + + hash_del(&conn->hl); + sfe_connections_size--; + kfree(conn->sic); + kfree(conn); + } else { + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_CT_DESTROY_MISS); + } + + spin_unlock_bh(&sfe_connections_lock); + + is_v4 ? sfe_ipv4_destroy_rule(&sid) : sfe_ipv6_destroy_rule(&sid); + + if (offloaded) { + fast_classifier_send_genl_msg(FAST_CLASSIFIER_C_DONE, &fc_msg); + } + + return NOTIFY_DONE; +} + +/* + * Netfilter conntrack event system to monitor connection tracking changes + */ +#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS +static struct notifier_block fast_classifier_conntrack_notifier = { + .notifier_call = fast_classifier_conntrack_event, +}; +#else +static struct nf_ct_event_notifier fast_classifier_conntrack_notifier = { + .fcn = fast_classifier_conntrack_event, +}; +#endif +#endif + +/* + * Structure to establish a hook into the post routing netfilter point - this + * will pick up local outbound and packets going from one interface to another. + * + * Note: see include/linux/netfilter_ipv4.h for info related to priority levels. + * We want to examine packets after NAT translation and any ALG processing. + */ +static struct nf_hook_ops fast_classifier_ops_post_routing[] __read_mostly = { + SFE_IPV4_NF_POST_ROUTING_HOOK(__fast_classifier_ipv4_post_routing_hook), + SFE_IPV6_NF_POST_ROUTING_HOOK(__fast_classifier_ipv6_post_routing_hook), +}; + +/* + * fast_classifier_sync_rule() + * Synchronize a connection's state. + */ +static void fast_classifier_sync_rule(struct sfe_connection_sync *sis) +{ + struct nf_conntrack_tuple_hash *h; + struct nf_conntrack_tuple tuple; + struct nf_conn *ct; + SFE_NF_CONN_ACCT(acct); + + /* + * Create a tuple so as to be able to look up a connection + */ + memset(&tuple, 0, sizeof(tuple)); + tuple.src.u.all = (__be16)sis->src_port; + tuple.dst.dir = IP_CT_DIR_ORIGINAL; + tuple.dst.protonum = (u8)sis->protocol; + tuple.dst.u.all = (__be16)sis->dest_port; + + if (sis->is_v6) { + tuple.src.u3.in6 = *((struct in6_addr *)sis->src_ip.ip6); + tuple.dst.u3.in6 = *((struct in6_addr *)sis->dest_ip.ip6); + tuple.src.l3num = AF_INET6; + + DEBUG_TRACE("update connection - p: %d, s: %pI6:%u, d: %pI6:%u\n", + (int)tuple.dst.protonum, + &tuple.src.u3.in6, (unsigned int)ntohs(tuple.src.u.all), + &tuple.dst.u3.in6, (unsigned int)ntohs(tuple.dst.u.all)); + } else { + tuple.src.u3.ip = sis->src_ip.ip; + tuple.dst.u3.ip = sis->dest_ip.ip; + tuple.src.l3num = AF_INET; + + DEBUG_TRACE("update connection - p: %d, s: %pI4:%u, d: %pI4:%u\n", + (int)tuple.dst.protonum, + &tuple.src.u3.ip, (unsigned int)ntohs(tuple.src.u.all), + &tuple.dst.u3.ip, (unsigned int)ntohs(tuple.dst.u.all)); + } + + /* + * Update packet count for ingress on bridge device + */ + if (skip_to_bridge_ingress) { + struct rtnl_link_stats64 nlstats; + nlstats.tx_packets = 0; + nlstats.tx_bytes = 0; + + if (sis->src_dev && IFF_EBRIDGE && + (sis->src_new_packet_count || sis->src_new_byte_count)) { + nlstats.rx_packets = sis->src_new_packet_count; + nlstats.rx_bytes = sis->src_new_byte_count; + spin_lock_bh(&sfe_connections_lock); + br_dev_update_stats(sis->src_dev, &nlstats); + spin_unlock_bh(&sfe_connections_lock); + } + if (sis->dest_dev && IFF_EBRIDGE && + (sis->dest_new_packet_count || sis->dest_new_byte_count)) { + nlstats.rx_packets = sis->dest_new_packet_count; + nlstats.rx_bytes = sis->dest_new_byte_count; + spin_lock_bh(&sfe_connections_lock); + br_dev_update_stats(sis->dest_dev, &nlstats); + spin_unlock_bh(&sfe_connections_lock); + } + } + + /* + * Look up conntrack connection + */ + h = nf_conntrack_find_get(&init_net, SFE_NF_CT_DEFAULT_ZONE, &tuple); + if (unlikely(!h)) { + DEBUG_TRACE("no connection found\n"); + return; + } + + ct = nf_ct_tuplehash_to_ctrack(h); + NF_CT_ASSERT(ct->timeout.data == (unsigned long)ct); + + /* + * Only update if this is not a fixed timeout + */ + if (!test_bit(IPS_FIXED_TIMEOUT_BIT, &ct->status)) { + spin_lock_bh(&ct->lock); + ct->timeout.expires += sis->delta_jiffies; + spin_unlock_bh(&ct->lock); + } + + acct = nf_conn_acct_find(ct); + if (acct) { + spin_lock_bh(&ct->lock); + atomic64_add(sis->src_new_packet_count, &SFE_ACCT_COUNTER(acct)[IP_CT_DIR_ORIGINAL].packets); + atomic64_add(sis->src_new_byte_count, &SFE_ACCT_COUNTER(acct)[IP_CT_DIR_ORIGINAL].bytes); + atomic64_add(sis->dest_new_packet_count, &SFE_ACCT_COUNTER(acct)[IP_CT_DIR_REPLY].packets); + atomic64_add(sis->dest_new_byte_count, &SFE_ACCT_COUNTER(acct)[IP_CT_DIR_REPLY].bytes); + spin_unlock_bh(&ct->lock); + } + + switch (sis->protocol) { + case IPPROTO_TCP: + spin_lock_bh(&ct->lock); + if (ct->proto.tcp.seen[0].td_maxwin < sis->src_td_max_window) { + ct->proto.tcp.seen[0].td_maxwin = sis->src_td_max_window; + } + if ((s32)(ct->proto.tcp.seen[0].td_end - sis->src_td_end) < 0) { + ct->proto.tcp.seen[0].td_end = sis->src_td_end; + } + if ((s32)(ct->proto.tcp.seen[0].td_maxend - sis->src_td_max_end) < 0) { + ct->proto.tcp.seen[0].td_maxend = sis->src_td_max_end; + } + if (ct->proto.tcp.seen[1].td_maxwin < sis->dest_td_max_window) { + ct->proto.tcp.seen[1].td_maxwin = sis->dest_td_max_window; + } + if ((s32)(ct->proto.tcp.seen[1].td_end - sis->dest_td_end) < 0) { + ct->proto.tcp.seen[1].td_end = sis->dest_td_end; + } + if ((s32)(ct->proto.tcp.seen[1].td_maxend - sis->dest_td_max_end) < 0) { + ct->proto.tcp.seen[1].td_maxend = sis->dest_td_max_end; + } + spin_unlock_bh(&ct->lock); + break; + } + + /* + * Release connection + */ + nf_ct_put(ct); +} + +/* + * fast_classifier_device_event() + */ +static int fast_classifier_device_event(struct notifier_block *this, unsigned long event, void *ptr) +{ + struct net_device *dev = SFE_DEV_EVENT_PTR(ptr); + + if (dev && (event == NETDEV_DOWN)) { + sfe_ipv4_destroy_all_rules_for_dev(dev); + sfe_ipv6_destroy_all_rules_for_dev(dev); + } + + return NOTIFY_DONE; +} + +/* + * fast_classifier_inet_event() + */ +static int fast_classifier_inet_event(struct notifier_block *this, unsigned long event, void *ptr) +{ + struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev; + + if (dev && (event == NETDEV_DOWN)) { + sfe_ipv4_destroy_all_rules_for_dev(dev); + } + + return NOTIFY_DONE; +} + +/* + * fast_classifier_inet6_event() + */ +static int fast_classifier_inet6_event(struct notifier_block *this, unsigned long event, void *ptr) +{ + struct net_device *dev = ((struct inet6_ifaddr *)ptr)->idev->dev; + + if (dev && (event == NETDEV_DOWN)) { + sfe_ipv6_destroy_all_rules_for_dev(dev); + } + + return NOTIFY_DONE; +} + +/* + * fast_classifier_get_offload_at_pkts() + */ +static ssize_t fast_classifier_get_offload_at_pkts(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", offload_at_pkts); +} + +/* + * fast_classifier_set_offload_at_pkts() + */ +static ssize_t fast_classifier_set_offload_at_pkts(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + long new; + int ret; + + ret = kstrtol(buf, 0, &new); + if (ret == -EINVAL || ((int)new != new)) + return -EINVAL; + + offload_at_pkts = new; + + return size; +} + +/* + * fast_classifier_get_debug_info() + */ +static ssize_t fast_classifier_get_debug_info(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + size_t len = 0; + struct sfe_connection *conn; + u32 i; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)) + struct hlist_node *node; +#endif + + spin_lock_bh(&sfe_connections_lock); + len += scnprintf(buf, PAGE_SIZE - len, "size=%d offload=%d offload_no_match=%d" + " offloaded=%d done=%d offloaded_fail=%d done_fail=%d\n", + sfe_connections_size, + atomic_read(&offload_msgs), + atomic_read(&offload_no_match_msgs), + atomic_read(&offloaded_msgs), + atomic_read(&done_msgs), + atomic_read(&offloaded_fail_msgs), + atomic_read(&done_fail_msgs)); + sfe_hash_for_each(fc_conn_ht, i, node, conn, hl) { + len += scnprintf(buf + len, PAGE_SIZE - len, + (conn->is_v4 ? "o=%d, p=%d [%pM]:%pI4:%u %pI4:%u:[%pM] m=%08x h=%d\n" : "o=%d, p=%d [%pM]:%pI6:%u %pI6:%u:[%pM] m=%08x h=%d\n"), + conn->offloaded, + conn->sic->protocol, + conn->sic->src_mac, + &conn->sic->src_ip, + conn->sic->src_port, + &conn->sic->dest_ip, + conn->sic->dest_port, + conn->sic->dest_mac_xlate, + conn->sic->mark, + conn->hits); + } + spin_unlock_bh(&sfe_connections_lock); + + return len; +} + +/* + * fast_classifier_get_skip_bridge_ingress() + */ +static ssize_t fast_classifier_get_skip_bridge_ingress(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", skip_to_bridge_ingress); +} + +/* + * fast_classifier_set_skip_bridge_ingress() + */ +static ssize_t fast_classifier_set_skip_bridge_ingress(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + long new; + int ret; + + ret = kstrtol(buf, 0, &new); + if (ret == -EINVAL || ((int)new != new)) + return -EINVAL; + + skip_to_bridge_ingress = new ? 1 : 0; + + return size; +} + +/* + * fast_classifier_get_exceptions + * dump exception counters + */ +static ssize_t fast_classifier_get_exceptions(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int idx, len; + struct fast_classifier *sc = &__sc; + + spin_lock_bh(&sc->lock); + for (len = 0, idx = 0; idx < FAST_CL_EXCEPTION_MAX; idx++) { + if (sc->exceptions[idx]) { + len += snprintf(buf + len, (ssize_t)(PAGE_SIZE - len), "%s = %d\n", fast_classifier_exception_events_string[idx], sc->exceptions[idx]); + } + } + spin_unlock_bh(&sc->lock); + + return len; +} + +/* + * sysfs attributes. + */ +static const struct device_attribute fast_classifier_offload_at_pkts_attr = + __ATTR(offload_at_pkts, S_IWUSR | S_IRUGO, fast_classifier_get_offload_at_pkts, fast_classifier_set_offload_at_pkts); +static const struct device_attribute fast_classifier_debug_info_attr = + __ATTR(debug_info, S_IRUGO, fast_classifier_get_debug_info, NULL); +static const struct device_attribute fast_classifier_skip_bridge_ingress = + __ATTR(skip_to_bridge_ingress, S_IWUSR | S_IRUGO, fast_classifier_get_skip_bridge_ingress, fast_classifier_set_skip_bridge_ingress); +static const struct device_attribute fast_classifier_exceptions_attr = + __ATTR(exceptions, S_IRUGO, fast_classifier_get_exceptions, NULL); + +/* + * fast_classifier_init() + */ +static int __init fast_classifier_init(void) +{ + struct fast_classifier *sc = &__sc; + int result = -1; + + printk(KERN_ALERT "fast-classifier: starting up\n"); + DEBUG_INFO("SFE CM init\n"); + + hash_init(fc_conn_ht); + + /* + * Create sys/fast_classifier + */ + sc->sys_fast_classifier = kobject_create_and_add("fast_classifier", NULL); + if (!sc->sys_fast_classifier) { + DEBUG_ERROR("failed to register fast_classifier\n"); + goto exit1; + } + + result = sysfs_create_file(sc->sys_fast_classifier, &fast_classifier_offload_at_pkts_attr.attr); + if (result) { + DEBUG_ERROR("failed to register offload at pkgs: %d\n", result); + goto exit2; + } + + result = sysfs_create_file(sc->sys_fast_classifier, &fast_classifier_debug_info_attr.attr); + if (result) { + DEBUG_ERROR("failed to register debug dev: %d\n", result); + sysfs_remove_file(sc->sys_fast_classifier, &fast_classifier_offload_at_pkts_attr.attr); + goto exit2; + } + + result = sysfs_create_file(sc->sys_fast_classifier, &fast_classifier_skip_bridge_ingress.attr); + if (result) { + DEBUG_ERROR("failed to register skip bridge on ingress: %d\n", result); + sysfs_remove_file(sc->sys_fast_classifier, &fast_classifier_offload_at_pkts_attr.attr); + sysfs_remove_file(sc->sys_fast_classifier, &fast_classifier_debug_info_attr.attr); + goto exit2; + } + + result = sysfs_create_file(sc->sys_fast_classifier, &fast_classifier_exceptions_attr.attr); + if (result) { + DEBUG_ERROR("failed to register exceptions file: %d\n", result); + sysfs_remove_file(sc->sys_fast_classifier, &fast_classifier_offload_at_pkts_attr.attr); + sysfs_remove_file(sc->sys_fast_classifier, &fast_classifier_debug_info_attr.attr); + sysfs_remove_file(sc->sys_fast_classifier, &fast_classifier_skip_bridge_ingress.attr); + goto exit2; + } + + sc->dev_notifier.notifier_call = fast_classifier_device_event; + sc->dev_notifier.priority = 1; + register_netdevice_notifier(&sc->dev_notifier); + + sc->inet_notifier.notifier_call = fast_classifier_inet_event; + sc->inet_notifier.priority = 1; + register_inetaddr_notifier(&sc->inet_notifier); + + sc->inet6_notifier.notifier_call = fast_classifier_inet6_event; + sc->inet6_notifier.priority = 1; + register_inet6addr_notifier(&sc->inet6_notifier); + + /* + * Register our netfilter hooks. + */ + result = nf_register_hooks(fast_classifier_ops_post_routing, ARRAY_SIZE(fast_classifier_ops_post_routing)); + if (result < 0) { + DEBUG_ERROR("can't register nf post routing hook: %d\n", result); + goto exit3; + } + +#ifdef CONFIG_NF_CONNTRACK_EVENTS + /* + * Register a notifier hook to get fast notifications of expired connections. + */ + result = nf_conntrack_register_notifier(&init_net, &fast_classifier_conntrack_notifier); + if (result < 0) { + DEBUG_ERROR("can't register nf notifier hook: %d\n", result); + goto exit4; + } +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)) + result = genl_register_family_with_ops_groups(&fast_classifier_gnl_family, + fast_classifier_gnl_ops, + fast_classifier_genl_mcgrp); + if (result) { + DEBUG_ERROR("failed to register genl ops: %d\n", result); + goto exit5; + } +#else + result = genl_register_family(&fast_classifier_gnl_family); + if (result) { + printk(KERN_CRIT "unable to register genl family\n"); + goto exit5; + } + + result = genl_register_ops(&fast_classifier_gnl_family, fast_classifier_gnl_ops); + if (result) { + printk(KERN_CRIT "unable to register ops\n"); + goto exit6; + } + + result = genl_register_mc_group(&fast_classifier_gnl_family, + fast_classifier_genl_mcgrp); + if (result) { + printk(KERN_CRIT "unable to register multicast group\n"); + goto exit6; + } +#endif + + printk(KERN_ALERT "fast-classifier: registered\n"); + + spin_lock_init(&sc->lock); + + /* + * Hook the receive path in the network stack. + */ + BUG_ON(athrs_fast_nat_recv); + RCU_INIT_POINTER(athrs_fast_nat_recv, fast_classifier_recv); + + /* + * Hook the shortcut sync callback. + */ + sfe_ipv4_register_sync_rule_callback(fast_classifier_sync_rule); + sfe_ipv6_register_sync_rule_callback(fast_classifier_sync_rule); + return 0; + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)) +exit6: + genl_unregister_family(&fast_classifier_gnl_family); +#endif + +exit5: +#ifdef CONFIG_NF_CONNTRACK_EVENTS + nf_conntrack_unregister_notifier(&init_net, &fast_classifier_conntrack_notifier); + +exit4: +#endif + nf_unregister_hooks(fast_classifier_ops_post_routing, ARRAY_SIZE(fast_classifier_ops_post_routing)); + +exit3: + unregister_inetaddr_notifier(&sc->inet_notifier); + unregister_inet6addr_notifier(&sc->inet6_notifier); + unregister_netdevice_notifier(&sc->dev_notifier); + sysfs_remove_file(sc->sys_fast_classifier, &fast_classifier_offload_at_pkts_attr.attr); + sysfs_remove_file(sc->sys_fast_classifier, &fast_classifier_debug_info_attr.attr); + sysfs_remove_file(sc->sys_fast_classifier, &fast_classifier_skip_bridge_ingress.attr); + sysfs_remove_file(sc->sys_fast_classifier, &fast_classifier_exceptions_attr.attr); + +exit2: + kobject_put(sc->sys_fast_classifier); + +exit1: + return result; +} + +/* + * fast_classifier_exit() + */ +static void __exit fast_classifier_exit(void) +{ + struct fast_classifier *sc = &__sc; + int result = -1; + + DEBUG_INFO("SFE CM exit\n"); + printk(KERN_ALERT "fast-classifier: shutting down\n"); + + /* + * Unregister our sync callback. + */ + sfe_ipv4_register_sync_rule_callback(NULL); + sfe_ipv6_register_sync_rule_callback(NULL); + + /* + * Unregister our receive callback. + */ + RCU_INIT_POINTER(athrs_fast_nat_recv, NULL); + + /* + * Wait for all callbacks to complete. + */ + rcu_barrier(); + + /* + * Destroy all connections. + */ + sfe_ipv4_destroy_all_rules_for_dev(NULL); + sfe_ipv6_destroy_all_rules_for_dev(NULL); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)) + result = genl_unregister_ops(&fast_classifier_gnl_family, fast_classifier_gnl_ops); + if (result != 0) { + printk(KERN_CRIT "Unable to unreigster genl_ops\n"); + } +#endif + + result = genl_unregister_family(&fast_classifier_gnl_family); + if (result != 0) { + printk(KERN_CRIT "Unable to unreigster genl_family\n"); + } + +#ifdef CONFIG_NF_CONNTRACK_EVENTS + nf_conntrack_unregister_notifier(&init_net, &fast_classifier_conntrack_notifier); + +#endif + nf_unregister_hooks(fast_classifier_ops_post_routing, ARRAY_SIZE(fast_classifier_ops_post_routing)); + + unregister_inet6addr_notifier(&sc->inet6_notifier); + unregister_inetaddr_notifier(&sc->inet_notifier); + unregister_netdevice_notifier(&sc->dev_notifier); + + kobject_put(sc->sys_fast_classifier); +} + +module_init(fast_classifier_init) +module_exit(fast_classifier_exit) + +MODULE_DESCRIPTION("Shortcut Forwarding Engine - Connection Manager"); +MODULE_LICENSE("Dual BSD/GPL"); + diff --git a/fast-classifier/src/fast-classifier.h b/fast-classifier/fast-classifier.h old mode 100755 new mode 100644 similarity index 100% rename from fast-classifier/src/fast-classifier.h rename to fast-classifier/fast-classifier.h diff --git a/fast-classifier/src/nl_classifier_test.c b/fast-classifier/nl_classifier_test.c old mode 100755 new mode 100644 similarity index 100% rename from fast-classifier/src/nl_classifier_test.c rename to fast-classifier/nl_classifier_test.c diff --git a/fast-classifier/src/userspace_example.c b/fast-classifier/userspace_example.c old mode 100755 new mode 100644 similarity index 100% rename from fast-classifier/src/userspace_example.c rename to fast-classifier/userspace_example.c diff --git a/glorytun-udp/init b/glorytun-udp/init index e9f7caf7c..33a86b76d 100755 --- a/glorytun-udp/init +++ b/glorytun-udp/init @@ -56,6 +56,8 @@ start_instance() { _log "starting ${PROG_NAME} ${1} instance $*" + host=$(resolveip $host) + if [ "$mode" = "to" ]; then bind="bind from addr :: port 5000 to addr $host port $port" else diff --git a/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js b/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js index 5ece96be2..73eaa4a22 100755 --- a/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +++ b/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js @@ -145,14 +145,14 @@ return view.extend({ o = s.taboption('general', form.Flag, 'masq', _('Masquerading')); o.editable = true; - - o = s.taboption('general', form.Flag, 'fullcone', _('Full Cone')); + o = s.taboption('general', form.Flag, 'fullcone', _('Full Cone')); o.editable = true; - o.depends('masq', '1'); - + o.depends('masq', '1'); + o = s.taboption('general', form.Flag, 'mtu_fix', _('MSS clamp')); + o.modalonly = true; o = s.taboption('general', form.Flag, 'mtu_fix', _('MSS clamping')); o.modalonly = true; - + o = s.taboption('general', widgets.NetworkSelect, 'network', _('Covered networks')); o.modalonly = true; o.multiple = true; diff --git a/luci-app-mptcp/po/de/mptcp.po b/luci-app-mptcp/po/de/mptcp.po index 9b8c194ab..a67d0bbce 100755 --- a/luci-app-mptcp/po/de/mptcp.po +++ b/luci-app-mptcp/po/de/mptcp.po @@ -37,11 +37,11 @@ msgstr "" "Prüfung auf transparenten Transport von MPTCP-Paketen zwischen Anschluss und " "Server." -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:40 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:52 msgid "Congestion Control" msgstr "Überlauf-Steuerung" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:69 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:97 msgid "Consecutive segments that should be sent for round robin" msgstr "" @@ -51,7 +51,7 @@ msgstr "" msgid "Current:" msgstr "derzeit:" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:40 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:52 #, fuzzy msgid "Default is cubic" msgstr "Voreinstellung ist 'bbr'" @@ -76,11 +76,11 @@ msgstr "Fehler" msgid "Established connections" msgstr "aufgebaute Verbindungen" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:63 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:91 msgid "Fill the congestion window on all subflows for round robin" msgstr "" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:46 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:74 msgid "Fullmesh subflows for each pair of IP addresses" msgstr "" "Datenströme im vollvermaschter Betrieb für die jeweiligen Gegegenstellen-" @@ -105,7 +105,7 @@ msgstr "Ankommend:" msgid "Interface" msgstr "Schnittstelle" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:75 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:104 msgid "Interfaces Settings" msgstr "Anschluss-Einstellungen" @@ -150,11 +150,11 @@ msgid "Multipath Debug" msgstr "Mehrfachausbreitungspfad-Analyse" #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:12 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:76 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:108 msgid "Multipath TCP" msgstr "Multipath-TCP" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:37 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:42 msgid "Multipath TCP SYN retries" msgstr "Multipath TCP SYN Wiederholungen" @@ -166,11 +166,17 @@ msgstr "Multipath TCP Prüfummen" msgid "Multipath TCP path-manager" msgstr "Multipath TCP Pfadkontrolle" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:29 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:31 msgid "Multipath TCP scheduler" msgstr "Multpath TCP Priorisierungskontrolle" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:27 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:47 +#, fuzzy +#| msgid "Multipath TCP" +msgid "Multipath TCP version" +msgstr "Multipath-TCP" + +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:28 msgid "Netlink" msgstr "Netlink-Layer" @@ -184,7 +190,7 @@ msgstr "" "tcp.org/pmwiki.php/Users/ConfigureMPTCP'>http://multipath-tcp.org/pmwiki.php/" "Users/ConfigureMPTCP (english)." -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:76 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:108 msgid "One interface must be set as master" msgstr "Ein Anschluss muss als 'primär' defininiert werden." @@ -200,7 +206,7 @@ msgstr "Abgehend:" msgid "Peak:" msgstr "Spitze:" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:52 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:80 msgid "Re-create fullmesh subflows after a timeout" msgstr "Wiederverbindungs-Wartezeit der Vollvermaschungs-Verbindungen" @@ -217,6 +223,12 @@ msgstr "Einstellungen" msgid "Test" msgstr "Test" +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:69 +msgid "" +"The number of MPTCP-level retransmission intervals with no traffic and " +"pending outstanding data on a given subflow required to declare it stale" +msgstr "" + #: luci-app-mptcp/luasrc/view/mptcp/multipath.htm:914 msgid "Upload:" msgstr "Upstream:" @@ -228,36 +240,36 @@ msgstr "Upstream:" msgid "Waiting for command to complete..." msgstr "Warte auf Abschluss der Aufgaben" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:80 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:112 msgid "backup" msgstr "Sicherung" #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:22 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:30 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:32 msgid "default" msgstr "Voreinstellung" #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:14 #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:17 #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:20 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:54 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:65 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:82 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:93 msgid "disable" msgstr "ausschalten" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:78 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:110 msgid "disabled" msgstr "aus" #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:13 #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:16 #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:19 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:53 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:64 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:81 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:92 msgid "enable" msgstr "anschalten" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:77 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:109 msgid "enabled" msgstr "an" @@ -295,14 +307,26 @@ msgstr "kBytes/s" msgid "kbit/s" msgstr "kBit/s" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:79 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:111 msgid "master" msgstr "primär" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:57 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:85 msgid "ndiffports subflows number" msgstr "ndiff-Ports Verbindungs-Nummer" +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:64 +msgid "" +"specifies the maximum number of ADD_ADDR suboptions accepted for each MPTCP " +"connection" +msgstr "" + +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:59 +msgid "" +"specifies the maximum number of additional subflows allowed for each MPTCP " +"connection" +msgstr "" + #~ msgid "BLEST" #~ msgstr "Blockierungsvorhersage-Betrieb" diff --git a/luci-app-mptcp/po/fr/mptcp.po b/luci-app-mptcp/po/fr/mptcp.po index 146ec4466..b47876f87 100755 --- a/luci-app-mptcp/po/fr/mptcp.po +++ b/luci-app-mptcp/po/fr/mptcp.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2021-04-30 16:16+0000\n" +"PO-Revision-Date: 2022-08-10 18:51+0000\n" "Last-Translator: Weblate Admin \n" "Language-Team: French \n" @@ -11,7 +11,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 4.5.2\n" +"X-Generator: Weblate 4.10.1\n" #: luci-app-mptcp/luasrc/view/mptcp/multipath.htm:775 msgid "(%d minute window, %d second interval)" @@ -38,13 +38,13 @@ msgstr "Bande passante" msgid "Check if MPTCP between interface and server is working." msgstr "Vérifiez si MPTCP entre l'interface et le serveur fonctionne." -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:40 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:52 msgid "Congestion Control" msgstr "Contrôle de la congestion" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:69 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:97 msgid "Consecutive segments that should be sent for round robin" -msgstr "" +msgstr "Segments consécutifs à envoyer pour round robin" #: luci-app-mptcp/luasrc/view/mptcp/multipath.htm:311 #: luci-app-mptcp/luasrc/view/mptcp/multipath.htm:314 @@ -52,7 +52,7 @@ msgstr "" msgid "Current:" msgstr "Actuellement :" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:40 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:52 msgid "Default is cubic" msgstr "La valeur par défaut est cubic" @@ -75,11 +75,12 @@ msgstr "Erreur" msgid "Established connections" msgstr "Connexions établies" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:63 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:91 msgid "Fill the congestion window on all subflows for round robin" msgstr "" +"Remplir la fenêtre de congestion de tous les sous-flux pour round robin" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:46 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:74 msgid "Fullmesh subflows for each pair of IP addresses" msgstr "Sous-flux Fullmesh pour chaque paire d'adresses IP" @@ -105,7 +106,7 @@ msgstr "Entrant :" msgid "Interface" msgstr "Interface" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:75 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:104 msgid "Interfaces Settings" msgstr "Paramètres des interfaces" @@ -150,11 +151,11 @@ msgid "Multipath Debug" msgstr "Débogage multipath" #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:12 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:76 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:108 msgid "Multipath TCP" msgstr "Multipath TCP" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:37 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:42 msgid "Multipath TCP SYN retries" msgstr "Tentatives Multipath TCP SYN" @@ -166,11 +167,15 @@ msgstr "Somme de contrôle Multipath TCP" msgid "Multipath TCP path-manager" msgstr "Gestionnaire de chemins Multipath TCP" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:29 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:31 msgid "Multipath TCP scheduler" msgstr "Planificateur Multipath TCP" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:27 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:47 +msgid "Multipath TCP version" +msgstr "Version de Multipath TCP" + +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:28 msgid "Netlink" msgstr "Netlink" @@ -184,7 +189,7 @@ msgstr "" "php/Users/ConfigureMPTCP'>http://multipath-tcp.org/pmwiki.php/Users/" "ConfigureMPTCP pour de l'aide." -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:76 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:108 msgid "One interface must be set as master" msgstr "Une interface doit être configuré en temps que maître" @@ -200,7 +205,7 @@ msgstr "Sortant :" msgid "Peak:" msgstr "Pointe :" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:52 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:80 msgid "Re-create fullmesh subflows after a timeout" msgstr "Recréer les sous-flux fullmesh après le délai d'expiration" @@ -215,7 +220,15 @@ msgstr "Paramètres" #: luci-app-mptcp/luasrc/view/mptcp/mptcp_check.htm:65 msgid "Test" +msgstr "Essai" + +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:69 +msgid "" +"The number of MPTCP-level retransmission intervals with no traffic and " +"pending outstanding data on a given subflow required to declare it stale" msgstr "" +"Le nombre d'intervalles de retransmission au niveau de MPTCP sans trafic et " +"en attente de données sur un sous-flux requis pour le déclarer obsolète" #: luci-app-mptcp/luasrc/view/mptcp/multipath.htm:914 msgid "Upload:" @@ -228,36 +241,36 @@ msgstr "Envoie :" msgid "Waiting for command to complete..." msgstr "En attente de la réponse de la commande..." -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:80 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:112 msgid "backup" msgstr "remplaçant" #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:22 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:30 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:32 msgid "default" msgstr "Défaut" #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:14 #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:17 #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:20 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:54 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:65 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:82 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:93 msgid "disable" msgstr "Désactive" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:78 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:110 msgid "disabled" msgstr "Désactivé" #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:13 #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:16 #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:19 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:53 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:64 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:81 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:92 msgid "enable" msgstr "Active" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:77 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:109 msgid "enabled" msgstr "Activé" @@ -295,14 +308,30 @@ msgstr "Ko/s" msgid "kbit/s" msgstr "kbit/s" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:79 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:111 msgid "master" msgstr "maître" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:57 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:85 msgid "ndiffports subflows number" msgstr "Nombre de sous-flux ndiffports" +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:64 +msgid "" +"specifies the maximum number of ADD_ADDR suboptions accepted for each MPTCP " +"connection" +msgstr "" +"spécifie le nombre maximum de sous-options ADD_ADDR acceptées pour chaque " +"connexion MPTCP" + +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:59 +msgid "" +"specifies the maximum number of additional subflows allowed for each MPTCP " +"connection" +msgstr "" +"spécifie le nombre maximum de sous-flux ADD_ADDR acceptées pour chaque " +"connexion MPTCP" + #~ msgid "binder" #~ msgstr "lier" diff --git a/luci-app-mptcp/po/it/mptcp.po b/luci-app-mptcp/po/it/mptcp.po index 048ef35ef..78e5a223e 100755 --- a/luci-app-mptcp/po/it/mptcp.po +++ b/luci-app-mptcp/po/it/mptcp.po @@ -35,11 +35,11 @@ msgstr "Larghezza banda" msgid "Check if MPTCP between interface and server is working." msgstr "Controlla se MPTCP tra l'interfaccia e il server funziona." -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:40 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:52 msgid "Congestion Control" msgstr "Controllo della congestione" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:69 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:97 msgid "Consecutive segments that should be sent for round robin" msgstr "" @@ -49,7 +49,7 @@ msgstr "" msgid "Current:" msgstr "Corrente:" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:40 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:52 #, fuzzy msgid "Default is cubic" msgstr "L'impostazione predefinita è bbr" @@ -74,11 +74,11 @@ msgstr "Errore" msgid "Established connections" msgstr "Connessioni stabilite" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:63 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:91 msgid "Fill the congestion window on all subflows for round robin" msgstr "" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:46 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:74 msgid "Fullmesh subflows for each pair of IP addresses" msgstr "Flussi secondari fullmesh per ogni coppia di indirizzi IP" @@ -101,7 +101,7 @@ msgstr "In entrata:" msgid "Interface" msgstr "Interfaccia" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:75 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:104 msgid "Interfaces Settings" msgstr "Impostazioni delle interfacce" @@ -146,11 +146,11 @@ msgid "Multipath Debug" msgstr "Debug multipath" #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:12 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:76 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:108 msgid "Multipath TCP" msgstr "Multipath TCP" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:37 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:42 msgid "Multipath TCP SYN retries" msgstr "Multipath TCP SYN riprova" @@ -162,11 +162,17 @@ msgstr "Multipath TCP checksum" msgid "Multipath TCP path-manager" msgstr "Multipath TCP path-manager" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:29 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:31 msgid "Multipath TCP scheduler" msgstr "Multipath TCP scheduler" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:27 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:47 +#, fuzzy +#| msgid "Multipath TCP" +msgid "Multipath TCP version" +msgstr "Multipath TCP" + +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:28 msgid "Netlink" msgstr "Netlink" @@ -177,7 +183,7 @@ msgid "" "ConfigureMPTCP for help." msgstr "" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:76 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:108 msgid "One interface must be set as master" msgstr "Un'interfaccia deve essere impostata come master" @@ -193,7 +199,7 @@ msgstr "Upload:" msgid "Peak:" msgstr "Picco:" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:52 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:80 msgid "Re-create fullmesh subflows after a timeout" msgstr "Ricrea i flussi secondari fullmesh dopo un timeout" @@ -210,6 +216,12 @@ msgstr "Impostazioni" msgid "Test" msgstr "Test" +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:69 +msgid "" +"The number of MPTCP-level retransmission intervals with no traffic and " +"pending outstanding data on a given subflow required to declare it stale" +msgstr "" + #: luci-app-mptcp/luasrc/view/mptcp/multipath.htm:914 msgid "Upload:" msgstr "Upload:" @@ -221,36 +233,36 @@ msgstr "Upload:" msgid "Waiting for command to complete..." msgstr "In attesa del completamento del comando ..." -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:80 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:112 msgid "backup" msgstr "backup" #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:22 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:30 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:32 msgid "default" msgstr "predefinito" #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:14 #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:17 #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:20 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:54 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:65 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:82 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:93 msgid "disable" msgstr "disabilita" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:78 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:110 msgid "disabled" msgstr "disabilitato" #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:13 #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:16 #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:19 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:53 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:64 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:81 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:92 msgid "enable" msgstr "Attivare" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:77 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:109 msgid "enabled" msgstr "Abilitato" @@ -288,14 +300,26 @@ msgstr "kB/s" msgid "kbit/s" msgstr "kbit/s" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:79 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:111 msgid "master" msgstr "Principale" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:57 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:85 msgid "ndiffports subflows number" msgstr "ndiffports subflows number" +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:64 +msgid "" +"specifies the maximum number of ADD_ADDR suboptions accepted for each MPTCP " +"connection" +msgstr "" + +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:59 +msgid "" +"specifies the maximum number of additional subflows allowed for each MPTCP " +"connection" +msgstr "" + #~ msgid "BLEST" #~ msgstr "BLEST" diff --git a/luci-app-mptcp/po/oc/mptcp.po b/luci-app-mptcp/po/oc/mptcp.po index 3a8ffd4f4..f9bd5bda5 100755 --- a/luci-app-mptcp/po/oc/mptcp.po +++ b/luci-app-mptcp/po/oc/mptcp.po @@ -35,11 +35,11 @@ msgstr "Benda passanta" msgid "Check if MPTCP between interface and server is working." msgstr "Verificar se MPTCP entre l‘interfàcia e lo servidor fonciona." -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:40 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:52 msgid "Congestion Control" msgstr "Contraròtle de congestion" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:69 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:97 msgid "Consecutive segments that should be sent for round robin" msgstr "" @@ -49,7 +49,7 @@ msgstr "" msgid "Current:" msgstr "Actualament :" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:40 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:52 #, fuzzy msgid "Default is cubic" msgstr "Per defaut bbr" @@ -74,11 +74,11 @@ msgstr "Error" msgid "Established connections" msgstr "Connexions establidas" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:63 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:91 msgid "Fill the congestion window on all subflows for round robin" msgstr "" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:46 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:74 msgid "Fullmesh subflows for each pair of IP addresses" msgstr "Jos flux Fullmesh per cada parelh d’adreças IP" @@ -101,7 +101,7 @@ msgstr "Dintrant :" msgid "Interface" msgstr "Interfàcia" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:75 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:104 msgid "Interfaces Settings" msgstr "Paramètres de las interfàcias" @@ -146,11 +146,11 @@ msgid "Multipath Debug" msgstr "Desbugatge multipath" #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:12 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:76 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:108 msgid "Multipath TCP" msgstr "Multipath TCP" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:37 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:42 msgid "Multipath TCP SYN retries" msgstr "Ensages Multipath TCP SYN" @@ -162,11 +162,17 @@ msgstr "Sòma de contraròtle Multipath TCP" msgid "Multipath TCP path-manager" msgstr "Gestionari dels camins Multipath TCP" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:29 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:31 msgid "Multipath TCP scheduler" msgstr "Planificator Multipath TCP" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:27 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:47 +#, fuzzy +#| msgid "Multipath TCP" +msgid "Multipath TCP version" +msgstr "Multipath TCP" + +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:28 msgid "Netlink" msgstr "Ligam ret" @@ -180,7 +186,7 @@ msgstr "" "Users/ConfigureMPTCP'>http://multipath-tcp.org/pmwiki.php/Users/" "ConfigureMPTCP per d’ajuda." -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:76 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:108 msgid "One interface must be set as master" msgstr "Una interfàcia deu èsser configurada coma principala" @@ -196,7 +202,7 @@ msgstr "Sortent :" msgid "Peak:" msgstr "Punta :" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:52 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:80 msgid "Re-create fullmesh subflows after a timeout" msgstr "Tornar crear los jos-flus fullmesh aprèp lo relambi d’expiracion" @@ -213,6 +219,12 @@ msgstr "Paramètres" msgid "Test" msgstr "Pròva" +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:69 +msgid "" +"The number of MPTCP-level retransmission intervals with no traffic and " +"pending outstanding data on a given subflow required to declare it stale" +msgstr "" + #: luci-app-mptcp/luasrc/view/mptcp/multipath.htm:914 msgid "Upload:" msgstr "Mandadís :" @@ -224,36 +236,36 @@ msgstr "Mandadís :" msgid "Waiting for command to complete..." msgstr "En espèra d’una responsa de la comanda..." -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:80 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:112 msgid "backup" msgstr "subordinat" #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:22 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:30 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:32 msgid "default" msgstr "Defaut" #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:14 #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:17 #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:20 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:54 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:65 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:82 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:93 msgid "disable" msgstr "desactivar" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:78 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:110 msgid "disabled" msgstr "desactivat" #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:13 #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:16 #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:19 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:53 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:64 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:81 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:92 msgid "enable" msgstr "Activar" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:77 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:109 msgid "enabled" msgstr "Activat" @@ -291,14 +303,26 @@ msgstr "kB/s" msgid "kbit/s" msgstr "kbit/s" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:79 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:111 msgid "master" msgstr "màger" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:57 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:85 msgid "ndiffports subflows number" msgstr "Nombre de jos-flux ndiffports" +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:64 +msgid "" +"specifies the maximum number of ADD_ADDR suboptions accepted for each MPTCP " +"connection" +msgstr "" + +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:59 +msgid "" +"specifies the maximum number of additional subflows allowed for each MPTCP " +"connection" +msgstr "" + #, fuzzy #~ msgid "BLEST" #~ msgstr "BLEST" diff --git a/luci-app-mptcp/po/ru/mptcp.po b/luci-app-mptcp/po/ru/mptcp.po index 721602f75..bdd6ac158 100644 --- a/luci-app-mptcp/po/ru/mptcp.po +++ b/luci-app-mptcp/po/ru/mptcp.po @@ -36,11 +36,11 @@ msgstr "Пропускная способность" msgid "Check if MPTCP between interface and server is working." msgstr "Проверьте, работает ли MPTCP между интерфейсом и сервером." -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:40 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:52 msgid "Congestion Control" msgstr "Контроль перегрузки" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:69 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:97 msgid "Consecutive segments that should be sent for round robin" msgstr "Последовательные сегменты, которые следует отправлять для round-robin" @@ -50,7 +50,7 @@ msgstr "Последовательные сегменты, которые сле msgid "Current:" msgstr "Текущая:" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:40 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:52 msgid "Default is cubic" msgstr "По умолчанию кубический" @@ -73,11 +73,11 @@ msgstr "Ошибка" msgid "Established connections" msgstr "Установленные соединения" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:63 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:91 msgid "Fill the congestion window on all subflows for round robin" msgstr "Заполнение окна перегрузки для всех подпотоков для round-robin" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:46 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:74 msgid "Fullmesh subflows for each pair of IP addresses" msgstr "Подпотоки Fullmesh для каждой пары IP-адресов" @@ -102,7 +102,7 @@ msgstr "Входящий:" msgid "Interface" msgstr "Интерфейс" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:75 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:104 msgid "Interfaces Settings" msgstr "Настройки интерфейсов" @@ -147,11 +147,11 @@ msgid "Multipath Debug" msgstr "Многоуровневая отладка" #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:12 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:76 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:108 msgid "Multipath TCP" msgstr "Многопоточный TCP" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:37 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:42 msgid "Multipath TCP SYN retries" msgstr "Попытки многопоточной TCP SYN" @@ -163,11 +163,17 @@ msgstr "Контрольная сумма многопоточного TCP" msgid "Multipath TCP path-manager" msgstr "Многопоточный TCP менеджер" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:29 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:31 msgid "Multipath TCP scheduler" msgstr "Планировщик многопоточного TCP" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:27 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:47 +#, fuzzy +#| msgid "Multipath TCP" +msgid "Multipath TCP version" +msgstr "Многопоточный TCP" + +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:28 msgid "Netlink" msgstr "Netlink" @@ -181,7 +187,7 @@ msgstr "" "Users/ConfigureMPTCP'>http://multipath-tcp.org/pmwiki.php/Users/" "ConfigureMPTCP для справки." -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:76 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:108 msgid "One interface must be set as master" msgstr "Один интерфейс должен быть установлен как главный" @@ -197,7 +203,7 @@ msgstr "Отправка:" msgid "Peak:" msgstr "Пиковое значение:" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:52 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:80 msgid "Re-create fullmesh subflows after a timeout" msgstr "Повторно создать подпотоки fullmesh после тайм-аута" @@ -214,6 +220,12 @@ msgstr "Настройки" msgid "Test" msgstr "Тест" +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:69 +msgid "" +"The number of MPTCP-level retransmission intervals with no traffic and " +"pending outstanding data on a given subflow required to declare it stale" +msgstr "" + #: luci-app-mptcp/luasrc/view/mptcp/multipath.htm:914 msgid "Upload:" msgstr "Отправка:" @@ -225,36 +237,36 @@ msgstr "Отправка:" msgid "Waiting for command to complete..." msgstr "Ожидание завершения команды..." -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:80 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:112 msgid "backup" msgstr "Резервирование" #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:22 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:30 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:32 msgid "default" msgstr "По умолчанию" #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:14 #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:17 #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:20 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:54 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:65 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:82 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:93 msgid "disable" msgstr "отключить" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:78 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:110 msgid "disabled" msgstr "отключить" #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:13 #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:16 #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:19 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:53 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:64 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:81 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:92 msgid "enable" msgstr "включить" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:77 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:109 msgid "enabled" msgstr "Установлено" @@ -292,10 +304,22 @@ msgstr "kB/s" msgid "kbit/s" msgstr "kbit/s" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:79 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:111 msgid "master" msgstr "мастер" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:57 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:85 msgid "ndiffports subflows number" msgstr "количество подпотоков ndiffports" + +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:64 +msgid "" +"specifies the maximum number of ADD_ADDR suboptions accepted for each MPTCP " +"connection" +msgstr "" + +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:59 +msgid "" +"specifies the maximum number of additional subflows allowed for each MPTCP " +"connection" +msgstr "" diff --git a/luci-app-mptcp/po/templates/mptcp.pot b/luci-app-mptcp/po/templates/mptcp.pot index 770f34333..dfecf162a 100755 --- a/luci-app-mptcp/po/templates/mptcp.pot +++ b/luci-app-mptcp/po/templates/mptcp.pot @@ -26,11 +26,11 @@ msgstr "" msgid "Check if MPTCP between interface and server is working." msgstr "" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:40 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:52 msgid "Congestion Control" msgstr "" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:69 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:97 msgid "Consecutive segments that should be sent for round robin" msgstr "" @@ -40,7 +40,7 @@ msgstr "" msgid "Current:" msgstr "" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:40 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:52 msgid "Default is cubic" msgstr "" @@ -63,11 +63,11 @@ msgstr "" msgid "Established connections" msgstr "" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:63 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:91 msgid "Fill the congestion window on all subflows for round robin" msgstr "" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:46 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:74 msgid "Fullmesh subflows for each pair of IP addresses" msgstr "" @@ -90,7 +90,7 @@ msgstr "" msgid "Interface" msgstr "" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:75 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:104 msgid "Interfaces Settings" msgstr "" @@ -135,11 +135,11 @@ msgid "Multipath Debug" msgstr "" #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:12 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:76 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:108 msgid "Multipath TCP" msgstr "" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:37 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:42 msgid "Multipath TCP SYN retries" msgstr "" @@ -151,11 +151,15 @@ msgstr "" msgid "Multipath TCP path-manager" msgstr "" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:29 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:31 msgid "Multipath TCP scheduler" msgstr "" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:27 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:47 +msgid "Multipath TCP version" +msgstr "" + +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:28 msgid "Netlink" msgstr "" @@ -166,7 +170,7 @@ msgid "" "ConfigureMPTCP for help." msgstr "" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:76 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:108 msgid "One interface must be set as master" msgstr "" @@ -182,7 +186,7 @@ msgstr "" msgid "Peak:" msgstr "" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:52 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:80 msgid "Re-create fullmesh subflows after a timeout" msgstr "" @@ -199,6 +203,12 @@ msgstr "" msgid "Test" msgstr "" +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:69 +msgid "" +"The number of MPTCP-level retransmission intervals with no traffic and " +"pending outstanding data on a given subflow required to declare it stale" +msgstr "" + #: luci-app-mptcp/luasrc/view/mptcp/multipath.htm:914 msgid "Upload:" msgstr "" @@ -210,36 +220,36 @@ msgstr "" msgid "Waiting for command to complete..." msgstr "" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:80 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:112 msgid "backup" msgstr "" #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:22 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:30 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:32 msgid "default" msgstr "" #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:14 #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:17 #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:20 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:54 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:65 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:82 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:93 msgid "disable" msgstr "" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:78 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:110 msgid "disabled" msgstr "" #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:13 #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:16 #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:19 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:53 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:64 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:81 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:92 msgid "enable" msgstr "" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:77 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:109 msgid "enabled" msgstr "" @@ -277,10 +287,22 @@ msgstr "" msgid "kbit/s" msgstr "" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:79 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:111 msgid "master" msgstr "" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:57 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:85 msgid "ndiffports subflows number" msgstr "" + +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:64 +msgid "" +"specifies the maximum number of ADD_ADDR suboptions accepted for each MPTCP " +"connection" +msgstr "" + +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:59 +msgid "" +"specifies the maximum number of additional subflows allowed for each MPTCP " +"connection" +msgstr "" diff --git a/luci-app-mptcp/po/zh_Hans/mptcp.po b/luci-app-mptcp/po/zh_Hans/mptcp.po index 6b16ddad4..36a27a977 100755 --- a/luci-app-mptcp/po/zh_Hans/mptcp.po +++ b/luci-app-mptcp/po/zh_Hans/mptcp.po @@ -1,14 +1,14 @@ msgid "" msgstr "" -"PO-Revision-Date: 2021-06-02 09:51+0000\n" -"Last-Translator: antrouter \n" +"PO-Revision-Date: 2022-08-12 19:29+0000\n" +"Last-Translator: Weblate Admin \n" "Language-Team: Chinese (Simplified) \n" "Language: zh_Hans\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 4.6.1\n" +"X-Generator: Weblate 4.10.1\n" #: luci-app-mptcp/luasrc/view/mptcp/multipath.htm:775 msgid "(%d minute window, %d second interval)" @@ -35,11 +35,11 @@ msgstr "带宽" msgid "Check if MPTCP between interface and server is working." msgstr "检查接口和服务器之间的MPTCP是否正常工作." -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:40 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:52 msgid "Congestion Control" msgstr "阻塞控制" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:69 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:97 msgid "Consecutive segments that should be sent for round robin" msgstr "连续轮播应发送的连续段" @@ -49,7 +49,7 @@ msgstr "连续轮播应发送的连续段" msgid "Current:" msgstr "实时:" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:40 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:52 msgid "Default is cubic" msgstr "默认设置 cubic" @@ -72,11 +72,11 @@ msgstr "错误" msgid "Established connections" msgstr "建立的连接" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:63 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:91 msgid "Fill the congestion window on all subflows for round robin" msgstr "在循环的所有子流上填充拥塞窗口" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:46 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:74 msgid "Fullmesh subflows for each pair of IP addresses" msgstr "每对IP地址的全网格子流" @@ -89,9 +89,7 @@ msgid "" "If you get \"TCPOptionMPTCPCapable [...] Sender's Key\" at the end, then " "MPTCP is supported. If there is a \"-TCPOptionMPTCPCapable\", then it's " "blocked." -msgstr "" -"如果最后得到“ TCPOptionMPTCPCapable发件人的密钥”,则支持MPTCP。unesdoc.unesco.org " -"unesdoc.unesco.org 如果存在“ -TCPOptionMPTCPCapable”,则将其阻止。" +msgstr "如果您在末尾获得“TCPOptionMPTCPCapable [...] Sender 's Key” ,则支持MPTCP" #: luci-app-mptcp/luasrc/view/mptcp/multipath.htm:929 msgid "Inbound:" @@ -101,7 +99,7 @@ msgstr "入站:" msgid "Interface" msgstr "接口" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:75 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:104 msgid "Interfaces Settings" msgstr "网卡设置" @@ -146,11 +144,11 @@ msgid "Multipath Debug" msgstr "Multipath 调试" #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:12 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:76 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:108 msgid "Multipath TCP" msgstr "多路径TCP" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:37 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:42 msgid "Multipath TCP SYN retries" msgstr "多路径 TCP SYN 重试" @@ -162,11 +160,16 @@ msgstr "多路径TCP校验和" msgid "Multipath TCP path-manager" msgstr "多路径TCP路径管理器" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:29 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:31 msgid "Multipath TCP scheduler" msgstr "多路径TCP调度程序" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:27 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:47 +#, fuzzy +msgid "Multipath TCP version" +msgstr "多路径TCP" + +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:28 msgid "Netlink" msgstr "网络链接" @@ -180,7 +183,7 @@ msgstr "" "ConfigureMPTCP'>http://multipath-tcp.org/pmwiki.php/Users/ConfigureMPTCP4 获取更多的支持." -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:76 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:108 msgid "One interface must be set as master" msgstr "必须设置一个网卡为主接口" @@ -196,7 +199,7 @@ msgstr "出站:" msgid "Peak:" msgstr "峰值:" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:52 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:80 msgid "Re-create fullmesh subflows after a timeout" msgstr "超时后重新创建全网格子流" @@ -213,6 +216,12 @@ msgstr "设置" msgid "Test" msgstr "测试" +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:69 +msgid "" +"The number of MPTCP-level retransmission intervals with no traffic and " +"pending outstanding data on a given subflow required to declare it stale" +msgstr "" + #: luci-app-mptcp/luasrc/view/mptcp/multipath.htm:914 msgid "Upload:" msgstr "上传:" @@ -224,36 +233,36 @@ msgstr "上传:" msgid "Waiting for command to complete..." msgstr "等待命令完成..." -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:80 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:112 msgid "backup" msgstr "备份" #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:22 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:30 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:32 msgid "default" msgstr "默认" #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:14 #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:17 #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:20 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:54 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:65 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:82 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:93 msgid "disable" msgstr "禁用" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:78 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:110 msgid "disabled" msgstr "禁用" #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:13 #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:16 #: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:19 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:53 -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:64 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:81 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:92 msgid "enable" msgstr "启用" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:77 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:109 msgid "enabled" msgstr "启用" @@ -291,14 +300,26 @@ msgstr "kB/秒" msgid "kbit/s" msgstr "kbit/秒" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:79 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:111 msgid "master" msgstr "主" -#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:57 +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:85 msgid "ndiffports subflows number" msgstr "ndiffports子流数" +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:64 +msgid "" +"specifies the maximum number of ADD_ADDR suboptions accepted for each MPTCP " +"connection" +msgstr "" + +#: luci-app-mptcp/luasrc/model/cbi/mptcp.lua:59 +msgid "" +"specifies the maximum number of additional subflows allowed for each MPTCP " +"connection" +msgstr "" + #~ msgid "BLEST" #~ msgstr "最好的" diff --git a/luci-app-omr-bypass/htdocs/luci-static/resources/view/services/omr-bypass.js b/luci-app-omr-bypass/htdocs/luci-static/resources/view/services/omr-bypass.js index 109279953..42f66adb6 100755 --- a/luci-app-omr-bypass/htdocs/luci-static/resources/view/services/omr-bypass.js +++ b/luci-app-omr-bypass/htdocs/luci-static/resources/view/services/omr-bypass.js @@ -223,6 +223,9 @@ return L.view.extend({ o.noinactive = true; o.nocreate = true; + o = s.option(form.Flag, 'ndpi', _('Enable ndpi')); + o.default = o.enabled; + o = s.option(form.Value, 'note', _('Note')); o.rmempty = true; diff --git a/luci-app-omr-bypass/po/it/omr-bypass.po b/luci-app-omr-bypass/po/it/omr-bypass.po index df50f91d0..203394eec 100755 --- a/luci-app-omr-bypass/po/it/omr-bypass.po +++ b/luci-app-omr-bypass/po/it/omr-bypass.po @@ -1,14 +1,14 @@ msgid "" msgstr "" -"PO-Revision-Date: 2020-10-02 08:44+0000\n" -"Last-Translator: Weblate Admin \n" +"PO-Revision-Date: 2022-02-21 21:14+0000\n" +"Last-Translator: Deleted User \n" "Language-Team: Italian \n" "Language: it\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.0.4\n" +"X-Generator: Weblate 4.10.1\n" #: luci-app-omr-bypass/htdocs/luci-static/resources/view/services/omr-bypass.js:166 #: luci-app-omr-bypass/htdocs/luci-static/resources/view/services/omr-bypass.js:174 @@ -32,7 +32,7 @@ msgstr "Domini" #: luci-app-omr-bypass/htdocs/luci-static/resources/view/services/omr-bypass.js:171 #: luci-app-omr-bypass/htdocs/luci-static/resources/view/services/omr-bypass.js:190 msgid "Enabled" -msgstr "" +msgstr "Abilitato" #: luci-app-omr-bypass/root/usr/share/rpcd/acl.d/luci-app-omr-bypass.json:3 msgid "Grant access to ndpi resources" diff --git a/luci-app-omr-bypass/root/etc/firewall.omr-bypass b/luci-app-omr-bypass/root/etc/firewall.omr-bypass index fe65adb2f..7efffb894 100755 --- a/luci-app-omr-bypass/root/etc/firewall.omr-bypass +++ b/luci-app-omr-bypass/root/etc/firewall.omr-bypass @@ -1,2 +1,2 @@ #!/bin/sh -/etc/init.d/omr-bypass reload_rules +[ -z "$(pgrep -f omr-bypass)" ] && /etc/init.d/omr-bypass reload_rules diff --git a/luci-app-omr-bypass/root/etc/init.d/omr-bypass b/luci-app-omr-bypass/root/etc/init.d/omr-bypass index 2b8f56972..b1f40a4e6 100755 --- a/luci-app-omr-bypass/root/etc/init.d/omr-bypass +++ b/luci-app-omr-bypass/root/etc/init.d/omr-bypass @@ -334,6 +334,7 @@ _bypass_proto() { config_get proto $1 proto config_get intf $1 interface config_get enabled $1 enabled + config_get ndpi $1 ndpi [ "$enabled" = "0" ] && return intf=$(echo $intf | sed -e 's/\./_/') [ -n "$intf" ] && [ -z "$(ipset --list | grep omr_dst_bypass_$intf)" ] && return @@ -341,17 +342,19 @@ _bypass_proto() { [ -z "$intf" ] && intf="all" [ -z "$proto" ] && return - if [ "$(uci -q get openmptcprouter.settings.ndpi)" != "0" ]; then + if [ "$(uci -q get openmptcprouter.settings.ndpi)" != "0" ] && [ "$ndpi" != "0" ]; then if [ "$intf" = "all" ]; then iptables-restore -w --wait=60 --noflush <<-EOF *mangle -A omr-bypass-dpi -m ndpi --proto $proto -j MARK --set-mark 0x539 + -A omr-bypass-dpi -m mark --mark 0x539 -j RETURN COMMIT EOF if [ "$disableipv6" = "0" ]; then ip6tables-restore -w --wait=60 --noflush <<-EOF *mangle -A omr-bypass6-dpi -m ndpi --proto $proto -j MARK --set-mark 0x6539 + -A omr-bypass6-dpi -m mark --mark 0x6539 -j RETURN COMMIT EOF fi @@ -359,12 +362,14 @@ _bypass_proto() { iptables-restore -w --wait=60 --noflush <<-EOF *mangle -A omr-bypass-dpi -m ndpi --proto $proto -j MARK --set-mark 0x539$intfid + -A omr-bypass-dpi -m mark --mark 0x539$intfid -j RETURN COMMIT EOF if [ "$disableipv6" = "0" ]; then ip6tables-restore -w --wait=60 --noflush <<-EOF *mangle -A omr-bypass6-dpi -m ndpi --proto $proto -j MARK --set-mark 0x6539$intfid + -A omr-bypass6-dpi -m mark --mark 0x6539$intfid -j RETURN COMMIT EOF fi @@ -464,18 +469,32 @@ _intf_rule_v2ray_rules() { #rule_name=$1 #[ "$rule_name" = "ss_rules" ] && rule_name="def" rule_name="def" - if [ "$(iptables --wait=40 -t nat -L -n | grep v2r_${rule_name}_pre_src)" != "" ] && [ "$(iptables-save | grep v2r | grep omr_dst_bypass_$intf)" = "" ]; then + if [ "$(iptables --wait=40 -t nat -L -n | grep v2r_${rule_name}_dst)" != "" ] && [ "$(iptables-save | grep v2r_${rule_name}_dst | grep omr_dst_bypass_$intf)" = "" ]; then iptables-restore -w --wait=60 --noflush <<-EOF *nat -I v2r_${rule_name}_dst 1 -m set --match-set omr_dst_bypass_$intf dst -j MARK --set-mark 0x539$count -I v2r_${rule_name}_dst 2 -m mark --mark 0x539$count -j RETURN + COMMIT + EOF + fi + if [ "$(iptables --wait=40 -t nat -L -n | grep v2r_${rule_name}_local_out)" != "" ] && [ "$(iptables-save | grep v2r_${rule_name}_local_out | grep omr_dst_bypass_$intf)" = "" ]; then + iptables-restore -w --wait=60 --noflush <<-EOF + *nat -I v2r_${rule_name}_local_out 1 -m set --match-set omr_dst_bypass_$intf dst -j MARK --set-mark 0x539$count -I v2r_${rule_name}_local_out 2 -m mark --mark 0x539$count -j RETURN + COMMIT + EOF + fi + if [ "$(iptables --wait=40 -t nat -L -n | grep v2r_${rule_name}_pre_src)" != "" ] && [ "$(iptables-save | grep v2r_${rule_name}_pre_src | grep omr_dst_bypass_$intf)" = "" ]; then + iptables-restore -w --wait=60 --noflush <<-EOF + *nat -I v2r_${rule_name}_pre_src 1 -m set --match-set omr_dst_bypass_$intf dst -j MARK --set-mark 0x539$count -I v2r_${rule_name}_pre_src 2 -m mark --mark 0x539$count -j RETURN COMMIT EOF fi + + if [ "$disableipv6" = "0" ]; then if [ "$(ip6tables-save | grep omr-bypass6 | grep omr6_dst_bypass_$intf)" = "" ]; then ip6tables-restore -w --wait=60 --noflush <<-EOF @@ -544,7 +563,9 @@ _intf_rule() { iptables-restore -w --wait=60 --noflush <<-EOF *mangle -I omr-bypass 1 -m set --match-set omr_dst_bypass_$intf dst -j MARK --set-mark 0x539$count + -I omr-bypass 2 -m mark --mark 0x539$count -j RETURN -I omr-bypass-local 1 -m set --match-set omr_dst_bypass_$intf dst -j MARK --set-mark 0x539$count + -I omr-bypass-local 2 -m mark --mark 0x539$count -j RETURN COMMIT EOF fi @@ -602,7 +623,7 @@ _ss_rules_config() { iptables-restore -w --wait=60 --noflush <<-EOF *nat -I ssr_${rule_name}_dst 1 -m set --match-set omr_dst_bypass_all dst -j MARK --set-mark 0x539 - -I ssr_${rule_name}_dst 1 -m mark --mark 0x539 -j RETURN + -I ssr_${rule_name}_dst 2 -m mark --mark 0x539 -j RETURN -I ssr_${rule_name}_local_out 1 -m set --match-set omr_dst_bypass_all dst -j MARK --set-mark 0x539 -I ssr_${rule_name}_local_out 2 -m mark --mark 0x539 -j RETURN -I ssr_${rule_name}_pre_src 1 -m set --match-set omr_dst_bypass_all dst -j MARK --set-mark 0x539 @@ -641,7 +662,7 @@ _v2ray_rules_config() { iptables-restore -w --wait=60 --noflush <<-EOF *nat -I v2r_${rule_name}_dst 1 -m set --match-set omr_dst_bypass_all dst -j MARK --set-mark 0x539 - -I v2r_${rule_name}_dst 1 -m mark --mark 0x539 -j RETURN + -I v2r_${rule_name}_dst 2 -m mark --mark 0x539 -j RETURN -I v2r_${rule_name}_local_out 1 -m set --match-set omr_dst_bypass_all dst -j MARK --set-mark 0x539 -I v2r_${rule_name}_local_out 2 -m mark --mark 0x539 -j RETURN -I v2r_${rule_name}_pre_src 1 -m set --match-set omr_dst_bypass_all dst -j MARK --set-mark 0x539 @@ -699,13 +720,13 @@ start_service() { iptables-restore -w --wait=60 --noflush <<-EOF *mangle :omr-bypass - - -I PREROUTING -m addrtype ! --dst-type LOCAL -j omr-bypass + -A PREROUTING -j omr-bypass COMMIT EOF iptables-restore -w --wait=60 --noflush <<-EOF *mangle :omr-bypass-local - - -I OUTPUT -m addrtype ! --dst-type LOCAL -j omr-bypass-local + -A OUTPUT -m addrtype ! --dst-type LOCAL -j omr-bypass-local COMMIT EOF if [ "$disableipv6" = "0" ]; then @@ -713,7 +734,7 @@ start_service() { ip6tables-restore -w --wait=60 --noflush <<-EOF *mangle :omr-bypass6 - - -I PREROUTING -m addrtype ! --dst-type LOCAL -j omr-bypass6 + -A PREROUTING -j omr-bypass6 COMMIT EOF fi @@ -760,11 +781,13 @@ start_service() { iptables-restore -w --wait=60 --noflush <<-EOF *mangle -A omr-bypass -m set --match-set omr_dst_bypass_all dst -j MARK --set-mark 0x539 + -A omr-bypass -m mark --mark 0x539 -j RETURN COMMIT EOF iptables-restore -w --wait=60 --noflush <<-EOF *mangle -A omr-bypass-local -m set --match-set omr_dst_bypass_all dst -j MARK --set-mark 0x539 + -A omr-bypass-local -m mark --mark 0x539 -j RETURN COMMIT EOF fi @@ -777,9 +800,8 @@ start_service() { iptables-restore -w --wait=60 --noflush <<-EOF *mangle :omr-bypass-dpi - - -A PREROUTING -m addrtype ! --dst-type LOCAL -j omr-bypass-dpi - -A OUTPUT -m addrtype ! --dst-type LOCAL -j omr-bypass-dpi - -A POSTROUTING -m addrtype --dst-type LOCAL -j omr-bypass-dpi + -A INPUT -j omr-bypass-dpi + -A FORWARD -j omr-bypass-dpi COMMIT EOF if [ "$disableipv6" = "0" ]; then @@ -787,9 +809,8 @@ start_service() { ip6tables-restore -w --wait=60 --noflush <<-EOF *mangle :omr-bypass6-dpi - - -A PREROUTING -m addrtype ! --dst-type LOCAL -j omr-bypass6-dpi - -A OUTPUT -m addrtype ! --dst-type LOCAL -j omr-bypass6-dpi - -A POSTROUTING -m addrtype --dst-type LOCAL -j omr-bypass6-dpi + -A INPUT -j omr-bypass6-dpi + -A FORWARD -j omr-bypass6-dpi COMMIT EOF fi diff --git a/luci-app-omr-dscp/po/it/omr-dscp.po b/luci-app-omr-dscp/po/it/omr-dscp.po index 6194b0c41..2ea86eaf8 100755 --- a/luci-app-omr-dscp/po/it/omr-dscp.po +++ b/luci-app-omr-dscp/po/it/omr-dscp.po @@ -1,14 +1,14 @@ msgid "" msgstr "" -"PO-Revision-Date: 2020-09-21 12:51+0000\n" -"Last-Translator: Weblate Admin \n" +"PO-Revision-Date: 2022-02-21 21:14+0000\n" +"Last-Translator: Deleted User \n" "Language-Team: Italian \n" "Language: it\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.0.4\n" +"X-Generator: Weblate 4.10.1\n" #: luci-app-omr-dscp/luasrc/model/cbi/dscp-domains.lua:21 #: luci-app-omr-dscp/luasrc/model/cbi/dscp.lua:73 @@ -93,7 +93,7 @@ msgstr "Servizi differenziati" #: luci-app-omr-dscp/luasrc/model/cbi/dscp.lua:29 msgid "Direction" -msgstr "" +msgstr "Direzione" #: luci-app-omr-dscp/luasrc/model/cbi/dscp-domains.lua:15 msgid "Domain" diff --git a/luci-app-omr-quota/po/it/omr-quota.po b/luci-app-omr-quota/po/it/omr-quota.po index 37e2dfec4..be100e360 100755 --- a/luci-app-omr-quota/po/it/omr-quota.po +++ b/luci-app-omr-quota/po/it/omr-quota.po @@ -1,14 +1,14 @@ msgid "" msgstr "" -"PO-Revision-Date: 2020-09-21 12:51+0000\n" -"Last-Translator: Weblate Admin \n" +"PO-Revision-Date: 2022-02-20 20:24+0000\n" +"Last-Translator: tiziano \n" "Language-Team: Italian \n" "Language: it\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.0.4\n" +"X-Generator: Weblate 4.10.1\n" #: luci-app-omr-quota/luasrc/view/omr-quota/cbi-select-add.htm:8 msgid "Add" @@ -24,7 +24,7 @@ msgstr "" #: luci-app-omr-quota/luasrc/model/cbi/quota/quota.lua:10 msgid "Interfaces" -msgstr "Interfaccia" +msgstr "Interfacce" #: luci-app-omr-quota/luasrc/model/cbi/quota/quota.lua:33 msgid "Interval between check (s)" diff --git a/luci-app-omr-tracker/po/it/omr-tracker.po b/luci-app-omr-tracker/po/it/omr-tracker.po index 4257d56b1..337631a7f 100755 --- a/luci-app-omr-tracker/po/it/omr-tracker.po +++ b/luci-app-omr-tracker/po/it/omr-tracker.po @@ -1,18 +1,18 @@ msgid "" msgstr "" -"PO-Revision-Date: 2020-09-21 12:51+0000\n" -"Last-Translator: Weblate Admin \n" +"PO-Revision-Date: 2022-02-20 20:24+0000\n" +"Last-Translator: tiziano \n" "Language-Team: Italian \n" "Language: it\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.0.4\n" +"X-Generator: Weblate 4.10.1\n" #: luci-app-omr-tracker/luasrc/view/omr-tracker/cbi-select-add.htm:8 msgid "Add" -msgstr "" +msgstr "Aggiungi" #: luci-app-omr-tracker/luasrc/model/cbi/omr-tracker.lua:117 #: luci-app-omr-tracker/luasrc/model/cbi/omr-tracker.lua:192 @@ -69,7 +69,7 @@ msgstr "" #: luci-app-omr-tracker/luasrc/model/cbi/omr-tracker.lua:154 msgid "Interfaces" -msgstr "" +msgstr "Interfacce" #: luci-app-omr-tracker/luasrc/view/omr-tracker/cbi-select-add.htm:9 msgid "Invalid" diff --git a/luci-app-openmptcprouter/luasrc/controller/openmptcprouter.lua b/luci-app-openmptcprouter/luasrc/controller/openmptcprouter.lua index 071aa1805..ce5edb130 100644 --- a/luci-app-openmptcprouter/luasrc/controller/openmptcprouter.lua +++ b/luci-app-openmptcprouter/luasrc/controller/openmptcprouter.lua @@ -584,10 +584,12 @@ function wizard_add() ucic:set("openmptcprouter",server,"get_config","1") end ucic:set("openmptcprouter",server,"master","1") + ucic:set("openmptcprouter",server,"current","1") ucic:set("openmptcprouter",server,"backup","0") else ucic:set("openmptcprouter",server,"get_config","0") ucic:set("openmptcprouter",server,"master","0") + ucic:set("openmptcprouter",server,"current","0") ucic:set("openmptcprouter",server,"backup","1") end if openmptcprouter_vps_disabled == "1" then @@ -640,7 +642,7 @@ function wizard_add() ucic:set("v2ray","main","enabled","0") ucic:foreach("shadowsocks-libev", "server", function(s) local sectionname = s[".name"] - if sectionname:match("^sss.*") then + if sectionname:match("^sss.*") and ucic:get("shadowsocks-libev",sectionname,"server") ~= "" then ucic:set("shadowsocks-libev",sectionname,"disabled","0") end end) @@ -709,7 +711,7 @@ function wizard_add() local nbip = 0 for _, ssip in pairs(server_ips) do ucic:set("shadowsocks-libev","sss" .. nbip,"server",ssip) - if default_proxy == "shadowsocks" and serversnb > disablednb then + if default_proxy == "shadowsocks" and serversnb > disablednb and ssip ~= "" then ucic:set("shadowsocks-libev","sss" .. nbip,"disabled","0") end nbip = nbip + 1 @@ -747,7 +749,7 @@ function wizard_add() local nbip = 0 for _, ssip in pairs(server_ips) do ucic:set("shadowsocks-libev","sss" .. nbip,"server",ssip) - if default_proxy == "shadowsocks" and serversnb > disablednb then + if default_proxy == "shadowsocks" and serversnb > disablednb and ssip ~= "" then ucic:set("shadowsocks-libev","sss" .. nbip,"disabled","0") end nbip = nbip + 1 @@ -843,8 +845,8 @@ function wizard_add() end else if serversnb == 0 then - ucic:set("shadowsocks-libev","sss0","disabled",shadowsocks_disable) - ucic:set("shadowsocks-libev","sss1","disabled",shadowsocks_disable) + ucic:set("shadowsocks-libev","sss0","disabled","1") + ucic:set("shadowsocks-libev","sss1","disabled","1") end ucic:set("shadowsocks-libev","sss0","key","") ucic:set("shadowsocks-libev","sss1","key","") @@ -1153,6 +1155,10 @@ function settings_add() local shadowsocksudp = luci.http.formvalue("shadowsocksudp") or "0" ucic:set("openmptcprouter","settings","shadowsocksudp",shadowsocksudp) + -- Enable/disable v2ray udp + local shadowsocksudp = luci.http.formvalue("v2rayudp") or "1" + ucic:set("v2ray","main_transparent_proxy","redirect_udp",v2rayudp) + -- Enable/disable nDPI local ndpi = luci.http.formvalue("ndpi") or "1" ucic:set("openmptcprouter","settings","ndpi",ndpi) diff --git a/luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm b/luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm index c6015c229..81dda5432 100755 --- a/luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm +++ b/luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm @@ -291,6 +291,12 @@ checked<% end %>> +
+ +
+ checked<% end %>> +
+
diff --git a/luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm b/luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm index eafdbeaa6..bb3935675 100644 --- a/luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm +++ b/luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm @@ -514,13 +514,13 @@ <% end %> -
+
" data-type="ip4addr">
-
+
" data-type="ip4addr"> diff --git a/luci-app-openmptcprouter/po/de/openmptcprouter.po b/luci-app-openmptcprouter/po/de/openmptcprouter.po index 58d482708..73e6b7cf6 100755 --- a/luci-app-openmptcprouter/po/de/openmptcprouter.po +++ b/luci-app-openmptcprouter/po/de/openmptcprouter.po @@ -1,46 +1,48 @@ msgid "" msgstr "" -"PO-Revision-Date: 2020-10-21 12:55+0000\n" -"Last-Translator: Anonymous \n" +"PO-Revision-Date: 2022-08-12 12:08+0000\n" +"Last-Translator: Weblate Admin \n" "Language-Team: German \n" "Language: de\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.0.4\n" +"X-Generator: Weblate 4.10.1\n" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:307 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:315 msgid "A Dead Simple VPN is a TCP VPN that can replace Glorytun TCP" msgstr "'Dead Simple VPN' ist ein TCP VPN das 'Glorytun TCP' ersetzen kann" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:302 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:304 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:310 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:312 msgid "A Dead Simple VPN key" msgstr "Schlüssel 'Dead Simple VPN'" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:100 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:108 msgid "" "A second server's IP can be set for dual IPv4/IPv6 server if WAN IPv6 are set" msgstr "" +"Die zweite IP eines Servers kann für Dual-IPv4/IPv6-Server festgelegt " +"werden, wenn WAN-IPv6 eingerichtet ist" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:111 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:119 msgid "API username to retrieve personnalized settings from the server." -msgstr "API Benutzername zum Download der Settings vom Server." +msgstr "API Benutzername zum Download der Einstellungen vom Server." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:809 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:814 msgid "APN" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:734 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:742 msgid "Accept IPv6 RA" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:156 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:164 msgid "Add a new server" msgstr "Neuen Server hinzufügen" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:989 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1044 msgid "Add an interface" msgstr "Interface hinzufügen" @@ -49,11 +51,11 @@ msgstr "Interface hinzufügen" msgid "Advanced Settings" msgstr "Erweiterte Einstellungen" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:161 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:169 msgid "Advanced settings" msgstr "Erweiterte Einstellungen" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:384 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:392 msgid "" "All VPN available here can do aggregation over MPTCP or using own internal " "method." @@ -65,19 +67,19 @@ msgstr "" msgid "All router settings" msgstr "Alle Router-Einstellungen" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:276 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:284 msgid "" "An Advanced Encryption Standard (AES) instruction set is integrated in the " "processor." msgstr "" "Die CPU beherrscht AES-NI-Befehle zur Beschleunigung der Verschlüsselung." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:835 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:840 msgid "Authentication Type" msgstr "Authentifizierungs Methode" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:873 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:889 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:878 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:894 msgid "Backup" msgstr "Backup" @@ -86,55 +88,60 @@ msgstr "Backup" msgid "Backup on server" msgstr "Backup der Router-Einstellungen auf den Server" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:371 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:383 msgid "Balancing" -msgstr "" +msgstr "Ausgleich" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:22 msgid "Beta" msgstr "Beta" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:310 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:312 msgid "Big time difference between the server and the router" -msgstr "" +msgstr "Großer Zeitunterschied zwischen dem Server und dem Router" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:564 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:572 msgid "Bridge" -msgstr "" +msgstr "Netzwerkbrücke" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:618 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:620 msgid "Bridge can't have multipath enabled" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:287 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:295 msgid "By default VPN is used for any traffic that is not TCP." msgstr "" "IP-Pakete, die nicht TCP sind, werden standardmäßig mit einem VPN-Protokoll " "übertragen." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:221 -#, fuzzy +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:229 msgid "" "By default proxy is used for any traffic that is TCP (and UDP for V2Ray)." msgstr "" -"IP-Pakete, die nicht TCP sind, werden standardmäßig mit einem VPN-Protokoll " -"übertragen." +"Standard wird TCP Netzwerk Verkehr über Proxy übertragen (Auch UDP für " +"V2Ray)." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:840 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:845 msgid "CHAP" +msgstr "CHAP" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:961 +msgid "" +"Cake queue discipline is not set, autorate will only work after a reboot if " +"enabled here." msgstr "" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:271 msgid "Can\\'t access and use server part" -msgstr "" +msgstr "Kann Server Teil nicht öffnen und verwenden" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:297 msgid "Can\\'t contact Server Admin Script" -msgstr "" +msgstr "Kann nicht verbinden zum Server Admin Skript" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:287 msgid "Can\\'t get public IP address from ShadowSocks" -msgstr "" +msgstr "Kann keine Public IP Adresse vom ShadowSocks beziehen" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:290 msgid "Can\\'t get public IP address from V2Ray" @@ -142,82 +149,82 @@ msgstr "" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:284 msgid "Can\\'t ping server" -msgstr "" +msgstr "Kann Server nicht pingen" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:415 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:423 msgid "China" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:568 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:576 msgid "" "Choose MacVLAN if you want to create a virtual interface based on a physical " "interface." msgstr "" +"Wähle MacVLAN um ein virtuelles Interface basierend auf ein Physikalisches " +"Interface an zu legen." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:502 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:588 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:647 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:510 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:596 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:655 msgid "Choose physical interface." -msgstr "" +msgstr "Wähle physikalische Schnittstelle." #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:135 msgid "Core temp:" -msgstr "" +msgstr "Kerntemperatur:" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:410 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:418 msgid "Country" -msgstr "" +msgstr "Land" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:407 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:415 #, fuzzy msgid "Country settings" msgstr "Alle Router-Einstellungen" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:454 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:599 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:462 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:607 msgid "DHCP" msgstr "DHCP" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:600 -#, fuzzy +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:608 msgid "DHCPv6" -msgstr "DHCP" +msgstr "DHCPv6" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:188 msgid "DNS issue: can\\'t resolve hostname" -msgstr "" +msgstr "DNS Problem: Hostnamen nicht beziehbar" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:355 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:367 msgid "Debug" -msgstr "" +msgstr "Debug" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:223 -#, fuzzy +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:231 msgid "Default Proxy" -msgstr "Standard VPN" +msgstr "Standard Proxy" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:337 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:345 msgid "Default VPN" msgstr "Standard VPN" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:77 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:543 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:85 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:551 msgid "Delete" msgstr "Löschen" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:741 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:768 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:789 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:749 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:774 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:794 msgid "Device" -msgstr "" +msgstr "Gerät" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:253 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:259 #, fuzzy -msgid "Disable HTTP test on Server API in status page" +msgid "Disable HTTP test on Server API" msgstr "Server-Ping Status-Prüfung aus" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:345 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:350 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:357 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:362 #, fuzzy msgid "Disable ModemManager" msgstr "Server-Ping aus" @@ -231,43 +238,41 @@ msgid "Disable TCP Fast Open on Linux and Shadowsocks configuration" msgstr "" "Abschalten von TCP-Fast-Open für Linux und die ShadowsSocks-Einstellungen" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:295 -#, fuzzy +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:307 msgid "Disable default gateway" -msgstr "Gateway-Ping aus" +msgstr "Default Gateway aus" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:300 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:312 msgid "Disable default gateway, no internet if VPS are down" -msgstr "" +msgstr "Default Gateway aus, kein Internet wenn VPS down ist" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:193 msgid "Disable external check" msgstr "Externe Prüfung aus" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:238 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:244 msgid "Disable gateway ping" msgstr "Gateway-Ping aus" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:243 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:249 #, fuzzy msgid "Disable gateway ping check in status page" msgstr "Gateway-Ping Statusüberprüfung aus" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:279 -#, fuzzy +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:285 msgid "Disable interfaces auto rename" -msgstr "Externe Prüfung aus" +msgstr "Automatische Umbenennung von Interfaces deaktivieren" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:330 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:342 msgid "Disable multipath test using tracebox" -msgstr "" +msgstr "Deaktiviere multipath Test mittels Tracebox" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:335 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:347 #, fuzzy msgid "Disable nDPI" msgstr "Server-Ping aus" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:340 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:352 msgid "Disable nDPI, used for protocols in OMR-ByPass" msgstr "" @@ -276,141 +281,152 @@ msgid "" "Disable ports redirection defined in firewall from server to this router" msgstr "Portweiterleitungen in der Server-Firewall zu diesem Router abschalten" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:284 -#, fuzzy +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:290 msgid "Disable renaming interfaces" -msgstr "Bezeichnung der Schnittstelle" +msgstr "Umbenennung der Schnittstelle deaktivieren" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:315 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:320 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:327 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:332 #, fuzzy msgid "Disable route loop detection" msgstr "Server-Ping aus" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:144 -#, fuzzy +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:152 msgid "Disable server" -msgstr "Server-Ping aus" +msgstr "Server deaktivieren" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:248 -#, fuzzy +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:254 msgid "Disable server http test" -msgstr "Server-Ping aus" +msgstr "Server-http-Test aus" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:305 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:317 msgid "Disable server ping" msgstr "Server-Ping aus" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:310 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:322 msgid "Disable server ping status check" msgstr "Server-Ping Status-Prüfung aus" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:325 -#, fuzzy +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:337 msgid "Disable tracebox test" -msgstr "Externe Prüfung aus" +msgstr "Deaktiviere tracebox Test" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:189 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:871 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:887 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:197 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:876 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:892 msgid "Disabled" -msgstr "" +msgstr "inaktiv" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:933 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:988 msgid "Download speed (Kb/s)" msgstr "Download-Geschwindigkeit (kBits/s)" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:369 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:381 msgid "Dynamic change" msgstr "Dynamische Anpassung" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:390 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:402 msgid "Enable Bridge Acceleration" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:209 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:217 #, fuzzy msgid "Enable DNS64" msgstr "SQM aktiv" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:384 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:396 msgid "Enable Fast Patch offloading for connections" msgstr "" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:187 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:186 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:194 msgid "Enable IPv6" msgstr "IPv6 aktiv" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:923 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:975 +msgid "Enable QoS" +msgstr "QoS aktiv" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:223 +msgid "Enable SIP ALG" +msgstr "SIP ALG aktiv" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:942 msgid "Enable SQM" msgstr "SQM aktiv" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:952 +#, fuzzy +msgid "Enable SQM autorate" +msgstr "SQM aktiv" + #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:79 msgid "Enable ShadowSocks Obfuscating" msgstr "Shadowsocks-Verschleierung aktiv" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:213 -#, fuzzy msgid "Enable TCP Low Latency" -msgstr "TCP-Fast-Open aus" +msgstr "Aktiviere TCP Low Latency" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:360 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:372 msgid "Enable debug logs" -msgstr "" +msgstr "Aktiviere debug Logs" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:190 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:870 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:886 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:198 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:875 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:891 msgid "Enabled" msgstr "Aktiv" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:259 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:267 msgid "Encryption" msgstr "Verschlüsselung" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:280 -#, fuzzy +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:288 msgid "Encryption method is used for Shadowsocks, V2Ray, Glorytun and OpenVPN." -msgstr "Verschlüsselungverfahren wird ebenfalls für Glorytun genutzt." +msgstr "" +"Verschlüsselungverfahren wird verwendet für Shadowsocks, V2Ray, Glorytun " +"and OpenVPN." #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:176 msgid "Filesystem is readonly" -msgstr "" +msgstr "Filesystem ist nur lesen" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:419 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:427 msgid "For China, set an accessible DNS and disable DNSSEC." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:178 -#, fuzzy -msgid "Force retrieve all keys from server." -msgstr "API Benutzername zum Download der Settings vom Server." - -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:173 -#, fuzzy -msgid "Force retrieve settings" -msgstr "Server-Einstellungen" - -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:829 -msgid "GPRS only" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:902 +msgid "Force TTL" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:561 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:764 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:186 +msgid "Force retrieve all keys from server." +msgstr "Erzwingen alle Schlüssel vom Server runter zu laden." + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:181 +msgid "Force retrieve settings" +msgstr "Erzwingen Einstellungen runter zu laden." + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:834 +msgid "GPRS only" +msgstr "Nur GPRS" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:563 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:766 msgid "Gateway DOWN" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:564 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:566 msgid "Gateway IPv6 DOWN" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:295 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:303 msgid "Glorytun TCP is used by default for UDP and ICMP" msgstr "Glorytun-TCP wird standardmäßig für UDP und ICMP genutzt." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:290 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:292 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:298 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:300 msgid "Glorytun key" msgstr "Glorytun Schlüssel" @@ -452,94 +468,91 @@ msgstr "IPv4 TCP SYN Wiederholversuche" msgid "IPv4 TCP SYN retries2" msgstr "IPv4 TCP SYN Wiederholversuche" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:510 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:653 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:518 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:661 msgid "IPv4 address" msgstr "IPv4-Adresse" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:669 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:677 msgid "IPv4 gateway" msgstr "IPv4-Standardgateway" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:516 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:663 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:524 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:671 msgid "IPv4 netmask" msgstr "IPv4-Netzmaske" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:199 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:207 msgid "IPv6 Prefix" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:683 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:710 -#, fuzzy +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:691 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:718 msgid "IPv6 address" -msgstr "IPv4-Adresse" +msgstr "IPv6-Adresse" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:697 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:720 -#, fuzzy +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:705 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:728 msgid "IPv6 gateway" -msgstr "IPv4-Standardgateway" +msgstr "IPv6-Standardgateway" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:632 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:804 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:634 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:806 msgid "IPv6 route received" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:184 -#, fuzzy +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:192 msgid "IPv6 settings" -msgstr "VPN-Einstellungen" +msgstr "IPv6-Einstellungen" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:209 msgid "IPv6 tunnel DOWN" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:350 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:352 msgid "IPv6:" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:214 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:222 msgid "If host support NAT64, you can enable DNS64 support." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:529 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:537 msgid "Interfaces settings" msgstr "Schnittstellen-Einstellungen" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:244 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:254 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:295 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:307 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:319 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:331 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:252 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:262 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:303 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:315 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:327 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:339 msgid "Key is retrieved from server API by default." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:121 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:129 msgid "" "Key to configure and retrieve others keys from Server and to set server " "settings from OpenMPTCProuter." msgstr "" "API-Schlüssel für die automatische Provisionierung der Schlüssel vom Server." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:427 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:435 #, fuzzy msgid "LAN interfaces settings" msgstr "Schnittstellen-Einstellungen" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:827 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:832 msgid "LTE" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:438 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:549 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:446 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:557 msgid "Label" msgstr "Bezeichnung" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:444 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:554 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:452 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:562 msgid "Label for the interface" msgstr "Bezeichnung der Schnittstelle" @@ -548,28 +561,28 @@ msgid "Last available backup on server:" msgstr "Aktuellstes auf dem Server verfügbares Backup:" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:124 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:327 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:329 #, fuzzy msgid "Latest available version" msgstr "Aktuellstes auf dem Server verfügbares Backup:" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:130 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:333 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:335 msgid "Load:" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:628 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:630 msgid "Looping route detected" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:319 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:327 msgid "MLVPN can replace Glorytun with connections with same latency" msgstr "" "MLVPN kann Glorytun auf Verbindungen mit identischer Latenz ('ping') " "ersetzen." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:314 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:316 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:322 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:324 msgid "MLVPN password" msgstr "MLVPN Schlüssel" @@ -577,56 +590,56 @@ msgstr "MLVPN Schlüssel" msgid "MPTCP is not enabled on the server" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:344 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:346 msgid "MPTCP may not be enabled on the server" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:393 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:913 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:401 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:929 msgid "MPTCP over VPN" msgstr "MPTCP über VPN" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:390 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:398 #, fuzzy msgid "MPTCP over VPN settings" msgstr "MPTCP über VPN" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:391 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:399 msgid "" "MPTCP over VPN should be used only when Multipath TCP is blocked on a " "connection." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:563 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:571 msgid "MacVLAN" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:872 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:888 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:877 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:893 msgid "Master" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:365 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:377 msgid "Master interface selection" msgstr "Primäre Schnittstelle:" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:409 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:421 msgid "Maximum scaling CPU frequency" msgstr "Maximaler CPU-Takt" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:403 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:415 msgid "Minimum scaling CPU frequency" msgstr "Minimaler CPU-Takt" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:824 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:829 msgid "Modem default" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:858 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:863 msgid "Modem init timeout" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:601 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:609 msgid "ModemManager" msgstr "" @@ -634,51 +647,51 @@ msgstr "" msgid "More than one default VPN is enabled" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:867 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:883 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:872 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:888 msgid "Multipath TCP" -msgstr "" +msgstr "Multipath-TCP" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:601 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:607 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:787 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:793 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:603 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:609 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:789 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:795 msgid "Multipath current state is" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:596 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:782 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:598 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:784 msgid "Multipath master already defined" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:567 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:767 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:569 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:769 msgid "Multipath seems to be blocked on the connection" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:602 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:610 msgid "NCM" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:838 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:843 msgid "NONE" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:623 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:625 msgid "Network interface MAC address duplicated" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:613 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:799 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:615 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:801 msgid "Network interface duplicated" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:579 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:581 msgid "Network interface not in WAN firewall zone" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:899 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:901 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:903 msgid "Network overview" msgstr "Netzwerk-Übersicht" @@ -686,8 +699,8 @@ msgstr "Netzwerk-Übersicht" msgid "Networks settings" msgstr "Netzwerk-Einstellungen" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:554 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:757 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:556 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:759 msgid "No IP defined" msgstr "" @@ -695,16 +708,16 @@ msgstr "" msgid "No IPv6 access" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:575 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:577 msgid "No Server http response after 1 second" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:571 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:771 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:573 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:773 msgid "No Server ping response after 1 second" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:656 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:658 msgid "No WAN with multipath enabled:" msgstr "" @@ -712,16 +725,16 @@ msgstr "" msgid "No available backup on server." msgstr "Keine Konfigurations-Sicherung des Routers auf dem Server verfügbar." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:370 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:382 msgid "No change" msgstr "Keine Änderungen" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:819 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:821 msgid "No data" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:558 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:761 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:560 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:763 msgid "No gateway defined" msgstr "" @@ -743,12 +756,12 @@ msgstr "" msgid "No server defined" msgstr "Allgemeine Servereinstellungen" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:265 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:413 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:273 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:421 msgid "None" msgstr "Keine" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:562 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:570 msgid "Normal" msgstr "" @@ -770,98 +783,98 @@ msgstr "Verschleierungs-Typ" msgid "Obfuscating will be enabled on both side" msgstr "Die Verschleierung wird auf beiden Seiten aktiviert." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:368 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:380 msgid "On wizard change" msgstr "Bei Änderungen mittels des Assistenten" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:233 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:241 msgid "Only ShadowSocks is supported with server multiple IPs for now." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:877 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:882 msgid "" "Only one interface must be set as \"Master\", this should be the most stable " "interface." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:135 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:143 msgid "Only one server can be master, else all servers are set as backup." msgstr "Nur eine Verbindung kann als 'primär' definiert werden." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:391 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:399 msgid "Only work with Shadowsocks as proxy." -msgstr "" +msgstr "Funktioniert nur mit Shadowsocks als Proxy." #: luci-app-openmptcprouter/root/usr/share/luci/menu.d/luci-app-openmptcprouter.json:3 msgid "OpenMPTCProuter" msgstr "OpenMPTCProuter" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:384 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:392 msgid "OpenVPN can't be used in multi VPS configuration." msgstr "" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:218 msgid "Optimize for latency instead of bandwidth" -msgstr "" +msgstr "Für niedrige Latenz anstatt für Bandbreite optimieren" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:455 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:605 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:463 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:613 #, fuzzy msgid "Other" msgstr "Andere" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:225 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:231 #, fuzzy msgid "Other settings" msgstr "Server-Einstellungen" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:839 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:844 msgid "PAP" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:841 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:846 msgid "PAP/CHAP" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:852 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:857 #, fuzzy msgid "PAP/CHAP password" msgstr "MLVPN Schlüssel" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:846 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:851 msgid "PAP/CHAP username" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:815 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:820 msgid "PIN code" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:603 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:611 msgid "PPPoE" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:467 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:573 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:614 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:475 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:581 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:622 #, fuzzy msgid "Physical interface" msgstr "Interface hinzufügen" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:825 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:830 msgid "Prefer LTE" -msgstr "" +msgstr "Bevorzuge LTE" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:826 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:831 msgid "Prefer UMTS" -msgstr "" +msgstr "Bevorzuge UMTS" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:94 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:102 #, fuzzy msgid "Primary server IP" msgstr "Server IPv4" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:449 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:594 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:457 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:602 msgid "Protocol" msgstr "Protokoll" @@ -869,20 +882,24 @@ msgstr "Protokoll" msgid "Proxy is DISABLED" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:220 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:228 #, fuzzy msgid "Proxy settings" msgstr "VPN-Einstellungen" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:355 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:357 msgid "Proxy traffic:" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:604 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:612 msgid "QMI" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:381 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:980 +msgid "QoS permit to prioritize any upload traffic." +msgstr "" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:393 msgid "Qualcomm Shortcut FE driver" msgstr "" @@ -890,7 +907,7 @@ msgstr "" msgid "Redirects all ports from server to this router" msgstr "Weiterleitung aller Ports vom Server auf den Router" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:999 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1054 msgid "Reset" msgstr "" @@ -898,34 +915,43 @@ msgstr "" msgid "Restore backup" msgstr "Parameter-Sicherung auf den Router wiederherstellen" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:171 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:179 #, fuzzy msgid "Retrieve settings from server" msgstr "API Benutzername zum Download der Settings vom Server." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:435 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:998 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:957 +msgid "SQM autorate is for LTE and connection without a stable speed." +msgstr "" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:947 +msgid "" +"SQM control bufferloat: the undesirable latency that arises when the router " +"buffers too much data." +msgstr "" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:447 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1053 msgid "Save & Apply" msgstr "Speichern und Anwenden" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:233 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:239 msgid "Save vnstats statistics on disk" msgstr "vnstat-Daten fortlaufend auf Datenträger schreiben" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:228 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:234 msgid "Save vnstats stats" msgstr "Speichern der vnstat-Daten" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:415 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:427 msgid "Scaling governor" msgstr "Methode der CPU-Taktung" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:95 -#, fuzzy +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:103 msgid "Secondary server IP" -msgstr "Server IPv4" +msgstr "zweite Server IP" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:992 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1047 msgid "Select the device you want to base the interface on." msgstr "Schnittstelle auswählen für diese Verbindung" @@ -933,65 +959,64 @@ msgstr "Schnittstelle auswählen für diese Verbindung" msgid "Send backup" msgstr "Parameter-Sicherung vom Router auf den Server" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:83 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:85 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:92 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:91 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:93 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:100 msgid "Server IP" msgstr "Server IPv4" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:87 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:97 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:95 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:105 #, fuzzy msgid "Server IP will be set for proxy and VPN" msgstr "" "Die Server-IP wird für die Protokolle ShadowSockes, Glorytun, OpenVPN und " "MLVPN verwendet." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:116 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:118 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:124 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:126 msgid "Server key" msgstr "Server-Schlüssel" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:43 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:67 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:75 msgid "Server settings" msgstr "Server-Einstellungen" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:106 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:108 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:114 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:116 msgid "Server username" msgstr "Server-Benutzername" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:821 -#, fuzzy +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:826 msgid "Service Type" -msgstr "Server-Schlüssel" +msgstr "Dienst Typ" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:401 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:409 msgid "Set VPN to use for MPTCP over VPN." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:658 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:688 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:715 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:666 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:696 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:723 msgid "Set an IP in the same network as the modem" msgstr "IP-Adresse im gleichen Subnetz wie das Modem angeben" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:408 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:416 msgid "Set configuration for countries with some specificities." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:674 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:702 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:725 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:682 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:710 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:733 msgid "Set here IP of the modem" msgstr "IPv4 des Modems" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:130 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:138 msgid "Set server as master" msgstr "Server als 'primär' definieren" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:232 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:240 #, fuzzy msgid "" "Set the default Proxy used for TCP when ShadowSocks is enabled, for TCP and " @@ -1000,7 +1025,7 @@ msgstr "" "Auswahl des VPNs für UDP und ICMP (Sofern ShadowSocks für TCP aktiv ist. " "Andernfalls auch für TCP)" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:384 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:392 #, fuzzy msgid "" "Set the default VPN used for ICMP (and UDP if proxy used is shadowsocks), " @@ -1009,14 +1034,14 @@ msgstr "" "Auswahl des VPNs für UDP und ICMP (Sofern ShadowSocks für TCP aktiv ist. " "Andernfalls auch für TCP)" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:943 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:998 msgid "" "Set value between 80-95% of max download speed link. 0 to disable SQM/QoS." msgstr "" "Wert von etwa 80-95% der Downstream-Bandbreite; '0' zum Abschalten von SQM/" "QoS." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:959 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1014 msgid "" "Set value between 80-95% of max upload speed link. 0 to disable SQM/QoS." msgstr "" @@ -1032,16 +1057,16 @@ msgstr "Parametrierungs-Assistent" msgid "ShadowSocks is not running" msgstr "Einstellungen ShadowSocks" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:244 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:252 msgid "ShadowSocks is used for TCP." msgstr "SchadowSocks wird für TCP genutzt." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:239 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:241 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:247 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:249 msgid "ShadowSocks key" msgstr "ShadowSocks Schlüssel" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:163 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:171 #, fuzzy msgid "Show advanced settings" msgstr "Erweiterte Einstellungen" @@ -1050,8 +1075,8 @@ msgstr "Erweiterte Einstellungen" msgid "Show all settings" msgstr "Alle Einstellungen anzeigen" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:453 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:598 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:461 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:606 msgid "Static address" msgstr "Statische Adresse" @@ -1059,7 +1084,7 @@ msgstr "Statische Adresse" msgid "Status" msgstr "Status" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:400 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:412 msgid "Systems settings" msgstr "System-Einstellungen" @@ -1070,7 +1095,7 @@ msgid "" "local end." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:278 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:286 msgid "" "There is no Advanced Encryption Standard (AES) instruction set integrated in " "the processor, you should use chacha20." @@ -1091,35 +1116,35 @@ msgid "" "retransmissions remain unacknowledged." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:263 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:269 #, fuzzy msgid "Timeout for VPS checks on status pages" msgstr "Gateway-Ping Statusüberprüfung aus" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:273 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:279 msgid "Timeout for retrieving WANs IP on status pages" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:365 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:367 msgid "Total traffic:" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:559 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:567 msgid "Type" -msgstr "" +msgstr "Typ" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:331 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:339 msgid "UBOND can replace Glorytun with connections with same latency" msgstr "" "UBOND kann ersatzweise für Glorytun genutzt werden, sofern die Verbindungen " "über identische Latenz verfügen." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:326 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:328 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:334 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:336 msgid "UBOND password" msgstr "UBOND Schlüssel" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:828 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:833 msgid "UMTS/GPRS" msgstr "" @@ -1137,17 +1162,17 @@ msgstr "automatische Aktualiserung des Servers" msgid "Update server" msgstr "Aktualisierung des Servers" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:949 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1004 msgid "Upload speed (Kb/s)" msgstr "Upstream-Bandbreite (kBit/s)" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:141 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:339 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:341 msgid "Uptime:" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:938 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:954 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:993 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1009 msgid "Used by Glorytun UDP and SQM/QoS if enabled. 0 to use default value." msgstr "" "Nutzung durch Glorytun für UDP und SQM/QoS, sofern aktiv. '0' für den " @@ -1157,34 +1182,33 @@ msgstr "" msgid "V2Ray is not running" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:254 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:262 #, fuzzy msgid "V2Ray is used for TCP and UDP." msgstr "SchadowSocks wird für TCP genutzt." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:251 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:259 msgid "V2Ray user" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:249 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:257 msgid "V2Ray user id" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:643 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:644 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:651 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:652 msgid "VLAN" msgstr "" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:184 -#, fuzzy msgid "VPN is not running" -msgstr "VPN-Einstellungen" +msgstr "VPN läuft nicht" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:286 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:294 msgid "VPN settings" msgstr "VPN-Einstellungen" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:360 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:362 msgid "VPN traffic:" msgstr "" @@ -1192,21 +1216,21 @@ msgstr "" msgid "VPN tunnel DOWN" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:258 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:264 msgid "VPS checks timeout" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:320 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:322 msgid "Version" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:268 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:274 msgid "WAN IPs retrieve timeout" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:584 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:589 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:775 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:586 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:591 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:777 msgid "Wan IP and gateway are identical" msgstr "" @@ -1216,15 +1240,20 @@ msgid "" "used to go outside." msgstr "Externe Prüfung der IP-Adressen der WAN-Adapter und der Server-IP" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:289 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:301 +#, fuzzy +msgid "When proxy V2Ray is used, use it for UDP" +msgstr "SchadowSocks wird für TCP genutzt." + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:295 msgid "When proxy shadowsocks is used, use it for UDP if VPN down" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:65 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:73 msgid "Wizard" msgstr "Assistent" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:414 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:422 msgid "World" msgstr "" @@ -1233,17 +1262,23 @@ msgstr "" msgid "You" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:918 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:934 msgid "You can enable MPTCP over VPN if your provider filter Multipath TCP." msgstr "" "'MPTCP over VPN' kann genutzt werden für Anschlüsse auf denen der Anbieter " "Multipath-TCP filtert." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:459 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:907 +msgid "" +"You can force a TTL. Some LTE provider detect tethering by inpecting packet " +"TTL value, setting it to 65 often solve the issue." +msgstr "" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:467 msgid "You can use DHCP if you have multiple real ethernet ports." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:609 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:617 msgid "" "You can use DHCP if you have multiple real ethernet ports. Select other if " "you want to use another protocol available in Network Interfaces page." @@ -1251,28 +1286,22 @@ msgstr "" "'DHCPclient' kann auf auf unabhängigen Schnittstellen genutzt werden. Andere " "Protokolle sind unter 'Netzwerk'/'Schnittstellen' einstellbar." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:204 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:212 msgid "You can use a public IPv6 prefix only if you set only one server." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:530 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:538 msgid "You must disable DHCP on your modems and set IP in different networks." msgstr "" "'DHCP' muss für diese Modems abgeschaltet und die IP-Adresse in ein andere " "Subnetz geändert werden." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:194 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:202 msgid "You should disable IPv6 here if server doesn't provide IPv6." msgstr "" "Server benötigt nutzbares IPv6. Andernfalls mit diesem Schalter die Nutzung " "sperren." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:928 -msgid "You should disable SQM for LTE or any interfaces with variable speed." -msgstr "" -"SQM sollte abgeschaltet werden für LTE und andere Verbindungen mit " -"variierender Geschwindigkeit." - #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:58 msgid "You shouldn't do that and you should redirect only needed ports" msgstr "" @@ -1286,7 +1315,7 @@ msgstr "" msgid "address:" msgstr "IPv4-Adresse" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:830 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:835 msgid "auto" msgstr "" @@ -1294,46 +1323,46 @@ msgstr "" msgid "empty key" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:504 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:506 #, fuzzy msgid "interface:" msgstr "Interface hinzufügen" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:488 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:737 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:490 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:739 #, fuzzy msgid "ip address:" msgstr "Statische Adresse" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:492 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:494 #, fuzzy msgid "ipv6 address:" msgstr "Statische Adresse" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:516 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:749 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:518 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:751 msgid "latency:" -msgstr "" +msgstr "Latenz:" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:520 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:753 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:522 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:755 msgid "mtu:" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:644 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:806 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:646 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:808 msgid "multipath:" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:524 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:526 msgid "operator:" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:269 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:277 msgid "other" msgstr "andere" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:528 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:530 msgid "phone number:" msgstr "" @@ -1341,32 +1370,36 @@ msgstr "" msgid "range:" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:532 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:534 msgid "state:" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:647 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:809 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:649 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:811 msgid "traffic control:" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:496 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:741 -#, fuzzy +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:498 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:743 msgid "wan address:" -msgstr "Statische Adresse" +msgstr "öffentliche IP Adresse:" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:500 -#, fuzzy +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:502 msgid "wan ipv6 address:" -msgstr "Statische Adresse" +msgstr "öffentliche ipv6 Adresse:" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:508 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:512 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:745 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:510 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:514 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:747 msgid "whois:" msgstr "" +#~ msgid "" +#~ "You should disable SQM for LTE or any interfaces with variable speed." +#~ msgstr "" +#~ "SQM sollte abgeschaltet werden für LTE und andere Verbindungen mit " +#~ "variierender Geschwindigkeit." + #~ msgid "Common server settings" #~ msgstr "Allgemeine Servereinstellungen" @@ -1384,3 +1417,7 @@ msgstr "" #~ msgid "Redundant" #~ msgstr "redundant" + +#, fuzzy +#~ msgid "Disable HTTP test on Server API in status page" +#~ msgstr "Server-Ping Status-Prüfung aus" diff --git a/luci-app-openmptcprouter/po/fr/openmptcprouter.po b/luci-app-openmptcprouter/po/fr/openmptcprouter.po index 001127345..c55a741bb 100755 --- a/luci-app-openmptcprouter/po/fr/openmptcprouter.po +++ b/luci-app-openmptcprouter/po/fr/openmptcprouter.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2021-06-01 06:35+0000\n" +"PO-Revision-Date: 2022-08-10 18:51+0000\n" "Last-Translator: Weblate Admin \n" "Language-Team: French \n" @@ -11,45 +11,45 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 4.6.1\n" +"X-Generator: Weblate 4.10.1\n" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:307 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:315 msgid "A Dead Simple VPN is a TCP VPN that can replace Glorytun TCP" msgstr "" "Dead Simple VPN est un VPN exploitant le protocole TCP qui peut remplacer " "Glorytun TCP" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:302 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:304 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:310 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:312 msgid "A Dead Simple VPN key" msgstr "Clef Dead Simple VPN" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:100 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:108 msgid "" "A second server's IP can be set for dual IPv4/IPv6 server if WAN IPv6 are set" msgstr "" "Si une connexion WAN a une connectivité IPv6, une seconde adresse IP peut " "être définie pour les VPS fonctionnant à la fois avec IPv4 et IPv6." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:111 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:119 msgid "API username to retrieve personnalized settings from the server." msgstr "" "Nom d'utilisateur pour récupérer la configuration personnalisée depuis le " "serveur." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:809 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:814 msgid "APN" msgstr "APN" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:734 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:742 msgid "Accept IPv6 RA" msgstr "Accepter IPv6 RA" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:156 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:164 msgid "Add a new server" msgstr "Ajouter un serveur" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:989 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1044 msgid "Add an interface" msgstr "Ajouter une interface" @@ -58,11 +58,11 @@ msgstr "Ajouter une interface" msgid "Advanced Settings" msgstr "Configuration avancée" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:161 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:169 msgid "Advanced settings" msgstr "Configuration avancée" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:384 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:392 msgid "" "All VPN available here can do aggregation over MPTCP or using own internal " "method." @@ -74,27 +74,27 @@ msgstr "" msgid "All router settings" msgstr "Tous les paramètres du routeur" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:276 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:284 msgid "" "An Advanced Encryption Standard (AES) instruction set is integrated in the " "processor." msgstr "Les instruction AES sont intégrées dans le processeur." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:835 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:840 msgid "Authentication Type" msgstr "Type d'authentification" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:873 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:889 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:878 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:894 msgid "Backup" -msgstr "Sauvegarder" +msgstr "Remplaçant" #: luci-app-openmptcprouter/luasrc/controller/openmptcprouter.lua:21 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/backup.htm:10 msgid "Backup on server" msgstr "Sauvegarde sur le serveur" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:371 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:383 msgid "Balancing" msgstr "Équilibrage" @@ -102,34 +102,42 @@ msgstr "Équilibrage" msgid "Beta" msgstr "Bêta" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:310 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:312 msgid "Big time difference between the server and the router" msgstr "Grande différence de temps entre le serveur et le routeur" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:564 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:572 msgid "Bridge" msgstr "Passerelle" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:618 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:620 msgid "Bridge can't have multipath enabled" -msgstr "Un pont ne peut avoir multipath d'activer" +msgstr "Les passerelles ne peuvent pas utiliser le protocole multipath" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:287 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:295 msgid "By default VPN is used for any traffic that is not TCP." msgstr "" "Par défaut le VPN est utilisé pour tout le trafic n'étant pas une connexion " "TCP." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:221 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:229 msgid "" "By default proxy is used for any traffic that is TCP (and UDP for V2Ray)." msgstr "" "Par défaut, le proxy est utilisé pour tout le trafic TCP (et UDP pour V2Ray)." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:840 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:845 msgid "CHAP" msgstr "CHAP" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:961 +msgid "" +"Cake queue discipline is not set, autorate will only work after a reboot if " +"enabled here." +msgstr "" +"La discipline de file d'attente Cake n'est pas définie, l'écriture ne " +"fonctionnera qu'après un redémarrage si elle est activée ici." + #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:271 msgid "Can\\'t access and use server part" msgstr "Impossible d\\'accéder et d\\'utiliser la partie serveur" @@ -150,11 +158,11 @@ msgstr "Pas d'adresse IP publique récupérée via V2Ray" msgid "Can\\'t ping server" msgstr "Pas de réponse du serveur" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:415 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:423 msgid "China" msgstr "Chine" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:568 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:576 msgid "" "Choose MacVLAN if you want to create a virtual interface based on a physical " "interface." @@ -162,9 +170,9 @@ msgstr "" "Choisissez MacVLAN si vous souhaitez créer une interface virtuelle basée sur " "une interface physique." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:502 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:588 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:647 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:510 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:596 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:655 msgid "Choose physical interface." msgstr "Choisissez l'interface physique." @@ -172,20 +180,20 @@ msgstr "Choisissez l'interface physique." msgid "Core temp:" msgstr "Température du cœur :" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:410 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:418 msgid "Country" msgstr "Pays" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:407 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:415 msgid "Country settings" msgstr "Paramètres de Pays" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:454 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:599 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:462 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:607 msgid "DHCP" msgstr "DHCP" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:600 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:608 msgid "DHCPv6" msgstr "DHCPv6" @@ -193,35 +201,35 @@ msgstr "DHCPv6" msgid "DNS issue: can\\'t resolve hostname" msgstr "Erreur DNS : impossible de résoudre des noms d\\'hôtes" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:355 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:367 msgid "Debug" msgstr "Déboguer" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:223 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:231 msgid "Default Proxy" msgstr "Proxy par défaut" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:337 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:345 msgid "Default VPN" msgstr "VPN par défaut" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:77 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:543 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:85 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:551 msgid "Delete" msgstr "Supprimer" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:741 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:768 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:789 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:749 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:774 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:794 msgid "Device" msgstr "Périphérique" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:253 -msgid "Disable HTTP test on Server API in status page" -msgstr "Désactiver le test HTTP sur l'API du serveur dans la page d'état" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:259 +msgid "Disable HTTP test on Server API" +msgstr "Désactiver le test HTTP sur l'API" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:345 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:350 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:357 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:362 msgid "Disable ModemManager" msgstr "Désactiver ModemManager" @@ -234,11 +242,11 @@ msgid "Disable TCP Fast Open on Linux and Shadowsocks configuration" msgstr "" "Désactiver TCP Fast Open sur Linux et dans la configuration de Shadowsocks" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:295 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:307 msgid "Disable default gateway" msgstr "Désactiver la passerelle par défaut" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:300 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:312 msgid "Disable default gateway, no internet if VPS are down" msgstr "" "Désactivez la passerelle par défaut, pas d'Internet si les VPS sont en panne" @@ -247,27 +255,27 @@ msgstr "" msgid "Disable external check" msgstr "Désactiver les tests externes" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:238 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:244 msgid "Disable gateway ping" msgstr "Désactiver le ping vers la passerelle" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:243 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:249 msgid "Disable gateway ping check in status page" msgstr "Désactiver le test ping de la passerelle dans la page d'état" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:279 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:285 msgid "Disable interfaces auto rename" msgstr "Désactiver le renommage automatique des interfaces" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:330 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:342 msgid "Disable multipath test using tracebox" msgstr "Désactiver le test multipath à l'aide de tracebox" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:335 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:347 msgid "Disable nDPI" msgstr "Désactiver nDPI" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:340 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:352 msgid "Disable nDPI, used for protocols in OMR-ByPass" msgstr "Désactiver nDPI, utilisé pour les protocoles dans OMR-ByPass" @@ -278,70 +286,82 @@ msgstr "" "Désactiver les redirections de ports définies dans la partie pare-feu du " "serveur vers ce routeur" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:284 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:290 msgid "Disable renaming interfaces" msgstr "Désactiver les interfaces de renommage" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:315 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:320 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:327 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:332 msgid "Disable route loop detection" msgstr "Désactiver la détection de boucle de routage" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:144 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:152 msgid "Disable server" msgstr "Désactiver le serveur" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:248 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:254 msgid "Disable server http test" msgstr "Désactiver le test HTTP vers le serveur" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:305 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:317 msgid "Disable server ping" msgstr "Désactiver le ping vers le serveur" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:310 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:322 msgid "Disable server ping status check" msgstr "Désactiver le test ping vers le serveur" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:325 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:337 msgid "Disable tracebox test" msgstr "Désactiver le test de tracebox" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:189 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:871 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:887 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:197 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:876 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:892 msgid "Disabled" msgstr "Désactiver" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:933 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:988 msgid "Download speed (Kb/s)" msgstr "Vitesse de téléchargement (Kb/s)" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:369 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:381 msgid "Dynamic change" msgstr "Changement dynamique" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:390 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:402 msgid "Enable Bridge Acceleration" msgstr "Activer l'accélération du pont" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:209 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:217 msgid "Enable DNS64" msgstr "Active DNS64" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:384 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:396 msgid "Enable Fast Patch offloading for connections" msgstr "Activer le déchargement Fast Patch pour les connexions" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:187 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:186 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:194 msgid "Enable IPv6" msgstr "Activer IPv6" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:923 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:975 +msgid "Enable QoS" +msgstr "Active QoS" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:223 +msgid "Enable SIP ALG" +msgstr "Activer SIP ALG" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:942 msgid "Enable SQM" msgstr "Active SQM" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:952 +msgid "Enable SQM autorate" +msgstr "Active SQM autoadaptatif" + #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:79 msgid "Enable ShadowSocks Obfuscating" msgstr "Activer le brouillage pour ShadowSocks" @@ -350,21 +370,21 @@ msgstr "Activer le brouillage pour ShadowSocks" msgid "Enable TCP Low Latency" msgstr "Activer la faible latence TCP" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:360 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:372 msgid "Enable debug logs" msgstr "Activer les journaux de débogage" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:190 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:870 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:886 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:198 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:875 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:891 msgid "Enabled" msgstr "Activer" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:259 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:267 msgid "Encryption" msgstr "Chiffrement" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:280 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:288 msgid "Encryption method is used for Shadowsocks, V2Ray, Glorytun and OpenVPN." msgstr "" "La méthode de chiffrement est utilisée pour Shadowsocks, V2Ray, Glorytun et " @@ -374,37 +394,41 @@ msgstr "" msgid "Filesystem is readonly" msgstr "Système de fichiers en lecture seule" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:419 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:427 msgid "For China, set an accessible DNS and disable DNSSEC." msgstr "Pour la Chine, définir un DNS accessible et désactiver DNSSEC." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:178 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:902 +msgid "Force TTL" +msgstr "Force le TTL" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:186 msgid "Force retrieve all keys from server." msgstr "Forcer la récupération de toutes les clés du serveur." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:173 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:181 msgid "Force retrieve settings" msgstr "Forcer la récupération des paramètres" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:829 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:834 msgid "GPRS only" msgstr "seulement GPRS" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:561 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:764 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:563 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:766 msgid "Gateway DOWN" msgstr "La passerelle ne répond pas" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:564 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:566 msgid "Gateway IPv6 DOWN" msgstr "La passerelle IPv6 ne répond pas" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:295 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:303 msgid "Glorytun TCP is used by default for UDP and ICMP" msgstr "Glorytun est utilisé par défaut pour UDP et ICMP" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:290 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:292 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:298 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:300 msgid "Glorytun key" msgstr "Clef Glorytun" @@ -446,40 +470,40 @@ msgstr "IPv4 TCP SYN retries1" msgid "IPv4 TCP SYN retries2" msgstr "IPv4 TCP SYN retries2" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:510 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:653 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:518 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:661 msgid "IPv4 address" msgstr "Adresse IPv4" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:669 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:677 msgid "IPv4 gateway" msgstr "Passerelle IPv4" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:516 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:663 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:524 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:671 msgid "IPv4 netmask" msgstr "Masque de sous-réseau IPv4" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:199 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:207 msgid "IPv6 Prefix" msgstr "Préfixe IPv6" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:683 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:710 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:691 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:718 msgid "IPv6 address" msgstr "Adresse IPv6" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:697 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:720 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:705 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:728 msgid "IPv6 gateway" msgstr "Passerelle IPv6" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:632 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:804 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:634 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:806 msgid "IPv6 route received" msgstr "Route IPv6 reçue" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:184 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:192 msgid "IPv6 settings" msgstr "Paramètres IPv6" @@ -487,30 +511,30 @@ msgstr "Paramètres IPv6" msgid "IPv6 tunnel DOWN" msgstr "Le tunnel IPv6 ne répond pas" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:350 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:352 msgid "IPv6:" msgstr "IPv6 :" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:214 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:222 msgid "If host support NAT64, you can enable DNS64 support." msgstr "" "Si l'hôte prend en charge NAT64, vous pouvez activer la prise en charge " "DNS64." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:529 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:537 msgid "Interfaces settings" msgstr "Paramètres des interfaces" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:244 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:254 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:295 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:307 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:319 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:331 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:252 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:262 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:303 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:315 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:327 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:339 msgid "Key is retrieved from server API by default." msgstr "La clé est récupérée de l'API du serveur par défaut." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:121 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:129 msgid "" "Key to configure and retrieve others keys from Server and to set server " "settings from OpenMPTCProuter." @@ -518,21 +542,21 @@ msgstr "" "Clef pour configurer et récupérer les autres clefs ainsi que les paramètres " "depuis le serveur." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:427 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:435 msgid "LAN interfaces settings" msgstr "Paramètres des interfaces LAN" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:827 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:832 msgid "LTE" msgstr "LTE" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:438 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:549 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:446 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:557 msgid "Label" msgstr "Étiquette" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:444 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:554 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:452 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:562 msgid "Label for the interface" msgstr "Étiquette pour l'interface" @@ -541,25 +565,25 @@ msgid "Last available backup on server:" msgstr "Dernière sauvegarde disponible sur le serveur :" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:124 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:327 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:329 msgid "Latest available version" msgstr "Dernière version disponible" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:130 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:333 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:335 msgid "Load:" msgstr "Charge :" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:628 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:630 msgid "Looping route detected" msgstr "Boucle de routage détectée" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:319 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:327 msgid "MLVPN can replace Glorytun with connections with same latency" msgstr "MLVPN peut remplacer Glorytun pour les connexions avec la même latence" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:314 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:316 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:322 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:324 msgid "MLVPN password" msgstr "Mot de passe MLVPN" @@ -567,20 +591,20 @@ msgstr "Mot de passe MLVPN" msgid "MPTCP is not enabled on the server" msgstr "MPTCP n'est pas activé sur le serveur" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:344 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:346 msgid "MPTCP may not be enabled on the server" msgstr "MPTCP semble ne pas être activé sur le serveur" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:393 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:913 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:401 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:929 msgid "MPTCP over VPN" msgstr "MPTCP sur VPN" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:390 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:398 msgid "MPTCP over VPN settings" msgstr "Paramètres MPTCP sur VPN" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:391 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:399 msgid "" "MPTCP over VPN should be used only when Multipath TCP is blocked on a " "connection." @@ -588,36 +612,36 @@ msgstr "" "MPTCP sur VPN ne doit être utilisé que lorsque Multipath TCP est bloqué sur " "une connexion." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:563 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:571 msgid "MacVLAN" msgstr "MacVLAN" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:872 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:888 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:877 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:893 msgid "Master" msgstr "Master" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:365 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:377 msgid "Master interface selection" msgstr "Sélection de l'interface maître" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:409 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:421 msgid "Maximum scaling CPU frequency" msgstr "Fréquence maximale du processeur" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:403 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:415 msgid "Minimum scaling CPU frequency" msgstr "Fréquence minimale du processeur" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:824 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:829 msgid "Modem default" msgstr "Modem par défaut" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:858 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:863 msgid "Modem init timeout" msgstr "Délai max. d'initialisation du modem" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:601 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:609 msgid "ModemManager" msgstr "ModemManager" @@ -625,51 +649,51 @@ msgstr "ModemManager" msgid "More than one default VPN is enabled" msgstr "Plus d\\'un VPN par défaut est activé" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:867 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:883 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:872 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:888 msgid "Multipath TCP" msgstr "Multipath TCP" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:601 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:607 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:787 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:793 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:603 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:609 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:789 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:795 msgid "Multipath current state is" msgstr "Multipath est actuellement" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:596 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:782 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:598 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:784 msgid "Multipath master already defined" msgstr "Maître multipath déjà défini" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:567 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:767 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:569 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:769 msgid "Multipath seems to be blocked on the connection" msgstr "Multipath semble bloquer sur la connexion" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:602 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:610 msgid "NCM" msgstr "NCM" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:838 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:843 msgid "NONE" msgstr "AUCUN" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:623 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:625 msgid "Network interface MAC address duplicated" msgstr "Adresse MAC dupliquée" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:613 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:799 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:615 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:801 msgid "Network interface duplicated" msgstr "Interface réseau dupliquée" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:579 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:581 msgid "Network interface not in WAN firewall zone" msgstr "L'interface réseau n'est pas dans la zone WAN du pare-feu" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:899 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:901 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:903 msgid "Network overview" msgstr "Aperçu réseau" @@ -677,8 +701,8 @@ msgstr "Aperçu réseau" msgid "Networks settings" msgstr "Paramètres réseaux" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:554 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:757 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:556 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:759 msgid "No IP defined" msgstr "Aucune IP définie" @@ -686,16 +710,16 @@ msgstr "Aucune IP définie" msgid "No IPv6 access" msgstr "Pas d'accès IPv6" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:575 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:577 msgid "No Server http response after 1 second" msgstr "Pas de réponse http du serveur après 1 seconde" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:571 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:771 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:573 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:773 msgid "No Server ping response after 1 second" msgstr "Pas de réponse au ping du serveur après 1 seconde" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:656 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:658 msgid "No WAN with multipath enabled:" msgstr "Pas de WAN avec le multipath activé :" @@ -703,16 +727,16 @@ msgstr "Pas de WAN avec le multipath activé :" msgid "No available backup on server." msgstr "Aucune sauvegarde disponible sur le serveur." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:370 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:382 msgid "No change" msgstr "Pas de changement" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:819 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:821 msgid "No data" msgstr "Pas de données" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:558 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:761 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:560 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:763 msgid "No gateway defined" msgstr "Aucune passerelle définie" @@ -733,12 +757,12 @@ msgstr "Pas d'adresse IP du serveur, pas d'adresse IP publique" msgid "No server defined" msgstr "Aucun serveur défini" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:265 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:413 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:273 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:421 msgid "None" msgstr "Aucun" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:562 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:570 msgid "Normal" msgstr "Normal" @@ -762,17 +786,17 @@ msgstr "Type de brouillage" msgid "Obfuscating will be enabled on both side" msgstr "Le brouillage sera activé des deux côtés" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:368 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:380 msgid "On wizard change" msgstr "En cas de changements dans l'assistant" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:233 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:241 msgid "Only ShadowSocks is supported with server multiple IPs for now." msgstr "" "Seul ShadowSocks est pris en charge pour la gestion d'un serveur ayant " "plusieurs adresses IP pour le moment." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:877 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:882 msgid "" "Only one interface must be set as \"Master\", this should be the most stable " "interface." @@ -780,12 +804,12 @@ msgstr "" "Une seule interface peut être défini comme maître. Cette interface est " "supposée être l'interface la plus stable." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:135 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:143 msgid "Only one server can be master, else all servers are set as backup." msgstr "" "Uniquement un serveur peut être maître, les autres sont définis en secours." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:391 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:399 msgid "Only work with Shadowsocks as proxy." msgstr "Ne fonctionne qu’avec Shadowsocks utilisé en proxy." @@ -793,7 +817,7 @@ msgstr "Ne fonctionne qu’avec Shadowsocks utilisé en proxy." msgid "OpenMPTCProuter" msgstr "OpenMPTCProuter" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:384 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:392 msgid "OpenVPN can't be used in multi VPS configuration." msgstr "OpenVPN ne peut pas être utilisé dans une configuration multi VPS." @@ -801,59 +825,59 @@ msgstr "OpenVPN ne peut pas être utilisé dans une configuration multi VPS." msgid "Optimize for latency instead of bandwidth" msgstr "Optimiser la latence au lieu de la bande passante" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:455 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:605 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:463 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:613 msgid "Other" msgstr "Autre" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:225 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:231 msgid "Other settings" msgstr "Autres paramètres" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:839 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:844 msgid "PAP" msgstr "PAP" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:841 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:846 msgid "PAP/CHAP" msgstr "PAP / CHAP" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:852 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:857 msgid "PAP/CHAP password" msgstr "Mot de passe PAP/CHAP" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:846 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:851 msgid "PAP/CHAP username" msgstr "Identifiant PAP/CHAP" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:815 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:820 msgid "PIN code" msgstr "Code PIN" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:603 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:611 msgid "PPPoE" msgstr "PPPoE" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:467 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:573 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:614 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:475 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:581 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:622 msgid "Physical interface" msgstr "Interface physique" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:825 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:830 msgid "Prefer LTE" msgstr "Préférer LTE" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:826 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:831 msgid "Prefer UMTS" msgstr "Préférer l'UMTS" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:94 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:102 msgid "Primary server IP" msgstr "IP principale du serveur" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:449 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:594 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:457 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:602 msgid "Protocol" msgstr "Protocole" @@ -861,19 +885,23 @@ msgstr "Protocole" msgid "Proxy is DISABLED" msgstr "Le proxy est DÉSACTIVÉ" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:220 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:228 msgid "Proxy settings" msgstr "Paramètres du Proxy" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:355 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:357 msgid "Proxy traffic:" msgstr "Trafic proxy :" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:604 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:612 msgid "QMI" msgstr "QMI" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:381 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:980 +msgid "QoS permit to prioritize any upload traffic." +msgstr "Le QoS permet de prioriser du trafic de téléchargement." + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:393 msgid "Qualcomm Shortcut FE driver" msgstr "Pilote Qualcomm Shortcut FE" @@ -881,7 +909,7 @@ msgstr "Pilote Qualcomm Shortcut FE" msgid "Redirects all ports from server to this router" msgstr "Rediriger tous les ports du serveur vers ce routeur" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:999 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1054 msgid "Reset" msgstr "Réinitialiser" @@ -889,32 +917,46 @@ msgstr "Réinitialiser" msgid "Restore backup" msgstr "Restauration de la sauvegarde" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:171 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:179 msgid "Retrieve settings from server" msgstr "Récupérer les paramètres du serveur" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:435 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:998 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:957 +msgid "SQM autorate is for LTE and connection without a stable speed." +msgstr "" +"SQM autoadaptatif est prévu pour les connexions LTE ainsi que toutes les " +"connexions n'ayant pas une vitesse stable." + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:947 +msgid "" +"SQM control bufferloat: the undesirable latency that arises when the router " +"buffers too much data." +msgstr "" +"SQM contrôle le bufferloat : la latence indésirable qui survient lorsque le " +"routeur met trop de données en mémoire tampon." + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:447 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1053 msgid "Save & Apply" msgstr "Sauvegarder et Appliquer" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:233 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:239 msgid "Save vnstats statistics on disk" msgstr "Sauvegarder les statistiques de vnstats sur le disque" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:228 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:234 msgid "Save vnstats stats" msgstr "Sauvegarder les statistiques de vnstats" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:415 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:427 msgid "Scaling governor" msgstr "Régulateur de mise à l'échelle" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:95 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:103 msgid "Secondary server IP" msgstr "IP secondaire du serveur" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:992 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1047 msgid "Select the device you want to base the interface on." msgstr "Sélectionnez le périphérique pour l'interface." @@ -922,61 +964,61 @@ msgstr "Sélectionnez le périphérique pour l'interface." msgid "Send backup" msgstr "Envoyer la sauvegarde" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:83 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:85 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:92 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:91 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:93 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:100 msgid "Server IP" msgstr "IP du serveur" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:87 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:97 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:95 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:105 msgid "Server IP will be set for proxy and VPN" msgstr "L'adresse IP du serveur sera définie pour le proxy et le VPN" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:116 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:118 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:124 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:126 msgid "Server key" msgstr "Clef du serveur" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:43 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:67 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:75 msgid "Server settings" msgstr "Paramètres du serveur" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:106 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:108 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:114 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:116 msgid "Server username" msgstr "Nom d'utilisateur sur le serveur" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:821 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:826 msgid "Service Type" msgstr "Type du service" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:401 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:409 msgid "Set VPN to use for MPTCP over VPN." msgstr "Configurez VPN à utiliser pour MPTCP sur VPN." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:658 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:688 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:715 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:666 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:696 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:723 msgid "Set an IP in the same network as the modem" msgstr "Mettez une IP dans le même réseau que le modem" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:408 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:416 msgid "Set configuration for countries with some specificities." msgstr "Définir une configuration spécifique pour certains pays." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:674 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:702 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:725 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:682 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:710 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:733 msgid "Set here IP of the modem" msgstr "Mettez ici l'IP du modem" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:130 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:138 msgid "Set server as master" msgstr "Configurer le serveur en tant que maître" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:232 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:240 msgid "" "Set the default Proxy used for TCP when ShadowSocks is enabled, for TCP and " "UDP when V2Ray is enabled." @@ -984,7 +1026,7 @@ msgstr "" "Définissez le proxy par défaut utilisé pour TCP lorsque ShadowSocks est " "activé, pour TCP et UDP lorsque V2Ray est activé." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:384 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:392 msgid "" "Set the default VPN used for ICMP (and UDP if proxy used is shadowsocks), " "for all traffic if proxy is disabled." @@ -992,14 +1034,14 @@ msgstr "" "Configure le VPN utilisé par défaut pour ICMP (et UDP si le proxy est " "ShadowSocks), pour tout le trafic quand le proxy est désactivé." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:943 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:998 msgid "" "Set value between 80-95% of max download speed link. 0 to disable SQM/QoS." msgstr "" "Réglez une valeur entre 80-95% de la vitesse de téléchargement maximale. 0 " "pour désactiver SQM/QoS." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:959 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1014 msgid "" "Set value between 80-95% of max upload speed link. 0 to disable SQM/QoS." msgstr "" @@ -1014,16 +1056,16 @@ msgstr "Assistant de configuration" msgid "ShadowSocks is not running" msgstr "ShadowSocks n'est pas lancé" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:244 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:252 msgid "ShadowSocks is used for TCP." msgstr "ShadowSocks est utilisé pour le TCP." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:239 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:241 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:247 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:249 msgid "ShadowSocks key" msgstr "Clef de ShadowSocks" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:163 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:171 msgid "Show advanced settings" msgstr "Afficher les paramètres avancés" @@ -1031,8 +1073,8 @@ msgstr "Afficher les paramètres avancés" msgid "Show all settings" msgstr "Voir tous les paramètres" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:453 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:598 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:461 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:606 msgid "Static address" msgstr "Adresse statique" @@ -1040,7 +1082,7 @@ msgstr "Adresse statique" msgid "Status" msgstr "État" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:400 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:412 msgid "Systems settings" msgstr "Paramètres systèmes" @@ -1054,7 +1096,7 @@ msgstr "" "référencée par aucune application) restera dans l'état FIN_WAIT_2 avant " "d'être abandonnée à l'extrémité locale." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:278 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:286 msgid "" "There is no Advanced Encryption Standard (AES) instruction set integrated in " "the processor, you should use chacha20." @@ -1080,34 +1122,34 @@ msgstr "" "Cette valeur influence le délai d'expiration d'une connexion TCP active, " "lorsque les retransmissions RTO ne sont pas acquittées." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:263 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:269 msgid "Timeout for VPS checks on status pages" msgstr "Délai d’expiration pour les vérifications VPS sur la page d’état" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:273 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:279 msgid "Timeout for retrieving WANs IP on status pages" msgstr "" "Délai d’expiration pour la récupération de l’adresse IP des WANs sur la " "pages d’état" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:365 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:367 msgid "Total traffic:" msgstr "Trafic total :" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:559 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:567 msgid "Type" msgstr "Type" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:331 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:339 msgid "UBOND can replace Glorytun with connections with same latency" msgstr "UBOND peut remplacer Glorytun par des connexions avec la même latence" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:326 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:328 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:334 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:336 msgid "UBOND password" msgstr "Mot de passe UBOND" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:828 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:833 msgid "UMTS/GPRS" msgstr "UMTS / GPRS" @@ -1124,17 +1166,17 @@ msgstr "Met à jour le serveur à la dernière version quand c'est nécessaire." msgid "Update server" msgstr "Mise à jour du serveur" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:949 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1004 msgid "Upload speed (Kb/s)" msgstr "Vitesse d'envoi (Kb/s)" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:141 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:339 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:341 msgid "Uptime:" msgstr "Durée de fonctionnement :" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:938 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:954 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:993 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1009 msgid "Used by Glorytun UDP and SQM/QoS if enabled. 0 to use default value." msgstr "" "Utilisé par Glorytun UDP et SQM/QoS si activé. 0 pour utiliser la valeur par " @@ -1144,20 +1186,20 @@ msgstr "" msgid "V2Ray is not running" msgstr "V2Ray n'est pas lancé" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:254 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:262 msgid "V2Ray is used for TCP and UDP." msgstr "V2Ray est utilisé pour TCP et UDP." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:251 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:259 msgid "V2Ray user" msgstr "Utilisateur V2Ray" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:249 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:257 msgid "V2Ray user id" msgstr "ID utilisateur V2Ray" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:643 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:644 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:651 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:652 msgid "VLAN" msgstr "VLAN" @@ -1165,11 +1207,11 @@ msgstr "VLAN" msgid "VPN is not running" msgstr "Le VPN n'est pas lancé" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:286 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:294 msgid "VPN settings" msgstr "Paramètres du VPN" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:360 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:362 msgid "VPN traffic:" msgstr "Trafic VPN :" @@ -1177,21 +1219,21 @@ msgstr "Trafic VPN :" msgid "VPN tunnel DOWN" msgstr "Le VPN ne répond pas" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:258 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:264 msgid "VPS checks timeout" msgstr "Délai d’expiration des contrôles VPS" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:320 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:322 msgid "Version" msgstr "Version" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:268 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:274 msgid "WAN IPs retrieve timeout" msgstr "Délai d'expiration pour la récupération des IPs WANs" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:584 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:589 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:775 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:586 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:591 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:777 msgid "Wan IP and gateway are identical" msgstr "La passerelle et l'adresse IP du WAN sont identiques" @@ -1201,17 +1243,21 @@ msgid "" "used to go outside." msgstr "Utilise des sites externes pour obtenir les IPs externes quand activé." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:289 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:301 +msgid "When proxy V2Ray is used, use it for UDP" +msgstr "Lorsque le proxy V2Ray est utilisé, l'utiliser pour UDP" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:295 msgid "When proxy shadowsocks is used, use it for UDP if VPN down" msgstr "" "Lorsque le proxy shadowsocks est utilisé, utilisez-le pour UDP si VPN en " "panne" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:65 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:73 msgid "Wizard" msgstr "Assistant" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:414 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:422 msgid "World" msgstr "Monde" @@ -1220,18 +1266,27 @@ msgstr "Monde" msgid "You" msgstr "Vous" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:918 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:934 msgid "You can enable MPTCP over VPN if your provider filter Multipath TCP." msgstr "" "Vous pouvez utiliser MTPCP over VPN si votre fournisseur filtre Multipath " "TCP." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:459 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:907 +msgid "" +"You can force a TTL. Some LTE provider detect tethering by inpecting packet " +"TTL value, setting it to 65 often solve the issue." +msgstr "" +"Vous pouvez forcer un TTL. Certains fournisseur détecte le partage de " +"connexion en inspectant la valeur TTL des paquets, une valeur de 65 règle " +"souvent le souci." + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:467 msgid "You can use DHCP if you have multiple real ethernet ports." msgstr "" "Vous pouvez utiliser DHCP si vous avez plusieurs ports Ethernet physique." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:609 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:617 msgid "" "You can use DHCP if you have multiple real ethernet ports. Select other if " "you want to use another protocol available in Network Interfaces page." @@ -1240,28 +1295,22 @@ msgstr "" "Choisissez autre si vous utilisez un autre protocole dans la page Réseau " "Interfaces." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:204 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:212 msgid "You can use a public IPv6 prefix only if you set only one server." msgstr "" "Vous ne pouvez utiliser un préfixe IPv6 public que si vous ne définissez " "qu'un seul serveur." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:530 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:538 msgid "You must disable DHCP on your modems and set IP in different networks." msgstr "" "Vous devez désactiver DHCP sur vos modems et configurer leurs IP dans des " "réseaux différents." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:194 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:202 msgid "You should disable IPv6 here if server doesn't provide IPv6." msgstr "Vous devriez désactiver IPv6 ici si le serveur ne supporte pas IPv6." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:928 -msgid "You should disable SQM for LTE or any interfaces with variable speed." -msgstr "" -"Vous devriez désactiver SQM pour la 4G ou toute interface avec une vitesse " -"très instable." - #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:58 msgid "You shouldn't do that and you should redirect only needed ports" msgstr "" @@ -1276,7 +1325,7 @@ msgstr "Votre IP n'a pas été attribuée par ce routeur" msgid "address:" msgstr "adresse :" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:830 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:835 msgid "auto" msgstr "auto" @@ -1284,43 +1333,43 @@ msgstr "auto" msgid "empty key" msgstr "clef vide" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:504 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:506 msgid "interface:" msgstr "interface :" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:488 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:737 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:490 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:739 msgid "ip address:" msgstr "adresse ip :" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:492 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:494 msgid "ipv6 address:" msgstr "adresse ipv6 :" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:516 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:749 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:518 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:751 msgid "latency:" msgstr "latence :" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:520 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:753 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:522 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:755 msgid "mtu:" msgstr "mtu :" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:644 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:806 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:646 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:808 msgid "multipath:" msgstr "multipath :" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:524 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:526 msgid "operator:" msgstr "opérateur :" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:269 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:277 msgid "other" msgstr "autre" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:528 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:530 msgid "phone number:" msgstr "Numéro de téléphone :" @@ -1328,30 +1377,36 @@ msgstr "Numéro de téléphone :" msgid "range:" msgstr "plage :" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:532 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:534 msgid "state:" msgstr "État :" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:647 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:809 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:649 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:811 msgid "traffic control:" msgstr "Contrôle du trafic :" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:496 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:741 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:498 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:743 msgid "wan address:" msgstr "adresse WAN :" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:500 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:502 msgid "wan ipv6 address:" msgstr "adresse WAN IPv6 :" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:508 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:512 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:745 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:510 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:514 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:747 msgid "whois:" msgstr "whois :" +#~ msgid "" +#~ "You should disable SQM for LTE or any interfaces with variable speed." +#~ msgstr "" +#~ "Vous devriez désactiver SQM pour la 4G ou toute interface avec une " +#~ "vitesse très instable." + #~ msgid "Common server settings" #~ msgstr "Paramètres des serveurs" @@ -1505,3 +1560,6 @@ msgstr "whois :" #~ msgid "MLVPN can replace Glorytun with connection with same latency" #~ msgstr "" #~ "MLVPN peut remplacer Glorytun pour les connexions avec la même latence" + +#~ msgid "Disable HTTP test on Server API in status page" +#~ msgstr "Désactiver le test HTTP sur l'API du serveur dans la page d'état" diff --git a/luci-app-openmptcprouter/po/it/openmptcprouter.po b/luci-app-openmptcprouter/po/it/openmptcprouter.po index 1d7926872..19c08ec9d 100755 --- a/luci-app-openmptcprouter/po/it/openmptcprouter.po +++ b/luci-app-openmptcprouter/po/it/openmptcprouter.po @@ -1,46 +1,57 @@ msgid "" msgstr "" -"PO-Revision-Date: 2020-12-01 17:19+0000\n" -"Last-Translator: Giuseppe Dipierro \n" +"PO-Revision-Date: 2022-08-12 12:08+0000\n" +"Last-Translator: Weblate Admin \n" "Language-Team: Italian \n" "Language: it\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.0.4\n" +"X-Generator: Weblate 4.10.1\n" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:315 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:307 msgid "A Dead Simple VPN is a TCP VPN that can replace Glorytun TCP" msgstr "Una Dead Simple VPN è una VPN TCP che può sostituire Glorytun TCP" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:310 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:312 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:302 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:304 msgid "A Dead Simple VPN key" msgstr "Chiave Dead Simple VPN" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:108 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:100 msgid "" "A second server's IP can be set for dual IPv4/IPv6 server if WAN IPv6 are set" msgstr "" +"Può essere impostato un secondo IP per il doppio server IPv4/IPv6 se è stato " +"impostato il server WAN IPv6" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:119 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:111 msgid "API username to retrieve personnalized settings from the server." msgstr "" "Nome utente API per recuperare le impostazioni personalizzate dal server." +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:814 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:809 msgid "APN" msgstr "APN" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:742 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:734 msgid "Accept IPv6 RA" -msgstr "" +msgstr "Accetta IPv6 RA" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:164 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:156 msgid "Add a new server" msgstr "Aggiungi un nuovo server" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1044 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:989 msgid "Add an interface" msgstr "Aggiungi un'interfaccia" @@ -50,10 +61,12 @@ msgstr "Aggiungi un'interfaccia" msgid "Advanced Settings" msgstr "Impostazioni avanzate" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:169 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:161 msgid "Advanced settings" msgstr "Impostazioni avanzate" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:392 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:384 msgid "" "All VPN available here can do aggregation over MPTCP or using own internal " @@ -66,6 +79,7 @@ msgstr "" msgid "All router settings" msgstr "Impostazioni del router" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:284 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:276 msgid "" "An Advanced Encryption Standard (AES) instruction set is integrated in the " @@ -74,10 +88,13 @@ msgstr "" "Un set di istruzioni Advanced Encryption Standard (AES) è integrato nel " "processore." +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:840 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:835 msgid "Authentication Type" msgstr "Tipo di autenticazione" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:878 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:894 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:873 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:889 msgid "Backup" @@ -88,6 +105,7 @@ msgstr "Backup" msgid "Backup on server" msgstr "Backup su server" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:383 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:371 msgid "Balancing" msgstr "Bilanciamento" @@ -96,24 +114,29 @@ msgstr "Bilanciamento" msgid "Beta" msgstr "Beta" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:312 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:310 msgid "Big time difference between the server and the router" msgstr "Grande differenza di fuso orario tra il server e il router" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:572 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:564 msgid "Bridge" msgstr "Ponte" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:620 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:618 msgid "Bridge can't have multipath enabled" -msgstr "" +msgstr "Il Bridge non può avere il multipath abilitato" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:295 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:287 msgid "By default VPN is used for any traffic that is not TCP." msgstr "" "Per impostazione predefinita, la VPN viene utilizzata per qualsiasi traffico " "che non sia TCP." +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:229 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:221 msgid "" "By default proxy is used for any traffic that is TCP (and UDP for V2Ray)." @@ -121,10 +144,17 @@ msgstr "" "Per impostazione predefinita, il proxy viene utilizzato per qualsiasi " "traffico che sia TCP (e UDP per V2Ray)." +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:845 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:840 msgid "CHAP" msgstr "CHAP" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:961 +msgid "" +"Cake queue discipline is not set, autorate will only work after a reboot if " +"enabled here." +msgstr "" + #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:271 msgid "Can\\'t access and use server part" msgstr "Impossibile accedere e utilizzare la parte server" @@ -138,18 +168,19 @@ msgid "Can\\'t get public IP address from ShadowSocks" msgstr "Impossibile ottenere un indirizzo IP pubblico da ShadowSocks" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:290 -#, fuzzy msgid "Can\\'t get public IP address from V2Ray" -msgstr "Impossibile ottenere un indirizzo IP pubblico da ShadowSocks" +msgstr "Impossibile ottenere un indirizzo IP pubblico da V2Ray" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:284 msgid "Can\\'t ping server" msgstr "Impossibile eseguire il ping del server" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:423 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:415 msgid "China" -msgstr "" +msgstr "Cina" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:576 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:568 msgid "" "Choose MacVLAN if you want to create a virtual interface based on a physical " @@ -158,6 +189,9 @@ msgstr "" "Scegli MacVLAN se desideri creare un'interfaccia virtuale basata su " "un'interfaccia fisica." +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:510 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:596 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:655 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:502 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:588 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:647 @@ -168,62 +202,74 @@ msgstr "Scegli l'interfaccia fisica." msgid "Core temp:" msgstr "Temp. Nucleo:" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:418 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:410 msgid "Country" -msgstr "" +msgstr "Nazione" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:415 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:407 -#, fuzzy msgid "Country settings" -msgstr "Impostazioni del router" +msgstr "Impostazioni nazionali del router" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:462 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:607 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:454 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:599 msgid "DHCP" msgstr "DHCP" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:608 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:600 -#, fuzzy msgid "DHCPv6" -msgstr "DHCP" +msgstr "DHCPv6" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:188 msgid "DNS issue: can\\'t resolve hostname" msgstr "Problema DNS: impossibile risolvere il nome host" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:367 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:355 msgid "Debug" msgstr "Debug" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:231 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:223 msgid "Default Proxy" msgstr "Proxy predefinito" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:345 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:337 msgid "Default VPN" msgstr "VPN predefinita" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:85 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:551 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:77 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:543 msgid "Delete" msgstr "Elimina" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:749 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:774 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:794 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:741 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:768 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:789 msgid "Device" msgstr "Dispositivo" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:253 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:259 #, fuzzy -msgid "Disable HTTP test on Server API in status page" -msgstr "Disabilitare il controllo dello stato del ping del server" +msgid "Disable HTTP test on Server API" +msgstr "Disabilitare il test HTTP sulle API Server nella pagina di stato" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:357 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:362 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:345 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:350 -#, fuzzy msgid "Disable ModemManager" -msgstr "ModemManager" +msgstr "Disabilita ModemManager" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:203 msgid "Disable TCP Fast Open" @@ -233,10 +279,12 @@ msgstr "Disabilita TCP Fast Open" msgid "Disable TCP Fast Open on Linux and Shadowsocks configuration" msgstr "Disabilita TCP Fast Open su Linux e configurazione Shadowsocks" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:307 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:295 msgid "Disable default gateway" msgstr "Disabilita il gateway predefinito" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:312 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:300 msgid "Disable default gateway, no internet if VPS are down" msgstr "" @@ -246,30 +294,32 @@ msgstr "" msgid "Disable external check" msgstr "Disabilita controllo esterno" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:244 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:238 msgid "Disable gateway ping" msgstr "Disabilita il ping del gateway" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:249 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:243 -#, fuzzy msgid "Disable gateway ping check in status page" -msgstr "Disabilitare il controllo dello stato del ping del gateway" +msgstr "Disabilita il controllo del ping del gateway nella pagina di stato" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:285 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:279 -#, fuzzy msgid "Disable interfaces auto rename" -msgstr "Disabilita il test Tracebox" +msgstr "Disabilita auto rinomina interfacce" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:342 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:330 msgid "Disable multipath test using tracebox" msgstr "Disabilita il test multipath usando tracebox" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:347 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:335 -#, fuzzy -#| msgid "Disabled" msgid "Disable nDPI" -msgstr "Disabilitato" +msgstr "Disabilita nDPI" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:352 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:340 msgid "Disable nDPI, used for protocols in OMR-ByPass" msgstr "" @@ -281,74 +331,102 @@ msgstr "" "Disabilita il reindirizzamento delle porte definito nel firewall dal server " "a questo router" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:290 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:284 -#, fuzzy msgid "Disable renaming interfaces" -msgstr "Etichetta per l'interfaccia" +msgstr "Disabilita rinomina interfaccia" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:327 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:332 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:315 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:320 #, fuzzy msgid "Disable route loop detection" msgstr "Disabilita il ping del server" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:152 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:144 msgid "Disable server" msgstr "Disabilita il server" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:254 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:248 -#, fuzzy msgid "Disable server http test" -msgstr "Disabilita il ping del server" +msgstr "Disabilita http test server" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:317 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:305 msgid "Disable server ping" msgstr "Disabilita il ping del server" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:322 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:310 msgid "Disable server ping status check" msgstr "Disabilitare il controllo dello stato del ping del server" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:337 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:325 msgid "Disable tracebox test" msgstr "Disabilita il test Tracebox" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:197 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:876 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:892 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:189 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:871 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:887 msgid "Disabled" msgstr "Disabilitato" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:988 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:933 msgid "Download speed (Kb/s)" msgstr "Velocità di download (Kb / s)" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:381 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:369 msgid "Dynamic change" msgstr "Cambiamento dinamico" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:402 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:390 msgid "Enable Bridge Acceleration" -msgstr "" +msgstr "Abilita Accelerazione modalità Bridge" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:217 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:209 -#, fuzzy msgid "Enable DNS64" -msgstr "Abilita MQ" +msgstr "Abilita DNS64" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:396 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:384 msgid "Enable Fast Patch offloading for connections" msgstr "" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:187 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:194 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:186 msgid "Enable IPv6" msgstr "Abilita IPv6" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:975 +msgid "Enable QoS" +msgstr "Abilita QoS" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:223 +msgid "Enable SIP ALG" +msgstr "Abilita SIP ALG" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:942 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:923 msgid "Enable SQM" msgstr "Abilita MQ" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:952 +#, fuzzy +msgid "Enable SQM autorate" +msgstr "Abilita MQ" + #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:79 msgid "Enable ShadowSocks Obfuscating" msgstr "Abilita l'offuscamento di ShadowSocks" @@ -357,20 +435,26 @@ msgstr "Abilita l'offuscamento di ShadowSocks" msgid "Enable TCP Low Latency" msgstr "Abilita TCP bassa latenza" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:372 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:360 msgid "Enable debug logs" msgstr "Abilita registro di debug" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:198 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:875 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:891 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:190 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:870 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:886 msgid "Enabled" msgstr "Abilitato" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:267 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:259 msgid "Encryption" msgstr "Crittografia" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:288 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:280 msgid "Encryption method is used for Shadowsocks, V2Ray, Glorytun and OpenVPN." msgstr "" @@ -381,37 +465,50 @@ msgstr "" msgid "Filesystem is readonly" msgstr "Il filesystem è di sola lettura" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:427 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:419 msgid "For China, set an accessible DNS and disable DNSSEC." +msgstr "Per la Cina, imposta un DNS accessibile e disabilita DNSSEC." + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:902 +msgid "Force TTL" msgstr "" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:186 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:178 msgid "Force retrieve all keys from server." msgstr "Forza il recupero di tutte le chiavi dal server." +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:181 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:173 msgid "Force retrieve settings" msgstr "Forza il recupero delle impostazioni" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:834 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:829 msgid "GPRS only" msgstr "Solo GPRS" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:563 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:766 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:561 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:764 msgid "Gateway DOWN" msgstr "Tipi di pagamento" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:566 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:564 -#, fuzzy msgid "Gateway IPv6 DOWN" -msgstr "Tipi di pagamento" +msgstr "Gateway IPV6 non raggiungibile" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:303 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:295 msgid "Glorytun TCP is used by default for UDP and ICMP" msgstr "" "Glorytun TCP viene utilizzato per impostazione predefinita per UDP e ICMP" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:298 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:300 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:290 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:292 msgid "Glorytun key" @@ -455,41 +552,52 @@ msgstr "IPv4 TCP SYN retries1" msgid "IPv4 TCP SYN retries2" msgstr "IPv4 TCP SYN retries2" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:518 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:661 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:510 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:653 msgid "IPv4 address" msgstr "Indirizzi IPv4" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:677 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:669 msgid "IPv4 gateway" msgstr "Gateway IPv4" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:524 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:671 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:516 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:663 msgid "IPv4 netmask" msgstr "Netmask IPv4" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:207 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:199 msgid "IPv6 Prefix" msgstr "Prefisso IPv6" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:691 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:718 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:683 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:710 -#, fuzzy msgid "IPv6 address" -msgstr "Indirizzi IPv4" +msgstr "Indirizzi IPv6" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:705 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:728 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:697 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:720 -#, fuzzy msgid "IPv6 gateway" -msgstr "Gateway IPv4" +msgstr "Gateway IPv6" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:634 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:806 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:632 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:804 msgid "IPv6 route received" msgstr "Instradamento IPv6 ricevuto" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:192 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:184 msgid "IPv6 settings" msgstr "Impostazioni IPv6" @@ -498,18 +606,27 @@ msgstr "Impostazioni IPv6" msgid "IPv6 tunnel DOWN" msgstr "Tunnel IPv6 GIÙ" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:352 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:350 msgid "IPv6:" msgstr "IPv6:" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:222 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:214 msgid "If host support NAT64, you can enable DNS64 support." -msgstr "" +msgstr "Se l'host supporta NAT64, puoi abilitare il supporto DNS64." +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:537 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:529 msgid "Interfaces settings" msgstr "Impostazioni delle interfacce" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:252 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:262 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:303 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:315 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:327 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:339 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:244 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:254 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:295 @@ -521,6 +638,7 @@ msgstr "" "La chiave viene recuperata dall'API del server per impostazione " "predefinita." +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:129 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:121 msgid "" "Key to configure and retrieve others keys from Server and to set server " @@ -529,19 +647,25 @@ msgstr "" "Tasto per configurare e recuperare altre chiavi dal server e per impostare " "le impostazioni del server da OpenMPTCProuter." +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:435 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:427 msgid "LAN interfaces settings" msgstr "Impostazioni delle interfacce LAN" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:832 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:827 msgid "LTE" msgstr "LTE" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:446 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:557 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:438 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:549 msgid "Label" msgstr "Etichetta" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:452 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:562 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:444 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:554 msgid "Label for the interface" @@ -552,23 +676,29 @@ msgid "Last available backup on server:" msgstr "Ultimo backup disponibile sul server:" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:124 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:329 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:327 msgid "Latest available version" msgstr "Ultima versione disponibile" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:130 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:335 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:333 msgid "Load:" msgstr "Carico:" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:630 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:628 msgid "Looping route detected" msgstr "" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:327 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:319 msgid "MLVPN can replace Glorytun with connections with same latency" msgstr "MLVPN può sostituire Glorytun con connessioni con la stessa latenza" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:322 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:324 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:314 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:316 msgid "MLVPN password" @@ -578,55 +708,70 @@ msgstr "Password MLVPN" msgid "MPTCP is not enabled on the server" msgstr "MPTCP non è abilitato sul server" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:346 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:344 msgid "MPTCP may not be enabled on the server" msgstr "MPTCP non è abilitato sul server" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:401 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:929 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:393 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:913 msgid "MPTCP over VPN" msgstr "MPTCP su VPN" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:398 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:390 -#, fuzzy msgid "MPTCP over VPN settings" -msgstr "MPTCP su VPN" +msgstr "Impostazioni MPTCP su VPN" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:399 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:391 msgid "" "MPTCP over VPN should be used only when Multipath TCP is blocked on a " "connection." msgstr "" +"MPTCP su VPN deve essere usato solo quando il Multipath TCP è bloccatp su " +"una connessione." +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:571 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:563 msgid "MacVLAN" msgstr "MacVLAN" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:877 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:893 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:872 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:888 msgid "Master" msgstr "Principale" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:377 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:365 msgid "Master interface selection" msgstr "Selezione dell'interfaccia principale" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:421 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:409 msgid "Maximum scaling CPU frequency" msgstr "Frequenza CPU di ridimensionamento massima" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:415 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:403 msgid "Minimum scaling CPU frequency" msgstr "Frequenza CPU con ridimensionamento minimo" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:829 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:824 msgid "Modem default" msgstr "Impostazione predefinita del modem" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:863 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:858 msgid "Modem init timeout" msgstr "Timeout inizializzazione modem" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:609 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:601 msgid "ModemManager" msgstr "ModemManager" @@ -635,11 +780,17 @@ msgstr "ModemManager" msgid "More than one default VPN is enabled" msgstr "È abilitata più di una VPN predefinita" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:872 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:888 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:867 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:883 msgid "Multipath TCP" msgstr "Multipath TCP" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:603 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:609 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:789 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:795 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:601 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:607 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:787 @@ -647,41 +798,50 @@ msgstr "Multipath TCP" msgid "Multipath current state is" msgstr "Lo stato corrente di Multipath è" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:598 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:784 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:596 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:782 msgid "Multipath master already defined" -msgstr "Multipath master già definito" +msgstr "Multipath principale già definito" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:569 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:769 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:567 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:767 msgid "Multipath seems to be blocked on the connection" msgstr "Multipath sembra essere bloccato sulla connessione" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:610 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:602 msgid "NCM" msgstr "NCM" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:843 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:838 msgid "NONE" msgstr "NESSUNO" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:625 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:623 -#, fuzzy msgid "Network interface MAC address duplicated" -msgstr "Interfaccia di rete duplicata" +msgstr "Interfaccia di rete con MAC address duplicata" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:615 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:801 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:613 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:799 msgid "Network interface duplicated" msgstr "Interfaccia di rete duplicata" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:581 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:579 -#, fuzzy msgid "Network interface not in WAN firewall zone" -msgstr "Interfaccia di rete duplicata" +msgstr "Interfaccia di rete non in WAN firewall zone" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:899 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:901 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:903 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:899 msgid "Network overview" msgstr "Panoramica della rete" @@ -689,6 +849,8 @@ msgstr "Panoramica della rete" msgid "Networks settings" msgstr "Impostazioni reti" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:556 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:759 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:554 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:757 msgid "No IP defined" @@ -698,32 +860,39 @@ msgstr "Nessun IP definito" msgid "No IPv6 access" msgstr "Nessun accesso IPv6" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:577 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:575 -#, fuzzy msgid "No Server http response after 1 second" -msgstr "Nessuna risposta al ping del server dopo 1 secondo" +msgstr "Nessuna risposta dal server HTTP dopo 1 secondo" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:573 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:773 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:571 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:771 msgid "No Server ping response after 1 second" -msgstr "Nessuna risposta al ping del server dopo 1 secondo" +msgstr "Nessuna risposta al ping dal server dopo 1 secondo" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:658 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:656 msgid "No WAN with multipath enabled:" -msgstr "" +msgstr "Nessuna WAN con multipath abilitata:" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/backup.htm:26 msgid "No available backup on server." msgstr "Nessun backup disponibile sul server." +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:382 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:370 msgid "No change" msgstr "Nessun cambiamento" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:821 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:819 msgid "No data" msgstr "Nessun dato" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:560 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:763 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:558 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:761 msgid "No gateway defined" @@ -735,24 +904,25 @@ msgid "No output" msgstr "Nessun output" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:293 -#, fuzzy msgid "No public IP address detected in less than 1 second" -msgstr "Nessun indirizzo IP WAN rilevato in meno di 1 secondo" +msgstr "Nessun indirizzo IP pubblico rilevato in meno di 1 secondo" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:267 -#, fuzzy msgid "No server IP address, No public IP address" -msgstr "Nessun indirizzo IP del server, nessun indirizzo IP WAN" +msgstr "Nessun indirizzo IP del server, nessun indirizzo IP pubblico" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:280 msgid "No server defined" msgstr "Nessun server definito" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:273 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:421 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:265 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:413 msgid "None" msgstr "Nessuno" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:570 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:562 msgid "Normal" msgstr "Normale" @@ -777,34 +947,42 @@ msgstr "Tipo di offuscamento" msgid "Obfuscating will be enabled on both side" msgstr "L'offuscamento sarà abilitato su entrambi i lati" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:380 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:368 msgid "On wizard change" msgstr "Al cambio della procedura guidata" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:241 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:233 msgid "Only ShadowSocks is supported with server multiple IPs for now." -msgstr "" +msgstr "Solo ShadowSocks è supportato con server multi IP per adesso." +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:882 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:877 msgid "" "Only one interface must be set as \"Master\", this should be the most stable " "interface." msgstr "" +"Solo un' interfaccia può essere impostata come \"Master\", deve essere " +"impostata l'interfaccia più stabile." +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:143 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:135 msgid "Only one server can be master, else all servers are set as backup." msgstr "" "Solo un server può essere master, altrimenti tutti i server sono impostati " "come backup." +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:399 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:391 msgid "Only work with Shadowsocks as proxy." -msgstr "" +msgstr "Funziona solo con Shadowsocks come proxy." #: luci-app-openmptcprouter/root/usr/share/luci/menu.d/luci-app-openmptcprouter.json:3 msgid "OpenMPTCProuter" msgstr "OpenMPTCProuter" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:392 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:384 msgid "OpenVPN can't be used in multi VPS configuration." msgstr "OpenVPN non può essere utilizzato nella configurazione multi VPS." @@ -813,58 +991,74 @@ msgstr "OpenVPN non può essere utilizzato nella configurazione multi VPS." msgid "Optimize for latency instead of bandwidth" msgstr "Ottimizza per la latenza invece che per la larghezza di banda" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:463 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:613 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:455 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:605 msgid "Other" msgstr "Altro" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:231 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:225 msgid "Other settings" msgstr "Altre impostazioni" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:844 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:839 msgid "PAP" msgstr "PAP" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:846 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:841 msgid "PAP/CHAP" msgstr "PAP/CHAP" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:857 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:852 msgid "PAP/CHAP password" msgstr "PAP/CHAP password" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:851 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:846 msgid "PAP/CHAP username" msgstr "Nome utente PAP/CHAP" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:820 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:815 msgid "PIN code" msgstr "Codice PIN" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:611 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:603 msgid "PPPoE" msgstr "PPPoE" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:475 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:581 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:622 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:467 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:573 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:614 msgid "Physical interface" msgstr "Interfaccia fisica" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:830 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:825 msgid "Prefer LTE" msgstr "Preferisci LTE" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:831 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:826 msgid "Prefer UMTS" msgstr "Preferisci UMTS" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:102 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:94 -#, fuzzy msgid "Primary server IP" -msgstr "Indirizzo IP del server" +msgstr "IP principale del server" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:457 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:602 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:449 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:594 msgid "Protocol" @@ -874,18 +1068,26 @@ msgstr "Protocollo" msgid "Proxy is DISABLED" msgstr "Il proxy è DISABILITATO" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:228 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:220 msgid "Proxy settings" msgstr "Impostazioni Proxy" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:357 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:355 msgid "Proxy traffic:" msgstr "Traffico proxy:" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:612 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:604 msgid "QMI" msgstr "QMI" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:980 +msgid "QoS permit to prioritize any upload traffic." +msgstr "" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:393 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:381 msgid "Qualcomm Shortcut FE driver" msgstr "" @@ -894,40 +1096,58 @@ msgstr "" msgid "Redirects all ports from server to this router" msgstr "Reindirizza tutte le porte dal server a questo router" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1054 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:999 msgid "Reset" -msgstr "" +msgstr "Resetta" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/backup.htm:32 msgid "Restore backup" msgstr "Ripristina backup" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:179 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:171 msgid "Retrieve settings from server" msgstr "Recupera le impostazioni dal server" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:957 +msgid "SQM autorate is for LTE and connection without a stable speed." +msgstr "" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:947 +msgid "" +"SQM control bufferloat: the undesirable latency that arises when the router " +"buffers too much data." +msgstr "" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:447 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1053 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:435 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:998 msgid "Save & Apply" msgstr "Salva e applica" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:239 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:233 msgid "Save vnstats statistics on disk" msgstr "Salva le statistiche di vnstats su disco" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:234 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:228 msgid "Save vnstats stats" msgstr "Salva le statistiche di vnstats" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:427 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:415 msgid "Scaling governor" msgstr "Governatore in scala" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:103 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:95 -#, fuzzy msgid "Secondary server IP" -msgstr "Indirizzo IP del server" +msgstr "IP secondario del server" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1047 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:992 msgid "Select the device you want to base the interface on." msgstr "Seleziona il dispositivo su cui vuoi basare l'interfaccia." @@ -936,60 +1156,81 @@ msgstr "Seleziona il dispositivo su cui vuoi basare l'interfaccia." msgid "Send backup" msgstr "Invia backup" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:91 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:93 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:100 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:83 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:85 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:92 msgid "Server IP" msgstr "Indirizzo IP del server" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:95 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:105 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:87 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:97 msgid "Server IP will be set for proxy and VPN" msgstr "L'IP del server verrà impostato per proxy e VPN" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:124 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:126 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:116 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:118 msgid "Server key" msgstr "Chiave server" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:43 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:75 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:67 msgid "Server settings" msgstr "Impostazioni server" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:114 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:116 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:106 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:108 msgid "Server username" msgstr "Nome utente del server" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:826 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:821 msgid "Service Type" msgstr "Tipo di servizio" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:409 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:401 msgid "Set VPN to use for MPTCP over VPN." -msgstr "" +msgstr "Seleziona la VPN da utilizzare per MPTCP su VPN." +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:666 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:696 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:723 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:658 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:688 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:715 msgid "Set an IP in the same network as the modem" msgstr "Imposta un IP nella stessa rete del modem" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:416 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:408 msgid "Set configuration for countries with some specificities." msgstr "" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:682 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:710 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:733 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:674 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:702 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:725 msgid "Set here IP of the modem" msgstr "Imposta qui l'IP del modem" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:138 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:130 msgid "Set server as master" msgstr "Imposta server come master" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:240 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:232 msgid "" "Set the default Proxy used for TCP when ShadowSocks is enabled, for TCP and " @@ -998,6 +1239,7 @@ msgstr "" "Imposta il proxy predefinito utilizzato per TCP quando ShadowSocks è " "abilitato, per TCP e UDP quando V2Ray è abilitato." +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:392 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:384 #, fuzzy msgid "" @@ -1007,6 +1249,7 @@ msgstr "" "Imposta la VPN predefinita utilizzata per UDP e ICMP quando ShadowSocks è " "abilitato, per tutto il traffico se ShadowSocks è disabilitato." +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:998 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:943 msgid "" "Set value between 80-95% of max download speed link. 0 to disable SQM/QoS." @@ -1014,6 +1257,7 @@ msgstr "" "Impostare il valore tra l'80 e il 95% della velocità massima di download " "del collegamento" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1014 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:959 msgid "" "Set value between 80-95% of max upload speed link. 0 to disable SQM/QoS." @@ -1029,15 +1273,19 @@ msgstr "Configurazione guidata" msgid "ShadowSocks is not running" msgstr "ShadowSocks non è in esecuzione" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:252 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:244 msgid "ShadowSocks is used for TCP." msgstr "ShadowSocks viene utilizzato per TCP." +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:247 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:249 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:239 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:241 msgid "ShadowSocks key" msgstr "Chiave ShadowSocks" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:171 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:163 #, fuzzy msgid "Show advanced settings" @@ -1047,6 +1295,8 @@ msgstr "Impostazioni avanzate" msgid "Show all settings" msgstr "Mostra tutte le impostazioni" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:461 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:606 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:453 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:598 msgid "Static address" @@ -1056,6 +1306,7 @@ msgstr "Indirizzo statico" msgid "Status" msgstr "Stato proprietà" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:412 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:400 msgid "Systems settings" msgstr "Impostazioni di sistema" @@ -1070,6 +1321,7 @@ msgstr "" "alcuna applicazione) rimarrà nello stato FIN_WAIT_2 prima che venga " "interrotta all'estremità locale." +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:286 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:278 msgid "" "There is no Advanced Encryption Standard (AES) instruction set integrated in " @@ -1096,32 +1348,40 @@ msgstr "" "Questo valore influenza il timeout di una connessione TCP attiva, quando le " "ritrasmissioni RTO rimangono non riconosciute." +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:269 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:263 #, fuzzy msgid "Timeout for VPS checks on status pages" msgstr "Disabilitare il controllo dello stato del ping del gateway" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:279 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:273 msgid "Timeout for retrieving WANs IP on status pages" msgstr "" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:367 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:365 msgid "Total traffic:" msgstr "Traffico globale:" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:567 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:559 msgid "Type" msgstr "Tipo" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:339 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:331 msgid "UBOND can replace Glorytun with connections with same latency" msgstr "UBOND può sostituire Glorytun con connessioni con la stessa latenza" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:334 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:336 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:326 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:328 msgid "UBOND password" msgstr "Password UBOND" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:833 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:828 msgid "UMTS/GPRS" msgstr "UMTS/GPRS" @@ -1131,60 +1391,70 @@ msgid "Update" msgstr "Aggiorna" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:22 -#, fuzzy msgid "Update remotly servers to latest version and reboot them." -msgstr "" -"Aggiorna in remoto il server alla versione più recente quando necessario." +msgstr "Aggiorna i server remoti all'ultima versione e riavviali." #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:20 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:24 msgid "Update server" msgstr "Aggiorna server" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1004 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:949 msgid "Upload speed (Kb/s)" msgstr "Velocità di caricamento (Kb / s)" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:141 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:341 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:339 msgid "Uptime:" msgstr "Tempo di funzionamento:" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:993 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1009 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:938 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:954 msgid "Used by Glorytun UDP and SQM/QoS if enabled. 0 to use default value." -msgstr "Utilizzato da Glorytun UDP e SQM / QoS se abilitato." +msgstr "" +"Utilizzato da Glorytun UDP e SQM / QoS se abilitato. 0 per usare i valori " +"predefiniti." #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:170 msgid "V2Ray is not running" msgstr "V2Ray non è in esecuzione" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:262 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:254 msgid "V2Ray is used for TCP and UDP." msgstr "V2Ray è utilizzato per TCP e UDP." +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:259 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:251 msgid "V2Ray user" msgstr "Utente V2Ray" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:257 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:249 msgid "V2Ray user id" msgstr "ID utente V2Ray" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:651 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:652 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:643 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:644 -#, fuzzy msgid "VLAN" -msgstr "MacVLAN" +msgstr "VLAN" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:184 msgid "VPN is not running" msgstr "VPN non è in esecuzione" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:294 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:286 msgid "VPN settings" msgstr "Impostazioni VPN" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:362 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:360 msgid "VPN traffic:" msgstr "Traffico VPN:" @@ -1193,18 +1463,24 @@ msgstr "Traffico VPN:" msgid "VPN tunnel DOWN" msgstr "Tunnel VPN non stabilito" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:264 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:258 msgid "VPS checks timeout" msgstr "" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:322 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:320 msgid "Version" msgstr "Versione" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:274 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:268 msgid "WAN IPs retrieve timeout" msgstr "" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:586 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:591 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:777 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:584 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:589 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:775 @@ -1219,14 +1495,22 @@ msgstr "" "Quando si abilita il controllo viene eseguito su siti esterni per ottenere " "ogni IP WAN e l'IP utilizzato per uscire." +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:301 +#, fuzzy +msgid "When proxy V2Ray is used, use it for UDP" +msgstr "V2Ray è utilizzato per TCP e UDP." + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:295 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:289 msgid "When proxy shadowsocks is used, use it for UDP if VPN down" msgstr "" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:73 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:65 msgid "Wizard" -msgstr "Wizard" +msgstr "Procedura guidata" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:422 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:414 msgid "World" msgstr "" @@ -1236,42 +1520,48 @@ msgstr "" msgid "You" msgstr "Ti" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:934 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:918 msgid "You can enable MPTCP over VPN if your provider filter Multipath TCP." msgstr "Puoi abilitare MPTCP su VPN se il tuo provider filtra Multipath TCP." +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:907 +msgid "" +"You can force a TTL. Some LTE provider detect tethering by inpecting packet " +"TTL value, setting it to 65 often solve the issue." +msgstr "" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:467 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:459 msgid "You can use DHCP if you have multiple real ethernet ports." msgstr "Puoi usare DHCP se hai più porte ethernet reali." +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:617 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:609 msgid "" "You can use DHCP if you have multiple real ethernet ports. Select other if " "you want to use another protocol available in Network Interfaces page." msgstr "Puoi usare DHCP se hai una WAN per ogni interfaccia." +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:212 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:204 msgid "You can use a public IPv6 prefix only if you set only one server." msgstr "" "È possibile utilizzare un prefisso IPv6 pubblico solo se si imposta un solo " "server." +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:538 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:530 msgid "You must disable DHCP on your modems and set IP in different networks." msgstr "" "È necessario disabilitare il DHCP sui modem e impostare l'IP in reti " "diverse." +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:202 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:194 msgid "You should disable IPv6 here if server doesn't provide IPv6." msgstr "Dovresti disabilitare IPv6 qui se il server non fornisce IPv6." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:928 -msgid "You should disable SQM for LTE or any interfaces with variable speed." -msgstr "" -"È necessario disabilitare SQM per LTE o qualsiasi interfaccia con velocità " -"variabile." - #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:58 msgid "You shouldn't do that and you should redirect only needed ports" msgstr "" @@ -1284,6 +1574,7 @@ msgstr "Il tuo IP non è stato affittato da questo router" msgid "address:" msgstr "Indirizzo:" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:835 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:830 msgid "auto" msgstr "Auto" @@ -1292,44 +1583,57 @@ msgstr "Auto" msgid "empty key" msgstr "chiave vuota" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:506 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:504 #, fuzzy msgid "interface:" msgstr "Aggiungi un'interfaccia" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:490 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:739 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:488 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:737 msgid "ip address:" msgstr "Indirizzo IP:" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:494 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:492 #, fuzzy msgid "ipv6 address:" msgstr "Indirizzo IP:" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:518 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:751 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:516 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:749 msgid "latency:" msgstr "latenza:" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:522 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:755 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:520 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:753 msgid "mtu:" msgstr "mtu:" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:646 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:808 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:644 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:806 msgid "multipath:" msgstr "multipath:" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:526 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:524 msgid "operator:" msgstr "operatore:" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:277 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:269 msgid "other" msgstr "Altro" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:530 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:528 msgid "phone number:" msgstr "numero di telefono:" @@ -1338,31 +1642,50 @@ msgstr "numero di telefono:" msgid "range:" msgstr "intervallo:" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:534 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:532 msgid "state:" msgstr "stato:" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:649 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:811 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:647 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:809 msgid "traffic control:" msgstr "controllo del traffico:" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:498 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:743 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:496 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:741 msgid "wan address:" msgstr "indirizzo wan:" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:502 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:500 #, fuzzy msgid "wan ipv6 address:" msgstr "indirizzo wan:" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:510 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:514 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:747 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:508 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:512 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:745 msgid "whois:" msgstr "whois:" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:928 +msgid "You should disable SQM for LTE or any interfaces with variable speed." +msgstr "" +"È necessario disabilitare SQM per LTE o qualsiasi interfaccia con velocità " +"variabile." + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:253 +msgid "Disable HTTP test on Server API in status page" +msgstr "Disabilitare il test HTTP sulle API Server nella pagina di stato" + #~ msgid "Common server settings" #~ msgstr "Impostazioni comuni del server" diff --git a/luci-app-openmptcprouter/po/oc/openmptcprouter.po b/luci-app-openmptcprouter/po/oc/openmptcprouter.po index 1d932aebe..f2f82cd0d 100755 --- a/luci-app-openmptcprouter/po/oc/openmptcprouter.po +++ b/luci-app-openmptcprouter/po/oc/openmptcprouter.po @@ -1,49 +1,49 @@ msgid "" msgstr "" -"PO-Revision-Date: 2020-10-19 09:37+0000\n" -"Last-Translator: Quentin PAGÈS \n" +"PO-Revision-Date: 2022-08-12 12:08+0000\n" +"Last-Translator: Weblate Admin \n" "Language-Team: Occitan \n" "Language: oc\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 4.0.4\n" +"X-Generator: Weblate 4.10.1\n" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:307 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:315 msgid "A Dead Simple VPN is a TCP VPN that can replace Glorytun TCP" msgstr "A Dead Simple VPN es un VPN TCP que pòt remplaçat Glorytun TCP" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:302 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:304 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:310 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:312 msgid "A Dead Simple VPN key" msgstr "Clau Dead Simple VPN" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:100 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:108 msgid "" "A second server's IP can be set for dual IPv4/IPv6 server if WAN IPv6 are set" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:111 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:119 msgid "API username to retrieve personnalized settings from the server." msgstr "" "Nom d’utilizaire per recuperar la configuracion personalizada del servidor " "estant." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:809 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:814 msgid "APN" msgstr "APN" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:734 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:742 msgid "Accept IPv6 RA" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:156 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:164 #, fuzzy msgid "Add a new server" msgstr "Ajustar un servidor" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:989 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1044 msgid "Add an interface" msgstr "Ajustar una interfàcia" @@ -52,11 +52,11 @@ msgstr "Ajustar una interfàcia" msgid "Advanced Settings" msgstr "Paramètres avançats" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:161 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:169 msgid "Advanced settings" msgstr "Paramètres avançats" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:384 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:392 msgid "" "All VPN available here can do aggregation over MPTCP or using own internal " "method." @@ -68,18 +68,18 @@ msgstr "" msgid "All router settings" msgstr "Totes los paramètres del router" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:276 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:284 msgid "" "An Advanced Encryption Standard (AES) instruction set is integrated in the " "processor." msgstr "Las instruccions AES son integradas al processor." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:835 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:840 msgid "Authentication Type" msgstr "Tipe d’autentificacion" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:873 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:889 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:878 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:894 msgid "Backup" msgstr "Salvagarda" @@ -88,7 +88,7 @@ msgstr "Salvagarda" msgid "Backup on server" msgstr "Salvagarda sul servidor" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:371 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:383 msgid "Balancing" msgstr "Equilibratge" @@ -96,32 +96,38 @@ msgstr "Equilibratge" msgid "Beta" msgstr "Beta" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:310 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:312 msgid "Big time difference between the server and the router" msgstr "Granda diferéncia de temps entre lo servidor e lo router" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:564 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:572 msgid "Bridge" msgstr "Pont" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:618 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:620 msgid "Bridge can't have multipath enabled" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:287 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:295 msgid "By default VPN is used for any traffic that is not TCP." msgstr "Per defaut lo VPN es utilizat pel trafic qu’es pas TCP." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:221 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:229 #, fuzzy msgid "" "By default proxy is used for any traffic that is TCP (and UDP for V2Ray)." msgstr "Per defaut lo VPN es utilizat pel trafic qu’es pas TCP." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:840 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:845 msgid "CHAP" msgstr "CHAP" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:961 +msgid "" +"Cake queue discipline is not set, autorate will only work after a reboot if " +"enabled here." +msgstr "" + #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:271 msgid "Can\\'t access and use server part" msgstr "Accès e utilizacion impossible la part servidor" @@ -142,19 +148,19 @@ msgstr "" msgid "Can\\'t ping server" msgstr "Cap de responsa del servidor" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:415 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:423 msgid "China" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:568 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:576 msgid "" "Choose MacVLAN if you want to create a virtual interface based on a physical " "interface." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:502 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:588 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:647 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:510 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:596 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:655 msgid "Choose physical interface." msgstr "Causissètz l’interfàcia fisica." @@ -162,21 +168,21 @@ msgstr "Causissètz l’interfàcia fisica." msgid "Core temp:" msgstr "Temperatura del còr :" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:410 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:418 msgid "Country" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:407 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:415 #, fuzzy msgid "Country settings" msgstr "Totes los paramètres del router" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:454 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:599 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:462 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:607 msgid "DHCP" msgstr "DHCP" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:600 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:608 #, fuzzy msgid "DHCPv6" msgstr "DHCP" @@ -185,37 +191,37 @@ msgstr "DHCP" msgid "DNS issue: can\\'t resolve hostname" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:355 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:367 msgid "Debug" msgstr "Desbugatge" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:223 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:231 #, fuzzy msgid "Default Proxy" msgstr "VPN per defaut" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:337 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:345 msgid "Default VPN" msgstr "VPN per defaut" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:77 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:543 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:85 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:551 msgid "Delete" msgstr "Suprimir" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:741 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:768 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:789 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:749 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:774 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:794 msgid "Device" msgstr "Periferic" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:253 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:259 #, fuzzy -msgid "Disable HTTP test on Server API in status page" +msgid "Disable HTTP test on Server API" msgstr "Desactivar la pròva ping cap al servidor" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:345 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:350 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:357 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:362 #, fuzzy msgid "Disable ModemManager" msgstr "ModemManager" @@ -230,12 +236,12 @@ msgstr "" "Desactivacion de TCP Fast Open per Lunix e dins la configuracion de " "Shadowsocks" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:295 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:307 #, fuzzy msgid "Disable default gateway" msgstr "Desactivar lo ping cap a la palanca" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:300 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:312 msgid "Disable default gateway, no internet if VPS are down" msgstr "" @@ -243,31 +249,30 @@ msgstr "" msgid "Disable external check" msgstr "Desactivar las pròvas extèrnas" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:238 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:244 msgid "Disable gateway ping" msgstr "Desactivar lo ping cap a la palanca" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:243 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:249 #, fuzzy msgid "Disable gateway ping check in status page" msgstr "Desactiva la pròva ping de la palanca" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:279 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:285 #, fuzzy msgid "Disable interfaces auto rename" msgstr "Desactivar las pròvas extèrnas" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:330 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:342 msgid "Disable multipath test using tracebox" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:335 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:347 #, fuzzy -#| msgid "Disabled" msgid "Disable nDPI" msgstr "Desactivat" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:340 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:352 msgid "Disable nDPI, used for protocols in OMR-ByPass" msgstr "" @@ -278,76 +283,89 @@ msgstr "" "Desactivar las redireccions de pòrts definits dins la part para-fuòc del " "servidor cap a aqueste router" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:284 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:290 #, fuzzy msgid "Disable renaming interfaces" msgstr "Etiqueta per l’interfàcia" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:315 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:320 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:327 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:332 #, fuzzy msgid "Disable route loop detection" msgstr "Desactivar lo ping cap al servidor" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:144 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:152 #, fuzzy msgid "Disable server" msgstr "Desactivar lo ping cap al servidor" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:248 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:254 #, fuzzy msgid "Disable server http test" msgstr "Desactivar lo ping cap al servidor" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:305 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:317 msgid "Disable server ping" msgstr "Desactivar lo ping cap al servidor" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:310 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:322 msgid "Disable server ping status check" msgstr "Desactivar la pròva ping cap al servidor" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:325 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:337 #, fuzzy msgid "Disable tracebox test" msgstr "Desactivar las pròvas extèrnas" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:189 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:871 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:887 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:197 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:876 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:892 msgid "Disabled" msgstr "Desactivat" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:933 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:988 msgid "Download speed (Kb/s)" msgstr "Velocitat de telecargament (Kb/s)" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:369 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:381 msgid "Dynamic change" msgstr "Cambiament dinamic" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:390 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:402 msgid "Enable Bridge Acceleration" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:209 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:217 #, fuzzy msgid "Enable DNS64" msgstr "Active SQM" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:384 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:396 msgid "Enable Fast Patch offloading for connections" msgstr "" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:187 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:186 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:194 msgid "Enable IPv6" msgstr "Activar l’IPv6" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:923 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:975 +msgid "Enable QoS" +msgstr "Active QoS" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:223 +msgid "Enable SIP ALG" +msgstr "Activar SIP ALG" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:942 msgid "Enable SQM" msgstr "Active SQM" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:952 +#, fuzzy +msgid "Enable SQM autorate" +msgstr "Active SQM" + #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:79 msgid "Enable ShadowSocks Obfuscating" msgstr "Activar las interferéncias per ShadowSocks" @@ -357,21 +375,21 @@ msgstr "Activar las interferéncias per ShadowSocks" msgid "Enable TCP Low Latency" msgstr "Desactivar TCP Fast Open" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:360 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:372 msgid "Enable debug logs" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:190 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:870 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:886 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:198 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:875 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:891 msgid "Enabled" msgstr "Activat" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:259 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:267 msgid "Encryption" msgstr "Chiframent" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:280 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:288 #, fuzzy msgid "Encryption method is used for Shadowsocks, V2Ray, Glorytun and OpenVPN." msgstr "Metòde de chiframent utilizat per Glorytun." @@ -380,42 +398,46 @@ msgstr "Metòde de chiframent utilizat per Glorytun." msgid "Filesystem is readonly" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:419 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:427 msgid "For China, set an accessible DNS and disable DNSSEC." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:178 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:902 +msgid "Force TTL" +msgstr "" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:186 #, fuzzy msgid "Force retrieve all keys from server." msgstr "" "Nom d’utilizaire per recuperar la configuracion personalizada del servidor " "estant." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:173 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:181 #, fuzzy msgid "Force retrieve settings" msgstr "Paramètres servidor" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:829 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:834 msgid "GPRS only" msgstr "solament GPRS" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:561 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:764 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:563 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:766 msgid "Gateway DOWN" msgstr "La palanca respond pas" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:564 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:566 #, fuzzy msgid "Gateway IPv6 DOWN" msgstr "La palanca respond pas" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:295 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:303 msgid "Glorytun TCP is used by default for UDP and ICMP" msgstr "Glorytun TCP es utilizat per defaut per UDP e ICMP" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:290 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:292 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:298 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:300 msgid "Glorytun key" msgstr "Clau Glorytun" @@ -457,42 +479,42 @@ msgstr "Ensages IPv4 TCP SYN" msgid "IPv4 TCP SYN retries2" msgstr "Ensages IPv4 TCP SYN" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:510 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:653 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:518 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:661 msgid "IPv4 address" msgstr "Adreça IPv4" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:669 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:677 msgid "IPv4 gateway" msgstr "Palanca IPv4" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:516 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:663 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:524 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:671 msgid "IPv4 netmask" msgstr "Masqueta ret IPv4" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:199 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:207 msgid "IPv6 Prefix" msgstr "Prefix IPv6" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:683 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:710 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:691 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:718 #, fuzzy msgid "IPv6 address" msgstr "Adreça IPv4" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:697 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:720 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:705 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:728 #, fuzzy msgid "IPv6 gateway" msgstr "Palanca IPv4" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:632 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:804 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:634 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:806 msgid "IPv6 route received" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:184 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:192 #, fuzzy msgid "IPv6 settings" msgstr "Paramètres del VPN" @@ -501,28 +523,28 @@ msgstr "Paramètres del VPN" msgid "IPv6 tunnel DOWN" msgstr "Lo tunèl IPv6 respond pas" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:350 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:352 msgid "IPv6:" msgstr "IPv6 :" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:214 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:222 msgid "If host support NAT64, you can enable DNS64 support." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:529 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:537 msgid "Interfaces settings" msgstr "Paramètres interfàcias" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:244 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:254 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:295 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:307 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:319 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:331 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:252 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:262 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:303 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:315 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:327 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:339 msgid "Key is retrieved from server API by default." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:121 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:129 msgid "" "Key to configure and retrieve others keys from Server and to set server " "settings from OpenMPTCProuter." @@ -530,22 +552,22 @@ msgstr "" "Clau per configurar e recuperar las autras claus e tanban los paramètres del " "servidor estant." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:427 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:435 #, fuzzy msgid "LAN interfaces settings" msgstr "Paramètres interfàcias" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:827 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:832 msgid "LTE" msgstr "LTE" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:438 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:549 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:446 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:557 msgid "Label" msgstr "Etiqueta" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:444 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:554 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:452 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:562 msgid "Label for the interface" msgstr "Etiqueta per l’interfàcia" @@ -554,26 +576,26 @@ msgid "Last available backup on server:" msgstr "Darrièra salvagarda disponibla sul servidor :" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:124 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:327 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:329 msgid "Latest available version" msgstr "Darrièra salvagarda disponibla sul servidor" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:130 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:333 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:335 msgid "Load:" msgstr "Carga :" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:628 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:630 msgid "Looping route detected" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:319 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:327 msgid "MLVPN can replace Glorytun with connections with same latency" msgstr "" "MLVPN pòt remplaçar Glorytun per las connexions amb la meteissa laténcia" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:314 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:316 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:322 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:324 msgid "MLVPN password" msgstr "Senhal MLVPN" @@ -581,56 +603,56 @@ msgstr "Senhal MLVPN" msgid "MPTCP is not enabled on the server" msgstr "MPTCP es pas activat sul servidor" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:344 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:346 msgid "MPTCP may not be enabled on the server" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:393 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:913 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:401 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:929 msgid "MPTCP over VPN" msgstr "MPTCP over VPN" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:390 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:398 #, fuzzy msgid "MPTCP over VPN settings" msgstr "MPTCP over VPN" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:391 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:399 msgid "" "MPTCP over VPN should be used only when Multipath TCP is blocked on a " "connection." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:563 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:571 msgid "MacVLAN" msgstr "MacVLAN" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:872 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:888 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:877 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:893 msgid "Master" msgstr "Principal" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:365 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:377 msgid "Master interface selection" msgstr "Seleccion de l’interfàcia màger" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:409 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:421 msgid "Maximum scaling CPU frequency" msgstr "Frequéncia maximala del processor" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:403 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:415 msgid "Minimum scaling CPU frequency" msgstr "Frequéncia minimala del processor" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:824 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:829 msgid "Modem default" msgstr "Modem per defaut" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:858 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:863 msgid "Modem init timeout" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:601 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:609 msgid "ModemManager" msgstr "ModemManager" @@ -638,53 +660,53 @@ msgstr "ModemManager" msgid "More than one default VPN is enabled" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:867 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:883 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:872 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:888 msgid "Multipath TCP" msgstr "Multipath TCP" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:601 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:607 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:787 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:793 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:603 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:609 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:789 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:795 msgid "Multipath current state is" msgstr "Multipath es actualament" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:596 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:782 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:598 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:784 msgid "Multipath master already defined" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:567 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:767 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:569 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:769 msgid "Multipath seems to be blocked on the connection" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:602 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:610 msgid "NCM" msgstr "NCM" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:838 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:843 msgid "NONE" msgstr "CAP" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:623 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:625 #, fuzzy msgid "Network interface MAC address duplicated" msgstr "Interfàcia ret doblada" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:613 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:799 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:615 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:801 msgid "Network interface duplicated" msgstr "Interfàcia ret doblada" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:579 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:581 #, fuzzy msgid "Network interface not in WAN firewall zone" msgstr "Interfàcia ret doblada" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:899 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:901 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:903 msgid "Network overview" msgstr "Vista ret" @@ -692,8 +714,8 @@ msgstr "Vista ret" msgid "Networks settings" msgstr "Paramètres ret" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:554 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:757 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:556 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:759 msgid "No IP defined" msgstr "Cap d’IP pas definida" @@ -701,16 +723,16 @@ msgstr "Cap d’IP pas definida" msgid "No IPv6 access" msgstr "Cap d’accès IPv6" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:575 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:577 msgid "No Server http response after 1 second" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:571 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:771 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:573 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:773 msgid "No Server ping response after 1 second" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:656 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:658 msgid "No WAN with multipath enabled:" msgstr "" @@ -718,16 +740,16 @@ msgstr "" msgid "No available backup on server." msgstr "Cap de salvagarda pas disponibla sul servidor." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:370 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:382 msgid "No change" msgstr "Cap de modificacion" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:819 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:821 msgid "No data" msgstr "Cap de donadas" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:558 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:761 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:560 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:763 msgid "No gateway defined" msgstr "Cap de palanca pas definida" @@ -749,12 +771,12 @@ msgstr "" msgid "No server defined" msgstr "Paramètres dels servidors" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:265 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:413 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:273 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:421 msgid "None" msgstr "Cap" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:562 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:570 msgid "Normal" msgstr "Normala" @@ -776,27 +798,27 @@ msgstr "Tipe d’interferéncia" msgid "Obfuscating will be enabled on both side" msgstr "Las interferéncias seràn activadas dels dos costats" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:368 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:380 msgid "On wizard change" msgstr "En modificant dins l’assistent" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:233 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:241 msgid "Only ShadowSocks is supported with server multiple IPs for now." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:877 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:882 msgid "" "Only one interface must be set as \"Master\", this should be the most stable " "interface." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:135 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:143 msgid "Only one server can be master, else all servers are set as backup." msgstr "" "Pas qu’un servidor pòt pas qu’èsser lo servidor màger, los autres son pel " "replegament." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:391 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:399 msgid "Only work with Shadowsocks as proxy." msgstr "" @@ -804,7 +826,7 @@ msgstr "" msgid "OpenMPTCProuter" msgstr "OpenMPTCProuter" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:384 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:392 msgid "OpenVPN can't be used in multi VPS configuration." msgstr "" @@ -812,63 +834,63 @@ msgstr "" msgid "Optimize for latency instead of bandwidth" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:455 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:605 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:463 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:613 msgid "Other" msgstr "Autre" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:225 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:231 #, fuzzy msgid "Other settings" msgstr "Paramètres servidor" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:839 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:844 msgid "PAP" msgstr "PAP" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:841 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:846 msgid "PAP/CHAP" msgstr "PAP / CHAP" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:852 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:857 #, fuzzy msgid "PAP/CHAP password" msgstr "Senhal MLVPN" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:846 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:851 msgid "PAP/CHAP username" msgstr "Identificant PAP / CHAP" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:815 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:820 msgid "PIN code" msgstr "Còdi PIN" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:603 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:611 msgid "PPPoE" msgstr "PPPoE" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:467 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:573 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:614 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:475 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:581 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:622 #, fuzzy msgid "Physical interface" msgstr "Ajustar una interfàcia" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:825 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:830 msgid "Prefer LTE" msgstr "Preferir LTE" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:826 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:831 msgid "Prefer UMTS" msgstr "Preferir UMTS" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:94 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:102 #, fuzzy msgid "Primary server IP" msgstr "IP servidor" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:449 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:594 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:457 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:602 msgid "Protocol" msgstr "Protocòl" @@ -876,20 +898,24 @@ msgstr "Protocòl" msgid "Proxy is DISABLED" msgstr "Lo servidor mandatari es DESACTIVAT" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:220 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:228 #, fuzzy msgid "Proxy settings" msgstr "Paramètres del VPN" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:355 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:357 msgid "Proxy traffic:" msgstr "Trafic mandatari :" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:604 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:612 msgid "QMI" msgstr "QMI" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:381 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:980 +msgid "QoS permit to prioritize any upload traffic." +msgstr "" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:393 msgid "Qualcomm Shortcut FE driver" msgstr "" @@ -897,7 +923,7 @@ msgstr "" msgid "Redirects all ports from server to this router" msgstr "Redigir totes los pòrts del servidor cap a aqueste router" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:999 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1054 msgid "Reset" msgstr "" @@ -905,33 +931,43 @@ msgstr "" msgid "Restore backup" msgstr "Restaurar salvagarda" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:171 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:179 msgid "Retrieve settings from server" msgstr "Recuperar la configuracion personalizada del servidor estant" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:435 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:998 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:957 +msgid "SQM autorate is for LTE and connection without a stable speed." +msgstr "" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:947 +msgid "" +"SQM control bufferloat: the undesirable latency that arises when the router " +"buffers too much data." +msgstr "" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:447 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1053 msgid "Save & Apply" msgstr "Salvagardar e aplicar" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:233 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:239 msgid "Save vnstats statistics on disk" msgstr "Salvagardar las estatisticas de vnstats sul disc" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:228 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:234 msgid "Save vnstats stats" msgstr "Salvagardar las estatisticas de vnstats" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:415 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:427 msgid "Scaling governor" msgstr "Regulator a l’escala" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:95 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:103 #, fuzzy msgid "Secondary server IP" msgstr "IP servidor" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:992 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1047 msgid "Select the device you want to base the interface on." msgstr "Seleccionatz lo periferic per l’interfàcia." @@ -939,63 +975,63 @@ msgstr "Seleccionatz lo periferic per l’interfàcia." msgid "Send backup" msgstr "Enviar la salvagarda" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:83 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:85 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:92 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:91 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:93 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:100 msgid "Server IP" msgstr "IP servidor" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:87 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:97 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:95 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:105 #, fuzzy msgid "Server IP will be set for proxy and VPN" msgstr "" "L’IP del servidor serà configurada per ShadowSocks, Glorytun, OpenVPN e MLVPN" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:116 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:118 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:124 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:126 msgid "Server key" msgstr "Clau servidor" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:43 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:67 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:75 msgid "Server settings" msgstr "Paramètres servidor" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:106 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:108 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:114 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:116 msgid "Server username" msgstr "Lo nom d'utilizaire servidor" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:821 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:826 msgid "Service Type" msgstr "Tipe de servici" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:401 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:409 msgid "Set VPN to use for MPTCP over VPN." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:658 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:688 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:715 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:666 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:696 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:723 msgid "Set an IP in the same network as the modem" msgstr "Botatz una IP dins lo meteis ret que lo modem" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:408 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:416 msgid "Set configuration for countries with some specificities." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:674 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:702 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:725 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:682 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:710 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:733 msgid "Set here IP of the modem" msgstr "Botatz l’IP del modem aquí" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:130 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:138 msgid "Set server as master" msgstr "Configurar lo servidor coma servidor màger" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:232 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:240 #, fuzzy msgid "" "Set the default Proxy used for TCP when ShadowSocks is enabled, for TCP and " @@ -1004,7 +1040,7 @@ msgstr "" "Configura lo VPN utilizat per defaut per l’UDP e l’ICMP quand ShadowSocks es " "activat, per tot lo trafic quand ShadowSocks es desactivat." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:384 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:392 #, fuzzy msgid "" "Set the default VPN used for ICMP (and UDP if proxy used is shadowsocks), " @@ -1013,14 +1049,14 @@ msgstr "" "Configura lo VPN utilizat per defaut per l’UDP e l’ICMP quand ShadowSocks es " "activat, per tot lo trafic quand ShadowSocks es desactivat." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:943 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:998 msgid "" "Set value between 80-95% of max download speed link. 0 to disable SQM/QoS." msgstr "" "Reglatz una valor entre 80-95% de la velocitat de telecargament maximala. 0 " "per desactivar SQM/QoS." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:959 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1014 msgid "" "Set value between 80-95% of max upload speed link. 0 to disable SQM/QoS." msgstr "" @@ -1036,16 +1072,16 @@ msgstr "Assistent de configuracion" msgid "ShadowSocks is not running" msgstr "Paramètres ShadowSocks" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:244 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:252 msgid "ShadowSocks is used for TCP." msgstr "ShadowSocks es utilizat per TCP." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:239 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:241 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:247 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:249 msgid "ShadowSocks key" msgstr "Clau de ShadowSocks" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:163 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:171 #, fuzzy msgid "Show advanced settings" msgstr "Paramètres avançats" @@ -1054,8 +1090,8 @@ msgstr "Paramètres avançats" msgid "Show all settings" msgstr "Veire totes los paramètres" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:453 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:598 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:461 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:606 msgid "Static address" msgstr "Adreça estatica" @@ -1063,7 +1099,7 @@ msgstr "Adreça estatica" msgid "Status" msgstr "Estatut" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:400 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:412 msgid "Systems settings" msgstr "Paramètres sistèma" @@ -1074,7 +1110,7 @@ msgid "" "local end." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:278 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:286 msgid "" "There is no Advanced Encryption Standard (AES) instruction set integrated in " "the processor, you should use chacha20." @@ -1095,34 +1131,34 @@ msgid "" "retransmissions remain unacknowledged." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:263 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:269 #, fuzzy msgid "Timeout for VPS checks on status pages" msgstr "Desactiva la pròva ping de la palanca" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:273 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:279 msgid "Timeout for retrieving WANs IP on status pages" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:365 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:367 msgid "Total traffic:" msgstr "Tradif total :" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:559 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:567 msgid "Type" msgstr "Tipe" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:331 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:339 msgid "UBOND can replace Glorytun with connections with same latency" msgstr "" "UBOND pòt remplaçar Glorytun per de connexions amb la meteissa laténcia" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:326 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:328 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:334 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:336 msgid "UBOND password" msgstr "Senhal UBOND" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:828 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:833 msgid "UMTS/GPRS" msgstr "UMTS / GPRS" @@ -1140,17 +1176,17 @@ msgstr "Met a jorn lo servidor amb la darrièra version quand cal." msgid "Update server" msgstr "Mesa a jorn del servidor" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:949 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1004 msgid "Upload speed (Kb/s)" msgstr "Velocitat de mandadís (Kb/s)" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:141 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:339 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:341 msgid "Uptime:" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:938 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:954 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:993 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1009 msgid "Used by Glorytun UDP and SQM/QoS if enabled. 0 to use default value." msgstr "" "Utilizat per Glorytun UDP e SQM/QoS se activat. 0 per utilizar la valor per " @@ -1160,21 +1196,21 @@ msgstr "" msgid "V2Ray is not running" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:254 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:262 #, fuzzy msgid "V2Ray is used for TCP and UDP." msgstr "ShadowSocks es utilizat per TCP." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:251 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:259 msgid "V2Ray user" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:249 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:257 msgid "V2Ray user id" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:643 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:644 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:651 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:652 #, fuzzy msgid "VLAN" msgstr "MacVLAN" @@ -1184,11 +1220,11 @@ msgstr "MacVLAN" msgid "VPN is not running" msgstr "Paramètres del VPN" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:286 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:294 msgid "VPN settings" msgstr "Paramètres del VPN" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:360 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:362 msgid "VPN traffic:" msgstr "" @@ -1196,21 +1232,21 @@ msgstr "" msgid "VPN tunnel DOWN" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:258 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:264 msgid "VPS checks timeout" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:320 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:322 msgid "Version" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:268 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:274 msgid "WAN IPs retrieve timeout" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:584 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:589 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:775 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:586 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:591 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:777 msgid "Wan IP and gateway are identical" msgstr "" @@ -1221,15 +1257,20 @@ msgid "" msgstr "" "Utiliza de sites extèrns per obténer d’adreças IP extèrnas quand activat." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:289 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:301 +#, fuzzy +msgid "When proxy V2Ray is used, use it for UDP" +msgstr "ShadowSocks es utilizat per TCP." + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:295 msgid "When proxy shadowsocks is used, use it for UDP if VPN down" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:65 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:73 msgid "Wizard" msgstr "Assistent" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:414 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:422 msgid "World" msgstr "" @@ -1238,16 +1279,22 @@ msgstr "" msgid "You" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:918 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:934 msgid "You can enable MPTCP over VPN if your provider filter Multipath TCP." msgstr "" "Podètz utilizar MTPCP over VPN se vòstre provesidor filtra Multipath TCP." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:459 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:907 +msgid "" +"You can force a TTL. Some LTE provider detect tethering by inpecting packet " +"TTL value, setting it to 65 often solve the issue." +msgstr "" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:467 msgid "You can use DHCP if you have multiple real ethernet ports." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:609 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:617 msgid "" "You can use DHCP if you have multiple real ethernet ports. Select other if " "you want to use another protocol available in Network Interfaces page." @@ -1255,26 +1302,20 @@ msgstr "" "Podètz utilizar DHCP s’avètz mantuns pòrts ret fisics. Causissètz autre " "s’utilizatz un autre protocòl dins la pagina Interfàcias Ret." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:204 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:212 msgid "You can use a public IPv6 prefix only if you set only one server." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:530 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:538 msgid "You must disable DHCP on your modems and set IP in different networks." msgstr "" "Vos cal desactivar lo DHCP sus vòstres modems e configurar lor IP dins de " "rets diferents." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:194 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:202 msgid "You should disable IPv6 here if server doesn't provide IPv6." msgstr "Deuriatz desactivar IPv6 aquí se lo servidor es pas compatible IPv6." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:928 -msgid "You should disable SQM for LTE or any interfaces with variable speed." -msgstr "" -"Vos cal desactivar SQM per la 4G o tota interfàcia amb una velocitat fòrça " -"instabla." - #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:58 msgid "You shouldn't do that and you should redirect only needed ports" msgstr "" @@ -1287,7 +1328,7 @@ msgstr "" msgid "address:" msgstr "Adreça IPv4 :" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:830 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:835 msgid "auto" msgstr "auto" @@ -1295,45 +1336,45 @@ msgstr "auto" msgid "empty key" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:504 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:506 #, fuzzy msgid "interface:" msgstr "Ajustar una interfàcia" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:488 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:737 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:490 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:739 msgid "ip address:" msgstr "Adreça IP :" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:492 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:494 #, fuzzy msgid "ipv6 address:" msgstr "Adreça IP :" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:516 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:749 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:518 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:751 msgid "latency:" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:520 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:753 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:522 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:755 msgid "mtu:" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:644 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:806 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:646 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:808 msgid "multipath:" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:524 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:526 msgid "operator:" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:269 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:277 msgid "other" msgstr "autre" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:528 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:530 msgid "phone number:" msgstr "" @@ -1341,31 +1382,37 @@ msgstr "" msgid "range:" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:532 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:534 msgid "state:" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:647 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:809 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:649 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:811 msgid "traffic control:" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:496 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:741 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:498 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:743 msgid "wan address:" msgstr "Adreça wan :" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:500 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:502 #, fuzzy msgid "wan ipv6 address:" msgstr "Adreça wan :" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:508 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:512 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:745 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:510 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:514 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:747 msgid "whois:" msgstr "" +#~ msgid "" +#~ "You should disable SQM for LTE or any interfaces with variable speed." +#~ msgstr "" +#~ "Vos cal desactivar SQM per la 4G o tota interfàcia amb una velocitat " +#~ "fòrça instabla." + #~ msgid "Common server settings" #~ msgstr "Paramètres dels servidors" @@ -1383,3 +1430,7 @@ msgstr "" #~ msgid "Redundant" #~ msgstr "Redondant" + +#, fuzzy +#~ msgid "Disable HTTP test on Server API in status page" +#~ msgstr "Desactivar la pròva ping cap al servidor" diff --git a/luci-app-openmptcprouter/po/templates/openmptcprouter.pot b/luci-app-openmptcprouter/po/templates/openmptcprouter.pot index 2b76bb623..6aed2a49c 100755 --- a/luci-app-openmptcprouter/po/templates/openmptcprouter.pot +++ b/luci-app-openmptcprouter/po/templates/openmptcprouter.pot @@ -1,37 +1,37 @@ msgid "" msgstr "Content-Type: text/plain; charset=UTF-8" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:307 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:315 msgid "A Dead Simple VPN is a TCP VPN that can replace Glorytun TCP" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:302 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:304 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:310 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:312 msgid "A Dead Simple VPN key" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:100 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:108 msgid "" "A second server's IP can be set for dual IPv4/IPv6 server if WAN IPv6 are set" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:111 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:119 msgid "API username to retrieve personnalized settings from the server." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:809 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:814 msgid "APN" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:734 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:742 msgid "Accept IPv6 RA" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:156 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:164 msgid "Add a new server" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:989 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1044 msgid "Add an interface" msgstr "" @@ -40,11 +40,11 @@ msgstr "" msgid "Advanced Settings" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:161 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:169 msgid "Advanced settings" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:384 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:392 msgid "" "All VPN available here can do aggregation over MPTCP or using own internal " "method." @@ -54,18 +54,18 @@ msgstr "" msgid "All router settings" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:276 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:284 msgid "" "An Advanced Encryption Standard (AES) instruction set is integrated in the " "processor." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:835 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:840 msgid "Authentication Type" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:873 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:889 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:878 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:894 msgid "Backup" msgstr "" @@ -74,7 +74,7 @@ msgstr "" msgid "Backup on server" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:371 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:383 msgid "Balancing" msgstr "" @@ -82,31 +82,37 @@ msgstr "" msgid "Beta" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:310 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:312 msgid "Big time difference between the server and the router" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:564 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:572 msgid "Bridge" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:618 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:620 msgid "Bridge can't have multipath enabled" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:287 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:295 msgid "By default VPN is used for any traffic that is not TCP." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:221 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:229 msgid "" "By default proxy is used for any traffic that is TCP (and UDP for V2Ray)." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:840 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:845 msgid "CHAP" msgstr "" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:961 +msgid "" +"Cake queue discipline is not set, autorate will only work after a reboot if " +"enabled here." +msgstr "" + #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:271 msgid "Can\\'t access and use server part" msgstr "" @@ -127,19 +133,19 @@ msgstr "" msgid "Can\\'t ping server" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:415 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:423 msgid "China" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:568 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:576 msgid "" "Choose MacVLAN if you want to create a virtual interface based on a physical " "interface." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:502 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:588 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:647 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:510 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:596 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:655 msgid "Choose physical interface." msgstr "" @@ -147,20 +153,20 @@ msgstr "" msgid "Core temp:" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:410 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:418 msgid "Country" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:407 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:415 msgid "Country settings" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:454 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:599 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:462 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:607 msgid "DHCP" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:600 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:608 msgid "DHCPv6" msgstr "" @@ -168,35 +174,35 @@ msgstr "" msgid "DNS issue: can\\'t resolve hostname" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:355 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:367 msgid "Debug" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:223 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:231 msgid "Default Proxy" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:337 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:345 msgid "Default VPN" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:77 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:543 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:85 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:551 msgid "Delete" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:741 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:768 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:789 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:749 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:774 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:794 msgid "Device" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:253 -msgid "Disable HTTP test on Server API in status page" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:259 +msgid "Disable HTTP test on Server API" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:345 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:350 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:357 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:362 msgid "Disable ModemManager" msgstr "" @@ -208,11 +214,11 @@ msgstr "" msgid "Disable TCP Fast Open on Linux and Shadowsocks configuration" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:295 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:307 msgid "Disable default gateway" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:300 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:312 msgid "Disable default gateway, no internet if VPS are down" msgstr "" @@ -220,27 +226,27 @@ msgstr "" msgid "Disable external check" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:238 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:244 msgid "Disable gateway ping" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:243 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:249 msgid "Disable gateway ping check in status page" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:279 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:285 msgid "Disable interfaces auto rename" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:330 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:342 msgid "Disable multipath test using tracebox" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:335 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:347 msgid "Disable nDPI" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:340 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:352 msgid "Disable nDPI, used for protocols in OMR-ByPass" msgstr "" @@ -249,70 +255,82 @@ msgid "" "Disable ports redirection defined in firewall from server to this router" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:284 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:290 msgid "Disable renaming interfaces" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:315 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:320 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:327 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:332 msgid "Disable route loop detection" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:144 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:152 msgid "Disable server" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:248 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:254 msgid "Disable server http test" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:305 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:317 msgid "Disable server ping" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:310 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:322 msgid "Disable server ping status check" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:325 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:337 msgid "Disable tracebox test" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:189 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:871 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:887 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:197 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:876 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:892 msgid "Disabled" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:933 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:988 msgid "Download speed (Kb/s)" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:369 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:381 msgid "Dynamic change" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:390 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:402 msgid "Enable Bridge Acceleration" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:209 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:217 msgid "Enable DNS64" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:384 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:396 msgid "Enable Fast Patch offloading for connections" msgstr "" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:187 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:186 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:194 msgid "Enable IPv6" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:923 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:975 +msgid "Enable QoS" +msgstr "" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:223 +msgid "Enable SIP ALG" +msgstr "" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:942 msgid "Enable SQM" msgstr "" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:952 +msgid "Enable SQM autorate" +msgstr "" + #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:79 msgid "Enable ShadowSocks Obfuscating" msgstr "" @@ -321,21 +339,21 @@ msgstr "" msgid "Enable TCP Low Latency" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:360 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:372 msgid "Enable debug logs" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:190 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:870 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:886 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:198 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:875 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:891 msgid "Enabled" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:259 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:267 msgid "Encryption" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:280 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:288 msgid "Encryption method is used for Shadowsocks, V2Ray, Glorytun and OpenVPN." msgstr "" @@ -343,37 +361,41 @@ msgstr "" msgid "Filesystem is readonly" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:419 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:427 msgid "For China, set an accessible DNS and disable DNSSEC." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:178 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:902 +msgid "Force TTL" +msgstr "" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:186 msgid "Force retrieve all keys from server." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:173 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:181 msgid "Force retrieve settings" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:829 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:834 msgid "GPRS only" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:561 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:764 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:563 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:766 msgid "Gateway DOWN" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:564 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:566 msgid "Gateway IPv6 DOWN" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:295 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:303 msgid "Glorytun TCP is used by default for UDP and ICMP" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:290 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:292 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:298 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:300 msgid "Glorytun key" msgstr "" @@ -413,40 +435,40 @@ msgstr "" msgid "IPv4 TCP SYN retries2" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:510 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:653 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:518 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:661 msgid "IPv4 address" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:669 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:677 msgid "IPv4 gateway" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:516 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:663 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:524 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:671 msgid "IPv4 netmask" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:199 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:207 msgid "IPv6 Prefix" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:683 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:710 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:691 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:718 msgid "IPv6 address" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:697 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:720 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:705 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:728 msgid "IPv6 gateway" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:632 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:804 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:634 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:806 msgid "IPv6 route received" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:184 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:192 msgid "IPv6 settings" msgstr "" @@ -454,48 +476,48 @@ msgstr "" msgid "IPv6 tunnel DOWN" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:350 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:352 msgid "IPv6:" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:214 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:222 msgid "If host support NAT64, you can enable DNS64 support." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:529 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:537 msgid "Interfaces settings" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:244 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:254 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:295 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:307 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:319 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:331 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:252 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:262 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:303 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:315 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:327 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:339 msgid "Key is retrieved from server API by default." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:121 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:129 msgid "" "Key to configure and retrieve others keys from Server and to set server " "settings from OpenMPTCProuter." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:427 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:435 msgid "LAN interfaces settings" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:827 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:832 msgid "LTE" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:438 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:549 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:446 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:557 msgid "Label" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:444 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:554 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:452 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:562 msgid "Label for the interface" msgstr "" @@ -504,25 +526,25 @@ msgid "Last available backup on server:" msgstr "" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:124 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:327 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:329 msgid "Latest available version" msgstr "" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:130 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:333 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:335 msgid "Load:" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:628 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:630 msgid "Looping route detected" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:319 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:327 msgid "MLVPN can replace Glorytun with connections with same latency" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:314 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:316 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:322 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:324 msgid "MLVPN password" msgstr "" @@ -530,55 +552,55 @@ msgstr "" msgid "MPTCP is not enabled on the server" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:344 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:346 msgid "MPTCP may not be enabled on the server" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:393 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:913 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:401 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:929 msgid "MPTCP over VPN" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:390 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:398 msgid "MPTCP over VPN settings" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:391 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:399 msgid "" "MPTCP over VPN should be used only when Multipath TCP is blocked on a " "connection." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:563 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:571 msgid "MacVLAN" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:872 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:888 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:877 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:893 msgid "Master" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:365 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:377 msgid "Master interface selection" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:409 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:421 msgid "Maximum scaling CPU frequency" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:403 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:415 msgid "Minimum scaling CPU frequency" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:824 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:829 msgid "Modem default" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:858 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:863 msgid "Modem init timeout" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:601 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:609 msgid "ModemManager" msgstr "" @@ -586,51 +608,51 @@ msgstr "" msgid "More than one default VPN is enabled" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:867 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:883 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:872 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:888 msgid "Multipath TCP" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:601 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:607 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:787 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:793 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:603 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:609 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:789 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:795 msgid "Multipath current state is" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:596 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:782 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:598 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:784 msgid "Multipath master already defined" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:567 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:767 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:569 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:769 msgid "Multipath seems to be blocked on the connection" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:602 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:610 msgid "NCM" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:838 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:843 msgid "NONE" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:623 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:625 msgid "Network interface MAC address duplicated" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:613 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:799 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:615 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:801 msgid "Network interface duplicated" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:579 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:581 msgid "Network interface not in WAN firewall zone" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:899 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:901 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:903 msgid "Network overview" msgstr "" @@ -638,8 +660,8 @@ msgstr "" msgid "Networks settings" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:554 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:757 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:556 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:759 msgid "No IP defined" msgstr "" @@ -647,16 +669,16 @@ msgstr "" msgid "No IPv6 access" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:575 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:577 msgid "No Server http response after 1 second" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:571 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:771 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:573 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:773 msgid "No Server ping response after 1 second" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:656 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:658 msgid "No WAN with multipath enabled:" msgstr "" @@ -664,16 +686,16 @@ msgstr "" msgid "No available backup on server." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:370 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:382 msgid "No change" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:819 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:821 msgid "No data" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:558 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:761 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:560 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:763 msgid "No gateway defined" msgstr "" @@ -694,12 +716,12 @@ msgstr "" msgid "No server defined" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:265 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:413 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:273 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:421 msgid "None" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:562 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:570 msgid "Normal" msgstr "" @@ -721,25 +743,25 @@ msgstr "" msgid "Obfuscating will be enabled on both side" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:368 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:380 msgid "On wizard change" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:233 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:241 msgid "Only ShadowSocks is supported with server multiple IPs for now." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:877 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:882 msgid "" "Only one interface must be set as \"Master\", this should be the most stable " "interface." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:135 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:143 msgid "Only one server can be master, else all servers are set as backup." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:391 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:399 msgid "Only work with Shadowsocks as proxy." msgstr "" @@ -747,7 +769,7 @@ msgstr "" msgid "OpenMPTCProuter" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:384 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:392 msgid "OpenVPN can't be used in multi VPS configuration." msgstr "" @@ -755,59 +777,59 @@ msgstr "" msgid "Optimize for latency instead of bandwidth" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:455 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:605 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:463 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:613 msgid "Other" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:225 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:231 msgid "Other settings" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:839 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:844 msgid "PAP" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:841 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:846 msgid "PAP/CHAP" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:852 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:857 msgid "PAP/CHAP password" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:846 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:851 msgid "PAP/CHAP username" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:815 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:820 msgid "PIN code" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:603 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:611 msgid "PPPoE" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:467 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:573 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:614 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:475 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:581 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:622 msgid "Physical interface" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:825 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:830 msgid "Prefer LTE" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:826 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:831 msgid "Prefer UMTS" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:94 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:102 msgid "Primary server IP" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:449 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:594 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:457 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:602 msgid "Protocol" msgstr "" @@ -815,19 +837,23 @@ msgstr "" msgid "Proxy is DISABLED" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:220 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:228 msgid "Proxy settings" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:355 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:357 msgid "Proxy traffic:" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:604 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:612 msgid "QMI" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:381 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:980 +msgid "QoS permit to prioritize any upload traffic." +msgstr "" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:393 msgid "Qualcomm Shortcut FE driver" msgstr "" @@ -835,7 +861,7 @@ msgstr "" msgid "Redirects all ports from server to this router" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:999 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1054 msgid "Reset" msgstr "" @@ -843,32 +869,42 @@ msgstr "" msgid "Restore backup" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:171 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:179 msgid "Retrieve settings from server" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:435 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:998 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:957 +msgid "SQM autorate is for LTE and connection without a stable speed." +msgstr "" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:947 +msgid "" +"SQM control bufferloat: the undesirable latency that arises when the router " +"buffers too much data." +msgstr "" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:447 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1053 msgid "Save & Apply" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:233 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:239 msgid "Save vnstats statistics on disk" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:228 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:234 msgid "Save vnstats stats" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:415 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:427 msgid "Scaling governor" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:95 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:103 msgid "Secondary server IP" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:992 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1047 msgid "Select the device you want to base the interface on." msgstr "" @@ -876,78 +912,78 @@ msgstr "" msgid "Send backup" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:83 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:85 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:92 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:91 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:93 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:100 msgid "Server IP" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:87 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:97 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:95 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:105 msgid "Server IP will be set for proxy and VPN" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:116 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:118 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:124 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:126 msgid "Server key" msgstr "" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:43 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:67 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:75 msgid "Server settings" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:106 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:108 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:114 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:116 msgid "Server username" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:821 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:826 msgid "Service Type" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:401 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:409 msgid "Set VPN to use for MPTCP over VPN." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:658 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:688 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:715 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:666 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:696 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:723 msgid "Set an IP in the same network as the modem" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:408 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:416 msgid "Set configuration for countries with some specificities." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:674 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:702 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:725 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:682 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:710 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:733 msgid "Set here IP of the modem" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:130 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:138 msgid "Set server as master" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:232 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:240 msgid "" "Set the default Proxy used for TCP when ShadowSocks is enabled, for TCP and " "UDP when V2Ray is enabled." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:384 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:392 msgid "" "Set the default VPN used for ICMP (and UDP if proxy used is shadowsocks), " "for all traffic if proxy is disabled." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:943 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:998 msgid "" "Set value between 80-95% of max download speed link. 0 to disable SQM/QoS." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:959 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1014 msgid "" "Set value between 80-95% of max upload speed link. 0 to disable SQM/QoS." msgstr "" @@ -960,16 +996,16 @@ msgstr "" msgid "ShadowSocks is not running" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:244 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:252 msgid "ShadowSocks is used for TCP." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:239 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:241 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:247 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:249 msgid "ShadowSocks key" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:163 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:171 msgid "Show advanced settings" msgstr "" @@ -977,8 +1013,8 @@ msgstr "" msgid "Show all settings" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:453 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:598 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:461 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:606 msgid "Static address" msgstr "" @@ -986,7 +1022,7 @@ msgstr "" msgid "Status" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:400 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:412 msgid "Systems settings" msgstr "" @@ -997,7 +1033,7 @@ msgid "" "local end." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:278 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:286 msgid "" "There is no Advanced Encryption Standard (AES) instruction set integrated in " "the processor, you should use chacha20." @@ -1016,32 +1052,32 @@ msgid "" "retransmissions remain unacknowledged." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:263 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:269 msgid "Timeout for VPS checks on status pages" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:273 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:279 msgid "Timeout for retrieving WANs IP on status pages" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:365 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:367 msgid "Total traffic:" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:559 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:567 msgid "Type" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:331 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:339 msgid "UBOND can replace Glorytun with connections with same latency" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:326 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:328 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:334 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:336 msgid "UBOND password" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:828 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:833 msgid "UMTS/GPRS" msgstr "" @@ -1058,17 +1094,17 @@ msgstr "" msgid "Update server" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:949 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1004 msgid "Upload speed (Kb/s)" msgstr "" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:141 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:339 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:341 msgid "Uptime:" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:938 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:954 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:993 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1009 msgid "Used by Glorytun UDP and SQM/QoS if enabled. 0 to use default value." msgstr "" @@ -1076,20 +1112,20 @@ msgstr "" msgid "V2Ray is not running" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:254 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:262 msgid "V2Ray is used for TCP and UDP." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:251 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:259 msgid "V2Ray user" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:249 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:257 msgid "V2Ray user id" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:643 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:644 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:651 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:652 msgid "VLAN" msgstr "" @@ -1097,11 +1133,11 @@ msgstr "" msgid "VPN is not running" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:286 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:294 msgid "VPN settings" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:360 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:362 msgid "VPN traffic:" msgstr "" @@ -1109,21 +1145,21 @@ msgstr "" msgid "VPN tunnel DOWN" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:258 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:264 msgid "VPS checks timeout" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:320 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:322 msgid "Version" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:268 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:274 msgid "WAN IPs retrieve timeout" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:584 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:589 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:775 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:586 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:591 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:777 msgid "Wan IP and gateway are identical" msgstr "" @@ -1133,15 +1169,19 @@ msgid "" "used to go outside." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:289 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:301 +msgid "When proxy V2Ray is used, use it for UDP" +msgstr "" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:295 msgid "When proxy shadowsocks is used, use it for UDP if VPN down" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:65 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:73 msgid "Wizard" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:414 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:422 msgid "World" msgstr "" @@ -1150,36 +1190,38 @@ msgstr "" msgid "You" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:918 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:934 msgid "You can enable MPTCP over VPN if your provider filter Multipath TCP." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:459 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:907 +msgid "" +"You can force a TTL. Some LTE provider detect tethering by inpecting packet " +"TTL value, setting it to 65 often solve the issue." +msgstr "" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:467 msgid "You can use DHCP if you have multiple real ethernet ports." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:609 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:617 msgid "" "You can use DHCP if you have multiple real ethernet ports. Select other if " "you want to use another protocol available in Network Interfaces page." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:204 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:212 msgid "You can use a public IPv6 prefix only if you set only one server." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:530 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:538 msgid "You must disable DHCP on your modems and set IP in different networks." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:194 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:202 msgid "You should disable IPv6 here if server doesn't provide IPv6." msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:928 -msgid "You should disable SQM for LTE or any interfaces with variable speed." -msgstr "" - #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:58 msgid "You shouldn't do that and you should redirect only needed ports" msgstr "" @@ -1192,7 +1234,7 @@ msgstr "" msgid "address:" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:830 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:835 msgid "auto" msgstr "" @@ -1200,43 +1242,43 @@ msgstr "" msgid "empty key" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:504 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:506 msgid "interface:" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:488 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:737 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:490 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:739 msgid "ip address:" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:492 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:494 msgid "ipv6 address:" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:516 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:749 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:518 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:751 msgid "latency:" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:520 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:753 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:522 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:755 msgid "mtu:" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:644 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:806 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:646 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:808 msgid "multipath:" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:524 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:526 msgid "operator:" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:269 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:277 msgid "other" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:528 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:530 msgid "phone number:" msgstr "" @@ -1244,26 +1286,26 @@ msgstr "" msgid "range:" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:532 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:534 msgid "state:" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:647 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:809 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:649 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:811 msgid "traffic control:" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:496 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:741 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:498 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:743 msgid "wan address:" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:500 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:502 msgid "wan ipv6 address:" msgstr "" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:508 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:512 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:745 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:510 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:514 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:747 msgid "whois:" msgstr "" diff --git a/luci-app-openmptcprouter/po/zh_Hans/openmptcprouter.po b/luci-app-openmptcprouter/po/zh_Hans/openmptcprouter.po index e8827e0ff..f06ba0249 100755 --- a/luci-app-openmptcprouter/po/zh_Hans/openmptcprouter.po +++ b/luci-app-openmptcprouter/po/zh_Hans/openmptcprouter.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2021-06-02 09:51+0000\n" -"Last-Translator: antrouter \n" +"PO-Revision-Date: 2022-08-12 12:08+0000\n" +"Last-Translator: Weblate Admin \n" "Language-Team: Chinese (Simplified) \n" "Language: zh_Hans\n" @@ -11,39 +11,39 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 4.6.1\n" +"X-Generator: Weblate 4.10.1\n" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:307 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:315 msgid "A Dead Simple VPN is a TCP VPN that can replace Glorytun TCP" msgstr "A Dead Simple VPN 是可以替代Glorytun TCP的TCP VPN" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:302 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:304 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:310 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:312 msgid "A Dead Simple VPN key" msgstr "简单VPN" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:100 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:108 msgid "" "A second server's IP can be set for dual IPv4/IPv6 server if WAN IPv6 are set" msgstr "如果设置了WAN IPv6,则可以为设置第二台服务器的IP双IPv4 / IPv6服务器" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:111 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:119 msgid "API username to retrieve personnalized settings from the server." msgstr "API用户名,从聚合服务器检索个性化设置." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:809 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:814 msgid "APN" msgstr "APN" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:734 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:742 msgid "Accept IPv6 RA" msgstr "接受IPv6 RA" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:156 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:164 msgid "Add a new server" msgstr "添加一个新聚合服务器" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:989 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1044 msgid "Add an interface" msgstr "添加网卡" @@ -52,11 +52,11 @@ msgstr "添加网卡" msgid "Advanced Settings" msgstr "高级设置" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:161 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:169 msgid "Advanced settings" msgstr "高级设置" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:384 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:392 msgid "" "All VPN available here can do aggregation over MPTCP or using own internal " "method." @@ -66,18 +66,18 @@ msgstr "这里可用的所有VPN都可以通过MPTCP或使用自己的内部进 msgid "All router settings" msgstr "所有路由器设置" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:276 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:284 msgid "" "An Advanced Encryption Standard (AES) instruction set is integrated in the " "processor." msgstr "处理器中集成了高级加密标准(AES)指令集." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:835 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:840 msgid "Authentication Type" msgstr "认证类型" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:873 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:889 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:878 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:894 msgid "Backup" msgstr "备份" @@ -86,7 +86,7 @@ msgstr "备份" msgid "Backup on server" msgstr "备份到服务器" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:371 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:383 msgid "Balancing" msgstr "均衡" @@ -94,31 +94,37 @@ msgstr "均衡" msgid "Beta" msgstr "测试版" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:310 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:312 msgid "Big time difference between the server and the router" msgstr "服务器和路由器之间的时间差距很大" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:564 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:572 msgid "Bridge" msgstr "桥接" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:618 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:620 msgid "Bridge can't have multipath enabled" msgstr "网桥无法启用多路径聚合" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:287 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:295 msgid "By default VPN is used for any traffic that is not TCP." msgstr "默认情况下,VPN用于非TCP的任何流量." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:221 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:229 msgid "" "By default proxy is used for any traffic that is TCP (and UDP for V2Ray)." -msgstr "默认情况下,代理用于任何TCP(对于V2Ray是UDP)流量。" +msgstr "默认情况下,仅代理TCP(如果选用V2Ray则代理TCP跟UDP还有ICMP任何)流量。" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:840 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:845 msgid "CHAP" msgstr "CHAP" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:961 +msgid "" +"Cake queue discipline is not set, autorate will only work after a reboot if " +"enabled here." +msgstr "" + #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:271 msgid "Can\\'t access and use server part" msgstr "无法访问和使用聚合服务器部分服务" @@ -139,19 +145,19 @@ msgstr "无法通过聚合服务器ShadowSocks获取公网IP地址" msgid "Can\\'t ping server" msgstr "无法ping聚合服务器" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:415 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:423 msgid "China" msgstr "中国专属" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:568 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:576 msgid "" "Choose MacVLAN if you want to create a virtual interface based on a physical " "interface." msgstr "如果要基于物理接口创建虚拟接口,请选择MacVLAN。" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:502 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:588 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:647 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:510 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:596 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:655 msgid "Choose physical interface." msgstr "选择物理接口。" @@ -159,20 +165,20 @@ msgstr "选择物理接口。" msgid "Core temp:" msgstr "核心温度:" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:410 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:418 msgid "Country" msgstr "国家" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:407 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:415 msgid "Country settings" msgstr "国家设置" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:454 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:599 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:462 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:607 msgid "DHCP" msgstr "DHCP" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:600 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:608 msgid "DHCPv6" msgstr "DHCPV6" @@ -180,35 +186,36 @@ msgstr "DHCPV6" msgid "DNS issue: can\\'t resolve hostname" msgstr "DNS问题:无法解析主机名" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:355 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:367 msgid "Debug" msgstr "调试模式" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:223 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:231 msgid "Default Proxy" msgstr "默认代理" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:337 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:345 msgid "Default VPN" msgstr "默认VPN" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:77 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:543 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:85 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:551 msgid "Delete" msgstr "删除" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:741 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:768 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:789 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:749 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:774 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:794 msgid "Device" msgstr "设备" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:253 -msgid "Disable HTTP test on Server API in status page" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:259 +#, fuzzy +msgid "Disable HTTP test on Server API" msgstr "在状态页面中禁用服务器API上的HTTP测试" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:345 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:350 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:357 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:362 msgid "Disable ModemManager" msgstr "禁用调制解调器管理器" @@ -220,11 +227,11 @@ msgstr "禁用TCP Fast Open" msgid "Disable TCP Fast Open on Linux and Shadowsocks configuration" msgstr "在Linux和Shadowsocks配置上禁用TCP快速打开" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:295 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:307 msgid "Disable default gateway" msgstr "关闭默认网关" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:300 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:312 msgid "Disable default gateway, no internet if VPS are down" msgstr "禁用默认网关,如果VPS关闭,则没办法链接互联网" @@ -232,27 +239,27 @@ msgstr "禁用默认网关,如果VPS关闭,则没办法链接互联网" msgid "Disable external check" msgstr "禁用外部检查" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:238 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:244 msgid "Disable gateway ping" msgstr "禁用网关ping" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:243 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:249 msgid "Disable gateway ping check in status page" msgstr "禁用状态页面网关ping检查" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:279 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:285 msgid "Disable interfaces auto rename" msgstr "禁用接口自动重命名" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:330 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:342 msgid "Disable multipath test using tracebox" msgstr "禁止使用tracebox多路径测试" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:335 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:347 msgid "Disable nDPI" msgstr "禁用 nDPI" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:340 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:352 msgid "Disable nDPI, used for protocols in OMR-ByPass" msgstr "禁用 nDPI,用于 OMR-ByPass 中的协议" @@ -261,70 +268,83 @@ msgid "" "Disable ports redirection defined in firewall from server to this router" msgstr "禁用防火墙中定义的从服务器到此路由器的端口重定向" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:284 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:290 msgid "Disable renaming interfaces" msgstr "禁用网卡重命名" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:315 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:320 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:327 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:332 msgid "Disable route loop detection" msgstr "禁用路由环路检测" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:144 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:152 msgid "Disable server" msgstr "关闭禁用聚合服务器" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:248 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:254 msgid "Disable server http test" msgstr "禁用服务器http 测试" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:305 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:317 msgid "Disable server ping" msgstr "禁用服务器ping" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:310 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:322 msgid "Disable server ping status check" msgstr "禁用服务器ping状态检查" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:325 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:337 msgid "Disable tracebox test" msgstr "禁用聚合检测" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:189 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:871 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:887 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:197 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:876 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:892 msgid "Disabled" msgstr "关闭" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:933 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:988 msgid "Download speed (Kb/s)" msgstr "下载速度 (Kb/s)" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:369 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:381 msgid "Dynamic change" msgstr "动态变化" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:390 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:402 msgid "Enable Bridge Acceleration" msgstr "启用网桥加速" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:209 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:217 msgid "Enable DNS64" msgstr "启用DNS64" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:384 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:396 msgid "Enable Fast Patch offloading for connections" msgstr "为连接启用快速流量卸载补丁" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:187 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:186 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:194 msgid "Enable IPv6" msgstr "开启 IPv6" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:923 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:975 +msgid "Enable QoS" +msgstr "开启 QoS" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:223 +msgid "Enable SIP ALG" +msgstr "开启 SIP ALG" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:942 msgid "Enable SQM" msgstr "开启 SQM" +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:952 +#, fuzzy +msgid "Enable SQM autorate" +msgstr "开启 SQM" + #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:79 msgid "Enable ShadowSocks Obfuscating" msgstr "启用ShadowSocks混淆" @@ -333,21 +353,21 @@ msgstr "启用ShadowSocks混淆" msgid "Enable TCP Low Latency" msgstr "启用TCP低延迟" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:360 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:372 msgid "Enable debug logs" msgstr "启用调试日志" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:190 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:870 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:886 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:198 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:875 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:891 msgid "Enabled" msgstr "启用" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:259 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:267 msgid "Encryption" msgstr "加密" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:280 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:288 msgid "Encryption method is used for Shadowsocks, V2Ray, Glorytun and OpenVPN." msgstr "加密方法用于Shadowsocks,V2Ray,Glorytun和OpenVPN。" @@ -355,37 +375,41 @@ msgstr "加密方法用于Shadowsocks,V2Ray,Glorytun和OpenVPN。" msgid "Filesystem is readonly" msgstr "文件系统处于只读状态/重新刷机吧" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:419 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:427 msgid "For China, set an accessible DNS and disable DNSSEC." msgstr "对于中国,设置专属的DNS并禁用DNSSEC." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:178 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:902 +msgid "Force TTL" +msgstr "" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:186 msgid "Force retrieve all keys from server." msgstr "强制从服务器检索并应用所有密钥。" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:173 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:181 msgid "Force retrieve settings" msgstr "强制检索设置" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:829 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:834 msgid "GPRS only" msgstr "仅GPRS" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:561 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:764 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:563 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:766 msgid "Gateway DOWN" msgstr "网关不通" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:564 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:566 msgid "Gateway IPv6 DOWN" msgstr "IPV6网关不通" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:295 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:303 msgid "Glorytun TCP is used by default for UDP and ICMP" msgstr "Glorytun TCP默认用于UDP和ICMP" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:290 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:292 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:298 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:300 msgid "Glorytun key" msgstr "Glorytun密钥" @@ -425,40 +449,40 @@ msgstr "IPv4 TCP SYN重试1" msgid "IPv4 TCP SYN retries2" msgstr "IPv4 TCP SYN重试2" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:510 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:653 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:518 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:661 msgid "IPv4 address" msgstr "IPv4地址" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:669 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:677 msgid "IPv4 gateway" msgstr "IPv4网关" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:516 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:663 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:524 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:671 msgid "IPv4 netmask" msgstr "IPv4网络掩码" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:199 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:207 msgid "IPv6 Prefix" msgstr "IPv6前缀" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:683 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:710 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:691 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:718 msgid "IPv6 address" msgstr "IPv6地址" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:697 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:720 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:705 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:728 msgid "IPv6 gateway" msgstr "IPv6网关" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:632 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:804 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:634 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:806 msgid "IPv6 route received" msgstr "经过的IPv6路由" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:184 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:192 msgid "IPv6 settings" msgstr "IPv6设置" @@ -466,48 +490,48 @@ msgstr "IPv6设置" msgid "IPv6 tunnel DOWN" msgstr "IPv6隧道DOWN" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:350 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:352 msgid "IPv6:" msgstr "IPv6 :" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:214 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:222 msgid "If host support NAT64, you can enable DNS64 support." msgstr "如果主机支持NAT64,则可以启用DNS64支持。" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:529 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:537 msgid "Interfaces settings" msgstr "接口设置" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:244 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:254 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:295 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:307 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:319 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:331 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:252 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:262 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:303 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:315 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:327 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:339 msgid "Key is retrieved from server API by default." msgstr "默认情况下,密钥是从服务器API检索的." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:121 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:129 msgid "" "Key to configure and retrieve others keys from Server and to set server " "settings from OpenMPTCProuter." msgstr "用于服务器配置密钥以及设置的密钥." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:427 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:435 msgid "LAN interfaces settings" msgstr "局域网接口设置" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:827 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:832 msgid "LTE" msgstr "4G LTE制式" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:438 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:549 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:446 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:557 msgid "Label" msgstr "标签" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:444 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:554 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:452 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:562 msgid "Label for the interface" msgstr "接口标签" @@ -516,25 +540,25 @@ msgid "Last available backup on server:" msgstr "服务器上的上次可用备份:" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:124 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:327 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:329 msgid "Latest available version" msgstr "最新可用的版本" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:130 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:333 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:335 msgid "Load:" msgstr "负载:" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:628 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:630 msgid "Looping route detected" msgstr "检测到循环路线" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:319 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:327 msgid "MLVPN can replace Glorytun with connections with same latency" msgstr "MLVPN可以用具有相同延迟的连接替换Glorytun" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:314 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:316 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:322 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:324 msgid "MLVPN password" msgstr "MLVPN密码" @@ -542,55 +566,55 @@ msgstr "MLVPN密码" msgid "MPTCP is not enabled on the server" msgstr "服务器上未启用MPTCP" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:344 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:346 msgid "MPTCP may not be enabled on the server" msgstr "服务器上可能未启用MPTCP" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:393 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:913 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:401 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:929 msgid "MPTCP over VPN" msgstr "通过MPTCP的VPN" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:390 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:398 msgid "MPTCP over VPN settings" msgstr "通过MPTCP的VPN设置" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:391 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:399 msgid "" "MPTCP over VPN should be used only when Multipath TCP is blocked on a " "connection." msgstr "仅当在链路上阻止多路径TCP时,才应该使用基于VPN的MPTCP。" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:563 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:571 msgid "MacVLAN" msgstr "Macvlan" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:872 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:888 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:877 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:893 msgid "Master" msgstr "主" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:365 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:377 msgid "Master interface selection" msgstr "主网卡选择" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:409 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:421 msgid "Maximum scaling CPU frequency" msgstr "最大扩展CPU频率" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:403 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:415 msgid "Minimum scaling CPU frequency" msgstr "最小扩展CPU频率" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:824 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:829 msgid "Modem default" msgstr "调制解调器默认" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:858 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:863 msgid "Modem init timeout" msgstr "调制解调器初始化超时" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:601 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:609 msgid "ModemManager" msgstr "调制解调器管理器" @@ -598,51 +622,51 @@ msgstr "调制解调器管理器" msgid "More than one default VPN is enabled" msgstr "启用了多个默认VPN" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:867 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:883 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:872 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:888 msgid "Multipath TCP" msgstr "多路径TCP" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:601 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:607 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:787 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:793 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:603 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:609 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:789 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:795 msgid "Multipath current state is" msgstr "多路径当前状态为" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:596 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:782 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:598 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:784 msgid "Multipath master already defined" msgstr "已定义多路径主机" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:567 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:767 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:569 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:769 msgid "Multipath seems to be blocked on the connection" msgstr "多路径似乎在连接上被阻止" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:602 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:610 msgid "NCM" msgstr "NCM" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:838 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:843 msgid "NONE" msgstr "无" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:623 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:625 msgid "Network interface MAC address duplicated" msgstr "网络接口MAC地址重复" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:613 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:799 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:615 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:801 msgid "Network interface duplicated" msgstr "网络接口重复" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:579 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:581 msgid "Network interface not in WAN firewall zone" msgstr "网络接口不在WAN防火墙区域中" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:899 #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:901 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:903 msgid "Network overview" msgstr "网络概览" @@ -650,8 +674,8 @@ msgstr "网络概览" msgid "Networks settings" msgstr "网络设置" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:554 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:757 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:556 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:759 msgid "No IP defined" msgstr "没有定义IP" @@ -659,16 +683,16 @@ msgstr "没有定义IP" msgid "No IPv6 access" msgstr "没有IPv6地址" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:575 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:577 msgid "No Server http response after 1 second" msgstr "1秒后无服务器HTTP响应" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:571 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:771 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:573 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:773 msgid "No Server ping response after 1 second" msgstr "1秒后无服务器ping响应" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:656 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:658 msgid "No WAN with multipath enabled:" msgstr "没有启用多路径的WAN:" @@ -676,16 +700,16 @@ msgstr "没有启用多路径的WAN:" msgid "No available backup on server." msgstr "服务器上没有可用的备份." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:370 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:382 msgid "No change" msgstr "没有改变" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:819 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:821 msgid "No data" msgstr "没有数据" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:558 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:761 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:560 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:763 msgid "No gateway defined" msgstr "未定义网关" @@ -706,12 +730,12 @@ msgstr "没有服务器IP地址,没有公共IP地址" msgid "No server defined" msgstr "未定义聚合服务器" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:265 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:413 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:273 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:421 msgid "None" msgstr "没有" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:562 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:570 msgid "Normal" msgstr "正常" @@ -733,25 +757,25 @@ msgstr "混淆类型" msgid "Obfuscating will be enabled on both side" msgstr "双方都将启用混淆" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:368 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:380 msgid "On wizard change" msgstr "通过向导更改" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:233 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:241 msgid "Only ShadowSocks is supported with server multiple IPs for now." msgstr "目前服务器如果有多个公网IP仅支持ShadowSocks." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:877 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:882 msgid "" "Only one interface must be set as \"Master\", this should be the most stable " "interface." msgstr "必须仅将一个接口设置为“主”,这应该是最稳定的接口。" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:135 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:143 msgid "Only one server can be master, else all servers are set as backup." msgstr "只能将一台服务器作为主服务器,否则将所有服务器都设置为备用服务器." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:391 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:399 msgid "Only work with Shadowsocks as proxy." msgstr "只有Shadowsocks作为代理工作。" @@ -759,7 +783,7 @@ msgstr "只有Shadowsocks作为代理工作。" msgid "OpenMPTCProuter" msgstr "聚合路由器" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:384 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:392 msgid "OpenVPN can't be used in multi VPS configuration." msgstr "OpenVPN不能用于多VPS配置." @@ -767,59 +791,59 @@ msgstr "OpenVPN不能用于多VPS配置." msgid "Optimize for latency instead of bandwidth" msgstr "优化延迟而不是带宽" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:455 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:605 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:463 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:613 msgid "Other" msgstr "其他" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:225 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:231 msgid "Other settings" msgstr "聚合其他设置" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:839 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:844 msgid "PAP" msgstr "PAP" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:841 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:846 msgid "PAP/CHAP" msgstr "PAP/CHAP" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:852 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:857 msgid "PAP/CHAP password" msgstr "PAP/CHAP 密码" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:846 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:851 msgid "PAP/CHAP username" msgstr "PAP/CHAP 账号" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:815 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:820 msgid "PIN code" msgstr "PIN码" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:603 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:611 msgid "PPPoE" msgstr "PPPoE拨号" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:467 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:573 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:614 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:475 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:581 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:622 msgid "Physical interface" msgstr "物理接口" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:825 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:830 msgid "Prefer LTE" msgstr "首选4G LTE制式" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:826 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:831 msgid "Prefer UMTS" msgstr "首选3G UMTS" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:94 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:102 msgid "Primary server IP" msgstr "主服务器IP" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:449 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:594 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:457 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:602 msgid "Protocol" msgstr "协议" @@ -827,19 +851,23 @@ msgstr "协议" msgid "Proxy is DISABLED" msgstr "代理已禁用" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:220 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:228 msgid "Proxy settings" msgstr "代理设置" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:355 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:357 msgid "Proxy traffic:" msgstr "代理流量:" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:604 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:612 msgid "QMI" msgstr "QMI" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:381 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:980 +msgid "QoS permit to prioritize any upload traffic." +msgstr "" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:393 msgid "Qualcomm Shortcut FE driver" msgstr "Qualcomm Shortcut FE驱动程序" @@ -847,7 +875,7 @@ msgstr "Qualcomm Shortcut FE驱动程序" msgid "Redirects all ports from server to this router" msgstr "将所有端口从服务器重定向到此路由器" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:999 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1054 msgid "Reset" msgstr "复位" @@ -855,32 +883,42 @@ msgstr "复位" msgid "Restore backup" msgstr "恢复备份" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:171 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:179 msgid "Retrieve settings from server" msgstr "从服务器检索设置" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:435 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:998 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:957 +msgid "SQM autorate is for LTE and connection without a stable speed." +msgstr "" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:947 +msgid "" +"SQM control bufferloat: the undesirable latency that arises when the router " +"buffers too much data." +msgstr "" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:447 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1053 msgid "Save & Apply" msgstr "保存并且应用设置" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:233 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:239 msgid "Save vnstats statistics on disk" msgstr "将vnstats统计信息保存在磁盘上" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:228 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:234 msgid "Save vnstats stats" msgstr "保存vnstats统计信息" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:415 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:427 msgid "Scaling governor" msgstr "超频" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:95 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:103 msgid "Secondary server IP" msgstr "辅助服务器IP" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:992 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1047 msgid "Select the device you want to base the interface on." msgstr "选择要作为基础的接口." @@ -888,69 +926,69 @@ msgstr "选择要作为基础的接口." msgid "Send backup" msgstr "发送备份" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:83 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:85 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:92 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:91 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:93 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:100 msgid "Server IP" msgstr "服务器IP" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:87 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:97 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:95 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:105 msgid "Server IP will be set for proxy and VPN" msgstr "将为代理和VPN设置服务器IP" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:116 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:118 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:124 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:126 msgid "Server key" msgstr "服务器密钥" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:43 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:67 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:75 msgid "Server settings" msgstr "聚合服务器设定" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:106 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:108 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:114 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:116 msgid "Server username" msgstr "服务器用户名" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:821 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:826 msgid "Service Type" msgstr "服务类型" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:401 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:409 msgid "Set VPN to use for MPTCP over VPN." msgstr "设置VPN以用于通过VPN的MPTCP。" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:658 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:688 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:715 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:666 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:696 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:723 msgid "Set an IP in the same network as the modem" msgstr "在与调制解调器相同的网络中设置IP" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:408 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:416 msgid "Set configuration for countries with some specificities." msgstr "设置具有某些特殊性的国家/地区的配置。" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:674 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:702 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:725 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:682 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:710 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:733 msgid "Set here IP of the modem" msgstr "在此处设置调制解调器的IP" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:130 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:138 msgid "Set server as master" msgstr "将服务器设置为主服务器" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:232 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:240 msgid "" "Set the default Proxy used for TCP when ShadowSocks is enabled, for TCP and " "UDP when V2Ray is enabled." msgstr "" -"设置启用ShadowSocks时用于TCP的默认代理,启用V2Ray时设置用于TCP和UDP的默认代" -"理." +"启用ShadowSocks时用于默认代理TC流量,启用V2Ray时用于默认代理TCP和UDP还有ICMP" +"任何流量." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:384 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:392 msgid "" "Set the default VPN used for ICMP (and UDP if proxy used is shadowsocks), " "for all traffic if proxy is disabled." @@ -958,12 +996,12 @@ msgstr "" "启用ShadowSocks时,为所有流量设置默认的VPN,用于UDP和ICMP,如果禁用" "ShadowSocks." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:943 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:998 msgid "" "Set value between 80-95% of max download speed link. 0 to disable SQM/QoS." msgstr "设置最大下载速度链接的80-95%之间的值。 0禁用SQM / QoS." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:959 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1014 msgid "" "Set value between 80-95% of max upload speed link. 0 to disable SQM/QoS." msgstr "设置为最大上传速度链接的80-95%之间的值。 0禁用SQM / QoS." @@ -976,16 +1014,16 @@ msgstr "聚合设置向导" msgid "ShadowSocks is not running" msgstr "ShadowSocks n'est pas lancé" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:244 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:252 msgid "ShadowSocks is used for TCP." msgstr "ShadowSocks用于TCP." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:239 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:241 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:247 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:249 msgid "ShadowSocks key" msgstr "ShadowSocks密钥" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:163 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:171 msgid "Show advanced settings" msgstr "显示高级设置" @@ -993,8 +1031,8 @@ msgstr "显示高级设置" msgid "Show all settings" msgstr "显示所有设定" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:453 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:598 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:461 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:606 msgid "Static address" msgstr "静态地址" @@ -1002,7 +1040,7 @@ msgstr "静态地址" msgid "Status" msgstr "状态" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:400 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:412 msgid "Systems settings" msgstr "系统设定" @@ -1015,7 +1053,7 @@ msgstr "" "孤立的(不再被任何应用程序引用)连接在本地端中止之前将保持FIN_WAIT_2状态的时" "间。" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:278 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:286 msgid "" "There is no Advanced Encryption Standard (AES) instruction set integrated in " "the processor, you should use chacha20." @@ -1036,32 +1074,32 @@ msgid "" "retransmissions remain unacknowledged." msgstr "当未确认RTO重传时,此值会影响有效TCP连接的超时。" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:263 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:269 msgid "Timeout for VPS checks on status pages" msgstr "状态页面上 VPS 检查的超时时间" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:273 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:279 msgid "Timeout for retrieving WANs IP on status pages" msgstr "在状态页面上检索 WAN IP 的超时时间" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:365 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:367 msgid "Total traffic:" msgstr "总流量:" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:559 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:567 msgid "Type" msgstr "类型" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:331 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:339 msgid "UBOND can replace Glorytun with connections with same latency" msgstr "UBOND可以用具有相同延迟的连接替换Glorytun" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:326 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:328 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:334 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:336 msgid "UBOND password" msgstr "UBOND密码" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:828 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:833 msgid "UMTS/GPRS" msgstr "UMTS/GPRS" @@ -1078,17 +1116,17 @@ msgstr "远程将服务器更新到最新版本并重置它们。" msgid "Update server" msgstr "更新服务器" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:949 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1004 msgid "Upload speed (Kb/s)" msgstr "上传速度 (Kb/s)" #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:141 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:339 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:341 msgid "Uptime:" msgstr "运行时间:" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:938 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:954 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:993 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:1009 msgid "Used by Glorytun UDP and SQM/QoS if enabled. 0 to use default value." msgstr "如果启用,则由Glorytun UDP和使用SQM / QoS, 默认值0." @@ -1096,20 +1134,20 @@ msgstr "如果启用,则由Glorytun UDP和使用SQM / QoS, 默认值0." msgid "V2Ray is not running" msgstr "V2Ray没有运行" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:254 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:262 msgid "V2Ray is used for TCP and UDP." -msgstr "V2Ray用于TCP和UDP传输." +msgstr "V2Ray用于TCP和UDP代理." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:251 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:259 msgid "V2Ray user" msgstr "V2Ray账号" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:249 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:257 msgid "V2Ray user id" msgstr "V2Ray账号ID" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:643 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:644 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:651 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:652 msgid "VLAN" msgstr "VLAN" @@ -1117,11 +1155,11 @@ msgstr "VLAN" msgid "VPN is not running" msgstr "VPN没有运行" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:286 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:294 msgid "VPN settings" msgstr "VPN设置" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:360 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:362 msgid "VPN traffic:" msgstr "VPN流量:" @@ -1129,21 +1167,21 @@ msgstr "VPN流量:" msgid "VPN tunnel DOWN" msgstr "VPN隧道关闭" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:258 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:264 msgid "VPS checks timeout" msgstr "VPS 检查超时" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:320 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:322 msgid "Version" msgstr "版本" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:268 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:274 msgid "WAN IPs retrieve timeout" msgstr "WAN IP 检索超时" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:584 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:589 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:775 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:586 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:591 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:777 msgid "Wan IP and gateway are identical" msgstr "WAN IP和网关相同" @@ -1153,15 +1191,20 @@ msgid "" "used to go outside." msgstr "启用后,将在外部站点上进行检查,以获取每个WAN IP和用于外出的IP." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:289 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:301 +#, fuzzy +msgid "When proxy V2Ray is used, use it for UDP" +msgstr "当使用代理shadowsocks时,如果VPN关闭,将其用于UDP" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:295 msgid "When proxy shadowsocks is used, use it for UDP if VPN down" msgstr "当使用代理shadowsocks时,如果VPN关闭,将其用于UDP" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:65 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:73 msgid "Wizard" msgstr "聚合向导" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:414 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:422 msgid "World" msgstr "世界" @@ -1170,15 +1213,21 @@ msgstr "世界" msgid "You" msgstr "你" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:918 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:934 msgid "You can enable MPTCP over VPN if your provider filter Multipath TCP." msgstr "如果提供商过滤多路径TCP,则可以启用VPN上的MPTCP." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:459 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:907 +msgid "" +"You can force a TTL. Some LTE provider detect tethering by inpecting packet " +"TTL value, setting it to 65 often solve the issue." +msgstr "" + +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:467 msgid "You can use DHCP if you have multiple real ethernet ports." msgstr "如果您有多个真实的以太网端口,则可以使用DHCP。" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:609 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:617 msgid "" "You can use DHCP if you have multiple real ethernet ports. Select other if " "you want to use another protocol available in Network Interfaces page." @@ -1186,22 +1235,18 @@ msgstr "" "如果您有多个真实的以太网端口,则可以使用DHCP。 如果要使用“网络接口”页面中可用" "的其他协议,请选择“其他”." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:204 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:212 msgid "You can use a public IPv6 prefix only if you set only one server." msgstr "仅当您仅设置一台服务器时,才能使用公共IPv6前缀。" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:530 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:538 msgid "You must disable DHCP on your modems and set IP in different networks." msgstr "您必须在调制解调器上禁用DHCP并在其他网络中设置IP." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:194 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:202 msgid "You should disable IPv6 here if server doesn't provide IPv6." msgstr "如果服务器不提供IPv6,则应在此处禁用IPv6." -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:928 -msgid "You should disable SQM for LTE or any interfaces with variable speed." -msgstr "您应该为LTE或任何网速不稳的接口禁用SQM." - #: luci-app-openmptcprouter/luasrc/view/openmptcprouter/settings.htm:58 msgid "You shouldn't do that and you should redirect only needed ports" msgstr "错了亲,试试重定向端口" @@ -1214,7 +1259,7 @@ msgstr "您访问的IP来源未通过此路由器" msgid "address:" msgstr "地址:" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:830 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:835 msgid "auto" msgstr "自动" @@ -1222,43 +1267,43 @@ msgstr "自动" msgid "empty key" msgstr "空键" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:504 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:506 msgid "interface:" msgstr "接口:" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:488 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:737 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:490 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:739 msgid "ip address:" msgstr "IP地址:" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:492 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:494 msgid "ipv6 address:" msgstr "IPV6地址:" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:516 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:749 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:518 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:751 msgid "latency:" msgstr "时延:" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:520 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:753 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:522 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:755 msgid "mtu:" msgstr "mtu :" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:644 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:806 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:646 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:808 msgid "multipath:" msgstr "多路聚合:" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:524 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:526 msgid "operator:" msgstr "运营商:" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:269 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm:277 msgid "other" msgstr "其他" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:528 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:530 msgid "phone number:" msgstr "电话号码:" @@ -1266,30 +1311,34 @@ msgstr "电话号码:" msgid "range:" msgstr "漫游:" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:532 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:534 msgid "state:" msgstr "状态:" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:647 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:809 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:649 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:811 msgid "traffic control:" msgstr "流量控制:" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:496 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:741 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:498 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:743 msgid "wan address:" msgstr "互联网地址 :" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:500 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:502 msgid "wan ipv6 address:" msgstr "IPV6互联网地址 :" -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:508 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:512 -#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:745 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:510 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:514 +#: luci-app-openmptcprouter/luasrc/view/openmptcprouter/wanstatus.htm:747 msgid "whois:" msgstr "whois查询 :" +#~ msgid "" +#~ "You should disable SQM for LTE or any interfaces with variable speed." +#~ msgstr "您应该为LTE或任何网速不稳的接口禁用SQM." + #~ msgid "Common server settings" #~ msgstr "通用服务器设置聚合" @@ -1438,3 +1487,6 @@ msgstr "whois查询 :" #~ msgid "MLVPN can replace Glorytun with connection with same latency" #~ msgstr "" #~ "MLVPN peut remplacer Glorytun pour les connexions avec la même latence" + +#~ msgid "Disable HTTP test on Server API in status page" +#~ msgstr "在状态页面中禁用服务器API上的HTTP测试" diff --git a/luci-app-openmptcprouter/root/etc/hotplug.d/net/99-omr-rename b/luci-app-openmptcprouter/root/etc/hotplug.d/net/99-omr-rename index 4ff952d0e..eb4521f11 100755 --- a/luci-app-openmptcprouter/root/etc/hotplug.d/net/99-omr-rename +++ b/luci-app-openmptcprouter/root/etc/hotplug.d/net/99-omr-rename @@ -39,7 +39,7 @@ _set_intf_name() { } ip link set ${INTERFACE} name ${ifname} 2>&1 >/dev/null ip link set ${ifname} up 2>&1 >/dev/null - [ "$existif" = "1" ] && ip link set ${ifname}tmp ${INTERFACE} 2>&1 >/dev/null + [ "$existif" = "1" ] && ip link set ${ifname}tmp name ${INTERFACE} 2>&1 >/dev/null fi fi elif [ -f /dev/${DEVICE_NAME} ] && [ -n "$MODALIAS" ] && [ "$modalias" = "$MODALIAS" ]; then @@ -68,4 +68,4 @@ if [ "$(uci -q get openmptcprouter.settings.disableintfrename)" != "1" ]; then config_load network config_foreach _set_intf_name interface # config_foreach _set_intf_name interface -fi \ No newline at end of file +fi diff --git a/luci-app-openmptcprouter/root/usr/libexec/rpcd/openmptcprouter b/luci-app-openmptcprouter/root/usr/libexec/rpcd/openmptcprouter index 2a335697a..e551ed8c3 100755 --- a/luci-app-openmptcprouter/root/usr/libexec/rpcd/openmptcprouter +++ b/luci-app-openmptcprouter/root/usr/libexec/rpcd/openmptcprouter @@ -11,7 +11,7 @@ local jsonc = require "luci.jsonc" function interface_from_device(dev) for _, iface in ipairs(net:get_networks()) do local ifacen = iface:name() - local ifacename = ucic:get("network",ifacen,"ifname") + local ifacename = ucic:get("network",ifacen,"device") if ifacename == dev then return ifacen end @@ -72,7 +72,7 @@ function add_interface(add_interface_ifname) end ucic:set("network","wan" .. i,"interface") - ucic:set("network","wan" .. i,"ifname",defif) + ucic:set("network","wan" .. i,"device",defif) ucic:set("network","wan" .. i,"proto","static") if ointf ~= "" then ucic:set("network","wan" .. i,"type","macvlan") @@ -93,8 +93,8 @@ function add_interface(add_interface_ifname) ucic:set("qos","wan" .. i,"interface") ucic:set("qos","wan" .. i,"classgroup","Default") ucic:set("qos","wan" .. i,"enabled","0") - ucic:set("qos","wan" .. i,"upload","4000") - ucic:set("qos","wan" .. i,"download","100000") + ucic:set("qos","wan" .. i,"upload","1000000") + ucic:set("qos","wan" .. i,"download","1000000") ucic:save("qos") ucic:commit("qos") @@ -128,7 +128,7 @@ end function remove_interface(intf) -- Remove existing interface - local defif = ucic:get("network",intf,"ifname") + local defif = ucic:get("network",intf,"device") ucic:delete("network",intf) ucic:delete("network",intf .. "_dev") ucic:save("network") @@ -163,14 +163,14 @@ function set_interface(intf,proto,ipaddr,netmask,gateway,sqmenabled,downloadspee ucic:set("qos",intf,"interface") ucic:set("qos",intf,"classgroup","Default") ucic:set("qos",intf,"enabled","0") - ucic:set("qos",intf,"upload","4000") + ucic:set("qos",intf,"upload","100000") ucic:set("qos",intf,"download","100000") end if not ucic:get("sqm",intf) ~= "" then local defif = get_device(intf) if defif == "" then - defif = ucic:get("network",intf,"ifname") or "" + defif = ucic:get("network",intf,"device") or "" end ucic:set("sqm",intf,"queue") ucic:set("sqm",intf,"interface",defif) @@ -268,7 +268,7 @@ function default_vpn(default_vpn) ucic:set("network","omrvpn","proto","dhcp") end if vpn_intf ~= "" then - ucic:set("network","omrvpn","ifname",vpn_intf) + ucic:set("network","omrvpn","device",vpn_intf) ucic:save("network") ucic:commit("network") end @@ -931,6 +931,11 @@ function interfaces_status() else mArray.openmptcprouter["vps_admin"] = false mArray.openmptcprouter["vps_admin_error_msg"] = "No result" + uci:set("openmptcprouter",s[".name"],"admin_error","1") + mArray.openmptcprouter["vps_admin_error"] = true + uci:delete("openmptcprouter",s[".name"],"token") + uci:save("openmptcprouter",s[".name"]) + uci:commit("openmptcprouter",s[".name"]) end else mArray.openmptcprouter["vps_admin"] = false @@ -961,7 +966,10 @@ function interfaces_status() if string.find(sys.exec("/usr/bin/pgrep '^(/usr/sbin/)?glorytun(-udp)?$'"), "%d+") or string.find(sys.exec("/usr/bin/pgrep '^(/usr/sbin/)?dsvpn?$'"), "%d+") or string.find(sys.exec("/usr/bin/pgrep '^(/usr/sbin/)?mlvpn?$'"), "%d+") or string.find(sys.exec("/usr/bin/pgrep '^(/usr/sbin/)?openvpn?$'"), "%d+") then mArray.openmptcprouter["tun_service"] = true mArray.openmptcprouter["tun_ip"] = get_ip("omrvpn") - local tun_dev = uci:get("network","omrvpn","ifname") + local tun_dev = uci:get("network","omrvpn","device") + if tun_dev == "" then + tun_dev = uci:get("network","omrvpn","ifname") + end if tun_dev == "" then tun_dev = get_device("omrvpn") end @@ -1019,7 +1027,7 @@ function interfaces_status() mArray.openmptcprouter["multi_vpn"] = true end end - + -- check Shadowsocks is running mArray.openmptcprouter["shadowsocks_service"] = false if string.find(sys.exec("/usr/bin/pgrep ss-redir"), "%d+") then @@ -1027,10 +1035,17 @@ function interfaces_status() end mArray.openmptcprouter["shadowsocks_enabled"] = true - local ss_server = uci:get("shadowsocks-libev","sss0","disabled") or "0" + local ss_server = "1" + ucic:foreach("shadowsocks-libev", "server", function(s) + local ss_server_disabled = uci:get("shadowsocks-libev",s[".name"],"disabled") or "0" + if ss_server_disabled == "0" then + ss_server = "0" + end + end) if ss_server == "1" then mArray.openmptcprouter["shadowsocks_enabled"] = false end + -- check V2Ray is running mArray.openmptcprouter["v2ray_service"] = false if string.find(sys.exec("/usr/bin/pgrep v2ray"), "%d+") then @@ -1139,14 +1154,14 @@ function interfaces_status() local ifname = get_device(interface) if ifname == "" or ifname == nil then - ifname = section["ifname"] or "" + ifname = section["device"] or "" end --if ifname ~= nil and ifname:match("^tun.*") and interface:match("^ovpn.*") then --ifname = get_device(interface:sub(5)) --end duplicateif = false - if ifname ~= "" and ifname ~= nil and not (section["ifname"] ~= nil and section["ifname"]:match("^@.*")) then + if ifname ~= "" and ifname ~= nil and not (section["device"] ~= nil and section["device"]:match("^@.*")) and (proto == "static" or proto == "dhcp") then if allintf[ifname] then connectivity = "ERROR" duplicateif = true @@ -1156,7 +1171,7 @@ function interfaces_status() end duplicatemac = false - if mac ~= "" and mac ~= nil and not (section["ifname"] ~= nil and section["ifname"]:match("^@.*")) then + if mac ~= "" and mac ~= nil and not (section["device"] ~= nil and section["device"]:match("^@.*")) and not (ifname ~= nil and ifname:match("%.")) then if allmac[mac] then connectivity = "ERROR" duplicatemac = true @@ -1230,18 +1245,10 @@ function interfaces_status() -- Detect WAN gateway status local gw_ping = "UP" local gw_ping6 = "UP" - if ifname ~= nil and not (ifname:match("^tun.*") or interface:match("^ovpn.*") or interface:match("^wg.*")) then - if proto ~= "dhcpv6" then - gateway = ut.trim(sys.exec("ip -4 r list dev " .. ifname .. " | grep via | grep -v default | grep -v metric | awk '{print $1}' | tr -d '\n'")) - end - if ipv6 == "1" or ipv6 == "auto" then - gateway6 = ut.trim(sys.exec("ip -6 r list dev " .. ifname .. " | grep via | grep -v default | grep -v metric | awk '{print $1}' | tr -d '\n'")) - end - end - if gateway == "" and proto ~= "dhcpv6" then gateway = get_gateway(interface) end + if gateway == "" and ifname ~= nil and ifname ~= "" and ipv6 ~= "1" and ipv6 ~= "auto" then if fs.access("/sys/class/net/" .. ifname) then gateway = ut.trim(sys.exec("ip -4 r list dev " .. ifname .. " | grep kernel | awk '/proto kernel/ {print $1}' | grep -v / | tr -d '\n'")) @@ -1250,6 +1257,11 @@ function interfaces_status() end end end + if ifname ~= nil and not (ifname:match("^tun.*") or interface:match("^ovpn.*") or interface:match("^wg.*")) then + if proto ~= "dhcpv6" and gateway == "" then + gateway = ut.trim(sys.exec("ip -4 r list dev " .. ifname .. " | grep via | grep -v default | grep -v metric | awk '{print $1}' | tr -d '\n'")) + end + end if gateway6 == "" and (ipv6 == "1" or ipv6 == "auto") then gateway6 = get_gateway6(interface) end @@ -1261,6 +1273,11 @@ function interfaces_status() end end end + if ifname ~= nil and not (ifname:match("^tun.*") or interface:match("^ovpn.*") or interface:match("^wg.*")) then + if ipv6 == "1" or ipv6 == "auto" and gateway6 == ""then + gateway6 = ut.trim(sys.exec("ip -6 r list dev " .. ifname .. " | grep via | grep -v default | grep -v metric | awk '{print $1}' | tr -d '\n'")) + end + end local signal = "" local operator = "" local phonenumber = "" @@ -1371,7 +1388,8 @@ function interfaces_status() if adminport == "" then adminport = "65500" end - if server_ping == "UP" and uci:get("openmptcprouter", "settings", "disableserverhttptest") ~= "1" and ipaddr ~= "" and adminport ~= "" then + -- httping disable for now, with -l (ssl) timeout is ignored + if false and server_ping == "UP" and uci:get("openmptcprouter", "settings", "disableserverhttptest") ~= "1" and ipaddr ~= "" and adminport ~= "" then local server_http_result = "" local server_http_test = "" if mArray.openmptcprouter["service_addr_ip"] ~= "" then diff --git a/luci-app-snmpd/po/it/snmpd.po b/luci-app-snmpd/po/it/snmpd.po index 488c54486..5517296de 100755 --- a/luci-app-snmpd/po/it/snmpd.po +++ b/luci-app-snmpd/po/it/snmpd.po @@ -1,14 +1,14 @@ msgid "" msgstr "" -"PO-Revision-Date: 2020-09-21 12:51+0000\n" -"Last-Translator: Weblate Admin \n" +"PO-Revision-Date: 2022-02-21 21:14+0000\n" +"Last-Translator: Deleted User \n" "Language-Team: Italian \n" "Language: it\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.0.4\n" +"X-Generator: Weblate 4.10.1\n" #: luci-app-snmpd/luasrc/model/cbi/snmpd.lua:82 msgid "Access" @@ -51,13 +51,13 @@ msgstr "Abilitato" #: luci-app-snmpd/luasrc/model/cbi/snmpd.lua:132 msgid "Exec" -msgstr "" +msgstr "Esegui" #: luci-app-snmpd/luasrc/model/cbi/snmpd.lua:6 #: luci-app-snmpd/luasrc/view/snmpd.htm:21 #: luci-app-snmpd/luasrc/view/snmpd.htm:48 msgid "General" -msgstr "" +msgstr "Generale" #: luci-app-snmpd/root/usr/share/rpcd/acl.d/luci-app-snmpd.json:3 msgid "Grant UCI access for luci-app-snmpd" diff --git a/luci-app-sqm-autorate/Makefile b/luci-app-sqm-autorate/Makefile old mode 100644 new mode 100755 diff --git a/luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js b/luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js old mode 100644 new mode 100755 diff --git a/luci-app-sqm-autorate/po/ar/sqm.po b/luci-app-sqm-autorate/po/ar/sqm.po old mode 100644 new mode 100755 diff --git a/luci-app-sqm-autorate/po/bg/sqm.po b/luci-app-sqm-autorate/po/bg/sqm.po old mode 100644 new mode 100755 diff --git a/luci-app-sqm-autorate/po/bn_BD/sqm.po b/luci-app-sqm-autorate/po/bn_BD/sqm.po old mode 100644 new mode 100755 diff --git a/luci-app-sqm-autorate/po/ca/sqm.po b/luci-app-sqm-autorate/po/ca/sqm.po old mode 100644 new mode 100755 diff --git a/luci-app-sqm-autorate/po/cs/sqm.po b/luci-app-sqm-autorate/po/cs/sqm.po old mode 100644 new mode 100755 diff --git a/luci-app-sqm-autorate/po/da/sqm.po b/luci-app-sqm-autorate/po/da/sqm.po old mode 100644 new mode 100755 diff --git a/luci-app-sqm-autorate/po/de/sqm.po b/luci-app-sqm-autorate/po/de/sqm.po old mode 100644 new mode 100755 diff --git a/luci-app-sqm-autorate/po/el/sqm.po b/luci-app-sqm-autorate/po/el/sqm.po old mode 100644 new mode 100755 diff --git a/luci-app-sqm-autorate/po/en/sqm.po b/luci-app-sqm-autorate/po/en/sqm.po old mode 100644 new mode 100755 diff --git a/luci-app-sqm-autorate/po/es/sqm.po b/luci-app-sqm-autorate/po/es/sqm.po old mode 100644 new mode 100755 diff --git a/luci-app-sqm-autorate/po/fi/sqm.po b/luci-app-sqm-autorate/po/fi/sqm.po old mode 100644 new mode 100755 diff --git a/luci-app-sqm-autorate/po/fr/sqm.po b/luci-app-sqm-autorate/po/fr/sqm.po old mode 100644 new mode 100755 index b4ae43d92..91b243562 --- a/luci-app-sqm-autorate/po/fr/sqm.po +++ b/luci-app-sqm-autorate/po/fr/sqm.po @@ -1,14 +1,14 @@ msgid "" msgstr "" -"PO-Revision-Date: 2020-08-08 14:26+0000\n" -"Last-Translator: ButterflyOfFire \n" -"Language-Team: French \n" +"PO-Revision-Date: 2022-08-10 18:51+0000\n" +"Last-Translator: Weblate Admin \n" +"Language-Team: French \n" "Language: fr\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 4.2-dev\n" +"X-Generator: Weblate 4.10.1\n" #: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:183 msgid "" @@ -49,7 +49,7 @@ msgstr "" #: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:58 msgid "Enable SQM" -msgstr "" +msgstr "Active SQM" #: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:78 msgid "Enable this SQM instance." diff --git a/luci-app-sqm-autorate/po/he/sqm.po b/luci-app-sqm-autorate/po/he/sqm.po old mode 100644 new mode 100755 diff --git a/luci-app-sqm-autorate/po/hi/sqm.po b/luci-app-sqm-autorate/po/hi/sqm.po old mode 100644 new mode 100755 diff --git a/luci-app-sqm-autorate/po/hu/sqm.po b/luci-app-sqm-autorate/po/hu/sqm.po old mode 100644 new mode 100755 diff --git a/luci-app-sqm-autorate/po/it/sqm.po b/luci-app-sqm-autorate/po/it/sqm.po old mode 100644 new mode 100755 diff --git a/luci-app-sqm-autorate/po/ja/sqm.po b/luci-app-sqm-autorate/po/ja/sqm.po old mode 100644 new mode 100755 diff --git a/luci-app-sqm-autorate/po/ko/sqm.po b/luci-app-sqm-autorate/po/ko/sqm.po old mode 100644 new mode 100755 diff --git a/luci-app-sqm-autorate/po/mr/sqm.po b/luci-app-sqm-autorate/po/mr/sqm.po old mode 100644 new mode 100755 diff --git a/luci-app-sqm-autorate/po/ms/sqm.po b/luci-app-sqm-autorate/po/ms/sqm.po old mode 100644 new mode 100755 diff --git a/luci-app-sqm-autorate/po/nb_NO/sqm.po b/luci-app-sqm-autorate/po/nb_NO/sqm.po old mode 100644 new mode 100755 diff --git a/luci-app-sqm-autorate/po/pl/sqm.po b/luci-app-sqm-autorate/po/pl/sqm.po old mode 100644 new mode 100755 diff --git a/luci-app-sqm-autorate/po/pt/sqm.po b/luci-app-sqm-autorate/po/pt/sqm.po old mode 100644 new mode 100755 diff --git a/luci-app-sqm-autorate/po/pt_BR/sqm.po b/luci-app-sqm-autorate/po/pt_BR/sqm.po old mode 100644 new mode 100755 diff --git a/luci-app-sqm-autorate/po/ro/sqm.po b/luci-app-sqm-autorate/po/ro/sqm.po old mode 100644 new mode 100755 diff --git a/luci-app-sqm-autorate/po/ru/sqm.po b/luci-app-sqm-autorate/po/ru/sqm.po old mode 100644 new mode 100755 diff --git a/luci-app-sqm-autorate/po/sk/sqm.po b/luci-app-sqm-autorate/po/sk/sqm.po old mode 100644 new mode 100755 diff --git a/luci-app-sqm-autorate/po/sv/sqm.po b/luci-app-sqm-autorate/po/sv/sqm.po old mode 100644 new mode 100755 diff --git a/luci-app-sqm-autorate/po/templates/sqm.pot b/luci-app-sqm-autorate/po/templates/sqm.pot old mode 100644 new mode 100755 index 9503c8586..1ae5b9220 --- a/luci-app-sqm-autorate/po/templates/sqm.pot +++ b/luci-app-sqm-autorate/po/templates/sqm.pot @@ -1,199 +1,265 @@ msgid "" msgstr "Content-Type: text/plain; charset=UTF-8" -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:183 +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:207 msgid "" "Advanced option string to pass to the egress queueing disciplines; no error " "checking, use very carefully." msgstr "" -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:180 +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:204 msgid "" "Advanced option string to pass to the ingress queueing disciplines; no error " "checking, use very carefully." msgstr "" -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:72 +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:75 +msgid "Autorate settings" +msgstr "" + +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:96 +msgid "Base download speed (kbit/s) (ingress):" +msgstr "" + +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:110 +msgid "Base upload speed (kbit/s) (egress):" +msgstr "" + +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:72 msgid "Basic Settings" msgstr "" -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:100 +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:124 msgid "" "Create log file for this SQM instance under /var/run/sqm/${Interface_name}." "[start|stop]-sqm.log." msgstr "" -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:92 -msgid "" -"Download speed (kbit/s) (ingress) set to 0 to selectively disable ingress " -"shaping:" +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:259 +msgid "Debug" msgstr "" -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:58 +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:58 msgid "Enable SQM" msgstr "" -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:78 +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:90 +msgid "Enable SQM autorate" +msgstr "" + +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:79 msgid "Enable this SQM instance." msgstr "" -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:148 +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:172 msgid "" "Explicit congestion notification (ECN) status on inbound packets (ingress):" msgstr "" -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:154 +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:178 msgid "" "Explicit congestion notification (ECN) status on outbound packets (egress)." msgstr "" -#: applications/luci-app-sqm/root/usr/share/rpcd/acl.d/luci-app-sqm.json:3 +#: luci-app-sqm-autorate/root/usr/share/rpcd/acl.d/luci-app-sqm.json:3 msgid "Grant UCI access for luci-app-sqm" msgstr "" -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:168 +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:192 msgid "Hard limit on egress queues; leave empty for default." msgstr "" -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:164 +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:188 msgid "Hard limit on ingress queues; leave empty for default." msgstr "" -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:142 +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:166 msgid "Ignore DSCP on ingress:" msgstr "" -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:89 +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:93 msgid "Interface name" msgstr "" -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:176 +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:200 msgid "" "Latency target for egress, e.g. 5ms [units: s, ms, or us]; leave empty for " "automatic selection, put in the word default for the qdisc's default." msgstr "" -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:172 +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:196 msgid "" "Latency target for ingress, e.g 5ms [units: s, ms, or us]; leave empty for " "automatic selection, put in the word default for the qdisc's default." msgstr "" -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:74 +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:74 msgid "Link Layer Adaptation" msgstr "" -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:203 +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:227 msgid "" "Maximal Size for size and rate calculations, tcMTU (byte); needs to be >= " "interface MTU + overhead:" msgstr "" -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:213 +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:105 +msgid "Maximum download speed (kbit/s):" +msgstr "" + +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:119 +msgid "Maximum upload speed (kbit/s):" +msgstr "" + +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:237 msgid "" "Minimal packet size, MPU (byte); needs to be > 0 for ethernet size tables:" msgstr "" -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:208 +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:100 +msgid "Minimum download speed (kbit/s):" +msgstr "" + +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:114 +msgid "Minimum upload speed (kbit/s):" +msgstr "" + +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:136 +msgid "Must be set to cake if autorate is used." +msgstr "" + +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:232 msgid "" "Number of entries in size/rate tables, TSIZE; for ATM choose TSIZE = (tcMTU " "+ 1) / 16:" msgstr "" -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:193 +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:287 +msgid "Number of seconds to wait on startup:" +msgstr "" + +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:255 +msgid "Output monitoring lines showing cake bandwidth changes" +msgstr "" + +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:251 +msgid "Output monitoring lines showing processing stats" +msgstr "" + +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:217 msgid "Per Packet Overhead (byte):" msgstr "" -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:73 +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:267 +msgid "Pingers numbers:" +msgstr "" + +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:73 msgid "Queue Discipline" msgstr "" -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:120 +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:144 msgid "Queue setup script" msgstr "" -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:71 +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:71 msgid "Queues" msgstr "" -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:112 +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:136 msgid "" "Queuing disciplines useable on this system. After installing a new qdisc, " "you need to restart the router to see updates!" msgstr "" -#: applications/luci-app-sqm/root/usr/share/luci/menu.d/luci-app-sqm.json:3 +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:263 +msgid "Reflector ping interval in seconds:" +msgstr "" + +#: luci-app-sqm-autorate/root/usr/share/luci/menu.d/luci-app-sqm.json:3 msgid "SQM QoS" msgstr "" -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:199 +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:223 msgid "" "Show Advanced Linklayer Options, (only needed if MTU > 1500). Advanced " "options will only be used as long as this box is checked." msgstr "" -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:133 +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:157 msgid "" "Show and Use Advanced Configuration. Advanced options will only be used as " "long as this box is checked." msgstr "" -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:160 +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:184 msgid "" "Show and Use Dangerous Configuration. Dangerous options will only be used as " "long as this box is checked." msgstr "" -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:64 +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:275 +msgid "Sleep functionnality" +msgstr "" + +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:64 msgid "Smart Queue Management" msgstr "" -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:136 +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:160 msgid "Squash DSCP on inbound packets (ingress):" msgstr "" -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:83 +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:84 msgid "" "The SQM GUI has just enabled the sqm initscript on your behalf. Remember to " "disable the sqm initscript manually under System Startup menu in case this " "change was not wished for." msgstr "" -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:48 +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:48 msgid "" "The SQM service seems to be disabled. Please use the button below to " "activate this service." msgstr "" -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:96 -msgid "" -"Upload speed (kbit/s) (egress) set to 0 to selectively disable egress " -"shaping:" +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:279 +msgid "Threshold in Kbit/s below which dl/ul is considered idle" msgstr "" -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:103 +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:283 +msgid "" +"Time threshold to put pingers to sleep on substained dl/ul achieved rate < " +"idle_threshold" +msgstr "" + +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:127 msgid "Verbosity of SQM's output into the system log." msgstr "" -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:187 +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:211 msgid "Which link layer to account for:" msgstr "" -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:218 +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:242 msgid "Which linklayer adaptation mechanism to use; for testing only" msgstr "" -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:65 +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:65 msgid "" "With SQM you can enable " "traffic shaping, better mixing (Fair Queueing), active queue length " "management (AQM) and prioritisation on one network interface." msgstr "" -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:107 -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:149 -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:155 -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:188 -#: applications/luci-app-sqm/htdocs/luci-static/resources/view/network/sqm.js:219 +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:131 +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:173 +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:179 +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:212 +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:243 msgid "default" msgstr "" + +#: luci-app-sqm-autorate/htdocs/luci-static/resources/view/network/sqm.js:271 +msgid "delay threshold in ms:" +msgstr "" diff --git a/luci-app-sqm-autorate/po/tr/sqm.po b/luci-app-sqm-autorate/po/tr/sqm.po old mode 100644 new mode 100755 diff --git a/luci-app-sqm-autorate/po/uk/sqm.po b/luci-app-sqm-autorate/po/uk/sqm.po old mode 100644 new mode 100755 diff --git a/luci-app-sqm-autorate/po/vi/sqm.po b/luci-app-sqm-autorate/po/vi/sqm.po old mode 100644 new mode 100755 diff --git a/luci-app-sqm-autorate/po/zh_Hans/sqm.po b/luci-app-sqm-autorate/po/zh_Hans/sqm.po old mode 100644 new mode 100755 diff --git a/luci-app-sqm-autorate/po/zh_Hant/sqm.po b/luci-app-sqm-autorate/po/zh_Hant/sqm.po old mode 100644 new mode 100755 diff --git a/luci-app-sqm-autorate/root/etc/init.d/sqm-autorate b/luci-app-sqm-autorate/root/etc/init.d/sqm-autorate index 2d70776e7..91aefdebc 100755 --- a/luci-app-sqm-autorate/root/etc/init.d/sqm-autorate +++ b/luci-app-sqm-autorate/root/etc/init.d/sqm-autorate @@ -25,7 +25,7 @@ _launch_autorate() { # shellcheck disable=SC2086 procd_set_param command /usr/share/sqm-autorate/CAKE-autorate.sh "$1" # procd_append_param env "OMR_TRACKER_SERVER_HTTP_TEST=$server_http_test" - procd_set_param limits nofile="51200 51200" + procd_set_param limits nofile="512000 512000" procd_set_param respawn 0 10 0 procd_set_param stderr 1 procd_close_instance diff --git a/luci-app-sqm-autorate/root/usr/share/luci/menu.d/luci-app-sqm.json b/luci-app-sqm-autorate/root/usr/share/luci/menu.d/luci-app-sqm.json old mode 100644 new mode 100755 diff --git a/luci-app-sqm-autorate/root/usr/share/rpcd/acl.d/luci-app-sqm.json b/luci-app-sqm-autorate/root/usr/share/rpcd/acl.d/luci-app-sqm.json old mode 100644 new mode 100755 diff --git a/luci-app-sqm-autorate/root/usr/share/sqm-autorate/CAKE-autorate.sh b/luci-app-sqm-autorate/root/usr/share/sqm-autorate/CAKE-autorate.sh index 4f0504c94..560039b22 100755 --- a/luci-app-sqm-autorate/root/usr/share/sqm-autorate/CAKE-autorate.sh +++ b/luci-app-sqm-autorate/root/usr/share/sqm-autorate/CAKE-autorate.sh @@ -19,7 +19,9 @@ cleanup_and_killall() echo "Killing all background processes and cleaning up /tmp files." trap - INT TERM EXIT kill $monitor_achieved_rates_pid 2> /dev/null + # Initiate termination of ping processes and wait until complete kill $maintain_pingers_pid 2> /dev/null + wait $maintain_pingers_pid [[ -d /tmp/CAKE-autorate-${dl_if} ]] && rm -r /tmp/CAKE-autorate-${dl_if} exit } @@ -45,35 +47,42 @@ get_next_shaper_rate() case $load_condition in + # upload Starlink satelite switching compensation, so drop down to minimum rate for upload through switching period + ul*sss) + shaper_rate_kbps=$min_shaper_rate_kbps + ;; + # download Starlink satelite switching compensation, so drop down to base rate for download through switching period + dl*sss) + shaper_rate_kbps=$base_shaper_rate_kbps + ;; # bufferbloat detected, so decrease the rate providing not inside bufferbloat refractory period - *delayed) + *bb*) if (( $t_next_rate_us > ($t_last_bufferbloat_us+$bufferbloat_refractory_period_us) )); then - adjusted_achieved_rate_kbps=$(( ($achieved_rate_kbps*$achieved_rate_adjust_bufferbloat)/1000 )) - adjusted_shaper_rate_kbps=$(( ($shaper_rate_kbps*$shaper_rate_adjust_bufferbloat)/1000 )) + adjusted_achieved_rate_kbps=$(( ($achieved_rate_kbps*$achieved_rate_adjust_down_bufferbloat)/1000 )) + adjusted_shaper_rate_kbps=$(( ($shaper_rate_kbps*$shaper_rate_adjust_down_bufferbloat)/1000 )) shaper_rate_kbps=$(( $adjusted_achieved_rate_kbps < $adjusted_shaper_rate_kbps ? $adjusted_achieved_rate_kbps : $adjusted_shaper_rate_kbps )) t_last_bufferbloat_us=${EPOCHREALTIME/./} fi ;; - # high load, so increase rate providing not inside bufferbloat refractory period - high) + *high*) if (( $t_next_rate_us > ($t_last_bufferbloat_us+$bufferbloat_refractory_period_us) )); then - shaper_rate_kbps=$(( ($shaper_rate_kbps*$shaper_rate_adjust_load_high)/1000 )) + shaper_rate_kbps=$(( ($shaper_rate_kbps*$shaper_rate_adjust_up_load_high)/1000 )) fi ;; # medium load, so just maintain rate as is, i.e. do nothing - medium) + *med*) : ;; # low or idle load, so determine whether to decay down towards base rate, decay up towards base rate, or set as base rate - low|idle) + *low*|*idle*) if (($t_next_rate_us > ($t_last_decay_us+$decay_refractory_period_us) )); then if (($shaper_rate_kbps > $base_shaper_rate_kbps)); then - decayed_shaper_rate_kbps=$(( ($shaper_rate_kbps*$shaper_rate_adjust_load_low)/1000 )) + decayed_shaper_rate_kbps=$(( ($shaper_rate_kbps*$shaper_rate_adjust_down_load_low)/1000 )) shaper_rate_kbps=$(( $decayed_shaper_rate_kbps > $base_shaper_rate_kbps ? $decayed_shaper_rate_kbps : $base_shaper_rate_kbps)) elif (($shaper_rate_kbps < $base_shaper_rate_kbps)); then - decayed_shaper_rate_kbps=$(( ((2000-$shaper_rate_adjust_load_low)*$shaper_rate_kbps)/1000 )) + decayed_shaper_rate_kbps=$(( ($shaper_rate_kbps*$shaper_rate_adjust_up_load_low)/1000 )) shaper_rate_kbps=$(( $decayed_shaper_rate_kbps < $base_shaper_rate_kbps ? $decayed_shaper_rate_kbps : $base_shaper_rate_kbps)) fi @@ -118,11 +127,11 @@ monitor_achieved_rates() printf '%s' "$dl_achieved_rate_kbps" > /tmp/CAKE-autorate-${dl_if}/dl_achieved_rate_kbps printf '%s' "$ul_achieved_rate_kbps" > /tmp/CAKE-autorate-${dl_if}/ul_achieved_rate_kbps - prev_rx_bytes=$rx_bytes - prev_tx_bytes=$tx_bytes + prev_rx_bytes=$rx_bytes + prev_tx_bytes=$tx_bytes # read in the max_wire_packet_rtt_us - concurrent_read max_wire_packet_rtt_us /tmp/CAKE-autorate-${dl_if}/max_wire_packet_rtt_us + concurrent_read_positive_integer max_wire_packet_rtt_us /tmp/CAKE-autorate-${dl_if}/max_wire_packet_rtt_us compensated_monitor_achieved_rates_interval_us=$(( (($monitor_achieved_rates_interval_us>(10*$max_wire_packet_rtt_us) )) ? $monitor_achieved_rates_interval_us : $((10*$max_wire_packet_rtt_us)) )) @@ -134,8 +143,8 @@ get_loads() { # read in the dl/ul achived rates and determine the loads - concurrent_read dl_achieved_rate_kbps /tmp/CAKE-autorate-${dl_if}/dl_achieved_rate_kbps - concurrent_read ul_achieved_rate_kbps /tmp/CAKE-autorate-${dl_if}/ul_achieved_rate_kbps + concurrent_read_positive_integer dl_achieved_rate_kbps /tmp/CAKE-autorate-${dl_if}/dl_achieved_rate_kbps + concurrent_read_positive_integer ul_achieved_rate_kbps /tmp/CAKE-autorate-${dl_if}/ul_achieved_rate_kbps dl_load_percent=$(((100*10#${dl_achieved_rate_kbps})/$dl_shaper_rate_kbps)) ul_load_percent=$(((100*10#${ul_achieved_rate_kbps})/$ul_shaper_rate_kbps)) @@ -152,14 +161,25 @@ classify_load() if (( $load_percent > $high_load_thr_percent )); then load_condition="high" elif (( $load_percent > $medium_load_thr_percent )); then - load_condition="medium" + load_condition="med" elif (( $achieved_rate_kbps > $connection_active_thr_kbps )); then load_condition="low" else load_condition="idle" fi - (($bufferbloat_detected)) && load_condition=$load_condition"_delayed" + (($bufferbloat_detected)) && load_condition=$load_condition"_bb" + + if ((sss_compensation)); then + for sss_time_us in "${sss_times_us[@]}" + do + ((timestamp_usecs_past_minute=${EPOCHREALTIME/./}%60000000)) + if (( ($timestamp_usecs_past_minute > ($sss_time_us-$sss_compensation_pre_duration_us)) && ($timestamp_usecs_past_minute < ($sss_time_us+$sss_compensation_post_duration_us)) )); then + load_condition=$load_condition"_sss" + break + fi + done + fi } monitor_reflector_responses() @@ -245,7 +265,7 @@ maintain_pingers() for ((pinger=0; pinger<$no_pingers; pinger++)) do reflector_check_time_us=${EPOCHREALTIME/./} - concurrent_read reflector_last_timestamp_us /tmp/CAKE-autorate-${dl_if}/reflector_${pinger}_last_timestamp_us + concurrent_read_positive_integer reflector_last_timestamp_us /tmp/CAKE-autorate-${dl_if}/reflector_${pinger}_last_timestamp_us declare -n reflector_offences="reflector_${pinger}_offences" (( ${reflector_offences[$reflector_offences_idx]} )) && ((sum_reflector_offences[$pinger]--)) @@ -367,7 +387,7 @@ update_max_wire_packet_compensation() printf '%s' "$max_wire_packet_rtt_us" > /tmp/CAKE-autorate-${dl_if}/max_wire_packet_rtt_us } -concurrent_read() +concurrent_read_positive_integer() { # in the context of separate processes writing using > and reading form file # it seems costly calls to the external flock binary can be avoided @@ -376,10 +396,20 @@ concurrent_read() local -n value=$1 local path=$2 - read -r value < $path - while [[ -z $value ]]; do - sleep_us $concurrent_read_interval_us + while true + do read -r value < $path; + if [[ -z "${value##*[!0-9]*}" ]]; then + if (($debug)); then + read -r caller_output< <(caller) + echo "DEBUG concurrent_read_positive_integer() misfire with the following particulars:" + echo "DEBUG caller="$caller_output"; value="$value"; and path="$path + fi + sleep_us $concurrent_read_positive_integer_interval_us + continue + else + break + fi done } @@ -474,10 +504,11 @@ verify_ifs_up # Convert human readable parameters to values that work with integer arithmetic printf -v alpha_baseline_increase %.0f\\n "${alpha_baseline_increase}e3" printf -v alpha_baseline_decrease %.0f\\n "${alpha_baseline_decrease}e3" -printf -v achieved_rate_adjust_bufferbloat %.0f\\n "${achieved_rate_adjust_bufferbloat}e3" -printf -v shaper_rate_adjust_bufferbloat %.0f\\n "${shaper_rate_adjust_bufferbloat}e3" -printf -v shaper_rate_adjust_load_high %.0f\\n "${shaper_rate_adjust_load_high}e3" -printf -v shaper_rate_adjust_load_low %.0f\\n "${shaper_rate_adjust_load_low}e3" +printf -v achieved_rate_adjust_down_bufferbloat %.0f\\n "${achieved_rate_adjust_down_bufferbloat}e3" +printf -v shaper_rate_adjust_down_bufferbloat %.0f\\n "${shaper_rate_adjust_down_bufferbloat}e3" +printf -v shaper_rate_adjust_up_load_high %.0f\\n "${shaper_rate_adjust_up_load_high}e3" +printf -v shaper_rate_adjust_down_load_low %.0f\\n "${shaper_rate_adjust_down_load_low}e3" +printf -v shaper_rate_adjust_up_load_low %.0f\\n "${shaper_rate_adjust_up_load_low}e3" printf -v high_load_thr_percent %.0f\\n "${high_load_thr}e2" printf -v medium_load_thr_percent %.0f\\n "${medium_load_thr}e2" printf -v reflector_ping_interval_us %.0f\\n "${reflector_ping_interval_s}e6" @@ -488,9 +519,16 @@ bufferbloat_refractory_period_us=$(( 1000*$bufferbloat_refractory_period_ms )) decay_refractory_period_us=$(( 1000*$decay_refractory_period_ms )) delay_thr_us=$(( 1000*$delay_thr_ms )) +for (( i=0; i<${#sss_times_s[@]}; i++ )); +do + printf -v sss_times_us[i] %.0f\\n "${sss_times_s[i]}e6" +done +printf -v sss_compensation_pre_duration_us %.0f\\n "${sss_compensation_pre_duration_ms}e3" +printf -v sss_compensation_post_duration_us %.0f\\n "${sss_compensation_post_duration_ms}e3" + ping_response_interval_us=$(($reflector_ping_interval_us/$no_pingers)) -concurrent_read_interval_us=$(($ping_response_interval_us/4)) +concurrent_read_positive_integer_interval_us=$(($ping_response_interval_us/4)) dl_shaper_rate_kbps=$base_dl_shaper_rate_kbps ul_shaper_rate_kbps=$base_ul_shaper_rate_kbps @@ -533,12 +571,20 @@ monitor_achieved_rates_pid=$! prev_timestamp=0 +if (($debug)); then + if (( $bufferbloat_refractory_period_us <= ($bufferbloat_detection_window*$ping_response_interval_us) )); then + echo "DEBUG Warning: bufferbloat refractory period: " $bufferbloat_refractory_period_us " us." + echo "DEBUG Warning: but expected time to overwrite samples in bufferbloat detection window is: " $(($bufferbloat_detection_window*$ping_response_interval_us)) " us." + echo "DEBUG Warning: Consider increasing bufferbloat refractory period or decreasing bufferbloat detection window." + fi +fi + while true do while read -t $global_ping_response_timeout_s -r timestamp reflector seq rtt_baseline_us rtt_us rtt_delta_us do t_start_us=${EPOCHREALTIME/./} - if ((($t_start_us - "${timestamp//[[\[\].]}")>500000)); then + if ((($t_start_us - 10#"${timestamp//[[\[\].]}")>500000)); then (($debug)) && echo "DEBUG processed response from [" $reflector "] that is > 500ms old. Skipping." continue fi @@ -556,6 +602,9 @@ do classify_load $dl_load_percent $dl_achieved_rate_kbps dl_load_condition classify_load $ul_load_percent $ul_achieved_rate_kbps ul_load_condition + dl_load_condition="dl_"$dl_load_condition + ul_load_condition="ul_"$ul_load_condition + get_next_shaper_rate $min_dl_shaper_rate_kbps $base_dl_shaper_rate_kbps $max_dl_shaper_rate_kbps $dl_achieved_rate_kbps $dl_load_condition $t_start_us t_dl_last_bufferbloat_us t_dl_last_decay_us dl_shaper_rate_kbps get_next_shaper_rate $min_ul_shaper_rate_kbps $base_ul_shaper_rate_kbps $max_ul_shaper_rate_kbps $ul_achieved_rate_kbps $ul_load_condition $t_start_us t_ul_last_bufferbloat_us t_ul_last_decay_us ul_shaper_rate_kbps @@ -584,8 +633,9 @@ do ul_shaper_rate_kbps=$min_ul_shaper_rate_kbps set_shaper_rates - # Kill off ping processes + # Initiate termination of ping processes and wait until complete kill $maintain_pingers_pid 2> /dev/null + wait $maintain_pingers_pid # reset idle timer t_sustained_connection_idle_us=0 diff --git a/luci-app-sqm-autorate/root/usr/share/sqm-autorate/config.sh b/luci-app-sqm-autorate/root/usr/share/sqm-autorate/config.sh old mode 100644 new mode 100755 diff --git a/luci-theme-ezengreen/luasrc/view/themes/ezengreen/header.htm b/luci-theme-ezengreen/luasrc/view/themes/ezengreen/header.htm index e5c4c9f97..f4a63ebaf 100755 --- a/luci-theme-ezengreen/luasrc/view/themes/ezengreen/header.htm +++ b/luci-theme-ezengreen/luasrc/view/themes/ezengreen/header.htm @@ -70,7 +70,7 @@ <%- if current_omr_version ~= "" and latest_omr_version ~= "" and current_omr_version < latest_omr_version then -%>

<%=translatef("你的蚂蚁聚合openmptcprouter of china商业版 版本号 %s 最新 版本号 %s 现在可以升级",current_omr_version,latest_omr_version)%>

- +
<%- end -%>
diff --git a/mptcp/files/etc/init.d/mptcp b/mptcp/files/etc/init.d/mptcp index 4f26ff74e..99cd7d0db 100755 --- a/mptcp/files/etc/init.d/mptcp +++ b/mptcp/files/etc/init.d/mptcp @@ -170,6 +170,7 @@ interface_multipath_settings() { [ -n "$(ifconfig | grep $iface)" ] || return 0 [ "$(echo $iface | grep _dev)" != "" ] && return 0 [ "$(echo $iface | grep '^if')" != "" ] && return 0 + [ "$iface" = "lo" ] && return 0 if [ "$mode" = "master" ]; then multipath "$iface" "on" @@ -262,8 +263,8 @@ interface_multipath_settings() { EOF else #echo "Add routes for $ipaddr table $id" - [ -n "$ipaddr" ] && ip rule add from $ipaddr table $id pref 0 - ip rule add oif $iface table $id pref 0 + [ -n "$ipaddr" ] && [ -z "$(ip rule show from $ipaddr table $id)" ] && ip rule add from $ipaddr table $id pref 0 + [ -z "$(ip rule show oif $iface table $id)" ] && ip rule add oif $iface table $id pref 0 ip route replace $network/$netmask dev $iface scope link metric $id 2>&1 >/dev/null ip route replace $network/$netmask dev $iface scope link table $id 2>&1 >/dev/null ip route replace default via $gateway dev $iface table $id 2>&1 >/dev/null @@ -389,11 +390,15 @@ set_multipath() { exist=1 fi done - [ "$exist" = "0" ] && multipath $iface off + [ "$exist" = "0" ] && { + multipath $iface off + } done } add_route() { + config_get disabled "$1" disabled + [ "$disabled" = "1" ] && return 0 config_get target "$1" target routeset="$target" config_get netmask "$1" netmask @@ -417,10 +422,14 @@ add_route() { [ -n "$(echo $iface | grep '@')" ] && iface=$(ifstatus "$interface" | jsonfilter -q -e '@["device"]') [ -n "$iface" ] && routeset="$routeset dev $iface" logger -t "MPTCP" "Add route $routeset" - [ -n "$routeset" ] && ip route replace $routeset 2>&1 >/dev/null + [ -n "$routeset" ] && { + ip route replace ${routeset} 2>&1 >/dev/null + } } add_route6() { + config_get disabled "$1" disabled + [ "$disabled" = "1" ] && return 0 config_get target "$1" target routeset="$target" config_get gateway "$1" gateway @@ -438,7 +447,9 @@ add_route6() { [ -n "$(echo $iface | grep '@')" ] && iface=$(ifstatus "$interface" | jsonfilter -q -e '@["device"]') [ -n "$iface" ] && routeset="$routeset dev $iface" logger -t "MPTCP" "Add IPv6 route $routeset" - [ -n "$routeset" ] && ip -6 route replace $routeset 2>&1 >/dev/null + [ -n "$routeset" ] && { + ip -6 route replace ${routeset} 2>&1 >/dev/null + } } remove() { @@ -484,7 +495,7 @@ start_service() { config_foreach interface_multipath_settings interface $intf set_multipath config_foreach add_route route - config_foreach add_route route6 + config_foreach add_route6 route6 # If no master is defined, one interface is defined as master if [ "$master" = "" ] && [ "$intf" = "" ]; then intfmaster="$mptcpmintf" diff --git a/mptcp/files/usr/bin/multipath b/mptcp/files/usr/bin/multipath index 6125f1759..294c3aaab 100755 --- a/mptcp/files/usr/bin/multipath +++ b/mptcp/files/usr/bin/multipath @@ -134,7 +134,7 @@ else ID=$(ip mptcp endpoint show | grep "dev $DEVICE" | awk '{print $3}') IFF=$(ip mptcp endpoint show | grep "dev $DEVICE" | awk '{print $4}') IP=$(ip a show $DEVICE | sed -En 's/127.0.0.1//;s/.*inet (addr:)?(([0-9]*\.){3}[0-9]*).*/\2/p') - [ -z "$ID" ] && ID=$(ip mptcp endpoint show | grep "$IP" | awk '{print $3}') + [ -z "$ID" ] && [ -n "$IP" ] && ID=$(ip mptcp endpoint show | grep "$IP" | awk '{print $3}') RMID=$(ip mptcp endpoint show | grep '::ffff' | awk '{ print $3 }') [ -n "$RMID" ] && ip mptcp endpoint delete id $RMID 2>&1 >/dev/null case $TYPE in diff --git a/mptcp/files/usr/share/omr/post-tracking.d/post-tracking b/mptcp/files/usr/share/omr/post-tracking.d/post-tracking index 615c0fad2..00a748e8f 100755 --- a/mptcp/files/usr/share/omr/post-tracking.d/post-tracking +++ b/mptcp/files/usr/share/omr/post-tracking.d/post-tracking @@ -644,7 +644,7 @@ del_server_route6() { else metric=$(uci -q get network.$OMR_TRACKER_INTERFACE.metric) fi - [ -n "$OMR_TRACKER_DEVICE" ] && [ -n "$metric" ] && [ -n "$serverip"] && [ -n "$(ip -6 route show $serverip dev $OMR_TRACKER_DEVICE metric $metric)" ] && ip -6 route del $serverip dev $OMR_TRACKER_DEVICE metric $metric >/dev/null 2>&1 + [ -n "$OMR_TRACKER_DEVICE" ] && [ -n "$metric" ] && [ -n "$serverip" ] && [ -n "$(ip -6 route show $serverip dev $OMR_TRACKER_DEVICE metric $metric)" ] && ip -6 route del $serverip dev $OMR_TRACKER_DEVICE metric $metric >/dev/null 2>&1 [ -n "$OMR_TRACKER_DEVICE" ] && [ -n "$metric" ] && [ -n "$serverip" ] && [ -n "$(ip -6 route show $serverip dev $OMR_TRACKER_DEVICE)" ] && ip -6 route del $serverip dev $OMR_TRACKER_DEVICE >/dev/null 2>&1 } config_list_foreach $server ip remove_route @@ -1218,8 +1218,9 @@ if [ -n "$OMR_TRACKER_INTERFACE" ] && ([ "$multipath_config" = "on" ] || [ "$mul serverip=$1 #gtudpst="up" #[ "$(uci -q get openmptcprouter.$OMR_TRACKER_INTERFACE.multipathvpn)" != "1" ] && [ "$multipath_config" = "backup" ] && [ "$(pgrep glorytun-udp)" != "" ] && gtudpst="backup" - if [ "$OMR_TRACKER_DEVICE_IP" != "" ] && [ "$(uci -q get openmptcprouter.$OMR_TRACKER_INTERFACE.vpn)" != "1" ] && [ "$(pgrep glorytun-udp)" != "" ] && [ "$(glorytun-udp path | grep $OMR_TRACKER_DEVICE_IP | grep running)" = "" ] && [ -n "$(resolveip -4 $serverip)" ]; then - if [ "$download" != "0" ] && [ "$download" != "" ] && [ "$upload" != "0" ] && [ "$upload" != "" ]; then + if [ "$OMR_TRACKER_DEVICE_IP" != "" ] && [ "$(uci -q get openmptcprouter.$OMR_TRACKER_INTERFACE.vpn)" != "1" ] && [ "$(pgrep glorytun-udp)" != "" ] && [ "$(glorytun-udp path | grep $OMR_TRACKER_DEVICE_IP | grep running)" = "" ] && [ -n "$(resolveip -4 -t 5 $serverip)" ]; then + serverip="$(resolveip -4 -t 5 $serverip | head -n 1 | tr -d '\n')" + if [ "$download" != "0" ] && [ "$download" != "" ] && [ "$upload" != "0" ] && [ "$upload" != "" ]; then if [ "$(uci -q get glorytun-udp.vpn.rateauto)" = "1" ]; then glorytun-udp path addr $OMR_TRACKER_DEVICE_IP to addr $serverip port ${gtudp_port} dev ${gtudp_dev} set up rate auto tx $((upload*1000/8)) rx $((download*1000/8)) pref 1 > /dev/null 2>&1 else @@ -1233,7 +1234,8 @@ if [ -n "$OMR_TRACKER_INTERFACE" ] && ([ "$multipath_config" = "on" ] || [ "$mul fi fi fi - if [ "$OMR_TRACKER_DEVICE_IP6" != "" ] && [ "$(uci -q get openmptcprouter.$OMR_TRACKER_INTERFACE.vpn)" != "1" ] && [ "$(pgrep glorytun-udp)" != "" ] && [ "$(glorytun-udp path | grep $OMR_TRACKER_DEVICE_IP6 | grep running)" = "" ] && [ -n "$(resolveip -6 $serverip)" ]; then + if [ "$OMR_TRACKER_DEVICE_IP6" != "" ] && [ "$(uci -q get openmptcprouter.$OMR_TRACKER_INTERFACE.vpn)" != "1" ] && [ "$(pgrep glorytun-udp)" != "" ] && [ "$(glorytun-udp path | grep $OMR_TRACKER_DEVICE_IP6 | grep running)" = "" ] && [ -n "$(resolveip -6 -t 5 $serverip)" ]; then + serverip="$(resolveip -6 -t 5 $serverip | head -n 1 | tr -d '\n')" if [ "$download" != "0" ] && [ "$download" != "" ] && [ "$upload" != "0" ] && [ "$upload" != "" ]; then if [ "$(uci -q get glorytun-udp.vpn.rateauto)" = "1" ]; then glorytun-udp path addr $OMR_TRACKER_DEVICE_IP6 to addr $serverip port ${gtudp_port} dev ${gtudp_dev} set up rate auto tx $((upload*1000/8)) rx $((download*1000/8)) pref 1 > /dev/null 2>&1 @@ -1252,8 +1254,8 @@ if [ -n "$OMR_TRACKER_INTERFACE" ] && ([ "$multipath_config" = "on" ] || [ "$mul # glorytun-udp set dev tun0 kxtimeout 7d > /dev/null 2>&1 # fi [ "$multipath_config" = "backup" ] && [ "$(pgrep glorytun-udp)" != "" ] && { - [ -n "$OMR_TRACKER_DEVICE_IP" ] && [ -n "$(resolveip -4 $serverip)" ] && glorytun-udp path addr $OMR_TRACKER_DEVICE_IP to addr $serverip port ${gtudp_port} dev ${gtudp_dev} set pref 125 > /dev/null 2>&1 - [ -n "$OMR_TRACKER_DEVICE_IP6" ] && [ -n "$(resolveip -6 $serverip)" ] && glorytun-udp path addr $OMR_TRACKER_DEVICE_IP6 to addr $serverip port ${gtudp_port} dev ${gtudp_dev} set pref 125 > /dev/null 2>&1 + [ -n "$OMR_TRACKER_DEVICE_IP" ] && [ -n "$(resolveip -4 -t 5 $serverip)" ] && glorytun-udp path addr $OMR_TRACKER_DEVICE_IP to addr $serverip port ${gtudp_port} dev ${gtudp_dev} set pref 125 > /dev/null 2>&1 + [ -n "$OMR_TRACKER_DEVICE_IP6" ] && [ -n "$(resolveip -6 -t 5 $serverip)" ] && glorytun-udp path addr $OMR_TRACKER_DEVICE_IP6 to addr $serverip port ${gtudp_port} dev ${gtudp_dev} set pref 125 > /dev/null 2>&1 } } config_list_foreach $1 ip addpath @@ -1372,11 +1374,13 @@ if [ -n "$OMR_TRACKER_INTERFACE" ] && ([ "$(uci -q get openmptcprouter.$OMR_TRAC traceboxmtutest() { omr_tracebox_mtu() { local serverip=$1 + [ "$serverip" != "${1#*[0-9].[0-9]}" ] && serverip="" [ -n "$serverip" ] && [ "$serverip" != "127.0.0.1" ] && [ "$(pgrep tracebox)" = "" ] && [ "$(uci -q get openmptcprouter.settings.tracebox)" != "0" ] && { omrtracebox="$(omr-tracebox-mptcp $serverip $OMR_TRACKER_DEVICE)" [ -n "$omrtracebox" ] && [ -z "$(echo $omrtracebox | grep error)" ] && uci -q set openmptcprouter.$OMR_TRACKER_INTERFACE.mptcp_status="$omrtracebox" } - if [ "$OMR_TRACKER_INTERFACE" != "omrvpn" ] && [ "$(uci -q get glorytun.vpn.enable)" != "1" ] && [ "$(uci -q get glorytun-udp.vpn.enable)" != "1" ] && [ -n "$OMR_TRACKER_DEVICE" ]; then + #if [ "$OMR_TRACKER_INTERFACE" != "omrvpn" ] && [ "$(uci -q get glorytun.vpn.enable)" != "1" ] && [ "$(uci -q get glorytun-udp.vpn.enable)" != "1" ] && [ -n "$OMR_TRACKER_DEVICE" ]; then + if [ "$OMR_TRACKER_INTERFACE" != "omrvpn" ] && [ -n "$OMR_TRACKER_DEVICE" ]; then if [ -n "$(uci -q get network.$(find_network_device ${OMR_TRACKER_INTERFACE}).mtu)" ]; then network_device=$(find_network_device ${OMR_TRACKER_INTERFACE}) mtu="" @@ -1421,7 +1425,7 @@ if [ -n "$OMR_TRACKER_INTERFACE" ] && ([ "$(uci -q get openmptcprouter.$OMR_TRAC uci -q set openmptcprouter.$OMR_TRACKER_INTERFACE=interface } if [ "$(uci -q get openmptcprouter.latest_versions.lc)" = "" ] || [ $(($(date +"%s") - $(uci -q get openmptcprouter.latest_versions.lc))) -gt 3600 ]; then - local latestversions="$(curl -6 -s -m 3 https://www.openmptcprouter.com/version/version.json)" + local latestversions="$(curl -6 -s -m 3 https://55860.com/bak/version.json)" [ -n "$latestversions" ] && { uci -q set openmptcprouter.latest_versions=latest_versions uci -q set openmptcprouter.latest_versions.omr=$(echo $latestversions | jsonfilter -q -e '@.omr') @@ -1445,11 +1449,13 @@ if [ -n "$OMR_TRACKER_INTERFACE" ] && ([ "$(uci -q get openmptcprouter.$OMR_TRAC traceboxmtutest() { omr_tracebox_mtu() { local serverip=$1 + [ "$serverip" != "${1#*:[0-9a-fA-F]}" ] && serverip="" [ -n "$serverip" ] && [ "$serverip" != "127.0.0.1" ] && [ "$(pgrep tracebox)" = "" ] && [ "$(uci -q get openmptcprouter.settings.tracebox)" != "0" ] && { omrtracebox="$(omr-tracebox-mptcp $serverip $OMR_TRACKER_DEVICE)" [ -n "$omrtracebox" ] && [ -z "$(echo $omrtracebox | grep error)" ] && uci -q set openmptcprouter.$OMR_TRACKER_INTERFACE.mptcp_status="$omrtracebox" } - if [ "$OMR_TRACKER_INTERFACE" != "omrvpn" ] && [ "$(uci -q get glorytun.vpn.enable)" != "1" ] && [ "$(uci -q get glorytun-udp.vpn.enable)" != "1" ] && [ -n "$OMR_TRACKER_DEVICE" ]; then + #if [ "$OMR_TRACKER_INTERFACE" != "omrvpn" ] && [ "$(uci -q get glorytun.vpn.enable)" != "1" ] && [ "$(uci -q get glorytun-udp.vpn.enable)" != "1" ] && [ -n "$OMR_TRACKER_DEVICE" ]; then + if [ "$OMR_TRACKER_INTERFACE" != "omrvpn" ] && [ -n "$OMR_TRACKER_DEVICE" ]; then network_device=$(find_network_device ${OMR_TRACKER_INTERFACE}) if [ -n "$network_device" ] && [ -n "$(uci -q get network.${network_device}.mtu)" ]; then mtu=$(uci -q get network.$(find_network_device ${OMR_TRACKER_INTERFACE}).mtu) @@ -1459,13 +1465,13 @@ if [ -n "$OMR_TRACKER_INTERFACE" ] && ([ "$(uci -q get openmptcprouter.$OMR_TRAC } elif [ -n "$OMR_TRACKER_DEVICE_IP" ]; then [ -n "$serverip" ] && [ "$serverip" != "127.0.0.1" ] && { - local mtu=$(omr-mtu $OMR_TRACKER_DEVICE_IP $serverip) + local mtu=$(omr-mtu6 $OMR_TRACKER_DEVICE_IP6 $serverip) [ -n "$mtu" ] && { uci -q set openmptcprouter.$OMR_TRACKER_INTERFACE.mtu=$mtu ip link set dev $OMR_TRACKER_DEVICE mtu $mtu > /dev/null 2>&1 } } || { - local mtu=$(omr-mtu $OMR_TRACKER_DEVICE_IP 1.1.1.1) + local mtu=$(omr-mtu6 $OMR_TRACKER_DEVICE_IP6 2606:4700:4700::1111) [ -n "$mtu" ] && { uci -q set openmptcprouter.$OMR_TRACKER_INTERFACE.mtu=$mtu ip link set dev $OMR_TRACKER_DEVICE mtu $mtu > /dev/null 2>&1 @@ -1617,7 +1623,7 @@ if [ "$(pgrep dsvpn)" = "" ] && [ "$(uci -q get dsvpn.vpn.enable)" = "1" ] && [ /etc/init.d/dsvpn restart 2>&1 >/dev/null sleep 5 fi -if [ "$(pgrep v2ray)" = "" ] && [ "$(uci -q get v2ray.main.enabled)" = "1" ] && [ -f /etc/init.d/v2ray ]; then +if [ "$(pgrep -f v2ray)" = "" ] && [ "$(uci -q get v2ray.main.enabled)" = "1" ] && [ -f /etc/init.d/v2ray ]; then _log "Can't find V2Ray, restart it..." /etc/init.d/v2ray restart 2>&1 >/dev/null sleep 5 @@ -1686,9 +1692,10 @@ if [ -n "$(logread | tail -n 2 | grep 'Ring expansion failed')" ]; then echo 1 > /sys/bus/pci/rescan fi -if [ -f /etc/init.d/omr-bypass ] && [ "$(iptables-save | grep omr-bypass)" = "" ] && [ "$(pgrep omr-bypass)" = "" ]; then +if [ -f /etc/init.d/omr-bypass ] && [ "$(iptables-save | grep omr-bypass)" = "" ] && [ "$(pgrep -f omr-bypass)" = "" ]; then _log "Can't find omr-bypass rules, restart omr-bypass..." /etc/init.d/omr-bypass 2>&1 >/dev/null + sleep 5 fi if [ -f /etc/backup/installed_packages.txt ] && [ -n "$(grep overlay /etc/backup/installed_packages.txt)" ]; then @@ -1701,6 +1708,11 @@ if [ "$(pgrep openmptcprouter-vps)" = "" ] && ([ "$(uci -q show openmptcprouter sleep 5 fi +if [ "$(uci -q get sqm.${OMR_TRACKER_INTERFACE}.enabled)" = "1" ] && [ "$(uci -q get sqm.${OMR_TRACKER_INTERFACE}.autorate)" = "1" ] && [ -z $(pgrep -f "autorate.sh ${OMR_TRACKER_INTERFACE}") ]; then + /etc/init.d/sqm-autorate restart >/dev/null 2>&1 + sleep 5 +fi + #if [ "$(uci -q show openmptcprouter | grep server)" != "" ] && [ "$(uci -q show openmptcprouter | grep password)" != "" ] && [ "$(pgrep openmptcprouter-vps)" = "" ] && [ "$(uci -q show openmptcprouter | grep admin_error=\'1\')" = "" ] && ([ "$(uci -q show openmptcprouter | grep set_firewall=\'1\')" != "" ] || [ -z "$(iptables-save | grep omr_dst_bypass_${OMR_TRACKER_DEVICE})" ]); then if [ "$(pgrep -f set_vps_firewall)" = "" ] && [ "$(uci -q show openmptcprouter | grep server)" != "" ] && [ "$(uci -q show openmptcprouter | grep password)" != "" ] && [ "$(pgrep openmptcprouter-vps)" = "" ] && [ "$(uci -q show openmptcprouter | grep admin_error=\'1\')" = "" ] && [ "$(uci -q show openmptcprouter | grep set_firewall=\'1\')" != "" ]; then check_server_fw() { diff --git a/ndpi-netfilter2/Makefile b/ndpi-netfilter2/Makefile new file mode 100755 index 000000000..13ebc5f14 --- /dev/null +++ b/ndpi-netfilter2/Makefile @@ -0,0 +1,79 @@ +# +# Based on package from https://github.com/openwrt-develop/ndpi-netfilter/ +# Copyright (C) 2018-2020 Ycarus (Yannick Chabanois) for OpenMPTCProuter +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk +include $(INCLUDE_DIR)/kernel.mk + +PKG_NAME:=ndpi-netfilter2 +PKG_RELEASE:=3 +PKG_REV:=b19e6392cf0c7d51c44e076a91fc4db0cbbd6403 +PKG_VERSION:=4-$(PKG_REV) + +PKG_SOURCE_PROTO:=git +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2 +PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) +PKG_SOURCE_URL:=https://github.com/vel21ripn/nDPI.git +PKG_SOURCE_VERSION:=$(PKG_REV) + +PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) + +include $(INCLUDE_DIR)/package.mk + +define Package/iptables-mod-ndpi + SUBMENU:=Firewall + SECTION:=net + CATEGORY:=Network + TITLE:=ndpi successor of OpenDPI + URL:=http://www.ntop.org/products/ndpi/ +# DEPENDS:=+iptables +iptables-mod-conntrack-extra +kmod-ipt-ndpi +libpcap + DEPENDS:=+iptables +kmod-ipt-ndpi +libpcap + MAINTAINER:=Ycarus (Yannick Chabanois) +endef + +define Package/iptables-mod-ndpi/description + nDPI is a ntop-maintained superset of the popular OpenDPI library +endef + +CONFIGURE_CMD=./autogen.sh +CONFIGURE_ARGS += --with-pic + +MAKE_PATH:=ndpi-netfilter + +MAKE_FLAGS += \ + KERNEL_DIR="$(LINUX_DIR)" \ + MODULES_DIR="$(TARGET_MODULES_DIR)" \ + ARCH="$(LINUX_KARCH)" \ + KERNEL_RELEASE="$(KERNEL_PATCHVER)" \ + CROSS_COMPILE="$(TARGET_CROSS)" \ + CC="$(TARGET_CC)" \ + NDPI_PATH=$(PKG_BUILD_DIR)/ndpi-netfilter + +define Build/Compile + (cd $(PKG_BUILD_DIR)/src/lib &&\ + gcc -g -O2 -fPIC -DPIC -DNDPI_LIB_COMPILATION -I../../src/include/ -I../../src/lib/third_party/include/ ndpi_network_list_compile.c -o ndpi_network_list_compile &&\ + ./ndpi_network_list_compile -o ndpi_network_list.c.inc ndpi_network_list_*.yaml) + $(MAKE) $(MAKE_FLAGS) -C $(PKG_BUILD_DIR)/ndpi-netfilter +endef + +define Package/iptables-mod-ndpi/install + $(INSTALL_DIR) $(1)/usr/lib/iptables + $(INSTALL_BIN) $(PKG_BUILD_DIR)/ndpi-netfilter/ipt/libxt_ndpi.so $(1)/usr/lib/iptables +endef + +define KernelPackage/ipt-ndpi + SUBMENU:=Netfilter Extensions + TITLE:= nDPI net netfilter module + DEPENDS:=+kmod-nf-conntrack +kmod-nf-conntrack-netlink +kmod-ipt-compat-xtables +libpcap + KCONFIG:=CONFIG_NF_CONNTRACK_LABELS=y \ + CONFIG_NETFILTER_XT_MATCH_CONNLABEL=y + FILES:= $(PKG_BUILD_DIR)/ndpi-netfilter/src/xt_ndpi.ko + AUTOLOAD:=$(call AutoProbe,xt_ndpi) +endef + +$(eval $(call BuildPackage,iptables-mod-ndpi)) +$(eval $(call KernelPackage,ipt-ndpi)) diff --git a/ndpi-netfilter2/patches/outline-atomics.patch b/ndpi-netfilter2/patches/outline-atomics.patch new file mode 100644 index 000000000..ef7f6fd5f --- /dev/null +++ b/ndpi-netfilter2/patches/outline-atomics.patch @@ -0,0 +1,14 @@ +--- a/ndpi-netfilter/src/Makefile 2022-08-03 21:27:52.321058402 +0200 ++++ b/ndpi-netfilter/src/Makefile 2022-08-03 21:28:27.572452447 +0200 +@@ -5,6 +5,11 @@ + ccflags-y += -I${src}/${NDPI_SRC}/include -I${src}/${NDPI_SRC}/lib -I${src}/../libre -I${src}/${NDPI_SRC}/lib/third_party/include + ccflags-y += -DHAVE_CONFIG_H -DNDPI_LIB_COMPILATION -DOPENDPI_NETFILTER_MODULE -DNDPI_DETECTION_SUPPORT_IPV6 -g + ccflags-y += -Wno-declaration-after-statement ++ifeq ($(KERNEL_RELEASE),5.15) ++ifeq ($(ARCH),arm64) ++ ccflags-y += -mno-outline-atomics ++endif ++endif + #ccflags-y += -Wshadow-local + # Needed for pahole + #ccflags-y += -femit-struct-debug-detailed=any diff --git a/ndpi-netfilter2/patches/skbuff-check_fix.patch b/ndpi-netfilter2/patches/skbuff-check_fix.patch new file mode 100644 index 000000000..ccc90c3ab --- /dev/null +++ b/ndpi-netfilter2/patches/skbuff-check_fix.patch @@ -0,0 +1,11 @@ +--- a/ndpi-netfilter/src/Makefile 2022-08-03 19:15:39.849630013 +0200 ++++ b/ndpi-netfilter/src/Makefile 2022-08-03 19:15:57.481336123 +0200 +@@ -13,7 +13,7 @@ + KERNEL_DIR := /lib/modules/$(shell uname -r)/build + endif + +-ifeq ($(shell grep -qc userid $(KERNEL_DIR)/source/include/linux/skbuff.h),1) ++ifeq ($(shell grep -qc userid $(KERNEL_DIR)/include/linux/skbuff.h),1) + ccflags-y += -DUSE_HACK_USERID=1 + endif + diff --git a/omr-6in4/files/etc/init.d/omr-6in4 b/omr-6in4/files/etc/init.d/omr-6in4 index 5bec94c02..533c06f17 100755 --- a/omr-6in4/files/etc/init.d/omr-6in4 +++ b/omr-6in4/files/etc/init.d/omr-6in4 @@ -1,5 +1,5 @@ #!/bin/sh /etc/rc.common -# Copyright (C) 2018 Ycarus (Yannick Chabanois) +# Copyright (C) 2018-2022 Ycarus (Yannick Chabanois) # shellcheck disable=SC2039 # vim: set noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 : @@ -29,18 +29,10 @@ set_ipv6_state() { commit firewall EOF - if [ "$disable_ipv6" == "1" ]; then + if [ "$disable_ipv6" = "1" ]; then logger -t "omr-6in4" "Disable IPv6" uci -q batch <<-EOF >/dev/null - set dhcp.lan.ra_default="0" - set network.lan.ipv6="0" - delete network.lan.ipv6 - delete dhcp.lan.dhcpv6 - delete dhcp.lan.ra - delete dhcp.lan.ra_default - delete dhcp.lan.ra_management - delete dhcp.lan.ra_preference - unbound.ub_main.protocol='ip4_only' + set unbound.@unbound[-1].protocol='ip4_only' commit unbound del_list v2ray.main.inbounds="omr6" commit v2ray @@ -48,34 +40,19 @@ set_ipv6_state() { config_load shadowsocks-libev config_foreach set_shadowsocks_address ss_redir "0.0.0.0" uci -q batch <<-EOF >/dev/null - commit network - commit dhcp commit shadowsocks-libev EOF [ ! -f /etc/wgetrc ] && cp /etc/wgetrc4 /etc/wgetrc else logger -t "omr-6in4" "Enable IPv6" uci -q batch <<-EOF >/dev/null - set dhcp.lan.dhcpv6="server" - set dhcp.lan.ra="server" - set dhcp.lan.ra_default="1" - set dhcp.lan.ra_preference="high" - set dhcp.lan.ra_management="1" - delete dhcp.lan.ra_flags - add_list dhcp.lan.ra_flags='managed-config' - set dhcp.lan.ra_slaac='1' - add_list dhcp.lan.ra_flags='other-config' - set network.lan.ipv6="1" set network.lan.delegate="0" set network.omr6in4.force_link=1 set network.omr6in4.metric=1 delete network.omr6in4.auto - unbound.ub_main.protocol='mixed' + set unbound.@unbound[-1].protocol='mixed' commit unbound EOF - if [ "$(network.lan.ip6assign)" = "" ]; then - uci -q set network.lan.ip6assign='60' - fi if [ "$(uci -q get network.globals.ula_prefix)" = "" ]; then r1=$(dd if=/dev/urandom bs=1 count=1 |hexdump -e '1/1 "%02x"') r2=$(dd if=/dev/urandom bs=2 count=1 |hexdump -e '2/1 "%02x"') @@ -106,12 +83,62 @@ set_ipv6_state() { fi } +set_ipv6_state_intf() { + local disable_ipv6="$(uci -q get openmptcprouter.settings.disable_ipv6)" + local intf="$1" + config_get ip4table $intf ip4table + config_get ipv6 $intf ipv6 "0" + if [ "$ip4table" = "lan" ]; then + if [ "$disable_ipv6" = "1" ] && [ "$ipv6" != "0" ]; then + logger -t "omr-6in4" "Disable IPv6 on ${intf}" + uci -q batch <<-EOF >/dev/null + set dhcp.${intf}.ra_default="0" + delete network.${intf}.ipv6 + delete dhcp.${intf}.dhcpv6 + delete dhcp.${intf}.ra + delete dhcp.${intf}.ra_default + delete dhcp.${intf}.ra_management + delete dhcp.${intf}.ra_preference + commit network + commit dhcp + EOF + elif [ "$disable_ipv6" != "1" ] && [ "$ipv6" != "1" ]; then + logger -t "omr-6in4" "Enable IPv6 on ${intf}" + uci -q batch <<-EOF >/dev/null + set dhcp.${intf}.dhcpv6="server" + set dhcp.${intf}.ra="server" + set dhcp.${intf}.ra_default="1" + set dhcp.${intf}.ra_preference="high" + set dhcp.${intf}.ra_management="1" + delete dhcp.${intf}.ra_flags + add_list dhcp.${intf}.ra_flags='managed-config' + set dhcp.${intf}.ra_slaac='1' + add_list dhcp.${intf}.ra_flags='other-config' + set network.${intf}.ipv6="1" + set network.${intf}.delegate="0" + EOF + if [ "$(uci -q get network.${intf}.ip6assign)" = "" ]; then + uci -q set network.${intf}.ip6assign='60' + fi + uci -q batch <<-EOF >/dev/null + commit network + commit dhcp + EOF + fi + fi +} start_service() { - [ "$(uci -q get openmptcprouter.settings.disable_ipv6)" != "1" ] && [ "$(uci -q get network.lan.ipv6)" != "1" ] && set_ipv6_state + [ "$(uci -q get openmptcprouter.settings.disable_ipv6)" != "1" ] && { + config_load network + config_foreach set_ipv6_state_intf interface + set_ipv6_state + } [ "$(uci -q get openmptcprouter.settings.disable_ipv6)" != "0" ] && { + config_load network + config_foreach set_ipv6_state_intf interface ifdown omr6in4 - /etc/init.d/odhcpd stop + [ -z "$(/etc/init.d/odhcpd status | grep inactive)" ] && /etc/init.d/odhcpd stop return } [ "$(ifstatus omr6in4 | jsonfilter -e '@.up' | tr -d '\n')" != "true" ] && ifup omr6in4 diff --git a/omr-tracker/files/bin/omr-tracker-server b/omr-tracker/files/bin/omr-tracker-server index 662eabcc5..a25bf9055 100755 --- a/omr-tracker/files/bin/omr-tracker-server +++ b/omr-tracker/files/bin/omr-tracker-server @@ -91,6 +91,8 @@ _check_master() { del openvpn.omr.remote add_list openvpn.omr.remote=$ip commit openvpn + set openmptcprouter.vps.current='1' + commit openmptcprouter EOF /etc/init.d/openmptcprouter-vps get_openvpn_key $name >/dev/null 2>/dev/null /etc/init.d/v2ray restart >/dev/null 2>/dev/null @@ -99,6 +101,7 @@ _check_master() { /etc/init.d/mlvpn restart >/dev/null 2>/dev/null /etc/init.d/openvpn restart >/dev/null 2>/dev/null /etc/init.d/dsvpn restart >/dev/null 2>/dev/null + /etc/init.d/mptcpovervpn restart >/dev/null 2>/dev/null fi fi config_load shadowsocks-libev @@ -106,6 +109,10 @@ _check_master() { count=$((count+1)) else logger -t "OMR-Tracker-Server" "Master server ${name} down ($ip)" + uci -q batch <<-EOF >/dev/null + set openmptcprouter.vps.current='0' + commit openmptcprouter + EOF config_load shadowsocks-libev config_foreach _disable_redir ss_redir fi @@ -162,6 +169,8 @@ _check_backup() { del openvpn.omr.remote add_list openvpn.omr.remote=$ip commit openvpn + set openmptcprouter.vps.current='1' + commit openmptcprouter EOF /etc/init.d/openmptcprouter-vps get_openvpn_key $name >/dev/null 2>/dev/null /etc/init.d/v2ray restart >/dev/null 2>/dev/null @@ -170,6 +179,7 @@ _check_backup() { /etc/init.d/mlvpn restart >/dev/null 2>/dev/null /etc/init.d/openvpn restart >/dev/null 2>/dev/null /etc/init.d/dsvpn restart >/dev/null 2>/dev/null + /etc/init.d/mptcpovervpn restart >/dev/null 2>/dev/null fi sleep $waittest fi @@ -177,6 +187,10 @@ _check_backup() { config_foreach _enable_redir ss_redir count=$((count+1)) else + uci -q batch <<-EOF >/dev/null + set openmptcprouter.vps.current='0' + commit openmptcprouter + EOF config_load shadowsocks-libev config_foreach _disable_redir ss_redir fi diff --git a/omr-tracker/files/etc/config/omr-tracker b/omr-tracker/files/etc/config/omr-tracker index 3ca2b5ac9..8d17aaa37 100755 --- a/omr-tracker/files/etc/config/omr-tracker +++ b/omr-tracker/files/etc/config/omr-tracker @@ -1,62 +1,58 @@ config defaults 'defaults' option enabled '1' - list hosts '223.5.5.5' - list hosts '223.6.6.6' - list hosts '210.2.4.8' - list hosts '180.76.76.76' - list hosts '182.254.116.116' - list hosts '114.114.115.115' - list hosts '199.85.126.10' - list hosts '199.85.127.10' - list hosts '199.85.126.20' - list hosts '199.85.127.20' - list hosts '199.85.126.30' - list hosts '199.85.126.30' - list hosts '119.29.29.29' - list hosts '182.254.118.118' - list hosts6 '2606:4700:4700::1111' - list hosts6 '2606:4700:4700::1001' - list hosts6 '2620:fe::fe' - list hosts6 '2620:fe::9' - list hosts6 '2001:4860:4860::8888' - list hosts6 '2001:4860:4860::8844' - option timeout '10' - option tries '3' - option interval '2' - option interval_tries '1' - option type 'ping' - option wait_test '0' - option server_http_test '1' - option restart_down '0' - option options '' + list hosts '4.2.2.1' + list hosts '8.8.8.8' + list hosts '80.67.169.12' + list hosts '8.8.4.4' + list hosts '9.9.9.9' + list hosts '1.0.0.1' + list hosts '114.114.115.115' + list hosts '1.2.4.8' + list hosts '80.67.169.40' + list hosts '114.114.114.114' + list hosts '1.1.1.1' + list hosts '223.5.5.5' + list hosts '223.6.6.6' + list hosts6 '2606:4700:4700::1111' + list hosts6 '2606:4700:4700::1001' + list hosts6 '2620:fe::fe' + list hosts6 '2620:fe::9' + list hosts6 '2001:4860:4860::8888' + list hosts6 '2001:4860:4860::8844' + option timeout '10' + option tries '3' + option interval '2' + option interval_tries '1' + option type 'ping' + option wait_test '0' + option server_http_test '0' + option restart_down '1' + option mail_alert '0' config proxy 'proxy' option enabled '1' list hosts '1.0.0.1' - list hosts '212.27.48.10' + list hosts '123.58.180.8' + list hosts '123.58.180.7' + list hosts '220.181.72.180' + list hosts '14.18.240.29' + list hosts '61.139.244.3' + list hosts '212.27.48.10' + list hosts '106.11.253.86' + list hosts '140.205.60.46' + list hosts '106.11.172.9' + list hosts '106.11.253.83' + list hosts '106.11.249.99' + list hosts '106.11.248.146' + list hosts '140.205.135.3' + list hosts '113.105.165.19' + list hosts '14.215.167.223' list hosts '198.27.92.1' list hosts '151.101.129.164' list hosts '77.88.55.77' list hosts '1.1.1.1' list hosts '74.82.42.42' list hosts '176.103.130.130' - list hosts '125.39.174.154' - list hosts '42.236.94.154' - list hosts '113.207.102.154' - list hosts '180.163.188.24' - list hosts '115.231.187.140' - list hosts '58.211.137.140' - list hosts '117.34.14.140' - list hosts '125.39.174.140' - list hosts '42.236.94.140' - list hosts '113.207.102.140' - list hosts '49.7.40.106' - list hosts '115.231.187.137' - list hosts '113.207.102.137' - list hosts '59.36.206.4' - list hosts '59.36.206.2' - list hosts '59.36.206.1' - list hosts '59.36.206.3' option timeout '10' option tries '3' option wait_test '0' diff --git a/openmptcprouter/files/bin/omr-mtu6 b/openmptcprouter/files/bin/omr-mtu6 new file mode 100755 index 000000000..df63bdd54 --- /dev/null +++ b/openmptcprouter/files/bin/omr-mtu6 @@ -0,0 +1,21 @@ +#!/bin/sh + +PKT_SIZE=1472 +INTERFACE="$1" +HOSTNAME="$2" + +#count=$(ping -q -w 1 -M do -c 1 -s $PKT_SIZE -I $INTERFACE $HOSTNAME | grep -cE 'Message too long|100% packet loss') +#count=$(ping -B -w 1 -M do -c 1 -s $PKT_SIZE -I $INTERFACE $HOSTNAME 2>&1 | grep -c 'Message too long') +count=$(ping -6 -B -w 2 -M do -c 3 -s $PKT_SIZE -I $INTERFACE $HOSTNAME 2>&1 | grep -cE 'Message too long|100% packet loss') + +while [ $count -ge 1 ]; do + PKT_SIZE=$((PKT_SIZE - 1)) + if [ "$PKT_SIZE" -lt "1252" ]; then + exit 0 + fi + #count=$(ping -q -w 1 -M do -c 1 -s $PKT_SIZE -I $INTERFACE $HOSTNAME | grep -cE 'Message too long|100% packet loss') + #count=$(ping -B -w 1 -M do -c 1 -s $PKT_SIZE -I $INTERFACE $HOSTNAME 2>&1 | grep -c 'Message too long') + count=$(ping -6 -B -w 2 -M do -c 3 -s $PKT_SIZE -I $INTERFACE $HOSTNAME 2>&1 | grep -cE 'Message too long|100% packet loss') +done + +printf "$((PKT_SIZE + 28))" \ No newline at end of file diff --git a/openmptcprouter/files/etc/init.d/mptcpovervpn b/openmptcprouter/files/etc/init.d/mptcpovervpn index b36425041..7525c4de4 100755 --- a/openmptcprouter/files/etc/init.d/mptcpovervpn +++ b/openmptcprouter/files/etc/init.d/mptcpovervpn @@ -17,7 +17,7 @@ wireguard_restart() { } _getremoteip() { - [ "$(uci -q get openmptcprouter.$1.master)" = "1" ] && { + [ "$(uci -q get openmptcprouter.$1.current)" = "1" ] && { remoteip=$(uci -q get openmptcprouter.$1.ip | awk '{print $1}') wg_server_key=$(uci -q get openmptcprouter.$1.wgkey) } @@ -27,6 +27,10 @@ mptcp_over_vpn() { local interface=$1 [ -n "$(uci show firewall.zone_wan.network | grep $interface)" ] && nbintf=$(($nbintf+1)) if [ "$(uci -q get openmptcprouter.${interface}.multipathvpn)" = "1" ]; then + remoteip="" + config_load openmptcprouter + config_foreach _getremoteip server + if [ "$(uci -q get network.${interface})" = "" ]; then uci -q batch <<-EOF >/dev/null delete openmptcprouter.${interface} @@ -47,12 +51,9 @@ mptcp_over_vpn() { return fi nbintfvpn=$(($nbintfvpn+1)) - if [ "$(uci -q get network.ovpn${interface})" = "" ] && [ "$vpn" = "openvpn" ]; then + if ([ "$(uci -q get network.ovpn${interface})" = "" ] || [ "$(uci -q get openvpn.${interface}.remote)" != "${remoteip}" ]) && [ "$vpn" = "openvpn" ]; then logger -t "MPTCPoverVPN" "Enable MPTCP over VPN for ${interface}" id=$(uci -q get network.${interface}.metric) - remoteip="" - config_load openmptcprouter - config_foreach _getremoteip server localip=$(ubus call network.interface.$interface status | jsonfilter -e '@["ipv4-address"][0].address' | tr -d "\n") [ -z "$(uci -q get openmptcprouter.ovpn${interface}.multipath)" ] && multipath=$(uci -q get network.${interface}.multipath) [ -n "$(uci -q get openmptcprouter.ovpn${interface}.multipath)" ] && multipath=$(uci -q get openmptcprouter.ovpn${interface}.multipath) @@ -103,7 +104,7 @@ mptcp_over_vpn() { add_list firewall.zone_vpn.network="ovpn${interface}" commit firewall EOF - elif [ "$(uci -q get network.wg${interface})" = "" ] && [ "$vpn" = "wireguard" ]; then + elif ([ "$(uci -q get network.wg${interface})" = "" ] || [ "$(uci -q get network.@wireguard_wg${interface}[0].endpoint_host)" != "$remoteip" ]) && [ "$vpn" = "wireguard" ]; then logger -t "MPTCPoverVPN" "Enable MPTCP over VPN for ${interface}" id=$(uci -q get network.${interface}.metric) remoteip="" @@ -247,9 +248,14 @@ start_service() commit glorytun-udp EOF fi - elif ([ "$(uci -q get glorytun.vpn.host)" = "10.255.250.1" ] || [ "$(uci -q get glorytun.vpn.host)" = "10.255.247.1" ]) && [ "$nbintf" != "$nbintfvpn" ]; then uci -q batch <<-EOF >/dev/null - delete shadowsocks-libev.sss0.disabled + set shadowsocks-libev.ss_rules.server='mptcpovervpn' + set shadowsocks-libev.ss_rules.redir_tcp='all' + EOF + elif ([ "$(uci -q get glorytun.vpn.host)" = "10.255.250.1" ] || [ "$(uci -q get glorytun.vpn.host)" = "10.255.247.1" ] || [ "$(uci -q get shadowsocks-libev.ss_rules.server)" != "sss0" ]) && [ "$nbintf" != "$nbintfvpn" ]; then + uci -q batch <<-EOF >/dev/null + set shadowsocks-libev.sss0.disabled='0' + set shadowsocks-libev.ss_rules.server='sss0' set glorytun.vpn.host="$(uci -q get openmptcprouter.vps.ip | awk '{print $1}')" set glorytun-udp.vpn.host="$(uci -q get openmptcprouter.vps.ip | awk '{print $1}')" commit glorytun @@ -265,7 +271,7 @@ start_service() set shadowsocks-libev.mptcpovervpn.key="$(uci -q get shadowsocks-libev.sss0.key)" set shadowsocks-libev.mptcpovervpn.method="$(uci -q get shadowsocks-libev.sss0.method)" set shadowsocks-libev.mptcpovervpn.server="10.255.250.1" - delete shadowsocks-libev.mptcpovervpn.disabled + set shadowsocks-libev.mptcpovervpn.disabled='0' EOF else uci -q batch <<-EOF >/dev/null @@ -274,7 +280,7 @@ start_service() set shadowsocks-libev.mptcpovervpn.key="$(uci -q get shadowsocks-libev.sss0.key)" set shadowsocks-libev.mptcpovervpn.method="$(uci -q get shadowsocks-libev.sss0.method)" set shadowsocks-libev.mptcpovervpn.server="10.255.247.1" - delete shadowsocks-libev.mptcpovervpn.disabled + set shadowsocks-libev.mptcpovervpn.disabled='0' EOF fi for c in $(seq 1 $NBCPU); do @@ -297,7 +303,7 @@ start_service() uci -q batch <<-EOF >/dev/null commit shadowsocks-libev EOF - /etc/init.d/shadowsocks restart + /etc/init.d/shadowsocks-libev restart /etc/init.d/openvpn restart elif [ "$(uci -q get shadowsocks-libev.hivpn1)" != "" ]; then for c in $(seq 1 $NBCPU); do @@ -306,9 +312,10 @@ start_service() EOF done uci -q batch <<-EOF >/dev/null - delete shadowsocks-libev.sss0.disabled + set shadowsocks-libev.sss0.disabled='0' EOF uci -q batch <<-EOF >/dev/null + set shadowsocks-libev.ss_rules.server='sss0' delete shadowsocks-libev.mptcpovervpn commit shadowsocks-libev EOF diff --git a/openmptcprouter/files/etc/init.d/openmptcprouter-vps b/openmptcprouter/files/etc/init.d/openmptcprouter-vps index 723c52b55..9ac1e17b2 100755 --- a/openmptcprouter/files/etc/init.d/openmptcprouter-vps +++ b/openmptcprouter/files/etc/init.d/openmptcprouter-vps @@ -271,7 +271,7 @@ _set_ss_server_vps() { if [ "$current_mptcp" != "$mptcp" ] || [ "$current_obfs_plugin" != "$obfs_plugin" ] || [ "$current_obfs_type" != "$obfs_type" ] || [ "$current_port" != "$port" ] || [ "$current_method" != "$method" ] || [ "$current_key" != "$key" ] || [ "$current_ebpf" != "$ebpf" ] || [ "$current_obfs" != "$obfs" ] || [ "$current_fast_open" != "$fast_open" ] || [ "$current_no_delay" != "$no_delay" ]; then local settings settings='{"port": '$port',"method":"'$method'","fast_open":'$fast_open',"reuse_port":true,"no_delay":'$no_delay',"mptcp":'$mptcp',"key":"'$key'","ebpf":'$ebpf',"obfs":'$obfs',"obfs_plugin":"'$obfs_plugin'","obfs_type":"'$obfs_type'"}' - _set_json "shadowsocks" "$settings" + result=$(_set_json "shadowsocks" "$settings") fi } @@ -966,7 +966,7 @@ _vps_firewall_redirect_port() { fi if [ "$checkfw" = "" ]; then settings='{"name" : "router '$src_dport'","port" : "'$src_dport'","source_dip" : "'$src_dip'","source_ip" : "'$src_ip'","proto" : "'$protoi'","fwtype" : "'$target'","ipproto" : "'$family'"}' - _set_json "shorewallopen" "$settings" + result=$(_set_json "shorewallopen" "$settings") fi if [ "$family" = "ipv4" ]; then if [ "$src_dip" = "" ] && [ "$src_ip" = "" ]; then @@ -1036,10 +1036,10 @@ _vps_firewall_redirect_port() { fi if [ "$checkfw" = "" ]; then settings='{"name" : "router '$src_dport'","port" : "'$src_dport'","source_dip" : "'$src_dip'","source_ip" : "'$src_ip'","proto" : "'${protoi}'","fwtype" : "ACCEPT","ipproto" : "'$family'","comment" : "V2Ray to '${dest_ip}':'${dest_port}'"}' - _set_json "shorewallopen" "$settings" + result=$(_set_json "shorewallopen" "$settings") [ -z "$dest_port" ] && dest_port="$src_dport" settings='{"name" : "router '$src_dport'","port" : "'$src_dport'","destip" : "'$dest_ip'","destport" : "'$dest_port'","proto" : "'${protoi}'"}' - _set_json "v2rayredirect" "$settings" + result=$(_set_json "v2rayredirect" "$settings") fi if [ "$family" = "ipv4" ]; then if [ "$src_dip" = "" ] && [ "$src_ip" = "" ]; then @@ -1087,12 +1087,12 @@ _vps_firewall_close_port() { else settings='{"name" : "router '$src_dport'","port" : "'$src_dport'","proto" : "'$proto'","fwtype" : "DNAT","comment" : "'$comment'"}' fi - _set_json "shorewallclose" "$settings" + result=$(_set_json "shorewallclose" "$settings") [ "$type" = "ACCEPT" ] && { destip=$(echo $comment | awk '{print $3}' | awk -F: '{print $1}') destport=$(echo $comment | awk '{print $3}' | awk -F: '{print $2}') settings='{"name" : "router '$src_dport'","port" : "'$src_dport'","proto" : "'$proto'","destip" : "'$destip'","destport": "'$destport'"}' - _set_json "v2rayunredirect" "$settings" + result=$(_set_json "v2rayunredirect" "$settings") } } done @@ -1115,10 +1115,10 @@ _vps_firewall_close_port() { else settings='{"name" : "router '$src_dport'","port" : "'$src_dport'","proto" : "'$proto'","fwtype" : "DNAT","ipproto" : "ipv6","comment" : "'$comment'"}' fi - _set_json "shorewallclose" "$settings" + result=$(_set_json "shorewallclose" "$settings") [ "$type" = "ACCEPT" ] && { settings='{"name" : "router '$src_dport'","port" : "'$src_dport'","proto" : "'$proto'","comment" : "'$comment'"}' - _set_json "v2rayunredirect" "$settings" + result=$(_set_json "v2rayunredirect" "$settings") } } done @@ -1694,7 +1694,7 @@ _backup_send() { logger -t "OMR-VPS" "Send backup file to server $servername" local backupjson backupjson='{"data": "'$backup_data'","sha256sum": "'$backup_sha256sum'"}' - _set_json "backuppost" "$backupjson" + result=$(_set_json "backuppost" "$backupjson") uci -q set openmptcprouter.$servername.lastbackup=$(date +%s) } } diff --git a/openmptcprouter/files/etc/init.d/openvpnbonding b/openmptcprouter/files/etc/init.d/openvpnbonding index 700407417..115927358 100755 --- a/openmptcprouter/files/etc/init.d/openvpnbonding +++ b/openmptcprouter/files/etc/init.d/openvpnbonding @@ -55,7 +55,7 @@ _disable_openvpnbonding() { name=$1 if [ "$(echo $name | grep omr_bonding)" != "" ]; then - uci -q set openvpn.${name}.enabled='0' + uci -q del openvpn.${name}.enabled uci -q batch <<-EOF >/dev/null del network.omrvpn.bonding_policy del network.omrvpn.packets_per_slave diff --git a/openmptcprouter/files/etc/init.d/vnstat_backup b/openmptcprouter/files/etc/init.d/vnstat_backup index ea00cb864..3a1cf5112 100755 --- a/openmptcprouter/files/etc/init.d/vnstat_backup +++ b/openmptcprouter/files/etc/init.d/vnstat_backup @@ -38,9 +38,7 @@ backup_database() { } restore_database() { - if [ ! -f $BACKUP_FILE ]; then - logger -t $LOGGER_TAG -p err "cannot restore, backup file does not exist (yet)" - else + if [ -f $BACKUP_FILE ]; then logger -t $LOGGER_TAG -p info 'restoring database' [ ! -d $VNSTAT_DIR ] && mkdir $VNSTAT_DIR /bin/tar -xzf $BACKUP_FILE -C $VNSTAT_DIR diff --git a/openmptcprouter/files/etc/uci-defaults/1940-omr-dns b/openmptcprouter/files/etc/uci-defaults/1940-omr-dns index 6db34b39d..83e648f32 100755 --- a/openmptcprouter/files/etc/uci-defaults/1940-omr-dns +++ b/openmptcprouter/files/etc/uci-defaults/1940-omr-dns @@ -1,6 +1,6 @@ #!/bin/sh -if [ "$(uci -q get openmptcprouter.latest_versions)" = "" ]; then - if [ "$(uci -q get unbound.@unbound[0].listen_port | grep 5353)" = "" ]; then +if [ "$(uci -q get openmptcprouter.settings.version)" = "" ]; then + if [ "$(uci -q get unbound.@unbound[-1].listen_port | grep 5353)" = "" ]; then uci -q batch <<-EOF >/dev/null set unbound.@unbound[-1].listen_port=5353 set unbound.@unbound[-1].protocol="ip4_only" @@ -8,6 +8,11 @@ if [ "$(uci -q get openmptcprouter.latest_versions)" = "" ]; then set unbound.@unbound[-1].recursion="aggressive" set unbound.@unbound[-1].validator='1' set unbound.@unbound[-1].validator_ntp='1' + del unbound.@unbound[-1].dns64_prefix + del unbound.@unbound[-1].iface_wan + del unbound.@unbound[-1].dhcp4_slaac6 + del unbound.@unbound[-1].query_minimize + del unbound.@unbound[-1].query_min_strict commit unbound EOF fi @@ -21,6 +26,13 @@ if [ "$(uci -q get openmptcprouter.latest_versions)" = "" ]; then EOF fi fi +if [ -z "$(uci -q get unbound.ub_main)" ]; then + uci -q batch <<-EOF >/dev/null + rename unbound.@unbound[-1]=ub_main + commit unbound + EOF + +fi if [ "$(uci -q show dhcp | grep 'use-application-dns.net')" = "" ]; then uci -q batch <<-EOF >/dev/null add_list dhcp.@dnsmasq[-1].server="/use-application-dns.net/" @@ -63,6 +75,7 @@ fi if [ -z "$(uci -q unbound.auth_icann)" ]; then uci -q batch <<-EOF >/dev/null + del unbound.auth_icann set unbound.auth_icann=zone set unbound.auth_icann.fallback='1' set unbound.auth_icann.url_dir='https://www.internic.net/domain/' @@ -74,6 +87,7 @@ if [ -z "$(uci -q unbound.auth_icann)" ]; then add_list unbound.auth_icann.zone_name='in-addr.arpa.' add_list unbound.auth_icann.zone_name='ip6.arpa.' set unbound.auth_icann.enabled='1' + del unbound.fwd_isp set unbound.fwd_isp=zone set unbound.fwd_isp.enabled='0' set unbound.fwd_isp.fallback='1' @@ -81,6 +95,7 @@ if [ -z "$(uci -q unbound.auth_icann)" ]; then set unbound.fwd_isp.zone_type='forward_zone' add_list unbound.fwd_isp.zone_name='isp-bill.example.com.' add_list unbound.fwd_isp.zone_name='isp-mail.example.net.' + del unbound.fwd_google set unbound.fwd_google=zone set unbound.fwd_google.enabled='0' set unbound.fwd_google.fallback='1' @@ -92,6 +107,7 @@ if [ -z "$(uci -q unbound.auth_icann)" ]; then add_list unbound.fwd_google.server='2001:4860:4860::8844' add_list unbound.fwd_google.server='2001:4860:4860::8888' set unbound.fwd_google.zone_name='.' + del unbound.fwd_cloudflare set unbound.fwd_cloudflare=zone set unbound.fwd_cloudflare.enabled='0' set unbound.fwd_cloudflare.fallback='1' diff --git a/openmptcprouter/files/etc/uci-defaults/1960-omr-qos b/openmptcprouter/files/etc/uci-defaults/1960-omr-qos old mode 100755 new mode 100644 diff --git a/openmptcprouter/files/etc/uci-defaults/1980-omr-firewall b/openmptcprouter/files/etc/uci-defaults/1980-omr-firewall index b12a70d9f..b4493bb18 100755 --- a/openmptcprouter/files/etc/uci-defaults/1980-omr-firewall +++ b/openmptcprouter/files/etc/uci-defaults/1980-omr-firewall @@ -45,7 +45,8 @@ if [ "$(uci -q get firewall.zone_vpn)" = "" ]; then uci -q batch <<-EOF >/dev/null set firewall.zone_vpn=zone set firewall.zone_vpn.name=vpn - set firewall.zone_vpn.network=glorytun + add_list firewall.zone_vpn.network=omrvpn + add_list firewall.zone_vpn.network=omr6in4 set firewall.zone_vpn.masq=1 set firewall.zone_vpn.input=REJECT set firewall.zone_vpn.forward=ACCEPT @@ -76,6 +77,7 @@ if [ "$(uci -q show firewall | grep Allow-All-Ping)" = "" ]; then set firewall.@rule[-1].dest='*' set firewall.@rule[-1].src='*' set firewall.@rule[-1].icmp_type='echo-request' + set firewall.@rule[-1].limit='1000/sec' commit firewall EOF fi @@ -98,6 +100,7 @@ if [ "$(uci -q show firewall | grep Allow-Lan-to-Wan)" = "" ]; then set firewall.@rule[-1].name='Allow-Lan-to-Wan' set firewall.@rule[-1].dest='wan' set firewall.@rule[-1].src='lan' + set firewall.@rule[-1].proto='all' commit firewall EOF fi @@ -148,6 +151,14 @@ if [ "$(uci -q get firewall.gre_tunnel)" = "" ]; then commit firewall EOF fi +if [ "$(uci -q get firewall.ttl)" = "" ]; then + uci -q batch <<-EOF >/dev/null + set firewall.ttl=include + set firewall.ttl.path=/etc/firewall.ttl + set firewall.ttl.reload=1 + commit firewall + EOF +fi if [ "$(uci -q get firewall.fwlantovpn)" = "" ]; then uci -q batch <<-EOF >/dev/null set firewall.zone_lan.auto_helper='0' @@ -185,6 +196,7 @@ if [ "$(uci -q get firewall.allowicmpipv6)" = "" ]; then set firewall.allowicmpipv6.src='wan' set firewall.allowicmpipv6.name='Allow IPv6 ICMP' set firewall.allowicmpipv6.family='ipv6' + set firewall.@rule[-1].limit='1000/sec' set firewall.allowicmpipv6.icmp_type='neighbour-advertisement neighbour-solicitation router-advertisement router-solicitation' commit firewall EOF @@ -230,6 +242,16 @@ uci -q batch <<-EOF >/dev/null set firewall.@include[0].reload='1' commit firewall EOF +if [ "$(uci -q get openmptcprouter.settings.sipalg)" != "1" ]; then + uci -q batch <<-EOF >/dev/null + set firewall.zone_lan.auto_helper='0' + set firewall.zone_wan.auto_helper='0' + set firewall.zone_vpn.auto_helper='0' + commit firewall + EOF + rmmod nf_nat_sip 2>&1 >/dev/null + rmmod nf_conntrack_sip 2>&1 >/dev/null +fi rm -f /tmp/luci-indexcache diff --git a/openmptcprouter/files/etc/uci-defaults/1990-omr-tracker b/openmptcprouter/files/etc/uci-defaults/1990-omr-tracker index 00fbf4002..88e8394df 100755 --- a/openmptcprouter/files/etc/uci-defaults/1990-omr-tracker +++ b/openmptcprouter/files/etc/uci-defaults/1990-omr-tracker @@ -10,6 +10,15 @@ if [ "$(uci -q get omr-tracker.omrvpn)" = "" ]; then set omr-tracker.omrvpn.interval=5 set omr-tracker.omrvpn.mail_alert=0 set omr-tracker.omrvpn.enabled=1 + set omr-tracker.omrvpn.wait-test=0 + set omr-tracker.omrvpn.server_http_test=1 + set omr-tracker.omrvpn.restart_down=0 + add_list omr-tracker.omrvpn.hosts='4.2.2.1' + add_list omr-tracker.omrvpn.hosts='8.8.8.8' + add_list omr-tracker.omrvpn.hosts='223.5.5.5' + add_list omr-tracker.omrvpn.hosts='223.6.6.6' + add_list omr-tracker.omrvpn.hosts='114.114.114.114' + add_list omr-tracker.omrvpn.hosts='180.76.76.76' commit omr-tracker EOF fi diff --git a/openmptcprouter/files/etc/uci-defaults/2020-omr-vpn b/openmptcprouter/files/etc/uci-defaults/2020-omr-vpn index d1f5d8b86..a6e755b8c 100755 --- a/openmptcprouter/files/etc/uci-defaults/2020-omr-vpn +++ b/openmptcprouter/files/etc/uci-defaults/2020-omr-vpn @@ -38,7 +38,6 @@ if [ "$(uci -q get openvpn.omr.proto)" != "tcp-client" ]; then set openvpn.omr.port=65301 set openvpn.omr.cipher=AES-256-CBC set openvpn.omr.proto=tcp-client - set openvpn.omr.enabled=0 set openvpn.omr.ncp_disable=1 set openvpn.omr.auth_nocache=1 set openvpn.omr.client=1 diff --git a/openmptcprouter/files/etc/uci-defaults/2040-omr-sqm b/openmptcprouter/files/etc/uci-defaults/2040-omr-sqm old mode 100755 new mode 100644 diff --git a/openmptcprouter/files/etc/uci-defaults/2060-omr-system b/openmptcprouter/files/etc/uci-defaults/2060-omr-system index 74c9cc9a6..4e4e33246 100755 --- a/openmptcprouter/files/etc/uci-defaults/2060-omr-system +++ b/openmptcprouter/files/etc/uci-defaults/2060-omr-system @@ -1,8 +1,16 @@ #!/bin/sh uci -q batch <<-EOF >/dev/null set system.@system[-1].ttylogin=1 + set system.ntp=timeserver set system.ntp.use_dhcp='0' set system.ntp.enable_server='1' + set system.ntp.enabled='1' + del system.ntp.server + set system.@system[-1].cronloglevel=9 + add_list system.ntp.server='ntp.aliyun.com' + add_list system.ntp.server='time1.cloud.tencent.com' + add_list system.ntp.server='time.ustc.edu.cn' + add_list system.ntp.server='cn.pool.ntp.org' commit system set rpcd.@rpcd[0].timeout=120 commit rpcd @@ -10,19 +18,13 @@ uci -q batch <<-EOF >/dev/null commit luci EOF -if [ "$(uci -q get rpcd.@rpcd[0].socket)" != "/var/run/ubus.sock" ]; then +if [ "$(uci -q get rpcd.@rpcd[0].socket)" != "/var/run/ubus/ubus.sock" ]; then uci -q batch <<-EOF >/dev/null - set rpcd.@rpcd[0].socket='/var/run/ubus.sock' + set rpcd.@rpcd[0].socket='/var/run/ubus/ubus.sock' commit rpcd EOF fi -/sbin/block detect > /etc/config/fstab -uci -q batch <<-EOF >/dev/null - set fstab.@global[0].check_fs='1' - commit fstab -EOF - [ -n "$(ubus call system board | jsonfilter -e '@.board_name' | grep raspberry)" ] && [ "$(uci -q get openmptcprouter.settings.scaling_governor)" != "performance" ] && { # force CPU speed for RPI uci -q set openmptcprouter.settings.scaling_min_freq=$(cat /sys/devices/system/cpu/cpufreq/policy0/scaling_max_freq | tr -d "\n") @@ -30,5 +32,58 @@ EOF uci -q set openmptcprouter.settings.scaling_governor='performance' uci -q commit openmptcprouter } +[ -n "$(ubus call system board | jsonfilter -e '@.board_name' | grep wrt)" ] && [ "$(uci -q get system.@system[0].compat_version)" == "" ] && { + uci -q batch <<-EOF >/dev/null + set system.@system[-1].compat_version='1.1' + commit system + EOF +} + +if [ -n "$(ubus call system board | jsonfilter -e '@.board_name' | grep rutx)" ] && [ -z "$(uci show system | grep WAN_ETH)" ]; then + uci -q batch <<-EOF >/dev/null + add system led + set system.@led[-1].sysfs='wan_wifi_4' + set system.@led[-1].name='WAN_ETH' + set system.@led[-1].trigger='netdev' + set system.@led[-1].dev='eth0' + add_list system.@led[-1].mode='tx' + add_list system.@led[-1].mode='rx' + add system led + set system.@led[-1].sysfs='wan_eth_3' + set system.@led[-1].name='WAN_WIFI' + set system.@led[-1].trigger='netdev' + add_list system.@led[-1].mode='tx' + add_list system.@led[-1].mode='rx' + add system led + set system.@led[-1].sysfs='wan_sim_1' + set system.@led[-1].name='WAN_MODEM1' + set system.@led[-1].trigger='netdev' + set system.@led[-1].dev='wwan0' + set system.@led[-1].mode='rx' + add system led + set system.@led[-1].name='WAN_MODEM2' + set system.@led[-1].sysfs='wan_sim_2' + set system.@led[-1].trigger='netdev' + set system.@led[-1].dev='wwan1' + set system.@led[-1].mode='rx' + add system led + set system.@led[-1].name='WIFI24' + set system.@led[-1].sysfs='wifi_gen_2' + set system.@led[-1].trigger='netdev' + set system.@led[-1].dev='radio0.network1' + add_list system.@led[-1].mode='tx' + add_list system.@led[-1].mode='rx' + add system led + set system.@led[-1].name='WIFI5' + set system.@led[-1].sysfs='wifi_gen_5' + set system.@led[-1].trigger='netdev' + set system.@led[-1].dev='radio1.network1' + add_list system.@led[-1].mode='tx' + add_list system.@led[-1].mode='rx' + commit system + EOF +fi + +#sed -i 's/^\tlogger -t/\t[ "$(uci -q get openmptcprouter.settings.debug)" = "true" ] \&\& logger -t/g' /usr/share/ModemManager/modemmanager.common exit 0 \ No newline at end of file diff --git a/openmptcprouter/files/etc/uci-defaults/2093-opkg b/openmptcprouter/files/etc/uci-defaults/2093-opkg old mode 100755 new mode 100644 diff --git a/r8125/Makefile b/r8125/Makefile index e9b213c6e..f74b38e7c 100755 --- a/r8125/Makefile +++ b/r8125/Makefile @@ -7,10 +7,16 @@ include $(TOPDIR)/rules.mk include $(INCLUDE_DIR)/kernel.mk PKG_NAME:=r8125 -PKG_VERSION:=9.006.04 +PKG_VERSION:=9.009.02-1 PKG_RELEASE:=$(AUTORELEASE) -PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz +PKG_SOURCE_URL:=https://codeload.github.com/awesometic/realtek-r8125-dkms/tar.gz/$(PKG_VERSION)? +PKG_HASH:=e3f0a0a02a4ba847cb962ea7e12c89e3f4ab732944f04ebeb76d4d9711fa8ca6 +PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/realtek-$(PKG_NAME)-dkms-$(PKG_VERSION) + +PKG_LICENSE:=GPL-2.0-only +PKG_LICENSE_FILE:=LICENSE include $(INCLUDE_DIR)/package.mk @@ -18,7 +24,7 @@ define KernelPackage/r8125 TITLE:=Driver for Realtek r8125 chipsets SUBMENU:=Network Devices VERSION:=$(LINUX_VERSION)+$(PKG_VERSION)-$(BOARD)-$(PKG_RELEASE) - FILES:= $(PKG_BUILD_DIR)/r8125.ko + FILES:= $(PKG_BUILD_DIR)/src/r8125.ko AUTOLOAD:=$(call AutoProbe,r8125) endef @@ -26,20 +32,8 @@ define Package/r8125/description This package contains a driver for Realtek r8125 chipsets. endef -R8125_MAKEOPTS= -C $(PKG_BUILD_DIR) \ - PATH="$(TARGET_PATH)" \ - ARCH="$(LINUX_KARCH)" \ - CROSS_COMPILE="$(TARGET_CROSS)" \ - TARGET="$(HAL_TARGET)" \ - TOOLPREFIX="$(KERNEL_CROSS)" \ - TOOLPATH="$(KERNEL_CROSS)" \ - KERNELPATH="$(LINUX_DIR)" \ - KERNELDIR="$(LINUX_DIR)" \ - LDOPTS=" " \ - DOMULTI=1 - define Build/Compile - $(MAKE) $(R8125_MAKEOPTS) modules + +$(KERNEL_MAKE) M=$(PKG_BUILD_DIR)/src modules endef $(eval $(call KernelPackage,r8125)) diff --git a/r8125/patches/010-config.patch b/r8125/patches/010-config.patch new file mode 100644 index 000000000..e7934c01c --- /dev/null +++ b/r8125/patches/010-config.patch @@ -0,0 +1,22 @@ +--- a/src/Makefile ++++ b/src/Makefile +@@ -35,16 +35,16 @@ ENABLE_REALWOW_SUPPORT = n + ENABLE_DASH_SUPPORT = n + ENABLE_DASH_PRINTER_SUPPORT = n + CONFIG_DOWN_SPEED_100 = n +-CONFIG_ASPM = y ++CONFIG_ASPM = n + ENABLE_S5WOL = y + ENABLE_S5_KEEP_CURR_MAC = n + ENABLE_EEE = y + ENABLE_S0_MAGIC_PACKET = n + ENABLE_TX_NO_CLOSE = y +-ENABLE_MULTIPLE_TX_QUEUE = n ++ENABLE_MULTIPLE_TX_QUEUE = y + ENABLE_PTP_SUPPORT = n + ENABLE_PTP_MASTER_MODE = n +-ENABLE_RSS_SUPPORT = n ++ENABLE_RSS_SUPPORT = y + ENABLE_LIB_SUPPORT = n + ENABLE_USE_FIRMWARE_FILE = n + DISABLE_PM_SUPPORT = n diff --git a/r8125/patches/020-5.19-support.patch b/r8125/patches/020-5.19-support.patch new file mode 100644 index 000000000..481c7739e --- /dev/null +++ b/r8125/patches/020-5.19-support.patch @@ -0,0 +1,18 @@ +--- a/src/r8125_n.c ++++ b/src/r8125_n.c +@@ -116,6 +116,15 @@ + #define FIRMWARE_8168FP_3 "rtl_nic/rtl8168fp-3.fw" + #define FIRMWARE_8168FP_4 "rtl_nic/rtl8168fp-4.fw" + ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 0) ++static inline void netif_set_gso_max_size(struct net_device *dev, ++ unsigned int size) ++{ ++ /* dev->gso_max_size is read locklessly from sk_setup_caps() */ ++ WRITE_ONCE(dev->gso_max_size, size); ++} ++#endif ++ + /* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). + The RTL chips use a 64 element hash table based on the Ethernet CRC. */ + static const int multicast_filter_limit = 32; diff --git a/r8125/patches/030-add-LED-configuration-from-OF.patch b/r8125/patches/030-add-LED-configuration-from-OF.patch new file mode 100644 index 000000000..5f6f1d29b --- /dev/null +++ b/r8125/patches/030-add-LED-configuration-from-OF.patch @@ -0,0 +1,43 @@ +--- a/src/r8125_n.c ++++ b/src/r8125_n.c +@@ -43,6 +43,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -10407,6 +10408,23 @@ rtl8125_setup_mqs_reg(struct rtl8125_private *tp) + } + } + ++static int ++rtl8125_led_configuration(struct rtl8125_private *tp) ++{ ++ u32 led_data; ++ int ret; ++ ++ ret = of_property_read_u32(tp->pci_dev->dev.of_node, ++ "realtek,led-data", &led_data); ++ ++ if (ret) ++ return ret; ++ ++ RTL_W16(tp, CustomLED, led_data); ++ ++ return 0; ++} ++ + static void + rtl8125_init_software_variable(struct net_device *dev) + { +@@ -10838,6 +10856,8 @@ rtl8125_init_software_variable(struct net_device *dev) + if (tp->InitRxDescType == RX_DESC_RING_TYPE_3) + tp->rtl8125_rx_config |= EnableRxDescV3; + ++ rtl8125_led_configuration(tp); ++ + tp->NicCustLedValue = RTL_R16(tp, CustomLED); + + tp->wol_opts = rtl8125_get_hw_wol(tp); diff --git a/r8152/Makefile b/r8152/Makefile index 9e199e273..2573b6624 100755 --- a/r8152/Makefile +++ b/r8152/Makefile @@ -7,12 +7,12 @@ include $(TOPDIR)/rules.mk include $(INCLUDE_DIR)/kernel.mk PKG_NAME:=r8152 -PKG_VERSION:=2.15.20211119 +PKG_VERSION:=2.16.1 PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/wget/realtek-r8152-linux/tar.gz/v$(PKG_VERSION)? -PKG_HASH:=b7926db3b4ca71d453ac1cf875d7a8ab409ece108edc6913e8bc1c0c3b99179d +PKG_HASH:=2be6a02f6e29485efd107bb7e777ad3c482d9db0ff7e5e6c5ef034a1557a395b PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/realtek-$(PKG_NAME)-linux-$(PKG_VERSION) @@ -23,13 +23,13 @@ PKG_MAINTAINER:=Tianling Shen include $(INCLUDE_DIR)/package.mk define KernelPackage/usb-net-rtl8152-vendor + VERSION:=$(LINUX_VERSION)+$(PKG_VERSION)-$(BOARD)-$(PKG_RELEASE) TITLE:=Kernel module for USB-to-Ethernet Realtek convertors SUBMENU:=USB Support - VERSION:=$(LINUX_VERSION)+$(PKG_VERSION)-$(BOARD)-$(PKG_RELEASE) DEPENDS:=+kmod-usb-net - CONFLICTS:=kmod-usb-net-rtl8152 - FILES:= $(PKG_BUILD_DIR)/r8152.ko + FILES:=$(PKG_BUILD_DIR)/r8152.ko AUTOLOAD:=$(call AutoProbe,r8152) + CONFLICTS:=kmod-usb-net-rtl8152 endef define KernelPackage/usb-net-rtl8152-vendor/description diff --git a/r8152/patches/010-5.19-support.patch b/r8152/patches/010-5.19-support.patch new file mode 100644 index 000000000..944e5bfcc --- /dev/null +++ b/r8152/patches/010-5.19-support.patch @@ -0,0 +1,19 @@ +--- a/r8152.c ++++ b/r8152.c +@@ -1026,6 +1026,16 @@ + #define RTL_ADVERTISED_1000_FULL BIT(5) + #define RTL_ADVERTISED_2500_FULL BIT(6) + ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 0) ++static inline void netif_set_gso_max_size(struct net_device *dev, ++ unsigned int size) ++{ ++ /* dev->gso_max_size is read locklessly from sk_setup_caps() */ ++ WRITE_ONCE(dev->gso_max_size, size); ++} ++#endif ++ ++ + /* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). + * The RTL chips use a 64 element hash table based on the Ethernet CRC. + */ diff --git a/r8168/Makefile b/r8168/Makefile index fd5977a5b..1258fc904 100644 --- a/r8168/Makefile +++ b/r8168/Makefile @@ -7,19 +7,16 @@ include $(TOPDIR)/rules.mk include $(INCLUDE_DIR)/kernel.mk PKG_NAME:=r8168 -PKG_VERSION:=8.049.02 -PKG_RELEASE:=$(AUTORELEAE) +PKG_VERSION:=8.050.03 +PKG_RELEASE:=$(AUTORELEASE) PKG_SOURCE_PROTO:=git PKG_SOURCE_URL:=https://github.com/BROBIRD/openwrt-r8168.git -PKG_SOURCE_DATE:=2021-10-08 -PKG_SOURCE_VERSION:=2b969c15afe403a685fc7ee069620782241e3ad6 -PKG_MIRROR_HASH:=e4632c10d460f005eff76da8a183d7ff0c8819b0d099872589b7b06a9b8d9952 +PKG_SOURCE_VERSION:=ddfaceacd1b7ed2857fb995642a8ffb1fc37e989 +PKG_MIRROR_HASH:=5428f60dc33e9503c6cfdf690c00077149dce24cbb0591129d905b9f1aad9202 PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) -MAKE_PATH:=src - include $(INCLUDE_DIR)/package.mk define KernelPackage/r8168 @@ -35,20 +32,8 @@ define Package/r8168/description This package contains a driver for Realtek r8168 chipsets. endef -R8168_MAKEOPTS= -C $(PKG_BUILD_DIR)/src \ - PATH="$(TARGET_PATH)" \ - ARCH="$(LINUX_KARCH)" \ - CROSS_COMPILE="$(TARGET_CROSS)" \ - TARGET="$(HAL_TARGET)" \ - TOOLPREFIX="$(KERNEL_CROSS)" \ - TOOLPATH="$(KERNEL_CROSS)" \ - KERNELPATH="$(LINUX_DIR)" \ - KERNELDIR="$(LINUX_DIR)" \ - LDOPTS=" " \ - DOMULTI=1 - define Build/Compile - $(MAKE) $(R8168_MAKEOPTS) modules + +$(KERNEL_MAKE) M=$(PKG_BUILD_DIR)/src modules endef $(eval $(call KernelPackage,r8168)) diff --git a/r8168/patches/001-r8168-add-LED-configuration-from-OF.patch b/r8168/patches/001-r8168-add-LED-configuration-from-OF.patch index 62a352dd8..f49842442 100644 --- a/r8168/patches/001-r8168-add-LED-configuration-from-OF.patch +++ b/r8168/patches/001-r8168-add-LED-configuration-from-OF.patch @@ -1,42 +1,42 @@ ---- a/src/r8168_n.c -+++ b/src/r8168_n.c -@@ -47,6 +47,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -23482,6 +23483,22 @@ rtl8168_set_bios_setting(struct net_devi - } - } - -+static int rtl8168_led_configuration(struct rtl8168_private *tp) -+{ -+ u32 led_data; -+ int ret; -+ -+ ret = of_property_read_u32(tp->pci_dev->dev.of_node, -+ "realtek,led-data", &led_data); -+ -+ if (ret) -+ return ret; -+ -+ RTL_W16(tp, CustomLED, led_data); -+ -+ return 0; -+} -+ - static void - rtl8168_init_software_variable(struct net_device *dev) - { -@@ -24000,6 +24017,8 @@ rtl8168_init_software_variable(struct ne - tp->NotWrMcuPatchCode = TRUE; - } - -+ rtl8168_led_configuration(tp); -+ - tp->NicCustLedValue = RTL_R16(tp, CustomLED); - - rtl8168_get_hw_wol(dev); +--- a/src/r8168_n.c ++++ b/src/r8168_n.c +@@ -47,6 +47,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -24643,6 +24644,22 @@ rtl8168_set_bios_setting(struct net_devi + } + } + ++static int rtl8168_led_configuration(struct rtl8168_private *tp) ++{ ++ u32 led_data; ++ int ret; ++ ++ ret = of_property_read_u32(tp->pci_dev->dev.of_node, ++ "realtek,led-data", &led_data); ++ ++ if (ret) ++ return ret; ++ ++ RTL_W16(tp, CustomLED, led_data); ++ ++ return 0; ++} ++ + static void + rtl8168_init_software_variable(struct net_device *dev) + { +@@ -25206,6 +25223,8 @@ rtl8168_init_software_variable(struct ne + tp->NotWrMcuPatchCode = TRUE; + } + ++ rtl8168_led_configuration(tp); ++ + tp->NicCustLedValue = RTL_R16(tp, CustomLED); + + rtl8168_get_hw_wol(dev); diff --git a/r8168/patches/020-5.18-support.patch b/r8168/patches/020-5.18-support.patch new file mode 100644 index 000000000..499389274 --- /dev/null +++ b/r8168/patches/020-5.18-support.patch @@ -0,0 +1,47 @@ +--- a/src/r8168_n.c ++++ b/src/r8168_n.c +@@ -3715,7 +3715,11 @@ + txd->opts2 = 0; + while (1) { + memset(tmpAddr, pattern++, len - 14); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5,18,0) + pci_dma_sync_single_for_device(tp->pci_dev, ++#else ++ dma_sync_single_for_device(tp_to_dev(tp), ++#endif + le64_to_cpu(mapping), + len, DMA_TO_DEVICE); + txd->opts1 = cpu_to_le32(DescOwn | FirstFrag | LastFrag | len); +@@ -3743,7 +3747,11 @@ + if (rx_len == len) { + dma_sync_single_for_cpu(tp_to_dev(tp), le64_to_cpu(rxd->addr), tp->rx_buf_sz, DMA_FROM_DEVICE); + i = memcmp(skb->data, rx_skb->data, rx_len); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5,18,0) + pci_dma_sync_single_for_device(tp->pci_dev, le64_to_cpu(rxd->addr), tp->rx_buf_sz, DMA_FROM_DEVICE); ++#else ++ dma_sync_single_for_device(tp_to_dev(tp), le64_to_cpu(rxd->addr), tp->rx_buf_sz, DMA_FROM_DEVICE); ++#endif + if (i == 0) { + // dev_printk(KERN_INFO, tp_to_dev(tp), "loopback test finished\n",rx_len,len); + break; +@@ -26464,11 +26472,20 @@ + + if ((sizeof(dma_addr_t) > 4) && + use_dac && ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5,18,0) + !pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) && + !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) { ++#else ++ !dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)) && ++ !dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64))) { ++#endif + dev->features |= NETIF_F_HIGHDMA; + } else { ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5,18,0) + rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); ++#else ++ rc = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); ++#endif + if (rc < 0) { + #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0) + if (netif_msg_probe(tp)) diff --git a/r8168/patches/030-5.19-support.patch b/r8168/patches/030-5.19-support.patch new file mode 100644 index 000000000..d4dca3125 --- /dev/null +++ b/r8168/patches/030-5.19-support.patch @@ -0,0 +1,18 @@ +--- a/src/r8168_n.c ++++ b/src/r8168_n.c +@@ -116,6 +116,15 @@ + #define FIRMWARE_8168FP_3 "rtl_nic/rtl8168fp-3.fw" + #define FIRMWARE_8168FP_4 "rtl_nic/rtl8168fp-4.fw" + ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 0) ++static inline void netif_set_gso_max_size(struct net_device *dev, ++ unsigned int size) ++{ ++ /* dev->gso_max_size is read locklessly from sk_setup_caps() */ ++ WRITE_ONCE(dev->gso_max_size, size); ++} ++#endif ++ + /* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). + The RTL chips use a 64 element hash table based on the Ethernet CRC. */ + static const int multicast_filter_limit = 32; diff --git a/shadowsocks-libev/files/shadowsocks-libev.init b/shadowsocks-libev/files/shadowsocks-libev.init index 9868e9044..c93f03a3e 100755 --- a/shadowsocks-libev/files/shadowsocks-libev.init +++ b/shadowsocks-libev/files/shadowsocks-libev.init @@ -186,7 +186,8 @@ ss_rules() { eval "$(validate_ss_rules_section "$cfg" ss_validate_mklocal)" validate_ss_rules_section "$cfg" || return 1 - [ "$disabled" = 0 ] || return 0 + [ "$disabled" != "1" ] || return 0 + [ "$(uci -q get shadowsocks-libev.${cfgrulesserver}.disabled)" != "1" ] || return 0 if [ "$ss_rules_redir_tcp_$redir_tcp" = "all" ]; then min_ss_redir_ports="65535" max_ss_redir_ports="0" @@ -356,7 +357,7 @@ rules_up() { done config_foreach ss_rules ss_rules [ -z "$(iptables-save | grep :ssr)" ] && logger -t "Shadowsocks" "Rules not applied" - [ -f /etc/init.d/omr-bypass ] && { + [ -f /etc/init.d/omr-bypass ] && [ -z "$(pgrep -f omr-bypass)" ] && { logger -t "Shadowsocks" "Reload omr-bypass rules" /etc/init.d/omr-bypass reload_rules } diff --git a/shadowsocks-v2ray-plugin/Makefile b/shadowsocks-v2ray-plugin/Makefile index f9e700fe1..4231140a5 100755 --- a/shadowsocks-v2ray-plugin/Makefile +++ b/shadowsocks-v2ray-plugin/Makefile @@ -25,7 +25,7 @@ GO_PKG:=github.com/shadowsocks/v2ray-plugin PKG_USE_MIPS16:=0 include $(INCLUDE_DIR)/package.mk -include ../golang/golang-package.mk +include $(TOPDIR)/feeds/openmptcprouter/golang/golang-package.mk define Package/v2ray-plugin SECTION:=net diff --git a/shortcut-fe/.gitignore b/shortcut-fe/.gitignore new file mode 100644 index 000000000..958088547 --- /dev/null +++ b/shortcut-fe/.gitignore @@ -0,0 +1,5 @@ +# Ouptut files + +*.o +*.s + diff --git a/shortcut-fe/src/Kconfig b/shortcut-fe/Kconfig old mode 100755 new mode 100644 similarity index 100% rename from shortcut-fe/src/Kconfig rename to shortcut-fe/Kconfig diff --git a/shortcut-fe/Makefile b/shortcut-fe/Makefile old mode 100755 new mode 100644 index 2baa86cbe..3b1ceaa44 --- a/shortcut-fe/Makefile +++ b/shortcut-fe/Makefile @@ -1,90 +1,23 @@ # -# Copyright (c) 2013-2018, 2020 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. +# Makefile for Shortcut FE. # -include $(TOPDIR)/rules.mk -include $(INCLUDE_DIR)/kernel.mk +obj-m += shortcut-fe.o -PKG_NAME:=shortcut-fe -PKG_RELEASE:=5 - -include $(INCLUDE_DIR)/package.mk - -define KernelPackage/shortcut-fe - SECTION:=kernel - CATEGORY:=Kernel modules - SUBMENU:=Network Support - DEPENDS:=@IPV6 +kmod-nf-conntrack - 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 - PROVIDES:=$(PKG_NAME) - 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 - -HAVE_ECM:=$(CONFIG_PACKAGE_kmod-qca-nss-ecm-premium)$(CONFIG_PACKAGE_kmod-qca-nss-ecm-noload)$(CONFIG_PACKAGE_kmod-qca-nss-ecm-premium-noload)$(CONFIG_PACKAGE_kmod-qca-nss-ecm-standard) - -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 \ - CONFIG_NF_CONNTRACK_EVENTS=y \ - CONFIG_XFRM=y - CONFLICTS:=kmod-shortcut-fe-drv -endef - -define KernelPackage/shortcut-fe-cm/Description -Simple connection manager for the Shortcut forwarding engine. -endef - -define Build/Compile - $(MAKE) $(PKG_JOBS) -C "$(LINUX_DIR)" \ - $(KERNEL_MAKE_FLAGS) \ - $(PKG_MAKE_FLAGS) \ - M="$(PKG_BUILD_DIR)" \ - EXTRA_CFLAGS+="-DSFE_SUPPORT_IPV6" SFE_SUPPORT_IPV6=y \ - $(if $(HAVE_ECM),EXTRA_CFLAGS+="-DCONFIG_SFE_ECM" CONFIG_SFE_ECM=y,) \ - 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 +ifdef SFE_SUPPORT_IPV6 +obj-m += shortcut-fe-ipv6.o endif -$(eval $(call KernelPackage,shortcut-fe)) -$(eval $(call KernelPackage,shortcut-fe-cm)) +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 + diff --git a/shortcut-fe/README b/shortcut-fe/README new file mode 100644 index 000000000..1bf1cc255 --- /dev/null +++ b/shortcut-fe/README @@ -0,0 +1,122 @@ +Shortcut Forwarding Engine +-------------------------- + +Welcome to "Shortcut" :-) + +Here's a quick FAQ: + + +Q) What is Shortcut? + +A) Shortcut is an in-Linux-kernel IP packet forwarding engine. It's designed +to offer very high speed IP packet forwarding based on IP connection tracking. +It's dramatically faster than the standard netfilter-based NAT forwarding path +but is designed to synchronise state back to netfilter/conntrack so that it +doesn't need to deal with all of the complexities of special cases. + + +Q) What versions of IP does it support? + +A) The current version only supports IPv4 but will be extended to support IPv6 in +the future. + + +Q) What transport protocols does it support? + +A) TCP and UDP. It also knows enough about ICMP to spot ICMP error messages +related to TCP and UDP and handle things accordingly. + + +Q) Is there a design spec for this software? + +A) Not at the moment. I'll write one when I get more time. The code is +intended to be a good tutorial though - it's very heavily commented. If you +find yourself reading something and not understanding it then I take that to +mean I've probably not done a sufficently good job of explaining what it's +doing in the comments. Let me know - I will try to fix it :-) + + +Q) Why was it written? + +A) It was written as a demonstration of what can be done to provide high +performance forwarding inside the kernel. There were two initial motivations: + +1) To provide a platform to enable research into how QoS analysis systems can +offload work and avoid huge Linux overheads. + +2) To provide a tool to investigate the behaviour of various processors, SoCs +and software sets so that we can characterize and design new network processor +SoCs. + + +Q) How much faster is it than the Linux kernel forwarding path? + +A) At the time of pushing this to github it's been tested on a QCA AP135. +This has a Scorpion (QCA Scopion, not the QMC one :-)) SoC, QCA9550. The +SoC's processor is a MIPS74K running at 720 MHz and with a DDR2 memory +subsystem that offers a peak of 600 MT/s (16-bit transfers). + +Running IPv4 NAT forwarding of UDP between the board's 2 GMAC ports and +using a SmartBits 200 as a traffic generator Linux is able to forward 70k PPS. +Once the SFE code is invoked this will increase to 350k PPS! + +There's also a slightly hacky mode which causes SFE to bypass the Linux +bridge layer, but this isn't really ready for use because it doesn't have +sufficient MAC address checks or integration of statistics back to the +Ethernet bridge, but that runs at 436k PPS. + + +Q) Are there any diagnostics? + +A) Yes, this is a research tool after all! There's a complex way to do this +that's more general purpose and a simple one - here's the simple one: + + mknod /dev/sfe c 253 0 + +The file /dev/sfe is an XML-ish output and provides details of all the +network connections currently being offloaded. It also reports the numbers +of packets that took various "exception" paths within the code. In addition +it provides a summary of the number of connections, attempts to accelerate +connections, cancel accelerations, etc. It also reports the numbers of +packets that were forwarded and not forwarded by the engine and has some +stats on the effectiveness of the hashing algorithm it uses. + + +Q) How does the code interact with Linux? + +A) There are four minor patches required to make this software run with +Linux. These are currently against a 3.3.8 or 3.4.0 kernel: + +* (net/core/dev.c) adds a hook to allow packets to be extracted out. + +* (net/netfilter/nf_conntrack_proto_tcp.c) exposes a state variable inside + netfilter that's necessary to enable TCP sequence and ACK checking within + the offload path. Note that this specific patch is against the QCA QSDK + patched version of 3.3.8 - there's a slightly braindead "performance" + patch in that kernel, courtesy of the OpenWrt community that makes the + Linux forwarding path slightly faster at the expense of losing + functionality :-( + +* (net/Kconfig) adds the shortcut-fe option. + +* (net/Makefile) adds the shortcut-fe build support. + +Once these are applied and the module is loaded then everything else +is automatic :-) The patches are in this git repo. + + +Q) Are any of the pieces reused from other projects? + +A) Yes! Some of the forwarding concepts are reused from the Ubicom Network +Accelerator that morphed into part of the Akronite NSS. This code has all +been substantially changed though to accomodate Linux's needs. + +There are also some pieces that I borrowed from the QCA "FastNAT" software +written by Xiaoping Fan . Xiaoping's code was the +first actual demonstration within QCA that this in-kernel concept could yield +signficant performance gains. + + +Enjoy! +Dave Hudson + diff --git a/shortcut-fe/fast-classifier/Makefile b/shortcut-fe/fast-classifier/Makefile new file mode 100644 index 000000000..09c1174dd --- /dev/null +++ b/shortcut-fe/fast-classifier/Makefile @@ -0,0 +1,109 @@ +# +# Copyright (c) 2013-2018 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:=fast-classifier +PKG_RELEASE:=6 + +include $(INCLUDE_DIR)/package.mk + +define KernelPackage/fast-classifier/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_EVENTS=y \ + CONFIG_NF_CONNTRACK_CHAIN_EVENTS=y \ + CONFIG_NF_CONNTRACK_MARK=y \ + CONFIG_XFRM=y + CONFLICTS:=kmod-shortcut-fe-drv kmod-shortcut-fe-cm +endef + +define KernelPackage/fast-classifier + $(call KernelPackage/fast-classifier/Default) +endef + +define KernelPackage/fast-classifier-noload + $(call KernelPackage/fast-classifier/Default) +endef + +define KernelPackage/fast-classifier/Default/description +FAST Classifier talks to SFE to make decisions about offloading connections +endef + +define KernelPackage/fast-classifier/description +$(call KernelPackage/fast-classifier/Default/description) +endef + +define KernelPackage/fast-classifier-noload/description +$(call KernelPackage/fast-classifier/Default/description) + +This package does not load fast-classifier 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 + +HAVE_ECM:=$(CONFIG_PACKAGE_kmod-qca-nss-ecm-premium)$(CONFIG_PACKAGE_kmod-qca-nss-ecm-noload)$(CONFIG_PACKAGE_kmod-qca-nss-ecm-premium-noload)$(CONFIG_PACKAGE_kmod-qca-nss-ecm-standard) + +define Build/Compile/kmod + +$(MAKE) $(PKG_JOBS) -C "$(LINUX_DIR)" \ + $(KERNEL_MAKE_FLAGS) \ + $(PKG_MAKE_FLAGS) \ + M="$(PKG_BUILD_DIR)" \ + CONFIG_FAST_CLASSIFIER=m \ + EXTRA_CFLAGS+="-DSFE_SUPPORT_IPV6" \ + $(if $(HAVE_ECM),EXTRA_CFLAGS+="-DCONFIG_SFE_ECM" CONFIG_SFE_ECM=y,) \ + 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,fast-classifier)) +#$(eval $(call KernelPackage,fast-classifier-noload)) +#$(eval $(call BuildPackage,fast-classifier-example)) diff --git a/shortcut-fe/fast-classifier/fast-classifier.c b/shortcut-fe/fast-classifier/fast-classifier.c new file mode 100644 index 000000000..d79404cba --- /dev/null +++ b/shortcut-fe/fast-classifier/fast-classifier.c @@ -0,0 +1,1892 @@ +/* + * fast-classifier.c + * Shortcut forwarding engine connection manager. + * fast-classifier + * + * Copyright (c) 2013-2018 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "fast-classifier.h" + +typedef enum fast_classifier_exception { + FAST_CL_EXCEPTION_PACKET_BROADCAST, + FAST_CL_EXCEPTION_PACKET_MULTICAST, + FAST_CL_EXCEPTION_NO_IIF, + FAST_CL_EXCEPTION_NO_CT, + FAST_CL_EXCEPTION_CT_NO_TRACK, + FAST_CL_EXCEPTION_CT_NO_CONFIRM, + FAST_CL_EXCEPTION_CT_IS_ALG, + FAST_CL_EXCEPTION_IS_IPV4_MCAST, + FAST_CL_EXCEPTION_IS_IPV6_MCAST, + FAST_CL_EXCEPTION_TCP_NOT_ASSURED, + FAST_CL_EXCEPTION_TCP_NOT_ESTABLISHED, + FAST_CL_EXCEPTION_UNKNOW_PROTOCOL, + FAST_CL_EXCEPTION_NO_SRC_DEV, + FAST_CL_EXCEPTION_NO_SRC_XLATE_DEV, + FAST_CL_EXCEPTION_NO_DEST_DEV, + FAST_CL_EXCEPTION_NO_DEST_XLATE_DEV, + FAST_CL_EXCEPTION_NO_BRIDGE, + FAST_CL_EXCEPTION_LOCAL_OUT, + FAST_CL_EXCEPTION_WAIT_FOR_ACCELERATION, + FAST_CL_EXCEPTION_UPDATE_PROTOCOL_FAIL, + FAST_CL_EXCEPTION_CT_DESTROY_MISS, + FAST_CL_EXCEPTION_MAX +} fast_classifier_exception_t; + +static char *fast_classifier_exception_events_string[FAST_CL_EXCEPTION_MAX] = { + "PACKET_BROADCAST", + "PACKET_MULTICAST", + "NO_IIF", + "NO_CT", + "CT_NO_TRACK", + "CT_NO_CONFIRM", + "CT_IS_ALG", + "IS_IPV4_MCAST", + "IS_IPV6_MCAST", + "TCP_NOT_ASSURED", + "TCP_NOT_ESTABLISHED", + "UNKNOW_PROTOCOL", + "NO_SRC_DEV", + "NO_SRC_XLATE_DEV", + "NO_DEST_DEV", + "NO_DEST_XLATE_DEV", + "NO_BRIDGE", + "LOCAL_OUT", + "WAIT_FOR_ACCELERATION", + "UPDATE_PROTOCOL_FAIL", + "CT_DESTROY_MISS", +}; + +/* + * Per-module structure. + */ +struct fast_classifier { + spinlock_t lock; /* Lock for SMP correctness */ + + /* + * Control state. + */ + struct kobject *sys_fast_classifier; /* sysfs linkage */ + + /* + * Callback notifiers. + */ + struct notifier_block dev_notifier; /* Device notifier */ + struct notifier_block inet_notifier; /* IPv4 notifier */ + struct notifier_block inet6_notifier; /* IPv6 notifier */ + u32 exceptions[FAST_CL_EXCEPTION_MAX]; +}; + +static struct fast_classifier __sc; + +static struct nla_policy fast_classifier_genl_policy[FAST_CLASSIFIER_A_MAX + 1] = { + [FAST_CLASSIFIER_A_TUPLE] = { + .type = NLA_UNSPEC, + .len = sizeof(struct fast_classifier_tuple) + }, +}; + +static struct genl_multicast_group fast_classifier_genl_mcgrp[] = { + { + .name = FAST_CLASSIFIER_GENL_MCGRP, + }, +}; + +static struct genl_family fast_classifier_gnl_family = { + .id = GENL_ID_GENERATE, + .hdrsize = FAST_CLASSIFIER_GENL_HDRSIZE, + .name = FAST_CLASSIFIER_GENL_NAME, + .version = FAST_CLASSIFIER_GENL_VERSION, + .maxattr = FAST_CLASSIFIER_A_MAX, +}; + +static int fast_classifier_offload_genl_msg(struct sk_buff *skb, struct genl_info *info); +static int fast_classifier_nl_genl_msg_DUMP(struct sk_buff *skb, struct netlink_callback *cb); + +static struct genl_ops fast_classifier_gnl_ops[] = { + { + .cmd = FAST_CLASSIFIER_C_OFFLOAD, + .flags = 0, + .policy = fast_classifier_genl_policy, + .doit = fast_classifier_offload_genl_msg, + .dumpit = NULL, + }, + { + .cmd = FAST_CLASSIFIER_C_OFFLOADED, + .flags = 0, + .policy = fast_classifier_genl_policy, + .doit = NULL, + .dumpit = fast_classifier_nl_genl_msg_DUMP, + }, + { + .cmd = FAST_CLASSIFIER_C_DONE, + .flags = 0, + .policy = fast_classifier_genl_policy, + .doit = NULL, + .dumpit = fast_classifier_nl_genl_msg_DUMP, + }, +}; + +static atomic_t offload_msgs = ATOMIC_INIT(0); +static atomic_t offload_no_match_msgs = ATOMIC_INIT(0); +static atomic_t offloaded_msgs = ATOMIC_INIT(0); +static atomic_t done_msgs = ATOMIC_INIT(0); + +static atomic_t offloaded_fail_msgs = ATOMIC_INIT(0); +static atomic_t done_fail_msgs = ATOMIC_INIT(0); + +/* + * Accelerate incoming packets destined for bridge device + * If a incoming packet is ultimatly destined for + * a bridge device we will first see the packet coming + * from the phyiscal device, we can skip straight to + * processing the packet like it came from the bridge + * for some more performance gains + * + * This only works when the hook is above the bridge. We + * only implement ingress for now, because for egress we + * want to have the bridge devices qdiscs be used. + */ +static bool skip_to_bridge_ingress; + +/* + * fast_classifier_incr_exceptions() + * increase an exception counter. + */ +static inline void fast_classifier_incr_exceptions(fast_classifier_exception_t except) +{ + struct fast_classifier *sc = &__sc; + + spin_lock_bh(&sc->lock); + sc->exceptions[except]++; + spin_unlock_bh(&sc->lock); +} + +/* + * fast_classifier_recv() + * Handle packet receives. + * + * Returns 1 if the packet is forwarded or 0 if it isn't. + */ +int fast_classifier_recv(struct sk_buff *skb) +{ + struct net_device *dev; + struct net_device *master_dev = NULL; + int ret = 0; + + /* + * We know that for the vast majority of packets we need the transport + * layer header so we may as well start to fetch it now! + */ + prefetch(skb->data + 32); + barrier(); + + dev = skb->dev; + + /* + * Process packet like it arrived on the bridge device + */ + if (skip_to_bridge_ingress && + (dev->priv_flags & IFF_BRIDGE_PORT)) { + master_dev = sfe_dev_get_master(dev); + if (!master_dev) { + DEBUG_WARN("master dev is NULL %s\n", dev->name); + goto rx_exit; + } + dev = master_dev; + } + + /* + * We're only interested in IPv4 and IPv6 packets. + */ + if (likely(htons(ETH_P_IP) == skb->protocol)) { + struct in_device *in_dev; + + /* + * Does our input device support IP processing? + */ + in_dev = (struct in_device *)dev->ip_ptr; + if (unlikely(!in_dev)) { + DEBUG_TRACE("no IP processing for device: %s\n", dev->name); + goto rx_exit; + } + + /* + * Does it have an IP address? If it doesn't then we can't do anything + * interesting here! + */ + if (unlikely(!in_dev->ifa_list)) { + DEBUG_TRACE("no IP address for device: %s\n", dev->name); + goto rx_exit; + } + + ret = sfe_ipv4_recv(dev, skb); + + } else if (likely(htons(ETH_P_IPV6) == skb->protocol)) { + struct inet6_dev *in_dev; + + /* + * Does our input device support IPv6 processing? + */ + in_dev = (struct inet6_dev *)dev->ip6_ptr; + if (unlikely(!in_dev)) { + DEBUG_TRACE("no IPv6 processing for device: %s\n", dev->name); + goto rx_exit; + } + + /* + * Does it have an IPv6 address? If it doesn't then we can't do anything + * interesting here! + */ + if (unlikely(list_empty(&in_dev->addr_list))) { + DEBUG_TRACE("no IPv6 address for device: %s\n", dev->name); + goto rx_exit; + } + + ret = sfe_ipv6_recv(dev, skb); + + } else { + DEBUG_TRACE("not IP packet\n"); + } + +rx_exit: + if (master_dev) { + dev_put(master_dev); + } + + return ret; +} + +/* + * fast_classifier_find_dev_and_mac_addr() + * Find the device and MAC address for a given IPv4 address. + * + * Returns true if we find the device and MAC address, otherwise false. + * + * We look up the rtable entry for the address and, from its neighbour + * structure, obtain the hardware address. This means this function also + * works if the neighbours are routers too. + */ +static bool fast_classifier_find_dev_and_mac_addr(sfe_ip_addr_t *addr, struct net_device **dev, u8 *mac_addr, bool is_v4) +{ + struct neighbour *neigh; + struct rtable *rt; + struct rt6_info *rt6; + struct dst_entry *dst; + struct net_device *mac_dev; + + /* + * Look up the rtable entry for the IP address then get the hardware + * address from its neighbour structure. This means this works when the + * neighbours are routers too. + */ + if (likely(is_v4)) { + rt = ip_route_output(&init_net, addr->ip, 0, 0, 0); + if (unlikely(IS_ERR(rt))) { + goto ret_fail; + } + + dst = (struct dst_entry *)rt; + } else { + rt6 = rt6_lookup(&init_net, (struct in6_addr *)addr->ip6, 0, 0, 0); + if (!rt6) { + goto ret_fail; + } + + dst = (struct dst_entry *)rt6; + } + + rcu_read_lock(); + neigh = sfe_dst_get_neighbour(dst, addr); + if (unlikely(!neigh)) { + rcu_read_unlock(); + dst_release(dst); + goto ret_fail; + } + + if (unlikely(!(neigh->nud_state & NUD_VALID))) { + rcu_read_unlock(); + neigh_release(neigh); + dst_release(dst); + goto ret_fail; + } + + mac_dev = neigh->dev; + if (!mac_dev) { + rcu_read_unlock(); + neigh_release(neigh); + dst_release(dst); + goto ret_fail; + } + + memcpy(mac_addr, neigh->ha, (size_t)mac_dev->addr_len); + + dev_hold(mac_dev); + *dev = mac_dev; + rcu_read_unlock(); + neigh_release(neigh); + dst_release(dst); + + return true; + +ret_fail: + if (is_v4) { + DEBUG_TRACE("failed to find MAC address for IP: %pI4\n", addr); + + } else { + DEBUG_TRACE("failed to find MAC address for IP: %pI6\n", addr); + } + + return false; +} + +static DEFINE_SPINLOCK(sfe_connections_lock); + +struct sfe_connection { + struct hlist_node hl; + struct sfe_connection_create *sic; + struct nf_conn *ct; + int hits; + int offload_permit; + int offloaded; + bool is_v4; + unsigned char smac[ETH_ALEN]; + unsigned char dmac[ETH_ALEN]; +}; + +static int sfe_connections_size; + +#define FC_CONN_HASH_ORDER 13 +static DEFINE_HASHTABLE(fc_conn_ht, FC_CONN_HASH_ORDER); + +static u32 fc_conn_hash(sfe_ip_addr_t *saddr, sfe_ip_addr_t *daddr, + unsigned short sport, unsigned short dport, bool is_v4) +{ + u32 idx, cnt = ((is_v4 ? sizeof(saddr->ip) : sizeof(saddr->ip6))/sizeof(u32)); + u32 hash = 0; + + for (idx = 0; idx < cnt; idx++) { + hash ^= ((u32 *)saddr)[idx] ^ ((u32 *)daddr)[idx]; + } + + return hash ^ (sport | (dport << 16)); +} + +/* + * fast_classifier_update_protocol() + * Update sfe_ipv4_create struct with new protocol information before we offload + */ +static int fast_classifier_update_protocol(struct sfe_connection_create *p_sic, struct nf_conn *ct) +{ + switch (p_sic->protocol) { + case IPPROTO_TCP: + p_sic->src_td_window_scale = ct->proto.tcp.seen[0].td_scale; + p_sic->src_td_max_window = ct->proto.tcp.seen[0].td_maxwin; + p_sic->src_td_end = ct->proto.tcp.seen[0].td_end; + p_sic->src_td_max_end = ct->proto.tcp.seen[0].td_maxend; + p_sic->dest_td_window_scale = ct->proto.tcp.seen[1].td_scale; + p_sic->dest_td_max_window = ct->proto.tcp.seen[1].td_maxwin; + p_sic->dest_td_end = ct->proto.tcp.seen[1].td_end; + p_sic->dest_td_max_end = ct->proto.tcp.seen[1].td_maxend; + + if (nf_ct_tcp_no_window_check + || (ct->proto.tcp.seen[0].flags & IP_CT_TCP_FLAG_BE_LIBERAL) + || (ct->proto.tcp.seen[1].flags & IP_CT_TCP_FLAG_BE_LIBERAL)) { + p_sic->flags |= SFE_CREATE_FLAG_NO_SEQ_CHECK; + } + + /* + * If the connection is shutting down do not manage it. + * state can not be SYN_SENT, SYN_RECV because connection is assured + * Not managed states: FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE. + */ + spin_lock(&ct->lock); + if (ct->proto.tcp.state != TCP_CONNTRACK_ESTABLISHED) { + spin_unlock(&ct->lock); + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_TCP_NOT_ESTABLISHED); + DEBUG_TRACE("connection in termination state: %#x, s: %pI4:%u, d: %pI4:%u\n", + ct->proto.tcp.state, &p_sic->src_ip, ntohs(p_sic->src_port), + &p_sic->dest_ip, ntohs(p_sic->dest_port)); + return 0; + } + spin_unlock(&ct->lock); + break; + + case IPPROTO_UDP: + break; + + default: + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_UNKNOW_PROTOCOL); + DEBUG_TRACE("unhandled protocol %d\n", p_sic->protocol); + return 0; + } + + return 1; +} + +/* fast_classifier_send_genl_msg() + * Function to send a generic netlink message + */ +static void fast_classifier_send_genl_msg(int msg, struct fast_classifier_tuple *fc_msg) +{ + struct sk_buff *skb; + int rc; + int buf_len; + int total_len; + void *msg_head; + + /* + * Calculate our packet payload size. + * Start with our family header. + */ + buf_len = fast_classifier_gnl_family.hdrsize; + + /* + * Add the nla_total_size of each attribute we're going to nla_put(). + */ + buf_len += nla_total_size(sizeof(*fc_msg)); + + /* + * Lastly we need to add space for the NL message header since + * genlmsg_new only accounts for the GENL header and not the + * outer NL header. To do this, we use a NL helper function which + * calculates the total size of a netlink message given a payload size. + * Note this value does not include the GENL header, but that's + * added automatically by genlmsg_new. + */ + total_len = nlmsg_total_size(buf_len); + skb = genlmsg_new(total_len, GFP_ATOMIC); + if (!skb) + return; + + msg_head = genlmsg_put(skb, 0, 0, &fast_classifier_gnl_family, 0, msg); + if (!msg_head) { + nlmsg_free(skb); + return; + } + + rc = nla_put(skb, FAST_CLASSIFIER_A_TUPLE, sizeof(struct fast_classifier_tuple), fc_msg); + if (rc != 0) { + genlmsg_cancel(skb, msg_head); + nlmsg_free(skb); + return; + } + +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 19 , 0)) + rc = genlmsg_end(skb, msg_head); + if (rc < 0) { + genlmsg_cancel(skb, msg_head); + nlmsg_free(skb); + return; + } +#else + genlmsg_end(skb, msg_head); + +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)) + rc = genlmsg_multicast(&fast_classifier_gnl_family, skb, 0, 0, GFP_ATOMIC); +#else + rc = genlmsg_multicast(skb, 0, fast_classifier_genl_mcgrp[0].id, GFP_ATOMIC); +#endif + switch (msg) { + case FAST_CLASSIFIER_C_OFFLOADED: + if (rc == 0) { + atomic_inc(&offloaded_msgs); + } else { + atomic_inc(&offloaded_fail_msgs); + } + break; + case FAST_CLASSIFIER_C_DONE: + if (rc == 0) { + atomic_inc(&done_msgs); + } else { + atomic_inc(&done_fail_msgs); + } + break; + default: + DEBUG_ERROR("fast-classifer: Unknown message type sent!\n"); + break; + } + + DEBUG_TRACE("Notify NL message %d ", msg); + if (fc_msg->ethertype == AF_INET) { + DEBUG_TRACE("sip=%pI4 dip=%pI4 ", &fc_msg->src_saddr, &fc_msg->dst_saddr); + } else { + DEBUG_TRACE("sip=%pI6 dip=%pI6 ", &fc_msg->src_saddr, &fc_msg->dst_saddr); + } + DEBUG_TRACE("protocol=%d sport=%d dport=%d smac=%pM dmac=%pM\n", + fc_msg->proto, fc_msg->sport, fc_msg->dport, fc_msg->smac, fc_msg->dmac); +} + +/* + * fast_classifier_find_conn() + * find a connection object in the hash table + * @pre the sfe_connection_lock must be held before calling this function + */ +static struct sfe_connection * +fast_classifier_find_conn(sfe_ip_addr_t *saddr, sfe_ip_addr_t *daddr, + unsigned short sport, unsigned short dport, + unsigned char proto, bool is_v4) +{ + struct sfe_connection_create *p_sic; + struct sfe_connection *conn; + u32 key; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)) + struct hlist_node *node; +#endif + + key = fc_conn_hash(saddr, daddr, sport, dport, is_v4); + + sfe_hash_for_each_possible(fc_conn_ht, conn, node, hl, key) { + if (conn->is_v4 != is_v4) { + continue; + } + + p_sic = conn->sic; + + if (p_sic->protocol == proto && + p_sic->src_port == sport && + p_sic->dest_port == dport && + sfe_addr_equal(&p_sic->src_ip, saddr, is_v4) && + sfe_addr_equal(&p_sic->dest_ip, daddr, is_v4)) { + return conn; + } + } + + DEBUG_TRACE("connection not found\n"); + return NULL; +} + +/* + * fast_classifier_sb_find_conn() + * find a connection object in the hash table according to information of packet + * if not found, reverse the tuple and try again. + * @pre the sfe_connection_lock must be held before calling this function + */ +static struct sfe_connection * +fast_classifier_sb_find_conn(sfe_ip_addr_t *saddr, sfe_ip_addr_t *daddr, + unsigned short sport, unsigned short dport, + unsigned char proto, bool is_v4) +{ + struct sfe_connection_create *p_sic; + struct sfe_connection *conn; + u32 key; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)) + struct hlist_node *node; +#endif + + key = fc_conn_hash(saddr, daddr, sport, dport, is_v4); + + sfe_hash_for_each_possible(fc_conn_ht, conn, node, hl, key) { + if (conn->is_v4 != is_v4) { + continue; + } + + p_sic = conn->sic; + + if (p_sic->protocol == proto && + p_sic->src_port == sport && + p_sic->dest_port_xlate == dport && + sfe_addr_equal(&p_sic->src_ip, saddr, is_v4) && + sfe_addr_equal(&p_sic->dest_ip_xlate, daddr, is_v4)) { + return conn; + } + } + + /* + * Reverse the tuple and try again + */ + key = fc_conn_hash(daddr, saddr, dport, sport, is_v4); + + sfe_hash_for_each_possible(fc_conn_ht, conn, node, hl, key) { + if (conn->is_v4 != is_v4) { + continue; + } + + p_sic = conn->sic; + + if (p_sic->protocol == proto && + p_sic->src_port == dport && + p_sic->dest_port_xlate == sport && + sfe_addr_equal(&p_sic->src_ip, daddr, is_v4) && + sfe_addr_equal(&p_sic->dest_ip_xlate, saddr, is_v4)) { + return conn; + } + } + + DEBUG_TRACE("connection not found\n"); + return NULL; +} + +/* + * fast_classifier_add_conn() + * add a connection object in the hash table if no duplicate + * @conn connection to add + * @return conn if successful, NULL if duplicate + */ +static struct sfe_connection * +fast_classifier_add_conn(struct sfe_connection *conn) +{ + struct sfe_connection_create *sic = conn->sic; + u32 key; + + spin_lock_bh(&sfe_connections_lock); + if (fast_classifier_find_conn(&sic->src_ip, &sic->dest_ip, sic->src_port, + sic->dest_port, sic->protocol, conn->is_v4)) { + spin_unlock_bh(&sfe_connections_lock); + return NULL; + } + + key = fc_conn_hash(&sic->src_ip, &sic->dest_ip, + sic->src_port, sic->dest_port, conn->is_v4); + + hash_add(fc_conn_ht, &conn->hl, key); + sfe_connections_size++; + spin_unlock_bh(&sfe_connections_lock); + + DEBUG_TRACE(" -> adding item to sfe_connections, new size: %d\n", sfe_connections_size); + + if (conn->is_v4) { + DEBUG_TRACE("new offloadable: key: %u proto: %d src_ip: %pI4 dst_ip: %pI4, src_port: %d, dst_port: %d\n", + key, sic->protocol, &(sic->src_ip), &(sic->dest_ip), sic->src_port, sic->dest_port); + } else { + DEBUG_TRACE("new offloadable: key: %u proto: %d src_ip: %pI6 dst_ip: %pI6, src_port: %d, dst_port: %d\n", + key, sic->protocol, &(sic->src_ip), &(sic->dest_ip), sic->src_port, sic->dest_port); + } + + return conn; +} + +/* + * fast_classifier_offload_genl_msg() + * Called from user space to offload a connection + */ +static int +fast_classifier_offload_genl_msg(struct sk_buff *skb, struct genl_info *info) +{ + struct nlattr *na; + struct fast_classifier_tuple *fc_msg; + struct sfe_connection *conn; + + na = info->attrs[FAST_CLASSIFIER_A_TUPLE]; + fc_msg = nla_data(na); + + if (fc_msg->ethertype == AF_INET) { + DEBUG_TRACE("want to offload: %d-%d, %pI4, %pI4, %d, %d SMAC=%pM DMAC=%pM\n", + fc_msg->ethertype, + fc_msg->proto, + &fc_msg->src_saddr, + &fc_msg->dst_saddr, + fc_msg->sport, + fc_msg->dport, + fc_msg->smac, + fc_msg->dmac); + } else { + DEBUG_TRACE("want to offload: %d-%d, %pI6, %pI6, %d, %d SMAC=%pM DMAC=%pM\n", + fc_msg->ethertype, + fc_msg->proto, + &fc_msg->src_saddr, + &fc_msg->dst_saddr, + fc_msg->sport, + fc_msg->dport, + fc_msg->smac, + fc_msg->dmac); + } + + spin_lock_bh(&sfe_connections_lock); + conn = fast_classifier_sb_find_conn((sfe_ip_addr_t *)&fc_msg->src_saddr, + (sfe_ip_addr_t *)&fc_msg->dst_saddr, + fc_msg->sport, + fc_msg->dport, + fc_msg->proto, + (fc_msg->ethertype == AF_INET)); + if (!conn) { + spin_unlock_bh(&sfe_connections_lock); + DEBUG_TRACE("REQUEST OFFLOAD NO MATCH\n"); + atomic_inc(&offload_no_match_msgs); + return 0; + } + + conn->offload_permit = 1; + spin_unlock_bh(&sfe_connections_lock); + atomic_inc(&offload_msgs); + + DEBUG_TRACE("INFO: calling sfe rule creation!\n"); + return 0; +} + +/* + * fast_classifier_nl_genl_msg_DUMP() + * ignore fast_classifier_messages OFFLOADED and DONE + */ +static int fast_classifier_nl_genl_msg_DUMP(struct sk_buff *skb, + struct netlink_callback *cb) +{ + return 0; +} + +/* auto offload connection once we have this many packets*/ +static int offload_at_pkts = 128; + +/* + * fast_classifier_post_routing() + * Called for packets about to leave the box - either locally generated or forwarded from another interface + */ +static unsigned int fast_classifier_post_routing(struct sk_buff *skb, bool is_v4) +{ + int ret; + struct sfe_connection_create sic; + struct sfe_connection_create *p_sic; + struct net_device *in; + struct nf_conn *ct; + enum ip_conntrack_info ctinfo; + struct net_device *dev; + struct net_device *src_dev; + struct net_device *dest_dev; + struct net_device *src_dev_tmp; + struct net_device *dest_dev_tmp; + struct net_device *src_br_dev = NULL; + struct net_device *dest_br_dev = NULL; + struct nf_conntrack_tuple orig_tuple; + struct nf_conntrack_tuple reply_tuple; + struct sfe_connection *conn; + + /* + * Don't process broadcast or multicast packets. + */ + if (unlikely(skb->pkt_type == PACKET_BROADCAST)) { + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_PACKET_BROADCAST); + DEBUG_TRACE("broadcast, ignoring\n"); + return NF_ACCEPT; + } + if (unlikely(skb->pkt_type == PACKET_MULTICAST)) { + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_PACKET_MULTICAST); + DEBUG_TRACE("multicast, ignoring\n"); + return NF_ACCEPT; + } + + /* + * Don't process packets that are not being forwarded. + */ + in = dev_get_by_index(&init_net, skb->skb_iif); + if (!in) { + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_NO_IIF); + DEBUG_TRACE("packet not forwarding\n"); + return NF_ACCEPT; + } + + dev_put(in); + + /* + * Don't process packets that aren't being tracked by conntrack. + */ + ct = nf_ct_get(skb, &ctinfo); + if (unlikely(!ct)) { + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_NO_CT); + DEBUG_TRACE("no conntrack connection, ignoring\n"); + return NF_ACCEPT; + } + + /* + * Don't process untracked connections. + */ + if (unlikely(nf_ct_is_untracked(ct))) { + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_CT_NO_TRACK); + DEBUG_TRACE("untracked connection\n"); + return NF_ACCEPT; + } + + /* + * Unconfirmed connection may be dropped by Linux at the final step, + * So we don't process unconfirmed connections. + */ + if (!nf_ct_is_confirmed(ct)) { + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_CT_NO_CONFIRM); + DEBUG_TRACE("unconfirmed connection\n"); + return NF_ACCEPT; + } + + /* + * Don't process connections that require support from a 'helper' (typically a NAT ALG). + */ + if (unlikely(nfct_help(ct))) { + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_CT_IS_ALG); + DEBUG_TRACE("connection has helper\n"); + return NF_ACCEPT; + } + + memset(&sic, 0, sizeof(sic)); + + /* + * Look up the details of our connection in conntrack. + * + * Note that the data we get from conntrack is for the "ORIGINAL" direction + * but our packet may actually be in the "REPLY" direction. + */ + orig_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; + reply_tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple; + sic.protocol = (s32)orig_tuple.dst.protonum; + + sic.flags = 0; + + /* + * Get addressing information, non-NAT first + */ + if (likely(is_v4)) { + u32 dscp; + + sic.src_ip.ip = (__be32)orig_tuple.src.u3.ip; + sic.dest_ip.ip = (__be32)orig_tuple.dst.u3.ip; + + if (ipv4_is_multicast(sic.src_ip.ip) || ipv4_is_multicast(sic.dest_ip.ip)) { + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_IS_IPV4_MCAST); + DEBUG_TRACE("multicast address\n"); + return NF_ACCEPT; + } + + /* + * NAT'ed addresses - note these are as seen from the 'reply' direction + * When NAT does not apply to this connection these will be identical to the above. + */ + sic.src_ip_xlate.ip = (__be32)reply_tuple.dst.u3.ip; + sic.dest_ip_xlate.ip = (__be32)reply_tuple.src.u3.ip; + + dscp = ipv4_get_dsfield(ip_hdr(skb)) >> XT_DSCP_SHIFT; + if (dscp) { + sic.dest_dscp = dscp; + sic.src_dscp = sic.dest_dscp; + sic.flags |= SFE_CREATE_FLAG_REMARK_DSCP; + } + } else { + u32 dscp; + + sic.src_ip.ip6[0] = *((struct sfe_ipv6_addr *)&orig_tuple.src.u3.in6); + sic.dest_ip.ip6[0] = *((struct sfe_ipv6_addr *)&orig_tuple.dst.u3.in6); + + if (ipv6_addr_is_multicast((struct in6_addr *)sic.src_ip.ip6) || + ipv6_addr_is_multicast((struct in6_addr *)sic.dest_ip.ip6)) { + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_IS_IPV6_MCAST); + DEBUG_TRACE("multicast address\n"); + return NF_ACCEPT; + } + + /* + * NAT'ed addresses - note these are as seen from the 'reply' direction + * When NAT does not apply to this connection these will be identical to the above. + */ + sic.src_ip_xlate.ip6[0] = *((struct sfe_ipv6_addr *)&reply_tuple.dst.u3.in6); + sic.dest_ip_xlate.ip6[0] = *((struct sfe_ipv6_addr *)&reply_tuple.src.u3.in6); + + dscp = ipv6_get_dsfield(ipv6_hdr(skb)) >> XT_DSCP_SHIFT; + if (dscp) { + sic.dest_dscp = dscp; + sic.src_dscp = sic.dest_dscp; + sic.flags |= SFE_CREATE_FLAG_REMARK_DSCP; + } + } + + switch (sic.protocol) { + case IPPROTO_TCP: + sic.src_port = orig_tuple.src.u.tcp.port; + sic.dest_port = orig_tuple.dst.u.tcp.port; + sic.src_port_xlate = reply_tuple.dst.u.tcp.port; + sic.dest_port_xlate = reply_tuple.src.u.tcp.port; + + /* + * Don't try to manage a non-established connection. + */ + if (!test_bit(IPS_ASSURED_BIT, &ct->status)) { + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_TCP_NOT_ASSURED); + DEBUG_TRACE("non-established connection\n"); + return NF_ACCEPT; + } + + break; + + case IPPROTO_UDP: + sic.src_port = orig_tuple.src.u.udp.port; + sic.dest_port = orig_tuple.dst.u.udp.port; + sic.src_port_xlate = reply_tuple.dst.u.udp.port; + sic.dest_port_xlate = reply_tuple.src.u.udp.port; + break; + + default: + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_UNKNOW_PROTOCOL); + DEBUG_TRACE("unhandled protocol %d\n", sic.protocol); + return NF_ACCEPT; + } + +#ifdef CONFIG_XFRM + sic.original_accel = 1; + sic.reply_accel = 1; +#endif + + /* + * Get QoS information + */ + if (skb->priority) { + sic.dest_priority = skb->priority; + sic.src_priority = sic.dest_priority; + sic.flags |= SFE_CREATE_FLAG_REMARK_PRIORITY; + } + + if (is_v4) { + DEBUG_TRACE("POST_ROUTE: checking new connection: %d src_ip: %pI4 dst_ip: %pI4, src_port: %d, dst_port: %d\n", + sic.protocol, &sic.src_ip, &sic.dest_ip, sic.src_port, sic.dest_port); + } else { + DEBUG_TRACE("POST_ROUTE: checking new connection: %d src_ip: %pI6 dst_ip: %pI6, src_port: %d, dst_port: %d\n", + sic.protocol, &sic.src_ip, &sic.dest_ip, sic.src_port, sic.dest_port); + } + + /* + * If we already have this connection in our list, skip it + * XXX: this may need to be optimized + */ + spin_lock_bh(&sfe_connections_lock); + + conn = fast_classifier_find_conn(&sic.src_ip, &sic.dest_ip, sic.src_port, sic.dest_port, sic.protocol, is_v4); + if (conn) { + conn->hits++; + + if (!conn->offloaded) { + if (conn->offload_permit || conn->hits >= offload_at_pkts) { + DEBUG_TRACE("OFFLOADING CONNECTION, TOO MANY HITS\n"); + + if (fast_classifier_update_protocol(conn->sic, conn->ct) == 0) { + spin_unlock_bh(&sfe_connections_lock); + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_UPDATE_PROTOCOL_FAIL); + DEBUG_TRACE("UNKNOWN PROTOCOL OR CONNECTION CLOSING, SKIPPING\n"); + return NF_ACCEPT; + } + + DEBUG_TRACE("INFO: calling sfe rule creation!\n"); + spin_unlock_bh(&sfe_connections_lock); + + ret = is_v4 ? sfe_ipv4_create_rule(conn->sic) : sfe_ipv6_create_rule(conn->sic); + if ((ret == 0) || (ret == -EADDRINUSE)) { + struct fast_classifier_tuple fc_msg; + + if (is_v4) { + fc_msg.ethertype = AF_INET; + fc_msg.src_saddr.in = *((struct in_addr *)&sic.src_ip); + fc_msg.dst_saddr.in = *((struct in_addr *)&sic.dest_ip_xlate); + } else { + fc_msg.ethertype = AF_INET6; + fc_msg.src_saddr.in6 = *((struct in6_addr *)&sic.src_ip); + fc_msg.dst_saddr.in6 = *((struct in6_addr *)&sic.dest_ip_xlate); + } + + fc_msg.proto = sic.protocol; + fc_msg.sport = sic.src_port; + fc_msg.dport = sic.dest_port_xlate; + memcpy(fc_msg.smac, conn->smac, ETH_ALEN); + memcpy(fc_msg.dmac, conn->dmac, ETH_ALEN); + fast_classifier_send_genl_msg(FAST_CLASSIFIER_C_OFFLOADED, &fc_msg); + conn->offloaded = 1; + } + + return NF_ACCEPT; + } + } + + spin_unlock_bh(&sfe_connections_lock); + if (conn->offloaded) { + is_v4 ? sfe_ipv4_update_rule(conn->sic) : sfe_ipv6_update_rule(conn->sic); + } + + DEBUG_TRACE("FOUND, SKIPPING\n"); + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_WAIT_FOR_ACCELERATION); + return NF_ACCEPT; + } + + spin_unlock_bh(&sfe_connections_lock); + + /* + * Get the net device and MAC addresses that correspond to the various source and + * destination host addresses. + */ + if (!fast_classifier_find_dev_and_mac_addr(&sic.src_ip, &src_dev_tmp, sic.src_mac, is_v4)) { + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_NO_SRC_DEV); + return NF_ACCEPT; + } + src_dev = src_dev_tmp; + + if (!fast_classifier_find_dev_and_mac_addr(&sic.src_ip_xlate, &dev, sic.src_mac_xlate, is_v4)) { + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_NO_SRC_XLATE_DEV); + goto done1; + } + dev_put(dev); + + if (!fast_classifier_find_dev_and_mac_addr(&sic.dest_ip, &dev, sic.dest_mac, is_v4)) { + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_NO_DEST_DEV); + goto done1; + } + dev_put(dev); + + if (!fast_classifier_find_dev_and_mac_addr(&sic.dest_ip_xlate, &dest_dev_tmp, sic.dest_mac_xlate, is_v4)) { + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_NO_DEST_XLATE_DEV); + goto done1; + } + dest_dev = dest_dev_tmp; + + /* + * Our devices may actually be part of a bridge interface. If that's + * the case then find the bridge interface instead. + */ + if (src_dev->priv_flags & IFF_BRIDGE_PORT) { + src_br_dev = sfe_dev_get_master(src_dev); + if (!src_br_dev) { + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_NO_BRIDGE); + DEBUG_TRACE("no bridge found for: %s\n", src_dev->name); + goto done2; + } + src_dev = src_br_dev; + } + + if (dest_dev->priv_flags & IFF_BRIDGE_PORT) { + dest_br_dev = sfe_dev_get_master(dest_dev); + if (!dest_br_dev) { + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_NO_BRIDGE); + DEBUG_TRACE("no bridge found for: %s\n", dest_dev->name); + goto done3; + } + dest_dev = dest_br_dev; + } + + sic.src_dev = src_dev; + sic.dest_dev = dest_dev; + + sic.src_mtu = src_dev->mtu; + sic.dest_mtu = dest_dev->mtu; + + if (skb->mark) { + DEBUG_TRACE("SKB MARK NON ZERO %x\n", skb->mark); + } + sic.mark = skb->mark; + + conn = kmalloc(sizeof(*conn), GFP_ATOMIC); + if (!conn) { + printk(KERN_CRIT "ERROR: no memory for sfe\n"); + goto done4; + } + conn->hits = 0; + conn->offload_permit = 0; + conn->offloaded = 0; + conn->is_v4 = is_v4; + DEBUG_TRACE("Source MAC=%pM\n", sic.src_mac); + memcpy(conn->smac, sic.src_mac, ETH_ALEN); + memcpy(conn->dmac, sic.dest_mac_xlate, ETH_ALEN); + + p_sic = kmalloc(sizeof(*p_sic), GFP_ATOMIC); + if (!p_sic) { + printk(KERN_CRIT "ERROR: no memory for sfe\n"); + kfree(conn); + goto done4; + } + + memcpy(p_sic, &sic, sizeof(sic)); + conn->sic = p_sic; + conn->ct = ct; + + if (!fast_classifier_add_conn(conn)) { + kfree(conn->sic); + kfree(conn); + } + + /* + * If we had bridge ports then release them too. + */ +done4: + if (dest_br_dev) { + dev_put(dest_br_dev); + } +done3: + if (src_br_dev) { + dev_put(src_br_dev); + } +done2: + dev_put(dest_dev_tmp); +done1: + dev_put(src_dev_tmp); + + return NF_ACCEPT; +} + +/* + * fast_classifier_ipv4_post_routing_hook() + * Called for packets about to leave the box - either locally generated or forwarded from another interface + */ +fast_classifier_ipv4_post_routing_hook(hooknum, ops, skb, in_unused, out, okfn) +{ + return fast_classifier_post_routing(skb, true); +} + +/* + * fast_classifier_ipv6_post_routing_hook() + * Called for packets about to leave the box - either locally generated or forwarded from another interface + */ +fast_classifier_ipv6_post_routing_hook(hooknum, ops, skb, in_unused, out, okfn) +{ + return fast_classifier_post_routing(skb, false); +} + +/* + * fast_classifier_update_mark() + * updates the mark for a fast-classifier connection + */ +static void fast_classifier_update_mark(struct sfe_connection_mark *mark, bool is_v4) +{ + struct sfe_connection *conn; + + spin_lock_bh(&sfe_connections_lock); + + conn = fast_classifier_find_conn(&mark->src_ip, &mark->dest_ip, + mark->src_port, mark->dest_port, + mark->protocol, is_v4); + if (conn) { + conn->sic->mark = mark->mark; + } + + spin_unlock_bh(&sfe_connections_lock); +} + +#ifdef CONFIG_NF_CONNTRACK_EVENTS +/* + * fast_classifier_conntrack_event() + * Callback event invoked when a conntrack connection's state changes. + */ +#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS +static int fast_classifier_conntrack_event(struct notifier_block *this, + unsigned long events, void *ptr) +#else +static int fast_classifier_conntrack_event(unsigned int events, struct nf_ct_event *item) +#endif +{ +#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS + struct nf_ct_event *item = ptr; +#endif + struct sfe_connection_destroy sid; + struct nf_conn *ct = item->ct; + struct nf_conntrack_tuple orig_tuple; + struct sfe_connection *conn; + struct fast_classifier_tuple fc_msg; + int offloaded = 0; + bool is_v4; + + /* + * If we don't have a conntrack entry then we're done. + */ + if (unlikely(!ct)) { + DEBUG_WARN("no ct in conntrack event callback\n"); + return NOTIFY_DONE; + } + + /* + * If this is an untracked connection then we can't have any state either. + */ + if (unlikely(nf_ct_is_untracked(ct))) { + DEBUG_TRACE("ignoring untracked conn\n"); + return NOTIFY_DONE; + } + + orig_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; + sid.protocol = (s32)orig_tuple.dst.protonum; + + /* + * Extract information from the conntrack connection. We're only interested + * in nominal connection information (i.e. we're ignoring any NAT information). + */ + if (likely(nf_ct_l3num(ct) == AF_INET)) { + sid.src_ip.ip = (__be32)orig_tuple.src.u3.ip; + sid.dest_ip.ip = (__be32)orig_tuple.dst.u3.ip; + is_v4 = true; + } else if (likely(nf_ct_l3num(ct) == AF_INET6)) { + sid.src_ip.ip6[0] = *((struct sfe_ipv6_addr *)&orig_tuple.src.u3.in6); + sid.dest_ip.ip6[0] = *((struct sfe_ipv6_addr *)&orig_tuple.dst.u3.in6); + is_v4 = false; + } else { + DEBUG_TRACE("ignoring non-IPv4 and non-IPv6 connection\n"); + return NOTIFY_DONE; + } + + switch (sid.protocol) { + case IPPROTO_TCP: + sid.src_port = orig_tuple.src.u.tcp.port; + sid.dest_port = orig_tuple.dst.u.tcp.port; + break; + + case IPPROTO_UDP: + sid.src_port = orig_tuple.src.u.udp.port; + sid.dest_port = orig_tuple.dst.u.udp.port; + break; + + default: + DEBUG_TRACE("unhandled protocol: %d\n", sid.protocol); + return NOTIFY_DONE; + } + + /* + * Check for an updated mark + */ + if ((events & (1 << IPCT_MARK)) && (ct->mark != 0)) { + struct sfe_connection_mark mark; + + mark.protocol = sid.protocol; + mark.src_ip = sid.src_ip; + mark.dest_ip = sid.dest_ip; + mark.src_port = sid.src_port; + mark.dest_port = sid.dest_port; + mark.mark = ct->mark; + + is_v4 ? sfe_ipv4_mark_rule(&mark) : sfe_ipv6_mark_rule(&mark); + fast_classifier_update_mark(&mark, is_v4); + } + + /* + * We're only interested in destroy events at this point + */ + if (unlikely(!(events & (1 << IPCT_DESTROY)))) { + DEBUG_TRACE("ignoring non-destroy event\n"); + return NOTIFY_DONE; + } + + if (is_v4) { + DEBUG_TRACE("Try to clean up: proto: %d src_ip: %pI4 dst_ip: %pI4, src_port: %d, dst_port: %d\n", + sid.protocol, &sid.src_ip, &sid.dest_ip, sid.src_port, sid.dest_port); + } else { + DEBUG_TRACE("Try to clean up: proto: %d src_ip: %pI6 dst_ip: %pI6, src_port: %d, dst_port: %d\n", + sid.protocol, &sid.src_ip, &sid.dest_ip, sid.src_port, sid.dest_port); + } + + spin_lock_bh(&sfe_connections_lock); + + conn = fast_classifier_find_conn(&sid.src_ip, &sid.dest_ip, sid.src_port, sid.dest_port, sid.protocol, is_v4); + if (conn && conn->offloaded) { + if (is_v4) { + fc_msg.ethertype = AF_INET; + fc_msg.src_saddr.in = *((struct in_addr *)&conn->sic->src_ip); + fc_msg.dst_saddr.in = *((struct in_addr *)&conn->sic->dest_ip_xlate); + } else { + fc_msg.ethertype = AF_INET6; + fc_msg.src_saddr.in6 = *((struct in6_addr *)&conn->sic->src_ip); + fc_msg.dst_saddr.in6 = *((struct in6_addr *)&conn->sic->dest_ip_xlate); + } + + fc_msg.proto = conn->sic->protocol; + fc_msg.sport = conn->sic->src_port; + fc_msg.dport = conn->sic->dest_port_xlate; + memcpy(fc_msg.smac, conn->smac, ETH_ALEN); + memcpy(fc_msg.dmac, conn->dmac, ETH_ALEN); + offloaded = 1; + } + + if (conn) { + DEBUG_TRACE("Free connection\n"); + + hash_del(&conn->hl); + sfe_connections_size--; + kfree(conn->sic); + kfree(conn); + } else { + fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_CT_DESTROY_MISS); + } + + spin_unlock_bh(&sfe_connections_lock); + + is_v4 ? sfe_ipv4_destroy_rule(&sid) : sfe_ipv6_destroy_rule(&sid); + + if (offloaded) { + fast_classifier_send_genl_msg(FAST_CLASSIFIER_C_DONE, &fc_msg); + } + + return NOTIFY_DONE; +} + +/* + * Netfilter conntrack event system to monitor connection tracking changes + */ +#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS +static struct notifier_block fast_classifier_conntrack_notifier = { + .notifier_call = fast_classifier_conntrack_event, +}; +#else +static struct nf_ct_event_notifier fast_classifier_conntrack_notifier = { + .fcn = fast_classifier_conntrack_event, +}; +#endif +#endif + +/* + * Structure to establish a hook into the post routing netfilter point - this + * will pick up local outbound and packets going from one interface to another. + * + * Note: see include/linux/netfilter_ipv4.h for info related to priority levels. + * We want to examine packets after NAT translation and any ALG processing. + */ +static struct nf_hook_ops fast_classifier_ops_post_routing[] __read_mostly = { + SFE_IPV4_NF_POST_ROUTING_HOOK(__fast_classifier_ipv4_post_routing_hook), + SFE_IPV6_NF_POST_ROUTING_HOOK(__fast_classifier_ipv6_post_routing_hook), +}; + +/* + * fast_classifier_sync_rule() + * Synchronize a connection's state. + */ +static void fast_classifier_sync_rule(struct sfe_connection_sync *sis) +{ + struct nf_conntrack_tuple_hash *h; + struct nf_conntrack_tuple tuple; + struct nf_conn *ct; + SFE_NF_CONN_ACCT(acct); + + /* + * Create a tuple so as to be able to look up a connection + */ + memset(&tuple, 0, sizeof(tuple)); + tuple.src.u.all = (__be16)sis->src_port; + tuple.dst.dir = IP_CT_DIR_ORIGINAL; + tuple.dst.protonum = (u8)sis->protocol; + tuple.dst.u.all = (__be16)sis->dest_port; + + if (sis->is_v6) { + tuple.src.u3.in6 = *((struct in6_addr *)sis->src_ip.ip6); + tuple.dst.u3.in6 = *((struct in6_addr *)sis->dest_ip.ip6); + tuple.src.l3num = AF_INET6; + + DEBUG_TRACE("update connection - p: %d, s: %pI6:%u, d: %pI6:%u\n", + (int)tuple.dst.protonum, + &tuple.src.u3.in6, (unsigned int)ntohs(tuple.src.u.all), + &tuple.dst.u3.in6, (unsigned int)ntohs(tuple.dst.u.all)); + } else { + tuple.src.u3.ip = sis->src_ip.ip; + tuple.dst.u3.ip = sis->dest_ip.ip; + tuple.src.l3num = AF_INET; + + DEBUG_TRACE("update connection - p: %d, s: %pI4:%u, d: %pI4:%u\n", + (int)tuple.dst.protonum, + &tuple.src.u3.ip, (unsigned int)ntohs(tuple.src.u.all), + &tuple.dst.u3.ip, (unsigned int)ntohs(tuple.dst.u.all)); + } + + /* + * Update packet count for ingress on bridge device + */ + if (skip_to_bridge_ingress) { + struct rtnl_link_stats64 nlstats; + nlstats.tx_packets = 0; + nlstats.tx_bytes = 0; + + if (sis->src_dev && IFF_EBRIDGE && + (sis->src_new_packet_count || sis->src_new_byte_count)) { + nlstats.rx_packets = sis->src_new_packet_count; + nlstats.rx_bytes = sis->src_new_byte_count; + spin_lock_bh(&sfe_connections_lock); + br_dev_update_stats(sis->src_dev, &nlstats); + spin_unlock_bh(&sfe_connections_lock); + } + if (sis->dest_dev && IFF_EBRIDGE && + (sis->dest_new_packet_count || sis->dest_new_byte_count)) { + nlstats.rx_packets = sis->dest_new_packet_count; + nlstats.rx_bytes = sis->dest_new_byte_count; + spin_lock_bh(&sfe_connections_lock); + br_dev_update_stats(sis->dest_dev, &nlstats); + spin_unlock_bh(&sfe_connections_lock); + } + } + + /* + * Look up conntrack connection + */ + h = nf_conntrack_find_get(&init_net, SFE_NF_CT_DEFAULT_ZONE, &tuple); + if (unlikely(!h)) { + DEBUG_TRACE("no connection found\n"); + return; + } + + ct = nf_ct_tuplehash_to_ctrack(h); + NF_CT_ASSERT(ct->timeout.data == (unsigned long)ct); + + /* + * Only update if this is not a fixed timeout + */ + if (!test_bit(IPS_FIXED_TIMEOUT_BIT, &ct->status)) { + spin_lock_bh(&ct->lock); + ct->timeout.expires += sis->delta_jiffies; + spin_unlock_bh(&ct->lock); + } + + acct = nf_conn_acct_find(ct); + if (acct) { + spin_lock_bh(&ct->lock); + atomic64_add(sis->src_new_packet_count, &SFE_ACCT_COUNTER(acct)[IP_CT_DIR_ORIGINAL].packets); + atomic64_add(sis->src_new_byte_count, &SFE_ACCT_COUNTER(acct)[IP_CT_DIR_ORIGINAL].bytes); + atomic64_add(sis->dest_new_packet_count, &SFE_ACCT_COUNTER(acct)[IP_CT_DIR_REPLY].packets); + atomic64_add(sis->dest_new_byte_count, &SFE_ACCT_COUNTER(acct)[IP_CT_DIR_REPLY].bytes); + spin_unlock_bh(&ct->lock); + } + + switch (sis->protocol) { + case IPPROTO_TCP: + spin_lock_bh(&ct->lock); + if (ct->proto.tcp.seen[0].td_maxwin < sis->src_td_max_window) { + ct->proto.tcp.seen[0].td_maxwin = sis->src_td_max_window; + } + if ((s32)(ct->proto.tcp.seen[0].td_end - sis->src_td_end) < 0) { + ct->proto.tcp.seen[0].td_end = sis->src_td_end; + } + if ((s32)(ct->proto.tcp.seen[0].td_maxend - sis->src_td_max_end) < 0) { + ct->proto.tcp.seen[0].td_maxend = sis->src_td_max_end; + } + if (ct->proto.tcp.seen[1].td_maxwin < sis->dest_td_max_window) { + ct->proto.tcp.seen[1].td_maxwin = sis->dest_td_max_window; + } + if ((s32)(ct->proto.tcp.seen[1].td_end - sis->dest_td_end) < 0) { + ct->proto.tcp.seen[1].td_end = sis->dest_td_end; + } + if ((s32)(ct->proto.tcp.seen[1].td_maxend - sis->dest_td_max_end) < 0) { + ct->proto.tcp.seen[1].td_maxend = sis->dest_td_max_end; + } + spin_unlock_bh(&ct->lock); + break; + } + + /* + * Release connection + */ + nf_ct_put(ct); +} + +/* + * fast_classifier_device_event() + */ +static int fast_classifier_device_event(struct notifier_block *this, unsigned long event, void *ptr) +{ + struct net_device *dev = SFE_DEV_EVENT_PTR(ptr); + + if (dev && (event == NETDEV_DOWN)) { + sfe_ipv4_destroy_all_rules_for_dev(dev); + sfe_ipv6_destroy_all_rules_for_dev(dev); + } + + return NOTIFY_DONE; +} + +/* + * fast_classifier_inet_event() + */ +static int fast_classifier_inet_event(struct notifier_block *this, unsigned long event, void *ptr) +{ + struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev; + + if (dev && (event == NETDEV_DOWN)) { + sfe_ipv4_destroy_all_rules_for_dev(dev); + } + + return NOTIFY_DONE; +} + +/* + * fast_classifier_inet6_event() + */ +static int fast_classifier_inet6_event(struct notifier_block *this, unsigned long event, void *ptr) +{ + struct net_device *dev = ((struct inet6_ifaddr *)ptr)->idev->dev; + + if (dev && (event == NETDEV_DOWN)) { + sfe_ipv6_destroy_all_rules_for_dev(dev); + } + + return NOTIFY_DONE; +} + +/* + * fast_classifier_get_offload_at_pkts() + */ +static ssize_t fast_classifier_get_offload_at_pkts(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", offload_at_pkts); +} + +/* + * fast_classifier_set_offload_at_pkts() + */ +static ssize_t fast_classifier_set_offload_at_pkts(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + long new; + int ret; + + ret = kstrtol(buf, 0, &new); + if (ret == -EINVAL || ((int)new != new)) + return -EINVAL; + + offload_at_pkts = new; + + return size; +} + +/* + * fast_classifier_get_debug_info() + */ +static ssize_t fast_classifier_get_debug_info(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + size_t len = 0; + struct sfe_connection *conn; + u32 i; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)) + struct hlist_node *node; +#endif + + spin_lock_bh(&sfe_connections_lock); + len += scnprintf(buf, PAGE_SIZE - len, "size=%d offload=%d offload_no_match=%d" + " offloaded=%d done=%d offloaded_fail=%d done_fail=%d\n", + sfe_connections_size, + atomic_read(&offload_msgs), + atomic_read(&offload_no_match_msgs), + atomic_read(&offloaded_msgs), + atomic_read(&done_msgs), + atomic_read(&offloaded_fail_msgs), + atomic_read(&done_fail_msgs)); + sfe_hash_for_each(fc_conn_ht, i, node, conn, hl) { + len += scnprintf(buf + len, PAGE_SIZE - len, + (conn->is_v4 ? "o=%d, p=%d [%pM]:%pI4:%u %pI4:%u:[%pM] m=%08x h=%d\n" : "o=%d, p=%d [%pM]:%pI6:%u %pI6:%u:[%pM] m=%08x h=%d\n"), + conn->offloaded, + conn->sic->protocol, + conn->sic->src_mac, + &conn->sic->src_ip, + conn->sic->src_port, + &conn->sic->dest_ip, + conn->sic->dest_port, + conn->sic->dest_mac_xlate, + conn->sic->mark, + conn->hits); + } + spin_unlock_bh(&sfe_connections_lock); + + return len; +} + +/* + * fast_classifier_get_skip_bridge_ingress() + */ +static ssize_t fast_classifier_get_skip_bridge_ingress(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", skip_to_bridge_ingress); +} + +/* + * fast_classifier_set_skip_bridge_ingress() + */ +static ssize_t fast_classifier_set_skip_bridge_ingress(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + long new; + int ret; + + ret = kstrtol(buf, 0, &new); + if (ret == -EINVAL || ((int)new != new)) + return -EINVAL; + + skip_to_bridge_ingress = new ? 1 : 0; + + return size; +} + +/* + * fast_classifier_get_exceptions + * dump exception counters + */ +static ssize_t fast_classifier_get_exceptions(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int idx, len; + struct fast_classifier *sc = &__sc; + + spin_lock_bh(&sc->lock); + for (len = 0, idx = 0; idx < FAST_CL_EXCEPTION_MAX; idx++) { + if (sc->exceptions[idx]) { + len += snprintf(buf + len, (ssize_t)(PAGE_SIZE - len), "%s = %d\n", fast_classifier_exception_events_string[idx], sc->exceptions[idx]); + } + } + spin_unlock_bh(&sc->lock); + + return len; +} + +/* + * sysfs attributes. + */ +static const struct device_attribute fast_classifier_offload_at_pkts_attr = + __ATTR(offload_at_pkts, S_IWUSR | S_IRUGO, fast_classifier_get_offload_at_pkts, fast_classifier_set_offload_at_pkts); +static const struct device_attribute fast_classifier_debug_info_attr = + __ATTR(debug_info, S_IRUGO, fast_classifier_get_debug_info, NULL); +static const struct device_attribute fast_classifier_skip_bridge_ingress = + __ATTR(skip_to_bridge_ingress, S_IWUSR | S_IRUGO, fast_classifier_get_skip_bridge_ingress, fast_classifier_set_skip_bridge_ingress); +static const struct device_attribute fast_classifier_exceptions_attr = + __ATTR(exceptions, S_IRUGO, fast_classifier_get_exceptions, NULL); + +/* + * fast_classifier_init() + */ +static int __init fast_classifier_init(void) +{ + struct fast_classifier *sc = &__sc; + int result = -1; + + printk(KERN_ALERT "fast-classifier: starting up\n"); + DEBUG_INFO("SFE CM init\n"); + + hash_init(fc_conn_ht); + + /* + * Create sys/fast_classifier + */ + sc->sys_fast_classifier = kobject_create_and_add("fast_classifier", NULL); + if (!sc->sys_fast_classifier) { + DEBUG_ERROR("failed to register fast_classifier\n"); + goto exit1; + } + + result = sysfs_create_file(sc->sys_fast_classifier, &fast_classifier_offload_at_pkts_attr.attr); + if (result) { + DEBUG_ERROR("failed to register offload at pkgs: %d\n", result); + goto exit2; + } + + result = sysfs_create_file(sc->sys_fast_classifier, &fast_classifier_debug_info_attr.attr); + if (result) { + DEBUG_ERROR("failed to register debug dev: %d\n", result); + sysfs_remove_file(sc->sys_fast_classifier, &fast_classifier_offload_at_pkts_attr.attr); + goto exit2; + } + + result = sysfs_create_file(sc->sys_fast_classifier, &fast_classifier_skip_bridge_ingress.attr); + if (result) { + DEBUG_ERROR("failed to register skip bridge on ingress: %d\n", result); + sysfs_remove_file(sc->sys_fast_classifier, &fast_classifier_offload_at_pkts_attr.attr); + sysfs_remove_file(sc->sys_fast_classifier, &fast_classifier_debug_info_attr.attr); + goto exit2; + } + + result = sysfs_create_file(sc->sys_fast_classifier, &fast_classifier_exceptions_attr.attr); + if (result) { + DEBUG_ERROR("failed to register exceptions file: %d\n", result); + sysfs_remove_file(sc->sys_fast_classifier, &fast_classifier_offload_at_pkts_attr.attr); + sysfs_remove_file(sc->sys_fast_classifier, &fast_classifier_debug_info_attr.attr); + sysfs_remove_file(sc->sys_fast_classifier, &fast_classifier_skip_bridge_ingress.attr); + goto exit2; + } + + sc->dev_notifier.notifier_call = fast_classifier_device_event; + sc->dev_notifier.priority = 1; + register_netdevice_notifier(&sc->dev_notifier); + + sc->inet_notifier.notifier_call = fast_classifier_inet_event; + sc->inet_notifier.priority = 1; + register_inetaddr_notifier(&sc->inet_notifier); + + sc->inet6_notifier.notifier_call = fast_classifier_inet6_event; + sc->inet6_notifier.priority = 1; + register_inet6addr_notifier(&sc->inet6_notifier); + + /* + * Register our netfilter hooks. + */ + result = nf_register_hooks(fast_classifier_ops_post_routing, ARRAY_SIZE(fast_classifier_ops_post_routing)); + if (result < 0) { + DEBUG_ERROR("can't register nf post routing hook: %d\n", result); + goto exit3; + } + +#ifdef CONFIG_NF_CONNTRACK_EVENTS + /* + * Register a notifier hook to get fast notifications of expired connections. + */ + result = nf_conntrack_register_notifier(&init_net, &fast_classifier_conntrack_notifier); + if (result < 0) { + DEBUG_ERROR("can't register nf notifier hook: %d\n", result); + goto exit4; + } +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)) + result = genl_register_family_with_ops_groups(&fast_classifier_gnl_family, + fast_classifier_gnl_ops, + fast_classifier_genl_mcgrp); + if (result) { + DEBUG_ERROR("failed to register genl ops: %d\n", result); + goto exit5; + } +#else + result = genl_register_family(&fast_classifier_gnl_family); + if (result) { + printk(KERN_CRIT "unable to register genl family\n"); + goto exit5; + } + + result = genl_register_ops(&fast_classifier_gnl_family, fast_classifier_gnl_ops); + if (result) { + printk(KERN_CRIT "unable to register ops\n"); + goto exit6; + } + + result = genl_register_mc_group(&fast_classifier_gnl_family, + fast_classifier_genl_mcgrp); + if (result) { + printk(KERN_CRIT "unable to register multicast group\n"); + goto exit6; + } +#endif + + printk(KERN_ALERT "fast-classifier: registered\n"); + + spin_lock_init(&sc->lock); + + /* + * Hook the receive path in the network stack. + */ + BUG_ON(athrs_fast_nat_recv); + RCU_INIT_POINTER(athrs_fast_nat_recv, fast_classifier_recv); + + /* + * Hook the shortcut sync callback. + */ + sfe_ipv4_register_sync_rule_callback(fast_classifier_sync_rule); + sfe_ipv6_register_sync_rule_callback(fast_classifier_sync_rule); + return 0; + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)) +exit6: + genl_unregister_family(&fast_classifier_gnl_family); +#endif + +exit5: +#ifdef CONFIG_NF_CONNTRACK_EVENTS + nf_conntrack_unregister_notifier(&init_net, &fast_classifier_conntrack_notifier); + +exit4: +#endif + nf_unregister_hooks(fast_classifier_ops_post_routing, ARRAY_SIZE(fast_classifier_ops_post_routing)); + +exit3: + unregister_inetaddr_notifier(&sc->inet_notifier); + unregister_inet6addr_notifier(&sc->inet6_notifier); + unregister_netdevice_notifier(&sc->dev_notifier); + sysfs_remove_file(sc->sys_fast_classifier, &fast_classifier_offload_at_pkts_attr.attr); + sysfs_remove_file(sc->sys_fast_classifier, &fast_classifier_debug_info_attr.attr); + sysfs_remove_file(sc->sys_fast_classifier, &fast_classifier_skip_bridge_ingress.attr); + sysfs_remove_file(sc->sys_fast_classifier, &fast_classifier_exceptions_attr.attr); + +exit2: + kobject_put(sc->sys_fast_classifier); + +exit1: + return result; +} + +/* + * fast_classifier_exit() + */ +static void __exit fast_classifier_exit(void) +{ + struct fast_classifier *sc = &__sc; + int result = -1; + + DEBUG_INFO("SFE CM exit\n"); + printk(KERN_ALERT "fast-classifier: shutting down\n"); + + /* + * Unregister our sync callback. + */ + sfe_ipv4_register_sync_rule_callback(NULL); + sfe_ipv6_register_sync_rule_callback(NULL); + + /* + * Unregister our receive callback. + */ + RCU_INIT_POINTER(athrs_fast_nat_recv, NULL); + + /* + * Wait for all callbacks to complete. + */ + rcu_barrier(); + + /* + * Destroy all connections. + */ + sfe_ipv4_destroy_all_rules_for_dev(NULL); + sfe_ipv6_destroy_all_rules_for_dev(NULL); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)) + result = genl_unregister_ops(&fast_classifier_gnl_family, fast_classifier_gnl_ops); + if (result != 0) { + printk(KERN_CRIT "Unable to unreigster genl_ops\n"); + } +#endif + + result = genl_unregister_family(&fast_classifier_gnl_family); + if (result != 0) { + printk(KERN_CRIT "Unable to unreigster genl_family\n"); + } + +#ifdef CONFIG_NF_CONNTRACK_EVENTS + nf_conntrack_unregister_notifier(&init_net, &fast_classifier_conntrack_notifier); + +#endif + nf_unregister_hooks(fast_classifier_ops_post_routing, ARRAY_SIZE(fast_classifier_ops_post_routing)); + + unregister_inet6addr_notifier(&sc->inet6_notifier); + unregister_inetaddr_notifier(&sc->inet_notifier); + unregister_netdevice_notifier(&sc->dev_notifier); + + kobject_put(sc->sys_fast_classifier); +} + +module_init(fast_classifier_init) +module_exit(fast_classifier_exit) + +MODULE_DESCRIPTION("Shortcut Forwarding Engine - Connection Manager"); +MODULE_LICENSE("Dual BSD/GPL"); + diff --git a/shortcut-fe/fast-classifier/fast-classifier.h b/shortcut-fe/fast-classifier/fast-classifier.h new file mode 100644 index 000000000..6b7a18cf6 --- /dev/null +++ b/shortcut-fe/fast-classifier/fast-classifier.h @@ -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 + +#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]; +}; diff --git a/shortcut-fe/fast-classifier/nl_classifier_test.c b/shortcut-fe/fast-classifier/nl_classifier_test.c new file mode 100644 index 000000000..639417964 --- /dev/null +++ b/shortcut-fe/fast-classifier/nl_classifier_test.c @@ -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 +#include +#include +#include +#include +#include + +#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 \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; +} diff --git a/fast-classifier/src/Makefile b/shortcut-fe/fast-classifier/src/Makefile old mode 100755 new mode 100644 similarity index 100% rename from fast-classifier/src/Makefile rename to shortcut-fe/fast-classifier/src/Makefile diff --git a/fast-classifier/src/fast-classifier.c b/shortcut-fe/fast-classifier/src/fast-classifier.c old mode 100755 new mode 100644 similarity index 99% rename from fast-classifier/src/fast-classifier.c rename to shortcut-fe/fast-classifier/src/fast-classifier.c index 746a0d6f9..944dfae38 --- a/fast-classifier/src/fast-classifier.c +++ b/shortcut-fe/fast-classifier/src/fast-classifier.c @@ -451,7 +451,7 @@ static u32 fc_conn_hash(sfe_ip_addr_t *saddr, sfe_ip_addr_t *daddr, */ static int fast_classifier_update_protocol(struct sfe_connection_create *p_sic, struct nf_conn *ct) { - #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0) + #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0) struct net *net=NULL ; struct nf_tcp_net *tn=NULL; #endif @@ -465,7 +465,7 @@ static int fast_classifier_update_protocol(struct sfe_connection_create *p_sic, p_sic->dest_td_max_window = ct->proto.tcp.seen[1].td_maxwin; p_sic->dest_td_end = ct->proto.tcp.seen[1].td_end; p_sic->dest_td_max_end = ct->proto.tcp.seen[1].td_maxend; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0) net = nf_ct_net(ct); tn = nf_tcp_pernet(net); if ((tn&&tn->tcp_no_window_check) diff --git a/shortcut-fe/fast-classifier/src/fast-classifier.h b/shortcut-fe/fast-classifier/src/fast-classifier.h new file mode 100644 index 000000000..6b7a18cf6 --- /dev/null +++ b/shortcut-fe/fast-classifier/src/fast-classifier.h @@ -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 + +#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]; +}; diff --git a/shortcut-fe/fast-classifier/src/nl_classifier_test.c b/shortcut-fe/fast-classifier/src/nl_classifier_test.c new file mode 100644 index 000000000..639417964 --- /dev/null +++ b/shortcut-fe/fast-classifier/src/nl_classifier_test.c @@ -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 +#include +#include +#include +#include +#include + +#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 \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; +} diff --git a/shortcut-fe/fast-classifier/src/userspace_example.c b/shortcut-fe/fast-classifier/src/userspace_example.c new file mode 100644 index 000000000..4f4113d99 --- /dev/null +++ b/shortcut-fe/fast-classifier/src/userspace_example.c @@ -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 +#include +#include +#include +#include + +#include + +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; +} diff --git a/shortcut-fe/fast-classifier/userspace_example.c b/shortcut-fe/fast-classifier/userspace_example.c new file mode 100644 index 000000000..4f4113d99 --- /dev/null +++ b/shortcut-fe/fast-classifier/userspace_example.c @@ -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 +#include +#include +#include +#include + +#include + +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; +} diff --git a/shortcut-fe/patches/Kconfig.patch b/shortcut-fe/patches/Kconfig.patch new file mode 100644 index 000000000..7df0abe83 --- /dev/null +++ b/shortcut-fe/patches/Kconfig.patch @@ -0,0 +1,12 @@ +diff --git a/net/Kconfig b/net/Kconfig +index 976cb63..4a7b0af 100644 +--- a/net/Kconfig ++++ b/net/Kconfig +@@ -236,6 +236,7 @@ source "net/dcb/Kconfig" + source "net/dns_resolver/Kconfig" + source "net/batman-adv/Kconfig" + source "net/openvswitch/Kconfig" ++source "net/shortcut-fe/Kconfig" + + config RPS + boolean "RPS" diff --git a/shortcut-fe/patches/Makefile.patch b/shortcut-fe/patches/Makefile.patch new file mode 100644 index 000000000..1ccc2b0ec --- /dev/null +++ b/shortcut-fe/patches/Makefile.patch @@ -0,0 +1,10 @@ +diff --git a/net/Makefile b/net/Makefile +index 6865dab..a8f0091 100644 +--- a/net/Makefile ++++ b/net/Makefile +@@ -71,3 +71,5 @@ obj-$(CONFIG_BATMAN_ADV) += batman-adv/ + obj-$(CONFIG_NFC) += nfc/ + obj-$(CONFIG_OPENVSWITCH) += openvswitch/ + obj-$(CONFIG_NET_ACTIVITY_STATS) += activity_stats.o ++obj-$(CONFIG_SHORTCUT_FE) += shortcut-fe/ ++ diff --git a/shortcut-fe/patches/dev.c.patch b/shortcut-fe/patches/dev.c.patch new file mode 100644 index 000000000..55fc03a74 --- /dev/null +++ b/shortcut-fe/patches/dev.c.patch @@ -0,0 +1,43 @@ +diff --git a/net/core/dev.c b/net/core/dev.c +index d23742f..1f0415f 100644 +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -3168,6 +3168,9 @@ void netdev_rx_handler_unregister(struct net_device *dev) + } + EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister); + ++int (*athrs_fast_nat_recv)(struct sk_buff *skb) __rcu __read_mostly; ++EXPORT_SYMBOL_GPL(athrs_fast_nat_recv); ++ + static int __netif_receive_skb(struct sk_buff *skb) + { + struct packet_type *ptype, *pt_prev; +@@ -3177,6 +3180,7 @@ static int __netif_receive_skb(struct sk_buff *skb) + bool deliver_exact = false; + int ret = NET_RX_DROP; + __be16 type; ++ int (*fast_recv)(struct sk_buff *skb); + + net_timestamp_check(!netdev_tstamp_prequeue, skb); + +@@ -3194,10 +3198,18 @@ static int __netif_receive_skb(struct sk_buff *skb) + skb_reset_transport_header(skb); + skb_reset_mac_len(skb); + +- pt_prev = NULL; +- + rcu_read_lock(); + ++ fast_recv = rcu_dereference(athrs_fast_nat_recv); ++ if (fast_recv) { ++ if (fast_recv(skb)) { ++ rcu_read_unlock(); ++ return NET_RX_SUCCESS; ++ } ++ } ++ ++ pt_prev = NULL; ++ + another_round: + + __this_cpu_inc(softnet_data.processed); diff --git a/shortcut-fe/patches/nf_conntrack_proto_tcp.c.patch b/shortcut-fe/patches/nf_conntrack_proto_tcp.c.patch new file mode 100644 index 000000000..2cd2313a2 --- /dev/null +++ b/shortcut-fe/patches/nf_conntrack_proto_tcp.c.patch @@ -0,0 +1,25 @@ +--- /home/dhudson/mips-orig/nf_conntrack_proto_tcp.c 2013-05-07 21:32:57.153896922 +0100 ++++ nf_conntrack_proto_tcp.c 2013-06-13 16:37:40.137102438 +0100 +@@ -27,18 +27,20 @@ + #include + #include + #include + #include + + /* Do not check the TCP window for incoming packets */ +-static int nf_ct_tcp_no_window_check __read_mostly = 1; ++int nf_ct_tcp_no_window_check __read_mostly = 0; ++EXPORT_SYMBOL_GPL(nf_ct_tcp_no_window_check); + + /* "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; ++int nf_ct_tcp_be_liberal __read_mostly = 0; ++EXPORT_SYMBOL_GPL(nf_ct_tcp_be_liberal); + + /* If it is set to zero, we disable picking up already established + connections. */ + static int nf_ct_tcp_loose __read_mostly = 1; + + /* Max number of the retransmitted packets without receiving an (acceptable) diff --git a/shortcut-fe/src/sfe.h b/shortcut-fe/sfe.h old mode 100755 new mode 100644 similarity index 100% rename from shortcut-fe/src/sfe.h rename to shortcut-fe/sfe.h diff --git a/shortcut-fe/src/sfe_backport.h b/shortcut-fe/sfe_backport.h old mode 100755 new mode 100644 similarity index 100% rename from shortcut-fe/src/sfe_backport.h rename to shortcut-fe/sfe_backport.h diff --git a/shortcut-fe/sfe_cm.c b/shortcut-fe/sfe_cm.c new file mode 100644 index 000000000..bd1bb88aa --- /dev/null +++ b/shortcut-fe/sfe_cm.c @@ -0,0 +1,1154 @@ +/* + * sfe-cm.c + * Shortcut forwarding engine connection manager. + * + * Copyright (c) 2013-2018, 2020 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sfe.h" +#include "sfe_cm.h" +#include "sfe_backport.h" + +typedef enum sfe_cm_exception { + SFE_CM_EXCEPTION_PACKET_BROADCAST, + SFE_CM_EXCEPTION_PACKET_MULTICAST, + SFE_CM_EXCEPTION_NO_IIF, + SFE_CM_EXCEPTION_NO_CT, + SFE_CM_EXCEPTION_CT_NO_TRACK, + SFE_CM_EXCEPTION_CT_NO_CONFIRM, + SFE_CM_EXCEPTION_CT_IS_ALG, + SFE_CM_EXCEPTION_IS_IPV4_MCAST, + SFE_CM_EXCEPTION_IS_IPV6_MCAST, + SFE_CM_EXCEPTION_TCP_NOT_ASSURED, + SFE_CM_EXCEPTION_TCP_NOT_ESTABLISHED, + SFE_CM_EXCEPTION_UNKNOW_PROTOCOL, + SFE_CM_EXCEPTION_NO_SRC_DEV, + SFE_CM_EXCEPTION_NO_SRC_XLATE_DEV, + SFE_CM_EXCEPTION_NO_DEST_DEV, + SFE_CM_EXCEPTION_NO_DEST_XLATE_DEV, + SFE_CM_EXCEPTION_NO_BRIDGE, + SFE_CM_EXCEPTION_LOCAL_OUT, + SFE_CM_EXCEPTION_MAX +} sfe_cm_exception_t; + +static char *sfe_cm_exception_events_string[SFE_CM_EXCEPTION_MAX] = { + "PACKET_BROADCAST", + "PACKET_MULTICAST", + "NO_IIF", + "NO_CT", + "CT_NO_TRACK", + "CT_NO_CONFIRM", + "CT_IS_ALG", + "IS_IPV4_MCAST", + "IS_IPV6_MCAST", + "TCP_NOT_ASSURED", + "TCP_NOT_ESTABLISHED", + "UNKNOW_PROTOCOL", + "NO_SRC_DEV", + "NO_SRC_XLATE_DEV", + "NO_DEST_DEV", + "NO_DEST_XLATE_DEV", + "NO_BRIDGE", + "LOCAL_OUT" +}; + +/* + * Per-module structure. + */ +struct sfe_cm { + spinlock_t lock; /* Lock for SMP correctness */ + + /* + * Control state. + */ + struct kobject *sys_sfe_cm; /* sysfs linkage */ + + /* + * Callback notifiers. + */ + struct notifier_block dev_notifier; /* Device notifier */ + struct notifier_block inet_notifier; /* IPv4 notifier */ + struct notifier_block inet6_notifier; /* IPv6 notifier */ + u32 exceptions[SFE_CM_EXCEPTION_MAX]; +}; + +static struct sfe_cm __sc; + +/* + * sfe_cm_incr_exceptions() + * increase an exception counter. + */ +static inline void sfe_cm_incr_exceptions(sfe_cm_exception_t except) +{ + struct sfe_cm *sc = &__sc; + + spin_lock_bh(&sc->lock); + sc->exceptions[except]++; + spin_unlock_bh(&sc->lock); +} + +/* + * sfe_cm_recv() + * Handle packet receives. + * + * Returns 1 if the packet is forwarded or 0 if it isn't. + */ +int sfe_cm_recv(struct sk_buff *skb) +{ + struct net_device *dev; + + /* + * We know that for the vast majority of packets we need the transport + * layer header so we may as well start to fetch it now! + */ + prefetch(skb->data + 32); + barrier(); + + dev = skb->dev; + + /* + * We're only interested in IPv4 and IPv6 packets. + */ + if (likely(htons(ETH_P_IP) == skb->protocol)) { + struct in_device *in_dev; + + /* + * Does our input device support IP processing? + */ + in_dev = (struct in_device *)dev->ip_ptr; + if (unlikely(!in_dev)) { + DEBUG_TRACE("no IP processing for device: %s\n", dev->name); + return 0; + } + + /* + * Does it have an IP address? If it doesn't then we can't do anything + * interesting here! + */ + if (unlikely(!in_dev->ifa_list)) { + DEBUG_TRACE("no IP address for device: %s\n", dev->name); + return 0; + } + + return sfe_ipv4_recv(dev, skb); + } + + if (likely(htons(ETH_P_IPV6) == skb->protocol)) { + struct inet6_dev *in_dev; + + /* + * Does our input device support IPv6 processing? + */ + in_dev = (struct inet6_dev *)dev->ip6_ptr; + if (unlikely(!in_dev)) { + DEBUG_TRACE("no IPv6 processing for device: %s\n", dev->name); + return 0; + } + + /* + * Does it have an IPv6 address? If it doesn't then we can't do anything + * interesting here! + */ + if (unlikely(list_empty(&in_dev->addr_list))) { + DEBUG_TRACE("no IPv6 address for device: %s\n", dev->name); + return 0; + } + + return sfe_ipv6_recv(dev, skb); + } + + DEBUG_TRACE("not IP packet\n"); + return 0; +} + +/* + * sfe_cm_find_dev_and_mac_addr() + * Find the device and MAC address for a given IPv4/IPv6 address. + * + * Returns true if we find the device and MAC address, otherwise false. + * + * We look up the rtable entry for the address and, from its neighbour + * structure, obtain the hardware address. This means this function also + * works if the neighbours are routers too. + */ +static bool sfe_cm_find_dev_and_mac_addr(sfe_ip_addr_t *addr, struct net_device **dev, u8 *mac_addr, int is_v4) +{ + struct neighbour *neigh; + struct rtable *rt; + struct rt6_info *rt6; + struct dst_entry *dst; + struct net_device *mac_dev; + + /* + * Look up the rtable entry for the IP address then get the hardware + * address from its neighbour structure. This means this work when the + * neighbours are routers too. + */ + if (likely(is_v4)) { + rt = ip_route_output(&init_net, addr->ip, 0, 0, 0); + if (unlikely(IS_ERR(rt))) { + goto ret_fail; + } + + dst = (struct dst_entry *)rt; + } else { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 17, 0)) + rt6 = rt6_lookup(&init_net, (struct in6_addr *)addr->ip6, 0, 0, 0); +#else + rt6 = rt6_lookup(&init_net, (struct in6_addr *)addr->ip6, 0, 0, NULL, 0); +#endif + if (!rt6) { + goto ret_fail; + } + + dst = (struct dst_entry *)rt6; + } + + rcu_read_lock(); + neigh = sfe_dst_get_neighbour(dst, addr); + if (unlikely(!neigh)) { + rcu_read_unlock(); + dst_release(dst); + goto ret_fail; + } + + if (unlikely(!(neigh->nud_state & NUD_VALID))) { + rcu_read_unlock(); + neigh_release(neigh); + dst_release(dst); + goto ret_fail; + } + + mac_dev = neigh->dev; + if (!mac_dev) { + rcu_read_unlock(); + neigh_release(neigh); + dst_release(dst); + goto ret_fail; + } + + memcpy(mac_addr, neigh->ha, (size_t)mac_dev->addr_len); + + dev_hold(mac_dev); + *dev = mac_dev; + rcu_read_unlock(); + neigh_release(neigh); + dst_release(dst); + + return true; + +ret_fail: + if (is_v4) { + DEBUG_TRACE("failed to find MAC address for IP: %pI4\n", &addr->ip); + + } else { + DEBUG_TRACE("failed to find MAC address for IP: %pI6\n", addr->ip6); + } + + return false; +} + +/* + * sfe_cm_post_routing() + * Called for packets about to leave the box - either locally generated or forwarded from another interface + */ +static unsigned int sfe_cm_post_routing(struct sk_buff *skb, int is_v4) +{ + struct sfe_connection_create sic; + struct net_device *in; + struct nf_conn *ct; + enum ip_conntrack_info ctinfo; + struct net_device *dev; + struct net_device *src_dev; + struct net_device *dest_dev; + struct net_device *src_dev_tmp; + struct net_device *dest_dev_tmp; + struct net_device *src_br_dev = NULL; + struct net_device *dest_br_dev = NULL; + struct nf_conntrack_tuple orig_tuple; + struct nf_conntrack_tuple reply_tuple; + SFE_NF_CONN_ACCT(acct); + + /* + * Don't process broadcast or multicast packets. + */ + if (unlikely(skb->pkt_type == PACKET_BROADCAST)) { + sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_PACKET_BROADCAST); + DEBUG_TRACE("broadcast, ignoring\n"); + return NF_ACCEPT; + } + if (unlikely(skb->pkt_type == PACKET_MULTICAST)) { + sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_PACKET_MULTICAST); + DEBUG_TRACE("multicast, ignoring\n"); + return NF_ACCEPT; + } + +#ifdef CONFIG_XFRM + /* + * Packet to xfrm for encapsulation, we can't process it + */ + if (unlikely(skb_dst(skb)->xfrm)) { + DEBUG_TRACE("packet to xfrm, ignoring\n"); + return NF_ACCEPT; + } +#endif + + /* + * Don't process locally generated packets. + */ + if (skb->sk) { + sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_LOCAL_OUT); + DEBUG_TRACE("skip local out packet\n"); + return NF_ACCEPT; + } + + /* + * Don't process packets that are not being forwarded. + */ + in = dev_get_by_index(&init_net, skb->skb_iif); + if (!in) { + sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_IIF); + DEBUG_TRACE("packet not forwarding\n"); + return NF_ACCEPT; + } + + dev_put(in); + + /* + * Don't process packets that aren't being tracked by conntrack. + */ + ct = nf_ct_get(skb, &ctinfo); + if (unlikely(!ct)) { + sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_CT); + DEBUG_TRACE("no conntrack connection, ignoring\n"); + return NF_ACCEPT; + } + + /* + * Don't process untracked connections. + */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)) + if (unlikely(nf_ct_is_untracked(ct))) { +#else + if (unlikely(ctinfo == IP_CT_UNTRACKED)) { +#endif + sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_CT_NO_TRACK); + DEBUG_TRACE("untracked connection\n"); + return NF_ACCEPT; + } + + /* + * Unconfirmed connection may be dropped by Linux at the final step, + * So we don't process unconfirmed connections. + */ + if (!nf_ct_is_confirmed(ct)) { + sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_CT_NO_CONFIRM); + DEBUG_TRACE("unconfirmed connection\n"); + return NF_ACCEPT; + } + + /* + * Don't process connections that require support from a 'helper' (typically a NAT ALG). + */ + if (unlikely(nfct_help(ct))) { + sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_CT_IS_ALG); + DEBUG_TRACE("connection has helper\n"); + return NF_ACCEPT; + } + + /* + * Check if the acceleration of a flow could be rejected quickly. + */ + acct = nf_conn_acct_find(ct); + if (acct) { + long long packets = atomic64_read(&SFE_ACCT_COUNTER(acct)[CTINFO2DIR(ctinfo)].packets); + if ((packets > 0xff) && (packets & 0xff)) { + /* + * Connection hits slow path at least 256 times, so it must be not able to accelerate. + * But we also give it a chance to walk through ECM every 256 packets + */ + return NF_ACCEPT; + } + } + + /* + * Look up the details of our connection in conntrack. + * + * Note that the data we get from conntrack is for the "ORIGINAL" direction + * but our packet may actually be in the "REPLY" direction. + */ + orig_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; + reply_tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple; + sic.protocol = (s32)orig_tuple.dst.protonum; + + sic.flags = 0; + + /* + * Get addressing information, non-NAT first + */ + if (likely(is_v4)) { + u32 dscp; + + sic.src_ip.ip = (__be32)orig_tuple.src.u3.ip; + sic.dest_ip.ip = (__be32)orig_tuple.dst.u3.ip; + + if (ipv4_is_multicast(sic.src_ip.ip) || ipv4_is_multicast(sic.dest_ip.ip)) { + sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_IS_IPV4_MCAST); + DEBUG_TRACE("multicast address\n"); + return NF_ACCEPT; + } + + /* + * NAT'ed addresses - note these are as seen from the 'reply' direction + * When NAT does not apply to this connection these will be identical to the above. + */ + sic.src_ip_xlate.ip = (__be32)reply_tuple.dst.u3.ip; + sic.dest_ip_xlate.ip = (__be32)reply_tuple.src.u3.ip; + + dscp = ipv4_get_dsfield(ip_hdr(skb)) >> XT_DSCP_SHIFT; + if (dscp) { + sic.dest_dscp = dscp; + sic.src_dscp = sic.dest_dscp; + sic.flags |= SFE_CREATE_FLAG_REMARK_DSCP; + } + } else { + u32 dscp; + + sic.src_ip.ip6[0] = *((struct sfe_ipv6_addr *)&orig_tuple.src.u3.in6); + sic.dest_ip.ip6[0] = *((struct sfe_ipv6_addr *)&orig_tuple.dst.u3.in6); + + if (ipv6_addr_is_multicast((struct in6_addr *)sic.src_ip.ip6) || + ipv6_addr_is_multicast((struct in6_addr *)sic.dest_ip.ip6)) { + sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_IS_IPV6_MCAST); + DEBUG_TRACE("multicast address\n"); + return NF_ACCEPT; + } + + /* + * NAT'ed addresses - note these are as seen from the 'reply' direction + * When NAT does not apply to this connection these will be identical to the above. + */ + sic.src_ip_xlate.ip6[0] = *((struct sfe_ipv6_addr *)&reply_tuple.dst.u3.in6); + sic.dest_ip_xlate.ip6[0] = *((struct sfe_ipv6_addr *)&reply_tuple.src.u3.in6); + + dscp = ipv6_get_dsfield(ipv6_hdr(skb)) >> XT_DSCP_SHIFT; + if (dscp) { + sic.dest_dscp = dscp; + sic.src_dscp = sic.dest_dscp; + sic.flags |= SFE_CREATE_FLAG_REMARK_DSCP; + } + } + + switch (sic.protocol) { + case IPPROTO_TCP: + sic.src_port = orig_tuple.src.u.tcp.port; + sic.dest_port = orig_tuple.dst.u.tcp.port; + sic.src_port_xlate = reply_tuple.dst.u.tcp.port; + sic.dest_port_xlate = reply_tuple.src.u.tcp.port; + sic.src_td_window_scale = ct->proto.tcp.seen[0].td_scale; + sic.src_td_max_window = ct->proto.tcp.seen[0].td_maxwin; + sic.src_td_end = ct->proto.tcp.seen[0].td_end; + sic.src_td_max_end = ct->proto.tcp.seen[0].td_maxend; + sic.dest_td_window_scale = ct->proto.tcp.seen[1].td_scale; + sic.dest_td_max_window = ct->proto.tcp.seen[1].td_maxwin; + sic.dest_td_end = ct->proto.tcp.seen[1].td_end; + sic.dest_td_max_end = ct->proto.tcp.seen[1].td_maxend; + + if (nf_ct_tcp_no_window_check + || (ct->proto.tcp.seen[0].flags & IP_CT_TCP_FLAG_BE_LIBERAL) + || (ct->proto.tcp.seen[1].flags & IP_CT_TCP_FLAG_BE_LIBERAL)) { + sic.flags |= SFE_CREATE_FLAG_NO_SEQ_CHECK; + } + + /* + * Don't try to manage a non-established connection. + */ + if (!test_bit(IPS_ASSURED_BIT, &ct->status)) { + sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_TCP_NOT_ASSURED); + DEBUG_TRACE("non-established connection\n"); + return NF_ACCEPT; + } + + /* + * If the connection is shutting down do not manage it. + * state can not be SYN_SENT, SYN_RECV because connection is assured + * Not managed states: FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE. + */ + spin_lock_bh(&ct->lock); + if (ct->proto.tcp.state != TCP_CONNTRACK_ESTABLISHED) { + spin_unlock_bh(&ct->lock); + sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_TCP_NOT_ESTABLISHED); + DEBUG_TRACE("connection in termination state: %#x, s: %pI4:%u, d: %pI4:%u\n", + ct->proto.tcp.state, &sic.src_ip, ntohs(sic.src_port), + &sic.dest_ip, ntohs(sic.dest_port)); + return NF_ACCEPT; + } + spin_unlock_bh(&ct->lock); + break; + + case IPPROTO_UDP: + sic.src_port = orig_tuple.src.u.udp.port; + sic.dest_port = orig_tuple.dst.u.udp.port; + sic.src_port_xlate = reply_tuple.dst.u.udp.port; + sic.dest_port_xlate = reply_tuple.src.u.udp.port; + break; + + default: + sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_UNKNOW_PROTOCOL); + DEBUG_TRACE("unhandled protocol %d\n", sic.protocol); + return NF_ACCEPT; + } + +#ifdef CONFIG_XFRM + sic.original_accel = 1; + sic.reply_accel = 1; + + /* + * For packets de-capsulated from xfrm, we still can accelerate it + * on the direction we just received the packet. + */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0)) + if (unlikely(skb->sp)) { +#else + if (unlikely(secpath_exists(skb))) { +#endif + if (sic.protocol == IPPROTO_TCP && + !(sic.flags & SFE_CREATE_FLAG_NO_SEQ_CHECK)) { + return NF_ACCEPT; + } + + if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) { + sic.reply_accel = 0; + } else { + sic.original_accel = 0; + } + } +#endif + + /* + * Get QoS information + */ + if (skb->priority) { + sic.dest_priority = skb->priority; + sic.src_priority = sic.dest_priority; + sic.flags |= SFE_CREATE_FLAG_REMARK_PRIORITY; + } + + /* + * Get the net device and MAC addresses that correspond to the various source and + * destination host addresses. + */ + if (!sfe_cm_find_dev_and_mac_addr(&sic.src_ip, &src_dev_tmp, sic.src_mac, is_v4)) { + sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_SRC_DEV); + return NF_ACCEPT; + } + src_dev = src_dev_tmp; + + if (!sfe_cm_find_dev_and_mac_addr(&sic.src_ip_xlate, &dev, sic.src_mac_xlate, is_v4)) { + sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_SRC_XLATE_DEV); + goto done1; + } + dev_put(dev); + + if (!sfe_cm_find_dev_and_mac_addr(&sic.dest_ip, &dev, sic.dest_mac, is_v4)) { + sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_DEST_DEV); + goto done1; + } + dev_put(dev); + + if (!sfe_cm_find_dev_and_mac_addr(&sic.dest_ip_xlate, &dest_dev_tmp, sic.dest_mac_xlate, is_v4)) { + sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_DEST_XLATE_DEV); + goto done1; + } + dest_dev = dest_dev_tmp; + + /* + * Our devices may actually be part of a bridge interface. If that's + * the case then find the bridge interface instead. + */ + if (src_dev->priv_flags & IFF_BRIDGE_PORT) { + src_br_dev = sfe_dev_get_master(src_dev); + if (!src_br_dev) { + sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_BRIDGE); + DEBUG_TRACE("no bridge found for: %s\n", src_dev->name); + goto done2; + } + src_dev = src_br_dev; + } + + if (dest_dev->priv_flags & IFF_BRIDGE_PORT) { + dest_br_dev = sfe_dev_get_master(dest_dev); + if (!dest_br_dev) { + sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_BRIDGE); + DEBUG_TRACE("no bridge found for: %s\n", dest_dev->name); + goto done3; + } + dest_dev = dest_br_dev; + } + + sic.src_dev = src_dev; + sic.dest_dev = dest_dev; + + sic.src_mtu = src_dev->mtu; + sic.dest_mtu = dest_dev->mtu; + + if (likely(is_v4)) { + sfe_ipv4_create_rule(&sic); + } else { + sfe_ipv6_create_rule(&sic); + } + + /* + * If we had bridge ports then release them too. + */ + if (dest_br_dev) { + dev_put(dest_br_dev); + } +done3: + if (src_br_dev) { + dev_put(src_br_dev); + } +done2: + dev_put(dest_dev_tmp); +done1: + dev_put(src_dev_tmp); + + return NF_ACCEPT; +} + +/* + * sfe_cm_ipv4_post_routing_hook() + * Called for packets about to leave the box - either locally generated or forwarded from another interface + */ +sfe_cm_ipv4_post_routing_hook(hooknum, ops, skb, in_unused, out, okfn) +{ + return sfe_cm_post_routing(skb, true); +} + +/* + * sfe_cm_ipv6_post_routing_hook() + * Called for packets about to leave the box - either locally generated or forwarded from another interface + */ +sfe_cm_ipv6_post_routing_hook(hooknum, ops, skb, in_unused, out, okfn) +{ + return sfe_cm_post_routing(skb, false); +} + +#ifdef CONFIG_NF_CONNTRACK_EVENTS +/* + * sfe_cm_conntrack_event() + * Callback event invoked when a conntrack connection's state changes. + */ +#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS +static int sfe_cm_conntrack_event(struct notifier_block *this, + unsigned long events, void *ptr) +#else +static int sfe_cm_conntrack_event(unsigned int events, struct nf_ct_event *item) +#endif +{ +#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS + struct nf_ct_event *item = ptr; +#endif + struct sfe_connection_destroy sid; + struct nf_conn *ct = item->ct; + struct nf_conntrack_tuple orig_tuple; + + /* + * If we don't have a conntrack entry then we're done. + */ + if (unlikely(!ct)) { + DEBUG_WARN("no ct in conntrack event callback\n"); + return NOTIFY_DONE; + } + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)) + if (unlikely(nf_ct_is_untracked(ct))) { + DEBUG_TRACE("ignoring untracked conn\n"); + return NOTIFY_DONE; + } +#endif + + /* + * We're only interested in destroy events. + */ + if (unlikely(!(events & (1 << IPCT_DESTROY)))) { + DEBUG_TRACE("ignoring non-destroy event\n"); + return NOTIFY_DONE; + } + + orig_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; + sid.protocol = (s32)orig_tuple.dst.protonum; + + /* + * Extract information from the conntrack connection. We're only interested + * in nominal connection information (i.e. we're ignoring any NAT information). + */ + switch (sid.protocol) { + case IPPROTO_TCP: + sid.src_port = orig_tuple.src.u.tcp.port; + sid.dest_port = orig_tuple.dst.u.tcp.port; + break; + + case IPPROTO_UDP: + sid.src_port = orig_tuple.src.u.udp.port; + sid.dest_port = orig_tuple.dst.u.udp.port; + break; + + default: + DEBUG_TRACE("unhandled protocol: %d\n", sid.protocol); + return NOTIFY_DONE; + } + + if (likely(nf_ct_l3num(ct) == AF_INET)) { + sid.src_ip.ip = (__be32)orig_tuple.src.u3.ip; + sid.dest_ip.ip = (__be32)orig_tuple.dst.u3.ip; + + sfe_ipv4_destroy_rule(&sid); + } else if (likely(nf_ct_l3num(ct) == AF_INET6)) { + sid.src_ip.ip6[0] = *((struct sfe_ipv6_addr *)&orig_tuple.src.u3.in6); + sid.dest_ip.ip6[0] = *((struct sfe_ipv6_addr *)&orig_tuple.dst.u3.in6); + + sfe_ipv6_destroy_rule(&sid); + } else { + DEBUG_TRACE("ignoring non-IPv4 and non-IPv6 connection\n"); + } + + return NOTIFY_DONE; +} + +/* + * Netfilter conntrack event system to monitor connection tracking changes + */ +#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS +static struct notifier_block sfe_cm_conntrack_notifier = { + .notifier_call = sfe_cm_conntrack_event, +}; +#else +static struct nf_ct_event_notifier sfe_cm_conntrack_notifier = { + .fcn = sfe_cm_conntrack_event, +}; +#endif +#endif + +/* + * Structure to establish a hook into the post routing netfilter point - this + * will pick up local outbound and packets going from one interface to another. + * + * Note: see include/linux/netfilter_ipv4.h for info related to priority levels. + * We want to examine packets after NAT translation and any ALG processing. + */ +static struct nf_hook_ops sfe_cm_ops_post_routing[] __read_mostly = { + SFE_IPV4_NF_POST_ROUTING_HOOK(__sfe_cm_ipv4_post_routing_hook), +#ifdef SFE_SUPPORT_IPV6 + SFE_IPV6_NF_POST_ROUTING_HOOK(__sfe_cm_ipv6_post_routing_hook), +#endif +}; + +/* + * sfe_cm_sync_rule() + * Synchronize a connection's state. + */ +static void sfe_cm_sync_rule(struct sfe_connection_sync *sis) +{ + struct nf_conntrack_tuple_hash *h; + struct nf_conntrack_tuple tuple; + struct nf_conn *ct; + SFE_NF_CONN_ACCT(acct); + + /* + * Create a tuple so as to be able to look up a connection + */ + memset(&tuple, 0, sizeof(tuple)); + tuple.src.u.all = (__be16)sis->src_port; + tuple.dst.dir = IP_CT_DIR_ORIGINAL; + tuple.dst.protonum = (u8)sis->protocol; + tuple.dst.u.all = (__be16)sis->dest_port; + + if (sis->is_v6) { + tuple.src.u3.in6 = *((struct in6_addr *)sis->src_ip.ip6); + tuple.dst.u3.in6 = *((struct in6_addr *)sis->dest_ip.ip6); + tuple.src.l3num = AF_INET6; + + DEBUG_TRACE("update connection - p: %d, s: %pI6:%u, d: %pI6:%u\n", + (int)tuple.dst.protonum, + &tuple.src.u3.in6, (unsigned int)ntohs(tuple.src.u.all), + &tuple.dst.u3.in6, (unsigned int)ntohs(tuple.dst.u.all)); + } else { + tuple.src.u3.ip = sis->src_ip.ip; + tuple.dst.u3.ip = sis->dest_ip.ip; + tuple.src.l3num = AF_INET; + + DEBUG_TRACE("update connection - p: %d, s: %pI4:%u, d: %pI4:%u\n", + (int)tuple.dst.protonum, + &tuple.src.u3.ip, (unsigned int)ntohs(tuple.src.u.all), + &tuple.dst.u3.ip, (unsigned int)ntohs(tuple.dst.u.all)); + } + + /* + * Look up conntrack connection + */ + h = nf_conntrack_find_get(&init_net, SFE_NF_CT_DEFAULT_ZONE, &tuple); + if (unlikely(!h)) { + DEBUG_TRACE("no connection found\n"); + return; + } + + ct = nf_ct_tuplehash_to_ctrack(h); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)) + NF_CT_ASSERT(ct->timeout.data == (unsigned long)ct); +#endif + /* + * Only update if this is not a fixed timeout + */ + if (!test_bit(IPS_FIXED_TIMEOUT_BIT, &ct->status)) { + spin_lock_bh(&ct->lock); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)) + ct->timeout.expires += sis->delta_jiffies; +#else + ct->timeout += sis->delta_jiffies; +#endif + spin_unlock_bh(&ct->lock); + } + + acct = nf_conn_acct_find(ct); + if (acct) { + spin_lock_bh(&ct->lock); + atomic64_add(sis->src_new_packet_count, &SFE_ACCT_COUNTER(acct)[IP_CT_DIR_ORIGINAL].packets); + atomic64_add(sis->src_new_byte_count, &SFE_ACCT_COUNTER(acct)[IP_CT_DIR_ORIGINAL].bytes); + atomic64_add(sis->dest_new_packet_count, &SFE_ACCT_COUNTER(acct)[IP_CT_DIR_REPLY].packets); + atomic64_add(sis->dest_new_byte_count, &SFE_ACCT_COUNTER(acct)[IP_CT_DIR_REPLY].bytes); + spin_unlock_bh(&ct->lock); + } + + switch (sis->protocol) { + case IPPROTO_TCP: + spin_lock_bh(&ct->lock); + if (ct->proto.tcp.seen[0].td_maxwin < sis->src_td_max_window) { + ct->proto.tcp.seen[0].td_maxwin = sis->src_td_max_window; + } + if ((s32)(ct->proto.tcp.seen[0].td_end - sis->src_td_end) < 0) { + ct->proto.tcp.seen[0].td_end = sis->src_td_end; + } + if ((s32)(ct->proto.tcp.seen[0].td_maxend - sis->src_td_max_end) < 0) { + ct->proto.tcp.seen[0].td_maxend = sis->src_td_max_end; + } + if (ct->proto.tcp.seen[1].td_maxwin < sis->dest_td_max_window) { + ct->proto.tcp.seen[1].td_maxwin = sis->dest_td_max_window; + } + if ((s32)(ct->proto.tcp.seen[1].td_end - sis->dest_td_end) < 0) { + ct->proto.tcp.seen[1].td_end = sis->dest_td_end; + } + if ((s32)(ct->proto.tcp.seen[1].td_maxend - sis->dest_td_max_end) < 0) { + ct->proto.tcp.seen[1].td_maxend = sis->dest_td_max_end; + } + spin_unlock_bh(&ct->lock); + break; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) + case IPPROTO_UDP: + /* + * In Linux connection track, UDP flow has two timeout values: + * /proc/sys/net/netfilter/nf_conntrack_udp_timeout: + * this is for uni-direction UDP flow, normally its value is 60 seconds + * /proc/sys/net/netfilter/nf_conntrack_udp_timeout_stream: + * this is for bi-direction UDP flow, normally its value is 180 seconds + * + * Linux will update timer of UDP flow to stream timeout once it seen packets + * in reply direction. But if flow is accelerated by NSS or SFE, Linux won't + * see any packets. So we have to do the same thing in our stats sync message. + */ + if (!test_bit(IPS_ASSURED_BIT, &ct->status) && acct) { + u_int64_t reply_pkts = atomic64_read(&SFE_ACCT_COUNTER(acct)[IP_CT_DIR_REPLY].packets); + + if (reply_pkts != 0) { + unsigned int *timeouts; + struct nf_conntrack_l4proto *l4proto __maybe_unused; + set_bit(IPS_SEEN_REPLY_BIT, &ct->status); + set_bit(IPS_ASSURED_BIT, &ct->status); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)) + l4proto = __nf_ct_l4proto_find((sis->is_v6 ? AF_INET6 : AF_INET), IPPROTO_UDP); + timeouts = nf_ct_timeout_lookup(&init_net, ct, l4proto); + spin_lock_bh(&ct->lock); + ct->timeout.expires = jiffies + timeouts[UDP_CT_REPLIED]; + spin_unlock_bh(&ct->lock); +#else + timeouts = nf_ct_timeout_lookup(ct); + if (!timeouts) { + timeouts = udp_get_timeouts(nf_ct_net(ct)); + } + + spin_lock_bh(&ct->lock); + ct->timeout = jiffies + timeouts[UDP_CT_REPLIED]; + spin_unlock_bh(&ct->lock); +#endif + } + } + break; +#endif /*KERNEL_VERSION(3, 4, 0)*/ + } + + /* + * Release connection + */ + nf_ct_put(ct); +} + +/* + * sfe_cm_device_event() + */ +int sfe_cm_device_event(struct notifier_block *this, unsigned long event, void *ptr) +{ + struct net_device *dev = SFE_DEV_EVENT_PTR(ptr); + + if (dev && (event == NETDEV_DOWN)) { + sfe_ipv4_destroy_all_rules_for_dev(dev); + sfe_ipv6_destroy_all_rules_for_dev(dev); + } + + return NOTIFY_DONE; +} + +/* + * sfe_cm_inet_event() + */ +static int sfe_cm_inet_event(struct notifier_block *this, unsigned long event, void *ptr) +{ + struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev; + + if (dev && (event == NETDEV_DOWN)) { + sfe_ipv4_destroy_all_rules_for_dev(dev); + } + + return NOTIFY_DONE; +} + +/* + * sfe_cm_inet6_event() + */ +static int sfe_cm_inet6_event(struct notifier_block *this, unsigned long event, void *ptr) +{ + struct net_device *dev = ((struct inet6_ifaddr *)ptr)->idev->dev; + + if (dev && (event == NETDEV_DOWN)) { + sfe_ipv6_destroy_all_rules_for_dev(dev); + } + + return NOTIFY_DONE; +} + +/* + * sfe_cm_get_exceptions + * dump exception counters + */ +static ssize_t sfe_cm_get_exceptions(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int idx, len; + struct sfe_cm *sc = &__sc; + + spin_lock_bh(&sc->lock); + for (len = 0, idx = 0; idx < SFE_CM_EXCEPTION_MAX; idx++) { + if (sc->exceptions[idx]) { + len += snprintf(buf + len, (ssize_t)(PAGE_SIZE - len), "%s = %d\n", sfe_cm_exception_events_string[idx], sc->exceptions[idx]); + } + } + spin_unlock_bh(&sc->lock); + + return len; +} + +/* + * sysfs attributes. + */ +static const struct device_attribute sfe_cm_exceptions_attr = + __ATTR(exceptions, S_IRUGO, sfe_cm_get_exceptions, NULL); + +/* + * sfe_cm_init() + */ +static int __init sfe_cm_init(void) +{ + struct sfe_cm *sc = &__sc; + int result = -1; + + DEBUG_INFO("SFE CM init\n"); + + /* + * Create sys/sfe_cm + */ + sc->sys_sfe_cm = kobject_create_and_add("sfe_cm", NULL); + if (!sc->sys_sfe_cm) { + DEBUG_ERROR("failed to register sfe_cm\n"); + goto exit1; + } + + /* + * Create sys/sfe_cm/exceptions + */ + result = sysfs_create_file(sc->sys_sfe_cm, &sfe_cm_exceptions_attr.attr); + if (result) { + DEBUG_ERROR("failed to register exceptions file: %d\n", result); + goto exit2; + } + + sc->dev_notifier.notifier_call = sfe_cm_device_event; + sc->dev_notifier.priority = 1; + register_netdevice_notifier(&sc->dev_notifier); + + sc->inet_notifier.notifier_call = sfe_cm_inet_event; + sc->inet_notifier.priority = 1; + register_inetaddr_notifier(&sc->inet_notifier); + + sc->inet6_notifier.notifier_call = sfe_cm_inet6_event; + sc->inet6_notifier.priority = 1; + register_inet6addr_notifier(&sc->inet6_notifier); + /* + * Register our netfilter hooks. + */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0)) + result = nf_register_hooks(sfe_cm_ops_post_routing, ARRAY_SIZE(sfe_cm_ops_post_routing)); +#else + result = nf_register_net_hooks(&init_net, sfe_cm_ops_post_routing, ARRAY_SIZE(sfe_cm_ops_post_routing)); +#endif + if (result < 0) { + DEBUG_ERROR("can't register nf post routing hook: %d\n", result); + goto exit3; + } + + /* + * Register a notifier hook to get fast notifications of expired connections. + * Note: In CONFIG_NF_CONNTRACK_CHAIN_EVENTS enabled case, nf_conntrack_register_notifier() + * function always returns 0. + */ +#ifdef CONFIG_NF_CONNTRACK_EVENTS +#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS + (void)nf_conntrack_register_notifier(&init_net, &sfe_cm_conntrack_notifier); +#else + result = nf_conntrack_register_notifier(&init_net, &sfe_cm_conntrack_notifier); + if (result < 0) { + DEBUG_ERROR("can't register nf notifier hook: %d\n", result); + goto exit4; + } +#endif +#endif + + spin_lock_init(&sc->lock); + + /* + * Hook the receive path in the network stack. + */ + BUG_ON(athrs_fast_nat_recv); + RCU_INIT_POINTER(athrs_fast_nat_recv, sfe_cm_recv); + + /* + * Hook the shortcut sync callback. + */ + sfe_ipv4_register_sync_rule_callback(sfe_cm_sync_rule); + sfe_ipv6_register_sync_rule_callback(sfe_cm_sync_rule); + return 0; + +#ifdef CONFIG_NF_CONNTRACK_EVENTS +#ifndef CONFIG_NF_CONNTRACK_CHAIN_EVENTS +exit4: +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0)) + nf_unregister_hooks(sfe_cm_ops_post_routing, ARRAY_SIZE(sfe_cm_ops_post_routing)); +#else + nf_unregister_net_hooks(&init_net, sfe_cm_ops_post_routing, ARRAY_SIZE(sfe_cm_ops_post_routing)); +#endif + +#endif +#endif +exit3: + unregister_inet6addr_notifier(&sc->inet6_notifier); + unregister_inetaddr_notifier(&sc->inet_notifier); + unregister_netdevice_notifier(&sc->dev_notifier); +exit2: + kobject_put(sc->sys_sfe_cm); + +exit1: + return result; +} + +/* + * sfe_cm_exit() + */ +static void __exit sfe_cm_exit(void) +{ + struct sfe_cm *sc = &__sc; + + DEBUG_INFO("SFE CM exit\n"); + + /* + * Unregister our sync callback. + */ + sfe_ipv4_register_sync_rule_callback(NULL); + sfe_ipv6_register_sync_rule_callback(NULL); + + /* + * Unregister our receive callback. + */ + RCU_INIT_POINTER(athrs_fast_nat_recv, NULL); + + /* + * Wait for all callbacks to complete. + */ + rcu_barrier(); + + /* + * Destroy all connections. + */ + sfe_ipv4_destroy_all_rules_for_dev(NULL); + sfe_ipv6_destroy_all_rules_for_dev(NULL); + +#ifdef CONFIG_NF_CONNTRACK_EVENTS + nf_conntrack_unregister_notifier(&init_net, &sfe_cm_conntrack_notifier); + +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0)) + nf_unregister_hooks(sfe_cm_ops_post_routing, ARRAY_SIZE(sfe_cm_ops_post_routing)); +#else + nf_unregister_net_hooks(&init_net, sfe_cm_ops_post_routing, ARRAY_SIZE(sfe_cm_ops_post_routing)); +#endif + unregister_inet6addr_notifier(&sc->inet6_notifier); + unregister_inetaddr_notifier(&sc->inet_notifier); + unregister_netdevice_notifier(&sc->dev_notifier); + + kobject_put(sc->sys_sfe_cm); +} + +module_init(sfe_cm_init) +module_exit(sfe_cm_exit) + +MODULE_DESCRIPTION("Shortcut Forwarding Engine - Connection Manager"); +MODULE_LICENSE("Dual BSD/GPL"); + diff --git a/shortcut-fe/sfe_cm.h b/shortcut-fe/sfe_cm.h new file mode 100644 index 000000000..23cbde859 --- /dev/null +++ b/shortcut-fe/sfe_cm.h @@ -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); +} diff --git a/shortcut-fe/sfe_ipv4.c b/shortcut-fe/sfe_ipv4.c new file mode 100644 index 000000000..9f7ebd1c9 --- /dev/null +++ b/shortcut-fe/sfe_ipv4.c @@ -0,0 +1,3610 @@ +/* + * sfe_ipv4.c + * Shortcut forwarding engine - IPv4 edition. + * + * Copyright (c) 2013-2016, 2019-2020 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 +#include +#include +#include +#include +#include +#include + +#include "sfe.h" +#include "sfe_cm.h" + +/* + * By default Linux IP header and transport layer header structures are + * unpacked, assuming that such headers should be 32-bit aligned. + * Unfortunately some wireless adaptors can't cope with this requirement and + * some CPUs can't handle misaligned accesses. For those platforms we + * define SFE_IPV4_UNALIGNED_IP_HEADER and mark the structures as packed. + * When we do this the compiler will generate slightly worse code than for the + * aligned case (on most platforms) but will be much quicker than fixing + * things up in an unaligned trap handler. + */ +#define SFE_IPV4_UNALIGNED_IP_HEADER 1 +#if SFE_IPV4_UNALIGNED_IP_HEADER +#define SFE_IPV4_UNALIGNED_STRUCT __attribute__((packed)) +#else +#define SFE_IPV4_UNALIGNED_STRUCT +#endif + +/* + * An Ethernet header, but with an optional "packed" attribute to + * help with performance on some platforms (see the definition of + * SFE_IPV4_UNALIGNED_STRUCT) + */ +struct sfe_ipv4_eth_hdr { + __be16 h_dest[ETH_ALEN / 2]; + __be16 h_source[ETH_ALEN / 2]; + __be16 h_proto; +} SFE_IPV4_UNALIGNED_STRUCT; + +#define SFE_IPV4_DSCP_MASK 0x3 +#define SFE_IPV4_DSCP_SHIFT 2 + +/* + * An IPv4 header, but with an optional "packed" attribute to + * help with performance on some platforms (see the definition of + * SFE_IPV4_UNALIGNED_STRUCT) + */ +struct sfe_ipv4_ip_hdr { +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 ihl:4, + version:4; +#elif defined (__BIG_ENDIAN_BITFIELD) + __u8 version:4, + ihl:4; +#else +#error "Please fix " +#endif + __u8 tos; + __be16 tot_len; + __be16 id; + __be16 frag_off; + __u8 ttl; + __u8 protocol; + __sum16 check; + __be32 saddr; + __be32 daddr; + + /* + * The options start here. + */ +} SFE_IPV4_UNALIGNED_STRUCT; + +/* + * A UDP header, but with an optional "packed" attribute to + * help with performance on some platforms (see the definition of + * SFE_IPV4_UNALIGNED_STRUCT) + */ +struct sfe_ipv4_udp_hdr { + __be16 source; + __be16 dest; + __be16 len; + __sum16 check; +} SFE_IPV4_UNALIGNED_STRUCT; + +/* + * A TCP header, but with an optional "packed" attribute to + * help with performance on some platforms (see the definition of + * SFE_IPV4_UNALIGNED_STRUCT) + */ +struct sfe_ipv4_tcp_hdr { + __be16 source; + __be16 dest; + __be32 seq; + __be32 ack_seq; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u16 res1:4, + doff:4, + fin:1, + syn:1, + rst:1, + psh:1, + ack:1, + urg:1, + ece:1, + cwr:1; +#elif defined(__BIG_ENDIAN_BITFIELD) + __u16 doff:4, + res1:4, + cwr:1, + ece:1, + urg:1, + ack:1, + psh:1, + rst:1, + syn:1, + fin:1; +#else +#error "Adjust your defines" +#endif + __be16 window; + __sum16 check; + __be16 urg_ptr; +} SFE_IPV4_UNALIGNED_STRUCT; + +/* + * Specifies the lower bound on ACK numbers carried in the TCP header + */ +#define SFE_IPV4_TCP_MAX_ACK_WINDOW 65520 + +/* + * IPv4 TCP connection match additional data. + */ +struct sfe_ipv4_tcp_connection_match { + u8 win_scale; /* Window scale */ + u32 max_win; /* Maximum window size seen */ + u32 end; /* Sequence number of the next byte to send (seq + segment length) */ + u32 max_end; /* Sequence number of the last byte to ack */ +}; + +/* + * Bit flags for IPv4 connection matching entry. + */ +#define SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_SRC (1<<0) + /* Perform source translation */ +#define SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_DEST (1<<1) + /* Perform destination translation */ +#define SFE_IPV4_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK (1<<2) + /* Ignore TCP sequence numbers */ +#define SFE_IPV4_CONNECTION_MATCH_FLAG_WRITE_FAST_ETH_HDR (1<<3) + /* Fast Ethernet header write */ +#define SFE_IPV4_CONNECTION_MATCH_FLAG_WRITE_L2_HDR (1<<4) + /* Fast Ethernet header write */ +#define SFE_IPV4_CONNECTION_MATCH_FLAG_PRIORITY_REMARK (1<<5) + /* remark priority of SKB */ +#define SFE_IPV4_CONNECTION_MATCH_FLAG_DSCP_REMARK (1<<6) + /* remark DSCP of packet */ + +/* + * IPv4 connection matching structure. + */ +struct sfe_ipv4_connection_match { + /* + * References to other objects. + */ + struct sfe_ipv4_connection_match *next; + struct sfe_ipv4_connection_match *prev; + struct sfe_ipv4_connection *connection; + struct sfe_ipv4_connection_match *counter_match; + /* Matches the flow in the opposite direction as the one in *connection */ + struct sfe_ipv4_connection_match *active_next; + struct sfe_ipv4_connection_match *active_prev; + bool active; /* Flag to indicate if we're on the active list */ + + /* + * Characteristics that identify flows that match this rule. + */ + struct net_device *match_dev; /* Network device */ + u8 match_protocol; /* Protocol */ + __be32 match_src_ip; /* Source IP address */ + __be32 match_dest_ip; /* Destination IP address */ + __be16 match_src_port; /* Source port/connection ident */ + __be16 match_dest_port; /* Destination port/connection ident */ + + /* + * Control the operations of the match. + */ + u32 flags; /* Bit flags */ +#ifdef CONFIG_NF_FLOW_COOKIE + u32 flow_cookie; /* used flow cookie, for debug */ +#endif +#ifdef CONFIG_XFRM + u32 flow_accel; /* The flow accelerated or not */ +#endif + + /* + * Connection state that we track once we match. + */ + union { /* Protocol-specific state */ + struct sfe_ipv4_tcp_connection_match tcp; + } protocol_state; + /* + * Stats recorded in a sync period. These stats will be added to + * rx_packet_count64/rx_byte_count64 after a sync period. + */ + u32 rx_packet_count; + u32 rx_byte_count; + + /* + * Packet translation information. + */ + __be32 xlate_src_ip; /* Address after source translation */ + __be16 xlate_src_port; /* Port/connection ident after source translation */ + u16 xlate_src_csum_adjustment; + /* Transport layer checksum adjustment after source translation */ + u16 xlate_src_partial_csum_adjustment; + /* Transport layer pseudo header checksum adjustment after source translation */ + + __be32 xlate_dest_ip; /* Address after destination translation */ + __be16 xlate_dest_port; /* Port/connection ident after destination translation */ + u16 xlate_dest_csum_adjustment; + /* Transport layer checksum adjustment after destination translation */ + u16 xlate_dest_partial_csum_adjustment; + /* Transport layer pseudo header checksum adjustment after destination translation */ + + /* + * QoS information + */ + u32 priority; + u32 dscp; + + /* + * Packet transmit information. + */ + struct net_device *xmit_dev; /* Network device on which to transmit */ + unsigned short int xmit_dev_mtu; + /* Interface MTU */ + u16 xmit_dest_mac[ETH_ALEN / 2]; + /* Destination MAC address to use when forwarding */ + u16 xmit_src_mac[ETH_ALEN / 2]; + /* Source MAC address to use when forwarding */ + + /* + * Summary stats. + */ + u64 rx_packet_count64; + u64 rx_byte_count64; +}; + +/* + * Per-connection data structure. + */ +struct sfe_ipv4_connection { + struct sfe_ipv4_connection *next; + /* Pointer to the next entry in a hash chain */ + struct sfe_ipv4_connection *prev; + /* Pointer to the previous entry in a hash chain */ + int protocol; /* IP protocol number */ + __be32 src_ip; /* Src IP addr pre-translation */ + __be32 src_ip_xlate; /* Src IP addr post-translation */ + __be32 dest_ip; /* Dest IP addr pre-translation */ + __be32 dest_ip_xlate; /* Dest IP addr post-translation */ + __be16 src_port; /* Src port pre-translation */ + __be16 src_port_xlate; /* Src port post-translation */ + __be16 dest_port; /* Dest port pre-translation */ + __be16 dest_port_xlate; /* Dest port post-translation */ + struct sfe_ipv4_connection_match *original_match; + /* Original direction matching structure */ + struct net_device *original_dev; + /* Original direction source device */ + struct sfe_ipv4_connection_match *reply_match; + /* Reply direction matching structure */ + struct net_device *reply_dev; /* Reply direction source device */ + u64 last_sync_jiffies; /* Jiffies count for the last sync */ + struct sfe_ipv4_connection *all_connections_next; + /* Pointer to the next entry in the list of all connections */ + struct sfe_ipv4_connection *all_connections_prev; + /* Pointer to the previous entry in the list of all connections */ + u32 mark; /* mark for outgoing packet */ + u32 debug_read_seq; /* sequence number for debug dump */ +}; + +/* + * IPv4 connections and hash table size information. + */ +#define SFE_IPV4_CONNECTION_HASH_SHIFT 12 +#define SFE_IPV4_CONNECTION_HASH_SIZE (1 << SFE_IPV4_CONNECTION_HASH_SHIFT) +#define SFE_IPV4_CONNECTION_HASH_MASK (SFE_IPV4_CONNECTION_HASH_SIZE - 1) + +#ifdef CONFIG_NF_FLOW_COOKIE +#define SFE_FLOW_COOKIE_SIZE 2048 +#define SFE_FLOW_COOKIE_MASK 0x7ff + +struct sfe_flow_cookie_entry { + struct sfe_ipv4_connection_match *match; + unsigned long last_clean_time; +}; +#endif + +enum sfe_ipv4_exception_events { + SFE_IPV4_EXCEPTION_EVENT_UDP_HEADER_INCOMPLETE, + SFE_IPV4_EXCEPTION_EVENT_UDP_NO_CONNECTION, + SFE_IPV4_EXCEPTION_EVENT_UDP_IP_OPTIONS_OR_INITIAL_FRAGMENT, + SFE_IPV4_EXCEPTION_EVENT_UDP_SMALL_TTL, + SFE_IPV4_EXCEPTION_EVENT_UDP_NEEDS_FRAGMENTATION, + SFE_IPV4_EXCEPTION_EVENT_TCP_HEADER_INCOMPLETE, + SFE_IPV4_EXCEPTION_EVENT_TCP_NO_CONNECTION_SLOW_FLAGS, + SFE_IPV4_EXCEPTION_EVENT_TCP_NO_CONNECTION_FAST_FLAGS, + SFE_IPV4_EXCEPTION_EVENT_TCP_IP_OPTIONS_OR_INITIAL_FRAGMENT, + SFE_IPV4_EXCEPTION_EVENT_TCP_SMALL_TTL, + SFE_IPV4_EXCEPTION_EVENT_TCP_NEEDS_FRAGMENTATION, + SFE_IPV4_EXCEPTION_EVENT_TCP_FLAGS, + SFE_IPV4_EXCEPTION_EVENT_TCP_SEQ_EXCEEDS_RIGHT_EDGE, + SFE_IPV4_EXCEPTION_EVENT_TCP_SMALL_DATA_OFFS, + SFE_IPV4_EXCEPTION_EVENT_TCP_BAD_SACK, + SFE_IPV4_EXCEPTION_EVENT_TCP_BIG_DATA_OFFS, + SFE_IPV4_EXCEPTION_EVENT_TCP_SEQ_BEFORE_LEFT_EDGE, + SFE_IPV4_EXCEPTION_EVENT_TCP_ACK_EXCEEDS_RIGHT_EDGE, + SFE_IPV4_EXCEPTION_EVENT_TCP_ACK_BEFORE_LEFT_EDGE, + SFE_IPV4_EXCEPTION_EVENT_ICMP_HEADER_INCOMPLETE, + SFE_IPV4_EXCEPTION_EVENT_ICMP_UNHANDLED_TYPE, + SFE_IPV4_EXCEPTION_EVENT_ICMP_IPV4_HEADER_INCOMPLETE, + SFE_IPV4_EXCEPTION_EVENT_ICMP_IPV4_NON_V4, + SFE_IPV4_EXCEPTION_EVENT_ICMP_IPV4_IP_OPTIONS_INCOMPLETE, + SFE_IPV4_EXCEPTION_EVENT_ICMP_IPV4_UDP_HEADER_INCOMPLETE, + SFE_IPV4_EXCEPTION_EVENT_ICMP_IPV4_TCP_HEADER_INCOMPLETE, + SFE_IPV4_EXCEPTION_EVENT_ICMP_IPV4_UNHANDLED_PROTOCOL, + SFE_IPV4_EXCEPTION_EVENT_ICMP_NO_CONNECTION, + SFE_IPV4_EXCEPTION_EVENT_ICMP_FLUSHED_CONNECTION, + SFE_IPV4_EXCEPTION_EVENT_HEADER_INCOMPLETE, + SFE_IPV4_EXCEPTION_EVENT_BAD_TOTAL_LENGTH, + SFE_IPV4_EXCEPTION_EVENT_NON_V4, + SFE_IPV4_EXCEPTION_EVENT_NON_INITIAL_FRAGMENT, + SFE_IPV4_EXCEPTION_EVENT_DATAGRAM_INCOMPLETE, + SFE_IPV4_EXCEPTION_EVENT_IP_OPTIONS_INCOMPLETE, + SFE_IPV4_EXCEPTION_EVENT_UNHANDLED_PROTOCOL, + SFE_IPV4_EXCEPTION_EVENT_LAST +}; + +static char *sfe_ipv4_exception_events_string[SFE_IPV4_EXCEPTION_EVENT_LAST] = { + "UDP_HEADER_INCOMPLETE", + "UDP_NO_CONNECTION", + "UDP_IP_OPTIONS_OR_INITIAL_FRAGMENT", + "UDP_SMALL_TTL", + "UDP_NEEDS_FRAGMENTATION", + "TCP_HEADER_INCOMPLETE", + "TCP_NO_CONNECTION_SLOW_FLAGS", + "TCP_NO_CONNECTION_FAST_FLAGS", + "TCP_IP_OPTIONS_OR_INITIAL_FRAGMENT", + "TCP_SMALL_TTL", + "TCP_NEEDS_FRAGMENTATION", + "TCP_FLAGS", + "TCP_SEQ_EXCEEDS_RIGHT_EDGE", + "TCP_SMALL_DATA_OFFS", + "TCP_BAD_SACK", + "TCP_BIG_DATA_OFFS", + "TCP_SEQ_BEFORE_LEFT_EDGE", + "TCP_ACK_EXCEEDS_RIGHT_EDGE", + "TCP_ACK_BEFORE_LEFT_EDGE", + "ICMP_HEADER_INCOMPLETE", + "ICMP_UNHANDLED_TYPE", + "ICMP_IPV4_HEADER_INCOMPLETE", + "ICMP_IPV4_NON_V4", + "ICMP_IPV4_IP_OPTIONS_INCOMPLETE", + "ICMP_IPV4_UDP_HEADER_INCOMPLETE", + "ICMP_IPV4_TCP_HEADER_INCOMPLETE", + "ICMP_IPV4_UNHANDLED_PROTOCOL", + "ICMP_NO_CONNECTION", + "ICMP_FLUSHED_CONNECTION", + "HEADER_INCOMPLETE", + "BAD_TOTAL_LENGTH", + "NON_V4", + "NON_INITIAL_FRAGMENT", + "DATAGRAM_INCOMPLETE", + "IP_OPTIONS_INCOMPLETE", + "UNHANDLED_PROTOCOL" +}; + +/* + * Per-module structure. + */ +struct sfe_ipv4 { + spinlock_t lock; /* Lock for SMP correctness */ + struct sfe_ipv4_connection_match *active_head; + /* Head of the list of recently active connections */ + struct sfe_ipv4_connection_match *active_tail; + /* Tail of the list of recently active connections */ + struct sfe_ipv4_connection *all_connections_head; + /* Head of the list of all connections */ + struct sfe_ipv4_connection *all_connections_tail; + /* Tail of the list of all connections */ + unsigned int num_connections; /* Number of connections */ + struct timer_list timer; /* Timer used for periodic sync ops */ + sfe_sync_rule_callback_t __rcu sync_rule_callback; + /* Callback function registered by a connection manager for stats syncing */ + struct sfe_ipv4_connection *conn_hash[SFE_IPV4_CONNECTION_HASH_SIZE]; + /* Connection hash table */ + struct sfe_ipv4_connection_match *conn_match_hash[SFE_IPV4_CONNECTION_HASH_SIZE]; + /* Connection match hash table */ +#ifdef CONFIG_NF_FLOW_COOKIE + struct sfe_flow_cookie_entry sfe_flow_cookie_table[SFE_FLOW_COOKIE_SIZE]; + /* flow cookie table*/ + flow_cookie_set_func_t flow_cookie_set_func; + /* function used to configure flow cookie in hardware*/ + int flow_cookie_enable; + /* Enable/disable flow cookie at runtime */ +#endif + + /* + * Stats recorded in a sync period. These stats will be added to + * connection_xxx64 after a sync period. + */ + u32 connection_create_requests; + /* Number of IPv4 connection create requests */ + u32 connection_create_collisions; + /* Number of IPv4 connection create requests that collided with existing hash table entries */ + u32 connection_destroy_requests; + /* Number of IPv4 connection destroy requests */ + u32 connection_destroy_misses; + /* Number of IPv4 connection destroy requests that missed our hash table */ + u32 connection_match_hash_hits; + /* Number of IPv4 connection match hash hits */ + u32 connection_match_hash_reorders; + /* Number of IPv4 connection match hash reorders */ + u32 connection_flushes; /* Number of IPv4 connection flushes */ + u32 packets_forwarded; /* Number of IPv4 packets forwarded */ + u32 packets_not_forwarded; /* Number of IPv4 packets not forwarded */ + u32 exception_events[SFE_IPV4_EXCEPTION_EVENT_LAST]; + + /* + * Summary statistics. + */ + u64 connection_create_requests64; + /* Number of IPv4 connection create requests */ + u64 connection_create_collisions64; + /* Number of IPv4 connection create requests that collided with existing hash table entries */ + u64 connection_destroy_requests64; + /* Number of IPv4 connection destroy requests */ + u64 connection_destroy_misses64; + /* Number of IPv4 connection destroy requests that missed our hash table */ + u64 connection_match_hash_hits64; + /* Number of IPv4 connection match hash hits */ + u64 connection_match_hash_reorders64; + /* Number of IPv4 connection match hash reorders */ + u64 connection_flushes64; /* Number of IPv4 connection flushes */ + u64 packets_forwarded64; /* Number of IPv4 packets forwarded */ + u64 packets_not_forwarded64; + /* Number of IPv4 packets not forwarded */ + u64 exception_events64[SFE_IPV4_EXCEPTION_EVENT_LAST]; + + /* + * Control state. + */ + struct kobject *sys_sfe_ipv4; /* sysfs linkage */ + int debug_dev; /* Major number of the debug char device */ + u32 debug_read_seq; /* sequence number for debug dump */ +}; + +/* + * Enumeration of the XML output. + */ +enum sfe_ipv4_debug_xml_states { + SFE_IPV4_DEBUG_XML_STATE_START, + SFE_IPV4_DEBUG_XML_STATE_CONNECTIONS_START, + SFE_IPV4_DEBUG_XML_STATE_CONNECTIONS_CONNECTION, + SFE_IPV4_DEBUG_XML_STATE_CONNECTIONS_END, + SFE_IPV4_DEBUG_XML_STATE_EXCEPTIONS_START, + SFE_IPV4_DEBUG_XML_STATE_EXCEPTIONS_EXCEPTION, + SFE_IPV4_DEBUG_XML_STATE_EXCEPTIONS_END, + SFE_IPV4_DEBUG_XML_STATE_STATS, + SFE_IPV4_DEBUG_XML_STATE_END, + SFE_IPV4_DEBUG_XML_STATE_DONE +}; + +/* + * XML write state. + */ +struct sfe_ipv4_debug_xml_write_state { + enum sfe_ipv4_debug_xml_states state; + /* XML output file state machine state */ + int iter_exception; /* Next exception iterator */ +}; + +typedef bool (*sfe_ipv4_debug_xml_write_method_t)(struct sfe_ipv4 *si, char *buffer, char *msg, size_t *length, + int *total_read, struct sfe_ipv4_debug_xml_write_state *ws); + +static struct sfe_ipv4 __si; + +/* + * sfe_ipv4_gen_ip_csum() + * Generate the IP checksum for an IPv4 header. + * + * Note that this function assumes that we have only 20 bytes of IP header. + */ +static inline u16 sfe_ipv4_gen_ip_csum(struct sfe_ipv4_ip_hdr *iph) +{ + u32 sum; + u16 *i = (u16 *)iph; + + iph->check = 0; + + /* + * Generate the sum. + */ + sum = i[0] + i[1] + i[2] + i[3] + i[4] + i[5] + i[6] + i[7] + i[8] + i[9]; + + /* + * Fold it to ones-complement form. + */ + sum = (sum & 0xffff) + (sum >> 16); + sum = (sum & 0xffff) + (sum >> 16); + + return (u16)sum ^ 0xffff; +} + +/* + * sfe_ipv4_get_connection_match_hash() + * Generate the hash used in connection match lookups. + */ +static inline unsigned int sfe_ipv4_get_connection_match_hash(struct net_device *dev, u8 protocol, + __be32 src_ip, __be16 src_port, + __be32 dest_ip, __be16 dest_port) +{ + size_t dev_addr = (size_t)dev; + u32 hash = ((u32)dev_addr) ^ ntohl(src_ip ^ dest_ip) ^ protocol ^ ntohs(src_port ^ dest_port); + return ((hash >> SFE_IPV4_CONNECTION_HASH_SHIFT) ^ hash) & SFE_IPV4_CONNECTION_HASH_MASK; +} + +/* + * sfe_ipv4_find_sfe_ipv4_connection_match() + * Get the IPv4 flow match info that corresponds to a particular 5-tuple. + * + * On entry we must be holding the lock that protects the hash table. + */ +static struct sfe_ipv4_connection_match * +sfe_ipv4_find_sfe_ipv4_connection_match(struct sfe_ipv4 *si, struct net_device *dev, u8 protocol, + __be32 src_ip, __be16 src_port, + __be32 dest_ip, __be16 dest_port) +{ + struct sfe_ipv4_connection_match *cm; + struct sfe_ipv4_connection_match *head; + unsigned int conn_match_idx; + + conn_match_idx = sfe_ipv4_get_connection_match_hash(dev, protocol, src_ip, src_port, dest_ip, dest_port); + cm = si->conn_match_hash[conn_match_idx]; + + /* + * If we don't have anything in this chain then bail. + */ + if (unlikely(!cm)) { + return NULL; + } + + /* + * Hopefully the first entry is the one we want. + */ + if ((cm->match_src_port == src_port) + && (cm->match_dest_port == dest_port) + && (cm->match_src_ip == src_ip) + && (cm->match_dest_ip == dest_ip) + && (cm->match_protocol == protocol) + && (cm->match_dev == dev)) { + si->connection_match_hash_hits++; + return cm; + } + + /* + * Unfortunately we didn't find it at head, so we search it in chain and + * move matching entry to the top of the hash chain. We presume that this + * will be reused again very quickly. + */ + head = cm; + do { + cm = cm->next; + } while (cm && (cm->match_src_port != src_port + || cm->match_dest_port != dest_port + || cm->match_src_ip != src_ip + || cm->match_dest_ip != dest_ip + || cm->match_protocol != protocol + || cm->match_dev != dev)); + + /* + * Not found then we're done. + */ + if (unlikely(!cm)) { + return NULL; + } + + /* + * We found a match so move it. + */ + if (cm->next) { + cm->next->prev = cm->prev; + } + cm->prev->next = cm->next; + cm->prev = NULL; + cm->next = head; + head->prev = cm; + si->conn_match_hash[conn_match_idx] = cm; + si->connection_match_hash_reorders++; + + return cm; +} + +/* + * sfe_ipv4_connection_match_update_summary_stats() + * Update the summary stats for a connection match entry. + */ +static inline void sfe_ipv4_connection_match_update_summary_stats(struct sfe_ipv4_connection_match *cm) +{ + cm->rx_packet_count64 += cm->rx_packet_count; + cm->rx_packet_count = 0; + cm->rx_byte_count64 += cm->rx_byte_count; + cm->rx_byte_count = 0; +} + +/* + * sfe_ipv4_connection_match_compute_translations() + * Compute port and address translations for a connection match entry. + */ +static void sfe_ipv4_connection_match_compute_translations(struct sfe_ipv4_connection_match *cm) +{ + /* + * Before we insert the entry look to see if this is tagged as doing address + * translations. If it is then work out the adjustment that we need to apply + * to the transport checksum. + */ + if (cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_SRC) { + /* + * Precompute an incremental checksum adjustment so we can + * edit packets in this stream very quickly. The algorithm is from RFC1624. + */ + u16 src_ip_hi = cm->match_src_ip >> 16; + u16 src_ip_lo = cm->match_src_ip & 0xffff; + u32 xlate_src_ip = ~cm->xlate_src_ip; + u16 xlate_src_ip_hi = xlate_src_ip >> 16; + u16 xlate_src_ip_lo = xlate_src_ip & 0xffff; + u16 xlate_src_port = ~cm->xlate_src_port; + u32 adj; + + /* + * When we compute this fold it down to a 16-bit offset + * as that way we can avoid having to do a double + * folding of the twos-complement result because the + * addition of 2 16-bit values cannot cause a double + * wrap-around! + */ + adj = src_ip_hi + src_ip_lo + cm->match_src_port + + xlate_src_ip_hi + xlate_src_ip_lo + xlate_src_port; + adj = (adj & 0xffff) + (adj >> 16); + adj = (adj & 0xffff) + (adj >> 16); + cm->xlate_src_csum_adjustment = (u16)adj; + + } + + if (cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_DEST) { + /* + * Precompute an incremental checksum adjustment so we can + * edit packets in this stream very quickly. The algorithm is from RFC1624. + */ + u16 dest_ip_hi = cm->match_dest_ip >> 16; + u16 dest_ip_lo = cm->match_dest_ip & 0xffff; + u32 xlate_dest_ip = ~cm->xlate_dest_ip; + u16 xlate_dest_ip_hi = xlate_dest_ip >> 16; + u16 xlate_dest_ip_lo = xlate_dest_ip & 0xffff; + u16 xlate_dest_port = ~cm->xlate_dest_port; + u32 adj; + + /* + * When we compute this fold it down to a 16-bit offset + * as that way we can avoid having to do a double + * folding of the twos-complement result because the + * addition of 2 16-bit values cannot cause a double + * wrap-around! + */ + adj = dest_ip_hi + dest_ip_lo + cm->match_dest_port + + xlate_dest_ip_hi + xlate_dest_ip_lo + xlate_dest_port; + adj = (adj & 0xffff) + (adj >> 16); + adj = (adj & 0xffff) + (adj >> 16); + cm->xlate_dest_csum_adjustment = (u16)adj; + } + + if (cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_SRC) { + u32 adj = ~cm->match_src_ip + cm->xlate_src_ip; + if (adj < cm->xlate_src_ip) { + adj++; + } + + adj = (adj & 0xffff) + (adj >> 16); + adj = (adj & 0xffff) + (adj >> 16); + cm->xlate_src_partial_csum_adjustment = (u16)adj; + } + + if (cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_DEST) { + u32 adj = ~cm->match_dest_ip + cm->xlate_dest_ip; + if (adj < cm->xlate_dest_ip) { + adj++; + } + + adj = (adj & 0xffff) + (adj >> 16); + adj = (adj & 0xffff) + (adj >> 16); + cm->xlate_dest_partial_csum_adjustment = (u16)adj; + } + +} + +/* + * sfe_ipv4_update_summary_stats() + * Update the summary stats. + */ +static void sfe_ipv4_update_summary_stats(struct sfe_ipv4 *si) +{ + int i; + + si->connection_create_requests64 += si->connection_create_requests; + si->connection_create_requests = 0; + si->connection_create_collisions64 += si->connection_create_collisions; + si->connection_create_collisions = 0; + si->connection_destroy_requests64 += si->connection_destroy_requests; + si->connection_destroy_requests = 0; + si->connection_destroy_misses64 += si->connection_destroy_misses; + si->connection_destroy_misses = 0; + si->connection_match_hash_hits64 += si->connection_match_hash_hits; + si->connection_match_hash_hits = 0; + si->connection_match_hash_reorders64 += si->connection_match_hash_reorders; + si->connection_match_hash_reorders = 0; + si->connection_flushes64 += si->connection_flushes; + si->connection_flushes = 0; + si->packets_forwarded64 += si->packets_forwarded; + si->packets_forwarded = 0; + si->packets_not_forwarded64 += si->packets_not_forwarded; + si->packets_not_forwarded = 0; + + for (i = 0; i < SFE_IPV4_EXCEPTION_EVENT_LAST; i++) { + si->exception_events64[i] += si->exception_events[i]; + si->exception_events[i] = 0; + } +} + +/* + * sfe_ipv4_insert_sfe_ipv4_connection_match() + * Insert a connection match into the hash. + * + * On entry we must be holding the lock that protects the hash table. + */ +static inline void sfe_ipv4_insert_sfe_ipv4_connection_match(struct sfe_ipv4 *si, + struct sfe_ipv4_connection_match *cm) +{ + struct sfe_ipv4_connection_match **hash_head; + struct sfe_ipv4_connection_match *prev_head; + unsigned int conn_match_idx + = sfe_ipv4_get_connection_match_hash(cm->match_dev, cm->match_protocol, + cm->match_src_ip, cm->match_src_port, + cm->match_dest_ip, cm->match_dest_port); + + hash_head = &si->conn_match_hash[conn_match_idx]; + prev_head = *hash_head; + cm->prev = NULL; + if (prev_head) { + prev_head->prev = cm; + } + + cm->next = prev_head; + *hash_head = cm; + +#ifdef CONFIG_NF_FLOW_COOKIE + if (!si->flow_cookie_enable) + return; + + /* + * Configure hardware to put a flow cookie in packet of this flow, + * then we can accelerate the lookup process when we received this packet. + */ + for (conn_match_idx = 1; conn_match_idx < SFE_FLOW_COOKIE_SIZE; conn_match_idx++) { + struct sfe_flow_cookie_entry *entry = &si->sfe_flow_cookie_table[conn_match_idx]; + + if ((NULL == entry->match) && time_is_before_jiffies(entry->last_clean_time + HZ)) { + flow_cookie_set_func_t func; + + rcu_read_lock(); + func = rcu_dereference(si->flow_cookie_set_func); + if (func) { + if (!func(cm->match_protocol, cm->match_src_ip, cm->match_src_port, + cm->match_dest_ip, cm->match_dest_port, conn_match_idx)) { + entry->match = cm; + cm->flow_cookie = conn_match_idx; + } + } + rcu_read_unlock(); + + break; + } + } +#endif +} + +/* + * sfe_ipv4_remove_sfe_ipv4_connection_match() + * Remove a connection match object from the hash. + * + * On entry we must be holding the lock that protects the hash table. + */ +static inline void sfe_ipv4_remove_sfe_ipv4_connection_match(struct sfe_ipv4 *si, struct sfe_ipv4_connection_match *cm) +{ +#ifdef CONFIG_NF_FLOW_COOKIE + if (si->flow_cookie_enable) { + /* + * Tell hardware that we no longer need a flow cookie in packet of this flow + */ + unsigned int conn_match_idx; + + for (conn_match_idx = 1; conn_match_idx < SFE_FLOW_COOKIE_SIZE; conn_match_idx++) { + struct sfe_flow_cookie_entry *entry = &si->sfe_flow_cookie_table[conn_match_idx]; + + if (cm == entry->match) { + flow_cookie_set_func_t func; + + rcu_read_lock(); + func = rcu_dereference(si->flow_cookie_set_func); + if (func) { + func(cm->match_protocol, cm->match_src_ip, cm->match_src_port, + cm->match_dest_ip, cm->match_dest_port, 0); + } + rcu_read_unlock(); + + cm->flow_cookie = 0; + entry->match = NULL; + entry->last_clean_time = jiffies; + break; + } + } + } +#endif + + /* + * Unlink the connection match entry from the hash. + */ + if (cm->prev) { + cm->prev->next = cm->next; + } else { + unsigned int conn_match_idx + = sfe_ipv4_get_connection_match_hash(cm->match_dev, cm->match_protocol, + cm->match_src_ip, cm->match_src_port, + cm->match_dest_ip, cm->match_dest_port); + si->conn_match_hash[conn_match_idx] = cm->next; + } + + if (cm->next) { + cm->next->prev = cm->prev; + } + + /* + * If the connection match entry is in the active list remove it. + */ + if (cm->active) { + if (likely(cm->active_prev)) { + cm->active_prev->active_next = cm->active_next; + } else { + si->active_head = cm->active_next; + } + + if (likely(cm->active_next)) { + cm->active_next->active_prev = cm->active_prev; + } else { + si->active_tail = cm->active_prev; + } + } +} + +/* + * sfe_ipv4_get_connection_hash() + * Generate the hash used in connection lookups. + */ +static inline unsigned int sfe_ipv4_get_connection_hash(u8 protocol, __be32 src_ip, __be16 src_port, + __be32 dest_ip, __be16 dest_port) +{ + u32 hash = ntohl(src_ip ^ dest_ip) ^ protocol ^ ntohs(src_port ^ dest_port); + return ((hash >> SFE_IPV4_CONNECTION_HASH_SHIFT) ^ hash) & SFE_IPV4_CONNECTION_HASH_MASK; +} + +/* + * sfe_ipv4_find_sfe_ipv4_connection() + * Get the IPv4 connection info that corresponds to a particular 5-tuple. + * + * On entry we must be holding the lock that protects the hash table. + */ +static inline struct sfe_ipv4_connection *sfe_ipv4_find_sfe_ipv4_connection(struct sfe_ipv4 *si, u32 protocol, + __be32 src_ip, __be16 src_port, + __be32 dest_ip, __be16 dest_port) +{ + struct sfe_ipv4_connection *c; + unsigned int conn_idx = sfe_ipv4_get_connection_hash(protocol, src_ip, src_port, dest_ip, dest_port); + c = si->conn_hash[conn_idx]; + + /* + * If we don't have anything in this chain then bale. + */ + if (unlikely(!c)) { + return NULL; + } + + /* + * Hopefully the first entry is the one we want. + */ + if ((c->src_port == src_port) + && (c->dest_port == dest_port) + && (c->src_ip == src_ip) + && (c->dest_ip == dest_ip) + && (c->protocol == protocol)) { + return c; + } + + /* + * Unfortunately we didn't find it at head, so we search it in chain. + */ + do { + c = c->next; + } while (c && (c->src_port != src_port + || c->dest_port != dest_port + || c->src_ip != src_ip + || c->dest_ip != dest_ip + || c->protocol != protocol)); + + /* + * Will need connection entry for next create/destroy metadata, + * So no need to re-order entry for these requests + */ + return c; +} + +/* + * sfe_ipv4_mark_rule() + * Updates the mark for a current offloaded connection + * + * Will take hash lock upon entry + */ +void sfe_ipv4_mark_rule(struct sfe_connection_mark *mark) +{ + struct sfe_ipv4 *si = &__si; + struct sfe_ipv4_connection *c; + + spin_lock_bh(&si->lock); + c = sfe_ipv4_find_sfe_ipv4_connection(si, mark->protocol, + mark->src_ip.ip, mark->src_port, + mark->dest_ip.ip, mark->dest_port); + if (c) { + WARN_ON((0 != c->mark) && (0 == mark->mark)); + c->mark = mark->mark; + } + spin_unlock_bh(&si->lock); + + if (c) { + DEBUG_TRACE("Matching connection found for mark, " + "setting from %08x to %08x\n", + c->mark, mark->mark); + } +} + +/* + * sfe_ipv4_insert_sfe_ipv4_connection() + * Insert a connection into the hash. + * + * On entry we must be holding the lock that protects the hash table. + */ +static void sfe_ipv4_insert_sfe_ipv4_connection(struct sfe_ipv4 *si, struct sfe_ipv4_connection *c) +{ + struct sfe_ipv4_connection **hash_head; + struct sfe_ipv4_connection *prev_head; + unsigned int conn_idx; + + /* + * Insert entry into the connection hash. + */ + conn_idx = sfe_ipv4_get_connection_hash(c->protocol, c->src_ip, c->src_port, + c->dest_ip, c->dest_port); + hash_head = &si->conn_hash[conn_idx]; + prev_head = *hash_head; + c->prev = NULL; + if (prev_head) { + prev_head->prev = c; + } + + c->next = prev_head; + *hash_head = c; + + /* + * Insert entry into the "all connections" list. + */ + if (si->all_connections_tail) { + c->all_connections_prev = si->all_connections_tail; + si->all_connections_tail->all_connections_next = c; + } else { + c->all_connections_prev = NULL; + si->all_connections_head = c; + } + + si->all_connections_tail = c; + c->all_connections_next = NULL; + si->num_connections++; + + /* + * Insert the connection match objects too. + */ + sfe_ipv4_insert_sfe_ipv4_connection_match(si, c->original_match); + sfe_ipv4_insert_sfe_ipv4_connection_match(si, c->reply_match); +} + +/* + * sfe_ipv4_remove_sfe_ipv4_connection() + * Remove a sfe_ipv4_connection object from the hash. + * + * On entry we must be holding the lock that protects the hash table. + */ +static void sfe_ipv4_remove_sfe_ipv4_connection(struct sfe_ipv4 *si, struct sfe_ipv4_connection *c) +{ + /* + * Remove the connection match objects. + */ + sfe_ipv4_remove_sfe_ipv4_connection_match(si, c->reply_match); + sfe_ipv4_remove_sfe_ipv4_connection_match(si, c->original_match); + + /* + * Unlink the connection. + */ + if (c->prev) { + c->prev->next = c->next; + } else { + unsigned int conn_idx = sfe_ipv4_get_connection_hash(c->protocol, c->src_ip, c->src_port, + c->dest_ip, c->dest_port); + si->conn_hash[conn_idx] = c->next; + } + + if (c->next) { + c->next->prev = c->prev; + } + + /* + * Unlink connection from all_connections list + */ + if (c->all_connections_prev) { + c->all_connections_prev->all_connections_next = c->all_connections_next; + } else { + si->all_connections_head = c->all_connections_next; + } + + if (c->all_connections_next) { + c->all_connections_next->all_connections_prev = c->all_connections_prev; + } else { + si->all_connections_tail = c->all_connections_prev; + } + + si->num_connections--; +} + +/* + * sfe_ipv4_sync_sfe_ipv4_connection() + * Sync a connection. + * + * On entry to this function we expect that the lock for the connection is either + * already held or isn't required. + */ +static void sfe_ipv4_gen_sync_sfe_ipv4_connection(struct sfe_ipv4 *si, struct sfe_ipv4_connection *c, + struct sfe_connection_sync *sis, sfe_sync_reason_t reason, + u64 now_jiffies) +{ + struct sfe_ipv4_connection_match *original_cm; + struct sfe_ipv4_connection_match *reply_cm; + + /* + * Fill in the update message. + */ + sis->is_v6 = 0; + sis->protocol = c->protocol; + sis->src_ip.ip = c->src_ip; + sis->src_ip_xlate.ip = c->src_ip_xlate; + sis->dest_ip.ip = c->dest_ip; + sis->dest_ip_xlate.ip = c->dest_ip_xlate; + sis->src_port = c->src_port; + sis->src_port_xlate = c->src_port_xlate; + sis->dest_port = c->dest_port; + sis->dest_port_xlate = c->dest_port_xlate; + + original_cm = c->original_match; + reply_cm = c->reply_match; + sis->src_td_max_window = original_cm->protocol_state.tcp.max_win; + sis->src_td_end = original_cm->protocol_state.tcp.end; + sis->src_td_max_end = original_cm->protocol_state.tcp.max_end; + sis->dest_td_max_window = reply_cm->protocol_state.tcp.max_win; + sis->dest_td_end = reply_cm->protocol_state.tcp.end; + sis->dest_td_max_end = reply_cm->protocol_state.tcp.max_end; + + sis->src_new_packet_count = original_cm->rx_packet_count; + sis->src_new_byte_count = original_cm->rx_byte_count; + sis->dest_new_packet_count = reply_cm->rx_packet_count; + sis->dest_new_byte_count = reply_cm->rx_byte_count; + + sfe_ipv4_connection_match_update_summary_stats(original_cm); + sfe_ipv4_connection_match_update_summary_stats(reply_cm); + + sis->src_dev = original_cm->match_dev; + sis->src_packet_count = original_cm->rx_packet_count64; + sis->src_byte_count = original_cm->rx_byte_count64; + + sis->dest_dev = reply_cm->match_dev; + sis->dest_packet_count = reply_cm->rx_packet_count64; + sis->dest_byte_count = reply_cm->rx_byte_count64; + + sis->reason = reason; + + /* + * Get the time increment since our last sync. + */ + sis->delta_jiffies = now_jiffies - c->last_sync_jiffies; + c->last_sync_jiffies = now_jiffies; +} + +/* + * sfe_ipv4_flush_sfe_ipv4_connection() + * Flush a connection and free all associated resources. + * + * We need to be called with bottom halves disabled locally as we need to acquire + * the connection hash lock and release it again. In general we're actually called + * from within a BH and so we're fine, but we're also called when connections are + * torn down. + */ +static void sfe_ipv4_flush_sfe_ipv4_connection(struct sfe_ipv4 *si, + struct sfe_ipv4_connection *c, + sfe_sync_reason_t reason) +{ + struct sfe_connection_sync sis; + u64 now_jiffies; + sfe_sync_rule_callback_t sync_rule_callback; + + rcu_read_lock(); + spin_lock_bh(&si->lock); + si->connection_flushes++; + sync_rule_callback = rcu_dereference(si->sync_rule_callback); + spin_unlock_bh(&si->lock); + + if (sync_rule_callback) { + /* + * Generate a sync message and then sync. + */ + now_jiffies = get_jiffies_64(); + sfe_ipv4_gen_sync_sfe_ipv4_connection(si, c, &sis, reason, now_jiffies); + sync_rule_callback(&sis); + } + + rcu_read_unlock(); + + /* + * Release our hold of the source and dest devices and free the memory + * for our connection objects. + */ + dev_put(c->original_dev); + dev_put(c->reply_dev); + kfree(c->original_match); + kfree(c->reply_match); + kfree(c); +} + +/* + * sfe_ipv4_recv_udp() + * Handle UDP packet receives and forwarding. + */ +static int sfe_ipv4_recv_udp(struct sfe_ipv4 *si, struct sk_buff *skb, struct net_device *dev, + unsigned int len, struct sfe_ipv4_ip_hdr *iph, unsigned int ihl, bool flush_on_find) +{ + struct sfe_ipv4_udp_hdr *udph; + __be32 src_ip; + __be32 dest_ip; + __be16 src_port; + __be16 dest_port; + struct sfe_ipv4_connection_match *cm; + u8 ttl; + struct net_device *xmit_dev; + + /* + * Is our packet too short to contain a valid UDP header? + */ + if (unlikely(!pskb_may_pull(skb, (sizeof(struct sfe_ipv4_udp_hdr) + ihl)))) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_UDP_HEADER_INCOMPLETE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("packet too short for UDP header\n"); + return 0; + } + + /* + * Read the IP address and port information. Read the IP header data first + * because we've almost certainly got that in the cache. We may not yet have + * the UDP header cached though so allow more time for any prefetching. + */ + src_ip = iph->saddr; + dest_ip = iph->daddr; + + udph = (struct sfe_ipv4_udp_hdr *)(skb->data + ihl); + src_port = udph->source; + dest_port = udph->dest; + + spin_lock_bh(&si->lock); + + /* + * Look for a connection match. + */ +#ifdef CONFIG_NF_FLOW_COOKIE + cm = si->sfe_flow_cookie_table[skb->flow_cookie & SFE_FLOW_COOKIE_MASK].match; + if (unlikely(!cm)) { + cm = sfe_ipv4_find_sfe_ipv4_connection_match(si, dev, IPPROTO_UDP, src_ip, src_port, dest_ip, dest_port); + } +#else + cm = sfe_ipv4_find_sfe_ipv4_connection_match(si, dev, IPPROTO_UDP, src_ip, src_port, dest_ip, dest_port); +#endif + if (unlikely(!cm)) { + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_UDP_NO_CONNECTION]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("no connection found\n"); + return 0; + } + + /* + * If our packet has beern marked as "flush on find" we can't actually + * forward it in the fast path, but now that we've found an associated + * connection we can flush that out before we process the packet. + */ + if (unlikely(flush_on_find)) { + struct sfe_ipv4_connection *c = cm->connection; + sfe_ipv4_remove_sfe_ipv4_connection(si, c); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_UDP_IP_OPTIONS_OR_INITIAL_FRAGMENT]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("flush on find\n"); + sfe_ipv4_flush_sfe_ipv4_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + +#ifdef CONFIG_XFRM + /* + * We can't accelerate the flow on this direction, just let it go + * through the slow path. + */ + if (unlikely(!cm->flow_accel)) { + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + return 0; + } +#endif + + /* + * Does our TTL allow forwarding? + */ + ttl = iph->ttl; + if (unlikely(ttl < 2)) { + struct sfe_ipv4_connection *c = cm->connection; + sfe_ipv4_remove_sfe_ipv4_connection(si, c); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_UDP_SMALL_TTL]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("ttl too low\n"); + sfe_ipv4_flush_sfe_ipv4_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + /* + * If our packet is larger than the MTU of the transmit interface then + * we can't forward it easily. + */ + if (unlikely(len > cm->xmit_dev_mtu)) { + struct sfe_ipv4_connection *c = cm->connection; + sfe_ipv4_remove_sfe_ipv4_connection(si, c); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_UDP_NEEDS_FRAGMENTATION]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("larger than mtu\n"); + sfe_ipv4_flush_sfe_ipv4_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + /* + * From this point on we're good to modify the packet. + */ + + /* + * Check if skb was cloned. If it was, unshare it. Because + * the data area is going to be written in this path and we don't want to + * change the cloned skb's data section. + */ + if (unlikely(skb_cloned(skb))) { + DEBUG_TRACE("%px: skb is a cloned skb\n", skb); + skb = skb_unshare(skb, GFP_ATOMIC); + if (!skb) { + DEBUG_WARN("Failed to unshare the cloned skb\n"); + return 0; + } + + /* + * Update the iph and udph pointers with the unshared skb's data area. + */ + iph = (struct sfe_ipv4_ip_hdr *)skb->data; + udph = (struct sfe_ipv4_udp_hdr *)(skb->data + ihl); + } + + /* + * Update DSCP + */ + if (unlikely(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_DSCP_REMARK)) { + iph->tos = (iph->tos & SFE_IPV4_DSCP_MASK) | cm->dscp; + } + + /* + * Decrement our TTL. + */ + iph->ttl = ttl - 1; + + /* + * Do we have to perform translations of the source address/port? + */ + if (unlikely(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_SRC)) { + u16 udp_csum; + + iph->saddr = cm->xlate_src_ip; + udph->source = cm->xlate_src_port; + + /* + * Do we have a non-zero UDP checksum? If we do then we need + * to update it. + */ + udp_csum = udph->check; + if (likely(udp_csum)) { + u32 sum; + + if (unlikely(skb->ip_summed == CHECKSUM_PARTIAL)) { + sum = udp_csum + cm->xlate_src_partial_csum_adjustment; + } else { + sum = udp_csum + cm->xlate_src_csum_adjustment; + } + + sum = (sum & 0xffff) + (sum >> 16); + udph->check = (u16)sum; + } + } + + /* + * Do we have to perform translations of the destination address/port? + */ + if (unlikely(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_DEST)) { + u16 udp_csum; + + iph->daddr = cm->xlate_dest_ip; + udph->dest = cm->xlate_dest_port; + + /* + * Do we have a non-zero UDP checksum? If we do then we need + * to update it. + */ + udp_csum = udph->check; + if (likely(udp_csum)) { + u32 sum; + + if (unlikely(skb->ip_summed == CHECKSUM_PARTIAL)) { + sum = udp_csum + cm->xlate_dest_partial_csum_adjustment; + } else { + sum = udp_csum + cm->xlate_dest_csum_adjustment; + } + + sum = (sum & 0xffff) + (sum >> 16); + udph->check = (u16)sum; + } + } + + /* + * Replace the IP checksum. + */ + iph->check = sfe_ipv4_gen_ip_csum(iph); + + /* + * Update traffic stats. + */ + cm->rx_packet_count++; + cm->rx_byte_count += len; + + /* + * If we're not already on the active list then insert ourselves at the tail + * of the current list. + */ + if (unlikely(!cm->active)) { + cm->active = true; + cm->active_prev = si->active_tail; + if (likely(si->active_tail)) { + si->active_tail->active_next = cm; + } else { + si->active_head = cm; + } + si->active_tail = cm; + } + + xmit_dev = cm->xmit_dev; + skb->dev = xmit_dev; + + /* + * Check to see if we need to write a header. + */ + if (likely(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_WRITE_L2_HDR)) { + if (unlikely(!(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_WRITE_FAST_ETH_HDR))) { + dev_hard_header(skb, xmit_dev, ETH_P_IP, + cm->xmit_dest_mac, cm->xmit_src_mac, len); + } else { + /* + * For the simple case we write this really fast. + */ + struct sfe_ipv4_eth_hdr *eth = (struct sfe_ipv4_eth_hdr *)__skb_push(skb, ETH_HLEN); + eth->h_proto = htons(ETH_P_IP); + eth->h_dest[0] = cm->xmit_dest_mac[0]; + eth->h_dest[1] = cm->xmit_dest_mac[1]; + eth->h_dest[2] = cm->xmit_dest_mac[2]; + eth->h_source[0] = cm->xmit_src_mac[0]; + eth->h_source[1] = cm->xmit_src_mac[1]; + eth->h_source[2] = cm->xmit_src_mac[2]; + } + } + + /* + * Update priority of skb. + */ + if (unlikely(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_PRIORITY_REMARK)) { + skb->priority = cm->priority; + } + + /* + * Mark outgoing packet. + */ + skb->mark = cm->connection->mark; + if (skb->mark) { + DEBUG_TRACE("SKB MARK is NON ZERO %x\n", skb->mark); + } + + si->packets_forwarded++; + spin_unlock_bh(&si->lock); + + /* + * We're going to check for GSO flags when we transmit the packet so + * start fetching the necessary cache line now. + */ + prefetch(skb_shinfo(skb)); + + /* + * Mark that this packet has been fast forwarded. + */ + skb->fast_forwarded = 1; + + /* + * Send the packet on its way. + */ + dev_queue_xmit(skb); + + return 1; +} + +/* + * sfe_ipv4_process_tcp_option_sack() + * Parse TCP SACK option and update ack according + */ +static bool sfe_ipv4_process_tcp_option_sack(const struct sfe_ipv4_tcp_hdr *th, const u32 data_offs, + u32 *ack) +{ + u32 length = sizeof(struct sfe_ipv4_tcp_hdr); + u8 *ptr = (u8 *)th + length; + + /* + * Ignore processing if TCP packet has only TIMESTAMP option. + */ + if (likely(data_offs == length + TCPOLEN_TIMESTAMP + 1 + 1) + && likely(ptr[0] == TCPOPT_NOP) + && likely(ptr[1] == TCPOPT_NOP) + && likely(ptr[2] == TCPOPT_TIMESTAMP) + && likely(ptr[3] == TCPOLEN_TIMESTAMP)) { + return true; + } + + /* + * TCP options. Parse SACK option. + */ + while (length < data_offs) { + u8 size; + u8 kind; + + ptr = (u8 *)th + length; + kind = *ptr; + + /* + * NOP, for padding + * Not in the switch because to fast escape and to not calculate size + */ + if (kind == TCPOPT_NOP) { + length++; + continue; + } + + if (kind == TCPOPT_SACK) { + u32 sack = 0; + u8 re = 1 + 1; + + size = *(ptr + 1); + if ((size < (1 + 1 + TCPOLEN_SACK_PERBLOCK)) + || ((size - (1 + 1)) % (TCPOLEN_SACK_PERBLOCK)) + || (size > (data_offs - length))) { + return false; + } + + re += 4; + while (re < size) { + u32 sack_re; + u8 *sptr = ptr + re; + sack_re = (sptr[0] << 24) | (sptr[1] << 16) | (sptr[2] << 8) | sptr[3]; + if (sack_re > sack) { + sack = sack_re; + } + re += TCPOLEN_SACK_PERBLOCK; + } + if (sack > *ack) { + *ack = sack; + } + length += size; + continue; + } + if (kind == TCPOPT_EOL) { + return true; + } + size = *(ptr + 1); + if (size < 2) { + return false; + } + length += size; + } + + return true; +} + +/* + * sfe_ipv4_recv_tcp() + * Handle TCP packet receives and forwarding. + */ +static int sfe_ipv4_recv_tcp(struct sfe_ipv4 *si, struct sk_buff *skb, struct net_device *dev, + unsigned int len, struct sfe_ipv4_ip_hdr *iph, unsigned int ihl, bool flush_on_find) +{ + struct sfe_ipv4_tcp_hdr *tcph; + __be32 src_ip; + __be32 dest_ip; + __be16 src_port; + __be16 dest_port; + struct sfe_ipv4_connection_match *cm; + struct sfe_ipv4_connection_match *counter_cm; + u8 ttl; + u32 flags; + struct net_device *xmit_dev; + + /* + * Is our packet too short to contain a valid UDP header? + */ + if (unlikely(!pskb_may_pull(skb, (sizeof(struct sfe_ipv4_tcp_hdr) + ihl)))) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_TCP_HEADER_INCOMPLETE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("packet too short for TCP header\n"); + return 0; + } + + /* + * Read the IP address and port information. Read the IP header data first + * because we've almost certainly got that in the cache. We may not yet have + * the TCP header cached though so allow more time for any prefetching. + */ + src_ip = iph->saddr; + dest_ip = iph->daddr; + + tcph = (struct sfe_ipv4_tcp_hdr *)(skb->data + ihl); + src_port = tcph->source; + dest_port = tcph->dest; + flags = tcp_flag_word(tcph); + + spin_lock_bh(&si->lock); + + /* + * Look for a connection match. + */ +#ifdef CONFIG_NF_FLOW_COOKIE + cm = si->sfe_flow_cookie_table[skb->flow_cookie & SFE_FLOW_COOKIE_MASK].match; + if (unlikely(!cm)) { + cm = sfe_ipv4_find_sfe_ipv4_connection_match(si, dev, IPPROTO_TCP, src_ip, src_port, dest_ip, dest_port); + } +#else + cm = sfe_ipv4_find_sfe_ipv4_connection_match(si, dev, IPPROTO_TCP, src_ip, src_port, dest_ip, dest_port); +#endif + if (unlikely(!cm)) { + /* + * We didn't get a connection but as TCP is connection-oriented that + * may be because this is a non-fast connection (not running established). + * For diagnostic purposes we differentiate this here. + */ + if (likely((flags & (TCP_FLAG_SYN | TCP_FLAG_RST | TCP_FLAG_FIN | TCP_FLAG_ACK)) == TCP_FLAG_ACK)) { + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_TCP_NO_CONNECTION_FAST_FLAGS]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("no connection found - fast flags\n"); + return 0; + } + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_TCP_NO_CONNECTION_SLOW_FLAGS]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("no connection found - slow flags: 0x%x\n", + flags & (TCP_FLAG_SYN | TCP_FLAG_RST | TCP_FLAG_FIN | TCP_FLAG_ACK)); + return 0; + } + + /* + * If our packet has beern marked as "flush on find" we can't actually + * forward it in the fast path, but now that we've found an associated + * connection we can flush that out before we process the packet. + */ + if (unlikely(flush_on_find)) { + struct sfe_ipv4_connection *c = cm->connection; + sfe_ipv4_remove_sfe_ipv4_connection(si, c); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_TCP_IP_OPTIONS_OR_INITIAL_FRAGMENT]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("flush on find\n"); + sfe_ipv4_flush_sfe_ipv4_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + +#ifdef CONFIG_XFRM + /* + * We can't accelerate the flow on this direction, just let it go + * through the slow path. + */ + if (unlikely(!cm->flow_accel)) { + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + return 0; + } +#endif + /* + * Does our TTL allow forwarding? + */ + ttl = iph->ttl; + if (unlikely(ttl < 2)) { + struct sfe_ipv4_connection *c = cm->connection; + sfe_ipv4_remove_sfe_ipv4_connection(si, c); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_TCP_SMALL_TTL]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("ttl too low\n"); + sfe_ipv4_flush_sfe_ipv4_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + /* + * If our packet is larger than the MTU of the transmit interface then + * we can't forward it easily. + */ + if (unlikely((len > cm->xmit_dev_mtu) && !skb_is_gso(skb))) { + struct sfe_ipv4_connection *c = cm->connection; + sfe_ipv4_remove_sfe_ipv4_connection(si, c); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_TCP_NEEDS_FRAGMENTATION]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("larger than mtu\n"); + sfe_ipv4_flush_sfe_ipv4_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + /* + * Look at our TCP flags. Anything missing an ACK or that has RST, SYN or FIN + * set is not a fast path packet. + */ + if (unlikely((flags & (TCP_FLAG_SYN | TCP_FLAG_RST | TCP_FLAG_FIN | TCP_FLAG_ACK)) != TCP_FLAG_ACK)) { + struct sfe_ipv4_connection *c = cm->connection; + sfe_ipv4_remove_sfe_ipv4_connection(si, c); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_TCP_FLAGS]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("TCP flags: 0x%x are not fast\n", + flags & (TCP_FLAG_SYN | TCP_FLAG_RST | TCP_FLAG_FIN | TCP_FLAG_ACK)); + sfe_ipv4_flush_sfe_ipv4_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + counter_cm = cm->counter_match; + + /* + * Are we doing sequence number checking? + */ + if (likely(!(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK))) { + u32 seq; + u32 ack; + u32 sack; + u32 data_offs; + u32 end; + u32 left_edge; + u32 scaled_win; + u32 max_end; + + /* + * Is our sequence fully past the right hand edge of the window? + */ + seq = ntohl(tcph->seq); + if (unlikely((s32)(seq - (cm->protocol_state.tcp.max_end + 1)) > 0)) { + struct sfe_ipv4_connection *c = cm->connection; + sfe_ipv4_remove_sfe_ipv4_connection(si, c); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_TCP_SEQ_EXCEEDS_RIGHT_EDGE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("seq: %u exceeds right edge: %u\n", + seq, cm->protocol_state.tcp.max_end + 1); + sfe_ipv4_flush_sfe_ipv4_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + /* + * Check that our TCP data offset isn't too short. + */ + data_offs = tcph->doff << 2; + if (unlikely(data_offs < sizeof(struct sfe_ipv4_tcp_hdr))) { + struct sfe_ipv4_connection *c = cm->connection; + sfe_ipv4_remove_sfe_ipv4_connection(si, c); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_TCP_SMALL_DATA_OFFS]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("TCP data offset: %u, too small\n", data_offs); + sfe_ipv4_flush_sfe_ipv4_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + /* + * Update ACK according to any SACK option. + */ + ack = ntohl(tcph->ack_seq); + sack = ack; + if (unlikely(!sfe_ipv4_process_tcp_option_sack(tcph, data_offs, &sack))) { + struct sfe_ipv4_connection *c = cm->connection; + sfe_ipv4_remove_sfe_ipv4_connection(si, c); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_TCP_BAD_SACK]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("TCP option SACK size is wrong\n"); + sfe_ipv4_flush_sfe_ipv4_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + /* + * Check that our TCP data offset isn't past the end of the packet. + */ + data_offs += sizeof(struct sfe_ipv4_ip_hdr); + if (unlikely(len < data_offs)) { + struct sfe_ipv4_connection *c = cm->connection; + sfe_ipv4_remove_sfe_ipv4_connection(si, c); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_TCP_BIG_DATA_OFFS]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("TCP data offset: %u, past end of packet: %u\n", + data_offs, len); + sfe_ipv4_flush_sfe_ipv4_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + end = seq + len - data_offs; + + /* + * Is our sequence fully before the left hand edge of the window? + */ + if (unlikely((s32)(end - (cm->protocol_state.tcp.end + - counter_cm->protocol_state.tcp.max_win - 1)) < 0)) { + struct sfe_ipv4_connection *c = cm->connection; + sfe_ipv4_remove_sfe_ipv4_connection(si, c); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_TCP_SEQ_BEFORE_LEFT_EDGE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("seq: %u before left edge: %u\n", + end, cm->protocol_state.tcp.end - counter_cm->protocol_state.tcp.max_win - 1); + sfe_ipv4_flush_sfe_ipv4_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + /* + * Are we acking data that is to the right of what has been sent? + */ + if (unlikely((s32)(sack - (counter_cm->protocol_state.tcp.end + 1)) > 0)) { + struct sfe_ipv4_connection *c = cm->connection; + sfe_ipv4_remove_sfe_ipv4_connection(si, c); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_TCP_ACK_EXCEEDS_RIGHT_EDGE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("ack: %u exceeds right edge: %u\n", + sack, counter_cm->protocol_state.tcp.end + 1); + sfe_ipv4_flush_sfe_ipv4_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + /* + * Is our ack too far before the left hand edge of the window? + */ + left_edge = counter_cm->protocol_state.tcp.end + - cm->protocol_state.tcp.max_win + - SFE_IPV4_TCP_MAX_ACK_WINDOW + - 1; + if (unlikely((s32)(sack - left_edge) < 0)) { + struct sfe_ipv4_connection *c = cm->connection; + sfe_ipv4_remove_sfe_ipv4_connection(si, c); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_TCP_ACK_BEFORE_LEFT_EDGE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("ack: %u before left edge: %u\n", sack, left_edge); + sfe_ipv4_flush_sfe_ipv4_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + /* + * Have we just seen the largest window size yet for this connection? If yes + * then we need to record the new value. + */ + scaled_win = ntohs(tcph->window) << cm->protocol_state.tcp.win_scale; + scaled_win += (sack - ack); + if (unlikely(cm->protocol_state.tcp.max_win < scaled_win)) { + cm->protocol_state.tcp.max_win = scaled_win; + } + + /* + * If our sequence and/or ack numbers have advanced then record the new state. + */ + if (likely((s32)(end - cm->protocol_state.tcp.end) >= 0)) { + cm->protocol_state.tcp.end = end; + } + + max_end = sack + scaled_win; + if (likely((s32)(max_end - counter_cm->protocol_state.tcp.max_end) >= 0)) { + counter_cm->protocol_state.tcp.max_end = max_end; + } + } + + /* + * From this point on we're good to modify the packet. + */ + + /* + * Check if skb was cloned. If it was, unshare it. Because + * the data area is going to be written in this path and we don't want to + * change the cloned skb's data section. + */ + if (unlikely(skb_cloned(skb))) { + DEBUG_TRACE("%px: skb is a cloned skb\n", skb); + skb = skb_unshare(skb, GFP_ATOMIC); + if (!skb) { + DEBUG_WARN("Failed to unshare the cloned skb\n"); + return 0; + } + + /* + * Update the iph and tcph pointers with the unshared skb's data area. + */ + iph = (struct sfe_ipv4_ip_hdr *)skb->data; + tcph = (struct sfe_ipv4_tcp_hdr *)(skb->data + ihl); + } + + /* + * Update DSCP + */ + if (unlikely(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_DSCP_REMARK)) { + iph->tos = (iph->tos & SFE_IPV4_DSCP_MASK) | cm->dscp; + } + + /* + * Decrement our TTL. + */ + iph->ttl = ttl - 1; + + /* + * Do we have to perform translations of the source address/port? + */ + if (unlikely(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_SRC)) { + u16 tcp_csum; + u32 sum; + + iph->saddr = cm->xlate_src_ip; + tcph->source = cm->xlate_src_port; + + /* + * Do we have a non-zero UDP checksum? If we do then we need + * to update it. + */ + tcp_csum = tcph->check; + if (unlikely(skb->ip_summed == CHECKSUM_PARTIAL)) { + sum = tcp_csum + cm->xlate_src_partial_csum_adjustment; + } else { + sum = tcp_csum + cm->xlate_src_csum_adjustment; + } + + sum = (sum & 0xffff) + (sum >> 16); + tcph->check = (u16)sum; + } + + /* + * Do we have to perform translations of the destination address/port? + */ + if (unlikely(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_DEST)) { + u16 tcp_csum; + u32 sum; + + iph->daddr = cm->xlate_dest_ip; + tcph->dest = cm->xlate_dest_port; + + /* + * Do we have a non-zero UDP checksum? If we do then we need + * to update it. + */ + tcp_csum = tcph->check; + if (unlikely(skb->ip_summed == CHECKSUM_PARTIAL)) { + sum = tcp_csum + cm->xlate_dest_partial_csum_adjustment; + } else { + sum = tcp_csum + cm->xlate_dest_csum_adjustment; + } + + sum = (sum & 0xffff) + (sum >> 16); + tcph->check = (u16)sum; + } + + /* + * Replace the IP checksum. + */ + iph->check = sfe_ipv4_gen_ip_csum(iph); + + /* + * Update traffic stats. + */ + cm->rx_packet_count++; + cm->rx_byte_count += len; + + /* + * If we're not already on the active list then insert ourselves at the tail + * of the current list. + */ + if (unlikely(!cm->active)) { + cm->active = true; + cm->active_prev = si->active_tail; + if (likely(si->active_tail)) { + si->active_tail->active_next = cm; + } else { + si->active_head = cm; + } + si->active_tail = cm; + } + + xmit_dev = cm->xmit_dev; + skb->dev = xmit_dev; + + /* + * Check to see if we need to write a header. + */ + if (likely(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_WRITE_L2_HDR)) { + if (unlikely(!(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_WRITE_FAST_ETH_HDR))) { + dev_hard_header(skb, xmit_dev, ETH_P_IP, + cm->xmit_dest_mac, cm->xmit_src_mac, len); + } else { + /* + * For the simple case we write this really fast. + */ + struct sfe_ipv4_eth_hdr *eth = (struct sfe_ipv4_eth_hdr *)__skb_push(skb, ETH_HLEN); + eth->h_proto = htons(ETH_P_IP); + eth->h_dest[0] = cm->xmit_dest_mac[0]; + eth->h_dest[1] = cm->xmit_dest_mac[1]; + eth->h_dest[2] = cm->xmit_dest_mac[2]; + eth->h_source[0] = cm->xmit_src_mac[0]; + eth->h_source[1] = cm->xmit_src_mac[1]; + eth->h_source[2] = cm->xmit_src_mac[2]; + } + } + + /* + * Update priority of skb. + */ + if (unlikely(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_PRIORITY_REMARK)) { + skb->priority = cm->priority; + } + + /* + * Mark outgoing packet + */ + skb->mark = cm->connection->mark; + if (skb->mark) { + DEBUG_TRACE("SKB MARK is NON ZERO %x\n", skb->mark); + } + + si->packets_forwarded++; + spin_unlock_bh(&si->lock); + + /* + * We're going to check for GSO flags when we transmit the packet so + * start fetching the necessary cache line now. + */ + prefetch(skb_shinfo(skb)); + + /* + * Mark that this packet has been fast forwarded. + */ + skb->fast_forwarded = 1; + + /* + * Send the packet on its way. + */ + dev_queue_xmit(skb); + + return 1; +} + +/* + * sfe_ipv4_recv_icmp() + * Handle ICMP packet receives. + * + * ICMP packets aren't handled as a "fast path" and always have us process them + * through the default Linux stack. What we do need to do is look for any errors + * about connections we are handling in the fast path. If we find any such + * connections then we want to flush their state so that the ICMP error path + * within Linux has all of the correct state should it need it. + */ +static int sfe_ipv4_recv_icmp(struct sfe_ipv4 *si, struct sk_buff *skb, struct net_device *dev, + unsigned int len, struct sfe_ipv4_ip_hdr *iph, unsigned int ihl) +{ + struct icmphdr *icmph; + struct sfe_ipv4_ip_hdr *icmp_iph; + unsigned int icmp_ihl_words; + unsigned int icmp_ihl; + u32 *icmp_trans_h; + struct sfe_ipv4_udp_hdr *icmp_udph; + struct sfe_ipv4_tcp_hdr *icmp_tcph; + __be32 src_ip; + __be32 dest_ip; + __be16 src_port; + __be16 dest_port; + struct sfe_ipv4_connection_match *cm; + struct sfe_ipv4_connection *c; + u32 pull_len = sizeof(struct icmphdr) + ihl; + + /* + * Is our packet too short to contain a valid ICMP header? + */ + len -= ihl; + if (!pskb_may_pull(skb, pull_len)) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_ICMP_HEADER_INCOMPLETE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("packet too short for ICMP header\n"); + return 0; + } + + /* + * We only handle "destination unreachable" and "time exceeded" messages. + */ + icmph = (struct icmphdr *)(skb->data + ihl); + if ((icmph->type != ICMP_DEST_UNREACH) + && (icmph->type != ICMP_TIME_EXCEEDED)) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_ICMP_UNHANDLED_TYPE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("unhandled ICMP type: 0x%x\n", icmph->type); + return 0; + } + + /* + * Do we have the full embedded IP header? + */ + len -= sizeof(struct icmphdr); + pull_len += sizeof(struct sfe_ipv4_ip_hdr); + if (!pskb_may_pull(skb, pull_len)) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_ICMP_IPV4_HEADER_INCOMPLETE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("Embedded IP header not complete\n"); + return 0; + } + + /* + * Is our embedded IP version wrong? + */ + icmp_iph = (struct sfe_ipv4_ip_hdr *)(icmph + 1); + if (unlikely(icmp_iph->version != 4)) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_ICMP_IPV4_NON_V4]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("IP version: %u\n", icmp_iph->version); + return 0; + } + + /* + * Do we have the full embedded IP header, including any options? + */ + icmp_ihl_words = icmp_iph->ihl; + icmp_ihl = icmp_ihl_words << 2; + pull_len += icmp_ihl - sizeof(struct sfe_ipv4_ip_hdr); + if (!pskb_may_pull(skb, pull_len)) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_ICMP_IPV4_IP_OPTIONS_INCOMPLETE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("Embedded header not large enough for IP options\n"); + return 0; + } + + len -= icmp_ihl; + icmp_trans_h = ((u32 *)icmp_iph) + icmp_ihl_words; + + /* + * Handle the embedded transport layer header. + */ + switch (icmp_iph->protocol) { + case IPPROTO_UDP: + /* + * We should have 8 bytes of UDP header - that's enough to identify + * the connection. + */ + pull_len += 8; + if (!pskb_may_pull(skb, pull_len)) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_ICMP_IPV4_UDP_HEADER_INCOMPLETE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("Incomplete embedded UDP header\n"); + return 0; + } + + icmp_udph = (struct sfe_ipv4_udp_hdr *)icmp_trans_h; + src_port = icmp_udph->source; + dest_port = icmp_udph->dest; + break; + + case IPPROTO_TCP: + /* + * We should have 8 bytes of TCP header - that's enough to identify + * the connection. + */ + pull_len += 8; + if (!pskb_may_pull(skb, pull_len)) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_ICMP_IPV4_TCP_HEADER_INCOMPLETE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("Incomplete embedded TCP header\n"); + return 0; + } + + icmp_tcph = (struct sfe_ipv4_tcp_hdr *)icmp_trans_h; + src_port = icmp_tcph->source; + dest_port = icmp_tcph->dest; + break; + + default: + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_ICMP_IPV4_UNHANDLED_PROTOCOL]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("Unhandled embedded IP protocol: %u\n", icmp_iph->protocol); + return 0; + } + + src_ip = icmp_iph->saddr; + dest_ip = icmp_iph->daddr; + + spin_lock_bh(&si->lock); + + /* + * Look for a connection match. Note that we reverse the source and destination + * here because our embedded message contains a packet that was sent in the + * opposite direction to the one in which we just received it. It will have + * been sent on the interface from which we received it though so that's still + * ok to use. + */ + cm = sfe_ipv4_find_sfe_ipv4_connection_match(si, dev, icmp_iph->protocol, dest_ip, dest_port, src_ip, src_port); + if (unlikely(!cm)) { + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_ICMP_NO_CONNECTION]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("no connection found\n"); + return 0; + } + + /* + * We found a connection so now remove it from the connection list and flush + * its state. + */ + c = cm->connection; + sfe_ipv4_remove_sfe_ipv4_connection(si, c); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_ICMP_FLUSHED_CONNECTION]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + sfe_ipv4_flush_sfe_ipv4_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; +} + +/* + * sfe_ipv4_recv() + * Handle packet receives and forwaring. + * + * Returns 1 if the packet is forwarded or 0 if it isn't. + */ +int sfe_ipv4_recv(struct net_device *dev, struct sk_buff *skb) +{ + struct sfe_ipv4 *si = &__si; + unsigned int len; + unsigned int tot_len; + unsigned int frag_off; + unsigned int ihl; + bool flush_on_find; + bool ip_options; + struct sfe_ipv4_ip_hdr *iph; + u32 protocol; + + /* + * Check that we have space for an IP header here. + */ + len = skb->len; + if (unlikely(!pskb_may_pull(skb, sizeof(struct sfe_ipv4_ip_hdr)))) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_HEADER_INCOMPLETE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("len: %u is too short\n", len); + return 0; + } + + /* + * Check that our "total length" is large enough for an IP header. + */ + iph = (struct sfe_ipv4_ip_hdr *)skb->data; + tot_len = ntohs(iph->tot_len); + if (unlikely(tot_len < sizeof(struct sfe_ipv4_ip_hdr))) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_BAD_TOTAL_LENGTH]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("tot_len: %u is too short\n", tot_len); + return 0; + } + + /* + * Is our IP version wrong? + */ + if (unlikely(iph->version != 4)) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_NON_V4]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("IP version: %u\n", iph->version); + return 0; + } + + /* + * Does our datagram fit inside the skb? + */ + if (unlikely(tot_len > len)) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_DATAGRAM_INCOMPLETE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("tot_len: %u, exceeds len: %u\n", tot_len, len); + return 0; + } + + /* + * Do we have a non-initial fragment? + */ + frag_off = ntohs(iph->frag_off); + if (unlikely(frag_off & IP_OFFSET)) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_NON_INITIAL_FRAGMENT]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("non-initial fragment\n"); + return 0; + } + + /* + * If we have a (first) fragment then mark it to cause any connection to flush. + */ + flush_on_find = unlikely(frag_off & IP_MF) ? true : false; + + /* + * Do we have any IP options? That's definite a slow path! If we do have IP + * options we need to recheck our header size. + */ + ihl = iph->ihl << 2; + ip_options = unlikely(ihl != sizeof(struct sfe_ipv4_ip_hdr)) ? true : false; + if (unlikely(ip_options)) { + if (unlikely(len < ihl)) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_IP_OPTIONS_INCOMPLETE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("len: %u is too short for header of size: %u\n", len, ihl); + return 0; + } + + flush_on_find = true; + } + + protocol = iph->protocol; + if (IPPROTO_UDP == protocol) { + return sfe_ipv4_recv_udp(si, skb, dev, len, iph, ihl, flush_on_find); + } + + if (IPPROTO_TCP == protocol) { + return sfe_ipv4_recv_tcp(si, skb, dev, len, iph, ihl, flush_on_find); + } + + if (IPPROTO_ICMP == protocol) { + return sfe_ipv4_recv_icmp(si, skb, dev, len, iph, ihl); + } + + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_UNHANDLED_PROTOCOL]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("not UDP, TCP or ICMP: %u\n", protocol); + return 0; +} + +static void +sfe_ipv4_update_tcp_state(struct sfe_ipv4_connection *c, + struct sfe_connection_create *sic) +{ + struct sfe_ipv4_connection_match *orig_cm; + struct sfe_ipv4_connection_match *repl_cm; + struct sfe_ipv4_tcp_connection_match *orig_tcp; + struct sfe_ipv4_tcp_connection_match *repl_tcp; + + orig_cm = c->original_match; + repl_cm = c->reply_match; + orig_tcp = &orig_cm->protocol_state.tcp; + repl_tcp = &repl_cm->protocol_state.tcp; + + /* update orig */ + if (orig_tcp->max_win < sic->src_td_max_window) { + orig_tcp->max_win = sic->src_td_max_window; + } + if ((s32)(orig_tcp->end - sic->src_td_end) < 0) { + orig_tcp->end = sic->src_td_end; + } + if ((s32)(orig_tcp->max_end - sic->src_td_max_end) < 0) { + orig_tcp->max_end = sic->src_td_max_end; + } + + /* update reply */ + if (repl_tcp->max_win < sic->dest_td_max_window) { + repl_tcp->max_win = sic->dest_td_max_window; + } + if ((s32)(repl_tcp->end - sic->dest_td_end) < 0) { + repl_tcp->end = sic->dest_td_end; + } + if ((s32)(repl_tcp->max_end - sic->dest_td_max_end) < 0) { + repl_tcp->max_end = sic->dest_td_max_end; + } + + /* update match flags */ + orig_cm->flags &= ~SFE_IPV4_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK; + repl_cm->flags &= ~SFE_IPV4_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK; + if (sic->flags & SFE_CREATE_FLAG_NO_SEQ_CHECK) { + orig_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK; + repl_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK; + } +} + +static void +sfe_ipv4_update_protocol_state(struct sfe_ipv4_connection *c, + struct sfe_connection_create *sic) +{ + switch (sic->protocol) { + case IPPROTO_TCP: + sfe_ipv4_update_tcp_state(c, sic); + break; + } +} + +void sfe_ipv4_update_rule(struct sfe_connection_create *sic) +{ + struct sfe_ipv4_connection *c; + struct sfe_ipv4 *si = &__si; + + spin_lock_bh(&si->lock); + + c = sfe_ipv4_find_sfe_ipv4_connection(si, + sic->protocol, + sic->src_ip.ip, + sic->src_port, + sic->dest_ip.ip, + sic->dest_port); + if (c != NULL) { + sfe_ipv4_update_protocol_state(c, sic); + } + + spin_unlock_bh(&si->lock); +} + +/* + * sfe_ipv4_create_rule() + * Create a forwarding rule. + */ +int sfe_ipv4_create_rule(struct sfe_connection_create *sic) +{ + struct sfe_ipv4 *si = &__si; + struct sfe_ipv4_connection *c; + struct sfe_ipv4_connection_match *original_cm; + struct sfe_ipv4_connection_match *reply_cm; + struct net_device *dest_dev; + struct net_device *src_dev; + + dest_dev = sic->dest_dev; + src_dev = sic->src_dev; + + if (unlikely((dest_dev->reg_state != NETREG_REGISTERED) || + (src_dev->reg_state != NETREG_REGISTERED))) { + return -EINVAL; + } + + spin_lock_bh(&si->lock); + si->connection_create_requests++; + + /* + * Check to see if there is already a flow that matches the rule we're + * trying to create. If there is then we can't create a new one. + */ + c = sfe_ipv4_find_sfe_ipv4_connection(si, + sic->protocol, + sic->src_ip.ip, + sic->src_port, + sic->dest_ip.ip, + sic->dest_port); + if (c != NULL) { + si->connection_create_collisions++; + + /* + * If we already have the flow then it's likely that this + * request to create the connection rule contains more + * up-to-date information. Check and update accordingly. + */ + sfe_ipv4_update_protocol_state(c, sic); + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("connection already exists - mark: %08x, p: %d\n" + " s: %s:%pxM:%pI4:%u, d: %s:%pxM:%pI4:%u\n", + sic->mark, sic->protocol, + sic->src_dev->name, sic->src_mac, &sic->src_ip.ip, ntohs(sic->src_port), + sic->dest_dev->name, sic->dest_mac, &sic->dest_ip.ip, ntohs(sic->dest_port)); + return -EADDRINUSE; + } + + /* + * Allocate the various connection tracking objects. + */ + c = (struct sfe_ipv4_connection *)kmalloc(sizeof(struct sfe_ipv4_connection), GFP_ATOMIC); + if (unlikely(!c)) { + spin_unlock_bh(&si->lock); + return -ENOMEM; + } + + original_cm = (struct sfe_ipv4_connection_match *)kmalloc(sizeof(struct sfe_ipv4_connection_match), GFP_ATOMIC); + if (unlikely(!original_cm)) { + spin_unlock_bh(&si->lock); + kfree(c); + return -ENOMEM; + } + + reply_cm = (struct sfe_ipv4_connection_match *)kmalloc(sizeof(struct sfe_ipv4_connection_match), GFP_ATOMIC); + if (unlikely(!reply_cm)) { + spin_unlock_bh(&si->lock); + kfree(original_cm); + kfree(c); + return -ENOMEM; + } + + /* + * Fill in the "original" direction connection matching object. + * Note that the transmit MAC address is "dest_mac_xlate" because + * we always know both ends of a connection by their translated + * addresses and not their public addresses. + */ + original_cm->match_dev = src_dev; + original_cm->match_protocol = sic->protocol; + original_cm->match_src_ip = sic->src_ip.ip; + original_cm->match_src_port = sic->src_port; + original_cm->match_dest_ip = sic->dest_ip.ip; + original_cm->match_dest_port = sic->dest_port; + original_cm->xlate_src_ip = sic->src_ip_xlate.ip; + original_cm->xlate_src_port = sic->src_port_xlate; + original_cm->xlate_dest_ip = sic->dest_ip_xlate.ip; + original_cm->xlate_dest_port = sic->dest_port_xlate; + original_cm->rx_packet_count = 0; + original_cm->rx_packet_count64 = 0; + original_cm->rx_byte_count = 0; + original_cm->rx_byte_count64 = 0; + original_cm->xmit_dev = dest_dev; + original_cm->xmit_dev_mtu = sic->dest_mtu; + memcpy(original_cm->xmit_src_mac, dest_dev->dev_addr, ETH_ALEN); + memcpy(original_cm->xmit_dest_mac, sic->dest_mac_xlate, ETH_ALEN); + original_cm->connection = c; + original_cm->counter_match = reply_cm; + original_cm->flags = 0; + if (sic->flags & SFE_CREATE_FLAG_REMARK_PRIORITY) { + original_cm->priority = sic->src_priority; + original_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_PRIORITY_REMARK; + } + if (sic->flags & SFE_CREATE_FLAG_REMARK_DSCP) { + original_cm->dscp = sic->src_dscp << SFE_IPV4_DSCP_SHIFT; + original_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_DSCP_REMARK; + } +#ifdef CONFIG_NF_FLOW_COOKIE + original_cm->flow_cookie = 0; +#endif +#ifdef CONFIG_XFRM + original_cm->flow_accel = sic->original_accel; +#endif + original_cm->active_next = NULL; + original_cm->active_prev = NULL; + original_cm->active = false; + + /* + * For PPP links we don't write an L2 header. For everything else we do. + */ + if (!(dest_dev->flags & IFF_POINTOPOINT)) { + original_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_WRITE_L2_HDR; + + /* + * If our dev writes Ethernet headers then we can write a really fast + * version. + */ + if (dest_dev->header_ops) { + if (dest_dev->header_ops->create == eth_header) { + original_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_WRITE_FAST_ETH_HDR; + } + } + } + + /* + * Fill in the "reply" direction connection matching object. + */ + reply_cm->match_dev = dest_dev; + reply_cm->match_protocol = sic->protocol; + reply_cm->match_src_ip = sic->dest_ip_xlate.ip; + reply_cm->match_src_port = sic->dest_port_xlate; + reply_cm->match_dest_ip = sic->src_ip_xlate.ip; + reply_cm->match_dest_port = sic->src_port_xlate; + reply_cm->xlate_src_ip = sic->dest_ip.ip; + reply_cm->xlate_src_port = sic->dest_port; + reply_cm->xlate_dest_ip = sic->src_ip.ip; + reply_cm->xlate_dest_port = sic->src_port; + reply_cm->rx_packet_count = 0; + reply_cm->rx_packet_count64 = 0; + reply_cm->rx_byte_count = 0; + reply_cm->rx_byte_count64 = 0; + reply_cm->xmit_dev = src_dev; + reply_cm->xmit_dev_mtu = sic->src_mtu; + memcpy(reply_cm->xmit_src_mac, src_dev->dev_addr, ETH_ALEN); + memcpy(reply_cm->xmit_dest_mac, sic->src_mac, ETH_ALEN); + reply_cm->connection = c; + reply_cm->counter_match = original_cm; + reply_cm->flags = 0; + if (sic->flags & SFE_CREATE_FLAG_REMARK_PRIORITY) { + reply_cm->priority = sic->dest_priority; + reply_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_PRIORITY_REMARK; + } + if (sic->flags & SFE_CREATE_FLAG_REMARK_DSCP) { + reply_cm->dscp = sic->dest_dscp << SFE_IPV4_DSCP_SHIFT; + reply_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_DSCP_REMARK; + } +#ifdef CONFIG_NF_FLOW_COOKIE + reply_cm->flow_cookie = 0; +#endif +#ifdef CONFIG_XFRM + reply_cm->flow_accel = sic->reply_accel; +#endif + reply_cm->active_next = NULL; + reply_cm->active_prev = NULL; + reply_cm->active = false; + + /* + * For PPP links we don't write an L2 header. For everything else we do. + */ + if (!(src_dev->flags & IFF_POINTOPOINT)) { + reply_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_WRITE_L2_HDR; + + /* + * If our dev writes Ethernet headers then we can write a really fast + * version. + */ + if (src_dev->header_ops) { + if (src_dev->header_ops->create == eth_header) { + reply_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_WRITE_FAST_ETH_HDR; + } + } + } + + + if (sic->dest_ip.ip != sic->dest_ip_xlate.ip || sic->dest_port != sic->dest_port_xlate) { + original_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_DEST; + reply_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_SRC; + } + + if (sic->src_ip.ip != sic->src_ip_xlate.ip || sic->src_port != sic->src_port_xlate) { + original_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_SRC; + reply_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_DEST; + } + + c->protocol = sic->protocol; + c->src_ip = sic->src_ip.ip; + c->src_ip_xlate = sic->src_ip_xlate.ip; + c->src_port = sic->src_port; + c->src_port_xlate = sic->src_port_xlate; + c->original_dev = src_dev; + c->original_match = original_cm; + c->dest_ip = sic->dest_ip.ip; + c->dest_ip_xlate = sic->dest_ip_xlate.ip; + c->dest_port = sic->dest_port; + c->dest_port_xlate = sic->dest_port_xlate; + c->reply_dev = dest_dev; + c->reply_match = reply_cm; + c->mark = sic->mark; + c->debug_read_seq = 0; + c->last_sync_jiffies = get_jiffies_64(); + + /* + * Take hold of our source and dest devices for the duration of the connection. + */ + dev_hold(c->original_dev); + dev_hold(c->reply_dev); + + /* + * Initialize the protocol-specific information that we track. + */ + switch (sic->protocol) { + case IPPROTO_TCP: + original_cm->protocol_state.tcp.win_scale = sic->src_td_window_scale; + original_cm->protocol_state.tcp.max_win = sic->src_td_max_window ? sic->src_td_max_window : 1; + original_cm->protocol_state.tcp.end = sic->src_td_end; + original_cm->protocol_state.tcp.max_end = sic->src_td_max_end; + reply_cm->protocol_state.tcp.win_scale = sic->dest_td_window_scale; + reply_cm->protocol_state.tcp.max_win = sic->dest_td_max_window ? sic->dest_td_max_window : 1; + reply_cm->protocol_state.tcp.end = sic->dest_td_end; + reply_cm->protocol_state.tcp.max_end = sic->dest_td_max_end; + if (sic->flags & SFE_CREATE_FLAG_NO_SEQ_CHECK) { + original_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK; + reply_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK; + } + break; + } + + sfe_ipv4_connection_match_compute_translations(original_cm); + sfe_ipv4_connection_match_compute_translations(reply_cm); + sfe_ipv4_insert_sfe_ipv4_connection(si, c); + + spin_unlock_bh(&si->lock); + + /* + * We have everything we need! + */ + DEBUG_INFO("new connection - mark: %08x, p: %d\n" + " s: %s:%pxM(%pxM):%pI4(%pI4):%u(%u)\n" + " d: %s:%pxM(%pxM):%pI4(%pI4):%u(%u)\n", + sic->mark, sic->protocol, + sic->src_dev->name, sic->src_mac, sic->src_mac_xlate, + &sic->src_ip.ip, &sic->src_ip_xlate.ip, ntohs(sic->src_port), ntohs(sic->src_port_xlate), + dest_dev->name, sic->dest_mac, sic->dest_mac_xlate, + &sic->dest_ip.ip, &sic->dest_ip_xlate.ip, ntohs(sic->dest_port), ntohs(sic->dest_port_xlate)); + + return 0; +} + +/* + * sfe_ipv4_destroy_rule() + * Destroy a forwarding rule. + */ +void sfe_ipv4_destroy_rule(struct sfe_connection_destroy *sid) +{ + struct sfe_ipv4 *si = &__si; + struct sfe_ipv4_connection *c; + + spin_lock_bh(&si->lock); + si->connection_destroy_requests++; + + /* + * Check to see if we have a flow that matches the rule we're trying + * to destroy. If there isn't then we can't destroy it. + */ + c = sfe_ipv4_find_sfe_ipv4_connection(si, sid->protocol, sid->src_ip.ip, sid->src_port, + sid->dest_ip.ip, sid->dest_port); + if (!c) { + si->connection_destroy_misses++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("connection does not exist - p: %d, s: %pI4:%u, d: %pI4:%u\n", + sid->protocol, &sid->src_ip, ntohs(sid->src_port), + &sid->dest_ip, ntohs(sid->dest_port)); + return; + } + + /* + * Remove our connection details from the hash tables. + */ + sfe_ipv4_remove_sfe_ipv4_connection(si, c); + spin_unlock_bh(&si->lock); + + sfe_ipv4_flush_sfe_ipv4_connection(si, c, SFE_SYNC_REASON_DESTROY); + + DEBUG_INFO("connection destroyed - p: %d, s: %pI4:%u, d: %pI4:%u\n", + sid->protocol, &sid->src_ip.ip, ntohs(sid->src_port), + &sid->dest_ip.ip, ntohs(sid->dest_port)); +} + +/* + * sfe_ipv4_register_sync_rule_callback() + * Register a callback for rule synchronization. + */ +void sfe_ipv4_register_sync_rule_callback(sfe_sync_rule_callback_t sync_rule_callback) +{ + struct sfe_ipv4 *si = &__si; + + spin_lock_bh(&si->lock); + rcu_assign_pointer(si->sync_rule_callback, sync_rule_callback); + spin_unlock_bh(&si->lock); +} + +/* + * sfe_ipv4_get_debug_dev() + */ +static ssize_t sfe_ipv4_get_debug_dev(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct sfe_ipv4 *si = &__si; + ssize_t count; + int num; + + spin_lock_bh(&si->lock); + num = si->debug_dev; + spin_unlock_bh(&si->lock); + + count = snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", num); + return count; +} + +/* + * sysfs attributes. + */ +static const struct device_attribute sfe_ipv4_debug_dev_attr = + __ATTR(debug_dev, S_IWUSR | S_IRUGO, sfe_ipv4_get_debug_dev, NULL); + +/* + * sfe_ipv4_destroy_all_rules_for_dev() + * Destroy all connections that match a particular device. + * + * If we pass dev as NULL then this destroys all connections. + */ +void sfe_ipv4_destroy_all_rules_for_dev(struct net_device *dev) +{ + struct sfe_ipv4 *si = &__si; + struct sfe_ipv4_connection *c; + +another_round: + spin_lock_bh(&si->lock); + + for (c = si->all_connections_head; c; c = c->all_connections_next) { + /* + * Does this connection relate to the device we are destroying? + */ + if (!dev + || (dev == c->original_dev) + || (dev == c->reply_dev)) { + break; + } + } + + if (c) { + sfe_ipv4_remove_sfe_ipv4_connection(si, c); + } + + spin_unlock_bh(&si->lock); + + if (c) { + sfe_ipv4_flush_sfe_ipv4_connection(si, c, SFE_SYNC_REASON_DESTROY); + goto another_round; + } +} + +/* + * sfe_ipv4_periodic_sync() + */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)) +static void sfe_ipv4_periodic_sync(unsigned long arg) +#else +static void sfe_ipv4_periodic_sync(struct timer_list *tl) +#endif +{ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)) + struct sfe_ipv4 *si = (struct sfe_ipv4 *)arg; +#else + struct sfe_ipv4 *si = from_timer(si, tl, timer); +#endif + u64 now_jiffies; + int quota; + sfe_sync_rule_callback_t sync_rule_callback; + + now_jiffies = get_jiffies_64(); + + rcu_read_lock(); + sync_rule_callback = rcu_dereference(si->sync_rule_callback); + if (!sync_rule_callback) { + rcu_read_unlock(); + goto done; + } + + spin_lock_bh(&si->lock); + sfe_ipv4_update_summary_stats(si); + + /* + * Get an estimate of the number of connections to parse in this sync. + */ + quota = (si->num_connections + 63) / 64; + + /* + * Walk the "active" list and sync the connection state. + */ + while (quota--) { + struct sfe_ipv4_connection_match *cm; + struct sfe_ipv4_connection_match *counter_cm; + struct sfe_ipv4_connection *c; + struct sfe_connection_sync sis; + + cm = si->active_head; + if (!cm) { + break; + } + + /* + * There's a possibility that our counter match is in the active list too. + * If it is then remove it. + */ + counter_cm = cm->counter_match; + if (counter_cm->active) { + counter_cm->active = false; + + /* + * We must have a connection preceding this counter match + * because that's the one that got us to this point, so we don't have + * to worry about removing the head of the list. + */ + counter_cm->active_prev->active_next = counter_cm->active_next; + + if (likely(counter_cm->active_next)) { + counter_cm->active_next->active_prev = counter_cm->active_prev; + } else { + si->active_tail = counter_cm->active_prev; + } + + counter_cm->active_next = NULL; + counter_cm->active_prev = NULL; + } + + /* + * Now remove the head of the active scan list. + */ + cm->active = false; + si->active_head = cm->active_next; + if (likely(cm->active_next)) { + cm->active_next->active_prev = NULL; + } else { + si->active_tail = NULL; + } + cm->active_next = NULL; + + /* + * Sync the connection state. + */ + c = cm->connection; + sfe_ipv4_gen_sync_sfe_ipv4_connection(si, c, &sis, SFE_SYNC_REASON_STATS, now_jiffies); + + /* + * We don't want to be holding the lock when we sync! + */ + spin_unlock_bh(&si->lock); + sync_rule_callback(&sis); + spin_lock_bh(&si->lock); + } + + spin_unlock_bh(&si->lock); + rcu_read_unlock(); + +done: + mod_timer(&si->timer, jiffies + ((HZ + 99) / 100)); +} + +#define CHAR_DEV_MSG_SIZE 768 + +/* + * sfe_ipv4_debug_dev_read_start() + * Generate part of the XML output. + */ +static bool sfe_ipv4_debug_dev_read_start(struct sfe_ipv4 *si, char *buffer, char *msg, size_t *length, + int *total_read, struct sfe_ipv4_debug_xml_write_state *ws) +{ + int bytes_read; + + si->debug_read_seq++; + + bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\n"); + if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) { + return false; + } + + *length -= bytes_read; + *total_read += bytes_read; + + ws->state++; + return true; +} + +/* + * sfe_ipv4_debug_dev_read_connections_start() + * Generate part of the XML output. + */ +static bool sfe_ipv4_debug_dev_read_connections_start(struct sfe_ipv4 *si, char *buffer, char *msg, size_t *length, + int *total_read, struct sfe_ipv4_debug_xml_write_state *ws) +{ + int bytes_read; + + bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t\n"); + if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) { + return false; + } + + *length -= bytes_read; + *total_read += bytes_read; + + ws->state++; + return true; +} + +/* + * sfe_ipv4_debug_dev_read_connections_connection() + * Generate part of the XML output. + */ +static bool sfe_ipv4_debug_dev_read_connections_connection(struct sfe_ipv4 *si, char *buffer, char *msg, size_t *length, + int *total_read, struct sfe_ipv4_debug_xml_write_state *ws) +{ + struct sfe_ipv4_connection *c; + struct sfe_ipv4_connection_match *original_cm; + struct sfe_ipv4_connection_match *reply_cm; + int bytes_read; + int protocol; + struct net_device *src_dev; + __be32 src_ip; + __be32 src_ip_xlate; + __be16 src_port; + __be16 src_port_xlate; + u64 src_rx_packets; + u64 src_rx_bytes; + struct net_device *dest_dev; + __be32 dest_ip; + __be32 dest_ip_xlate; + __be16 dest_port; + __be16 dest_port_xlate; + u64 dest_rx_packets; + u64 dest_rx_bytes; + u64 last_sync_jiffies; + u32 mark, src_priority, dest_priority, src_dscp, dest_dscp; +#ifdef CONFIG_NF_FLOW_COOKIE + int src_flow_cookie, dst_flow_cookie; +#endif + + spin_lock_bh(&si->lock); + + for (c = si->all_connections_head; c; c = c->all_connections_next) { + if (c->debug_read_seq < si->debug_read_seq) { + c->debug_read_seq = si->debug_read_seq; + break; + } + } + + /* + * If there were no connections then move to the next state. + */ + if (!c) { + spin_unlock_bh(&si->lock); + ws->state++; + return true; + } + + original_cm = c->original_match; + reply_cm = c->reply_match; + + protocol = c->protocol; + src_dev = c->original_dev; + src_ip = c->src_ip; + src_ip_xlate = c->src_ip_xlate; + src_port = c->src_port; + src_port_xlate = c->src_port_xlate; + src_priority = original_cm->priority; + src_dscp = original_cm->dscp >> SFE_IPV4_DSCP_SHIFT; + + sfe_ipv4_connection_match_update_summary_stats(original_cm); + sfe_ipv4_connection_match_update_summary_stats(reply_cm); + + src_rx_packets = original_cm->rx_packet_count64; + src_rx_bytes = original_cm->rx_byte_count64; + dest_dev = c->reply_dev; + dest_ip = c->dest_ip; + dest_ip_xlate = c->dest_ip_xlate; + dest_port = c->dest_port; + dest_port_xlate = c->dest_port_xlate; + dest_priority = reply_cm->priority; + dest_dscp = reply_cm->dscp >> SFE_IPV4_DSCP_SHIFT; + dest_rx_packets = reply_cm->rx_packet_count64; + dest_rx_bytes = reply_cm->rx_byte_count64; + last_sync_jiffies = get_jiffies_64() - c->last_sync_jiffies; + mark = c->mark; +#ifdef CONFIG_NF_FLOW_COOKIE + src_flow_cookie = original_cm->flow_cookie; + dst_flow_cookie = reply_cm->flow_cookie; +#endif + spin_unlock_bh(&si->lock); + + bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t\t\n", + protocol, + src_dev->name, + &src_ip, &src_ip_xlate, + ntohs(src_port), ntohs(src_port_xlate), + src_priority, src_dscp, + src_rx_packets, src_rx_bytes, + dest_dev->name, + &dest_ip, &dest_ip_xlate, + ntohs(dest_port), ntohs(dest_port_xlate), + dest_priority, dest_dscp, + dest_rx_packets, dest_rx_bytes, +#ifdef CONFIG_NF_FLOW_COOKIE + src_flow_cookie, dst_flow_cookie, +#endif + last_sync_jiffies, mark); + + if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) { + return false; + } + + *length -= bytes_read; + *total_read += bytes_read; + + return true; +} + +/* + * sfe_ipv4_debug_dev_read_connections_end() + * Generate part of the XML output. + */ +static bool sfe_ipv4_debug_dev_read_connections_end(struct sfe_ipv4 *si, char *buffer, char *msg, size_t *length, + int *total_read, struct sfe_ipv4_debug_xml_write_state *ws) +{ + int bytes_read; + + bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t\n"); + if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) { + return false; + } + + *length -= bytes_read; + *total_read += bytes_read; + + ws->state++; + return true; +} + +/* + * sfe_ipv4_debug_dev_read_exceptions_start() + * Generate part of the XML output. + */ +static bool sfe_ipv4_debug_dev_read_exceptions_start(struct sfe_ipv4 *si, char *buffer, char *msg, size_t *length, + int *total_read, struct sfe_ipv4_debug_xml_write_state *ws) +{ + int bytes_read; + + bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t\n"); + if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) { + return false; + } + + *length -= bytes_read; + *total_read += bytes_read; + + ws->state++; + return true; +} + +/* + * sfe_ipv4_debug_dev_read_exceptions_exception() + * Generate part of the XML output. + */ +static bool sfe_ipv4_debug_dev_read_exceptions_exception(struct sfe_ipv4 *si, char *buffer, char *msg, size_t *length, + int *total_read, struct sfe_ipv4_debug_xml_write_state *ws) +{ + u64 ct; + + spin_lock_bh(&si->lock); + ct = si->exception_events64[ws->iter_exception]; + spin_unlock_bh(&si->lock); + + if (ct) { + int bytes_read; + + bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, + "\t\t\n", + sfe_ipv4_exception_events_string[ws->iter_exception], + ct); + if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) { + return false; + } + + *length -= bytes_read; + *total_read += bytes_read; + } + + ws->iter_exception++; + if (ws->iter_exception >= SFE_IPV4_EXCEPTION_EVENT_LAST) { + ws->iter_exception = 0; + ws->state++; + } + + return true; +} + +/* + * sfe_ipv4_debug_dev_read_exceptions_end() + * Generate part of the XML output. + */ +static bool sfe_ipv4_debug_dev_read_exceptions_end(struct sfe_ipv4 *si, char *buffer, char *msg, size_t *length, + int *total_read, struct sfe_ipv4_debug_xml_write_state *ws) +{ + int bytes_read; + + bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t\n"); + if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) { + return false; + } + + *length -= bytes_read; + *total_read += bytes_read; + + ws->state++; + return true; +} + +/* + * sfe_ipv4_debug_dev_read_stats() + * Generate part of the XML output. + */ +static bool sfe_ipv4_debug_dev_read_stats(struct sfe_ipv4 *si, char *buffer, char *msg, size_t *length, + int *total_read, struct sfe_ipv4_debug_xml_write_state *ws) +{ + int bytes_read; + unsigned int num_connections; + u64 packets_forwarded; + u64 packets_not_forwarded; + u64 connection_create_requests; + u64 connection_create_collisions; + u64 connection_destroy_requests; + u64 connection_destroy_misses; + u64 connection_flushes; + u64 connection_match_hash_hits; + u64 connection_match_hash_reorders; + + spin_lock_bh(&si->lock); + sfe_ipv4_update_summary_stats(si); + + num_connections = si->num_connections; + packets_forwarded = si->packets_forwarded64; + packets_not_forwarded = si->packets_not_forwarded64; + connection_create_requests = si->connection_create_requests64; + connection_create_collisions = si->connection_create_collisions64; + connection_destroy_requests = si->connection_destroy_requests64; + connection_destroy_misses = si->connection_destroy_misses64; + connection_flushes = si->connection_flushes64; + connection_match_hash_hits = si->connection_match_hash_hits64; + connection_match_hash_reorders = si->connection_match_hash_reorders64; + spin_unlock_bh(&si->lock); + + bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t\n", + num_connections, + packets_forwarded, + packets_not_forwarded, + connection_create_requests, + connection_create_collisions, + connection_destroy_requests, + connection_destroy_misses, + connection_flushes, + connection_match_hash_hits, + connection_match_hash_reorders); + if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) { + return false; + } + + *length -= bytes_read; + *total_read += bytes_read; + + ws->state++; + return true; +} + +/* + * sfe_ipv4_debug_dev_read_end() + * Generate part of the XML output. + */ +static bool sfe_ipv4_debug_dev_read_end(struct sfe_ipv4 *si, char *buffer, char *msg, size_t *length, + int *total_read, struct sfe_ipv4_debug_xml_write_state *ws) +{ + int bytes_read; + + bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\n"); + if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) { + return false; + } + + *length -= bytes_read; + *total_read += bytes_read; + + ws->state++; + return true; +} + +/* + * Array of write functions that write various XML elements that correspond to + * our XML output state machine. + */ +static sfe_ipv4_debug_xml_write_method_t sfe_ipv4_debug_xml_write_methods[SFE_IPV4_DEBUG_XML_STATE_DONE] = { + sfe_ipv4_debug_dev_read_start, + sfe_ipv4_debug_dev_read_connections_start, + sfe_ipv4_debug_dev_read_connections_connection, + sfe_ipv4_debug_dev_read_connections_end, + sfe_ipv4_debug_dev_read_exceptions_start, + sfe_ipv4_debug_dev_read_exceptions_exception, + sfe_ipv4_debug_dev_read_exceptions_end, + sfe_ipv4_debug_dev_read_stats, + sfe_ipv4_debug_dev_read_end, +}; + +/* + * sfe_ipv4_debug_dev_read() + * Send info to userspace upon read request from user + */ +static ssize_t sfe_ipv4_debug_dev_read(struct file *filp, char *buffer, size_t length, loff_t *offset) +{ + char msg[CHAR_DEV_MSG_SIZE]; + int total_read = 0; + struct sfe_ipv4_debug_xml_write_state *ws; + struct sfe_ipv4 *si = &__si; + + ws = (struct sfe_ipv4_debug_xml_write_state *)filp->private_data; + while ((ws->state != SFE_IPV4_DEBUG_XML_STATE_DONE) && (length > CHAR_DEV_MSG_SIZE)) { + if ((sfe_ipv4_debug_xml_write_methods[ws->state])(si, buffer, msg, &length, &total_read, ws)) { + continue; + } + } + + return total_read; +} + +/* + * sfe_ipv4_debug_dev_write() + * Write to char device resets some stats + */ +static ssize_t sfe_ipv4_debug_dev_write(struct file *filp, const char *buffer, size_t length, loff_t *offset) +{ + struct sfe_ipv4 *si = &__si; + + spin_lock_bh(&si->lock); + sfe_ipv4_update_summary_stats(si); + + si->packets_forwarded64 = 0; + si->packets_not_forwarded64 = 0; + si->connection_create_requests64 = 0; + si->connection_create_collisions64 = 0; + si->connection_destroy_requests64 = 0; + si->connection_destroy_misses64 = 0; + si->connection_flushes64 = 0; + si->connection_match_hash_hits64 = 0; + si->connection_match_hash_reorders64 = 0; + spin_unlock_bh(&si->lock); + + return length; +} + +/* + * sfe_ipv4_debug_dev_open() + */ +static int sfe_ipv4_debug_dev_open(struct inode *inode, struct file *file) +{ + struct sfe_ipv4_debug_xml_write_state *ws; + + ws = (struct sfe_ipv4_debug_xml_write_state *)file->private_data; + if (!ws) { + ws = kzalloc(sizeof(struct sfe_ipv4_debug_xml_write_state), GFP_KERNEL); + if (!ws) { + return -ENOMEM; + } + + ws->state = SFE_IPV4_DEBUG_XML_STATE_START; + file->private_data = ws; + } + + return 0; +} + +/* + * sfe_ipv4_debug_dev_release() + */ +static int sfe_ipv4_debug_dev_release(struct inode *inode, struct file *file) +{ + struct sfe_ipv4_debug_xml_write_state *ws; + + ws = (struct sfe_ipv4_debug_xml_write_state *)file->private_data; + if (ws) { + /* + * We've finished with our output so free the write state. + */ + kfree(ws); + } + + return 0; +} + +/* + * File operations used in the debug char device + */ +static struct file_operations sfe_ipv4_debug_dev_fops = { + .read = sfe_ipv4_debug_dev_read, + .write = sfe_ipv4_debug_dev_write, + .open = sfe_ipv4_debug_dev_open, + .release = sfe_ipv4_debug_dev_release +}; + +#ifdef CONFIG_NF_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) +{ + struct sfe_ipv4 *si = &__si; + + BUG_ON(!cb); + + if (si->flow_cookie_set_func) { + return -1; + } + + rcu_assign_pointer(si->flow_cookie_set_func, cb); + return 0; +} + +/* + * 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) +{ + struct sfe_ipv4 *si = &__si; + + RCU_INIT_POINTER(si->flow_cookie_set_func, NULL); + return 0; +} + +/* + * sfe_ipv4_get_flow_cookie() + */ +static ssize_t sfe_ipv4_get_flow_cookie(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct sfe_ipv4 *si = &__si; + return snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", si->flow_cookie_enable); +} + +/* + * sfe_ipv4_set_flow_cookie() + */ +static ssize_t sfe_ipv4_set_flow_cookie(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct sfe_ipv4 *si = &__si; + strict_strtol(buf, 0, (long int *)&si->flow_cookie_enable); + + return size; +} + +/* + * sysfs attributes. + */ +static const struct device_attribute sfe_ipv4_flow_cookie_attr = + __ATTR(flow_cookie_enable, S_IWUSR | S_IRUGO, sfe_ipv4_get_flow_cookie, sfe_ipv4_set_flow_cookie); +#endif /*CONFIG_NF_FLOW_COOKIE*/ + +/* + * sfe_ipv4_init() + */ +static int __init sfe_ipv4_init(void) +{ + struct sfe_ipv4 *si = &__si; + int result = -1; + + DEBUG_INFO("SFE IPv4 init\n"); + + /* + * Create sys/sfe_ipv4 + */ + si->sys_sfe_ipv4 = kobject_create_and_add("sfe_ipv4", NULL); + if (!si->sys_sfe_ipv4) { + DEBUG_ERROR("failed to register sfe_ipv4\n"); + goto exit1; + } + + /* + * Create files, one for each parameter supported by this module. + */ + result = sysfs_create_file(si->sys_sfe_ipv4, &sfe_ipv4_debug_dev_attr.attr); + if (result) { + DEBUG_ERROR("failed to register debug dev file: %d\n", result); + goto exit2; + } + +#ifdef CONFIG_NF_FLOW_COOKIE + result = sysfs_create_file(si->sys_sfe_ipv4, &sfe_ipv4_flow_cookie_attr.attr); + if (result) { + DEBUG_ERROR("failed to register flow cookie enable file: %d\n", result); + goto exit3; + } +#endif /* CONFIG_NF_FLOW_COOKIE */ + + /* + * Register our debug char device. + */ + result = register_chrdev(0, "sfe_ipv4", &sfe_ipv4_debug_dev_fops); + if (result < 0) { + DEBUG_ERROR("Failed to register chrdev: %d\n", result); + goto exit4; + } + + si->debug_dev = result; + + /* + * Create a timer to handle periodic statistics. + */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)) + setup_timer(&si->timer, sfe_ipv4_periodic_sync, (unsigned long)si); +#else + timer_setup(&si->timer, sfe_ipv4_periodic_sync, 0); +#endif + mod_timer(&si->timer, jiffies + ((HZ + 99) / 100)); + + spin_lock_init(&si->lock); + + return 0; + +exit4: +#ifdef CONFIG_NF_FLOW_COOKIE + sysfs_remove_file(si->sys_sfe_ipv4, &sfe_ipv4_flow_cookie_attr.attr); + +exit3: +#endif /* CONFIG_NF_FLOW_COOKIE */ + sysfs_remove_file(si->sys_sfe_ipv4, &sfe_ipv4_debug_dev_attr.attr); + +exit2: + kobject_put(si->sys_sfe_ipv4); + +exit1: + return result; +} + +/* + * sfe_ipv4_exit() + */ +static void __exit sfe_ipv4_exit(void) +{ + struct sfe_ipv4 *si = &__si; + + DEBUG_INFO("SFE IPv4 exit\n"); + + /* + * Destroy all connections. + */ + sfe_ipv4_destroy_all_rules_for_dev(NULL); + + del_timer_sync(&si->timer); + + unregister_chrdev(si->debug_dev, "sfe_ipv4"); + +#ifdef CONFIG_NF_FLOW_COOKIE + sysfs_remove_file(si->sys_sfe_ipv4, &sfe_ipv4_flow_cookie_attr.attr); +#endif /* CONFIG_NF_FLOW_COOKIE */ + sysfs_remove_file(si->sys_sfe_ipv4, &sfe_ipv4_debug_dev_attr.attr); + + kobject_put(si->sys_sfe_ipv4); + +} + +module_init(sfe_ipv4_init) +module_exit(sfe_ipv4_exit) + +EXPORT_SYMBOL(sfe_ipv4_recv); +EXPORT_SYMBOL(sfe_ipv4_create_rule); +EXPORT_SYMBOL(sfe_ipv4_destroy_rule); +EXPORT_SYMBOL(sfe_ipv4_destroy_all_rules_for_dev); +EXPORT_SYMBOL(sfe_ipv4_register_sync_rule_callback); +EXPORT_SYMBOL(sfe_ipv4_mark_rule); +EXPORT_SYMBOL(sfe_ipv4_update_rule); +#ifdef CONFIG_NF_FLOW_COOKIE +EXPORT_SYMBOL(sfe_register_flow_cookie_cb); +EXPORT_SYMBOL(sfe_unregister_flow_cookie_cb); +#endif + +MODULE_DESCRIPTION("Shortcut Forwarding Engine - IPv4 edition"); +MODULE_LICENSE("Dual BSD/GPL"); + diff --git a/shortcut-fe/sfe_ipv6.c b/shortcut-fe/sfe_ipv6.c new file mode 100644 index 000000000..a7cb811a9 --- /dev/null +++ b/shortcut-fe/sfe_ipv6.c @@ -0,0 +1,3617 @@ +/* + * sfe_ipv6.c + * Shortcut forwarding engine - IPv6 support. + * + * Copyright (c) 2015-2016, 2019-2020 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 +#include +#include +#include +#include +#include +#include + +#include "sfe.h" +#include "sfe_cm.h" + +/* + * By default Linux IP header and transport layer header structures are + * unpacked, assuming that such headers should be 32-bit aligned. + * Unfortunately some wireless adaptors can't cope with this requirement and + * some CPUs can't handle misaligned accesses. For those platforms we + * define SFE_IPV6_UNALIGNED_IP_HEADER and mark the structures as packed. + * When we do this the compiler will generate slightly worse code than for the + * aligned case (on most platforms) but will be much quicker than fixing + * things up in an unaligned trap handler. + */ +#define SFE_IPV6_UNALIGNED_IP_HEADER 1 +#if SFE_IPV6_UNALIGNED_IP_HEADER +#define SFE_IPV6_UNALIGNED_STRUCT __attribute__((packed)) +#else +#define SFE_IPV6_UNALIGNED_STRUCT +#endif + +#define CHAR_DEV_MSG_SIZE 768 + +/* + * An Ethernet header, but with an optional "packed" attribute to + * help with performance on some platforms (see the definition of + * SFE_IPV6_UNALIGNED_STRUCT) + */ +struct sfe_ipv6_eth_hdr { + __be16 h_dest[ETH_ALEN / 2]; + __be16 h_source[ETH_ALEN / 2]; + __be16 h_proto; +} SFE_IPV6_UNALIGNED_STRUCT; + +#define SFE_IPV6_DSCP_MASK 0xf03f +#define SFE_IPV6_DSCP_SHIFT 2 + +/* + * An IPv6 header, but with an optional "packed" attribute to + * help with performance on some platforms (see the definition of + * SFE_IPV6_UNALIGNED_STRUCT) + */ +struct sfe_ipv6_ip_hdr { +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 priority:4, + version:4; +#elif defined(__BIG_ENDIAN_BITFIELD) + __u8 version:4, + priority:4; +#else +#error "Please fix " +#endif + __u8 flow_lbl[3]; + __be16 payload_len; + __u8 nexthdr; + __u8 hop_limit; + struct sfe_ipv6_addr saddr; + struct sfe_ipv6_addr daddr; + + /* + * The extension header start here. + */ +} SFE_IPV6_UNALIGNED_STRUCT; + +#define SFE_IPV6_EXT_HDR_HOP 0 +#define SFE_IPV6_EXT_HDR_ROUTING 43 +#define SFE_IPV6_EXT_HDR_FRAG 44 +#define SFE_IPV6_EXT_HDR_ESP 50 +#define SFE_IPV6_EXT_HDR_AH 51 +#define SFE_IPV6_EXT_HDR_NONE 59 +#define SFE_IPV6_EXT_HDR_DST 60 +#define SFE_IPV6_EXT_HDR_MH 135 + +/* + * fragmentation header + */ + +struct sfe_ipv6_frag_hdr { + __u8 nexthdr; + __u8 reserved; + __be16 frag_off; + __be32 identification; +}; + +#define SFE_IPV6_FRAG_OFFSET 0xfff8 + +/* + * generic IPv6 extension header + */ +struct sfe_ipv6_ext_hdr { + __u8 next_hdr; + __u8 hdr_len; + __u8 padding[6]; +} SFE_IPV6_UNALIGNED_STRUCT; + +/* + * A UDP header, but with an optional "packed" attribute to + * help with performance on some platforms (see the definition of + * SFE_IPV6_UNALIGNED_STRUCT) + */ +struct sfe_ipv6_udp_hdr { + __be16 source; + __be16 dest; + __be16 len; + __sum16 check; +} SFE_IPV6_UNALIGNED_STRUCT; + +/* + * A TCP header, but with an optional "packed" attribute to + * help with performance on some platforms (see the definition of + * SFE_IPV6_UNALIGNED_STRUCT) + */ +struct sfe_ipv6_tcp_hdr { + __be16 source; + __be16 dest; + __be32 seq; + __be32 ack_seq; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u16 res1:4, + doff:4, + fin:1, + syn:1, + rst:1, + psh:1, + ack:1, + urg:1, + ece:1, + cwr:1; +#elif defined(__BIG_ENDIAN_BITFIELD) + __u16 doff:4, + res1:4, + cwr:1, + ece:1, + urg:1, + ack:1, + psh:1, + rst:1, + syn:1, + fin:1; +#else +#error "Adjust your defines" +#endif + __be16 window; + __sum16 check; + __be16 urg_ptr; +} SFE_IPV6_UNALIGNED_STRUCT; + +/* + * Specifies the lower bound on ACK numbers carried in the TCP header + */ +#define SFE_IPV6_TCP_MAX_ACK_WINDOW 65520 + +/* + * IPv6 TCP connection match additional data. + */ +struct sfe_ipv6_tcp_connection_match { + u8 win_scale; /* Window scale */ + u32 max_win; /* Maximum window size seen */ + u32 end; /* Sequence number of the next byte to send (seq + segment length) */ + u32 max_end; /* Sequence number of the last byte to ack */ +}; + +/* + * Bit flags for IPv6 connection matching entry. + */ +#define SFE_IPV6_CONNECTION_MATCH_FLAG_XLATE_SRC (1<<0) + /* Perform source translation */ +#define SFE_IPV6_CONNECTION_MATCH_FLAG_XLATE_DEST (1<<1) + /* Perform destination translation */ +#define SFE_IPV6_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK (1<<2) + /* Ignore TCP sequence numbers */ +#define SFE_IPV6_CONNECTION_MATCH_FLAG_WRITE_FAST_ETH_HDR (1<<3) + /* Fast Ethernet header write */ +#define SFE_IPV6_CONNECTION_MATCH_FLAG_WRITE_L2_HDR (1<<4) + /* Fast Ethernet header write */ +#define SFE_IPV6_CONNECTION_MATCH_FLAG_PRIORITY_REMARK (1<<5) + /* remark priority of SKB */ +#define SFE_IPV6_CONNECTION_MATCH_FLAG_DSCP_REMARK (1<<6) + /* remark DSCP of packet */ + +/* + * IPv6 connection matching structure. + */ +struct sfe_ipv6_connection_match { + /* + * References to other objects. + */ + struct sfe_ipv6_connection_match *next; + struct sfe_ipv6_connection_match *prev; + struct sfe_ipv6_connection *connection; + struct sfe_ipv6_connection_match *counter_match; + /* Matches the flow in the opposite direction as the one in connection */ + struct sfe_ipv6_connection_match *active_next; + struct sfe_ipv6_connection_match *active_prev; + bool active; /* Flag to indicate if we're on the active list */ + + /* + * Characteristics that identify flows that match this rule. + */ + struct net_device *match_dev; /* Network device */ + u8 match_protocol; /* Protocol */ + struct sfe_ipv6_addr match_src_ip[1]; /* Source IP address */ + struct sfe_ipv6_addr match_dest_ip[1]; /* Destination IP address */ + __be16 match_src_port; /* Source port/connection ident */ + __be16 match_dest_port; /* Destination port/connection ident */ + + /* + * Control the operations of the match. + */ + u32 flags; /* Bit flags */ +#ifdef CONFIG_NF_FLOW_COOKIE + u32 flow_cookie; /* used flow cookie, for debug */ +#endif +#ifdef CONFIG_XFRM + u32 flow_accel; /* The flow accelerated or not */ +#endif + + /* + * Connection state that we track once we match. + */ + union { /* Protocol-specific state */ + struct sfe_ipv6_tcp_connection_match tcp; + } protocol_state; + /* + * Stats recorded in a sync period. These stats will be added to + * rx_packet_count64/rx_byte_count64 after a sync period. + */ + u32 rx_packet_count; + u32 rx_byte_count; + + /* + * Packet translation information. + */ + struct sfe_ipv6_addr xlate_src_ip[1]; /* Address after source translation */ + __be16 xlate_src_port; /* Port/connection ident after source translation */ + u16 xlate_src_csum_adjustment; + /* Transport layer checksum adjustment after source translation */ + struct sfe_ipv6_addr xlate_dest_ip[1]; /* Address after destination translation */ + __be16 xlate_dest_port; /* Port/connection ident after destination translation */ + u16 xlate_dest_csum_adjustment; + /* Transport layer checksum adjustment after destination translation */ + + /* + * QoS information + */ + u32 priority; + u32 dscp; + + /* + * Packet transmit information. + */ + struct net_device *xmit_dev; /* Network device on which to transmit */ + unsigned short int xmit_dev_mtu; + /* Interface MTU */ + u16 xmit_dest_mac[ETH_ALEN / 2]; + /* Destination MAC address to use when forwarding */ + u16 xmit_src_mac[ETH_ALEN / 2]; + /* Source MAC address to use when forwarding */ + + /* + * Summary stats. + */ + u64 rx_packet_count64; + u64 rx_byte_count64; +}; + +/* + * Per-connection data structure. + */ +struct sfe_ipv6_connection { + struct sfe_ipv6_connection *next; + /* Pointer to the next entry in a hash chain */ + struct sfe_ipv6_connection *prev; + /* Pointer to the previous entry in a hash chain */ + int protocol; /* IP protocol number */ + struct sfe_ipv6_addr src_ip[1]; /* Src IP addr pre-translation */ + struct sfe_ipv6_addr src_ip_xlate[1]; /* Src IP addr post-translation */ + struct sfe_ipv6_addr dest_ip[1]; /* Dest IP addr pre-translation */ + struct sfe_ipv6_addr dest_ip_xlate[1]; /* Dest IP addr post-translation */ + __be16 src_port; /* Src port pre-translation */ + __be16 src_port_xlate; /* Src port post-translation */ + __be16 dest_port; /* Dest port pre-translation */ + __be16 dest_port_xlate; /* Dest port post-translation */ + struct sfe_ipv6_connection_match *original_match; + /* Original direction matching structure */ + struct net_device *original_dev; + /* Original direction source device */ + struct sfe_ipv6_connection_match *reply_match; + /* Reply direction matching structure */ + struct net_device *reply_dev; /* Reply direction source device */ + u64 last_sync_jiffies; /* Jiffies count for the last sync */ + struct sfe_ipv6_connection *all_connections_next; + /* Pointer to the next entry in the list of all connections */ + struct sfe_ipv6_connection *all_connections_prev; + /* Pointer to the previous entry in the list of all connections */ + u32 mark; /* mark for outgoing packet */ + u32 debug_read_seq; /* sequence number for debug dump */ +}; + +/* + * IPv6 connections and hash table size information. + */ +#define SFE_IPV6_CONNECTION_HASH_SHIFT 12 +#define SFE_IPV6_CONNECTION_HASH_SIZE (1 << SFE_IPV6_CONNECTION_HASH_SHIFT) +#define SFE_IPV6_CONNECTION_HASH_MASK (SFE_IPV6_CONNECTION_HASH_SIZE - 1) + +#ifdef CONFIG_NF_FLOW_COOKIE +#define SFE_FLOW_COOKIE_SIZE 2048 +#define SFE_FLOW_COOKIE_MASK 0x7ff + +struct sfe_ipv6_flow_cookie_entry { + struct sfe_ipv6_connection_match *match; + unsigned long last_clean_time; +}; +#endif + +enum sfe_ipv6_exception_events { + SFE_IPV6_EXCEPTION_EVENT_UDP_HEADER_INCOMPLETE, + SFE_IPV6_EXCEPTION_EVENT_UDP_NO_CONNECTION, + SFE_IPV6_EXCEPTION_EVENT_UDP_IP_OPTIONS_OR_INITIAL_FRAGMENT, + SFE_IPV6_EXCEPTION_EVENT_UDP_SMALL_TTL, + SFE_IPV6_EXCEPTION_EVENT_UDP_NEEDS_FRAGMENTATION, + SFE_IPV6_EXCEPTION_EVENT_TCP_HEADER_INCOMPLETE, + SFE_IPV6_EXCEPTION_EVENT_TCP_NO_CONNECTION_SLOW_FLAGS, + SFE_IPV6_EXCEPTION_EVENT_TCP_NO_CONNECTION_FAST_FLAGS, + SFE_IPV6_EXCEPTION_EVENT_TCP_IP_OPTIONS_OR_INITIAL_FRAGMENT, + SFE_IPV6_EXCEPTION_EVENT_TCP_SMALL_TTL, + SFE_IPV6_EXCEPTION_EVENT_TCP_NEEDS_FRAGMENTATION, + SFE_IPV6_EXCEPTION_EVENT_TCP_FLAGS, + SFE_IPV6_EXCEPTION_EVENT_TCP_SEQ_EXCEEDS_RIGHT_EDGE, + SFE_IPV6_EXCEPTION_EVENT_TCP_SMALL_DATA_OFFS, + SFE_IPV6_EXCEPTION_EVENT_TCP_BAD_SACK, + SFE_IPV6_EXCEPTION_EVENT_TCP_BIG_DATA_OFFS, + SFE_IPV6_EXCEPTION_EVENT_TCP_SEQ_BEFORE_LEFT_EDGE, + SFE_IPV6_EXCEPTION_EVENT_TCP_ACK_EXCEEDS_RIGHT_EDGE, + SFE_IPV6_EXCEPTION_EVENT_TCP_ACK_BEFORE_LEFT_EDGE, + SFE_IPV6_EXCEPTION_EVENT_ICMP_HEADER_INCOMPLETE, + SFE_IPV6_EXCEPTION_EVENT_ICMP_UNHANDLED_TYPE, + SFE_IPV6_EXCEPTION_EVENT_ICMP_IPV6_HEADER_INCOMPLETE, + SFE_IPV6_EXCEPTION_EVENT_ICMP_IPV6_NON_V6, + SFE_IPV6_EXCEPTION_EVENT_ICMP_IPV6_IP_OPTIONS_INCOMPLETE, + SFE_IPV6_EXCEPTION_EVENT_ICMP_IPV6_UDP_HEADER_INCOMPLETE, + SFE_IPV6_EXCEPTION_EVENT_ICMP_IPV6_TCP_HEADER_INCOMPLETE, + SFE_IPV6_EXCEPTION_EVENT_ICMP_IPV6_UNHANDLED_PROTOCOL, + SFE_IPV6_EXCEPTION_EVENT_ICMP_NO_CONNECTION, + SFE_IPV6_EXCEPTION_EVENT_ICMP_FLUSHED_CONNECTION, + SFE_IPV6_EXCEPTION_EVENT_HEADER_INCOMPLETE, + SFE_IPV6_EXCEPTION_EVENT_BAD_TOTAL_LENGTH, + SFE_IPV6_EXCEPTION_EVENT_NON_V6, + SFE_IPV6_EXCEPTION_EVENT_NON_INITIAL_FRAGMENT, + SFE_IPV6_EXCEPTION_EVENT_DATAGRAM_INCOMPLETE, + SFE_IPV6_EXCEPTION_EVENT_IP_OPTIONS_INCOMPLETE, + SFE_IPV6_EXCEPTION_EVENT_UNHANDLED_PROTOCOL, + SFE_IPV6_EXCEPTION_EVENT_FLOW_COOKIE_ADD_FAIL, + SFE_IPV6_EXCEPTION_EVENT_LAST +}; + +static char *sfe_ipv6_exception_events_string[SFE_IPV6_EXCEPTION_EVENT_LAST] = { + "UDP_HEADER_INCOMPLETE", + "UDP_NO_CONNECTION", + "UDP_IP_OPTIONS_OR_INITIAL_FRAGMENT", + "UDP_SMALL_TTL", + "UDP_NEEDS_FRAGMENTATION", + "TCP_HEADER_INCOMPLETE", + "TCP_NO_CONNECTION_SLOW_FLAGS", + "TCP_NO_CONNECTION_FAST_FLAGS", + "TCP_IP_OPTIONS_OR_INITIAL_FRAGMENT", + "TCP_SMALL_TTL", + "TCP_NEEDS_FRAGMENTATION", + "TCP_FLAGS", + "TCP_SEQ_EXCEEDS_RIGHT_EDGE", + "TCP_SMALL_DATA_OFFS", + "TCP_BAD_SACK", + "TCP_BIG_DATA_OFFS", + "TCP_SEQ_BEFORE_LEFT_EDGE", + "TCP_ACK_EXCEEDS_RIGHT_EDGE", + "TCP_ACK_BEFORE_LEFT_EDGE", + "ICMP_HEADER_INCOMPLETE", + "ICMP_UNHANDLED_TYPE", + "ICMP_IPV6_HEADER_INCOMPLETE", + "ICMP_IPV6_NON_V6", + "ICMP_IPV6_IP_OPTIONS_INCOMPLETE", + "ICMP_IPV6_UDP_HEADER_INCOMPLETE", + "ICMP_IPV6_TCP_HEADER_INCOMPLETE", + "ICMP_IPV6_UNHANDLED_PROTOCOL", + "ICMP_NO_CONNECTION", + "ICMP_FLUSHED_CONNECTION", + "HEADER_INCOMPLETE", + "BAD_TOTAL_LENGTH", + "NON_V6", + "NON_INITIAL_FRAGMENT", + "DATAGRAM_INCOMPLETE", + "IP_OPTIONS_INCOMPLETE", + "UNHANDLED_PROTOCOL", + "FLOW_COOKIE_ADD_FAIL" +}; + +/* + * Per-module structure. + */ +struct sfe_ipv6 { + spinlock_t lock; /* Lock for SMP correctness */ + struct sfe_ipv6_connection_match *active_head; + /* Head of the list of recently active connections */ + struct sfe_ipv6_connection_match *active_tail; + /* Tail of the list of recently active connections */ + struct sfe_ipv6_connection *all_connections_head; + /* Head of the list of all connections */ + struct sfe_ipv6_connection *all_connections_tail; + /* Tail of the list of all connections */ + unsigned int num_connections; /* Number of connections */ + struct timer_list timer; /* Timer used for periodic sync ops */ + sfe_sync_rule_callback_t __rcu sync_rule_callback; + /* Callback function registered by a connection manager for stats syncing */ + struct sfe_ipv6_connection *conn_hash[SFE_IPV6_CONNECTION_HASH_SIZE]; + /* Connection hash table */ + struct sfe_ipv6_connection_match *conn_match_hash[SFE_IPV6_CONNECTION_HASH_SIZE]; + /* Connection match hash table */ +#ifdef CONFIG_NF_FLOW_COOKIE + struct sfe_ipv6_flow_cookie_entry sfe_flow_cookie_table[SFE_FLOW_COOKIE_SIZE]; + /* flow cookie table*/ + sfe_ipv6_flow_cookie_set_func_t flow_cookie_set_func; + /* function used to configure flow cookie in hardware*/ + int flow_cookie_enable; + /* Enable/disable flow cookie at runtime */ +#endif + + /* + * Stats recorded in a sync period. These stats will be added to + * connection_xxx64 after a sync period. + */ + u32 connection_create_requests; + /* Number of IPv6 connection create requests */ + u32 connection_create_collisions; + /* Number of IPv6 connection create requests that collided with existing hash table entries */ + u32 connection_destroy_requests; + /* Number of IPv6 connection destroy requests */ + u32 connection_destroy_misses; + /* Number of IPv6 connection destroy requests that missed our hash table */ + u32 connection_match_hash_hits; + /* Number of IPv6 connection match hash hits */ + u32 connection_match_hash_reorders; + /* Number of IPv6 connection match hash reorders */ + u32 connection_flushes; /* Number of IPv6 connection flushes */ + u32 packets_forwarded; /* Number of IPv6 packets forwarded */ + u32 packets_not_forwarded; /* Number of IPv6 packets not forwarded */ + u32 exception_events[SFE_IPV6_EXCEPTION_EVENT_LAST]; + + /* + * Summary statistics. + */ + u64 connection_create_requests64; + /* Number of IPv6 connection create requests */ + u64 connection_create_collisions64; + /* Number of IPv6 connection create requests that collided with existing hash table entries */ + u64 connection_destroy_requests64; + /* Number of IPv6 connection destroy requests */ + u64 connection_destroy_misses64; + /* Number of IPv6 connection destroy requests that missed our hash table */ + u64 connection_match_hash_hits64; + /* Number of IPv6 connection match hash hits */ + u64 connection_match_hash_reorders64; + /* Number of IPv6 connection match hash reorders */ + u64 connection_flushes64; /* Number of IPv6 connection flushes */ + u64 packets_forwarded64; /* Number of IPv6 packets forwarded */ + u64 packets_not_forwarded64; + /* Number of IPv6 packets not forwarded */ + u64 exception_events64[SFE_IPV6_EXCEPTION_EVENT_LAST]; + + /* + * Control state. + */ + struct kobject *sys_sfe_ipv6; /* sysfs linkage */ + int debug_dev; /* Major number of the debug char device */ + u32 debug_read_seq; /* sequence number for debug dump */ +}; + +/* + * Enumeration of the XML output. + */ +enum sfe_ipv6_debug_xml_states { + SFE_IPV6_DEBUG_XML_STATE_START, + SFE_IPV6_DEBUG_XML_STATE_CONNECTIONS_START, + SFE_IPV6_DEBUG_XML_STATE_CONNECTIONS_CONNECTION, + SFE_IPV6_DEBUG_XML_STATE_CONNECTIONS_END, + SFE_IPV6_DEBUG_XML_STATE_EXCEPTIONS_START, + SFE_IPV6_DEBUG_XML_STATE_EXCEPTIONS_EXCEPTION, + SFE_IPV6_DEBUG_XML_STATE_EXCEPTIONS_END, + SFE_IPV6_DEBUG_XML_STATE_STATS, + SFE_IPV6_DEBUG_XML_STATE_END, + SFE_IPV6_DEBUG_XML_STATE_DONE +}; + +/* + * XML write state. + */ +struct sfe_ipv6_debug_xml_write_state { + enum sfe_ipv6_debug_xml_states state; + /* XML output file state machine state */ + int iter_exception; /* Next exception iterator */ +}; + +typedef bool (*sfe_ipv6_debug_xml_write_method_t)(struct sfe_ipv6 *si, char *buffer, char *msg, size_t *length, + int *total_read, struct sfe_ipv6_debug_xml_write_state *ws); + +static struct sfe_ipv6 __si6; + +/* + * sfe_ipv6_get_debug_dev() + */ +static ssize_t sfe_ipv6_get_debug_dev(struct device *dev, struct device_attribute *attr, char *buf); + +/* + * sysfs attributes. + */ +static const struct device_attribute sfe_ipv6_debug_dev_attr = + __ATTR(debug_dev, S_IWUSR | S_IRUGO, sfe_ipv6_get_debug_dev, NULL); + +/* + * sfe_ipv6_is_ext_hdr() + * check if we recognize ipv6 extension header + */ +static inline bool sfe_ipv6_is_ext_hdr(u8 hdr) +{ + return (hdr == SFE_IPV6_EXT_HDR_HOP) || + (hdr == SFE_IPV6_EXT_HDR_ROUTING) || + (hdr == SFE_IPV6_EXT_HDR_FRAG) || + (hdr == SFE_IPV6_EXT_HDR_AH) || + (hdr == SFE_IPV6_EXT_HDR_DST) || + (hdr == SFE_IPV6_EXT_HDR_MH); +} + +/* + * sfe_ipv6_change_dsfield() + * change dscp field in IPv6 packet + */ +static inline void sfe_ipv6_change_dsfield(struct sfe_ipv6_ip_hdr *iph, u8 dscp) +{ + __be16 *p = (__be16 *)iph; + + *p = ((*p & htons(SFE_IPV6_DSCP_MASK)) | htons((u16)dscp << 4)); +} + +/* + * sfe_ipv6_get_connection_match_hash() + * Generate the hash used in connection match lookups. + */ +static inline unsigned int sfe_ipv6_get_connection_match_hash(struct net_device *dev, u8 protocol, + struct sfe_ipv6_addr *src_ip, __be16 src_port, + struct sfe_ipv6_addr *dest_ip, __be16 dest_port) +{ + u32 idx, hash = 0; + size_t dev_addr = (size_t)dev; + + for (idx = 0; idx < 4; idx++) { + hash ^= src_ip->addr[idx] ^ dest_ip->addr[idx]; + } + hash = ((u32)dev_addr) ^ hash ^ protocol ^ ntohs(src_port ^ dest_port); + return ((hash >> SFE_IPV6_CONNECTION_HASH_SHIFT) ^ hash) & SFE_IPV6_CONNECTION_HASH_MASK; +} + +/* + * sfe_ipv6_find_connection_match() + * Get the IPv6 flow match info that corresponds to a particular 5-tuple. + * + * On entry we must be holding the lock that protects the hash table. + */ +static struct sfe_ipv6_connection_match * +sfe_ipv6_find_connection_match(struct sfe_ipv6 *si, struct net_device *dev, u8 protocol, + struct sfe_ipv6_addr *src_ip, __be16 src_port, + struct sfe_ipv6_addr *dest_ip, __be16 dest_port) +{ + struct sfe_ipv6_connection_match *cm; + struct sfe_ipv6_connection_match *head; + unsigned int conn_match_idx; + + conn_match_idx = sfe_ipv6_get_connection_match_hash(dev, protocol, src_ip, src_port, dest_ip, dest_port); + cm = si->conn_match_hash[conn_match_idx]; + + /* + * If we don't have anything in this chain then bail. + */ + if (unlikely(!cm)) { + return NULL; + } + + /* + * Hopefully the first entry is the one we want. + */ + if ((cm->match_src_port == src_port) + && (cm->match_dest_port == dest_port) + && (sfe_ipv6_addr_equal(cm->match_src_ip, src_ip)) + && (sfe_ipv6_addr_equal(cm->match_dest_ip, dest_ip)) + && (cm->match_protocol == protocol) + && (cm->match_dev == dev)) { + si->connection_match_hash_hits++; + return cm; + } + + /* + * Unfortunately we didn't find it at head, so we search it in chain and + * move matching entry to the top of the hash chain. We presume that this + * will be reused again very quickly. + */ + head = cm; + do { + cm = cm->next; + } while (cm && (cm->match_src_port != src_port + || cm->match_dest_port != dest_port + || !sfe_ipv6_addr_equal(cm->match_src_ip, src_ip) + || !sfe_ipv6_addr_equal(cm->match_dest_ip, dest_ip) + || cm->match_protocol != protocol + || cm->match_dev != dev)); + + /* + * Not found then we're done. + */ + if (unlikely(!cm)) { + return NULL; + } + + /* + * We found a match so move it. + */ + if (cm->next) { + cm->next->prev = cm->prev; + } + cm->prev->next = cm->next; + cm->prev = NULL; + cm->next = head; + head->prev = cm; + si->conn_match_hash[conn_match_idx] = cm; + si->connection_match_hash_reorders++; + + return cm; +} + +/* + * sfe_ipv6_connection_match_update_summary_stats() + * Update the summary stats for a connection match entry. + */ +static inline void sfe_ipv6_connection_match_update_summary_stats(struct sfe_ipv6_connection_match *cm) +{ + cm->rx_packet_count64 += cm->rx_packet_count; + cm->rx_packet_count = 0; + cm->rx_byte_count64 += cm->rx_byte_count; + cm->rx_byte_count = 0; +} + +/* + * sfe_ipv6_connection_match_compute_translations() + * Compute port and address translations for a connection match entry. + */ +static void sfe_ipv6_connection_match_compute_translations(struct sfe_ipv6_connection_match *cm) +{ + u32 diff[9]; + u32 *idx_32; + u16 *idx_16; + + /* + * Before we insert the entry look to see if this is tagged as doing address + * translations. If it is then work out the adjustment that we need to apply + * to the transport checksum. + */ + if (cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_XLATE_SRC) { + u32 adj = 0; + u32 carry = 0; + + /* + * Precompute an incremental checksum adjustment so we can + * edit packets in this stream very quickly. The algorithm is from RFC1624. + */ + idx_32 = diff; + *(idx_32++) = cm->match_src_ip->addr[0]; + *(idx_32++) = cm->match_src_ip->addr[1]; + *(idx_32++) = cm->match_src_ip->addr[2]; + *(idx_32++) = cm->match_src_ip->addr[3]; + + idx_16 = (u16 *)idx_32; + *(idx_16++) = cm->match_src_port; + *(idx_16++) = ~cm->xlate_src_port; + idx_32 = (u32 *)idx_16; + + *(idx_32++) = ~cm->xlate_src_ip->addr[0]; + *(idx_32++) = ~cm->xlate_src_ip->addr[1]; + *(idx_32++) = ~cm->xlate_src_ip->addr[2]; + *(idx_32++) = ~cm->xlate_src_ip->addr[3]; + + /* + * When we compute this fold it down to a 16-bit offset + * as that way we can avoid having to do a double + * folding of the twos-complement result because the + * addition of 2 16-bit values cannot cause a double + * wrap-around! + */ + for (idx_32 = diff; idx_32 < diff + 9; idx_32++) { + u32 w = *idx_32; + adj += carry; + adj += w; + carry = (w > adj); + } + adj += carry; + adj = (adj & 0xffff) + (adj >> 16); + adj = (adj & 0xffff) + (adj >> 16); + cm->xlate_src_csum_adjustment = (u16)adj; + } + + if (cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_XLATE_DEST) { + u32 adj = 0; + u32 carry = 0; + + /* + * Precompute an incremental checksum adjustment so we can + * edit packets in this stream very quickly. The algorithm is from RFC1624. + */ + idx_32 = diff; + *(idx_32++) = cm->match_dest_ip->addr[0]; + *(idx_32++) = cm->match_dest_ip->addr[1]; + *(idx_32++) = cm->match_dest_ip->addr[2]; + *(idx_32++) = cm->match_dest_ip->addr[3]; + + idx_16 = (u16 *)idx_32; + *(idx_16++) = cm->match_dest_port; + *(idx_16++) = ~cm->xlate_dest_port; + idx_32 = (u32 *)idx_16; + + *(idx_32++) = ~cm->xlate_dest_ip->addr[0]; + *(idx_32++) = ~cm->xlate_dest_ip->addr[1]; + *(idx_32++) = ~cm->xlate_dest_ip->addr[2]; + *(idx_32++) = ~cm->xlate_dest_ip->addr[3]; + + /* + * When we compute this fold it down to a 16-bit offset + * as that way we can avoid having to do a double + * folding of the twos-complement result because the + * addition of 2 16-bit values cannot cause a double + * wrap-around! + */ + for (idx_32 = diff; idx_32 < diff + 9; idx_32++) { + u32 w = *idx_32; + adj += carry; + adj += w; + carry = (w > adj); + } + adj += carry; + adj = (adj & 0xffff) + (adj >> 16); + adj = (adj & 0xffff) + (adj >> 16); + cm->xlate_dest_csum_adjustment = (u16)adj; + } +} + +/* + * sfe_ipv6_update_summary_stats() + * Update the summary stats. + */ +static void sfe_ipv6_update_summary_stats(struct sfe_ipv6 *si) +{ + int i; + + si->connection_create_requests64 += si->connection_create_requests; + si->connection_create_requests = 0; + si->connection_create_collisions64 += si->connection_create_collisions; + si->connection_create_collisions = 0; + si->connection_destroy_requests64 += si->connection_destroy_requests; + si->connection_destroy_requests = 0; + si->connection_destroy_misses64 += si->connection_destroy_misses; + si->connection_destroy_misses = 0; + si->connection_match_hash_hits64 += si->connection_match_hash_hits; + si->connection_match_hash_hits = 0; + si->connection_match_hash_reorders64 += si->connection_match_hash_reorders; + si->connection_match_hash_reorders = 0; + si->connection_flushes64 += si->connection_flushes; + si->connection_flushes = 0; + si->packets_forwarded64 += si->packets_forwarded; + si->packets_forwarded = 0; + si->packets_not_forwarded64 += si->packets_not_forwarded; + si->packets_not_forwarded = 0; + + for (i = 0; i < SFE_IPV6_EXCEPTION_EVENT_LAST; i++) { + si->exception_events64[i] += si->exception_events[i]; + si->exception_events[i] = 0; + } +} + +/* + * sfe_ipv6_insert_connection_match() + * Insert a connection match into the hash. + * + * On entry we must be holding the lock that protects the hash table. + */ +static inline void sfe_ipv6_insert_connection_match(struct sfe_ipv6 *si, + struct sfe_ipv6_connection_match *cm) +{ + struct sfe_ipv6_connection_match **hash_head; + struct sfe_ipv6_connection_match *prev_head; + unsigned int conn_match_idx + = sfe_ipv6_get_connection_match_hash(cm->match_dev, cm->match_protocol, + cm->match_src_ip, cm->match_src_port, + cm->match_dest_ip, cm->match_dest_port); + + hash_head = &si->conn_match_hash[conn_match_idx]; + prev_head = *hash_head; + cm->prev = NULL; + if (prev_head) { + prev_head->prev = cm; + } + + cm->next = prev_head; + *hash_head = cm; + +#ifdef CONFIG_NF_FLOW_COOKIE + if (!si->flow_cookie_enable || !(cm->flags & (SFE_IPV6_CONNECTION_MATCH_FLAG_XLATE_SRC | SFE_IPV6_CONNECTION_MATCH_FLAG_XLATE_DEST))) + return; + + /* + * Configure hardware to put a flow cookie in packet of this flow, + * then we can accelerate the lookup process when we received this packet. + */ + for (conn_match_idx = 1; conn_match_idx < SFE_FLOW_COOKIE_SIZE; conn_match_idx++) { + struct sfe_ipv6_flow_cookie_entry *entry = &si->sfe_flow_cookie_table[conn_match_idx]; + + if ((NULL == entry->match) && time_is_before_jiffies(entry->last_clean_time + HZ)) { + sfe_ipv6_flow_cookie_set_func_t func; + + rcu_read_lock(); + func = rcu_dereference(si->flow_cookie_set_func); + if (func) { + if (!func(cm->match_protocol, cm->match_src_ip->addr, cm->match_src_port, + cm->match_dest_ip->addr, cm->match_dest_port, conn_match_idx)) { + entry->match = cm; + cm->flow_cookie = conn_match_idx; + } else { + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_FLOW_COOKIE_ADD_FAIL]++; + } + } + rcu_read_unlock(); + + break; + } + } +#endif +} + +/* + * sfe_ipv6_remove_connection_match() + * Remove a connection match object from the hash. + * + * On entry we must be holding the lock that protects the hash table. + */ +static inline void sfe_ipv6_remove_connection_match(struct sfe_ipv6 *si, struct sfe_ipv6_connection_match *cm) +{ +#ifdef CONFIG_NF_FLOW_COOKIE + if (si->flow_cookie_enable) { + /* + * Tell hardware that we no longer need a flow cookie in packet of this flow + */ + unsigned int conn_match_idx; + + for (conn_match_idx = 1; conn_match_idx < SFE_FLOW_COOKIE_SIZE; conn_match_idx++) { + struct sfe_ipv6_flow_cookie_entry *entry = &si->sfe_flow_cookie_table[conn_match_idx]; + + if (cm == entry->match) { + sfe_ipv6_flow_cookie_set_func_t func; + + rcu_read_lock(); + func = rcu_dereference(si->flow_cookie_set_func); + if (func) { + func(cm->match_protocol, cm->match_src_ip->addr, cm->match_src_port, + cm->match_dest_ip->addr, cm->match_dest_port, 0); + } + rcu_read_unlock(); + + cm->flow_cookie = 0; + entry->match = NULL; + entry->last_clean_time = jiffies; + break; + } + } + } +#endif + + /* + * Unlink the connection match entry from the hash. + */ + if (cm->prev) { + cm->prev->next = cm->next; + } else { + unsigned int conn_match_idx + = sfe_ipv6_get_connection_match_hash(cm->match_dev, cm->match_protocol, + cm->match_src_ip, cm->match_src_port, + cm->match_dest_ip, cm->match_dest_port); + si->conn_match_hash[conn_match_idx] = cm->next; + } + + if (cm->next) { + cm->next->prev = cm->prev; + } + + /* + * If the connection match entry is in the active list remove it. + */ + if (cm->active) { + if (likely(cm->active_prev)) { + cm->active_prev->active_next = cm->active_next; + } else { + si->active_head = cm->active_next; + } + + if (likely(cm->active_next)) { + cm->active_next->active_prev = cm->active_prev; + } else { + si->active_tail = cm->active_prev; + } + } +} + +/* + * sfe_ipv6_get_connection_hash() + * Generate the hash used in connection lookups. + */ +static inline unsigned int sfe_ipv6_get_connection_hash(u8 protocol, struct sfe_ipv6_addr *src_ip, __be16 src_port, + struct sfe_ipv6_addr *dest_ip, __be16 dest_port) +{ + u32 idx, hash = 0; + + for (idx = 0; idx < 4; idx++) { + hash ^= src_ip->addr[idx] ^ dest_ip->addr[idx]; + } + hash = hash ^ protocol ^ ntohs(src_port ^ dest_port); + return ((hash >> SFE_IPV6_CONNECTION_HASH_SHIFT) ^ hash) & SFE_IPV6_CONNECTION_HASH_MASK; +} + +/* + * sfe_ipv6_find_connection() + * Get the IPv6 connection info that corresponds to a particular 5-tuple. + * + * On entry we must be holding the lock that protects the hash table. + */ +static inline struct sfe_ipv6_connection *sfe_ipv6_find_connection(struct sfe_ipv6 *si, u32 protocol, + struct sfe_ipv6_addr *src_ip, __be16 src_port, + struct sfe_ipv6_addr *dest_ip, __be16 dest_port) +{ + struct sfe_ipv6_connection *c; + unsigned int conn_idx = sfe_ipv6_get_connection_hash(protocol, src_ip, src_port, dest_ip, dest_port); + c = si->conn_hash[conn_idx]; + + /* + * If we don't have anything in this chain then bale. + */ + if (unlikely(!c)) { + return NULL; + } + + /* + * Hopefully the first entry is the one we want. + */ + if ((c->src_port == src_port) + && (c->dest_port == dest_port) + && (sfe_ipv6_addr_equal(c->src_ip, src_ip)) + && (sfe_ipv6_addr_equal(c->dest_ip, dest_ip)) + && (c->protocol == protocol)) { + return c; + } + + /* + * Unfortunately we didn't find it at head, so we search it in chain. + */ + do { + c = c->next; + } while (c && (c->src_port != src_port + || c->dest_port != dest_port + || !sfe_ipv6_addr_equal(c->src_ip, src_ip) + || !sfe_ipv6_addr_equal(c->dest_ip, dest_ip) + || c->protocol != protocol)); + + /* + * Will need connection entry for next create/destroy metadata, + * So no need to re-order entry for these requests + */ + return c; +} + +/* + * sfe_ipv6_mark_rule() + * Updates the mark for a current offloaded connection + * + * Will take hash lock upon entry + */ +void sfe_ipv6_mark_rule(struct sfe_connection_mark *mark) +{ + struct sfe_ipv6 *si = &__si6; + struct sfe_ipv6_connection *c; + + spin_lock_bh(&si->lock); + c = sfe_ipv6_find_connection(si, mark->protocol, + mark->src_ip.ip6, mark->src_port, + mark->dest_ip.ip6, mark->dest_port); + if (c) { + WARN_ON((0 != c->mark) && (0 == mark->mark)); + c->mark = mark->mark; + } + spin_unlock_bh(&si->lock); + + if (c) { + DEBUG_TRACE("Matching connection found for mark, " + "setting from %08x to %08x\n", + c->mark, mark->mark); + } +} + +/* + * sfe_ipv6_insert_connection() + * Insert a connection into the hash. + * + * On entry we must be holding the lock that protects the hash table. + */ +static void sfe_ipv6_insert_connection(struct sfe_ipv6 *si, struct sfe_ipv6_connection *c) +{ + struct sfe_ipv6_connection **hash_head; + struct sfe_ipv6_connection *prev_head; + unsigned int conn_idx; + + /* + * Insert entry into the connection hash. + */ + conn_idx = sfe_ipv6_get_connection_hash(c->protocol, c->src_ip, c->src_port, + c->dest_ip, c->dest_port); + hash_head = &si->conn_hash[conn_idx]; + prev_head = *hash_head; + c->prev = NULL; + if (prev_head) { + prev_head->prev = c; + } + + c->next = prev_head; + *hash_head = c; + + /* + * Insert entry into the "all connections" list. + */ + if (si->all_connections_tail) { + c->all_connections_prev = si->all_connections_tail; + si->all_connections_tail->all_connections_next = c; + } else { + c->all_connections_prev = NULL; + si->all_connections_head = c; + } + + si->all_connections_tail = c; + c->all_connections_next = NULL; + si->num_connections++; + + /* + * Insert the connection match objects too. + */ + sfe_ipv6_insert_connection_match(si, c->original_match); + sfe_ipv6_insert_connection_match(si, c->reply_match); +} + +/* + * sfe_ipv6_remove_connection() + * Remove a sfe_ipv6_connection object from the hash. + * + * On entry we must be holding the lock that protects the hash table. + */ +static void sfe_ipv6_remove_connection(struct sfe_ipv6 *si, struct sfe_ipv6_connection *c) +{ + /* + * Remove the connection match objects. + */ + sfe_ipv6_remove_connection_match(si, c->reply_match); + sfe_ipv6_remove_connection_match(si, c->original_match); + + /* + * Unlink the connection. + */ + if (c->prev) { + c->prev->next = c->next; + } else { + unsigned int conn_idx = sfe_ipv6_get_connection_hash(c->protocol, c->src_ip, c->src_port, + c->dest_ip, c->dest_port); + si->conn_hash[conn_idx] = c->next; + } + + if (c->next) { + c->next->prev = c->prev; + } + + /* + * Unlink connection from all_connections list + */ + if (c->all_connections_prev) { + c->all_connections_prev->all_connections_next = c->all_connections_next; + } else { + si->all_connections_head = c->all_connections_next; + } + + if (c->all_connections_next) { + c->all_connections_next->all_connections_prev = c->all_connections_prev; + } else { + si->all_connections_tail = c->all_connections_prev; + } + + si->num_connections--; +} + +/* + * sfe_ipv6_gen_sync_connection() + * Sync a connection. + * + * On entry to this function we expect that the lock for the connection is either + * already held or isn't required. + */ +static void sfe_ipv6_gen_sync_connection(struct sfe_ipv6 *si, struct sfe_ipv6_connection *c, + struct sfe_connection_sync *sis, sfe_sync_reason_t reason, + u64 now_jiffies) +{ + struct sfe_ipv6_connection_match *original_cm; + struct sfe_ipv6_connection_match *reply_cm; + + /* + * Fill in the update message. + */ + sis->is_v6 = 1; + sis->protocol = c->protocol; + sis->src_ip.ip6[0] = c->src_ip[0]; + sis->src_ip_xlate.ip6[0] = c->src_ip_xlate[0]; + sis->dest_ip.ip6[0] = c->dest_ip[0]; + sis->dest_ip_xlate.ip6[0] = c->dest_ip_xlate[0]; + sis->src_port = c->src_port; + sis->src_port_xlate = c->src_port_xlate; + sis->dest_port = c->dest_port; + sis->dest_port_xlate = c->dest_port_xlate; + + original_cm = c->original_match; + reply_cm = c->reply_match; + sis->src_td_max_window = original_cm->protocol_state.tcp.max_win; + sis->src_td_end = original_cm->protocol_state.tcp.end; + sis->src_td_max_end = original_cm->protocol_state.tcp.max_end; + sis->dest_td_max_window = reply_cm->protocol_state.tcp.max_win; + sis->dest_td_end = reply_cm->protocol_state.tcp.end; + sis->dest_td_max_end = reply_cm->protocol_state.tcp.max_end; + + sis->src_new_packet_count = original_cm->rx_packet_count; + sis->src_new_byte_count = original_cm->rx_byte_count; + sis->dest_new_packet_count = reply_cm->rx_packet_count; + sis->dest_new_byte_count = reply_cm->rx_byte_count; + + sfe_ipv6_connection_match_update_summary_stats(original_cm); + sfe_ipv6_connection_match_update_summary_stats(reply_cm); + + sis->src_dev = original_cm->match_dev; + sis->src_packet_count = original_cm->rx_packet_count64; + sis->src_byte_count = original_cm->rx_byte_count64; + + sis->dest_dev = reply_cm->match_dev; + sis->dest_packet_count = reply_cm->rx_packet_count64; + sis->dest_byte_count = reply_cm->rx_byte_count64; + + sis->reason = reason; + + /* + * Get the time increment since our last sync. + */ + sis->delta_jiffies = now_jiffies - c->last_sync_jiffies; + c->last_sync_jiffies = now_jiffies; +} + +/* + * sfe_ipv6_flush_connection() + * Flush a connection and free all associated resources. + * + * We need to be called with bottom halves disabled locally as we need to acquire + * the connection hash lock and release it again. In general we're actually called + * from within a BH and so we're fine, but we're also called when connections are + * torn down. + */ +static void sfe_ipv6_flush_connection(struct sfe_ipv6 *si, + struct sfe_ipv6_connection *c, + sfe_sync_reason_t reason) +{ + struct sfe_connection_sync sis; + u64 now_jiffies; + sfe_sync_rule_callback_t sync_rule_callback; + + rcu_read_lock(); + spin_lock_bh(&si->lock); + si->connection_flushes++; + sync_rule_callback = rcu_dereference(si->sync_rule_callback); + spin_unlock_bh(&si->lock); + + if (sync_rule_callback) { + /* + * Generate a sync message and then sync. + */ + now_jiffies = get_jiffies_64(); + sfe_ipv6_gen_sync_connection(si, c, &sis, reason, now_jiffies); + sync_rule_callback(&sis); + } + + rcu_read_unlock(); + + /* + * Release our hold of the source and dest devices and free the memory + * for our connection objects. + */ + dev_put(c->original_dev); + dev_put(c->reply_dev); + kfree(c->original_match); + kfree(c->reply_match); + kfree(c); +} + +/* + * sfe_ipv6_recv_udp() + * Handle UDP packet receives and forwarding. + */ +static int sfe_ipv6_recv_udp(struct sfe_ipv6 *si, struct sk_buff *skb, struct net_device *dev, + unsigned int len, struct sfe_ipv6_ip_hdr *iph, unsigned int ihl, bool flush_on_find) +{ + struct sfe_ipv6_udp_hdr *udph; + struct sfe_ipv6_addr *src_ip; + struct sfe_ipv6_addr *dest_ip; + __be16 src_port; + __be16 dest_port; + struct sfe_ipv6_connection_match *cm; + struct net_device *xmit_dev; + + /* + * Is our packet too short to contain a valid UDP header? + */ + if (!pskb_may_pull(skb, (sizeof(struct sfe_ipv6_udp_hdr) + ihl))) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_UDP_HEADER_INCOMPLETE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("packet too short for UDP header\n"); + return 0; + } + + /* + * Read the IP address and port information. Read the IP header data first + * because we've almost certainly got that in the cache. We may not yet have + * the UDP header cached though so allow more time for any prefetching. + */ + src_ip = &iph->saddr; + dest_ip = &iph->daddr; + + udph = (struct sfe_ipv6_udp_hdr *)(skb->data + ihl); + src_port = udph->source; + dest_port = udph->dest; + + spin_lock_bh(&si->lock); + + /* + * Look for a connection match. + */ +#ifdef CONFIG_NF_FLOW_COOKIE + cm = si->sfe_flow_cookie_table[skb->flow_cookie & SFE_FLOW_COOKIE_MASK].match; + if (unlikely(!cm)) { + cm = sfe_ipv6_find_connection_match(si, dev, IPPROTO_UDP, src_ip, src_port, dest_ip, dest_port); + } +#else + cm = sfe_ipv6_find_connection_match(si, dev, IPPROTO_UDP, src_ip, src_port, dest_ip, dest_port); +#endif + if (unlikely(!cm)) { + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_UDP_NO_CONNECTION]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("no connection found\n"); + return 0; + } + + /* + * If our packet has beern marked as "flush on find" we can't actually + * forward it in the fast path, but now that we've found an associated + * connection we can flush that out before we process the packet. + */ + if (unlikely(flush_on_find)) { + struct sfe_ipv6_connection *c = cm->connection; + sfe_ipv6_remove_connection(si, c); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_UDP_IP_OPTIONS_OR_INITIAL_FRAGMENT]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("flush on find\n"); + sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + +#ifdef CONFIG_XFRM + /* + * We can't accelerate the flow on this direction, just let it go + * through the slow path. + */ + if (unlikely(!cm->flow_accel)) { + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + return 0; + } +#endif + + /* + * Does our hop_limit allow forwarding? + */ + if (unlikely(iph->hop_limit < 2)) { + struct sfe_ipv6_connection *c = cm->connection; + sfe_ipv6_remove_connection(si, c); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_UDP_SMALL_TTL]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("hop_limit too low\n"); + sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + /* + * If our packet is larger than the MTU of the transmit interface then + * we can't forward it easily. + */ + if (unlikely(len > cm->xmit_dev_mtu)) { + struct sfe_ipv6_connection *c = cm->connection; + sfe_ipv6_remove_connection(si, c); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_UDP_NEEDS_FRAGMENTATION]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("larger than mtu\n"); + sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + /* + * From this point on we're good to modify the packet. + */ + + /* + * Check if skb was cloned. If it was, unshare it. Because + * the data area is going to be written in this path and we don't want to + * change the cloned skb's data section. + */ + if (unlikely(skb_cloned(skb))) { + DEBUG_TRACE("%px: skb is a cloned skb\n", skb); + skb = skb_unshare(skb, GFP_ATOMIC); + if (!skb) { + DEBUG_WARN("Failed to unshare the cloned skb\n"); + return 0; + } + + /* + * Update the iph and udph pointers with the unshared skb's data area. + */ + iph = (struct sfe_ipv6_ip_hdr *)skb->data; + udph = (struct sfe_ipv6_udp_hdr *)(skb->data + ihl); + } + + /* + * Update DSCP + */ + if (unlikely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_DSCP_REMARK)) { + sfe_ipv6_change_dsfield(iph, cm->dscp); + } + + /* + * Decrement our hop_limit. + */ + iph->hop_limit -= 1; + + /* + * Do we have to perform translations of the source address/port? + */ + if (unlikely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_XLATE_SRC)) { + u16 udp_csum; + + iph->saddr = cm->xlate_src_ip[0]; + udph->source = cm->xlate_src_port; + + /* + * Do we have a non-zero UDP checksum? If we do then we need + * to update it. + */ + udp_csum = udph->check; + if (likely(udp_csum)) { + u32 sum = udp_csum + cm->xlate_src_csum_adjustment; + sum = (sum & 0xffff) + (sum >> 16); + udph->check = (u16)sum; + } + } + + /* + * Do we have to perform translations of the destination address/port? + */ + if (unlikely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_XLATE_DEST)) { + u16 udp_csum; + + iph->daddr = cm->xlate_dest_ip[0]; + udph->dest = cm->xlate_dest_port; + + /* + * Do we have a non-zero UDP checksum? If we do then we need + * to update it. + */ + udp_csum = udph->check; + if (likely(udp_csum)) { + u32 sum = udp_csum + cm->xlate_dest_csum_adjustment; + sum = (sum & 0xffff) + (sum >> 16); + udph->check = (u16)sum; + } + } + + /* + * Update traffic stats. + */ + cm->rx_packet_count++; + cm->rx_byte_count += len; + + /* + * If we're not already on the active list then insert ourselves at the tail + * of the current list. + */ + if (unlikely(!cm->active)) { + cm->active = true; + cm->active_prev = si->active_tail; + if (likely(si->active_tail)) { + si->active_tail->active_next = cm; + } else { + si->active_head = cm; + } + si->active_tail = cm; + } + + xmit_dev = cm->xmit_dev; + skb->dev = xmit_dev; + + /* + * Check to see if we need to write a header. + */ + if (likely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_WRITE_L2_HDR)) { + if (unlikely(!(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_WRITE_FAST_ETH_HDR))) { + dev_hard_header(skb, xmit_dev, ETH_P_IPV6, + cm->xmit_dest_mac, cm->xmit_src_mac, len); + } else { + /* + * For the simple case we write this really fast. + */ + struct sfe_ipv6_eth_hdr *eth = (struct sfe_ipv6_eth_hdr *)__skb_push(skb, ETH_HLEN); + eth->h_proto = htons(ETH_P_IPV6); + eth->h_dest[0] = cm->xmit_dest_mac[0]; + eth->h_dest[1] = cm->xmit_dest_mac[1]; + eth->h_dest[2] = cm->xmit_dest_mac[2]; + eth->h_source[0] = cm->xmit_src_mac[0]; + eth->h_source[1] = cm->xmit_src_mac[1]; + eth->h_source[2] = cm->xmit_src_mac[2]; + } + } + + /* + * Update priority of skb. + */ + if (unlikely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_PRIORITY_REMARK)) { + skb->priority = cm->priority; + } + + /* + * Mark outgoing packet. + */ + skb->mark = cm->connection->mark; + if (skb->mark) { + DEBUG_TRACE("SKB MARK is NON ZERO %x\n", skb->mark); + } + + si->packets_forwarded++; + spin_unlock_bh(&si->lock); + + /* + * We're going to check for GSO flags when we transmit the packet so + * start fetching the necessary cache line now. + */ + prefetch(skb_shinfo(skb)); + + /* + * Mark that this packet has been fast forwarded. + */ + skb->fast_forwarded = 1; + + /* + * Send the packet on its way. + */ + dev_queue_xmit(skb); + + return 1; +} + +/* + * sfe_ipv6_process_tcp_option_sack() + * Parse TCP SACK option and update ack according + */ +static bool sfe_ipv6_process_tcp_option_sack(const struct sfe_ipv6_tcp_hdr *th, const u32 data_offs, + u32 *ack) +{ + u32 length = sizeof(struct sfe_ipv6_tcp_hdr); + u8 *ptr = (u8 *)th + length; + + /* + * Ignore processing if TCP packet has only TIMESTAMP option. + */ + if (likely(data_offs == length + TCPOLEN_TIMESTAMP + 1 + 1) + && likely(ptr[0] == TCPOPT_NOP) + && likely(ptr[1] == TCPOPT_NOP) + && likely(ptr[2] == TCPOPT_TIMESTAMP) + && likely(ptr[3] == TCPOLEN_TIMESTAMP)) { + return true; + } + + /* + * TCP options. Parse SACK option. + */ + while (length < data_offs) { + u8 size; + u8 kind; + + ptr = (u8 *)th + length; + kind = *ptr; + + /* + * NOP, for padding + * Not in the switch because to fast escape and to not calculate size + */ + if (kind == TCPOPT_NOP) { + length++; + continue; + } + + if (kind == TCPOPT_SACK) { + u32 sack = 0; + u8 re = 1 + 1; + + size = *(ptr + 1); + if ((size < (1 + 1 + TCPOLEN_SACK_PERBLOCK)) + || ((size - (1 + 1)) % (TCPOLEN_SACK_PERBLOCK)) + || (size > (data_offs - length))) { + return false; + } + + re += 4; + while (re < size) { + u32 sack_re; + u8 *sptr = ptr + re; + sack_re = (sptr[0] << 24) | (sptr[1] << 16) | (sptr[2] << 8) | sptr[3]; + if (sack_re > sack) { + sack = sack_re; + } + re += TCPOLEN_SACK_PERBLOCK; + } + if (sack > *ack) { + *ack = sack; + } + length += size; + continue; + } + if (kind == TCPOPT_EOL) { + return true; + } + size = *(ptr + 1); + if (size < 2) { + return false; + } + length += size; + } + + return true; +} + +/* + * sfe_ipv6_recv_tcp() + * Handle TCP packet receives and forwarding. + */ +static int sfe_ipv6_recv_tcp(struct sfe_ipv6 *si, struct sk_buff *skb, struct net_device *dev, + unsigned int len, struct sfe_ipv6_ip_hdr *iph, unsigned int ihl, bool flush_on_find) +{ + struct sfe_ipv6_tcp_hdr *tcph; + struct sfe_ipv6_addr *src_ip; + struct sfe_ipv6_addr *dest_ip; + __be16 src_port; + __be16 dest_port; + struct sfe_ipv6_connection_match *cm; + struct sfe_ipv6_connection_match *counter_cm; + u32 flags; + struct net_device *xmit_dev; + + /* + * Is our packet too short to contain a valid UDP header? + */ + if (!pskb_may_pull(skb, (sizeof(struct sfe_ipv6_tcp_hdr) + ihl))) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_TCP_HEADER_INCOMPLETE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("packet too short for TCP header\n"); + return 0; + } + + /* + * Read the IP address and port information. Read the IP header data first + * because we've almost certainly got that in the cache. We may not yet have + * the TCP header cached though so allow more time for any prefetching. + */ + src_ip = &iph->saddr; + dest_ip = &iph->daddr; + + tcph = (struct sfe_ipv6_tcp_hdr *)(skb->data + ihl); + src_port = tcph->source; + dest_port = tcph->dest; + flags = tcp_flag_word(tcph); + + spin_lock_bh(&si->lock); + + /* + * Look for a connection match. + */ +#ifdef CONFIG_NF_FLOW_COOKIE + cm = si->sfe_flow_cookie_table[skb->flow_cookie & SFE_FLOW_COOKIE_MASK].match; + if (unlikely(!cm)) { + cm = sfe_ipv6_find_connection_match(si, dev, IPPROTO_TCP, src_ip, src_port, dest_ip, dest_port); + } +#else + cm = sfe_ipv6_find_connection_match(si, dev, IPPROTO_TCP, src_ip, src_port, dest_ip, dest_port); +#endif + if (unlikely(!cm)) { + /* + * We didn't get a connection but as TCP is connection-oriented that + * may be because this is a non-fast connection (not running established). + * For diagnostic purposes we differentiate this here. + */ + if (likely((flags & (TCP_FLAG_SYN | TCP_FLAG_RST | TCP_FLAG_FIN | TCP_FLAG_ACK)) == TCP_FLAG_ACK)) { + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_TCP_NO_CONNECTION_FAST_FLAGS]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("no connection found - fast flags\n"); + return 0; + } + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_TCP_NO_CONNECTION_SLOW_FLAGS]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("no connection found - slow flags: 0x%x\n", + flags & (TCP_FLAG_SYN | TCP_FLAG_RST | TCP_FLAG_FIN | TCP_FLAG_ACK)); + return 0; + } + + /* + * If our packet has beern marked as "flush on find" we can't actually + * forward it in the fast path, but now that we've found an associated + * connection we can flush that out before we process the packet. + */ + if (unlikely(flush_on_find)) { + struct sfe_ipv6_connection *c = cm->connection; + sfe_ipv6_remove_connection(si, c); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_TCP_IP_OPTIONS_OR_INITIAL_FRAGMENT]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("flush on find\n"); + sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + +#ifdef CONFIG_XFRM + /* + * We can't accelerate the flow on this direction, just let it go + * through the slow path. + */ + if (unlikely(!cm->flow_accel)) { + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + return 0; + } +#endif + + /* + * Does our hop_limit allow forwarding? + */ + if (unlikely(iph->hop_limit < 2)) { + struct sfe_ipv6_connection *c = cm->connection; + sfe_ipv6_remove_connection(si, c); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_TCP_SMALL_TTL]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("hop_limit too low\n"); + sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + /* + * If our packet is larger than the MTU of the transmit interface then + * we can't forward it easily. + */ + if (unlikely((len > cm->xmit_dev_mtu) && !skb_is_gso(skb))) { + struct sfe_ipv6_connection *c = cm->connection; + sfe_ipv6_remove_connection(si, c); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_TCP_NEEDS_FRAGMENTATION]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("larger than mtu\n"); + sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + /* + * Look at our TCP flags. Anything missing an ACK or that has RST, SYN or FIN + * set is not a fast path packet. + */ + if (unlikely((flags & (TCP_FLAG_SYN | TCP_FLAG_RST | TCP_FLAG_FIN | TCP_FLAG_ACK)) != TCP_FLAG_ACK)) { + struct sfe_ipv6_connection *c = cm->connection; + sfe_ipv6_remove_connection(si, c); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_TCP_FLAGS]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("TCP flags: 0x%x are not fast\n", + flags & (TCP_FLAG_SYN | TCP_FLAG_RST | TCP_FLAG_FIN | TCP_FLAG_ACK)); + sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + counter_cm = cm->counter_match; + + /* + * Are we doing sequence number checking? + */ + if (likely(!(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK))) { + u32 seq; + u32 ack; + u32 sack; + u32 data_offs; + u32 end; + u32 left_edge; + u32 scaled_win; + u32 max_end; + + /* + * Is our sequence fully past the right hand edge of the window? + */ + seq = ntohl(tcph->seq); + if (unlikely((s32)(seq - (cm->protocol_state.tcp.max_end + 1)) > 0)) { + struct sfe_ipv6_connection *c = cm->connection; + sfe_ipv6_remove_connection(si, c); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_TCP_SEQ_EXCEEDS_RIGHT_EDGE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("seq: %u exceeds right edge: %u\n", + seq, cm->protocol_state.tcp.max_end + 1); + sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + /* + * Check that our TCP data offset isn't too short. + */ + data_offs = tcph->doff << 2; + if (unlikely(data_offs < sizeof(struct sfe_ipv6_tcp_hdr))) { + struct sfe_ipv6_connection *c = cm->connection; + sfe_ipv6_remove_connection(si, c); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_TCP_SMALL_DATA_OFFS]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("TCP data offset: %u, too small\n", data_offs); + sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + /* + * Update ACK according to any SACK option. + */ + ack = ntohl(tcph->ack_seq); + sack = ack; + if (unlikely(!sfe_ipv6_process_tcp_option_sack(tcph, data_offs, &sack))) { + struct sfe_ipv6_connection *c = cm->connection; + sfe_ipv6_remove_connection(si, c); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_TCP_BAD_SACK]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("TCP option SACK size is wrong\n"); + sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + /* + * Check that our TCP data offset isn't past the end of the packet. + */ + data_offs += sizeof(struct sfe_ipv6_ip_hdr); + if (unlikely(len < data_offs)) { + struct sfe_ipv6_connection *c = cm->connection; + sfe_ipv6_remove_connection(si, c); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_TCP_BIG_DATA_OFFS]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("TCP data offset: %u, past end of packet: %u\n", + data_offs, len); + sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + end = seq + len - data_offs; + + /* + * Is our sequence fully before the left hand edge of the window? + */ + if (unlikely((s32)(end - (cm->protocol_state.tcp.end + - counter_cm->protocol_state.tcp.max_win - 1)) < 0)) { + struct sfe_ipv6_connection *c = cm->connection; + sfe_ipv6_remove_connection(si, c); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_TCP_SEQ_BEFORE_LEFT_EDGE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("seq: %u before left edge: %u\n", + end, cm->protocol_state.tcp.end - counter_cm->protocol_state.tcp.max_win - 1); + sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + /* + * Are we acking data that is to the right of what has been sent? + */ + if (unlikely((s32)(sack - (counter_cm->protocol_state.tcp.end + 1)) > 0)) { + struct sfe_ipv6_connection *c = cm->connection; + sfe_ipv6_remove_connection(si, c); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_TCP_ACK_EXCEEDS_RIGHT_EDGE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("ack: %u exceeds right edge: %u\n", + sack, counter_cm->protocol_state.tcp.end + 1); + sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + /* + * Is our ack too far before the left hand edge of the window? + */ + left_edge = counter_cm->protocol_state.tcp.end + - cm->protocol_state.tcp.max_win + - SFE_IPV6_TCP_MAX_ACK_WINDOW + - 1; + if (unlikely((s32)(sack - left_edge) < 0)) { + struct sfe_ipv6_connection *c = cm->connection; + sfe_ipv6_remove_connection(si, c); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_TCP_ACK_BEFORE_LEFT_EDGE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("ack: %u before left edge: %u\n", sack, left_edge); + sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + /* + * Have we just seen the largest window size yet for this connection? If yes + * then we need to record the new value. + */ + scaled_win = ntohs(tcph->window) << cm->protocol_state.tcp.win_scale; + scaled_win += (sack - ack); + if (unlikely(cm->protocol_state.tcp.max_win < scaled_win)) { + cm->protocol_state.tcp.max_win = scaled_win; + } + + /* + * If our sequence and/or ack numbers have advanced then record the new state. + */ + if (likely((s32)(end - cm->protocol_state.tcp.end) >= 0)) { + cm->protocol_state.tcp.end = end; + } + + max_end = sack + scaled_win; + if (likely((s32)(max_end - counter_cm->protocol_state.tcp.max_end) >= 0)) { + counter_cm->protocol_state.tcp.max_end = max_end; + } + } + + /* + * From this point on we're good to modify the packet. + */ + + /* + * Check if skb was cloned. If it was, unshare it. Because + * the data area is going to be written in this path and we don't want to + * change the cloned skb's data section. + */ + if (unlikely(skb_cloned(skb))) { + DEBUG_TRACE("%px: skb is a cloned skb\n", skb); + skb = skb_unshare(skb, GFP_ATOMIC); + if (!skb) { + DEBUG_WARN("Failed to unshare the cloned skb\n"); + return 0; + } + + /* + * Update the iph and tcph pointers with the unshared skb's data area. + */ + iph = (struct sfe_ipv6_ip_hdr *)skb->data; + tcph = (struct sfe_ipv6_tcp_hdr *)(skb->data + ihl); + } + + /* + * Update DSCP + */ + if (unlikely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_DSCP_REMARK)) { + sfe_ipv6_change_dsfield(iph, cm->dscp); + } + + /* + * Decrement our hop_limit. + */ + iph->hop_limit -= 1; + + /* + * Do we have to perform translations of the source address/port? + */ + if (unlikely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_XLATE_SRC)) { + u16 tcp_csum; + u32 sum; + + iph->saddr = cm->xlate_src_ip[0]; + tcph->source = cm->xlate_src_port; + + /* + * Do we have a non-zero UDP checksum? If we do then we need + * to update it. + */ + tcp_csum = tcph->check; + sum = tcp_csum + cm->xlate_src_csum_adjustment; + sum = (sum & 0xffff) + (sum >> 16); + tcph->check = (u16)sum; + } + + /* + * Do we have to perform translations of the destination address/port? + */ + if (unlikely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_XLATE_DEST)) { + u16 tcp_csum; + u32 sum; + + iph->daddr = cm->xlate_dest_ip[0]; + tcph->dest = cm->xlate_dest_port; + + /* + * Do we have a non-zero UDP checksum? If we do then we need + * to update it. + */ + tcp_csum = tcph->check; + sum = tcp_csum + cm->xlate_dest_csum_adjustment; + sum = (sum & 0xffff) + (sum >> 16); + tcph->check = (u16)sum; + } + + /* + * Update traffic stats. + */ + cm->rx_packet_count++; + cm->rx_byte_count += len; + + /* + * If we're not already on the active list then insert ourselves at the tail + * of the current list. + */ + if (unlikely(!cm->active)) { + cm->active = true; + cm->active_prev = si->active_tail; + if (likely(si->active_tail)) { + si->active_tail->active_next = cm; + } else { + si->active_head = cm; + } + si->active_tail = cm; + } + + xmit_dev = cm->xmit_dev; + skb->dev = xmit_dev; + + /* + * Check to see if we need to write a header. + */ + if (likely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_WRITE_L2_HDR)) { + if (unlikely(!(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_WRITE_FAST_ETH_HDR))) { + dev_hard_header(skb, xmit_dev, ETH_P_IPV6, + cm->xmit_dest_mac, cm->xmit_src_mac, len); + } else { + /* + * For the simple case we write this really fast. + */ + struct sfe_ipv6_eth_hdr *eth = (struct sfe_ipv6_eth_hdr *)__skb_push(skb, ETH_HLEN); + eth->h_proto = htons(ETH_P_IPV6); + eth->h_dest[0] = cm->xmit_dest_mac[0]; + eth->h_dest[1] = cm->xmit_dest_mac[1]; + eth->h_dest[2] = cm->xmit_dest_mac[2]; + eth->h_source[0] = cm->xmit_src_mac[0]; + eth->h_source[1] = cm->xmit_src_mac[1]; + eth->h_source[2] = cm->xmit_src_mac[2]; + } + } + + /* + * Update priority of skb. + */ + if (unlikely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_PRIORITY_REMARK)) { + skb->priority = cm->priority; + } + + /* + * Mark outgoing packet + */ + skb->mark = cm->connection->mark; + if (skb->mark) { + DEBUG_TRACE("SKB MARK is NON ZERO %x\n", skb->mark); + } + + si->packets_forwarded++; + spin_unlock_bh(&si->lock); + + /* + * We're going to check for GSO flags when we transmit the packet so + * start fetching the necessary cache line now. + */ + prefetch(skb_shinfo(skb)); + + /* + * Mark that this packet has been fast forwarded. + */ + skb->fast_forwarded = 1; + + /* + * Send the packet on its way. + */ + dev_queue_xmit(skb); + + return 1; +} + +/* + * sfe_ipv6_recv_icmp() + * Handle ICMP packet receives. + * + * ICMP packets aren't handled as a "fast path" and always have us process them + * through the default Linux stack. What we do need to do is look for any errors + * about connections we are handling in the fast path. If we find any such + * connections then we want to flush their state so that the ICMP error path + * within Linux has all of the correct state should it need it. + */ +static int sfe_ipv6_recv_icmp(struct sfe_ipv6 *si, struct sk_buff *skb, struct net_device *dev, + unsigned int len, struct sfe_ipv6_ip_hdr *iph, unsigned int ihl) +{ + struct icmp6hdr *icmph; + struct sfe_ipv6_ip_hdr *icmp_iph; + struct sfe_ipv6_udp_hdr *icmp_udph; + struct sfe_ipv6_tcp_hdr *icmp_tcph; + struct sfe_ipv6_addr *src_ip; + struct sfe_ipv6_addr *dest_ip; + __be16 src_port; + __be16 dest_port; + struct sfe_ipv6_connection_match *cm; + struct sfe_ipv6_connection *c; + u8 next_hdr; + + /* + * Is our packet too short to contain a valid ICMP header? + */ + len -= ihl; + if (!pskb_may_pull(skb, ihl + sizeof(struct icmp6hdr))) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_ICMP_HEADER_INCOMPLETE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("packet too short for ICMP header\n"); + return 0; + } + + /* + * We only handle "destination unreachable" and "time exceeded" messages. + */ + icmph = (struct icmp6hdr *)(skb->data + ihl); + if ((icmph->icmp6_type != ICMPV6_DEST_UNREACH) + && (icmph->icmp6_type != ICMPV6_TIME_EXCEED)) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_ICMP_UNHANDLED_TYPE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("unhandled ICMP type: 0x%x\n", icmph->icmp6_type); + return 0; + } + + /* + * Do we have the full embedded IP header? + * We should have 8 bytes of next L4 header - that's enough to identify + * the connection. + */ + len -= sizeof(struct icmp6hdr); + ihl += sizeof(struct icmp6hdr); + if (!pskb_may_pull(skb, ihl + sizeof(struct sfe_ipv6_ip_hdr) + sizeof(struct sfe_ipv6_ext_hdr))) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_ICMP_IPV6_HEADER_INCOMPLETE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("Embedded IP header not complete\n"); + return 0; + } + + /* + * Is our embedded IP version wrong? + */ + icmp_iph = (struct sfe_ipv6_ip_hdr *)(icmph + 1); + if (unlikely(icmp_iph->version != 6)) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_ICMP_IPV6_NON_V6]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("IP version: %u\n", icmp_iph->version); + return 0; + } + + len -= sizeof(struct sfe_ipv6_ip_hdr); + ihl += sizeof(struct sfe_ipv6_ip_hdr); + next_hdr = icmp_iph->nexthdr; + while (unlikely(sfe_ipv6_is_ext_hdr(next_hdr))) { + struct sfe_ipv6_ext_hdr *ext_hdr; + unsigned int ext_hdr_len; + + ext_hdr = (struct sfe_ipv6_ext_hdr *)(skb->data + ihl); + if (next_hdr == SFE_IPV6_EXT_HDR_FRAG) { + struct sfe_ipv6_frag_hdr *frag_hdr = (struct sfe_ipv6_frag_hdr *)ext_hdr; + unsigned int frag_off = ntohs(frag_hdr->frag_off); + + if (frag_off & SFE_IPV6_FRAG_OFFSET) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_NON_INITIAL_FRAGMENT]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("non-initial fragment\n"); + return 0; + } + } + + ext_hdr_len = ext_hdr->hdr_len; + ext_hdr_len <<= 3; + ext_hdr_len += sizeof(struct sfe_ipv6_ext_hdr); + len -= ext_hdr_len; + ihl += ext_hdr_len; + /* + * We should have 8 bytes of next header - that's enough to identify + * the connection. + */ + if (!pskb_may_pull(skb, ihl + sizeof(struct sfe_ipv6_ext_hdr))) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_HEADER_INCOMPLETE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("extension header %d not completed\n", next_hdr); + return 0; + } + + next_hdr = ext_hdr->next_hdr; + } + + /* + * Handle the embedded transport layer header. + */ + switch (next_hdr) { + case IPPROTO_UDP: + icmp_udph = (struct sfe_ipv6_udp_hdr *)(skb->data + ihl); + src_port = icmp_udph->source; + dest_port = icmp_udph->dest; + break; + + case IPPROTO_TCP: + icmp_tcph = (struct sfe_ipv6_tcp_hdr *)(skb->data + ihl); + src_port = icmp_tcph->source; + dest_port = icmp_tcph->dest; + break; + + default: + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_ICMP_IPV6_UNHANDLED_PROTOCOL]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("Unhandled embedded IP protocol: %u\n", next_hdr); + return 0; + } + + src_ip = &icmp_iph->saddr; + dest_ip = &icmp_iph->daddr; + + spin_lock_bh(&si->lock); + + /* + * Look for a connection match. Note that we reverse the source and destination + * here because our embedded message contains a packet that was sent in the + * opposite direction to the one in which we just received it. It will have + * been sent on the interface from which we received it though so that's still + * ok to use. + */ + cm = sfe_ipv6_find_connection_match(si, dev, icmp_iph->nexthdr, dest_ip, dest_port, src_ip, src_port); + if (unlikely(!cm)) { + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_ICMP_NO_CONNECTION]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("no connection found\n"); + return 0; + } + + /* + * We found a connection so now remove it from the connection list and flush + * its state. + */ + c = cm->connection; + sfe_ipv6_remove_connection(si, c); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_ICMP_FLUSHED_CONNECTION]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; +} + +/* + * sfe_ipv6_recv() + * Handle packet receives and forwaring. + * + * Returns 1 if the packet is forwarded or 0 if it isn't. + */ +int sfe_ipv6_recv(struct net_device *dev, struct sk_buff *skb) +{ + struct sfe_ipv6 *si = &__si6; + unsigned int len; + unsigned int payload_len; + unsigned int ihl = sizeof(struct sfe_ipv6_ip_hdr); + bool flush_on_find = false; + struct sfe_ipv6_ip_hdr *iph; + u8 next_hdr; + + /* + * Check that we have space for an IP header and an uplayer header here. + */ + len = skb->len; + if (!pskb_may_pull(skb, ihl + sizeof(struct sfe_ipv6_ext_hdr))) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_HEADER_INCOMPLETE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("len: %u is too short\n", len); + return 0; + } + + /* + * Is our IP version wrong? + */ + iph = (struct sfe_ipv6_ip_hdr *)skb->data; + if (unlikely(iph->version != 6)) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_NON_V6]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("IP version: %u\n", iph->version); + return 0; + } + + /* + * Does our datagram fit inside the skb? + */ + payload_len = ntohs(iph->payload_len); + if (unlikely(payload_len > (len - ihl))) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_DATAGRAM_INCOMPLETE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("payload_len: %u, exceeds len: %u\n", payload_len, (len - (unsigned int)sizeof(struct sfe_ipv6_ip_hdr))); + return 0; + } + + next_hdr = iph->nexthdr; + while (unlikely(sfe_ipv6_is_ext_hdr(next_hdr))) { + struct sfe_ipv6_ext_hdr *ext_hdr; + unsigned int ext_hdr_len; + + ext_hdr = (struct sfe_ipv6_ext_hdr *)(skb->data + ihl); + if (next_hdr == SFE_IPV6_EXT_HDR_FRAG) { + struct sfe_ipv6_frag_hdr *frag_hdr = (struct sfe_ipv6_frag_hdr *)ext_hdr; + unsigned int frag_off = ntohs(frag_hdr->frag_off); + + if (frag_off & SFE_IPV6_FRAG_OFFSET) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_NON_INITIAL_FRAGMENT]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("non-initial fragment\n"); + return 0; + } + } + + ext_hdr_len = ext_hdr->hdr_len; + ext_hdr_len <<= 3; + ext_hdr_len += sizeof(struct sfe_ipv6_ext_hdr); + ihl += ext_hdr_len; + if (!pskb_may_pull(skb, ihl + sizeof(struct sfe_ipv6_ext_hdr))) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_HEADER_INCOMPLETE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("extension header %d not completed\n", next_hdr); + return 0; + } + + flush_on_find = true; + next_hdr = ext_hdr->next_hdr; + } + + if (IPPROTO_UDP == next_hdr) { + return sfe_ipv6_recv_udp(si, skb, dev, len, iph, ihl, flush_on_find); + } + + if (IPPROTO_TCP == next_hdr) { + return sfe_ipv6_recv_tcp(si, skb, dev, len, iph, ihl, flush_on_find); + } + + if (IPPROTO_ICMPV6 == next_hdr) { + return sfe_ipv6_recv_icmp(si, skb, dev, len, iph, ihl); + } + + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_UNHANDLED_PROTOCOL]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("not UDP, TCP or ICMP: %u\n", next_hdr); + return 0; +} + +/* + * sfe_ipv6_update_tcp_state() + * update TCP window variables. + */ +static void +sfe_ipv6_update_tcp_state(struct sfe_ipv6_connection *c, + struct sfe_connection_create *sic) +{ + struct sfe_ipv6_connection_match *orig_cm; + struct sfe_ipv6_connection_match *repl_cm; + struct sfe_ipv6_tcp_connection_match *orig_tcp; + struct sfe_ipv6_tcp_connection_match *repl_tcp; + + orig_cm = c->original_match; + repl_cm = c->reply_match; + orig_tcp = &orig_cm->protocol_state.tcp; + repl_tcp = &repl_cm->protocol_state.tcp; + + /* update orig */ + if (orig_tcp->max_win < sic->src_td_max_window) { + orig_tcp->max_win = sic->src_td_max_window; + } + if ((s32)(orig_tcp->end - sic->src_td_end) < 0) { + orig_tcp->end = sic->src_td_end; + } + if ((s32)(orig_tcp->max_end - sic->src_td_max_end) < 0) { + orig_tcp->max_end = sic->src_td_max_end; + } + + /* update reply */ + if (repl_tcp->max_win < sic->dest_td_max_window) { + repl_tcp->max_win = sic->dest_td_max_window; + } + if ((s32)(repl_tcp->end - sic->dest_td_end) < 0) { + repl_tcp->end = sic->dest_td_end; + } + if ((s32)(repl_tcp->max_end - sic->dest_td_max_end) < 0) { + repl_tcp->max_end = sic->dest_td_max_end; + } + + /* update match flags */ + orig_cm->flags &= ~SFE_IPV6_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK; + repl_cm->flags &= ~SFE_IPV6_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK; + if (sic->flags & SFE_CREATE_FLAG_NO_SEQ_CHECK) { + orig_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK; + repl_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK; + } +} + +/* + * sfe_ipv6_update_protocol_state() + * update protocol specified state machine. + */ +static void +sfe_ipv6_update_protocol_state(struct sfe_ipv6_connection *c, + struct sfe_connection_create *sic) +{ + switch (sic->protocol) { + case IPPROTO_TCP: + sfe_ipv6_update_tcp_state(c, sic); + break; + } +} + +/* + * sfe_ipv6_update_rule() + * update forwarding rule after rule is created. + */ +void sfe_ipv6_update_rule(struct sfe_connection_create *sic) +{ + struct sfe_ipv6_connection *c; + struct sfe_ipv6 *si = &__si6; + + spin_lock_bh(&si->lock); + + c = sfe_ipv6_find_connection(si, + sic->protocol, + sic->src_ip.ip6, + sic->src_port, + sic->dest_ip.ip6, + sic->dest_port); + if (c != NULL) { + sfe_ipv6_update_protocol_state(c, sic); + } + + spin_unlock_bh(&si->lock); +} + +/* + * sfe_ipv6_create_rule() + * Create a forwarding rule. + */ +int sfe_ipv6_create_rule(struct sfe_connection_create *sic) +{ + struct sfe_ipv6 *si = &__si6; + struct sfe_ipv6_connection *c; + struct sfe_ipv6_connection_match *original_cm; + struct sfe_ipv6_connection_match *reply_cm; + struct net_device *dest_dev; + struct net_device *src_dev; + + dest_dev = sic->dest_dev; + src_dev = sic->src_dev; + + if (unlikely((dest_dev->reg_state != NETREG_REGISTERED) || + (src_dev->reg_state != NETREG_REGISTERED))) { + return -EINVAL; + } + + spin_lock_bh(&si->lock); + si->connection_create_requests++; + + /* + * Check to see if there is already a flow that matches the rule we're + * trying to create. If there is then we can't create a new one. + */ + c = sfe_ipv6_find_connection(si, + sic->protocol, + sic->src_ip.ip6, + sic->src_port, + sic->dest_ip.ip6, + sic->dest_port); + if (c != NULL) { + si->connection_create_collisions++; + + /* + * If we already have the flow then it's likely that this + * request to create the connection rule contains more + * up-to-date information. Check and update accordingly. + */ + sfe_ipv6_update_protocol_state(c, sic); + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("connection already exists - mark: %08x, p: %d\n" + " s: %s:%pxM:%pI6:%u, d: %s:%pxM:%pI6:%u\n", + sic->mark, sic->protocol, + sic->src_dev->name, sic->src_mac, sic->src_ip.ip6, ntohs(sic->src_port), + sic->dest_dev->name, sic->dest_mac, sic->dest_ip.ip6, ntohs(sic->dest_port)); + return -EADDRINUSE; + } + + /* + * Allocate the various connection tracking objects. + */ + c = (struct sfe_ipv6_connection *)kmalloc(sizeof(struct sfe_ipv6_connection), GFP_ATOMIC); + if (unlikely(!c)) { + spin_unlock_bh(&si->lock); + return -ENOMEM; + } + + original_cm = (struct sfe_ipv6_connection_match *)kmalloc(sizeof(struct sfe_ipv6_connection_match), GFP_ATOMIC); + if (unlikely(!original_cm)) { + spin_unlock_bh(&si->lock); + kfree(c); + return -ENOMEM; + } + + reply_cm = (struct sfe_ipv6_connection_match *)kmalloc(sizeof(struct sfe_ipv6_connection_match), GFP_ATOMIC); + if (unlikely(!reply_cm)) { + spin_unlock_bh(&si->lock); + kfree(original_cm); + kfree(c); + return -ENOMEM; + } + + /* + * Fill in the "original" direction connection matching object. + * Note that the transmit MAC address is "dest_mac_xlate" because + * we always know both ends of a connection by their translated + * addresses and not their public addresses. + */ + original_cm->match_dev = src_dev; + original_cm->match_protocol = sic->protocol; + original_cm->match_src_ip[0] = sic->src_ip.ip6[0]; + original_cm->match_src_port = sic->src_port; + original_cm->match_dest_ip[0] = sic->dest_ip.ip6[0]; + original_cm->match_dest_port = sic->dest_port; + original_cm->xlate_src_ip[0] = sic->src_ip_xlate.ip6[0]; + original_cm->xlate_src_port = sic->src_port_xlate; + original_cm->xlate_dest_ip[0] = sic->dest_ip_xlate.ip6[0]; + original_cm->xlate_dest_port = sic->dest_port_xlate; + original_cm->rx_packet_count = 0; + original_cm->rx_packet_count64 = 0; + original_cm->rx_byte_count = 0; + original_cm->rx_byte_count64 = 0; + original_cm->xmit_dev = dest_dev; + original_cm->xmit_dev_mtu = sic->dest_mtu; + memcpy(original_cm->xmit_src_mac, dest_dev->dev_addr, ETH_ALEN); + memcpy(original_cm->xmit_dest_mac, sic->dest_mac_xlate, ETH_ALEN); + original_cm->connection = c; + original_cm->counter_match = reply_cm; + original_cm->flags = 0; + if (sic->flags & SFE_CREATE_FLAG_REMARK_PRIORITY) { + original_cm->priority = sic->src_priority; + original_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_PRIORITY_REMARK; + } + if (sic->flags & SFE_CREATE_FLAG_REMARK_DSCP) { + original_cm->dscp = sic->src_dscp << SFE_IPV6_DSCP_SHIFT; + original_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_DSCP_REMARK; + } +#ifdef CONFIG_NF_FLOW_COOKIE + original_cm->flow_cookie = 0; +#endif +#ifdef CONFIG_XFRM + original_cm->flow_accel = sic->original_accel; +#endif + original_cm->active_next = NULL; + original_cm->active_prev = NULL; + original_cm->active = false; + + /* + * For PPP links we don't write an L2 header. For everything else we do. + */ + if (!(dest_dev->flags & IFF_POINTOPOINT)) { + original_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_WRITE_L2_HDR; + + /* + * If our dev writes Ethernet headers then we can write a really fast + * version. + */ + if (dest_dev->header_ops) { + if (dest_dev->header_ops->create == eth_header) { + original_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_WRITE_FAST_ETH_HDR; + } + } + } + + /* + * Fill in the "reply" direction connection matching object. + */ + reply_cm->match_dev = dest_dev; + reply_cm->match_protocol = sic->protocol; + reply_cm->match_src_ip[0] = sic->dest_ip_xlate.ip6[0]; + reply_cm->match_src_port = sic->dest_port_xlate; + reply_cm->match_dest_ip[0] = sic->src_ip_xlate.ip6[0]; + reply_cm->match_dest_port = sic->src_port_xlate; + reply_cm->xlate_src_ip[0] = sic->dest_ip.ip6[0]; + reply_cm->xlate_src_port = sic->dest_port; + reply_cm->xlate_dest_ip[0] = sic->src_ip.ip6[0]; + reply_cm->xlate_dest_port = sic->src_port; + reply_cm->rx_packet_count = 0; + reply_cm->rx_packet_count64 = 0; + reply_cm->rx_byte_count = 0; + reply_cm->rx_byte_count64 = 0; + reply_cm->xmit_dev = src_dev; + reply_cm->xmit_dev_mtu = sic->src_mtu; + memcpy(reply_cm->xmit_src_mac, src_dev->dev_addr, ETH_ALEN); + memcpy(reply_cm->xmit_dest_mac, sic->src_mac, ETH_ALEN); + reply_cm->connection = c; + reply_cm->counter_match = original_cm; + reply_cm->flags = 0; + if (sic->flags & SFE_CREATE_FLAG_REMARK_PRIORITY) { + reply_cm->priority = sic->dest_priority; + reply_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_PRIORITY_REMARK; + } + if (sic->flags & SFE_CREATE_FLAG_REMARK_DSCP) { + reply_cm->dscp = sic->dest_dscp << SFE_IPV6_DSCP_SHIFT; + reply_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_DSCP_REMARK; + } +#ifdef CONFIG_NF_FLOW_COOKIE + reply_cm->flow_cookie = 0; +#endif +#ifdef CONFIG_XFRM + reply_cm->flow_accel = sic->reply_accel; +#endif + reply_cm->active_next = NULL; + reply_cm->active_prev = NULL; + reply_cm->active = false; + + /* + * For PPP links we don't write an L2 header. For everything else we do. + */ + if (!(src_dev->flags & IFF_POINTOPOINT)) { + reply_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_WRITE_L2_HDR; + + /* + * If our dev writes Ethernet headers then we can write a really fast + * version. + */ + if (src_dev->header_ops) { + if (src_dev->header_ops->create == eth_header) { + reply_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_WRITE_FAST_ETH_HDR; + } + } + } + + + if (!sfe_ipv6_addr_equal(sic->dest_ip.ip6, sic->dest_ip_xlate.ip6) || sic->dest_port != sic->dest_port_xlate) { + original_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_XLATE_DEST; + reply_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_XLATE_SRC; + } + + if (!sfe_ipv6_addr_equal(sic->src_ip.ip6, sic->src_ip_xlate.ip6) || sic->src_port != sic->src_port_xlate) { + original_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_XLATE_SRC; + reply_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_XLATE_DEST; + } + + c->protocol = sic->protocol; + c->src_ip[0] = sic->src_ip.ip6[0]; + c->src_ip_xlate[0] = sic->src_ip_xlate.ip6[0]; + c->src_port = sic->src_port; + c->src_port_xlate = sic->src_port_xlate; + c->original_dev = src_dev; + c->original_match = original_cm; + c->dest_ip[0] = sic->dest_ip.ip6[0]; + c->dest_ip_xlate[0] = sic->dest_ip_xlate.ip6[0]; + c->dest_port = sic->dest_port; + c->dest_port_xlate = sic->dest_port_xlate; + c->reply_dev = dest_dev; + c->reply_match = reply_cm; + c->mark = sic->mark; + c->debug_read_seq = 0; + c->last_sync_jiffies = get_jiffies_64(); + + /* + * Take hold of our source and dest devices for the duration of the connection. + */ + dev_hold(c->original_dev); + dev_hold(c->reply_dev); + + /* + * Initialize the protocol-specific information that we track. + */ + switch (sic->protocol) { + case IPPROTO_TCP: + original_cm->protocol_state.tcp.win_scale = sic->src_td_window_scale; + original_cm->protocol_state.tcp.max_win = sic->src_td_max_window ? sic->src_td_max_window : 1; + original_cm->protocol_state.tcp.end = sic->src_td_end; + original_cm->protocol_state.tcp.max_end = sic->src_td_max_end; + reply_cm->protocol_state.tcp.win_scale = sic->dest_td_window_scale; + reply_cm->protocol_state.tcp.max_win = sic->dest_td_max_window ? sic->dest_td_max_window : 1; + reply_cm->protocol_state.tcp.end = sic->dest_td_end; + reply_cm->protocol_state.tcp.max_end = sic->dest_td_max_end; + if (sic->flags & SFE_CREATE_FLAG_NO_SEQ_CHECK) { + original_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK; + reply_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK; + } + break; + } + + sfe_ipv6_connection_match_compute_translations(original_cm); + sfe_ipv6_connection_match_compute_translations(reply_cm); + sfe_ipv6_insert_connection(si, c); + + spin_unlock_bh(&si->lock); + + /* + * We have everything we need! + */ + DEBUG_INFO("new connection - mark: %08x, p: %d\n" + " s: %s:%pxM(%pxM):%pI6(%pI6):%u(%u)\n" + " d: %s:%pxM(%pxM):%pI6(%pI6):%u(%u)\n", + sic->mark, sic->protocol, + sic->src_dev->name, sic->src_mac, sic->src_mac_xlate, + sic->src_ip.ip6, sic->src_ip_xlate.ip6, ntohs(sic->src_port), ntohs(sic->src_port_xlate), + dest_dev->name, sic->dest_mac, sic->dest_mac_xlate, + sic->dest_ip.ip6, sic->dest_ip_xlate.ip6, ntohs(sic->dest_port), ntohs(sic->dest_port_xlate)); + + return 0; +} + +/* + * sfe_ipv6_destroy_rule() + * Destroy a forwarding rule. + */ +void sfe_ipv6_destroy_rule(struct sfe_connection_destroy *sid) +{ + struct sfe_ipv6 *si = &__si6; + struct sfe_ipv6_connection *c; + + spin_lock_bh(&si->lock); + si->connection_destroy_requests++; + + /* + * Check to see if we have a flow that matches the rule we're trying + * to destroy. If there isn't then we can't destroy it. + */ + c = sfe_ipv6_find_connection(si, sid->protocol, sid->src_ip.ip6, sid->src_port, + sid->dest_ip.ip6, sid->dest_port); + if (!c) { + si->connection_destroy_misses++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("connection does not exist - p: %d, s: %pI6:%u, d: %pI6:%u\n", + sid->protocol, sid->src_ip.ip6, ntohs(sid->src_port), + sid->dest_ip.ip6, ntohs(sid->dest_port)); + return; + } + + /* + * Remove our connection details from the hash tables. + */ + sfe_ipv6_remove_connection(si, c); + spin_unlock_bh(&si->lock); + + sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_DESTROY); + + DEBUG_INFO("connection destroyed - p: %d, s: %pI6:%u, d: %pI6:%u\n", + sid->protocol, sid->src_ip.ip6, ntohs(sid->src_port), + sid->dest_ip.ip6, ntohs(sid->dest_port)); +} + +/* + * sfe_ipv6_register_sync_rule_callback() + * Register a callback for rule synchronization. + */ +void sfe_ipv6_register_sync_rule_callback(sfe_sync_rule_callback_t sync_rule_callback) +{ + struct sfe_ipv6 *si = &__si6; + + spin_lock_bh(&si->lock); + rcu_assign_pointer(si->sync_rule_callback, sync_rule_callback); + spin_unlock_bh(&si->lock); +} + +/* + * sfe_ipv6_get_debug_dev() + */ +static ssize_t sfe_ipv6_get_debug_dev(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct sfe_ipv6 *si = &__si6; + ssize_t count; + int num; + + spin_lock_bh(&si->lock); + num = si->debug_dev; + spin_unlock_bh(&si->lock); + + count = snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", num); + return count; +} + +/* + * sfe_ipv6_destroy_all_rules_for_dev() + * Destroy all connections that match a particular device. + * + * If we pass dev as NULL then this destroys all connections. + */ +void sfe_ipv6_destroy_all_rules_for_dev(struct net_device *dev) +{ + struct sfe_ipv6 *si = &__si6; + struct sfe_ipv6_connection *c; + +another_round: + spin_lock_bh(&si->lock); + + for (c = si->all_connections_head; c; c = c->all_connections_next) { + /* + * Does this connection relate to the device we are destroying? + */ + if (!dev + || (dev == c->original_dev) + || (dev == c->reply_dev)) { + break; + } + } + + if (c) { + sfe_ipv6_remove_connection(si, c); + } + + spin_unlock_bh(&si->lock); + + if (c) { + sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_DESTROY); + goto another_round; + } +} + +/* + * sfe_ipv6_periodic_sync() + */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)) +static void sfe_ipv6_periodic_sync(unsigned long arg) +#else +static void sfe_ipv6_periodic_sync(struct timer_list *tl) +#endif +{ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)) + struct sfe_ipv6 *si = (struct sfe_ipv6 *)arg; +#else + struct sfe_ipv6 *si = from_timer(si, tl, timer); +#endif + u64 now_jiffies; + int quota; + sfe_sync_rule_callback_t sync_rule_callback; + + now_jiffies = get_jiffies_64(); + + rcu_read_lock(); + sync_rule_callback = rcu_dereference(si->sync_rule_callback); + if (!sync_rule_callback) { + rcu_read_unlock(); + goto done; + } + + spin_lock_bh(&si->lock); + sfe_ipv6_update_summary_stats(si); + + /* + * Get an estimate of the number of connections to parse in this sync. + */ + quota = (si->num_connections + 63) / 64; + + /* + * Walk the "active" list and sync the connection state. + */ + while (quota--) { + struct sfe_ipv6_connection_match *cm; + struct sfe_ipv6_connection_match *counter_cm; + struct sfe_ipv6_connection *c; + struct sfe_connection_sync sis; + + cm = si->active_head; + if (!cm) { + break; + } + + /* + * There's a possibility that our counter match is in the active list too. + * If it is then remove it. + */ + counter_cm = cm->counter_match; + if (counter_cm->active) { + counter_cm->active = false; + + /* + * We must have a connection preceding this counter match + * because that's the one that got us to this point, so we don't have + * to worry about removing the head of the list. + */ + counter_cm->active_prev->active_next = counter_cm->active_next; + + if (likely(counter_cm->active_next)) { + counter_cm->active_next->active_prev = counter_cm->active_prev; + } else { + si->active_tail = counter_cm->active_prev; + } + + counter_cm->active_next = NULL; + counter_cm->active_prev = NULL; + } + + /* + * Now remove the head of the active scan list. + */ + cm->active = false; + si->active_head = cm->active_next; + if (likely(cm->active_next)) { + cm->active_next->active_prev = NULL; + } else { + si->active_tail = NULL; + } + cm->active_next = NULL; + + /* + * Sync the connection state. + */ + c = cm->connection; + sfe_ipv6_gen_sync_connection(si, c, &sis, SFE_SYNC_REASON_STATS, now_jiffies); + + /* + * We don't want to be holding the lock when we sync! + */ + spin_unlock_bh(&si->lock); + sync_rule_callback(&sis); + spin_lock_bh(&si->lock); + } + + spin_unlock_bh(&si->lock); + rcu_read_unlock(); + +done: + mod_timer(&si->timer, jiffies + ((HZ + 99) / 100)); +} + +/* + * sfe_ipv6_debug_dev_read_start() + * Generate part of the XML output. + */ +static bool sfe_ipv6_debug_dev_read_start(struct sfe_ipv6 *si, char *buffer, char *msg, size_t *length, + int *total_read, struct sfe_ipv6_debug_xml_write_state *ws) +{ + int bytes_read; + + si->debug_read_seq++; + + bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\n"); + if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) { + return false; + } + + *length -= bytes_read; + *total_read += bytes_read; + + ws->state++; + return true; +} + +/* + * sfe_ipv6_debug_dev_read_connections_start() + * Generate part of the XML output. + */ +static bool sfe_ipv6_debug_dev_read_connections_start(struct sfe_ipv6 *si, char *buffer, char *msg, size_t *length, + int *total_read, struct sfe_ipv6_debug_xml_write_state *ws) +{ + int bytes_read; + + bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t\n"); + if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) { + return false; + } + + *length -= bytes_read; + *total_read += bytes_read; + + ws->state++; + return true; +} + +/* + * sfe_ipv6_debug_dev_read_connections_connection() + * Generate part of the XML output. + */ +static bool sfe_ipv6_debug_dev_read_connections_connection(struct sfe_ipv6 *si, char *buffer, char *msg, size_t *length, + int *total_read, struct sfe_ipv6_debug_xml_write_state *ws) +{ + struct sfe_ipv6_connection *c; + struct sfe_ipv6_connection_match *original_cm; + struct sfe_ipv6_connection_match *reply_cm; + int bytes_read; + int protocol; + struct net_device *src_dev; + struct sfe_ipv6_addr src_ip; + struct sfe_ipv6_addr src_ip_xlate; + __be16 src_port; + __be16 src_port_xlate; + u64 src_rx_packets; + u64 src_rx_bytes; + struct net_device *dest_dev; + struct sfe_ipv6_addr dest_ip; + struct sfe_ipv6_addr dest_ip_xlate; + __be16 dest_port; + __be16 dest_port_xlate; + u64 dest_rx_packets; + u64 dest_rx_bytes; + u64 last_sync_jiffies; + u32 mark, src_priority, dest_priority, src_dscp, dest_dscp; +#ifdef CONFIG_NF_FLOW_COOKIE + int src_flow_cookie, dst_flow_cookie; +#endif + + spin_lock_bh(&si->lock); + + for (c = si->all_connections_head; c; c = c->all_connections_next) { + if (c->debug_read_seq < si->debug_read_seq) { + c->debug_read_seq = si->debug_read_seq; + break; + } + } + + /* + * If there were no connections then move to the next state. + */ + if (!c) { + spin_unlock_bh(&si->lock); + ws->state++; + return true; + } + + original_cm = c->original_match; + reply_cm = c->reply_match; + + protocol = c->protocol; + src_dev = c->original_dev; + src_ip = c->src_ip[0]; + src_ip_xlate = c->src_ip_xlate[0]; + src_port = c->src_port; + src_port_xlate = c->src_port_xlate; + src_priority = original_cm->priority; + src_dscp = original_cm->dscp >> SFE_IPV6_DSCP_SHIFT; + + sfe_ipv6_connection_match_update_summary_stats(original_cm); + sfe_ipv6_connection_match_update_summary_stats(reply_cm); + + src_rx_packets = original_cm->rx_packet_count64; + src_rx_bytes = original_cm->rx_byte_count64; + dest_dev = c->reply_dev; + dest_ip = c->dest_ip[0]; + dest_ip_xlate = c->dest_ip_xlate[0]; + dest_port = c->dest_port; + dest_port_xlate = c->dest_port_xlate; + dest_priority = reply_cm->priority; + dest_dscp = reply_cm->dscp >> SFE_IPV6_DSCP_SHIFT; + dest_rx_packets = reply_cm->rx_packet_count64; + dest_rx_bytes = reply_cm->rx_byte_count64; + last_sync_jiffies = get_jiffies_64() - c->last_sync_jiffies; + mark = c->mark; +#ifdef CONFIG_NF_FLOW_COOKIE + src_flow_cookie = original_cm->flow_cookie; + dst_flow_cookie = reply_cm->flow_cookie; +#endif + spin_unlock_bh(&si->lock); + + bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t\t\n", + protocol, + src_dev->name, + &src_ip, &src_ip_xlate, + ntohs(src_port), ntohs(src_port_xlate), + src_priority, src_dscp, + src_rx_packets, src_rx_bytes, + dest_dev->name, + &dest_ip, &dest_ip_xlate, + ntohs(dest_port), ntohs(dest_port_xlate), + dest_priority, dest_dscp, + dest_rx_packets, dest_rx_bytes, +#ifdef CONFIG_NF_FLOW_COOKIE + src_flow_cookie, dst_flow_cookie, +#endif + last_sync_jiffies, mark); + + if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) { + return false; + } + + *length -= bytes_read; + *total_read += bytes_read; + + return true; +} + +/* + * sfe_ipv6_debug_dev_read_connections_end() + * Generate part of the XML output. + */ +static bool sfe_ipv6_debug_dev_read_connections_end(struct sfe_ipv6 *si, char *buffer, char *msg, size_t *length, + int *total_read, struct sfe_ipv6_debug_xml_write_state *ws) +{ + int bytes_read; + + bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t\n"); + if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) { + return false; + } + + *length -= bytes_read; + *total_read += bytes_read; + + ws->state++; + return true; +} + +/* + * sfe_ipv6_debug_dev_read_exceptions_start() + * Generate part of the XML output. + */ +static bool sfe_ipv6_debug_dev_read_exceptions_start(struct sfe_ipv6 *si, char *buffer, char *msg, size_t *length, + int *total_read, struct sfe_ipv6_debug_xml_write_state *ws) +{ + int bytes_read; + + bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t\n"); + if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) { + return false; + } + + *length -= bytes_read; + *total_read += bytes_read; + + ws->state++; + return true; +} + +/* + * sfe_ipv6_debug_dev_read_exceptions_exception() + * Generate part of the XML output. + */ +static bool sfe_ipv6_debug_dev_read_exceptions_exception(struct sfe_ipv6 *si, char *buffer, char *msg, size_t *length, + int *total_read, struct sfe_ipv6_debug_xml_write_state *ws) +{ + u64 ct; + + spin_lock_bh(&si->lock); + ct = si->exception_events64[ws->iter_exception]; + spin_unlock_bh(&si->lock); + + if (ct) { + int bytes_read; + + bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, + "\t\t\n", + sfe_ipv6_exception_events_string[ws->iter_exception], + ct); + if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) { + return false; + } + + *length -= bytes_read; + *total_read += bytes_read; + } + + ws->iter_exception++; + if (ws->iter_exception >= SFE_IPV6_EXCEPTION_EVENT_LAST) { + ws->iter_exception = 0; + ws->state++; + } + + return true; +} + +/* + * sfe_ipv6_debug_dev_read_exceptions_end() + * Generate part of the XML output. + */ +static bool sfe_ipv6_debug_dev_read_exceptions_end(struct sfe_ipv6 *si, char *buffer, char *msg, size_t *length, + int *total_read, struct sfe_ipv6_debug_xml_write_state *ws) +{ + int bytes_read; + + bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t\n"); + if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) { + return false; + } + + *length -= bytes_read; + *total_read += bytes_read; + + ws->state++; + return true; +} + +/* + * sfe_ipv6_debug_dev_read_stats() + * Generate part of the XML output. + */ +static bool sfe_ipv6_debug_dev_read_stats(struct sfe_ipv6 *si, char *buffer, char *msg, size_t *length, + int *total_read, struct sfe_ipv6_debug_xml_write_state *ws) +{ + int bytes_read; + unsigned int num_connections; + u64 packets_forwarded; + u64 packets_not_forwarded; + u64 connection_create_requests; + u64 connection_create_collisions; + u64 connection_destroy_requests; + u64 connection_destroy_misses; + u64 connection_flushes; + u64 connection_match_hash_hits; + u64 connection_match_hash_reorders; + + spin_lock_bh(&si->lock); + sfe_ipv6_update_summary_stats(si); + + num_connections = si->num_connections; + packets_forwarded = si->packets_forwarded64; + packets_not_forwarded = si->packets_not_forwarded64; + connection_create_requests = si->connection_create_requests64; + connection_create_collisions = si->connection_create_collisions64; + connection_destroy_requests = si->connection_destroy_requests64; + connection_destroy_misses = si->connection_destroy_misses64; + connection_flushes = si->connection_flushes64; + connection_match_hash_hits = si->connection_match_hash_hits64; + connection_match_hash_reorders = si->connection_match_hash_reorders64; + spin_unlock_bh(&si->lock); + + bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t\n", + num_connections, + packets_forwarded, + packets_not_forwarded, + connection_create_requests, + connection_create_collisions, + connection_destroy_requests, + connection_destroy_misses, + connection_flushes, + connection_match_hash_hits, + connection_match_hash_reorders); + if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) { + return false; + } + + *length -= bytes_read; + *total_read += bytes_read; + + ws->state++; + return true; +} + +/* + * sfe_ipv6_debug_dev_read_end() + * Generate part of the XML output. + */ +static bool sfe_ipv6_debug_dev_read_end(struct sfe_ipv6 *si, char *buffer, char *msg, size_t *length, + int *total_read, struct sfe_ipv6_debug_xml_write_state *ws) +{ + int bytes_read; + + bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\n"); + if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) { + return false; + } + + *length -= bytes_read; + *total_read += bytes_read; + + ws->state++; + return true; +} + +/* + * Array of write functions that write various XML elements that correspond to + * our XML output state machine. + */ +static sfe_ipv6_debug_xml_write_method_t sfe_ipv6_debug_xml_write_methods[SFE_IPV6_DEBUG_XML_STATE_DONE] = { + sfe_ipv6_debug_dev_read_start, + sfe_ipv6_debug_dev_read_connections_start, + sfe_ipv6_debug_dev_read_connections_connection, + sfe_ipv6_debug_dev_read_connections_end, + sfe_ipv6_debug_dev_read_exceptions_start, + sfe_ipv6_debug_dev_read_exceptions_exception, + sfe_ipv6_debug_dev_read_exceptions_end, + sfe_ipv6_debug_dev_read_stats, + sfe_ipv6_debug_dev_read_end, +}; + +/* + * sfe_ipv6_debug_dev_read() + * Send info to userspace upon read request from user + */ +static ssize_t sfe_ipv6_debug_dev_read(struct file *filp, char *buffer, size_t length, loff_t *offset) +{ + char msg[CHAR_DEV_MSG_SIZE]; + int total_read = 0; + struct sfe_ipv6_debug_xml_write_state *ws; + struct sfe_ipv6 *si = &__si6; + + ws = (struct sfe_ipv6_debug_xml_write_state *)filp->private_data; + while ((ws->state != SFE_IPV6_DEBUG_XML_STATE_DONE) && (length > CHAR_DEV_MSG_SIZE)) { + if ((sfe_ipv6_debug_xml_write_methods[ws->state])(si, buffer, msg, &length, &total_read, ws)) { + continue; + } + } + + return total_read; +} + +/* + * sfe_ipv6_debug_dev_write() + * Write to char device resets some stats + */ +static ssize_t sfe_ipv6_debug_dev_write(struct file *filp, const char *buffer, size_t length, loff_t *offset) +{ + struct sfe_ipv6 *si = &__si6; + + spin_lock_bh(&si->lock); + sfe_ipv6_update_summary_stats(si); + + si->packets_forwarded64 = 0; + si->packets_not_forwarded64 = 0; + si->connection_create_requests64 = 0; + si->connection_create_collisions64 = 0; + si->connection_destroy_requests64 = 0; + si->connection_destroy_misses64 = 0; + si->connection_flushes64 = 0; + si->connection_match_hash_hits64 = 0; + si->connection_match_hash_reorders64 = 0; + spin_unlock_bh(&si->lock); + + return length; +} + +/* + * sfe_ipv6_debug_dev_open() + */ +static int sfe_ipv6_debug_dev_open(struct inode *inode, struct file *file) +{ + struct sfe_ipv6_debug_xml_write_state *ws; + + ws = (struct sfe_ipv6_debug_xml_write_state *)file->private_data; + if (ws) { + return 0; + } + + ws = kzalloc(sizeof(struct sfe_ipv6_debug_xml_write_state), GFP_KERNEL); + if (!ws) { + return -ENOMEM; + } + + ws->state = SFE_IPV6_DEBUG_XML_STATE_START; + file->private_data = ws; + + return 0; +} + +/* + * sfe_ipv6_debug_dev_release() + */ +static int sfe_ipv6_debug_dev_release(struct inode *inode, struct file *file) +{ + struct sfe_ipv6_debug_xml_write_state *ws; + + ws = (struct sfe_ipv6_debug_xml_write_state *)file->private_data; + if (ws) { + /* + * We've finished with our output so free the write state. + */ + kfree(ws); + } + + return 0; +} + +/* + * File operations used in the debug char device + */ +static struct file_operations sfe_ipv6_debug_dev_fops = { + .read = sfe_ipv6_debug_dev_read, + .write = sfe_ipv6_debug_dev_write, + .open = sfe_ipv6_debug_dev_open, + .release = sfe_ipv6_debug_dev_release +}; + +#ifdef CONFIG_NF_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) +{ + struct sfe_ipv6 *si = &__si6; + + BUG_ON(!cb); + + if (si->flow_cookie_set_func) { + return -1; + } + + rcu_assign_pointer(si->flow_cookie_set_func, cb); + return 0; +} + +/* + * 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) +{ + struct sfe_ipv6 *si = &__si6; + + RCU_INIT_POINTER(si->flow_cookie_set_func, NULL); + return 0; +} + +/* + * sfe_ipv6_get_flow_cookie() + */ +static ssize_t sfe_ipv6_get_flow_cookie(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct sfe_ipv6 *si = &__si6; + return snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", si->flow_cookie_enable); +} + +/* + * sfe_ipv6_set_flow_cookie() + */ +static ssize_t sfe_ipv6_set_flow_cookie(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct sfe_ipv6 *si = &__si6; + strict_strtol(buf, 0, (long int *)&si->flow_cookie_enable); + + return size; +} + +/* + * sysfs attributes. + */ +static const struct device_attribute sfe_ipv6_flow_cookie_attr = + __ATTR(flow_cookie_enable, S_IWUSR | S_IRUGO, sfe_ipv6_get_flow_cookie, sfe_ipv6_set_flow_cookie); +#endif /*CONFIG_NF_FLOW_COOKIE*/ + +/* + * sfe_ipv6_init() + */ +static int __init sfe_ipv6_init(void) +{ + struct sfe_ipv6 *si = &__si6; + int result = -1; + + DEBUG_INFO("SFE IPv6 init\n"); + + /* + * Create sys/sfe_ipv6 + */ + si->sys_sfe_ipv6 = kobject_create_and_add("sfe_ipv6", NULL); + if (!si->sys_sfe_ipv6) { + DEBUG_ERROR("failed to register sfe_ipv6\n"); + goto exit1; + } + + /* + * Create files, one for each parameter supported by this module. + */ + result = sysfs_create_file(si->sys_sfe_ipv6, &sfe_ipv6_debug_dev_attr.attr); + if (result) { + DEBUG_ERROR("failed to register debug dev file: %d\n", result); + goto exit2; + } + +#ifdef CONFIG_NF_FLOW_COOKIE + result = sysfs_create_file(si->sys_sfe_ipv6, &sfe_ipv6_flow_cookie_attr.attr); + if (result) { + DEBUG_ERROR("failed to register flow cookie enable file: %d\n", result); + goto exit3; + } +#endif /* CONFIG_NF_FLOW_COOKIE */ + + /* + * Register our debug char device. + */ + result = register_chrdev(0, "sfe_ipv6", &sfe_ipv6_debug_dev_fops); + if (result < 0) { + DEBUG_ERROR("Failed to register chrdev: %d\n", result); + goto exit4; + } + + si->debug_dev = result; + + /* + * Create a timer to handle periodic statistics. + */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)) + setup_timer(&si->timer, sfe_ipv6_periodic_sync, (unsigned long)si); +#else + timer_setup(&si->timer, sfe_ipv6_periodic_sync, 0); +#endif + mod_timer(&si->timer, jiffies + ((HZ + 99) / 100)); + + spin_lock_init(&si->lock); + + return 0; + +exit4: +#ifdef CONFIG_NF_FLOW_COOKIE + sysfs_remove_file(si->sys_sfe_ipv6, &sfe_ipv6_flow_cookie_attr.attr); + +exit3: +#endif /* CONFIG_NF_FLOW_COOKIE */ + sysfs_remove_file(si->sys_sfe_ipv6, &sfe_ipv6_debug_dev_attr.attr); + +exit2: + kobject_put(si->sys_sfe_ipv6); + +exit1: + return result; +} + +/* + * sfe_ipv6_exit() + */ +static void __exit sfe_ipv6_exit(void) +{ + struct sfe_ipv6 *si = &__si6; + + DEBUG_INFO("SFE IPv6 exit\n"); + + /* + * Destroy all connections. + */ + sfe_ipv6_destroy_all_rules_for_dev(NULL); + + del_timer_sync(&si->timer); + + unregister_chrdev(si->debug_dev, "sfe_ipv6"); + +#ifdef CONFIG_NF_FLOW_COOKIE + sysfs_remove_file(si->sys_sfe_ipv6, &sfe_ipv6_flow_cookie_attr.attr); +#endif /* CONFIG_NF_FLOW_COOKIE */ + sysfs_remove_file(si->sys_sfe_ipv6, &sfe_ipv6_debug_dev_attr.attr); + + kobject_put(si->sys_sfe_ipv6); +} + +module_init(sfe_ipv6_init) +module_exit(sfe_ipv6_exit) + +EXPORT_SYMBOL(sfe_ipv6_recv); +EXPORT_SYMBOL(sfe_ipv6_create_rule); +EXPORT_SYMBOL(sfe_ipv6_destroy_rule); +EXPORT_SYMBOL(sfe_ipv6_destroy_all_rules_for_dev); +EXPORT_SYMBOL(sfe_ipv6_register_sync_rule_callback); +EXPORT_SYMBOL(sfe_ipv6_mark_rule); +EXPORT_SYMBOL(sfe_ipv6_update_rule); +#ifdef CONFIG_NF_FLOW_COOKIE +EXPORT_SYMBOL(sfe_ipv6_register_flow_cookie_cb); +EXPORT_SYMBOL(sfe_ipv6_unregister_flow_cookie_cb); +#endif + +MODULE_DESCRIPTION("Shortcut Forwarding Engine - IPv6 support"); +MODULE_LICENSE("Dual BSD/GPL"); + diff --git a/shortcut-fe/shortcut-fe/Kconfig b/shortcut-fe/shortcut-fe/Kconfig new file mode 100644 index 000000000..487f1e065 --- /dev/null +++ b/shortcut-fe/shortcut-fe/Kconfig @@ -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. diff --git a/shortcut-fe/shortcut-fe/Makefile b/shortcut-fe/shortcut-fe/Makefile new file mode 100644 index 000000000..dd53042e5 --- /dev/null +++ b/shortcut-fe/shortcut-fe/Makefile @@ -0,0 +1,88 @@ +# +# Copyright (c) 2013-2018, 2020 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:=8 + +include $(INCLUDE_DIR)/package.mk + +define KernelPackage/shortcut-fe + SECTION:=kernel + CATEGORY:=Kernel modules + SUBMENU:=Network Support + DEPENDS:=@IPV6 +kmod-nf-conntrack + 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 + PROVIDES:=$(PKG_NAME) + 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)/usr/bin + $(INSTALL_BIN) ./files/usr/bin/sfe_dump $(1)/usr/bin +endef + +HAVE_ECM:=$(CONFIG_PACKAGE_kmod-qca-nss-ecm-premium)$(CONFIG_PACKAGE_kmod-qca-nss-ecm-noload)$(CONFIG_PACKAGE_kmod-qca-nss-ecm-premium-noload)$(CONFIG_PACKAGE_kmod-qca-nss-ecm-standard) + +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 \ + CONFIG_NF_CONNTRACK_EVENTS=y \ + CONFIG_XFRM=y + CONFLICTS:=kmod-shortcut-fe-drv +endef + +define KernelPackage/shortcut-fe-cm/Description +Simple connection manager for the Shortcut forwarding engine. +endef + +define Build/Compile + $(MAKE) $(PKG_JOBS) -C "$(LINUX_DIR)" \ + $(KERNEL_MAKE_FLAGS) \ + $(PKG_MAKE_FLAGS) \ + M="$(PKG_BUILD_DIR)" \ + EXTRA_CFLAGS+="-DSFE_SUPPORT_IPV6" SFE_SUPPORT_IPV6=y \ + $(if $(HAVE_ECM),EXTRA_CFLAGS+="-DCONFIG_SFE_ECM" CONFIG_SFE_ECM=y,) \ + 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)) diff --git a/shortcut-fe/files/etc/init.d/shortcut-fe b/shortcut-fe/shortcut-fe/files/etc/init.d/shortcut-fe old mode 100755 new mode 100644 similarity index 90% rename from shortcut-fe/files/etc/init.d/shortcut-fe rename to shortcut-fe/shortcut-fe/files/etc/init.d/shortcut-fe index 786e52df0..838512a36 --- a/shortcut-fe/files/etc/init.d/shortcut-fe +++ b/shortcut-fe/shortcut-fe/files/etc/init.d/shortcut-fe @@ -15,7 +15,7 @@ #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=99 +START=70 have_cm() { [ -d "/sys/kernel/debug/ecm" ] && echo 1 && return @@ -43,7 +43,9 @@ start() { } stop() { - [ -d "/sys/module/shortcut_fe_drv" ] && rmmod shortcut_fe_drv [ -d "/sys/module/shortcut_fe_cm" ] && rmmod shortcut_fe_cm + [ -d "/sys/module/shortcut_fe_ipv6" ] && rmmod shortcut_fe_ipv6 + [ -d "/sys/module/shortcut_fe" ] && rmmod shortcut_fe + [ -d "/sys/module/shortcut_fe_drv" ] && rmmod shortcut_fe_drv [ -d "/sys/module/fast_classifier" ] && rmmod fast_classifier } diff --git a/shortcut-fe/files/usr/bin/sfe_dump b/shortcut-fe/shortcut-fe/files/usr/bin/sfe_dump similarity index 100% rename from shortcut-fe/files/usr/bin/sfe_dump rename to shortcut-fe/shortcut-fe/files/usr/bin/sfe_dump diff --git a/shortcut-fe/shortcut-fe/sfe.h b/shortcut-fe/shortcut-fe/sfe.h new file mode 100644 index 000000000..279e7b3dc --- /dev/null +++ b/shortcut-fe/shortcut-fe/sfe.h @@ -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*/ diff --git a/shortcut-fe/shortcut-fe/sfe_backport.h b/shortcut-fe/shortcut-fe/sfe_backport.h new file mode 100644 index 000000000..d2d60c73c --- /dev/null +++ b/shortcut-fe/shortcut-fe/sfe_backport.h @@ -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 + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) +#include +#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, addr) +#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 diff --git a/shortcut-fe/shortcut-fe/sfe_cm.c b/shortcut-fe/shortcut-fe/sfe_cm.c new file mode 100644 index 000000000..bd1bb88aa --- /dev/null +++ b/shortcut-fe/shortcut-fe/sfe_cm.c @@ -0,0 +1,1154 @@ +/* + * sfe-cm.c + * Shortcut forwarding engine connection manager. + * + * Copyright (c) 2013-2018, 2020 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sfe.h" +#include "sfe_cm.h" +#include "sfe_backport.h" + +typedef enum sfe_cm_exception { + SFE_CM_EXCEPTION_PACKET_BROADCAST, + SFE_CM_EXCEPTION_PACKET_MULTICAST, + SFE_CM_EXCEPTION_NO_IIF, + SFE_CM_EXCEPTION_NO_CT, + SFE_CM_EXCEPTION_CT_NO_TRACK, + SFE_CM_EXCEPTION_CT_NO_CONFIRM, + SFE_CM_EXCEPTION_CT_IS_ALG, + SFE_CM_EXCEPTION_IS_IPV4_MCAST, + SFE_CM_EXCEPTION_IS_IPV6_MCAST, + SFE_CM_EXCEPTION_TCP_NOT_ASSURED, + SFE_CM_EXCEPTION_TCP_NOT_ESTABLISHED, + SFE_CM_EXCEPTION_UNKNOW_PROTOCOL, + SFE_CM_EXCEPTION_NO_SRC_DEV, + SFE_CM_EXCEPTION_NO_SRC_XLATE_DEV, + SFE_CM_EXCEPTION_NO_DEST_DEV, + SFE_CM_EXCEPTION_NO_DEST_XLATE_DEV, + SFE_CM_EXCEPTION_NO_BRIDGE, + SFE_CM_EXCEPTION_LOCAL_OUT, + SFE_CM_EXCEPTION_MAX +} sfe_cm_exception_t; + +static char *sfe_cm_exception_events_string[SFE_CM_EXCEPTION_MAX] = { + "PACKET_BROADCAST", + "PACKET_MULTICAST", + "NO_IIF", + "NO_CT", + "CT_NO_TRACK", + "CT_NO_CONFIRM", + "CT_IS_ALG", + "IS_IPV4_MCAST", + "IS_IPV6_MCAST", + "TCP_NOT_ASSURED", + "TCP_NOT_ESTABLISHED", + "UNKNOW_PROTOCOL", + "NO_SRC_DEV", + "NO_SRC_XLATE_DEV", + "NO_DEST_DEV", + "NO_DEST_XLATE_DEV", + "NO_BRIDGE", + "LOCAL_OUT" +}; + +/* + * Per-module structure. + */ +struct sfe_cm { + spinlock_t lock; /* Lock for SMP correctness */ + + /* + * Control state. + */ + struct kobject *sys_sfe_cm; /* sysfs linkage */ + + /* + * Callback notifiers. + */ + struct notifier_block dev_notifier; /* Device notifier */ + struct notifier_block inet_notifier; /* IPv4 notifier */ + struct notifier_block inet6_notifier; /* IPv6 notifier */ + u32 exceptions[SFE_CM_EXCEPTION_MAX]; +}; + +static struct sfe_cm __sc; + +/* + * sfe_cm_incr_exceptions() + * increase an exception counter. + */ +static inline void sfe_cm_incr_exceptions(sfe_cm_exception_t except) +{ + struct sfe_cm *sc = &__sc; + + spin_lock_bh(&sc->lock); + sc->exceptions[except]++; + spin_unlock_bh(&sc->lock); +} + +/* + * sfe_cm_recv() + * Handle packet receives. + * + * Returns 1 if the packet is forwarded or 0 if it isn't. + */ +int sfe_cm_recv(struct sk_buff *skb) +{ + struct net_device *dev; + + /* + * We know that for the vast majority of packets we need the transport + * layer header so we may as well start to fetch it now! + */ + prefetch(skb->data + 32); + barrier(); + + dev = skb->dev; + + /* + * We're only interested in IPv4 and IPv6 packets. + */ + if (likely(htons(ETH_P_IP) == skb->protocol)) { + struct in_device *in_dev; + + /* + * Does our input device support IP processing? + */ + in_dev = (struct in_device *)dev->ip_ptr; + if (unlikely(!in_dev)) { + DEBUG_TRACE("no IP processing for device: %s\n", dev->name); + return 0; + } + + /* + * Does it have an IP address? If it doesn't then we can't do anything + * interesting here! + */ + if (unlikely(!in_dev->ifa_list)) { + DEBUG_TRACE("no IP address for device: %s\n", dev->name); + return 0; + } + + return sfe_ipv4_recv(dev, skb); + } + + if (likely(htons(ETH_P_IPV6) == skb->protocol)) { + struct inet6_dev *in_dev; + + /* + * Does our input device support IPv6 processing? + */ + in_dev = (struct inet6_dev *)dev->ip6_ptr; + if (unlikely(!in_dev)) { + DEBUG_TRACE("no IPv6 processing for device: %s\n", dev->name); + return 0; + } + + /* + * Does it have an IPv6 address? If it doesn't then we can't do anything + * interesting here! + */ + if (unlikely(list_empty(&in_dev->addr_list))) { + DEBUG_TRACE("no IPv6 address for device: %s\n", dev->name); + return 0; + } + + return sfe_ipv6_recv(dev, skb); + } + + DEBUG_TRACE("not IP packet\n"); + return 0; +} + +/* + * sfe_cm_find_dev_and_mac_addr() + * Find the device and MAC address for a given IPv4/IPv6 address. + * + * Returns true if we find the device and MAC address, otherwise false. + * + * We look up the rtable entry for the address and, from its neighbour + * structure, obtain the hardware address. This means this function also + * works if the neighbours are routers too. + */ +static bool sfe_cm_find_dev_and_mac_addr(sfe_ip_addr_t *addr, struct net_device **dev, u8 *mac_addr, int is_v4) +{ + struct neighbour *neigh; + struct rtable *rt; + struct rt6_info *rt6; + struct dst_entry *dst; + struct net_device *mac_dev; + + /* + * Look up the rtable entry for the IP address then get the hardware + * address from its neighbour structure. This means this work when the + * neighbours are routers too. + */ + if (likely(is_v4)) { + rt = ip_route_output(&init_net, addr->ip, 0, 0, 0); + if (unlikely(IS_ERR(rt))) { + goto ret_fail; + } + + dst = (struct dst_entry *)rt; + } else { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 17, 0)) + rt6 = rt6_lookup(&init_net, (struct in6_addr *)addr->ip6, 0, 0, 0); +#else + rt6 = rt6_lookup(&init_net, (struct in6_addr *)addr->ip6, 0, 0, NULL, 0); +#endif + if (!rt6) { + goto ret_fail; + } + + dst = (struct dst_entry *)rt6; + } + + rcu_read_lock(); + neigh = sfe_dst_get_neighbour(dst, addr); + if (unlikely(!neigh)) { + rcu_read_unlock(); + dst_release(dst); + goto ret_fail; + } + + if (unlikely(!(neigh->nud_state & NUD_VALID))) { + rcu_read_unlock(); + neigh_release(neigh); + dst_release(dst); + goto ret_fail; + } + + mac_dev = neigh->dev; + if (!mac_dev) { + rcu_read_unlock(); + neigh_release(neigh); + dst_release(dst); + goto ret_fail; + } + + memcpy(mac_addr, neigh->ha, (size_t)mac_dev->addr_len); + + dev_hold(mac_dev); + *dev = mac_dev; + rcu_read_unlock(); + neigh_release(neigh); + dst_release(dst); + + return true; + +ret_fail: + if (is_v4) { + DEBUG_TRACE("failed to find MAC address for IP: %pI4\n", &addr->ip); + + } else { + DEBUG_TRACE("failed to find MAC address for IP: %pI6\n", addr->ip6); + } + + return false; +} + +/* + * sfe_cm_post_routing() + * Called for packets about to leave the box - either locally generated or forwarded from another interface + */ +static unsigned int sfe_cm_post_routing(struct sk_buff *skb, int is_v4) +{ + struct sfe_connection_create sic; + struct net_device *in; + struct nf_conn *ct; + enum ip_conntrack_info ctinfo; + struct net_device *dev; + struct net_device *src_dev; + struct net_device *dest_dev; + struct net_device *src_dev_tmp; + struct net_device *dest_dev_tmp; + struct net_device *src_br_dev = NULL; + struct net_device *dest_br_dev = NULL; + struct nf_conntrack_tuple orig_tuple; + struct nf_conntrack_tuple reply_tuple; + SFE_NF_CONN_ACCT(acct); + + /* + * Don't process broadcast or multicast packets. + */ + if (unlikely(skb->pkt_type == PACKET_BROADCAST)) { + sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_PACKET_BROADCAST); + DEBUG_TRACE("broadcast, ignoring\n"); + return NF_ACCEPT; + } + if (unlikely(skb->pkt_type == PACKET_MULTICAST)) { + sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_PACKET_MULTICAST); + DEBUG_TRACE("multicast, ignoring\n"); + return NF_ACCEPT; + } + +#ifdef CONFIG_XFRM + /* + * Packet to xfrm for encapsulation, we can't process it + */ + if (unlikely(skb_dst(skb)->xfrm)) { + DEBUG_TRACE("packet to xfrm, ignoring\n"); + return NF_ACCEPT; + } +#endif + + /* + * Don't process locally generated packets. + */ + if (skb->sk) { + sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_LOCAL_OUT); + DEBUG_TRACE("skip local out packet\n"); + return NF_ACCEPT; + } + + /* + * Don't process packets that are not being forwarded. + */ + in = dev_get_by_index(&init_net, skb->skb_iif); + if (!in) { + sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_IIF); + DEBUG_TRACE("packet not forwarding\n"); + return NF_ACCEPT; + } + + dev_put(in); + + /* + * Don't process packets that aren't being tracked by conntrack. + */ + ct = nf_ct_get(skb, &ctinfo); + if (unlikely(!ct)) { + sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_CT); + DEBUG_TRACE("no conntrack connection, ignoring\n"); + return NF_ACCEPT; + } + + /* + * Don't process untracked connections. + */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)) + if (unlikely(nf_ct_is_untracked(ct))) { +#else + if (unlikely(ctinfo == IP_CT_UNTRACKED)) { +#endif + sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_CT_NO_TRACK); + DEBUG_TRACE("untracked connection\n"); + return NF_ACCEPT; + } + + /* + * Unconfirmed connection may be dropped by Linux at the final step, + * So we don't process unconfirmed connections. + */ + if (!nf_ct_is_confirmed(ct)) { + sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_CT_NO_CONFIRM); + DEBUG_TRACE("unconfirmed connection\n"); + return NF_ACCEPT; + } + + /* + * Don't process connections that require support from a 'helper' (typically a NAT ALG). + */ + if (unlikely(nfct_help(ct))) { + sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_CT_IS_ALG); + DEBUG_TRACE("connection has helper\n"); + return NF_ACCEPT; + } + + /* + * Check if the acceleration of a flow could be rejected quickly. + */ + acct = nf_conn_acct_find(ct); + if (acct) { + long long packets = atomic64_read(&SFE_ACCT_COUNTER(acct)[CTINFO2DIR(ctinfo)].packets); + if ((packets > 0xff) && (packets & 0xff)) { + /* + * Connection hits slow path at least 256 times, so it must be not able to accelerate. + * But we also give it a chance to walk through ECM every 256 packets + */ + return NF_ACCEPT; + } + } + + /* + * Look up the details of our connection in conntrack. + * + * Note that the data we get from conntrack is for the "ORIGINAL" direction + * but our packet may actually be in the "REPLY" direction. + */ + orig_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; + reply_tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple; + sic.protocol = (s32)orig_tuple.dst.protonum; + + sic.flags = 0; + + /* + * Get addressing information, non-NAT first + */ + if (likely(is_v4)) { + u32 dscp; + + sic.src_ip.ip = (__be32)orig_tuple.src.u3.ip; + sic.dest_ip.ip = (__be32)orig_tuple.dst.u3.ip; + + if (ipv4_is_multicast(sic.src_ip.ip) || ipv4_is_multicast(sic.dest_ip.ip)) { + sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_IS_IPV4_MCAST); + DEBUG_TRACE("multicast address\n"); + return NF_ACCEPT; + } + + /* + * NAT'ed addresses - note these are as seen from the 'reply' direction + * When NAT does not apply to this connection these will be identical to the above. + */ + sic.src_ip_xlate.ip = (__be32)reply_tuple.dst.u3.ip; + sic.dest_ip_xlate.ip = (__be32)reply_tuple.src.u3.ip; + + dscp = ipv4_get_dsfield(ip_hdr(skb)) >> XT_DSCP_SHIFT; + if (dscp) { + sic.dest_dscp = dscp; + sic.src_dscp = sic.dest_dscp; + sic.flags |= SFE_CREATE_FLAG_REMARK_DSCP; + } + } else { + u32 dscp; + + sic.src_ip.ip6[0] = *((struct sfe_ipv6_addr *)&orig_tuple.src.u3.in6); + sic.dest_ip.ip6[0] = *((struct sfe_ipv6_addr *)&orig_tuple.dst.u3.in6); + + if (ipv6_addr_is_multicast((struct in6_addr *)sic.src_ip.ip6) || + ipv6_addr_is_multicast((struct in6_addr *)sic.dest_ip.ip6)) { + sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_IS_IPV6_MCAST); + DEBUG_TRACE("multicast address\n"); + return NF_ACCEPT; + } + + /* + * NAT'ed addresses - note these are as seen from the 'reply' direction + * When NAT does not apply to this connection these will be identical to the above. + */ + sic.src_ip_xlate.ip6[0] = *((struct sfe_ipv6_addr *)&reply_tuple.dst.u3.in6); + sic.dest_ip_xlate.ip6[0] = *((struct sfe_ipv6_addr *)&reply_tuple.src.u3.in6); + + dscp = ipv6_get_dsfield(ipv6_hdr(skb)) >> XT_DSCP_SHIFT; + if (dscp) { + sic.dest_dscp = dscp; + sic.src_dscp = sic.dest_dscp; + sic.flags |= SFE_CREATE_FLAG_REMARK_DSCP; + } + } + + switch (sic.protocol) { + case IPPROTO_TCP: + sic.src_port = orig_tuple.src.u.tcp.port; + sic.dest_port = orig_tuple.dst.u.tcp.port; + sic.src_port_xlate = reply_tuple.dst.u.tcp.port; + sic.dest_port_xlate = reply_tuple.src.u.tcp.port; + sic.src_td_window_scale = ct->proto.tcp.seen[0].td_scale; + sic.src_td_max_window = ct->proto.tcp.seen[0].td_maxwin; + sic.src_td_end = ct->proto.tcp.seen[0].td_end; + sic.src_td_max_end = ct->proto.tcp.seen[0].td_maxend; + sic.dest_td_window_scale = ct->proto.tcp.seen[1].td_scale; + sic.dest_td_max_window = ct->proto.tcp.seen[1].td_maxwin; + sic.dest_td_end = ct->proto.tcp.seen[1].td_end; + sic.dest_td_max_end = ct->proto.tcp.seen[1].td_maxend; + + if (nf_ct_tcp_no_window_check + || (ct->proto.tcp.seen[0].flags & IP_CT_TCP_FLAG_BE_LIBERAL) + || (ct->proto.tcp.seen[1].flags & IP_CT_TCP_FLAG_BE_LIBERAL)) { + sic.flags |= SFE_CREATE_FLAG_NO_SEQ_CHECK; + } + + /* + * Don't try to manage a non-established connection. + */ + if (!test_bit(IPS_ASSURED_BIT, &ct->status)) { + sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_TCP_NOT_ASSURED); + DEBUG_TRACE("non-established connection\n"); + return NF_ACCEPT; + } + + /* + * If the connection is shutting down do not manage it. + * state can not be SYN_SENT, SYN_RECV because connection is assured + * Not managed states: FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE. + */ + spin_lock_bh(&ct->lock); + if (ct->proto.tcp.state != TCP_CONNTRACK_ESTABLISHED) { + spin_unlock_bh(&ct->lock); + sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_TCP_NOT_ESTABLISHED); + DEBUG_TRACE("connection in termination state: %#x, s: %pI4:%u, d: %pI4:%u\n", + ct->proto.tcp.state, &sic.src_ip, ntohs(sic.src_port), + &sic.dest_ip, ntohs(sic.dest_port)); + return NF_ACCEPT; + } + spin_unlock_bh(&ct->lock); + break; + + case IPPROTO_UDP: + sic.src_port = orig_tuple.src.u.udp.port; + sic.dest_port = orig_tuple.dst.u.udp.port; + sic.src_port_xlate = reply_tuple.dst.u.udp.port; + sic.dest_port_xlate = reply_tuple.src.u.udp.port; + break; + + default: + sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_UNKNOW_PROTOCOL); + DEBUG_TRACE("unhandled protocol %d\n", sic.protocol); + return NF_ACCEPT; + } + +#ifdef CONFIG_XFRM + sic.original_accel = 1; + sic.reply_accel = 1; + + /* + * For packets de-capsulated from xfrm, we still can accelerate it + * on the direction we just received the packet. + */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0)) + if (unlikely(skb->sp)) { +#else + if (unlikely(secpath_exists(skb))) { +#endif + if (sic.protocol == IPPROTO_TCP && + !(sic.flags & SFE_CREATE_FLAG_NO_SEQ_CHECK)) { + return NF_ACCEPT; + } + + if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) { + sic.reply_accel = 0; + } else { + sic.original_accel = 0; + } + } +#endif + + /* + * Get QoS information + */ + if (skb->priority) { + sic.dest_priority = skb->priority; + sic.src_priority = sic.dest_priority; + sic.flags |= SFE_CREATE_FLAG_REMARK_PRIORITY; + } + + /* + * Get the net device and MAC addresses that correspond to the various source and + * destination host addresses. + */ + if (!sfe_cm_find_dev_and_mac_addr(&sic.src_ip, &src_dev_tmp, sic.src_mac, is_v4)) { + sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_SRC_DEV); + return NF_ACCEPT; + } + src_dev = src_dev_tmp; + + if (!sfe_cm_find_dev_and_mac_addr(&sic.src_ip_xlate, &dev, sic.src_mac_xlate, is_v4)) { + sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_SRC_XLATE_DEV); + goto done1; + } + dev_put(dev); + + if (!sfe_cm_find_dev_and_mac_addr(&sic.dest_ip, &dev, sic.dest_mac, is_v4)) { + sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_DEST_DEV); + goto done1; + } + dev_put(dev); + + if (!sfe_cm_find_dev_and_mac_addr(&sic.dest_ip_xlate, &dest_dev_tmp, sic.dest_mac_xlate, is_v4)) { + sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_DEST_XLATE_DEV); + goto done1; + } + dest_dev = dest_dev_tmp; + + /* + * Our devices may actually be part of a bridge interface. If that's + * the case then find the bridge interface instead. + */ + if (src_dev->priv_flags & IFF_BRIDGE_PORT) { + src_br_dev = sfe_dev_get_master(src_dev); + if (!src_br_dev) { + sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_BRIDGE); + DEBUG_TRACE("no bridge found for: %s\n", src_dev->name); + goto done2; + } + src_dev = src_br_dev; + } + + if (dest_dev->priv_flags & IFF_BRIDGE_PORT) { + dest_br_dev = sfe_dev_get_master(dest_dev); + if (!dest_br_dev) { + sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_BRIDGE); + DEBUG_TRACE("no bridge found for: %s\n", dest_dev->name); + goto done3; + } + dest_dev = dest_br_dev; + } + + sic.src_dev = src_dev; + sic.dest_dev = dest_dev; + + sic.src_mtu = src_dev->mtu; + sic.dest_mtu = dest_dev->mtu; + + if (likely(is_v4)) { + sfe_ipv4_create_rule(&sic); + } else { + sfe_ipv6_create_rule(&sic); + } + + /* + * If we had bridge ports then release them too. + */ + if (dest_br_dev) { + dev_put(dest_br_dev); + } +done3: + if (src_br_dev) { + dev_put(src_br_dev); + } +done2: + dev_put(dest_dev_tmp); +done1: + dev_put(src_dev_tmp); + + return NF_ACCEPT; +} + +/* + * sfe_cm_ipv4_post_routing_hook() + * Called for packets about to leave the box - either locally generated or forwarded from another interface + */ +sfe_cm_ipv4_post_routing_hook(hooknum, ops, skb, in_unused, out, okfn) +{ + return sfe_cm_post_routing(skb, true); +} + +/* + * sfe_cm_ipv6_post_routing_hook() + * Called for packets about to leave the box - either locally generated or forwarded from another interface + */ +sfe_cm_ipv6_post_routing_hook(hooknum, ops, skb, in_unused, out, okfn) +{ + return sfe_cm_post_routing(skb, false); +} + +#ifdef CONFIG_NF_CONNTRACK_EVENTS +/* + * sfe_cm_conntrack_event() + * Callback event invoked when a conntrack connection's state changes. + */ +#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS +static int sfe_cm_conntrack_event(struct notifier_block *this, + unsigned long events, void *ptr) +#else +static int sfe_cm_conntrack_event(unsigned int events, struct nf_ct_event *item) +#endif +{ +#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS + struct nf_ct_event *item = ptr; +#endif + struct sfe_connection_destroy sid; + struct nf_conn *ct = item->ct; + struct nf_conntrack_tuple orig_tuple; + + /* + * If we don't have a conntrack entry then we're done. + */ + if (unlikely(!ct)) { + DEBUG_WARN("no ct in conntrack event callback\n"); + return NOTIFY_DONE; + } + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)) + if (unlikely(nf_ct_is_untracked(ct))) { + DEBUG_TRACE("ignoring untracked conn\n"); + return NOTIFY_DONE; + } +#endif + + /* + * We're only interested in destroy events. + */ + if (unlikely(!(events & (1 << IPCT_DESTROY)))) { + DEBUG_TRACE("ignoring non-destroy event\n"); + return NOTIFY_DONE; + } + + orig_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; + sid.protocol = (s32)orig_tuple.dst.protonum; + + /* + * Extract information from the conntrack connection. We're only interested + * in nominal connection information (i.e. we're ignoring any NAT information). + */ + switch (sid.protocol) { + case IPPROTO_TCP: + sid.src_port = orig_tuple.src.u.tcp.port; + sid.dest_port = orig_tuple.dst.u.tcp.port; + break; + + case IPPROTO_UDP: + sid.src_port = orig_tuple.src.u.udp.port; + sid.dest_port = orig_tuple.dst.u.udp.port; + break; + + default: + DEBUG_TRACE("unhandled protocol: %d\n", sid.protocol); + return NOTIFY_DONE; + } + + if (likely(nf_ct_l3num(ct) == AF_INET)) { + sid.src_ip.ip = (__be32)orig_tuple.src.u3.ip; + sid.dest_ip.ip = (__be32)orig_tuple.dst.u3.ip; + + sfe_ipv4_destroy_rule(&sid); + } else if (likely(nf_ct_l3num(ct) == AF_INET6)) { + sid.src_ip.ip6[0] = *((struct sfe_ipv6_addr *)&orig_tuple.src.u3.in6); + sid.dest_ip.ip6[0] = *((struct sfe_ipv6_addr *)&orig_tuple.dst.u3.in6); + + sfe_ipv6_destroy_rule(&sid); + } else { + DEBUG_TRACE("ignoring non-IPv4 and non-IPv6 connection\n"); + } + + return NOTIFY_DONE; +} + +/* + * Netfilter conntrack event system to monitor connection tracking changes + */ +#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS +static struct notifier_block sfe_cm_conntrack_notifier = { + .notifier_call = sfe_cm_conntrack_event, +}; +#else +static struct nf_ct_event_notifier sfe_cm_conntrack_notifier = { + .fcn = sfe_cm_conntrack_event, +}; +#endif +#endif + +/* + * Structure to establish a hook into the post routing netfilter point - this + * will pick up local outbound and packets going from one interface to another. + * + * Note: see include/linux/netfilter_ipv4.h for info related to priority levels. + * We want to examine packets after NAT translation and any ALG processing. + */ +static struct nf_hook_ops sfe_cm_ops_post_routing[] __read_mostly = { + SFE_IPV4_NF_POST_ROUTING_HOOK(__sfe_cm_ipv4_post_routing_hook), +#ifdef SFE_SUPPORT_IPV6 + SFE_IPV6_NF_POST_ROUTING_HOOK(__sfe_cm_ipv6_post_routing_hook), +#endif +}; + +/* + * sfe_cm_sync_rule() + * Synchronize a connection's state. + */ +static void sfe_cm_sync_rule(struct sfe_connection_sync *sis) +{ + struct nf_conntrack_tuple_hash *h; + struct nf_conntrack_tuple tuple; + struct nf_conn *ct; + SFE_NF_CONN_ACCT(acct); + + /* + * Create a tuple so as to be able to look up a connection + */ + memset(&tuple, 0, sizeof(tuple)); + tuple.src.u.all = (__be16)sis->src_port; + tuple.dst.dir = IP_CT_DIR_ORIGINAL; + tuple.dst.protonum = (u8)sis->protocol; + tuple.dst.u.all = (__be16)sis->dest_port; + + if (sis->is_v6) { + tuple.src.u3.in6 = *((struct in6_addr *)sis->src_ip.ip6); + tuple.dst.u3.in6 = *((struct in6_addr *)sis->dest_ip.ip6); + tuple.src.l3num = AF_INET6; + + DEBUG_TRACE("update connection - p: %d, s: %pI6:%u, d: %pI6:%u\n", + (int)tuple.dst.protonum, + &tuple.src.u3.in6, (unsigned int)ntohs(tuple.src.u.all), + &tuple.dst.u3.in6, (unsigned int)ntohs(tuple.dst.u.all)); + } else { + tuple.src.u3.ip = sis->src_ip.ip; + tuple.dst.u3.ip = sis->dest_ip.ip; + tuple.src.l3num = AF_INET; + + DEBUG_TRACE("update connection - p: %d, s: %pI4:%u, d: %pI4:%u\n", + (int)tuple.dst.protonum, + &tuple.src.u3.ip, (unsigned int)ntohs(tuple.src.u.all), + &tuple.dst.u3.ip, (unsigned int)ntohs(tuple.dst.u.all)); + } + + /* + * Look up conntrack connection + */ + h = nf_conntrack_find_get(&init_net, SFE_NF_CT_DEFAULT_ZONE, &tuple); + if (unlikely(!h)) { + DEBUG_TRACE("no connection found\n"); + return; + } + + ct = nf_ct_tuplehash_to_ctrack(h); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)) + NF_CT_ASSERT(ct->timeout.data == (unsigned long)ct); +#endif + /* + * Only update if this is not a fixed timeout + */ + if (!test_bit(IPS_FIXED_TIMEOUT_BIT, &ct->status)) { + spin_lock_bh(&ct->lock); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)) + ct->timeout.expires += sis->delta_jiffies; +#else + ct->timeout += sis->delta_jiffies; +#endif + spin_unlock_bh(&ct->lock); + } + + acct = nf_conn_acct_find(ct); + if (acct) { + spin_lock_bh(&ct->lock); + atomic64_add(sis->src_new_packet_count, &SFE_ACCT_COUNTER(acct)[IP_CT_DIR_ORIGINAL].packets); + atomic64_add(sis->src_new_byte_count, &SFE_ACCT_COUNTER(acct)[IP_CT_DIR_ORIGINAL].bytes); + atomic64_add(sis->dest_new_packet_count, &SFE_ACCT_COUNTER(acct)[IP_CT_DIR_REPLY].packets); + atomic64_add(sis->dest_new_byte_count, &SFE_ACCT_COUNTER(acct)[IP_CT_DIR_REPLY].bytes); + spin_unlock_bh(&ct->lock); + } + + switch (sis->protocol) { + case IPPROTO_TCP: + spin_lock_bh(&ct->lock); + if (ct->proto.tcp.seen[0].td_maxwin < sis->src_td_max_window) { + ct->proto.tcp.seen[0].td_maxwin = sis->src_td_max_window; + } + if ((s32)(ct->proto.tcp.seen[0].td_end - sis->src_td_end) < 0) { + ct->proto.tcp.seen[0].td_end = sis->src_td_end; + } + if ((s32)(ct->proto.tcp.seen[0].td_maxend - sis->src_td_max_end) < 0) { + ct->proto.tcp.seen[0].td_maxend = sis->src_td_max_end; + } + if (ct->proto.tcp.seen[1].td_maxwin < sis->dest_td_max_window) { + ct->proto.tcp.seen[1].td_maxwin = sis->dest_td_max_window; + } + if ((s32)(ct->proto.tcp.seen[1].td_end - sis->dest_td_end) < 0) { + ct->proto.tcp.seen[1].td_end = sis->dest_td_end; + } + if ((s32)(ct->proto.tcp.seen[1].td_maxend - sis->dest_td_max_end) < 0) { + ct->proto.tcp.seen[1].td_maxend = sis->dest_td_max_end; + } + spin_unlock_bh(&ct->lock); + break; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) + case IPPROTO_UDP: + /* + * In Linux connection track, UDP flow has two timeout values: + * /proc/sys/net/netfilter/nf_conntrack_udp_timeout: + * this is for uni-direction UDP flow, normally its value is 60 seconds + * /proc/sys/net/netfilter/nf_conntrack_udp_timeout_stream: + * this is for bi-direction UDP flow, normally its value is 180 seconds + * + * Linux will update timer of UDP flow to stream timeout once it seen packets + * in reply direction. But if flow is accelerated by NSS or SFE, Linux won't + * see any packets. So we have to do the same thing in our stats sync message. + */ + if (!test_bit(IPS_ASSURED_BIT, &ct->status) && acct) { + u_int64_t reply_pkts = atomic64_read(&SFE_ACCT_COUNTER(acct)[IP_CT_DIR_REPLY].packets); + + if (reply_pkts != 0) { + unsigned int *timeouts; + struct nf_conntrack_l4proto *l4proto __maybe_unused; + set_bit(IPS_SEEN_REPLY_BIT, &ct->status); + set_bit(IPS_ASSURED_BIT, &ct->status); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)) + l4proto = __nf_ct_l4proto_find((sis->is_v6 ? AF_INET6 : AF_INET), IPPROTO_UDP); + timeouts = nf_ct_timeout_lookup(&init_net, ct, l4proto); + spin_lock_bh(&ct->lock); + ct->timeout.expires = jiffies + timeouts[UDP_CT_REPLIED]; + spin_unlock_bh(&ct->lock); +#else + timeouts = nf_ct_timeout_lookup(ct); + if (!timeouts) { + timeouts = udp_get_timeouts(nf_ct_net(ct)); + } + + spin_lock_bh(&ct->lock); + ct->timeout = jiffies + timeouts[UDP_CT_REPLIED]; + spin_unlock_bh(&ct->lock); +#endif + } + } + break; +#endif /*KERNEL_VERSION(3, 4, 0)*/ + } + + /* + * Release connection + */ + nf_ct_put(ct); +} + +/* + * sfe_cm_device_event() + */ +int sfe_cm_device_event(struct notifier_block *this, unsigned long event, void *ptr) +{ + struct net_device *dev = SFE_DEV_EVENT_PTR(ptr); + + if (dev && (event == NETDEV_DOWN)) { + sfe_ipv4_destroy_all_rules_for_dev(dev); + sfe_ipv6_destroy_all_rules_for_dev(dev); + } + + return NOTIFY_DONE; +} + +/* + * sfe_cm_inet_event() + */ +static int sfe_cm_inet_event(struct notifier_block *this, unsigned long event, void *ptr) +{ + struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev; + + if (dev && (event == NETDEV_DOWN)) { + sfe_ipv4_destroy_all_rules_for_dev(dev); + } + + return NOTIFY_DONE; +} + +/* + * sfe_cm_inet6_event() + */ +static int sfe_cm_inet6_event(struct notifier_block *this, unsigned long event, void *ptr) +{ + struct net_device *dev = ((struct inet6_ifaddr *)ptr)->idev->dev; + + if (dev && (event == NETDEV_DOWN)) { + sfe_ipv6_destroy_all_rules_for_dev(dev); + } + + return NOTIFY_DONE; +} + +/* + * sfe_cm_get_exceptions + * dump exception counters + */ +static ssize_t sfe_cm_get_exceptions(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int idx, len; + struct sfe_cm *sc = &__sc; + + spin_lock_bh(&sc->lock); + for (len = 0, idx = 0; idx < SFE_CM_EXCEPTION_MAX; idx++) { + if (sc->exceptions[idx]) { + len += snprintf(buf + len, (ssize_t)(PAGE_SIZE - len), "%s = %d\n", sfe_cm_exception_events_string[idx], sc->exceptions[idx]); + } + } + spin_unlock_bh(&sc->lock); + + return len; +} + +/* + * sysfs attributes. + */ +static const struct device_attribute sfe_cm_exceptions_attr = + __ATTR(exceptions, S_IRUGO, sfe_cm_get_exceptions, NULL); + +/* + * sfe_cm_init() + */ +static int __init sfe_cm_init(void) +{ + struct sfe_cm *sc = &__sc; + int result = -1; + + DEBUG_INFO("SFE CM init\n"); + + /* + * Create sys/sfe_cm + */ + sc->sys_sfe_cm = kobject_create_and_add("sfe_cm", NULL); + if (!sc->sys_sfe_cm) { + DEBUG_ERROR("failed to register sfe_cm\n"); + goto exit1; + } + + /* + * Create sys/sfe_cm/exceptions + */ + result = sysfs_create_file(sc->sys_sfe_cm, &sfe_cm_exceptions_attr.attr); + if (result) { + DEBUG_ERROR("failed to register exceptions file: %d\n", result); + goto exit2; + } + + sc->dev_notifier.notifier_call = sfe_cm_device_event; + sc->dev_notifier.priority = 1; + register_netdevice_notifier(&sc->dev_notifier); + + sc->inet_notifier.notifier_call = sfe_cm_inet_event; + sc->inet_notifier.priority = 1; + register_inetaddr_notifier(&sc->inet_notifier); + + sc->inet6_notifier.notifier_call = sfe_cm_inet6_event; + sc->inet6_notifier.priority = 1; + register_inet6addr_notifier(&sc->inet6_notifier); + /* + * Register our netfilter hooks. + */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0)) + result = nf_register_hooks(sfe_cm_ops_post_routing, ARRAY_SIZE(sfe_cm_ops_post_routing)); +#else + result = nf_register_net_hooks(&init_net, sfe_cm_ops_post_routing, ARRAY_SIZE(sfe_cm_ops_post_routing)); +#endif + if (result < 0) { + DEBUG_ERROR("can't register nf post routing hook: %d\n", result); + goto exit3; + } + + /* + * Register a notifier hook to get fast notifications of expired connections. + * Note: In CONFIG_NF_CONNTRACK_CHAIN_EVENTS enabled case, nf_conntrack_register_notifier() + * function always returns 0. + */ +#ifdef CONFIG_NF_CONNTRACK_EVENTS +#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS + (void)nf_conntrack_register_notifier(&init_net, &sfe_cm_conntrack_notifier); +#else + result = nf_conntrack_register_notifier(&init_net, &sfe_cm_conntrack_notifier); + if (result < 0) { + DEBUG_ERROR("can't register nf notifier hook: %d\n", result); + goto exit4; + } +#endif +#endif + + spin_lock_init(&sc->lock); + + /* + * Hook the receive path in the network stack. + */ + BUG_ON(athrs_fast_nat_recv); + RCU_INIT_POINTER(athrs_fast_nat_recv, sfe_cm_recv); + + /* + * Hook the shortcut sync callback. + */ + sfe_ipv4_register_sync_rule_callback(sfe_cm_sync_rule); + sfe_ipv6_register_sync_rule_callback(sfe_cm_sync_rule); + return 0; + +#ifdef CONFIG_NF_CONNTRACK_EVENTS +#ifndef CONFIG_NF_CONNTRACK_CHAIN_EVENTS +exit4: +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0)) + nf_unregister_hooks(sfe_cm_ops_post_routing, ARRAY_SIZE(sfe_cm_ops_post_routing)); +#else + nf_unregister_net_hooks(&init_net, sfe_cm_ops_post_routing, ARRAY_SIZE(sfe_cm_ops_post_routing)); +#endif + +#endif +#endif +exit3: + unregister_inet6addr_notifier(&sc->inet6_notifier); + unregister_inetaddr_notifier(&sc->inet_notifier); + unregister_netdevice_notifier(&sc->dev_notifier); +exit2: + kobject_put(sc->sys_sfe_cm); + +exit1: + return result; +} + +/* + * sfe_cm_exit() + */ +static void __exit sfe_cm_exit(void) +{ + struct sfe_cm *sc = &__sc; + + DEBUG_INFO("SFE CM exit\n"); + + /* + * Unregister our sync callback. + */ + sfe_ipv4_register_sync_rule_callback(NULL); + sfe_ipv6_register_sync_rule_callback(NULL); + + /* + * Unregister our receive callback. + */ + RCU_INIT_POINTER(athrs_fast_nat_recv, NULL); + + /* + * Wait for all callbacks to complete. + */ + rcu_barrier(); + + /* + * Destroy all connections. + */ + sfe_ipv4_destroy_all_rules_for_dev(NULL); + sfe_ipv6_destroy_all_rules_for_dev(NULL); + +#ifdef CONFIG_NF_CONNTRACK_EVENTS + nf_conntrack_unregister_notifier(&init_net, &sfe_cm_conntrack_notifier); + +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0)) + nf_unregister_hooks(sfe_cm_ops_post_routing, ARRAY_SIZE(sfe_cm_ops_post_routing)); +#else + nf_unregister_net_hooks(&init_net, sfe_cm_ops_post_routing, ARRAY_SIZE(sfe_cm_ops_post_routing)); +#endif + unregister_inet6addr_notifier(&sc->inet6_notifier); + unregister_inetaddr_notifier(&sc->inet_notifier); + unregister_netdevice_notifier(&sc->dev_notifier); + + kobject_put(sc->sys_sfe_cm); +} + +module_init(sfe_cm_init) +module_exit(sfe_cm_exit) + +MODULE_DESCRIPTION("Shortcut Forwarding Engine - Connection Manager"); +MODULE_LICENSE("Dual BSD/GPL"); + diff --git a/shortcut-fe/shortcut-fe/sfe_cm.h b/shortcut-fe/shortcut-fe/sfe_cm.h new file mode 100644 index 000000000..23cbde859 --- /dev/null +++ b/shortcut-fe/shortcut-fe/sfe_cm.h @@ -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); +} diff --git a/shortcut-fe/shortcut-fe/sfe_ipv4.c b/shortcut-fe/shortcut-fe/sfe_ipv4.c new file mode 100644 index 000000000..9f7ebd1c9 --- /dev/null +++ b/shortcut-fe/shortcut-fe/sfe_ipv4.c @@ -0,0 +1,3610 @@ +/* + * sfe_ipv4.c + * Shortcut forwarding engine - IPv4 edition. + * + * Copyright (c) 2013-2016, 2019-2020 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 +#include +#include +#include +#include +#include +#include + +#include "sfe.h" +#include "sfe_cm.h" + +/* + * By default Linux IP header and transport layer header structures are + * unpacked, assuming that such headers should be 32-bit aligned. + * Unfortunately some wireless adaptors can't cope with this requirement and + * some CPUs can't handle misaligned accesses. For those platforms we + * define SFE_IPV4_UNALIGNED_IP_HEADER and mark the structures as packed. + * When we do this the compiler will generate slightly worse code than for the + * aligned case (on most platforms) but will be much quicker than fixing + * things up in an unaligned trap handler. + */ +#define SFE_IPV4_UNALIGNED_IP_HEADER 1 +#if SFE_IPV4_UNALIGNED_IP_HEADER +#define SFE_IPV4_UNALIGNED_STRUCT __attribute__((packed)) +#else +#define SFE_IPV4_UNALIGNED_STRUCT +#endif + +/* + * An Ethernet header, but with an optional "packed" attribute to + * help with performance on some platforms (see the definition of + * SFE_IPV4_UNALIGNED_STRUCT) + */ +struct sfe_ipv4_eth_hdr { + __be16 h_dest[ETH_ALEN / 2]; + __be16 h_source[ETH_ALEN / 2]; + __be16 h_proto; +} SFE_IPV4_UNALIGNED_STRUCT; + +#define SFE_IPV4_DSCP_MASK 0x3 +#define SFE_IPV4_DSCP_SHIFT 2 + +/* + * An IPv4 header, but with an optional "packed" attribute to + * help with performance on some platforms (see the definition of + * SFE_IPV4_UNALIGNED_STRUCT) + */ +struct sfe_ipv4_ip_hdr { +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 ihl:4, + version:4; +#elif defined (__BIG_ENDIAN_BITFIELD) + __u8 version:4, + ihl:4; +#else +#error "Please fix " +#endif + __u8 tos; + __be16 tot_len; + __be16 id; + __be16 frag_off; + __u8 ttl; + __u8 protocol; + __sum16 check; + __be32 saddr; + __be32 daddr; + + /* + * The options start here. + */ +} SFE_IPV4_UNALIGNED_STRUCT; + +/* + * A UDP header, but with an optional "packed" attribute to + * help with performance on some platforms (see the definition of + * SFE_IPV4_UNALIGNED_STRUCT) + */ +struct sfe_ipv4_udp_hdr { + __be16 source; + __be16 dest; + __be16 len; + __sum16 check; +} SFE_IPV4_UNALIGNED_STRUCT; + +/* + * A TCP header, but with an optional "packed" attribute to + * help with performance on some platforms (see the definition of + * SFE_IPV4_UNALIGNED_STRUCT) + */ +struct sfe_ipv4_tcp_hdr { + __be16 source; + __be16 dest; + __be32 seq; + __be32 ack_seq; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u16 res1:4, + doff:4, + fin:1, + syn:1, + rst:1, + psh:1, + ack:1, + urg:1, + ece:1, + cwr:1; +#elif defined(__BIG_ENDIAN_BITFIELD) + __u16 doff:4, + res1:4, + cwr:1, + ece:1, + urg:1, + ack:1, + psh:1, + rst:1, + syn:1, + fin:1; +#else +#error "Adjust your defines" +#endif + __be16 window; + __sum16 check; + __be16 urg_ptr; +} SFE_IPV4_UNALIGNED_STRUCT; + +/* + * Specifies the lower bound on ACK numbers carried in the TCP header + */ +#define SFE_IPV4_TCP_MAX_ACK_WINDOW 65520 + +/* + * IPv4 TCP connection match additional data. + */ +struct sfe_ipv4_tcp_connection_match { + u8 win_scale; /* Window scale */ + u32 max_win; /* Maximum window size seen */ + u32 end; /* Sequence number of the next byte to send (seq + segment length) */ + u32 max_end; /* Sequence number of the last byte to ack */ +}; + +/* + * Bit flags for IPv4 connection matching entry. + */ +#define SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_SRC (1<<0) + /* Perform source translation */ +#define SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_DEST (1<<1) + /* Perform destination translation */ +#define SFE_IPV4_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK (1<<2) + /* Ignore TCP sequence numbers */ +#define SFE_IPV4_CONNECTION_MATCH_FLAG_WRITE_FAST_ETH_HDR (1<<3) + /* Fast Ethernet header write */ +#define SFE_IPV4_CONNECTION_MATCH_FLAG_WRITE_L2_HDR (1<<4) + /* Fast Ethernet header write */ +#define SFE_IPV4_CONNECTION_MATCH_FLAG_PRIORITY_REMARK (1<<5) + /* remark priority of SKB */ +#define SFE_IPV4_CONNECTION_MATCH_FLAG_DSCP_REMARK (1<<6) + /* remark DSCP of packet */ + +/* + * IPv4 connection matching structure. + */ +struct sfe_ipv4_connection_match { + /* + * References to other objects. + */ + struct sfe_ipv4_connection_match *next; + struct sfe_ipv4_connection_match *prev; + struct sfe_ipv4_connection *connection; + struct sfe_ipv4_connection_match *counter_match; + /* Matches the flow in the opposite direction as the one in *connection */ + struct sfe_ipv4_connection_match *active_next; + struct sfe_ipv4_connection_match *active_prev; + bool active; /* Flag to indicate if we're on the active list */ + + /* + * Characteristics that identify flows that match this rule. + */ + struct net_device *match_dev; /* Network device */ + u8 match_protocol; /* Protocol */ + __be32 match_src_ip; /* Source IP address */ + __be32 match_dest_ip; /* Destination IP address */ + __be16 match_src_port; /* Source port/connection ident */ + __be16 match_dest_port; /* Destination port/connection ident */ + + /* + * Control the operations of the match. + */ + u32 flags; /* Bit flags */ +#ifdef CONFIG_NF_FLOW_COOKIE + u32 flow_cookie; /* used flow cookie, for debug */ +#endif +#ifdef CONFIG_XFRM + u32 flow_accel; /* The flow accelerated or not */ +#endif + + /* + * Connection state that we track once we match. + */ + union { /* Protocol-specific state */ + struct sfe_ipv4_tcp_connection_match tcp; + } protocol_state; + /* + * Stats recorded in a sync period. These stats will be added to + * rx_packet_count64/rx_byte_count64 after a sync period. + */ + u32 rx_packet_count; + u32 rx_byte_count; + + /* + * Packet translation information. + */ + __be32 xlate_src_ip; /* Address after source translation */ + __be16 xlate_src_port; /* Port/connection ident after source translation */ + u16 xlate_src_csum_adjustment; + /* Transport layer checksum adjustment after source translation */ + u16 xlate_src_partial_csum_adjustment; + /* Transport layer pseudo header checksum adjustment after source translation */ + + __be32 xlate_dest_ip; /* Address after destination translation */ + __be16 xlate_dest_port; /* Port/connection ident after destination translation */ + u16 xlate_dest_csum_adjustment; + /* Transport layer checksum adjustment after destination translation */ + u16 xlate_dest_partial_csum_adjustment; + /* Transport layer pseudo header checksum adjustment after destination translation */ + + /* + * QoS information + */ + u32 priority; + u32 dscp; + + /* + * Packet transmit information. + */ + struct net_device *xmit_dev; /* Network device on which to transmit */ + unsigned short int xmit_dev_mtu; + /* Interface MTU */ + u16 xmit_dest_mac[ETH_ALEN / 2]; + /* Destination MAC address to use when forwarding */ + u16 xmit_src_mac[ETH_ALEN / 2]; + /* Source MAC address to use when forwarding */ + + /* + * Summary stats. + */ + u64 rx_packet_count64; + u64 rx_byte_count64; +}; + +/* + * Per-connection data structure. + */ +struct sfe_ipv4_connection { + struct sfe_ipv4_connection *next; + /* Pointer to the next entry in a hash chain */ + struct sfe_ipv4_connection *prev; + /* Pointer to the previous entry in a hash chain */ + int protocol; /* IP protocol number */ + __be32 src_ip; /* Src IP addr pre-translation */ + __be32 src_ip_xlate; /* Src IP addr post-translation */ + __be32 dest_ip; /* Dest IP addr pre-translation */ + __be32 dest_ip_xlate; /* Dest IP addr post-translation */ + __be16 src_port; /* Src port pre-translation */ + __be16 src_port_xlate; /* Src port post-translation */ + __be16 dest_port; /* Dest port pre-translation */ + __be16 dest_port_xlate; /* Dest port post-translation */ + struct sfe_ipv4_connection_match *original_match; + /* Original direction matching structure */ + struct net_device *original_dev; + /* Original direction source device */ + struct sfe_ipv4_connection_match *reply_match; + /* Reply direction matching structure */ + struct net_device *reply_dev; /* Reply direction source device */ + u64 last_sync_jiffies; /* Jiffies count for the last sync */ + struct sfe_ipv4_connection *all_connections_next; + /* Pointer to the next entry in the list of all connections */ + struct sfe_ipv4_connection *all_connections_prev; + /* Pointer to the previous entry in the list of all connections */ + u32 mark; /* mark for outgoing packet */ + u32 debug_read_seq; /* sequence number for debug dump */ +}; + +/* + * IPv4 connections and hash table size information. + */ +#define SFE_IPV4_CONNECTION_HASH_SHIFT 12 +#define SFE_IPV4_CONNECTION_HASH_SIZE (1 << SFE_IPV4_CONNECTION_HASH_SHIFT) +#define SFE_IPV4_CONNECTION_HASH_MASK (SFE_IPV4_CONNECTION_HASH_SIZE - 1) + +#ifdef CONFIG_NF_FLOW_COOKIE +#define SFE_FLOW_COOKIE_SIZE 2048 +#define SFE_FLOW_COOKIE_MASK 0x7ff + +struct sfe_flow_cookie_entry { + struct sfe_ipv4_connection_match *match; + unsigned long last_clean_time; +}; +#endif + +enum sfe_ipv4_exception_events { + SFE_IPV4_EXCEPTION_EVENT_UDP_HEADER_INCOMPLETE, + SFE_IPV4_EXCEPTION_EVENT_UDP_NO_CONNECTION, + SFE_IPV4_EXCEPTION_EVENT_UDP_IP_OPTIONS_OR_INITIAL_FRAGMENT, + SFE_IPV4_EXCEPTION_EVENT_UDP_SMALL_TTL, + SFE_IPV4_EXCEPTION_EVENT_UDP_NEEDS_FRAGMENTATION, + SFE_IPV4_EXCEPTION_EVENT_TCP_HEADER_INCOMPLETE, + SFE_IPV4_EXCEPTION_EVENT_TCP_NO_CONNECTION_SLOW_FLAGS, + SFE_IPV4_EXCEPTION_EVENT_TCP_NO_CONNECTION_FAST_FLAGS, + SFE_IPV4_EXCEPTION_EVENT_TCP_IP_OPTIONS_OR_INITIAL_FRAGMENT, + SFE_IPV4_EXCEPTION_EVENT_TCP_SMALL_TTL, + SFE_IPV4_EXCEPTION_EVENT_TCP_NEEDS_FRAGMENTATION, + SFE_IPV4_EXCEPTION_EVENT_TCP_FLAGS, + SFE_IPV4_EXCEPTION_EVENT_TCP_SEQ_EXCEEDS_RIGHT_EDGE, + SFE_IPV4_EXCEPTION_EVENT_TCP_SMALL_DATA_OFFS, + SFE_IPV4_EXCEPTION_EVENT_TCP_BAD_SACK, + SFE_IPV4_EXCEPTION_EVENT_TCP_BIG_DATA_OFFS, + SFE_IPV4_EXCEPTION_EVENT_TCP_SEQ_BEFORE_LEFT_EDGE, + SFE_IPV4_EXCEPTION_EVENT_TCP_ACK_EXCEEDS_RIGHT_EDGE, + SFE_IPV4_EXCEPTION_EVENT_TCP_ACK_BEFORE_LEFT_EDGE, + SFE_IPV4_EXCEPTION_EVENT_ICMP_HEADER_INCOMPLETE, + SFE_IPV4_EXCEPTION_EVENT_ICMP_UNHANDLED_TYPE, + SFE_IPV4_EXCEPTION_EVENT_ICMP_IPV4_HEADER_INCOMPLETE, + SFE_IPV4_EXCEPTION_EVENT_ICMP_IPV4_NON_V4, + SFE_IPV4_EXCEPTION_EVENT_ICMP_IPV4_IP_OPTIONS_INCOMPLETE, + SFE_IPV4_EXCEPTION_EVENT_ICMP_IPV4_UDP_HEADER_INCOMPLETE, + SFE_IPV4_EXCEPTION_EVENT_ICMP_IPV4_TCP_HEADER_INCOMPLETE, + SFE_IPV4_EXCEPTION_EVENT_ICMP_IPV4_UNHANDLED_PROTOCOL, + SFE_IPV4_EXCEPTION_EVENT_ICMP_NO_CONNECTION, + SFE_IPV4_EXCEPTION_EVENT_ICMP_FLUSHED_CONNECTION, + SFE_IPV4_EXCEPTION_EVENT_HEADER_INCOMPLETE, + SFE_IPV4_EXCEPTION_EVENT_BAD_TOTAL_LENGTH, + SFE_IPV4_EXCEPTION_EVENT_NON_V4, + SFE_IPV4_EXCEPTION_EVENT_NON_INITIAL_FRAGMENT, + SFE_IPV4_EXCEPTION_EVENT_DATAGRAM_INCOMPLETE, + SFE_IPV4_EXCEPTION_EVENT_IP_OPTIONS_INCOMPLETE, + SFE_IPV4_EXCEPTION_EVENT_UNHANDLED_PROTOCOL, + SFE_IPV4_EXCEPTION_EVENT_LAST +}; + +static char *sfe_ipv4_exception_events_string[SFE_IPV4_EXCEPTION_EVENT_LAST] = { + "UDP_HEADER_INCOMPLETE", + "UDP_NO_CONNECTION", + "UDP_IP_OPTIONS_OR_INITIAL_FRAGMENT", + "UDP_SMALL_TTL", + "UDP_NEEDS_FRAGMENTATION", + "TCP_HEADER_INCOMPLETE", + "TCP_NO_CONNECTION_SLOW_FLAGS", + "TCP_NO_CONNECTION_FAST_FLAGS", + "TCP_IP_OPTIONS_OR_INITIAL_FRAGMENT", + "TCP_SMALL_TTL", + "TCP_NEEDS_FRAGMENTATION", + "TCP_FLAGS", + "TCP_SEQ_EXCEEDS_RIGHT_EDGE", + "TCP_SMALL_DATA_OFFS", + "TCP_BAD_SACK", + "TCP_BIG_DATA_OFFS", + "TCP_SEQ_BEFORE_LEFT_EDGE", + "TCP_ACK_EXCEEDS_RIGHT_EDGE", + "TCP_ACK_BEFORE_LEFT_EDGE", + "ICMP_HEADER_INCOMPLETE", + "ICMP_UNHANDLED_TYPE", + "ICMP_IPV4_HEADER_INCOMPLETE", + "ICMP_IPV4_NON_V4", + "ICMP_IPV4_IP_OPTIONS_INCOMPLETE", + "ICMP_IPV4_UDP_HEADER_INCOMPLETE", + "ICMP_IPV4_TCP_HEADER_INCOMPLETE", + "ICMP_IPV4_UNHANDLED_PROTOCOL", + "ICMP_NO_CONNECTION", + "ICMP_FLUSHED_CONNECTION", + "HEADER_INCOMPLETE", + "BAD_TOTAL_LENGTH", + "NON_V4", + "NON_INITIAL_FRAGMENT", + "DATAGRAM_INCOMPLETE", + "IP_OPTIONS_INCOMPLETE", + "UNHANDLED_PROTOCOL" +}; + +/* + * Per-module structure. + */ +struct sfe_ipv4 { + spinlock_t lock; /* Lock for SMP correctness */ + struct sfe_ipv4_connection_match *active_head; + /* Head of the list of recently active connections */ + struct sfe_ipv4_connection_match *active_tail; + /* Tail of the list of recently active connections */ + struct sfe_ipv4_connection *all_connections_head; + /* Head of the list of all connections */ + struct sfe_ipv4_connection *all_connections_tail; + /* Tail of the list of all connections */ + unsigned int num_connections; /* Number of connections */ + struct timer_list timer; /* Timer used for periodic sync ops */ + sfe_sync_rule_callback_t __rcu sync_rule_callback; + /* Callback function registered by a connection manager for stats syncing */ + struct sfe_ipv4_connection *conn_hash[SFE_IPV4_CONNECTION_HASH_SIZE]; + /* Connection hash table */ + struct sfe_ipv4_connection_match *conn_match_hash[SFE_IPV4_CONNECTION_HASH_SIZE]; + /* Connection match hash table */ +#ifdef CONFIG_NF_FLOW_COOKIE + struct sfe_flow_cookie_entry sfe_flow_cookie_table[SFE_FLOW_COOKIE_SIZE]; + /* flow cookie table*/ + flow_cookie_set_func_t flow_cookie_set_func; + /* function used to configure flow cookie in hardware*/ + int flow_cookie_enable; + /* Enable/disable flow cookie at runtime */ +#endif + + /* + * Stats recorded in a sync period. These stats will be added to + * connection_xxx64 after a sync period. + */ + u32 connection_create_requests; + /* Number of IPv4 connection create requests */ + u32 connection_create_collisions; + /* Number of IPv4 connection create requests that collided with existing hash table entries */ + u32 connection_destroy_requests; + /* Number of IPv4 connection destroy requests */ + u32 connection_destroy_misses; + /* Number of IPv4 connection destroy requests that missed our hash table */ + u32 connection_match_hash_hits; + /* Number of IPv4 connection match hash hits */ + u32 connection_match_hash_reorders; + /* Number of IPv4 connection match hash reorders */ + u32 connection_flushes; /* Number of IPv4 connection flushes */ + u32 packets_forwarded; /* Number of IPv4 packets forwarded */ + u32 packets_not_forwarded; /* Number of IPv4 packets not forwarded */ + u32 exception_events[SFE_IPV4_EXCEPTION_EVENT_LAST]; + + /* + * Summary statistics. + */ + u64 connection_create_requests64; + /* Number of IPv4 connection create requests */ + u64 connection_create_collisions64; + /* Number of IPv4 connection create requests that collided with existing hash table entries */ + u64 connection_destroy_requests64; + /* Number of IPv4 connection destroy requests */ + u64 connection_destroy_misses64; + /* Number of IPv4 connection destroy requests that missed our hash table */ + u64 connection_match_hash_hits64; + /* Number of IPv4 connection match hash hits */ + u64 connection_match_hash_reorders64; + /* Number of IPv4 connection match hash reorders */ + u64 connection_flushes64; /* Number of IPv4 connection flushes */ + u64 packets_forwarded64; /* Number of IPv4 packets forwarded */ + u64 packets_not_forwarded64; + /* Number of IPv4 packets not forwarded */ + u64 exception_events64[SFE_IPV4_EXCEPTION_EVENT_LAST]; + + /* + * Control state. + */ + struct kobject *sys_sfe_ipv4; /* sysfs linkage */ + int debug_dev; /* Major number of the debug char device */ + u32 debug_read_seq; /* sequence number for debug dump */ +}; + +/* + * Enumeration of the XML output. + */ +enum sfe_ipv4_debug_xml_states { + SFE_IPV4_DEBUG_XML_STATE_START, + SFE_IPV4_DEBUG_XML_STATE_CONNECTIONS_START, + SFE_IPV4_DEBUG_XML_STATE_CONNECTIONS_CONNECTION, + SFE_IPV4_DEBUG_XML_STATE_CONNECTIONS_END, + SFE_IPV4_DEBUG_XML_STATE_EXCEPTIONS_START, + SFE_IPV4_DEBUG_XML_STATE_EXCEPTIONS_EXCEPTION, + SFE_IPV4_DEBUG_XML_STATE_EXCEPTIONS_END, + SFE_IPV4_DEBUG_XML_STATE_STATS, + SFE_IPV4_DEBUG_XML_STATE_END, + SFE_IPV4_DEBUG_XML_STATE_DONE +}; + +/* + * XML write state. + */ +struct sfe_ipv4_debug_xml_write_state { + enum sfe_ipv4_debug_xml_states state; + /* XML output file state machine state */ + int iter_exception; /* Next exception iterator */ +}; + +typedef bool (*sfe_ipv4_debug_xml_write_method_t)(struct sfe_ipv4 *si, char *buffer, char *msg, size_t *length, + int *total_read, struct sfe_ipv4_debug_xml_write_state *ws); + +static struct sfe_ipv4 __si; + +/* + * sfe_ipv4_gen_ip_csum() + * Generate the IP checksum for an IPv4 header. + * + * Note that this function assumes that we have only 20 bytes of IP header. + */ +static inline u16 sfe_ipv4_gen_ip_csum(struct sfe_ipv4_ip_hdr *iph) +{ + u32 sum; + u16 *i = (u16 *)iph; + + iph->check = 0; + + /* + * Generate the sum. + */ + sum = i[0] + i[1] + i[2] + i[3] + i[4] + i[5] + i[6] + i[7] + i[8] + i[9]; + + /* + * Fold it to ones-complement form. + */ + sum = (sum & 0xffff) + (sum >> 16); + sum = (sum & 0xffff) + (sum >> 16); + + return (u16)sum ^ 0xffff; +} + +/* + * sfe_ipv4_get_connection_match_hash() + * Generate the hash used in connection match lookups. + */ +static inline unsigned int sfe_ipv4_get_connection_match_hash(struct net_device *dev, u8 protocol, + __be32 src_ip, __be16 src_port, + __be32 dest_ip, __be16 dest_port) +{ + size_t dev_addr = (size_t)dev; + u32 hash = ((u32)dev_addr) ^ ntohl(src_ip ^ dest_ip) ^ protocol ^ ntohs(src_port ^ dest_port); + return ((hash >> SFE_IPV4_CONNECTION_HASH_SHIFT) ^ hash) & SFE_IPV4_CONNECTION_HASH_MASK; +} + +/* + * sfe_ipv4_find_sfe_ipv4_connection_match() + * Get the IPv4 flow match info that corresponds to a particular 5-tuple. + * + * On entry we must be holding the lock that protects the hash table. + */ +static struct sfe_ipv4_connection_match * +sfe_ipv4_find_sfe_ipv4_connection_match(struct sfe_ipv4 *si, struct net_device *dev, u8 protocol, + __be32 src_ip, __be16 src_port, + __be32 dest_ip, __be16 dest_port) +{ + struct sfe_ipv4_connection_match *cm; + struct sfe_ipv4_connection_match *head; + unsigned int conn_match_idx; + + conn_match_idx = sfe_ipv4_get_connection_match_hash(dev, protocol, src_ip, src_port, dest_ip, dest_port); + cm = si->conn_match_hash[conn_match_idx]; + + /* + * If we don't have anything in this chain then bail. + */ + if (unlikely(!cm)) { + return NULL; + } + + /* + * Hopefully the first entry is the one we want. + */ + if ((cm->match_src_port == src_port) + && (cm->match_dest_port == dest_port) + && (cm->match_src_ip == src_ip) + && (cm->match_dest_ip == dest_ip) + && (cm->match_protocol == protocol) + && (cm->match_dev == dev)) { + si->connection_match_hash_hits++; + return cm; + } + + /* + * Unfortunately we didn't find it at head, so we search it in chain and + * move matching entry to the top of the hash chain. We presume that this + * will be reused again very quickly. + */ + head = cm; + do { + cm = cm->next; + } while (cm && (cm->match_src_port != src_port + || cm->match_dest_port != dest_port + || cm->match_src_ip != src_ip + || cm->match_dest_ip != dest_ip + || cm->match_protocol != protocol + || cm->match_dev != dev)); + + /* + * Not found then we're done. + */ + if (unlikely(!cm)) { + return NULL; + } + + /* + * We found a match so move it. + */ + if (cm->next) { + cm->next->prev = cm->prev; + } + cm->prev->next = cm->next; + cm->prev = NULL; + cm->next = head; + head->prev = cm; + si->conn_match_hash[conn_match_idx] = cm; + si->connection_match_hash_reorders++; + + return cm; +} + +/* + * sfe_ipv4_connection_match_update_summary_stats() + * Update the summary stats for a connection match entry. + */ +static inline void sfe_ipv4_connection_match_update_summary_stats(struct sfe_ipv4_connection_match *cm) +{ + cm->rx_packet_count64 += cm->rx_packet_count; + cm->rx_packet_count = 0; + cm->rx_byte_count64 += cm->rx_byte_count; + cm->rx_byte_count = 0; +} + +/* + * sfe_ipv4_connection_match_compute_translations() + * Compute port and address translations for a connection match entry. + */ +static void sfe_ipv4_connection_match_compute_translations(struct sfe_ipv4_connection_match *cm) +{ + /* + * Before we insert the entry look to see if this is tagged as doing address + * translations. If it is then work out the adjustment that we need to apply + * to the transport checksum. + */ + if (cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_SRC) { + /* + * Precompute an incremental checksum adjustment so we can + * edit packets in this stream very quickly. The algorithm is from RFC1624. + */ + u16 src_ip_hi = cm->match_src_ip >> 16; + u16 src_ip_lo = cm->match_src_ip & 0xffff; + u32 xlate_src_ip = ~cm->xlate_src_ip; + u16 xlate_src_ip_hi = xlate_src_ip >> 16; + u16 xlate_src_ip_lo = xlate_src_ip & 0xffff; + u16 xlate_src_port = ~cm->xlate_src_port; + u32 adj; + + /* + * When we compute this fold it down to a 16-bit offset + * as that way we can avoid having to do a double + * folding of the twos-complement result because the + * addition of 2 16-bit values cannot cause a double + * wrap-around! + */ + adj = src_ip_hi + src_ip_lo + cm->match_src_port + + xlate_src_ip_hi + xlate_src_ip_lo + xlate_src_port; + adj = (adj & 0xffff) + (adj >> 16); + adj = (adj & 0xffff) + (adj >> 16); + cm->xlate_src_csum_adjustment = (u16)adj; + + } + + if (cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_DEST) { + /* + * Precompute an incremental checksum adjustment so we can + * edit packets in this stream very quickly. The algorithm is from RFC1624. + */ + u16 dest_ip_hi = cm->match_dest_ip >> 16; + u16 dest_ip_lo = cm->match_dest_ip & 0xffff; + u32 xlate_dest_ip = ~cm->xlate_dest_ip; + u16 xlate_dest_ip_hi = xlate_dest_ip >> 16; + u16 xlate_dest_ip_lo = xlate_dest_ip & 0xffff; + u16 xlate_dest_port = ~cm->xlate_dest_port; + u32 adj; + + /* + * When we compute this fold it down to a 16-bit offset + * as that way we can avoid having to do a double + * folding of the twos-complement result because the + * addition of 2 16-bit values cannot cause a double + * wrap-around! + */ + adj = dest_ip_hi + dest_ip_lo + cm->match_dest_port + + xlate_dest_ip_hi + xlate_dest_ip_lo + xlate_dest_port; + adj = (adj & 0xffff) + (adj >> 16); + adj = (adj & 0xffff) + (adj >> 16); + cm->xlate_dest_csum_adjustment = (u16)adj; + } + + if (cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_SRC) { + u32 adj = ~cm->match_src_ip + cm->xlate_src_ip; + if (adj < cm->xlate_src_ip) { + adj++; + } + + adj = (adj & 0xffff) + (adj >> 16); + adj = (adj & 0xffff) + (adj >> 16); + cm->xlate_src_partial_csum_adjustment = (u16)adj; + } + + if (cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_DEST) { + u32 adj = ~cm->match_dest_ip + cm->xlate_dest_ip; + if (adj < cm->xlate_dest_ip) { + adj++; + } + + adj = (adj & 0xffff) + (adj >> 16); + adj = (adj & 0xffff) + (adj >> 16); + cm->xlate_dest_partial_csum_adjustment = (u16)adj; + } + +} + +/* + * sfe_ipv4_update_summary_stats() + * Update the summary stats. + */ +static void sfe_ipv4_update_summary_stats(struct sfe_ipv4 *si) +{ + int i; + + si->connection_create_requests64 += si->connection_create_requests; + si->connection_create_requests = 0; + si->connection_create_collisions64 += si->connection_create_collisions; + si->connection_create_collisions = 0; + si->connection_destroy_requests64 += si->connection_destroy_requests; + si->connection_destroy_requests = 0; + si->connection_destroy_misses64 += si->connection_destroy_misses; + si->connection_destroy_misses = 0; + si->connection_match_hash_hits64 += si->connection_match_hash_hits; + si->connection_match_hash_hits = 0; + si->connection_match_hash_reorders64 += si->connection_match_hash_reorders; + si->connection_match_hash_reorders = 0; + si->connection_flushes64 += si->connection_flushes; + si->connection_flushes = 0; + si->packets_forwarded64 += si->packets_forwarded; + si->packets_forwarded = 0; + si->packets_not_forwarded64 += si->packets_not_forwarded; + si->packets_not_forwarded = 0; + + for (i = 0; i < SFE_IPV4_EXCEPTION_EVENT_LAST; i++) { + si->exception_events64[i] += si->exception_events[i]; + si->exception_events[i] = 0; + } +} + +/* + * sfe_ipv4_insert_sfe_ipv4_connection_match() + * Insert a connection match into the hash. + * + * On entry we must be holding the lock that protects the hash table. + */ +static inline void sfe_ipv4_insert_sfe_ipv4_connection_match(struct sfe_ipv4 *si, + struct sfe_ipv4_connection_match *cm) +{ + struct sfe_ipv4_connection_match **hash_head; + struct sfe_ipv4_connection_match *prev_head; + unsigned int conn_match_idx + = sfe_ipv4_get_connection_match_hash(cm->match_dev, cm->match_protocol, + cm->match_src_ip, cm->match_src_port, + cm->match_dest_ip, cm->match_dest_port); + + hash_head = &si->conn_match_hash[conn_match_idx]; + prev_head = *hash_head; + cm->prev = NULL; + if (prev_head) { + prev_head->prev = cm; + } + + cm->next = prev_head; + *hash_head = cm; + +#ifdef CONFIG_NF_FLOW_COOKIE + if (!si->flow_cookie_enable) + return; + + /* + * Configure hardware to put a flow cookie in packet of this flow, + * then we can accelerate the lookup process when we received this packet. + */ + for (conn_match_idx = 1; conn_match_idx < SFE_FLOW_COOKIE_SIZE; conn_match_idx++) { + struct sfe_flow_cookie_entry *entry = &si->sfe_flow_cookie_table[conn_match_idx]; + + if ((NULL == entry->match) && time_is_before_jiffies(entry->last_clean_time + HZ)) { + flow_cookie_set_func_t func; + + rcu_read_lock(); + func = rcu_dereference(si->flow_cookie_set_func); + if (func) { + if (!func(cm->match_protocol, cm->match_src_ip, cm->match_src_port, + cm->match_dest_ip, cm->match_dest_port, conn_match_idx)) { + entry->match = cm; + cm->flow_cookie = conn_match_idx; + } + } + rcu_read_unlock(); + + break; + } + } +#endif +} + +/* + * sfe_ipv4_remove_sfe_ipv4_connection_match() + * Remove a connection match object from the hash. + * + * On entry we must be holding the lock that protects the hash table. + */ +static inline void sfe_ipv4_remove_sfe_ipv4_connection_match(struct sfe_ipv4 *si, struct sfe_ipv4_connection_match *cm) +{ +#ifdef CONFIG_NF_FLOW_COOKIE + if (si->flow_cookie_enable) { + /* + * Tell hardware that we no longer need a flow cookie in packet of this flow + */ + unsigned int conn_match_idx; + + for (conn_match_idx = 1; conn_match_idx < SFE_FLOW_COOKIE_SIZE; conn_match_idx++) { + struct sfe_flow_cookie_entry *entry = &si->sfe_flow_cookie_table[conn_match_idx]; + + if (cm == entry->match) { + flow_cookie_set_func_t func; + + rcu_read_lock(); + func = rcu_dereference(si->flow_cookie_set_func); + if (func) { + func(cm->match_protocol, cm->match_src_ip, cm->match_src_port, + cm->match_dest_ip, cm->match_dest_port, 0); + } + rcu_read_unlock(); + + cm->flow_cookie = 0; + entry->match = NULL; + entry->last_clean_time = jiffies; + break; + } + } + } +#endif + + /* + * Unlink the connection match entry from the hash. + */ + if (cm->prev) { + cm->prev->next = cm->next; + } else { + unsigned int conn_match_idx + = sfe_ipv4_get_connection_match_hash(cm->match_dev, cm->match_protocol, + cm->match_src_ip, cm->match_src_port, + cm->match_dest_ip, cm->match_dest_port); + si->conn_match_hash[conn_match_idx] = cm->next; + } + + if (cm->next) { + cm->next->prev = cm->prev; + } + + /* + * If the connection match entry is in the active list remove it. + */ + if (cm->active) { + if (likely(cm->active_prev)) { + cm->active_prev->active_next = cm->active_next; + } else { + si->active_head = cm->active_next; + } + + if (likely(cm->active_next)) { + cm->active_next->active_prev = cm->active_prev; + } else { + si->active_tail = cm->active_prev; + } + } +} + +/* + * sfe_ipv4_get_connection_hash() + * Generate the hash used in connection lookups. + */ +static inline unsigned int sfe_ipv4_get_connection_hash(u8 protocol, __be32 src_ip, __be16 src_port, + __be32 dest_ip, __be16 dest_port) +{ + u32 hash = ntohl(src_ip ^ dest_ip) ^ protocol ^ ntohs(src_port ^ dest_port); + return ((hash >> SFE_IPV4_CONNECTION_HASH_SHIFT) ^ hash) & SFE_IPV4_CONNECTION_HASH_MASK; +} + +/* + * sfe_ipv4_find_sfe_ipv4_connection() + * Get the IPv4 connection info that corresponds to a particular 5-tuple. + * + * On entry we must be holding the lock that protects the hash table. + */ +static inline struct sfe_ipv4_connection *sfe_ipv4_find_sfe_ipv4_connection(struct sfe_ipv4 *si, u32 protocol, + __be32 src_ip, __be16 src_port, + __be32 dest_ip, __be16 dest_port) +{ + struct sfe_ipv4_connection *c; + unsigned int conn_idx = sfe_ipv4_get_connection_hash(protocol, src_ip, src_port, dest_ip, dest_port); + c = si->conn_hash[conn_idx]; + + /* + * If we don't have anything in this chain then bale. + */ + if (unlikely(!c)) { + return NULL; + } + + /* + * Hopefully the first entry is the one we want. + */ + if ((c->src_port == src_port) + && (c->dest_port == dest_port) + && (c->src_ip == src_ip) + && (c->dest_ip == dest_ip) + && (c->protocol == protocol)) { + return c; + } + + /* + * Unfortunately we didn't find it at head, so we search it in chain. + */ + do { + c = c->next; + } while (c && (c->src_port != src_port + || c->dest_port != dest_port + || c->src_ip != src_ip + || c->dest_ip != dest_ip + || c->protocol != protocol)); + + /* + * Will need connection entry for next create/destroy metadata, + * So no need to re-order entry for these requests + */ + return c; +} + +/* + * sfe_ipv4_mark_rule() + * Updates the mark for a current offloaded connection + * + * Will take hash lock upon entry + */ +void sfe_ipv4_mark_rule(struct sfe_connection_mark *mark) +{ + struct sfe_ipv4 *si = &__si; + struct sfe_ipv4_connection *c; + + spin_lock_bh(&si->lock); + c = sfe_ipv4_find_sfe_ipv4_connection(si, mark->protocol, + mark->src_ip.ip, mark->src_port, + mark->dest_ip.ip, mark->dest_port); + if (c) { + WARN_ON((0 != c->mark) && (0 == mark->mark)); + c->mark = mark->mark; + } + spin_unlock_bh(&si->lock); + + if (c) { + DEBUG_TRACE("Matching connection found for mark, " + "setting from %08x to %08x\n", + c->mark, mark->mark); + } +} + +/* + * sfe_ipv4_insert_sfe_ipv4_connection() + * Insert a connection into the hash. + * + * On entry we must be holding the lock that protects the hash table. + */ +static void sfe_ipv4_insert_sfe_ipv4_connection(struct sfe_ipv4 *si, struct sfe_ipv4_connection *c) +{ + struct sfe_ipv4_connection **hash_head; + struct sfe_ipv4_connection *prev_head; + unsigned int conn_idx; + + /* + * Insert entry into the connection hash. + */ + conn_idx = sfe_ipv4_get_connection_hash(c->protocol, c->src_ip, c->src_port, + c->dest_ip, c->dest_port); + hash_head = &si->conn_hash[conn_idx]; + prev_head = *hash_head; + c->prev = NULL; + if (prev_head) { + prev_head->prev = c; + } + + c->next = prev_head; + *hash_head = c; + + /* + * Insert entry into the "all connections" list. + */ + if (si->all_connections_tail) { + c->all_connections_prev = si->all_connections_tail; + si->all_connections_tail->all_connections_next = c; + } else { + c->all_connections_prev = NULL; + si->all_connections_head = c; + } + + si->all_connections_tail = c; + c->all_connections_next = NULL; + si->num_connections++; + + /* + * Insert the connection match objects too. + */ + sfe_ipv4_insert_sfe_ipv4_connection_match(si, c->original_match); + sfe_ipv4_insert_sfe_ipv4_connection_match(si, c->reply_match); +} + +/* + * sfe_ipv4_remove_sfe_ipv4_connection() + * Remove a sfe_ipv4_connection object from the hash. + * + * On entry we must be holding the lock that protects the hash table. + */ +static void sfe_ipv4_remove_sfe_ipv4_connection(struct sfe_ipv4 *si, struct sfe_ipv4_connection *c) +{ + /* + * Remove the connection match objects. + */ + sfe_ipv4_remove_sfe_ipv4_connection_match(si, c->reply_match); + sfe_ipv4_remove_sfe_ipv4_connection_match(si, c->original_match); + + /* + * Unlink the connection. + */ + if (c->prev) { + c->prev->next = c->next; + } else { + unsigned int conn_idx = sfe_ipv4_get_connection_hash(c->protocol, c->src_ip, c->src_port, + c->dest_ip, c->dest_port); + si->conn_hash[conn_idx] = c->next; + } + + if (c->next) { + c->next->prev = c->prev; + } + + /* + * Unlink connection from all_connections list + */ + if (c->all_connections_prev) { + c->all_connections_prev->all_connections_next = c->all_connections_next; + } else { + si->all_connections_head = c->all_connections_next; + } + + if (c->all_connections_next) { + c->all_connections_next->all_connections_prev = c->all_connections_prev; + } else { + si->all_connections_tail = c->all_connections_prev; + } + + si->num_connections--; +} + +/* + * sfe_ipv4_sync_sfe_ipv4_connection() + * Sync a connection. + * + * On entry to this function we expect that the lock for the connection is either + * already held or isn't required. + */ +static void sfe_ipv4_gen_sync_sfe_ipv4_connection(struct sfe_ipv4 *si, struct sfe_ipv4_connection *c, + struct sfe_connection_sync *sis, sfe_sync_reason_t reason, + u64 now_jiffies) +{ + struct sfe_ipv4_connection_match *original_cm; + struct sfe_ipv4_connection_match *reply_cm; + + /* + * Fill in the update message. + */ + sis->is_v6 = 0; + sis->protocol = c->protocol; + sis->src_ip.ip = c->src_ip; + sis->src_ip_xlate.ip = c->src_ip_xlate; + sis->dest_ip.ip = c->dest_ip; + sis->dest_ip_xlate.ip = c->dest_ip_xlate; + sis->src_port = c->src_port; + sis->src_port_xlate = c->src_port_xlate; + sis->dest_port = c->dest_port; + sis->dest_port_xlate = c->dest_port_xlate; + + original_cm = c->original_match; + reply_cm = c->reply_match; + sis->src_td_max_window = original_cm->protocol_state.tcp.max_win; + sis->src_td_end = original_cm->protocol_state.tcp.end; + sis->src_td_max_end = original_cm->protocol_state.tcp.max_end; + sis->dest_td_max_window = reply_cm->protocol_state.tcp.max_win; + sis->dest_td_end = reply_cm->protocol_state.tcp.end; + sis->dest_td_max_end = reply_cm->protocol_state.tcp.max_end; + + sis->src_new_packet_count = original_cm->rx_packet_count; + sis->src_new_byte_count = original_cm->rx_byte_count; + sis->dest_new_packet_count = reply_cm->rx_packet_count; + sis->dest_new_byte_count = reply_cm->rx_byte_count; + + sfe_ipv4_connection_match_update_summary_stats(original_cm); + sfe_ipv4_connection_match_update_summary_stats(reply_cm); + + sis->src_dev = original_cm->match_dev; + sis->src_packet_count = original_cm->rx_packet_count64; + sis->src_byte_count = original_cm->rx_byte_count64; + + sis->dest_dev = reply_cm->match_dev; + sis->dest_packet_count = reply_cm->rx_packet_count64; + sis->dest_byte_count = reply_cm->rx_byte_count64; + + sis->reason = reason; + + /* + * Get the time increment since our last sync. + */ + sis->delta_jiffies = now_jiffies - c->last_sync_jiffies; + c->last_sync_jiffies = now_jiffies; +} + +/* + * sfe_ipv4_flush_sfe_ipv4_connection() + * Flush a connection and free all associated resources. + * + * We need to be called with bottom halves disabled locally as we need to acquire + * the connection hash lock and release it again. In general we're actually called + * from within a BH and so we're fine, but we're also called when connections are + * torn down. + */ +static void sfe_ipv4_flush_sfe_ipv4_connection(struct sfe_ipv4 *si, + struct sfe_ipv4_connection *c, + sfe_sync_reason_t reason) +{ + struct sfe_connection_sync sis; + u64 now_jiffies; + sfe_sync_rule_callback_t sync_rule_callback; + + rcu_read_lock(); + spin_lock_bh(&si->lock); + si->connection_flushes++; + sync_rule_callback = rcu_dereference(si->sync_rule_callback); + spin_unlock_bh(&si->lock); + + if (sync_rule_callback) { + /* + * Generate a sync message and then sync. + */ + now_jiffies = get_jiffies_64(); + sfe_ipv4_gen_sync_sfe_ipv4_connection(si, c, &sis, reason, now_jiffies); + sync_rule_callback(&sis); + } + + rcu_read_unlock(); + + /* + * Release our hold of the source and dest devices and free the memory + * for our connection objects. + */ + dev_put(c->original_dev); + dev_put(c->reply_dev); + kfree(c->original_match); + kfree(c->reply_match); + kfree(c); +} + +/* + * sfe_ipv4_recv_udp() + * Handle UDP packet receives and forwarding. + */ +static int sfe_ipv4_recv_udp(struct sfe_ipv4 *si, struct sk_buff *skb, struct net_device *dev, + unsigned int len, struct sfe_ipv4_ip_hdr *iph, unsigned int ihl, bool flush_on_find) +{ + struct sfe_ipv4_udp_hdr *udph; + __be32 src_ip; + __be32 dest_ip; + __be16 src_port; + __be16 dest_port; + struct sfe_ipv4_connection_match *cm; + u8 ttl; + struct net_device *xmit_dev; + + /* + * Is our packet too short to contain a valid UDP header? + */ + if (unlikely(!pskb_may_pull(skb, (sizeof(struct sfe_ipv4_udp_hdr) + ihl)))) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_UDP_HEADER_INCOMPLETE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("packet too short for UDP header\n"); + return 0; + } + + /* + * Read the IP address and port information. Read the IP header data first + * because we've almost certainly got that in the cache. We may not yet have + * the UDP header cached though so allow more time for any prefetching. + */ + src_ip = iph->saddr; + dest_ip = iph->daddr; + + udph = (struct sfe_ipv4_udp_hdr *)(skb->data + ihl); + src_port = udph->source; + dest_port = udph->dest; + + spin_lock_bh(&si->lock); + + /* + * Look for a connection match. + */ +#ifdef CONFIG_NF_FLOW_COOKIE + cm = si->sfe_flow_cookie_table[skb->flow_cookie & SFE_FLOW_COOKIE_MASK].match; + if (unlikely(!cm)) { + cm = sfe_ipv4_find_sfe_ipv4_connection_match(si, dev, IPPROTO_UDP, src_ip, src_port, dest_ip, dest_port); + } +#else + cm = sfe_ipv4_find_sfe_ipv4_connection_match(si, dev, IPPROTO_UDP, src_ip, src_port, dest_ip, dest_port); +#endif + if (unlikely(!cm)) { + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_UDP_NO_CONNECTION]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("no connection found\n"); + return 0; + } + + /* + * If our packet has beern marked as "flush on find" we can't actually + * forward it in the fast path, but now that we've found an associated + * connection we can flush that out before we process the packet. + */ + if (unlikely(flush_on_find)) { + struct sfe_ipv4_connection *c = cm->connection; + sfe_ipv4_remove_sfe_ipv4_connection(si, c); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_UDP_IP_OPTIONS_OR_INITIAL_FRAGMENT]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("flush on find\n"); + sfe_ipv4_flush_sfe_ipv4_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + +#ifdef CONFIG_XFRM + /* + * We can't accelerate the flow on this direction, just let it go + * through the slow path. + */ + if (unlikely(!cm->flow_accel)) { + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + return 0; + } +#endif + + /* + * Does our TTL allow forwarding? + */ + ttl = iph->ttl; + if (unlikely(ttl < 2)) { + struct sfe_ipv4_connection *c = cm->connection; + sfe_ipv4_remove_sfe_ipv4_connection(si, c); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_UDP_SMALL_TTL]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("ttl too low\n"); + sfe_ipv4_flush_sfe_ipv4_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + /* + * If our packet is larger than the MTU of the transmit interface then + * we can't forward it easily. + */ + if (unlikely(len > cm->xmit_dev_mtu)) { + struct sfe_ipv4_connection *c = cm->connection; + sfe_ipv4_remove_sfe_ipv4_connection(si, c); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_UDP_NEEDS_FRAGMENTATION]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("larger than mtu\n"); + sfe_ipv4_flush_sfe_ipv4_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + /* + * From this point on we're good to modify the packet. + */ + + /* + * Check if skb was cloned. If it was, unshare it. Because + * the data area is going to be written in this path and we don't want to + * change the cloned skb's data section. + */ + if (unlikely(skb_cloned(skb))) { + DEBUG_TRACE("%px: skb is a cloned skb\n", skb); + skb = skb_unshare(skb, GFP_ATOMIC); + if (!skb) { + DEBUG_WARN("Failed to unshare the cloned skb\n"); + return 0; + } + + /* + * Update the iph and udph pointers with the unshared skb's data area. + */ + iph = (struct sfe_ipv4_ip_hdr *)skb->data; + udph = (struct sfe_ipv4_udp_hdr *)(skb->data + ihl); + } + + /* + * Update DSCP + */ + if (unlikely(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_DSCP_REMARK)) { + iph->tos = (iph->tos & SFE_IPV4_DSCP_MASK) | cm->dscp; + } + + /* + * Decrement our TTL. + */ + iph->ttl = ttl - 1; + + /* + * Do we have to perform translations of the source address/port? + */ + if (unlikely(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_SRC)) { + u16 udp_csum; + + iph->saddr = cm->xlate_src_ip; + udph->source = cm->xlate_src_port; + + /* + * Do we have a non-zero UDP checksum? If we do then we need + * to update it. + */ + udp_csum = udph->check; + if (likely(udp_csum)) { + u32 sum; + + if (unlikely(skb->ip_summed == CHECKSUM_PARTIAL)) { + sum = udp_csum + cm->xlate_src_partial_csum_adjustment; + } else { + sum = udp_csum + cm->xlate_src_csum_adjustment; + } + + sum = (sum & 0xffff) + (sum >> 16); + udph->check = (u16)sum; + } + } + + /* + * Do we have to perform translations of the destination address/port? + */ + if (unlikely(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_DEST)) { + u16 udp_csum; + + iph->daddr = cm->xlate_dest_ip; + udph->dest = cm->xlate_dest_port; + + /* + * Do we have a non-zero UDP checksum? If we do then we need + * to update it. + */ + udp_csum = udph->check; + if (likely(udp_csum)) { + u32 sum; + + if (unlikely(skb->ip_summed == CHECKSUM_PARTIAL)) { + sum = udp_csum + cm->xlate_dest_partial_csum_adjustment; + } else { + sum = udp_csum + cm->xlate_dest_csum_adjustment; + } + + sum = (sum & 0xffff) + (sum >> 16); + udph->check = (u16)sum; + } + } + + /* + * Replace the IP checksum. + */ + iph->check = sfe_ipv4_gen_ip_csum(iph); + + /* + * Update traffic stats. + */ + cm->rx_packet_count++; + cm->rx_byte_count += len; + + /* + * If we're not already on the active list then insert ourselves at the tail + * of the current list. + */ + if (unlikely(!cm->active)) { + cm->active = true; + cm->active_prev = si->active_tail; + if (likely(si->active_tail)) { + si->active_tail->active_next = cm; + } else { + si->active_head = cm; + } + si->active_tail = cm; + } + + xmit_dev = cm->xmit_dev; + skb->dev = xmit_dev; + + /* + * Check to see if we need to write a header. + */ + if (likely(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_WRITE_L2_HDR)) { + if (unlikely(!(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_WRITE_FAST_ETH_HDR))) { + dev_hard_header(skb, xmit_dev, ETH_P_IP, + cm->xmit_dest_mac, cm->xmit_src_mac, len); + } else { + /* + * For the simple case we write this really fast. + */ + struct sfe_ipv4_eth_hdr *eth = (struct sfe_ipv4_eth_hdr *)__skb_push(skb, ETH_HLEN); + eth->h_proto = htons(ETH_P_IP); + eth->h_dest[0] = cm->xmit_dest_mac[0]; + eth->h_dest[1] = cm->xmit_dest_mac[1]; + eth->h_dest[2] = cm->xmit_dest_mac[2]; + eth->h_source[0] = cm->xmit_src_mac[0]; + eth->h_source[1] = cm->xmit_src_mac[1]; + eth->h_source[2] = cm->xmit_src_mac[2]; + } + } + + /* + * Update priority of skb. + */ + if (unlikely(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_PRIORITY_REMARK)) { + skb->priority = cm->priority; + } + + /* + * Mark outgoing packet. + */ + skb->mark = cm->connection->mark; + if (skb->mark) { + DEBUG_TRACE("SKB MARK is NON ZERO %x\n", skb->mark); + } + + si->packets_forwarded++; + spin_unlock_bh(&si->lock); + + /* + * We're going to check for GSO flags when we transmit the packet so + * start fetching the necessary cache line now. + */ + prefetch(skb_shinfo(skb)); + + /* + * Mark that this packet has been fast forwarded. + */ + skb->fast_forwarded = 1; + + /* + * Send the packet on its way. + */ + dev_queue_xmit(skb); + + return 1; +} + +/* + * sfe_ipv4_process_tcp_option_sack() + * Parse TCP SACK option and update ack according + */ +static bool sfe_ipv4_process_tcp_option_sack(const struct sfe_ipv4_tcp_hdr *th, const u32 data_offs, + u32 *ack) +{ + u32 length = sizeof(struct sfe_ipv4_tcp_hdr); + u8 *ptr = (u8 *)th + length; + + /* + * Ignore processing if TCP packet has only TIMESTAMP option. + */ + if (likely(data_offs == length + TCPOLEN_TIMESTAMP + 1 + 1) + && likely(ptr[0] == TCPOPT_NOP) + && likely(ptr[1] == TCPOPT_NOP) + && likely(ptr[2] == TCPOPT_TIMESTAMP) + && likely(ptr[3] == TCPOLEN_TIMESTAMP)) { + return true; + } + + /* + * TCP options. Parse SACK option. + */ + while (length < data_offs) { + u8 size; + u8 kind; + + ptr = (u8 *)th + length; + kind = *ptr; + + /* + * NOP, for padding + * Not in the switch because to fast escape and to not calculate size + */ + if (kind == TCPOPT_NOP) { + length++; + continue; + } + + if (kind == TCPOPT_SACK) { + u32 sack = 0; + u8 re = 1 + 1; + + size = *(ptr + 1); + if ((size < (1 + 1 + TCPOLEN_SACK_PERBLOCK)) + || ((size - (1 + 1)) % (TCPOLEN_SACK_PERBLOCK)) + || (size > (data_offs - length))) { + return false; + } + + re += 4; + while (re < size) { + u32 sack_re; + u8 *sptr = ptr + re; + sack_re = (sptr[0] << 24) | (sptr[1] << 16) | (sptr[2] << 8) | sptr[3]; + if (sack_re > sack) { + sack = sack_re; + } + re += TCPOLEN_SACK_PERBLOCK; + } + if (sack > *ack) { + *ack = sack; + } + length += size; + continue; + } + if (kind == TCPOPT_EOL) { + return true; + } + size = *(ptr + 1); + if (size < 2) { + return false; + } + length += size; + } + + return true; +} + +/* + * sfe_ipv4_recv_tcp() + * Handle TCP packet receives and forwarding. + */ +static int sfe_ipv4_recv_tcp(struct sfe_ipv4 *si, struct sk_buff *skb, struct net_device *dev, + unsigned int len, struct sfe_ipv4_ip_hdr *iph, unsigned int ihl, bool flush_on_find) +{ + struct sfe_ipv4_tcp_hdr *tcph; + __be32 src_ip; + __be32 dest_ip; + __be16 src_port; + __be16 dest_port; + struct sfe_ipv4_connection_match *cm; + struct sfe_ipv4_connection_match *counter_cm; + u8 ttl; + u32 flags; + struct net_device *xmit_dev; + + /* + * Is our packet too short to contain a valid UDP header? + */ + if (unlikely(!pskb_may_pull(skb, (sizeof(struct sfe_ipv4_tcp_hdr) + ihl)))) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_TCP_HEADER_INCOMPLETE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("packet too short for TCP header\n"); + return 0; + } + + /* + * Read the IP address and port information. Read the IP header data first + * because we've almost certainly got that in the cache. We may not yet have + * the TCP header cached though so allow more time for any prefetching. + */ + src_ip = iph->saddr; + dest_ip = iph->daddr; + + tcph = (struct sfe_ipv4_tcp_hdr *)(skb->data + ihl); + src_port = tcph->source; + dest_port = tcph->dest; + flags = tcp_flag_word(tcph); + + spin_lock_bh(&si->lock); + + /* + * Look for a connection match. + */ +#ifdef CONFIG_NF_FLOW_COOKIE + cm = si->sfe_flow_cookie_table[skb->flow_cookie & SFE_FLOW_COOKIE_MASK].match; + if (unlikely(!cm)) { + cm = sfe_ipv4_find_sfe_ipv4_connection_match(si, dev, IPPROTO_TCP, src_ip, src_port, dest_ip, dest_port); + } +#else + cm = sfe_ipv4_find_sfe_ipv4_connection_match(si, dev, IPPROTO_TCP, src_ip, src_port, dest_ip, dest_port); +#endif + if (unlikely(!cm)) { + /* + * We didn't get a connection but as TCP is connection-oriented that + * may be because this is a non-fast connection (not running established). + * For diagnostic purposes we differentiate this here. + */ + if (likely((flags & (TCP_FLAG_SYN | TCP_FLAG_RST | TCP_FLAG_FIN | TCP_FLAG_ACK)) == TCP_FLAG_ACK)) { + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_TCP_NO_CONNECTION_FAST_FLAGS]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("no connection found - fast flags\n"); + return 0; + } + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_TCP_NO_CONNECTION_SLOW_FLAGS]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("no connection found - slow flags: 0x%x\n", + flags & (TCP_FLAG_SYN | TCP_FLAG_RST | TCP_FLAG_FIN | TCP_FLAG_ACK)); + return 0; + } + + /* + * If our packet has beern marked as "flush on find" we can't actually + * forward it in the fast path, but now that we've found an associated + * connection we can flush that out before we process the packet. + */ + if (unlikely(flush_on_find)) { + struct sfe_ipv4_connection *c = cm->connection; + sfe_ipv4_remove_sfe_ipv4_connection(si, c); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_TCP_IP_OPTIONS_OR_INITIAL_FRAGMENT]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("flush on find\n"); + sfe_ipv4_flush_sfe_ipv4_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + +#ifdef CONFIG_XFRM + /* + * We can't accelerate the flow on this direction, just let it go + * through the slow path. + */ + if (unlikely(!cm->flow_accel)) { + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + return 0; + } +#endif + /* + * Does our TTL allow forwarding? + */ + ttl = iph->ttl; + if (unlikely(ttl < 2)) { + struct sfe_ipv4_connection *c = cm->connection; + sfe_ipv4_remove_sfe_ipv4_connection(si, c); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_TCP_SMALL_TTL]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("ttl too low\n"); + sfe_ipv4_flush_sfe_ipv4_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + /* + * If our packet is larger than the MTU of the transmit interface then + * we can't forward it easily. + */ + if (unlikely((len > cm->xmit_dev_mtu) && !skb_is_gso(skb))) { + struct sfe_ipv4_connection *c = cm->connection; + sfe_ipv4_remove_sfe_ipv4_connection(si, c); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_TCP_NEEDS_FRAGMENTATION]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("larger than mtu\n"); + sfe_ipv4_flush_sfe_ipv4_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + /* + * Look at our TCP flags. Anything missing an ACK or that has RST, SYN or FIN + * set is not a fast path packet. + */ + if (unlikely((flags & (TCP_FLAG_SYN | TCP_FLAG_RST | TCP_FLAG_FIN | TCP_FLAG_ACK)) != TCP_FLAG_ACK)) { + struct sfe_ipv4_connection *c = cm->connection; + sfe_ipv4_remove_sfe_ipv4_connection(si, c); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_TCP_FLAGS]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("TCP flags: 0x%x are not fast\n", + flags & (TCP_FLAG_SYN | TCP_FLAG_RST | TCP_FLAG_FIN | TCP_FLAG_ACK)); + sfe_ipv4_flush_sfe_ipv4_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + counter_cm = cm->counter_match; + + /* + * Are we doing sequence number checking? + */ + if (likely(!(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK))) { + u32 seq; + u32 ack; + u32 sack; + u32 data_offs; + u32 end; + u32 left_edge; + u32 scaled_win; + u32 max_end; + + /* + * Is our sequence fully past the right hand edge of the window? + */ + seq = ntohl(tcph->seq); + if (unlikely((s32)(seq - (cm->protocol_state.tcp.max_end + 1)) > 0)) { + struct sfe_ipv4_connection *c = cm->connection; + sfe_ipv4_remove_sfe_ipv4_connection(si, c); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_TCP_SEQ_EXCEEDS_RIGHT_EDGE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("seq: %u exceeds right edge: %u\n", + seq, cm->protocol_state.tcp.max_end + 1); + sfe_ipv4_flush_sfe_ipv4_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + /* + * Check that our TCP data offset isn't too short. + */ + data_offs = tcph->doff << 2; + if (unlikely(data_offs < sizeof(struct sfe_ipv4_tcp_hdr))) { + struct sfe_ipv4_connection *c = cm->connection; + sfe_ipv4_remove_sfe_ipv4_connection(si, c); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_TCP_SMALL_DATA_OFFS]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("TCP data offset: %u, too small\n", data_offs); + sfe_ipv4_flush_sfe_ipv4_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + /* + * Update ACK according to any SACK option. + */ + ack = ntohl(tcph->ack_seq); + sack = ack; + if (unlikely(!sfe_ipv4_process_tcp_option_sack(tcph, data_offs, &sack))) { + struct sfe_ipv4_connection *c = cm->connection; + sfe_ipv4_remove_sfe_ipv4_connection(si, c); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_TCP_BAD_SACK]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("TCP option SACK size is wrong\n"); + sfe_ipv4_flush_sfe_ipv4_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + /* + * Check that our TCP data offset isn't past the end of the packet. + */ + data_offs += sizeof(struct sfe_ipv4_ip_hdr); + if (unlikely(len < data_offs)) { + struct sfe_ipv4_connection *c = cm->connection; + sfe_ipv4_remove_sfe_ipv4_connection(si, c); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_TCP_BIG_DATA_OFFS]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("TCP data offset: %u, past end of packet: %u\n", + data_offs, len); + sfe_ipv4_flush_sfe_ipv4_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + end = seq + len - data_offs; + + /* + * Is our sequence fully before the left hand edge of the window? + */ + if (unlikely((s32)(end - (cm->protocol_state.tcp.end + - counter_cm->protocol_state.tcp.max_win - 1)) < 0)) { + struct sfe_ipv4_connection *c = cm->connection; + sfe_ipv4_remove_sfe_ipv4_connection(si, c); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_TCP_SEQ_BEFORE_LEFT_EDGE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("seq: %u before left edge: %u\n", + end, cm->protocol_state.tcp.end - counter_cm->protocol_state.tcp.max_win - 1); + sfe_ipv4_flush_sfe_ipv4_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + /* + * Are we acking data that is to the right of what has been sent? + */ + if (unlikely((s32)(sack - (counter_cm->protocol_state.tcp.end + 1)) > 0)) { + struct sfe_ipv4_connection *c = cm->connection; + sfe_ipv4_remove_sfe_ipv4_connection(si, c); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_TCP_ACK_EXCEEDS_RIGHT_EDGE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("ack: %u exceeds right edge: %u\n", + sack, counter_cm->protocol_state.tcp.end + 1); + sfe_ipv4_flush_sfe_ipv4_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + /* + * Is our ack too far before the left hand edge of the window? + */ + left_edge = counter_cm->protocol_state.tcp.end + - cm->protocol_state.tcp.max_win + - SFE_IPV4_TCP_MAX_ACK_WINDOW + - 1; + if (unlikely((s32)(sack - left_edge) < 0)) { + struct sfe_ipv4_connection *c = cm->connection; + sfe_ipv4_remove_sfe_ipv4_connection(si, c); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_TCP_ACK_BEFORE_LEFT_EDGE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("ack: %u before left edge: %u\n", sack, left_edge); + sfe_ipv4_flush_sfe_ipv4_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + /* + * Have we just seen the largest window size yet for this connection? If yes + * then we need to record the new value. + */ + scaled_win = ntohs(tcph->window) << cm->protocol_state.tcp.win_scale; + scaled_win += (sack - ack); + if (unlikely(cm->protocol_state.tcp.max_win < scaled_win)) { + cm->protocol_state.tcp.max_win = scaled_win; + } + + /* + * If our sequence and/or ack numbers have advanced then record the new state. + */ + if (likely((s32)(end - cm->protocol_state.tcp.end) >= 0)) { + cm->protocol_state.tcp.end = end; + } + + max_end = sack + scaled_win; + if (likely((s32)(max_end - counter_cm->protocol_state.tcp.max_end) >= 0)) { + counter_cm->protocol_state.tcp.max_end = max_end; + } + } + + /* + * From this point on we're good to modify the packet. + */ + + /* + * Check if skb was cloned. If it was, unshare it. Because + * the data area is going to be written in this path and we don't want to + * change the cloned skb's data section. + */ + if (unlikely(skb_cloned(skb))) { + DEBUG_TRACE("%px: skb is a cloned skb\n", skb); + skb = skb_unshare(skb, GFP_ATOMIC); + if (!skb) { + DEBUG_WARN("Failed to unshare the cloned skb\n"); + return 0; + } + + /* + * Update the iph and tcph pointers with the unshared skb's data area. + */ + iph = (struct sfe_ipv4_ip_hdr *)skb->data; + tcph = (struct sfe_ipv4_tcp_hdr *)(skb->data + ihl); + } + + /* + * Update DSCP + */ + if (unlikely(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_DSCP_REMARK)) { + iph->tos = (iph->tos & SFE_IPV4_DSCP_MASK) | cm->dscp; + } + + /* + * Decrement our TTL. + */ + iph->ttl = ttl - 1; + + /* + * Do we have to perform translations of the source address/port? + */ + if (unlikely(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_SRC)) { + u16 tcp_csum; + u32 sum; + + iph->saddr = cm->xlate_src_ip; + tcph->source = cm->xlate_src_port; + + /* + * Do we have a non-zero UDP checksum? If we do then we need + * to update it. + */ + tcp_csum = tcph->check; + if (unlikely(skb->ip_summed == CHECKSUM_PARTIAL)) { + sum = tcp_csum + cm->xlate_src_partial_csum_adjustment; + } else { + sum = tcp_csum + cm->xlate_src_csum_adjustment; + } + + sum = (sum & 0xffff) + (sum >> 16); + tcph->check = (u16)sum; + } + + /* + * Do we have to perform translations of the destination address/port? + */ + if (unlikely(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_DEST)) { + u16 tcp_csum; + u32 sum; + + iph->daddr = cm->xlate_dest_ip; + tcph->dest = cm->xlate_dest_port; + + /* + * Do we have a non-zero UDP checksum? If we do then we need + * to update it. + */ + tcp_csum = tcph->check; + if (unlikely(skb->ip_summed == CHECKSUM_PARTIAL)) { + sum = tcp_csum + cm->xlate_dest_partial_csum_adjustment; + } else { + sum = tcp_csum + cm->xlate_dest_csum_adjustment; + } + + sum = (sum & 0xffff) + (sum >> 16); + tcph->check = (u16)sum; + } + + /* + * Replace the IP checksum. + */ + iph->check = sfe_ipv4_gen_ip_csum(iph); + + /* + * Update traffic stats. + */ + cm->rx_packet_count++; + cm->rx_byte_count += len; + + /* + * If we're not already on the active list then insert ourselves at the tail + * of the current list. + */ + if (unlikely(!cm->active)) { + cm->active = true; + cm->active_prev = si->active_tail; + if (likely(si->active_tail)) { + si->active_tail->active_next = cm; + } else { + si->active_head = cm; + } + si->active_tail = cm; + } + + xmit_dev = cm->xmit_dev; + skb->dev = xmit_dev; + + /* + * Check to see if we need to write a header. + */ + if (likely(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_WRITE_L2_HDR)) { + if (unlikely(!(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_WRITE_FAST_ETH_HDR))) { + dev_hard_header(skb, xmit_dev, ETH_P_IP, + cm->xmit_dest_mac, cm->xmit_src_mac, len); + } else { + /* + * For the simple case we write this really fast. + */ + struct sfe_ipv4_eth_hdr *eth = (struct sfe_ipv4_eth_hdr *)__skb_push(skb, ETH_HLEN); + eth->h_proto = htons(ETH_P_IP); + eth->h_dest[0] = cm->xmit_dest_mac[0]; + eth->h_dest[1] = cm->xmit_dest_mac[1]; + eth->h_dest[2] = cm->xmit_dest_mac[2]; + eth->h_source[0] = cm->xmit_src_mac[0]; + eth->h_source[1] = cm->xmit_src_mac[1]; + eth->h_source[2] = cm->xmit_src_mac[2]; + } + } + + /* + * Update priority of skb. + */ + if (unlikely(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_PRIORITY_REMARK)) { + skb->priority = cm->priority; + } + + /* + * Mark outgoing packet + */ + skb->mark = cm->connection->mark; + if (skb->mark) { + DEBUG_TRACE("SKB MARK is NON ZERO %x\n", skb->mark); + } + + si->packets_forwarded++; + spin_unlock_bh(&si->lock); + + /* + * We're going to check for GSO flags when we transmit the packet so + * start fetching the necessary cache line now. + */ + prefetch(skb_shinfo(skb)); + + /* + * Mark that this packet has been fast forwarded. + */ + skb->fast_forwarded = 1; + + /* + * Send the packet on its way. + */ + dev_queue_xmit(skb); + + return 1; +} + +/* + * sfe_ipv4_recv_icmp() + * Handle ICMP packet receives. + * + * ICMP packets aren't handled as a "fast path" and always have us process them + * through the default Linux stack. What we do need to do is look for any errors + * about connections we are handling in the fast path. If we find any such + * connections then we want to flush their state so that the ICMP error path + * within Linux has all of the correct state should it need it. + */ +static int sfe_ipv4_recv_icmp(struct sfe_ipv4 *si, struct sk_buff *skb, struct net_device *dev, + unsigned int len, struct sfe_ipv4_ip_hdr *iph, unsigned int ihl) +{ + struct icmphdr *icmph; + struct sfe_ipv4_ip_hdr *icmp_iph; + unsigned int icmp_ihl_words; + unsigned int icmp_ihl; + u32 *icmp_trans_h; + struct sfe_ipv4_udp_hdr *icmp_udph; + struct sfe_ipv4_tcp_hdr *icmp_tcph; + __be32 src_ip; + __be32 dest_ip; + __be16 src_port; + __be16 dest_port; + struct sfe_ipv4_connection_match *cm; + struct sfe_ipv4_connection *c; + u32 pull_len = sizeof(struct icmphdr) + ihl; + + /* + * Is our packet too short to contain a valid ICMP header? + */ + len -= ihl; + if (!pskb_may_pull(skb, pull_len)) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_ICMP_HEADER_INCOMPLETE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("packet too short for ICMP header\n"); + return 0; + } + + /* + * We only handle "destination unreachable" and "time exceeded" messages. + */ + icmph = (struct icmphdr *)(skb->data + ihl); + if ((icmph->type != ICMP_DEST_UNREACH) + && (icmph->type != ICMP_TIME_EXCEEDED)) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_ICMP_UNHANDLED_TYPE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("unhandled ICMP type: 0x%x\n", icmph->type); + return 0; + } + + /* + * Do we have the full embedded IP header? + */ + len -= sizeof(struct icmphdr); + pull_len += sizeof(struct sfe_ipv4_ip_hdr); + if (!pskb_may_pull(skb, pull_len)) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_ICMP_IPV4_HEADER_INCOMPLETE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("Embedded IP header not complete\n"); + return 0; + } + + /* + * Is our embedded IP version wrong? + */ + icmp_iph = (struct sfe_ipv4_ip_hdr *)(icmph + 1); + if (unlikely(icmp_iph->version != 4)) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_ICMP_IPV4_NON_V4]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("IP version: %u\n", icmp_iph->version); + return 0; + } + + /* + * Do we have the full embedded IP header, including any options? + */ + icmp_ihl_words = icmp_iph->ihl; + icmp_ihl = icmp_ihl_words << 2; + pull_len += icmp_ihl - sizeof(struct sfe_ipv4_ip_hdr); + if (!pskb_may_pull(skb, pull_len)) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_ICMP_IPV4_IP_OPTIONS_INCOMPLETE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("Embedded header not large enough for IP options\n"); + return 0; + } + + len -= icmp_ihl; + icmp_trans_h = ((u32 *)icmp_iph) + icmp_ihl_words; + + /* + * Handle the embedded transport layer header. + */ + switch (icmp_iph->protocol) { + case IPPROTO_UDP: + /* + * We should have 8 bytes of UDP header - that's enough to identify + * the connection. + */ + pull_len += 8; + if (!pskb_may_pull(skb, pull_len)) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_ICMP_IPV4_UDP_HEADER_INCOMPLETE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("Incomplete embedded UDP header\n"); + return 0; + } + + icmp_udph = (struct sfe_ipv4_udp_hdr *)icmp_trans_h; + src_port = icmp_udph->source; + dest_port = icmp_udph->dest; + break; + + case IPPROTO_TCP: + /* + * We should have 8 bytes of TCP header - that's enough to identify + * the connection. + */ + pull_len += 8; + if (!pskb_may_pull(skb, pull_len)) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_ICMP_IPV4_TCP_HEADER_INCOMPLETE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("Incomplete embedded TCP header\n"); + return 0; + } + + icmp_tcph = (struct sfe_ipv4_tcp_hdr *)icmp_trans_h; + src_port = icmp_tcph->source; + dest_port = icmp_tcph->dest; + break; + + default: + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_ICMP_IPV4_UNHANDLED_PROTOCOL]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("Unhandled embedded IP protocol: %u\n", icmp_iph->protocol); + return 0; + } + + src_ip = icmp_iph->saddr; + dest_ip = icmp_iph->daddr; + + spin_lock_bh(&si->lock); + + /* + * Look for a connection match. Note that we reverse the source and destination + * here because our embedded message contains a packet that was sent in the + * opposite direction to the one in which we just received it. It will have + * been sent on the interface from which we received it though so that's still + * ok to use. + */ + cm = sfe_ipv4_find_sfe_ipv4_connection_match(si, dev, icmp_iph->protocol, dest_ip, dest_port, src_ip, src_port); + if (unlikely(!cm)) { + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_ICMP_NO_CONNECTION]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("no connection found\n"); + return 0; + } + + /* + * We found a connection so now remove it from the connection list and flush + * its state. + */ + c = cm->connection; + sfe_ipv4_remove_sfe_ipv4_connection(si, c); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_ICMP_FLUSHED_CONNECTION]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + sfe_ipv4_flush_sfe_ipv4_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; +} + +/* + * sfe_ipv4_recv() + * Handle packet receives and forwaring. + * + * Returns 1 if the packet is forwarded or 0 if it isn't. + */ +int sfe_ipv4_recv(struct net_device *dev, struct sk_buff *skb) +{ + struct sfe_ipv4 *si = &__si; + unsigned int len; + unsigned int tot_len; + unsigned int frag_off; + unsigned int ihl; + bool flush_on_find; + bool ip_options; + struct sfe_ipv4_ip_hdr *iph; + u32 protocol; + + /* + * Check that we have space for an IP header here. + */ + len = skb->len; + if (unlikely(!pskb_may_pull(skb, sizeof(struct sfe_ipv4_ip_hdr)))) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_HEADER_INCOMPLETE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("len: %u is too short\n", len); + return 0; + } + + /* + * Check that our "total length" is large enough for an IP header. + */ + iph = (struct sfe_ipv4_ip_hdr *)skb->data; + tot_len = ntohs(iph->tot_len); + if (unlikely(tot_len < sizeof(struct sfe_ipv4_ip_hdr))) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_BAD_TOTAL_LENGTH]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("tot_len: %u is too short\n", tot_len); + return 0; + } + + /* + * Is our IP version wrong? + */ + if (unlikely(iph->version != 4)) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_NON_V4]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("IP version: %u\n", iph->version); + return 0; + } + + /* + * Does our datagram fit inside the skb? + */ + if (unlikely(tot_len > len)) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_DATAGRAM_INCOMPLETE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("tot_len: %u, exceeds len: %u\n", tot_len, len); + return 0; + } + + /* + * Do we have a non-initial fragment? + */ + frag_off = ntohs(iph->frag_off); + if (unlikely(frag_off & IP_OFFSET)) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_NON_INITIAL_FRAGMENT]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("non-initial fragment\n"); + return 0; + } + + /* + * If we have a (first) fragment then mark it to cause any connection to flush. + */ + flush_on_find = unlikely(frag_off & IP_MF) ? true : false; + + /* + * Do we have any IP options? That's definite a slow path! If we do have IP + * options we need to recheck our header size. + */ + ihl = iph->ihl << 2; + ip_options = unlikely(ihl != sizeof(struct sfe_ipv4_ip_hdr)) ? true : false; + if (unlikely(ip_options)) { + if (unlikely(len < ihl)) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_IP_OPTIONS_INCOMPLETE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("len: %u is too short for header of size: %u\n", len, ihl); + return 0; + } + + flush_on_find = true; + } + + protocol = iph->protocol; + if (IPPROTO_UDP == protocol) { + return sfe_ipv4_recv_udp(si, skb, dev, len, iph, ihl, flush_on_find); + } + + if (IPPROTO_TCP == protocol) { + return sfe_ipv4_recv_tcp(si, skb, dev, len, iph, ihl, flush_on_find); + } + + if (IPPROTO_ICMP == protocol) { + return sfe_ipv4_recv_icmp(si, skb, dev, len, iph, ihl); + } + + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV4_EXCEPTION_EVENT_UNHANDLED_PROTOCOL]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("not UDP, TCP or ICMP: %u\n", protocol); + return 0; +} + +static void +sfe_ipv4_update_tcp_state(struct sfe_ipv4_connection *c, + struct sfe_connection_create *sic) +{ + struct sfe_ipv4_connection_match *orig_cm; + struct sfe_ipv4_connection_match *repl_cm; + struct sfe_ipv4_tcp_connection_match *orig_tcp; + struct sfe_ipv4_tcp_connection_match *repl_tcp; + + orig_cm = c->original_match; + repl_cm = c->reply_match; + orig_tcp = &orig_cm->protocol_state.tcp; + repl_tcp = &repl_cm->protocol_state.tcp; + + /* update orig */ + if (orig_tcp->max_win < sic->src_td_max_window) { + orig_tcp->max_win = sic->src_td_max_window; + } + if ((s32)(orig_tcp->end - sic->src_td_end) < 0) { + orig_tcp->end = sic->src_td_end; + } + if ((s32)(orig_tcp->max_end - sic->src_td_max_end) < 0) { + orig_tcp->max_end = sic->src_td_max_end; + } + + /* update reply */ + if (repl_tcp->max_win < sic->dest_td_max_window) { + repl_tcp->max_win = sic->dest_td_max_window; + } + if ((s32)(repl_tcp->end - sic->dest_td_end) < 0) { + repl_tcp->end = sic->dest_td_end; + } + if ((s32)(repl_tcp->max_end - sic->dest_td_max_end) < 0) { + repl_tcp->max_end = sic->dest_td_max_end; + } + + /* update match flags */ + orig_cm->flags &= ~SFE_IPV4_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK; + repl_cm->flags &= ~SFE_IPV4_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK; + if (sic->flags & SFE_CREATE_FLAG_NO_SEQ_CHECK) { + orig_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK; + repl_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK; + } +} + +static void +sfe_ipv4_update_protocol_state(struct sfe_ipv4_connection *c, + struct sfe_connection_create *sic) +{ + switch (sic->protocol) { + case IPPROTO_TCP: + sfe_ipv4_update_tcp_state(c, sic); + break; + } +} + +void sfe_ipv4_update_rule(struct sfe_connection_create *sic) +{ + struct sfe_ipv4_connection *c; + struct sfe_ipv4 *si = &__si; + + spin_lock_bh(&si->lock); + + c = sfe_ipv4_find_sfe_ipv4_connection(si, + sic->protocol, + sic->src_ip.ip, + sic->src_port, + sic->dest_ip.ip, + sic->dest_port); + if (c != NULL) { + sfe_ipv4_update_protocol_state(c, sic); + } + + spin_unlock_bh(&si->lock); +} + +/* + * sfe_ipv4_create_rule() + * Create a forwarding rule. + */ +int sfe_ipv4_create_rule(struct sfe_connection_create *sic) +{ + struct sfe_ipv4 *si = &__si; + struct sfe_ipv4_connection *c; + struct sfe_ipv4_connection_match *original_cm; + struct sfe_ipv4_connection_match *reply_cm; + struct net_device *dest_dev; + struct net_device *src_dev; + + dest_dev = sic->dest_dev; + src_dev = sic->src_dev; + + if (unlikely((dest_dev->reg_state != NETREG_REGISTERED) || + (src_dev->reg_state != NETREG_REGISTERED))) { + return -EINVAL; + } + + spin_lock_bh(&si->lock); + si->connection_create_requests++; + + /* + * Check to see if there is already a flow that matches the rule we're + * trying to create. If there is then we can't create a new one. + */ + c = sfe_ipv4_find_sfe_ipv4_connection(si, + sic->protocol, + sic->src_ip.ip, + sic->src_port, + sic->dest_ip.ip, + sic->dest_port); + if (c != NULL) { + si->connection_create_collisions++; + + /* + * If we already have the flow then it's likely that this + * request to create the connection rule contains more + * up-to-date information. Check and update accordingly. + */ + sfe_ipv4_update_protocol_state(c, sic); + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("connection already exists - mark: %08x, p: %d\n" + " s: %s:%pxM:%pI4:%u, d: %s:%pxM:%pI4:%u\n", + sic->mark, sic->protocol, + sic->src_dev->name, sic->src_mac, &sic->src_ip.ip, ntohs(sic->src_port), + sic->dest_dev->name, sic->dest_mac, &sic->dest_ip.ip, ntohs(sic->dest_port)); + return -EADDRINUSE; + } + + /* + * Allocate the various connection tracking objects. + */ + c = (struct sfe_ipv4_connection *)kmalloc(sizeof(struct sfe_ipv4_connection), GFP_ATOMIC); + if (unlikely(!c)) { + spin_unlock_bh(&si->lock); + return -ENOMEM; + } + + original_cm = (struct sfe_ipv4_connection_match *)kmalloc(sizeof(struct sfe_ipv4_connection_match), GFP_ATOMIC); + if (unlikely(!original_cm)) { + spin_unlock_bh(&si->lock); + kfree(c); + return -ENOMEM; + } + + reply_cm = (struct sfe_ipv4_connection_match *)kmalloc(sizeof(struct sfe_ipv4_connection_match), GFP_ATOMIC); + if (unlikely(!reply_cm)) { + spin_unlock_bh(&si->lock); + kfree(original_cm); + kfree(c); + return -ENOMEM; + } + + /* + * Fill in the "original" direction connection matching object. + * Note that the transmit MAC address is "dest_mac_xlate" because + * we always know both ends of a connection by their translated + * addresses and not their public addresses. + */ + original_cm->match_dev = src_dev; + original_cm->match_protocol = sic->protocol; + original_cm->match_src_ip = sic->src_ip.ip; + original_cm->match_src_port = sic->src_port; + original_cm->match_dest_ip = sic->dest_ip.ip; + original_cm->match_dest_port = sic->dest_port; + original_cm->xlate_src_ip = sic->src_ip_xlate.ip; + original_cm->xlate_src_port = sic->src_port_xlate; + original_cm->xlate_dest_ip = sic->dest_ip_xlate.ip; + original_cm->xlate_dest_port = sic->dest_port_xlate; + original_cm->rx_packet_count = 0; + original_cm->rx_packet_count64 = 0; + original_cm->rx_byte_count = 0; + original_cm->rx_byte_count64 = 0; + original_cm->xmit_dev = dest_dev; + original_cm->xmit_dev_mtu = sic->dest_mtu; + memcpy(original_cm->xmit_src_mac, dest_dev->dev_addr, ETH_ALEN); + memcpy(original_cm->xmit_dest_mac, sic->dest_mac_xlate, ETH_ALEN); + original_cm->connection = c; + original_cm->counter_match = reply_cm; + original_cm->flags = 0; + if (sic->flags & SFE_CREATE_FLAG_REMARK_PRIORITY) { + original_cm->priority = sic->src_priority; + original_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_PRIORITY_REMARK; + } + if (sic->flags & SFE_CREATE_FLAG_REMARK_DSCP) { + original_cm->dscp = sic->src_dscp << SFE_IPV4_DSCP_SHIFT; + original_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_DSCP_REMARK; + } +#ifdef CONFIG_NF_FLOW_COOKIE + original_cm->flow_cookie = 0; +#endif +#ifdef CONFIG_XFRM + original_cm->flow_accel = sic->original_accel; +#endif + original_cm->active_next = NULL; + original_cm->active_prev = NULL; + original_cm->active = false; + + /* + * For PPP links we don't write an L2 header. For everything else we do. + */ + if (!(dest_dev->flags & IFF_POINTOPOINT)) { + original_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_WRITE_L2_HDR; + + /* + * If our dev writes Ethernet headers then we can write a really fast + * version. + */ + if (dest_dev->header_ops) { + if (dest_dev->header_ops->create == eth_header) { + original_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_WRITE_FAST_ETH_HDR; + } + } + } + + /* + * Fill in the "reply" direction connection matching object. + */ + reply_cm->match_dev = dest_dev; + reply_cm->match_protocol = sic->protocol; + reply_cm->match_src_ip = sic->dest_ip_xlate.ip; + reply_cm->match_src_port = sic->dest_port_xlate; + reply_cm->match_dest_ip = sic->src_ip_xlate.ip; + reply_cm->match_dest_port = sic->src_port_xlate; + reply_cm->xlate_src_ip = sic->dest_ip.ip; + reply_cm->xlate_src_port = sic->dest_port; + reply_cm->xlate_dest_ip = sic->src_ip.ip; + reply_cm->xlate_dest_port = sic->src_port; + reply_cm->rx_packet_count = 0; + reply_cm->rx_packet_count64 = 0; + reply_cm->rx_byte_count = 0; + reply_cm->rx_byte_count64 = 0; + reply_cm->xmit_dev = src_dev; + reply_cm->xmit_dev_mtu = sic->src_mtu; + memcpy(reply_cm->xmit_src_mac, src_dev->dev_addr, ETH_ALEN); + memcpy(reply_cm->xmit_dest_mac, sic->src_mac, ETH_ALEN); + reply_cm->connection = c; + reply_cm->counter_match = original_cm; + reply_cm->flags = 0; + if (sic->flags & SFE_CREATE_FLAG_REMARK_PRIORITY) { + reply_cm->priority = sic->dest_priority; + reply_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_PRIORITY_REMARK; + } + if (sic->flags & SFE_CREATE_FLAG_REMARK_DSCP) { + reply_cm->dscp = sic->dest_dscp << SFE_IPV4_DSCP_SHIFT; + reply_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_DSCP_REMARK; + } +#ifdef CONFIG_NF_FLOW_COOKIE + reply_cm->flow_cookie = 0; +#endif +#ifdef CONFIG_XFRM + reply_cm->flow_accel = sic->reply_accel; +#endif + reply_cm->active_next = NULL; + reply_cm->active_prev = NULL; + reply_cm->active = false; + + /* + * For PPP links we don't write an L2 header. For everything else we do. + */ + if (!(src_dev->flags & IFF_POINTOPOINT)) { + reply_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_WRITE_L2_HDR; + + /* + * If our dev writes Ethernet headers then we can write a really fast + * version. + */ + if (src_dev->header_ops) { + if (src_dev->header_ops->create == eth_header) { + reply_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_WRITE_FAST_ETH_HDR; + } + } + } + + + if (sic->dest_ip.ip != sic->dest_ip_xlate.ip || sic->dest_port != sic->dest_port_xlate) { + original_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_DEST; + reply_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_SRC; + } + + if (sic->src_ip.ip != sic->src_ip_xlate.ip || sic->src_port != sic->src_port_xlate) { + original_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_SRC; + reply_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_DEST; + } + + c->protocol = sic->protocol; + c->src_ip = sic->src_ip.ip; + c->src_ip_xlate = sic->src_ip_xlate.ip; + c->src_port = sic->src_port; + c->src_port_xlate = sic->src_port_xlate; + c->original_dev = src_dev; + c->original_match = original_cm; + c->dest_ip = sic->dest_ip.ip; + c->dest_ip_xlate = sic->dest_ip_xlate.ip; + c->dest_port = sic->dest_port; + c->dest_port_xlate = sic->dest_port_xlate; + c->reply_dev = dest_dev; + c->reply_match = reply_cm; + c->mark = sic->mark; + c->debug_read_seq = 0; + c->last_sync_jiffies = get_jiffies_64(); + + /* + * Take hold of our source and dest devices for the duration of the connection. + */ + dev_hold(c->original_dev); + dev_hold(c->reply_dev); + + /* + * Initialize the protocol-specific information that we track. + */ + switch (sic->protocol) { + case IPPROTO_TCP: + original_cm->protocol_state.tcp.win_scale = sic->src_td_window_scale; + original_cm->protocol_state.tcp.max_win = sic->src_td_max_window ? sic->src_td_max_window : 1; + original_cm->protocol_state.tcp.end = sic->src_td_end; + original_cm->protocol_state.tcp.max_end = sic->src_td_max_end; + reply_cm->protocol_state.tcp.win_scale = sic->dest_td_window_scale; + reply_cm->protocol_state.tcp.max_win = sic->dest_td_max_window ? sic->dest_td_max_window : 1; + reply_cm->protocol_state.tcp.end = sic->dest_td_end; + reply_cm->protocol_state.tcp.max_end = sic->dest_td_max_end; + if (sic->flags & SFE_CREATE_FLAG_NO_SEQ_CHECK) { + original_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK; + reply_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK; + } + break; + } + + sfe_ipv4_connection_match_compute_translations(original_cm); + sfe_ipv4_connection_match_compute_translations(reply_cm); + sfe_ipv4_insert_sfe_ipv4_connection(si, c); + + spin_unlock_bh(&si->lock); + + /* + * We have everything we need! + */ + DEBUG_INFO("new connection - mark: %08x, p: %d\n" + " s: %s:%pxM(%pxM):%pI4(%pI4):%u(%u)\n" + " d: %s:%pxM(%pxM):%pI4(%pI4):%u(%u)\n", + sic->mark, sic->protocol, + sic->src_dev->name, sic->src_mac, sic->src_mac_xlate, + &sic->src_ip.ip, &sic->src_ip_xlate.ip, ntohs(sic->src_port), ntohs(sic->src_port_xlate), + dest_dev->name, sic->dest_mac, sic->dest_mac_xlate, + &sic->dest_ip.ip, &sic->dest_ip_xlate.ip, ntohs(sic->dest_port), ntohs(sic->dest_port_xlate)); + + return 0; +} + +/* + * sfe_ipv4_destroy_rule() + * Destroy a forwarding rule. + */ +void sfe_ipv4_destroy_rule(struct sfe_connection_destroy *sid) +{ + struct sfe_ipv4 *si = &__si; + struct sfe_ipv4_connection *c; + + spin_lock_bh(&si->lock); + si->connection_destroy_requests++; + + /* + * Check to see if we have a flow that matches the rule we're trying + * to destroy. If there isn't then we can't destroy it. + */ + c = sfe_ipv4_find_sfe_ipv4_connection(si, sid->protocol, sid->src_ip.ip, sid->src_port, + sid->dest_ip.ip, sid->dest_port); + if (!c) { + si->connection_destroy_misses++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("connection does not exist - p: %d, s: %pI4:%u, d: %pI4:%u\n", + sid->protocol, &sid->src_ip, ntohs(sid->src_port), + &sid->dest_ip, ntohs(sid->dest_port)); + return; + } + + /* + * Remove our connection details from the hash tables. + */ + sfe_ipv4_remove_sfe_ipv4_connection(si, c); + spin_unlock_bh(&si->lock); + + sfe_ipv4_flush_sfe_ipv4_connection(si, c, SFE_SYNC_REASON_DESTROY); + + DEBUG_INFO("connection destroyed - p: %d, s: %pI4:%u, d: %pI4:%u\n", + sid->protocol, &sid->src_ip.ip, ntohs(sid->src_port), + &sid->dest_ip.ip, ntohs(sid->dest_port)); +} + +/* + * sfe_ipv4_register_sync_rule_callback() + * Register a callback for rule synchronization. + */ +void sfe_ipv4_register_sync_rule_callback(sfe_sync_rule_callback_t sync_rule_callback) +{ + struct sfe_ipv4 *si = &__si; + + spin_lock_bh(&si->lock); + rcu_assign_pointer(si->sync_rule_callback, sync_rule_callback); + spin_unlock_bh(&si->lock); +} + +/* + * sfe_ipv4_get_debug_dev() + */ +static ssize_t sfe_ipv4_get_debug_dev(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct sfe_ipv4 *si = &__si; + ssize_t count; + int num; + + spin_lock_bh(&si->lock); + num = si->debug_dev; + spin_unlock_bh(&si->lock); + + count = snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", num); + return count; +} + +/* + * sysfs attributes. + */ +static const struct device_attribute sfe_ipv4_debug_dev_attr = + __ATTR(debug_dev, S_IWUSR | S_IRUGO, sfe_ipv4_get_debug_dev, NULL); + +/* + * sfe_ipv4_destroy_all_rules_for_dev() + * Destroy all connections that match a particular device. + * + * If we pass dev as NULL then this destroys all connections. + */ +void sfe_ipv4_destroy_all_rules_for_dev(struct net_device *dev) +{ + struct sfe_ipv4 *si = &__si; + struct sfe_ipv4_connection *c; + +another_round: + spin_lock_bh(&si->lock); + + for (c = si->all_connections_head; c; c = c->all_connections_next) { + /* + * Does this connection relate to the device we are destroying? + */ + if (!dev + || (dev == c->original_dev) + || (dev == c->reply_dev)) { + break; + } + } + + if (c) { + sfe_ipv4_remove_sfe_ipv4_connection(si, c); + } + + spin_unlock_bh(&si->lock); + + if (c) { + sfe_ipv4_flush_sfe_ipv4_connection(si, c, SFE_SYNC_REASON_DESTROY); + goto another_round; + } +} + +/* + * sfe_ipv4_periodic_sync() + */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)) +static void sfe_ipv4_periodic_sync(unsigned long arg) +#else +static void sfe_ipv4_periodic_sync(struct timer_list *tl) +#endif +{ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)) + struct sfe_ipv4 *si = (struct sfe_ipv4 *)arg; +#else + struct sfe_ipv4 *si = from_timer(si, tl, timer); +#endif + u64 now_jiffies; + int quota; + sfe_sync_rule_callback_t sync_rule_callback; + + now_jiffies = get_jiffies_64(); + + rcu_read_lock(); + sync_rule_callback = rcu_dereference(si->sync_rule_callback); + if (!sync_rule_callback) { + rcu_read_unlock(); + goto done; + } + + spin_lock_bh(&si->lock); + sfe_ipv4_update_summary_stats(si); + + /* + * Get an estimate of the number of connections to parse in this sync. + */ + quota = (si->num_connections + 63) / 64; + + /* + * Walk the "active" list and sync the connection state. + */ + while (quota--) { + struct sfe_ipv4_connection_match *cm; + struct sfe_ipv4_connection_match *counter_cm; + struct sfe_ipv4_connection *c; + struct sfe_connection_sync sis; + + cm = si->active_head; + if (!cm) { + break; + } + + /* + * There's a possibility that our counter match is in the active list too. + * If it is then remove it. + */ + counter_cm = cm->counter_match; + if (counter_cm->active) { + counter_cm->active = false; + + /* + * We must have a connection preceding this counter match + * because that's the one that got us to this point, so we don't have + * to worry about removing the head of the list. + */ + counter_cm->active_prev->active_next = counter_cm->active_next; + + if (likely(counter_cm->active_next)) { + counter_cm->active_next->active_prev = counter_cm->active_prev; + } else { + si->active_tail = counter_cm->active_prev; + } + + counter_cm->active_next = NULL; + counter_cm->active_prev = NULL; + } + + /* + * Now remove the head of the active scan list. + */ + cm->active = false; + si->active_head = cm->active_next; + if (likely(cm->active_next)) { + cm->active_next->active_prev = NULL; + } else { + si->active_tail = NULL; + } + cm->active_next = NULL; + + /* + * Sync the connection state. + */ + c = cm->connection; + sfe_ipv4_gen_sync_sfe_ipv4_connection(si, c, &sis, SFE_SYNC_REASON_STATS, now_jiffies); + + /* + * We don't want to be holding the lock when we sync! + */ + spin_unlock_bh(&si->lock); + sync_rule_callback(&sis); + spin_lock_bh(&si->lock); + } + + spin_unlock_bh(&si->lock); + rcu_read_unlock(); + +done: + mod_timer(&si->timer, jiffies + ((HZ + 99) / 100)); +} + +#define CHAR_DEV_MSG_SIZE 768 + +/* + * sfe_ipv4_debug_dev_read_start() + * Generate part of the XML output. + */ +static bool sfe_ipv4_debug_dev_read_start(struct sfe_ipv4 *si, char *buffer, char *msg, size_t *length, + int *total_read, struct sfe_ipv4_debug_xml_write_state *ws) +{ + int bytes_read; + + si->debug_read_seq++; + + bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\n"); + if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) { + return false; + } + + *length -= bytes_read; + *total_read += bytes_read; + + ws->state++; + return true; +} + +/* + * sfe_ipv4_debug_dev_read_connections_start() + * Generate part of the XML output. + */ +static bool sfe_ipv4_debug_dev_read_connections_start(struct sfe_ipv4 *si, char *buffer, char *msg, size_t *length, + int *total_read, struct sfe_ipv4_debug_xml_write_state *ws) +{ + int bytes_read; + + bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t\n"); + if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) { + return false; + } + + *length -= bytes_read; + *total_read += bytes_read; + + ws->state++; + return true; +} + +/* + * sfe_ipv4_debug_dev_read_connections_connection() + * Generate part of the XML output. + */ +static bool sfe_ipv4_debug_dev_read_connections_connection(struct sfe_ipv4 *si, char *buffer, char *msg, size_t *length, + int *total_read, struct sfe_ipv4_debug_xml_write_state *ws) +{ + struct sfe_ipv4_connection *c; + struct sfe_ipv4_connection_match *original_cm; + struct sfe_ipv4_connection_match *reply_cm; + int bytes_read; + int protocol; + struct net_device *src_dev; + __be32 src_ip; + __be32 src_ip_xlate; + __be16 src_port; + __be16 src_port_xlate; + u64 src_rx_packets; + u64 src_rx_bytes; + struct net_device *dest_dev; + __be32 dest_ip; + __be32 dest_ip_xlate; + __be16 dest_port; + __be16 dest_port_xlate; + u64 dest_rx_packets; + u64 dest_rx_bytes; + u64 last_sync_jiffies; + u32 mark, src_priority, dest_priority, src_dscp, dest_dscp; +#ifdef CONFIG_NF_FLOW_COOKIE + int src_flow_cookie, dst_flow_cookie; +#endif + + spin_lock_bh(&si->lock); + + for (c = si->all_connections_head; c; c = c->all_connections_next) { + if (c->debug_read_seq < si->debug_read_seq) { + c->debug_read_seq = si->debug_read_seq; + break; + } + } + + /* + * If there were no connections then move to the next state. + */ + if (!c) { + spin_unlock_bh(&si->lock); + ws->state++; + return true; + } + + original_cm = c->original_match; + reply_cm = c->reply_match; + + protocol = c->protocol; + src_dev = c->original_dev; + src_ip = c->src_ip; + src_ip_xlate = c->src_ip_xlate; + src_port = c->src_port; + src_port_xlate = c->src_port_xlate; + src_priority = original_cm->priority; + src_dscp = original_cm->dscp >> SFE_IPV4_DSCP_SHIFT; + + sfe_ipv4_connection_match_update_summary_stats(original_cm); + sfe_ipv4_connection_match_update_summary_stats(reply_cm); + + src_rx_packets = original_cm->rx_packet_count64; + src_rx_bytes = original_cm->rx_byte_count64; + dest_dev = c->reply_dev; + dest_ip = c->dest_ip; + dest_ip_xlate = c->dest_ip_xlate; + dest_port = c->dest_port; + dest_port_xlate = c->dest_port_xlate; + dest_priority = reply_cm->priority; + dest_dscp = reply_cm->dscp >> SFE_IPV4_DSCP_SHIFT; + dest_rx_packets = reply_cm->rx_packet_count64; + dest_rx_bytes = reply_cm->rx_byte_count64; + last_sync_jiffies = get_jiffies_64() - c->last_sync_jiffies; + mark = c->mark; +#ifdef CONFIG_NF_FLOW_COOKIE + src_flow_cookie = original_cm->flow_cookie; + dst_flow_cookie = reply_cm->flow_cookie; +#endif + spin_unlock_bh(&si->lock); + + bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t\t\n", + protocol, + src_dev->name, + &src_ip, &src_ip_xlate, + ntohs(src_port), ntohs(src_port_xlate), + src_priority, src_dscp, + src_rx_packets, src_rx_bytes, + dest_dev->name, + &dest_ip, &dest_ip_xlate, + ntohs(dest_port), ntohs(dest_port_xlate), + dest_priority, dest_dscp, + dest_rx_packets, dest_rx_bytes, +#ifdef CONFIG_NF_FLOW_COOKIE + src_flow_cookie, dst_flow_cookie, +#endif + last_sync_jiffies, mark); + + if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) { + return false; + } + + *length -= bytes_read; + *total_read += bytes_read; + + return true; +} + +/* + * sfe_ipv4_debug_dev_read_connections_end() + * Generate part of the XML output. + */ +static bool sfe_ipv4_debug_dev_read_connections_end(struct sfe_ipv4 *si, char *buffer, char *msg, size_t *length, + int *total_read, struct sfe_ipv4_debug_xml_write_state *ws) +{ + int bytes_read; + + bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t\n"); + if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) { + return false; + } + + *length -= bytes_read; + *total_read += bytes_read; + + ws->state++; + return true; +} + +/* + * sfe_ipv4_debug_dev_read_exceptions_start() + * Generate part of the XML output. + */ +static bool sfe_ipv4_debug_dev_read_exceptions_start(struct sfe_ipv4 *si, char *buffer, char *msg, size_t *length, + int *total_read, struct sfe_ipv4_debug_xml_write_state *ws) +{ + int bytes_read; + + bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t\n"); + if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) { + return false; + } + + *length -= bytes_read; + *total_read += bytes_read; + + ws->state++; + return true; +} + +/* + * sfe_ipv4_debug_dev_read_exceptions_exception() + * Generate part of the XML output. + */ +static bool sfe_ipv4_debug_dev_read_exceptions_exception(struct sfe_ipv4 *si, char *buffer, char *msg, size_t *length, + int *total_read, struct sfe_ipv4_debug_xml_write_state *ws) +{ + u64 ct; + + spin_lock_bh(&si->lock); + ct = si->exception_events64[ws->iter_exception]; + spin_unlock_bh(&si->lock); + + if (ct) { + int bytes_read; + + bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, + "\t\t\n", + sfe_ipv4_exception_events_string[ws->iter_exception], + ct); + if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) { + return false; + } + + *length -= bytes_read; + *total_read += bytes_read; + } + + ws->iter_exception++; + if (ws->iter_exception >= SFE_IPV4_EXCEPTION_EVENT_LAST) { + ws->iter_exception = 0; + ws->state++; + } + + return true; +} + +/* + * sfe_ipv4_debug_dev_read_exceptions_end() + * Generate part of the XML output. + */ +static bool sfe_ipv4_debug_dev_read_exceptions_end(struct sfe_ipv4 *si, char *buffer, char *msg, size_t *length, + int *total_read, struct sfe_ipv4_debug_xml_write_state *ws) +{ + int bytes_read; + + bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t\n"); + if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) { + return false; + } + + *length -= bytes_read; + *total_read += bytes_read; + + ws->state++; + return true; +} + +/* + * sfe_ipv4_debug_dev_read_stats() + * Generate part of the XML output. + */ +static bool sfe_ipv4_debug_dev_read_stats(struct sfe_ipv4 *si, char *buffer, char *msg, size_t *length, + int *total_read, struct sfe_ipv4_debug_xml_write_state *ws) +{ + int bytes_read; + unsigned int num_connections; + u64 packets_forwarded; + u64 packets_not_forwarded; + u64 connection_create_requests; + u64 connection_create_collisions; + u64 connection_destroy_requests; + u64 connection_destroy_misses; + u64 connection_flushes; + u64 connection_match_hash_hits; + u64 connection_match_hash_reorders; + + spin_lock_bh(&si->lock); + sfe_ipv4_update_summary_stats(si); + + num_connections = si->num_connections; + packets_forwarded = si->packets_forwarded64; + packets_not_forwarded = si->packets_not_forwarded64; + connection_create_requests = si->connection_create_requests64; + connection_create_collisions = si->connection_create_collisions64; + connection_destroy_requests = si->connection_destroy_requests64; + connection_destroy_misses = si->connection_destroy_misses64; + connection_flushes = si->connection_flushes64; + connection_match_hash_hits = si->connection_match_hash_hits64; + connection_match_hash_reorders = si->connection_match_hash_reorders64; + spin_unlock_bh(&si->lock); + + bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t\n", + num_connections, + packets_forwarded, + packets_not_forwarded, + connection_create_requests, + connection_create_collisions, + connection_destroy_requests, + connection_destroy_misses, + connection_flushes, + connection_match_hash_hits, + connection_match_hash_reorders); + if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) { + return false; + } + + *length -= bytes_read; + *total_read += bytes_read; + + ws->state++; + return true; +} + +/* + * sfe_ipv4_debug_dev_read_end() + * Generate part of the XML output. + */ +static bool sfe_ipv4_debug_dev_read_end(struct sfe_ipv4 *si, char *buffer, char *msg, size_t *length, + int *total_read, struct sfe_ipv4_debug_xml_write_state *ws) +{ + int bytes_read; + + bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\n"); + if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) { + return false; + } + + *length -= bytes_read; + *total_read += bytes_read; + + ws->state++; + return true; +} + +/* + * Array of write functions that write various XML elements that correspond to + * our XML output state machine. + */ +static sfe_ipv4_debug_xml_write_method_t sfe_ipv4_debug_xml_write_methods[SFE_IPV4_DEBUG_XML_STATE_DONE] = { + sfe_ipv4_debug_dev_read_start, + sfe_ipv4_debug_dev_read_connections_start, + sfe_ipv4_debug_dev_read_connections_connection, + sfe_ipv4_debug_dev_read_connections_end, + sfe_ipv4_debug_dev_read_exceptions_start, + sfe_ipv4_debug_dev_read_exceptions_exception, + sfe_ipv4_debug_dev_read_exceptions_end, + sfe_ipv4_debug_dev_read_stats, + sfe_ipv4_debug_dev_read_end, +}; + +/* + * sfe_ipv4_debug_dev_read() + * Send info to userspace upon read request from user + */ +static ssize_t sfe_ipv4_debug_dev_read(struct file *filp, char *buffer, size_t length, loff_t *offset) +{ + char msg[CHAR_DEV_MSG_SIZE]; + int total_read = 0; + struct sfe_ipv4_debug_xml_write_state *ws; + struct sfe_ipv4 *si = &__si; + + ws = (struct sfe_ipv4_debug_xml_write_state *)filp->private_data; + while ((ws->state != SFE_IPV4_DEBUG_XML_STATE_DONE) && (length > CHAR_DEV_MSG_SIZE)) { + if ((sfe_ipv4_debug_xml_write_methods[ws->state])(si, buffer, msg, &length, &total_read, ws)) { + continue; + } + } + + return total_read; +} + +/* + * sfe_ipv4_debug_dev_write() + * Write to char device resets some stats + */ +static ssize_t sfe_ipv4_debug_dev_write(struct file *filp, const char *buffer, size_t length, loff_t *offset) +{ + struct sfe_ipv4 *si = &__si; + + spin_lock_bh(&si->lock); + sfe_ipv4_update_summary_stats(si); + + si->packets_forwarded64 = 0; + si->packets_not_forwarded64 = 0; + si->connection_create_requests64 = 0; + si->connection_create_collisions64 = 0; + si->connection_destroy_requests64 = 0; + si->connection_destroy_misses64 = 0; + si->connection_flushes64 = 0; + si->connection_match_hash_hits64 = 0; + si->connection_match_hash_reorders64 = 0; + spin_unlock_bh(&si->lock); + + return length; +} + +/* + * sfe_ipv4_debug_dev_open() + */ +static int sfe_ipv4_debug_dev_open(struct inode *inode, struct file *file) +{ + struct sfe_ipv4_debug_xml_write_state *ws; + + ws = (struct sfe_ipv4_debug_xml_write_state *)file->private_data; + if (!ws) { + ws = kzalloc(sizeof(struct sfe_ipv4_debug_xml_write_state), GFP_KERNEL); + if (!ws) { + return -ENOMEM; + } + + ws->state = SFE_IPV4_DEBUG_XML_STATE_START; + file->private_data = ws; + } + + return 0; +} + +/* + * sfe_ipv4_debug_dev_release() + */ +static int sfe_ipv4_debug_dev_release(struct inode *inode, struct file *file) +{ + struct sfe_ipv4_debug_xml_write_state *ws; + + ws = (struct sfe_ipv4_debug_xml_write_state *)file->private_data; + if (ws) { + /* + * We've finished with our output so free the write state. + */ + kfree(ws); + } + + return 0; +} + +/* + * File operations used in the debug char device + */ +static struct file_operations sfe_ipv4_debug_dev_fops = { + .read = sfe_ipv4_debug_dev_read, + .write = sfe_ipv4_debug_dev_write, + .open = sfe_ipv4_debug_dev_open, + .release = sfe_ipv4_debug_dev_release +}; + +#ifdef CONFIG_NF_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) +{ + struct sfe_ipv4 *si = &__si; + + BUG_ON(!cb); + + if (si->flow_cookie_set_func) { + return -1; + } + + rcu_assign_pointer(si->flow_cookie_set_func, cb); + return 0; +} + +/* + * 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) +{ + struct sfe_ipv4 *si = &__si; + + RCU_INIT_POINTER(si->flow_cookie_set_func, NULL); + return 0; +} + +/* + * sfe_ipv4_get_flow_cookie() + */ +static ssize_t sfe_ipv4_get_flow_cookie(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct sfe_ipv4 *si = &__si; + return snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", si->flow_cookie_enable); +} + +/* + * sfe_ipv4_set_flow_cookie() + */ +static ssize_t sfe_ipv4_set_flow_cookie(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct sfe_ipv4 *si = &__si; + strict_strtol(buf, 0, (long int *)&si->flow_cookie_enable); + + return size; +} + +/* + * sysfs attributes. + */ +static const struct device_attribute sfe_ipv4_flow_cookie_attr = + __ATTR(flow_cookie_enable, S_IWUSR | S_IRUGO, sfe_ipv4_get_flow_cookie, sfe_ipv4_set_flow_cookie); +#endif /*CONFIG_NF_FLOW_COOKIE*/ + +/* + * sfe_ipv4_init() + */ +static int __init sfe_ipv4_init(void) +{ + struct sfe_ipv4 *si = &__si; + int result = -1; + + DEBUG_INFO("SFE IPv4 init\n"); + + /* + * Create sys/sfe_ipv4 + */ + si->sys_sfe_ipv4 = kobject_create_and_add("sfe_ipv4", NULL); + if (!si->sys_sfe_ipv4) { + DEBUG_ERROR("failed to register sfe_ipv4\n"); + goto exit1; + } + + /* + * Create files, one for each parameter supported by this module. + */ + result = sysfs_create_file(si->sys_sfe_ipv4, &sfe_ipv4_debug_dev_attr.attr); + if (result) { + DEBUG_ERROR("failed to register debug dev file: %d\n", result); + goto exit2; + } + +#ifdef CONFIG_NF_FLOW_COOKIE + result = sysfs_create_file(si->sys_sfe_ipv4, &sfe_ipv4_flow_cookie_attr.attr); + if (result) { + DEBUG_ERROR("failed to register flow cookie enable file: %d\n", result); + goto exit3; + } +#endif /* CONFIG_NF_FLOW_COOKIE */ + + /* + * Register our debug char device. + */ + result = register_chrdev(0, "sfe_ipv4", &sfe_ipv4_debug_dev_fops); + if (result < 0) { + DEBUG_ERROR("Failed to register chrdev: %d\n", result); + goto exit4; + } + + si->debug_dev = result; + + /* + * Create a timer to handle periodic statistics. + */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)) + setup_timer(&si->timer, sfe_ipv4_periodic_sync, (unsigned long)si); +#else + timer_setup(&si->timer, sfe_ipv4_periodic_sync, 0); +#endif + mod_timer(&si->timer, jiffies + ((HZ + 99) / 100)); + + spin_lock_init(&si->lock); + + return 0; + +exit4: +#ifdef CONFIG_NF_FLOW_COOKIE + sysfs_remove_file(si->sys_sfe_ipv4, &sfe_ipv4_flow_cookie_attr.attr); + +exit3: +#endif /* CONFIG_NF_FLOW_COOKIE */ + sysfs_remove_file(si->sys_sfe_ipv4, &sfe_ipv4_debug_dev_attr.attr); + +exit2: + kobject_put(si->sys_sfe_ipv4); + +exit1: + return result; +} + +/* + * sfe_ipv4_exit() + */ +static void __exit sfe_ipv4_exit(void) +{ + struct sfe_ipv4 *si = &__si; + + DEBUG_INFO("SFE IPv4 exit\n"); + + /* + * Destroy all connections. + */ + sfe_ipv4_destroy_all_rules_for_dev(NULL); + + del_timer_sync(&si->timer); + + unregister_chrdev(si->debug_dev, "sfe_ipv4"); + +#ifdef CONFIG_NF_FLOW_COOKIE + sysfs_remove_file(si->sys_sfe_ipv4, &sfe_ipv4_flow_cookie_attr.attr); +#endif /* CONFIG_NF_FLOW_COOKIE */ + sysfs_remove_file(si->sys_sfe_ipv4, &sfe_ipv4_debug_dev_attr.attr); + + kobject_put(si->sys_sfe_ipv4); + +} + +module_init(sfe_ipv4_init) +module_exit(sfe_ipv4_exit) + +EXPORT_SYMBOL(sfe_ipv4_recv); +EXPORT_SYMBOL(sfe_ipv4_create_rule); +EXPORT_SYMBOL(sfe_ipv4_destroy_rule); +EXPORT_SYMBOL(sfe_ipv4_destroy_all_rules_for_dev); +EXPORT_SYMBOL(sfe_ipv4_register_sync_rule_callback); +EXPORT_SYMBOL(sfe_ipv4_mark_rule); +EXPORT_SYMBOL(sfe_ipv4_update_rule); +#ifdef CONFIG_NF_FLOW_COOKIE +EXPORT_SYMBOL(sfe_register_flow_cookie_cb); +EXPORT_SYMBOL(sfe_unregister_flow_cookie_cb); +#endif + +MODULE_DESCRIPTION("Shortcut Forwarding Engine - IPv4 edition"); +MODULE_LICENSE("Dual BSD/GPL"); + diff --git a/shortcut-fe/shortcut-fe/sfe_ipv6.c b/shortcut-fe/shortcut-fe/sfe_ipv6.c new file mode 100644 index 000000000..a7cb811a9 --- /dev/null +++ b/shortcut-fe/shortcut-fe/sfe_ipv6.c @@ -0,0 +1,3617 @@ +/* + * sfe_ipv6.c + * Shortcut forwarding engine - IPv6 support. + * + * Copyright (c) 2015-2016, 2019-2020 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 +#include +#include +#include +#include +#include +#include + +#include "sfe.h" +#include "sfe_cm.h" + +/* + * By default Linux IP header and transport layer header structures are + * unpacked, assuming that such headers should be 32-bit aligned. + * Unfortunately some wireless adaptors can't cope with this requirement and + * some CPUs can't handle misaligned accesses. For those platforms we + * define SFE_IPV6_UNALIGNED_IP_HEADER and mark the structures as packed. + * When we do this the compiler will generate slightly worse code than for the + * aligned case (on most platforms) but will be much quicker than fixing + * things up in an unaligned trap handler. + */ +#define SFE_IPV6_UNALIGNED_IP_HEADER 1 +#if SFE_IPV6_UNALIGNED_IP_HEADER +#define SFE_IPV6_UNALIGNED_STRUCT __attribute__((packed)) +#else +#define SFE_IPV6_UNALIGNED_STRUCT +#endif + +#define CHAR_DEV_MSG_SIZE 768 + +/* + * An Ethernet header, but with an optional "packed" attribute to + * help with performance on some platforms (see the definition of + * SFE_IPV6_UNALIGNED_STRUCT) + */ +struct sfe_ipv6_eth_hdr { + __be16 h_dest[ETH_ALEN / 2]; + __be16 h_source[ETH_ALEN / 2]; + __be16 h_proto; +} SFE_IPV6_UNALIGNED_STRUCT; + +#define SFE_IPV6_DSCP_MASK 0xf03f +#define SFE_IPV6_DSCP_SHIFT 2 + +/* + * An IPv6 header, but with an optional "packed" attribute to + * help with performance on some platforms (see the definition of + * SFE_IPV6_UNALIGNED_STRUCT) + */ +struct sfe_ipv6_ip_hdr { +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 priority:4, + version:4; +#elif defined(__BIG_ENDIAN_BITFIELD) + __u8 version:4, + priority:4; +#else +#error "Please fix " +#endif + __u8 flow_lbl[3]; + __be16 payload_len; + __u8 nexthdr; + __u8 hop_limit; + struct sfe_ipv6_addr saddr; + struct sfe_ipv6_addr daddr; + + /* + * The extension header start here. + */ +} SFE_IPV6_UNALIGNED_STRUCT; + +#define SFE_IPV6_EXT_HDR_HOP 0 +#define SFE_IPV6_EXT_HDR_ROUTING 43 +#define SFE_IPV6_EXT_HDR_FRAG 44 +#define SFE_IPV6_EXT_HDR_ESP 50 +#define SFE_IPV6_EXT_HDR_AH 51 +#define SFE_IPV6_EXT_HDR_NONE 59 +#define SFE_IPV6_EXT_HDR_DST 60 +#define SFE_IPV6_EXT_HDR_MH 135 + +/* + * fragmentation header + */ + +struct sfe_ipv6_frag_hdr { + __u8 nexthdr; + __u8 reserved; + __be16 frag_off; + __be32 identification; +}; + +#define SFE_IPV6_FRAG_OFFSET 0xfff8 + +/* + * generic IPv6 extension header + */ +struct sfe_ipv6_ext_hdr { + __u8 next_hdr; + __u8 hdr_len; + __u8 padding[6]; +} SFE_IPV6_UNALIGNED_STRUCT; + +/* + * A UDP header, but with an optional "packed" attribute to + * help with performance on some platforms (see the definition of + * SFE_IPV6_UNALIGNED_STRUCT) + */ +struct sfe_ipv6_udp_hdr { + __be16 source; + __be16 dest; + __be16 len; + __sum16 check; +} SFE_IPV6_UNALIGNED_STRUCT; + +/* + * A TCP header, but with an optional "packed" attribute to + * help with performance on some platforms (see the definition of + * SFE_IPV6_UNALIGNED_STRUCT) + */ +struct sfe_ipv6_tcp_hdr { + __be16 source; + __be16 dest; + __be32 seq; + __be32 ack_seq; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u16 res1:4, + doff:4, + fin:1, + syn:1, + rst:1, + psh:1, + ack:1, + urg:1, + ece:1, + cwr:1; +#elif defined(__BIG_ENDIAN_BITFIELD) + __u16 doff:4, + res1:4, + cwr:1, + ece:1, + urg:1, + ack:1, + psh:1, + rst:1, + syn:1, + fin:1; +#else +#error "Adjust your defines" +#endif + __be16 window; + __sum16 check; + __be16 urg_ptr; +} SFE_IPV6_UNALIGNED_STRUCT; + +/* + * Specifies the lower bound on ACK numbers carried in the TCP header + */ +#define SFE_IPV6_TCP_MAX_ACK_WINDOW 65520 + +/* + * IPv6 TCP connection match additional data. + */ +struct sfe_ipv6_tcp_connection_match { + u8 win_scale; /* Window scale */ + u32 max_win; /* Maximum window size seen */ + u32 end; /* Sequence number of the next byte to send (seq + segment length) */ + u32 max_end; /* Sequence number of the last byte to ack */ +}; + +/* + * Bit flags for IPv6 connection matching entry. + */ +#define SFE_IPV6_CONNECTION_MATCH_FLAG_XLATE_SRC (1<<0) + /* Perform source translation */ +#define SFE_IPV6_CONNECTION_MATCH_FLAG_XLATE_DEST (1<<1) + /* Perform destination translation */ +#define SFE_IPV6_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK (1<<2) + /* Ignore TCP sequence numbers */ +#define SFE_IPV6_CONNECTION_MATCH_FLAG_WRITE_FAST_ETH_HDR (1<<3) + /* Fast Ethernet header write */ +#define SFE_IPV6_CONNECTION_MATCH_FLAG_WRITE_L2_HDR (1<<4) + /* Fast Ethernet header write */ +#define SFE_IPV6_CONNECTION_MATCH_FLAG_PRIORITY_REMARK (1<<5) + /* remark priority of SKB */ +#define SFE_IPV6_CONNECTION_MATCH_FLAG_DSCP_REMARK (1<<6) + /* remark DSCP of packet */ + +/* + * IPv6 connection matching structure. + */ +struct sfe_ipv6_connection_match { + /* + * References to other objects. + */ + struct sfe_ipv6_connection_match *next; + struct sfe_ipv6_connection_match *prev; + struct sfe_ipv6_connection *connection; + struct sfe_ipv6_connection_match *counter_match; + /* Matches the flow in the opposite direction as the one in connection */ + struct sfe_ipv6_connection_match *active_next; + struct sfe_ipv6_connection_match *active_prev; + bool active; /* Flag to indicate if we're on the active list */ + + /* + * Characteristics that identify flows that match this rule. + */ + struct net_device *match_dev; /* Network device */ + u8 match_protocol; /* Protocol */ + struct sfe_ipv6_addr match_src_ip[1]; /* Source IP address */ + struct sfe_ipv6_addr match_dest_ip[1]; /* Destination IP address */ + __be16 match_src_port; /* Source port/connection ident */ + __be16 match_dest_port; /* Destination port/connection ident */ + + /* + * Control the operations of the match. + */ + u32 flags; /* Bit flags */ +#ifdef CONFIG_NF_FLOW_COOKIE + u32 flow_cookie; /* used flow cookie, for debug */ +#endif +#ifdef CONFIG_XFRM + u32 flow_accel; /* The flow accelerated or not */ +#endif + + /* + * Connection state that we track once we match. + */ + union { /* Protocol-specific state */ + struct sfe_ipv6_tcp_connection_match tcp; + } protocol_state; + /* + * Stats recorded in a sync period. These stats will be added to + * rx_packet_count64/rx_byte_count64 after a sync period. + */ + u32 rx_packet_count; + u32 rx_byte_count; + + /* + * Packet translation information. + */ + struct sfe_ipv6_addr xlate_src_ip[1]; /* Address after source translation */ + __be16 xlate_src_port; /* Port/connection ident after source translation */ + u16 xlate_src_csum_adjustment; + /* Transport layer checksum adjustment after source translation */ + struct sfe_ipv6_addr xlate_dest_ip[1]; /* Address after destination translation */ + __be16 xlate_dest_port; /* Port/connection ident after destination translation */ + u16 xlate_dest_csum_adjustment; + /* Transport layer checksum adjustment after destination translation */ + + /* + * QoS information + */ + u32 priority; + u32 dscp; + + /* + * Packet transmit information. + */ + struct net_device *xmit_dev; /* Network device on which to transmit */ + unsigned short int xmit_dev_mtu; + /* Interface MTU */ + u16 xmit_dest_mac[ETH_ALEN / 2]; + /* Destination MAC address to use when forwarding */ + u16 xmit_src_mac[ETH_ALEN / 2]; + /* Source MAC address to use when forwarding */ + + /* + * Summary stats. + */ + u64 rx_packet_count64; + u64 rx_byte_count64; +}; + +/* + * Per-connection data structure. + */ +struct sfe_ipv6_connection { + struct sfe_ipv6_connection *next; + /* Pointer to the next entry in a hash chain */ + struct sfe_ipv6_connection *prev; + /* Pointer to the previous entry in a hash chain */ + int protocol; /* IP protocol number */ + struct sfe_ipv6_addr src_ip[1]; /* Src IP addr pre-translation */ + struct sfe_ipv6_addr src_ip_xlate[1]; /* Src IP addr post-translation */ + struct sfe_ipv6_addr dest_ip[1]; /* Dest IP addr pre-translation */ + struct sfe_ipv6_addr dest_ip_xlate[1]; /* Dest IP addr post-translation */ + __be16 src_port; /* Src port pre-translation */ + __be16 src_port_xlate; /* Src port post-translation */ + __be16 dest_port; /* Dest port pre-translation */ + __be16 dest_port_xlate; /* Dest port post-translation */ + struct sfe_ipv6_connection_match *original_match; + /* Original direction matching structure */ + struct net_device *original_dev; + /* Original direction source device */ + struct sfe_ipv6_connection_match *reply_match; + /* Reply direction matching structure */ + struct net_device *reply_dev; /* Reply direction source device */ + u64 last_sync_jiffies; /* Jiffies count for the last sync */ + struct sfe_ipv6_connection *all_connections_next; + /* Pointer to the next entry in the list of all connections */ + struct sfe_ipv6_connection *all_connections_prev; + /* Pointer to the previous entry in the list of all connections */ + u32 mark; /* mark for outgoing packet */ + u32 debug_read_seq; /* sequence number for debug dump */ +}; + +/* + * IPv6 connections and hash table size information. + */ +#define SFE_IPV6_CONNECTION_HASH_SHIFT 12 +#define SFE_IPV6_CONNECTION_HASH_SIZE (1 << SFE_IPV6_CONNECTION_HASH_SHIFT) +#define SFE_IPV6_CONNECTION_HASH_MASK (SFE_IPV6_CONNECTION_HASH_SIZE - 1) + +#ifdef CONFIG_NF_FLOW_COOKIE +#define SFE_FLOW_COOKIE_SIZE 2048 +#define SFE_FLOW_COOKIE_MASK 0x7ff + +struct sfe_ipv6_flow_cookie_entry { + struct sfe_ipv6_connection_match *match; + unsigned long last_clean_time; +}; +#endif + +enum sfe_ipv6_exception_events { + SFE_IPV6_EXCEPTION_EVENT_UDP_HEADER_INCOMPLETE, + SFE_IPV6_EXCEPTION_EVENT_UDP_NO_CONNECTION, + SFE_IPV6_EXCEPTION_EVENT_UDP_IP_OPTIONS_OR_INITIAL_FRAGMENT, + SFE_IPV6_EXCEPTION_EVENT_UDP_SMALL_TTL, + SFE_IPV6_EXCEPTION_EVENT_UDP_NEEDS_FRAGMENTATION, + SFE_IPV6_EXCEPTION_EVENT_TCP_HEADER_INCOMPLETE, + SFE_IPV6_EXCEPTION_EVENT_TCP_NO_CONNECTION_SLOW_FLAGS, + SFE_IPV6_EXCEPTION_EVENT_TCP_NO_CONNECTION_FAST_FLAGS, + SFE_IPV6_EXCEPTION_EVENT_TCP_IP_OPTIONS_OR_INITIAL_FRAGMENT, + SFE_IPV6_EXCEPTION_EVENT_TCP_SMALL_TTL, + SFE_IPV6_EXCEPTION_EVENT_TCP_NEEDS_FRAGMENTATION, + SFE_IPV6_EXCEPTION_EVENT_TCP_FLAGS, + SFE_IPV6_EXCEPTION_EVENT_TCP_SEQ_EXCEEDS_RIGHT_EDGE, + SFE_IPV6_EXCEPTION_EVENT_TCP_SMALL_DATA_OFFS, + SFE_IPV6_EXCEPTION_EVENT_TCP_BAD_SACK, + SFE_IPV6_EXCEPTION_EVENT_TCP_BIG_DATA_OFFS, + SFE_IPV6_EXCEPTION_EVENT_TCP_SEQ_BEFORE_LEFT_EDGE, + SFE_IPV6_EXCEPTION_EVENT_TCP_ACK_EXCEEDS_RIGHT_EDGE, + SFE_IPV6_EXCEPTION_EVENT_TCP_ACK_BEFORE_LEFT_EDGE, + SFE_IPV6_EXCEPTION_EVENT_ICMP_HEADER_INCOMPLETE, + SFE_IPV6_EXCEPTION_EVENT_ICMP_UNHANDLED_TYPE, + SFE_IPV6_EXCEPTION_EVENT_ICMP_IPV6_HEADER_INCOMPLETE, + SFE_IPV6_EXCEPTION_EVENT_ICMP_IPV6_NON_V6, + SFE_IPV6_EXCEPTION_EVENT_ICMP_IPV6_IP_OPTIONS_INCOMPLETE, + SFE_IPV6_EXCEPTION_EVENT_ICMP_IPV6_UDP_HEADER_INCOMPLETE, + SFE_IPV6_EXCEPTION_EVENT_ICMP_IPV6_TCP_HEADER_INCOMPLETE, + SFE_IPV6_EXCEPTION_EVENT_ICMP_IPV6_UNHANDLED_PROTOCOL, + SFE_IPV6_EXCEPTION_EVENT_ICMP_NO_CONNECTION, + SFE_IPV6_EXCEPTION_EVENT_ICMP_FLUSHED_CONNECTION, + SFE_IPV6_EXCEPTION_EVENT_HEADER_INCOMPLETE, + SFE_IPV6_EXCEPTION_EVENT_BAD_TOTAL_LENGTH, + SFE_IPV6_EXCEPTION_EVENT_NON_V6, + SFE_IPV6_EXCEPTION_EVENT_NON_INITIAL_FRAGMENT, + SFE_IPV6_EXCEPTION_EVENT_DATAGRAM_INCOMPLETE, + SFE_IPV6_EXCEPTION_EVENT_IP_OPTIONS_INCOMPLETE, + SFE_IPV6_EXCEPTION_EVENT_UNHANDLED_PROTOCOL, + SFE_IPV6_EXCEPTION_EVENT_FLOW_COOKIE_ADD_FAIL, + SFE_IPV6_EXCEPTION_EVENT_LAST +}; + +static char *sfe_ipv6_exception_events_string[SFE_IPV6_EXCEPTION_EVENT_LAST] = { + "UDP_HEADER_INCOMPLETE", + "UDP_NO_CONNECTION", + "UDP_IP_OPTIONS_OR_INITIAL_FRAGMENT", + "UDP_SMALL_TTL", + "UDP_NEEDS_FRAGMENTATION", + "TCP_HEADER_INCOMPLETE", + "TCP_NO_CONNECTION_SLOW_FLAGS", + "TCP_NO_CONNECTION_FAST_FLAGS", + "TCP_IP_OPTIONS_OR_INITIAL_FRAGMENT", + "TCP_SMALL_TTL", + "TCP_NEEDS_FRAGMENTATION", + "TCP_FLAGS", + "TCP_SEQ_EXCEEDS_RIGHT_EDGE", + "TCP_SMALL_DATA_OFFS", + "TCP_BAD_SACK", + "TCP_BIG_DATA_OFFS", + "TCP_SEQ_BEFORE_LEFT_EDGE", + "TCP_ACK_EXCEEDS_RIGHT_EDGE", + "TCP_ACK_BEFORE_LEFT_EDGE", + "ICMP_HEADER_INCOMPLETE", + "ICMP_UNHANDLED_TYPE", + "ICMP_IPV6_HEADER_INCOMPLETE", + "ICMP_IPV6_NON_V6", + "ICMP_IPV6_IP_OPTIONS_INCOMPLETE", + "ICMP_IPV6_UDP_HEADER_INCOMPLETE", + "ICMP_IPV6_TCP_HEADER_INCOMPLETE", + "ICMP_IPV6_UNHANDLED_PROTOCOL", + "ICMP_NO_CONNECTION", + "ICMP_FLUSHED_CONNECTION", + "HEADER_INCOMPLETE", + "BAD_TOTAL_LENGTH", + "NON_V6", + "NON_INITIAL_FRAGMENT", + "DATAGRAM_INCOMPLETE", + "IP_OPTIONS_INCOMPLETE", + "UNHANDLED_PROTOCOL", + "FLOW_COOKIE_ADD_FAIL" +}; + +/* + * Per-module structure. + */ +struct sfe_ipv6 { + spinlock_t lock; /* Lock for SMP correctness */ + struct sfe_ipv6_connection_match *active_head; + /* Head of the list of recently active connections */ + struct sfe_ipv6_connection_match *active_tail; + /* Tail of the list of recently active connections */ + struct sfe_ipv6_connection *all_connections_head; + /* Head of the list of all connections */ + struct sfe_ipv6_connection *all_connections_tail; + /* Tail of the list of all connections */ + unsigned int num_connections; /* Number of connections */ + struct timer_list timer; /* Timer used for periodic sync ops */ + sfe_sync_rule_callback_t __rcu sync_rule_callback; + /* Callback function registered by a connection manager for stats syncing */ + struct sfe_ipv6_connection *conn_hash[SFE_IPV6_CONNECTION_HASH_SIZE]; + /* Connection hash table */ + struct sfe_ipv6_connection_match *conn_match_hash[SFE_IPV6_CONNECTION_HASH_SIZE]; + /* Connection match hash table */ +#ifdef CONFIG_NF_FLOW_COOKIE + struct sfe_ipv6_flow_cookie_entry sfe_flow_cookie_table[SFE_FLOW_COOKIE_SIZE]; + /* flow cookie table*/ + sfe_ipv6_flow_cookie_set_func_t flow_cookie_set_func; + /* function used to configure flow cookie in hardware*/ + int flow_cookie_enable; + /* Enable/disable flow cookie at runtime */ +#endif + + /* + * Stats recorded in a sync period. These stats will be added to + * connection_xxx64 after a sync period. + */ + u32 connection_create_requests; + /* Number of IPv6 connection create requests */ + u32 connection_create_collisions; + /* Number of IPv6 connection create requests that collided with existing hash table entries */ + u32 connection_destroy_requests; + /* Number of IPv6 connection destroy requests */ + u32 connection_destroy_misses; + /* Number of IPv6 connection destroy requests that missed our hash table */ + u32 connection_match_hash_hits; + /* Number of IPv6 connection match hash hits */ + u32 connection_match_hash_reorders; + /* Number of IPv6 connection match hash reorders */ + u32 connection_flushes; /* Number of IPv6 connection flushes */ + u32 packets_forwarded; /* Number of IPv6 packets forwarded */ + u32 packets_not_forwarded; /* Number of IPv6 packets not forwarded */ + u32 exception_events[SFE_IPV6_EXCEPTION_EVENT_LAST]; + + /* + * Summary statistics. + */ + u64 connection_create_requests64; + /* Number of IPv6 connection create requests */ + u64 connection_create_collisions64; + /* Number of IPv6 connection create requests that collided with existing hash table entries */ + u64 connection_destroy_requests64; + /* Number of IPv6 connection destroy requests */ + u64 connection_destroy_misses64; + /* Number of IPv6 connection destroy requests that missed our hash table */ + u64 connection_match_hash_hits64; + /* Number of IPv6 connection match hash hits */ + u64 connection_match_hash_reorders64; + /* Number of IPv6 connection match hash reorders */ + u64 connection_flushes64; /* Number of IPv6 connection flushes */ + u64 packets_forwarded64; /* Number of IPv6 packets forwarded */ + u64 packets_not_forwarded64; + /* Number of IPv6 packets not forwarded */ + u64 exception_events64[SFE_IPV6_EXCEPTION_EVENT_LAST]; + + /* + * Control state. + */ + struct kobject *sys_sfe_ipv6; /* sysfs linkage */ + int debug_dev; /* Major number of the debug char device */ + u32 debug_read_seq; /* sequence number for debug dump */ +}; + +/* + * Enumeration of the XML output. + */ +enum sfe_ipv6_debug_xml_states { + SFE_IPV6_DEBUG_XML_STATE_START, + SFE_IPV6_DEBUG_XML_STATE_CONNECTIONS_START, + SFE_IPV6_DEBUG_XML_STATE_CONNECTIONS_CONNECTION, + SFE_IPV6_DEBUG_XML_STATE_CONNECTIONS_END, + SFE_IPV6_DEBUG_XML_STATE_EXCEPTIONS_START, + SFE_IPV6_DEBUG_XML_STATE_EXCEPTIONS_EXCEPTION, + SFE_IPV6_DEBUG_XML_STATE_EXCEPTIONS_END, + SFE_IPV6_DEBUG_XML_STATE_STATS, + SFE_IPV6_DEBUG_XML_STATE_END, + SFE_IPV6_DEBUG_XML_STATE_DONE +}; + +/* + * XML write state. + */ +struct sfe_ipv6_debug_xml_write_state { + enum sfe_ipv6_debug_xml_states state; + /* XML output file state machine state */ + int iter_exception; /* Next exception iterator */ +}; + +typedef bool (*sfe_ipv6_debug_xml_write_method_t)(struct sfe_ipv6 *si, char *buffer, char *msg, size_t *length, + int *total_read, struct sfe_ipv6_debug_xml_write_state *ws); + +static struct sfe_ipv6 __si6; + +/* + * sfe_ipv6_get_debug_dev() + */ +static ssize_t sfe_ipv6_get_debug_dev(struct device *dev, struct device_attribute *attr, char *buf); + +/* + * sysfs attributes. + */ +static const struct device_attribute sfe_ipv6_debug_dev_attr = + __ATTR(debug_dev, S_IWUSR | S_IRUGO, sfe_ipv6_get_debug_dev, NULL); + +/* + * sfe_ipv6_is_ext_hdr() + * check if we recognize ipv6 extension header + */ +static inline bool sfe_ipv6_is_ext_hdr(u8 hdr) +{ + return (hdr == SFE_IPV6_EXT_HDR_HOP) || + (hdr == SFE_IPV6_EXT_HDR_ROUTING) || + (hdr == SFE_IPV6_EXT_HDR_FRAG) || + (hdr == SFE_IPV6_EXT_HDR_AH) || + (hdr == SFE_IPV6_EXT_HDR_DST) || + (hdr == SFE_IPV6_EXT_HDR_MH); +} + +/* + * sfe_ipv6_change_dsfield() + * change dscp field in IPv6 packet + */ +static inline void sfe_ipv6_change_dsfield(struct sfe_ipv6_ip_hdr *iph, u8 dscp) +{ + __be16 *p = (__be16 *)iph; + + *p = ((*p & htons(SFE_IPV6_DSCP_MASK)) | htons((u16)dscp << 4)); +} + +/* + * sfe_ipv6_get_connection_match_hash() + * Generate the hash used in connection match lookups. + */ +static inline unsigned int sfe_ipv6_get_connection_match_hash(struct net_device *dev, u8 protocol, + struct sfe_ipv6_addr *src_ip, __be16 src_port, + struct sfe_ipv6_addr *dest_ip, __be16 dest_port) +{ + u32 idx, hash = 0; + size_t dev_addr = (size_t)dev; + + for (idx = 0; idx < 4; idx++) { + hash ^= src_ip->addr[idx] ^ dest_ip->addr[idx]; + } + hash = ((u32)dev_addr) ^ hash ^ protocol ^ ntohs(src_port ^ dest_port); + return ((hash >> SFE_IPV6_CONNECTION_HASH_SHIFT) ^ hash) & SFE_IPV6_CONNECTION_HASH_MASK; +} + +/* + * sfe_ipv6_find_connection_match() + * Get the IPv6 flow match info that corresponds to a particular 5-tuple. + * + * On entry we must be holding the lock that protects the hash table. + */ +static struct sfe_ipv6_connection_match * +sfe_ipv6_find_connection_match(struct sfe_ipv6 *si, struct net_device *dev, u8 protocol, + struct sfe_ipv6_addr *src_ip, __be16 src_port, + struct sfe_ipv6_addr *dest_ip, __be16 dest_port) +{ + struct sfe_ipv6_connection_match *cm; + struct sfe_ipv6_connection_match *head; + unsigned int conn_match_idx; + + conn_match_idx = sfe_ipv6_get_connection_match_hash(dev, protocol, src_ip, src_port, dest_ip, dest_port); + cm = si->conn_match_hash[conn_match_idx]; + + /* + * If we don't have anything in this chain then bail. + */ + if (unlikely(!cm)) { + return NULL; + } + + /* + * Hopefully the first entry is the one we want. + */ + if ((cm->match_src_port == src_port) + && (cm->match_dest_port == dest_port) + && (sfe_ipv6_addr_equal(cm->match_src_ip, src_ip)) + && (sfe_ipv6_addr_equal(cm->match_dest_ip, dest_ip)) + && (cm->match_protocol == protocol) + && (cm->match_dev == dev)) { + si->connection_match_hash_hits++; + return cm; + } + + /* + * Unfortunately we didn't find it at head, so we search it in chain and + * move matching entry to the top of the hash chain. We presume that this + * will be reused again very quickly. + */ + head = cm; + do { + cm = cm->next; + } while (cm && (cm->match_src_port != src_port + || cm->match_dest_port != dest_port + || !sfe_ipv6_addr_equal(cm->match_src_ip, src_ip) + || !sfe_ipv6_addr_equal(cm->match_dest_ip, dest_ip) + || cm->match_protocol != protocol + || cm->match_dev != dev)); + + /* + * Not found then we're done. + */ + if (unlikely(!cm)) { + return NULL; + } + + /* + * We found a match so move it. + */ + if (cm->next) { + cm->next->prev = cm->prev; + } + cm->prev->next = cm->next; + cm->prev = NULL; + cm->next = head; + head->prev = cm; + si->conn_match_hash[conn_match_idx] = cm; + si->connection_match_hash_reorders++; + + return cm; +} + +/* + * sfe_ipv6_connection_match_update_summary_stats() + * Update the summary stats for a connection match entry. + */ +static inline void sfe_ipv6_connection_match_update_summary_stats(struct sfe_ipv6_connection_match *cm) +{ + cm->rx_packet_count64 += cm->rx_packet_count; + cm->rx_packet_count = 0; + cm->rx_byte_count64 += cm->rx_byte_count; + cm->rx_byte_count = 0; +} + +/* + * sfe_ipv6_connection_match_compute_translations() + * Compute port and address translations for a connection match entry. + */ +static void sfe_ipv6_connection_match_compute_translations(struct sfe_ipv6_connection_match *cm) +{ + u32 diff[9]; + u32 *idx_32; + u16 *idx_16; + + /* + * Before we insert the entry look to see if this is tagged as doing address + * translations. If it is then work out the adjustment that we need to apply + * to the transport checksum. + */ + if (cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_XLATE_SRC) { + u32 adj = 0; + u32 carry = 0; + + /* + * Precompute an incremental checksum adjustment so we can + * edit packets in this stream very quickly. The algorithm is from RFC1624. + */ + idx_32 = diff; + *(idx_32++) = cm->match_src_ip->addr[0]; + *(idx_32++) = cm->match_src_ip->addr[1]; + *(idx_32++) = cm->match_src_ip->addr[2]; + *(idx_32++) = cm->match_src_ip->addr[3]; + + idx_16 = (u16 *)idx_32; + *(idx_16++) = cm->match_src_port; + *(idx_16++) = ~cm->xlate_src_port; + idx_32 = (u32 *)idx_16; + + *(idx_32++) = ~cm->xlate_src_ip->addr[0]; + *(idx_32++) = ~cm->xlate_src_ip->addr[1]; + *(idx_32++) = ~cm->xlate_src_ip->addr[2]; + *(idx_32++) = ~cm->xlate_src_ip->addr[3]; + + /* + * When we compute this fold it down to a 16-bit offset + * as that way we can avoid having to do a double + * folding of the twos-complement result because the + * addition of 2 16-bit values cannot cause a double + * wrap-around! + */ + for (idx_32 = diff; idx_32 < diff + 9; idx_32++) { + u32 w = *idx_32; + adj += carry; + adj += w; + carry = (w > adj); + } + adj += carry; + adj = (adj & 0xffff) + (adj >> 16); + adj = (adj & 0xffff) + (adj >> 16); + cm->xlate_src_csum_adjustment = (u16)adj; + } + + if (cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_XLATE_DEST) { + u32 adj = 0; + u32 carry = 0; + + /* + * Precompute an incremental checksum adjustment so we can + * edit packets in this stream very quickly. The algorithm is from RFC1624. + */ + idx_32 = diff; + *(idx_32++) = cm->match_dest_ip->addr[0]; + *(idx_32++) = cm->match_dest_ip->addr[1]; + *(idx_32++) = cm->match_dest_ip->addr[2]; + *(idx_32++) = cm->match_dest_ip->addr[3]; + + idx_16 = (u16 *)idx_32; + *(idx_16++) = cm->match_dest_port; + *(idx_16++) = ~cm->xlate_dest_port; + idx_32 = (u32 *)idx_16; + + *(idx_32++) = ~cm->xlate_dest_ip->addr[0]; + *(idx_32++) = ~cm->xlate_dest_ip->addr[1]; + *(idx_32++) = ~cm->xlate_dest_ip->addr[2]; + *(idx_32++) = ~cm->xlate_dest_ip->addr[3]; + + /* + * When we compute this fold it down to a 16-bit offset + * as that way we can avoid having to do a double + * folding of the twos-complement result because the + * addition of 2 16-bit values cannot cause a double + * wrap-around! + */ + for (idx_32 = diff; idx_32 < diff + 9; idx_32++) { + u32 w = *idx_32; + adj += carry; + adj += w; + carry = (w > adj); + } + adj += carry; + adj = (adj & 0xffff) + (adj >> 16); + adj = (adj & 0xffff) + (adj >> 16); + cm->xlate_dest_csum_adjustment = (u16)adj; + } +} + +/* + * sfe_ipv6_update_summary_stats() + * Update the summary stats. + */ +static void sfe_ipv6_update_summary_stats(struct sfe_ipv6 *si) +{ + int i; + + si->connection_create_requests64 += si->connection_create_requests; + si->connection_create_requests = 0; + si->connection_create_collisions64 += si->connection_create_collisions; + si->connection_create_collisions = 0; + si->connection_destroy_requests64 += si->connection_destroy_requests; + si->connection_destroy_requests = 0; + si->connection_destroy_misses64 += si->connection_destroy_misses; + si->connection_destroy_misses = 0; + si->connection_match_hash_hits64 += si->connection_match_hash_hits; + si->connection_match_hash_hits = 0; + si->connection_match_hash_reorders64 += si->connection_match_hash_reorders; + si->connection_match_hash_reorders = 0; + si->connection_flushes64 += si->connection_flushes; + si->connection_flushes = 0; + si->packets_forwarded64 += si->packets_forwarded; + si->packets_forwarded = 0; + si->packets_not_forwarded64 += si->packets_not_forwarded; + si->packets_not_forwarded = 0; + + for (i = 0; i < SFE_IPV6_EXCEPTION_EVENT_LAST; i++) { + si->exception_events64[i] += si->exception_events[i]; + si->exception_events[i] = 0; + } +} + +/* + * sfe_ipv6_insert_connection_match() + * Insert a connection match into the hash. + * + * On entry we must be holding the lock that protects the hash table. + */ +static inline void sfe_ipv6_insert_connection_match(struct sfe_ipv6 *si, + struct sfe_ipv6_connection_match *cm) +{ + struct sfe_ipv6_connection_match **hash_head; + struct sfe_ipv6_connection_match *prev_head; + unsigned int conn_match_idx + = sfe_ipv6_get_connection_match_hash(cm->match_dev, cm->match_protocol, + cm->match_src_ip, cm->match_src_port, + cm->match_dest_ip, cm->match_dest_port); + + hash_head = &si->conn_match_hash[conn_match_idx]; + prev_head = *hash_head; + cm->prev = NULL; + if (prev_head) { + prev_head->prev = cm; + } + + cm->next = prev_head; + *hash_head = cm; + +#ifdef CONFIG_NF_FLOW_COOKIE + if (!si->flow_cookie_enable || !(cm->flags & (SFE_IPV6_CONNECTION_MATCH_FLAG_XLATE_SRC | SFE_IPV6_CONNECTION_MATCH_FLAG_XLATE_DEST))) + return; + + /* + * Configure hardware to put a flow cookie in packet of this flow, + * then we can accelerate the lookup process when we received this packet. + */ + for (conn_match_idx = 1; conn_match_idx < SFE_FLOW_COOKIE_SIZE; conn_match_idx++) { + struct sfe_ipv6_flow_cookie_entry *entry = &si->sfe_flow_cookie_table[conn_match_idx]; + + if ((NULL == entry->match) && time_is_before_jiffies(entry->last_clean_time + HZ)) { + sfe_ipv6_flow_cookie_set_func_t func; + + rcu_read_lock(); + func = rcu_dereference(si->flow_cookie_set_func); + if (func) { + if (!func(cm->match_protocol, cm->match_src_ip->addr, cm->match_src_port, + cm->match_dest_ip->addr, cm->match_dest_port, conn_match_idx)) { + entry->match = cm; + cm->flow_cookie = conn_match_idx; + } else { + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_FLOW_COOKIE_ADD_FAIL]++; + } + } + rcu_read_unlock(); + + break; + } + } +#endif +} + +/* + * sfe_ipv6_remove_connection_match() + * Remove a connection match object from the hash. + * + * On entry we must be holding the lock that protects the hash table. + */ +static inline void sfe_ipv6_remove_connection_match(struct sfe_ipv6 *si, struct sfe_ipv6_connection_match *cm) +{ +#ifdef CONFIG_NF_FLOW_COOKIE + if (si->flow_cookie_enable) { + /* + * Tell hardware that we no longer need a flow cookie in packet of this flow + */ + unsigned int conn_match_idx; + + for (conn_match_idx = 1; conn_match_idx < SFE_FLOW_COOKIE_SIZE; conn_match_idx++) { + struct sfe_ipv6_flow_cookie_entry *entry = &si->sfe_flow_cookie_table[conn_match_idx]; + + if (cm == entry->match) { + sfe_ipv6_flow_cookie_set_func_t func; + + rcu_read_lock(); + func = rcu_dereference(si->flow_cookie_set_func); + if (func) { + func(cm->match_protocol, cm->match_src_ip->addr, cm->match_src_port, + cm->match_dest_ip->addr, cm->match_dest_port, 0); + } + rcu_read_unlock(); + + cm->flow_cookie = 0; + entry->match = NULL; + entry->last_clean_time = jiffies; + break; + } + } + } +#endif + + /* + * Unlink the connection match entry from the hash. + */ + if (cm->prev) { + cm->prev->next = cm->next; + } else { + unsigned int conn_match_idx + = sfe_ipv6_get_connection_match_hash(cm->match_dev, cm->match_protocol, + cm->match_src_ip, cm->match_src_port, + cm->match_dest_ip, cm->match_dest_port); + si->conn_match_hash[conn_match_idx] = cm->next; + } + + if (cm->next) { + cm->next->prev = cm->prev; + } + + /* + * If the connection match entry is in the active list remove it. + */ + if (cm->active) { + if (likely(cm->active_prev)) { + cm->active_prev->active_next = cm->active_next; + } else { + si->active_head = cm->active_next; + } + + if (likely(cm->active_next)) { + cm->active_next->active_prev = cm->active_prev; + } else { + si->active_tail = cm->active_prev; + } + } +} + +/* + * sfe_ipv6_get_connection_hash() + * Generate the hash used in connection lookups. + */ +static inline unsigned int sfe_ipv6_get_connection_hash(u8 protocol, struct sfe_ipv6_addr *src_ip, __be16 src_port, + struct sfe_ipv6_addr *dest_ip, __be16 dest_port) +{ + u32 idx, hash = 0; + + for (idx = 0; idx < 4; idx++) { + hash ^= src_ip->addr[idx] ^ dest_ip->addr[idx]; + } + hash = hash ^ protocol ^ ntohs(src_port ^ dest_port); + return ((hash >> SFE_IPV6_CONNECTION_HASH_SHIFT) ^ hash) & SFE_IPV6_CONNECTION_HASH_MASK; +} + +/* + * sfe_ipv6_find_connection() + * Get the IPv6 connection info that corresponds to a particular 5-tuple. + * + * On entry we must be holding the lock that protects the hash table. + */ +static inline struct sfe_ipv6_connection *sfe_ipv6_find_connection(struct sfe_ipv6 *si, u32 protocol, + struct sfe_ipv6_addr *src_ip, __be16 src_port, + struct sfe_ipv6_addr *dest_ip, __be16 dest_port) +{ + struct sfe_ipv6_connection *c; + unsigned int conn_idx = sfe_ipv6_get_connection_hash(protocol, src_ip, src_port, dest_ip, dest_port); + c = si->conn_hash[conn_idx]; + + /* + * If we don't have anything in this chain then bale. + */ + if (unlikely(!c)) { + return NULL; + } + + /* + * Hopefully the first entry is the one we want. + */ + if ((c->src_port == src_port) + && (c->dest_port == dest_port) + && (sfe_ipv6_addr_equal(c->src_ip, src_ip)) + && (sfe_ipv6_addr_equal(c->dest_ip, dest_ip)) + && (c->protocol == protocol)) { + return c; + } + + /* + * Unfortunately we didn't find it at head, so we search it in chain. + */ + do { + c = c->next; + } while (c && (c->src_port != src_port + || c->dest_port != dest_port + || !sfe_ipv6_addr_equal(c->src_ip, src_ip) + || !sfe_ipv6_addr_equal(c->dest_ip, dest_ip) + || c->protocol != protocol)); + + /* + * Will need connection entry for next create/destroy metadata, + * So no need to re-order entry for these requests + */ + return c; +} + +/* + * sfe_ipv6_mark_rule() + * Updates the mark for a current offloaded connection + * + * Will take hash lock upon entry + */ +void sfe_ipv6_mark_rule(struct sfe_connection_mark *mark) +{ + struct sfe_ipv6 *si = &__si6; + struct sfe_ipv6_connection *c; + + spin_lock_bh(&si->lock); + c = sfe_ipv6_find_connection(si, mark->protocol, + mark->src_ip.ip6, mark->src_port, + mark->dest_ip.ip6, mark->dest_port); + if (c) { + WARN_ON((0 != c->mark) && (0 == mark->mark)); + c->mark = mark->mark; + } + spin_unlock_bh(&si->lock); + + if (c) { + DEBUG_TRACE("Matching connection found for mark, " + "setting from %08x to %08x\n", + c->mark, mark->mark); + } +} + +/* + * sfe_ipv6_insert_connection() + * Insert a connection into the hash. + * + * On entry we must be holding the lock that protects the hash table. + */ +static void sfe_ipv6_insert_connection(struct sfe_ipv6 *si, struct sfe_ipv6_connection *c) +{ + struct sfe_ipv6_connection **hash_head; + struct sfe_ipv6_connection *prev_head; + unsigned int conn_idx; + + /* + * Insert entry into the connection hash. + */ + conn_idx = sfe_ipv6_get_connection_hash(c->protocol, c->src_ip, c->src_port, + c->dest_ip, c->dest_port); + hash_head = &si->conn_hash[conn_idx]; + prev_head = *hash_head; + c->prev = NULL; + if (prev_head) { + prev_head->prev = c; + } + + c->next = prev_head; + *hash_head = c; + + /* + * Insert entry into the "all connections" list. + */ + if (si->all_connections_tail) { + c->all_connections_prev = si->all_connections_tail; + si->all_connections_tail->all_connections_next = c; + } else { + c->all_connections_prev = NULL; + si->all_connections_head = c; + } + + si->all_connections_tail = c; + c->all_connections_next = NULL; + si->num_connections++; + + /* + * Insert the connection match objects too. + */ + sfe_ipv6_insert_connection_match(si, c->original_match); + sfe_ipv6_insert_connection_match(si, c->reply_match); +} + +/* + * sfe_ipv6_remove_connection() + * Remove a sfe_ipv6_connection object from the hash. + * + * On entry we must be holding the lock that protects the hash table. + */ +static void sfe_ipv6_remove_connection(struct sfe_ipv6 *si, struct sfe_ipv6_connection *c) +{ + /* + * Remove the connection match objects. + */ + sfe_ipv6_remove_connection_match(si, c->reply_match); + sfe_ipv6_remove_connection_match(si, c->original_match); + + /* + * Unlink the connection. + */ + if (c->prev) { + c->prev->next = c->next; + } else { + unsigned int conn_idx = sfe_ipv6_get_connection_hash(c->protocol, c->src_ip, c->src_port, + c->dest_ip, c->dest_port); + si->conn_hash[conn_idx] = c->next; + } + + if (c->next) { + c->next->prev = c->prev; + } + + /* + * Unlink connection from all_connections list + */ + if (c->all_connections_prev) { + c->all_connections_prev->all_connections_next = c->all_connections_next; + } else { + si->all_connections_head = c->all_connections_next; + } + + if (c->all_connections_next) { + c->all_connections_next->all_connections_prev = c->all_connections_prev; + } else { + si->all_connections_tail = c->all_connections_prev; + } + + si->num_connections--; +} + +/* + * sfe_ipv6_gen_sync_connection() + * Sync a connection. + * + * On entry to this function we expect that the lock for the connection is either + * already held or isn't required. + */ +static void sfe_ipv6_gen_sync_connection(struct sfe_ipv6 *si, struct sfe_ipv6_connection *c, + struct sfe_connection_sync *sis, sfe_sync_reason_t reason, + u64 now_jiffies) +{ + struct sfe_ipv6_connection_match *original_cm; + struct sfe_ipv6_connection_match *reply_cm; + + /* + * Fill in the update message. + */ + sis->is_v6 = 1; + sis->protocol = c->protocol; + sis->src_ip.ip6[0] = c->src_ip[0]; + sis->src_ip_xlate.ip6[0] = c->src_ip_xlate[0]; + sis->dest_ip.ip6[0] = c->dest_ip[0]; + sis->dest_ip_xlate.ip6[0] = c->dest_ip_xlate[0]; + sis->src_port = c->src_port; + sis->src_port_xlate = c->src_port_xlate; + sis->dest_port = c->dest_port; + sis->dest_port_xlate = c->dest_port_xlate; + + original_cm = c->original_match; + reply_cm = c->reply_match; + sis->src_td_max_window = original_cm->protocol_state.tcp.max_win; + sis->src_td_end = original_cm->protocol_state.tcp.end; + sis->src_td_max_end = original_cm->protocol_state.tcp.max_end; + sis->dest_td_max_window = reply_cm->protocol_state.tcp.max_win; + sis->dest_td_end = reply_cm->protocol_state.tcp.end; + sis->dest_td_max_end = reply_cm->protocol_state.tcp.max_end; + + sis->src_new_packet_count = original_cm->rx_packet_count; + sis->src_new_byte_count = original_cm->rx_byte_count; + sis->dest_new_packet_count = reply_cm->rx_packet_count; + sis->dest_new_byte_count = reply_cm->rx_byte_count; + + sfe_ipv6_connection_match_update_summary_stats(original_cm); + sfe_ipv6_connection_match_update_summary_stats(reply_cm); + + sis->src_dev = original_cm->match_dev; + sis->src_packet_count = original_cm->rx_packet_count64; + sis->src_byte_count = original_cm->rx_byte_count64; + + sis->dest_dev = reply_cm->match_dev; + sis->dest_packet_count = reply_cm->rx_packet_count64; + sis->dest_byte_count = reply_cm->rx_byte_count64; + + sis->reason = reason; + + /* + * Get the time increment since our last sync. + */ + sis->delta_jiffies = now_jiffies - c->last_sync_jiffies; + c->last_sync_jiffies = now_jiffies; +} + +/* + * sfe_ipv6_flush_connection() + * Flush a connection and free all associated resources. + * + * We need to be called with bottom halves disabled locally as we need to acquire + * the connection hash lock and release it again. In general we're actually called + * from within a BH and so we're fine, but we're also called when connections are + * torn down. + */ +static void sfe_ipv6_flush_connection(struct sfe_ipv6 *si, + struct sfe_ipv6_connection *c, + sfe_sync_reason_t reason) +{ + struct sfe_connection_sync sis; + u64 now_jiffies; + sfe_sync_rule_callback_t sync_rule_callback; + + rcu_read_lock(); + spin_lock_bh(&si->lock); + si->connection_flushes++; + sync_rule_callback = rcu_dereference(si->sync_rule_callback); + spin_unlock_bh(&si->lock); + + if (sync_rule_callback) { + /* + * Generate a sync message and then sync. + */ + now_jiffies = get_jiffies_64(); + sfe_ipv6_gen_sync_connection(si, c, &sis, reason, now_jiffies); + sync_rule_callback(&sis); + } + + rcu_read_unlock(); + + /* + * Release our hold of the source and dest devices and free the memory + * for our connection objects. + */ + dev_put(c->original_dev); + dev_put(c->reply_dev); + kfree(c->original_match); + kfree(c->reply_match); + kfree(c); +} + +/* + * sfe_ipv6_recv_udp() + * Handle UDP packet receives and forwarding. + */ +static int sfe_ipv6_recv_udp(struct sfe_ipv6 *si, struct sk_buff *skb, struct net_device *dev, + unsigned int len, struct sfe_ipv6_ip_hdr *iph, unsigned int ihl, bool flush_on_find) +{ + struct sfe_ipv6_udp_hdr *udph; + struct sfe_ipv6_addr *src_ip; + struct sfe_ipv6_addr *dest_ip; + __be16 src_port; + __be16 dest_port; + struct sfe_ipv6_connection_match *cm; + struct net_device *xmit_dev; + + /* + * Is our packet too short to contain a valid UDP header? + */ + if (!pskb_may_pull(skb, (sizeof(struct sfe_ipv6_udp_hdr) + ihl))) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_UDP_HEADER_INCOMPLETE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("packet too short for UDP header\n"); + return 0; + } + + /* + * Read the IP address and port information. Read the IP header data first + * because we've almost certainly got that in the cache. We may not yet have + * the UDP header cached though so allow more time for any prefetching. + */ + src_ip = &iph->saddr; + dest_ip = &iph->daddr; + + udph = (struct sfe_ipv6_udp_hdr *)(skb->data + ihl); + src_port = udph->source; + dest_port = udph->dest; + + spin_lock_bh(&si->lock); + + /* + * Look for a connection match. + */ +#ifdef CONFIG_NF_FLOW_COOKIE + cm = si->sfe_flow_cookie_table[skb->flow_cookie & SFE_FLOW_COOKIE_MASK].match; + if (unlikely(!cm)) { + cm = sfe_ipv6_find_connection_match(si, dev, IPPROTO_UDP, src_ip, src_port, dest_ip, dest_port); + } +#else + cm = sfe_ipv6_find_connection_match(si, dev, IPPROTO_UDP, src_ip, src_port, dest_ip, dest_port); +#endif + if (unlikely(!cm)) { + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_UDP_NO_CONNECTION]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("no connection found\n"); + return 0; + } + + /* + * If our packet has beern marked as "flush on find" we can't actually + * forward it in the fast path, but now that we've found an associated + * connection we can flush that out before we process the packet. + */ + if (unlikely(flush_on_find)) { + struct sfe_ipv6_connection *c = cm->connection; + sfe_ipv6_remove_connection(si, c); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_UDP_IP_OPTIONS_OR_INITIAL_FRAGMENT]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("flush on find\n"); + sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + +#ifdef CONFIG_XFRM + /* + * We can't accelerate the flow on this direction, just let it go + * through the slow path. + */ + if (unlikely(!cm->flow_accel)) { + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + return 0; + } +#endif + + /* + * Does our hop_limit allow forwarding? + */ + if (unlikely(iph->hop_limit < 2)) { + struct sfe_ipv6_connection *c = cm->connection; + sfe_ipv6_remove_connection(si, c); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_UDP_SMALL_TTL]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("hop_limit too low\n"); + sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + /* + * If our packet is larger than the MTU of the transmit interface then + * we can't forward it easily. + */ + if (unlikely(len > cm->xmit_dev_mtu)) { + struct sfe_ipv6_connection *c = cm->connection; + sfe_ipv6_remove_connection(si, c); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_UDP_NEEDS_FRAGMENTATION]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("larger than mtu\n"); + sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + /* + * From this point on we're good to modify the packet. + */ + + /* + * Check if skb was cloned. If it was, unshare it. Because + * the data area is going to be written in this path and we don't want to + * change the cloned skb's data section. + */ + if (unlikely(skb_cloned(skb))) { + DEBUG_TRACE("%px: skb is a cloned skb\n", skb); + skb = skb_unshare(skb, GFP_ATOMIC); + if (!skb) { + DEBUG_WARN("Failed to unshare the cloned skb\n"); + return 0; + } + + /* + * Update the iph and udph pointers with the unshared skb's data area. + */ + iph = (struct sfe_ipv6_ip_hdr *)skb->data; + udph = (struct sfe_ipv6_udp_hdr *)(skb->data + ihl); + } + + /* + * Update DSCP + */ + if (unlikely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_DSCP_REMARK)) { + sfe_ipv6_change_dsfield(iph, cm->dscp); + } + + /* + * Decrement our hop_limit. + */ + iph->hop_limit -= 1; + + /* + * Do we have to perform translations of the source address/port? + */ + if (unlikely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_XLATE_SRC)) { + u16 udp_csum; + + iph->saddr = cm->xlate_src_ip[0]; + udph->source = cm->xlate_src_port; + + /* + * Do we have a non-zero UDP checksum? If we do then we need + * to update it. + */ + udp_csum = udph->check; + if (likely(udp_csum)) { + u32 sum = udp_csum + cm->xlate_src_csum_adjustment; + sum = (sum & 0xffff) + (sum >> 16); + udph->check = (u16)sum; + } + } + + /* + * Do we have to perform translations of the destination address/port? + */ + if (unlikely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_XLATE_DEST)) { + u16 udp_csum; + + iph->daddr = cm->xlate_dest_ip[0]; + udph->dest = cm->xlate_dest_port; + + /* + * Do we have a non-zero UDP checksum? If we do then we need + * to update it. + */ + udp_csum = udph->check; + if (likely(udp_csum)) { + u32 sum = udp_csum + cm->xlate_dest_csum_adjustment; + sum = (sum & 0xffff) + (sum >> 16); + udph->check = (u16)sum; + } + } + + /* + * Update traffic stats. + */ + cm->rx_packet_count++; + cm->rx_byte_count += len; + + /* + * If we're not already on the active list then insert ourselves at the tail + * of the current list. + */ + if (unlikely(!cm->active)) { + cm->active = true; + cm->active_prev = si->active_tail; + if (likely(si->active_tail)) { + si->active_tail->active_next = cm; + } else { + si->active_head = cm; + } + si->active_tail = cm; + } + + xmit_dev = cm->xmit_dev; + skb->dev = xmit_dev; + + /* + * Check to see if we need to write a header. + */ + if (likely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_WRITE_L2_HDR)) { + if (unlikely(!(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_WRITE_FAST_ETH_HDR))) { + dev_hard_header(skb, xmit_dev, ETH_P_IPV6, + cm->xmit_dest_mac, cm->xmit_src_mac, len); + } else { + /* + * For the simple case we write this really fast. + */ + struct sfe_ipv6_eth_hdr *eth = (struct sfe_ipv6_eth_hdr *)__skb_push(skb, ETH_HLEN); + eth->h_proto = htons(ETH_P_IPV6); + eth->h_dest[0] = cm->xmit_dest_mac[0]; + eth->h_dest[1] = cm->xmit_dest_mac[1]; + eth->h_dest[2] = cm->xmit_dest_mac[2]; + eth->h_source[0] = cm->xmit_src_mac[0]; + eth->h_source[1] = cm->xmit_src_mac[1]; + eth->h_source[2] = cm->xmit_src_mac[2]; + } + } + + /* + * Update priority of skb. + */ + if (unlikely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_PRIORITY_REMARK)) { + skb->priority = cm->priority; + } + + /* + * Mark outgoing packet. + */ + skb->mark = cm->connection->mark; + if (skb->mark) { + DEBUG_TRACE("SKB MARK is NON ZERO %x\n", skb->mark); + } + + si->packets_forwarded++; + spin_unlock_bh(&si->lock); + + /* + * We're going to check for GSO flags when we transmit the packet so + * start fetching the necessary cache line now. + */ + prefetch(skb_shinfo(skb)); + + /* + * Mark that this packet has been fast forwarded. + */ + skb->fast_forwarded = 1; + + /* + * Send the packet on its way. + */ + dev_queue_xmit(skb); + + return 1; +} + +/* + * sfe_ipv6_process_tcp_option_sack() + * Parse TCP SACK option and update ack according + */ +static bool sfe_ipv6_process_tcp_option_sack(const struct sfe_ipv6_tcp_hdr *th, const u32 data_offs, + u32 *ack) +{ + u32 length = sizeof(struct sfe_ipv6_tcp_hdr); + u8 *ptr = (u8 *)th + length; + + /* + * Ignore processing if TCP packet has only TIMESTAMP option. + */ + if (likely(data_offs == length + TCPOLEN_TIMESTAMP + 1 + 1) + && likely(ptr[0] == TCPOPT_NOP) + && likely(ptr[1] == TCPOPT_NOP) + && likely(ptr[2] == TCPOPT_TIMESTAMP) + && likely(ptr[3] == TCPOLEN_TIMESTAMP)) { + return true; + } + + /* + * TCP options. Parse SACK option. + */ + while (length < data_offs) { + u8 size; + u8 kind; + + ptr = (u8 *)th + length; + kind = *ptr; + + /* + * NOP, for padding + * Not in the switch because to fast escape and to not calculate size + */ + if (kind == TCPOPT_NOP) { + length++; + continue; + } + + if (kind == TCPOPT_SACK) { + u32 sack = 0; + u8 re = 1 + 1; + + size = *(ptr + 1); + if ((size < (1 + 1 + TCPOLEN_SACK_PERBLOCK)) + || ((size - (1 + 1)) % (TCPOLEN_SACK_PERBLOCK)) + || (size > (data_offs - length))) { + return false; + } + + re += 4; + while (re < size) { + u32 sack_re; + u8 *sptr = ptr + re; + sack_re = (sptr[0] << 24) | (sptr[1] << 16) | (sptr[2] << 8) | sptr[3]; + if (sack_re > sack) { + sack = sack_re; + } + re += TCPOLEN_SACK_PERBLOCK; + } + if (sack > *ack) { + *ack = sack; + } + length += size; + continue; + } + if (kind == TCPOPT_EOL) { + return true; + } + size = *(ptr + 1); + if (size < 2) { + return false; + } + length += size; + } + + return true; +} + +/* + * sfe_ipv6_recv_tcp() + * Handle TCP packet receives and forwarding. + */ +static int sfe_ipv6_recv_tcp(struct sfe_ipv6 *si, struct sk_buff *skb, struct net_device *dev, + unsigned int len, struct sfe_ipv6_ip_hdr *iph, unsigned int ihl, bool flush_on_find) +{ + struct sfe_ipv6_tcp_hdr *tcph; + struct sfe_ipv6_addr *src_ip; + struct sfe_ipv6_addr *dest_ip; + __be16 src_port; + __be16 dest_port; + struct sfe_ipv6_connection_match *cm; + struct sfe_ipv6_connection_match *counter_cm; + u32 flags; + struct net_device *xmit_dev; + + /* + * Is our packet too short to contain a valid UDP header? + */ + if (!pskb_may_pull(skb, (sizeof(struct sfe_ipv6_tcp_hdr) + ihl))) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_TCP_HEADER_INCOMPLETE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("packet too short for TCP header\n"); + return 0; + } + + /* + * Read the IP address and port information. Read the IP header data first + * because we've almost certainly got that in the cache. We may not yet have + * the TCP header cached though so allow more time for any prefetching. + */ + src_ip = &iph->saddr; + dest_ip = &iph->daddr; + + tcph = (struct sfe_ipv6_tcp_hdr *)(skb->data + ihl); + src_port = tcph->source; + dest_port = tcph->dest; + flags = tcp_flag_word(tcph); + + spin_lock_bh(&si->lock); + + /* + * Look for a connection match. + */ +#ifdef CONFIG_NF_FLOW_COOKIE + cm = si->sfe_flow_cookie_table[skb->flow_cookie & SFE_FLOW_COOKIE_MASK].match; + if (unlikely(!cm)) { + cm = sfe_ipv6_find_connection_match(si, dev, IPPROTO_TCP, src_ip, src_port, dest_ip, dest_port); + } +#else + cm = sfe_ipv6_find_connection_match(si, dev, IPPROTO_TCP, src_ip, src_port, dest_ip, dest_port); +#endif + if (unlikely(!cm)) { + /* + * We didn't get a connection but as TCP is connection-oriented that + * may be because this is a non-fast connection (not running established). + * For diagnostic purposes we differentiate this here. + */ + if (likely((flags & (TCP_FLAG_SYN | TCP_FLAG_RST | TCP_FLAG_FIN | TCP_FLAG_ACK)) == TCP_FLAG_ACK)) { + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_TCP_NO_CONNECTION_FAST_FLAGS]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("no connection found - fast flags\n"); + return 0; + } + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_TCP_NO_CONNECTION_SLOW_FLAGS]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("no connection found - slow flags: 0x%x\n", + flags & (TCP_FLAG_SYN | TCP_FLAG_RST | TCP_FLAG_FIN | TCP_FLAG_ACK)); + return 0; + } + + /* + * If our packet has beern marked as "flush on find" we can't actually + * forward it in the fast path, but now that we've found an associated + * connection we can flush that out before we process the packet. + */ + if (unlikely(flush_on_find)) { + struct sfe_ipv6_connection *c = cm->connection; + sfe_ipv6_remove_connection(si, c); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_TCP_IP_OPTIONS_OR_INITIAL_FRAGMENT]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("flush on find\n"); + sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + +#ifdef CONFIG_XFRM + /* + * We can't accelerate the flow on this direction, just let it go + * through the slow path. + */ + if (unlikely(!cm->flow_accel)) { + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + return 0; + } +#endif + + /* + * Does our hop_limit allow forwarding? + */ + if (unlikely(iph->hop_limit < 2)) { + struct sfe_ipv6_connection *c = cm->connection; + sfe_ipv6_remove_connection(si, c); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_TCP_SMALL_TTL]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("hop_limit too low\n"); + sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + /* + * If our packet is larger than the MTU of the transmit interface then + * we can't forward it easily. + */ + if (unlikely((len > cm->xmit_dev_mtu) && !skb_is_gso(skb))) { + struct sfe_ipv6_connection *c = cm->connection; + sfe_ipv6_remove_connection(si, c); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_TCP_NEEDS_FRAGMENTATION]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("larger than mtu\n"); + sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + /* + * Look at our TCP flags. Anything missing an ACK or that has RST, SYN or FIN + * set is not a fast path packet. + */ + if (unlikely((flags & (TCP_FLAG_SYN | TCP_FLAG_RST | TCP_FLAG_FIN | TCP_FLAG_ACK)) != TCP_FLAG_ACK)) { + struct sfe_ipv6_connection *c = cm->connection; + sfe_ipv6_remove_connection(si, c); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_TCP_FLAGS]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("TCP flags: 0x%x are not fast\n", + flags & (TCP_FLAG_SYN | TCP_FLAG_RST | TCP_FLAG_FIN | TCP_FLAG_ACK)); + sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + counter_cm = cm->counter_match; + + /* + * Are we doing sequence number checking? + */ + if (likely(!(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK))) { + u32 seq; + u32 ack; + u32 sack; + u32 data_offs; + u32 end; + u32 left_edge; + u32 scaled_win; + u32 max_end; + + /* + * Is our sequence fully past the right hand edge of the window? + */ + seq = ntohl(tcph->seq); + if (unlikely((s32)(seq - (cm->protocol_state.tcp.max_end + 1)) > 0)) { + struct sfe_ipv6_connection *c = cm->connection; + sfe_ipv6_remove_connection(si, c); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_TCP_SEQ_EXCEEDS_RIGHT_EDGE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("seq: %u exceeds right edge: %u\n", + seq, cm->protocol_state.tcp.max_end + 1); + sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + /* + * Check that our TCP data offset isn't too short. + */ + data_offs = tcph->doff << 2; + if (unlikely(data_offs < sizeof(struct sfe_ipv6_tcp_hdr))) { + struct sfe_ipv6_connection *c = cm->connection; + sfe_ipv6_remove_connection(si, c); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_TCP_SMALL_DATA_OFFS]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("TCP data offset: %u, too small\n", data_offs); + sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + /* + * Update ACK according to any SACK option. + */ + ack = ntohl(tcph->ack_seq); + sack = ack; + if (unlikely(!sfe_ipv6_process_tcp_option_sack(tcph, data_offs, &sack))) { + struct sfe_ipv6_connection *c = cm->connection; + sfe_ipv6_remove_connection(si, c); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_TCP_BAD_SACK]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("TCP option SACK size is wrong\n"); + sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + /* + * Check that our TCP data offset isn't past the end of the packet. + */ + data_offs += sizeof(struct sfe_ipv6_ip_hdr); + if (unlikely(len < data_offs)) { + struct sfe_ipv6_connection *c = cm->connection; + sfe_ipv6_remove_connection(si, c); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_TCP_BIG_DATA_OFFS]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("TCP data offset: %u, past end of packet: %u\n", + data_offs, len); + sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + end = seq + len - data_offs; + + /* + * Is our sequence fully before the left hand edge of the window? + */ + if (unlikely((s32)(end - (cm->protocol_state.tcp.end + - counter_cm->protocol_state.tcp.max_win - 1)) < 0)) { + struct sfe_ipv6_connection *c = cm->connection; + sfe_ipv6_remove_connection(si, c); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_TCP_SEQ_BEFORE_LEFT_EDGE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("seq: %u before left edge: %u\n", + end, cm->protocol_state.tcp.end - counter_cm->protocol_state.tcp.max_win - 1); + sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + /* + * Are we acking data that is to the right of what has been sent? + */ + if (unlikely((s32)(sack - (counter_cm->protocol_state.tcp.end + 1)) > 0)) { + struct sfe_ipv6_connection *c = cm->connection; + sfe_ipv6_remove_connection(si, c); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_TCP_ACK_EXCEEDS_RIGHT_EDGE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("ack: %u exceeds right edge: %u\n", + sack, counter_cm->protocol_state.tcp.end + 1); + sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + /* + * Is our ack too far before the left hand edge of the window? + */ + left_edge = counter_cm->protocol_state.tcp.end + - cm->protocol_state.tcp.max_win + - SFE_IPV6_TCP_MAX_ACK_WINDOW + - 1; + if (unlikely((s32)(sack - left_edge) < 0)) { + struct sfe_ipv6_connection *c = cm->connection; + sfe_ipv6_remove_connection(si, c); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_TCP_ACK_BEFORE_LEFT_EDGE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("ack: %u before left edge: %u\n", sack, left_edge); + sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; + } + + /* + * Have we just seen the largest window size yet for this connection? If yes + * then we need to record the new value. + */ + scaled_win = ntohs(tcph->window) << cm->protocol_state.tcp.win_scale; + scaled_win += (sack - ack); + if (unlikely(cm->protocol_state.tcp.max_win < scaled_win)) { + cm->protocol_state.tcp.max_win = scaled_win; + } + + /* + * If our sequence and/or ack numbers have advanced then record the new state. + */ + if (likely((s32)(end - cm->protocol_state.tcp.end) >= 0)) { + cm->protocol_state.tcp.end = end; + } + + max_end = sack + scaled_win; + if (likely((s32)(max_end - counter_cm->protocol_state.tcp.max_end) >= 0)) { + counter_cm->protocol_state.tcp.max_end = max_end; + } + } + + /* + * From this point on we're good to modify the packet. + */ + + /* + * Check if skb was cloned. If it was, unshare it. Because + * the data area is going to be written in this path and we don't want to + * change the cloned skb's data section. + */ + if (unlikely(skb_cloned(skb))) { + DEBUG_TRACE("%px: skb is a cloned skb\n", skb); + skb = skb_unshare(skb, GFP_ATOMIC); + if (!skb) { + DEBUG_WARN("Failed to unshare the cloned skb\n"); + return 0; + } + + /* + * Update the iph and tcph pointers with the unshared skb's data area. + */ + iph = (struct sfe_ipv6_ip_hdr *)skb->data; + tcph = (struct sfe_ipv6_tcp_hdr *)(skb->data + ihl); + } + + /* + * Update DSCP + */ + if (unlikely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_DSCP_REMARK)) { + sfe_ipv6_change_dsfield(iph, cm->dscp); + } + + /* + * Decrement our hop_limit. + */ + iph->hop_limit -= 1; + + /* + * Do we have to perform translations of the source address/port? + */ + if (unlikely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_XLATE_SRC)) { + u16 tcp_csum; + u32 sum; + + iph->saddr = cm->xlate_src_ip[0]; + tcph->source = cm->xlate_src_port; + + /* + * Do we have a non-zero UDP checksum? If we do then we need + * to update it. + */ + tcp_csum = tcph->check; + sum = tcp_csum + cm->xlate_src_csum_adjustment; + sum = (sum & 0xffff) + (sum >> 16); + tcph->check = (u16)sum; + } + + /* + * Do we have to perform translations of the destination address/port? + */ + if (unlikely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_XLATE_DEST)) { + u16 tcp_csum; + u32 sum; + + iph->daddr = cm->xlate_dest_ip[0]; + tcph->dest = cm->xlate_dest_port; + + /* + * Do we have a non-zero UDP checksum? If we do then we need + * to update it. + */ + tcp_csum = tcph->check; + sum = tcp_csum + cm->xlate_dest_csum_adjustment; + sum = (sum & 0xffff) + (sum >> 16); + tcph->check = (u16)sum; + } + + /* + * Update traffic stats. + */ + cm->rx_packet_count++; + cm->rx_byte_count += len; + + /* + * If we're not already on the active list then insert ourselves at the tail + * of the current list. + */ + if (unlikely(!cm->active)) { + cm->active = true; + cm->active_prev = si->active_tail; + if (likely(si->active_tail)) { + si->active_tail->active_next = cm; + } else { + si->active_head = cm; + } + si->active_tail = cm; + } + + xmit_dev = cm->xmit_dev; + skb->dev = xmit_dev; + + /* + * Check to see if we need to write a header. + */ + if (likely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_WRITE_L2_HDR)) { + if (unlikely(!(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_WRITE_FAST_ETH_HDR))) { + dev_hard_header(skb, xmit_dev, ETH_P_IPV6, + cm->xmit_dest_mac, cm->xmit_src_mac, len); + } else { + /* + * For the simple case we write this really fast. + */ + struct sfe_ipv6_eth_hdr *eth = (struct sfe_ipv6_eth_hdr *)__skb_push(skb, ETH_HLEN); + eth->h_proto = htons(ETH_P_IPV6); + eth->h_dest[0] = cm->xmit_dest_mac[0]; + eth->h_dest[1] = cm->xmit_dest_mac[1]; + eth->h_dest[2] = cm->xmit_dest_mac[2]; + eth->h_source[0] = cm->xmit_src_mac[0]; + eth->h_source[1] = cm->xmit_src_mac[1]; + eth->h_source[2] = cm->xmit_src_mac[2]; + } + } + + /* + * Update priority of skb. + */ + if (unlikely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_PRIORITY_REMARK)) { + skb->priority = cm->priority; + } + + /* + * Mark outgoing packet + */ + skb->mark = cm->connection->mark; + if (skb->mark) { + DEBUG_TRACE("SKB MARK is NON ZERO %x\n", skb->mark); + } + + si->packets_forwarded++; + spin_unlock_bh(&si->lock); + + /* + * We're going to check for GSO flags when we transmit the packet so + * start fetching the necessary cache line now. + */ + prefetch(skb_shinfo(skb)); + + /* + * Mark that this packet has been fast forwarded. + */ + skb->fast_forwarded = 1; + + /* + * Send the packet on its way. + */ + dev_queue_xmit(skb); + + return 1; +} + +/* + * sfe_ipv6_recv_icmp() + * Handle ICMP packet receives. + * + * ICMP packets aren't handled as a "fast path" and always have us process them + * through the default Linux stack. What we do need to do is look for any errors + * about connections we are handling in the fast path. If we find any such + * connections then we want to flush their state so that the ICMP error path + * within Linux has all of the correct state should it need it. + */ +static int sfe_ipv6_recv_icmp(struct sfe_ipv6 *si, struct sk_buff *skb, struct net_device *dev, + unsigned int len, struct sfe_ipv6_ip_hdr *iph, unsigned int ihl) +{ + struct icmp6hdr *icmph; + struct sfe_ipv6_ip_hdr *icmp_iph; + struct sfe_ipv6_udp_hdr *icmp_udph; + struct sfe_ipv6_tcp_hdr *icmp_tcph; + struct sfe_ipv6_addr *src_ip; + struct sfe_ipv6_addr *dest_ip; + __be16 src_port; + __be16 dest_port; + struct sfe_ipv6_connection_match *cm; + struct sfe_ipv6_connection *c; + u8 next_hdr; + + /* + * Is our packet too short to contain a valid ICMP header? + */ + len -= ihl; + if (!pskb_may_pull(skb, ihl + sizeof(struct icmp6hdr))) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_ICMP_HEADER_INCOMPLETE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("packet too short for ICMP header\n"); + return 0; + } + + /* + * We only handle "destination unreachable" and "time exceeded" messages. + */ + icmph = (struct icmp6hdr *)(skb->data + ihl); + if ((icmph->icmp6_type != ICMPV6_DEST_UNREACH) + && (icmph->icmp6_type != ICMPV6_TIME_EXCEED)) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_ICMP_UNHANDLED_TYPE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("unhandled ICMP type: 0x%x\n", icmph->icmp6_type); + return 0; + } + + /* + * Do we have the full embedded IP header? + * We should have 8 bytes of next L4 header - that's enough to identify + * the connection. + */ + len -= sizeof(struct icmp6hdr); + ihl += sizeof(struct icmp6hdr); + if (!pskb_may_pull(skb, ihl + sizeof(struct sfe_ipv6_ip_hdr) + sizeof(struct sfe_ipv6_ext_hdr))) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_ICMP_IPV6_HEADER_INCOMPLETE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("Embedded IP header not complete\n"); + return 0; + } + + /* + * Is our embedded IP version wrong? + */ + icmp_iph = (struct sfe_ipv6_ip_hdr *)(icmph + 1); + if (unlikely(icmp_iph->version != 6)) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_ICMP_IPV6_NON_V6]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("IP version: %u\n", icmp_iph->version); + return 0; + } + + len -= sizeof(struct sfe_ipv6_ip_hdr); + ihl += sizeof(struct sfe_ipv6_ip_hdr); + next_hdr = icmp_iph->nexthdr; + while (unlikely(sfe_ipv6_is_ext_hdr(next_hdr))) { + struct sfe_ipv6_ext_hdr *ext_hdr; + unsigned int ext_hdr_len; + + ext_hdr = (struct sfe_ipv6_ext_hdr *)(skb->data + ihl); + if (next_hdr == SFE_IPV6_EXT_HDR_FRAG) { + struct sfe_ipv6_frag_hdr *frag_hdr = (struct sfe_ipv6_frag_hdr *)ext_hdr; + unsigned int frag_off = ntohs(frag_hdr->frag_off); + + if (frag_off & SFE_IPV6_FRAG_OFFSET) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_NON_INITIAL_FRAGMENT]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("non-initial fragment\n"); + return 0; + } + } + + ext_hdr_len = ext_hdr->hdr_len; + ext_hdr_len <<= 3; + ext_hdr_len += sizeof(struct sfe_ipv6_ext_hdr); + len -= ext_hdr_len; + ihl += ext_hdr_len; + /* + * We should have 8 bytes of next header - that's enough to identify + * the connection. + */ + if (!pskb_may_pull(skb, ihl + sizeof(struct sfe_ipv6_ext_hdr))) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_HEADER_INCOMPLETE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("extension header %d not completed\n", next_hdr); + return 0; + } + + next_hdr = ext_hdr->next_hdr; + } + + /* + * Handle the embedded transport layer header. + */ + switch (next_hdr) { + case IPPROTO_UDP: + icmp_udph = (struct sfe_ipv6_udp_hdr *)(skb->data + ihl); + src_port = icmp_udph->source; + dest_port = icmp_udph->dest; + break; + + case IPPROTO_TCP: + icmp_tcph = (struct sfe_ipv6_tcp_hdr *)(skb->data + ihl); + src_port = icmp_tcph->source; + dest_port = icmp_tcph->dest; + break; + + default: + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_ICMP_IPV6_UNHANDLED_PROTOCOL]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("Unhandled embedded IP protocol: %u\n", next_hdr); + return 0; + } + + src_ip = &icmp_iph->saddr; + dest_ip = &icmp_iph->daddr; + + spin_lock_bh(&si->lock); + + /* + * Look for a connection match. Note that we reverse the source and destination + * here because our embedded message contains a packet that was sent in the + * opposite direction to the one in which we just received it. It will have + * been sent on the interface from which we received it though so that's still + * ok to use. + */ + cm = sfe_ipv6_find_connection_match(si, dev, icmp_iph->nexthdr, dest_ip, dest_port, src_ip, src_port); + if (unlikely(!cm)) { + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_ICMP_NO_CONNECTION]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("no connection found\n"); + return 0; + } + + /* + * We found a connection so now remove it from the connection list and flush + * its state. + */ + c = cm->connection; + sfe_ipv6_remove_connection(si, c); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_ICMP_FLUSHED_CONNECTION]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH); + return 0; +} + +/* + * sfe_ipv6_recv() + * Handle packet receives and forwaring. + * + * Returns 1 if the packet is forwarded or 0 if it isn't. + */ +int sfe_ipv6_recv(struct net_device *dev, struct sk_buff *skb) +{ + struct sfe_ipv6 *si = &__si6; + unsigned int len; + unsigned int payload_len; + unsigned int ihl = sizeof(struct sfe_ipv6_ip_hdr); + bool flush_on_find = false; + struct sfe_ipv6_ip_hdr *iph; + u8 next_hdr; + + /* + * Check that we have space for an IP header and an uplayer header here. + */ + len = skb->len; + if (!pskb_may_pull(skb, ihl + sizeof(struct sfe_ipv6_ext_hdr))) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_HEADER_INCOMPLETE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("len: %u is too short\n", len); + return 0; + } + + /* + * Is our IP version wrong? + */ + iph = (struct sfe_ipv6_ip_hdr *)skb->data; + if (unlikely(iph->version != 6)) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_NON_V6]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("IP version: %u\n", iph->version); + return 0; + } + + /* + * Does our datagram fit inside the skb? + */ + payload_len = ntohs(iph->payload_len); + if (unlikely(payload_len > (len - ihl))) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_DATAGRAM_INCOMPLETE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("payload_len: %u, exceeds len: %u\n", payload_len, (len - (unsigned int)sizeof(struct sfe_ipv6_ip_hdr))); + return 0; + } + + next_hdr = iph->nexthdr; + while (unlikely(sfe_ipv6_is_ext_hdr(next_hdr))) { + struct sfe_ipv6_ext_hdr *ext_hdr; + unsigned int ext_hdr_len; + + ext_hdr = (struct sfe_ipv6_ext_hdr *)(skb->data + ihl); + if (next_hdr == SFE_IPV6_EXT_HDR_FRAG) { + struct sfe_ipv6_frag_hdr *frag_hdr = (struct sfe_ipv6_frag_hdr *)ext_hdr; + unsigned int frag_off = ntohs(frag_hdr->frag_off); + + if (frag_off & SFE_IPV6_FRAG_OFFSET) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_NON_INITIAL_FRAGMENT]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("non-initial fragment\n"); + return 0; + } + } + + ext_hdr_len = ext_hdr->hdr_len; + ext_hdr_len <<= 3; + ext_hdr_len += sizeof(struct sfe_ipv6_ext_hdr); + ihl += ext_hdr_len; + if (!pskb_may_pull(skb, ihl + sizeof(struct sfe_ipv6_ext_hdr))) { + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_HEADER_INCOMPLETE]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("extension header %d not completed\n", next_hdr); + return 0; + } + + flush_on_find = true; + next_hdr = ext_hdr->next_hdr; + } + + if (IPPROTO_UDP == next_hdr) { + return sfe_ipv6_recv_udp(si, skb, dev, len, iph, ihl, flush_on_find); + } + + if (IPPROTO_TCP == next_hdr) { + return sfe_ipv6_recv_tcp(si, skb, dev, len, iph, ihl, flush_on_find); + } + + if (IPPROTO_ICMPV6 == next_hdr) { + return sfe_ipv6_recv_icmp(si, skb, dev, len, iph, ihl); + } + + spin_lock_bh(&si->lock); + si->exception_events[SFE_IPV6_EXCEPTION_EVENT_UNHANDLED_PROTOCOL]++; + si->packets_not_forwarded++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("not UDP, TCP or ICMP: %u\n", next_hdr); + return 0; +} + +/* + * sfe_ipv6_update_tcp_state() + * update TCP window variables. + */ +static void +sfe_ipv6_update_tcp_state(struct sfe_ipv6_connection *c, + struct sfe_connection_create *sic) +{ + struct sfe_ipv6_connection_match *orig_cm; + struct sfe_ipv6_connection_match *repl_cm; + struct sfe_ipv6_tcp_connection_match *orig_tcp; + struct sfe_ipv6_tcp_connection_match *repl_tcp; + + orig_cm = c->original_match; + repl_cm = c->reply_match; + orig_tcp = &orig_cm->protocol_state.tcp; + repl_tcp = &repl_cm->protocol_state.tcp; + + /* update orig */ + if (orig_tcp->max_win < sic->src_td_max_window) { + orig_tcp->max_win = sic->src_td_max_window; + } + if ((s32)(orig_tcp->end - sic->src_td_end) < 0) { + orig_tcp->end = sic->src_td_end; + } + if ((s32)(orig_tcp->max_end - sic->src_td_max_end) < 0) { + orig_tcp->max_end = sic->src_td_max_end; + } + + /* update reply */ + if (repl_tcp->max_win < sic->dest_td_max_window) { + repl_tcp->max_win = sic->dest_td_max_window; + } + if ((s32)(repl_tcp->end - sic->dest_td_end) < 0) { + repl_tcp->end = sic->dest_td_end; + } + if ((s32)(repl_tcp->max_end - sic->dest_td_max_end) < 0) { + repl_tcp->max_end = sic->dest_td_max_end; + } + + /* update match flags */ + orig_cm->flags &= ~SFE_IPV6_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK; + repl_cm->flags &= ~SFE_IPV6_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK; + if (sic->flags & SFE_CREATE_FLAG_NO_SEQ_CHECK) { + orig_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK; + repl_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK; + } +} + +/* + * sfe_ipv6_update_protocol_state() + * update protocol specified state machine. + */ +static void +sfe_ipv6_update_protocol_state(struct sfe_ipv6_connection *c, + struct sfe_connection_create *sic) +{ + switch (sic->protocol) { + case IPPROTO_TCP: + sfe_ipv6_update_tcp_state(c, sic); + break; + } +} + +/* + * sfe_ipv6_update_rule() + * update forwarding rule after rule is created. + */ +void sfe_ipv6_update_rule(struct sfe_connection_create *sic) +{ + struct sfe_ipv6_connection *c; + struct sfe_ipv6 *si = &__si6; + + spin_lock_bh(&si->lock); + + c = sfe_ipv6_find_connection(si, + sic->protocol, + sic->src_ip.ip6, + sic->src_port, + sic->dest_ip.ip6, + sic->dest_port); + if (c != NULL) { + sfe_ipv6_update_protocol_state(c, sic); + } + + spin_unlock_bh(&si->lock); +} + +/* + * sfe_ipv6_create_rule() + * Create a forwarding rule. + */ +int sfe_ipv6_create_rule(struct sfe_connection_create *sic) +{ + struct sfe_ipv6 *si = &__si6; + struct sfe_ipv6_connection *c; + struct sfe_ipv6_connection_match *original_cm; + struct sfe_ipv6_connection_match *reply_cm; + struct net_device *dest_dev; + struct net_device *src_dev; + + dest_dev = sic->dest_dev; + src_dev = sic->src_dev; + + if (unlikely((dest_dev->reg_state != NETREG_REGISTERED) || + (src_dev->reg_state != NETREG_REGISTERED))) { + return -EINVAL; + } + + spin_lock_bh(&si->lock); + si->connection_create_requests++; + + /* + * Check to see if there is already a flow that matches the rule we're + * trying to create. If there is then we can't create a new one. + */ + c = sfe_ipv6_find_connection(si, + sic->protocol, + sic->src_ip.ip6, + sic->src_port, + sic->dest_ip.ip6, + sic->dest_port); + if (c != NULL) { + si->connection_create_collisions++; + + /* + * If we already have the flow then it's likely that this + * request to create the connection rule contains more + * up-to-date information. Check and update accordingly. + */ + sfe_ipv6_update_protocol_state(c, sic); + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("connection already exists - mark: %08x, p: %d\n" + " s: %s:%pxM:%pI6:%u, d: %s:%pxM:%pI6:%u\n", + sic->mark, sic->protocol, + sic->src_dev->name, sic->src_mac, sic->src_ip.ip6, ntohs(sic->src_port), + sic->dest_dev->name, sic->dest_mac, sic->dest_ip.ip6, ntohs(sic->dest_port)); + return -EADDRINUSE; + } + + /* + * Allocate the various connection tracking objects. + */ + c = (struct sfe_ipv6_connection *)kmalloc(sizeof(struct sfe_ipv6_connection), GFP_ATOMIC); + if (unlikely(!c)) { + spin_unlock_bh(&si->lock); + return -ENOMEM; + } + + original_cm = (struct sfe_ipv6_connection_match *)kmalloc(sizeof(struct sfe_ipv6_connection_match), GFP_ATOMIC); + if (unlikely(!original_cm)) { + spin_unlock_bh(&si->lock); + kfree(c); + return -ENOMEM; + } + + reply_cm = (struct sfe_ipv6_connection_match *)kmalloc(sizeof(struct sfe_ipv6_connection_match), GFP_ATOMIC); + if (unlikely(!reply_cm)) { + spin_unlock_bh(&si->lock); + kfree(original_cm); + kfree(c); + return -ENOMEM; + } + + /* + * Fill in the "original" direction connection matching object. + * Note that the transmit MAC address is "dest_mac_xlate" because + * we always know both ends of a connection by their translated + * addresses and not their public addresses. + */ + original_cm->match_dev = src_dev; + original_cm->match_protocol = sic->protocol; + original_cm->match_src_ip[0] = sic->src_ip.ip6[0]; + original_cm->match_src_port = sic->src_port; + original_cm->match_dest_ip[0] = sic->dest_ip.ip6[0]; + original_cm->match_dest_port = sic->dest_port; + original_cm->xlate_src_ip[0] = sic->src_ip_xlate.ip6[0]; + original_cm->xlate_src_port = sic->src_port_xlate; + original_cm->xlate_dest_ip[0] = sic->dest_ip_xlate.ip6[0]; + original_cm->xlate_dest_port = sic->dest_port_xlate; + original_cm->rx_packet_count = 0; + original_cm->rx_packet_count64 = 0; + original_cm->rx_byte_count = 0; + original_cm->rx_byte_count64 = 0; + original_cm->xmit_dev = dest_dev; + original_cm->xmit_dev_mtu = sic->dest_mtu; + memcpy(original_cm->xmit_src_mac, dest_dev->dev_addr, ETH_ALEN); + memcpy(original_cm->xmit_dest_mac, sic->dest_mac_xlate, ETH_ALEN); + original_cm->connection = c; + original_cm->counter_match = reply_cm; + original_cm->flags = 0; + if (sic->flags & SFE_CREATE_FLAG_REMARK_PRIORITY) { + original_cm->priority = sic->src_priority; + original_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_PRIORITY_REMARK; + } + if (sic->flags & SFE_CREATE_FLAG_REMARK_DSCP) { + original_cm->dscp = sic->src_dscp << SFE_IPV6_DSCP_SHIFT; + original_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_DSCP_REMARK; + } +#ifdef CONFIG_NF_FLOW_COOKIE + original_cm->flow_cookie = 0; +#endif +#ifdef CONFIG_XFRM + original_cm->flow_accel = sic->original_accel; +#endif + original_cm->active_next = NULL; + original_cm->active_prev = NULL; + original_cm->active = false; + + /* + * For PPP links we don't write an L2 header. For everything else we do. + */ + if (!(dest_dev->flags & IFF_POINTOPOINT)) { + original_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_WRITE_L2_HDR; + + /* + * If our dev writes Ethernet headers then we can write a really fast + * version. + */ + if (dest_dev->header_ops) { + if (dest_dev->header_ops->create == eth_header) { + original_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_WRITE_FAST_ETH_HDR; + } + } + } + + /* + * Fill in the "reply" direction connection matching object. + */ + reply_cm->match_dev = dest_dev; + reply_cm->match_protocol = sic->protocol; + reply_cm->match_src_ip[0] = sic->dest_ip_xlate.ip6[0]; + reply_cm->match_src_port = sic->dest_port_xlate; + reply_cm->match_dest_ip[0] = sic->src_ip_xlate.ip6[0]; + reply_cm->match_dest_port = sic->src_port_xlate; + reply_cm->xlate_src_ip[0] = sic->dest_ip.ip6[0]; + reply_cm->xlate_src_port = sic->dest_port; + reply_cm->xlate_dest_ip[0] = sic->src_ip.ip6[0]; + reply_cm->xlate_dest_port = sic->src_port; + reply_cm->rx_packet_count = 0; + reply_cm->rx_packet_count64 = 0; + reply_cm->rx_byte_count = 0; + reply_cm->rx_byte_count64 = 0; + reply_cm->xmit_dev = src_dev; + reply_cm->xmit_dev_mtu = sic->src_mtu; + memcpy(reply_cm->xmit_src_mac, src_dev->dev_addr, ETH_ALEN); + memcpy(reply_cm->xmit_dest_mac, sic->src_mac, ETH_ALEN); + reply_cm->connection = c; + reply_cm->counter_match = original_cm; + reply_cm->flags = 0; + if (sic->flags & SFE_CREATE_FLAG_REMARK_PRIORITY) { + reply_cm->priority = sic->dest_priority; + reply_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_PRIORITY_REMARK; + } + if (sic->flags & SFE_CREATE_FLAG_REMARK_DSCP) { + reply_cm->dscp = sic->dest_dscp << SFE_IPV6_DSCP_SHIFT; + reply_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_DSCP_REMARK; + } +#ifdef CONFIG_NF_FLOW_COOKIE + reply_cm->flow_cookie = 0; +#endif +#ifdef CONFIG_XFRM + reply_cm->flow_accel = sic->reply_accel; +#endif + reply_cm->active_next = NULL; + reply_cm->active_prev = NULL; + reply_cm->active = false; + + /* + * For PPP links we don't write an L2 header. For everything else we do. + */ + if (!(src_dev->flags & IFF_POINTOPOINT)) { + reply_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_WRITE_L2_HDR; + + /* + * If our dev writes Ethernet headers then we can write a really fast + * version. + */ + if (src_dev->header_ops) { + if (src_dev->header_ops->create == eth_header) { + reply_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_WRITE_FAST_ETH_HDR; + } + } + } + + + if (!sfe_ipv6_addr_equal(sic->dest_ip.ip6, sic->dest_ip_xlate.ip6) || sic->dest_port != sic->dest_port_xlate) { + original_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_XLATE_DEST; + reply_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_XLATE_SRC; + } + + if (!sfe_ipv6_addr_equal(sic->src_ip.ip6, sic->src_ip_xlate.ip6) || sic->src_port != sic->src_port_xlate) { + original_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_XLATE_SRC; + reply_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_XLATE_DEST; + } + + c->protocol = sic->protocol; + c->src_ip[0] = sic->src_ip.ip6[0]; + c->src_ip_xlate[0] = sic->src_ip_xlate.ip6[0]; + c->src_port = sic->src_port; + c->src_port_xlate = sic->src_port_xlate; + c->original_dev = src_dev; + c->original_match = original_cm; + c->dest_ip[0] = sic->dest_ip.ip6[0]; + c->dest_ip_xlate[0] = sic->dest_ip_xlate.ip6[0]; + c->dest_port = sic->dest_port; + c->dest_port_xlate = sic->dest_port_xlate; + c->reply_dev = dest_dev; + c->reply_match = reply_cm; + c->mark = sic->mark; + c->debug_read_seq = 0; + c->last_sync_jiffies = get_jiffies_64(); + + /* + * Take hold of our source and dest devices for the duration of the connection. + */ + dev_hold(c->original_dev); + dev_hold(c->reply_dev); + + /* + * Initialize the protocol-specific information that we track. + */ + switch (sic->protocol) { + case IPPROTO_TCP: + original_cm->protocol_state.tcp.win_scale = sic->src_td_window_scale; + original_cm->protocol_state.tcp.max_win = sic->src_td_max_window ? sic->src_td_max_window : 1; + original_cm->protocol_state.tcp.end = sic->src_td_end; + original_cm->protocol_state.tcp.max_end = sic->src_td_max_end; + reply_cm->protocol_state.tcp.win_scale = sic->dest_td_window_scale; + reply_cm->protocol_state.tcp.max_win = sic->dest_td_max_window ? sic->dest_td_max_window : 1; + reply_cm->protocol_state.tcp.end = sic->dest_td_end; + reply_cm->protocol_state.tcp.max_end = sic->dest_td_max_end; + if (sic->flags & SFE_CREATE_FLAG_NO_SEQ_CHECK) { + original_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK; + reply_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK; + } + break; + } + + sfe_ipv6_connection_match_compute_translations(original_cm); + sfe_ipv6_connection_match_compute_translations(reply_cm); + sfe_ipv6_insert_connection(si, c); + + spin_unlock_bh(&si->lock); + + /* + * We have everything we need! + */ + DEBUG_INFO("new connection - mark: %08x, p: %d\n" + " s: %s:%pxM(%pxM):%pI6(%pI6):%u(%u)\n" + " d: %s:%pxM(%pxM):%pI6(%pI6):%u(%u)\n", + sic->mark, sic->protocol, + sic->src_dev->name, sic->src_mac, sic->src_mac_xlate, + sic->src_ip.ip6, sic->src_ip_xlate.ip6, ntohs(sic->src_port), ntohs(sic->src_port_xlate), + dest_dev->name, sic->dest_mac, sic->dest_mac_xlate, + sic->dest_ip.ip6, sic->dest_ip_xlate.ip6, ntohs(sic->dest_port), ntohs(sic->dest_port_xlate)); + + return 0; +} + +/* + * sfe_ipv6_destroy_rule() + * Destroy a forwarding rule. + */ +void sfe_ipv6_destroy_rule(struct sfe_connection_destroy *sid) +{ + struct sfe_ipv6 *si = &__si6; + struct sfe_ipv6_connection *c; + + spin_lock_bh(&si->lock); + si->connection_destroy_requests++; + + /* + * Check to see if we have a flow that matches the rule we're trying + * to destroy. If there isn't then we can't destroy it. + */ + c = sfe_ipv6_find_connection(si, sid->protocol, sid->src_ip.ip6, sid->src_port, + sid->dest_ip.ip6, sid->dest_port); + if (!c) { + si->connection_destroy_misses++; + spin_unlock_bh(&si->lock); + + DEBUG_TRACE("connection does not exist - p: %d, s: %pI6:%u, d: %pI6:%u\n", + sid->protocol, sid->src_ip.ip6, ntohs(sid->src_port), + sid->dest_ip.ip6, ntohs(sid->dest_port)); + return; + } + + /* + * Remove our connection details from the hash tables. + */ + sfe_ipv6_remove_connection(si, c); + spin_unlock_bh(&si->lock); + + sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_DESTROY); + + DEBUG_INFO("connection destroyed - p: %d, s: %pI6:%u, d: %pI6:%u\n", + sid->protocol, sid->src_ip.ip6, ntohs(sid->src_port), + sid->dest_ip.ip6, ntohs(sid->dest_port)); +} + +/* + * sfe_ipv6_register_sync_rule_callback() + * Register a callback for rule synchronization. + */ +void sfe_ipv6_register_sync_rule_callback(sfe_sync_rule_callback_t sync_rule_callback) +{ + struct sfe_ipv6 *si = &__si6; + + spin_lock_bh(&si->lock); + rcu_assign_pointer(si->sync_rule_callback, sync_rule_callback); + spin_unlock_bh(&si->lock); +} + +/* + * sfe_ipv6_get_debug_dev() + */ +static ssize_t sfe_ipv6_get_debug_dev(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct sfe_ipv6 *si = &__si6; + ssize_t count; + int num; + + spin_lock_bh(&si->lock); + num = si->debug_dev; + spin_unlock_bh(&si->lock); + + count = snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", num); + return count; +} + +/* + * sfe_ipv6_destroy_all_rules_for_dev() + * Destroy all connections that match a particular device. + * + * If we pass dev as NULL then this destroys all connections. + */ +void sfe_ipv6_destroy_all_rules_for_dev(struct net_device *dev) +{ + struct sfe_ipv6 *si = &__si6; + struct sfe_ipv6_connection *c; + +another_round: + spin_lock_bh(&si->lock); + + for (c = si->all_connections_head; c; c = c->all_connections_next) { + /* + * Does this connection relate to the device we are destroying? + */ + if (!dev + || (dev == c->original_dev) + || (dev == c->reply_dev)) { + break; + } + } + + if (c) { + sfe_ipv6_remove_connection(si, c); + } + + spin_unlock_bh(&si->lock); + + if (c) { + sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_DESTROY); + goto another_round; + } +} + +/* + * sfe_ipv6_periodic_sync() + */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)) +static void sfe_ipv6_periodic_sync(unsigned long arg) +#else +static void sfe_ipv6_periodic_sync(struct timer_list *tl) +#endif +{ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)) + struct sfe_ipv6 *si = (struct sfe_ipv6 *)arg; +#else + struct sfe_ipv6 *si = from_timer(si, tl, timer); +#endif + u64 now_jiffies; + int quota; + sfe_sync_rule_callback_t sync_rule_callback; + + now_jiffies = get_jiffies_64(); + + rcu_read_lock(); + sync_rule_callback = rcu_dereference(si->sync_rule_callback); + if (!sync_rule_callback) { + rcu_read_unlock(); + goto done; + } + + spin_lock_bh(&si->lock); + sfe_ipv6_update_summary_stats(si); + + /* + * Get an estimate of the number of connections to parse in this sync. + */ + quota = (si->num_connections + 63) / 64; + + /* + * Walk the "active" list and sync the connection state. + */ + while (quota--) { + struct sfe_ipv6_connection_match *cm; + struct sfe_ipv6_connection_match *counter_cm; + struct sfe_ipv6_connection *c; + struct sfe_connection_sync sis; + + cm = si->active_head; + if (!cm) { + break; + } + + /* + * There's a possibility that our counter match is in the active list too. + * If it is then remove it. + */ + counter_cm = cm->counter_match; + if (counter_cm->active) { + counter_cm->active = false; + + /* + * We must have a connection preceding this counter match + * because that's the one that got us to this point, so we don't have + * to worry about removing the head of the list. + */ + counter_cm->active_prev->active_next = counter_cm->active_next; + + if (likely(counter_cm->active_next)) { + counter_cm->active_next->active_prev = counter_cm->active_prev; + } else { + si->active_tail = counter_cm->active_prev; + } + + counter_cm->active_next = NULL; + counter_cm->active_prev = NULL; + } + + /* + * Now remove the head of the active scan list. + */ + cm->active = false; + si->active_head = cm->active_next; + if (likely(cm->active_next)) { + cm->active_next->active_prev = NULL; + } else { + si->active_tail = NULL; + } + cm->active_next = NULL; + + /* + * Sync the connection state. + */ + c = cm->connection; + sfe_ipv6_gen_sync_connection(si, c, &sis, SFE_SYNC_REASON_STATS, now_jiffies); + + /* + * We don't want to be holding the lock when we sync! + */ + spin_unlock_bh(&si->lock); + sync_rule_callback(&sis); + spin_lock_bh(&si->lock); + } + + spin_unlock_bh(&si->lock); + rcu_read_unlock(); + +done: + mod_timer(&si->timer, jiffies + ((HZ + 99) / 100)); +} + +/* + * sfe_ipv6_debug_dev_read_start() + * Generate part of the XML output. + */ +static bool sfe_ipv6_debug_dev_read_start(struct sfe_ipv6 *si, char *buffer, char *msg, size_t *length, + int *total_read, struct sfe_ipv6_debug_xml_write_state *ws) +{ + int bytes_read; + + si->debug_read_seq++; + + bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\n"); + if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) { + return false; + } + + *length -= bytes_read; + *total_read += bytes_read; + + ws->state++; + return true; +} + +/* + * sfe_ipv6_debug_dev_read_connections_start() + * Generate part of the XML output. + */ +static bool sfe_ipv6_debug_dev_read_connections_start(struct sfe_ipv6 *si, char *buffer, char *msg, size_t *length, + int *total_read, struct sfe_ipv6_debug_xml_write_state *ws) +{ + int bytes_read; + + bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t\n"); + if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) { + return false; + } + + *length -= bytes_read; + *total_read += bytes_read; + + ws->state++; + return true; +} + +/* + * sfe_ipv6_debug_dev_read_connections_connection() + * Generate part of the XML output. + */ +static bool sfe_ipv6_debug_dev_read_connections_connection(struct sfe_ipv6 *si, char *buffer, char *msg, size_t *length, + int *total_read, struct sfe_ipv6_debug_xml_write_state *ws) +{ + struct sfe_ipv6_connection *c; + struct sfe_ipv6_connection_match *original_cm; + struct sfe_ipv6_connection_match *reply_cm; + int bytes_read; + int protocol; + struct net_device *src_dev; + struct sfe_ipv6_addr src_ip; + struct sfe_ipv6_addr src_ip_xlate; + __be16 src_port; + __be16 src_port_xlate; + u64 src_rx_packets; + u64 src_rx_bytes; + struct net_device *dest_dev; + struct sfe_ipv6_addr dest_ip; + struct sfe_ipv6_addr dest_ip_xlate; + __be16 dest_port; + __be16 dest_port_xlate; + u64 dest_rx_packets; + u64 dest_rx_bytes; + u64 last_sync_jiffies; + u32 mark, src_priority, dest_priority, src_dscp, dest_dscp; +#ifdef CONFIG_NF_FLOW_COOKIE + int src_flow_cookie, dst_flow_cookie; +#endif + + spin_lock_bh(&si->lock); + + for (c = si->all_connections_head; c; c = c->all_connections_next) { + if (c->debug_read_seq < si->debug_read_seq) { + c->debug_read_seq = si->debug_read_seq; + break; + } + } + + /* + * If there were no connections then move to the next state. + */ + if (!c) { + spin_unlock_bh(&si->lock); + ws->state++; + return true; + } + + original_cm = c->original_match; + reply_cm = c->reply_match; + + protocol = c->protocol; + src_dev = c->original_dev; + src_ip = c->src_ip[0]; + src_ip_xlate = c->src_ip_xlate[0]; + src_port = c->src_port; + src_port_xlate = c->src_port_xlate; + src_priority = original_cm->priority; + src_dscp = original_cm->dscp >> SFE_IPV6_DSCP_SHIFT; + + sfe_ipv6_connection_match_update_summary_stats(original_cm); + sfe_ipv6_connection_match_update_summary_stats(reply_cm); + + src_rx_packets = original_cm->rx_packet_count64; + src_rx_bytes = original_cm->rx_byte_count64; + dest_dev = c->reply_dev; + dest_ip = c->dest_ip[0]; + dest_ip_xlate = c->dest_ip_xlate[0]; + dest_port = c->dest_port; + dest_port_xlate = c->dest_port_xlate; + dest_priority = reply_cm->priority; + dest_dscp = reply_cm->dscp >> SFE_IPV6_DSCP_SHIFT; + dest_rx_packets = reply_cm->rx_packet_count64; + dest_rx_bytes = reply_cm->rx_byte_count64; + last_sync_jiffies = get_jiffies_64() - c->last_sync_jiffies; + mark = c->mark; +#ifdef CONFIG_NF_FLOW_COOKIE + src_flow_cookie = original_cm->flow_cookie; + dst_flow_cookie = reply_cm->flow_cookie; +#endif + spin_unlock_bh(&si->lock); + + bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t\t\n", + protocol, + src_dev->name, + &src_ip, &src_ip_xlate, + ntohs(src_port), ntohs(src_port_xlate), + src_priority, src_dscp, + src_rx_packets, src_rx_bytes, + dest_dev->name, + &dest_ip, &dest_ip_xlate, + ntohs(dest_port), ntohs(dest_port_xlate), + dest_priority, dest_dscp, + dest_rx_packets, dest_rx_bytes, +#ifdef CONFIG_NF_FLOW_COOKIE + src_flow_cookie, dst_flow_cookie, +#endif + last_sync_jiffies, mark); + + if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) { + return false; + } + + *length -= bytes_read; + *total_read += bytes_read; + + return true; +} + +/* + * sfe_ipv6_debug_dev_read_connections_end() + * Generate part of the XML output. + */ +static bool sfe_ipv6_debug_dev_read_connections_end(struct sfe_ipv6 *si, char *buffer, char *msg, size_t *length, + int *total_read, struct sfe_ipv6_debug_xml_write_state *ws) +{ + int bytes_read; + + bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t\n"); + if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) { + return false; + } + + *length -= bytes_read; + *total_read += bytes_read; + + ws->state++; + return true; +} + +/* + * sfe_ipv6_debug_dev_read_exceptions_start() + * Generate part of the XML output. + */ +static bool sfe_ipv6_debug_dev_read_exceptions_start(struct sfe_ipv6 *si, char *buffer, char *msg, size_t *length, + int *total_read, struct sfe_ipv6_debug_xml_write_state *ws) +{ + int bytes_read; + + bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t\n"); + if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) { + return false; + } + + *length -= bytes_read; + *total_read += bytes_read; + + ws->state++; + return true; +} + +/* + * sfe_ipv6_debug_dev_read_exceptions_exception() + * Generate part of the XML output. + */ +static bool sfe_ipv6_debug_dev_read_exceptions_exception(struct sfe_ipv6 *si, char *buffer, char *msg, size_t *length, + int *total_read, struct sfe_ipv6_debug_xml_write_state *ws) +{ + u64 ct; + + spin_lock_bh(&si->lock); + ct = si->exception_events64[ws->iter_exception]; + spin_unlock_bh(&si->lock); + + if (ct) { + int bytes_read; + + bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, + "\t\t\n", + sfe_ipv6_exception_events_string[ws->iter_exception], + ct); + if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) { + return false; + } + + *length -= bytes_read; + *total_read += bytes_read; + } + + ws->iter_exception++; + if (ws->iter_exception >= SFE_IPV6_EXCEPTION_EVENT_LAST) { + ws->iter_exception = 0; + ws->state++; + } + + return true; +} + +/* + * sfe_ipv6_debug_dev_read_exceptions_end() + * Generate part of the XML output. + */ +static bool sfe_ipv6_debug_dev_read_exceptions_end(struct sfe_ipv6 *si, char *buffer, char *msg, size_t *length, + int *total_read, struct sfe_ipv6_debug_xml_write_state *ws) +{ + int bytes_read; + + bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t\n"); + if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) { + return false; + } + + *length -= bytes_read; + *total_read += bytes_read; + + ws->state++; + return true; +} + +/* + * sfe_ipv6_debug_dev_read_stats() + * Generate part of the XML output. + */ +static bool sfe_ipv6_debug_dev_read_stats(struct sfe_ipv6 *si, char *buffer, char *msg, size_t *length, + int *total_read, struct sfe_ipv6_debug_xml_write_state *ws) +{ + int bytes_read; + unsigned int num_connections; + u64 packets_forwarded; + u64 packets_not_forwarded; + u64 connection_create_requests; + u64 connection_create_collisions; + u64 connection_destroy_requests; + u64 connection_destroy_misses; + u64 connection_flushes; + u64 connection_match_hash_hits; + u64 connection_match_hash_reorders; + + spin_lock_bh(&si->lock); + sfe_ipv6_update_summary_stats(si); + + num_connections = si->num_connections; + packets_forwarded = si->packets_forwarded64; + packets_not_forwarded = si->packets_not_forwarded64; + connection_create_requests = si->connection_create_requests64; + connection_create_collisions = si->connection_create_collisions64; + connection_destroy_requests = si->connection_destroy_requests64; + connection_destroy_misses = si->connection_destroy_misses64; + connection_flushes = si->connection_flushes64; + connection_match_hash_hits = si->connection_match_hash_hits64; + connection_match_hash_reorders = si->connection_match_hash_reorders64; + spin_unlock_bh(&si->lock); + + bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t\n", + num_connections, + packets_forwarded, + packets_not_forwarded, + connection_create_requests, + connection_create_collisions, + connection_destroy_requests, + connection_destroy_misses, + connection_flushes, + connection_match_hash_hits, + connection_match_hash_reorders); + if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) { + return false; + } + + *length -= bytes_read; + *total_read += bytes_read; + + ws->state++; + return true; +} + +/* + * sfe_ipv6_debug_dev_read_end() + * Generate part of the XML output. + */ +static bool sfe_ipv6_debug_dev_read_end(struct sfe_ipv6 *si, char *buffer, char *msg, size_t *length, + int *total_read, struct sfe_ipv6_debug_xml_write_state *ws) +{ + int bytes_read; + + bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\n"); + if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) { + return false; + } + + *length -= bytes_read; + *total_read += bytes_read; + + ws->state++; + return true; +} + +/* + * Array of write functions that write various XML elements that correspond to + * our XML output state machine. + */ +static sfe_ipv6_debug_xml_write_method_t sfe_ipv6_debug_xml_write_methods[SFE_IPV6_DEBUG_XML_STATE_DONE] = { + sfe_ipv6_debug_dev_read_start, + sfe_ipv6_debug_dev_read_connections_start, + sfe_ipv6_debug_dev_read_connections_connection, + sfe_ipv6_debug_dev_read_connections_end, + sfe_ipv6_debug_dev_read_exceptions_start, + sfe_ipv6_debug_dev_read_exceptions_exception, + sfe_ipv6_debug_dev_read_exceptions_end, + sfe_ipv6_debug_dev_read_stats, + sfe_ipv6_debug_dev_read_end, +}; + +/* + * sfe_ipv6_debug_dev_read() + * Send info to userspace upon read request from user + */ +static ssize_t sfe_ipv6_debug_dev_read(struct file *filp, char *buffer, size_t length, loff_t *offset) +{ + char msg[CHAR_DEV_MSG_SIZE]; + int total_read = 0; + struct sfe_ipv6_debug_xml_write_state *ws; + struct sfe_ipv6 *si = &__si6; + + ws = (struct sfe_ipv6_debug_xml_write_state *)filp->private_data; + while ((ws->state != SFE_IPV6_DEBUG_XML_STATE_DONE) && (length > CHAR_DEV_MSG_SIZE)) { + if ((sfe_ipv6_debug_xml_write_methods[ws->state])(si, buffer, msg, &length, &total_read, ws)) { + continue; + } + } + + return total_read; +} + +/* + * sfe_ipv6_debug_dev_write() + * Write to char device resets some stats + */ +static ssize_t sfe_ipv6_debug_dev_write(struct file *filp, const char *buffer, size_t length, loff_t *offset) +{ + struct sfe_ipv6 *si = &__si6; + + spin_lock_bh(&si->lock); + sfe_ipv6_update_summary_stats(si); + + si->packets_forwarded64 = 0; + si->packets_not_forwarded64 = 0; + si->connection_create_requests64 = 0; + si->connection_create_collisions64 = 0; + si->connection_destroy_requests64 = 0; + si->connection_destroy_misses64 = 0; + si->connection_flushes64 = 0; + si->connection_match_hash_hits64 = 0; + si->connection_match_hash_reorders64 = 0; + spin_unlock_bh(&si->lock); + + return length; +} + +/* + * sfe_ipv6_debug_dev_open() + */ +static int sfe_ipv6_debug_dev_open(struct inode *inode, struct file *file) +{ + struct sfe_ipv6_debug_xml_write_state *ws; + + ws = (struct sfe_ipv6_debug_xml_write_state *)file->private_data; + if (ws) { + return 0; + } + + ws = kzalloc(sizeof(struct sfe_ipv6_debug_xml_write_state), GFP_KERNEL); + if (!ws) { + return -ENOMEM; + } + + ws->state = SFE_IPV6_DEBUG_XML_STATE_START; + file->private_data = ws; + + return 0; +} + +/* + * sfe_ipv6_debug_dev_release() + */ +static int sfe_ipv6_debug_dev_release(struct inode *inode, struct file *file) +{ + struct sfe_ipv6_debug_xml_write_state *ws; + + ws = (struct sfe_ipv6_debug_xml_write_state *)file->private_data; + if (ws) { + /* + * We've finished with our output so free the write state. + */ + kfree(ws); + } + + return 0; +} + +/* + * File operations used in the debug char device + */ +static struct file_operations sfe_ipv6_debug_dev_fops = { + .read = sfe_ipv6_debug_dev_read, + .write = sfe_ipv6_debug_dev_write, + .open = sfe_ipv6_debug_dev_open, + .release = sfe_ipv6_debug_dev_release +}; + +#ifdef CONFIG_NF_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) +{ + struct sfe_ipv6 *si = &__si6; + + BUG_ON(!cb); + + if (si->flow_cookie_set_func) { + return -1; + } + + rcu_assign_pointer(si->flow_cookie_set_func, cb); + return 0; +} + +/* + * 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) +{ + struct sfe_ipv6 *si = &__si6; + + RCU_INIT_POINTER(si->flow_cookie_set_func, NULL); + return 0; +} + +/* + * sfe_ipv6_get_flow_cookie() + */ +static ssize_t sfe_ipv6_get_flow_cookie(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct sfe_ipv6 *si = &__si6; + return snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", si->flow_cookie_enable); +} + +/* + * sfe_ipv6_set_flow_cookie() + */ +static ssize_t sfe_ipv6_set_flow_cookie(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct sfe_ipv6 *si = &__si6; + strict_strtol(buf, 0, (long int *)&si->flow_cookie_enable); + + return size; +} + +/* + * sysfs attributes. + */ +static const struct device_attribute sfe_ipv6_flow_cookie_attr = + __ATTR(flow_cookie_enable, S_IWUSR | S_IRUGO, sfe_ipv6_get_flow_cookie, sfe_ipv6_set_flow_cookie); +#endif /*CONFIG_NF_FLOW_COOKIE*/ + +/* + * sfe_ipv6_init() + */ +static int __init sfe_ipv6_init(void) +{ + struct sfe_ipv6 *si = &__si6; + int result = -1; + + DEBUG_INFO("SFE IPv6 init\n"); + + /* + * Create sys/sfe_ipv6 + */ + si->sys_sfe_ipv6 = kobject_create_and_add("sfe_ipv6", NULL); + if (!si->sys_sfe_ipv6) { + DEBUG_ERROR("failed to register sfe_ipv6\n"); + goto exit1; + } + + /* + * Create files, one for each parameter supported by this module. + */ + result = sysfs_create_file(si->sys_sfe_ipv6, &sfe_ipv6_debug_dev_attr.attr); + if (result) { + DEBUG_ERROR("failed to register debug dev file: %d\n", result); + goto exit2; + } + +#ifdef CONFIG_NF_FLOW_COOKIE + result = sysfs_create_file(si->sys_sfe_ipv6, &sfe_ipv6_flow_cookie_attr.attr); + if (result) { + DEBUG_ERROR("failed to register flow cookie enable file: %d\n", result); + goto exit3; + } +#endif /* CONFIG_NF_FLOW_COOKIE */ + + /* + * Register our debug char device. + */ + result = register_chrdev(0, "sfe_ipv6", &sfe_ipv6_debug_dev_fops); + if (result < 0) { + DEBUG_ERROR("Failed to register chrdev: %d\n", result); + goto exit4; + } + + si->debug_dev = result; + + /* + * Create a timer to handle periodic statistics. + */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)) + setup_timer(&si->timer, sfe_ipv6_periodic_sync, (unsigned long)si); +#else + timer_setup(&si->timer, sfe_ipv6_periodic_sync, 0); +#endif + mod_timer(&si->timer, jiffies + ((HZ + 99) / 100)); + + spin_lock_init(&si->lock); + + return 0; + +exit4: +#ifdef CONFIG_NF_FLOW_COOKIE + sysfs_remove_file(si->sys_sfe_ipv6, &sfe_ipv6_flow_cookie_attr.attr); + +exit3: +#endif /* CONFIG_NF_FLOW_COOKIE */ + sysfs_remove_file(si->sys_sfe_ipv6, &sfe_ipv6_debug_dev_attr.attr); + +exit2: + kobject_put(si->sys_sfe_ipv6); + +exit1: + return result; +} + +/* + * sfe_ipv6_exit() + */ +static void __exit sfe_ipv6_exit(void) +{ + struct sfe_ipv6 *si = &__si6; + + DEBUG_INFO("SFE IPv6 exit\n"); + + /* + * Destroy all connections. + */ + sfe_ipv6_destroy_all_rules_for_dev(NULL); + + del_timer_sync(&si->timer); + + unregister_chrdev(si->debug_dev, "sfe_ipv6"); + +#ifdef CONFIG_NF_FLOW_COOKIE + sysfs_remove_file(si->sys_sfe_ipv6, &sfe_ipv6_flow_cookie_attr.attr); +#endif /* CONFIG_NF_FLOW_COOKIE */ + sysfs_remove_file(si->sys_sfe_ipv6, &sfe_ipv6_debug_dev_attr.attr); + + kobject_put(si->sys_sfe_ipv6); +} + +module_init(sfe_ipv6_init) +module_exit(sfe_ipv6_exit) + +EXPORT_SYMBOL(sfe_ipv6_recv); +EXPORT_SYMBOL(sfe_ipv6_create_rule); +EXPORT_SYMBOL(sfe_ipv6_destroy_rule); +EXPORT_SYMBOL(sfe_ipv6_destroy_all_rules_for_dev); +EXPORT_SYMBOL(sfe_ipv6_register_sync_rule_callback); +EXPORT_SYMBOL(sfe_ipv6_mark_rule); +EXPORT_SYMBOL(sfe_ipv6_update_rule); +#ifdef CONFIG_NF_FLOW_COOKIE +EXPORT_SYMBOL(sfe_ipv6_register_flow_cookie_cb); +EXPORT_SYMBOL(sfe_ipv6_unregister_flow_cookie_cb); +#endif + +MODULE_DESCRIPTION("Shortcut Forwarding Engine - IPv6 support"); +MODULE_LICENSE("Dual BSD/GPL"); + diff --git a/shortcut-fe/shortcut-fe/src/Kconfig b/shortcut-fe/shortcut-fe/src/Kconfig new file mode 100644 index 000000000..487f1e065 --- /dev/null +++ b/shortcut-fe/shortcut-fe/src/Kconfig @@ -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. diff --git a/shortcut-fe/src/Makefile b/shortcut-fe/shortcut-fe/src/Makefile old mode 100755 new mode 100644 similarity index 100% rename from shortcut-fe/src/Makefile rename to shortcut-fe/shortcut-fe/src/Makefile diff --git a/shortcut-fe/shortcut-fe/src/sfe.h b/shortcut-fe/shortcut-fe/src/sfe.h new file mode 100644 index 000000000..279e7b3dc --- /dev/null +++ b/shortcut-fe/shortcut-fe/src/sfe.h @@ -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*/ diff --git a/shortcut-fe/shortcut-fe/src/sfe_backport.h b/shortcut-fe/shortcut-fe/src/sfe_backport.h new file mode 100644 index 000000000..d2d60c73c --- /dev/null +++ b/shortcut-fe/shortcut-fe/src/sfe_backport.h @@ -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 + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) +#include +#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, addr) +#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 diff --git a/shortcut-fe/src/sfe_cm.c b/shortcut-fe/shortcut-fe/src/sfe_cm.c old mode 100755 new mode 100644 similarity index 99% rename from shortcut-fe/src/sfe_cm.c rename to shortcut-fe/shortcut-fe/src/sfe_cm.c index 68304b388..2d3f79a04 --- a/shortcut-fe/src/sfe_cm.c +++ b/shortcut-fe/shortcut-fe/src/sfe_cm.c @@ -501,7 +501,7 @@ static unsigned int sfe_cm_post_routing(struct sk_buff *skb, int is_v4) sic.dest_td_max_window = ct->proto.tcp.seen[1].td_maxwin; sic.dest_td_end = ct->proto.tcp.seen[1].td_end; sic.dest_td_max_end = ct->proto.tcp.seen[1].td_maxend; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0) net = nf_ct_net(ct); tn = nf_tcp_pernet(net); if ((tn&&tn->tcp_no_window_check) diff --git a/shortcut-fe/src/sfe_cm.h b/shortcut-fe/shortcut-fe/src/sfe_cm.h old mode 100755 new mode 100644 similarity index 100% rename from shortcut-fe/src/sfe_cm.h rename to shortcut-fe/shortcut-fe/src/sfe_cm.h diff --git a/shortcut-fe/src/sfe_ipv4.c b/shortcut-fe/shortcut-fe/src/sfe_ipv4.c old mode 100755 new mode 100644 similarity index 100% rename from shortcut-fe/src/sfe_ipv4.c rename to shortcut-fe/shortcut-fe/src/sfe_ipv4.c diff --git a/shortcut-fe/src/sfe_ipv6.c b/shortcut-fe/shortcut-fe/src/sfe_ipv6.c old mode 100755 new mode 100644 similarity index 100% rename from shortcut-fe/src/sfe_ipv6.c rename to shortcut-fe/shortcut-fe/src/sfe_ipv6.c diff --git a/simulated-driver/Makefile b/shortcut-fe/simulated-driver/Makefile old mode 100755 new mode 100644 similarity index 100% rename from simulated-driver/Makefile rename to shortcut-fe/simulated-driver/Makefile diff --git a/simulated-driver/patches/200-nss-qdisc-support.patch b/shortcut-fe/simulated-driver/patches/200-nss-qdisc-support.patch old mode 100755 new mode 100644 similarity index 100% rename from simulated-driver/patches/200-nss-qdisc-support.patch rename to shortcut-fe/simulated-driver/patches/200-nss-qdisc-support.patch diff --git a/shortcut-fe/simulated-driver/sfe_drv.c b/shortcut-fe/simulated-driver/sfe_drv.c new file mode 100644 index 000000000..98677d911 --- /dev/null +++ b/shortcut-fe/simulated-driver/sfe_drv.c @@ -0,0 +1,1323 @@ +/* + * sfe_drv.c + * simulated sfe driver for shortcut forwarding engine. + * + * Copyright (c) 2015,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 +#include +#include +#include +#include +#include +#include + +#include "../shortcut-fe/sfe.h" +#include "../shortcut-fe/sfe_cm.h" +#include "sfe_drv.h" + +typedef enum sfe_drv_exception { + SFE_DRV_EXCEPTION_IPV4_MSG_UNKNOW, + SFE_DRV_EXCEPTION_IPV6_MSG_UNKNOW, + SFE_DRV_EXCEPTION_CONNECTION_INVALID, + SFE_DRV_EXCEPTION_NOT_SUPPORT_BRIDGE, + SFE_DRV_EXCEPTION_TCP_INVALID, + SFE_DRV_EXCEPTION_PROTOCOL_NOT_SUPPORT, + SFE_DRV_EXCEPTION_SRC_DEV_NOT_L3, + SFE_DRV_EXCEPTION_DEST_DEV_NOT_L3, + SFE_DRV_EXCEPTION_CREATE_FAILED, + SFE_DRV_EXCEPTION_ENQUEUE_FAILED, + SFE_DRV_EXCEPTION_NOT_SUPPORT_6RD, + SFE_DRV_EXCEPTION_NO_SYNC_CB, + SFE_DRV_EXCEPTION_MAX +} sfe_drv_exception_t; + +static char *sfe_drv_exception_events_string[SFE_DRV_EXCEPTION_MAX] = { + "IPV4_MSG_UNKNOW", + "IPV6_MSG_UNKNOW", + "CONNECTION_INVALID", + "NOT_SUPPORT_BRIDGE", + "TCP_INVALID", + "PROTOCOL_NOT_SUPPORT", + "SRC_DEV_NOT_L3", + "DEST_DEV_NOT_L3", + "CREATE_FAILED", + "ENQUEUE_FAILED", + "NOT_SUPPORT_6RD", + "NO_SYNC_CB" +}; + +#define SFE_MESSAGE_VERSION 0x1 +#define SFE_MAX_CONNECTION_NUM 65535 +#define sfe_drv_ipv6_addr_copy(src, dest) memcpy((void *)(dest), (void *)(src), 16) +#define sfe_drv_ipv4_stopped(CTX) (rcu_dereference((CTX)->ipv4_stats_sync_cb) == NULL) +#define sfe_drv_ipv6_stopped(CTX) (rcu_dereference((CTX)->ipv6_stats_sync_cb) == NULL) + +/* + * message type of queued response message + */ +typedef enum { + SFE_DRV_MSG_TYPE_IPV4, + SFE_DRV_MSG_TYPE_IPV6 +} sfe_drv_msg_types_t; + +/* + * queued response message, + * will be sent back to caller in workqueue + */ +struct sfe_drv_response_msg { + struct list_head node; + sfe_drv_msg_types_t type; + void *msg[0]; +}; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0) +#define list_first_entry_or_null(ptr, type, member) \ + (!list_empty(ptr) ? list_first_entry(ptr, type, member) : NULL) +#endif + +/* + * sfe driver context instance, private for sfe driver + */ +struct sfe_drv_ctx_instance_internal { + struct sfe_drv_ctx_instance base;/* exported sfe driver context, is public to user of sfe driver*/ + + /* + * Control state. + */ + struct kobject *sys_sfe_drv; /* sysfs linkage */ + + struct list_head msg_queue; /* response message queue*/ + spinlock_t lock; /* Lock to protect message queue */ + + struct work_struct work; /* work to send response message back to caller*/ + + sfe_ipv4_msg_callback_t __rcu ipv4_stats_sync_cb; /* callback to call to sync ipv4 statistics */ + void *ipv4_stats_sync_data; /* argument for above callback: ipv4_stats_sync_cb */ + + sfe_ipv6_msg_callback_t __rcu ipv6_stats_sync_cb; /* callback to call to sync ipv6 statistics */ + void *ipv6_stats_sync_data; /* argument for above callback: ipv6_stats_sync_cb */ + + u32 exceptions[SFE_DRV_EXCEPTION_MAX]; /* statistics for exception */ +}; + +static struct sfe_drv_ctx_instance_internal __sfe_drv_ctx; + +/* + * convert public sfe driver context to internal context + */ +#define SFE_DRV_CTX_TO_PRIVATE(base) (struct sfe_drv_ctx_instance_internal *)(base) +/* + * convert internal sfe driver context to public context + */ +#define SFE_DRV_CTX_TO_PUBLIC(intrv) (struct sfe_drv_ctx_instance *)(intrv) + +/* + * sfe_drv_incr_exceptions() + * increase an exception counter. + */ +static inline void sfe_drv_incr_exceptions(sfe_drv_exception_t except) +{ + struct sfe_drv_ctx_instance_internal *sfe_drv_ctx = &__sfe_drv_ctx; + + spin_lock_bh(&sfe_drv_ctx->lock); + sfe_drv_ctx->exceptions[except]++; + spin_unlock_bh(&sfe_drv_ctx->lock); +} + +/* + * sfe_drv_dev_is_layer_3_interface() + * check if a network device is ipv4 or ipv6 layer 3 interface + * + * @param dev network device to check + * @param check_v4 check ipv4 layer 3 interface(which have ipv4 address) or ipv6 layer 3 interface(which have ipv6 address) + */ +inline bool sfe_drv_dev_is_layer_3_interface(struct net_device *dev, bool check_v4) +{ + struct in_device *in4_dev; + struct inet6_dev *in6_dev; + + BUG_ON(!dev); + + if (likely(check_v4)) { + /* + * Does our input device support IPv4 processing? + */ + in4_dev = (struct in_device *)dev->ip_ptr; + if (unlikely(!in4_dev)) { + return false; + } + + /* + * Does it have an IPv4 address? If it doesn't then we can't do anything + * interesting here! + */ + if (unlikely(!in4_dev->ifa_list)) { + return false; + } + + return true; + } + + /* + * Does our input device support IPv6 processing? + */ + in6_dev = (struct inet6_dev *)dev->ip6_ptr; + if (unlikely(!in6_dev)) { + return false; + } + + /* + * Does it have an IPv6 address? If it doesn't then we can't do anything + * interesting here! + */ + if (unlikely(list_empty(&in6_dev->addr_list))) { + return false; + } + + return true; +} + +/* + * sfe_drv_clean_response_msg_by_type() + * clean response message in queue when ECM exit + * + * @param sfe_drv_ctx sfe driver context + * @param msg_type message type, ipv4 or ipv6 + */ +static void sfe_drv_clean_response_msg_by_type(struct sfe_drv_ctx_instance_internal *sfe_drv_ctx, sfe_drv_msg_types_t msg_type) +{ + struct sfe_drv_response_msg *response, *tmp; + + if (!sfe_drv_ctx) { + return; + } + + spin_lock_bh(&sfe_drv_ctx->lock); + list_for_each_entry_safe(response, tmp, &sfe_drv_ctx->msg_queue, node) { + if (response->type == msg_type) { + list_del(&response->node); + /* + * free response message + */ + kfree(response); + } + } + spin_unlock_bh(&sfe_drv_ctx->lock); + +} + +/* + * sfe_drv_process_response_msg() + * send all pending response message to ECM by calling callback function included in message + * + * @param work work structure + */ +static void sfe_drv_process_response_msg(struct work_struct *work) +{ + struct sfe_drv_ctx_instance_internal *sfe_drv_ctx = container_of(work, struct sfe_drv_ctx_instance_internal, work); + struct sfe_drv_response_msg *response; + + spin_lock_bh(&sfe_drv_ctx->lock); + while ((response = list_first_entry_or_null(&sfe_drv_ctx->msg_queue, struct sfe_drv_response_msg, node))) { + list_del(&response->node); + spin_unlock_bh(&sfe_drv_ctx->lock); + rcu_read_lock(); + + /* + * send response message back to caller + */ + if ((response->type == SFE_DRV_MSG_TYPE_IPV4) && !sfe_drv_ipv4_stopped(sfe_drv_ctx)) { + struct sfe_ipv4_msg *msg = (struct sfe_ipv4_msg *)response->msg; + sfe_ipv4_msg_callback_t callback = (sfe_ipv4_msg_callback_t)msg->cm.cb; + if (callback) { + callback((void *)msg->cm.app_data, msg); + } + } else if ((response->type == SFE_DRV_MSG_TYPE_IPV6) && !sfe_drv_ipv6_stopped(sfe_drv_ctx)) { + struct sfe_ipv6_msg *msg = (struct sfe_ipv6_msg *)response->msg; + sfe_ipv6_msg_callback_t callback = (sfe_ipv6_msg_callback_t)msg->cm.cb; + if (callback) { + callback((void *)msg->cm.app_data, msg); + } + } + + rcu_read_unlock(); + /* + * free response message + */ + kfree(response); + spin_lock_bh(&sfe_drv_ctx->lock); + } + spin_unlock_bh(&sfe_drv_ctx->lock); +} + +/* + * sfe_drv_alloc_response_msg() + * alloc and construct new response message + * + * @param type message type + * @param msg used to construct response message if not NULL + * + * @return !NULL, success; NULL, failed + */ +static struct sfe_drv_response_msg * +sfe_drv_alloc_response_msg(sfe_drv_msg_types_t type, void *msg) +{ + struct sfe_drv_response_msg *response; + int size; + + switch (type) { + case SFE_DRV_MSG_TYPE_IPV4: + size = sizeof(struct sfe_ipv4_msg); + break; + case SFE_DRV_MSG_TYPE_IPV6: + size = sizeof(struct sfe_ipv6_msg); + break; + default: + DEBUG_ERROR("message type %d not supported\n", type); + return NULL; + } + + response = (struct sfe_drv_response_msg *)kzalloc(sizeof(struct sfe_drv_response_msg) + size, GFP_ATOMIC); + if (!response) { + DEBUG_ERROR("allocate memory failed\n"); + return NULL; + } + + response->type = type; + + if (msg) { + memcpy(response->msg, msg, size); + } + + return response; +} + +/* + * sfe_drv_enqueue_msg() + * queue response message + * + * @param sfe_drv_ctx sfe driver context + * @param response response message to be queue + */ +static inline void sfe_drv_enqueue_msg(struct sfe_drv_ctx_instance_internal *sfe_drv_ctx, struct sfe_drv_response_msg *response) +{ + spin_lock_bh(&sfe_drv_ctx->lock); + list_add_tail(&response->node, &sfe_drv_ctx->msg_queue); + spin_unlock_bh(&sfe_drv_ctx->lock); + + schedule_work(&sfe_drv_ctx->work); +} + +/* + * sfe_cmn_msg_init() + * Initialize the common message structure. + * + * @param ncm message to init + * @param if_num interface number related with this message + * @param type message type + * @param cb callback function to process repsonse of this message + * @param app_data argument for above callback function + */ +static void sfe_cmn_msg_init(struct sfe_cmn_msg *ncm, u16 if_num, u32 type, u32 len, void *cb, void *app_data) +{ + ncm->interface = if_num; + ncm->version = SFE_MESSAGE_VERSION; + ncm->type = type; + ncm->len = len; + ncm->cb = (sfe_ptr_t)cb; + ncm->app_data = (sfe_ptr_t)app_data; +} + +/* + * sfe_drv_ipv4_stats_sync_callback() + * Synchronize a connection's state. + * + * @param sis SFE statistics from SFE core engine + */ +static void sfe_drv_ipv4_stats_sync_callback(struct sfe_connection_sync *sis) +{ + struct sfe_drv_ctx_instance_internal *sfe_drv_ctx = &__sfe_drv_ctx; + struct sfe_ipv4_msg msg; + struct sfe_ipv4_conn_sync *sync_msg; + sfe_ipv4_msg_callback_t sync_cb; + + rcu_read_lock(); + sync_cb = rcu_dereference(sfe_drv_ctx->ipv4_stats_sync_cb); + if (!sync_cb) { + rcu_read_unlock(); + sfe_drv_incr_exceptions(SFE_DRV_EXCEPTION_NO_SYNC_CB); + return; + } + + sync_msg = &msg.msg.conn_stats; + + memset(&msg, 0, sizeof(msg)); + sfe_cmn_msg_init(&msg.cm, 0, SFE_RX_CONN_STATS_SYNC_MSG, + sizeof(struct sfe_ipv4_conn_sync), NULL, NULL); + + /* + * fill connection specific information + */ + sync_msg->protocol = (u8)sis->protocol; + sync_msg->flow_ip = sis->src_ip.ip; + sync_msg->flow_ip_xlate = sis->src_ip_xlate.ip; + sync_msg->flow_ident = sis->src_port; + sync_msg->flow_ident_xlate = sis->src_port_xlate; + + sync_msg->return_ip = sis->dest_ip.ip; + sync_msg->return_ip_xlate = sis->dest_ip_xlate.ip; + sync_msg->return_ident = sis->dest_port; + sync_msg->return_ident_xlate = sis->dest_port_xlate; + + /* + * fill TCP protocol specific information + */ + if (sis->protocol == IPPROTO_TCP) { + sync_msg->flow_max_window = sis->src_td_max_window; + sync_msg->flow_end = sis->src_td_end; + sync_msg->flow_max_end = sis->src_td_max_end; + + sync_msg->return_max_window = sis->dest_td_max_window; + sync_msg->return_end = sis->dest_td_end; + sync_msg->return_max_end = sis->dest_td_max_end; + } + + /* + * fill statistics information + */ + sync_msg->flow_rx_packet_count = sis->src_new_packet_count; + sync_msg->flow_rx_byte_count = sis->src_new_byte_count; + sync_msg->flow_tx_packet_count = sis->dest_new_packet_count; + sync_msg->flow_tx_byte_count = sis->dest_new_byte_count; + + sync_msg->return_rx_packet_count = sis->dest_new_packet_count; + sync_msg->return_rx_byte_count = sis->dest_new_byte_count; + sync_msg->return_tx_packet_count = sis->src_new_packet_count; + sync_msg->return_tx_byte_count = sis->src_new_byte_count; + + /* + * fill expiration time to extend, in unit of msec + */ + sync_msg->inc_ticks = (((u32)sis->delta_jiffies) * MSEC_PER_SEC)/HZ; + + /* + * fill other information + */ + switch (sis->reason) { + case SFE_SYNC_REASON_DESTROY: + sync_msg->reason = SFE_RULE_SYNC_REASON_DESTROY; + break; + case SFE_SYNC_REASON_FLUSH: + sync_msg->reason = SFE_RULE_SYNC_REASON_FLUSH; + break; + default: + sync_msg->reason = SFE_RULE_SYNC_REASON_STATS; + break; + } + + /* + * SFE sync calling is excuted in a timer, so we can redirect it to ECM directly. + */ + sync_cb(sfe_drv_ctx->ipv4_stats_sync_data, &msg); + rcu_read_unlock(); +} + +/* + * sfe_drv_create_ipv4_rule_msg() + * convert create message format from ecm to sfe + * + * @param sfe_drv_ctx sfe driver context + * @param msg The IPv4 message + * + * @return sfe_tx_status_t The status of the Tx operation + */ +sfe_tx_status_t sfe_drv_create_ipv4_rule_msg(struct sfe_drv_ctx_instance_internal *sfe_drv_ctx, struct sfe_ipv4_msg *msg) +{ + struct sfe_connection_create sic; + struct net_device *src_dev = NULL; + struct net_device *dest_dev = NULL; + struct sfe_drv_response_msg *response; + enum sfe_cmn_response ret; + + response = sfe_drv_alloc_response_msg(SFE_DRV_MSG_TYPE_IPV4, msg); + if (!response) { + sfe_drv_incr_exceptions(SFE_DRV_EXCEPTION_ENQUEUE_FAILED); + return SFE_TX_FAILURE_QUEUE; + } + + if (!(msg->msg.rule_create.valid_flags & SFE_RULE_CREATE_CONN_VALID)) { + ret = SFE_CMN_RESPONSE_EMSG; + sfe_drv_incr_exceptions(SFE_DRV_EXCEPTION_CONNECTION_INVALID); + goto failed_ret; + } + + /* + * not support bridged flows now + */ + if (msg->msg.rule_create.rule_flags & SFE_RULE_CREATE_FLAG_BRIDGE_FLOW) { + ret = SFE_CMN_RESPONSE_EINTERFACE; + sfe_drv_incr_exceptions(SFE_DRV_EXCEPTION_NOT_SUPPORT_BRIDGE); + goto failed_ret; + } + + sic.protocol = msg->msg.rule_create.tuple.protocol; + sic.src_ip.ip = msg->msg.rule_create.tuple.flow_ip; + sic.dest_ip.ip = msg->msg.rule_create.tuple.return_ip; + sic.src_ip_xlate.ip = msg->msg.rule_create.conn_rule.flow_ip_xlate; + sic.dest_ip_xlate.ip = msg->msg.rule_create.conn_rule.return_ip_xlate; + + sic.flags = 0; + switch (sic.protocol) { + case IPPROTO_TCP: + if (!(msg->msg.rule_create.valid_flags & SFE_RULE_CREATE_TCP_VALID)) { + ret = SFE_CMN_RESPONSE_EMSG; + sfe_drv_incr_exceptions(SFE_DRV_EXCEPTION_TCP_INVALID); + goto failed_ret; + } + + sic.src_port = msg->msg.rule_create.tuple.flow_ident; + sic.dest_port = msg->msg.rule_create.tuple.return_ident; + sic.src_port_xlate = msg->msg.rule_create.conn_rule.flow_ident_xlate; + sic.dest_port_xlate = msg->msg.rule_create.conn_rule.return_ident_xlate; + sic.src_td_window_scale = msg->msg.rule_create.tcp_rule.flow_window_scale; + sic.src_td_max_window = msg->msg.rule_create.tcp_rule.flow_max_window; + sic.src_td_end = msg->msg.rule_create.tcp_rule.flow_end; + sic.src_td_max_end = msg->msg.rule_create.tcp_rule.flow_max_end; + sic.dest_td_window_scale = msg->msg.rule_create.tcp_rule.return_window_scale; + sic.dest_td_max_window = msg->msg.rule_create.tcp_rule.return_max_window; + sic.dest_td_end = msg->msg.rule_create.tcp_rule.return_end; + sic.dest_td_max_end = msg->msg.rule_create.tcp_rule.return_max_end; + if (msg->msg.rule_create.rule_flags & SFE_RULE_CREATE_FLAG_NO_SEQ_CHECK) { + sic.flags |= SFE_CREATE_FLAG_NO_SEQ_CHECK; + } + break; + + case IPPROTO_UDP: + sic.src_port = msg->msg.rule_create.tuple.flow_ident; + sic.dest_port = msg->msg.rule_create.tuple.return_ident; + sic.src_port_xlate = msg->msg.rule_create.conn_rule.flow_ident_xlate; + sic.dest_port_xlate = msg->msg.rule_create.conn_rule.return_ident_xlate; + break; + + default: + ret = SFE_CMN_RESPONSE_EMSG; + sfe_drv_incr_exceptions(SFE_DRV_EXCEPTION_PROTOCOL_NOT_SUPPORT); + goto failed_ret; + } + + memcpy(sic.src_mac, msg->msg.rule_create.conn_rule.flow_mac, ETH_ALEN); + memset(sic.src_mac_xlate, 0, ETH_ALEN); + memset(sic.dest_mac, 0, ETH_ALEN); + memcpy(sic.dest_mac_xlate, msg->msg.rule_create.conn_rule.return_mac, ETH_ALEN); + + /* + * Does our input device support IP processing? + */ + src_dev = dev_get_by_index(&init_net, msg->msg.rule_create.conn_rule.flow_top_interface_num); + if (!src_dev || !sfe_drv_dev_is_layer_3_interface(src_dev, true)) { + ret = SFE_CMN_RESPONSE_EINTERFACE; + sfe_drv_incr_exceptions(SFE_DRV_EXCEPTION_SRC_DEV_NOT_L3); + goto failed_ret; + } + + /* + * Does our output device support IP processing? + */ + dest_dev = dev_get_by_index(&init_net, msg->msg.rule_create.conn_rule.return_top_interface_num); + if (!dest_dev || !sfe_drv_dev_is_layer_3_interface(dest_dev, true)) { + ret = SFE_CMN_RESPONSE_EINTERFACE; + sfe_drv_incr_exceptions(SFE_DRV_EXCEPTION_DEST_DEV_NOT_L3); + goto failed_ret; + } + + sic.src_dev = src_dev; + sic.dest_dev = dest_dev; + + sic.src_mtu = msg->msg.rule_create.conn_rule.flow_mtu; + sic.dest_mtu = msg->msg.rule_create.conn_rule.return_mtu; + + if (msg->msg.rule_create.valid_flags & SFE_RULE_CREATE_QOS_VALID) { + sic.src_priority = msg->msg.rule_create.qos_rule.flow_qos_tag; + sic.dest_priority = msg->msg.rule_create.qos_rule.return_qos_tag; + sic.flags |= SFE_CREATE_FLAG_REMARK_PRIORITY; + } + + if (msg->msg.rule_create.valid_flags & SFE_RULE_CREATE_DSCP_MARKING_VALID) { + sic.src_dscp = msg->msg.rule_create.dscp_rule.flow_dscp; + sic.dest_dscp = msg->msg.rule_create.dscp_rule.return_dscp; + sic.flags |= SFE_CREATE_FLAG_REMARK_DSCP; + } + +#ifdef CONFIG_XFRM + if (msg->msg.rule_create.valid_flags & SFE_RULE_CREATE_DIRECTION_VALID) { + sic.original_accel = msg->msg.rule_create.direction_rule.flow_accel; + sic.reply_accel = msg->msg.rule_create.direction_rule.return_accel; + } else { + sic.original_accel = sic.reply_accel = 1; + } +#endif + + if (!sfe_ipv4_create_rule(&sic)) { + /* success */ + ret = SFE_CMN_RESPONSE_ACK; + } else { + /* failed */ + ret = SFE_CMN_RESPONSE_EMSG; + sfe_drv_incr_exceptions(SFE_DRV_EXCEPTION_CREATE_FAILED); + } + + /* + * fall through + */ +failed_ret: + if (src_dev) { + dev_put(src_dev); + } + + if (dest_dev) { + dev_put(dest_dev); + } + + /* + * try to queue response message + */ + ((struct sfe_ipv4_msg *)response->msg)->cm.response = msg->cm.response = ret; + sfe_drv_enqueue_msg(sfe_drv_ctx, response); + + return SFE_TX_SUCCESS; +} + +/* + * sfe_drv_destroy_ipv4_rule_msg() + * convert destroy message format from ecm to sfe + * + * @param sfe_drv_ctx sfe driver context + * @param msg The IPv4 message + * + * @return sfe_tx_status_t The status of the Tx operation + */ +sfe_tx_status_t sfe_drv_destroy_ipv4_rule_msg(struct sfe_drv_ctx_instance_internal *sfe_drv_ctx, struct sfe_ipv4_msg *msg) +{ + struct sfe_connection_destroy sid; + struct sfe_drv_response_msg *response; + + response = sfe_drv_alloc_response_msg(SFE_DRV_MSG_TYPE_IPV4, msg); + if (!response) { + sfe_drv_incr_exceptions(SFE_DRV_EXCEPTION_ENQUEUE_FAILED); + return SFE_TX_FAILURE_QUEUE; + } + + sid.protocol = msg->msg.rule_destroy.tuple.protocol; + sid.src_ip.ip = msg->msg.rule_destroy.tuple.flow_ip; + sid.dest_ip.ip = msg->msg.rule_destroy.tuple.return_ip; + sid.src_port = msg->msg.rule_destroy.tuple.flow_ident; + sid.dest_port = msg->msg.rule_destroy.tuple.return_ident; + + sfe_ipv4_destroy_rule(&sid); + + /* + * try to queue response message + */ + ((struct sfe_ipv4_msg *)response->msg)->cm.response = msg->cm.response = SFE_CMN_RESPONSE_ACK; + sfe_drv_enqueue_msg(sfe_drv_ctx, response); + + return SFE_TX_SUCCESS; +} + +/* + * sfe_drv_ipv4_tx() + * Transmit an IPv4 message to the sfe + * + * @param sfe_drv_ctx sfe driver context + * @param msg The IPv4 message + * + * @return sfe_tx_status_t The status of the Tx operation + */ +sfe_tx_status_t sfe_drv_ipv4_tx(struct sfe_drv_ctx_instance *sfe_drv_ctx, struct sfe_ipv4_msg *msg) +{ + switch (msg->cm.type) { + case SFE_TX_CREATE_RULE_MSG: + return sfe_drv_create_ipv4_rule_msg(SFE_DRV_CTX_TO_PRIVATE(sfe_drv_ctx), msg); + case SFE_TX_DESTROY_RULE_MSG: + return sfe_drv_destroy_ipv4_rule_msg(SFE_DRV_CTX_TO_PRIVATE(sfe_drv_ctx), msg); + default: + sfe_drv_incr_exceptions(SFE_DRV_EXCEPTION_IPV4_MSG_UNKNOW); + return SFE_TX_FAILURE_NOT_ENABLED; + } +} +EXPORT_SYMBOL(sfe_drv_ipv4_tx); + +/* + * sfe_ipv4_msg_init() + * Initialize IPv4 message. + */ +void sfe_ipv4_msg_init(struct sfe_ipv4_msg *nim, u16 if_num, u32 type, u32 len, + sfe_ipv4_msg_callback_t cb, void *app_data) +{ + sfe_cmn_msg_init(&nim->cm, if_num, type, len, (void *)cb, app_data); +} +EXPORT_SYMBOL(sfe_ipv4_msg_init); + +/* + * sfe_drv_ipv4_max_conn_count() + * return maximum number of entries SFE supported + */ +int sfe_drv_ipv4_max_conn_count(void) +{ + return SFE_MAX_CONNECTION_NUM; +} +EXPORT_SYMBOL(sfe_drv_ipv4_max_conn_count); + +/* + * sfe_drv_ipv4_notify_register() + * Register a notifier callback for IPv4 messages from sfe driver + * + * @param cb The callback pointer + * @param app_data The application context for this message + * + * @return struct sfe_drv_ctx_instance * The sfe driver context + */ +struct sfe_drv_ctx_instance *sfe_drv_ipv4_notify_register(sfe_ipv4_msg_callback_t cb, void *app_data) +{ + struct sfe_drv_ctx_instance_internal *sfe_drv_ctx = &__sfe_drv_ctx; + + spin_lock_bh(&sfe_drv_ctx->lock); + /* + * Hook the shortcut sync callback. + */ + if (cb && !sfe_drv_ctx->ipv4_stats_sync_cb) { + sfe_ipv4_register_sync_rule_callback(sfe_drv_ipv4_stats_sync_callback); + } + + rcu_assign_pointer(sfe_drv_ctx->ipv4_stats_sync_cb, cb); + sfe_drv_ctx->ipv4_stats_sync_data = app_data; + + spin_unlock_bh(&sfe_drv_ctx->lock); + + return SFE_DRV_CTX_TO_PUBLIC(sfe_drv_ctx); +} +EXPORT_SYMBOL(sfe_drv_ipv4_notify_register); + +/* + * sfe_drv_ipv4_notify_unregister() + * Un-Register a notifier callback for IPv4 messages from sfe driver + */ +void sfe_drv_ipv4_notify_unregister(void) +{ + struct sfe_drv_ctx_instance_internal *sfe_drv_ctx = &__sfe_drv_ctx; + + spin_lock_bh(&sfe_drv_ctx->lock); + /* + * Unregister our sync callback. + */ + if (sfe_drv_ctx->ipv4_stats_sync_cb) { + sfe_ipv4_register_sync_rule_callback(NULL); + rcu_assign_pointer(sfe_drv_ctx->ipv4_stats_sync_cb, NULL); + sfe_drv_ctx->ipv4_stats_sync_data = NULL; + } + spin_unlock_bh(&sfe_drv_ctx->lock); + + sfe_drv_clean_response_msg_by_type(sfe_drv_ctx, SFE_DRV_MSG_TYPE_IPV4); + + return; +} +EXPORT_SYMBOL(sfe_drv_ipv4_notify_unregister); + +/* + * sfe_drv_ipv6_stats_sync_callback() + * Synchronize a connection's state. + */ +static void sfe_drv_ipv6_stats_sync_callback(struct sfe_connection_sync *sis) +{ + struct sfe_drv_ctx_instance_internal *sfe_drv_ctx = &__sfe_drv_ctx; + struct sfe_ipv6_msg msg; + struct sfe_ipv6_conn_sync *sync_msg; + sfe_ipv6_msg_callback_t sync_cb; + + rcu_read_lock(); + sync_cb = rcu_dereference(sfe_drv_ctx->ipv6_stats_sync_cb); + if (!sync_cb) { + rcu_read_unlock(); + sfe_drv_incr_exceptions(SFE_DRV_EXCEPTION_NO_SYNC_CB); + return; + } + + sync_msg = &msg.msg.conn_stats; + + memset(&msg, 0, sizeof(msg)); + sfe_cmn_msg_init(&msg.cm, 0, SFE_RX_CONN_STATS_SYNC_MSG, + sizeof(struct sfe_ipv6_conn_sync), NULL, NULL); + + /* + * fill connection specific information + */ + sync_msg->protocol = (u8)sis->protocol; + sfe_drv_ipv6_addr_copy(sis->src_ip.ip6, sync_msg->flow_ip); + sync_msg->flow_ident = sis->src_port; + + sfe_drv_ipv6_addr_copy(sis->dest_ip.ip6, sync_msg->return_ip); + sync_msg->return_ident = sis->dest_port; + + /* + * fill TCP protocol specific information + */ + if (sis->protocol == IPPROTO_TCP) { + sync_msg->flow_max_window = sis->src_td_max_window; + sync_msg->flow_end = sis->src_td_end; + sync_msg->flow_max_end = sis->src_td_max_end; + + sync_msg->return_max_window = sis->dest_td_max_window; + sync_msg->return_end = sis->dest_td_end; + sync_msg->return_max_end = sis->dest_td_max_end; + } + + /* + * fill statistics information + */ + sync_msg->flow_rx_packet_count = sis->src_new_packet_count; + sync_msg->flow_rx_byte_count = sis->src_new_byte_count; + sync_msg->flow_tx_packet_count = sis->dest_new_packet_count; + sync_msg->flow_tx_byte_count = sis->dest_new_byte_count; + + sync_msg->return_rx_packet_count = sis->dest_new_packet_count; + sync_msg->return_rx_byte_count = sis->dest_new_byte_count; + sync_msg->return_tx_packet_count = sis->src_new_packet_count; + sync_msg->return_tx_byte_count = sis->src_new_byte_count; + + /* + * fill expiration time to extend, in unit of msec + */ + sync_msg->inc_ticks = (((u32)sis->delta_jiffies) * MSEC_PER_SEC)/HZ; + + /* + * fill other information + */ + switch (sis->reason) { + case SFE_SYNC_REASON_DESTROY: + sync_msg->reason = SFE_RULE_SYNC_REASON_DESTROY; + break; + case SFE_SYNC_REASON_FLUSH: + sync_msg->reason = SFE_RULE_SYNC_REASON_FLUSH; + break; + default: + sync_msg->reason = SFE_RULE_SYNC_REASON_STATS; + break; + } + + /* + * SFE sync calling is excuted in a timer, so we can redirect it to ECM directly. + */ + sync_cb(sfe_drv_ctx->ipv6_stats_sync_data, &msg); + rcu_read_unlock(); +} + +/* + * sfe_drv_create_ipv6_rule_msg() + * convert create message format from ecm to sfe + * + * @param sfe_drv_ctx sfe driver context + * @param msg The IPv6 message + * + * @return sfe_tx_status_t The status of the Tx operation + */ +sfe_tx_status_t sfe_drv_create_ipv6_rule_msg(struct sfe_drv_ctx_instance_internal *sfe_drv_ctx, struct sfe_ipv6_msg *msg) +{ + struct sfe_connection_create sic; + struct net_device *src_dev = NULL; + struct net_device *dest_dev = NULL; + struct sfe_drv_response_msg *response; + enum sfe_cmn_response ret; + + response = sfe_drv_alloc_response_msg(SFE_DRV_MSG_TYPE_IPV6, msg); + if (!response) { + sfe_drv_incr_exceptions(SFE_DRV_EXCEPTION_ENQUEUE_FAILED); + return SFE_TX_FAILURE_QUEUE; + } + + if (!(msg->msg.rule_create.valid_flags & SFE_RULE_CREATE_CONN_VALID)) { + ret = SFE_CMN_RESPONSE_EMSG; + sfe_drv_incr_exceptions(SFE_DRV_EXCEPTION_CONNECTION_INVALID); + goto failed_ret; + } + + /* + * not support bridged flows now + */ + if (msg->msg.rule_create.rule_flags & SFE_RULE_CREATE_FLAG_BRIDGE_FLOW) { + ret = SFE_CMN_RESPONSE_EINTERFACE; + sfe_drv_incr_exceptions(SFE_DRV_EXCEPTION_NOT_SUPPORT_BRIDGE); + goto failed_ret; + } + + sic.protocol = msg->msg.rule_create.tuple.protocol; + sfe_drv_ipv6_addr_copy(msg->msg.rule_create.tuple.flow_ip, sic.src_ip.ip6); + sfe_drv_ipv6_addr_copy(msg->msg.rule_create.tuple.return_ip, sic.dest_ip.ip6); + sfe_drv_ipv6_addr_copy(msg->msg.rule_create.tuple.flow_ip, sic.src_ip_xlate.ip6); + sfe_drv_ipv6_addr_copy(msg->msg.rule_create.tuple.return_ip, sic.dest_ip_xlate.ip6); + + sic.flags = 0; + switch (sic.protocol) { + case IPPROTO_TCP: + if (!(msg->msg.rule_create.valid_flags & SFE_RULE_CREATE_TCP_VALID)) { + ret = SFE_CMN_RESPONSE_EMSG; + sfe_drv_incr_exceptions(SFE_DRV_EXCEPTION_TCP_INVALID); + goto failed_ret; + } + + sic.src_port = msg->msg.rule_create.tuple.flow_ident; + sic.dest_port = msg->msg.rule_create.tuple.return_ident; + sic.src_port_xlate = msg->msg.rule_create.tuple.flow_ident; + sic.dest_port_xlate = msg->msg.rule_create.tuple.return_ident; + sic.src_td_window_scale = msg->msg.rule_create.tcp_rule.flow_window_scale; + sic.src_td_max_window = msg->msg.rule_create.tcp_rule.flow_max_window; + sic.src_td_end = msg->msg.rule_create.tcp_rule.flow_end; + sic.src_td_max_end = msg->msg.rule_create.tcp_rule.flow_max_end; + sic.dest_td_window_scale = msg->msg.rule_create.tcp_rule.return_window_scale; + sic.dest_td_max_window = msg->msg.rule_create.tcp_rule.return_max_window; + sic.dest_td_end = msg->msg.rule_create.tcp_rule.return_end; + sic.dest_td_max_end = msg->msg.rule_create.tcp_rule.return_max_end; + if (msg->msg.rule_create.rule_flags & SFE_RULE_CREATE_FLAG_NO_SEQ_CHECK) { + sic.flags |= SFE_CREATE_FLAG_NO_SEQ_CHECK; + } + break; + + case IPPROTO_UDP: + sic.src_port = msg->msg.rule_create.tuple.flow_ident; + sic.dest_port = msg->msg.rule_create.tuple.return_ident; + sic.src_port_xlate = msg->msg.rule_create.tuple.flow_ident; + sic.dest_port_xlate = msg->msg.rule_create.tuple.return_ident; + break; + + default: + ret = SFE_CMN_RESPONSE_EMSG; + sfe_drv_incr_exceptions(SFE_DRV_EXCEPTION_PROTOCOL_NOT_SUPPORT); + goto failed_ret; + } + + memcpy(sic.src_mac, msg->msg.rule_create.conn_rule.flow_mac, ETH_ALEN); + memset(sic.src_mac_xlate, 0, ETH_ALEN); + memset(sic.dest_mac, 0, ETH_ALEN); + memcpy(sic.dest_mac_xlate, msg->msg.rule_create.conn_rule.return_mac, ETH_ALEN); + /* + * Does our input device support IP processing? + */ + src_dev = dev_get_by_index(&init_net, msg->msg.rule_create.conn_rule.flow_top_interface_num); + if (!src_dev || !sfe_drv_dev_is_layer_3_interface(src_dev, false)) { + ret = SFE_CMN_RESPONSE_EINTERFACE; + sfe_drv_incr_exceptions(SFE_DRV_EXCEPTION_SRC_DEV_NOT_L3); + goto failed_ret; + } + + /* + * Does our output device support IP processing? + */ + dest_dev = dev_get_by_index(&init_net, msg->msg.rule_create.conn_rule.return_top_interface_num); + if (!dest_dev || !sfe_drv_dev_is_layer_3_interface(dest_dev, false)) { + ret = SFE_CMN_RESPONSE_EINTERFACE; + sfe_drv_incr_exceptions(SFE_DRV_EXCEPTION_DEST_DEV_NOT_L3); + goto failed_ret; + } + + sic.src_dev = src_dev; + sic.dest_dev = dest_dev; + + sic.src_mtu = msg->msg.rule_create.conn_rule.flow_mtu; + sic.dest_mtu = msg->msg.rule_create.conn_rule.return_mtu; + + if (msg->msg.rule_create.valid_flags & SFE_RULE_CREATE_QOS_VALID) { + sic.src_priority = msg->msg.rule_create.qos_rule.flow_qos_tag; + sic.dest_priority = msg->msg.rule_create.qos_rule.return_qos_tag; + sic.flags |= SFE_CREATE_FLAG_REMARK_PRIORITY; + } + + if (msg->msg.rule_create.valid_flags & SFE_RULE_CREATE_DSCP_MARKING_VALID) { + sic.src_dscp = msg->msg.rule_create.dscp_rule.flow_dscp; + sic.dest_dscp = msg->msg.rule_create.dscp_rule.return_dscp; + sic.flags |= SFE_CREATE_FLAG_REMARK_DSCP; + } + +#ifdef CONFIG_XFRM + if (msg->msg.rule_create.valid_flags & SFE_RULE_CREATE_DIRECTION_VALID) { + sic.original_accel = msg->msg.rule_create.direction_rule.flow_accel; + sic.reply_accel = msg->msg.rule_create.direction_rule.return_accel; + } else { + sic.original_accel = sic.reply_accel = 1; + } +#endif + + if (!sfe_ipv6_create_rule(&sic)) { + /* success */ + ret = SFE_CMN_RESPONSE_ACK; + } else { + /* failed */ + ret = SFE_CMN_RESPONSE_EMSG; + sfe_drv_incr_exceptions(SFE_DRV_EXCEPTION_CREATE_FAILED); + } + + /* + * fall through + */ +failed_ret: + if (src_dev) { + dev_put(src_dev); + } + + if (dest_dev) { + dev_put(dest_dev); + } + + /* + * try to queue response message + */ + ((struct sfe_ipv6_msg *)response->msg)->cm.response = msg->cm.response = ret; + sfe_drv_enqueue_msg(sfe_drv_ctx, response); + + return SFE_TX_SUCCESS; +} + +/* + * sfe_drv_destroy_ipv6_rule_msg() + * convert destroy message format from ecm to sfe + * + * @param sfe_drv_ctx sfe driver context + * @param msg The IPv6 message + * + * @return sfe_tx_status_t The status of the Tx operation + */ +sfe_tx_status_t sfe_drv_destroy_ipv6_rule_msg(struct sfe_drv_ctx_instance_internal *sfe_drv_ctx, struct sfe_ipv6_msg *msg) +{ + struct sfe_connection_destroy sid; + struct sfe_drv_response_msg *response; + + response = sfe_drv_alloc_response_msg(SFE_DRV_MSG_TYPE_IPV6, msg); + if (!response) { + sfe_drv_incr_exceptions(SFE_DRV_EXCEPTION_ENQUEUE_FAILED); + return SFE_TX_FAILURE_QUEUE; + } + + sid.protocol = msg->msg.rule_destroy.tuple.protocol; + sfe_drv_ipv6_addr_copy(msg->msg.rule_destroy.tuple.flow_ip, sid.src_ip.ip6); + sfe_drv_ipv6_addr_copy(msg->msg.rule_destroy.tuple.return_ip, sid.dest_ip.ip6); + sid.src_port = msg->msg.rule_destroy.tuple.flow_ident; + sid.dest_port = msg->msg.rule_destroy.tuple.return_ident; + + sfe_ipv6_destroy_rule(&sid); + + /* + * try to queue response message + */ + ((struct sfe_ipv6_msg *)response->msg)->cm.response = msg->cm.response = SFE_CMN_RESPONSE_ACK; + sfe_drv_enqueue_msg(sfe_drv_ctx, response); + + return SFE_TX_SUCCESS; +} + +/* + * sfe_drv_ipv6_tx() + * Transmit an IPv6 message to the sfe + * + * @param sfe_drv_ctx sfe driver context + * @param msg The IPv6 message + * + * @return sfe_tx_status_t The status of the Tx operation + */ +sfe_tx_status_t sfe_drv_ipv6_tx(struct sfe_drv_ctx_instance *sfe_drv_ctx, struct sfe_ipv6_msg *msg) +{ + switch (msg->cm.type) { + case SFE_TX_CREATE_RULE_MSG: + return sfe_drv_create_ipv6_rule_msg(SFE_DRV_CTX_TO_PRIVATE(sfe_drv_ctx), msg); + case SFE_TX_DESTROY_RULE_MSG: + return sfe_drv_destroy_ipv6_rule_msg(SFE_DRV_CTX_TO_PRIVATE(sfe_drv_ctx), msg); + default: + sfe_drv_incr_exceptions(SFE_DRV_EXCEPTION_IPV6_MSG_UNKNOW); + return SFE_TX_FAILURE_NOT_ENABLED; + } +} +EXPORT_SYMBOL(sfe_drv_ipv6_tx); + +/* + * sfe_ipv6_msg_init() + * Initialize IPv6 message. + */ +void sfe_ipv6_msg_init(struct sfe_ipv6_msg *nim, u16 if_num, u32 type, u32 len, + sfe_ipv6_msg_callback_t cb, void *app_data) +{ + sfe_cmn_msg_init(&nim->cm, if_num, type, len, (void *)cb, app_data); +} +EXPORT_SYMBOL(sfe_ipv6_msg_init); + +/* + * sfe_drv_ipv6_max_conn_count() + * return maximum number of entries SFE supported + */ +int sfe_drv_ipv6_max_conn_count(void) +{ + return SFE_MAX_CONNECTION_NUM; +} +EXPORT_SYMBOL(sfe_drv_ipv6_max_conn_count); + +/* + * sfe_drv_ipv6_notify_register() + * Register a notifier callback for IPv6 messages from sfe driver + * + * @param cb The callback pointer + * @param app_data The application context for this message + * + * @return struct sfe_drv_ctx_instance * The sfe driver context + */ +struct sfe_drv_ctx_instance *sfe_drv_ipv6_notify_register(sfe_ipv6_msg_callback_t cb, void *app_data) +{ + struct sfe_drv_ctx_instance_internal *sfe_drv_ctx = &__sfe_drv_ctx; + + spin_lock_bh(&sfe_drv_ctx->lock); + /* + * Hook the shortcut sync callback. + */ + if (cb && !sfe_drv_ctx->ipv6_stats_sync_cb) { + sfe_ipv6_register_sync_rule_callback(sfe_drv_ipv6_stats_sync_callback); + } + + rcu_assign_pointer(sfe_drv_ctx->ipv6_stats_sync_cb, cb); + sfe_drv_ctx->ipv6_stats_sync_data = app_data; + + spin_unlock_bh(&sfe_drv_ctx->lock); + + return SFE_DRV_CTX_TO_PUBLIC(sfe_drv_ctx); +} +EXPORT_SYMBOL(sfe_drv_ipv6_notify_register); + +/* + * sfe_drv_ipv6_notify_unregister() + * Un-Register a notifier callback for IPv6 messages from sfe driver + */ +void sfe_drv_ipv6_notify_unregister(void) +{ + struct sfe_drv_ctx_instance_internal *sfe_drv_ctx = &__sfe_drv_ctx; + + spin_lock_bh(&sfe_drv_ctx->lock); + /* + * Unregister our sync callback. + */ + if (sfe_drv_ctx->ipv6_stats_sync_cb) { + sfe_ipv6_register_sync_rule_callback(NULL); + rcu_assign_pointer(sfe_drv_ctx->ipv6_stats_sync_cb, NULL); + sfe_drv_ctx->ipv6_stats_sync_data = NULL; + } + spin_unlock_bh(&sfe_drv_ctx->lock); + + sfe_drv_clean_response_msg_by_type(sfe_drv_ctx, SFE_DRV_MSG_TYPE_IPV6); + + return; +} +EXPORT_SYMBOL(sfe_drv_ipv6_notify_unregister); + +/* + * sfe_tun6rd_tx() + * Transmit a tun6rd message to sfe engine + */ +sfe_tx_status_t sfe_tun6rd_tx(struct sfe_drv_ctx_instance *sfe_drv_ctx, struct sfe_tun6rd_msg *msg) +{ + sfe_drv_incr_exceptions(SFE_DRV_EXCEPTION_NOT_SUPPORT_6RD); + return SFE_TX_FAILURE_NOT_ENABLED; +} +EXPORT_SYMBOL(sfe_tun6rd_tx); + +/* + * sfe_tun6rd_msg_init() + * Initialize sfe_tun6rd msg. + */ +void sfe_tun6rd_msg_init(struct sfe_tun6rd_msg *ncm, u16 if_num, u32 type, u32 len, void *cb, void *app_data) +{ + sfe_cmn_msg_init(&ncm->cm, if_num, type, len, cb, app_data); +} +EXPORT_SYMBOL(sfe_tun6rd_msg_init); + +/* + * sfe_drv_recv() + * Handle packet receives. + * + * Returns 1 if the packet is forwarded or 0 if it isn't. + */ +int sfe_drv_recv(struct sk_buff *skb) +{ + struct net_device *dev; + + /* + * We know that for the vast majority of packets we need the transport + * layer header so we may as well start to fetch it now! + */ + prefetch(skb->data + 32); + barrier(); + + dev = skb->dev; + +/* + * TODO: Remove the check when INgress Qdisc is ported to 5.4 kernel. + */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 4, 0)) +#ifdef CONFIG_NET_CLS_ACT + /* + * If ingress Qdisc configured, and packet not processed by ingress Qdisc yet + * We can not accelerate this packet. + */ + if (dev->ingress_queue && !(skb->tc_verd & TC_NCLS)) { + return 0; + } +#endif +#endif + + /* + * We're only interested in IPv4 and IPv6 packets. + */ + if (likely(htons(ETH_P_IP) == skb->protocol)) { + if (sfe_drv_dev_is_layer_3_interface(dev, true)) { + return sfe_ipv4_recv(dev, skb); + } else { + DEBUG_TRACE("no IPv4 address for device: %s\n", dev->name); + return 0; + } + } + + if (likely(htons(ETH_P_IPV6) == skb->protocol)) { + if (sfe_drv_dev_is_layer_3_interface(dev, false)) { + return sfe_ipv6_recv(dev, skb); + } else { + DEBUG_TRACE("no IPv6 address for device: %s\n", dev->name); + return 0; + } + } + + DEBUG_TRACE("not IP packet\n"); + return 0; +} + +/* + * sfe_drv_get_exceptions() + * dump exception counters + */ +static ssize_t sfe_drv_get_exceptions(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int idx, len; + struct sfe_drv_ctx_instance_internal *sfe_drv_ctx = &__sfe_drv_ctx; + + spin_lock_bh(&sfe_drv_ctx->lock); + for (len = 0, idx = 0; idx < SFE_DRV_EXCEPTION_MAX; idx++) { + if (sfe_drv_ctx->exceptions[idx]) { + len += snprintf(buf + len, (ssize_t)(PAGE_SIZE - len), "%s = %d\n", sfe_drv_exception_events_string[idx], sfe_drv_ctx->exceptions[idx]); + } + } + spin_unlock_bh(&sfe_drv_ctx->lock); + + return len; +} + +/* + * sysfs attributes. + */ +static const struct device_attribute sfe_drv_exceptions_attr = + __ATTR(exceptions, S_IRUGO, sfe_drv_get_exceptions, NULL); + +/* + * sfe_drv_init() + */ +static int __init sfe_drv_init(void) +{ + struct sfe_drv_ctx_instance_internal *sfe_drv_ctx = &__sfe_drv_ctx; + int result = -1; + + /* + * Create sys/sfe_drv + */ + sfe_drv_ctx->sys_sfe_drv = kobject_create_and_add("sfe_drv", NULL); + if (!sfe_drv_ctx->sys_sfe_drv) { + DEBUG_ERROR("failed to register sfe_drv\n"); + goto exit1; + } + + /* + * Create sys/sfe_drv/exceptions + */ + result = sysfs_create_file(sfe_drv_ctx->sys_sfe_drv, &sfe_drv_exceptions_attr.attr); + if (result) { + DEBUG_ERROR("failed to register exceptions file: %d\n", result); + goto exit2; + } + + spin_lock_init(&sfe_drv_ctx->lock); + + INIT_LIST_HEAD(&sfe_drv_ctx->msg_queue); + INIT_WORK(&sfe_drv_ctx->work, sfe_drv_process_response_msg); + + /* + * Hook the receive path in the network stack. + */ + BUG_ON(athrs_fast_nat_recv); + RCU_INIT_POINTER(athrs_fast_nat_recv, sfe_drv_recv); + + return 0; +exit2: + kobject_put(sfe_drv_ctx->sys_sfe_drv); +exit1: + return result; +} + +/* + * sfe_drv_exit() + */ +static void __exit sfe_drv_exit(void) +{ + struct sfe_drv_ctx_instance_internal *sfe_drv_ctx = &__sfe_drv_ctx; + + /* + * Unregister our receive callback. + */ + RCU_INIT_POINTER(athrs_fast_nat_recv, NULL); + + /* + * Wait for all callbacks to complete. + */ + rcu_barrier(); + + /* + * Destroy all connections. + */ + sfe_ipv4_destroy_all_rules_for_dev(NULL); + sfe_ipv6_destroy_all_rules_for_dev(NULL); + + /* + * stop work queue, and flush all pending message in queue + */ + cancel_work_sync(&sfe_drv_ctx->work); + sfe_drv_process_response_msg(&sfe_drv_ctx->work); + + /* + * Unregister our sync callback. + */ + sfe_drv_ipv4_notify_unregister(); + sfe_drv_ipv6_notify_unregister(); + + kobject_put(sfe_drv_ctx->sys_sfe_drv); + + return; +} + +module_init(sfe_drv_init) +module_exit(sfe_drv_exit) + +MODULE_AUTHOR("Qualcomm Atheros Inc."); +MODULE_DESCRIPTION("Simulated driver for Shortcut Forwarding Engine"); +MODULE_LICENSE("Dual BSD/GPL"); + diff --git a/shortcut-fe/simulated-driver/sfe_drv.h b/shortcut-fe/simulated-driver/sfe_drv.h new file mode 100644 index 000000000..729caffd3 --- /dev/null +++ b/shortcut-fe/simulated-driver/sfe_drv.h @@ -0,0 +1,553 @@ +/* + * sfe_drv.h + * simulated driver headers for shortcut forwarding engine. + * + * Copyright (c) 2015,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. + */ + +#ifndef __SFE_DRV_H +#define __SFE_DRV_H + +#define MAX_VLAN_DEPTH 2 +#define SFE_VLAN_ID_NOT_CONFIGURED 0xfff +#define SFE_MC_IF_MAX 16 + +#define SFE_SPECIAL_INTERFACE_BASE 0x7f00 +#define SFE_SPECIAL_INTERFACE_IPV4 (SFE_SPECIAL_INTERFACE_BASE + 1) +#define SFE_SPECIAL_INTERFACE_IPV6 (SFE_SPECIAL_INTERFACE_BASE + 2) +#define SFE_SPECIAL_INTERFACE_IPSEC (SFE_SPECIAL_INTERFACE_BASE + 3) +#define SFE_SPECIAL_INTERFACE_L2TP (SFE_SPECIAL_INTERFACE_BASE + 4) +#define SFE_SPECIAL_INTERFACE_PPTP (SFE_SPECIAL_INTERFACE_BASE + 5) + +/** + * Rule creation & rule update flags. + */ +#define SFE_RULE_CREATE_FLAG_NO_SEQ_CHECK (1<<0) /**< Do not perform TCP sequence number checks */ +#define SFE_RULE_CREATE_FLAG_BRIDGE_FLOW (1<<1) /**< This is a pure bridge forwarding flow */ +#define SFE_RULE_CREATE_FLAG_ROUTED (1<<2) /**< Rule is for a routed connection */ +#define SFE_RULE_CREATE_FLAG_DSCP_MARKING (1<<3) /**< Rule has for a DSCP marking configured*/ +#define SFE_RULE_CREATE_FLAG_VLAN_MARKING (1<<4) /**< Rule has for a VLAN marking configured*/ +#define SFE_RULE_UPDATE_FLAG_CHANGE_MTU (1<<5) /**< Update MTU of connection interfaces */ +#define SFE_RULE_CREATE_FLAG_ICMP_NO_CME_FLUSH (1<<6)/**< Rule for not flushing CME on ICMP pkt */ +#define SFE_RULE_CREATE_FLAG_L2_ENCAP (1<<7) /**< consists of an encapsulating protocol that carries an IPv4 payload within it. */ +#define SFE_RULE_CREATE_FLAG_MC_JOIN (1<<8) /**< Interface has joined the flow */ +#define SFE_RULE_CREATE_FLAG_MC_LEAVE (1<<9) /**< Interface has left the flow */ +#define SFE_RULE_CREATE_FLAG_MC_UPDATE (1<<10)/**< Multicast Rule update */ +/** + * Rule creation validity flags. + */ +#define SFE_RULE_CREATE_CONN_VALID (1<<0) /**< IPv4 Connection is valid */ +#define SFE_RULE_CREATE_TCP_VALID (1<<1) /**< TCP Protocol fields are valid */ +#define SFE_RULE_CREATE_PPPOE_VALID (1<<2) /**< PPPoE fields are valid */ +#define SFE_RULE_CREATE_QOS_VALID (1<<3) /**< QoS fields are valid */ +#define SFE_RULE_CREATE_VLAN_VALID (1<<4) /**< VLAN fields are valid */ +#define SFE_RULE_CREATE_DSCP_MARKING_VALID (1<<5) /**< DSCP marking fields are valid */ +#define SFE_RULE_CREATE_VLAN_MARKING_VALID (1<<6) /**< VLAN marking fields are valid */ +#define SFE_RULE_CREATE_MC_NAT_VALID (1<<7) /**< Interface is configured with Source-NAT */ +#define SFE_RULE_CREATE_DIRECTION_VALID (1<<8) /**< specify acceleration directions */ + +/* + * 32/64 bits pointer type + */ +#ifdef __LP64__ +typedef uint64_t sfe_ptr_t; +#else +typedef uint32_t sfe_ptr_t; +#endif + +typedef enum sfe_rule_sync_reason { + SFE_RULE_SYNC_REASON_STATS, /* Sync is to synchronize stats */ + SFE_RULE_SYNC_REASON_FLUSH, /* Sync is to flush a entry */ + SFE_RULE_SYNC_REASON_EVICT, /* Sync is to evict a entry */ + SFE_RULE_SYNC_REASON_DESTROY /* Sync is to destroy a entry(requested by connection manager) */ + +} sfe_rule_sync_reason_t; + +/** + * Tx command status + */ +typedef enum { + SFE_TX_SUCCESS = 0, /**< Success */ + SFE_TX_FAILURE, /**< Command failure other than descriptor not available */ + SFE_TX_FAILURE_QUEUE, /**< Command failure due to descriptor not available */ + SFE_TX_FAILURE_NOT_READY, /**< Command failure due to SFE state uninitialized */ + SFE_TX_FAILURE_TOO_LARGE, /**< Command is too large to fit in one message */ + SFE_TX_FAILURE_TOO_SHORT, /**< Command/Packet is shorter than expected size */ + SFE_TX_FAILURE_NOT_SUPPORTED, /**< Command/Packet not accepted for forwarding */ + SFE_TX_FAILURE_BAD_PARAM, /**< Command failure due to bad parameters */ + SFE_TX_FAILURE_NOT_ENABLED, /**< Command failure due to SFE feature is not enabled */ +} sfe_tx_status_t; + +/** + * Common response structure + */ +enum sfe_cmn_response { + SFE_CMN_RESPONSE_ACK, /**< Message Acknowledge */ + SFE_CMN_RESPONSE_EVERSION, /**< Message Version Error */ + SFE_CMN_RESPONSE_EINTERFACE, /**< Message Interface Error */ + SFE_CMN_RESPONSE_ELENGTH, /**< Message Length Error */ + SFE_CMN_RESPONSE_EMSG, /**< Message Error */ + SFE_CMM_RESPONSE_NOTIFY, /**< Message Independant of Request */ + SFE_CMN_RESPONSE_LAST +}; + +/** + * IPv4 bridge/route rule messages + */ +enum sfe_message_types { + SFE_TX_CREATE_RULE_MSG, /**< IPv4/6 create rule message */ + SFE_TX_DESTROY_RULE_MSG, /**< IPv4/6 destroy rule message */ + SFE_RX_CONN_STATS_SYNC_MSG, /**< IPv4/6 connection stats sync message */ + SFE_TX_CREATE_MC_RULE_MSG, /**< IPv4/6 multicast create rule message */ + SFE_TUN6RD_ADD_UPDATE_PEER, /**< Add/update peer for 6rd tunnel */ + SFE_MAX_MSG_TYPES, /**< IPv4/6 message max type number */ +}; + +/** + * Common message structure + */ +struct sfe_cmn_msg { + u16 version; /**< Version id for main message format */ + u16 interface; /**< Primary Key for all messages */ + enum sfe_cmn_response response; /**< Primary response */ + u32 type; /**< Decetralized request #, to be used to match response # */ + u32 error; /**< Decentralized specific error message, response == EMSG */ + sfe_ptr_t cb; /**< Place for callback pointer */ + sfe_ptr_t app_data; /**< Place for app data */ + u32 len; /**< What is the length of the message excluding this header */ +}; + +/** + * Common 5 tuple structure + */ +struct sfe_ipv4_5tuple { + __be32 flow_ip; /**< Flow IP address */ + __be32 return_ip; /**< Return IP address */ + __be16 flow_ident; /**< Flow ident (e.g. TCP/UDP port) */ + __be16 return_ident; /**< Return ident (e.g. TCP/UDP port) */ + u8 protocol; /**< Protocol number */ + u8 reserved[3]; /**< Padded for alignment */ +}; + +/** + * Common 5 tuple structure + */ +struct sfe_ipv6_5tuple { + __be32 flow_ip[4]; /**< Flow IP address */ + __be32 return_ip[4]; /**< Return IP address */ + __be16 flow_ident; /**< Flow ident (e.g. TCP/UDP port) */ + __be16 return_ident; /**< Return ident (e.g. TCP/UDP port) */ + u8 protocol; /**< Protocol number */ + u8 reserved[3]; /**< Padded for alignment */ +}; + +/** + * Connection create structure + */ +struct sfe_ipv4_connection_rule { + u8 flow_mac[6]; /**< Flow MAC address */ + u8 return_mac[6]; /**< Return MAC address */ + s32 flow_interface_num; /**< Flow interface number */ + s32 return_interface_num; /**< Return interface number */ + s32 flow_top_interface_num; /* Top flow interface number */ + s32 return_top_interface_num;/* Top return interface number */ + u32 flow_mtu; /**< Flow interface`s MTU */ + u32 return_mtu; /**< Return interface`s MTU */ + __be32 flow_ip_xlate; /**< Translated flow IP address */ + __be32 return_ip_xlate; /**< Translated return IP address */ + __be16 flow_ident_xlate; /**< Translated flow ident (e.g. port) */ + __be16 return_ident_xlate; /**< Translated return ident (e.g. port) */ +}; + +/** + * Connection create structure + */ +struct sfe_ipv6_connection_rule { + u8 flow_mac[6]; /**< Flow MAC address */ + u8 return_mac[6]; /**< Return MAC address */ + s32 flow_interface_num; /**< Flow interface number */ + s32 return_interface_num; /**< Return interface number */ + s32 flow_top_interface_num; /* Top flow interface number */ + s32 return_top_interface_num;/* Top return interface number */ + u32 flow_mtu; /**< Flow interface's MTU */ + u32 return_mtu; /**< Return interface's MTU */ +}; + +/** + * TCP connection rule structure + */ +struct sfe_protocol_tcp_rule { + u32 flow_max_window; /**< Flow direction's largest seen window */ + u32 return_max_window; /**< Return direction's largest seen window */ + u32 flow_end; /**< Flow direction's largest seen sequence + segment length */ + u32 return_end; /**< Return direction's largest seen sequence + segment length */ + u32 flow_max_end; /**< Flow direction's largest seen ack + max(1, win) */ + u32 return_max_end; /**< Return direction's largest seen ack + max(1, win) */ + u8 flow_window_scale; /**< Flow direction's window scaling factor */ + u8 return_window_scale; /**< Return direction's window scaling factor */ + u16 reserved; /**< Padded for alignment */ +}; + +/** + * PPPoE connection rules structure + */ +struct sfe_pppoe_rule { + u16 flow_pppoe_session_id; /**< Flow direction`s PPPoE session ID. */ + u16 flow_pppoe_remote_mac[3]; /**< Flow direction`s PPPoE Server MAC address */ + u16 return_pppoe_session_id; /**< Return direction's PPPoE session ID. */ + u16 return_pppoe_remote_mac[3]; /**< Return direction's PPPoE Server MAC address */ +}; + +/** + * QoS connection rule structure + */ +struct sfe_qos_rule { + u32 flow_qos_tag; /**< QoS tag associated with this rule for flow direction */ + u32 return_qos_tag; /**< QoS tag associated with this rule for return direction */ +}; + +/** + * DSCP connection rule structure + */ +struct sfe_dscp_rule { + u8 flow_dscp; /**< Egress DSCP value for flow direction */ + u8 return_dscp; /**< Egress DSCP value for return direction */ + u8 reserved[2]; /**< Padded for alignment */ +}; + +/** + * VLAN connection rule structure + */ +struct sfe_vlan_rule { + u32 ingress_vlan_tag; /**< VLAN Tag for the ingress packets */ + u32 egress_vlan_tag; /**< VLAN Tag for egress packets */ +}; + +/** + * Acceleration direction rule structure + * Sometimes we just want to accelerate traffic in one direction but not in another. + */ +struct sfe_acceleration_direction_rule { + u8 flow_accel; /**< Accelerate in flow direction */ + u8 return_accel; /**< Accelerate in return direction */ + u8 reserved[2]; /**< Padded for alignment */ +}; + +/** + * The IPv4 rule create sub-message structure. + */ +struct sfe_ipv4_rule_create_msg { + /* Request */ + u16 valid_flags; /**< Bit flags associated with the validity of parameters */ + u16 rule_flags; /**< Bit flags associated with the rule */ + + struct sfe_ipv4_5tuple tuple; /**< Holds values of the 5 tuple */ + + struct sfe_ipv4_connection_rule conn_rule; /**< Basic connection specific data */ + struct sfe_protocol_tcp_rule tcp_rule; /**< TCP related accleration parameters */ + struct sfe_pppoe_rule pppoe_rule; /**< PPPoE related accleration parameters */ + struct sfe_qos_rule qos_rule; /**< QoS related accleration parameters */ + struct sfe_dscp_rule dscp_rule; /**< DSCP related accleration parameters */ + struct sfe_vlan_rule vlan_primary_rule; /**< Primary VLAN related accleration parameters */ + struct sfe_vlan_rule vlan_secondary_rule; /**< Secondary VLAN related accleration parameters */ +#ifdef CONFIG_XFRM + struct sfe_acceleration_direction_rule direction_rule;/* Direction related accleration parameters*/ +#endif + /* Response */ + u32 index; /**< Slot ID for cache stats to host OS */ +}; + +/** + * The IPv4 rule destroy sub-message structure. + */ +struct sfe_ipv4_rule_destroy_msg { + struct sfe_ipv4_5tuple tuple; /**< Holds values of the 5 tuple */ +}; + +/** + * The SFE IPv4 rule sync structure. + */ +struct sfe_ipv4_conn_sync { + u32 index; /**< Slot ID for cache stats to host OS */ + u8 protocol; /**< Protocol number */ + __be32 flow_ip; /**< Flow IP address */ + __be32 flow_ip_xlate; /**< Translated flow IP address */ + __be16 flow_ident; /**< Flow ident (e.g. port) */ + __be16 flow_ident_xlate; /**< Translated flow ident (e.g. port) */ + u32 flow_max_window; /**< Flow direction's largest seen window */ + u32 flow_end; /**< Flow direction's largest seen sequence + segment length */ + u32 flow_max_end; /**< Flow direction's largest seen ack + max(1, win) */ + u32 flow_rx_packet_count; /**< Flow interface's RX packet count */ + u32 flow_rx_byte_count; /**< Flow interface's RX byte count */ + u32 flow_tx_packet_count; /**< Flow interface's TX packet count */ + u32 flow_tx_byte_count; /**< Flow interface's TX byte count */ + u16 flow_pppoe_session_id; /**< Flow interface`s PPPoE session ID. */ + u16 flow_pppoe_remote_mac[3]; + /**< Flow interface's PPPoE remote server MAC address if there is any */ + __be32 return_ip; /**< Return IP address */ + __be32 return_ip_xlate; /**< Translated return IP address */ + __be16 return_ident; /**< Return ident (e.g. port) */ + __be16 return_ident_xlate; /**< Translated return ident (e.g. port) */ + u32 return_max_window; /**< Return direction's largest seen window */ + u32 return_end; /**< Return direction's largest seen sequence + segment length */ + u32 return_max_end; /**< Return direction's largest seen ack + max(1, win) */ + u32 return_rx_packet_count; + /**< Return interface's RX packet count */ + u32 return_rx_byte_count; /**< Return interface's RX byte count */ + u32 return_tx_packet_count; + /**< Return interface's TX packet count */ + u32 return_tx_byte_count; /**< Return interface's TX byte count */ + u16 return_pppoe_session_id; + /**< Return interface`s PPPoE session ID. */ + u16 return_pppoe_remote_mac[3]; + /**< Return interface's PPPoE remote server MAC address if there is any */ + u32 inc_ticks; /**< Number of ticks since the last sync */ + u32 reason; /**< Reason for the sync */ + + u8 flags; /**< Bit flags associated with the rule */ + u32 qos_tag; /**< QoS Tag */ + u32 cause; /**< Flush Cause */ +}; + +/* + * Message structure to send/receive IPv4 bridge/route commands + */ +struct sfe_ipv4_msg { + struct sfe_cmn_msg cm; /**< Message Header */ + union { + struct sfe_ipv4_rule_create_msg rule_create; /**< Message: rule create */ + struct sfe_ipv4_rule_destroy_msg rule_destroy; /**< Message: rule destroy */ + struct sfe_ipv4_conn_sync conn_stats; /**< Message: connection stats sync */ + } msg; +}; + +/** + * Callback to be called when IPv4 message is received + */ +typedef void (*sfe_ipv4_msg_callback_t)(void *app_data, struct sfe_ipv4_msg *msg); + +/** + * The IPv6 rule create sub-message structure. + */ +struct sfe_ipv6_rule_create_msg { + /* + * Request + */ + u16 valid_flags; /**< Bit flags associated with the validity of parameters */ + u16 rule_flags; /**< Bit flags associated with the rule */ + struct sfe_ipv6_5tuple tuple; /**< Holds values of the 5 tuple */ + struct sfe_ipv6_connection_rule conn_rule; /**< Basic connection specific data */ + struct sfe_protocol_tcp_rule tcp_rule; /**< Protocol related accleration parameters */ + struct sfe_pppoe_rule pppoe_rule; /**< PPPoE related accleration parameters */ + struct sfe_qos_rule qos_rule; /**< QoS related accleration parameters */ + struct sfe_dscp_rule dscp_rule; /**< DSCP related accleration parameters */ + struct sfe_vlan_rule vlan_primary_rule; /**< VLAN related accleration parameters */ + struct sfe_vlan_rule vlan_secondary_rule; /**< VLAN related accleration parameters */ +#ifdef CONFIG_XFRM + struct sfe_acceleration_direction_rule direction_rule;/* Direction related accleration parameters*/ +#endif + /* + * Response + */ + u32 index; /**< Slot ID for cache stats to host OS */ +}; + +/** + * The IPv6 rule destroy sub-message structure. + */ +struct sfe_ipv6_rule_destroy_msg { + struct sfe_ipv6_5tuple tuple; /**< Holds values of the 5 tuple */ +}; + +/** + * The SFE IPv6 rule sync structure. + */ +struct sfe_ipv6_conn_sync { + u32 index; /**< Slot ID for cache stats to host OS */ + u8 protocol; /**< Protocol number */ + __be32 flow_ip[4]; /**< Flow IP address */ + __be16 flow_ident; /**< Flow ident (e.g. port) */ + u32 flow_max_window; /**< Flow direction's largest seen window */ + u32 flow_end; /**< Flow direction's largest seen sequence + segment length */ + u32 flow_max_end; /**< Flow direction's largest seen ack + max(1, win) */ + u32 flow_rx_packet_count; /**< Flow interface's RX packet count */ + u32 flow_rx_byte_count; /**< Flow interface's RX byte count */ + u32 flow_tx_packet_count; /**< Flow interface's TX packet count */ + u32 flow_tx_byte_count; /**< Flow interface's TX byte count */ + u16 flow_pppoe_session_id; /**< Flow interface`s PPPoE session ID. */ + u16 flow_pppoe_remote_mac[3]; + /**< Flow interface's PPPoE remote server MAC address if there is any */ + __be32 return_ip[4]; /**< Return IP address */ + __be16 return_ident; /**< Return ident (e.g. port) */ + u32 return_max_window; /**< Return direction's largest seen window */ + u32 return_end; /**< Return direction's largest seen sequence + segment length */ + u32 return_max_end; /**< Return direction's largest seen ack + max(1, win) */ + u32 return_rx_packet_count; + /**< Return interface's RX packet count */ + u32 return_rx_byte_count; /**< Return interface's RX byte count */ + u32 return_tx_packet_count; + /**< Return interface's TX packet count */ + u32 return_tx_byte_count; /**< Return interface's TX byte count */ + u16 return_pppoe_session_id; + /**< Return interface`s PPPoE session ID. */ + u16 return_pppoe_remote_mac[3]; + /**< Return interface's PPPoE remote server MAC address if there is any */ + u32 inc_ticks; /**< Number of ticks since the last sync */ + u32 reason; /**< Reason for the sync */ + u8 flags; /**< Bit flags associated with the rule */ + u32 qos_tag; /**< QoS Tag */ + u32 cause; /**< Flush cause associated with the rule */ +}; + +/** + * Message structure to send/receive IPv6 bridge/route commands + */ +struct sfe_ipv6_msg { + struct sfe_cmn_msg cm; /**< Message Header */ + union { + struct sfe_ipv6_rule_create_msg rule_create; /**< Message: rule create */ + struct sfe_ipv6_rule_destroy_msg rule_destroy; /**< Message: rule destroy */ + struct sfe_ipv6_conn_sync conn_stats; /**< Message: stats sync */ + } msg; +}; + +/** + * Callback to be called when IPv6 message is received + */ +typedef void (*sfe_ipv6_msg_callback_t)(void *app_data, struct sfe_ipv6_msg *msg); + +/** + * 6rd tunnel peer addr. + */ +struct sfe_tun6rd_set_peer_msg { + __be32 ipv6_address[4]; /* The peer's ipv6 addr*/ + __be32 dest; /* The peer's ipv4 addr*/ +}; + +/** + * Message structure to send/receive 6rd tunnel messages + */ +struct sfe_tun6rd_msg { + struct sfe_cmn_msg cm; /* Message Header */ + union { + struct sfe_tun6rd_set_peer_msg peer; /* Message: add/update peer */ + } msg; +}; + +/* + * sfe driver context instance + */ +struct sfe_drv_ctx_instance { + int not_used; +}; + +/* + * sfe_drv_ipv4_max_conn_count() + * Return the maximum number of IPv4 connections that the sfe acceleration engine supports + * + * @return int The number of connections that can be accelerated by the sfe + */ +int sfe_drv_ipv4_max_conn_count(void); + +/* + * sfe_drv_ipv4_tx() + * Transmit an IPv4 message to the sfe + * + * @param sfe_drv_ctx sfe driver context + * @param msg The IPv4 message + * + * @return sfe_tx_status_t The status of the Tx operation + */ +extern sfe_tx_status_t sfe_drv_ipv4_tx(struct sfe_drv_ctx_instance *sfe_drv_ctx, struct sfe_ipv4_msg *msg); + +/* + * sfe_drv_ipv4_notify_register() + * Register a notifier callback for IPv4 messages from sfe driver + * + * @param cb The callback pointer + * @param app_data The application context for this message + * + * @return struct sfe_drv_ctx_instance * The sfe driver context + */ +extern struct sfe_drv_ctx_instance *sfe_drv_ipv4_notify_register(sfe_ipv4_msg_callback_t cb, void *app_data); + +/* + * sfe_drv_ipv4_notify_unregister() + * Un-Register a notifier callback for IPv4 messages from sfe driver + */ +extern void sfe_drv_ipv4_notify_unregister(void); + +/* + * sfe_ipv4_msg_init() + * IPv4 message init + */ +extern void sfe_ipv4_msg_init(struct sfe_ipv4_msg *nim, u16 if_num, u32 type, u32 len, + sfe_ipv4_msg_callback_t cb, void *app_data); + +/* + * sfe_drv_ipv6_max_conn_count() + * Return the maximum number of IPv6 connections that the sfe acceleration engine supports + * + * @return int The number of connections that can be accelerated by the sfe + */ +int sfe_drv_ipv6_max_conn_count(void); + +/* + * sfe_drv_ipv6_tx() + * Transmit an IPv6 message to the sfe + * + * @param sfe_drv_ctx sfe driver context + * @param msg The IPv6 message + * + * @return sfe_tx_status_t The status of the Tx operation + */ +extern sfe_tx_status_t sfe_drv_ipv6_tx(struct sfe_drv_ctx_instance *sfe_drv_ctx, struct sfe_ipv6_msg *msg); + +/* + * sfe_drv_ipv6_notify_register() + * Register a notifier callback for IPv6 messages from sfe driver + * + * @param cb The callback pointer + * @param app_data The application context for this message + * + * @return struct sfe_drv_ctx_instance * The sfe driver context + */ +extern struct sfe_drv_ctx_instance *sfe_drv_ipv6_notify_register(sfe_ipv6_msg_callback_t cb, void *app_data); + +/* + * sfe_drv_ipv6_notify_unregister() + * Un-Register a notifier callback for IPv6 messages from sfe driver + */ +extern void sfe_drv_ipv6_notify_unregister(void); + +/* + * sfe_ipv6_msg_init() + * IPv6 message init + */ +extern void sfe_ipv6_msg_init(struct sfe_ipv6_msg *nim, u16 if_num, u32 type, u32 len, + sfe_ipv6_msg_callback_t cb, void *app_data); + +/* + * sfe_tun6rd_tx() + * Transmit a tun6rd message to sfe engine + */ +sfe_tx_status_t sfe_tun6rd_tx(struct sfe_drv_ctx_instance *sfe_ctx, struct sfe_tun6rd_msg *msg); + +/* + * sfe_tun6rd_msg_init() + * Initialize sfe_tun6rd msg. + */ +void sfe_tun6rd_msg_init(struct sfe_tun6rd_msg *ncm, u16 if_num, u32 type, u32 len, + void *cb, void *app_data); + +#endif /* __SFE_DRV_H */ diff --git a/upx/Makefile b/upx/Makefile new file mode 100644 index 000000000..b58bd8cd2 --- /dev/null +++ b/upx/Makefile @@ -0,0 +1,66 @@ +# +# Copyright (C) 2011-2020 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# +include $(TOPDIR)/rules.mk + +PKG_NAME:=upx +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Xingwang Liao +PKG_LICENSE:=GPL-2.0-only +PKG_LICENSE_FILES:=COPYING LICENSE + +PKG_SOURCE_PROTO:=git +PKG_SOURCE_DATE:=2022-01-15 +PKG_SOURCE_VERSION:=a46b63817a9c6ad5af7cf519332e859f11558592 +PKG_SOURCE_URL:=https://github.com/upx/upx.git +PKG_SOURCE:=$(PKG_NAME)-$(PKG_SOURCE_DATE).tar.gz + +HOST_BUILD_DEPENDS:=ucl/host + +include $(INCLUDE_DIR)/host-build.mk +include $(INCLUDE_DIR)/package.mk + +define Host/Compile + UPX_UCLDIR=$(STAGING_DIR_HOST) \ + $(MAKE) -C $(HOST_BUILD_DIR)/src \ + CXXFLAGS_WERROR="" LDFLAGS="$(HOST_LDFLAGS)" \ + CXX="$(HOSTCXX)" +endef + +define Host/Install + $(CP) $(HOST_BUILD_DIR)/src/upx.out $(STAGING_DIR_HOST)/bin/upx +endef + +define Host/Clean + rm -f $(STAGING_DIR_HOST)/bin/upx +endef + +define Package/upx + SECTION:=utils + CATEGORY:=Utilities + DEPENDS:=+libucl +libstdcpp +zlib + TITLE:=The Ultimate Packer for eXecutables + URL:=https://upx.github.io/ +endef + +define Package/upx/description +UPX is a free, portable, extendable, high-performance executable packer for +several different executable formats. It achieves an excellent compression ratio +and offers very fast decompression. Your executables suffer no memory overhead +or other drawbacks for most of the formats supported, because of in-place +decompression. +endef + +MAKE_PATH := src + +define Package/upx/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/src/upx.out $(1)/usr/bin/upx +endef + +$(eval $(call HostBuild)) +$(eval $(call BuildPackage,upx)) diff --git a/v2ray-core/files/etc/init.d/v2ray b/v2ray-core/files/etc/init.d/v2ray index f8772a0e1..ffe8d1db4 100755 --- a/v2ray-core/files/etc/init.d/v2ray +++ b/v2ray-core/files/etc/init.d/v2ray @@ -414,12 +414,17 @@ add_v2ray_redirect_rules() { # This part need a rewrite v2ray-rules -f - v2ray-rules -l ${port} -L ${port} -s $OUTBOUND_SERVERS_V4 --rule-name def --src-default forward --dst-default forward --local-default forward + logger -t "v2ray" "v2ray-rules -l ${port} -L ${port} -s $OUTBOUND_SERVERS_V4 --rule-name def --src-default forward --dst-default forward --local-default forward" + commandline="-l ${port} -s $OUTBOUND_SERVERS_V4 --rule-name def --src-default forward --dst-default forward --local-default forward" + [ "$(uci -q get v2ray.main_transparent_proxy.redirect_udp)" = "1" ] && commandline="$commandline -L ${port}" + v2ray-rules $commandline [ "$(uci -q get v2ray.main.inbounds | grep omr6)" != "" ] && { v2ray-rules6 -f - v2ray-rules6 -l $((port+1)) -L $((port+1)) -s $OUTBOUND_SERVERS_V6 --rule-name def --src-default forward --dst-default forward --local-default forward + commandline="-l $((port+1)) -L $((port+1)) -s $OUTBOUND_SERVERS_V6 --rule-name def --src-default forward --dst-default forward --local-default forward" + [ "$(uci -q get v2ray.main_transparent_proxy.redirect_udp)" = "1" ] && commandline="$commandline -L ${port+1}" + v2ray-rules6 $commandline } - [ -f /etc/init.d/omr-bypass ] && { + [ -f /etc/init.d/omr-bypass ] && [ -z "$(pgrep -f omr-bypass)" ] && { logger -t "v2ray" "Reload omr-bypass rules" /etc/init.d/omr-bypass reload_rules } @@ -2101,7 +2106,7 @@ rules_up() { logger -t "v2ray" "Rules UP" add_v2ray_redirect_rules } - [ -f /etc/init.d/omr-bypass ] && { + [ -f /etc/init.d/omr-bypass ] && [ -z "$(pgrep -f omr-bypass)" ] && { logger -t "v2ray" "Reload omr-bypass rules" /etc/init.d/omr-bypass reload_rules } diff --git a/v2ray-ext/Makefile b/v2ray-ext/Makefile index f1fd155fb..2983d536f 100755 --- a/v2ray-ext/Makefile +++ b/v2ray-ext/Makefile @@ -25,7 +25,7 @@ GO_PKG:=v2ray.com/ext GO_PKG_SOURCE_ONLY:=1 include $(INCLUDE_DIR)/package.mk -include ../golang/golang-package.mk +include $(TOPDIR)/feeds/openmptcprouter/golang/golang-package.mk define Package/v2ray-ext-dev $(call GoPackage/GoSubMenu)