nss-udp-st: Remove incompatible UDP speedtest module/tool

It is only compatible with IPQ95XX/53XX. Remove it for now to avoid any
user confusion.
This commit is contained in:
Qosmio 2024-03-24 21:53:59 -04:00
parent 1625586a6c
commit 8ffa394fb7
17 changed files with 0 additions and 2425 deletions

View File

@ -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)))

View File

@ -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"

View File

@ -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");

View File

@ -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

View File

@ -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; /* kernels 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*/

View File

@ -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");

View File

@ -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;
}

View File

@ -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*/

View File

@ -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_*/

View File

@ -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;
}

View File

@ -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*/

View File

@ -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;
}

View File

@ -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*/

View File

@ -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))

View File

@ -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

View File

@ -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;
}

View File

@ -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*/