[ipq806x] : IPV6 6RD Host module for NSS
These changes include host 6rd module and connection manager
changes to push 6rd tunnel rule.
Change-Id: I77fb43545f7478b58c3f1e85c42008f075a74ab2
Signed-off-by: Bharath M Kumar <mbkumar@codeaurora.org>
Reviewed-by: Abhishek Rastogi <arastogi@codeaurora.org>
diff --git a/Makefile b/Makefile
index 308754c..a6f3fd0 100755
--- a/Makefile
+++ b/Makefile
@@ -21,6 +21,11 @@
obj-m += qca-nss-connmgr-ipv4.o
obj-m += qca-nss-connmgr-ipv6.o
+ifeq "$(CONFIG_IPV6_SIT_6RD)" "y"
+obj-m += qca-nss-tun6rd.o
+qca-nss-tun6rd-objs := nss_tun6rd.o
+ccflags-y += -DNSS_TUN6RD_DEBUG_LEVEL=0
+endif
qca-nss-connmgr-ipv4-objs := nss_connmgr_ipv4.o
qca-nss-connmgr-ipv6-objs := nss_connmgr_ipv6.o
diff --git a/nss_connmgr_ipv4.c b/nss_connmgr_ipv4.c
index 87d7222..842f221 100755
--- a/nss_connmgr_ipv4.c
+++ b/nss_connmgr_ipv4.c
@@ -527,13 +527,15 @@
/*
* Only work with standard 802.3 mac address sizes
+ * Skip mac address check for Tunnel interface
*/
- if (in->addr_len != 6) {
- NSS_CONNMGR_DEBUG_TRACE("in device (%s) not 802.3 hw addr len (%u), ignoring: %p\n", in->name, (unsigned)in->addr_len, skb);
+ if ((in->addr_len != 6) && (in->type != ARPHRD_SIT)) {
dev_put(in);
+ NSS_CONNMGR_DEBUG_TRACE("in device (%s) not 802.3 hw addr len (%u), ignoring: %p\n", in->name, (unsigned)in->addr_len, skb);
return NF_ACCEPT;
}
- if (out->addr_len != 6) {
+
+ if ((out->addr_len != 6) && (out->type != ARPHRD_SIT)) {
dev_put(in);
NSS_CONNMGR_DEBUG_TRACE("out device (%s) not 802.3 hw addr len (%u), ignoring: %p\n", out->name, (unsigned)out->addr_len, skb);
return NF_ACCEPT;
@@ -658,6 +660,13 @@
unic.dest_port_xlate = (int32_t)reply_tuple.src.u.udp.port;
break;
+ case IPPROTO_IPV6:
+ unic.src_port = 0;
+ unic.dest_port = 0;
+ unic.src_port_xlate = 0;
+ unic.dest_port_xlate = 0;
+ break;
+
default:
/*
* Streamengine compatibility - database stores non-ported protocols with port numbers equal to negative protocol number
@@ -1208,12 +1217,13 @@
/*
* Only work with standard 802.3 mac address sizes
*/
- if (in->addr_len != 6) {
- NSS_CONNMGR_DEBUG_TRACE("in device (%s) not 802.3 hw addr len (%u), ignoring: %p\n", in->name, (unsigned)in->addr_len, skb);
+ if ((in->addr_len != 6) && (in->type != ARPHRD_SIT)) {
dev_put(in);
+ NSS_CONNMGR_DEBUG_TRACE("in device (%s) not 802.3 hw addr len (%u), ignoring: %p\n", in->name, (unsigned)in->addr_len, skb);
return NF_ACCEPT;
}
- if (out->addr_len != 6) {
+
+ if ((out->addr_len != 6) && (out->type != ARPHRD_SIT)) {
dev_put(in);
NSS_CONNMGR_DEBUG_TRACE("out device (%s) not 802.3 hw addr len (%u), ignoring: %p\n", out->name, (unsigned)out->addr_len, skb);
return NF_ACCEPT;
@@ -1329,6 +1339,13 @@
unic.dest_port_xlate = (int32_t)reply_tuple.src.u.udp.port;
break;
+ case IPPROTO_IPV6:
+ unic.src_port = 0;
+ unic.dest_port = 0;
+ unic.src_port_xlate = 0;
+ unic.dest_port_xlate = 0;
+ break;
+
default:
/*
* Streamengine compatibility - database stores non-ported protocols with port numbers equal to negative protocol number
diff --git a/nss_connmgr_ipv6.c b/nss_connmgr_ipv6.c
index f2bc5e1..5ac0d3a 100755
--- a/nss_connmgr_ipv6.c
+++ b/nss_connmgr_ipv6.c
@@ -543,14 +543,15 @@
/*
* Only work with standard 802.3 mac address sizes
+ * Skip mac address check for Tunnel interface
*/
- if (in->addr_len != 6) {
- NSS_CONNMGR_DEBUG_TRACE("in device (%s) not 802.3 hw addr len (%u), ignoring: %p\n", in->name, (unsigned)in->addr_len, skb);
+ if ((in->addr_len != 6) && (in->type != ARPHRD_SIT)) {
dev_put(in);
+ NSS_CONNMGR_DEBUG_TRACE("in device (%s) not 802.3 hw addr len (%u), ignoring: %p\n", in->name, (unsigned)in->addr_len, skb);
return NF_ACCEPT;
}
- if (out->addr_len != 6) {
+ if ((out->addr_len != 6) && (out->type != ARPHRD_SIT)) {
dev_put(in);
NSS_CONNMGR_DEBUG_TRACE("out device (%s) not 802.3 hw addr len (%u), ignoring: %p\n", out->name, (unsigned)out->addr_len, skb);
return NF_ACCEPT;
@@ -958,13 +959,13 @@
/*
* Only work with standard 802.3 mac address sizes
*/
- if (in->addr_len != 6) {
+ if ((in->addr_len != 6) && (in->type != ARPHRD_SIT)) {
NSS_CONNMGR_DEBUG_TRACE("in device (%s) not 802.3 hw addr len (%u), ignoring: %p\n", in->name, (unsigned)in->addr_len, skb);
dev_put(in);
return NF_ACCEPT;
}
- if (out->addr_len != 6) {
+ if ((out->addr_len != 6) && (out->type != ARPHRD_SIT)) {
dev_put(in);
NSS_CONNMGR_DEBUG_TRACE("out device (%s) not 802.3 hw addr len (%u), ignoring: %p\n", out->name, (unsigned)out->addr_len, skb);
return NF_ACCEPT;
diff --git a/nss_init.c b/nss_init.c
index 170bc95..e10a3a6 100755
--- a/nss_init.c
+++ b/nss_init.c
@@ -312,6 +312,10 @@
nss_top->wlan_handler_id = nss_dev->id;
}
+ if (npd->tun6rd_enabled == NSS_FEATURE_ENABLED) {
+ nss_top->tun6rd_handler_id = nss_dev->id;
+ }
+
if (npd->gmac_enabled[0] == NSS_FEATURE_ENABLED) {
nss_top->phys_if_handler_id[0] = nss_dev->id;
}
diff --git a/nss_tun6rd.c b/nss_tun6rd.c
new file mode 100644
index 0000000..cda58aa
--- /dev/null
+++ b/nss_tun6rd.c
@@ -0,0 +1,442 @@
+/*
+ **************************************************************************
+ * Copyright (c) 2013, Qualcomm Atheros, Inc.
+ * 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_tun6rd.c
+ *
+ * This file is the NSS 6rd tunnel module
+ * ------------------------REVISION HISTORY-----------------------------
+ * Qualcomm Atheros 15/sep/2013 Created
+ */
+
+#include <linux/types.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <net/ipv6.h>
+#include <net/ipip.h>
+#include <linux/if_arp.h>
+#include "nss_api_if.h"
+#include "nss_hlos_if.h"
+
+#define NSS_TUNRD_IF_NUMBER 10
+
+/*
+ * NSS tun6rd debug macros
+ */
+#if (NSS_TUN6RD_DEBUG_LEVEL < 1)
+#define nss_tun6rd_assert(fmt, args...)
+#else
+#define nss_tun6d_assert(c) if (!(c)) { BUG_ON(!(c)); }
+#endif
+
+#if (NSS_TUN6RD_DEBUG_LEVEL < 2)
+#define nss_tun6rd_error(fmt, args...)
+#else
+#define nss_tun6rd_error(fmt, args...) printk(KERN_WARNING "nss tun6rd:"fmt, ##args)
+#endif
+
+#if (NSS_TUN6RD_DEBUG_LEVEL < 3)
+#define nss_tun6rd_warning(fmt, args...)
+#else
+#define nss_tun6rd_warning(fmt, args...) printk(KERN_WARNING "nss tun6rd:"fmt, ##args)
+#endif
+
+#if (NSS_TUN6RD_DEBUG_LEVEL < 4)
+#define nss_tun6rd_info(fmt, args...)
+#else
+#define nss_tun6rd_info(fmt, args...) printk(KERN_INFO "nss tun6rd :"fmt, ##args)
+#endif
+
+#if (NSS_TUN6RD_DEBUG_LEVEL < 5)
+#define nss_tun6rd_trace(fmt, args...)
+#else
+#define nss_tun6rd_trace(fmt, args...) printk(KERN_DEBUG "nss tun6rd :"fmt, ##args)
+#endif
+
+void nss_tun6rd_exception(void *ctx, void *buf);
+
+enum tun6rd_metadata_types {
+ TUN6RD_METADATA_TYPE_IF_UP,
+ TUN6RD_METADATA_TYPE_IF_DOWN
+};
+
+/*
+ * 6rd configuration command structure
+ */
+struct nss_tunnel_6rd_cfg{
+ uint32_t prefix[4]; /*6rd prefix */
+ uint32_t relay_prefix; /* Relay prefix */
+ uint16_t prefixlen; /* 6rd prefix len */
+ uint16_t relay_prefixlen; /* Relay prefix length*/
+ uint32_t saddr; /* Tunnel source address */
+ uint32_t daddr; /* Tunnel destination addresss */
+ uint8_t tos; /* Tunnel tos field */
+ uint8_t ttl; /* Tunnel ttl field */
+
+};
+
+/*
+ * 6rd tunnel interface down command structure
+ */
+struct tun6rd_if_down_param{
+ uint32_t prefix[4]; /*Tunnel 6rd prefix */
+};
+
+/*
+ * 6rd Tunnel generic param
+ */
+struct nss_tunnel_6rd_param {
+ enum tun6rd_metadata_types type;
+ union {
+ struct nss_tunnel_6rd_cfg cfg;
+ struct tun6rd_if_down_param ifdown_param;
+ }sub;
+};
+
+/*
+ * 6rd tunnel host instance
+ */
+struct nss_tun6rd_tunnel{
+ void *nss_ctx;
+ uint32_t if_num;
+ struct net_device *netdev;
+ uint32_t device_up;
+};
+
+struct nss_tun6rd_tunnel g_tun6rd;
+
+/*
+ * Internal function
+ */
+static int
+nss_tun6rd_dev_event(struct notifier_block *nb,
+ unsigned long event,
+ void *dev);
+
+/*
+ * Linux Net device Notifier
+ */
+struct notifier_block nss_tun6rd_notifier = {
+ .notifier_call = nss_tun6rd_dev_event,
+};
+
+/*
+ * nss_tun6rd_dev_up()
+ * 6RD Tunnel device i/f up handler
+ */
+void nss_tun6rd_dev_up( struct net_device * netdev)
+{
+ struct ip_tunnel *tunnel;
+ struct ip_tunnel_6rd_parm *ip6rd;
+ const struct iphdr *tiph;
+ struct nss_tunnel_6rd_param tun6rdparam;
+ struct nss_tunnel_6rd_cfg *tun6rdcfg;
+ nss_tx_status_t status;
+
+ /*
+ * Validate netdev for ipv6-in-ipv4 Tunnel
+ */
+ if (netdev->type != ARPHRD_SIT ) {
+ return;
+ }
+
+ tunnel = (struct ip_tunnel*)netdev_priv(netdev);
+ ip6rd = &tunnel->ip6rd;
+
+ /*
+ * Valid 6rd Tunnel Check
+ * 1. 6rd Prefix len should be non zero
+ * 2. Relay prefix length should not be greater then 32
+ * 3. To allow for stateless address auto-configuration on the CE LAN side,
+ * 6rd delegated prefix SHOULD be /64 or shorter.
+ */
+ if ((ip6rd->prefixlen == 0 )
+ || (ip6rd->relay_prefixlen > 32)
+ || (ip6rd->prefixlen
+ + (32 - ip6rd->relay_prefixlen) > 64)){
+
+ nss_tun6rd_error("Invalid 6rd argument prefix len %d \
+ relayprefix len %d \n",
+ ip6rd->prefixlen,ip6rd->relay_prefixlen);
+ return;
+ }
+
+ nss_tun6rd_info(" Valid 6rd Tunnel Prefix %x %x %x %x \n \
+ prefix len %d relay_prefix %d relay_prefixlen %d \n",
+ ip6rd->prefix.s6_addr32[0],ip6rd->prefix.s6_addr32[1],
+ ip6rd->prefix.s6_addr32[2],ip6rd->prefix.s6_addr32[3],
+ ip6rd->prefixlen, ip6rd->relay_prefix,
+ ip6rd->relay_prefixlen);
+
+ /*
+ * Prepare The Tunnel configuration parameter to send to nss
+ */
+ memset( &tun6rdparam, 0, sizeof(struct nss_tunnel_6rd_param));
+ tun6rdparam.type = TUN6RD_METADATA_TYPE_IF_UP;
+ tun6rdcfg = (struct nss_tunnel_6rd_cfg *)&tun6rdparam.sub.cfg;
+
+ /*
+ * Find the Tunnel device ipHeader info
+ */
+ tiph = &tunnel->parms.iph ;
+ nss_tun6rd_trace(" Tunnel Param srcaddr %x daddr %x ttl %d tos %x\n",
+ tiph->saddr, tiph->daddr,tiph->ttl,tiph->tos);
+
+ if(tiph->saddr == 0) {
+ nss_tun6rd_error("Tunnel src address not configured %x\n",
+ tiph->saddr);
+ return;
+ }
+
+ if (tiph->daddr == 0) {
+ nss_tun6rd_error("Tunnel dest address not configured %x\n",
+ tiph->daddr);
+ return;
+ }
+
+ tun6rdcfg->prefixlen = ip6rd->prefixlen;
+ tun6rdcfg->relay_prefix = ip6rd->relay_prefix;
+ tun6rdcfg->relay_prefixlen = ip6rd->relay_prefixlen;
+ tun6rdcfg->saddr = ntohl(tiph->saddr);
+ tun6rdcfg->daddr = ntohl(tiph->daddr);
+ tun6rdcfg->prefix[0] = ntohl(ip6rd->prefix.s6_addr32[0]);
+ tun6rdcfg->prefix[1] = ntohl(ip6rd->prefix.s6_addr32[1]);
+ tun6rdcfg->prefix[2] = ntohl(ip6rd->prefix.s6_addr32[2]);
+ tun6rdcfg->prefix[3] = ntohl(ip6rd->prefix.s6_addr32[3]);
+ tun6rdcfg->ttl = tiph->ttl;
+ tun6rdcfg->tos = tiph->tos;
+
+ nss_tun6rd_trace(" 6rd Tunnel info \n");
+ nss_tun6rd_trace(" saddr %x daddr %d ttl %x tos %x \n",
+ tiph->saddr, tiph->daddr, tiph->ttl, tiph->tos);
+ nss_tun6rd_trace(" Prefix %x:%x:%x:%x Prefix len %d \n",
+ ip6rd->prefix.s6_addr32[0], ip6rd->prefix.s6_addr32[1],
+ ip6rd->prefix.s6_addr32[2], ip6rd->prefix.s6_addr32[3],
+ ip6rd->prefixlen);
+ nss_tun6rd_trace("Relay Prefix %x Len %d\n",
+ ip6rd->relay_prefix, ip6rd->relay_prefixlen);
+
+ /*
+ * Register 6rd tunnel with NSS
+ */
+ g_tun6rd.nss_ctx = nss_register_tun6rd_if(g_tun6rd.if_num,
+ nss_tun6rd_exception,
+ netdev);
+ if (g_tun6rd.nss_ctx == NULL) {
+ nss_tun6rd_trace("nss_register_tun6rd_if Failed \n");
+ return;
+ } else {
+ nss_tun6rd_trace("nss_register_tun6rd_if Success \n");
+ }
+
+ nss_tun6rd_trace("Sending 6rd tunnel i/f up command to NSS %x \n",
+ (int)g_tun6rd.nss_ctx);
+
+ /*
+ * Send 6rd Tunnel UP command to NSS
+ */
+ status = nss_tx_generic_if_buf(g_tun6rd.nss_ctx,
+ g_tun6rd.if_num,
+ (uint8_t *)&tun6rdparam,
+ sizeof(struct nss_tunnel_6rd_param));
+
+ if (status != NSS_TX_SUCCESS) {
+ nss_tun6rd_error("Tunnel up command error %d \n", status);
+ return;
+ }
+
+ g_tun6rd.device_up = 1;
+}
+
+/*
+ * nss_tun6rd_dev_down()
+ * 6RD Tunnel device i/f down handler
+ */
+void nss_tun6rd_dev_down( struct net_device * netdev)
+{
+ struct ip_tunnel *tunnel;
+ struct ip_tunnel_6rd_parm *ip6rd;
+ struct nss_tunnel_6rd_param tun6rdparam;
+ struct tun6rd_if_down_param *ifdown;
+ nss_tx_status_t status;
+
+ /*
+ * Check if tunnel 6rd is registered ?
+ */
+ if (g_tun6rd.nss_ctx == NULL) {
+ return;
+ }
+
+ /*
+ * Validate netdev for ipv6-in-ipv4 Tunnel
+ */
+ if (netdev->type != ARPHRD_SIT ) {
+ return;
+ }
+
+ tunnel = (struct ip_tunnel*)netdev_priv(netdev);
+ ip6rd = &tunnel->ip6rd;
+
+ /*
+ * Valid 6rd Tunnel Check
+ */
+ if ((ip6rd->prefixlen == 0 )
+ || (ip6rd->relay_prefixlen > 32 )
+ || (ip6rd->prefixlen
+ + (32 - ip6rd->relay_prefixlen) > 64)){
+
+ nss_tun6rd_error("Invalid 6rd argument prefix len %d \
+ relayprefix len %d \n",
+ ip6rd->prefixlen,ip6rd->relay_prefixlen);
+ return;
+ }
+
+ memset( &tun6rdparam, 0, sizeof(struct nss_tunnel_6rd_param));
+ tun6rdparam.type = TUN6RD_METADATA_TYPE_IF_DOWN;
+ ifdown = (struct tun6rd_if_down_param *)&tun6rdparam.sub.ifdown_param;
+ ifdown->prefix[0] = ntohl(ip6rd->prefix.s6_addr32[0]);
+ ifdown->prefix[1] = ntohl(ip6rd->prefix.s6_addr32[1]);
+ ifdown->prefix[2] = ntohl(ip6rd->prefix.s6_addr32[2]);
+ ifdown->prefix[3] = ntohl(ip6rd->prefix.s6_addr32[3]);
+
+ nss_tun6rd_trace(" Prefix %x:%x:%x:%x Prefix len %d \n",
+ ip6rd->prefix.s6_addr32[0], ip6rd->prefix.s6_addr32[1],
+ ip6rd->prefix.s6_addr32[2], ip6rd->prefix.s6_addr32[3],
+ ip6rd->prefixlen);
+
+
+ nss_tun6rd_trace("Sending Tunnle 6rd Down command %x \n",g_tun6rd.if_num);
+ status = nss_tx_generic_if_buf(g_tun6rd.nss_ctx,
+ g_tun6rd.if_num,
+ (uint8_t *)&tun6rdparam,
+ sizeof(struct nss_tunnel_6rd_param));
+
+ if (status != NSS_TX_SUCCESS) {
+ nss_tun6rd_error("Tunnel down command error %d \n", status);
+ return;
+ }
+
+ /*
+ * Un-Register 6rd tunnel with NSS
+ */
+ nss_unregister_tun6rd_if(g_tun6rd.if_num);
+ g_tun6rd.nss_ctx = NULL;
+ g_tun6rd.device_up = 0;
+ return;
+}
+
+/*
+ * nss_tun6rd_dev_event()
+ * Net device notifier for 6rd module
+ */
+static int nss_tun6rd_dev_event(struct notifier_block *nb,
+ unsigned long event, void *dev)
+{
+ struct net_device *netdev = (struct net_device *)dev;
+
+ nss_tun6rd_trace("%s\n",__FUNCTION__);
+ switch (event) {
+ case NETDEV_UP:
+ nss_tun6rd_trace(" NETDEV_UP :event %lu name %s \n",
+ event,netdev->name);
+ nss_tun6rd_dev_up(netdev);
+ break;
+
+ case NETDEV_DOWN:
+ nss_tun6rd_trace(" NETDEV_DOWN :event %lu name %s \n",
+ event,netdev->name);
+ nss_tun6rd_dev_down(netdev);
+ break;
+
+ default:
+ nss_tun6rd_trace("Unhandled notifier dev %s event %x \n",
+ netdev->name,(int)event);
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+
+/*
+ * nss_tun6rd_exception()
+ * Exception handler registered to NSS driver
+ */
+void nss_tun6rd_exception(void *ctx, void *buf)
+{
+ struct net_device *dev = (struct net_device *)ctx;
+ struct sk_buff *skb = (struct sk_buff *)buf;
+ const struct iphdr *iph;
+
+ skb->dev = dev;
+ nss_tun6rd_info("received - %d bytes name %s ver %x \n",
+ skb->len,dev->name,skb->data[0]);
+
+ iph = (const struct iphdr *)skb->data;
+
+ /*
+ * Packet after Decap/Encap Did not find the Rule.
+ */
+ if (iph->version == 4) {
+ skb->protocol = htons(ETH_P_IP);
+ } else {
+ skb->protocol = htons(ETH_P_IPV6);
+ }
+
+ skb_reset_network_header(skb);
+ skb->pkt_type = PACKET_HOST;
+ skb->skb_iif = dev->ifindex;
+ skb->ip_summed = CHECKSUM_NONE;
+ netif_receive_skb(skb);
+}
+
+/*
+ * nss_tun6rd_init_module()
+ * Tunnel 6rd module init function
+ */
+int __init nss_tun6rd_init_module(void)
+{
+ nss_tun6rd_info("module (platform - IPQ806x , Build - %s:%s) loaded\n",
+ __DATE__, __TIME__);
+
+ register_netdevice_notifier(&nss_tun6rd_notifier);
+ nss_tun6rd_trace("Netdev Notifier registerd \n");
+
+ g_tun6rd.if_num = NSS_TUNRD_IF_NUMBER;
+ g_tun6rd.netdev = NULL;
+ g_tun6rd.device_up = 0;
+ g_tun6rd.nss_ctx = NULL;
+
+ return 0;
+}
+
+/*
+ * nss_tun6rd_exit_module()
+ * Tunnel 6rd module exit function
+ */
+void __exit nss_tun6rd_exit_module(void)
+{
+
+ unregister_netdevice_notifier(&nss_tun6rd_notifier);
+ nss_tun6rd_info("module unloaded\n");
+}
+
+module_init(nss_tun6rd_init_module);
+module_exit(nss_tun6rd_exit_module);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("NSS tun6rd offload manager");