mirror of
https://github.com/breeze303/nss-packages.git
synced 2025-12-16 16:57:29 +00:00
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:
parent
1625586a6c
commit
8ffa394fb7
@ -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*/
|
||||
Loading…
Reference in New Issue
Block a user