[qca-nss-clients] Clients module for gre_redir_lag family.
1. Provide netlink support for gre_redir_lag family.
2. Command supported: create, destroy, map, unmap, set_next, add_hash, del_hash.
Change-Id: I9dac36e0637ee45a00433ad7cec0e2be0d15af8f
Signed-off-by: Himanshu Joshi <himajosh@codeaurora.org>
diff --git a/netlink/Makefile b/netlink/Makefile
index ecdba8c..3072316 100644
--- a/netlink/Makefile
+++ b/netlink/Makefile
@@ -8,11 +8,14 @@
ccflags-y += -DCONFIG_NSS_NLIPV6=1
ccflags-y += -DCONFIG_NSS_NLIPSEC=1
ccflags-y += -DCONFIG_NSS_NLOAM=1
-ccflags-y += -DCONFIG_NSS_NLGRE_REDIR=1
+ccflags-y += -DCONFIG_NSS_NLGRE_REDIR_FAMILY=1
qca-nss-netlink-objs := nss_nl.o
+qca-nss-netlink-objs += nss_nlgre_redir_family.o
+qca-nss-netlink-objs += nss_nlgre_redir_cmd.o
+qca-nss-netlink-objs += nss_nlgre_redir_cmn.o
qca-nss-netlink-objs += nss_nlgre_redir.o
-qca-nss-netlink-objs += nss_nlgre_redir_mgr.o
+qca-nss-netlink-objs += nss_nlgre_redir_lag.o
qca-nss-netlink-objs += nss_nlipv4.o
qca-nss-netlink-objs += nss_nlipv6.o
qca-nss-netlink-objs += nss_nlipsec.o
diff --git a/netlink/include/nss_nlgre_redir_if.h b/netlink/include/nss_nlgre_redir_if.h
index 1b8a376..95ddc5c 100644
--- a/netlink/include/nss_nlgre_redir_if.h
+++ b/netlink/include/nss_nlgre_redir_if.h
@@ -17,43 +17,13 @@
#ifndef __NSS_NLGRE_REDIR_IF_H
#define __NSS_NLGRE_REDIR_IF_H
-/**
- * @file nss_nlgre_redir_if.h
- * NSS Netlink gre_redir headers
- */
#define NSS_NLGRE_REDIR_TUN_TYPE_MAX_SZ 16 /**< Maximum length of tunnel type */
#define NSS_NLGRE_REDIR_MODE_MAX_SZ 16 /**< Maximum length of mode */
-#define NSS_NLGRE_REDIR_NEEDED_HEADROOM 192 /**< Maximum headroom available */
-#define NSS_NLGRE_REDIR_RADIO_ID_MAX 2 /**< Radio Id max size */
-#define NSS_NLGRE_REDIR_RADIO_ID_MIN 0 /**< Radio Id min size */
-#define NSS_NLGRE_REDIR_VAP_ID_MAX 16 /**< Vap Id max size */
-#define NSS_NLGRE_REDIR_VAP_ID_MIN 0 /**< Vap Id min size */
-#define NSS_NLGRE_REDIR_MAX_TUNNELS 24 /**< Maximum number of tunnels allowed */
#define NSS_NLGRE_REDIR_FAMILY "nss_nlgre_redir" /**< Family */
#define NSS_NLGRE_REDIR_MCAST_GRP "nss_nlgrerdr_mc" /**< Multicast group */
/**
- * @brief netdevice private data
- */
-struct nss_gre_redir_ndev_priv {
- uint32_t gre_seq; /**< Sequence number */
-};
-
-/**
- * @brief context need to be maintained globally for GRE redirect tunnel.
- */
-struct nss_nlgre_redir_pvt_data {
- struct net_device *dev; /**< Net device */
- int32_t host_inner_ifnum; /**< Interface no. of pnode host inner */
- int32_t wifi_offl_inner_ifnum; /**< Interface no. of pnode wifi offld inner */
- int32_t sjack_inner_ifnum; /**< Interface no. of pnode sjack inner */
- int32_t outer_ifnum; /**< Interface no. of pnode outer */
- int32_t vap_nss_if; /**< Interface no. of vap */
- bool enable; /**< Device is enabled or not */
-};
-
-/**
- * @brief enumeration for all command types.
+ * @brief Enumeration for all command types.
*/
enum nss_nlgre_redir_cmd_type {
NSS_NLGRE_REDIR_CMD_TYPE_UNKNOWN, /**< Unknown command type */
@@ -62,17 +32,24 @@
NSS_NLGRE_REDIR_CMD_TYPE_MAP, /**< Map the vap interface to tunnel id */
NSS_NLGRE_REDIR_CMD_TYPE_UNMAP, /**< Unmap vap and tunnel id */
NSS_NLGRE_REDIR_CMD_TYPE_SET_NEXT_HOP, /**< Set the next hop of inner interface */
+ NSS_NLGRE_REDIR_CMD_TYPE_ADD_HASH, /**< Add a hash entry*/
+ NSS_NLGRE_REDIR_CMD_TYPE_DEL_HASH, /**< Delete a hash entry */
NSS_NLGRE_REDIR_CMD_TYPE_MAX, /**< Max number of commands */
};
/**
- * @brief parameters to create a tunnel.
+ * @brief Parameters to create a tunnel.
*/
struct nss_nlgre_redir_create_tun {
- uint32_t sip[4]; /**< Src IP address */
- uint32_t dip[4]; /**< Dest IP address */
- uint16_t iptype; /**< Ip version */
- uint8_t res[2]; /**< Padding to make size multiple of 4 */
+ uint32_t sip[4]; /**< Src address of tunnel */
+ uint32_t dip[4]; /**< Dest address of tunnel */
+ uint32_t ssip[4]; /**< Src address of second tunnel */
+ uint32_t sdip[4]; /**< Dest address of second tunnel */
+ uint8_t hash_mode; /**< Indicates how the traffic should be mapped */
+ uint8_t iptype; /**< IPv4 = 1 and IPV6 = 2 */
+ char mode[NSS_NLGRE_REDIR_MODE_MAX_SZ]; /**< Mode can be sjack or wifi */
+ bool lag_enable; /**< Indicates whether lag is enabled or not */
+ uint8_t res; /**< Padding to make size multiple of 4 */
};
/**
@@ -114,6 +91,18 @@
};
/**
+ * @brief parameters to perform hash operations.
+ */
+struct nss_nlgre_redir_hash_ops {
+ uint16_t slave; /**< Tunnel to which the traffic should be mapped */
+ uint8_t smac[6]; /**< Source mac address */
+ uint8_t dmac[6]; /**< Destination mac address */
+ char mode[NSS_NLGRE_REDIR_MODE_MAX_SZ]; /**< Sjack or wifi */
+};
+
+/**@}*/
+
+/**
* @brief gre_redir message
*/
struct nss_nlgre_redir_rule {
@@ -128,6 +117,7 @@
struct nss_nlgre_redir_map map; /**< Map the interface */
struct nss_nlgre_redir_unmap unmap; /**< Unmap the interface */
struct nss_nlgre_redir_set_next snext; /**< Set next hop */
+ struct nss_nlgre_redir_hash_ops hash_ops; /**< Add and del hash value(s) */
} msg;
};
diff --git a/netlink/nss_nl.c b/netlink/nss_nl.c
index f8e8e6d..6e697ca 100644
--- a/netlink/nss_nl.c
+++ b/netlink/nss_nl.c
@@ -33,7 +33,7 @@
#include "nss_nlipv6_if.h"
#include "nss_nlipsec_if.h"
#include "nss_nlgre_redir_if.h"
-#include "nss_nlgre_redir.h"
+#include "nss_nlgre_redir_family.h"
#include "nss_nloam_if.h"
#if defined (CONFIG_NSS_NLCRYPTO)
#include "nss_nlcrypto_if.h"
@@ -129,9 +129,9 @@
* NSS_NLGRE_REDIR
*/
.name = NSS_NLGRE_REDIR_FAMILY, /* gre_redir */
- .entry = NSS_NLGRE_REDIR_INIT, /* init */
- .exit = NSS_NLGRE_REDIR_EXIT, /* exit */
- .valid = CONFIG_NSS_NLGRE_REDIR /* 1 or 0 */
+ .entry = NSS_NLGRE_REDIR_FAMILY_INIT, /* init */
+ .exit = NSS_NLGRE_REDIR_FAMILY_EXIT, /* exit */
+ .valid = CONFIG_NSS_NLGRE_REDIR_FAMILY /* 1 or 0 */
},
};
diff --git a/netlink/nss_nlgre_redir.c b/netlink/nss_nlgre_redir.c
index 5f3e296..4fccc26 100644
--- a/netlink/nss_nlgre_redir.c
+++ b/netlink/nss_nlgre_redir.c
@@ -1,5 +1,5 @@
/*
- **************************************************************************
+ ***************************************************************************
* Copyright (c) 2015-2016,2018-2019, 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
@@ -11,361 +11,164 @@
* 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.
- **************************************************************************
+ ***************************************************************************
*/
-/*
- * nss_nlgre_redir.c
- * NSS Netlink gre_redir Handler
- */
#include <linux/version.h>
+#include <linux/etherdevice.h>
+#include <linux/if_ether.h>
#include <net/genetlink.h>
#include <nss_api_if.h>
-#include <nss_nlcmn_if.h>
#include <nss_nl_if.h>
-#include <nss_nlgre_redir_if.h>
+#include "nss_nlcmn_if.h"
#include "nss_nl.h"
+#include "nss_nlgre_redir_if.h"
+#include "nss_nlgre_redir_cmn.h"
#include "nss_nlgre_redir.h"
-#include "nss_nlgre_redir_mgr.h"
/*
- * Get max size of the array
+ * nss_nlgre_redir_destroy_tun()
+ * Destroys the gre_redir tunnel
*/
-#define NSS_NLGRE_REDIR_OPS_SZ ARRAY_SIZE(nss_nlgre_redir_ops)
-
-/*
- * nss_nlgre_redir_family
- * Gre_redir family definition
- */
-static struct genl_family nss_nlgre_redir_family = {
- .id = GENL_ID_GENERATE, /* Auto generate ID */
- .name = NSS_NLGRE_REDIR_FAMILY, /* family name string */
- .hdrsize = sizeof(struct nss_nlgre_redir_rule), /* NSS NETLINK gre_redir rule */
- .version = NSS_NL_VER, /* Set it to NSS_NLGRE_REDIR version */
- .maxattr = NSS_NLGRE_REDIR_CMD_TYPE_MAX, /* maximum commands supported */
- .netnsok = true,
- .pre_doit = NULL,
- .post_doit = NULL,
-};
-
-/*
- * nss_nlgre_redir_mcgrp
- * Multicast group for sending message status & events
- */
-static const struct genl_multicast_group nss_nlgre_redir_mcgrp[] = {
- {.name = NSS_NLGRE_REDIR_MCAST_GRP},
-};
-
-/*
- * nss_nlgre_redir_ops_create_tun()
- * Handler for tunnel create
- */
-static int nss_nlgre_redir_ops_create_tun(struct sk_buff *skb, struct genl_info *info)
+int nss_nlgre_redir_destroy_tun(struct net_device *dev)
{
- struct nss_nlgre_redir_rule *nl_rule;
- struct nss_nlcmn *nl_cm;
- int ret = 0;
+ int ret;
- /*
- * Extract the message payload
- */
- nl_cm = nss_nl_get_msg(&nss_nlgre_redir_family, info, NSS_NLGRE_REDIR_CMD_TYPE_CREATE_TUN);
- if (!nl_cm) {
- nss_nl_error("Unable to extract create tunnel data\n");
- ret = -EINVAL;
- goto fail;
- }
-
- /*
- * Message validation required before accepting the configuration
- */
- nl_rule = container_of(nl_cm, struct nss_nlgre_redir_rule, cm);
-
- /*
- * Create a gre tunnel
- */
- ret = nss_nlgre_redir_mgr_create_tun(&nl_rule->msg.create);
- if(ret == -1) {
- nss_nl_error("Unable to create tunnel\n");
- ret = -EAGAIN;
- goto fail;
- }
-
- nss_nl_info("Successfully created gretun%d tunnel\n", ret);
-fail:
- return ret;
-}
-
-/*
- * nss_nlgre_redir_ops_destroy_tun()
- * Handler destroy tunnel
- */
-static int nss_nlgre_redir_ops_destroy_tun(struct sk_buff *skb, struct genl_info *info)
-{
- struct nss_nlgre_redir_rule *nl_rule;
- struct net_device *dev;
- struct nss_nlcmn *nl_cm;
- int ret = 0;
-
- /*
- * Extract the message payload
- */
- nl_cm = nss_nl_get_msg(&nss_nlgre_redir_family, info, NSS_NLGRE_REDIR_CMD_TYPE_DESTROY_TUN);
- if (!nl_cm) {
- nss_nl_error("Unable to extract destroy tunnel data\n");
- ret = -EINVAL;
- goto fail;
- }
-
- /*
- * Message validation required before accepting the configuration
- */
- nl_rule = container_of(nl_cm, struct nss_nlgre_redir_rule, cm);
-
- /*
- * Get the dev reference
- */
- dev = dev_get_by_name(&init_net, nl_rule->msg.destroy.netdev);
if (!dev) {
- nss_nl_error("Invalid parameter: %s\n", nl_rule->msg.destroy.netdev);
- ret = -ENODEV;
- goto fail;
+ nss_nl_error("Dev is NULL\n");
+ return -EINVAL;
}
- /*
- * Destroy the tunnel
- */
- ret = nss_nlgre_redir_mgr_destroy_tun(dev);
- if (ret == -1) {
- nss_nl_error("Unable to destroy tunnel: %s\n", nl_rule->msg.destroy.netdev);
- ret = -EAGAIN;
- dev_put(dev);
- goto fail;
+ ret = nss_nlgre_redir_cmn_destroy_tun(dev);
+ if (ret < 0) {
+ nss_nl_error("Could not destroy the tunnel\n");
+ return -EINVAL;
}
- nss_nl_info("Successfully destroyed gretun = %s tunnel\n", nl_rule->msg.destroy.netdev);
-fail:
- return ret;
+ nss_nl_info("Successfully destroyed the tunnel\n");
+ return 0;
}
/*
- * nss_nlgre_redir_ops_map()
- * Handler for map command
+ * nss_nlgre_redir_create_tun()
+ * Creates a gre_redir tunnel
*/
-static int nss_nlgre_redir_ops_map(struct sk_buff *skb, struct genl_info *info)
+int nss_nlgre_redir_create_tun(struct nss_nlgre_redir_create_tun *create_params)
{
- struct nss_nlgre_redir_rule *nl_rule;
- struct nss_nlcmn *nl_cm;
- uint32_t vap_nss_if, tun_type;
struct net_device *dev;
- int ret = 0;
- /*
- * extract the message payload
- */
- nl_cm = nss_nl_get_msg(&nss_nlgre_redir_family, info, NSS_NLGRE_REDIR_CMD_TYPE_MAP);
- if (!nl_cm) {
- nss_nl_error("Unable to extract map interface data\n");
- ret = -EINVAL;
- goto fail;
+ if (!create_params) {
+ nss_nl_error("create_params is NULL\n");
+ return -EINVAL;
}
- /*
- * Message validation required before accepting the configuration
- */
- nl_rule = container_of(nl_cm, struct nss_nlgre_redir_rule, cm);
-
- /*
- * Get the dev reference
- */
- dev = dev_get_by_name(&init_net, nl_rule->msg.map.vap_nss_if);
+ dev = nss_nlgre_redir_cmn_create_tun(create_params->sip, create_params->dip, create_params->iptype);
if (!dev) {
- nss_nl_error("Invalid parameter: vap_nss_if\n");
- ret = -ENODEV;
- goto fail;
+ nss_nl_error("Could not create tunnel\n");
+ return -EINVAL;
}
- vap_nss_if = nss_cmn_get_interface_number_by_dev(dev);
- dev_put(dev);
- tun_type = nss_nlgre_redir_mgr_tunnel_type(nl_rule->msg.map.tun_type);
-
- /*
- * map the interface
- */
- ret = nss_nlgre_redir_mgr_interface_map(vap_nss_if, tun_type, &nl_rule->msg.map);
- if(!ret) {
- nss_nl_error("Unable to map nss interface\n");
- ret = -EAGAIN;
- goto fail;
- }
-
- nss_nl_info("Successfully mapped nss interface.\n");
-fail:
- return ret;
+ nss_nl_info("Successfully created the tunnel = %s\n", dev->name);
+ return 0;
}
/*
- * nss_nlgre_redir_ops_unmap()
- * Handler for unmap command
+ * nss_nlgre_redir_map_interface()
+ * Maps the nss interface to the tunnel ID
*/
-static int nss_nlgre_redir_ops_unmap(struct sk_buff *skb, struct genl_info *info)
+int nss_nlgre_redir_map_interface(struct nss_nlgre_redir_map *map_params)
{
- struct nss_nlgre_redir_rule *nl_rule;
- struct nss_nlcmn *nl_cm;
- struct net_device *dev;
- int32_t vap_nss_if;
- int ret = 0;
+ struct nss_ctx_instance *nss_ctx;
+ uint32_t nexthop_nssif, vap_nss_if;
+ uint8_t tun_type;
+ int ret;
- /*
- * extract the message payload
- */
- nl_cm = nss_nl_get_msg(&nss_nlgre_redir_family, info, NSS_NLGRE_REDIR_CMD_TYPE_UNMAP);
- if (!nl_cm) {
- nss_nl_error("Unable to extract unmap data\n");
- ret = -EINVAL;
- goto fail;
+ if (!map_params) {
+ nss_nl_error("map params is NULL\n");
+ return -EINVAL;
}
- /*
- * Message validation required before accepting the configuration
- */
- nl_rule = container_of(nl_cm, struct nss_nlgre_redir_rule, cm);
+ nss_ctx = nss_gre_redir_get_context();
+ vap_nss_if = nss_nlgre_redir_cmn_get_dev_ifnum(map_params->vap_nss_if);
/*
- * Get the dev reference
+ * Get tunnel type from tun_type string
*/
- dev = dev_get_by_name(&init_net, nl_rule->msg.unmap.vap_nss_if);
- if (!dev) {
- nss_nl_error("Invalid parameter: dev_name\n");
- ret = -ENODEV;
- goto fail;
- }
-
- vap_nss_if = nss_cmn_get_interface_number_by_dev(dev);
- dev_put(dev);
-
- /*
- * Unmap the interface
- */
- ret = nss_nlgre_redir_mgr_interface_unmap(vap_nss_if, &nl_rule->msg.unmap);
- if(!ret) {
- nss_nl_error("Unable to unmap nss interface\n");
- ret = -EAGAIN;
- goto fail;
- }
-
- nss_nl_info("Successfully unmapped the nss interface.\n");
-fail:
- return ret;
-}
-
-/*
- * nss_nlgre_redir_ops_set_next()
- * Handler for set_next command
- */
-static int nss_nlgre_redir_ops_set_next(struct sk_buff *skb, struct genl_info *info)
-{
- struct nss_nlgre_redir_rule *nl_rule;
- struct nss_nlcmn *nl_cm;
- int ret = 0;
-
- /*
- * extract the message payload
- */
- nl_cm = nss_nl_get_msg(&nss_nlgre_redir_family, info, NSS_NLGRE_REDIR_CMD_TYPE_SET_NEXT_HOP);
- if (!nl_cm) {
- nss_nl_error("Unable to extract set_next_hop data\n");
- ret = -EINVAL;
- goto fail;
- }
-
- /*
- * Message validation required before accepting the configuration
- */
- nl_rule = container_of(nl_cm, struct nss_nlgre_redir_rule, cm);
-
- ret = nss_nlgre_redir_mgr_set_next_hop(&nl_rule->msg.snext);
- if (!ret) {
- nss_nl_error("Unable to set next hop\n");
- ret = -EAGAIN;
- goto fail;
- }
-
- nss_nl_info("Successfully set the next hop\n");
-fail:
- return ret;
-}
-
-/*
- * nss_nlgre_redir_get_ifnum()
- * Get the interface number corresponding to netdev
- */
-int nss_nlgre_redir_get_ifnum(struct net_device* dev, enum nss_dynamic_interface_type type)
-{
- int ifnum;
-
- /*
- * Get the interface number depending upon the dev and type
- */
- ifnum = nss_cmn_get_interface_number_by_dev_and_type(dev, type);
- if (ifnum < 0) {
- nss_nl_error("%p: Failed to find interface number (dev:%s, type:%d)\n", dev, dev->name, type);
+ tun_type = nss_nlgre_redir_cmn_get_tun_type(map_params->tun_type);
+ switch(tun_type) {
+ case NSS_NLGRE_REDIR_TUN_TYPE_DTUN:
+ case NSS_NLGRE_REDIR_TUN_TYPE_TUN:
+ nexthop_nssif = vap_nss_if;
+ break;
+ case NSS_NLGRE_REDIR_TUN_TYPE_SPLIT:
+ nexthop_nssif = NSS_ETH_RX_INTERFACE;
+ break;
+ default:
+ nss_nl_error("%p: not a valid tunnel_type\n", nss_ctx);
return -1;
}
- return ifnum;
-}
-
-/*
- * nss_nlgre_redir_ops
- * Operation table called by the generic netlink layer based on the command
- */
-static struct genl_ops nss_nlgre_redir_ops[] = {
- {.cmd = NSS_NLGRE_REDIR_CMD_TYPE_CREATE_TUN, .doit = nss_nlgre_redir_ops_create_tun,},
- {.cmd = NSS_NLGRE_REDIR_CMD_TYPE_DESTROY_TUN, .doit = nss_nlgre_redir_ops_destroy_tun,},
- {.cmd = NSS_NLGRE_REDIR_CMD_TYPE_MAP, .doit = nss_nlgre_redir_ops_map,},
- {.cmd = NSS_NLGRE_REDIR_CMD_TYPE_UNMAP, .doit = nss_nlgre_redir_ops_unmap,},
- {.cmd = NSS_NLGRE_REDIR_CMD_TYPE_SET_NEXT_HOP, .doit = nss_nlgre_redir_ops_set_next,},
-};
-
-/*
- * nss_nlgre_redir_init()
- * handler init
- */
-bool nss_nlgre_redir_init(void)
-{
- int err;
- nss_nl_info_always("Init NSS netlink gre_redir handler\n");
-
/*
- * register NETLINK ops with the family
+ * Map the nss interface
*/
- err = genl_register_family_with_ops_groups(&nss_nlgre_redir_family, nss_nlgre_redir_ops, nss_nlgre_redir_mcgrp);
- if (err) {
- nss_nl_info_always("Error: %d unable to register gre_redir family\n", err);
- return false;
+ ret = nss_nlgre_redir_cmn_map_interface(nexthop_nssif, 0, map_params);
+ if (ret == -1) {
+ nss_nl_error("%p: Unable to map nss interface\n", nss_ctx);
+ return -1;
}
- return true;
+ nss_nl_info("Successfully mapped the nss interface to tunnel ID\n");
+ return 0;
}
/*
- * nss_nlgre_redir_exit()
- * handler exit
+ * nss_nlgre_redir_set_next_hop()
+ * Sets the next hop of vap as wifi_offld_inner interface of gre_redir node
*/
-bool nss_nlgre_redir_exit(void)
+int nss_nlgre_redir_set_next_hop(struct nss_nlgre_redir_set_next *set_next_params)
{
- int err;
- nss_nl_info_always("Exit NSS netlink gre_redir handler\n");
+ enum nss_nlgre_redir_cmn_mode_type mode;
+ struct nss_ctx_instance *nss_ctx;
+ struct net_device *next_dev;
+ uint32_t nexthop_ifnum;
+ int ret;
- /*
- * unregister the ops family
- */
- err = genl_unregister_family(&nss_nlgre_redir_family);
- if (err) {
- nss_nl_info_always("Error: %d unable to unregister gre_redir NETLINK family\n", err);
- return false;
+ if (!set_next_params) {
+ nss_nl_error("set next params is NULL\n");
+ return -EINVAL;
}
- return true;
+ nss_ctx = nss_gre_redir_get_context();
+ next_dev = dev_get_by_name(&init_net, set_next_params->next_dev_name);
+ if (!next_dev) {
+ nss_nl_error("%p: Unable to get the reference to dev %s\n", nss_ctx, set_next_params->next_dev_name);
+ return -1;
+ }
+
+ dev_put(next_dev);
+ mode = nss_nlgre_redir_cmn_mode_str_to_enum(set_next_params->mode);
+ switch(mode) {
+ case NSS_NLGRE_REDIR_CMN_MODE_TYPE_WIFI:
+ /*
+ * Gets the wifi_offl_inner_ifnum interface number of gretun[index]
+ */
+ nexthop_ifnum = nss_nlgre_redir_cmn_get_tun_ifnum(NSS_NLGRE_REDIR_CMN_MODE_TYPE_WIFI, next_dev);
+ break;
+ case NSS_NLGRE_REDIR_CMN_MODE_TYPE_SPLIT:
+ nexthop_ifnum = NSS_ETH_RX_INTERFACE;
+ break;
+ default:
+ nss_nl_error("%p: Unknown set next mode\n", nss_ctx);
+ return -1;
+ }
+
+ ret = nss_nlgre_redir_cmn_set_next_hop(nexthop_ifnum, set_next_params);
+ if (ret == -1) {
+ nss_nl_error("%p: Unable to set the next hop\n", nss_ctx);
+ return -1;
+ }
+
+ nss_nl_info("Successfully set the next hop\n");
+ return 0;
}
+
diff --git a/netlink/nss_nlgre_redir.h b/netlink/nss_nlgre_redir.h
index ac42019..16ab737 100644
--- a/netlink/nss_nlgre_redir.h
+++ b/netlink/nss_nlgre_redir.h
@@ -1,5 +1,5 @@
/*
- **************************************************************************
+ ***************************************************************************
* Copyright (c) 2014-2015,2019, 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
@@ -14,37 +14,41 @@
**************************************************************************
*/
-/*
- * nss_nlgre_redir.h
- * NSS Netlink gre_redir API definitions
- */
-#ifndef __NSS_NLGRE_REDIR_H
-#define __NSS_NLGRE_REDIR_H
+#define NSS_NLGRE_REDIR_MODE_MAX_SZ 16 /**< Max size of mode value */
/*
- * nss_nlgre_redir_get_ifnum()
- * Get the interface number corresponding to netdev
+ * nss_nlgre_redir_tun_type
+ * Different tunnel types supported in gre_redir
*/
-int nss_nlgre_redir_get_ifnum(struct net_device* dev, enum nss_dynamic_interface_type type);
+enum nss_nlgre_redir_tun_type {
+ NSS_NLGRE_REDIR_TUN_TYPE_UNKNOWN, /**< Unknown tunnel type */
+ NSS_NLGRE_REDIR_TUN_TYPE_TUN, /**< Raw mode 802.11 frames traffic*/
+ NSS_NLGRE_REDIR_TUN_TYPE_DTUN, /**< For 802.3 frames traffic */
+ NSS_NLGRE_REDIR_TUN_TYPE_SPLIT, /**< For split mode */
+ NSS_NLGRE_REDIR_TUN_TYPE_MAX /**< Max number of tun type supported */
+};
/*
- * nss_nlgre_redir_init()
- * To initialize the gre_redir module
+ * nss_nlgre_redir_map_interface()
+ * Interface map message.
*/
-bool nss_nlgre_redir_init(void);
+int nss_nlgre_redir_map_interface(struct nss_nlgre_redir_map *map_params);
/*
- * nss_nlgre_redir_exit()
- * Exit the gre_redir module
+ * nss_nlgre_redir_set_next_hop()
+ * Sets next hop as gre-redir for wifi.
*/
-bool nss_nlgre_redir_exit(void);
+int nss_nlgre_redir_set_next_hop(struct nss_nlgre_redir_set_next *setnext_params);
-#if defined(CONFIG_NSS_NLGRE_REDIR)
-#define NSS_NLGRE_REDIR_INIT nss_nlgre_redir_init
-#define NSS_NLGRE_REDIR_EXIT nss_nlgre_redir_exit
-#else
-#define NSS_NLGRE_REDIR_INIT 0
-#define NSS_NLGRE_REDIR_EXIT 0
-#endif /* !CONFIG_NSS_NLGRE_REDIR */
+/*
+ * nss_nlgre_redir_create_tun()
+ * Unregisters and deallocs dynamic interfaces.
+ */
+int nss_nlgre_redir_create_tun(struct nss_nlgre_redir_create_tun *create_params);
-#endif /* __NSS_NLGRE_REDIR_H */
+/*
+ * nss_nlgre_redir_destroy_tun()
+ * Destroy tunnel in tunnel mode.
+ */
+int nss_nlgre_redir_destroy_tun(struct net_device *dev);
+
diff --git a/netlink/nss_nlgre_redir_cmd.c b/netlink/nss_nlgre_redir_cmd.c
new file mode 100644
index 0000000..3653bea
--- /dev/null
+++ b/netlink/nss_nlgre_redir_cmd.c
@@ -0,0 +1,443 @@
+/*
+ **************************************************************************
+ * Copyright (c) 2015-2016,2018-2019, 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.
+ **************************************************************************
+ */
+
+/*
+ * nss_nlgre_redir.c
+ * NSS Netlink gre_redir Handler
+ */
+#include <linux/version.h>
+#include <net/genetlink.h>
+#include <nss_api_if.h>
+#include <nss_nlcmn_if.h>
+#include <nss_nl_if.h>
+#include <nss_nlgre_redir_if.h>
+#include "nss_nl.h"
+#include "nss_nlgre_redir.h"
+#include "nss_nlgre_redir_cmd.h"
+#include "nss_nlgre_redir_cmn.h"
+#include "nss_nlgre_redir_lag.h"
+
+/*
+ * To get lock on deploy_mode
+ */
+static DEFINE_SPINLOCK(lock);
+
+/*
+ * Variable to keep track of mode we are operating
+ */
+static enum nss_nlgre_redir_cmd_deploy_mode deploy_mode;
+
+/*
+ * nss_nlgre_redir_cmd_family
+ * Gre_redir family definition
+ */
+struct genl_family nss_nlgre_redir_cmd_family = {
+ .id = GENL_ID_GENERATE, /* Auto generate ID */
+ .name = NSS_NLGRE_REDIR_FAMILY, /* family name string */
+ .hdrsize = sizeof(struct nss_nlgre_redir_rule), /* NSS NETLINK gre_redir rule */
+ .version = NSS_NL_VER, /* Set it to NSS_NLGRE_REDIR version */
+ .maxattr = NSS_NLGRE_REDIR_CMD_TYPE_MAX, /* maximum commands supported */
+ .netnsok = true,
+ .pre_doit = NULL,
+ .post_doit = NULL,
+};
+
+/*
+ * nss_nlgre_redir_cmd_get_deploy_mode()
+ * Returns deploy_mode value
+ */
+static inline enum nss_nlgre_redir_cmd_deploy_mode nss_nlgre_redir_cmd_get_deploy_mode(void)
+{
+ enum nss_nlgre_redir_cmd_deploy_mode ret_deploy_mode;
+ spin_lock(&lock);
+ ret_deploy_mode = deploy_mode;
+ spin_unlock(&lock);
+ return ret_deploy_mode;
+}
+
+/*
+ * nss_nlgre_redir_cmd_set_deploy_mode()
+ * Sets the value of deploy_mode to parameter passed
+ */
+static inline void nss_nlgre_redir_cmd_set_deploy_mode(enum nss_nlgre_redir_cmd_deploy_mode param_deploy_mode)
+{
+ spin_lock(&lock);
+ deploy_mode = param_deploy_mode;
+ spin_unlock(&lock);
+}
+
+/*
+ * nss_nlgre_redir_cmd_ops_tun_create()
+ * Handler for tunnel create
+ */
+static int nss_nlgre_redir_cmd_ops_tun_create(struct sk_buff *skb, struct genl_info *info)
+{
+ struct nss_nlgre_redir_rule *nl_rule;
+ struct nss_nlcmn *nl_cm;
+ int ret = 0;
+
+ /*
+ * Extract the message payload
+ */
+ nl_cm = nss_nl_get_msg(&nss_nlgre_redir_cmd_family, info, NSS_NLGRE_REDIR_CMD_TYPE_CREATE_TUN);
+ if (!nl_cm) {
+ nss_nl_error("Unable to extract create tunnel data\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Message validation required before accepting the configuration
+ */
+ nl_rule = container_of(nl_cm, struct nss_nlgre_redir_rule, cm);
+
+ /*
+ * Create tunnel based on value of lag_enable
+ */
+ if (!nl_rule->msg.create.lag_enable) {
+ nss_nlgre_redir_cmd_set_deploy_mode(NSS_NLGRE_REDIR_CMD_DEPLOY_MODE_NON_LAG);
+ ret = nss_nlgre_redir_create_tun(&nl_rule->msg.create);
+ if (ret < 0) {
+ nss_nl_error("Unable to create tunnel\n");
+ return -EAGAIN;
+ }
+
+ goto done;
+ }
+
+ /*
+ * Create a lag tunnel
+ */
+ nss_nlgre_redir_cmd_set_deploy_mode(NSS_NLGRE_REDIR_CMD_DEPLOY_MODE_LAG);
+ ret = nss_nlgre_redir_lag_create_tun(&nl_rule->msg.create);
+ if (ret < 0) {
+ nss_nl_error("Unable to create lag tunnel\n");
+ return -EAGAIN;
+ }
+done:
+ nss_nl_info("Successfully created tunnel\n");
+ return 0;
+}
+
+/*
+ * nss_nlgre_redir_cmd_ops_destroy_tun()
+ * Handler to destroy tunnel
+ */
+static int nss_nlgre_redir_cmd_ops_tun_destroy(struct sk_buff *skb, struct genl_info *info)
+{
+ enum nss_nlgre_redir_cmd_deploy_mode deploy_mode;
+ struct nss_nlgre_redir_rule *nl_rule;
+ struct nss_nlcmn *nl_cm;
+ struct net_device *dev;
+ int ret = 0;
+
+ /*
+ * Extract the message payload
+ */
+ nl_cm = nss_nl_get_msg(&nss_nlgre_redir_cmd_family, info, NSS_NLGRE_REDIR_CMD_TYPE_DESTROY_TUN);
+ if (!nl_cm) {
+ nss_nl_error("Unable to extract destroy tunnel data\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Message validation required before accepting the configuration
+ */
+ nl_rule = container_of(nl_cm, struct nss_nlgre_redir_rule, cm);
+
+ /*
+ * Get the dev reference
+ */
+ dev = dev_get_by_name(&init_net, nl_rule->msg.destroy.netdev);
+ if (!dev) {
+ nss_nl_error("Invalid parameters: %s\n", nl_rule->msg.destroy.netdev);
+ return -ENODEV;
+ }
+
+ dev_put(dev);
+
+ /*
+ * Destroy the non-lag tunnel
+ */
+ deploy_mode = nss_nlgre_redir_cmd_get_deploy_mode();
+ if (deploy_mode != NSS_NLGRE_REDIR_CMD_DEPLOY_MODE_LAG) {
+ ret = nss_nlgre_redir_destroy_tun(dev);
+ if (ret < 0) {
+ nss_nl_error("Unable to destroy tunnel: %s\n", nl_rule->msg.destroy.netdev);
+ dev_put(dev);
+ return -EAGAIN;
+ }
+
+ goto done;
+ }
+
+ /*
+ * Destroy the lag tunnel
+ */
+ ret = nss_nlgre_redir_lag_destroy_tun(dev);
+ if (ret < 0) {
+ nss_nl_error("Unable to destroy tunnel: %s\n", nl_rule->msg.destroy.netdev);
+ dev_put(dev);
+ return -EAGAIN;
+ }
+
+done:
+ nss_nl_info("Successfully destroyed gretun = %s tunnel\n", nl_rule->msg.destroy.netdev);
+ return 0;
+}
+
+/*
+ * nss_nlgre_redir_cmd_ops_map()
+ * Handler for map command
+ */
+static int nss_nlgre_redir_cmd_ops_map(struct sk_buff *skb, struct genl_info *info)
+{
+ enum nss_nlgre_redir_cmd_deploy_mode deploy_mode;
+ struct nss_nlgre_redir_rule *nl_rule;
+ struct nss_nlcmn *nl_cm;
+ int ret = 0;
+
+ /*
+ * extract the message payload
+ */
+ nl_cm = nss_nl_get_msg(&nss_nlgre_redir_cmd_family, info, NSS_NLGRE_REDIR_CMD_TYPE_MAP);
+ if (!nl_cm) {
+ nss_nl_error("Unable to extract map interface data\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Message validation required before accepting the configuration
+ */
+ nl_rule = container_of(nl_cm, struct nss_nlgre_redir_rule, cm);
+
+ /*
+ * Map the interface
+ */
+ deploy_mode = nss_nlgre_redir_cmd_get_deploy_mode();
+ if (deploy_mode != NSS_NLGRE_REDIR_CMD_DEPLOY_MODE_LAG) {
+ ret = nss_nlgre_redir_map_interface(&nl_rule->msg.map);
+ if(ret < 0) {
+ nss_nl_error("Unable to map nss interface\n");
+ return -EAGAIN;
+ }
+
+ goto done;
+ }
+
+ ret = nss_nlgre_redir_lag_map_interface(&nl_rule->msg.map);
+ if (ret < 0) {
+ nss_nl_error("Unable to map nss interface\n");
+ return -EAGAIN;
+ }
+done:
+ nss_nl_info("Successfully mapped nss interface.\n");
+ return 0;
+}
+
+/*
+ * nss_nlgre_redir_cmd_ops_unmap()
+ * Handler for unmap command
+ */
+static int nss_nlgre_redir_cmd_ops_unmap(struct sk_buff *skb, struct genl_info *info)
+{
+ struct nss_nlgre_redir_rule *nl_rule;
+ struct nss_nlcmn *nl_cm;
+ int ret = 0;
+
+ /*
+ * extract the message payload
+ */
+ nl_cm = nss_nl_get_msg(&nss_nlgre_redir_cmd_family, info, NSS_NLGRE_REDIR_CMD_TYPE_UNMAP);
+ if (!nl_cm) {
+ nss_nl_error("Unable to extract unmap data\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Message validation required before accepting the configuration
+ */
+ nl_rule = container_of(nl_cm, struct nss_nlgre_redir_rule, cm);
+
+ /*
+ * Unmap the interface
+ */
+ ret = nss_nlgre_redir_cmn_unmap_interface(&nl_rule->msg.unmap);
+ if(ret < 0) {
+ nss_nl_error("Unable to unmap nss interface\n");
+ return -EAGAIN;
+ }
+
+ nss_nl_info("Successfully unmapped the nss interface.\n");
+ return 0;
+}
+
+/*
+ * nss_nlgre_redir_cmd_set_next()
+ * Handler for set_next command
+ */
+static int nss_nlgre_redir_cmd_ops_set_next(struct sk_buff *skb, struct genl_info *info)
+{
+ enum nss_nlgre_redir_cmd_deploy_mode deploy_mode;
+ struct nss_nlgre_redir_rule *nl_rule;
+ struct nss_nlcmn *nl_cm;
+ int ret = 0;
+
+ /*
+ * extract the message payload
+ */
+ nl_cm = nss_nl_get_msg(&nss_nlgre_redir_cmd_family, info, NSS_NLGRE_REDIR_CMD_TYPE_SET_NEXT_HOP);
+ if (!nl_cm) {
+ nss_nl_error("Unable to extract set_next_hop data\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Message validation required before accepting the configuration
+ */
+ nl_rule = container_of(nl_cm, struct nss_nlgre_redir_rule, cm);
+
+ /*
+ * Set the next hop of ath0 as wifi_offld_inner of gre_redir node
+ */
+ deploy_mode = nss_nlgre_redir_cmd_get_deploy_mode();
+ if (deploy_mode != NSS_NLGRE_REDIR_CMD_DEPLOY_MODE_LAG) {
+ ret = nss_nlgre_redir_set_next_hop(&nl_rule->msg.snext);
+ if (ret < 0) {
+ nss_nl_error("Unable to set next hop\n");
+ return -EAGAIN;
+ }
+
+ goto done;
+ }
+
+ /*
+ * Set the next hop of ath0 as lag US node's inner interface
+ */
+ ret = nss_nlgre_redir_lag_set_next_hop(&nl_rule->msg.snext);
+ if (ret < 0) {
+ nss_nl_error("Unable to set the next hop\n");
+ return -EAGAIN;
+ }
+
+done:
+ nss_nl_info("Successfully set the next hop\n");
+ return 0;
+}
+
+/*
+ * nss_nlgre_redir_cmd_add_hash()
+ * Handler for adding hash a value
+ */
+static int nss_nlgre_redir_cmd_ops_add_hash(struct sk_buff *skb, struct genl_info *info)
+{
+ struct nss_nlgre_redir_rule *nl_rule;
+ struct nss_nlcmn *nl_cm;
+ int ret;
+
+ /*
+ * extract the message payload
+ */
+ nl_cm = nss_nl_get_msg(&nss_nlgre_redir_cmd_family, info, NSS_NLGRE_REDIR_CMD_TYPE_ADD_HASH);
+ if (!nl_cm) {
+ nss_nl_error("Unable to add a new hash value.\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Message validation required before accepting the configuration
+ */
+ nl_rule = container_of(nl_cm, struct nss_nlgre_redir_rule, cm);
+ ret = nss_nlgre_redir_lag_add_hash(&nl_rule->msg.hash_ops);
+ if(ret < 0) {
+ nss_nl_error("Unable to add hash value.\n");
+ return -EINVAL;
+ }
+
+ nss_nl_info("Successfully added a hash value.\n");
+ return 0;
+}
+
+/*
+ * nss_nlgre_redir_cmd_del_hash()
+ * Handler for deleting a hash value
+ */
+static int nss_nlgre_redir_cmd_ops_del_hash(struct sk_buff *skb, struct genl_info *info)
+{
+ struct nss_nlgre_redir_rule *nl_rule;
+ struct nss_nlcmn *nl_cm;
+ int ret;
+
+ /*
+ * extract the message payload
+ */
+ nl_cm = nss_nl_get_msg(&nss_nlgre_redir_cmd_family, info, NSS_NLGRE_REDIR_CMD_TYPE_DEL_HASH);
+ if (!nl_cm) {
+ nss_nl_error("Unable to delete the hash value.\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Message validation required before accepting the configuration
+ */
+ nl_rule = container_of(nl_cm, struct nss_nlgre_redir_rule, cm);
+
+ /*
+ * Delete hash value corresponding to smac and dmac
+ */
+ ret = nss_nlgre_redir_lag_del_hash(&nl_rule->msg.hash_ops);
+ if(ret < 0) {
+ nss_nl_error("Unable to delete hash value.\n");
+ return -EINVAL;
+ }
+
+ nss_nl_info("Successfully deleted the hash entry.\n");
+ return 0;
+}
+
+/*
+ * nss_nlgre_redir_cmd_ops
+ * Operation table called by the generic netlink layer based on the command
+ */
+struct genl_ops nss_nlgre_redir_cmd_ops[] = {
+ {.cmd = NSS_NLGRE_REDIR_CMD_TYPE_CREATE_TUN, .doit = nss_nlgre_redir_cmd_ops_tun_create,},
+ {.cmd = NSS_NLGRE_REDIR_CMD_TYPE_DESTROY_TUN, .doit = nss_nlgre_redir_cmd_ops_tun_destroy,},
+ {.cmd = NSS_NLGRE_REDIR_CMD_TYPE_MAP, .doit = nss_nlgre_redir_cmd_ops_map,},
+ {.cmd = NSS_NLGRE_REDIR_CMD_TYPE_UNMAP, .doit = nss_nlgre_redir_cmd_ops_unmap,},
+ {.cmd = NSS_NLGRE_REDIR_CMD_TYPE_SET_NEXT_HOP, .doit = nss_nlgre_redir_cmd_ops_set_next,},
+ {.cmd = NSS_NLGRE_REDIR_CMD_TYPE_ADD_HASH, .doit = nss_nlgre_redir_cmd_ops_add_hash,},
+ {.cmd = NSS_NLGRE_REDIR_CMD_TYPE_DEL_HASH, .doit = nss_nlgre_redir_cmd_ops_del_hash,},
+};
+
+/*
+ * nss_nlgre_redir_cmd_get_ifnum()
+ * Get the interface number corresponding to netdev
+ */
+int nss_nlgre_redir_cmd_get_ifnum(struct net_device* dev, enum nss_dynamic_interface_type type)
+{
+ int ifnum;
+
+ /*
+ * Get the interface number depending upon the dev and type
+ */
+ ifnum = nss_cmn_get_interface_number_by_dev_and_type(dev, type);
+ if (ifnum < 0) {
+ nss_nl_error("%p: Failed to find interface number (dev:%s, type:%d)\n", dev, dev->name, type);
+ return -1;
+ }
+
+ return ifnum;
+}
+
diff --git a/netlink/nss_nlgre_redir_cmd.h b/netlink/nss_nlgre_redir_cmd.h
new file mode 100644
index 0000000..858f82a
--- /dev/null
+++ b/netlink/nss_nlgre_redir_cmd.h
@@ -0,0 +1,51 @@
+/*
+ **************************************************************************
+ * Copyright (c) 2014-2015,2019, 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.
+ **************************************************************************
+ */
+
+/*
+ * nss_nlgre_redir_cmd.h
+ * NSS Netlink gre_redir API definitions
+ */
+#ifndef __NSS_NLGRE_REDIR_CMD_H
+#define __NSS_NLGRE_REDIR_CMD_H
+#define NSS_NLGRE_REDIR_CMD_MAX 7
+/*
+ * nss_nlgre_redir_cmd_deploy_mode
+ * Gre_redir deployment mode types
+ */
+enum nss_nlgre_redir_cmd_deploy_mode {
+ NSS_NLGRE_REDIR_CMD_DEPLOY_MODE_UNKNOWN, /**< Invalid mode */
+ NSS_NLGRE_REDIR_CMD_DEPLOY_MODE_NON_LAG, /**< Basic tunnel mode */
+ NSS_NLGRE_REDIR_CMD_DEPLOY_MODE_LAG, /**< Lag mode */
+ NSS_NLGRE_REDIR_CMD_DEPLOY_MODE_MAX /**< Maximum deploy mode */
+};
+
+/*
+ * To keep track of family operations
+ */
+extern struct genl_family nss_nlgre_redir_cmd_family;
+
+/*
+ * Gre_redir generic netlink operations
+ */
+extern struct genl_ops nss_nlgre_redir_cmd_ops[NSS_NLGRE_REDIR_CMD_MAX];
+
+/*
+ * nss_nlgre_redir_cmd_get_ifnum()
+ * Get the interface number corresponding to netdev
+ */
+int nss_nlgre_redir_cmd_get_ifnum(struct net_device* dev, enum nss_dynamic_interface_type type);
+
+#endif /* __NSS_NLGRE_REDIR_CMD_H */
diff --git a/netlink/nss_nlgre_redir_cmn.c b/netlink/nss_nlgre_redir_cmn.c
new file mode 100644
index 0000000..f927a9d
--- /dev/null
+++ b/netlink/nss_nlgre_redir_cmn.c
@@ -0,0 +1,902 @@
+/*
+ ***************************************************************************
+ * Copyright (c) 2015-2016,2018-2019, 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 <linux/version.h>
+#include <linux/etherdevice.h>
+#include <linux/if_ether.h>
+#include <net/genetlink.h>
+#include <nss_api_if.h>
+#include <nss_nl_if.h>
+#include "nss_nlcmn_if.h"
+#include "nss_nl.h"
+#include "nss_nlgre_redir_if.h"
+#include "nss_nlgre_redir_cmn.h"
+
+static struct nss_nlgre_redir_cmn_tun_data tun_data[NSS_NLGRE_REDIR_CMN_MAX_TUNNELS];
+static const struct net_device_ops gre_redir_netdev_ops;
+static DEFINE_SPINLOCK(lock);
+
+/*
+ * nss_nlgre_redir_cmn_get_tun_data()
+ * Returns the tun_data after checking for lock
+ */
+static struct nss_nlgre_redir_cmn_tun_data nss_nlgre_redir_cmn_get_tun_data(struct net_device *dev)
+{
+ struct nss_nlgre_redir_cmn_tun_data dummy_tun_data = {0};
+ int index;
+
+ spin_lock(&lock);
+ for (index = 0; index < NSS_NLGRE_REDIR_CMN_MAX_TUNNELS; index++) {
+ if (dev != tun_data[index].dev) {
+ continue;
+ }
+
+ spin_unlock(&lock);
+ return tun_data[index];
+ }
+
+ spin_unlock(&lock);
+ return dummy_tun_data;
+}
+
+/*
+ * nss_nlgre_redir_cmn_get_next_free_tun()
+ * Returns the next free tunnel available
+ */
+static int nss_nlgre_redir_cmn_get_next_free_tun(void)
+{
+ int index;
+
+ spin_lock(&lock);
+ for (index = 0; index < NSS_NLGRE_REDIR_CMN_MAX_TUNNELS ; index++) {
+ if (!tun_data[index].enable) {
+ spin_unlock(&lock);
+ return index;
+ }
+ }
+
+ spin_unlock(&lock);
+ nss_nl_error("Max tunnel count exceeded: %d\n", index);
+ return -1;
+}
+
+/*
+ * nss_nlgre_redir_cmn_set_tun_data()
+ * Set the tun_data value to value passed
+ */
+static bool nss_nlgre_redir_cmn_set_tun_data(struct nss_nlgre_redir_cmn_tun_data *data, int index)
+{
+ if (!data) {
+ nss_nl_error("data is NULL\n");
+ return false;
+ }
+
+ spin_lock(&lock);
+ tun_data[index] = *data;
+ spin_unlock(&lock);
+ return true;
+}
+
+/*
+ * nss_nlgre_redir_cmn_init_tun_data()
+ * Initializes the tun_data
+ */
+static void nss_nlgre_redir_cmn_init_tun_data(struct nss_nlgre_redir_cmn_tun_data *tun_data)
+{
+ tun_data->dev = NULL;
+ tun_data->enable = false;
+ tun_data->host_inner_ifnum = -1;
+ tun_data->wifi_offl_inner_ifnum = -1;
+ tun_data->sjack_inner_ifnum = -1;
+ tun_data->outer_ifnum = -1;
+}
+
+/*
+ * nss_nlgre_redir_cmn_deinit_tun_data()
+ * Deinitialize private data for the given index.
+ */
+static bool nss_nlgre_redir_cmn_deinit_tun_data(struct nss_nlgre_redir_cmn_tun_data *tun_data, int index)
+{
+ struct nss_ctx_instance *nss_ctx;
+
+ nss_ctx = nss_gre_redir_get_context();
+ tun_data->dev = NULL;
+ tun_data->enable = false;
+ tun_data->host_inner_ifnum = -1;
+ tun_data->wifi_offl_inner_ifnum = -1;
+ tun_data->sjack_inner_ifnum = -1;
+ tun_data->outer_ifnum = -1;
+
+ if (!nss_nlgre_redir_cmn_set_tun_data(tun_data, index)) {
+ nss_nl_error("%p: Unable to set tun_data\n", nss_ctx);
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * nss_nlgre_redir_cmn_host_data_cb()
+ * Data callback for host offload inner node.
+ */
+static void nss_nlgre_redir_cmn_host_data_cb(struct net_device *netdev, struct sk_buff *skb, struct napi_struct *napi)
+{
+ struct nss_ctx_instance *nss_ctx = nss_gre_redir_get_context();
+ struct nss_gre_redir_decap_per_pkt_metadata *meta_data_decap = NULL;
+
+ if (!skb) {
+ nss_nl_trace("%p: SKB is NULL\n", nss_ctx);
+ return;
+ }
+
+ meta_data_decap = (struct nss_gre_redir_decap_per_pkt_metadata *)(skb->data - NSS_GRE_REDIR_PER_PACKET_METADATA_OFFSET);
+ skb->protocol = eth_type_trans(skb, netdev);
+ netif_receive_skb(skb);
+}
+
+/*
+ * nss_nlgre_redir_cmn_wifi_offl_data_cb()
+ * Data callback for wifi offload inner node.
+ */
+static void nss_nlgre_redir_cmn_wifi_offl_data_cb(struct net_device *netdev, struct sk_buff *skb, struct napi_struct *napi)
+{
+ nss_nl_trace("%p: Exception packet on wifi offld inner:\n", skb);
+ nss_nlgre_redir_cmn_print_skb(skb);
+ dev_kfree_skb(skb);
+}
+
+/*
+ * nss_nlgre_redir_cmn_sjack_data_cb
+ * Data callback for sjack inner node.
+ */
+static void nss_nlgre_redir_cmn_sjack_data_cb(struct net_device *netdev, struct sk_buff *skb, struct napi_struct *napi)
+{
+ nss_nl_trace("%p: Exception packet on sjack inner node:\n", skb);
+ nss_nlgre_redir_cmn_print_skb(skb);
+ dev_kfree_skb(skb);
+}
+
+/*
+ * nss_nlgre_redir_cmn_outer_data_cb()
+ * Data callback for outer node.
+ */
+static void nss_nlgre_redir_cmn_outer_data_cb(struct net_device *netdev, struct sk_buff *skb, struct napi_struct *napi)
+{
+ nss_nl_trace("%p: Exception packet on outer node:\n", skb);
+ nss_nlgre_redir_cmn_print_skb(skb);
+ dev_kfree_skb(skb);
+}
+
+/*
+ * nss_nlgre_redir_cmn_map_unmap_msg_cb()
+ * HLOS->NSS message completion callback.
+ */
+static void nss_nlgre_redir_cmn_map_unmap_msg_cb(void *app_data, struct nss_cmn_msg *cmnmsg)
+{
+ struct nss_ctx_instance *nss_ctx = nss_gre_redir_get_context();
+ nss_nl_info("%p: callback gre_redir tunnel msg from NSS\n", nss_ctx);
+}
+
+/*
+ * nss_nlgre_redir_cmn_interface_alloc_and_register()
+ * Allocates nodes and registers callbacks
+ */
+static int nss_nlgre_redir_cmn_interface_alloc_and_register(struct nss_nlgre_redir_cmn_tun_data *tun_data, struct net_device *dev)
+{
+ struct nss_ctx_instance *nss_ctx = nss_gre_redir_get_context();
+
+ tun_data->host_inner_ifnum = nss_gre_redir_alloc_and_register_node(dev,
+ nss_nlgre_redir_cmn_host_data_cb,
+ NULL, NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_WIFI_HOST_INNER, dev);
+ nss_nl_info("%p: host_inner = %d\n", nss_ctx, tun_data->host_inner_ifnum);
+ if (tun_data->host_inner_ifnum == -1) {
+ nss_nl_error("%p: Unable to allocate and register wifi host inner interface\n", nss_ctx);
+ return -1;
+ }
+
+ tun_data->wifi_offl_inner_ifnum = nss_gre_redir_alloc_and_register_node(dev,
+ nss_nlgre_redir_cmn_wifi_offl_data_cb,
+ NULL, NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_WIFI_OFFL_INNER, dev);
+ nss_nl_info("%p: wifi_inner = %d\n", nss_ctx, tun_data->wifi_offl_inner_ifnum);
+ if (tun_data->wifi_offl_inner_ifnum == -1) {
+ nss_nl_error("%p: Unable to allocate and register wifi offload inner interface\n", nss_ctx);
+ return -1;
+ }
+
+ tun_data->sjack_inner_ifnum = nss_gre_redir_alloc_and_register_node(dev,
+ nss_nlgre_redir_cmn_sjack_data_cb,
+ NULL, NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_SJACK_INNER, dev);
+ nss_nl_info("%p: sjack_inner = %d\n", nss_ctx, tun_data->sjack_inner_ifnum);
+ if (tun_data->sjack_inner_ifnum == -1) {
+ nss_nl_error("%p: Unable to allocate and register sjack inner interface\n", nss_ctx);
+ return -1;
+ }
+
+ tun_data->outer_ifnum = nss_gre_redir_alloc_and_register_node(dev,
+ nss_nlgre_redir_cmn_outer_data_cb,
+ NULL, NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_OUTER, dev);
+ nss_nl_info("%p: outer = %d\n", nss_ctx, tun_data->outer_ifnum);
+ if (tun_data->outer_ifnum == -1) {
+ nss_nl_error("%p: Unable to allocate and register outer interface\n", nss_ctx);
+ return -1;
+ }
+
+ return 0;
+
+}
+
+/*
+ * nss_nlgre_redir_cmn_open_interface()
+ * Used when the interface is opened for use.
+ */
+static int nss_nlgre_redir_cmn_open_interface(struct net_device *dev)
+{
+ struct nss_gre_redir_cmn_ndev_priv *priv;
+ priv = netdev_priv(dev);
+ priv->gre_seq = 0;
+ netif_start_queue(dev);
+ netif_carrier_on(dev);
+ return 0;
+}
+
+/*
+ * nss_nlgre_redir_cmn_close_interace()
+ * Used when the interface is closed.
+ */
+static int nss_nlgre_redir_cmn_close_interface(struct net_device *dev)
+{
+ netif_stop_queue (dev);
+ netif_carrier_off(dev);
+ return 0;
+}
+
+/*
+ * nss_nlgre_redir_cmn_xmit_data()
+ * Used when the interface is used for transmit data.
+ */
+static netdev_tx_t nss_nlgre_redir_cmn_xmit_data(struct sk_buff *skb, struct net_device *dev)
+{
+ struct nss_gre_redir_encap_per_pkt_metadata *meta_data_encap = NULL;
+ struct nss_gre_redir_cmn_ndev_priv *priv;
+ uint32_t ifnum, ret = 0;
+ struct nss_ctx_instance *nss_ctx;
+
+ nss_ctx = nss_gre_redir_get_context();
+ priv = netdev_priv(dev);
+ ifnum = nss_cmn_get_interface_number_by_dev_and_type(dev, NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_WIFI_HOST_INNER);
+
+ /*
+ * Initializing the start of skb with offset of metadata
+ */
+ *(skb->head) = NSS_GRE_REDIR_PER_PACKET_METADATA_OFFSET;
+
+ /*
+ * Configuring gre_redir meta data.
+ */
+ meta_data_encap = (struct nss_gre_redir_encap_per_pkt_metadata *)(skb->data - NSS_GRE_REDIR_PER_PACKET_METADATA_OFFSET);
+ memset(meta_data_encap, 0, sizeof(struct nss_gre_redir_encap_per_pkt_metadata));
+ meta_data_encap->gre_flags = 0;
+ meta_data_encap->gre_prio = 0;
+ meta_data_encap->gre_seq = ++priv->gre_seq;
+ meta_data_encap->gre_tunnel_id = 10;
+ meta_data_encap->ip_dscp = 0;
+ meta_data_encap->ip_df_override = 0;
+ meta_data_encap->ipsec_pattern = 0;
+
+ nss_ctx = nss_gre_redir_get_context();
+ ret = nss_gre_redir_tx_buf(nss_ctx, skb, ifnum);
+ if (ret != NSS_TX_SUCCESS) {
+ nss_nl_error("%p: Transmit failed and returned with %d\n", nss_ctx, ret);
+ dev_kfree_skb_any(skb);
+ }
+
+ return ret;
+}
+
+/*
+ * nss_nlgre_redir_cmn_stats64_get()
+ * Used to get link statistics.
+ */
+static struct rtnl_link_stats64 *nss_nlgre_redir_cmn_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
+{
+ struct nss_gre_redir_tunnel_stats get_stats;
+ bool found = false;
+ int i;
+
+ for (i = 0; i < NSS_GRE_REDIR_MAX_INTERFACES; i++) {
+ if (!nss_gre_redir_get_stats(i, &get_stats)) {
+ continue;
+ }
+
+ if (get_stats.dev != dev) {
+ continue;
+ }
+
+ found = true;
+ break;
+ }
+
+ if (found == false)
+ return NULL;
+
+ stats->tx_bytes = get_stats.node_stats.tx_bytes;
+ stats->tx_packets = get_stats.node_stats.tx_packets;
+ stats->rx_bytes = get_stats.node_stats.rx_bytes;
+ stats->rx_packets = get_stats.node_stats.rx_packets;
+ for (i = 0;i < ARRAY_SIZE(get_stats.node_stats.rx_dropped); i++) {
+ stats->rx_dropped += get_stats.node_stats.rx_dropped[i];
+ }
+
+ stats->tx_dropped = get_stats.tx_dropped;
+
+ return stats;
+}
+
+/*
+ * nss_nlgre_redir_cmn_set_mac_address()
+ * Sets the mac address of netdev
+ */
+static int nss_nlgre_redir_cmn_set_mac_address(struct net_device *dev, void *p)
+{
+ struct sockaddr *addr = (struct sockaddr *)p;
+
+ if (!is_valid_ether_addr(addr->sa_data)) {
+ nss_nl_error("%pM: MAC address validation failed\n", addr->sa_data);
+ return -EINVAL;
+ }
+
+ memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
+ return 0;
+}
+
+/*
+ * nss_nlgre_redir_cmn_netdev_destructor()
+ * Unregisters and free the net device
+ */
+static void nss_nlgre_redir_cmn_netdev_destructor(struct net_device *dev)
+{
+ nss_nl_info("Gre_redir tunnel device freed %s\n", dev->name);
+ free_netdev(dev);
+}
+
+/*
+ * nss_nlgre_redir_cmn_dev_setup()
+ * To setup the netdevice
+ */
+static void nss_nlgre_redir_cmn_dev_setup(struct net_device *dev)
+{
+ ether_setup(dev);
+ dev->needed_headroom = NSS_NLGRE_REDIR_CMN_NEEDED_HEADROOM;
+ dev->netdev_ops = &gre_redir_netdev_ops;
+ dev->destructor = nss_nlgre_redir_cmn_netdev_destructor;
+ eth_hw_addr_random(dev);
+}
+
+/*
+ * net_device_ops
+ * Netdevice operations.
+ */
+static const struct net_device_ops gre_redir_netdev_ops = {
+ .ndo_open = nss_nlgre_redir_cmn_open_interface,
+ .ndo_stop = nss_nlgre_redir_cmn_close_interface,
+ .ndo_start_xmit = nss_nlgre_redir_cmn_xmit_data,
+ .ndo_get_stats64 = nss_nlgre_redir_cmn_get_stats64,
+ .ndo_set_mac_address = nss_nlgre_redir_cmn_set_mac_address,
+};
+
+/*
+ * nss_nlgre_redir_cmn_mode_str_to_enum()
+ * Returns the type of mode
+ */
+enum nss_nlgre_redir_cmn_mode_type nss_nlgre_redir_cmn_mode_str_to_enum(char *mode)
+{
+ if (!mode)
+ return NSS_NLGRE_REDIR_CMN_MODE_TYPE_UNKNOWN;
+ if (!strncmp(mode, "wifi", NSS_NLGRE_REDIR_MODE_MAX_SZ))
+ return NSS_NLGRE_REDIR_CMN_MODE_TYPE_WIFI;
+ if (!strncmp(mode, "split", NSS_NLGRE_REDIR_MODE_MAX_SZ))
+ return NSS_NLGRE_REDIR_CMN_MODE_TYPE_SPLIT;
+
+ return NSS_NLGRE_REDIR_CMN_MODE_TYPE_UNKNOWN;
+}
+
+/*
+ * nss_nlgre_redir_cmn_get_tun_ifnum()
+ * Returns the interface number of the net device
+ */
+int32_t nss_nlgre_redir_cmn_get_tun_ifnum(enum nss_nlgre_redir_cmn_mode_type type, struct net_device *dev)
+{
+ struct nss_nlgre_redir_cmn_tun_data tun_data;
+
+ if (!dev) {
+ nss_nl_error("net_dev is NULL\n");
+ return -1;
+ }
+
+ tun_data = nss_nlgre_redir_cmn_get_tun_data(dev);
+ if (!tun_data.dev) {
+ nss_nl_error("Invalid tun_data: %p\n", tun_data.dev);
+ return -1;
+ }
+
+ switch(type) {
+ case NSS_NLGRE_REDIR_CMN_MODE_TYPE_WIFI:
+ return tun_data.wifi_offl_inner_ifnum;
+ case NSS_NLGRE_REDIR_CMN_MODE_TYPE_SPLIT:
+ return NSS_ETH_RX_INTERFACE;
+ default:
+ nss_nl_error("Wrong mode type: %d\n", type);
+ return -1;
+ }
+
+ return -1;
+}
+
+/*
+ * nss_nlgre_redir_cmn_get_tun_type()
+ * Returns the type of tunnel we'll operate in
+ */
+enum nss_nlgre_redir_cmn_tun_type nss_nlgre_redir_cmn_get_tun_type(char *tun_type)
+{
+ if (!tun_type)
+ return NSS_NLGRE_REDIR_CMN_TUN_TYPE_UNKNOWN;
+ if (!strncmp(tun_type, "tun", NSS_NLGRE_REDIR_CMN_TUN_TYPE_MAX_SZ))
+ return NSS_NLGRE_REDIR_CMN_TUN_TYPE_TUN;
+ if (!strncmp(tun_type, "dtun", NSS_NLGRE_REDIR_CMN_TUN_TYPE_MAX_SZ))
+ return NSS_NLGRE_REDIR_CMN_TUN_TYPE_DTUN;
+ if (!strncmp(tun_type, "split", NSS_NLGRE_REDIR_CMN_TUN_TYPE_MAX_SZ))
+ return NSS_NLGRE_REDIR_CMN_TUN_TYPE_SPLIT;
+
+ return NSS_NLGRE_REDIR_CMN_TUN_TYPE_UNKNOWN;
+}
+
+/*
+ * nss_nlgre_redir_cmn_get_tun_data_index()
+ * Returns index in array of private data.
+ */
+int nss_nlgre_redir_cmn_get_tun_data_index(struct net_device *dev)
+{
+ struct nss_ctx_instance *nss_ctx;
+ uint32_t iter;
+
+ nss_ctx = nss_gre_redir_get_context();
+ if (!dev) {
+ nss_nl_error("%p: Dev is NULL\n", nss_ctx);
+ return -1;
+ }
+
+ spin_lock(&lock);
+ for (iter = 0; iter < NSS_NLGRE_REDIR_CMN_MAX_TUNNELS; iter++) {
+ if (tun_data[iter].dev != dev) {
+ continue;
+ }
+
+ spin_unlock(&lock);
+ return iter;
+ }
+
+ spin_unlock(&lock);
+ return -1;
+}
+
+/*
+ * nss_nlgre_redir_cmn_print_skb()
+ * Prints the skb data
+ */
+void nss_nlgre_redir_cmn_print_skb(struct sk_buff *skb)
+{
+ int length;
+ int iter;
+
+ /*
+ * Check if length is less than 16 bytes
+ * Else bring down to minimum multiple of 16 bytes.
+ */
+ if (skb->len < 16) {
+ nss_nl_trace("%p: Skb too small to print min size: 16 bytes\n", skb);
+ return;
+ }
+
+ length = (skb->len / 16);
+ if (length > NSS_NLGRE_REDIR_CMN_MAX_SKB_PRINT_LEN)
+ length = NSS_NLGRE_REDIR_CMN_MAX_SKB_PRINT_LEN;
+
+ /*
+ * Print first 48 bytes of sk_buff
+ */
+ for (iter = 0; iter < length; iter++) {
+ nss_nl_trace("%04xx: %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x\n", iter,
+ skb->data[iter * 8], skb->data[iter * 8 + 1], skb->data[iter * 8 + 2], skb->data[iter * 8 + 3],
+ skb->data[iter * 8 + 4], skb->data[iter * 8 + 5], skb->data[iter * 8 + 6], skb->data[iter * 8 + 7],
+ skb->data[iter * 8 + 8], skb->data[iter * 8 + 9], skb->data[iter * 8 + 10], skb->data[iter * 8 + 11],
+ skb->data[iter * 8 + 10], skb->data[iter * 8 + 13], skb->data[iter * 8 + 14], skb->data[iter * 8 + 15]);
+ }
+}
+
+/*
+ * nss_gre_redir_unregister_and_deallocate()
+ * Unregisters and deallocates corresponding dev and node.
+ */
+bool nss_nlgre_redir_cmn_unregister_and_deallocate(struct net_device *dev, uint32_t type)
+{
+ nss_tx_status_t status;
+ int ifnum;
+ bool ret;
+
+ ifnum = nss_cmn_get_interface_number_by_dev_and_type(dev, type);
+ if (ifnum == -1) {
+ nss_nl_error("%p: unable to get NSS interface for net device %s of type %d\n", dev, dev->name, type);
+ return false;
+ }
+
+ ret = nss_gre_redir_unregister_if(ifnum);
+ if (!ret) {
+ nss_nl_error("%p: Unable to unregister interface %d\n", dev, ret);
+ return false;
+ }
+
+ status = nss_dynamic_interface_dealloc_node(ifnum, type);
+ if (status != NSS_TX_SUCCESS) {
+ nss_nl_error("%p: Unable to deallocate node %d\n", dev, status);
+ return false;
+ }
+
+ nss_nl_trace("%s: Sucessfully unregistered and deallocated %d\n", dev->name, ifnum);
+ return true;
+}
+
+/*
+ * nss_nlgre_redir_cmn_interfaces_unregister_and_dealloc
+ * Find out the interfaces to be deallocated
+ */
+void nss_nlgre_redir_cmn_interfaces_unregister_and_dealloc(struct nss_nlgre_redir_cmn_tun_data *tun_data)
+{
+ struct nss_ctx_instance *nss_ctx;
+
+ nss_ctx = nss_gre_redir_get_context();
+ if (tun_data->sjack_inner_ifnum != -1) {
+ if(!nss_nlgre_redir_cmn_unregister_and_deallocate(tun_data->dev, NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_WIFI_HOST_INNER)) {
+ nss_nl_error("%p: Unable to unregister and deallocate node of type %d\n", nss_ctx,
+ NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_WIFI_HOST_INNER);
+ }
+ }
+
+ if (tun_data->wifi_offl_inner_ifnum != -1) {
+ if (!nss_nlgre_redir_cmn_unregister_and_deallocate(tun_data->dev, NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_WIFI_OFFL_INNER)) {
+ nss_nl_error("%p: Unable to unregister and deallocate node of type %d\n", nss_ctx,
+ NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_WIFI_OFFL_INNER);
+ }
+ }
+
+ if (tun_data->host_inner_ifnum != -1) {
+ if (!nss_nlgre_redir_cmn_unregister_and_deallocate(tun_data->dev, NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_SJACK_INNER)) {
+ nss_nl_error("%p: Unable to unregister and deallocate node of type %d\n", nss_ctx,
+ NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_SJACK_INNER);
+ }
+ }
+
+ if (tun_data->outer_ifnum != -1) {
+ if (!nss_nlgre_redir_cmn_unregister_and_deallocate(tun_data->dev, NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_OUTER)) {
+ nss_nl_error("%p: Unable to unregister and deallocate node of type %d\n", nss_ctx,
+ NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_OUTER);
+ }
+ }
+
+ nss_nl_trace("%s: Sucessfully unregistered and deallocated\n", tun_data->dev->name);
+}
+
+/*
+ * nss_nlgre_redir_cmn_destroy_tun()
+ * Unregisters and deallocs dynamic interfaces.
+ */
+int nss_nlgre_redir_cmn_destroy_tun(struct net_device *dev)
+{
+ struct nss_ctx_instance *nss_ctx = nss_gre_redir_get_context();
+ struct nss_nlgre_redir_cmn_tun_data tun_data;
+ int index;
+
+ dev_hold(dev);
+ tun_data = nss_nlgre_redir_cmn_get_tun_data(dev);
+ if (!tun_data.dev) {
+ nss_nl_error("%p: Invalid tun data\n", nss_ctx);
+ return -1;
+ }
+
+ index = nss_nlgre_redir_cmn_get_tun_data_index(tun_data.dev);
+ if (index < NSS_NLGRE_REDIR_CMN_MIN_TUNNELS || index >= NSS_NLGRE_REDIR_CMN_MAX_TUNNELS) {
+ nss_nl_error("%p: index out of bound %d\n", nss_ctx, index);
+ return -1;
+ }
+
+ nss_nlgre_redir_cmn_interfaces_unregister_and_dealloc(&tun_data);
+ nss_nlgre_redir_cmn_deinit_tun_data(&tun_data, index);
+ dev_put(dev);
+ unregister_netdev(dev);
+ nss_nl_info("%p: Successfully destroyed gretun = gretun%d tunnel\n", dev, index);
+ return index;
+}
+
+/*
+ * nss_nlgre_redir_cmn_create_tun()
+ * Allocates netdevice and configures tunnel.
+ */
+struct net_device *nss_nlgre_redir_cmn_create_tun(uint32_t sip[4], uint32_t dip[4], uint8_t iptype)
+{
+ struct nss_ctx_instance *nss_ctx = nss_gre_redir_get_context();
+ struct nss_gre_redir_outer_configure_msg ngrocm = {0};
+ struct nss_gre_redir_inner_configure_msg ngrm = {0};
+ struct nss_nlgre_redir_cmn_tun_data tun_data;
+ struct nss_gre_redir_cmn_ndev_priv *priv;
+ struct net_device *dev;
+ nss_tx_status_t status;
+ int tun_idx = -1, ret;
+
+ tun_idx = nss_nlgre_redir_cmn_get_next_free_tun();
+ if (tun_idx == -1) {
+ nss_nl_error("Unable to allocate any tunnel\n");
+ return NULL;
+ }
+
+ /*
+ * Initializes the tun_data
+ */
+ nss_nlgre_redir_cmn_init_tun_data(&tun_data);
+ dev = alloc_netdev(sizeof(*priv), "gretun%d", NET_NAME_UNKNOWN, nss_nlgre_redir_cmn_dev_setup);
+ if (!dev) {
+ nss_nl_error("Unable to allocate netdev\n");
+ return NULL;
+ }
+
+ if (register_netdev(dev)) {
+ nss_nl_warn("Unable to register netdev %s\n", dev->name);
+ free_netdev(dev);
+ goto fail;
+ }
+
+ /*
+ * Dynamic interface allocation.
+ */
+ ret = nss_nlgre_redir_cmn_interface_alloc_and_register(&tun_data, dev);
+ if (ret == -1) {
+ nss_nl_error("%p: Unable to allocate and register gre_redir nodes\n", nss_ctx);
+ unregister_netdev(dev);
+ goto fail;
+ }
+
+ memcpy(ngrm.ip_src_addr, sip, sizeof(ngrm.ip_src_addr));
+ memcpy(ngrm.ip_dest_addr, dip, sizeof(ngrm.ip_dest_addr));
+
+ /*
+ * TODO: Dynamic assignment of values from userspace
+ * ip_df_policy value currently hard coded. This needs to be supplied from userspace.
+ */
+ ngrm.ip_hdr_type = iptype;
+ ngrm.ip_df_policy = 0;
+ ngrm.gre_version = 0;
+ ngrm.ip_ttl = NSS_NLGRE_REDIR_CMN_IP_TTL;
+ ngrm.except_outerif = tun_data.outer_ifnum;
+
+ /*
+ * TODO: Dynamic assignment of values from userspace
+ * rps_hint value currently hard coded. This needs to be supplied from userspace.
+ */
+ ngrocm.ip_hdr_type = iptype;
+ ngrocm.rps_hint = 0;
+ ngrocm.except_hostif = tun_data.host_inner_ifnum;
+ ngrocm.except_offlif = tun_data.wifi_offl_inner_ifnum;
+ ngrocm.except_sjackif = tun_data.sjack_inner_ifnum;
+
+ status = nss_gre_redir_configure_inner_node(tun_data.host_inner_ifnum, &ngrm);
+ if (status != NSS_TX_SUCCESS) {
+ nss_nl_warn("%p: unable to configure host inner node %d\n", nss_ctx, tun_data.host_inner_ifnum);
+ unregister_netdev(dev);
+ goto fail;
+ }
+
+ status = nss_gre_redir_configure_inner_node(tun_data.wifi_offl_inner_ifnum, &ngrm);
+ if (status != NSS_TX_SUCCESS) {
+ nss_nl_warn("%p: unable to configure wifi offload inner node %d\n", nss_ctx, tun_data.host_inner_ifnum);
+ unregister_netdev(dev);
+ goto fail;
+ }
+
+ status = nss_gre_redir_configure_inner_node(tun_data.sjack_inner_ifnum, &ngrm);
+ if (status != NSS_TX_SUCCESS) {
+ nss_nl_warn("%p: unable to configure sjack inner node %d\n", nss_ctx, tun_data.sjack_inner_ifnum);
+ unregister_netdev(dev);
+ goto fail;
+ }
+
+ status = nss_gre_redir_configure_outer_node(tun_data.outer_ifnum, &ngrocm);
+ if (status != NSS_TX_SUCCESS) {
+ nss_nl_warn("%p: unable to configure outer node %d\n", nss_ctx, tun_data.host_inner_ifnum);
+ unregister_netdev(dev);
+ goto fail;
+ }
+
+ tun_data.enable = true;
+ tun_data.dev = dev;
+ if (!nss_nlgre_redir_cmn_set_tun_data(&tun_data, tun_idx)) {
+ nss_nl_error("%p: Unable to set tun data\n", nss_ctx);
+ unregister_netdev(dev);
+ goto fail;
+ }
+
+ return dev;
+fail:
+ nss_nlgre_redir_cmn_interfaces_unregister_and_dealloc(&tun_data);
+ nss_nlgre_redir_cmn_deinit_tun_data(&tun_data, tun_idx);
+ return NULL;
+}
+
+/*
+ * nss_nlgre_redir_cmn_get_dev_ifnum()
+ * Returns the interface number by dev and type
+ */
+int32_t nss_nlgre_redir_cmn_get_dev_ifnum(char *dev_name)
+{
+ struct net_device *dev;
+ uint32_t ifnum;
+
+ if (!dev_name) {
+ nss_nl_error("dev_name is NULL\n");
+ return -1;
+ }
+
+ /*
+ * Get the dev reference
+ */
+ dev = dev_get_by_name(&init_net, dev_name);
+ if (!dev) {
+ nss_nl_error("Invalid parameter: %s\n", dev_name);
+ return -ENODEV;
+ }
+
+ ifnum = nss_cmn_get_interface_number_by_dev(dev);
+ dev_put(dev);
+ return ifnum;
+}
+
+/*
+ * nss_nlgre_redir_cmn_map_interface()
+ * Map nss interface to tunnel ID.
+ */
+int nss_nlgre_redir_cmn_map_interface(uint32_t nexthop_nssif, uint16_t lag_en, struct nss_nlgre_redir_map *map_params)
+{
+ struct nss_gre_redir_msg ngrm;
+ struct nss_ctx_instance *nss_ctx;
+ nss_tx_status_t ret;
+ uint32_t vap_nss_if;
+ uint8_t tun_type;
+ uint32_t len;
+
+ len = sizeof(struct nss_gre_redir_msg) - sizeof(struct nss_cmn_msg);
+ nss_ctx = nss_gre_redir_get_context();
+ tun_type = nss_nlgre_redir_cmn_get_tun_type(map_params->tun_type);
+ vap_nss_if = nss_nlgre_redir_cmn_get_dev_ifnum(map_params->vap_nss_if);
+ if ((vap_nss_if >= NSS_DYNAMIC_IF_START+NSS_MAX_DYNAMIC_INTERFACES) || (vap_nss_if < NSS_DYNAMIC_IF_START)) {
+ nss_nl_error("%p: vap_nss_if is out of valid range for vap: %d\n", nss_ctx, vap_nss_if);
+ return -1;
+ }
+
+ if (map_params->rid >= NSS_NLGRE_REDIR_CMN_RADIO_ID_MAX) {
+ nss_nl_error("%p: radio_id is out of valid range for vap: %d\n", nss_ctx, vap_nss_if);
+ return -1;
+ }
+
+ if (map_params->vid >= NSS_NLGRE_REDIR_CMN_VAP_ID_MAX) {
+ nss_nl_error("%p: vap_id is out of valid range for vap: %d\n", nss_ctx, vap_nss_if);
+ return -1;
+ }
+
+ nss_cmn_msg_init(&ngrm.cm, NSS_GRE_REDIR_INTERFACE, NSS_GRE_REDIR_TX_INTERFACE_MAP_MSG,
+ len, nss_nlgre_redir_cmn_map_unmap_msg_cb, NULL);
+
+ ngrm.msg.interface_map.vap_nssif = vap_nss_if;
+ ngrm.msg.interface_map.radio_id = map_params->rid;
+ ngrm.msg.interface_map.vap_id = map_params->vid;
+ ngrm.msg.interface_map.tunnel_type = tun_type;
+ ngrm.msg.interface_map.ipsec_pattern = map_params->ipsec_sa_pattern;
+ ngrm.msg.interface_map.lag_en = lag_en;
+ ngrm.msg.interface_map.nexthop_nssif = nexthop_nssif;
+
+ ret = nss_gre_redir_tx_msg_sync(nss_ctx, &ngrm);
+ if (ret != NSS_TX_SUCCESS) {
+ nss_nl_error("%p: Tx to firmware failed\n", nss_ctx);
+ return -1;
+ }
+
+ nss_nl_info("%p: Successfully transmitted msg to firmware\n", nss_ctx);
+ return 0;
+}
+
+/*
+ * nss_nlgre_redir_cmn_unmap_interface()
+ * Interface unmap message.
+ */
+int nss_nlgre_redir_cmn_unmap_interface(struct nss_nlgre_redir_unmap *unmap_params)
+{
+ struct nss_ctx_instance *nss_ctx;
+ struct nss_gre_redir_msg ngrm;
+ uint32_t vap_nss_if, len;
+ nss_tx_status_t ret;
+
+ len = sizeof(struct nss_gre_redir_msg) - sizeof(struct nss_cmn_msg);
+ vap_nss_if = nss_nlgre_redir_cmn_get_dev_ifnum(unmap_params->vap_nss_if);
+ nss_ctx = nss_gre_redir_get_context();
+
+ if ((vap_nss_if >= NSS_DYNAMIC_IF_START+NSS_MAX_DYNAMIC_INTERFACES) || (vap_nss_if < NSS_DYNAMIC_IF_START)) {
+ nss_nl_error("%p: vap_nss_if is out of valid range for vap: %d\n", nss_ctx, vap_nss_if);
+ return -1;
+ }
+
+ if (unmap_params->rid >= NSS_NLGRE_REDIR_CMN_RADIO_ID_MAX) {
+ nss_nl_error("%p: radio_id is out of valid range for vap: %d\n", nss_ctx, vap_nss_if);
+ return -1;
+ }
+
+ if (unmap_params->vid >= NSS_NLGRE_REDIR_CMN_VAP_ID_MAX) {
+ nss_nl_error("%p: vap_id is out of valid range for vap: %d\n", nss_ctx, vap_nss_if);
+ return -1;
+ }
+
+ nss_cmn_msg_init(&ngrm.cm, NSS_GRE_REDIR_INTERFACE, NSS_GRE_REDIR_TX_INTERFACE_UNMAP_MSG,
+ len, nss_nlgre_redir_cmn_map_unmap_msg_cb, NULL);
+ ngrm.msg.interface_unmap.vap_nssif = vap_nss_if;
+ ngrm.msg.interface_unmap.radio_id = unmap_params->rid;
+ ngrm.msg.interface_unmap.vap_id = unmap_params->vid;
+
+ ret = nss_gre_redir_tx_msg_sync(nss_ctx, &ngrm);
+ if (ret != NSS_TX_SUCCESS) {
+ nss_nl_error("%p: Tx to firmware failed\n", nss_ctx);
+ return -1;
+ }
+
+ nss_nl_info("%p: Successfully transmitted msg to firmware\n", nss_ctx);
+ return 0;
+}
+
+/*
+ * nss_nlgre_redir_cmn_set_next_hop()
+ * Sets next hop as gre-redir for wifi.
+ */
+int nss_nlgre_redir_cmn_set_next_hop(uint32_t next_dev_ifnum, struct nss_nlgre_redir_set_next *setnext_params)
+{
+ struct nss_ctx_instance *nss_ctx;
+ nss_tx_status_t ret;
+ int ifnumber;
+ void *ctx;
+
+ nss_ctx = nss_gre_redir_get_context();
+ ifnumber = nss_nlgre_redir_cmn_get_dev_ifnum(setnext_params->dev_name);
+ if (ifnumber == -1) {
+ nss_nl_error("%p: Unable to find NSS interface for net device %s\n", nss_ctx, setnext_params->dev_name);
+ return -1;
+ }
+
+ nss_nl_info("%p: next hop interface number is %d\n", nss_ctx, next_dev_ifnum);
+ ctx = nss_wifi_get_context();
+
+ ret = nss_wifi_vdev_set_next_hop(ctx, ifnumber, next_dev_ifnum);
+ if (ret != NSS_TX_SUCCESS) {
+ nss_nl_error("%p: wifi drv api failed to set next hop\n", nss_ctx);
+ return -1;
+ }
+
+ nss_nl_info("%p: Successfully set the next hop\n", nss_ctx);
+ return 0;
+}
+
diff --git a/netlink/nss_nlgre_redir_cmn.h b/netlink/nss_nlgre_redir_cmn.h
new file mode 100644
index 0000000..64daaaa
--- /dev/null
+++ b/netlink/nss_nlgre_redir_cmn.h
@@ -0,0 +1,155 @@
+/*
+ ***************************************************************************
+ * Copyright (c) 2014-2015,2019, 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.
+ **************************************************************************
+ */
+
+/*
+ * NSS Netlink gre_redir headers
+ */
+#define NSS_NLGRE_REDIR_CMN_NEEDED_HEADROOM 192 /**< Maximum headroom available */
+#define NSS_NLGRE_REDIR_CMN_RADIO_ID_MAX 2 /**< Radio Id max size */
+#define NSS_NLGRE_REDIR_CMN_RADIO_ID_MIN 0 /**< Radio Id min size */
+#define NSS_NLGRE_REDIR_CMN_VAP_ID_MAX 16 /**< Vap Id max size */
+#define NSS_NLGRE_REDIR_CMN_VAP_ID_MIN 0 /**< Vap Id min size */
+#define NSS_NLGRE_REDIR_CMN_MAX_TUNNELS 24 /**< Maximum number of tunnels allowed */
+#define NSS_NLGRE_REDIR_CMN_TUN_TYPE_MAX_SZ 16 /**< Maximum size of tunnel type */
+#define NSS_NLGRE_REDIR_CMN_MAX_SKB_PRINT_LEN 3 /**< Maximum length of skb to print */
+#define NSS_NLGRE_REDIR_CMN_MIN_TUNNELS 0 /**< Mininum number of tunnels required */
+#define NSS_NLGRE_REDIR_CMN_IP_TTL 128 /**< Time to live for IP */
+
+/*
+ * netdevice private data
+ */
+struct nss_gre_redir_cmn_ndev_priv {
+ uint32_t gre_seq; /**< Sequence number */
+};
+
+/*
+ * Context need to be maintained globally for GRE redirect tunnel.
+ */
+struct nss_nlgre_redir_cmn_tun_data {
+ struct net_device *dev; /**< Net device */
+ int32_t host_inner_ifnum; /**< Interface no. of pnode host inner */
+ int32_t wifi_offl_inner_ifnum; /**< Interface no. of pnode wifi offld inner */
+ int32_t sjack_inner_ifnum; /**< Interface no. of pnode sjack inner */
+ int32_t outer_ifnum; /**< Interface no. of pnode outer */
+ bool enable; /**< Device is enabled or not */
+};
+
+/*
+ * nss_nlgre_redir_cmn_tun_type
+ * Different tunnel types supported in gre_redir
+ */
+enum nss_nlgre_redir_cmn_tun_type {
+ NSS_NLGRE_REDIR_CMN_TUN_TYPE_UNKNOWN, /**< Unknown tunnel type */
+ NSS_NLGRE_REDIR_CMN_TUN_TYPE_TUN, /**< Raw mode 802.11 frames traffic*/
+ NSS_NLGRE_REDIR_CMN_TUN_TYPE_DTUN, /**< For 802.3 frames traffic */
+ NSS_NLGRE_REDIR_CMN_TUN_TYPE_SPLIT, /**< For split mode */
+ NSS_NLGRE_REDIR_CMN_TUN_TYPE_MAX /**< Max number of tun type supported */
+};
+
+/*
+ * nss_nlgre_redir_cmn_mode_type
+ * Modes available for setting next hop
+ */
+enum nss_nlgre_redir_cmn_mode_type {
+ NSS_NLGRE_REDIR_CMN_MODE_TYPE_UNKNOWN, /**< Unknown mode type */
+ NSS_NLGRE_REDIR_CMN_MODE_TYPE_WIFI, /**< ath0 ---> wifi_offld_inner */
+ NSS_NLGRE_REDIR_CMN_MODE_TYPE_SPLIT, /**< ath0 ---> ETH_RX_INTERFACE */
+ NSS_NLGRE_REDIR_CMN_MODE_TYPE_MAX /**< Max number of modes supported */
+};
+
+/*
+ * nss_nlgre_redir_cmn_init()
+ * Initializes the tun_data
+ */
+void nss_nlgre_redir_cmn_init(void);
+
+/*
+ * nss_nlgre_redir_cmn_get_tun_ifnum()
+ * Returns the interface number corresponding to dev
+ */
+int32_t nss_nlgre_redir_cmn_get_tun_ifnum(enum nss_nlgre_redir_cmn_mode_type type, struct net_device *dev);
+/*
+ * nss_nlgre_redir_cmn_mode_str_to_enum()
+ * Returns the enum converted value of the string
+ */
+enum nss_nlgre_redir_cmn_mode_type nss_nlgre_redir_cmn_mode_str_to_enum(char *mode);
+
+/*
+ * nss_nlgre_redir_cmn_get_tun_data_index()
+ * Returns the interface number of dev
+ */
+int nss_nlgre_redir_cmn_get_tun_data_index(struct net_device *dev);
+
+/*
+ * nss_nlgre_redir_cmn_get_dev_ifnum()
+ * Returns the interface number of dev
+ */
+int32_t nss_nlgre_redir_cmn_get_dev_ifnum(char *dev_name);
+
+/*
+ * nss_nlgre_redir_cmn_get_tun_type()
+ * Returns the tunnel type
+ */
+enum nss_nlgre_redir_cmn_tun_type nss_nlgre_redir_cmn_get_tun_type(char *tun_type);
+
+/*
+ * nss_gre_redir_cmn_unregister_and_deallocate()
+ * Unregisters and deallocates a node.
+ */
+bool nss_nlgre_redir_cmn_unregister_and_deallocate(struct net_device *dev, uint32_t type);
+
+/*
+ * nss_nlgre_redir_cmn_print_skb()
+ * Prints the first 48 bytes of skb
+ */
+void nss_nlgre_redir_cmn_print_skb(struct sk_buff *skb);
+
+/*
+ * nss_nlgre_redir_cmn_create_tun()
+ * Creates a gre_redir tunnel
+ */
+struct net_device *nss_nlgre_redir_cmn_create_tun(uint32_t sip[4], uint32_t dip[4], uint8_t iptype);
+
+/*
+ * nss_nlgre_redir_cmn_destroy_tun()
+ * Destroys the gre_redir tunnel
+ */
+int nss_nlgre_redir_cmn_destroy_tun(struct net_device *dev);
+
+/*
+ * nss_nlgre_redir_cmn_unmap_interface()
+ * Unmaps the nss interface
+ */
+int nss_nlgre_redir_cmn_unmap_interface(struct nss_nlgre_redir_unmap *unmap_params);
+
+/*
+ * nss_nlgre_redir_cmn_map_interface()
+ * Unmaps the nss interface
+ */
+int nss_nlgre_redir_cmn_map_interface(uint32_t nexthop_nssif, uint16_t lag_en, struct nss_nlgre_redir_map *map_params);
+
+/*
+ * nss_nlgre_redir_cmn_set_next_hop()
+ * Sets the next hop of the nss ath0 interface
+ */
+int nss_nlgre_redir_cmn_set_next_hop(uint32_t next_dev_ifnum, struct nss_nlgre_redir_set_next *set_next_params);
+
+/*
+ * nss_nlgre_redir_cmn_init()
+ * Initializes tun_data and lock variable.
+ */
+void nss_nlgre_redir_cmn_init(void);
+
diff --git a/netlink/nss_nlgre_redir_family.c b/netlink/nss_nlgre_redir_family.c
new file mode 100644
index 0000000..43a8f3d
--- /dev/null
+++ b/netlink/nss_nlgre_redir_family.c
@@ -0,0 +1,78 @@
+/*
+ **************************************************************************
+ * Copyright (c) 2015-2016,2018-2019, 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.
+ **************************************************************************
+ */
+
+/*
+ * nss_nlgre_redir.c
+ * NSS Netlink gre_redir Handler
+ */
+#include <linux/version.h>
+#include <net/genetlink.h>
+#include <nss_api_if.h>
+#include <nss_nlcmn_if.h>
+#include <nss_nl_if.h>
+#include <nss_nlgre_redir_if.h>
+#include "nss_nl.h"
+#include "nss_nlgre_redir_cmd.h"
+
+/*
+ * nss_nlgre_redir_cmd_mcgrp
+ * Multicast group for sending message status & events
+ */
+static const struct genl_multicast_group nss_nlgre_redir_family_mcgrp[] = {
+ {.name = NSS_NLGRE_REDIR_MCAST_GRP},
+};
+
+/*
+ * nss_nlgre_redir_family_init()
+ * handler init
+ */
+bool nss_nlgre_redir_family_init(void)
+{
+ int err;
+ nss_nl_info_always("Init NSS netlink gre_redir handler\n");
+
+ /*
+ * register NETLINK ops with the family
+ */
+ err = genl_register_family_with_ops_groups(&nss_nlgre_redir_cmd_family, nss_nlgre_redir_cmd_ops, nss_nlgre_redir_family_mcgrp);
+ if (err) {
+ nss_nl_info_always("Error: %d unable to register gre_redir family\n", err);
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * nss_nlgre_redir_family_exit()
+ * handler exit
+ */
+bool nss_nlgre_redir_family_exit(void)
+{
+ int err;
+ nss_nl_info_always("Exit NSS netlink gre_redir handler\n");
+
+ /*
+ * unregister the ops family
+ */
+ err = genl_unregister_family(&nss_nlgre_redir_cmd_family);
+ if (err) {
+ nss_nl_info_always("Error: %d unable to unregister gre_redir NETLINK family\n", err);
+ return false;
+ }
+
+ return true;
+}
diff --git a/netlink/nss_nlgre_redir_family.h b/netlink/nss_nlgre_redir_family.h
new file mode 100644
index 0000000..dbad4e1
--- /dev/null
+++ b/netlink/nss_nlgre_redir_family.h
@@ -0,0 +1,44 @@
+/*
+ **************************************************************************
+ * Copyright (c) 2014-2015,2019, 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.
+ **************************************************************************
+ */
+
+/*
+ * nss_nlgre_redir_family.h
+ * NSS Netlink gre_redir API definitions
+ */
+#ifndef __NSS_NLGRE_REDIR_FAMILY_H
+#define __NSS_NLGRE_REDIR_FAMILY_H
+
+/*
+ * nss_nlgre_redir_family_init()
+ * To initialize the gre_redir module
+ */
+bool nss_nlgre_redir_family_init(void);
+
+/*
+ * nss_nlgre_redir_family_exit()
+ * Exit the gre_redir module
+ */
+bool nss_nlgre_redir_family_exit(void);
+
+#if defined(CONFIG_NSS_NLGRE_REDIR_FAMILY)
+#define NSS_NLGRE_REDIR_FAMILY_INIT nss_nlgre_redir_family_init
+#define NSS_NLGRE_REDIR_FAMILY_EXIT nss_nlgre_redir_family_exit
+#else
+#define NSS_NLGRE_REDIR_FAMILY_INIT 0
+#define NSS_NLGRE_REDIR_FAMILY_EXIT 0
+#endif /* !CONFIG_NSS_NLGRE_REDIR_FAMILY */
+
+#endif /* __NSS_NLGRE_REDIR_FAMILY_H */
diff --git a/netlink/nss_nlgre_redir_lag.c b/netlink/nss_nlgre_redir_lag.c
new file mode 100644
index 0000000..7b76bcc
--- /dev/null
+++ b/netlink/nss_nlgre_redir_lag.c
@@ -0,0 +1,439 @@
+/*
+ ***************************************************************************
+ * Copyright (c) 2015-2016,2018-2019, 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 <linux/version.h>
+#include <linux/etherdevice.h>
+#include <linux/if_ether.h>
+#include <net/genetlink.h>
+#include <nss_api_if.h>
+#include <nss_nl_if.h>
+#include "nss_nlcmn_if.h"
+#include "nss_nl.h"
+#include "nss_nlgre_redir_if.h"
+#include "nss_nlgre_redir_cmn.h"
+#include "nss_nlgre_redir_lag.h"
+
+/*
+ * Spin_lock for lag_pvt_data
+ */
+static DEFINE_SPINLOCK(lock);
+
+static struct nss_nlgre_redir_lag_pvt_data lag_pvt_data;
+static const struct net_device_ops dummy_netdev_ops;
+
+/*
+ * nss_nlgre_redir_lag_msg_completion_cb()
+ * HLOS->NSS message completion callback.
+ */
+static void nss_nlgre_redir_lag_msg_completion_cb(void *app_data, struct nss_cmn_msg *cmnmsg)
+{
+ struct nss_ctx_instance *nss_ctx = nss_gre_redir_get_context();
+ nss_nl_info("%p: callback gre_redir tunnel msg from NSS\n", nss_ctx);
+}
+
+/*
+ * nss_nlgre_redir_lag_us_data_cb()
+ * Exception handler for LAG_US node.
+ */
+static void nss_nlgre_redir_lag_us_data_cb(struct net_device *netdev, struct sk_buff *skb, struct napi_struct *napi)
+{
+ nss_nl_trace("Exception packet on lag_us node:\n");
+ nss_nlgre_redir_cmn_print_skb(skb);
+ dev_kfree_skb_any(skb);
+}
+
+/*
+ * nss_nlgre_redir_lag_ds_data_cb()
+ * Exception handler for LAG_DS node.
+ */
+static void nss_nlgre_redir_lag_ds_data_cb(struct net_device *netdev, struct sk_buff *skb, struct napi_struct *napi)
+{
+ nss_nl_trace("Exception packet on lag_ds node:\n");
+ nss_nlgre_redir_cmn_print_skb(skb);
+ dev_kfree_skb_any(skb);
+}
+
+/*
+ * nss_nlgre_redir_lag_us_msg_cb()
+ * GRE LAG upstream NSS->HLOS message callback.
+ */
+static void nss_nlgre_redir_lag_us_msg_cb(void *app_data, struct nss_cmn_msg *cmnmsg)
+{
+ struct nss_gre_redir_lag_us_msg *tunmsg = (struct nss_gre_redir_lag_us_msg *)cmnmsg;
+ int i;
+
+ if (tunmsg->cm.type != NSS_GRE_REDIR_LAG_US_DB_HASH_NODE_MSG) {
+ return;
+ }
+
+ nss_nl_trace("%p: callback_stats: count = %u index = %u\n", tunmsg,
+ tunmsg->msg.hash_stats.count, tunmsg->msg.hash_stats.db_entry_idx);
+ for (i = 0; i < tunmsg->msg.hash_stats.count; i++) {
+ nss_nl_trace("%p: hits = %llu smac = %pM dmac = %pM\n", tunmsg,
+ tunmsg->msg.hash_stats.hstats[i].hits,
+ &(tunmsg->msg.hash_stats.hstats[i].src_mac),
+ &(tunmsg->msg.hash_stats.hstats[i].dest_mac));
+ }
+}
+
+/*
+ * nss_nlgre_redir_lag_ds_msg_cb()
+ * GRE LAG upstream NSS->HLOS message callback.
+ */
+static void nss_nlgre_redir_lag_ds_msg_cb(void *app_data, struct nss_cmn_msg *cmnmsg)
+{
+ struct nss_gre_redir_lag_ds_msg *tunmsg = (struct nss_gre_redir_lag_ds_msg *)cmnmsg;
+
+ if (tunmsg->cm.type != NSS_GRE_REDIR_LAG_DS_STATS_SYNC_MSG) {
+ return;
+ }
+
+
+ nss_nl_trace("%p: callback_stats: invalid_dest: %u, exception_cnt: %u\n", tunmsg,
+ tunmsg->msg.ds_sync_stats.ds_stats.dst_invalid,
+ tunmsg->msg.ds_sync_stats.ds_stats.exception_cnt);
+
+
+}
+
+/*
+ * nss_nlgre_redir_lag_get_lag_pvt_data()
+ * Return lag_pvt_data after lock checking
+ */
+static struct nss_nlgre_redir_lag_pvt_data nss_nlgre_redir_lag_get_lag_pvt_data(void)
+{
+ struct nss_nlgre_redir_lag_pvt_data ret_lag_pvt_data;
+
+ spin_lock(&lock);
+ ret_lag_pvt_data = lag_pvt_data;
+ spin_unlock(&lock);
+ return ret_lag_pvt_data;
+}
+
+/*
+ * nss_nlgre_redir_lag_set_lag_pvt_data()
+ * Return lag_pvt_data after lock checking
+ */
+static void nss_nlgre_redir_lag_set_lag_pvt_data(struct nss_nlgre_redir_lag_pvt_data *data)
+{
+ spin_lock(&lock);
+ lag_pvt_data = *data;
+ spin_unlock(&lock);
+}
+
+/*
+ * nss_nlgre_redir_lag_destroy_tun()
+ * Destroy tunnel in LAG mode.
+ */
+int nss_nlgre_redir_lag_destroy_tun(struct net_device *dev)
+{
+ struct nss_ctx_instance *nss_ctx = nss_gre_redir_get_context();
+ struct nss_nlgre_redir_lag_pvt_data lag_pvt_data;
+ uint8_t tun_idx;
+ int ret;
+
+ if (!dev) {
+ nss_nl_error("%p: Dev is null\n", nss_ctx);
+ return -1;
+ }
+
+ dev_hold(dev);
+
+ /*
+ * Unregister and deallocate the lag US and DS interfaces
+ */
+ lag_pvt_data = nss_nlgre_redir_lag_get_lag_pvt_data();
+ ret = nss_gre_redir_lag_us_unregister_and_dealloc(lag_pvt_data.inner_ifnum);
+ if (ret) {
+ nss_nl_error("%p: Unable to deallocate node %d\n", dev, lag_pvt_data.inner_ifnum);
+ }
+
+ ret = nss_gre_redir_lag_ds_unregister_and_dealloc(lag_pvt_data.outer_ifnum);
+ if (ret) {
+ nss_nl_error("%p: Unable to deallocate node %d\n", dev, lag_pvt_data.outer_ifnum);
+ }
+
+ for (tun_idx = 0; tun_idx < NSS_NLGRE_REDIR_LAG_SLAVES; tun_idx++) {
+ if (!lag_pvt_data.slaves[tun_idx]) {
+ nss_nl_error("%p: Slave tunnel index out of range\n", nss_ctx);
+ ret = -1;
+ goto done;
+ }
+
+ ret = nss_nlgre_redir_cmn_destroy_tun(lag_pvt_data.slaves[tun_idx]);
+ if (ret == -1) {
+ nss_nl_error("%p: Unable to destroy tunnel associated with slave %d\n", nss_ctx, tun_idx+1);
+ goto done;
+ }
+
+ nss_nl_info("%p: Successfully destroyed slave tunnel %d\n", nss_ctx, tun_idx+1);
+ }
+
+done:
+ /*
+ * Free the lag dummy dev resources
+ */
+ dev_put(dev);
+ unregister_netdev(dev);
+ free_netdev(dev);
+ lag_pvt_data.dev = NULL;
+ return ret;
+}
+
+/*
+ * nss_nlgre_redir_lag_create_tun()
+ * Cretate GRE redir tunnel in LAG mode.
+ */
+int nss_nlgre_redir_lag_create_tun(struct nss_nlgre_redir_create_tun *create_params)
+{
+ struct nss_nlgre_redir_lag_pvt_data lag_pvt_data;
+ struct nss_gre_redir_lag_us_config_msg config;
+ struct nss_gre_redir_cmn_ndev_priv *gr;
+ struct nss_ctx_instance *nss_ctx;
+ struct net_device *dummy_dev;
+ bool status;
+ int iter;
+
+ nss_ctx = nss_gre_redir_get_context();
+ lag_pvt_data = nss_nlgre_redir_lag_get_lag_pvt_data();
+ lag_pvt_data.slaves[0] = nss_nlgre_redir_cmn_create_tun(create_params->sip, create_params->dip, create_params->iptype);
+ if (!lag_pvt_data.slaves[0]) {
+ nss_nl_error("%p: Unable to create tunnel for %dst slave\n", nss_ctx, 1);
+ goto fail0;
+ }
+
+ lag_pvt_data.slaves[1] = nss_nlgre_redir_cmn_create_tun(create_params->ssip, create_params->sdip, create_params->iptype);
+ if (!lag_pvt_data.slaves[1]) {
+ nss_nl_error("%p: Unable to create tunnel for %dnd slave\n", nss_ctx, 2);
+ goto fail0;
+ }
+
+ dummy_dev = alloc_netdev(sizeof(*gr), "grelag%d", NET_NAME_UNKNOWN, ether_setup);
+ if (!dummy_dev) {
+ nss_nl_error("%p: Unable to allocate net_dev for dummy_dev\n", nss_ctx);
+ goto fail0;
+ }
+
+ dummy_dev->needed_headroom = NSS_NLGRE_REDIR_CMN_NEEDED_HEADROOM;
+ dummy_dev->netdev_ops = &dummy_netdev_ops;
+ lag_pvt_data.inner_ifnum = nss_gre_redir_lag_us_alloc_and_register_node(dummy_dev,
+ nss_nlgre_redir_lag_us_data_cb, nss_nlgre_redir_lag_us_msg_cb, dummy_dev);
+
+ if (lag_pvt_data.inner_ifnum == -1) {
+ nss_nl_error("%p: Unable to allocate or register LAG US dynamic node.\n", nss_ctx);
+ goto fail1;
+ }
+
+ nss_nl_info("%p: LAG US interface number = %d\n", nss_ctx, lag_pvt_data.inner_ifnum);
+ lag_pvt_data.outer_ifnum = nss_gre_redir_lag_ds_alloc_and_register_node(dummy_dev,
+ nss_nlgre_redir_lag_ds_data_cb, nss_nlgre_redir_lag_ds_msg_cb, dummy_dev);
+
+ if (lag_pvt_data.outer_ifnum == -1) {
+ nss_nl_error("%p: Unable to allocate or register LAG DS dynamic node.\n", nss_ctx);
+ goto fail2;
+ }
+
+ nss_nl_info("%p: LAG DS interface number = %d\n", nss_ctx, lag_pvt_data.outer_ifnum);
+
+ config.hash_mode = create_params->hash_mode;
+ config.num_slaves = NSS_NLGRE_REDIR_LAG_SLAVES;
+
+ for (iter = 0; iter < NSS_NLGRE_REDIR_LAG_SLAVES; iter++) {
+ config.if_num[iter] = nss_nlgre_redir_cmn_get_tun_ifnum(NSS_NLGRE_REDIR_CMN_MODE_TYPE_WIFI, lag_pvt_data.slaves[iter]);
+ }
+
+ status = nss_gre_redir_lag_us_configure_node(lag_pvt_data.inner_ifnum, &config);
+ if (!status) {
+ nss_nl_info("%p: Unable to configure LAG US node.\n", nss_ctx);
+ goto fail3;
+ }
+
+ if (register_netdev(dummy_dev)) {
+ nss_nl_error("%p: Unable to register dummy_dev\n", nss_ctx);
+ goto fail3;
+ }
+
+ lag_pvt_data.dev = dummy_dev;
+ nss_nlgre_redir_lag_set_lag_pvt_data(&lag_pvt_data);
+ return 0;
+
+fail3:
+ nss_nlgre_redir_cmn_unregister_and_deallocate(dummy_dev, NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_LAG_DS);
+fail2:
+ nss_nlgre_redir_cmn_unregister_and_deallocate(dummy_dev, NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_LAG_US);
+fail1:
+ free_netdev(dummy_dev);
+fail0:
+ for (iter = 0; iter < NSS_NLGRE_REDIR_LAG_SLAVES; iter++) {
+ if (!lag_pvt_data.slaves[iter]) {
+ nss_nlgre_redir_cmn_destroy_tun(lag_pvt_data.slaves[iter]);
+ continue;
+ }
+
+ break;
+ }
+
+ return -1;
+}
+
+/*
+ * nss_nlgre_redir_lag_map_interface()
+ * Maps the nss interface to tunnel ID
+ */
+int nss_nlgre_redir_lag_map_interface(struct nss_nlgre_redir_map *map_params)
+{
+ struct nss_nlgre_redir_lag_pvt_data lag_pvt_data;
+ struct nss_ctx_instance *nss_ctx;
+ uint32_t nexthop_nssif;
+ int ret;
+
+ nss_ctx = nss_gre_redir_get_context();
+ lag_pvt_data = nss_nlgre_redir_lag_get_lag_pvt_data();
+ nexthop_nssif = lag_pvt_data.outer_ifnum;
+ ret = nss_nlgre_redir_cmn_map_interface(nexthop_nssif, 1, map_params);
+ if (ret == -1) {
+ nss_nl_error("%p: Unable to map nss interface\n", nss_ctx);
+ return -1;
+ }
+
+ nss_nl_info("Successfully mapped the nss interface to tunnel ID\n");
+ return 0;
+}
+
+/*
+ * nss_nlgre_redir_lag_set_next_hop()
+ * Sets the next hop of ath0 interface as lag US node's interface
+ */
+int nss_nlgre_redir_lag_set_next_hop(struct nss_nlgre_redir_set_next *set_next_params)
+{
+ struct nss_nlgre_redir_lag_pvt_data lag_pvt_data;
+ struct nss_ctx_instance *nss_ctx;
+ uint32_t nexthop_ifnum;
+ int ret;
+
+ nss_ctx = nss_gre_redir_get_context();
+ lag_pvt_data = nss_nlgre_redir_lag_get_lag_pvt_data();
+ nexthop_ifnum = lag_pvt_data.inner_ifnum;
+ ret = nss_nlgre_redir_cmn_set_next_hop(nexthop_ifnum, set_next_params);
+ if (ret == -1) {
+ nss_nl_error("%p: Unable to set the next hop as lag US node's interface\n", nss_ctx);
+ return -1;
+ }
+
+ nss_nl_info("Successfully set the next hop as lag US node's interface\n");
+ return 0;
+}
+
+/*
+ * nss_nlgre_redir_lag_add_hash()
+ * Add hash entry.
+ */
+int nss_nlgre_redir_lag_add_hash(struct nss_nlgre_redir_hash_ops *hash_ops)
+{
+ struct nss_nlgre_redir_lag_pvt_data lag_pvt_data;
+ struct nss_gre_redir_lag_us_msg *nglm;
+ struct nss_ctx_instance *nss_ctx;
+ nss_tx_status_t status;
+ uint32_t len;
+ int i;
+
+ lag_pvt_data = nss_nlgre_redir_lag_get_lag_pvt_data();
+ nss_ctx = nss_gre_redir_lag_us_get_context();
+ if (!nss_ctx) {
+ nss_nl_error("Unable to get nss context\n");
+ return -1;
+ }
+
+ nglm = kmalloc(sizeof(struct nss_gre_redir_lag_us_msg), GFP_KERNEL);
+ if (!nglm) {
+ nss_nl_error("%p: Unable to allocate memory to send add hash msg.\n", nss_ctx);
+ return -1;
+ }
+
+ len = sizeof(struct nss_gre_redir_lag_us_msg) - sizeof(struct nss_cmn_msg);
+ nss_cmn_msg_init(&nglm->cm, lag_pvt_data.inner_ifnum, NSS_GRE_REDIR_LAG_US_ADD_HASH_NODE_MSG, len,
+ nss_nlgre_redir_lag_msg_completion_cb, NULL);
+ memcpy((void *)(nglm->msg.add_hash.src_mac), (void *)hash_ops->smac, sizeof(nglm->msg.add_hash.src_mac));
+ memcpy((void *)(nglm->msg.add_hash.dest_mac), (void *)hash_ops->dmac, sizeof(nglm->msg.add_hash.dest_mac));
+ for (i = 0; i < NSS_NLGRE_REDIR_LAG_SLAVES; i++) {
+ if (hash_ops->slave != i) {
+ continue;
+ }
+
+ nglm->msg.add_hash.if_num = nss_nlgre_redir_cmn_get_tun_ifnum(NSS_NLGRE_REDIR_CMN_MODE_TYPE_WIFI,
+ lag_pvt_data.slaves[i]);
+ break;
+ }
+
+ if (i == NSS_NLGRE_REDIR_LAG_SLAVES || nglm->msg.add_hash.if_num == -1) {
+ nss_nl_error("%p: Invalid value for index, valid slaves: [%s, %s]\n", nss_ctx,
+ lag_pvt_data.slaves[0]->name, lag_pvt_data.slaves[1]->name);
+ return -1;
+ }
+
+ nss_nl_info("smac = %pM dmac = %pM ifnum = %d\n", &(nglm->msg.add_hash.src_mac),
+ &(nglm->msg.add_hash.dest_mac), nglm->msg.add_hash.if_num);
+ status = nss_gre_redir_lag_us_tx_msg_sync(nss_ctx, nglm);
+ kfree(nglm);
+ if (status != NSS_TX_SUCCESS) {
+ nss_nl_error("%p: Unable to add hash entry.\n", nss_ctx);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * nss_nlgre_redir_lag_del_hash()
+ * Delete hash entry.
+ */
+int nss_nlgre_redir_lag_del_hash(struct nss_nlgre_redir_hash_ops *hash_ops)
+{
+ struct nss_nlgre_redir_lag_pvt_data lag_pvt_data;
+ struct nss_gre_redir_lag_us_msg *nglm;
+ struct nss_ctx_instance *nss_ctx;
+ nss_tx_status_t status;
+ uint32_t len;
+
+ lag_pvt_data = nss_nlgre_redir_lag_get_lag_pvt_data();
+ nss_ctx = nss_gre_redir_lag_us_get_context();
+ if (!nss_ctx) {
+ nss_nl_error("Unable to get nss context\n");
+ return -1;
+ }
+
+ nglm = kmalloc(sizeof(struct nss_gre_redir_lag_us_msg), GFP_KERNEL);
+ if (!nglm) {
+ nss_nl_error("%p: Unable to allocate memory to send del hash msg.\n", nss_ctx);
+ return -1;
+ }
+
+ len = sizeof(struct nss_gre_redir_lag_us_msg) - sizeof(struct nss_cmn_msg);
+ nss_cmn_msg_init(&nglm->cm, lag_pvt_data.inner_ifnum, NSS_GRE_REDIR_LAG_US_DEL_HASH_NODE_MSG, len,
+ nss_nlgre_redir_lag_msg_completion_cb, NULL);
+ memcpy((void *)(nglm->msg.del_hash.src_mac), (void *)hash_ops->smac, sizeof(nglm->msg.del_hash.src_mac));
+ memcpy((void *)(nglm->msg.del_hash.dest_mac), (void *)hash_ops->dmac, sizeof(nglm->msg.del_hash.dest_mac));
+ nss_nl_info("smac = %pM dmac = %pM\n", &(nglm->msg.del_hash.src_mac), &(nglm->msg.del_hash.dest_mac));
+ status = nss_gre_redir_lag_us_tx_msg_sync(nss_ctx, nglm);
+ kfree(nglm);
+ if (status != NSS_TX_SUCCESS) {
+ nss_nl_error("%p: Unable to delete hash entry.\n", nss_ctx);
+ return -1;
+ }
+
+ return 0;
+}
+
diff --git a/netlink/nss_nlgre_redir_lag.h b/netlink/nss_nlgre_redir_lag.h
new file mode 100644
index 0000000..b0b7ee1
--- /dev/null
+++ b/netlink/nss_nlgre_redir_lag.h
@@ -0,0 +1,65 @@
+/*
+ ***************************************************************************
+ * Copyright (c) 2014-2015,2019, 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.
+ **************************************************************************
+ */
+
+#define NSS_NLGRE_REDIR_LAG_SLAVES 2 /**< Maximum number of slaves for lag tunnel */
+
+/*
+ * nss_nlgre_redir_lag_pvt_data
+ * Context need to be maintained for LAG deployment.
+ */
+struct nss_nlgre_redir_lag_pvt_data {
+ uint32_t inner_ifnum; /**< Inner ifnum of lag netdev */
+ uint32_t outer_ifnum; /**< Outer ifnum of lag netdev */
+ struct net_device *slaves[2]; /**< Slave's dev reference*/
+ struct net_device *dev; /**< Pointer to netdev for lag */
+};
+
+/*
+ * nss_nlgre_redir_lag_create_tun()
+ * Creates a lag node and configures LAG US/DS dynamic nodes.
+ */
+int nss_nlgre_redir_lag_create_tun(struct nss_nlgre_redir_create_tun *create_params);
+
+/*
+ * nss_nlgre_redir_lag_destroy_tun()
+ * Destroys the lag tunnel.
+ */
+int nss_nlgre_redir_lag_destroy_tun(struct net_device *dev);
+
+/*
+ * nss_nlgre_redir_lag_set_next_hop()
+ * Sets the next hop as lag US node
+ */
+int nss_nlgre_redir_lag_set_next_hop(struct nss_nlgre_redir_set_next *set_next_params);
+
+/*
+ * nss_nlgre_redir_lag_map_interface()
+ * Maps the vap interface to tunnel ID
+ */
+int nss_nlgre_redir_lag_map_interface(struct nss_nlgre_redir_map *map_params);
+
+/*
+ * nss_nlgre_redir_lag_add_hash()
+ * Add hash entry.
+ */
+int nss_nlgre_redir_lag_add_hash(struct nss_nlgre_redir_hash_ops *hash_ops);
+
+/*
+ * nss_nlgre_redir_lag_del_hash()
+ * Delete hash entry.
+ */
+int nss_nlgre_redir_lag_del_hash(struct nss_nlgre_redir_hash_ops *hash_ops);
+
diff --git a/netlink/nss_nlgre_redir_mgr.c b/netlink/nss_nlgre_redir_mgr.c
deleted file mode 100644
index 72ccd7d..0000000
--- a/netlink/nss_nlgre_redir_mgr.c
+++ /dev/null
@@ -1,728 +0,0 @@
-/*
- ***************************************************************************
- * Copyright (c) 2015-2016,2018-2019, 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 <linux/version.h>
-#include <linux/etherdevice.h>
-#include <linux/if_ether.h>
-#include <net/genetlink.h>
-#include <nss_api_if.h>
-#include <nss_nl_if.h>
-#include "nss_nlcmn_if.h"
-#include "nss_nl.h"
-#include "nss_nlgre_redir_if.h"
-
-#define DRIVER_NAME "nss_gre_redir"
-
-static struct nss_nlgre_redir_pvt_data pvt_data[NSS_NLGRE_REDIR_MAX_TUNNELS];
-static const struct net_device_ops gre_netdev_ops;
-
-/*
- * nss_nlgre_redir_mgr_get_pvt_data_index()
- * Returns Index in array of private data.
- */
-static bool nss_nlgre_redir_mgr_get_pvt_data_index(struct net_device *dev, uint32_t *index)
-{
- uint32_t i;
- struct nss_ctx_instance *nss_ctx = nss_gre_redir_get_context();
-
- *index = -1;
- if (!dev) {
- nss_nl_error("%p: Dev is NULL\n", nss_ctx);
- return false;
- }
-
- for (i = 0; i < NSS_NLGRE_REDIR_MAX_TUNNELS; i++) {
- if (pvt_data[i].dev != dev) {
- continue;
- }
-
- *index = i;
- return true;
- }
-
- return false;
-}
-
-/*
- * nss_nlgre_redir_mgr_xmit()
- * Used when the interface is used for transmit data.
- */
-static netdev_tx_t nss_nlgre_redir_mgr_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- struct nss_gre_redir_ndev_priv *priv;
- struct nss_gre_redir_encap_per_pkt_metadata *gre_encap = NULL;
- uint32_t ifnum, ret = 0;
- uint32_t *mdata_ptr = (uint32_t *)&skb->head[0];
- struct nss_ctx_instance *nss_ctx = nss_gre_redir_get_context();
-
- priv = netdev_priv(dev);
- ifnum = nss_cmn_get_interface_number_by_dev_and_type(dev, NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_WIFI_HOST_INNER);
- *mdata_ptr = NSS_GRE_REDIR_PER_PACKET_METADATA_OFFSET;
-
- /*
- * configuring gre meta data
- */
- gre_encap = (struct nss_gre_redir_encap_per_pkt_metadata *)(skb->head + NSS_GRE_REDIR_PER_PACKET_METADATA_OFFSET);
- if (gre_encap == NULL) {
- nss_nl_error("%p: Not a valid skb to transmit\n", nss_ctx);
- dev_kfree_skb_any(skb);
- return -EINVAL;
- }
-
- memset(gre_encap, 0, sizeof(struct nss_gre_redir_encap_per_pkt_metadata));
- gre_encap->gre_flags = 0;
- gre_encap->gre_prio = 0;
- gre_encap->gre_seq = ++priv->gre_seq;
- gre_encap->gre_tunnel_id = 10;
- gre_encap->ip_dscp = 0;
- gre_encap->ip_df_override = 0;
- gre_encap->ipsec_pattern = 0;
-
- nss_ctx = nss_gre_redir_get_context();
- ret = nss_gre_redir_tx_buf(nss_ctx, skb, ifnum);
- if (ret != NSS_TX_SUCCESS) {
- nss_nl_error("%p: Transmit failed and returned with %d\n", nss_ctx, ret);
- dev_kfree_skb_any(skb);
- }
-
- return ret;
-}
-
-/*
- * nss_nlgre_redir_mgr_host_data_cb()
- * Data callback for host offload inner node.
- */
-static void nss_nlgre_redir_mgr_host_data_cb(struct net_device *netdev, struct sk_buff *skb, struct napi_struct *napi)
-{
- struct nss_gre_redir_decap_per_pkt_metadata *gre_decap = NULL;
- struct nss_ctx_instance *nss_ctx = nss_gre_redir_get_context();
-
- if (!skb) {
- nss_nl_error("%p: SKB in NULL\n", nss_ctx);
- return;
- }
-
- gre_decap = (struct nss_gre_redir_decap_per_pkt_metadata *)(skb->head + NSS_GRE_REDIR_PER_PACKET_METADATA_OFFSET);
- if (!gre_decap) {
- nss_nl_error("%p: Not a valid skb\n", nss_ctx);
- dev_kfree_skb_any(skb);
- return;
- }
-
- skb->protocol = eth_type_trans(skb, netdev);
- netif_receive_skb(skb);
-}
-
-/*
- * nss_nlgre_redir_mgr_print_skb()
- * Prints the skb data
- */
-static void nss_nlgre_redir_mgr_print_skb(struct sk_buff *skb)
-{
- int length;
- int iter;
-
- /*
- * Check if length is less than 12 bytes
- * Else bring down to minimum multiple of 12 bytes.
- */
- if (skb->len < 16)
- nss_nl_trace("Skb too small to print min size: 16 bytes\n");
- else
- length = (skb->len / 16);
- /*
- * Print first 48 bytes of sk_buff
- */
- for (iter = 0; iter < length && length <= 3; iter++) {
- nss_nl_trace("%04xx: %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x\n", iter,
- skb->data[iter*8], skb->data[iter*8 + 1], skb->data[iter*8 + 2], skb->data[iter*8 + 3],
- skb->data[iter*8 + 4], skb->data[iter*8 + 5], skb->data[iter*8 + 6], skb->data[iter*8 + 7],
- skb->data[iter*8 + 8], skb->data[iter*8 + 9], skb->data[iter*8 + 10], skb->data[iter*8 + 11],
- skb->data[iter*8 + 10], skb->data[iter*8 + 13], skb->data[iter*8 + 14], skb->data[iter*8 + 15]);
- }
-}
-
-/*
- * nss_nlgre_redir_mgr_wifi_offl_data_cb()
- * Data callback for wifi offload inner node.
- */
-static void nss_nlgre_redir_mgr_wifi_offl_data_cb(struct net_device *netdev, struct sk_buff *skb, struct napi_struct *napi)
-{
- nss_nl_trace("Exception packet on wifi offld inner printing skb:\n");
- nss_nlgre_redir_mgr_print_skb(skb);
- dev_kfree_skb(skb);
-}
-
-/*
- * nss_nlgre_redir_mgr_sjack_data_cb
- * Data callback for sjack inner node.
- */
-static void nss_nlgre_redir_mgr_sjack_data_cb(struct net_device *netdev, struct sk_buff *skb, struct napi_struct *napi)
-{
- nss_nl_trace("Exception packet on sjack inner node printing skb:\n");
- nss_nlgre_redir_mgr_print_skb(skb);
- dev_kfree_skb(skb);
-}
-
-/*
- * nss_nlgre_redir_mgr_outer_data_cb()
- * Data callback for outer node.
- */
-static void nss_nlgre_redir_mgr_outer_data_cb(struct net_device *netdev, struct sk_buff *skb, struct napi_struct *napi)
-{
- nss_nl_trace("Exception packet on outer node printing skb:\n");
- nss_nlgre_redir_mgr_print_skb(skb);
- dev_kfree_skb(skb);
-}
-
-/*
- * nss_nlgre_redir_mgr_cb_gre_msg()
- * HLOS->NSS message completion callback.
- */
-static void nss_nlgre_redir_mgr_cb_gre_msg(void)
-{
- struct nss_ctx_instance *nss_ctx = nss_gre_redir_get_context();
- nss_nl_info("%p: callback gre tunnel msg from NSS\n", nss_ctx);
-}
-
-/*
- * nss_nlgre_redir_mgr_deinit_pvt_data()
- * Deinitialize private data for the given index.
- */
-static bool nss_nlgre_redir_mgr_deinit_pvt_data(uint32_t index)
-{
- struct nss_ctx_instance *nss_ctx = nss_gre_redir_get_context();
-
- if (index == NSS_NLGRE_REDIR_MAX_TUNNELS) {
- nss_nl_error("%p: Index is out of range\n", nss_ctx);
- return false;
- }
-
- pvt_data[index].dev = NULL;
- pvt_data[index].enable = false;
- pvt_data[index].host_inner_ifnum = -1;
- pvt_data[index].wifi_offl_inner_ifnum = -1;
- pvt_data[index].sjack_inner_ifnum = -1;
- pvt_data[index].outer_ifnum = -1;
- return true;
-}
-
-/*
- * nss_nlgre_redir_mgr_tunnel_type
- * Returns tunnel type
- */
-enum nss_gre_redir_tunnel_types nss_nlgre_redir_mgr_tunnel_type(char *tun_type)
-{
- if (tun_type == NULL)
- return NSS_GRE_REDIR_TUNNEL_TYPE_UNKNOWN;
- if (!strncmp(tun_type, "tun", NSS_NLGRE_REDIR_TUN_TYPE_MAX_SZ))
- return NSS_GRE_REDIR_TUNNEL_TYPE_TUN;
- if (!strncmp(tun_type, "dtun", NSS_NLGRE_REDIR_TUN_TYPE_MAX_SZ))
- return NSS_GRE_REDIR_TUNNEL_TYPE_DTUN;
- if (!strncmp(tun_type, "split", NSS_NLGRE_REDIR_TUN_TYPE_MAX_SZ))
- return NSS_GRE_REDIR_TUNNEL_TYPE_SPLIT;
-
- return NSS_GRE_REDIR_TUNNEL_TYPE_UNKNOWN;
-}
-
-/*
- * nss_gre_redir_unregister_and_deallocate()
- * Unregisters and deallocates a node.
- */
-bool nss_nlgre_redir_mgr_unregister_and_deallocate(struct net_device *dev, uint32_t type)
-{
- int ifnum;
- bool ret;
- nss_tx_status_t status;
-
- ifnum = nss_cmn_get_interface_number_by_dev_and_type(dev, type);
- if (ifnum == -1) {
- nss_nl_error("%p: unable to get NSS interface for net device %s of type %d\n", dev, dev->name, type);
- return false;
- }
-
- ret = nss_gre_redir_unregister_if(ifnum);
- if (!ret) {
- nss_nl_error("%p: Unable to unregister interface %d\n", dev, ifnum);
- return false;
- }
-
- status = nss_dynamic_interface_dealloc_node(ifnum, type);
- if (status != NSS_TX_SUCCESS) {
- nss_nl_error("%p: Unable to deallocate node %d\n", dev, ifnum);
- return false;
- }
-
- return true;
-}
-
-/*
- * nss_nlgre_redir_mgr_interfaces_unregister_and_dealloc
- * Find out the interfaces to be deallocated
- */
-void nss_nlgre_redir_mgr_interfaces_unregister_and_dealloc(struct net_device *dev, int tun)
-{
- struct nss_ctx_instance *nss_ctx = nss_gre_redir_get_context();
- if (pvt_data[tun].sjack_inner_ifnum != -1) {
- if(!nss_nlgre_redir_mgr_unregister_and_deallocate(dev, NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_WIFI_HOST_INNER)) {
- nss_nl_error("%p: Unable to unregister and deallocate node of type %d\n", nss_ctx,
- NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_WIFI_HOST_INNER);
- }
- }
-
- if (pvt_data[tun].wifi_offl_inner_ifnum != -1) {
- if (!nss_nlgre_redir_mgr_unregister_and_deallocate(dev, NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_WIFI_OFFL_INNER)) {
- nss_nl_error("%p: Unable to unregister and deallocate node of type %d\n", nss_ctx,
- NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_WIFI_OFFL_INNER);
- }
- }
-
- if (pvt_data[tun].host_inner_ifnum != -1) {
- if (!nss_nlgre_redir_mgr_unregister_and_deallocate(dev, NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_SJACK_INNER)) {
- nss_nl_error("%p: Unable to unregister and deallocate node of type %d\n", nss_ctx,
- NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_SJACK_INNER);
- }
- }
-
- if (pvt_data[tun].outer_ifnum != -1) {
- if (!nss_nlgre_redir_mgr_unregister_and_deallocate(dev, NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_OUTER)) {
- nss_nl_error("%p: Unable to unregister and deallocate node of type %d\n", nss_ctx,
- NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_OUTER);
- }
- }
-}
-
-/*
- * nss_nlgre_redir_mgr_ether_setup()
- * Used to setup the ethernet functionality
- */
-void nss_nlgre_redir_mgr_ether_setup(struct net_device *dev)
-{
- eth_hw_addr_random(dev);
-}
-
-/*
- * nss_nlgre_redir_mgr_destroy_tun()
- * Unregisters and deallocs dynamic interfaces.
- */
-int nss_nlgre_redir_mgr_destroy_tun(struct net_device *dev)
-{
- int index;
- struct nss_ctx_instance *nss_ctx = nss_gre_redir_get_context();
-
- if (!dev) {
- nss_nl_error("%p: Dev is NULL\n", nss_ctx);
- return -1;
- }
-
- if (!nss_nlgre_redir_mgr_get_pvt_data_index(dev, &index)) {
- nss_nl_error("%p: Unable to find tunnel associated with net dev\n", dev);
- return -1;
- }
-
- nss_nlgre_redir_mgr_interfaces_unregister_and_dealloc(dev, index);
- nss_nlgre_redir_mgr_deinit_pvt_data(index);
- dev_put(dev);
- unregister_netdev(dev);
- free_netdev(dev);
-
- return index;
-}
-
-/*
- * nss_nlgre_redir_mgr_interface_map()
- * Interface map message.
- */
-bool nss_nlgre_redir_mgr_interface_map(uint32_t vap_nss_if, uint32_t tun_type, struct nss_nlgre_redir_map *if_map_params)
-{
- struct nss_gre_redir_msg ngrm;
- struct nss_ctx_instance *nss_ctx;
- nss_tx_status_t ret;
- uint32_t len = sizeof(struct nss_gre_redir_msg) - sizeof(struct nss_cmn_msg);
- nss_ctx = nss_gre_redir_get_context();
-
- if ((vap_nss_if >= NSS_DYNAMIC_IF_START+NSS_MAX_DYNAMIC_INTERFACES) || (vap_nss_if < NSS_DYNAMIC_IF_START)) {
- nss_nl_error("%p: vap_nss_if is out of valid range for vap: %d\n", nss_ctx, vap_nss_if);
- return false;
- }
-
- if (if_map_params->rid >= NSS_NLGRE_REDIR_RADIO_ID_MAX) {
- nss_nl_error("%p: radio_id is out of valid range for vap: %d\n", nss_ctx, vap_nss_if);
- return false;
- }
-
- if (if_map_params->vid >= NSS_NLGRE_REDIR_VAP_ID_MAX) {
- nss_nl_error("%p: vap_id is out of valid range for vap: %d\n", nss_ctx, vap_nss_if);
- return false;
- }
-
- if ((tun_type <= NSS_GRE_REDIR_TUNNEL_TYPE_UNKNOWN) || (tun_type >= NSS_GRE_REDIR_TUNNEL_TYPE_MAX)) {
- nss_nl_error("%p: not a valid tunnel_type\n", nss_ctx);
- return false;
- }
-
- nss_cmn_msg_init(&ngrm.cm, NSS_GRE_REDIR_INTERFACE, NSS_GRE_REDIR_TX_INTERFACE_MAP_MSG,
- len, nss_nlgre_redir_mgr_cb_gre_msg, NULL);
-
- ngrm.msg.interface_map.vap_nssif = vap_nss_if;
- ngrm.msg.interface_map.radio_id = if_map_params->rid;
- ngrm.msg.interface_map.vap_id = if_map_params->vid;
- ngrm.msg.interface_map.tunnel_type = tun_type;
- ngrm.msg.interface_map.ipsec_pattern = if_map_params->ipsec_sa_pattern;
-
- if (tun_type == NSS_GRE_REDIR_TUNNEL_TYPE_SPLIT) {
- ngrm.msg.interface_map.nexthop_nssif = NSS_ETH_RX_INTERFACE;
- } else {
- ngrm.msg.interface_map.nexthop_nssif = vap_nss_if;
- }
-
- ngrm.msg.interface_map.lag_en = 0;
- ret = nss_gre_redir_tx_msg_sync(nss_ctx, &ngrm);
- if (ret != NSS_TX_SUCCESS) {
- nss_nl_error("%p: Tx to firmware failed\n", nss_ctx);
- return false;
- }
-
- nss_nl_info("%p: Successfully transmitted msg to firmware\n", nss_ctx);
- return true;
-}
-
-/*
- * nss_nlgre_redir_mgr_interface_unmap()
- * Interface unmap message.
- */
-bool nss_nlgre_redir_mgr_interface_unmap(uint32_t vap_nss_if, struct nss_nlgre_redir_unmap *if_unmap_params)
-{
- struct nss_gre_redir_msg ngrm;
- struct nss_ctx_instance *nss_ctx;
- nss_tx_status_t ret;
- uint32_t len = sizeof(struct nss_gre_redir_msg) - sizeof(struct nss_cmn_msg);
- nss_ctx = nss_gre_redir_get_context();
-
- if ((vap_nss_if >= NSS_DYNAMIC_IF_START+NSS_MAX_DYNAMIC_INTERFACES) || (vap_nss_if < NSS_DYNAMIC_IF_START)) {
- nss_nl_error("%p: vap_nss_if is out of valid range for vap: %d\n", nss_ctx, vap_nss_if);
- return false;
- }
-
- if (if_unmap_params->rid >= NSS_NLGRE_REDIR_RADIO_ID_MAX) {
- nss_nl_error("%p: radio_id is out of valid range for vap: %d\n", nss_ctx, vap_nss_if);
- return false;
- }
-
- if (if_unmap_params->vid >= NSS_NLGRE_REDIR_VAP_ID_MAX) {
- nss_nl_error("%p: vap_id is out of valid range for vap: %d\n", nss_ctx, vap_nss_if);
- return false;
- }
-
- nss_cmn_msg_init(&ngrm.cm, NSS_GRE_REDIR_INTERFACE, NSS_GRE_REDIR_TX_INTERFACE_UNMAP_MSG,
- len, nss_nlgre_redir_mgr_cb_gre_msg, NULL);
- ngrm.msg.interface_unmap.vap_nssif = vap_nss_if;
- ngrm.msg.interface_unmap.radio_id = if_unmap_params->rid;
- ngrm.msg.interface_unmap.vap_id = if_unmap_params->vid;
-
- ret = nss_gre_redir_tx_msg_sync(nss_ctx, &ngrm);
- if (ret != NSS_TX_SUCCESS) {
- nss_nl_error("%p: Tx to firmware failed\n", nss_ctx);
- return false;
- }
-
- nss_nl_info("%p: Successfully transmitted msg to firmware\n", nss_ctx);
- return true;
-}
-
-/*
- * nss_nlgre_redir_mgr_set_next_hop()
- * Sets next hop as gre-redir for wifi.
- */
-bool nss_nlgre_redir_mgr_set_next_hop(struct nss_nlgre_redir_set_next *setnext_params)
-{
- void *ctx;
- int ifnumber, next_dev_ifnum, index;
- struct net_device *dev, *tundev;
- nss_tx_status_t ret;
- struct nss_ctx_instance *nss_ctx = nss_gre_redir_get_context();
-
- dev = dev_get_by_name(&init_net, setnext_params->dev_name);
- if (!dev) {
- nss_nl_error("%p: Unable to find net device corresponding to device %s\n", nss_ctx, setnext_params->dev_name);
- return false;
- }
-
- ifnumber = nss_cmn_get_interface_number_by_dev(dev);
- dev_put(dev);
- if (ifnumber == -1) {
- nss_nl_error("%p: Unable to find NSS interface for net device %s\n", nss_ctx, setnext_params->dev_name);
- return false;
- }
-
- if (!strncmp(setnext_params->mode, "split", NSS_NLGRE_REDIR_TUN_TYPE_MAX_SZ)) {
- next_dev_ifnum = NSS_ETH_RX_INTERFACE;
- } else {
- tundev = dev_get_by_name(&init_net, setnext_params->next_dev_name);
- if (!tundev) {
- nss_nl_error("%p: Unable to find net device corresponding to device %s\n", nss_ctx, setnext_params->next_dev_name);
- return false;
- }
-
- if (!nss_nlgre_redir_mgr_get_pvt_data_index(tundev, &index)) {
- nss_nl_error("%p: Unable to find tunnel associated with device\n", tundev);
- dev_put(tundev);
- return false;
- }
-
- dev_put(tundev);
- next_dev_ifnum = pvt_data[index].wifi_offl_inner_ifnum;
- }
-
- nss_nl_info("%p: next hop interface number is %d\n", nss_ctx, next_dev_ifnum);
- ctx = nss_wifi_get_context();
- ret = nss_wifi_vdev_set_next_hop(ctx, ifnumber, next_dev_ifnum);
-
- if (ret != NSS_TX_SUCCESS) {
- nss_nl_error("%p: wifi drv api failed to set next hop\n", nss_ctx);
- return false;
- }
-
- return true;
-}
-
-/*
- * nss_nlgre_redir_mgr_create_tun()
- * Allocates net_dev and configures tunnel.
- */
-int nss_nlgre_redir_mgr_create_tun(struct nss_nlgre_redir_create_tun *create_params)
-{
- int i, tun_idx = -1;
- struct net_device *dev;
- struct nss_gre_redir_ndev_priv *priv;
- struct nss_gre_redir_inner_configure_msg ngrm;
- struct nss_gre_redir_outer_configure_msg ngrocm;
- nss_tx_status_t status;
- struct nss_ctx_instance *nss_ctx = nss_gre_redir_get_context();
-
- dev = alloc_netdev(sizeof(*priv), "gretun%d", NET_NAME_UNKNOWN, ether_setup);
- if (!dev) {
- nss_nl_error("Unable to allocate netdev\n");
- return tun_idx;
- }
-
- dev->needed_headroom = NSS_NLGRE_REDIR_NEEDED_HEADROOM;
- dev->netdev_ops = &gre_netdev_ops;
- for (i = 0; i < NSS_NLGRE_REDIR_MAX_TUNNELS ; i++) {
- if (!pvt_data[i].enable) {
- tun_idx = i;
- break;
- }
- }
-
- if (tun_idx == -1) {
- nss_nl_error("Unable to allocate any tunnel\n");
- return tun_idx;
- }
-
- /*
- * Dynamic interface allocation.
- */
- pvt_data[tun_idx].host_inner_ifnum = nss_gre_redir_alloc_and_register_node(dev,
- nss_nlgre_redir_mgr_host_data_cb,
- NULL, NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_WIFI_HOST_INNER, dev);
- nss_nl_info("%p: host_inner = %d\n", nss_ctx, pvt_data[tun_idx].host_inner_ifnum);
- if (pvt_data[tun_idx].host_inner_ifnum == -1) {
- nss_nl_error("%p: Unable to allocate and register wifi host inner interface\n", nss_ctx);
- goto fail;
- }
-
- pvt_data[tun_idx].wifi_offl_inner_ifnum = nss_gre_redir_alloc_and_register_node(dev,
- nss_nlgre_redir_mgr_wifi_offl_data_cb,
- NULL, NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_WIFI_OFFL_INNER, dev);
- nss_nl_info("%p: wifi_inner = %d\n", nss_ctx, pvt_data[tun_idx].wifi_offl_inner_ifnum);
- if (pvt_data[tun_idx].wifi_offl_inner_ifnum == -1) {
- nss_nl_error("%p: Unable to allocate and register wifi offload inner interface\n", nss_ctx);
- goto fail;
- }
-
- pvt_data[tun_idx].sjack_inner_ifnum = nss_gre_redir_alloc_and_register_node(dev,
- nss_nlgre_redir_mgr_sjack_data_cb,
- NULL, NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_SJACK_INNER, dev);
- nss_nl_info("%p: sjack_inner = %d\n", nss_ctx, pvt_data[tun_idx].sjack_inner_ifnum);
- if (pvt_data[tun_idx].sjack_inner_ifnum == -1) {
- nss_nl_error("%p: Unable to allocate and register sjack inner interface\n", nss_ctx);
- goto fail;
- }
-
- pvt_data[tun_idx].outer_ifnum = nss_gre_redir_alloc_and_register_node(dev,
- nss_nlgre_redir_mgr_outer_data_cb,
- NULL, NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_OUTER, dev);
- nss_nl_info("%p: outer = %d\n", nss_ctx, pvt_data[tun_idx].outer_ifnum);
- if (pvt_data[tun_idx].outer_ifnum == -1) {
- nss_nl_error("%p: Unable to allocate and register outer interface\n", nss_ctx);
- goto fail;
- }
-
- memset(&ngrm, 0, sizeof(struct nss_gre_redir_inner_configure_msg));
- memset(&ngrocm, 0, sizeof(struct nss_gre_redir_outer_configure_msg));
- ngrm.ip_hdr_type = create_params->iptype;
- ngrocm.ip_hdr_type = create_params->iptype;
-
- memcpy(ngrm.ip_src_addr, create_params->sip, sizeof(ngrm.ip_src_addr));
- memcpy(ngrm.ip_dest_addr, create_params->dip, sizeof(ngrm.ip_dest_addr));
-
- /*
- * TODO: Dynamic assignment of values from userspace
- * ip_df_policy value currently hard coded. This needs to be supplied from userspace.
- */
- ngrm.ip_df_policy = 0;
- ngrm.gre_version = 0;
- ngrm.ip_ttl = 128;
- ngrm.except_outerif = pvt_data[tun_idx].outer_ifnum;
-
- /*
- * TODO: Dynamic assignment of values from userspace
- * rps_hint value currently hard coded. This needs to be supplied from userspace.
- */
- ngrocm.rps_hint = 0;
- ngrocm.except_hostif = pvt_data[tun_idx].host_inner_ifnum;
- ngrocm.except_offlif = pvt_data[tun_idx].wifi_offl_inner_ifnum;
- ngrocm.except_sjackif = pvt_data[tun_idx].sjack_inner_ifnum;
-
- status = nss_gre_redir_configure_inner_node(pvt_data[tun_idx].host_inner_ifnum, &ngrm);
- if (status != NSS_TX_SUCCESS) {
- nss_nl_warn("%p: unable to configure host inner node %d\n", nss_ctx, pvt_data[tun_idx].host_inner_ifnum);
- goto fail;
- }
-
- status = nss_gre_redir_configure_inner_node(pvt_data[tun_idx].wifi_offl_inner_ifnum, &ngrm);
- if (status != NSS_TX_SUCCESS) {
- nss_nl_warn("%p: unable to configure wifi offload inner node %d\n", nss_ctx, pvt_data[tun_idx].host_inner_ifnum);
- goto fail;
- }
-
- status = nss_gre_redir_configure_inner_node(pvt_data[tun_idx].sjack_inner_ifnum, &ngrm);
- if (status != NSS_TX_SUCCESS) {
- nss_nl_warn("%p: unable to configure sjack inner node %d\n", nss_ctx, pvt_data[tun_idx].sjack_inner_ifnum);
- goto fail;
- }
-
- status = nss_gre_redir_configure_outer_node(pvt_data[tun_idx].outer_ifnum, &ngrocm);
- if (status != NSS_TX_SUCCESS) {
- nss_nl_warn("%p: unable to configure outer node %d\n", nss_ctx, pvt_data[tun_idx].host_inner_ifnum);
- goto fail;
- }
-
- nss_nlgre_redir_mgr_ether_setup(dev);
- if (register_netdev(dev)) {
- nss_nl_warn("%p: Unable to register netdev\n", nss_ctx);
- nss_nlgre_redir_mgr_destroy_tun(dev);
- }
-
- pvt_data[tun_idx].enable = true;
- pvt_data[tun_idx].dev = dev;
-
- return tun_idx;
-fail:
- nss_nlgre_redir_mgr_interfaces_unregister_and_dealloc(dev, tun_idx);
- nss_nlgre_redir_mgr_deinit_pvt_data(tun_idx);
- free_netdev(dev);
- return -1;
-}
-
-/*
- * nss_nlgre_redir_mgr_open()
- * Used when the interface is opened for use.
- */
-static int nss_nlgre_redir_mgr_open(struct net_device *dev)
-{
- struct nss_gre_redir_ndev_priv *priv;
- priv = netdev_priv(dev);
- priv->gre_seq = 0;
- netif_start_queue(dev);
- netif_carrier_on(dev);
- return 0;
-}
-
-/*
- * nss_nlgre_redir_mgr_close()
- * Used when the interface is closed.
- */
-static int nss_nlgre_redir_mgr_close(struct net_device *dev)
-{
- netif_stop_queue (dev);
- netif_carrier_off(dev);
- return 0;
-}
-
-/*
- * nss_nlgre_redir_mgr_get_stats64()
- * Used when to get link statistics.
- */
-static struct rtnl_link_stats64 *nss_nlgre_redir_mgr_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
-{
- bool ret = false;
- int i;
- struct nss_gre_redir_tunnel_stats get_stats;
-
- for (i = 0; i < NSS_GRE_REDIR_MAX_INTERFACES; i++) {
- ret = nss_gre_redir_get_stats(i, &get_stats);
- if (ret == true && get_stats.dev == dev) {
- break;
- }
- }
- if (ret == false)
- return stats;
-
- stats->tx_bytes = get_stats.node_stats.tx_bytes;
- stats->tx_packets = get_stats.node_stats.tx_packets;
- stats->rx_bytes = get_stats.node_stats.rx_bytes;
- stats->rx_packets = get_stats.node_stats.rx_packets;
- for (i = 0;i < ARRAY_SIZE(get_stats.node_stats.rx_dropped); i++) {
- stats->rx_dropped += get_stats.node_stats.rx_dropped[i];
- }
-
- stats->tx_dropped = get_stats.tx_dropped;
-
- return stats;
-}
-
-/*
- * nss_nlgre_redir_mgr_set_mac_address()
- * Sets the MAC address.
- */
-static int nss_nlgre_redir_mgr_set_mac_address(struct net_device *dev, void *p)
-{
- struct sockaddr *addr = (struct sockaddr *)p;
-
- if (!is_valid_ether_addr(addr->sa_data)) {
- nss_nl_error("MAC address validation failed \n");
- return -EINVAL;
- }
-
- memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
- return 0;
-}
-
-/*
- * net_device_ops
- * Netdevice operations.
- */
-static const struct net_device_ops gre_netdev_ops = {
- .ndo_open = nss_nlgre_redir_mgr_open,
- .ndo_stop = nss_nlgre_redir_mgr_close,
- .ndo_start_xmit = nss_nlgre_redir_mgr_xmit,
- .ndo_get_stats64 = nss_nlgre_redir_mgr_get_stats64,
- .ndo_set_mac_address = nss_nlgre_redir_mgr_set_mac_address,
-};
-
-MODULE_DESCRIPTION("NSS GRE_REDIR module");
diff --git a/netlink/nss_nlgre_redir_mgr.h b/netlink/nss_nlgre_redir_mgr.h
deleted file mode 100644
index 076998b..0000000
--- a/netlink/nss_nlgre_redir_mgr.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- ***************************************************************************
- * Copyright (c) 2014-2015,2019, 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.
- **************************************************************************
- */
-
-/*
- * nss_nlgre_redir_mgr_interface_map()
- * Interface map message.
- */
-bool nss_nlgre_redir_mgr_interface_map(uint32_t vap_nssif, uint32_t tun_type, struct nss_nlgre_redir_map *interface_map_params);
-
-/*
- * nss_nlgre_redir_mgr_interface_unmap()
- * Interface unmap message.
- */
-bool nss_nlgre_redir_mgr_interface_unmap(uint32_t vap_nssif, struct nss_nlgre_redir_unmap *interface_unmap_params);
-
-/*
- * nss_nlgre_redir_mgr_set_next_hop()
- * Sets next hop as gre-redir for wifi.
- */
-bool nss_nlgre_redir_mgr_set_next_hop(struct nss_nlgre_redir_set_next *interface_setnext_params);
-
-/*
- * nss_nlgre_redir_mgr_create_tun()
- * Allocates net_dev and configures tunnel.
- */
-int nss_nlgre_redir_mgr_create_tun(struct nss_nlgre_redir_create_tun *create_params);
-
-/*
- * nss_nlgre_redir_mgr_destroy_tun()
- * Unregisters and deallocs dynamic interfaces.
- */
-bool nss_nlgre_redir_mgr_destroy_tun(struct net_device *dev);
-
-/*
- * nss_gre_redir_tunnel_types nss_nlgre_redir_mgr_tunnel_type()
- * Returns the tunnel type
- */
-enum nss_gre_redir_tunnel_types nss_nlgre_redir_mgr_tunnel_type(char *tun_type);
diff --git a/netlink/nss_nlipv4.c b/netlink/nss_nlipv4.c
index 02819a7..e102a15 100644
--- a/netlink/nss_nlipv4.c
+++ b/netlink/nss_nlipv4.c
@@ -51,7 +51,7 @@
#include "nss_ipsecmgr.h"
#include "nss_nl.h"
#include "nss_nlcmn_if.h"
-#include "nss_nlgre_redir.h"
+#include "nss_nlgre_redir_cmd.h"
#include "nss_nlipsec_if.h"
#include "nss_nlipsec.h"
#include "nss_nlipv4_if.h"
@@ -326,7 +326,7 @@
/*
* Currently this implementation is only for gre_redir
*/
- conn->flow_interface_num = nss_nlgre_redir_get_ifnum(flow_dev,
+ conn->flow_interface_num = nss_nlgre_redir_cmd_get_ifnum(flow_dev,
NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_OUTER);
if (conn->flow_interface_num < 0 ) {
nss_nl_error("%p: Failed to get flow interface number (dev:%s, type:%d)\n",
@@ -384,7 +384,7 @@
break;
case NSS_NL_IFTYPE_TUNNEL_GRE:
- conn->return_interface_num = nss_nlgre_redir_get_ifnum(return_dev,
+ conn->return_interface_num = nss_nlgre_redir_cmd_get_ifnum(return_dev,
NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_WIFI_OFFL_INNER);
if (conn->return_interface_num < 0 ) {
nss_nl_error("%p: Failed to get return interface number (dev:%s, type:%d)\n",
diff --git a/netlink/nss_nlipv6.c b/netlink/nss_nlipv6.c
index 0fe5a97..c673832 100644
--- a/netlink/nss_nlipv6.c
+++ b/netlink/nss_nlipv6.c
@@ -57,7 +57,7 @@
#include "nss_nlipv6_if.h"
#include "nss_ipsecmgr.h"
#include "nss_nlipsec_if.h"
-#include "nss_nlgre_redir.h"
+#include "nss_nlgre_redir_cmd.h"
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
#define DST_NEIGH_LOOKUP(dst, ip_addr) dst_neigh_lookup(dst, ip_addr)
@@ -337,7 +337,7 @@
break;
case NSS_NL_IFTYPE_TUNNEL_GRE:
- conn->flow_interface_num = nss_nlgre_redir_get_ifnum(flow_dev, NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_OUTER);
+ conn->flow_interface_num = nss_nlgre_redir_cmd_get_ifnum(flow_dev, NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_OUTER);
if (conn->flow_interface_num < 0 ) {
nss_nl_error("%p: Failed to get flow interface number (dev:%s, type:%d)\n",
flow_dev, flow_dev->name, flow_iftype);
@@ -395,7 +395,7 @@
break;
case NSS_NL_IFTYPE_TUNNEL_GRE:
- conn->return_interface_num = nss_nlgre_redir_get_ifnum(return_dev,
+ conn->return_interface_num = nss_nlgre_redir_cmd_get_ifnum(return_dev,
NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_WIFI_OFFL_INNER);
if (conn->return_interface_num < 0 ) {
nss_nl_error("%p: Failed to get return interface number (dev:%s, type:%d)\n",