From 487f8d1df0d407f1c04385b5fb1b5e1fa1913f19 Mon Sep 17 00:00:00 2001 From: bitthief Date: Fri, 3 Feb 2023 05:52:54 +0200 Subject: [PATCH] qca: add nss-userspace-oss --- qca/nss-userspace-oss/libnl-nss/Makefile | 45 ++ qca/nss-userspace-oss/libnl-nss/src/Makefile | 35 + .../libnl-nss/src/include/nss_nlbase.h | 71 ++ .../libnl-nss/src/include/nss_nldtls_api.h | 119 +++ .../libnl-nss/src/include/nss_nlipv4_api.h | 253 +++++++ .../libnl-nss/src/include/nss_nlipv6_api.h | 253 +++++++ .../libnl-nss/src/include/nss_nlist_api.h | 220 ++++++ .../libnl-nss/src/include/nss_nlmcast_api.h | 102 +++ .../libnl-nss/src/include/nss_nlsock_api.h | 197 +++++ .../libnl-nss/src/nss_nldtls_api.c | 138 ++++ .../libnl-nss/src/nss_nlipv4_api.c | 176 +++++ .../libnl-nss/src/nss_nlipv6_api.c | 176 +++++ .../libnl-nss/src/nss_nlmcast_api.c | 146 ++++ .../libnl-nss/src/nss_nlsock.c | 498 ++++++++++++ qca/nss-userspace-oss/nssinfo/Makefile | 39 + qca/nss-userspace-oss/nssinfo/src/Makefile | 35 + .../nssinfo/src/src/nssinfo.c | 714 ++++++++++++++++++ .../nssinfo/src/src/nssinfo.h | 233 ++++++ .../src/src/nssinfo_dynamic_interface.c | 72 ++ .../src/src/nssinfo_dynamic_interface.h | 28 + .../nssinfo/src/src/nssinfo_ethrx.c | 215 ++++++ .../nssinfo/src/src/nssinfo_ethrx.h | 28 + .../nssinfo/src/src/nssinfo_ipv4.c | 215 ++++++ .../nssinfo/src/src/nssinfo_ipv4.h | 30 + .../nssinfo/src/src/nssinfo_ipv6.c | 212 ++++++ .../nssinfo/src/src/nssinfo_ipv6.h | 30 + .../nssinfo/src/src/nssinfo_lso_rx.c | 195 +++++ .../nssinfo/src/src/nssinfo_lso_rx.h | 28 + .../nssinfo/src/src/nssinfo_main.c | 191 +++++ .../nssinfo/src/src/nssinfo_n2h.c | 209 +++++ .../nssinfo/src/src/nssinfo_n2h.h | 28 + 31 files changed, 4931 insertions(+) create mode 100644 qca/nss-userspace-oss/libnl-nss/Makefile create mode 100644 qca/nss-userspace-oss/libnl-nss/src/Makefile create mode 100644 qca/nss-userspace-oss/libnl-nss/src/include/nss_nlbase.h create mode 100644 qca/nss-userspace-oss/libnl-nss/src/include/nss_nldtls_api.h create mode 100644 qca/nss-userspace-oss/libnl-nss/src/include/nss_nlipv4_api.h create mode 100644 qca/nss-userspace-oss/libnl-nss/src/include/nss_nlipv6_api.h create mode 100644 qca/nss-userspace-oss/libnl-nss/src/include/nss_nlist_api.h create mode 100644 qca/nss-userspace-oss/libnl-nss/src/include/nss_nlmcast_api.h create mode 100644 qca/nss-userspace-oss/libnl-nss/src/include/nss_nlsock_api.h create mode 100644 qca/nss-userspace-oss/libnl-nss/src/nss_nldtls_api.c create mode 100644 qca/nss-userspace-oss/libnl-nss/src/nss_nlipv4_api.c create mode 100644 qca/nss-userspace-oss/libnl-nss/src/nss_nlipv6_api.c create mode 100644 qca/nss-userspace-oss/libnl-nss/src/nss_nlmcast_api.c create mode 100644 qca/nss-userspace-oss/libnl-nss/src/nss_nlsock.c create mode 100644 qca/nss-userspace-oss/nssinfo/Makefile create mode 100644 qca/nss-userspace-oss/nssinfo/src/Makefile create mode 100644 qca/nss-userspace-oss/nssinfo/src/src/nssinfo.c create mode 100644 qca/nss-userspace-oss/nssinfo/src/src/nssinfo.h create mode 100644 qca/nss-userspace-oss/nssinfo/src/src/nssinfo_dynamic_interface.c create mode 100644 qca/nss-userspace-oss/nssinfo/src/src/nssinfo_dynamic_interface.h create mode 100644 qca/nss-userspace-oss/nssinfo/src/src/nssinfo_ethrx.c create mode 100644 qca/nss-userspace-oss/nssinfo/src/src/nssinfo_ethrx.h create mode 100644 qca/nss-userspace-oss/nssinfo/src/src/nssinfo_ipv4.c create mode 100644 qca/nss-userspace-oss/nssinfo/src/src/nssinfo_ipv4.h create mode 100644 qca/nss-userspace-oss/nssinfo/src/src/nssinfo_ipv6.c create mode 100644 qca/nss-userspace-oss/nssinfo/src/src/nssinfo_ipv6.h create mode 100644 qca/nss-userspace-oss/nssinfo/src/src/nssinfo_lso_rx.c create mode 100644 qca/nss-userspace-oss/nssinfo/src/src/nssinfo_lso_rx.h create mode 100644 qca/nss-userspace-oss/nssinfo/src/src/nssinfo_main.c create mode 100644 qca/nss-userspace-oss/nssinfo/src/src/nssinfo_n2h.c create mode 100644 qca/nss-userspace-oss/nssinfo/src/src/nssinfo_n2h.h diff --git a/qca/nss-userspace-oss/libnl-nss/Makefile b/qca/nss-userspace-oss/libnl-nss/Makefile new file mode 100644 index 0000000..321a99f --- /dev/null +++ b/qca/nss-userspace-oss/libnl-nss/Makefile @@ -0,0 +1,45 @@ +include $(TOPDIR)/rules.mk +include $(INCLUDE_DIR)/kernel.mk + +PKG_NAME:=libnl-nss +PKG_RELEASE:=1 + +include $(INCLUDE_DIR)/package.mk + +define Package/libnl-nss + SECTION:=Libs + CATEGORY:=Libraries + TITLE:=Framework to communicate between userspace applications and the kernel. + DEPENDS:=+libpthread +libnl +kmod-qca-nss-drv-netlink +endef + +define Package/libnl-nss/description + A framework in the userspace that establishes communication between userspace applications and the kernel. +endef + +TOOL_CFLAGS:= -I$(STAGING_DIR)/usr/include/qca-nss-clients \ + -I$(STAGING_DIR)/usr/include/qca-nss-drv \ + -I$(STAGING_DIR)/usr/include/libnl3 + +TOOL_LDFLAGS:= -L$(STAGING_DIR)/lib + +define Build/Compile + $(MAKE) -C $(PKG_BUILD_DIR) \ + CC="$(TARGET_CC)" \ + AR="$(TARGET_AR) " \ + CFLAGS="$(TOOL_CFLAGS)" \ + LD_LIBRARY_PATH="$(TOOL_LDFLAGS)" +endef + +define Build/InstallDev + $(INSTALL_DIR) $(STAGING_DIR)/usr/include/libnl-nss + $(CP) $(PKG_BUILD_DIR)/obj/libnl-nss.so $(STAGING_DIR)/usr/lib + $(CP) $(PKG_BUILD_DIR)/include/* $(STAGING_DIR)/usr/include/libnl-nss +endef + +define Package/libnl-nss/install + $(INSTALL_DIR) $(1)/lib + $(INSTALL_DATA) $(PKG_BUILD_DIR)/obj/libnl-nss.so $(1)/lib +endef + +$(eval $(call BuildPackage,libnl-nss)) diff --git a/qca/nss-userspace-oss/libnl-nss/src/Makefile b/qca/nss-userspace-oss/libnl-nss/src/Makefile new file mode 100644 index 0000000..ad9e3f9 --- /dev/null +++ b/qca/nss-userspace-oss/libnl-nss/src/Makefile @@ -0,0 +1,35 @@ +MKDIR = @mkdir -p $(@D) +SRCPATH = ./ +OBJPATH = obj + +BINARY = $(OBJPATH)/libnl-nss.so +SOURCES = $(wildcard $(SRCPATH)/*.c) +OBJECTS = $(SOURCES:$(SRCPATH)/%.c=$(OBJPATH)/%.o) +HEADERS = $(wildcard $(SRCPATH)/*.h) + +INCLUDE += -I./include +LDFLAGS = -lnl-3 -lnl-genl-3 +EXTRA_CFLAGS = -Wall -Werror -fPIC -Wl,-z,relro -Wl,-z,now +EXTRA_LDFLAGS = -pie -Wl,-z,relro -Wl,-z,now + +all: release + +release: $(BINARY) + +$(OBJPATH)/%.o: $(SRCPATH)/%.c $(HEADERS) + $(MKDIR) + @echo [CC] $@ + @$(CC) -c $(CFLAGS) $(INCLUDE) $(EXTRA_CFLAGS) -o $@ $< + +$(BINARY): $(OBJECTS) + @echo $(BINARY) + @echo [LD] $@ + @$(CC) -shared -o $@ $^ $(LDFLAGS) $(LDLIBS) + +clean: + @echo [Clean] + @rm -f $(OBJECTS) + @rm -f $(BINARY) + @rm -rf $(OBJPATH) + +.PHONY: clean diff --git a/qca/nss-userspace-oss/libnl-nss/src/include/nss_nlbase.h b/qca/nss-userspace-oss/libnl-nss/src/include/nss_nlbase.h new file mode 100644 index 0000000..ffc2222 --- /dev/null +++ b/qca/nss-userspace-oss/libnl-nss/src/include/nss_nlbase.h @@ -0,0 +1,71 @@ +/* + ************************************************************************** + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +#ifndef __NSS_NLBASE_H__ +#define __NSS_NLBASE_H__ + +/* + * TODO: Remove inter-dependencies between the header files. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Generic Netlink header */ +#include +#include +#include + +#if !defined (likely) || !defined (unlikely) +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) +#endif + +/* NSS headers */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif /* __NSS_NLBASE_H__ */ diff --git a/qca/nss-userspace-oss/libnl-nss/src/include/nss_nldtls_api.h b/qca/nss-userspace-oss/libnl-nss/src/include/nss_nldtls_api.h new file mode 100644 index 0000000..608eea5 --- /dev/null +++ b/qca/nss-userspace-oss/libnl-nss/src/include/nss_nldtls_api.h @@ -0,0 +1,119 @@ +/* + ************************************************************************** + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +#ifndef __NSS_NLDTLS_API_H__ +#define __NSS_NLDTLS_API_H__ + +/** @addtogroup chapter_nldtls + This chapter describes Data Transport Layer Security (DTLS) APIs in the user space. + These APIs are wrapper functions for DTLS family specific operations. + */ + +/** @addtogroup nss_nldtls_datatypes @{ */ + +/** + * Response callback for DTLS. + * + * @param[in] user_ctx User context (provided at socket open). + * @param[in] rule DTLS rule. + * @param[in] resp_ctx User data per callback. + * + * @return + * None. + */ +typedef void (*nss_nldtls_resp_t)(void *user_ctx, struct nss_nldtls_rule *rule, void *resp_ctx); + +/** + * Event callback for DTLS. + * + * @param[in] user_ctx User context (provided at socket open). + * @param[in] rule DTLS rule. + * + * @return + * None. + */ +typedef void (*nss_nldtls_event_t)(void *user_ctx, struct nss_nldtls_rule *rule); + +/** + * NSS NL DTLS response. + */ +struct nss_nldtls_resp { + void *data; /**< Response context. */ + nss_nldtls_resp_t cb; /**< Response callback. */ +}; + +/** + * NSS NL DTLS context. + */ +struct nss_nldtls_ctx { + struct nss_nlsock_ctx sock; /**< NSS socket context. */ + nss_nldtls_event_t event; /**< NSS event callback function. */ +}; + +/** @} *//* end_addtogroup nss_nldtls_datatypes */ +/** @addtogroup nss_nldtls_functions @{ */ + +/** + * Opens NSS NL DTLS socket. + * + * @param[in] ctx NSS NL socket context allocated by the caller. + * @param[in] user_ctx User context stored per socket. + * @param[in] event_cb Event callback handler. + * + * @return + * Status of the open call. + */ +int nss_nldtls_sock_open(struct nss_nldtls_ctx *ctx, void *user_ctx, nss_nldtls_event_t event_cb); + +/** + * Closes NSS NL DTLS socket. + * + * @param[in] ctx NSS NL context. + * + * @return + * None. + */ +void nss_nldtls_sock_close(struct nss_nldtls_ctx *ctx); + +/** + * Send a DTLS rule synchronously to NSS NL NETLINK. + * + * @param[in] ctx NSS DTLS NL context. + * @param[in] rule DTLS rule. + * @param[in] cb Response callback handler. + * @param[in] data Data received from sender. + * + * @return + * Send status: + * - 0 -- Success. + * - Negative version error (-ve) -- Failure. + */ +int nss_nldtls_sock_send(struct nss_nldtls_ctx *ctx, struct nss_nldtls_rule *rule, nss_nldtls_resp_t cb, void *data); + +/** + * Initializes create rule message. + * + * @param[in] rule DTLS rule. + * @param[in] type Type of command. + * + * @return + * None. + */ +void nss_nldtls_init_rule(struct nss_nldtls_rule *rule, enum nss_nldtls_cmd_type type); + +/** @} *//* end_addtogroup nss_nldtls_functions */ + +#endif /* __NSS_NLDTLS_API_H__ */ diff --git a/qca/nss-userspace-oss/libnl-nss/src/include/nss_nlipv4_api.h b/qca/nss-userspace-oss/libnl-nss/src/include/nss_nlipv4_api.h new file mode 100644 index 0000000..edc55e9 --- /dev/null +++ b/qca/nss-userspace-oss/libnl-nss/src/include/nss_nlipv4_api.h @@ -0,0 +1,253 @@ +/* + ************************************************************************** + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +#ifndef __NSS_NLIPV4_API_H__ +#define __NSS_NLIPV4_API_H__ + +#define NSS_IPV4_RULE_CREATE_IDENTIFIER_VALID 0x1000 /**< Identifier is valid. */ + +/** @addtogroup chapter_nlipv4 + This chapter describes IPv4 APIs in the user space. + These APIs are wrapper functions for IPv4 family specific operations. +*/ + +/** @addtogroup nss_nlipv4_datatypes @{ */ + +/** + * Response callback for IPv4. + * + * @param[in] user_ctx User context (provided at socket open). + * @param[in] rule IPv4 rule. + * @param[in] resp_ctx User data per callback. + * + * @return + * None. + */ +typedef void (*nss_nlipv4_resp_t)(void *user_ctx, struct nss_nlipv4_rule *rule, void *resp_ctx); + +/** + * Event callback for IPv4. + * + * @param[in] user_ctx User context (provided at socket open). + * @param[in] rule IPv4 rule. + * + * @return + * None. + */ +typedef void (*nss_nlipv4_event_t)(void *user_ctx, struct nss_nlipv4_rule *rule); + +/** + * NSS NL IPv4 response. + */ +struct nss_nlipv4_resp { + void *data; /**< Response context. */ + nss_nlipv4_resp_t cb; /**< Response callback. */ +}; + +/** + * NSS NL IPv4 context. + */ +struct nss_nlipv4_ctx { + struct nss_nlsock_ctx sock; /**< NSS socket context. */ + nss_nlipv4_event_t event; /**< NSS event callback function. */ +}; + +/** @} *//* end_addtogroup nss_nlipv4_datatypes */ +/** @addtogroup nss_nlipv4_functions @{ */ + +/** + * Opens NSS NL IPv4 socket. + * + * @param[in] ctx NSS NL socket context allocated by the caller. + * @param[in] user_ctx User context stored per socket. + * @param[in] event_cb Event callback handler. + * + * @return + * Status of the open call. + */ +int nss_nlipv4_sock_open(struct nss_nlipv4_ctx *ctx, void *user_ctx, nss_nlipv4_event_t event_cb); + +/** + * Closes NSS NL IPv4 socket. + * + * @param[in] ctx NSS NL context. + * + * @return + * None. + */ +void nss_nlipv4_sock_close(struct nss_nlipv4_ctx *ctx); + +/** + * Sends an IPv4 rule synchronously to NSS NETLINK. + * + * @param[in] ctx NSS NL IPv4 context. + * @param[in] rule IPv4 rule. + * @param[in] cb Response callback handler. + * @param[in] data Response data per callback. + * + * @return + * Send status: + * - 0 -- Success. + * - Negative version error (-ve) -- Failure. + */ +int nss_nlipv4_sock_send(struct nss_nlipv4_ctx *ctx, struct nss_nlipv4_rule *rule, nss_nlipv4_resp_t cb, void *data); + +/** + * Initializes IPv4 rule message. + * + * @param[in] rule IPv4 rule. + * @param[in] type Command type. + * + * @return + * None. + */ +void nss_nlipv4_init_rule(struct nss_nlipv4_rule *rule, enum nss_ipv4_message_types type); + +/** + * Initializes connection rule for create message. + * + * @param[in] create Creates message. + * + * @return + * None. + */ +static inline void nss_nlipv4_init_conn_rule(struct nss_ipv4_rule_create_msg *create) +{ + create->valid_flags |= NSS_IPV4_RULE_CREATE_CONN_VALID; +} + +/** + * Enables route flow. + * + * @param[in] create Creates message. + * + * @return + * None. + */ +static inline void nss_nlipv4_init_route_flow_rule(struct nss_ipv4_rule_create_msg *create) +{ + create->rule_flags |= NSS_IPV4_RULE_CREATE_FLAG_ROUTED; +} + +/** + * Enables bridge flow. + * + * @param[in] create Creates message. + * + * @return + * None. + */ +static inline void nss_nlipv4_init_bridge_flow_rule(struct nss_ipv4_rule_create_msg *create) +{ + create->rule_flags |= NSS_IPV4_RULE_CREATE_FLAG_BRIDGE_FLOW; +} + +/** + * Initializes TCP protocol rule for create message. + * + * @param[in] create Creates message. + * + * @return + * None. + */ +static inline void nss_nlipv4_init_tcp_rule(struct nss_ipv4_rule_create_msg *create) +{ + create->valid_flags |= NSS_IPV4_RULE_CREATE_TCP_VALID; +} + +/** + * Initializes PPPoE rule for create message. + * + * @param[in] create Creates message. + * + * @return + * None. + */ +static inline void nss_nlipv4_init_pppoe_rule(struct nss_ipv4_rule_create_msg *create) +{ + create->valid_flags |= NSS_IPV4_RULE_CREATE_PPPOE_VALID; +} + +/** + * Initializes QoS rule for create message. + * + * @param[in] create Creates message. + * + * @return + * None. + */ +static inline void nss_nlipv4_init_qos_rule(struct nss_ipv4_rule_create_msg *create) +{ + create->valid_flags |= NSS_IPV4_RULE_CREATE_QOS_VALID; +} + +/** + * Initializes DSCP rule for create message. + * + * @param[in] create Creates message. + * + * @return + * None. + */ +static inline void nss_nlipv4_init_dscp_rule(struct nss_ipv4_rule_create_msg *create) +{ + create->valid_flags |= NSS_IPV4_RULE_CREATE_DSCP_MARKING_VALID; +} + +/** + * Initializes VLAN rule for create message. + * + * @param[in] create Creates message. + * + * @return + * None. + */ +static inline void nss_nlipv4_init_vlan_rule(struct nss_ipv4_rule_create_msg *create) +{ + struct nss_ipv4_vlan_rule *primary; + struct nss_ipv4_vlan_rule *secondary; + + primary = &create->vlan_primary_rule; + secondary = &create->vlan_secondary_rule; + + create->valid_flags |= NSS_IPV4_RULE_CREATE_VLAN_VALID; + + /* + * set the tags to default values + */ + primary->ingress_vlan_tag = NSS_NLIPV4_VLAN_ID_NOT_CONFIGURED; + primary->egress_vlan_tag = NSS_NLIPV4_VLAN_ID_NOT_CONFIGURED; + + secondary->ingress_vlan_tag = NSS_NLIPV4_VLAN_ID_NOT_CONFIGURED; + secondary->egress_vlan_tag = NSS_NLIPV4_VLAN_ID_NOT_CONFIGURED; +} + +/** + * Initializes Identifier rule for create message. + * + * @param[in] create Creates message. + * + * @return + * None. + */ +static inline void nss_nlipv4_init_identifier_rule(struct nss_ipv4_rule_create_msg *create) +{ + create->valid_flags |= NSS_IPV4_RULE_CREATE_IDENTIFIER_VALID; +} + +/** @} *//* end_addtogroup nss_nlipv4_functions */ + +#endif /* __NSS_NLIPV4_API_H__ */ diff --git a/qca/nss-userspace-oss/libnl-nss/src/include/nss_nlipv6_api.h b/qca/nss-userspace-oss/libnl-nss/src/include/nss_nlipv6_api.h new file mode 100644 index 0000000..a503421 --- /dev/null +++ b/qca/nss-userspace-oss/libnl-nss/src/include/nss_nlipv6_api.h @@ -0,0 +1,253 @@ +/* + ************************************************************************** + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +#ifndef __NSS_NLIPV6_API_H__ +#define __NSS_NLIPV6_API_H__ + +#define NSS_IPV6_RULE_CREATE_IDENTIFIER_VALID 0x1000 /**< Identifier is valid. */ + +/** @addtogroup chapter_nlipv6 + This chapter describes IPv6 APIs in the user space. + These APIs are wrapper functions for IPv6 family specific operations. +*/ + +/** @addtogroup nss_nlipv6_datatypes @{ */ + +/** + * Response callback for IPv6. + * + * @param[in] user_ctx User context (provided at socket open). + * @param[in] rule IPv6 rule. + * @param[in] resp_ctx user data per callback. + * + * @return + * None. + */ +typedef void (*nss_nlipv6_resp_t)(void *user_ctx, struct nss_nlipv6_rule *rule, void *resp_ctx); + +/** + * Event callback for IPv6. + * + * @param[in] user_ctx User context (provided at socket open). + * @param[in] rule IPv6 Rule. + * + * @return + * None. + */ +typedef void (*nss_nlipv6_event_t)(void *user_ctx, struct nss_nlipv6_rule *rule); + +/** + * NSS NL IPv6 response. + */ +struct nss_nlipv6_resp { + void *data; /**< Response context. */ + nss_nlipv6_resp_t cb; /**< Response callback. */ +}; + +/** + * NSS NL IPv6 context. + */ +struct nss_nlipv6_ctx { + struct nss_nlsock_ctx sock; /**< NSS socket context. */ + nss_nlipv6_event_t event; /**< NSS event callback function. */ +}; + +/** @} *//* end_addtogroup nss_nlipv6_datatypes */ +/** @addtogroup nss_nlipv6_functions @{ */ + +/** + * Opens NSS NL IPv6 socket. + * + * @param[in] ctx NSS NL socket context allocated by the caller. + * @param[in] user_ctx User context stored per socket. + * @param[in] event_cb Event callback handler. + * + * @return + * Status of the open call. + */ +int nss_nlipv6_sock_open(struct nss_nlipv6_ctx *ctx, void *user_ctx, nss_nlipv6_event_t event_cb); + +/** + * Closes NSS NL IPv6 socket. + * + * @param[in] ctx NSS NL context. + * + * @return + * None. + */ +void nss_nlipv6_sock_close(struct nss_nlipv6_ctx *ctx); + +/** + * Sends an IPv6 rule synchronously to NSS NETLINK. + * + * @param[in] ctx NSS IPv6 NL context. + * @param[in] rule IPv6 rule. + * @param[in] cb Response callback handler. + * @param[in] data Response data per callback. + * + * @return + * Send status: + * - 0 -- Success. + * - Negative version error (-ve) -- Failure. + */ +int nss_nlipv6_sock_send(struct nss_nlipv6_ctx *ctx, struct nss_nlipv6_rule *rule, nss_nlipv6_resp_t cb, void *data); + +/** + * Initializes rule message. + * + * @param[in] rule IPv6 rule. + * @param[in] type Command type. + * + * @return + * None. + */ +void nss_nlipv6_init_rule(struct nss_nlipv6_rule *rule, enum nss_ipv6_message_types type); + +/** + * Initializes connection rule for create message. + * + * @param[in] create Creates message. + * + * @return + * None. + */ +static inline void nss_nlipv6_init_conn_rule(struct nss_ipv6_rule_create_msg *create) +{ + create->valid_flags |= NSS_IPV6_RULE_CREATE_CONN_VALID; +} + +/** + * Enables route flow. + * + * @param[in] create Creates message. + * + * @return + * None. + */ +static inline void nss_nlipv6_init_route_flow_rule(struct nss_ipv6_rule_create_msg *create) +{ + create->rule_flags |= NSS_IPV6_RULE_CREATE_FLAG_ROUTED; +} + +/** + * Enables bridge flow. + * + * @param[in] create create message. + * + * @return + * None. + */ +static inline void nss_nlipv6_init_bridge_flow_rule(struct nss_ipv6_rule_create_msg *create) +{ + create->rule_flags |= NSS_IPV6_RULE_CREATE_FLAG_BRIDGE_FLOW; +} + +/** + * Initializes TCP protocol rule for create message. + * + * @param[in] create Creates message. + * + * @return + * None. + */ +static inline void nss_nlipv6_init_tcp_rule(struct nss_ipv6_rule_create_msg *create) +{ + create->valid_flags |= NSS_IPV6_RULE_CREATE_TCP_VALID; +} + +/** + * Initializes PPPoE rule for create message. + * + * @param[in] create Creates message. + * + * @return + * None. + */ +static inline void nss_nlipv6_init_pppoe_rule(struct nss_ipv6_rule_create_msg *create) +{ + create->valid_flags |= NSS_IPV6_RULE_CREATE_PPPOE_VALID; +} + +/** + * Initializes QoS rule for create message. + * + * @param[in] create Creates message. + * + * @return + * None. + */ +static inline void nss_nlipv6_init_qos_rule(struct nss_ipv6_rule_create_msg *create) +{ + create->valid_flags |= NSS_IPV6_RULE_CREATE_QOS_VALID; +} + +/** + * Initializes DSCP rule for create message. + * + * @param[in] create Creates message. + * + * @return + * None. + */ +static inline void nss_nlipv6_init_dscp_rule(struct nss_ipv6_rule_create_msg *create) +{ + create->valid_flags |= NSS_IPV6_RULE_CREATE_DSCP_MARKING_VALID; +} + +/** + * Initializes VLAN rule for create message. + * + * @param[in] create Creates message. + * + * @return + * None. + */ +static inline void nss_nlipv6_init_vlan_rule(struct nss_ipv6_rule_create_msg *create) +{ + struct nss_ipv6_vlan_rule *primary; + struct nss_ipv6_vlan_rule *secondary; + + primary = &create->vlan_primary_rule; + secondary = &create->vlan_secondary_rule; + + create->valid_flags |= NSS_IPV6_RULE_CREATE_VLAN_VALID; + + /* + * set the tags to default values + */ + primary->ingress_vlan_tag = NSS_NLIPV6_VLAN_ID_NOT_CONFIGURED; + primary->egress_vlan_tag = NSS_NLIPV6_VLAN_ID_NOT_CONFIGURED; + + secondary->ingress_vlan_tag = NSS_NLIPV6_VLAN_ID_NOT_CONFIGURED; + secondary->egress_vlan_tag = NSS_NLIPV6_VLAN_ID_NOT_CONFIGURED; +} + +/** + * Initializes Identifier rule for create message. + * + * @param[in] create Creates message. + * + * @return + * None. + */ +static inline void nss_nlipv6_init_identifier_rule(struct nss_ipv6_rule_create_msg *create) +{ + create->valid_flags |= NSS_IPV6_RULE_CREATE_IDENTIFIER_VALID; +} + +/** @} *//* end_addtogroup nss_nlipv6_functions */ + +#endif /* __NSS_NLIPV6_API_H__ */ diff --git a/qca/nss-userspace-oss/libnl-nss/src/include/nss_nlist_api.h b/qca/nss-userspace-oss/libnl-nss/src/include/nss_nlist_api.h new file mode 100644 index 0000000..6b8bb05 --- /dev/null +++ b/qca/nss-userspace-oss/libnl-nss/src/include/nss_nlist_api.h @@ -0,0 +1,220 @@ +/* + ************************************************************************** + * Copyright (c) 2019,2021 The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +#ifndef __NSS_NLIST_H__ +#define __NSS_NLIST_H__ + +/** @addtogroup chapter_nlist + This chapter describes Netlink list APIs in the user space. +*/ + +/** @ingroup nss_nlist_datatypes + * List node + */ +struct nss_nlist { + struct nss_nlist *next; /**< Next node. */ + struct nss_nlist *prev; /**< Previous node. */ +}; + +/** @addtogroup nss_nlist_functions @{ */ + +/** + * Initializes the list node. + * + * @param[in] node List node. + * + * @return + * None. + */ +static inline void nss_nlist_init(struct nss_nlist *node) +{ + node->next = node->prev = node; +} + +/** + * Gets the previous node. + * + * @param[in] node Previous node. + * + * @return + * Previous node or head node. + */ +static inline struct nss_nlist *nss_nlist_prev(struct nss_nlist *node) +{ + return node->prev; +} + +/** + * Gets the next node. + * + * @param[in] node Next node. + * + * @return + * Next node or head node. + */ +static inline struct nss_nlist *nss_nlist_next(struct nss_nlist *node) +{ + return node->next; +} + +/** + * Initializes the head node. + * + * @param[in] head Head of list. + * + * @return + * None. + */ +static inline void nss_nlist_init_head(struct nss_nlist *head) +{ + nss_nlist_init(head); +} + +/** + * Returns first node in the list. + * + * @param[in] head List head. + * + * @return + * First node. + */ +static inline struct nss_nlist *nss_nlist_first(struct nss_nlist *head) +{ + return nss_nlist_next(head); +} + +/** + * Returns last node in the list. + * + * @param[in] head List head. + * + * @return + * Last node. + */ +static inline struct nss_nlist *nss_nlist_last(struct nss_nlist *head) +{ + return nss_nlist_prev(head); +} + +/** + * Checks if list is empty. + * + * @param[in] head List head. + * + * @return + * TRUE if empty. + */ +static inline bool nss_nlist_isempty(struct nss_nlist *head) +{ + struct nss_nlist *first = nss_nlist_first(head); + + return first == head; +} + +/** + * Checks if corresponding node is the last node. + * + * @param[in] head Head node. + * @param[in] node Node to check. + * + * @return + * TRUE if it is the last node. + */ +static inline bool nss_nlist_islast(struct nss_nlist *head, struct nss_nlist *node) +{ + struct nss_nlist *last = nss_nlist_last(head); + + return last == node; +} + +/** + * Adds node to head of the list. + * + * @param[in] head List head. + * @param[in] node Node to add. + * + * @return + * None. + */ +static inline void nss_nlist_add_head(struct nss_nlist *head, struct nss_nlist *node) +{ + struct nss_nlist *first = nss_nlist_first(head); + + node->prev = head; + node->next = first; + + first->prev = node; + head->next = node; + +} + +/** + * Adds node to tail of the list. + * + * @param[in] head List head. + * @param[in] node Node to add. + * + * @return + * None. + */ +static inline void nss_nlist_add_tail(struct nss_nlist *head, struct nss_nlist *node) +{ + struct nss_nlist *last = nss_nlist_last(head); + + node->next = head; + node->prev = last; + + last->next = node; + head->prev = node; +} + +/** + * Unlinks node from the list. + * + * @param[in] node Node to unlink. + * + * @return + * None. + */ +static inline void nss_nlist_unlink(struct nss_nlist *node) +{ + struct nss_nlist *prev = nss_nlist_prev(node); + struct nss_nlist *next = nss_nlist_next(node); + + prev->next = next; + next->prev = prev; + + nss_nlist_init(node); +} + +/** @} *//* end_addtogroup nss_nlist_functions */ + +/** @ingroup nss_nlist_macros + * Lists node iterator. + * + * @hideinitializer + * @param[in] _tmp Temporary node for assignment. + * @param[in] _head Head node to start. + * + * @return + * None. + */ +#define nss_nlist_iterate(_tmp, _head) \ + for ((_tmp) = nss_nlist_first((_head)); \ + !nss_nlist_islast((_head), (_tmp)); \ + (_tmp) = nss_nlist_next((_tmp)) + +#endif /* __NSS_NLIST_H__ */ diff --git a/qca/nss-userspace-oss/libnl-nss/src/include/nss_nlmcast_api.h b/qca/nss-userspace-oss/libnl-nss/src/include/nss_nlmcast_api.h new file mode 100644 index 0000000..8fcf5d8 --- /dev/null +++ b/qca/nss-userspace-oss/libnl-nss/src/include/nss_nlmcast_api.h @@ -0,0 +1,102 @@ +/* + ************************************************************************** + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +#ifndef __NSS_NLMCAST_API_H__ +#define __NSS_NLMCAST_API_H__ + +/** @addtogroup chapter_nlmcast + This chapter describes multicast APIs in the user space. + These APIs are wrapper functions for multicast specific operations. +*/ + +/** @addtogroup nss_nlmcast_datatypes @{ */ + +/** + * Event callback for multicast. + * + * @param[in] cmd Command received in generic Netlink header. + * @param[in] data Data received in Netlink message. + */ +typedef void (*nss_nlmcast_event_t)(int cmd, void *data); + +/** + * NSS multicast context. + */ +struct nss_nlmcast_ctx { + struct nss_nlsock_ctx sock; /**< NSS socket context. */ + nss_nlmcast_event_t event; /**< NSS event callback function. */ +}; + +/** @} *//* end_addtogroup nss_nlmcast_datatypes */ +/** @addtogroup nss_nlmcast_functions @{ */ + +/** + * Listens to NSS NL multicast event data. + * + * @param[in] ctx Multicast context. + * + * @return + * Listen status. + */ +int nss_nlmcast_sock_listen(struct nss_nlmcast_ctx *ctx); + +/** + * Subscribe the multicast group to receive responses. + * + * @param[in] ctx Multicast context. + * @param[in] grp_name NSS NL group name. + * + * @return + * Subscription status. + */ +int nss_nlmcast_sock_join_grp(struct nss_nlmcast_ctx *ctx, char *grp_name); + +/** + * Unsubscribe the multicast group to stop receiving responses. + * + * @param[in] ctx Multicast context. + * @param[in] grp_name NSS NL group name. + * + * @return + * Status of the operation. + */ +int nss_nlmcast_sock_leave_grp(struct nss_nlmcast_ctx *ctx, char *grp_name); + +/** + * Opens a socket for listening to NSS NL event data. + * + * @param[in] ctx Multicast context. + * @param[in] cb Callback function. + * @param[in] family_name NSS NL family name. + * + * @return + * Status of the operation. + */ +int nss_nlmcast_sock_open(struct nss_nlmcast_ctx *ctx, nss_nlmcast_event_t cb, const char *family_name); + +/** + * Closes socket. + * + * @param[in] ctx Multicast context. + * + * @return + * None. + */ +void nss_nlmcast_sock_close(struct nss_nlmcast_ctx *ctx); + +/** @} *//* end_addtogroup nss_nlmcast_functions */ + +#endif /* __NSS_NLMCAST_API_H__ */ diff --git a/qca/nss-userspace-oss/libnl-nss/src/include/nss_nlsock_api.h b/qca/nss-userspace-oss/libnl-nss/src/include/nss_nlsock_api.h new file mode 100644 index 0000000..7a42071 --- /dev/null +++ b/qca/nss-userspace-oss/libnl-nss/src/include/nss_nlsock_api.h @@ -0,0 +1,197 @@ +/* + ************************************************************************** + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +#ifndef __NSS_NLSOCK_API_H__ +#define __NSS_NLSOCK_API_H__ + +/** @addtogroup chapter_nlsocket + This chapter describes socket APIs for direct use. + + @note1hang + Use these APIs(s) only if there are no available helpers for the specific family. +*/ + +/** + * @ingroup nss_nlsocket_datatypes + * NSS NL socket context. + */ +struct nss_nlsock_ctx { + /* Public, caller must populate using helpers */ + const char *family_name; /**< Family name. */ + void *user_ctx; /**< Socket user context. */ + + /* Private, maintained by the library */ + pthread_t thread; /**< Response sync. */ + pthread_spinlock_t lock; /**< Context lock. */ + int ref_cnt; /**< References to the socket. */ + + struct nl_sock *nl_sk; /**< Linux NL socket. */ + struct nl_cb *nl_cb; /**< NSS NL callback context. */ + + pid_t pid; /**< Process ID associated with the socket. */ + int family_id; /**< Family identifier. */ + int grp_id; /**< Group indentifier. */ + bool is_avail; /**< Indicates if the socket is available to send or listen. */ +}; + +/** @addtogroup nss_nlsocket_macros @{ */ + +/** + * Prints error log. + * + * @param[in] arg Argument to be printed + */ +#define nss_nlsock_log_error(arg, ...) printf("NSS_NLERROR(%s[%d]):"arg, __func__, __LINE__, ##__VA_ARGS__) + +/** + * Prints arguments + * + * @param[in] arg Argument to be printed + */ +#define nss_nlsock_log_info(arg, ...) printf("NSS_NLINFO(%s[%d]):"arg, __func__, __LINE__, ##__VA_ARGS__) + +/** @} *//* end_addtogroup nss_nlsocket_macros */ + +/** @addtogroup nss_nlsocket_functions @{ */ + +/** + * Sets family name. + * + * @param[in] sock Socket context. + * @param[in] name Family name. + * + * @return + * None. + */ +static inline void nss_nlsock_set_family(struct nss_nlsock_ctx *sock, const char *name) +{ + sock->family_name = name; +} + +/** + * Sets user context. + * + * @param[in] sock Socket context. + * @param[in] user User context. + * + * @return + * None. + */ +static inline void nss_nlsock_set_user_ctx(struct nss_nlsock_ctx *sock, void *user) +{ + sock->user_ctx = user; +} + +/** + * Extracts NSS NL message data. + * + * @param[in] msg NL message. + * + * @return + * Pointer to start of NSS NL message. + */ +static inline void *nss_nlsock_get_data(struct nl_msg *msg) +{ + struct genlmsghdr *genl_hdr = nlmsg_data((nlmsg_hdr(msg))); + + return genlmsg_data(genl_hdr); +} + +/** + * Opens NSS NL family socket. + * + * @param[in] sock Socket context to be allocated by the caller. + * @param[in] cb Callback function for response. + * + * @return + * Status of the operation. + * + * @note The underlying entity should set the sock->family name for the socket to open. + */ +int nss_nlsock_open(struct nss_nlsock_ctx *sock, nl_recvmsg_msg_cb_t cb); + +/** + * Closes NSS NL family socket. + * + * @param[in] sock Socket context. + * + * @return + * None. + */ +void nss_nlsock_close(struct nss_nlsock_ctx *sock); + +/** + * Sends NSS NL message synchronously. + * + * @param[in] sock Socket context. + * @param[in] cm Common message header. + * @param[in] data Message data. + * @param[in] has_resp Determines if response is needed from kernel. + * + * @detdesc The function blocks until ack/error is received from the kernel + * and also blocks for the message response from the kernel if is_resp is TRUE + + * @return + * Status of the send operation. + */ +int nss_nlsock_send(struct nss_nlsock_ctx *sock, struct nss_nlcmn *cm, void *data, bool has_resp); + +/** + * Listens to asynchronous events from kernel. + * + * @param[in] sock Socket context. + * + * @return + * Listen status. + */ +int nss_nlsock_listen(struct nss_nlsock_ctx *sock); + +/** + * Subscribes to multicast group. + * + * @param[in] sock Socket context. + * @param[in] grp_name NSS NL group name. + * + * @return + * Subscription status. + */ +int nss_nlsock_join_grp(struct nss_nlsock_ctx *sock, char *grp_name); + +/** + * Unsubscribes from multicast group. + * + * @param[in] sock Socket context. + * @param[in] grp_name NSS NL group name. + * + * @return + * Status of the operation. + */ +int nss_nlsock_leave_grp(struct nss_nlsock_ctx *sock, char *grp_name); + +/** + * Opens a socket for listening to NSS NL event data. + * + * @param[in] sock Socket context. + * @param[in] cb Callback function. + * + * @return + * Status of the operation. + */ +int nss_nlsock_open_mcast(struct nss_nlsock_ctx *sock, nl_recvmsg_msg_cb_t cb); + +/** @} *//* end_addtogroup nss_nlsocket_functions */ + +#endif /* __NSS_NLSOCK_API_H__ */ diff --git a/qca/nss-userspace-oss/libnl-nss/src/nss_nldtls_api.c b/qca/nss-userspace-oss/libnl-nss/src/nss_nldtls_api.c new file mode 100644 index 0000000..4ad42ef --- /dev/null +++ b/qca/nss-userspace-oss/libnl-nss/src/nss_nldtls_api.c @@ -0,0 +1,138 @@ +/* + ************************************************************************** + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +#include +#include +#include + +/* + * nss_nldtls_sock_cb() + * Callback func for dtls netlink socket + */ +int nss_nldtls_sock_cb(struct nl_msg *msg, void *arg) +{ + pid_t pid = getpid(); + + struct nss_nldtls_rule *rule = nss_nlsock_get_data(msg); + + if (!rule) { + nss_nlsock_log_error("%d:failed to get NSS NL dtls header\n", pid); + return NL_SKIP; + } + + uint8_t cmd = nss_nlcmn_get_cmd(&rule->cm); + + switch (cmd) { + case NSS_NLDTLS_CMD_TYPE_CREATE_TUN: + case NSS_NLDTLS_CMD_TYPE_DESTROY_TUN: + case NSS_NLDTLS_CMD_TYPE_UPDATE_CONFIG: + case NSS_NLDTLS_CMD_TYPE_TX_PKTS: + return NL_OK; + + default: + nss_nlsock_log_error("%d:unsupported message cmd type(%d)\n", pid, cmd); + return NL_SKIP; + } +} + +/* + * nss_nldtls_sock_open() + * Opens the NSS dtls NL socket for usage + */ +int nss_nldtls_sock_open(struct nss_nldtls_ctx *ctx, void *user_ctx, nss_nldtls_event_t event_cb) +{ + pid_t pid = getpid(); + int error; + + if (!ctx) { + nss_nlsock_log_error("%d: invalid parameters passed\n", pid); + return -EINVAL; + } + + memset(ctx, 0, sizeof(*ctx)); + + nss_nlsock_set_family(&ctx->sock, NSS_NLDTLS_FAMILY); + nss_nlsock_set_user_ctx(&ctx->sock, user_ctx); + + /* + * try opening the socket with Linux + */ + error = nss_nlsock_open(&ctx->sock, nss_nldtls_sock_cb); + if (error) { + nss_nlsock_log_error("%d:unable to open NSS dtls socket, error(%d)\n", pid, error); + goto fail; + } + + return 0; +fail: + memset(ctx, 0, sizeof(*ctx)); + return error; +} + +/* + * nss_nldtls_sock_close() + * Close the NSS dtls NL socket + */ +void nss_nldtls_sock_close(struct nss_nldtls_ctx *ctx) +{ + nss_nlsock_close(&ctx->sock); + memset(ctx, 0, sizeof(struct nss_nldtls_ctx)); +} + +/* + * nss_nldtls_sock_send() + * Send the dtls message synchronously through the socket + */ +int nss_nldtls_sock_send(struct nss_nldtls_ctx *ctx, struct nss_nldtls_rule *rule, nss_nldtls_resp_t cb, void *data) +{ + int32_t family_id = ctx->sock.family_id; + struct nss_nldtls_resp *resp; + pid_t pid = getpid(); + bool has_resp = false; + int error = 0; + + if (!rule) { + nss_nlsock_log_error("%d:invalid NSS dtls rule\n", pid); + return -EINVAL; + } + + if (cb) { + nss_nlcmn_set_cb_owner(&rule->cm, family_id); + + resp = nss_nlcmn_get_cb_data(&rule->cm, family_id); + assert(resp); + + resp->data = data; + resp->cb = cb; + has_resp = true; + } + + error = nss_nlsock_send(&ctx->sock, &rule->cm, rule, has_resp); + if (error) { + nss_nlsock_log_error("%d:failed to send NSS dtls rule, error(%d)\n", pid, error); + } + + return error; +} + +/* + * nss_nldtls_init_rule() + * Initialize the dtls rule + */ +void nss_nldtls_init_rule(struct nss_nldtls_rule *rule, enum nss_nldtls_cmd_type type) +{ + nss_nldtls_rule_init(rule, type); +} diff --git a/qca/nss-userspace-oss/libnl-nss/src/nss_nlipv4_api.c b/qca/nss-userspace-oss/libnl-nss/src/nss_nlipv4_api.c new file mode 100644 index 0000000..0088d72 --- /dev/null +++ b/qca/nss-userspace-oss/libnl-nss/src/nss_nlipv4_api.c @@ -0,0 +1,176 @@ +/* + ************************************************************************** + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +#include +#include +#include + +/* + * nss_nlipv4_sock_cb() + * NSS NL IPv4 callback + */ +int nss_nlipv4_sock_cb(struct nl_msg *msg, void *arg) +{ + pid_t pid = getpid(); + + struct nss_nlipv4_ctx *ctx = (struct nss_nlipv4_ctx *)arg; + struct nss_nlsock_ctx *sock = &ctx->sock; + + struct nss_nlipv4_rule *rule = nss_nlsock_get_data(msg); + if (!rule) { + nss_nlsock_log_error("%d:failed to get NSS NL IPv4 header\n", pid); + return NL_SKIP; + } + + uint8_t cmd = nss_nlcmn_get_cmd(&rule->cm); + + switch (cmd) { + case NSS_IPV4_TX_CREATE_RULE_MSG: + case NSS_IPV4_TX_DESTROY_RULE_MSG: + { + void *cb_data = nss_nlcmn_get_cb_data(&rule->cm, sock->family_id); + if (!cb_data) { + return NL_SKIP; + } + + /* + * Note: The callback user can modify the CB content so it + * needs to locally save the response data for further use + * after the callback is completed + */ + struct nss_nlipv4_resp resp; + memcpy(&resp, cb_data, sizeof(struct nss_nlipv4_resp)); + + /* + * clear the ownership of the CB so that callback user can + * use it if needed + */ + nss_nlcmn_clr_cb_owner(&rule->cm); + + if (!resp.cb) { + nss_nlsock_log_info("%d:no IPv4 response callback for cmd(%d)\n", pid, cmd); + return NL_SKIP; + } + + resp.cb(sock->user_ctx, rule, resp.data); + + return NL_OK; + } + + case NSS_IPV4_RX_CONN_STATS_SYNC_MSG: + { + nss_nlipv4_event_t event = ctx->event; + + assert(event); + event(sock->user_ctx, rule); + + return NL_OK; + } + + default: + nss_nlsock_log_error("%d:unsupported message cmd type(%d)\n", pid, cmd); + return NL_SKIP; + } +} + +/* + * nss_nlipv4_sock_open() + * this opens the NSS IPv4 NL socket for usage + */ +int nss_nlipv4_sock_open(struct nss_nlipv4_ctx *ctx, void *user_ctx, nss_nlipv4_event_t event_cb) +{ + pid_t pid = getpid(); + int error; + + if (!ctx) { + nss_nlsock_log_error("%d: invalid parameters passed\n", pid); + return -EINVAL; + } + + memset(ctx, 0, sizeof(*ctx)); + + nss_nlsock_set_family(&ctx->sock, NSS_NLIPV4_FAMILY); + nss_nlsock_set_user_ctx(&ctx->sock, user_ctx); + + /* + * try opening the socket with Linux + */ + error = nss_nlsock_open(&ctx->sock, nss_nlipv4_sock_cb); + if (error) { + nss_nlsock_log_error("%d:unable to open NSS IPv4 socket, error(%d)\n", pid, error); + goto fail; + } + + return 0; +fail: + memset(ctx, 0, sizeof(*ctx)); + return error; +} + +/* + * nss_nlipv4_sock_close() + * close the NSS IPv4 NL socket + */ +void nss_nlipv4_sock_close(struct nss_nlipv4_ctx *ctx) +{ + nss_nlsock_close(&ctx->sock); +} + +/* + * nss_nlipv4_sock_send() + * register callback and send the IPv4 message synchronously through the socket + */ +int nss_nlipv4_sock_send(struct nss_nlipv4_ctx *ctx, struct nss_nlipv4_rule *rule, nss_nlipv4_resp_t cb, void *data) +{ + int32_t family_id = ctx->sock.family_id; + struct nss_nlipv4_resp *resp; + pid_t pid = getpid(); + bool has_resp = false; + int error; + + if (!rule) { + nss_nlsock_log_error("%d:invalid NSS IPv4 rule\n", pid); + return -ENOMEM; + } + + if (cb) { + nss_nlcmn_set_cb_owner(&rule->cm, family_id); + + resp = nss_nlcmn_get_cb_data(&rule->cm, family_id); + assert(resp); + + resp->data = data; + resp->cb = cb; + has_resp = true; + } + + error = nss_nlsock_send(&ctx->sock, &rule->cm, rule, has_resp); + if (error) { + nss_nlsock_log_error("%d:failed to send NSS IPv4 rule, error(%d)\n", pid, error); + return error; + } + + return 0; +} + +/* + * nss_nlipv4_init_rule() + * init the rule message + */ +void nss_nlipv4_init_rule(struct nss_nlipv4_rule *rule, enum nss_ipv4_message_types type) +{ + nss_nlipv4_rule_init(rule, type); +} diff --git a/qca/nss-userspace-oss/libnl-nss/src/nss_nlipv6_api.c b/qca/nss-userspace-oss/libnl-nss/src/nss_nlipv6_api.c new file mode 100644 index 0000000..fa0bbf2 --- /dev/null +++ b/qca/nss-userspace-oss/libnl-nss/src/nss_nlipv6_api.c @@ -0,0 +1,176 @@ +/* + ************************************************************************** + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +#include +#include +#include + +/* + * nss_nlipv6_sock_cb() + * NSS NL IPv6 callback + */ +int nss_nlipv6_sock_cb(struct nl_msg *msg, void *arg) +{ + pid_t pid = getpid(); + + struct nss_nlipv6_ctx *ctx = (struct nss_nlipv6_ctx *)arg; + struct nss_nlsock_ctx *sock = &ctx->sock; + + struct nss_nlipv6_rule *rule = nss_nlsock_get_data(msg); + if (!rule) { + nss_nlsock_log_error("%d:failed to get NSS NL IPv6 header\n", pid); + return NL_SKIP; + } + + uint8_t cmd = nss_nlcmn_get_cmd(&rule->cm); + + switch (cmd) { + case NSS_IPV6_TX_CREATE_RULE_MSG: + case NSS_IPV6_TX_DESTROY_RULE_MSG: + { + void *cb_data = nss_nlcmn_get_cb_data(&rule->cm, sock->family_id); + if (!cb_data) { + return NL_SKIP; + } + + /* + * Note: The callback user can modify the CB content so it + * needs to locally save the response data for further use + * after the callback is completed + */ + struct nss_nlipv6_resp resp; + memcpy(&resp, cb_data, sizeof(struct nss_nlipv6_resp)); + + /* + * clear the ownership of the CB so that callback user can + * use it if needed + */ + nss_nlcmn_clr_cb_owner(&rule->cm); + + if (!resp.cb) { + nss_nlsock_log_info("%d:no IPv6 response callback for cmd(%d)\n", pid, cmd); + return NL_SKIP; + } + + resp.cb(sock->user_ctx, rule, resp.data); + + return NL_OK; + } + + case NSS_IPV6_RX_CONN_STATS_SYNC_MSG: + { + nss_nlipv6_event_t event = ctx->event; + + assert(event); + event(sock->user_ctx, rule); + + return NL_OK; + } + + default: + nss_nlsock_log_error("%d:unsupported message cmd type(%d)\n", pid, cmd); + return NL_SKIP; + } +} + +/* + * nss_nlipv6_sock_open() + * this opens the NSS IPv6 NL socket for usage + */ +int nss_nlipv6_sock_open(struct nss_nlipv6_ctx *ctx, void *user_ctx, nss_nlipv6_event_t event_cb) +{ + pid_t pid = getpid(); + int error; + + if (!ctx) { + nss_nlsock_log_error("%d: invalid parameters passed\n", pid); + return -EINVAL; + } + + memset(ctx, 0, sizeof(*ctx)); + + nss_nlsock_set_family(&ctx->sock, NSS_NLIPV6_FAMILY); + nss_nlsock_set_user_ctx(&ctx->sock, user_ctx); + + /* + * try opening the socket with Linux + */ + error = nss_nlsock_open(&ctx->sock, nss_nlipv6_sock_cb); + if (error) { + nss_nlsock_log_error("%d:unable to open NSS IPv6 socket, error(%d)\n", pid, error); + goto fail; + } + + return 0; +fail: + memset(ctx, 0, sizeof(*ctx)); + return error; +} + +/* + * nss_nlipv6_sock_close() + * close the NSS IPv6 NL socket + */ +void nss_nlipv6_sock_close(struct nss_nlipv6_ctx *ctx) +{ + nss_nlsock_close(&ctx->sock); +} + +/* + * nss_nlipv6_sock_send() + * register callback and send the IPv6 message synchronously through the socket + */ +int nss_nlipv6_sock_send(struct nss_nlipv6_ctx *ctx, struct nss_nlipv6_rule *rule, nss_nlipv6_resp_t cb, void *data) +{ + int32_t family_id = ctx->sock.family_id; + struct nss_nlipv6_resp *resp; + pid_t pid = getpid(); + bool has_resp = false; + int error; + + if (!rule) { + nss_nlsock_log_error("%d:invalid NSS IPv6 rule\n", pid); + return -ENOMEM; + } + + if (cb) { + nss_nlcmn_set_cb_owner(&rule->cm, family_id); + + resp = nss_nlcmn_get_cb_data(&rule->cm, family_id); + assert(resp); + + resp->data = data; + resp->cb = cb; + has_resp = true; + } + + error = nss_nlsock_send(&ctx->sock, &rule->cm, rule, has_resp); + if (error) { + nss_nlsock_log_error("%d:failed to send NSS IPv6 rule, error(%d)\n", pid, error); + return error; + } + + return 0; +} + +/* + * nss_nlipv6_init_rule() + * init the rule message + */ +void nss_nlipv6_init_rule(struct nss_nlipv6_rule *rule, enum nss_ipv6_message_types type) +{ + nss_nlipv6_rule_init(rule, type); +} diff --git a/qca/nss-userspace-oss/libnl-nss/src/nss_nlmcast_api.c b/qca/nss-userspace-oss/libnl-nss/src/nss_nlmcast_api.c new file mode 100644 index 0000000..7646440 --- /dev/null +++ b/qca/nss-userspace-oss/libnl-nss/src/nss_nlmcast_api.c @@ -0,0 +1,146 @@ +/* + ************************************************************************** + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +#include +#include +#include + +/* + * nss_nlmcast_sock_cb() + * NSS NL mcast callback. + */ +static int nss_nlmcast_sock_cb(struct nl_msg *msg, void *arg) +{ + struct nss_nlmcast_ctx *ctx = (struct nss_nlmcast_ctx *)arg; + struct genlmsghdr *genl_hdr = nlmsg_data((nlmsg_hdr(msg))); + uint8_t cmd = genl_hdr->cmd; + + void *data = nss_nlsock_get_data(msg); + if (!data) { + nss_nlsock_log_error("%d:failed to get NSS NL msg header\n", getpid()); + return NL_SKIP; + } + + nss_nlmcast_event_t event = ctx->event; + assert(event); + event(cmd, data); + return NL_OK; +} + +/* + * nss_nlmcast_sock_open() + * Open the NL socket for listening to MCAST events from kernel. + */ +int nss_nlmcast_sock_open(struct nss_nlmcast_ctx *ctx, nss_nlmcast_event_t event_cb, const char *family_name) +{ + int error; + + if (!ctx || !event_cb) { + nss_nlsock_log_error("Invalid parameters passed\n"); + return -EINVAL; + } + + memset(ctx, 0, sizeof(*ctx)); + + nss_nlsock_set_family(&ctx->sock, family_name); + + /* + * Subscribe to the NSS NL Multicast group. + */ + error = nss_nlsock_open_mcast(&ctx->sock, nss_nlmcast_sock_cb); + if (error) { + nss_nlsock_log_error("Unable to create socket, error(%d)\n", error); + return error; + } + + ctx->event = event_cb; + return 0; +} + +/* + * nss_nlmcast_sock_close() + * Close the NL socket. + */ +void nss_nlmcast_sock_close(struct nss_nlmcast_ctx *ctx) +{ + nss_nlsock_close(&ctx->sock); +} + +/* + * nss_nlmcast_sock_join_grp() + * Subscribe for MCAST group from kernel. + */ +int nss_nlmcast_sock_join_grp(struct nss_nlmcast_ctx *ctx, char *grp_name) +{ + int error; + + if (!ctx || !grp_name) { + nss_nlsock_log_error("Invalid parameters passed\n"); + return -EINVAL; + } + + error = nss_nlsock_join_grp(&ctx->sock, grp_name); + if (error) { + nss_nlsock_log_error("Unable to subscribe for mcast group, error(%d)\n", error); + return error; + } + + return 0; +} + +/* + * nss_nlmcast_sock_leave_grp() + * Unsubscribe for MCAST group from kernel. + */ +int nss_nlmcast_sock_leave_grp(struct nss_nlmcast_ctx *ctx, char *grp_name) +{ + int error; + + if (!ctx || !grp_name) { + nss_nlsock_log_error("Invalid parameters passed\n"); + return -EINVAL; + } + + error = nss_nlsock_leave_grp(&ctx->sock, grp_name); + if (error) { + nss_nlsock_log_error("Unable to unsubscribe for mcast group, error(%d)\n", error); + return error; + } + + return 0; +} + +/* + * nss_nlmcast_sock_listen() + * Listen for MCAST events from kernel + */ +int nss_nlmcast_sock_listen(struct nss_nlmcast_ctx *ctx) +{ + int error; + + if (!ctx) { + nss_nlsock_log_error("Invalid parameters passed\n"); + return -EINVAL; + } + + error = nss_nlsock_listen(&ctx->sock); + if (error) { + nss_nlsock_log_error("Unable to listen to mcast events, error(%d)\n", error); + return error; + } + + return 0; +} diff --git a/qca/nss-userspace-oss/libnl-nss/src/nss_nlsock.c b/qca/nss-userspace-oss/libnl-nss/src/nss_nlsock.c new file mode 100644 index 0000000..451982f --- /dev/null +++ b/qca/nss-userspace-oss/libnl-nss/src/nss_nlsock.c @@ -0,0 +1,498 @@ +/* + ************************************************************************** + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +/* + * @file netlink socket handler + */ + +#include +#include + +/* + * nss_nlsock_deinit() + * de-initialize the socket + */ +static void nss_nlsock_deinit(struct nss_nlsock_ctx *sock) +{ + assert(sock); + + nl_cb_put(sock->nl_cb); + sock->nl_cb = NULL; + + nl_socket_free(sock->nl_sk); + sock->nl_sk = NULL; +} + +/* + * nss_nlsock_init() + * initialize the socket and callback + */ +static int nss_nlsock_init(struct nss_nlsock_ctx *sock, nl_recvmsg_msg_cb_t cb) +{ + int error; + + assert(sock); + + /* + * Initialize spinlock + */ + error = pthread_spin_init(&sock->lock, PTHREAD_PROCESS_PRIVATE); + if (error) { + nss_nlsock_log_error("Failed to init spinlock for family(%s), error %d\n", sock->family_name, error); + return error; + } + + sock->pid = getpid(); + + /* + * create callback + */ + sock->nl_cb = nl_cb_alloc(NL_CB_CUSTOM); + if (!sock->nl_cb) { + nss_nlsock_log_error("%d:failed to alloc callback for family(%s)\n",sock->pid, sock->family_name); + goto fail1; + } + + /* + * register callback + */ + nl_cb_set(sock->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, cb, sock); + + /* + * Create netlink socket + */ + sock->nl_sk = nl_socket_alloc_cb(sock->nl_cb); + if (!sock->nl_sk) { + nss_nlsock_log_error("%d:failed to alloc socket for family(%s)\n", sock->pid, sock->family_name); + goto fail2; + } + + sock->ref_cnt = 1; + + /* + * is_avail is set to indicate the socket is available for send/listen + */ + sock->is_avail = true; + return 0; + +fail2: + nl_cb_put(sock->nl_cb); + sock->nl_cb = NULL; +fail1: + pthread_spin_destroy(&sock->lock); + sock->lock = (pthread_spinlock_t)0; + return -ENOMEM; +} + +/* + * nss_nlsock_deref() + * decrement the reference count and free socket resources if '0' + */ +static inline void nss_nlsock_deref(struct nss_nlsock_ctx *sock) +{ + assert(sock->ref_cnt > 0); + + pthread_spin_lock(&sock->lock); + if (--sock->ref_cnt) { + pthread_spin_unlock(&sock->lock); + return; + } + + /* + * When there are no more references on the socket, + * deinitialize the socket and destroy the spin lock + * created during nss_nlsock_init + */ + nss_nlsock_deinit(sock); + pthread_spin_unlock(&sock->lock); + + pthread_spin_destroy(&sock->lock); + sock->lock = (pthread_spinlock_t)0; +} + +/* + * nss_nlsock_ref() + * Increment the reference count. + * + * if ref_cnt == 0, return false + * if ref_cnt != 0, increment the socket reference count and return true + */ +static inline bool nss_nlsock_ref(struct nss_nlsock_ctx *sock) +{ + /* + * if ref count is 0, it means there are no references + * on the socket and so return false. Socket will eventually be + * freed by nss_nlsock_deinit else increment the ref count + */ + pthread_spin_lock(&sock->lock); + if (sock->ref_cnt == 0) { + pthread_spin_unlock(&sock->lock); + return false; + } + + sock->ref_cnt++; + pthread_spin_unlock(&sock->lock); + + return true; +} + +/* + * nss_nlsock_listen_callback() + * listen to responses from the netlink socket + * + * The API keeps listening for the responses on the netlink socket + * until socket close is initiated and there are no more + * responses on the socket + */ +static void *nss_nlsock_listen_callback(void *arg) +{ + struct nss_nlsock_ctx *sock = (struct nss_nlsock_ctx *)arg; + assert(sock); + + /* + * drain responses on the socket + */ + for (;;) { + /* + * if, socket is freed then break out + */ + if (!nss_nlsock_ref(sock)) { + break; + } + + /* + * get or block for pending messages + */ + nl_recvmsgs(sock->nl_sk, sock->nl_cb); + nss_nlsock_deref(sock); + } + + return NULL; +} + +/* + * nss_nlsock_msg_init() + * Initialize parameters to send message down the socket + */ +static int nss_nlsock_msg_init(struct nss_nlsock_ctx *sock, struct nss_nlcmn *cm, void *data, struct nl_msg *msg) +{ + int pid = sock->pid; + void *user_hdr; + uint32_t ver; + uint8_t cmd; + int len; + + ver = nss_nlcmn_get_ver(cm); + len = nss_nlcmn_get_len(cm); + cmd = nss_nlcmn_get_cmd(cm); + + /* + * create space for user header + */ + user_hdr = genlmsg_put(msg, pid, NL_AUTO_SEQ, sock->family_id, len, 0, cmd, ver); + if (!user_hdr) { + nss_nlsock_log_error("%d:failed to put message header of len(%d)\n", pid, len); + return -ENOMEM; + + } + + memcpy(user_hdr, data, len); + return 0; +} + +/* + * nss_nlsock_leave_grp() + * nl socket unsubscribe for the multicast group + */ +int nss_nlsock_leave_grp(struct nss_nlsock_ctx *sock, char *grp_name) +{ + int error; + + assert(sock->ref_cnt > 0); + + /* + * Resolve the group + */ + sock->grp_id = genl_ctrl_resolve_grp(sock->nl_sk, sock->family_name, grp_name); + if (sock->grp_id < 0) { + nss_nlsock_log_error("failed to resolve group(%s)\n", grp_name); + return -EINVAL; + } + + /* + * Unsubscribe for the mcast async events + */ + error = nl_socket_drop_memberships(sock->nl_sk, sock->grp_id, 0); + if (error < 0) { + nss_nlsock_log_error("failed to deregister grp(%s)\n", grp_name); + return error; + } + + return 0; +} + +/* + * nss_nlsock_join_grp() + * nl socket subscribe for the multicast group + */ +int nss_nlsock_join_grp(struct nss_nlsock_ctx *sock, char *grp_name) +{ + int error; + + assert(sock->ref_cnt > 0); + + /* + * Resolve the group + */ + sock->grp_id = genl_ctrl_resolve_grp(sock->nl_sk, sock->family_name, grp_name); + if (sock->grp_id < 0) { + nss_nlsock_log_error("failed to resolve group(%s)\n", grp_name); + return -EINVAL; + } + + /* + * Subscribe for the mcast async events + */ + error = nl_socket_add_memberships(sock->nl_sk, sock->grp_id, 0); + if (error < 0) { + nss_nlsock_log_error("failed to register grp(%s)\n", grp_name); + return error; + } + + return 0; +} + +/* + * nss_nlsock_open_mcast() + * Open the socket for async events + */ +int nss_nlsock_open_mcast(struct nss_nlsock_ctx *sock, nl_recvmsg_msg_cb_t cb) +{ + int error; + assert(sock); + + error = nss_nlsock_init(sock, cb); + if (error) { + nss_nlsock_log_error("%d:failed to initialize socket(%s)\n", sock->pid, sock->family_name); + return error; + } + + /* + * Disable seq number and auto ack checks for sockets listening for mcast events + */ + nl_socket_disable_seq_check(sock->nl_sk); + nl_socket_disable_auto_ack(sock->nl_sk); + + /* + * Connect the socket with the netlink bus + */ + if (genl_connect(sock->nl_sk)) { + nss_nlsock_log_error("%d:failed to connect socket for family(%s)\n", sock->pid, sock->family_name); + error = -EBUSY; + goto free_sock; + } + return 0; + +free_sock: + nss_nlsock_deref(sock); + return error; +} + +/* + * nss_nlsock_send() + * send a message synchronously through the socket + */ +int nss_nlsock_send(struct nss_nlsock_ctx *sock, struct nss_nlcmn *cm, void *data, bool has_resp) +{ + int pid = sock->pid; + struct nl_msg *msg; + int error; + + /* + * return -EBUSY if the socket is currently unavailable for sending message + */ + pthread_spin_lock(&sock->lock); + if (!sock->is_avail) { + pthread_spin_unlock(&sock->lock); + return -EBUSY; + } + + /* + * To indicate the socket is unavailable until the current thread completes the send/listen. + * This is to prevent other threads from simultaneous send/listen. + */ + sock->is_avail = false; + pthread_spin_unlock(&sock->lock); + + /* + * allocate new message buffer + */ + msg = nlmsg_alloc(); + if (!msg) { + nss_nlsock_log_error("%d:failed to allocate message buffer\n", pid); + sock->is_avail = true; + return -ENOMEM; + } + + /* + * Holds a reference on the socket until msg is sent down to the kernel + */ + if (!nss_nlsock_ref(sock)) { + nss_nlsock_log_error("%d:failed to get NL socket\n", pid); + nlmsg_free(msg); + sock->is_avail = true; + return -EINVAL; + } + + /* + * Initialize message parameters + */ + error = nss_nlsock_msg_init(sock, cm, data, msg); + if (error) { + nss_nlsock_log_error("%d:failed to initialize message structure (family:%s, error:%d)\n", + pid, sock->family_name, error); + nss_nlsock_deref(sock); + nlmsg_free(msg); + sock->is_avail = true; + return error; + } + + /* + * If has_resp is true and msg is sent to FW, then there will be two + * netlink messages coming from kernel - FW response and ACK + * If msg fails in netlink, then error will be returned from kernel. + * If has_resp is false, then there is only one netlink message + * coming from kernel: either ACK or error + * In case firmware response is sent before nl_recvmsgs is invoked, + * the response will be queued until the listener is available. + */ + error = nl_send_sync(sock->nl_sk, msg); + if (error < 0) { + nss_nlsock_log_error("%d:failed to send (family:%s, error:%d)\n", pid, sock->family_name, error); + nss_nlsock_deref(sock); + sock->is_avail = true; + return error; + } + + if (has_resp) { + nl_recvmsgs(sock->nl_sk, sock->nl_cb); + } + + nss_nlsock_deref(sock); + sock->is_avail = true; + return 0; +} + +/* + * nss_nlsock_listen() + * listen for async events on the socket + */ +int nss_nlsock_listen(struct nss_nlsock_ctx *sock) +{ + int error; + + assert(sock->ref_cnt > 0); + + /* + * return -EBUSY if the socket is currently unavailable for listening + */ + if (!sock->is_avail) { + return -EBUSY; + } + + /* + * To indicate the socket is unavailable until the current thread completes the send/listen. + * This is to prevent other threads from simultaneous send/listen. + */ + sock->is_avail = false; + + /* + * Create an async thread for clearing the pending resp on the socket asynchronously + */ + error = pthread_create(&sock->thread, NULL, nss_nlsock_listen_callback, sock); + if (error) { + nss_nlsock_log_error("%d:failed to create sync thread for family(%s)\n", sock->pid, sock->family_name); + return error; + } + + return 0; +} + +/* + * nss_nlsock_close() + * close the allocated socket and all associated memory + */ +void nss_nlsock_close(struct nss_nlsock_ctx *sock) +{ + assert(sock); + assert(sock->nl_sk); + assert(sock->ref_cnt > 0); + + /* + * put the reference down for the socket + */ + nss_nlsock_deref(sock); + + /* + * wait for the async thread to complete + */ + if (sock->thread) { + pthread_join(sock->thread, NULL); + sock->thread = NULL; + } +} + +/* + * nss_nlsock_open() + * open a socket for unicast communication with the generic netlink framework + */ +int nss_nlsock_open(struct nss_nlsock_ctx *sock, nl_recvmsg_msg_cb_t cb) +{ + int error = 0; + assert(sock); + + error = nss_nlsock_init(sock, cb); + if (error) { + nss_nlsock_log_error("%d:failed to initialize socket(%s)\n", sock->pid, sock->family_name); + return error; + } + + /* + * Connect the socket with the netlink bus + */ + if (genl_connect(sock->nl_sk)) { + nss_nlsock_log_error("%d:failed to connect socket for family(%s)\n", sock->pid, sock->family_name); + error = -EBUSY; + goto free_sock; + } + + /* + * resolve the family + */ + sock->family_id = genl_ctrl_resolve(sock->nl_sk, sock->family_name); + if (sock->family_id <= 0) { + nss_nlsock_log_error("%d:failed to resolve family(%s)\n", sock->pid, sock->family_name); + error = -EINVAL; + goto free_sock; + } + + return 0; + +free_sock: + + nss_nlsock_deref(sock); + return error; +} diff --git a/qca/nss-userspace-oss/nssinfo/Makefile b/qca/nss-userspace-oss/nssinfo/Makefile new file mode 100644 index 0000000..1339ac8 --- /dev/null +++ b/qca/nss-userspace-oss/nssinfo/Makefile @@ -0,0 +1,39 @@ +include $(TOPDIR)/rules.mk +include $(INCLUDE_DIR)/kernel.mk + +PKG_NAME:=nssinfo +PKG_RELEASE:=1 + +include $(INCLUDE_DIR)/package.mk + +define Package/nssinfo + SECTION:=utils + CATEGORY:=Utilities + TITLE:=Userspace utility for fetching stats from NSS + DEPENDS:=+libncurses +libnl-nss +endef + +define Package/nssinfo/description + A userspace utility for fetching stats from NSS. +endef + +TOOL_CFLAGS:= -I$(STAGING_DIR)/usr/include/qca-nss-clients \ + -I$(STAGING_DIR)/usr/include/qca-nss-drv \ + -I$(STAGING_DIR)/usr/include/libnl3 \ + -I$(STAGING_DIR)/usr/include/libnl-nss + +TOOL_LDFLAGS:= -L$(STAGING_DIR)/lib + +define Build/Compile + $(MAKE) -C $(PKG_BUILD_DIR) \ + CC="$(TARGET_CC)" \ + CFLAGS="$(TOOL_CFLAGS)" \ + LD_LIBRARY_PATH="$(TOOL_LDFLAGS)" +endef + +define Package/nssinfo/install + $(INSTALL_DIR) $(1)/usr/sbin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/obj/nssinfo $(1)/usr/sbin/ +endef + +$(eval $(call BuildPackage,nssinfo)) diff --git a/qca/nss-userspace-oss/nssinfo/src/Makefile b/qca/nss-userspace-oss/nssinfo/src/Makefile new file mode 100644 index 0000000..0ef19b3 --- /dev/null +++ b/qca/nss-userspace-oss/nssinfo/src/Makefile @@ -0,0 +1,35 @@ +MKDIR = mkdir -p $(@D) +SRCPATH = src +OBJPATH = obj +SRCDIR = ./ + +BINARY = $(OBJPATH)/nssinfo +SOURCES = $(wildcard $(SRCDIR)/src/*.c) +HEADERS = $(wildcard $(SRCDIR)/include/*.h) +OBJECTS = $(SOURCES:$(SRCDIR)/src/%.c=$(OBJPATH)/%.o) + +INCLUDE += -I../lib/include +EXTRA_CFLAGS = -Wall -Wno-error=format-truncation -UENABLE_DEBUG +LDFLAGS = -lnl-nss -lncurses +LDLIBS = -L../lib/obj + +all: release + +release: $(BINARY) + +$(OBJPATH)/%.o: $(SRCPATH)/%.c $(HEADERS) + $(MKDIR) + @echo [CC] $@ + @$(CC) -c $(CFLAGS) $(EXTRA_CFLAGS) $(INCLUDE) -o $@ $< + +$(BINARY): $(OBJECTS) + @echo $(BINARY) + @echo [LD] $@ + @$(CC) -o $@ $^ $(LDFLAGS) $(LDLIBS) +clean: + @echo [Clean] + @rm -f $(OBJECTS) + @rm -f $(BINARY) + @rmdir $(OBJPATH) + +.PHONY: clean diff --git a/qca/nss-userspace-oss/nssinfo/src/src/nssinfo.c b/qca/nss-userspace-oss/nssinfo/src/src/nssinfo.c new file mode 100644 index 0000000..60ce1ce --- /dev/null +++ b/qca/nss-userspace-oss/nssinfo/src/src/nssinfo.c @@ -0,0 +1,714 @@ +/* + ************************************************************************** + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +/* + * @file NSSINFO handler + */ +#include +#include "nssinfo.h" + +static pthread_t nssinfo_display_thread; /* Display statistics thread */ +static char buf[NSSINFO_STR_LEN]; /* Formatted stats buffer */ +bool display_all_stats; /* Display all stats per sub-system */ +int invalid_input; /* Identify invalid input */ +FILE *output_file; /* Output file pointer */ +FILE *flow_file; /* Flow file pointer */ + +/* Array of pointers to node stats */ +struct node *nodes[NSS_MAX_CORES][NSS_MAX_NET_INTERFACES]; + +/* + * NSS subsystems in alphabetical order for nssinfo tool + * - Make sure the order here is the same as in 'enum nss_nlcmn_subsys' + * defined in qca-nss-clients/netlink/include/nss_nlcmn_if.h. + */ +struct nssinfo_subsystem_info nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_MAX] = { + {.subsystem_name = "dynamic_interface", .init = nssinfo_dynamic_interface_init, .deinit = nssinfo_dynamic_interface_deinit}, + {.subsystem_name = "eth_rx", .init = nssinfo_eth_rx_init, .deinit = nssinfo_eth_rx_deinit}, + {.subsystem_name = "ipv4", .init = nssinfo_ipv4_init, .deinit = nssinfo_ipv4_deinit}, + {.subsystem_name = "ipv6", .init = nssinfo_ipv6_init, .deinit = nssinfo_ipv6_deinit}, + {.subsystem_name = "lso_rx", .init = nssinfo_lso_rx_init, .deinit = nssinfo_lso_rx_deinit}, + {.subsystem_name = "n2h", .init = nssinfo_n2h_init, .deinit = nssinfo_n2h_deinit}, +}; + +char *nssinfo_summary_fmt = "%-12s %-13s %-13s %-9s %-9s\n"; + +/* + * nssinfo_print_summary_header() + * Print the summary header. + */ +void nssinfo_print_summary_header(void) +{ + nssinfo_stats_print(nssinfo_summary_fmt, "Node", "RX Pkts", "TX Pkts", "Drops", "Exceptions"); + nssinfo_stats_print(nssinfo_summary_fmt, "----", "-------", "-------", "-----", "----------"); +} + +/* + * nssinfo_print_summary() + * Print the summary of the stats: + * - rx pkts + * - tx pkts + * - rx queue drops + * - exceptions + */ +void nssinfo_print_summary(char *node, uint64_t *cmn_node_stats, uint64_t *exception_stats, uint64_t exception_max) +{ + int i; + uint64_t drops = 0, exceptions = 0; + char str_rx[NSSINFO_STR_LEN], str_tx[NSSINFO_STR_LEN], str_drop[NSSINFO_STR_LEN], str_ex[NSSINFO_STR_LEN]; + + assert(cmn_node_stats); + + memset(str_rx, 0, sizeof(str_rx)); + memset(str_tx, 0, sizeof(str_tx)); + memset(str_drop, 0, sizeof(str_drop)); + memset(str_ex, 0, sizeof(str_ex)); + + for (i = NSS_STATS_NODE_RX_QUEUE_0_DROPPED; i < NSS_STATS_NODE_MAX; i++) { + drops += cmn_node_stats[i]; + } + + if (exception_stats) { + for (i = 0 ; i < exception_max; i++) { + exceptions += exception_stats[i]; + } + } + + if (cmn_node_stats[NSS_STATS_NODE_RX_PKTS] > 0 || cmn_node_stats[NSS_STATS_NODE_TX_PKTS] > 0 || + drops > 0 || exceptions > 0 || arguments.verbose) { + char *format_stats = nssinfo_format_stats(cmn_node_stats[NSS_STATS_NODE_RX_PKTS]); + strlcpy(str_rx, format_stats, sizeof(str_rx)); + format_stats = nssinfo_format_stats(cmn_node_stats[NSS_STATS_NODE_TX_PKTS]); + strlcpy(str_tx, format_stats, sizeof(str_tx)); + format_stats = nssinfo_format_stats(drops); + strlcpy(str_drop, format_stats, sizeof(str_drop)); + if (exception_stats) { + format_stats = nssinfo_format_stats(exceptions); + strlcpy(str_ex, format_stats, sizeof(str_ex)); + } + nssinfo_stats_print(nssinfo_summary_fmt, node, str_rx, str_tx, str_drop, str_ex); + } +} + +/* + * nssinfo_print_all() + * Print detailed statistics. + */ +void nssinfo_print_all(char *node, char *stat_details, struct nssinfo_stats_info *stats_info, uint64_t max, uint64_t *stats_val) +{ + int i; + uint16_t maxlen = 0; + char *type; + + for (i = 0; i < max; i++){ + if (strlen(stats_info[i].stats_name) > maxlen) { + maxlen = strlen(stats_info[i].stats_name); + } + } + + /* + * Display stats header, e.g. "#ipv4 Common Stats\n" + */ + if (stat_details != NULL) { + nssinfo_stats_print("#%s\n", stat_details); + } + + /* Display each stat, e.g. + * ipv4_rx_byts = 32903179 common + * ipv4_mc_create_invalid_interface = 12 special + * ... + */ + for (i = 0; i < max; i++) { + if (arguments.verbose || stats_val[i] > 0) { + + switch (stats_info[i].stats_type) { + case NSS_STATS_TYPE_COMMON: + type = "common"; + break; + + case NSS_STATS_TYPE_SPECIAL: + type = "special"; + break; + + case NSS_STATS_TYPE_DROP: + type = "drop"; + break; + + case NSS_STATS_TYPE_ERROR: + type = "error"; + break; + + case NSS_STATS_TYPE_EXCEPTION: + type = "exception"; + break; + + default: + type = "unknown"; + break; + } + + nssinfo_stats_print("%s_%-*s = %-20llu %-s\n", + node, maxlen, stats_info[i].stats_name, stats_val[i], type); + } + } + nssinfo_stats_print("\n"); + + return; +} + +/* + * nssinfo_parse_stats_strings() + * Parse each line in the debug strings file. + * + * Each line has the following format: + * \t , \n + * for example: + * root@OpenWrt:/sys/kernel/debug/qca-nss-drv/strings# cat n2h + * 0 , rx_pkts + * ... + * 1 , rx_queue[0]_drops + * ... + * 4 , n2h_data_interface_invalid + */ +static void nssinfo_parse_stats_strings(struct nssinfo_stats_info *info, char *line) +{ + char *token; + char *rest = NULL; + + token = strtok_r(line, " ", &rest); + if (token) { + info->stats_type = atoi(token); + token = strtok_r(NULL, ",", &rest); + } + if (token) { + token = strtok_r(token, " ", &rest); + } + if (token) { + token = strtok_r(token, "\n", &rest); + } + if (token) { + strlcpy(info->stats_name, token, sizeof(info->stats_name)); + } +} + +/* + * nssinfo_stats_info_init() + * Init 'struct nssinfo_stats_info' from a file in /sys/kernel/debug/qca-nss-drv/strings/. + */ +int nssinfo_stats_info_init(struct nssinfo_stats_info *info, char *strings_file) +{ + FILE *fptr; + char line[NSS_STATS_MAX_STR_LENGTH]; + + fptr = fopen(strings_file, "r"); + if (!fptr) { + nssinfo_error("Unable to open\n"); + return -1; + } + + while (fgets(line, NSS_STATS_MAX_STR_LENGTH, fptr)) { + nssinfo_parse_stats_strings(info, line); + info++; + } + fclose(fptr); + + return 0; +} + +/* + * nssinfo_node_stats_destroy() + * Release memories used to store the node stats. + */ +void nssinfo_node_stats_destroy(pthread_mutex_t *mutex, uint32_t core_id, uint32_t if_num) +{ + struct node *p, *next; + + if (mutex) { + pthread_mutex_lock(mutex); + } + + p = nodes[core_id][if_num]; + nodes[core_id][if_num] = NULL; + + if (mutex) { + pthread_mutex_unlock(mutex); + } + + while (p) { + next = p->next; + + if (p->cmn_node_stats) { + free(p->cmn_node_stats); + } + + if (p->node_stats) { + free(p->node_stats); + } + + if (p->exception_stats) { + free(p->exception_stats); + } + + free(p); + + p = next; + } + + return; +} + +/* + * nssinfo_add_comma() + * Add commas in thousand's place in statistics. + */ +static char* nssinfo_add_comma(uint64_t num) +{ + if (num < 1000) { + snprintf(buf, sizeof(buf), "%llu", num); + return buf; + } + + nssinfo_add_comma(num/1000); + snprintf(buf + strlen(buf), sizeof(buf[NSSINFO_STR_LEN] + strlen(buf)), ",%03llu", num % 1000); + return buf; +} + +/* + * nssinfo_add_suffix() + * Convert number into K thousands M million and B billion suffix. + */ +static char* nssinfo_add_suffix(uint64_t num) +{ + if (num < 1000) { + snprintf(buf, sizeof(buf), "%llu", num); + return buf; + } + + if (1000 <= num && num < 1000000) { + snprintf(buf , sizeof(buf), "%.2lfK", num / 1000.0); + return buf; + } + + if (1000000 <= num && num < 1000000000) { + snprintf(buf , sizeof(buf), "%.2lfM", num / 1000000.0); + return buf; + } + + if (1000000000 <= num) { + snprintf(buf , sizeof(buf), "%.2lfB", num / 1000000000.0); + return buf; + } + + return buf; +} + +/* + * nssinfo_format_stats() + * Format statistics value. + */ +char* nssinfo_format_stats(uint64_t num) +{ + memset(buf, 0, sizeof(buf)); + if (!arguments.higher_unit) { + return nssinfo_add_comma(num); + } + + return nssinfo_add_suffix(num); +} + +/* + * nssinfo_stats_display() + * Invoke each sub-system's display function. + */ +static void *nssinfo_stats_display(void *arg) +{ + int i, j, core; + char mesg[]="NSS STATS"; + + pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); + + for (;;) { + nssinfo_stats_print("\t\t\t%s\n", mesg); + + /* + * If user does not specify a core id, + * check if the flow file is specified and display stats accordingly. + */ + if (arguments.core < 0) { + /* + * If flow file is not specified (via '-f' option), + * display each node's summary stats in alphabetical order for all the cores. + */ + if (!flow_file) { + for (core = 0 ; core < NSS_MAX_CORES ; core++) { + nssinfo_stats_print("Stats for core %d\n",core); + nssinfo_print_summary_header(); + for (i = 0 ; i < NSS_NLCMN_SUBSYS_MAX; i++) { + if (nssinfo_subsystem_array[i].is_inited && i != NSS_NLCMN_SUBSYS_DYNAMIC_INTERFACE) { + nssinfo_subsystem_array[i].display(core, NULL); + } + } + nssinfo_stats_print("\n"); + } + + goto done; + } + + /* + * Flow file is specified (via '-f' option), + * Parse the network graph from flow file and display the node's summary stats + * For example, the network graph would look like + * ipv4-0 eth_rx-0 n2h-1 + * Where, node = ipv4 , core = 0 + * node = eth_rx , core = 0 + * node = n2h , core = 1 + */ + char *line = NULL; + char *rest = NULL; + size_t len = 0; + ssize_t read; + char *node = NULL; + int matched = 0; + + nssinfo_print_summary_header(); + fseek(flow_file, 0, SEEK_SET); + while ((read = getline(&line, &len, flow_file)) != -1) { + node = strtok_r(line, "-", &rest); + + while (node != NULL) { + core = atoi(strtok_r(NULL, " ", &rest)); + if (core >= NSS_MAX_CORES || core < 0) { + printf("Invalid core id `%d'\n", core); + exit(-1); + } + + for (j = 0; j < NSS_NLCMN_SUBSYS_MAX; j++) { + if (nssinfo_subsystem_array[j].is_inited && + strstr(node, nssinfo_subsystem_array[j].subsystem_name)) { + if (j != NSS_NLCMN_SUBSYS_DYNAMIC_INTERFACE) { + ++matched; + nssinfo_subsystem_array[j].display(core, node); + } + } + } + + node = strtok_r(NULL, "-", &rest); + } + + /* If all NODE names are invalid */ + if (matched == invalid_input) { + nssinfo_error("Invalid input\n"); + return NULL; + } + } + + if (line) { + free(line); + } + + goto done; + } + + if (!arguments.strings[0]) { + /* + * If a core id is specified (via '-c' option) but NODE is not specified, + * display each node's summary stats in alphabetical order for that core. + */ + nssinfo_stats_print("Stats for core %d\n", arguments.core); + nssinfo_print_summary_header(); + for (i = 0 ; i < NSS_NLCMN_SUBSYS_MAX; i++) { + if (nssinfo_subsystem_array[i].is_inited && i != NSS_NLCMN_SUBSYS_DYNAMIC_INTERFACE) { + nssinfo_subsystem_array[i].display(arguments.core, NULL); + } + } + + goto done; + } + + /* + * If a core id is specified and at least one NODE is specified. + */ + nssinfo_stats_print("Stats for core %d\n", arguments.core); + + /* + * If user specifies only one NODE, then display all stats for this NODE. + * For example, if NODE="ipv4", then display: + * - common stats (i.e. enum nss_stats_node) + * - ipv4 special stats (i.e. enum nss_ipv4_stats_types) + * - ipv4 exception stats (i.e. enum nss_ipv4_exception_events) + */ + if (!arguments.strings[1]) { + display_all_stats = true; + } else { + /* + * If user specifies more than one NODEs, then display the summary stats for each node + */ + nssinfo_print_summary_header(); + } + + /* + * Now, display NODEs in the desired order. + */ + int matched = 0; + for (i = 0; arguments.strings[i]; i++) { + for (j = 0; j < NSS_NLCMN_SUBSYS_MAX; j++) { + if (nssinfo_subsystem_array[j].is_inited && + strstr(arguments.strings[i], nssinfo_subsystem_array[j].subsystem_name)) { + if (j != NSS_NLCMN_SUBSYS_DYNAMIC_INTERFACE) { + ++matched; + nssinfo_subsystem_array[j].display(arguments.core, arguments.strings[i]); + } + } + + } + } + + /* + * If all NODE names are invalid. + */ + if (matched == invalid_input) { + nssinfo_error("Invalid input\n"); + return NULL; + } +done: + /* + * If using ncurses, refresh the screen. + */ + if (!output_file) { + refresh(); /* draw on screen */ + clear(); /* clear screen buffer */ + move(0, 0); /* move cursor to (line, column)=(0,0) */ + } + + invalid_input = 0; + sleep(arguments.rate); + } +} + +/* + * nssinfo_curses_init() + * Initialize curses library. + */ +static int nssinfo_curses_init() +{ + int rows, cols; + + if (!initscr()) { /* satrt curses mode */ + nssinfo_error("Unable to initialize curses screen\n"); + return -EOPNOTSUPP; + } + + getmaxyx(stdscr, rows, cols); /* get the size of the screen */ + if (rows < CURSES_ROWS_MIN) { + nssinfo_error("Screen must be at least %d rows in height", CURSES_ROWS_MIN); + goto out; + } + if (cols < CURSES_COLS_MIN) { + nssinfo_error("Screen must be at least %d columns width", CURSES_COLS_MIN); + goto out; + } + + cbreak(); /* disable line buffering */ + noecho(); /* not to echo the input back to the screen */ + nonl(); /* disable 'enter' key translation */ + keypad(stdscr, TRUE); /* enable keypad keys, such as arrow keys, etc. */ + nodelay(stdscr, TRUE); /* cause getch() to be a non-blocking call */ + curs_set(0); /* make the cursor invisible */ + clear(); /* clear screen buffer */ + move(0, 0); /* move cursor to (line, column)=(0,0) */ + return 0; + +out: + endwin(); /* stop curses mode */ + return -1; +} + +/* + * nssinfo_termination_handler() + * Terminates all the modules. + */ +static void nssinfo_termination_handler(int signum) +{ + pthread_cancel(nssinfo_display_thread); +} + +/* + * nssinfo_display_init() + * Handle displaying all the stats. + */ +static int nssinfo_display_init() +{ + int error; + + if (!output_file) { + if (nssinfo_curses_init() != 0) { + return -1; + } + } + + error = pthread_create(&nssinfo_display_thread, NULL, nssinfo_stats_display, NULL); + if (error) { + nssinfo_error("failed to create display thread, error %d\n", error); + if (!output_file) { + endwin(); + } + } + + return error; +} + +/* + * nssinfo_display_wait() + * Wait for the display thread. + */ +static int nssinfo_display_wait() +{ + /* + * waiting for the display thread to be terminated. + */ + pthread_join(nssinfo_display_thread, NULL); + + if (!output_file) { + refresh(); + endwin(); + } + + return 0; +} + +/* + * nssinfo_notify_callback + * Get notified when NL message is received. + */ +static void nssinfo_notify_callback(int cmd, void *data) +{ + if (cmd < NSS_NLCMN_SUBSYS_MAX && nssinfo_subsystem_array[cmd].is_inited) { + nssinfo_subsystem_array[cmd].notify(data); + } else { + nssinfo_error("Unknown message type %d\n", cmd); + } +} + +/* + */ +static void nssinfo_deinit(struct nss_nlmcast_ctx *ctx) +{ + int i, core; + struct node *node; + nssinfo_deinit_t deinit; + + /* + * Close NL socket and terminate ctx->sock.thread + */ + nss_nlmcast_sock_close(ctx); + + /* + * Release memory used for storing stats + */ + for (core = 0; core < NSS_MAX_CORES; ++core) { + for (i = 0; i < NSS_MAX_NET_INTERFACES; ++i) { + node = nodes[core][i]; + if (node) { + assert(node->subsystem_id != NSS_NLCMN_SUBSYS_DYNAMIC_INTERFACE); + nssinfo_subsystem_array[node->subsystem_id].destroy(core, i); + } + } + } + + /* + * Release resources used by each subsystem + */ + for (i = 0; i < NSS_NLCMN_SUBSYS_MAX; i++) { + deinit = nssinfo_subsystem_array[i].deinit; + if (deinit) { + deinit(ctx); + } + } +} + +/* + * nssinfo_init() + * Initialize all the modules. + */ +int nssinfo_init(void) +{ + int error, i; + struct nss_nlmcast_ctx ctx; + nssinfo_init_t init; + + memset(&ctx, 0, sizeof(ctx)); + + /* + * Create NL socket + */ + error = nss_nlmcast_sock_open(&ctx, nssinfo_notify_callback, NULL); + if (error) { + nssinfo_error("Socket creation failed for NSSINFO, error(%d)\n", error); + return error; + } + + /* + * Initialize all the subsystems and subscribe for mcast groups. + */ + for (i = 0; i < NSS_NLCMN_SUBSYS_MAX; i++) { + init = nssinfo_subsystem_array[i].init; + if (init) { + error = init(&ctx); + if (error) { + nssinfo_error("%s init failed, error(%d)\n", nssinfo_subsystem_array[i].subsystem_name, error); + } + } + } + + /* + * Listen for MCAST events from kernel. + */ + error = nss_nlmcast_sock_listen(&ctx); + if (error < 0) { + nssinfo_error("failed to listen for mcast events from kernel\n"); + goto end; + } + + /* + * Create a thread which displays the stats continuously. + */ + error = nssinfo_display_init(); + if (error) { + goto end; + } + + /* + * Install CTRL-C handler + */ + struct sigaction new_action; + new_action.sa_handler = nssinfo_termination_handler; + sigemptyset(&new_action.sa_mask); + new_action.sa_flags = 0; + error = sigaction(SIGINT, &new_action, NULL); + if (error) { + nssinfo_error("failed to install CTRL-C handler\n"); + goto end; + } + + /* + * main thread is waiting here + */ + nssinfo_display_wait(); + +end: + nssinfo_deinit(&ctx); + return error; +} diff --git a/qca/nss-userspace-oss/nssinfo/src/src/nssinfo.h b/qca/nss-userspace-oss/nssinfo/src/src/nssinfo.h new file mode 100644 index 0000000..6a3d10b --- /dev/null +++ b/qca/nss-userspace-oss/nssinfo/src/src/nssinfo.h @@ -0,0 +1,233 @@ +/* + ************************************************************************** + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +#ifndef __NSSINFO_FAMILY_H +#define __NSSINFO_FAMILY_H + +#include "nss_nlbase.h" +#include "ncurses.h" +#include "nssinfo_ipv4.h" +#include "nssinfo_ipv6.h" +#include "nssinfo_ethrx.h" +#include "nssinfo_n2h.h" +#include "nssinfo_dynamic_interface.h" +#include "nssinfo_lso_rx.h" +#include "nss_api_if.h" +#include "nss_dynamic_interface.h" +#include "nss_stats_public.h" + +#define NSSINFO_COLOR_RST "\x1b[0m" +#define NSSINFO_COLOR_GRN "\x1b[32m" +#define NSSINFO_COLOR_RED "\x1b[31m" +#define NSSINFO_COLOR_MGT "\x1b[35m" + +#ifdef ENABLE_DEBUG +#define nssinfo_info(fmt, arg...) printf(NSSINFO_COLOR_GRN"INF "NSSINFO_COLOR_RST fmt, ## arg) +#define nssinfo_trace(fmt, arg...) printf(NSSINFO_COLOR_MGT"TRC(%s:%d) "NSSINFO_COLOR_RST fmt, __func__, __LINE__, ## arg) +#define nssinfo_options(fmt, arg...) printf(NSSINFO_COLOR_MGT"OPT_%d "NSSINFO_COLOR_RST fmt, ## arg) +#define nssinfo_warn(fmt, arg...) printf(NSSINFO_COLOR_RED"WARN(%s:%d) "NSSINFO_COLOR_RST fmt, __func__, __LINE__, ##arg) +#else +#define nssinfo_info(fmt, arg...) +#define nssinfo_trace(fmt, arg...) +#define nssinfo_options(fmt, arg...) +#define nssinfo_warn(fmt, arg...) +#endif +#define nssinfo_error(fmt, arg...) printf(NSSINFO_COLOR_RED"ERR(%s:%d) "NSSINFO_COLOR_RST fmt, __func__, __LINE__, ## arg) + +#define nssinfo_stats_print(fmt, arg...) ({ \ + if (output_file) { \ + fprintf(output_file, fmt, ## arg); \ + } else { \ + wprintw(stdscr, fmt, ## arg); \ + } \ + }) +/* + * Minimum terminal size to use curses library + */ +#define CURSES_ROWS_MIN 4 +#define CURSES_COLS_MIN 48 + +/* + * Maximum formatted statistics length + */ +#define NSSINFO_STR_LEN 30 + +extern bool display_all_stats; +extern FILE *output_file; +extern FILE *flow_file; +extern int invalid_input; +extern struct arguments arguments; +extern char *nssinfo_summary_fmt; + +/** + * @brief display method_t function + * + * @param core[IN] NSS core id + */ +typedef void (*nssinfo_stats_display_t)(int core, char *input); + +/** + * @brief stats notify method_t function + * + * @param data[IN] data received from Netlink client + */ +typedef void (*nssinfo_stats_notify_t)(void *data); + +/** + * @brief init method_t function + * + * @param data[IN] an opague context to be used for initialization + */ +typedef int (*nssinfo_init_t)(void *data); + +/** + * @brief deinit method_t function + * + * @param data[IN] an opague context to be used for deinitialization + */ +typedef void (*nssinfo_deinit_t)(void *data); + +/** + * @brief destroy method_t function + * + * @param core_id[IN] core id of the node to be destroyed + * @param if_num[IN] interface id of the node to be destroyed + */ +typedef void (*nssinfo_destroy_t)(uint32_t core_id, uint32_t if_num); + +/** + * @brief Used by main to communicate with parse_opt + */ +struct arguments { + bool verbose; /*< '-v' >*/ + char *output_file; /*< file arg to '--output' >*/ + char *flow_file; /*< file arg to '--flowfile' >*/ + bool higher_unit; /*< display higher units '-h' >*/ + int core; /*< core id >*/ + char **strings; /*< non-option arguments: [NODE1 [NODE2 ...]] >*/ + int rate; /*< display rate in second >*/ +}; + +/** + * @brief NSSINFO subsystem information + */ +struct nssinfo_subsystem_info { + char *subsystem_name; /**< Subsystem name string */ + nssinfo_init_t init; /**< Initialize method_t */ + nssinfo_deinit_t deinit; /**< Deinitialize method_t */ + nssinfo_stats_display_t display; /**< Display method_t */ + nssinfo_stats_notify_t notify; /**< Stats notify method_t */ + nssinfo_destroy_t destroy; /**< Stats notify method_t */ + bool is_inited; /**< True if the subsystem is initialized */ +}; + +extern struct nssinfo_subsystem_info nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_MAX]; + +/** + * @brief NSSINFO pnode stats + */ +struct node { + struct node *next; /**< Pointer to next node */ + uint64_t id; /**< Dynamic interface number */ + int type; /**< see 'enum nss_dynamic_interface_type' */ + int subsystem_id; /**< see 'enum nss_nlcmn_subsys' */ + void *cmn_node_stats; /**< Common node stats */ + void *node_stats; /**< Special stats */ + void *exception_stats; /**< Exception stats */ +}; + +extern struct node *nodes[NSS_MAX_CORES][NSS_MAX_NET_INTERFACES]; + +/** + * @brief Structure definition carrying stats info. + */ +struct nssinfo_stats_info { + char stats_name[NSS_STATS_MAX_STR_LENGTH]; /* stat name */ + int stats_type; /* enum that tags stat type */ +}; + +/** + * @brief validates core id and interface number + * + * @param core_id[IN] validates the core d + * @param if_num[IN] validates the interface number + * + * @return true on success or false for failure + */ +static inline bool nssinfo_coreid_ifnum_valid(uint32_t core_id, uint32_t if_num) +{ + return (core_id < NSS_MAX_CORES && if_num < NSS_MAX_NET_INTERFACES); +} + +/** + * @brief initialize all the modules + * + * @param flow_file[IN] parse it and display output accordingly + * + * @return 0 on success or -ve for failure + */ +int nssinfo_init(void); + +/** + * @brief Format statistics value + * + * @param num[IN] statistics value in uint64_t + * + * @return comma separated string + */ +char* nssinfo_format_stats(uint64_t num); + +/** + * @brief Init nssinfo_stats_info from kernel debug file. + * + * @param info[IN] pointer to a nssinfo_stats_info array + * @param line[IN] string file in kernel/debug/qca-nss-drv/strings/ + */ +int nssinfo_stats_info_init(struct nssinfo_stats_info *info, char *strings_file); + +/** + * @brief Free all resources used for node stats. + * + * @param mutex[IN] mutex lock + * @param core_id[IN] core id + * @param if_num[IN] node's interface number + */ +void nssinfo_node_stats_destroy(pthread_mutex_t *mutex, uint32_t core_id, uint32_t if_num); + +/** + * @brief Print detailed statistics. + * + * @param node[IN] node for which stats to be printed + * @param stat_details[IN] statistics details to be printed + * @param stats_info[IN] statistics information + * @param max[IN] maximum number of strings + * @param stats_val[IN] statistics values + */ +void nssinfo_print_all(char *node, char *stat_details, struct nssinfo_stats_info *stats_info, uint64_t max, uint64_t *stats_val); + +/** + * @brief Print the summary of the statistics. + * + * @param node[IN] node for which stats to be printed + * @param cmn_node_stats[IN] common node stats + * @param exception_stats[IN] exception stats + * @param exception_max[IN] maximum exception type + */ +void nssinfo_print_summary(char *node, uint64_t *cmn_node_stats, uint64_t *exception_stats, uint64_t exception_max); + +void nssinfo_print_summary_header(void); + +#endif /* __NSSINFO_FAMILY_H*/ diff --git a/qca/nss-userspace-oss/nssinfo/src/src/nssinfo_dynamic_interface.c b/qca/nss-userspace-oss/nssinfo/src/src/nssinfo_dynamic_interface.c new file mode 100644 index 0000000..3d3c412 --- /dev/null +++ b/qca/nss-userspace-oss/nssinfo/src/src/nssinfo_dynamic_interface.c @@ -0,0 +1,72 @@ +/* + ************************************************************************** + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +/* + * @file NSSINFO dynamic interface handler + */ +#include "nssinfo.h" +#include + +/* + * nssinfo_dynamic_interface_destroy_notify() + * Dynamic interface notify callback function. + */ +static void nssinfo_dynamic_interface_destroy_notify(void *data) +{ + struct nss_dynamic_interface_notification *nss_info = (struct nss_dynamic_interface_notification *)data; + struct node *node = nodes[nss_info->core_id][nss_info->if_num]; + + if (!node) { + return; + } + + nssinfo_subsystem_array[node->subsystem_id].destroy(nss_info->core_id, nss_info->if_num); +} + +/* + * nssinfo_dynamic_interface_deinit() + * Deinitialize dynamic_interface module. + */ +void nssinfo_dynamic_interface_deinit(void *data) +{ + struct nss_nlmcast_ctx *ctx = (struct nss_nlmcast_ctx *)data; + + nss_nlmcast_sock_leave_grp(ctx, NSS_NLDYNAMIC_INTERFACE_MCAST_GRP); +} + +/* + * nssinfo_dynamic_interface_init() + * Initialize dynamic interface module. + */ +int nssinfo_dynamic_interface_init(void *data) +{ + int error; + struct nss_nlmcast_ctx *ctx = (struct nss_nlmcast_ctx *)data; + + /* + * Subscribe for dynamic interface multicast group. + */ + nss_nlsock_set_family(&ctx->sock, NSS_NLDYNAMIC_INTERFACE_FAMILY); + error = nss_nlmcast_sock_join_grp(ctx, NSS_NLDYNAMIC_INTERFACE_MCAST_GRP); + if (error) { + nssinfo_warn("Unable to join dynamic interface multicast group.\n"); + return error; + } + + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_DYNAMIC_INTERFACE].notify = nssinfo_dynamic_interface_destroy_notify; + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_DYNAMIC_INTERFACE].is_inited = true; + return 0; +} diff --git a/qca/nss-userspace-oss/nssinfo/src/src/nssinfo_dynamic_interface.h b/qca/nss-userspace-oss/nssinfo/src/src/nssinfo_dynamic_interface.h new file mode 100644 index 0000000..6e33fa1 --- /dev/null +++ b/qca/nss-userspace-oss/nssinfo/src/src/nssinfo_dynamic_interface.h @@ -0,0 +1,28 @@ +/* + ************************************************************************** + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +#ifndef __NSSINFO_DYNAMIC_INTERFACE_H +#define __NSSINFO_DYNAMIC_INTERFACE_H + +/** + * @brief initialize dynamic interface module. + * + * @return 0 on success or -ve for failure + */ +int nssinfo_dynamic_interface_init(void *data); +void nssinfo_dynamic_interface_deinit(void *data); + +#endif /* __NSSINFO_DYNAMIC_INTERFACE_H*/ diff --git a/qca/nss-userspace-oss/nssinfo/src/src/nssinfo_ethrx.c b/qca/nss-userspace-oss/nssinfo/src/src/nssinfo_ethrx.c new file mode 100644 index 0000000..5b80c15 --- /dev/null +++ b/qca/nss-userspace-oss/nssinfo/src/src/nssinfo_ethrx.c @@ -0,0 +1,215 @@ +/* + ************************************************************************** + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +/* + * @file NSSINFO Ethernet Rx handler + */ +#include "nssinfo.h" +#include +#include + +static pthread_mutex_t eth_rx_lock; +static struct nssinfo_stats_info nss_eth_rx_cmn_stats_str[NSS_STATS_NODE_MAX]; +static struct nssinfo_stats_info nss_eth_rx_stats_str[NSS_ETH_RX_STATS_MAX]; +static struct nssinfo_stats_info nss_eth_rx_exception_stats_str[NSS_ETH_RX_EXCEPTION_EVENT_MAX]; + +/* + * nssinfo_eth_rx_stats_display() + * Ethernet Rx display callback function. + */ +static void nssinfo_eth_rx_stats_display(int core, char *input) +{ + struct node *eth_rx_node; + + if (input && strncmp(input, nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_ETHRX].subsystem_name, strlen(input))) { + ++invalid_input; + nssinfo_trace("Invalid node name: %s\n", input); + return; + } + + pthread_mutex_lock(ð_rx_lock); + eth_rx_node = nodes[core][NSS_ETH_RX_INTERFACE]; + if (!eth_rx_node) { + pthread_mutex_unlock(ð_rx_lock); + return; + } + + if (!display_all_stats) { + nssinfo_print_summary("eth_rx", (uint64_t *)eth_rx_node->cmn_node_stats, (uint64_t *)eth_rx_node->exception_stats, NSS_ETH_RX_EXCEPTION_EVENT_MAX); + pthread_mutex_unlock(ð_rx_lock); + return; + } + + nssinfo_print_all("eth_rx", "eth_rx Common Stats", nss_eth_rx_cmn_stats_str, NSS_STATS_NODE_MAX, (uint64_t *)eth_rx_node->cmn_node_stats); + nssinfo_print_all("eth_rx", "eth_rx Special Stats", nss_eth_rx_stats_str, NSS_ETH_RX_STATS_MAX, (uint64_t *)eth_rx_node->node_stats); + nssinfo_print_all("eth_rx", "eth_rx Exception Stats", nss_eth_rx_exception_stats_str, NSS_ETH_RX_EXCEPTION_EVENT_MAX, (uint64_t *)eth_rx_node->exception_stats); + + pthread_mutex_unlock(ð_rx_lock); +} + +/* + * nssinfo_eth_rx_stats_notify() + * Ethernet Rx statistics notify callback function. + */ +static void nssinfo_eth_rx_stats_notify(void *data) +{ + uint64_t *cmn_node_stats, *node_stats, *exception_stats; + struct nss_eth_rx_stats_notification *nss_stats = (struct nss_eth_rx_stats_notification *)data; + struct node *eth_rx_node; + struct node **eth_rx_ptr; + + if (!nssinfo_coreid_ifnum_valid(nss_stats->core_id, NSS_ETH_RX_INTERFACE)) { + return; + } + + pthread_mutex_lock(ð_rx_lock); + eth_rx_ptr = &nodes[nss_stats->core_id][NSS_ETH_RX_INTERFACE]; + eth_rx_node = *eth_rx_ptr; + if (eth_rx_node) { + memcpy(eth_rx_node->cmn_node_stats, &nss_stats->cmn_node_stats, sizeof(nss_stats->cmn_node_stats)); + memcpy(eth_rx_node->node_stats, &nss_stats->special_stats, sizeof(nss_stats->special_stats)); + memcpy(eth_rx_node->exception_stats, &nss_stats->exception_stats, sizeof(nss_stats->exception_stats)); + pthread_mutex_unlock(ð_rx_lock); + return; + } + pthread_mutex_unlock(ð_rx_lock); + + eth_rx_node = (struct node *)calloc(1, sizeof(struct node)); + if (!eth_rx_node) { + nssinfo_warn("Failed to allocate memory for eth rx node\n"); + return; + } + + cmn_node_stats = (uint64_t *)malloc(sizeof(nss_stats->cmn_node_stats)); + if (!cmn_node_stats) { + nssinfo_warn("Failed to allocate memory for eth rx common node statistics\n"); + goto eth_rx_node_free; + } + + node_stats = (uint64_t *)malloc(sizeof(nss_stats->special_stats)); + if (!node_stats) { + nssinfo_warn("Failed to allocate memory for eth rx special stats\n"); + goto cmn_node_stats_free; + } + + exception_stats = (uint64_t *)malloc(sizeof(nss_stats->exception_stats)); + if (!exception_stats) { + nssinfo_warn("Failed to allocate memory for eth rx exception stats\n"); + goto node_stats_free; + } + + memcpy(cmn_node_stats, &nss_stats->cmn_node_stats, sizeof(nss_stats->cmn_node_stats)); + memcpy(node_stats, &nss_stats->special_stats, sizeof(nss_stats->special_stats)); + memcpy(exception_stats, &nss_stats->exception_stats, sizeof(nss_stats->exception_stats)); + eth_rx_node->cmn_node_stats = cmn_node_stats; + eth_rx_node->node_stats = node_stats; + eth_rx_node->exception_stats = exception_stats; + eth_rx_node->subsystem_id = NSS_NLCMN_SUBSYS_ETHRX; + + /* + * Notifify is guaranteed to be single threaded via Netlink listen callback + */ + pthread_mutex_lock(ð_rx_lock); + nodes[nss_stats->core_id][NSS_ETH_RX_INTERFACE] = eth_rx_node; + pthread_mutex_unlock(ð_rx_lock); + return; + +node_stats_free: + free(node_stats); + +cmn_node_stats_free: + free(cmn_node_stats); + +eth_rx_node_free: + free(eth_rx_node); + return; +} + +/* + * nssinfo_eth_rx_destroy() + * Destroy ethernet Rx node. + */ +static void nssinfo_eth_rx_destroy(uint32_t core_id, uint32_t if_num) +{ + if (nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_ETHRX].is_inited) { + nssinfo_node_stats_destroy(ð_rx_lock, core_id, NSS_ETH_RX_INTERFACE); + } +} + +/* + * nssinfo_ethrx_deinit() + * Deinitialize ethrx module. + */ +void nssinfo_eth_rx_deinit(void *data) +{ + struct nss_nlmcast_ctx *ctx = (struct nss_nlmcast_ctx *)data; + + if (nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_ETHRX].is_inited) { + pthread_mutex_destroy(ð_rx_lock); + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_ETHRX].is_inited = false; + } + + nss_nlmcast_sock_leave_grp(ctx, NSS_NLETHRX_MCAST_GRP); +} + +/* + * nssinfo_eth_rx_init() + * Initialize Ethernet Rx module. + */ +int nssinfo_eth_rx_init(void *data) +{ + int error; + struct nss_nlmcast_ctx *ctx = (struct nss_nlmcast_ctx *)data; + + /* + * Subscribe for Ethernet Rx MCAST group. + */ + nss_nlsock_set_family(&ctx->sock, NSS_NLETHRX_FAMILY); + error = nss_nlmcast_sock_join_grp(ctx, NSS_NLETHRX_MCAST_GRP); + if (error) { + nssinfo_warn("Unable to join Ethernet Rx mcast group.\n"); + return error; + } + + if (nssinfo_stats_info_init(nss_eth_rx_cmn_stats_str, + "/sys/kernel/debug/qca-nss-drv/strings/common_node_stats") != 0) { + goto fail; + } + + if (nssinfo_stats_info_init(nss_eth_rx_stats_str, + "/sys/kernel/debug/qca-nss-drv/strings/eth_rx/special_stats_str") != 0) { + goto fail; + } + + if (nssinfo_stats_info_init(nss_eth_rx_exception_stats_str, + "/sys/kernel/debug/qca-nss-drv/strings/eth_rx/exception_stats_str") != 0) { + goto fail; + } + + if (pthread_mutex_init(ð_rx_lock, NULL) != 0) { + nssinfo_warn("Mutex init has failed for Ethernet Rx\n"); + goto fail; + } + + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_ETHRX].display = nssinfo_eth_rx_stats_display; + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_ETHRX].notify = nssinfo_eth_rx_stats_notify; + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_ETHRX].destroy = nssinfo_eth_rx_destroy; + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_ETHRX].is_inited = true; + return 0; +fail: + nss_nlmcast_sock_leave_grp(ctx, NSS_NLETHRX_MCAST_GRP); + return -1; +} diff --git a/qca/nss-userspace-oss/nssinfo/src/src/nssinfo_ethrx.h b/qca/nss-userspace-oss/nssinfo/src/src/nssinfo_ethrx.h new file mode 100644 index 0000000..e1261f7 --- /dev/null +++ b/qca/nss-userspace-oss/nssinfo/src/src/nssinfo_ethrx.h @@ -0,0 +1,28 @@ +/* + ************************************************************************** + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +#ifndef __NSSINFO_ETHRX_H +#define __NSSINFO_ETHRX_H + +/** + * @brief initialize Ethernet Rx module. + * + * @return 0 on success or -ve for failure + */ +int nssinfo_eth_rx_init(void *data); +void nssinfo_eth_rx_deinit(void *data); + +#endif /* __NSSINFO_ETHRX_H*/ diff --git a/qca/nss-userspace-oss/nssinfo/src/src/nssinfo_ipv4.c b/qca/nss-userspace-oss/nssinfo/src/src/nssinfo_ipv4.c new file mode 100644 index 0000000..83e8386 --- /dev/null +++ b/qca/nss-userspace-oss/nssinfo/src/src/nssinfo_ipv4.c @@ -0,0 +1,215 @@ +/* + ************************************************************************** + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +/* + * @file NSSINFO ipv4 handler + */ +#include "nssinfo.h" + +static pthread_mutex_t ipv4_lock; +static struct nssinfo_stats_info nss_stats_str_node[NSS_STATS_NODE_MAX]; +static struct nssinfo_stats_info nss_ipv4_stats_str[NSS_IPV4_STATS_MAX]; +static struct nssinfo_stats_info nss_ipv4_exception_stats_str[NSS_IPV4_EXCEPTION_EVENT_MAX]; + +/* + * nssinfo_ipv4_stats_display() + * IPv4 display callback function. + */ +static void nssinfo_ipv4_stats_display(int core, char *input) +{ + struct node *ipv4_node; + + if (input && strncmp(input, nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_IPV4].subsystem_name, strlen(input)) != 0) { + ++invalid_input; + nssinfo_trace("Invalid node name: %s\n", input); + return; + } + + pthread_mutex_lock(&ipv4_lock); + ipv4_node = nodes[core][NSS_IPV4_RX_INTERFACE]; + if (!ipv4_node) { + pthread_mutex_unlock(&ipv4_lock); + return; + } + + if (!display_all_stats) { + nssinfo_print_summary("ipv4", (uint64_t *)ipv4_node->cmn_node_stats, (uint64_t *)ipv4_node->exception_stats, NSS_IPV4_EXCEPTION_EVENT_MAX); + pthread_mutex_unlock(&ipv4_lock); + return; + } + + nssinfo_print_all("ipv4", "ipv4 Common Stats", nss_stats_str_node, NSS_STATS_NODE_MAX, (uint64_t *)ipv4_node->cmn_node_stats); + nssinfo_print_all("ipv4", "ipv4 Special Stats", nss_ipv4_stats_str, NSS_IPV4_STATS_MAX, (uint64_t *)ipv4_node->node_stats); + nssinfo_print_all("ipv4", "ipv4 Exception Stats", nss_ipv4_exception_stats_str, NSS_IPV4_EXCEPTION_EVENT_MAX, (uint64_t *)ipv4_node->exception_stats); + + pthread_mutex_unlock(&ipv4_lock); +} + +/* + * nssinfo_ipv4_stats_notify() + * IPv4 stats notify callback function. + */ +static void nssinfo_ipv4_stats_notify(void *data) +{ + uint64_t *cmn_node_stats, *node_stats, *exception_stats; + struct nss_nlipv4_rule *rule = (struct nss_nlipv4_rule *)data; + struct node *ipv4_node; + struct node **ipv4_ptr; + + if (!nssinfo_coreid_ifnum_valid(rule->stats.core_id, NSS_IPV4_RX_INTERFACE)) { + return; + } + + ipv4_ptr = &nodes[rule->stats.core_id][NSS_IPV4_RX_INTERFACE]; + + pthread_mutex_lock(&ipv4_lock); + ipv4_node = *ipv4_ptr; + if (ipv4_node) { + memcpy(ipv4_node->cmn_node_stats, &rule->stats.cmn_node_stats, sizeof(rule->stats.cmn_node_stats)); + memcpy(ipv4_node->node_stats, &rule->stats.special_stats, sizeof(rule->stats.special_stats)); + memcpy(ipv4_node->exception_stats, &rule->stats.exception_stats, sizeof(rule->stats.exception_stats)); + pthread_mutex_unlock(&ipv4_lock); + return; + } + pthread_mutex_unlock(&ipv4_lock); + + ipv4_node = (struct node *)calloc(1, sizeof(struct node)); + if (!ipv4_node) { + nssinfo_warn("Failed to allocate memory for ipv4 node\n"); + return; + } + + cmn_node_stats = (uint64_t *)malloc(sizeof(rule->stats.cmn_node_stats)); + if (!cmn_node_stats) { + nssinfo_warn("Failed to allocate memory for ipv4 common node stats\n"); + goto ipv4_node_free; + } + + node_stats = (uint64_t *)malloc(sizeof(rule->stats.special_stats)); + if (!node_stats) { + nssinfo_warn("Failed to allocate memory for ipv4 special stats\n"); + goto cmn_node_stats_free; + } + + exception_stats = (uint64_t *)malloc(sizeof(rule->stats.exception_stats)); + if (!exception_stats) { + nssinfo_warn("Failed to allocate memory for ipv4 exception stats\n"); + goto node_stats_free; + } + + memcpy(cmn_node_stats, &rule->stats.cmn_node_stats, sizeof(rule->stats.cmn_node_stats)); + memcpy(node_stats, &rule->stats.special_stats, sizeof(rule->stats.special_stats)); + memcpy(exception_stats, &rule->stats.exception_stats, sizeof(rule->stats.exception_stats)); + + ipv4_node->cmn_node_stats = cmn_node_stats; + ipv4_node->node_stats = node_stats; + ipv4_node->exception_stats = exception_stats; + ipv4_node->subsystem_id = NSS_NLCMN_SUBSYS_IPV4; + + /* + * Notifify is guaranteed to be single threaded via Netlink listen callback + */ + pthread_mutex_lock(&ipv4_lock); + *ipv4_ptr = ipv4_node; + pthread_mutex_unlock(&ipv4_lock); + return; + +node_stats_free: + free(node_stats); + +cmn_node_stats_free: + free(cmn_node_stats); + +ipv4_node_free: + free(ipv4_node); +} + +/* + * nssinfo_ipv4_destroy() + * Destroy IPv4 node. + */ +static void nssinfo_ipv4_destroy(uint32_t core_id, uint32_t if_num) +{ + if (nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_IPV4].is_inited) { + nssinfo_node_stats_destroy(&ipv4_lock, core_id, NSS_IPV4_RX_INTERFACE); + } +} + +/* + * nssinfo_ipv4_deinit() + * Initialize IPv4 module. + */ +void nssinfo_ipv4_deinit(void *data) +{ + struct nss_nlmcast_ctx *ctx = (struct nss_nlmcast_ctx *)data; + + if (nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_IPV4].is_inited) { + pthread_mutex_destroy(&ipv4_lock); + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_IPV4].is_inited = false; + } + + nss_nlmcast_sock_leave_grp(ctx, NSS_NLIPV4_MCAST_GRP); +} + +/* + * nssinfo_ipv4_init() + * Initialize IPv4 module. + */ +int nssinfo_ipv4_init(void *data) +{ + int error; + struct nss_nlmcast_ctx *ctx = (struct nss_nlmcast_ctx *)data; + + /* + * Subscribe for IPV4 MCAST group. + */ + nss_nlsock_set_family(&ctx->sock, NSS_NLIPV4_FAMILY); + error = nss_nlmcast_sock_join_grp(ctx, NSS_NLIPV4_MCAST_GRP); + if (error) { + nssinfo_warn("Unable to join IPv4 mcast group\n"); + return error; + } + + if (nssinfo_stats_info_init(nss_stats_str_node, + "/sys/kernel/debug/qca-nss-drv/strings/common_node_stats") != 0) { + goto fail; + } + + if (nssinfo_stats_info_init(nss_ipv4_stats_str, + "/sys/kernel/debug/qca-nss-drv/strings/ipv4/special_stats_str") != 0) { + goto fail; + } + + if (nssinfo_stats_info_init(nss_ipv4_exception_stats_str, + "/sys/kernel/debug/qca-nss-drv/strings/ipv4/exception_stats_str") != 0) { + goto fail; + } + + if (pthread_mutex_init(&ipv4_lock, NULL) != 0) { + nssinfo_warn("Mutex init has failed for IPV4\n"); + goto fail; + } + + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_IPV4].display = nssinfo_ipv4_stats_display; + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_IPV4].notify = nssinfo_ipv4_stats_notify; + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_IPV4].destroy = nssinfo_ipv4_destroy; + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_IPV4].is_inited = true; + return 0; + +fail: + nss_nlmcast_sock_leave_grp(ctx, NSS_NLIPV4_MCAST_GRP); + return -1; +} diff --git a/qca/nss-userspace-oss/nssinfo/src/src/nssinfo_ipv4.h b/qca/nss-userspace-oss/nssinfo/src/src/nssinfo_ipv4.h new file mode 100644 index 0000000..ca29939 --- /dev/null +++ b/qca/nss-userspace-oss/nssinfo/src/src/nssinfo_ipv4.h @@ -0,0 +1,30 @@ +/* + ************************************************************************** + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +#ifndef __NSSINFO_IPV4_H +#define __NSSINFO_IPV4_H + +#define NSSINFO_IPV4_HDR_VERSION 4 + +/** + * @brief initialize IPv4 module. + * + * @return 0 on success or -ve for failure + */ +int nssinfo_ipv4_init(void *data); +void nssinfo_ipv4_deinit(void *data); + +#endif /* __NSSINFO_IPV4_H*/ diff --git a/qca/nss-userspace-oss/nssinfo/src/src/nssinfo_ipv6.c b/qca/nss-userspace-oss/nssinfo/src/src/nssinfo_ipv6.c new file mode 100644 index 0000000..16af31c --- /dev/null +++ b/qca/nss-userspace-oss/nssinfo/src/src/nssinfo_ipv6.c @@ -0,0 +1,212 @@ +/* + ************************************************************************** + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +/* + * @file NSSINFO ipv6 handler + */ +#include "nssinfo.h" + +static pthread_mutex_t ipv6_lock; +static struct nssinfo_stats_info nss_stats_str_node[NSS_STATS_NODE_MAX]; +static struct nssinfo_stats_info nss_ipv6_stats_str[NSS_IPV6_STATS_MAX]; +static struct nssinfo_stats_info nss_ipv6_exception_stats_str[NSS_IPV6_EXCEPTION_EVENT_MAX]; + +/* + * nssinfo_ipv6_stats_display() + * IPv6 display callback function. + */ +static void nssinfo_ipv6_stats_display(int core, char *input) +{ + struct node *ipv6_node; + + if (input && strncmp(input, nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_IPV6].subsystem_name, strlen(input))) { + ++invalid_input; + nssinfo_trace("Invalid node name: %s\n", input); + return; + } + + pthread_mutex_lock(&ipv6_lock); + ipv6_node = nodes[core][NSS_IPV6_RX_INTERFACE]; + if (!ipv6_node) { + pthread_mutex_unlock(&ipv6_lock); + return; + } + + if (display_all_stats) { + nssinfo_print_all("ipv6", "ipv6 Common Stats", nss_stats_str_node, NSS_STATS_NODE_MAX, (uint64_t *)ipv6_node->cmn_node_stats); + nssinfo_print_all("ipv6", "ipv6 Special Stats", nss_ipv6_stats_str, NSS_IPV6_STATS_MAX, (uint64_t *)ipv6_node->node_stats); + nssinfo_print_all("ipv6", "ipv6 Exception Stats", nss_ipv6_exception_stats_str, NSS_IPV6_EXCEPTION_EVENT_MAX, (uint64_t *)ipv6_node->exception_stats); + + pthread_mutex_unlock(&ipv6_lock); + return; + } + + nssinfo_print_summary("ipv6", (uint64_t *)ipv6_node->cmn_node_stats, (uint64_t *)ipv6_node->exception_stats, NSS_IPV6_EXCEPTION_EVENT_MAX); + pthread_mutex_unlock(&ipv6_lock); +} + +/* + * nssinfo_ipv6_stats_notify() + * IPv6 stats notify callback function. + */ +static void nssinfo_ipv6_stats_notify(void *data) +{ + uint64_t *cmn_node_stats, *node_stats, *exception_stats; + struct nss_nlipv6_rule *rule = (struct nss_nlipv6_rule *)data; + struct node *ipv6_node; + struct node **ipv6_ptr; + + if (!nssinfo_coreid_ifnum_valid(rule->stats.core_id, NSS_IPV6_RX_INTERFACE)) { + return; + } + + pthread_mutex_lock(&ipv6_lock); + ipv6_ptr = &nodes[rule->stats.core_id][NSS_IPV6_RX_INTERFACE]; + ipv6_node = *ipv6_ptr; + if (ipv6_node) { + memcpy(ipv6_node->cmn_node_stats, &rule->stats.cmn_node_stats, sizeof(rule->stats.cmn_node_stats)); + memcpy(ipv6_node->node_stats, &rule->stats.special_stats, sizeof(rule->stats.special_stats)); + memcpy(ipv6_node->exception_stats, &rule->stats.exception_stats, sizeof(rule->stats.exception_stats)); + pthread_mutex_unlock(&ipv6_lock); + return; + } + pthread_mutex_unlock(&ipv6_lock); + + ipv6_node = (struct node *)calloc(1, sizeof(struct node)); + if (!ipv6_node) { + nssinfo_warn("Failed to allocate memory for ipv6 node\n"); + return; + } + + cmn_node_stats = (uint64_t *)malloc(sizeof(rule->stats.cmn_node_stats)); + if (!cmn_node_stats) { + nssinfo_warn("Failed to allocate memory for ipv6 common node statistics\n"); + goto ipv6_node_free; + } + + node_stats = (uint64_t *)malloc(sizeof(rule->stats.special_stats)); + if (!node_stats) { + nssinfo_warn("Failed to allocate memory for ipv6 special stats\n"); + goto cmn_node_stats_free; + } + + exception_stats = (uint64_t *)malloc(sizeof(rule->stats.exception_stats)); + if (!exception_stats) { + nssinfo_warn("Failed to allocate memory for ipv6 exception stats\n"); + goto node_stats_free; + } + + memcpy(cmn_node_stats, &rule->stats.cmn_node_stats, sizeof(rule->stats.cmn_node_stats)); + memcpy(node_stats, &rule->stats.special_stats, sizeof(rule->stats.special_stats)); + memcpy(exception_stats, &rule->stats.exception_stats, sizeof(rule->stats.exception_stats)); + ipv6_node->cmn_node_stats = cmn_node_stats; + ipv6_node->node_stats = node_stats; + ipv6_node->exception_stats = exception_stats; + ipv6_node->subsystem_id = NSS_NLCMN_SUBSYS_IPV6; + + /* + * Notifify is guaranteed to be single threaded via Netlink listen callback + */ + pthread_mutex_lock(&ipv6_lock); + *ipv6_ptr = ipv6_node; + pthread_mutex_unlock(&ipv6_lock); + return; + +node_stats_free: + free(node_stats); + +cmn_node_stats_free: + free(cmn_node_stats); + +ipv6_node_free: + free(ipv6_node); +} + +/* + * nssinfo_ipv6_destroy() + * Destroy IPv6 node. + */ +static void nssinfo_ipv6_destroy(uint32_t core_id, uint32_t if_num) +{ + if (nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_IPV6].is_inited) { + nssinfo_node_stats_destroy(&ipv6_lock, core_id, NSS_IPV6_RX_INTERFACE); + } +} + +/* + * nssinfo_ipv6_deinit() + * Deinitialize ipv6 module. + */ +void nssinfo_ipv6_deinit(void *data) +{ + struct nss_nlmcast_ctx *ctx = (struct nss_nlmcast_ctx *)data; + + if (nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_IPV6].is_inited) { + pthread_mutex_destroy(&ipv6_lock); + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_IPV6].is_inited = false; + } + + nss_nlmcast_sock_leave_grp(ctx, NSS_NLIPV6_MCAST_GRP); +} + +/* + * nssinfo_ipv6_init() + * Initialize IPv6 module. + */ +int nssinfo_ipv6_init(void *data) +{ + int error; + struct nss_nlmcast_ctx *ctx = (struct nss_nlmcast_ctx *)data; + + /* + * Subscribe for IPV6 MCAST group. + */ + nss_nlsock_set_family(&ctx->sock, NSS_NLIPV6_FAMILY); + error = nss_nlmcast_sock_join_grp(ctx, NSS_NLIPV6_MCAST_GRP); + if (error) { + nssinfo_warn("Unable to join IPv6 mcast group\n"); + return error; + } + + if (nssinfo_stats_info_init(nss_stats_str_node, + "/sys/kernel/debug/qca-nss-drv/strings/common_node_stats") != 0) { + goto fail; + } + + if (nssinfo_stats_info_init(nss_ipv6_stats_str, + "/sys/kernel/debug/qca-nss-drv/strings/ipv6/special_stats_str") != 0) { + goto fail; + } + + if (nssinfo_stats_info_init(nss_ipv6_exception_stats_str, + "/sys/kernel/debug/qca-nss-drv/strings/ipv6/exception_stats_str") != 0) { + goto fail; + } + + if (pthread_mutex_init(&ipv6_lock, NULL) != 0) { + nssinfo_warn("Mutex init has failed for IPV6\n"); + goto fail; + } + + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_IPV6].display = nssinfo_ipv6_stats_display; + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_IPV6].notify = nssinfo_ipv6_stats_notify; + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_IPV6].destroy = nssinfo_ipv6_destroy; + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_IPV6].is_inited = true; + return 0; +fail: + nss_nlmcast_sock_leave_grp(ctx, NSS_NLIPV6_MCAST_GRP); + return -1; +} diff --git a/qca/nss-userspace-oss/nssinfo/src/src/nssinfo_ipv6.h b/qca/nss-userspace-oss/nssinfo/src/src/nssinfo_ipv6.h new file mode 100644 index 0000000..5bb5fa5 --- /dev/null +++ b/qca/nss-userspace-oss/nssinfo/src/src/nssinfo_ipv6.h @@ -0,0 +1,30 @@ +/* + ************************************************************************** + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +#ifndef __NSSINFO_IPV6_H +#define __NSSINFO_IPV6_H + +#define NSSINFO_IPV6_HDR_VERSION 4 + +/** + * @brief initialize IPv4 module. + * + * @return 0 on success or -ve for failure + */ +int nssinfo_ipv6_init(void *data); +void nssinfo_ipv6_deinit(void *data); + +#endif /* __NSSINFO_IPV6_H*/ diff --git a/qca/nss-userspace-oss/nssinfo/src/src/nssinfo_lso_rx.c b/qca/nss-userspace-oss/nssinfo/src/src/nssinfo_lso_rx.c new file mode 100644 index 0000000..bbe7274 --- /dev/null +++ b/qca/nss-userspace-oss/nssinfo/src/src/nssinfo_lso_rx.c @@ -0,0 +1,195 @@ +/* + ************************************************************************** + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +/* + * @file NSSINFO lso_rx handler + */ +#include "nssinfo.h" +#include +#include + +static pthread_mutex_t lso_rx_lock; +static struct nssinfo_stats_info nss_stats_str_node[NSS_STATS_NODE_MAX]; +static struct nssinfo_stats_info nss_lso_rx_stats_str[NSS_LSO_RX_STATS_MAX]; + +/* + * nssinfo_lso_rx_stats_display() + * LSO Rx display callback function. + */ +static void nssinfo_lso_rx_stats_display(int core, char *input) +{ + struct node *lso_rx_node; + + if (input && strncmp(input, nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_LSO_RX].subsystem_name, strlen(input))) { + ++invalid_input; + nssinfo_trace("Invalid node name: %s\n", input); + return; + } + + pthread_mutex_lock(&lso_rx_lock); + lso_rx_node = nodes[core][NSS_LSO_RX_INTERFACE]; + if (!lso_rx_node) { + pthread_mutex_unlock(&lso_rx_lock); + nssinfo_error("%s is not running on the NPU\n", input); + return; + } + + if (display_all_stats) { + nssinfo_print_all("lso_rx", "lso_rx Common Stats", nss_stats_str_node, NSS_STATS_NODE_MAX, (uint64_t *)lso_rx_node->cmn_node_stats); + nssinfo_print_all("lso_rx", "lso_rx Special Stats", nss_lso_rx_stats_str, NSS_LSO_RX_STATS_MAX, (uint64_t *)lso_rx_node->node_stats); + pthread_mutex_unlock(&lso_rx_lock); + return; + } + + nssinfo_print_summary("lso_rx", (uint64_t *)lso_rx_node->cmn_node_stats, NULL, 0); + pthread_mutex_unlock(&lso_rx_lock); +} + +/* + * nssinfo_lso_rx_stats_notify() + * LSO Rx stats notify callback function. + */ +static void nssinfo_lso_rx_stats_notify(void *data) +{ + uint64_t *cmn_node_stats, *node_stats; + struct nss_lso_rx_stats_notification *nss_stats = (struct nss_lso_rx_stats_notification *)data; + struct node *lso_rx_node; + struct node **lso_rx_ptr; + + if (!nssinfo_coreid_ifnum_valid(nss_stats->core_id, NSS_LSO_RX_INTERFACE)) { + return; + } + + pthread_mutex_lock(&lso_rx_lock); + lso_rx_ptr = &nodes[nss_stats->core_id][NSS_LSO_RX_INTERFACE]; + lso_rx_node = *lso_rx_ptr; + if (lso_rx_node) { + memcpy(lso_rx_node->cmn_node_stats, &nss_stats->cmn_node_stats, sizeof(nss_stats->cmn_node_stats)); + memcpy(lso_rx_node->node_stats, &nss_stats->node_stats, sizeof(nss_stats->node_stats)); + pthread_mutex_unlock(&lso_rx_lock); + return; + } + pthread_mutex_unlock(&lso_rx_lock); + + lso_rx_node = (struct node *)calloc(1, sizeof(struct node)); + if (!lso_rx_node) { + nssinfo_warn("Failed to allocate memory for lso_rx node\n"); + return; + } + + cmn_node_stats = (uint64_t *)malloc(sizeof(nss_stats->cmn_node_stats)); + if (!cmn_node_stats) { + nssinfo_warn("Failed to allocate memory for lso_rx common node statistics\n"); + goto lso_rx_node_free; + } + + node_stats = (uint64_t *)malloc(sizeof(nss_stats->node_stats)); + if (!node_stats) { + nssinfo_warn("Failed to allocate memory for lso_rx connection stats\n"); + goto cmn_node_stats_free; + } + + memcpy(cmn_node_stats, &nss_stats->cmn_node_stats, sizeof(nss_stats->cmn_node_stats)); + memcpy(node_stats, &nss_stats->node_stats, sizeof(nss_stats->node_stats)); + lso_rx_node->cmn_node_stats = cmn_node_stats; + lso_rx_node->node_stats = node_stats; + lso_rx_node->subsystem_id = NSS_NLCMN_SUBSYS_LSO_RX; + + /* + * Notify is guaranteed to be single threaded via Netlink listen callback + */ + pthread_mutex_lock(&lso_rx_lock); + *lso_rx_ptr = lso_rx_node; + pthread_mutex_unlock(&lso_rx_lock); + return; + +cmn_node_stats_free: + free(cmn_node_stats); + +lso_rx_node_free: + free(lso_rx_node); +} + +/* + * nssinfo_lso_rx_destroy() + * Destroy LSO Rx node. + */ +static void nssinfo_lso_rx_destroy(uint32_t core_id, uint32_t if_num) +{ + if (nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_LSO_RX].is_inited) { + nssinfo_node_stats_destroy(&lso_rx_lock, core_id, NSS_LSO_RX_INTERFACE); + } +} + +/* + * nssinfo_lso_rx_deinit() + * Deinitialize lso_rx module. + */ +void nssinfo_lso_rx_deinit(void *data) +{ + struct nss_nlmcast_ctx *ctx = (struct nss_nlmcast_ctx *)data; + + if (nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_LSO_RX].is_inited) { + pthread_mutex_destroy(&lso_rx_lock); + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_LSO_RX].is_inited = false; + } + + nss_nlmcast_sock_leave_grp(ctx, NSS_NLLSO_RX_MCAST_GRP); +} + +/* + * nssinfo_lso_rx_init() + * Initialize LSO Rx module. + */ +int nssinfo_lso_rx_init(void *data) +{ + int error; + struct nss_nlmcast_ctx *ctx = (struct nss_nlmcast_ctx *)data; + + /* + * Subscribe for LSO Rx multicast group. + */ + nss_nlsock_set_family(&ctx->sock, NSS_NLLSO_RX_FAMILY); + error = nss_nlmcast_sock_join_grp(ctx, NSS_NLLSO_RX_MCAST_GRP); + if (error) { + nssinfo_warn("Unable to join LSO Rx multicast group\n"); + return error; + } + + if (nssinfo_stats_info_init(nss_stats_str_node, + "/sys/kernel/debug/qca-nss-drv/strings/common_node_stats") != 0) { + goto fail; + } + + if (nssinfo_stats_info_init(nss_lso_rx_stats_str, + "/sys/kernel/debug/qca-nss-drv/strings/lso_rx") != 0) { + goto fail; + } + + if (pthread_mutex_init(&lso_rx_lock, NULL) != 0) { + nssinfo_warn("Mutex init has failed for LSO Rx\n"); + goto fail; + } + + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_LSO_RX].display = nssinfo_lso_rx_stats_display; + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_LSO_RX].notify = nssinfo_lso_rx_stats_notify; + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_LSO_RX].destroy = nssinfo_lso_rx_destroy; + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_LSO_RX].is_inited = true; + return 0; +fail: + nss_nlmcast_sock_leave_grp(ctx, NSS_NLLSO_RX_MCAST_GRP); + return -1; +} diff --git a/qca/nss-userspace-oss/nssinfo/src/src/nssinfo_lso_rx.h b/qca/nss-userspace-oss/nssinfo/src/src/nssinfo_lso_rx.h new file mode 100644 index 0000000..98fa804 --- /dev/null +++ b/qca/nss-userspace-oss/nssinfo/src/src/nssinfo_lso_rx.h @@ -0,0 +1,28 @@ +/* + ************************************************************************** + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +#ifndef __NSSINFO_LSO_RX_H +#define __NSSINFO_LSO_RX_H + +/** + * @brief initialize LSO_RX module. + * + * @return 0 on success or -ve for failure + */ +int nssinfo_lso_rx_init(void *data); +void nssinfo_lso_rx_deinit(void *data); + +#endif /* __NSSINFO_LSO_RX_H*/ diff --git a/qca/nss-userspace-oss/nssinfo/src/src/nssinfo_main.c b/qca/nss-userspace-oss/nssinfo/src/src/nssinfo_main.c new file mode 100644 index 0000000..6070273 --- /dev/null +++ b/qca/nss-userspace-oss/nssinfo/src/src/nssinfo_main.c @@ -0,0 +1,191 @@ +/* + ************************************************************************** + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +#include "nssinfo.h" +#include + +static const char *nssinfo_version = "1.0"; + +static struct option long_options[] = { + {"verbose", no_argument, NULL, 'v'}, + {"higherunit", no_argument, NULL, 'u'}, + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'V'}, + {"output", required_argument, NULL, 'o'}, + {"flowfile", required_argument, NULL, 'f'}, + {"core", required_argument, NULL, 'c'}, + {"rate", required_argument, NULL, 'r'}, + {0, 0, 0, 0} +}; +static char *short_options = "vuh?Vo:f:c:r:"; + +static void print_help(void) +{ + printf("nssinfo is an userspace tool used to display NODE stats from NSS-FW\n"); + printf("Usage: nssinfo [OPTION ...] [-c ID [NODE1 NODE2 ...]]\n"); + printf("OPTION:\n"); + printf(" -c, --core=ID Display statistics based on core id\n"); + printf(" -f, --flowfile=FILE Specify output content in FILE\n"); + printf(" -o, --output=FILE Write output to FILE instead of stdout\n"); + printf(" -r, --rate=RATE Update screen every RATE seconds\n"); + printf(" -u, --higherunit Display stats in higher units, i.e. K, M, B\n"); + printf(" -v, --verbose Display all the stats (zero and non-zero stats)\n"); + printf(" -V, --version Print program version\n"); + printf(" -h, --help Give this help message\n"); + printf("Examples:\n"); + printf(" nssinfo\n"); + printf(" nssinfo -c0\n"); + printf(" nssinfo -c0 ipv4 edma[0] edma[4]\n"); + printf(" nssinfo -r5 -o stats.log\n"); +} + +struct arguments arguments; + +/* + * getopt_parse() + * Parse command line arguments using getopt_long(). + */ +static int getopt_parse(int argc, char **argv, void *a) +{ + struct arguments *arguments = (struct arguments *)a; + + while (1) { + int key = getopt_long(argc, argv, short_options, long_options, NULL); + + /* + * Detect the end of the options. + */ + if (key == -1) + break; + + switch (key) { + case 'v': + arguments->verbose = true; + break; + + case 'u': + arguments->higher_unit = true; + break; + + case 'f': + arguments->flow_file = optarg; + break; + + case 'o': + arguments->output_file = optarg; + break; + + case 'r': /* -r5 */ + arguments->rate = atoi(optarg); + if (arguments->rate <= 0) { + printf("Invalid rate `%s'\n", optarg); + exit(-1); + } + break; + + case 'c': /* -c0 */ + arguments->core = atoi(optarg); + if (arguments->core >= NSS_MAX_CORES || arguments->core < 0) { + printf("Invalid core id `%s'\n", optarg); + exit(-1); + } + break; + + case 'h': + print_help(); + exit(0); + + case 'V': + printf("%s\n", nssinfo_version); + exit(0); + + case '?': + default: + /* + * getopt_long already printed an error message. + */ + exit(-1); + } + } + + /* Any remaining non-option arguments start from argv[optind]. + * Init arguments->strings so that + * arguments->strings[0] points to the 1st non-option argument + * arguments->strings[1] points to the 2nd non-option argument + * ... + * arguments->strings[n] points to the last non-option argument + * arguments->strings[n+1] is NULL + * + * For example, + * If user enters 'nssinfo -c1 edma1 edma2', optind is 2 at this point and + * arguments->strings[0] = "edma1", arguments->strings[1] = "edma2", arguments->strings[2] = NULL. + * If user does not specify any non-option argument (e.g. nssinfo -v), + * argv[optind] is NULL so arguments->strings[0] is NULL. + */ + arguments->strings = &argv[optind]; + + return 0; +} + +/* + * main() + */ +int main(int argc, char **argv) +{ + int error; + + arguments.output_file = NULL; + arguments.flow_file = NULL; + arguments.verbose = false; + arguments.higher_unit = false; + arguments.core = -1; /* display stats for all cores */ + arguments.rate = 1; /* 1 sec */ + + getopt_parse(argc, argv, &arguments); + + if (arguments.output_file) { + output_file = fopen(arguments.output_file, "w"); + if (!output_file) { + nssinfo_error("Error opening output file!\n"); + exit(1); + } + } + + if (arguments.flow_file) { + flow_file = fopen(arguments.flow_file, "r"); + if (!flow_file) { + nssinfo_error("Error opening flow file!\n"); + error = -1; + goto end; + } + } + + error = nssinfo_init(); + if (error) { + nssinfo_info("Nssinfo initialization failed(%d)\n", error); + } + + if (flow_file) { + fclose(flow_file); + } + +end: + if (output_file) { + fclose(output_file); + } + + return error; +} diff --git a/qca/nss-userspace-oss/nssinfo/src/src/nssinfo_n2h.c b/qca/nss-userspace-oss/nssinfo/src/src/nssinfo_n2h.c new file mode 100644 index 0000000..4aac456 --- /dev/null +++ b/qca/nss-userspace-oss/nssinfo/src/src/nssinfo_n2h.c @@ -0,0 +1,209 @@ +/* + ************************************************************************** + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +/* + * @file NSSINFO n2h handler + */ +#include "nssinfo.h" +#include +#include + +static pthread_mutex_t n2h_lock; +static uint64_t drv_stats[NSS_STATS_DRV_MAX]; +static struct nssinfo_stats_info nssinfo_n2h_stats_str[NSS_N2H_STATS_MAX]; + +/* + * nssinfo_n2h_stats_display() + * N2H display callback function. + */ +static void nssinfo_n2h_stats_display(int core, char *input) +{ + struct node *n2h_node; + char str_rx[NSSINFO_STR_LEN], str_tx[NSSINFO_STR_LEN]; + + if (input && strncmp(input, nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_N2H].subsystem_name, strlen(input))) { + ++invalid_input; + nssinfo_trace("Invalid node name: %s\n", input); + return; + } + + pthread_mutex_lock(&n2h_lock); + n2h_node = nodes[core][NSS_N2H_INTERFACE]; + if (!n2h_node) { + pthread_mutex_unlock(&n2h_lock); + return; + } + + if (display_all_stats) { + nssinfo_print_all("n2h", "n2h Stats", nssinfo_n2h_stats_str, NSS_N2H_STATS_MAX, (uint64_t *)n2h_node->node_stats); + pthread_mutex_unlock(&n2h_lock); + return; + } + + nssinfo_print_summary("n2h", (uint64_t *)n2h_node->node_stats, NULL, 0); + + if (core == (NSS_MAX_CORES - 1)) { + + char *format_stats = nssinfo_format_stats(drv_stats[NSS_STATS_DRV_RX_CMD_RESP]); + strlcpy(str_rx, format_stats, sizeof(str_rx)); + format_stats = nssinfo_format_stats(drv_stats[NSS_STATS_DRV_TX_CMD_REQ]); + strlcpy(str_tx, format_stats, sizeof(str_tx)); + nssinfo_stats_print(nssinfo_summary_fmt, " buf_cmd", str_rx, str_tx, "", ""); + + memset(str_rx, 0, sizeof(str_rx)); + memset(str_tx, 0, sizeof(str_tx)); + format_stats = nssinfo_format_stats(drv_stats[NSS_STATS_DRV_RX_EMPTY]); + strlcpy(str_rx, format_stats, sizeof(str_rx)); + format_stats = nssinfo_format_stats(drv_stats[NSS_STATS_DRV_TX_EMPTY]); + strlcpy(str_tx, format_stats, sizeof(str_tx)); + nssinfo_stats_print(nssinfo_summary_fmt, " buf_emty", str_rx, str_tx, "", ""); + + memset(str_rx, 0, sizeof(str_rx)); + memset(str_tx, 0, sizeof(str_tx)); + format_stats = nssinfo_format_stats(drv_stats[NSS_STATS_DRV_RX_PACKET]); + strlcpy(str_rx, format_stats, sizeof(str_rx)); + format_stats = nssinfo_format_stats(drv_stats[NSS_STATS_DRV_TX_PACKET]); + strlcpy(str_tx, format_stats, sizeof(str_tx)); + nssinfo_stats_print(nssinfo_summary_fmt, " buf_pkt", str_rx, str_tx, "", ""); + + memset(str_rx, 0, sizeof(str_rx)); + format_stats = nssinfo_format_stats(drv_stats[NSS_STATS_DRV_RX_STATUS]); + strlcpy(str_rx, format_stats, sizeof(str_rx)); + nssinfo_stats_print(nssinfo_summary_fmt, " status_sync", str_rx, "", "", ""); + } + pthread_mutex_unlock(&n2h_lock); +} + +/* + * nssinfo_n2h_stats_notify() + * N2H stats notify callback function. + */ +static void nssinfo_n2h_stats_notify(void *data) +{ + uint64_t *node_stats; + struct nss_n2h_stats_notification *nss_stats = (struct nss_n2h_stats_notification *)data; + struct node *n2h_node; + struct node **n2h_ptr; + + if (!nssinfo_coreid_ifnum_valid(nss_stats->core_id, NSS_N2H_INTERFACE)) { + return; + } + + pthread_mutex_lock(&n2h_lock); + n2h_ptr = &nodes[nss_stats->core_id][NSS_N2H_INTERFACE]; + n2h_node = *n2h_ptr; + if (n2h_node) { + memcpy(n2h_node->node_stats, &nss_stats->n2h_stats, sizeof(nss_stats->n2h_stats)); + memcpy(drv_stats, &nss_stats->drv_stats, sizeof(nss_stats->drv_stats)); + pthread_mutex_unlock(&n2h_lock); + return; + } + pthread_mutex_unlock(&n2h_lock); + + n2h_node = (struct node *)calloc(1, sizeof(struct node)); + if (!n2h_node) { + nssinfo_warn("Failed to allocate memory for N2H node\n"); + return; + } + + node_stats = (uint64_t *)malloc(sizeof(nss_stats->n2h_stats)); + if (!node_stats) { + nssinfo_warn("Failed to allocate memory for n2h node stats\n"); + goto n2h_node_free; + } + + memcpy(node_stats, &nss_stats->n2h_stats, sizeof(nss_stats->n2h_stats)); + memcpy(drv_stats, &nss_stats->drv_stats, sizeof(nss_stats->drv_stats)); + n2h_node->node_stats = node_stats; + n2h_node->subsystem_id = NSS_NLCMN_SUBSYS_N2H; + + /* + * Notify is guaranteed to be single threaded via Netlink listen callback + */ + pthread_mutex_lock(&n2h_lock); + *n2h_ptr = n2h_node; + pthread_mutex_unlock(&n2h_lock); + return; + +n2h_node_free: + free(n2h_node); +} + +/* + * nssinfo_n2h_destroy() + * Destroy N2H node. + */ +static void nssinfo_n2h_destroy(uint32_t core_id, uint32_t if_num) +{ + if (nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_N2H].is_inited) { + nssinfo_node_stats_destroy(&n2h_lock, core_id, NSS_N2H_INTERFACE); + } +} + +/* + * nssinfo_n2h_deinit() + * Deinitialize n2h module. + */ +void nssinfo_n2h_deinit(void *data) +{ + struct nss_nlmcast_ctx *ctx = (struct nss_nlmcast_ctx *)data; + + if (nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_N2H].is_inited) { + pthread_mutex_destroy(&n2h_lock); + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_N2H].is_inited = false; + } + + nss_nlmcast_sock_leave_grp(ctx, NSS_NLN2H_MCAST_GRP); +} + +/* + * nssinfo_n2h_init() + * Initialize N2H module. + */ +int nssinfo_n2h_init(void *data) +{ + int error; + struct nss_nlmcast_ctx *ctx = (struct nss_nlmcast_ctx *)data; + + /* + * Subscribe for N2H MCAST group. + */ + nss_nlsock_set_family(&ctx->sock, NSS_NLN2H_FAMILY); + error = nss_nlmcast_sock_join_grp(ctx, NSS_NLN2H_MCAST_GRP); + if (error) { + nssinfo_warn("Unable to join N2H mcast group.\n"); + return error; + } + + if (nssinfo_stats_info_init(nssinfo_n2h_stats_str, + "/sys/kernel/debug/qca-nss-drv/strings/n2h") != 0) { + goto fail; + } + + if (pthread_mutex_init(&n2h_lock, NULL) != 0) { + nssinfo_warn("Mutex init has failed for n2h\n"); + goto fail; + } + + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_N2H].display = nssinfo_n2h_stats_display; + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_N2H].notify = nssinfo_n2h_stats_notify; + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_N2H].destroy = nssinfo_n2h_destroy; + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_N2H].is_inited = true; + return 0; +fail: + nss_nlmcast_sock_leave_grp(ctx, NSS_NLN2H_MCAST_GRP); + return -1; +} diff --git a/qca/nss-userspace-oss/nssinfo/src/src/nssinfo_n2h.h b/qca/nss-userspace-oss/nssinfo/src/src/nssinfo_n2h.h new file mode 100644 index 0000000..eb3897a --- /dev/null +++ b/qca/nss-userspace-oss/nssinfo/src/src/nssinfo_n2h.h @@ -0,0 +1,28 @@ +/* + ************************************************************************** + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +#ifndef __NSSINFO_N2H_H +#define __NSSINFO_N2H_H + +/** + * @brief initialize N2H module. + * + * @return 0 on success or -ve for failure + */ +int nssinfo_n2h_init(void *data); +void nssinfo_n2h_deinit(void *data); + +#endif /* __NSSINFO_N2H_H*/