[qca-nss-clients] Support for GRE tunnel
Change-Id: I13959f881f0c07ee6f2bb99957e20461800a76c7
Signed-off-by: Suman Ghosh <sumaghos@codeaurora.org>
diff --git a/gre/nss_connmgr_gre.c b/gre/nss_connmgr_gre.c
index adaf7c3..ccaaaec 100644
--- a/gre/nss_connmgr_gre.c
+++ b/gre/nss_connmgr_gre.c
@@ -1,6 +1,6 @@
/*
**************************************************************************
- * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018 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.
@@ -353,25 +353,21 @@
}
/*
- * nss_connmgr_gre_exception()
+ * nss_connmgr_gre_tap_exception()
+ * Exception handler for GRETAP device
*/
-static void nss_connmgr_gre_exception(struct net_device *dev, struct sk_buff *skb,
+static void nss_connmgr_gre_tap_exception(struct net_device *dev, struct sk_buff *skb,
__attribute__((unused)) struct napi_struct *napi)
{
struct ethhdr *eth_hdr;
- if (unlikely(!enable_notifier)) {
- nss_connmgr_gre_error("%p: NSS GRE exception handler called\n", dev);
- dev_kfree_skb_any(skb);
- return;
- }
-
if (unlikely(!pskb_may_pull(skb, sizeof(struct ethhdr)))) {
nss_connmgr_gre_warning("%p: pskb_may_pull failed for skb:%p\n", dev, skb);
dev_kfree_skb_any(skb);
return;
}
eth_hdr = (struct ethhdr *)skb->data;
+ nss_connmgr_gre_warning("%p: eth_hdr->h_proto: %d\n", dev, eth_hdr->h_proto);
if (likely(ntohs(eth_hdr->h_proto) >= ETH_P_802_3_MIN)) {
switch (ntohs(eth_hdr->h_proto)) {
case ETH_P_IP:
@@ -380,14 +376,14 @@
dev_kfree_skb_any(skb);
return;
}
- return nss_connmgr_gre_v4_exception(dev, skb);
+ return nss_connmgr_gre_tap_v4_exception(dev, skb);
case ETH_P_IPV6:
if (unlikely(!pskb_may_pull(skb, sizeof(struct ipv6hdr)))) {
nss_connmgr_gre_warning("%p: pskb_may_pull failed for skb:%p\n", dev, skb);
dev_kfree_skb_any(skb);
return;
}
- return nss_connmgr_gre_v6_exception(dev, skb);
+ return nss_connmgr_gre_tap_v6_exception(dev, skb);
default:
break;
}
@@ -402,6 +398,38 @@
}
/*
+ * nss_connmgr_gre_tun_exception()
+ * Exception handler for GRETUN device
+ */
+static void nss_connmgr_gre_tun_exception(struct net_device *dev, struct sk_buff *skb,
+ __attribute__((unused)) struct napi_struct *napi)
+{
+ struct iphdr *iph;
+
+ if (unlikely(!pskb_may_pull(skb, sizeof(struct iphdr)))) {
+ nss_connmgr_gre_warning("%p: pskb_may_pull failed for skb:%p\n", dev, skb);
+ dev_kfree_skb_any(skb);
+ return;
+ }
+ iph = (struct iphdr *)skb->data;
+ switch (iph->version) {
+ case 4:
+ return nss_connmgr_gre_tun_v4_exception(dev, skb);
+ case 6:
+ if (unlikely(!pskb_may_pull(skb, sizeof(struct ipv6hdr)))) {
+ nss_connmgr_gre_warning("%p: pskb_may_pull failed for skb:%p\n", dev, skb);
+ dev_kfree_skb_any(skb);
+ return;
+ }
+ return nss_connmgr_gre_tun_v6_exception(dev, skb);
+ default:
+ nss_connmgr_gre_warning("%p: wrong IP version set to skb:%p\n", dev, skb);
+ dev_kfree_skb_any(skb);
+ break;
+ }
+}
+
+/*
* nss_connmgr_gre_rx_pkt()
* GRE Tap function to receive packet from NSS.
*/
@@ -817,7 +845,7 @@
struct nss_gre_config_msg *cmsg = &req.msg.cmsg;
int if_number;
uint32_t features = 0;
- struct nss_ctx_instance *nss_ctx;
+ struct nss_ctx_instance *nss_ctx = NULL;
nss_tx_status_t status;
struct net_device *next_dev = NULL;
@@ -851,11 +879,25 @@
/*
* Register gre tunnel with NSS
*/
- nss_ctx = nss_gre_register_if(if_number,
- nss_connmgr_gre_exception,
- nss_connmgr_gre_event_receive,
- dev,
- features);
+ if ((dev->type == ARPHRD_IPGRE) || (dev->type == ARPHRD_IP6GRE)) {
+ /*
+ * GRE Tunnel mode
+ */
+ nss_ctx = nss_gre_register_if(if_number,
+ nss_connmgr_gre_tun_exception,
+ nss_connmgr_gre_event_receive,
+ dev,
+ features);
+ } else {
+ /*
+ * GRE Tap mode
+ */
+ nss_ctx = nss_gre_register_if(if_number,
+ nss_connmgr_gre_tap_exception,
+ nss_connmgr_gre_event_receive,
+ dev,
+ features);
+ }
if (!nss_ctx) {
status = nss_dynamic_interface_dealloc_node(if_number, NSS_DYNAMIC_INTERFACE_TYPE_GRE);
diff --git a/gre/nss_connmgr_gre.h b/gre/nss_connmgr_gre.h
index 011518d..1de1b38 100644
--- a/gre/nss_connmgr_gre.h
+++ b/gre/nss_connmgr_gre.h
@@ -1,6 +1,6 @@
/*
**************************************************************************
- * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018 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.
@@ -85,7 +85,10 @@
int nss_connmgr_gre_v4_get_config(struct net_device *dev, struct nss_gre_msg *req, struct net_device **next_dev, bool hold);
int nss_connmgr_gre_v6_get_config(struct net_device *dev, struct nss_gre_msg *req, struct net_device **next_dev, bool hold);
-void nss_connmgr_gre_v4_exception(struct net_device *dev, struct sk_buff *skb);
-void nss_connmgr_gre_v6_exception(struct net_device *dev, struct sk_buff *skb);
+void nss_connmgr_gre_tap_v4_exception(struct net_device *dev, struct sk_buff *skb);
+void nss_connmgr_gre_tap_v6_exception(struct net_device *dev, struct sk_buff *skb);
+
+void nss_connmgr_gre_tun_v4_exception(struct net_device *dev, struct sk_buff *skb);
+void nss_connmgr_gre_tun_v6_exception(struct net_device *dev, struct sk_buff *skb);
#endif
diff --git a/gre/nss_connmgr_gre_v4.c b/gre/nss_connmgr_gre_v4.c
index 111720f..f830773 100644
--- a/gre/nss_connmgr_gre_v4.c
+++ b/gre/nss_connmgr_gre_v4.c
@@ -1,6 +1,6 @@
/*
**************************************************************************
- * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018 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.
@@ -220,9 +220,10 @@
}
/*
- * nss_connmgr_gre_v4_exception()
+ * nss_connmgr_gre_tap_v4_exception()
+ * Handle IPv4 exception for GRETAP
*/
-void nss_connmgr_gre_v4_exception(struct net_device *dev, struct sk_buff *skb)
+void nss_connmgr_gre_tap_v4_exception(struct net_device *dev, struct sk_buff *skb)
{
struct ethhdr *eth_hdr = (struct ethhdr *)skb->data;
struct iphdr *iph = (struct iphdr *)(eth_hdr + 1);
@@ -247,6 +248,10 @@
dev_kfree_skb_any(skb);
return;
}
+
+ /*
+ * TODO: Support parsing GRE options
+ */
skb_pull(skb, (sizeof(struct ethhdr) + sizeof(struct iphdr)
+ sizeof(struct gre_base_hdr)));
@@ -269,6 +274,67 @@
}
/*
+ * nss_connmgr_gre_tun_v4_exception()
+ * Handle IPv4 exception for GRETUN
+ */
+void nss_connmgr_gre_tun_v4_exception(struct net_device *dev, struct sk_buff *skb)
+{
+ struct iphdr *iph_outer = (struct iphdr *)skb->data;
+ struct iphdr *iph_inner;
+
+ if (iph_outer->protocol != IPPROTO_GRE) {
+ /*
+ * These are decapped IP packets.
+ */
+ if (iph_outer->version == 4) {
+ skb->protocol = htons(ETH_P_IP);
+ } else if (iph_outer->version == 6){
+ skb->protocol = htons(ETH_P_IPV6);
+ } else {
+ nss_connmgr_gre_info("%p: wrong IP version in GRE decapped packet. skb: :%p\n", dev, skb);
+ dev_kfree_skb_any(skb);
+ return;
+ }
+ skb->pkt_type = PACKET_HOST;
+ skb->dev = dev;
+
+ netif_receive_skb(skb);
+ return;
+ }
+
+ /*
+ * GRE encapsulated packet exceptioned, remove the encapsulation
+ * and transmit on GRE interface.
+ */
+ if (unlikely(!pskb_may_pull(skb, sizeof(struct iphdr) + sizeof(struct gre_base_hdr)))) {
+ nss_connmgr_gre_warning("%p: pskb_may_pull failed for skb:%p\n", dev, skb);
+ dev_kfree_skb_any(skb);
+ return;
+ }
+
+ /*
+ * TODO: Support parsing GRE options
+ */
+ skb_pull(skb, sizeof(struct iphdr) + sizeof(struct gre_base_hdr));
+ iph_inner = (struct iphdr *)skb->data;
+ skb->dev = dev;
+ if (iph_inner->version == 4) {
+ skb->protocol = htons(ETH_P_IP);
+ } else if (iph_inner->version == 6){
+ skb->protocol = htons(ETH_P_IPV6);
+ } else {
+ nss_connmgr_gre_info("%p: wrong IP version in GRE encapped packet. skb: %p\n", dev, skb);
+ dev_kfree_skb_any(skb);
+ return;
+ }
+ skb_reset_mac_header(skb);
+ skb_reset_network_header(skb);
+ skb_reset_transport_header(skb);
+ skb_reset_mac_len(skb);
+ dev_queue_xmit(skb);
+}
+
+/*
* nss_connmgr_gre_v4_get_config()
* Fill in config message to send to NSS.
*/
diff --git a/gre/nss_connmgr_gre_v6.c b/gre/nss_connmgr_gre_v6.c
index f3c3ef8..bb41fb3 100644
--- a/gre/nss_connmgr_gre_v6.c
+++ b/gre/nss_connmgr_gre_v6.c
@@ -1,6 +1,6 @@
/*
**************************************************************************
- * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018 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.
@@ -122,9 +122,10 @@
}
/*
- * nss_connmgr_gre_v6_exception()
+ * nss_connmgr_gre_tap_v6_exception()
+ * Handle IPv6 exception for GRETAP
*/
-void nss_connmgr_gre_v6_exception(struct net_device *dev, struct sk_buff *skb)
+void nss_connmgr_gre_tap_v6_exception(struct net_device *dev, struct sk_buff *skb)
{
struct ethhdr *eth = (struct ethhdr *)skb->data;
struct ipv6hdr *ip6h = (struct ipv6hdr *)(eth + 1);
@@ -149,6 +150,10 @@
dev_kfree_skb_any(skb);
return;
}
+
+ /*
+ * TODO: Support parsing GRE options
+ */
skb_pull(skb, (sizeof(struct ethhdr) + sizeof(struct ipv6hdr)
+ sizeof(struct gre_base_hdr)));
@@ -171,6 +176,68 @@
}
/*
+ * nss_connmgr_gre_tun_v6_exception()
+ * Handle IPv6 exception for GRETUN
+ */
+void nss_connmgr_gre_tun_v6_exception(struct net_device *dev, struct sk_buff *skb)
+{
+ struct ipv6hdr *ip6h_outer = (struct ipv6hdr *)skb->data;
+ struct ipv6hdr *ip6h_inner;
+
+ if (ip6h_outer->nexthdr != IPPROTO_GRE) {
+ /*
+ * These are decapped IP packets.
+ */
+ if (ip6h_outer->version == 4) {
+ skb->protocol = htons(ETH_P_IP);
+ } else if (ip6h_outer->version == 6){
+ skb->protocol = htons(ETH_P_IPV6);
+ } else {
+ nss_connmgr_gre_info("%p: wrong IP version in GRE decapped packet. skb: %p\n", dev, skb);
+ dev_kfree_skb_any(skb);
+ return;
+ }
+ skb->pkt_type = PACKET_HOST;
+ skb->dev = dev;
+
+ netif_receive_skb(skb);
+ return;
+ }
+
+ /*
+ * GRE encapsulated packet exceptioned, remove the encapsulation
+ * and transmit on GRE interface.
+ */
+ if (unlikely(!pskb_may_pull(skb, sizeof(struct ipv6hdr) + sizeof(struct gre_base_hdr)))) {
+ nss_connmgr_gre_warning("%p: pskb_may_pull failed for skb:%p\n", dev, skb);
+ dev_kfree_skb_any(skb);
+ return;
+ }
+
+ /*
+ * TODO: Support parsing GRE options
+ */
+ skb_pull(skb, sizeof(struct ipv6hdr) + sizeof(struct gre_base_hdr));
+
+ ip6h_inner = (struct ipv6hdr *)skb->data;
+ skb->dev = dev;
+ if (ip6h_inner->version == 4) {
+ skb->protocol = htons(ETH_P_IP);
+ } else if (ip6h_inner->version == 6){
+ skb->protocol = htons(ETH_P_IPV6);
+ } else {
+ nss_connmgr_gre_info("%p: wrong IP version in GRE encapped packet. skb: %p\n", dev, skb);
+ dev_kfree_skb_any(skb);
+ return;
+ }
+ skb_reset_mac_header(skb);
+ skb_reset_network_header(skb);
+ skb_reset_transport_header(skb);
+ skb_reset_mac_len(skb);
+ dev_queue_xmit(skb);
+}
+
+/*
* nss_connmgr_gre_v6_set_config()
* Set user config to dev inerface.
*/