mirror of
https://github.com/qosmio/nss-packages.git
synced 2025-12-18 17:21:56 +00:00
Merge branch 'NSS-12.4-K6.1' into NSS-12.4-K6.6
This commit is contained in:
commit
fd81770c4c
@ -10,7 +10,7 @@ include $(TOPDIR)/rules.mk
|
|||||||
PKG_NAME:=nss-firmware
|
PKG_NAME:=nss-firmware
|
||||||
PKG_SOURCE_DATE:=2022-07-12
|
PKG_SOURCE_DATE:=2022-07-12
|
||||||
PKG_SOURCE_VERSION:=ade6bff594377c9d9c79b45e39bf104303d919bc
|
PKG_SOURCE_VERSION:=ade6bff594377c9d9c79b45e39bf104303d919bc
|
||||||
PKG_MIRROR_HASH:=af0521893064b7bc52baab263e12c7db5462461ddac30d02647ed76d999b59fb
|
PKG_MIRROR_HASH:=503f2dc2daae113826b52a6150f0932c6ce605b555e1d47a2ca57ec0d684c202
|
||||||
PKG_RELEASE:=2
|
PKG_RELEASE:=2
|
||||||
|
|
||||||
PKG_SOURCE_PROTO:=git
|
PKG_SOURCE_PROTO:=git
|
||||||
|
|||||||
@ -1,53 +0,0 @@
|
|||||||
include $(TOPDIR)/rules.mk
|
|
||||||
include $(INCLUDE_DIR)/kernel.mk
|
|
||||||
|
|
||||||
PKG_NAME:=nss-udp-st-drv
|
|
||||||
PKG_RELEASE:=1
|
|
||||||
|
|
||||||
include $(INCLUDE_DIR)/package.mk
|
|
||||||
|
|
||||||
define KernelPackage/$(PKG_NAME)
|
|
||||||
SECTION:=kernel
|
|
||||||
CATEGORY:=Kernel modules
|
|
||||||
SUBMENU:=Network Support
|
|
||||||
DEPENDS:=@(TARGET_qualcommax||TARGET_ipq60xx) +kmod-pppoe
|
|
||||||
TITLE:=Kernel driver for NSS UDP Speedtest
|
|
||||||
FILES:=$(PKG_BUILD_DIR)/nss-udp-st.ko
|
|
||||||
endef
|
|
||||||
|
|
||||||
define KernelPackage/$(PKG_NAME)/Description
|
|
||||||
Kernel driver for host data path NSS UDP speedtest
|
|
||||||
endef
|
|
||||||
|
|
||||||
define KernelPackage/$(PKG_NAME)/install
|
|
||||||
$(INSTALL_DIR) $(1)/usr/bin
|
|
||||||
endef
|
|
||||||
|
|
||||||
ifeq ($(CONFIG_TARGET_SUBTARGET), "ipq807x")
|
|
||||||
SOC="ipq807x_64"
|
|
||||||
subtarget:=$(CONFIG_TARGET_SUBTARGET)
|
|
||||||
else ifeq ($(CONFIG_TARGET_BOARD), "ipq60xx")
|
|
||||||
SOC="ipq60xx_64"
|
|
||||||
subtarget:=$(SUBTARGET)
|
|
||||||
endif
|
|
||||||
|
|
||||||
define Build/InstallDev
|
|
||||||
$(INSTALL_DIR) $(STAGING_DIR)/usr/include/nss-udp-st-drv
|
|
||||||
$(CP) $(PKG_BUILD_DIR)/exports/* $(STAGING_DIR)/usr/include/nss-udp-st-drv/
|
|
||||||
endef
|
|
||||||
|
|
||||||
EXTRA_CFLAGS+= -I$(STAGING_DIR)/usr/include/nss-udp-st-drv/
|
|
||||||
|
|
||||||
define Build/Compile
|
|
||||||
+$(MAKE) -C "$(LINUX_DIR)" \
|
|
||||||
CROSS_COMPILE="$(TARGET_CROSS)" \
|
|
||||||
ARCH="$(LINUX_KARCH)" \
|
|
||||||
M="$(PKG_BUILD_DIR)" \
|
|
||||||
EXTRA_CFLAGS="$(EXTRA_CFLAGS)" \
|
|
||||||
SoC=$(SOC) \
|
|
||||||
$(KERNEL_MAKE_FLAGS) \
|
|
||||||
$(PKG_JOBS) \
|
|
||||||
modules
|
|
||||||
endef
|
|
||||||
|
|
||||||
$(eval $(call KernelPackage,$(PKG_NAME)))
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
--- a/nss_udp_st_tx.c
|
|
||||||
+++ b/nss_udp_st_tx.c
|
|
||||||
@@ -23,6 +23,7 @@
|
|
||||||
#include <net/netfilter/nf_conntrack_core.h>
|
|
||||||
#include <linux/if_vlan.h>
|
|
||||||
#include <linux/if_pppox.h>
|
|
||||||
+#include <linux/ppp_defs.h>
|
|
||||||
#include <net/ip6_checksum.h>
|
|
||||||
#include "nss_udp_st_public.h"
|
|
||||||
|
|
||||||
@ -1,28 +0,0 @@
|
|||||||
--- a/nss_udp_st_tx.c
|
|
||||||
+++ b/nss_udp_st_tx.c
|
|
||||||
@@ -18,7 +18,7 @@
|
|
||||||
|
|
||||||
#include <linux/list.h>
|
|
||||||
#include <linux/string.h>
|
|
||||||
-#include <linux/hrtimer.h>
|
|
||||||
+// #include <linux/hrtimer.h>
|
|
||||||
#include <net/act_api.h>
|
|
||||||
#include <net/netfilter/nf_conntrack_core.h>
|
|
||||||
#include <linux/if_vlan.h>
|
|
||||||
@@ -34,6 +34,9 @@ static enum hrtimer_restart tx_hr_restar
|
|
||||||
static struct vlan_hdr vh;
|
|
||||||
static struct net_device *xmit_dev;
|
|
||||||
static struct pppoe_opt info;
|
|
||||||
+extern void hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode);
|
|
||||||
+extern void hrtimer_init(struct hrtimer *timer, clockid_t clock_id,enum hrtimer_mode mode);
|
|
||||||
+extern int hrtimer_cancel(struct hrtimer *timer);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_generate_ipv4_hdr()
|
|
||||||
@@ -576,3 +579,6 @@ bool nss_udp_st_tx(void)
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
+MODULE_AUTHOR("Qualcomm Technologies");
|
|
||||||
+MODULE_DESCRIPTION("NSS UDP Speedtest");
|
|
||||||
+MODULE_LICENSE("Dual BSD/GPL");
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
#
|
|
||||||
# Makefile for NSS UDP Speed Test
|
|
||||||
#
|
|
||||||
obj ?= .
|
|
||||||
|
|
||||||
NSS_UDP_ST_BASE_OBJS := nss_udp_st_drv.o nss_udp_st_rx.o nss_udp_st_tx.o nss_udp_st_ip.o
|
|
||||||
|
|
||||||
obj-m += nss-udp-st.o
|
|
||||||
|
|
||||||
#
|
|
||||||
# Base files
|
|
||||||
#
|
|
||||||
nss-udp-st-objs := $(NSS_UDP_ST_BASE_OBJS)
|
|
||||||
|
|
||||||
ccflags-y += -Werror -Wall -I$(obj) -I$(obj)/exports
|
|
||||||
@ -1,198 +0,0 @@
|
|||||||
/*
|
|
||||||
**************************************************************************
|
|
||||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. 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 __NSS_UDP_ST_DRV_H
|
|
||||||
#define __NSS_UDP_ST_DRV_H
|
|
||||||
|
|
||||||
#ifdef __KERNEL__ /* only kernel will use. */
|
|
||||||
#include <linux/sizes.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define NSS_UDP_ST_IFNAMSZ 24
|
|
||||||
#define NSS_UDP_ST_IPNAMSZ 40
|
|
||||||
#define NSS_UDP_ST_MODESZ 24
|
|
||||||
|
|
||||||
#ifdef __KERNEL__ /* only kernel will use. */
|
|
||||||
#define NSS_UDP_ST_FLAG_IPV4 0x1
|
|
||||||
#define NSS_UDP_ST_FLAG_IPV6 0x2
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* NSS UDP speedtest ioctl parameters
|
|
||||||
*/
|
|
||||||
#define NSS_UDP_ST_IOCTL_MAGIC 'n'
|
|
||||||
#define NSS_UDP_ST_IOCTL_INIT _IOW(NSS_UDP_ST_IOCTL_MAGIC, 0, struct nss_udp_st_param* )
|
|
||||||
#define NSS_UDP_ST_IOCTL_START_TX _IOW(NSS_UDP_ST_IOCTL_MAGIC, 1, int)
|
|
||||||
#define NSS_UDP_ST_IOCTL_START_RX _IOW(NSS_UDP_ST_IOCTL_MAGIC, 2, int)
|
|
||||||
#define NSS_UDP_ST_IOCTL_STOP _IO(NSS_UDP_ST_IOCTL_MAGIC, 3)
|
|
||||||
#define NSS_UDP_ST_DEV "/dev/nss_udp_st"
|
|
||||||
|
|
||||||
#ifdef __KERNEL__ /* only kernel will use. */
|
|
||||||
#define NSS_UDP_ST_MAX_HEADROOM 32 /* Maximum headroom needed */
|
|
||||||
#define NSS_UDP_ST_MAX_TAILROOM 32 /* Maximum tailroom needed */
|
|
||||||
#define NSS_UDP_ST_BUFFER_SIZE_MAX 1500 /* 1500 bytes */
|
|
||||||
#define NSS_UDP_ST_RATE_MAX 20000000000 /* 20 Gbps */
|
|
||||||
|
|
||||||
extern struct nss_udp_st nust;
|
|
||||||
extern struct delayed_work nss_udp_st_tx_delayed_work;
|
|
||||||
extern struct workqueue_struct *work_queue;
|
|
||||||
extern void nss_udp_st_update_stats(size_t pkt_size);
|
|
||||||
extern uint64_t nss_udp_st_tx_num_pkt;
|
|
||||||
extern struct net_device *nust_dev;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_rule
|
|
||||||
* NSS UDP speedtest rules parameters
|
|
||||||
*/
|
|
||||||
enum nss_udp_st_rule {
|
|
||||||
NSS_UDP_ST_SIP, /* source IP */
|
|
||||||
NSS_UDP_ST_DIP, /* destination IP */
|
|
||||||
NSS_UDP_ST_SPORT, /* source port */
|
|
||||||
NSS_UDP_ST_DPORT, /* destination port */
|
|
||||||
NSS_UDP_ST_FLAGS, /* IP version flag */
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_stats_stats
|
|
||||||
* time stats
|
|
||||||
*/
|
|
||||||
enum nss_udp_st_stats_time {
|
|
||||||
NSS_UDP_ST_STATS_TIME_START, /* Start time of the test */
|
|
||||||
NSS_UDP_ST_STATS_TIME_CURRENT, /* Current time of the running test */
|
|
||||||
NSS_UDP_ST_STATS_TIME_ELAPSED, /* Elapsed time of the current test */
|
|
||||||
NSS_UDP_ST_STATS_TIME_MAX /* Maximum timer statistics type */
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_error
|
|
||||||
* error stats
|
|
||||||
*/
|
|
||||||
enum nss_udp_st_error {
|
|
||||||
NSS_UDP_ST_ERROR_NONE, /* no error */
|
|
||||||
NSS_UDP_ST_ERROR_INCORRECT_RATE, /* incorrect rate */
|
|
||||||
NSS_UDP_ST_ERROR_INCORRECT_BUFFER_SIZE, /* incorrect buffer size */
|
|
||||||
NSS_UDP_ST_ERROR_MEMORY_FAILURE, /* Memory allocation failed */
|
|
||||||
NSS_UDP_ST_ERROR_INCORRECT_IP_VERSION, /* Incorrect IP version */
|
|
||||||
NSS_UDP_ST_ERROR_PACKET_DROP, /* Packet Drop */
|
|
||||||
NSS_UDP_ST_ERROR_MAX /* Maximum error statistics type */
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_type
|
|
||||||
* tx/rx flags
|
|
||||||
*/
|
|
||||||
enum nss_udp_st_type {
|
|
||||||
NSS_UDP_ST_TX, /* Tx 0 */
|
|
||||||
NSS_UDP_ST_RX, /* Rx 1 */
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_param
|
|
||||||
* config parameters for Tx test
|
|
||||||
*/
|
|
||||||
struct nss_udp_st_param {
|
|
||||||
uint32_t rate; /* target rate in Mbps */
|
|
||||||
uint32_t buffer_sz; /* buffer size of each packet */
|
|
||||||
uint32_t dscp; /* dscp flag for tx packet */
|
|
||||||
char net_dev[NSS_UDP_ST_IFNAMSZ]; /* net device interface */
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_opt
|
|
||||||
* 5 tuple config parameters
|
|
||||||
*/
|
|
||||||
struct nss_udp_st_opt {
|
|
||||||
uint16_t sport; /* source port */
|
|
||||||
uint16_t dport; /* destination port */
|
|
||||||
uint16_t ip_version; /* ip version flag */
|
|
||||||
char sip[NSS_UDP_ST_IPNAMSZ]; /* source ip string */
|
|
||||||
char dip[NSS_UDP_ST_IPNAMSZ]; /* dest ip string */
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef __KERNEL__ /* only kernel will use. */
|
|
||||||
/*
|
|
||||||
* nss_udp_st_mode
|
|
||||||
* start/stop flags
|
|
||||||
*/
|
|
||||||
enum nss_udp_st_mode {
|
|
||||||
NSS_UDP_ST_STOP, /* Stop 0 */
|
|
||||||
NSS_UDP_ST_START, /* Start 1 */
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_ip
|
|
||||||
* ipv4/ipv6 params
|
|
||||||
*/
|
|
||||||
struct nss_udp_st_ip {
|
|
||||||
union {
|
|
||||||
uint32_t ipv4; /* IPv4 address. */
|
|
||||||
uint32_t ipv6[4]; /* IPv6 address. */
|
|
||||||
} ip;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_pkt_stats
|
|
||||||
* packet stats
|
|
||||||
*/
|
|
||||||
struct nss_udp_st_pkt_stats {
|
|
||||||
atomic_long_t tx_packets; /* Number of packets transmitted */
|
|
||||||
atomic_long_t tx_bytes; /* Number of bytes transmitted */
|
|
||||||
atomic_long_t rx_packets; /* Number of packets received */
|
|
||||||
atomic_long_t rx_bytes; /* Number of bytes received */
|
|
||||||
};
|
|
||||||
/*
|
|
||||||
* nss_udp_st_stats
|
|
||||||
* stats for tx/rx test
|
|
||||||
*/
|
|
||||||
struct nss_udp_st_stats {
|
|
||||||
struct nss_udp_st_pkt_stats p_stats; /* Packet statistics */
|
|
||||||
atomic_long_t timer_stats[NSS_UDP_ST_STATS_TIME_MAX]; /* Time statistics */
|
|
||||||
atomic_long_t errors[NSS_UDP_ST_ERROR_MAX]; /* Error statistics */
|
|
||||||
bool first_pkt; /* First packet flag */
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_rules
|
|
||||||
* config rules configured for tx/rx test
|
|
||||||
*/
|
|
||||||
struct nss_udp_st_rules {
|
|
||||||
struct list_head list; /* kernel’s list structure */
|
|
||||||
struct nss_udp_st_ip sip; /* source ip */
|
|
||||||
struct nss_udp_st_ip dip; /* dest ip */
|
|
||||||
uint16_t sport; /* source port */
|
|
||||||
uint16_t dport; /* dest port */
|
|
||||||
uint16_t flags; /* version of IP address */
|
|
||||||
uint8_t dst_mac[ETH_ALEN]; /* dest mac */
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st
|
|
||||||
* config/rules/stats for tx/rx test
|
|
||||||
*/
|
|
||||||
struct nss_udp_st {
|
|
||||||
struct nss_udp_st_param config; /* config params for tx */
|
|
||||||
struct nss_udp_st_rules rules; /* database for config rules */
|
|
||||||
struct nss_udp_st_stats stats; /* result statistics */
|
|
||||||
uint32_t rule_count; /* no of rules configured */
|
|
||||||
uint64_t time; /* duration of test */
|
|
||||||
bool mode; /* start =0; stop=1 */
|
|
||||||
bool dir; /* tx=0; rx=1 */
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /*NSS_UDP_ST_H*/
|
|
||||||
@ -1,393 +0,0 @@
|
|||||||
/*
|
|
||||||
**************************************************************************
|
|
||||||
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. 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 <net/act_api.h>
|
|
||||||
#include <linux/major.h>
|
|
||||||
#include <net/netfilter/nf_conntrack_core.h>
|
|
||||||
#include "nss_udp_st_public.h"
|
|
||||||
|
|
||||||
#define DEVICE_NAME "nss_udp_st"
|
|
||||||
#define CLASS_NAME "nss_udp_st"
|
|
||||||
|
|
||||||
static const struct file_operations nss_udp_st_ops;
|
|
||||||
static struct class *dump_class;
|
|
||||||
static int dump_major;
|
|
||||||
|
|
||||||
struct nss_udp_st nust;
|
|
||||||
struct delayed_work nss_udp_st_tx_delayed_work;
|
|
||||||
struct workqueue_struct *work_queue;
|
|
||||||
void nss_udp_st_update_stats(size_t pkt_size);
|
|
||||||
uint64_t nss_udp_st_tx_num_pkt;
|
|
||||||
struct net_device *nust_dev;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_rx_ipv4_pre_routing_hook
|
|
||||||
* pre-routing hook into netfilter packet monitoring point for IPv4
|
|
||||||
*/
|
|
||||||
static struct nf_hook_ops nss_udp_st_nf_ipv4_ops[] __read_mostly = {
|
|
||||||
{
|
|
||||||
.hook = nss_udp_st_rx_ipv4_pre_routing_hook,
|
|
||||||
.pf = NFPROTO_IPV4,
|
|
||||||
.hooknum = NF_INET_PRE_ROUTING,
|
|
||||||
.priority = NF_IP_PRI_RAW_BEFORE_DEFRAG,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_rx_ipv6_pre_routing_hook
|
|
||||||
* pre-routing hook into netfilter packet monitoring point for IPv6
|
|
||||||
*/
|
|
||||||
static struct nf_hook_ops nss_udp_st_nf_ipv6_ops[] __read_mostly = {
|
|
||||||
{
|
|
||||||
.hook = nss_udp_st_rx_ipv6_pre_routing_hook,
|
|
||||||
.pf = NFPROTO_IPV6,
|
|
||||||
.hooknum = NF_INET_PRE_ROUTING,
|
|
||||||
.priority = NF_IP_PRI_RAW_BEFORE_DEFRAG,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_check_rules()
|
|
||||||
* check for ARP resolution and valid return mac
|
|
||||||
*/
|
|
||||||
static int nss_udp_st_check_rules(struct nss_udp_st_rules *rules)
|
|
||||||
{
|
|
||||||
if (rules->flags == NSS_UDP_ST_FLAG_IPV4) {
|
|
||||||
if (nss_udp_st_get_macaddr_ipv4(rules->dip.ip.ipv4, (uint8_t *)&rules->dst_mac)) {
|
|
||||||
pr_err("Error in Updating the Return MAC Address\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
} else if (rules->flags == NSS_UDP_ST_FLAG_IPV6) {
|
|
||||||
if (nss_udp_st_get_macaddr_ipv6(rules->dip.ip.ipv6, (uint8_t *)&rules->dst_mac)) {
|
|
||||||
pr_err("Error in Updating the Return MAC Address\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pr_err("invalid ip version flag\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_clear_rules()
|
|
||||||
* clear rules list
|
|
||||||
*/
|
|
||||||
static void nss_udp_st_clear_rules(void)
|
|
||||||
{
|
|
||||||
struct nss_udp_st_rules *pos = NULL;
|
|
||||||
struct nss_udp_st_rules *n = NULL;
|
|
||||||
|
|
||||||
list_for_each_entry_safe(pos, n, &nust.rules.list, list) {
|
|
||||||
list_del(&pos->list);
|
|
||||||
kfree(pos);
|
|
||||||
}
|
|
||||||
nust.rule_count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_open()
|
|
||||||
* open for file ops on /dev/nss-udp-st
|
|
||||||
*/
|
|
||||||
static int nss_udp_st_open(struct inode *inode, struct file *file)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_release()
|
|
||||||
* release /dev/nss-udp-st
|
|
||||||
*/
|
|
||||||
static int nss_udp_st_release(struct inode *inode, struct file *file)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_read()
|
|
||||||
* send stats to userspace
|
|
||||||
*/
|
|
||||||
static ssize_t nss_udp_st_read(struct file *file, char __user *buf,
|
|
||||||
size_t count, loff_t *ppos)
|
|
||||||
{
|
|
||||||
int copied = 0;
|
|
||||||
copied = copy_to_user(buf, &nust.stats, sizeof(struct nss_udp_st_stats));
|
|
||||||
return copied;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_write()
|
|
||||||
* receive rules from userspace
|
|
||||||
*/
|
|
||||||
static ssize_t nss_udp_st_write(struct file *file, const char __user *buf,
|
|
||||||
size_t count, loff_t *ppos)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
struct nss_udp_st_opt opt;
|
|
||||||
struct nss_udp_st_rules *rules;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* don't push rules if test has already started
|
|
||||||
*/
|
|
||||||
if (nust.mode == NSS_UDP_ST_START) {
|
|
||||||
pr_err("Test already started\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
rules = (struct nss_udp_st_rules *)kzalloc(sizeof(struct nss_udp_st_rules), GFP_KERNEL);
|
|
||||||
if (!rules) {
|
|
||||||
atomic_long_inc(&nust.stats.errors[NSS_UDP_ST_ERROR_MEMORY_FAILURE]);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = copy_from_user((void *)(uintptr_t)&opt, (void __user *)buf, sizeof(struct nss_udp_st_opt));
|
|
||||||
if (ret) {
|
|
||||||
kfree(rules);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
rules->sport = opt.sport;
|
|
||||||
rules->dport = opt.dport;
|
|
||||||
if(opt.ip_version == 4) {
|
|
||||||
rules->flags |= NSS_UDP_ST_FLAG_IPV4;
|
|
||||||
nss_udp_st_get_ipaddr_ntoh(opt.sip, sizeof(struct in_addr), &rules->sip.ip.ipv4);
|
|
||||||
nss_udp_st_get_ipaddr_ntoh(opt.dip, sizeof(struct in_addr), &rules->dip.ip.ipv4);
|
|
||||||
} else if(opt.ip_version == 6) {
|
|
||||||
rules->flags |= NSS_UDP_ST_FLAG_IPV6;
|
|
||||||
nss_udp_st_get_ipaddr_ntoh(opt.sip, sizeof(struct in6_addr), rules->sip.ip.ipv6);
|
|
||||||
nss_udp_st_get_ipaddr_ntoh(opt.dip, sizeof(struct in6_addr), rules->dip.ip.ipv6);
|
|
||||||
} else {
|
|
||||||
kfree(rules);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = nss_udp_st_check_rules(rules);
|
|
||||||
if (ret) {
|
|
||||||
kfree(rules);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
list_add_tail(&(rules->list), &(nust.rules.list));
|
|
||||||
nust.rule_count++;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_reset_stats()
|
|
||||||
* clear stats before starting test
|
|
||||||
*/
|
|
||||||
static void nss_udp_st_reset_stats(void) {
|
|
||||||
memset(&nust.stats, 0, sizeof(struct nss_udp_st_stats));
|
|
||||||
nust.stats.first_pkt = true;
|
|
||||||
nss_udp_st_tx_num_pkt = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_ioctl()
|
|
||||||
* receive ioctl to init / start / stop test
|
|
||||||
*/
|
|
||||||
static long nss_udp_st_ioctl(struct file *file, unsigned int ioctl_num,
|
|
||||||
unsigned long arg)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
switch (ioctl_num) {
|
|
||||||
case NSS_UDP_ST_IOCTL_INIT:
|
|
||||||
memset(&(nust.config), 0, sizeof(struct nss_udp_st_param));
|
|
||||||
ret = copy_from_user((void *)&(nust.config), (void __user *)arg, sizeof(struct nss_udp_st_param));
|
|
||||||
if (ret) {
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NSS_UDP_ST_IOCTL_START_TX:
|
|
||||||
if (nust.mode == NSS_UDP_ST_START) {
|
|
||||||
pr_err("Tx test already started\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
nss_udp_st_reset_stats();
|
|
||||||
nust.dir = NSS_UDP_ST_TX;
|
|
||||||
|
|
||||||
ret = copy_from_user((void *)&(nust.time), (void __user *)arg, sizeof(nust.time));
|
|
||||||
if (ret) {
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
if (!nust.time) {
|
|
||||||
nust.time = NSS_UDP_ST_TX_DEFAULT_TIMEOUT;
|
|
||||||
}
|
|
||||||
if (!nss_udp_st_tx()) {
|
|
||||||
pr_err("Unable to start Tx test\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
nust.mode = NSS_UDP_ST_START;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NSS_UDP_ST_IOCTL_START_RX:
|
|
||||||
if (nust.mode == NSS_UDP_ST_START) {
|
|
||||||
pr_err("Rx test already started\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
nss_udp_st_reset_stats();
|
|
||||||
nust.dir = NSS_UDP_ST_RX;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* register pre-routing hook for rx path
|
|
||||||
*/
|
|
||||||
ret = nf_register_net_hooks(&init_net, nss_udp_st_nf_ipv4_ops, ARRAY_SIZE(nss_udp_st_nf_ipv4_ops));
|
|
||||||
if (ret < 0) {
|
|
||||||
pr_err("Can't register Rx netfilter hooks.\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = nf_register_net_hooks(&init_net, nss_udp_st_nf_ipv6_ops, ARRAY_SIZE(nss_udp_st_nf_ipv6_ops));
|
|
||||||
if (ret < 0) {
|
|
||||||
pr_err("Can't register Rx netfilter hooks.\n");
|
|
||||||
nf_unregister_net_hooks(&init_net, nss_udp_st_nf_ipv4_ops, ARRAY_SIZE(nss_udp_st_nf_ipv4_ops));
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
nust.mode = NSS_UDP_ST_START;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NSS_UDP_ST_IOCTL_STOP:
|
|
||||||
if (nust.mode == NSS_UDP_ST_STOP)
|
|
||||||
break;
|
|
||||||
|
|
||||||
nust.mode = NSS_UDP_ST_STOP;
|
|
||||||
|
|
||||||
if (nust.dir == NSS_UDP_ST_RX) {
|
|
||||||
/*
|
|
||||||
* de-register pre-routing hook for rx path
|
|
||||||
*/
|
|
||||||
nf_unregister_net_hooks(&init_net, nss_udp_st_nf_ipv4_ops, ARRAY_SIZE(nss_udp_st_nf_ipv4_ops));
|
|
||||||
nf_unregister_net_hooks(&init_net, nss_udp_st_nf_ipv6_ops, ARRAY_SIZE(nss_udp_st_nf_ipv6_ops));
|
|
||||||
} else {
|
|
||||||
nss_udp_st_hrtimer_cleanup();
|
|
||||||
}
|
|
||||||
nss_udp_st_clear_rules();
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
ret = -EINVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* file ops for /dev/nss_udp_st
|
|
||||||
*/
|
|
||||||
static const struct file_operations nss_udp_st_ops = {
|
|
||||||
.open = nss_udp_st_open,
|
|
||||||
.read = nss_udp_st_read,
|
|
||||||
.write = nss_udp_st_write,
|
|
||||||
.unlocked_ioctl = nss_udp_st_ioctl,
|
|
||||||
.release = nss_udp_st_release,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_init()
|
|
||||||
* create char device /dev/nss_udp_st
|
|
||||||
*/
|
|
||||||
static int __init nss_udp_st_init(void)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
struct device *dump_dev;
|
|
||||||
|
|
||||||
memset(&nust, 0, sizeof(struct nss_udp_st));
|
|
||||||
INIT_LIST_HEAD(&(nust.rules.list));
|
|
||||||
|
|
||||||
dump_major = register_chrdev(UNNAMED_MAJOR, DEVICE_NAME, &nss_udp_st_ops);
|
|
||||||
if (dump_major < 0) {
|
|
||||||
ret = dump_major;
|
|
||||||
pr_err("Unable to allocate a major number err = %d\n", ret);
|
|
||||||
goto reg_failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
dump_class = class_create(THIS_MODULE, CLASS_NAME);
|
|
||||||
if (IS_ERR(dump_class)) {
|
|
||||||
ret = PTR_ERR(dump_class);
|
|
||||||
pr_err("Unable to create dump class = %d\n", ret);
|
|
||||||
goto class_failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
dump_dev = device_create(dump_class, NULL, MKDEV(dump_major, 0), NULL, DEVICE_NAME);
|
|
||||||
if (IS_ERR(dump_dev)) {
|
|
||||||
ret = PTR_ERR(dump_dev);
|
|
||||||
pr_err("Unable to create a device err = %d\n", ret);
|
|
||||||
goto device_failed;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
device_failed:
|
|
||||||
class_destroy(dump_class);
|
|
||||||
class_failed:
|
|
||||||
unregister_chrdev(dump_major, DEVICE_NAME);
|
|
||||||
reg_failed:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_exit()
|
|
||||||
* clean up for /dev/nss_udp_st
|
|
||||||
*/
|
|
||||||
static void __exit nss_udp_st_exit(void)
|
|
||||||
{
|
|
||||||
nust.mode = NSS_UDP_ST_STOP;
|
|
||||||
device_destroy(dump_class, MKDEV(dump_major, 0));
|
|
||||||
class_destroy(dump_class);
|
|
||||||
unregister_chrdev(dump_major, DEVICE_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_update_stats()
|
|
||||||
* update packet and time stats for tx/rx
|
|
||||||
*/
|
|
||||||
void nss_udp_st_update_stats(size_t pkt_size)
|
|
||||||
{
|
|
||||||
long time_curr;
|
|
||||||
long time_start;
|
|
||||||
|
|
||||||
if (nust.stats.first_pkt) {
|
|
||||||
atomic_long_set(&nust.stats.timer_stats[NSS_UDP_ST_STATS_TIME_START], (jiffies * 1000/HZ));
|
|
||||||
nust.stats.first_pkt = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nust.dir == NSS_UDP_ST_TX) {
|
|
||||||
atomic_long_inc(&nust.stats.p_stats.tx_packets);
|
|
||||||
atomic_long_add(pkt_size, &nust.stats.p_stats.tx_bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nust.dir == NSS_UDP_ST_RX) {
|
|
||||||
atomic_long_inc(&nust.stats.p_stats.rx_packets);
|
|
||||||
atomic_long_add(pkt_size, &nust.stats.p_stats.rx_bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
atomic_long_set(&nust.stats.timer_stats[NSS_UDP_ST_STATS_TIME_CURRENT], (jiffies * 1000/HZ));
|
|
||||||
|
|
||||||
time_curr = atomic_long_read(&nust.stats.timer_stats[NSS_UDP_ST_STATS_TIME_CURRENT]);
|
|
||||||
time_start = atomic_long_read(&nust.stats.timer_stats[NSS_UDP_ST_STATS_TIME_START]);
|
|
||||||
atomic_long_set(&nust.stats.timer_stats[NSS_UDP_ST_STATS_TIME_ELAPSED], (long)(time_curr - time_start));
|
|
||||||
}
|
|
||||||
|
|
||||||
module_init(nss_udp_st_init);
|
|
||||||
module_exit(nss_udp_st_exit);
|
|
||||||
|
|
||||||
MODULE_AUTHOR("Qualcomm Technologies");
|
|
||||||
MODULE_DESCRIPTION("NSS UDP Speedtest");
|
|
||||||
MODULE_LICENSE("Dual BSD/GPL");
|
|
||||||
@ -1,307 +0,0 @@
|
|||||||
/*
|
|
||||||
**************************************************************************
|
|
||||||
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
|
||||||
*
|
|
||||||
* Permission to use, copy, modify, and/or distribute this software for
|
|
||||||
* any purpose with or without fee is hereby granted, provided that the
|
|
||||||
* above copyright notice and this permission notice appear in all copies.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
|
||||||
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
**************************************************************************
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/inet.h>
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/etherdevice.h>
|
|
||||||
#include <net/sock.h>
|
|
||||||
#include <net/arp.h>
|
|
||||||
#include <net/dst.h>
|
|
||||||
#include <net/ipv6.h>
|
|
||||||
#include <net/ip.h>
|
|
||||||
#include <net/route.h>
|
|
||||||
#include <net/ip6_route.h>
|
|
||||||
#include "nss_udp_st_ip.h"
|
|
||||||
|
|
||||||
#define NSS_UDP_ST_IPV4_SIZE sizeof(struct in_addr)
|
|
||||||
#define NSS_UDP_ST_IPV6_SIZE sizeof(struct in6_addr)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_get_ipaddr_ntoh()
|
|
||||||
* extract the IPv4 or IPv6 address in host order from the incoming data
|
|
||||||
*/
|
|
||||||
int nss_udp_st_get_ipaddr_ntoh(const char *arg, uint16_t data_sz, uint32_t *data)
|
|
||||||
{
|
|
||||||
|
|
||||||
uint32_t dest[4];
|
|
||||||
|
|
||||||
if (!arg || !data) {
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(data_sz) {
|
|
||||||
case NSS_UDP_ST_IPV4_SIZE: /* IPv4 */
|
|
||||||
if(!in4_pton(arg, -1, (uint8_t *)data, '\0', NULL)) {
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
data[0] = ntohl(data[0]);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case NSS_UDP_ST_IPV6_SIZE: /* IPv6 */
|
|
||||||
if(!in6_pton(arg, -1,(uint8_t *)data, -1, NULL)) {
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
nss_udp_st_swap_addr_ipv6(data, dest);
|
|
||||||
|
|
||||||
data[0] = ntohl(dest[0]);
|
|
||||||
data[1] = ntohl(dest[1]);
|
|
||||||
data[2] = ntohl(dest[2]);
|
|
||||||
data[3] = ntohl(dest[3]);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
default:
|
|
||||||
pr_err("IP address storage incorrect:%d\n", data_sz);
|
|
||||||
return -E2BIG;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_get_neigh_ipv4()
|
|
||||||
* Returns neighbour reference for a given IP address
|
|
||||||
*/
|
|
||||||
static struct neighbour *nss_udp_st_get_neigh_ipv4(uint32_t ip_addr)
|
|
||||||
{
|
|
||||||
struct neighbour *neigh;
|
|
||||||
struct rtable *rt;
|
|
||||||
struct dst_entry *dst;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* search for route entry
|
|
||||||
*/
|
|
||||||
rt = ip_route_output(&init_net, ip_addr, 0, 0, 0);
|
|
||||||
if (IS_ERR(rt)) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
dst = (struct dst_entry *)rt;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* neighbour lookup using IP address in the route table
|
|
||||||
*/
|
|
||||||
neigh = dst_neigh_lookup(dst, &ip_addr);
|
|
||||||
if (likely(neigh)) {
|
|
||||||
dst_release(dst);
|
|
||||||
return neigh;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* neighbour lookup using IP address, device in the arp table
|
|
||||||
*/
|
|
||||||
neigh = neigh_lookup(&arp_tbl, &ip_addr, dst->dev);
|
|
||||||
if (likely(neigh)) {
|
|
||||||
dst_release(dst);
|
|
||||||
return neigh;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* dst reference count was held during the lookup
|
|
||||||
*/
|
|
||||||
dst_release(dst);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_get_macaddr_get_ipv4()
|
|
||||||
* Return the hardware (MAC) address of the given IPv4 address, if any.
|
|
||||||
*
|
|
||||||
* Returns 0 on success or a negative result on failure.
|
|
||||||
* We look up the rtable entry for the address and,
|
|
||||||
* from its neighbour structure,obtain the hardware address.
|
|
||||||
* This means we will also work if the neighbours are routers too.
|
|
||||||
*/
|
|
||||||
int nss_udp_st_get_macaddr_ipv4(uint32_t ip_addr, uint8_t mac_addr[])
|
|
||||||
{
|
|
||||||
struct neighbour *neigh;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* handle multicast IP address seperately
|
|
||||||
*/
|
|
||||||
if (ipv4_is_multicast(htonl(ip_addr))) {
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* retrieve the neighbour
|
|
||||||
*/
|
|
||||||
rcu_read_lock();
|
|
||||||
neigh = nss_udp_st_get_neigh_ipv4(htonl(ip_addr));
|
|
||||||
if (!neigh) {
|
|
||||||
rcu_read_unlock();
|
|
||||||
pr_err("neighbour lookup failed for IP:0x%x\n", ip_addr);
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
rcu_read_unlock();
|
|
||||||
|
|
||||||
if ((neigh->nud_state & NUD_VALID) == 0) {
|
|
||||||
pr_err("neighbour state is invalid for IP:0x%x\n", ip_addr);
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!neigh->dev) {
|
|
||||||
pr_err("neighbour device not found for IP:0x%x\n", ip_addr);
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_multicast_ether_addr(neigh->ha)) {
|
|
||||||
pr_err( "neighbour MAC address is multicast or broadcast\n");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
ether_addr_copy(mac_addr, neigh->ha);
|
|
||||||
neigh_release(neigh);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
fail:
|
|
||||||
neigh_release(neigh);
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_get_neigh_ipv6()
|
|
||||||
* Returns neighbour reference for a given IP address
|
|
||||||
*/
|
|
||||||
struct neighbour *nss_udp_st_get_neigh_ipv6(uint32_t dst_addr[4])
|
|
||||||
{
|
|
||||||
struct neighbour *neigh;
|
|
||||||
struct dst_entry *dst;
|
|
||||||
struct rt6_info *rt;
|
|
||||||
struct in6_addr daddr;
|
|
||||||
|
|
||||||
NSS_UDP_ST_IPV6_ADDR_TO_IN6_ADDR(daddr, dst_addr);
|
|
||||||
|
|
||||||
rt = rt6_lookup(&init_net, &daddr, NULL, 0, NULL, 0);
|
|
||||||
if (!rt) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
dst = (struct dst_entry *)rt;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* neighbour lookup using IP address in the route table
|
|
||||||
*/
|
|
||||||
neigh = dst_neigh_lookup(dst, &daddr);
|
|
||||||
if (likely(neigh)) {
|
|
||||||
neigh_hold(neigh);
|
|
||||||
dst_release(dst);
|
|
||||||
return neigh;
|
|
||||||
}
|
|
||||||
dst_release(dst);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_get_ipv6_addr_hton()
|
|
||||||
* Convert the ipv6 address from host order to network order.
|
|
||||||
*/
|
|
||||||
void nss_udp_st_get_ipv6_addr_hton(uint32_t src[4], uint32_t dst[4])
|
|
||||||
{
|
|
||||||
nss_udp_st_swap_addr_ipv6(src, dst);
|
|
||||||
|
|
||||||
dst[0] = htonl(dst[0]);
|
|
||||||
dst[1] = htonl(dst[1]);
|
|
||||||
dst[2] = htonl(dst[2]);
|
|
||||||
dst[3] = htonl(dst[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_get_addr_ntoh()
|
|
||||||
* Convert the ipv6 address from network order to host order.
|
|
||||||
*/
|
|
||||||
void nss_udp_st_get_ipv6_addr_ntoh(uint32_t src[4], uint32_t dst[4])
|
|
||||||
{
|
|
||||||
nss_udp_st_swap_addr_ipv6(src, dst);
|
|
||||||
|
|
||||||
dst[0] = ntohl(dst[0]);
|
|
||||||
dst[1] = ntohl(dst[1]);
|
|
||||||
dst[2] = ntohl(dst[2]);
|
|
||||||
dst[3] = ntohl(dst[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_get_macaddr_get_ipv6()
|
|
||||||
* Return the hardware (MAC) address of the given ipv6 address, if any.
|
|
||||||
*
|
|
||||||
* Returns 0 on success or a negative result on failure.
|
|
||||||
* We look up the rtable entry for the address and,
|
|
||||||
* from its neighbour structure,obtain the hardware address.
|
|
||||||
* This means we will also work if the neighbours are routers too.
|
|
||||||
*/
|
|
||||||
int nss_udp_st_get_macaddr_ipv6(uint32_t ip_addr[4], uint8_t mac_addr[])
|
|
||||||
{
|
|
||||||
struct neighbour *neigh;
|
|
||||||
struct in6_addr addr;
|
|
||||||
|
|
||||||
nss_udp_st_get_ipv6_addr_hton(ip_addr, addr.s6_addr32);
|
|
||||||
|
|
||||||
if (ipv6_addr_is_multicast(&addr)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* retrieve the neighbour
|
|
||||||
*/
|
|
||||||
rcu_read_lock();
|
|
||||||
neigh = nss_udp_st_get_neigh_ipv6(addr.s6_addr32);
|
|
||||||
if (!neigh) {
|
|
||||||
rcu_read_unlock();
|
|
||||||
pr_info("neighbour lookup failed for %pI6c\n", addr.s6_addr32);
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
rcu_read_unlock();
|
|
||||||
|
|
||||||
if ((neigh->nud_state & NUD_VALID) == 0) {
|
|
||||||
pr_err("neighbour state is invalid for %pI6c\n", addr.s6_addr32);
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!neigh->dev) {
|
|
||||||
pr_err("neighbour device not found for %pI6c\n", addr.s6_addr32);
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_multicast_ether_addr(neigh->ha)) {
|
|
||||||
pr_err("neighbour MAC address is multicast or broadcast\n");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
ether_addr_copy(mac_addr, neigh->ha);
|
|
||||||
neigh_release(neigh);
|
|
||||||
return 0;
|
|
||||||
fail:
|
|
||||||
neigh_release(neigh);
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_compare_ipv6()
|
|
||||||
* Comapre ipv6 source and dest addresses
|
|
||||||
*/
|
|
||||||
bool nss_udp_st_compare_ipv6(uint32_t src[4], uint32_t dst[4])
|
|
||||||
{
|
|
||||||
if ((src[0] == dst[0]) && (src[1] == dst[1]) &&
|
|
||||||
(src[2] == dst[2]) && (src[3]==dst[3])) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
@ -1,63 +0,0 @@
|
|||||||
/*
|
|
||||||
**************************************************************************
|
|
||||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. 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 __NSS_UDP_ST_IP_H
|
|
||||||
#define __NSS_UDP_ST_IP_H
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Converts the format of an IPv6 address from NSS to Linux
|
|
||||||
*/
|
|
||||||
#define NSS_UDP_ST_IPV6_ADDR_TO_IN6_ADDR(in6, ipv6) \
|
|
||||||
{ \
|
|
||||||
in6.in6_u.u6_addr32[0] = ((uint32_t *)ipv6)[0]; \
|
|
||||||
in6.in6_u.u6_addr32[1] = ((uint32_t *)ipv6)[1]; \
|
|
||||||
in6.in6_u.u6_addr32[2] = ((uint32_t *)ipv6)[2]; \
|
|
||||||
in6.in6_u.u6_addr32[3] = ((uint32_t *)ipv6)[3]; \
|
|
||||||
}
|
|
||||||
|
|
||||||
int nss_udp_st_get_ipaddr_ntoh(const char *arg, uint16_t data_sz, uint32_t *data);
|
|
||||||
|
|
||||||
void nss_udp_st_get_ipv6_addr_hton(uint32_t src[4], uint32_t dst[4]);
|
|
||||||
|
|
||||||
void nss_udp_st_get_ipv6_addr_ntoh(uint32_t src[4], uint32_t dst[4]);
|
|
||||||
|
|
||||||
int nss_udp_st_get_macaddr_ipv4(uint32_t ip_addr, uint8_t mac_addr[]);
|
|
||||||
|
|
||||||
int nss_udp_st_get_macaddr_ipv6(uint32_t ip_addr[4], uint8_t mac_addr[]);
|
|
||||||
|
|
||||||
bool nss_udp_st_compare_ipv6(uint32_t src[4], uint32_t dst[4]);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_swap_addr_ipv6()
|
|
||||||
* Swap the ipv6 source and destination address.
|
|
||||||
*/
|
|
||||||
static inline void nss_udp_st_swap_addr_ipv6(uint32_t *src, uint32_t *dst)
|
|
||||||
{
|
|
||||||
uint32_t temp[4];
|
|
||||||
|
|
||||||
if (src == dst) {
|
|
||||||
memcpy(temp, src, sizeof(temp));
|
|
||||||
src = temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
dst[0] = src[3];
|
|
||||||
dst[1] = src[2];
|
|
||||||
dst[2] = src[1];
|
|
||||||
dst[3] = src[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /*NSS_UDP_ST_IP_H*/
|
|
||||||
@ -1,37 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file nss_udp_st_public.h
|
|
||||||
* NSS UDP ST Public definitions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _NSS_UDP_ST_PUBLIC_H_
|
|
||||||
#define _NSS_UDP_ST_PUBLIC_H_
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @addtogroup nss_udp_st_public_subsystem
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "nss_udp_st_drv.h"
|
|
||||||
#include "nss_udp_st_tx.h"
|
|
||||||
#include "nss_udp_st_rx.h"
|
|
||||||
#include "nss_udp_st_ip.h"
|
|
||||||
|
|
||||||
/** @} */ /* end_addtogroup nss_udp_st_public_subsystem */
|
|
||||||
|
|
||||||
#endif /*_NSS_UDP_ST_PUBLIC_H_*/
|
|
||||||
@ -1,107 +0,0 @@
|
|||||||
/*
|
|
||||||
**************************************************************************
|
|
||||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
|
||||||
*
|
|
||||||
* Permission to use, copy, modify, and/or distribute this software for
|
|
||||||
* any purpose with or without fee is hereby granted, provided that the
|
|
||||||
* above copyright notice and this permission notice appear in all copies.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
|
||||||
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
**************************************************************************
|
|
||||||
*/
|
|
||||||
#include <linux/list.h>
|
|
||||||
#include <linux/skbuff.h>
|
|
||||||
#include <net/netfilter/nf_conntrack_core.h>
|
|
||||||
#include "nss_udp_st_public.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_rx_ipv4_pre_routing_hook()
|
|
||||||
* pre-routing hook into netfilter packet monitoring point for IPv4
|
|
||||||
*/
|
|
||||||
unsigned int nss_udp_st_rx_ipv4_pre_routing_hook(void *priv, struct sk_buff *skb, const struct nf_hook_state *state)
|
|
||||||
{
|
|
||||||
struct udphdr *uh;
|
|
||||||
struct iphdr *iph;
|
|
||||||
struct nss_udp_st_rules *rules = NULL;
|
|
||||||
struct nss_udp_st_rules *n = NULL;
|
|
||||||
|
|
||||||
iph = (struct iphdr *)skb_network_header(skb);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Not a UDP speedtest packet
|
|
||||||
*/
|
|
||||||
if (iph->protocol != IPPROTO_UDP) {
|
|
||||||
return NF_ACCEPT;
|
|
||||||
}
|
|
||||||
|
|
||||||
uh = (struct udphdr *)skb_transport_header(skb);
|
|
||||||
|
|
||||||
list_for_each_entry_safe(rules, n, &nust.rules.list, list) {
|
|
||||||
/*
|
|
||||||
* If incoming packet matches 5tuple, it is a speedtest packet.
|
|
||||||
* Increase Rx packet stats and drop packet.
|
|
||||||
*/
|
|
||||||
if ((rules->flags & NSS_UDP_ST_FLAG_IPV4) &&
|
|
||||||
(rules->sip.ip.ipv4 == ntohl(iph->daddr)) &&
|
|
||||||
(rules->dip.ip.ipv4 == ntohl(iph->saddr)) &&
|
|
||||||
(rules->sport == ntohs(uh->source)) &&
|
|
||||||
(rules->dport == ntohs(uh->dest)) ) {
|
|
||||||
nss_udp_st_update_stats(ntohs(iph->tot_len) + sizeof(struct ethhdr));
|
|
||||||
kfree_skb(skb);
|
|
||||||
return NF_STOLEN;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NF_ACCEPT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_rx_ipv6_pre_routing_hook()
|
|
||||||
* pre-routing hook into netfilter packet monitoring point for IPv6
|
|
||||||
*/
|
|
||||||
unsigned int nss_udp_st_rx_ipv6_pre_routing_hook(void *priv, struct sk_buff *skb, const struct nf_hook_state *state)
|
|
||||||
{
|
|
||||||
struct udphdr *uh;
|
|
||||||
struct ipv6hdr *iph;
|
|
||||||
struct in6_addr saddr;
|
|
||||||
struct in6_addr daddr;
|
|
||||||
struct nss_udp_st_rules *rules = NULL;
|
|
||||||
struct nss_udp_st_rules *n = NULL;
|
|
||||||
|
|
||||||
iph = (struct ipv6hdr *)skb_network_header(skb);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Not a UDP speedtest packet
|
|
||||||
*/
|
|
||||||
if (iph->nexthdr != IPPROTO_UDP) {
|
|
||||||
return NF_ACCEPT;
|
|
||||||
}
|
|
||||||
|
|
||||||
uh = (struct udphdr *)skb_transport_header(skb);
|
|
||||||
|
|
||||||
nss_udp_st_get_ipv6_addr_ntoh(iph->saddr.s6_addr32, saddr.s6_addr32);
|
|
||||||
nss_udp_st_get_ipv6_addr_ntoh(iph->daddr.s6_addr32, daddr.s6_addr32);
|
|
||||||
|
|
||||||
list_for_each_entry_safe(rules, n, &nust.rules.list, list) {
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If incoming packet matches 5tuple, it is a speedtest packet.
|
|
||||||
* Increase Rx packet stats and drop packet.
|
|
||||||
*/
|
|
||||||
if ((rules->flags & NSS_UDP_ST_FLAG_IPV6) &&
|
|
||||||
(nss_udp_st_compare_ipv6(rules->sip.ip.ipv6, daddr.s6_addr32)) &&
|
|
||||||
(nss_udp_st_compare_ipv6(rules->dip.ip.ipv6, saddr.s6_addr32)) &&
|
|
||||||
(rules->sport == ntohs(uh->source)) &&
|
|
||||||
(rules->dport == ntohs(uh->dest))) {
|
|
||||||
nss_udp_st_update_stats(ntohs(iph->payload_len) + sizeof(struct ethhdr));
|
|
||||||
kfree_skb(skb);
|
|
||||||
return NF_STOLEN;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NF_ACCEPT;
|
|
||||||
}
|
|
||||||
@ -1,28 +0,0 @@
|
|||||||
/*
|
|
||||||
**************************************************************************
|
|
||||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. 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 __NSS_UDP_ST_RX_H
|
|
||||||
#define __NSS_UDP_ST_RX_H
|
|
||||||
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/netfilter.h>
|
|
||||||
|
|
||||||
unsigned int nss_udp_st_rx_ipv4_pre_routing_hook(void *priv, struct sk_buff *skb, const struct nf_hook_state *state);
|
|
||||||
|
|
||||||
unsigned int nss_udp_st_rx_ipv6_pre_routing_hook(void *priv, struct sk_buff *skb, const struct nf_hook_state *state);
|
|
||||||
|
|
||||||
#endif /*NSS_UDP_ST_RX_H*/
|
|
||||||
@ -1,577 +0,0 @@
|
|||||||
/*
|
|
||||||
**************************************************************************
|
|
||||||
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
|
||||||
*
|
|
||||||
* Permission to use, copy, modify, and/or distribute this software for
|
|
||||||
* any purpose with or without fee is hereby granted, provided that the
|
|
||||||
* above copyright notice and this permission notice appear in all copies.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
|
||||||
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
**************************************************************************
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/list.h>
|
|
||||||
#include <linux/string.h>
|
|
||||||
#include <linux/hrtimer.h>
|
|
||||||
#include <net/act_api.h>
|
|
||||||
#include <net/netfilter/nf_conntrack_core.h>
|
|
||||||
#include <linux/if_vlan.h>
|
|
||||||
#include <linux/if_pppox.h>
|
|
||||||
#include <net/ip6_checksum.h>
|
|
||||||
#include "nss_udp_st_public.h"
|
|
||||||
|
|
||||||
int tx_timer_flag;
|
|
||||||
static ktime_t kt;
|
|
||||||
static struct hrtimer tx_hr_timer;
|
|
||||||
static enum hrtimer_restart tx_hr_restart = HRTIMER_NORESTART;
|
|
||||||
static struct vlan_hdr vh;
|
|
||||||
static struct net_device *xmit_dev;
|
|
||||||
static struct pppoe_opt info;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_generate_ipv4_hdr()
|
|
||||||
* generate ipv4 header
|
|
||||||
*/
|
|
||||||
static inline void nss_udp_st_generate_ipv4_hdr(struct iphdr *iph, uint16_t ip_len, struct nss_udp_st_rules *rules)
|
|
||||||
{
|
|
||||||
iph->version = 4;
|
|
||||||
iph->ihl = 5;
|
|
||||||
iph->tos = nust.config.dscp;
|
|
||||||
iph->tot_len = htons(ip_len);
|
|
||||||
iph->id = 0;
|
|
||||||
iph->frag_off = 0;
|
|
||||||
iph->ttl = 64;
|
|
||||||
iph->protocol = IPPROTO_UDP;
|
|
||||||
iph->check = 0;
|
|
||||||
iph->saddr = htonl(rules->sip.ip.ipv4);
|
|
||||||
iph->daddr = htonl(rules->dip.ip.ipv4);
|
|
||||||
iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_generate_ipv6_hdr()
|
|
||||||
* generate ipv6 header
|
|
||||||
*/
|
|
||||||
static inline void nss_udp_st_generate_ipv6_hdr(struct ipv6hdr *ipv6h, uint16_t ip_len, struct nss_udp_st_rules *rules)
|
|
||||||
{
|
|
||||||
struct in6_addr addr;
|
|
||||||
|
|
||||||
ipv6h->version = 6;
|
|
||||||
memset(&ipv6h->flow_lbl, 0, sizeof(ipv6h->flow_lbl));
|
|
||||||
ipv6h->nexthdr = IPPROTO_UDP;
|
|
||||||
ipv6h->payload_len = htons(ip_len - sizeof(*ipv6h));
|
|
||||||
ipv6h->hop_limit = 64;
|
|
||||||
nss_udp_st_get_ipv6_addr_hton(rules->sip.ip.ipv6, addr.s6_addr32);
|
|
||||||
memcpy(ipv6h->saddr.s6_addr32, addr.s6_addr32, sizeof(ipv6h->saddr.s6_addr32));
|
|
||||||
nss_udp_st_get_ipv6_addr_hton(rules->dip.ip.ipv6, addr.s6_addr32);
|
|
||||||
memcpy(ipv6h->daddr.s6_addr32, addr.s6_addr32, sizeof(ipv6h->daddr.s6_addr32));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_generate_udp_hdr()
|
|
||||||
* generate udp header
|
|
||||||
*/
|
|
||||||
static void nss_udp_st_generate_udp_hdr(struct udphdr *uh, uint16_t udp_len, struct nss_udp_st_rules *rules)
|
|
||||||
{
|
|
||||||
|
|
||||||
uh->source = htons(rules->sport);
|
|
||||||
uh->dest = htons(rules->dport);
|
|
||||||
uh->len = htons(udp_len);
|
|
||||||
|
|
||||||
if (rules->flags & NSS_UDP_ST_FLAG_IPV4) {
|
|
||||||
uh->check = csum_tcpudp_magic(rules->sip.ip.ipv4, rules->dip.ip.ipv4, udp_len, IPPROTO_UDP,
|
|
||||||
csum_partial(uh, udp_len, 0));
|
|
||||||
} else if (rules->flags & NSS_UDP_ST_FLAG_IPV6) {
|
|
||||||
struct in6_addr saddr;
|
|
||||||
struct in6_addr daddr;
|
|
||||||
|
|
||||||
nss_udp_st_get_ipv6_addr_hton(rules->sip.ip.ipv6, saddr.s6_addr32);
|
|
||||||
nss_udp_st_get_ipv6_addr_hton(rules->dip.ip.ipv6, daddr.s6_addr32);
|
|
||||||
|
|
||||||
uh->check = csum_ipv6_magic(&saddr, &daddr, udp_len, IPPROTO_UDP,
|
|
||||||
csum_partial(uh, udp_len, 0));
|
|
||||||
} else {
|
|
||||||
atomic_long_inc(&nust.stats.errors[NSS_UDP_ST_ERROR_INCORRECT_IP_VERSION]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uh->check == 0) {
|
|
||||||
uh->check = CSUM_MANGLED_0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_generate_eth_hdr()
|
|
||||||
* generate L2 header
|
|
||||||
*/
|
|
||||||
static inline void nss_udp_st_generate_eth_hdr(struct sk_buff *skb, const uint8_t *src_mac, uint8_t *dst_mac)
|
|
||||||
{
|
|
||||||
struct ethhdr *eh = (struct ethhdr *)skb_push(skb, ETH_HLEN);
|
|
||||||
skb_reset_mac_header(skb);
|
|
||||||
|
|
||||||
eh->h_proto = skb->protocol;
|
|
||||||
memcpy(eh->h_source, src_mac, ETH_ALEN);
|
|
||||||
memcpy(eh->h_dest, dst_mac, ETH_ALEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_generate_vlan_hdr
|
|
||||||
* Generate VLAN header
|
|
||||||
*/
|
|
||||||
static void nss_udp_st_generate_vlan_hdr(struct sk_buff *skb, struct net_device *ndev)
|
|
||||||
{
|
|
||||||
struct vlan_hdr *vhdr;
|
|
||||||
|
|
||||||
skb_push(skb, VLAN_HLEN);
|
|
||||||
vhdr = (struct vlan_hdr *)skb->data;
|
|
||||||
vhdr->h_vlan_TCI = htons(vh.h_vlan_TCI);
|
|
||||||
vhdr->h_vlan_encapsulated_proto = skb->protocol;
|
|
||||||
skb->protocol = htons(vh.h_vlan_encapsulated_proto);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_generate_pppoe_hdr
|
|
||||||
* Generate PPPoE header
|
|
||||||
*/
|
|
||||||
static void nss_udp_st_generate_pppoe_hdr(struct sk_buff *skb, uint16_t ppp_protocol)
|
|
||||||
{
|
|
||||||
struct pppoe_hdr *ph;
|
|
||||||
unsigned char *pp;
|
|
||||||
unsigned int data_len;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Insert the PPP header protocol
|
|
||||||
*/
|
|
||||||
pp = skb_push(skb, 2);
|
|
||||||
put_unaligned_be16(ppp_protocol, pp);
|
|
||||||
|
|
||||||
data_len = skb->len;
|
|
||||||
|
|
||||||
ph = (struct pppoe_hdr *)skb_push(skb, sizeof(*ph));
|
|
||||||
skb_reset_network_header(skb);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Headers in skb will look like in below sequence
|
|
||||||
* | PPPoE hdr(6 bytes) | PPP hdr (2 bytes) | L3 hdr |
|
|
||||||
*
|
|
||||||
* The length field in the PPPoE header indicates the length of the PPPoE payload which
|
|
||||||
* consists of a 2-byte PPP header plus a skb->len.
|
|
||||||
*/
|
|
||||||
ph->ver = 1;
|
|
||||||
ph->type = 1;
|
|
||||||
ph->code = 0;
|
|
||||||
ph->sid = (uint16_t)info.pa.sid;
|
|
||||||
ph->length = htons(data_len);
|
|
||||||
|
|
||||||
skb->protocol = htons(ETH_P_PPP_SES);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_tx_packets()
|
|
||||||
* allocate, populate and send tx packet
|
|
||||||
*/
|
|
||||||
static void nss_udp_st_tx_packets(struct net_device *ndev, struct nss_udp_st_rules *rules)
|
|
||||||
{
|
|
||||||
struct sk_buff *skb;
|
|
||||||
struct udphdr *uh;
|
|
||||||
struct iphdr *iph;
|
|
||||||
struct ipv6hdr *ipv6h;
|
|
||||||
size_t align_offset;
|
|
||||||
size_t skb_sz;
|
|
||||||
size_t pkt_sz;
|
|
||||||
uint16_t ip_len;
|
|
||||||
uint16_t udp_len;
|
|
||||||
unsigned char *data;
|
|
||||||
uint16_t ppp_protocol;
|
|
||||||
|
|
||||||
pkt_sz = nust.config.buffer_sz;
|
|
||||||
ip_len = pkt_sz;
|
|
||||||
|
|
||||||
if (rules->flags & NSS_UDP_ST_FLAG_IPV4) {
|
|
||||||
udp_len = pkt_sz - sizeof(*iph);
|
|
||||||
} else if (rules->flags & NSS_UDP_ST_FLAG_IPV6) {
|
|
||||||
udp_len = pkt_sz - sizeof(*ipv6h);
|
|
||||||
} else {
|
|
||||||
atomic_long_inc(&nust.stats.errors[NSS_UDP_ST_ERROR_INCORRECT_IP_VERSION]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
skb_sz = NSS_UDP_ST_MIN_HEADROOM + pkt_sz + sizeof(struct ethhdr) + NSS_UDP_ST_MIN_TAILROOM + SMP_CACHE_BYTES;
|
|
||||||
|
|
||||||
skb = dev_alloc_skb(skb_sz);
|
|
||||||
if (!skb) {
|
|
||||||
atomic_long_inc(&nust.stats.errors[NSS_UDP_ST_ERROR_MEMORY_FAILURE]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
align_offset = PTR_ALIGN(skb->data, SMP_CACHE_BYTES) - skb->data;
|
|
||||||
skb_reserve(skb, NSS_UDP_ST_MAX_HEADROOM + align_offset + sizeof(uint16_t));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* populate udp header
|
|
||||||
*/
|
|
||||||
skb_push(skb, sizeof(*uh));
|
|
||||||
skb_reset_transport_header(skb);
|
|
||||||
uh = udp_hdr(skb);
|
|
||||||
nss_udp_st_generate_udp_hdr(uh, udp_len, rules);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* populate ipv4 or ipv6 header
|
|
||||||
*/
|
|
||||||
if (rules->flags & NSS_UDP_ST_FLAG_IPV4) {
|
|
||||||
skb_push(skb, sizeof(*iph));
|
|
||||||
skb_reset_network_header(skb);
|
|
||||||
iph = ip_hdr(skb);
|
|
||||||
nss_udp_st_generate_ipv4_hdr(iph, ip_len, rules);
|
|
||||||
data = skb_put(skb, pkt_sz - sizeof(*iph) - sizeof(*uh));
|
|
||||||
memset(data, 0, pkt_sz - sizeof(*iph) - sizeof(*uh));
|
|
||||||
} else if (rules->flags & NSS_UDP_ST_FLAG_IPV6) {
|
|
||||||
skb_push(skb, sizeof(*ipv6h));
|
|
||||||
skb_reset_network_header(skb);
|
|
||||||
ipv6h = ipv6_hdr(skb);
|
|
||||||
nss_udp_st_generate_ipv6_hdr(ipv6h, ip_len, rules);
|
|
||||||
data = skb_put(skb, pkt_sz - sizeof(*ipv6h) - sizeof(*uh));
|
|
||||||
memset(data, 0, pkt_sz - sizeof(*ipv6h) - sizeof(*uh));
|
|
||||||
} else {
|
|
||||||
atomic_long_inc(&nust.stats.errors[NSS_UDP_ST_ERROR_INCORRECT_IP_VERSION]);
|
|
||||||
kfree_skb(skb);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (ndev->type) {
|
|
||||||
case ARPHRD_PPP:
|
|
||||||
if (rules->flags & NSS_UDP_ST_FLAG_IPV4) {
|
|
||||||
ppp_protocol = PPP_IP;
|
|
||||||
} else {
|
|
||||||
ppp_protocol = PPP_IPV6;
|
|
||||||
}
|
|
||||||
|
|
||||||
nss_udp_st_generate_pppoe_hdr(skb, ppp_protocol);
|
|
||||||
|
|
||||||
if(is_vlan_dev(info.dev)) {
|
|
||||||
nss_udp_st_generate_vlan_hdr(skb, info.dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* populate ethernet header
|
|
||||||
*/
|
|
||||||
nss_udp_st_generate_eth_hdr(skb, xmit_dev->dev_addr, info.pa.remote);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ARPHRD_ETHER:
|
|
||||||
if (rules->flags & NSS_UDP_ST_FLAG_IPV4) {
|
|
||||||
skb->protocol = htons(ETH_P_IP);
|
|
||||||
} else {
|
|
||||||
skb->protocol = htons(ETH_P_IPV6);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(is_vlan_dev(ndev)) {
|
|
||||||
nss_udp_st_generate_vlan_hdr(skb, ndev);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* populate ethernet header
|
|
||||||
*/
|
|
||||||
nss_udp_st_generate_eth_hdr(skb, xmit_dev->dev_addr, rules->dst_mac);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* tx packet
|
|
||||||
*/
|
|
||||||
skb->dev = xmit_dev;
|
|
||||||
if (xmit_dev->netdev_ops->ndo_start_xmit(skb, xmit_dev) != NETDEV_TX_OK) {
|
|
||||||
kfree_skb(skb);
|
|
||||||
atomic_long_inc(&nust.stats.errors[NSS_UDP_ST_ERROR_PACKET_DROP]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
nss_udp_st_update_stats(ip_len + sizeof(struct ethhdr));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_set_dev()
|
|
||||||
* get net_device
|
|
||||||
*/
|
|
||||||
static bool nss_udp_st_set_dev(void)
|
|
||||||
{
|
|
||||||
nust_dev = dev_get_by_name(&init_net, nust.config.net_dev);
|
|
||||||
if (!nust_dev) {
|
|
||||||
pr_err("Cannot find the net device\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_tx_valid()
|
|
||||||
* check if test time has elapsed
|
|
||||||
*/
|
|
||||||
bool nss_udp_st_tx_valid(void)
|
|
||||||
{
|
|
||||||
long long elapsed = atomic_long_read(&nust.stats.timer_stats[NSS_UDP_ST_STATS_TIME_ELAPSED]);
|
|
||||||
|
|
||||||
if (elapsed < (nust.time * 1000)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
nust.mode = NSS_UDP_ST_STOP;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_vlan_iface_config
|
|
||||||
* Configure the WLAN interface as VLAN
|
|
||||||
*/
|
|
||||||
static int nss_udp_st_vlan_iface_config(struct net_device *dev)
|
|
||||||
{
|
|
||||||
xmit_dev = vlan_dev_next_dev(dev);
|
|
||||||
if (!xmit_dev) {
|
|
||||||
pr_err("Cannot find the physical net device\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_vlan_dev(xmit_dev) || xmit_dev->type != ARPHRD_ETHER) {
|
|
||||||
pr_warn("%px: QinQ or non-ethernet VLAN master (%s) is not supported\n", dev,
|
|
||||||
xmit_dev->name);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
vh.h_vlan_TCI = vlan_dev_vlan_id(dev);
|
|
||||||
vh.h_vlan_encapsulated_proto = ntohs(vlan_dev_vlan_proto(dev));
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_pppoe_iface_config
|
|
||||||
* Configure the WLAN interface as PPPoE
|
|
||||||
*/
|
|
||||||
static int nss_udp_st_pppoe_iface_config(struct net_device *dev)
|
|
||||||
{
|
|
||||||
struct ppp_channel *ppp_chan[1];
|
|
||||||
int channel_count;
|
|
||||||
int channel_protocol;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Gets the PPPoE channel information.
|
|
||||||
*/
|
|
||||||
channel_count = ppp_hold_channels(dev, ppp_chan, 1);
|
|
||||||
if (channel_count != 1) {
|
|
||||||
pr_warn("%px: Unable to get the channel for device: %s\n", dev, dev->name);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
channel_protocol = ppp_channel_get_protocol(ppp_chan[0]);
|
|
||||||
if (channel_protocol != PX_PROTO_OE) {
|
|
||||||
pr_warn("%px: PPP channel protocol is not PPPoE for device: %s\n", dev, dev->name);
|
|
||||||
ppp_release_channels(ppp_chan, 1);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pppoe_channel_addressing_get(ppp_chan[0], &info)) {
|
|
||||||
pr_warn("%px: Unable to get the PPPoE session information for device: %s\n", dev, dev->name);
|
|
||||||
ppp_release_channels(ppp_chan, 1);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check if the next device is a VLAN (eth0-eth0.100-pppoe-wan)
|
|
||||||
*/
|
|
||||||
if (is_vlan_dev(info.dev)) {
|
|
||||||
/*
|
|
||||||
* Next device is a VLAN device (eth0.100)
|
|
||||||
*/
|
|
||||||
if (nss_udp_st_vlan_iface_config(info.dev) < 0) {
|
|
||||||
pr_warn("%px: Unable to get PPPoE's VLAN device's (%s) next dev\n", dev,
|
|
||||||
info.dev->name);
|
|
||||||
ret = -1;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* PPPoE interface can be created on linux bridge, OVS bridge and LAG devices.
|
|
||||||
* udp_st doesn't support these hierarchies.
|
|
||||||
*/
|
|
||||||
if ((info.dev->priv_flags & (IFF_EBRIDGE | IFF_OPENVSWITCH))
|
|
||||||
|| ((info.dev->flags & IFF_MASTER) && (info.dev->priv_flags & IFF_BONDING))) {
|
|
||||||
pr_warn("%px: PPPoE over bridge and LAG interfaces are not supported, dev: %s info.dev: %s\n",dev, dev->name, info.dev->name);
|
|
||||||
ret = -1;
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* PPPoE only (eth0-pppoe-wan)
|
|
||||||
*/
|
|
||||||
xmit_dev = info.dev;
|
|
||||||
}
|
|
||||||
|
|
||||||
fail:
|
|
||||||
dev_put(info.dev);
|
|
||||||
ppp_release_channels(ppp_chan, 1);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_tx_work_send_packets()
|
|
||||||
* generate and send packets per rule
|
|
||||||
*/
|
|
||||||
static void nss_udp_st_tx_work_send_packets(void)
|
|
||||||
{
|
|
||||||
int i = 0;
|
|
||||||
struct nss_udp_st_rules *pos = NULL;
|
|
||||||
struct nss_udp_st_rules *n = NULL;
|
|
||||||
|
|
||||||
if (!nss_udp_st_tx_valid() || nust.mode == NSS_UDP_ST_STOP ) {
|
|
||||||
dev_put(nust_dev);
|
|
||||||
tx_hr_restart = HRTIMER_NORESTART;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
list_for_each_entry_safe(pos, n, &nust.rules.list, list) {
|
|
||||||
for (i = 0; i < nss_udp_st_tx_num_pkt; i++) {
|
|
||||||
/*
|
|
||||||
* check if test time has elapsed or test has been stopped
|
|
||||||
*/
|
|
||||||
if (!nss_udp_st_tx_valid() || nust.mode == NSS_UDP_ST_STOP ) {
|
|
||||||
dev_put(nust_dev);
|
|
||||||
tx_hr_restart = HRTIMER_NORESTART;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
nss_udp_st_tx_packets(nust_dev, pos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tx_hr_restart = HRTIMER_RESTART;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_tx_init()
|
|
||||||
* initialize speedtest for tx
|
|
||||||
*/
|
|
||||||
static bool nss_udp_st_tx_init(void)
|
|
||||||
{
|
|
||||||
uint64_t total_bps;
|
|
||||||
|
|
||||||
if (nust.config.rate > NSS_UDP_ST_RATE_MAX) {
|
|
||||||
atomic_long_inc(&nust.stats.errors[NSS_UDP_ST_ERROR_INCORRECT_RATE]);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nust.config.buffer_sz > NSS_UDP_ST_BUFFER_SIZE_MAX) {
|
|
||||||
atomic_long_inc(&nust.stats.errors[NSS_UDP_ST_ERROR_INCORRECT_BUFFER_SIZE]);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
total_bps = (uint64_t)nust.config.rate * 1024 * 1024;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* calculate number of pkts to send per rule per 10 ms
|
|
||||||
*/
|
|
||||||
nss_udp_st_tx_num_pkt = total_bps / (nust.rule_count * (nust.config.buffer_sz + sizeof(struct ethhdr)) * 8 * NSS_UDP_ST_TX_TIMER);
|
|
||||||
nss_udp_st_tx_num_pkt ++;
|
|
||||||
pr_debug("total number of packets to tx every 100ms %llu\n",nss_udp_st_tx_num_pkt);
|
|
||||||
if(!nss_udp_st_set_dev()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_hrtimer_cleanup()
|
|
||||||
* cancel hrtimer
|
|
||||||
*/
|
|
||||||
void nss_udp_st_hrtimer_cleanup(void)
|
|
||||||
{
|
|
||||||
hrtimer_cancel(&tx_hr_timer);
|
|
||||||
tx_hr_restart = HRTIMER_NORESTART;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_hrtimer_callback()
|
|
||||||
* hrtimer callback function
|
|
||||||
*/
|
|
||||||
static enum hrtimer_restart nss_udp_st_hrtimer_callback(struct hrtimer *timer)
|
|
||||||
{
|
|
||||||
nss_udp_st_tx_work_send_packets();
|
|
||||||
if(tx_hr_restart == HRTIMER_RESTART) {
|
|
||||||
hrtimer_forward_now(timer, kt);
|
|
||||||
}
|
|
||||||
return tx_hr_restart;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_hrtimer_init()
|
|
||||||
* initialize hrtimer
|
|
||||||
*/
|
|
||||||
void nss_udp_st_hrtimer_init(void)
|
|
||||||
{
|
|
||||||
tx_hr_restart = HRTIMER_RESTART;
|
|
||||||
kt = ktime_set(0,10000000);
|
|
||||||
hrtimer_init(&tx_hr_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS_HARD);
|
|
||||||
tx_hr_timer.function = &nss_udp_st_hrtimer_callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_tx()
|
|
||||||
* start speedtest for tx
|
|
||||||
*/
|
|
||||||
bool nss_udp_st_tx(void)
|
|
||||||
{
|
|
||||||
if (!nss_udp_st_tx_init()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (nust_dev->type) {
|
|
||||||
case ARPHRD_PPP:
|
|
||||||
if(nss_udp_st_pppoe_iface_config(nust_dev) < 0) {
|
|
||||||
pr_err("Could not configure pppoe, dev: %s\n", nust_dev->name);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ARPHRD_ETHER:
|
|
||||||
if ((nust_dev->priv_flags & (IFF_EBRIDGE | IFF_OPENVSWITCH))
|
|
||||||
|| ((nust_dev->flags & IFF_MASTER) && (nust_dev->priv_flags & IFF_BONDING))) {
|
|
||||||
pr_err("Bridge and LAG interfaces are not supported, dev: %s\n", nust_dev->name);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_vlan_dev(nust_dev)) {
|
|
||||||
if (nss_udp_st_vlan_iface_config(nust_dev) < 0) {
|
|
||||||
pr_err("Could not configure vlan, dev: %s\n", nust_dev->name);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
xmit_dev = nust_dev;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
pr_err("Unsupported speedtest interface: %s\n", nust_dev->name);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
pr_debug("Speedtest interface: %s\n", nust_dev->name);
|
|
||||||
|
|
||||||
if (!tx_timer_flag) {
|
|
||||||
nss_udp_st_hrtimer_init();
|
|
||||||
hrtimer_start(&tx_hr_timer, kt, HRTIMER_MODE_ABS_HARD);
|
|
||||||
tx_timer_flag = 1;
|
|
||||||
} else {
|
|
||||||
hrtimer_restart(&tx_hr_timer);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
/*
|
|
||||||
**************************************************************************
|
|
||||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. 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 __NSS_UDP_ST_TX_H
|
|
||||||
#define __NSS_UDP_ST_TX_H
|
|
||||||
|
|
||||||
#define NSS_UDP_ST_TX_DEFAULT_TIMEOUT 50 /* Default Tx test duration*/
|
|
||||||
#define NSS_UDP_ST_TX_TIMER 100 /* To caluculate pkt per 10 ms*/
|
|
||||||
#define NSS_UDP_ST_MIN_HEADROOM 32 /* Min headroom needed */
|
|
||||||
#define NSS_UDP_ST_MIN_TAILROOM 32 /* Min tailroom needed */
|
|
||||||
|
|
||||||
bool nss_udp_st_tx_valid(void);
|
|
||||||
|
|
||||||
bool nss_udp_st_tx(void);
|
|
||||||
|
|
||||||
void nss_udp_st_hrtimer_cleanup(void);
|
|
||||||
|
|
||||||
#endif /*NSS_UDP_ST_TX_H*/
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
include $(TOPDIR)/rules.mk
|
|
||||||
include $(INCLUDE_DIR)/kernel.mk
|
|
||||||
|
|
||||||
PKG_NAME:=nss-udp-st
|
|
||||||
PKG_RELEASE:=1
|
|
||||||
|
|
||||||
include $(INCLUDE_DIR)/package.mk
|
|
||||||
|
|
||||||
define Package/nss-udp-st
|
|
||||||
SECTION:=utils
|
|
||||||
CATEGORY:=Utilities
|
|
||||||
URL:=http://www.qualcomm.com
|
|
||||||
TITLE:=NSS UDP SpeedTest
|
|
||||||
DEPENDS:=@TARGET_qualcommax +kmod-nss-udp-st-drv
|
|
||||||
endef
|
|
||||||
|
|
||||||
define Package/nss-udp-st/description/Default
|
|
||||||
A userspace utility for host data path nss udp speedtest
|
|
||||||
endef
|
|
||||||
|
|
||||||
TARGET_CFLAGS += -I$(STAGING_DIR)/usr/include/nss-udp-st-drv/
|
|
||||||
|
|
||||||
define Build/Compile
|
|
||||||
$(MAKE) -C $(PKG_BUILD_DIR) \
|
|
||||||
CC="$(TARGET_CC)" \
|
|
||||||
CFLAGS="$(TARGET_CFLAGS)" \
|
|
||||||
LDFLAGS="$(TARGET_LDFLAGS)"
|
|
||||||
endef
|
|
||||||
|
|
||||||
define Package/nss-udp-st/install
|
|
||||||
$(INSTALL_DIR) $(1)/usr/sbin
|
|
||||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/nss-udp-st $(1)/usr/sbin/
|
|
||||||
endef
|
|
||||||
|
|
||||||
$(eval $(call BuildPackage,nss-udp-st))
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
#Sources to compile
|
|
||||||
CSRCS := nss-udp-st.c
|
|
||||||
|
|
||||||
all:
|
|
||||||
$(CC) $(CFLAGS) $(LDFLAGS) -g3 -Wall -Werror -pie -fPIC \
|
|
||||||
$(CSRCS) -o nss-udp-st
|
|
||||||
clean:
|
|
||||||
rm -f nss-udp-st
|
|
||||||
@ -1,461 +0,0 @@
|
|||||||
/*
|
|
||||||
**************************************************************************
|
|
||||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. 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.
|
|
||||||
**************************************************************************
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @file NSS UDP Speetest App
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <getopt.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include "nss-udp-st.h"
|
|
||||||
|
|
||||||
struct nss_udp_st_param st_param;
|
|
||||||
struct nss_udp_st_opt st_opt;
|
|
||||||
struct nss_udp_st_cfg st_cfg;
|
|
||||||
struct nss_udp_st_stat st_stat;
|
|
||||||
|
|
||||||
struct option long_options[] =
|
|
||||||
{
|
|
||||||
{"mode", required_argument, NULL, 'm'},
|
|
||||||
{"type", required_argument, NULL, 'x'},
|
|
||||||
{"sip", required_argument, NULL, 's'},
|
|
||||||
{"dip", required_argument, NULL, 'd'},
|
|
||||||
{"sport", required_argument, NULL, 'y'},
|
|
||||||
{"dport", required_argument, NULL, 'z'},
|
|
||||||
{"net_dev", required_argument, NULL, 'n'},
|
|
||||||
{"version", required_argument, NULL, 'f'},
|
|
||||||
{"time", required_argument, NULL, 't'},
|
|
||||||
{"rate", required_argument, NULL, 'r'},
|
|
||||||
{"buffer_sz", required_argument, NULL, 'b'},
|
|
||||||
{"dscp", required_argument, NULL, 'c'},
|
|
||||||
{"help", no_argument, NULL, 'h'},
|
|
||||||
{0, 0, 0, 0}
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_init()
|
|
||||||
* Load nss speedtest driver and initialize test parameters
|
|
||||||
*/
|
|
||||||
static int nss_udp_st_init(void)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
mkdir(NSS_UDP_ST_LOG, 0777);
|
|
||||||
ret = ioctl(st_cfg.handle, NSS_UDP_ST_IOCTL_INIT, &st_param);
|
|
||||||
if (ret < 0) {
|
|
||||||
printf("ioctl error %d\n", ret);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_final()
|
|
||||||
* Unload nss speedtest driver
|
|
||||||
*/
|
|
||||||
static void nss_udp_st_final(void)
|
|
||||||
{
|
|
||||||
system("rmmod nss-udp-st.ko");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_create()
|
|
||||||
* Configure NSS UDP speedtest rules
|
|
||||||
*/
|
|
||||||
static int nss_udp_st_create(void)
|
|
||||||
{
|
|
||||||
FILE *fp = NULL;
|
|
||||||
|
|
||||||
fp = fopen(NSS_UDP_ST_RULES, "a+");
|
|
||||||
if (!fp) {
|
|
||||||
printf("create/open file error\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(fp, "sip=<%s> dip=<%s> sport=<%d> dport=<%d> version=<%d>\n",
|
|
||||||
st_opt.sip, st_opt.dip, st_opt.sport, st_opt.dport, st_opt.ip_version);
|
|
||||||
|
|
||||||
fclose(fp);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_list()
|
|
||||||
* List NSS UDP speedtest rules
|
|
||||||
*/
|
|
||||||
static int nss_udp_st_list(void)
|
|
||||||
{
|
|
||||||
FILE *fp = NULL;
|
|
||||||
char *buffer = NULL;
|
|
||||||
size_t size = 0;
|
|
||||||
|
|
||||||
fp = fopen(NSS_UDP_ST_RULES, "r");
|
|
||||||
if (!fp) {
|
|
||||||
printf("create/open file error\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((getline(&buffer, &size, fp)) != -1) {
|
|
||||||
printf("\n%s", buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(buffer);
|
|
||||||
fclose(fp);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_clear()
|
|
||||||
* Clear NSS UDP speedtest rules
|
|
||||||
*/
|
|
||||||
static int nss_udp_st_clear(void)
|
|
||||||
{
|
|
||||||
FILE *fp = NULL;
|
|
||||||
|
|
||||||
fp = fopen(NSS_UDP_ST_RULES, "w");
|
|
||||||
if (!fp) {
|
|
||||||
printf("create/open file error\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(fp);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_push_rules()
|
|
||||||
* Push NSS UDP speedtest rules to driver
|
|
||||||
*/
|
|
||||||
static int nss_udp_st_push_rules(void)
|
|
||||||
{
|
|
||||||
FILE *fp = NULL;
|
|
||||||
char *buffer = NULL;
|
|
||||||
char *token = NULL;
|
|
||||||
char *saveptr = NULL;
|
|
||||||
size_t size = 0;
|
|
||||||
int count = 0;
|
|
||||||
int ret = 0;
|
|
||||||
bool flag = true;
|
|
||||||
|
|
||||||
fp = fopen(NSS_UDP_ST_RULES, "r");
|
|
||||||
if (!fp) {
|
|
||||||
printf("create/open file error\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((getline(&buffer, &size, fp)) != -1) {
|
|
||||||
flag = true;
|
|
||||||
count = 0;
|
|
||||||
token=strtok_r(buffer, "<>", &saveptr);
|
|
||||||
memset(&st_opt, 0, sizeof(st_opt));
|
|
||||||
while(token != NULL) {
|
|
||||||
flag = !flag;
|
|
||||||
if (flag) {
|
|
||||||
if (count == NSS_UDP_ST_SIP)
|
|
||||||
strlcpy(st_opt.sip, token, sizeof(st_opt.sip));
|
|
||||||
if (count == NSS_UDP_ST_DIP)
|
|
||||||
strlcpy(st_opt.dip, token, sizeof(st_opt.dip));
|
|
||||||
if (count == NSS_UDP_ST_SPORT)
|
|
||||||
st_opt.sport=atoi(token);
|
|
||||||
if (count == NSS_UDP_ST_DPORT)
|
|
||||||
st_opt.dport=atoi(token);
|
|
||||||
if (count == NSS_UDP_ST_FLAGS)
|
|
||||||
st_opt.ip_version=atoi(token);
|
|
||||||
|
|
||||||
count ++;
|
|
||||||
}
|
|
||||||
token = strtok_r(NULL, "<>", &saveptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = write(st_cfg.handle, &st_opt, sizeof(st_opt));
|
|
||||||
if (ret < 0) {
|
|
||||||
printf("invalid rule config option\n");
|
|
||||||
printf("write error %d\n",ret);
|
|
||||||
free(buffer);
|
|
||||||
fclose(fp);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(buffer);
|
|
||||||
fclose(fp);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_start()
|
|
||||||
* Send ioctl to start NSS UDP speedtest
|
|
||||||
*/
|
|
||||||
static int nss_udp_st_start(void)
|
|
||||||
{
|
|
||||||
int ret = nss_udp_st_push_rules();
|
|
||||||
if (ret) {
|
|
||||||
printf("invalid rule config option\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (st_cfg.type == NSS_UDP_ST_TX) {
|
|
||||||
ret = ioctl(st_cfg.handle, NSS_UDP_ST_IOCTL_START_TX, &st_cfg.time);
|
|
||||||
} else if (st_cfg.type == NSS_UDP_ST_RX) {
|
|
||||||
ret = ioctl(st_cfg.handle, NSS_UDP_ST_IOCTL_START_RX);
|
|
||||||
} else {
|
|
||||||
printf("invalid type option\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret < 0) {
|
|
||||||
printf("ioctl error %d\n", ret);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_stop()
|
|
||||||
* Send ioctl to stop NSS USP speedtest
|
|
||||||
*/
|
|
||||||
static int nss_udp_st_stop(void)
|
|
||||||
{
|
|
||||||
int ret = ioctl(st_cfg.handle, NSS_UDP_ST_IOCTL_STOP);
|
|
||||||
if (ret < 0) {
|
|
||||||
printf("ioctl error %d\n", ret);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_stats()
|
|
||||||
* Read NSS UDP speedtest results
|
|
||||||
*/
|
|
||||||
static int nss_udp_st_stats(void)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
FILE *fp = NULL;
|
|
||||||
long long bytes = 0;
|
|
||||||
|
|
||||||
ret = read(st_cfg.handle, &st_stat, sizeof(st_stat));
|
|
||||||
if (ret < 0) {
|
|
||||||
printf("read error %d\n",ret);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (st_cfg.type == NSS_UDP_ST_TX) {
|
|
||||||
fp = fopen(NSS_UDP_ST_TX_STATS, "w");
|
|
||||||
if (!fp) {
|
|
||||||
printf("create/open file error\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(fp, "\nPacket Stats\n");
|
|
||||||
fprintf(fp, "\ttx_packets = %lld packets\n",st_stat.p_stats.tx_packets);
|
|
||||||
fprintf(fp, "\ttx_bytes = %lld bytes\n",st_stat.p_stats.tx_bytes);
|
|
||||||
bytes = st_stat.p_stats.tx_bytes;
|
|
||||||
} else if (st_cfg.type == NSS_UDP_ST_RX) {
|
|
||||||
fp = fopen(NSS_UDP_ST_RX_STATS, "w");
|
|
||||||
if (!fp) {
|
|
||||||
printf("create/open file error\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(fp, "\nPacket Stats\n\n");
|
|
||||||
fprintf(fp, "\trx_packets = %lld packets\n",st_stat.p_stats.rx_packets);
|
|
||||||
fprintf(fp, "\trx_bytes = %lld bytes\n",st_stat.p_stats.rx_bytes);
|
|
||||||
bytes = st_stat.p_stats.rx_bytes;
|
|
||||||
} else {
|
|
||||||
printf("type error\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(fp, "\nTime Stats\n");
|
|
||||||
fprintf(fp, "\tstart time = %lld ms\n",st_stat.timer_stats[NSS_UDP_ST_STATS_TIME_START]);
|
|
||||||
fprintf(fp, "\tcapture time = %lld ms\n",
|
|
||||||
st_stat.timer_stats[NSS_UDP_ST_STATS_TIME_CURRENT]);
|
|
||||||
fprintf(fp, "\telapsed time = %lld ms\n",
|
|
||||||
st_stat.timer_stats[NSS_UDP_ST_STATS_TIME_ELAPSED]);
|
|
||||||
|
|
||||||
fprintf(fp, "\nError Stats\n");
|
|
||||||
fprintf(fp, "\tincorrect rate = %lld\n",
|
|
||||||
st_stat.errors[NSS_UDP_ST_ERROR_INCORRECT_RATE]);
|
|
||||||
fprintf(fp, "\tincorrect buffer size = %lld\n",
|
|
||||||
st_stat.errors[NSS_UDP_ST_ERROR_INCORRECT_BUFFER_SIZE]);
|
|
||||||
fprintf(fp, "\tmemory failure = %lld\n",
|
|
||||||
st_stat.errors[NSS_UDP_ST_ERROR_MEMORY_FAILURE]);
|
|
||||||
fprintf(fp, "\tpacket drop count = %lld\n",
|
|
||||||
st_stat.errors[NSS_UDP_ST_ERROR_PACKET_DROP]);
|
|
||||||
fprintf(fp, "\tincorrect ip version = %lld\n",
|
|
||||||
st_stat.errors[NSS_UDP_ST_ERROR_INCORRECT_IP_VERSION]);
|
|
||||||
|
|
||||||
fprintf(fp, "\nThroughput Stats\n");
|
|
||||||
fprintf(fp, "\tthroughput = %lld Mbps\n",
|
|
||||||
(bytes * 8)/(st_stat.timer_stats[NSS_UDP_ST_STATS_TIME_ELAPSED] * 1000));
|
|
||||||
fclose(fp);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_usage()
|
|
||||||
* Usage for command line arguments
|
|
||||||
*/
|
|
||||||
static void nss_udp_st_usage(void)
|
|
||||||
{
|
|
||||||
printf("\nUsage:");
|
|
||||||
printf("\n./nss_udp_st --mode <init> --rate <rate in Mbps> \
|
|
||||||
--buffer_sz <buffer_size in bytes> --dscp <dscp> --net_dev <net_dev>");
|
|
||||||
printf("\n./nss_udp_st --mode <create> --sip <sip> --dip <dip> \
|
|
||||||
--sport <sport> --dport <dport> --version <4/6>");
|
|
||||||
printf("\n./nss_udp_st --mode <start> --type <tx/rx> --time <time in seconds>");
|
|
||||||
printf("\n./nss_udp_st --mode <stats> --type <tx/rx>");
|
|
||||||
printf("\n./nss_udp_st --mode <list/clear/final>");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_get_opt()
|
|
||||||
* Parse command line arguments
|
|
||||||
*/
|
|
||||||
static int nss_udp_st_get_opt(int args, char **argv)
|
|
||||||
{
|
|
||||||
int c = 0;
|
|
||||||
int option_index = 0;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
c = getopt_long_only(args, argv, "m:x:s:d:y:z:n:f:t:r:b:c",
|
|
||||||
long_options, &option_index);
|
|
||||||
if (c == -1)
|
|
||||||
break;
|
|
||||||
|
|
||||||
switch (c) {
|
|
||||||
case 'm':
|
|
||||||
strlcpy(st_cfg.mode, optarg, sizeof(st_cfg.mode));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'x':
|
|
||||||
if (!strcmp(optarg, "tx")) {
|
|
||||||
st_cfg.type = NSS_UDP_ST_TX;
|
|
||||||
} else if (!strcmp(optarg, "rx")) {
|
|
||||||
st_cfg.type = NSS_UDP_ST_RX;
|
|
||||||
} else {
|
|
||||||
printf("invalid option for type (tx/rx)\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 's':
|
|
||||||
strlcpy(st_opt.sip, optarg, sizeof(st_opt.sip));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'd':
|
|
||||||
strlcpy(st_opt.dip, optarg, sizeof(st_opt.dip));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'y':
|
|
||||||
st_opt.sport = atoi(optarg);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'z':
|
|
||||||
st_opt.dport = atoi(optarg);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'n':
|
|
||||||
strlcpy(st_param.net_dev, optarg, sizeof(st_param.net_dev));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'f':
|
|
||||||
st_opt.ip_version = atoi(optarg);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 't':
|
|
||||||
st_cfg.time = atoi(optarg);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'r':
|
|
||||||
st_param.rate = atoi(optarg);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'b':
|
|
||||||
st_param.buffer_sz = atoi(optarg);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'c':
|
|
||||||
st_param.dscp = atoi(optarg);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'h':
|
|
||||||
nss_udp_st_usage();
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
nss_udp_st_usage();
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* main()
|
|
||||||
* Invoke helper function based on command line arguments
|
|
||||||
*/
|
|
||||||
int main(int args, char **argv)
|
|
||||||
{
|
|
||||||
|
|
||||||
memset(&st_param, 0, sizeof(st_param));
|
|
||||||
memset(&st_opt, 0, sizeof(st_opt));
|
|
||||||
memset(&st_cfg, 0, sizeof(st_cfg));
|
|
||||||
memset(&st_stat, 0, sizeof(st_stat));
|
|
||||||
|
|
||||||
if (nss_udp_st_get_opt(args, argv)) {
|
|
||||||
printf("invalid command line options\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!strcmp(st_cfg.mode,"init")) {
|
|
||||||
system("insmod nss-udp-st.ko");
|
|
||||||
st_cfg.handle = open(NSS_UDP_ST_DEV, O_RDWR);
|
|
||||||
nss_udp_st_init();
|
|
||||||
close(st_cfg.handle);
|
|
||||||
} else if (!strcmp(st_cfg.mode,"final")) {
|
|
||||||
nss_udp_st_final();
|
|
||||||
} else if (!strcmp(st_cfg.mode,"create")) {
|
|
||||||
nss_udp_st_create();
|
|
||||||
} else if (!strcmp(st_cfg.mode,"list")) {
|
|
||||||
nss_udp_st_list();
|
|
||||||
} else if (!strcmp(st_cfg.mode,"clear")) {
|
|
||||||
nss_udp_st_clear();
|
|
||||||
} else if (!strcmp(st_cfg.mode,"start")) {
|
|
||||||
st_cfg.handle = open(NSS_UDP_ST_DEV, O_RDWR);
|
|
||||||
nss_udp_st_start();
|
|
||||||
close(st_cfg.handle);
|
|
||||||
} else if (!strcmp(st_cfg.mode,"stop")) {
|
|
||||||
st_cfg.handle = open(NSS_UDP_ST_DEV, O_RDWR);
|
|
||||||
nss_udp_st_stop();
|
|
||||||
close(st_cfg.handle);
|
|
||||||
} else if (!strcmp(st_cfg.mode,"stats")) {
|
|
||||||
st_cfg.handle = open(NSS_UDP_ST_DEV, O_RDWR);
|
|
||||||
nss_udp_st_stats();
|
|
||||||
close(st_cfg.handle);
|
|
||||||
} else {
|
|
||||||
printf("invalid command line options for mode\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@ -1,73 +0,0 @@
|
|||||||
/*
|
|
||||||
**************************************************************************
|
|
||||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. 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 __NSS_UDP_ST_H
|
|
||||||
#define __NSS_UDP_ST_H
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <stdatomic.h>
|
|
||||||
#include "nss_udp_st_drv.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* NSS UDP speedtest path parameters
|
|
||||||
*/
|
|
||||||
#define NSS_UDP_ST_LOG "/tmp/nss-udp-st"
|
|
||||||
#define NSS_UDP_ST_TX_STATS "/tmp/nss-udp-st/tx_stats"
|
|
||||||
#define NSS_UDP_ST_RX_STATS "/tmp/nss-udp-st/rx_stats"
|
|
||||||
#define NSS_UDP_ST_RULES "/tmp/nss-udp-st/rules"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_cfg
|
|
||||||
* NSS UDP speedtest common parameters
|
|
||||||
*/
|
|
||||||
struct nss_udp_st_cfg {
|
|
||||||
long time; /* time for speedtest */
|
|
||||||
int handle; /* handle for NSS_UDP_ST_DEV */
|
|
||||||
int type; /* type ( tx/rx ) */
|
|
||||||
char mode[NSS_UDP_ST_MODESZ]; /* mode for speedtest */
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_pkt_stats
|
|
||||||
* packet stats
|
|
||||||
*/
|
|
||||||
struct nss_udp_st_pkt_stats {
|
|
||||||
atomic_llong tx_packets; /* Number of packets transmitted */
|
|
||||||
atomic_llong tx_bytes; /* Number of bytes transmitted */
|
|
||||||
atomic_llong rx_packets; /* Number of packets received */
|
|
||||||
atomic_llong rx_bytes; /* Number of bytes received */
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nss_udp_st_stat
|
|
||||||
* stats for tx/rx test
|
|
||||||
*/
|
|
||||||
struct nss_udp_st_stat {
|
|
||||||
struct nss_udp_st_pkt_stats p_stats; /* Packet statistics */
|
|
||||||
atomic_llong timer_stats[NSS_UDP_ST_STATS_TIME_MAX]; /* Time statistics */
|
|
||||||
atomic_llong errors[NSS_UDP_ST_ERROR_MAX]; /* Error statistics */
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /*__NSS_UDP_ST_H*/
|
|
||||||
@ -39,7 +39,7 @@ instead or relying on a downstream api not present upstream.
|
|||||||
spin_lock_bh(&ct->lock);
|
spin_lock_bh(&ct->lock);
|
||||||
--- a/frontends/sfe/ecm_sfe_ipv4.c
|
--- a/frontends/sfe/ecm_sfe_ipv4.c
|
||||||
+++ b/frontends/sfe/ecm_sfe_ipv4.c
|
+++ b/frontends/sfe/ecm_sfe_ipv4.c
|
||||||
@@ -562,7 +562,8 @@ sync_conntrack:
|
@@ -563,7 +563,8 @@ sync_conntrack:
|
||||||
#else
|
#else
|
||||||
timeouts = nf_ct_timeout_lookup(ct);
|
timeouts = nf_ct_timeout_lookup(ct);
|
||||||
if (!timeouts) {
|
if (!timeouts) {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
--- a/ecm_interface.c
|
--- a/ecm_interface.c
|
||||||
+++ b/ecm_interface.c
|
+++ b/ecm_interface.c
|
||||||
@@ -3603,7 +3603,7 @@ identifier_update:
|
@@ -3616,7 +3616,7 @@ identifier_update:
|
||||||
if (skb && (skb->skb_iif == dev->ifindex)) {
|
if (skb && (skb->skb_iif == dev->ifindex)) {
|
||||||
struct pppol2tp_common_addr info;
|
struct pppol2tp_common_addr info;
|
||||||
|
|
||||||
@ -9,7 +9,7 @@
|
|||||||
DEBUG_TRACE("%px: Net device: %px is MULTILINK PPP - Unknown to the ECM\n", feci, dev);
|
DEBUG_TRACE("%px: Net device: %px is MULTILINK PPP - Unknown to the ECM\n", feci, dev);
|
||||||
type_info.unknown.os_specific_ident = dev_interface_num;
|
type_info.unknown.os_specific_ident = dev_interface_num;
|
||||||
|
|
||||||
@@ -3613,7 +3613,7 @@ identifier_update:
|
@@ -3626,7 +3626,7 @@ identifier_update:
|
||||||
ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, ae_interface_num, dev_mtu);
|
ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, ae_interface_num, dev_mtu);
|
||||||
return ii;
|
return ii;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
--- a/ecm_classifier_mscs.c
|
--- a/ecm_classifier_mscs.c
|
||||||
+++ b/ecm_classifier_mscs.c
|
+++ b/ecm_classifier_mscs.c
|
||||||
@@ -426,7 +426,6 @@ static void ecm_classifier_mscs_process(
|
@@ -428,7 +428,6 @@ static void ecm_classifier_mscs_process(
|
||||||
struct ecm_db_connection_instance *ci = NULL;
|
struct ecm_db_connection_instance *ci = NULL;
|
||||||
struct ecm_front_end_connection_instance *feci;
|
struct ecm_front_end_connection_instance *feci;
|
||||||
ecm_front_end_acceleration_mode_t accel_mode;
|
ecm_front_end_acceleration_mode_t accel_mode;
|
||||||
@ -8,7 +8,7 @@
|
|||||||
uint32_t became_relevant = 0;
|
uint32_t became_relevant = 0;
|
||||||
ecm_classifier_mscs_process_callback_t cb = NULL;
|
ecm_classifier_mscs_process_callback_t cb = NULL;
|
||||||
ecm_classifier_mscs_result_t result = 0;
|
ecm_classifier_mscs_result_t result = 0;
|
||||||
@@ -437,10 +436,10 @@ static void ecm_classifier_mscs_process(
|
@@ -439,10 +438,10 @@ static void ecm_classifier_mscs_process(
|
||||||
struct net_device *src_dev = NULL;
|
struct net_device *src_dev = NULL;
|
||||||
struct net_device *dest_dev = NULL;
|
struct net_device *dest_dev = NULL;
|
||||||
uint64_t slow_pkts;
|
uint64_t slow_pkts;
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
--- a/ecm_interface.c
|
--- a/ecm_interface.c
|
||||||
+++ b/ecm_interface.c
|
+++ b/ecm_interface.c
|
||||||
@@ -8269,24 +8269,6 @@ static struct ctl_table ecm_interface_ta
|
@@ -8303,24 +8303,6 @@ static struct ctl_table ecm_interface_ta
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -25,7 +25,7 @@
|
|||||||
#ifdef ECM_INTERFACE_IPSEC_GLUE_LAYER_SUPPORT_ENABLE
|
#ifdef ECM_INTERFACE_IPSEC_GLUE_LAYER_SUPPORT_ENABLE
|
||||||
/*
|
/*
|
||||||
* ecm_interface_ipsec_register_callbacks()
|
* ecm_interface_ipsec_register_callbacks()
|
||||||
@@ -8783,7 +8765,7 @@ int ecm_interface_init(void)
|
@@ -8817,7 +8799,7 @@ int ecm_interface_init(void)
|
||||||
/*
|
/*
|
||||||
* Register sysctl table.
|
* Register sysctl table.
|
||||||
*/
|
*/
|
||||||
@ -36,7 +36,7 @@
|
|||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
--- a/frontends/ecm_front_end_common.c
|
--- a/frontends/ecm_front_end_common.c
|
||||||
+++ b/frontends/ecm_front_end_common.c
|
+++ b/frontends/ecm_front_end_common.c
|
||||||
@@ -1164,34 +1164,16 @@ static struct ctl_table ecm_front_end_sy
|
@@ -1180,34 +1180,16 @@ static struct ctl_table ecm_front_end_sy
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -73,7 +73,7 @@
|
|||||||
#ifdef ECM_FRONT_END_SFE_ENABLE
|
#ifdef ECM_FRONT_END_SFE_ENABLE
|
||||||
if (ecm_front_end_ctl_tbl_hdr) {
|
if (ecm_front_end_ctl_tbl_hdr) {
|
||||||
ecm_sfe_sysctl_tbl_init();
|
ecm_sfe_sysctl_tbl_init();
|
||||||
@@ -1203,7 +1185,7 @@ void ecm_front_end_common_sysctl_registe
|
@@ -1219,7 +1201,7 @@ void ecm_front_end_common_sysctl_registe
|
||||||
* ecm_front_end_common_sysctl_unregister()
|
* ecm_front_end_common_sysctl_unregister()
|
||||||
* Function to unregister sysctl node during front end exit
|
* Function to unregister sysctl node during front end exit
|
||||||
*/
|
*/
|
||||||
@ -82,7 +82,7 @@
|
|||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Unregister sysctl table.
|
* Unregister sysctl table.
|
||||||
@@ -1702,7 +1684,11 @@ bool ecm_front_end_common_intf_ingress_q
|
@@ -1718,7 +1700,11 @@ bool ecm_front_end_common_intf_ingress_q
|
||||||
{
|
{
|
||||||
#if defined(CONFIG_NET_CLS_ACT)
|
#if defined(CONFIG_NET_CLS_ACT)
|
||||||
struct net_device *dev;
|
struct net_device *dev;
|
||||||
@ -95,7 +95,7 @@
|
|||||||
|
|
||||||
dev = dev_get_by_index(&init_net, interface_num);
|
dev = dev_get_by_index(&init_net, interface_num);
|
||||||
if (!dev) {
|
if (!dev) {
|
||||||
@@ -1711,8 +1697,13 @@ bool ecm_front_end_common_intf_ingress_q
|
@@ -1727,8 +1713,13 @@ bool ecm_front_end_common_intf_ingress_q
|
||||||
}
|
}
|
||||||
|
|
||||||
BUG_ON(!rcu_read_lock_bh_held());
|
BUG_ON(!rcu_read_lock_bh_held());
|
||||||
@ -111,7 +111,7 @@
|
|||||||
DEBUG_INFO("Ingress Qdisc is present for device[%s]\n", dev->name);
|
DEBUG_INFO("Ingress Qdisc is present for device[%s]\n", dev->name);
|
||||||
dev_put(dev);
|
dev_put(dev);
|
||||||
return true;
|
return true;
|
||||||
@@ -1735,7 +1726,11 @@ bool ecm_front_end_common_intf_qdisc_che
|
@@ -1751,7 +1742,11 @@ bool ecm_front_end_common_intf_qdisc_che
|
||||||
struct Qdisc *q;
|
struct Qdisc *q;
|
||||||
int i;
|
int i;
|
||||||
#if defined(CONFIG_NET_CLS_ACT) && defined(CONFIG_NET_EGRESS)
|
#if defined(CONFIG_NET_CLS_ACT) && defined(CONFIG_NET_EGRESS)
|
||||||
@ -124,7 +124,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
*is_ppeq = false;
|
*is_ppeq = false;
|
||||||
@@ -1766,8 +1761,12 @@ bool ecm_front_end_common_intf_qdisc_che
|
@@ -1782,8 +1777,12 @@ bool ecm_front_end_common_intf_qdisc_che
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CONFIG_NET_CLS_ACT) && defined(CONFIG_NET_EGRESS)
|
#if defined(CONFIG_NET_CLS_ACT) && defined(CONFIG_NET_EGRESS)
|
||||||
|
|||||||
@ -0,0 +1,14 @@
|
|||||||
|
--- a/ecm_interface.c
|
||||||
|
+++ b/ecm_interface.c
|
||||||
|
@@ -4033,7 +4033,11 @@ static uint32_t ecm_interface_multicast_
|
||||||
|
* For MLO bond netdevice, destination for multicast is bond netdevice itself
|
||||||
|
* Therefore, slave lookup is not needed.
|
||||||
|
*/
|
||||||
|
+#ifdef ECM_FRONT_END_SFE_ENABLE
|
||||||
|
if (ecm_front_end_is_lag_master(dest_dev) && !bond_is_mlo_device(dest_dev)) {
|
||||||
|
+#else
|
||||||
|
+ if (ecm_front_end_is_lag_master(dest_dev)) {
|
||||||
|
+#endif
|
||||||
|
/*
|
||||||
|
* Link aggregation
|
||||||
|
* Figure out which slave device of the link aggregation will be used to reach the destination.
|
||||||
Loading…
Reference in New Issue
Block a user