[qca-nss-clients] Fixes for netlink user

1. IPv4 fixes for inner/outer
2. IPv6 fixes for inner/outer
3. IPsec inner/outer changes

Change-Id: I9d86ff242b3c9d25e442a5c377449d56d03a7cd6
Signed-off-by: Ratheesh Kannoth <rkannoth@codeaurora.org>
Signed-off-by: pavir <pavir@codeaurora.org>
diff --git a/netlink/include/nss_nl_if.h b/netlink/include/nss_nl_if.h
index 6edac57..784bb44 100644
--- a/netlink/include/nss_nl_if.h
+++ b/netlink/include/nss_nl_if.h
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2016, 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.
@@ -27,6 +27,20 @@
 
 #define NSS_NL_VER ((NSS_NL_VER_MAJOR << NSS_NL_VER_SHIFT) | NSS_NL_VER_MINOR)
 
+/**
+ * @brief interface types
+ */
+enum nss_nl_iftype {
+	NSS_NL_IFTYPE_PHYSICAL = 0,
+	NSS_NL_IFTYPE_VLAN,
+	NSS_NL_IFTYPE_PPPOE,
+	NSS_NL_IFTYPE_TUNNEL_IPSEC,
+	NSS_NL_IFTYPE_TUNNEL_GRE,
+	NSS_NL_IFTYPE_TUNNEL_PPTP,
+	NSS_NL_IFTYPE_TUNNEL_TUN6RD,
+	NSS_NL_IFTYPE_MAX
+};
+
 #endif /* __NSS_NL_IF_H */
 
 
diff --git a/netlink/include/nss_nlipsec_if.h b/netlink/include/nss_nlipsec_if.h
index 9bd3a8a..0095334 100644
--- a/netlink/include/nss_nlipsec_if.h
+++ b/netlink/include/nss_nlipsec_if.h
@@ -24,38 +24,62 @@
 
 /*
  * @file nss_nlipsec_if.h
- *	NSS Netlink IPsec headers */
+ *	NSS Netlink IPsec headers
+ */
 
 #define NSS_NLIPSEC_FAMILY "nss_nlipsec"	/**< IPsec family */
 #define NSS_NLIPSEC_MAX_TUNNELS 16		/**< Max tunnels */
 #define NSS_NLIPSEC_MCAST_GRP "nss_nlipsec_mc"
+#define NSS_NLIPSEC_CIPHER_KEY_MAX 32
+#define NSS_NLIPSEC_AUTH_KEY_MAX 64
+#define NSS_NLIPSEC_NONCE_SIZE_MAX 4
+
 /**
  * @brief ipsec commands types
  */
 enum nss_nlipsec_cmd {
-	NSS_NLIPSEC_CMD_UNSPEC,			/**< Unspecified cmd. */
-	NSS_NLIPSEC_CMD_CREATE_TUNNEL,		/**< Create tunnel. */
-	NSS_NLIPSEC_CMD_DESTROY_TUNNEL,		/**< Destroy tunnel. */
-	NSS_NLIPSEC_CMD_ADD_SA,			/**< Add Security AssociationA. */
-	NSS_NLIPSEC_CMD_DEL_SA,			/**< Delete Security Association. */
-	NSS_NLIPSEC_CMD_ADD_FLOW,		/**< Add flow. */
-	NSS_NLIPSEC_CMD_DEL_FLOW,		/**< Delete flow. */
+	NSS_NLIPSEC_CMD_UNSPEC,				/**< Unspecified cmd. */
+	NSS_NLIPSEC_CMD_ADD_TUNNEL,			/**< Create tunnel. */
+	NSS_NLIPSEC_CMD_DEL_TUNNEL,			/**< Destroy tunnel. */
+	NSS_NLIPSEC_CMD_ADD_SA,				/**< Add Security AssociationA. */
+	NSS_NLIPSEC_CMD_DEL_SA,				/**< Delete Security Association. */
+	NSS_NLIPSEC_CMD_ADD_FLOW,			/**< Add flow. */
+	NSS_NLIPSEC_CMD_DEL_FLOW,			/**< Delete flow. */
 	NSS_NLIPSEC_CMD_MAX
 };
 
 /**
+ * @brief IPsec SA message
+ */
+struct nss_nlipsec_rule_sa {
+	struct nss_ipsecmgr_sa_tuple tuple;		/**< Security Association tuple. */
+	struct nss_ipsecmgr_sa_data data;		/**< Security Association data. */
+	uint8_t cipher_key[NSS_NLIPSEC_CIPHER_KEY_MAX];	/**< Cipher key. */
+	uint8_t auth_key[NSS_NLIPSEC_AUTH_KEY_MAX];	/**< Authentication key. */
+	uint8_t nonce[NSS_NLIPSEC_NONCE_SIZE_MAX];	/**< Nonce. */
+
+};
+
+/**
+ * @brief IPsec flow message
+ */
+struct nss_nlipsec_rule_flow {
+	struct nss_ipsecmgr_flow_tuple tuple;		/**< Flow tuple. */
+	struct nss_ipsecmgr_sa_tuple sa;		/**< Flow data. */
+};
+
+/**
  * @brief IPsec message
  */
 struct nss_nlipsec_rule {
-	struct nss_nlcmn cm;			/**< Common message header. */
-	uint8_t ifname[IFNAMSIZ];		/**< IPSec interface name. */
-	struct nss_ipsecmgr_flow_outer outer;	/**< Outer flow data. */
+	struct nss_nlcmn cm;				/**< Common message header. */
+	char ifname[IFNAMSIZ];				/**< IPSec interface name. */
 
 	union {
-		struct nss_ipsecmgr_sa sa;		/**< Security Association data. */
-		struct nss_ipsecmgr_flow_inner flow;	/**< Inner flow.  */
+		struct nss_nlipsec_rule_flow flow;	/**< Flow rule. */
+		struct nss_nlipsec_rule_sa sa;		/**< SA rule. */
 		struct nss_ipsecmgr_event event;	/**< IPsec event. */
-	} data;
+	} rule;
 };
 
 /**
@@ -70,5 +94,4 @@
 	nss_nlcmn_init_cmd(&rule->cm, sizeof(struct nss_nlipsec_rule), type);
 }
 
-/**@}*/
 #endif /* __NSS_NLIPSEC_IF_H */
diff --git a/netlink/include/nss_nlipv4_if.h b/netlink/include/nss_nlipv4_if.h
index b2d820f..0cbd706 100644
--- a/netlink/include/nss_nlipv4_if.h
+++ b/netlink/include/nss_nlipv4_if.h
@@ -29,20 +29,22 @@
 
 #define NSS_NLIPV4_ARPHRD_IPSEC_TUNNEL_TYPE 0x31
 #define NSS_NLIPV4_VLAN_ID_NOT_CONFIGURED 0xFFF
+#define NSS_NLIPV4_MIN_MTU 576
+#define NSS_NLIPV4_MAX_MTU 65535
 
 /**
  * @brief IPv4 rule
  */
 struct nss_nlipv4_rule {
-	struct nss_nlcmn cm;		/**< common message header */
+	struct nss_nlcmn cm;			/**< common message header */
 
-	char flow_ifname[IFNAMSIZ];	/**< ingress interface name */
-	char return_ifname[IFNAMSIZ];	/**< egress interface name */
+	char flow_ifname[IFNAMSIZ];		/**< ingress interface name */
+	char return_ifname[IFNAMSIZ];		/**< egress interface name */
 
-	uint16_t flow_iftype;            /**< ingress interface type */
-	uint16_t return_iftype;            /**< egress interface type */
+	enum nss_nl_iftype flow_iftype;		/**< ingress interface type */
+	enum nss_nl_iftype return_iftype;	/**< egress interface type */
 
-	struct nss_ipv4_msg nim;	/**< rule message */
+	struct nss_ipv4_msg nim;		/**< rule message */
 };
 
 /**
diff --git a/netlink/include/nss_nlipv6_if.h b/netlink/include/nss_nlipv6_if.h
index f036d9f..bdf9216 100644
--- a/netlink/include/nss_nlipv6_if.h
+++ b/netlink/include/nss_nlipv6_if.h
@@ -28,6 +28,8 @@
 #define NSS_NLIPV6_MCAST_GRP "nss_nlipv6_mc"
 #define NSS_NLIPV6_ARPHRD_IPSEC_TUNNEL_TYPE 0x31
 #define NSS_NLIPV6_VLAN_ID_NOT_CONFIGURED 0xFFF
+#define NSS_NLIPV6_MIN_MTU 1280
+#define NSS_NLIPV6_MAX_MTU 65535
 
 #define NSS_NLIPV6_ADDR_BITS (sizeof(uint32_t) * 4 * BITS_PER_BYTE)	/* 128 bits */
 #define NSS_NLIPV6_SUBNET_BITS (sizeof(uint32_t) * 4 * BITS_PER_BYTE)	/* 128 bits */
@@ -36,15 +38,15 @@
  * @brief IPv6 rule
  */
 struct nss_nlipv6_rule {
-	struct nss_nlcmn cm;		/**< common message header */
+	struct nss_nlcmn cm;			/**< common message header */
 
-	char flow_ifname[IFNAMSIZ];	/**< ingress interface name */
-	char return_ifname[IFNAMSIZ];	/**< egress interface name */
+	char flow_ifname[IFNAMSIZ];		/**< ingress interface name */
+	char return_ifname[IFNAMSIZ];		/**< egress interface name */
 
-	uint16_t flow_iftype;            /**< ingress interface type */
-	uint16_t return_iftype;            /**< egress interface type */
+	enum nss_nl_iftype flow_iftype;		/**< ingress interface type */
+	enum nss_nl_iftype return_iftype;	/**< egress interface type */
 
-	struct nss_ipv6_msg nim;	/**< rule message */
+	struct nss_ipv6_msg nim;		/**< rule message */
 };
 
 /**
@@ -79,4 +81,5 @@
 	dst[3] = src[0];
 
 }
+
 #endif /* __NSS_NLIPV6_IF_H */
diff --git a/netlink/nss_nlipsec.c b/netlink/nss_nlipsec.c
index 93b2436..0c66fa9 100644
--- a/netlink/nss_nlipsec.c
+++ b/netlink/nss_nlipsec.c
@@ -35,11 +35,13 @@
 #include <nss_ipsec.h>
 #include <nss_ipsecmgr.h>
 #include <nss_nl_if.h>
+#include <nss_ipsec_cmn.h>
 #include "nss_crypto_defines.h"
 #include "nss_nl.h"
 #include "nss_nlcmn_if.h"
 #include "nss_nlipsec_if.h"
 #include "nss_nlipv6_if.h"
+#include "nss_nlipv4_if.h"
 
 /*
  * Hold netdevice references
@@ -55,6 +57,7 @@
  */
 struct nss_nlipsec_ctx {
 	atomic_t tunnels;	/* Number tunnels allocated */
+
 	/*
 	 * This table stores device reference associated
 	 * to the IPsec tunnel that it has created through NETLINK
@@ -182,17 +185,101 @@
 	/*
 	 * Copy the contents of the sync message into the NETLINK message
 	 */
-	memcpy(&nl_rule->data.event, ev, sizeof(struct nss_ipsecmgr_event));
+	memcpy(&nl_rule->rule.event, ev, sizeof(struct nss_ipsecmgr_event));
 
 	nss_nl_mcast_event(&nss_nlipsec_family, skb);
 }
 
 /*
+ * nss_nlipsec_get_ifnum()
+ *	Extract dynamic interface number for inner/outer
+ */
+int nss_nlipsec_get_ifnum(struct net_device *dev, uint8_t proto, uint16_t dest_port, uint16_t src_port)
+{
+	enum nss_dynamic_interface_type type;
+	int ifnum;
+
+	/*
+	 * If the flow is outer, then set the IPsec outer interface type else
+	 * set the inner interface type to obtain interface number.
+	 */
+	switch (proto) {
+	case IPPROTO_ESP:
+		type = NSS_DYNAMIC_INTERFACE_TYPE_IPSEC_CMN_OUTER;
+		break;
+
+	case IPPROTO_UDP:
+		if (dest_port == NSS_IPSECMGR_NATT_PORT_DATA)
+			type = NSS_DYNAMIC_INTERFACE_TYPE_IPSEC_CMN_OUTER;
+		else if (src_port == NSS_IPSECMGR_NATT_PORT_DATA)
+			type = NSS_DYNAMIC_INTERFACE_TYPE_IPSEC_CMN_OUTER;
+		else
+			type = NSS_DYNAMIC_INTERFACE_TYPE_IPSEC_CMN_INNER;
+
+		break;
+
+	default:
+		type = NSS_DYNAMIC_INTERFACE_TYPE_IPSEC_CMN_INNER;
+		break;
+	}
+
+	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;
+	}
+
+	/*
+	 * Interface number with core-id
+	 */
+	return nss_ipsec_cmn_get_ifnum_with_coreid(ifnum);
+
+}
+
+/*
+ * nss_nlipsec_get_mtu()
+ * 	Provide maximum mtu if it is an outer flow and maintain minimum mtu
+ */
+int nss_nlipsec_get_mtu(struct net_device *dev, uint8_t ip_ver, uint8_t proto, uint16_t dest_port, uint16_t src_port)
+{
+	int mtu = dev->mtu;
+
+	/*
+	 * If, flow device is IPsec tunnel and protocol is ESP or NAT-T (UDP@4500)
+	 * then the operation is Decapsulation. In this we would like to keep the MTU
+	 * at the maximum(65536). This would avoid fragmenting the  packet in NSS before
+	 * delivering it for IPsec decap. Also, if the device mtu is less than the minimum
+	 * mtu, we set it to the minimum mtu.
+	 */
+	switch (ip_ver) {
+	case 4:
+		if (proto == IPPROTO_ESP)
+			mtu = NSS_NLIPV4_MAX_MTU;
+		else if ((proto == IPPROTO_UDP) && (dest_port == NSS_IPSECMGR_NATT_PORT_DATA))
+			mtu = NSS_NLIPV4_MAX_MTU;
+		else if ((proto == IPPROTO_UDP) && (src_port == NSS_IPSECMGR_NATT_PORT_DATA))
+			mtu = NSS_NLIPV4_MAX_MTU;
+		else if (dev->mtu < NSS_NLIPV4_MIN_MTU)
+			mtu = NSS_NLIPV4_MIN_MTU;
+
+		break;
+	case 6:
+		if (proto == IPPROTO_ESP)
+			mtu = NSS_NLIPV6_MAX_MTU;
+		else if (dev->mtu < NSS_NLIPV6_MIN_MTU)
+			mtu = NSS_NLIPV6_MIN_MTU;
+
+		break;
+	}
+
+	return mtu;
+}
+
+/*
  * nss_nlipsec_op_create_tunnel()
  *	Add IPsec tunnel
  */
-static int nss_nlipsec_op_create_tunnel(struct sk_buff *skb,
-					struct genl_info *info)
+static int nss_nlipsec_op_create_tunnel(struct sk_buff *skb, struct genl_info *info)
 {
 	struct nss_nlipsec_rule *nl_rule;
 	struct nss_ipsecmgr_callback cb;
@@ -204,8 +291,7 @@
 	/*
 	 * Extract the message payload
 	 */
-	nl_cm = nss_nl_get_msg(&nss_nlipsec_family, info,
-			       NSS_NLIPSEC_CMD_CREATE_TUNNEL);
+	nl_cm = nss_nl_get_msg(&nss_nlipsec_family, info, NSS_NLIPSEC_CMD_ADD_TUNNEL);
 	if (!nl_cm) {
 		nss_nl_error("unable to extract create tunnel data\n");
 		return -EINVAL;
@@ -214,8 +300,7 @@
 	pid = nl_cm->pid;
 
 	if (atomic_read(&gbl_ctx.tunnels) == NSS_NLIPSEC_MAX_TUNNELS) {
-		nss_nl_error("%d: max allowed tunnel reached (%d)\n", pid,
-			     NSS_NLIPSEC_MAX_TUNNELS);
+		nss_nl_error("%d: max allowed tunnel reached (%d)\n", pid, NSS_NLIPSEC_MAX_TUNNELS);
 		return -EINVAL;
 	}
 
@@ -255,7 +340,7 @@
 	/*
 	 * Init the command
 	 */
-	nss_nlipsec_rule_init(nl_rule, NSS_NLIPSEC_CMD_CREATE_TUNNEL);
+	nss_nlipsec_rule_init(nl_rule, NSS_NLIPSEC_CMD_ADD_TUNNEL);
 
 	/*
 	 * We need to send the  name to the user; copy
@@ -280,8 +365,7 @@
  * nss_nlipsec_op_destroy_tunnel()
  *	Delete an IPsec tunnel
  */
-static int nss_nlipsec_op_destroy_tunnel(struct sk_buff *skb,
-					 struct genl_info *info)
+static int nss_nlipsec_op_destroy_tunnel(struct sk_buff *skb, struct genl_info *info)
 {
 	struct nss_nlipsec_rule *nl_rule;
 	struct nss_nlipsec_ref *ref;
@@ -292,8 +376,7 @@
 	/*
 	 * Extract the message payload
 	 */
-	nl_cm = nss_nl_get_msg(&nss_nlipsec_family, info,
-			       NSS_NLIPSEC_CMD_DESTROY_TUNNEL);
+	nl_cm = nss_nl_get_msg(&nss_nlipsec_family, info, NSS_NLIPSEC_CMD_DEL_TUNNEL);
 	if (!nl_cm) {
 		nss_nl_error("unable to extract destroy tunnel data\n");
 		return -EINVAL;
@@ -314,8 +397,7 @@
 	 */
 	dev = dev_get_by_name(&init_net, nl_rule->ifname);
 	if (!dev) {
-		nss_nl_error("%d: unable to find netdevice (%s)\n", pid,
-			     nl_rule->ifname);
+		nss_nl_error("%d: unable to find netdevice (%s)\n", pid, nl_rule->ifname);
 		return -EINVAL;
 	}
 
@@ -324,8 +406,7 @@
 	 */
 	ref = nss_nlipsec_find_ref(dev);
 	if (!ref) {
-		nss_nl_error("%d: (%s) was not created through NL_IPSEC\n",
-			     pid, dev->name);
+		nss_nl_error("%d: (%s) was not created through NL_IPSEC\n", pid, dev->name);
 		dev_put(dev);
 		return -EINVAL;
 	}
@@ -350,9 +431,8 @@
  * nss_nlipsec_get_rule()
  *	Extract the rule message
  */
-static struct nss_nlipsec_rule *nss_nlipsec_get_rule(struct genl_info *info,
-						     enum nss_nlipsec_cmd cmd,
-						     struct net_device **dev)
+static struct nss_nlipsec_rule *nss_nlipsec_get_rule(struct genl_info *info, enum nss_nlipsec_cmd cmd,
+							struct net_device **dev)
 {
 	struct nss_nlipsec_rule *nl_rule;
 	struct nss_nlipsec_ref *ref;
@@ -374,19 +454,16 @@
 
 	*dev = dev_get_by_name(&init_net, nl_rule->ifname);
 	if (!(*dev)) {
-		nss_nl_error("%d: Unable to find Linux net_device(%s)\n", pid,
-			     nl_rule->ifname);
+		nss_nl_error("%d: Unable to find Linux net_device(%s)\n", pid, nl_rule->ifname);
 		return NULL;
 	}
 
 	ref = nss_nlipsec_find_ref(*dev);
 	if (!ref) {
-		nss_nl_error("%d: (%s) was not created through NL_IPSEC",
-			     pid, (*dev)->name);
+		nss_nl_error("%d: (%s) was not created through NL_IPSEC", pid, (*dev)->name);
 		dev_put(*dev);
 		return NULL;
 	}
-	nss_nlipsec_del_ref(ref);
 	return nl_rule;
 }
 
@@ -396,11 +473,12 @@
  */
 static int nss_nlipsec_op_add_sa(struct sk_buff *skb, struct genl_info *info)
 {
+	struct nss_ipsecmgr_sa_data *sa_data;
+	struct nss_nlipsec_rule_sa *sa_rule;
 	struct nss_nlipsec_rule *nl_rule;
-	struct nss_ipsecmgr_sa *sa;
 	struct net_device *dev;
 	uint32_t pid, if_num;
-	int error;
+	int error = 0;
 
 	nl_rule = nss_nlipsec_get_rule(info, NSS_NLIPSEC_CMD_ADD_SA, &dev);
 	if (!nl_rule) {
@@ -412,22 +490,26 @@
 	nss_nl_error("%d: device(%s)", pid, dev->name);
 
 	/*
-	 * Get the SA data from the message
+	 * Get the SA rule and data from the message
 	 */
-	sa = &nl_rule->data.sa;
+	sa_rule = &nl_rule->rule.sa;
+	sa_data = &nl_rule->rule.sa.data;
 
-	/* TODO: need to add verify the SA */
+	/*
+	 * Switch to kernel pointers
+	 */
+	sa_data->cmn.keys.cipher_key = sa_rule->cipher_key;
+	sa_data->cmn.keys.auth_key = sa_rule->auth_key;
+	sa_data->cmn.keys.nonce = sa_rule->nonce;
 
-	if (nss_ipsecmgr_sa_add(dev, &nl_rule->outer, sa, &if_num)) {
-		nss_nl_error("%d: Failed to add SA for net device(%s)\n",
-			     pid, nl_rule->ifname);
+	if (nss_ipsecmgr_sa_add(dev, &sa_rule->tuple, sa_data, &if_num)) {
+		nss_nl_error("%d: Failed to add SA for net device(%s)\n", pid, nl_rule->ifname);
 		error = -EINVAL;
-		goto done;
 	}
 
-	return 0;
-
-done:
+	/*
+	 *  dev_put for dev_get done on nss_nlipsec_get_rule
+	 */
 	dev_put(dev);
 	return error;
 }
@@ -439,10 +521,8 @@
 static int nss_nlipsec_op_delete_sa(struct sk_buff *skb, struct genl_info *info)
 {
 	struct nss_nlipsec_rule *nl_rule;
-	struct nss_ipsecmgr_sa *sa;
 	struct net_device *dev;
 	uint32_t pid;
-	int err = 0;
 
 	nl_rule = nss_nlipsec_get_rule(info, NSS_NLIPSEC_CMD_DEL_SA, &dev);
 	if (!nl_rule) {
@@ -453,14 +533,13 @@
 	pid = nl_rule->cm.pid;
 	nss_nl_error("%d: device(%s)", pid, dev->name);
 
-	sa = &nl_rule->data.sa;
+	nss_ipsecmgr_sa_del(dev, &nl_rule->rule.sa.tuple);
 
-	/* TODO: need to verify before destroying */
-
-	nss_ipsecmgr_sa_del(dev, &nl_rule->outer);
-
+	/*
+	 *  dev_put for dev_get done on nss_nlipsec_get_rule
+	 */
 	dev_put(dev);
-	return err;
+	return 0;
 }
 
 /*
@@ -469,8 +548,8 @@
  */
 static int nss_nlipsec_op_add_flow(struct sk_buff *skb, struct genl_info *info)
 {
-	struct nss_ipsecmgr_flow_inner *inner;
-	struct nss_ipsecmgr_flow_outer *outer;
+	struct nss_ipsecmgr_flow_tuple *flow_tuple;
+	struct nss_ipsecmgr_sa_tuple *sa_tuple;
 	struct nss_nlipsec_rule *nl_rule;
 	struct net_device *dev;
 	uint32_t pid;
@@ -485,17 +564,17 @@
 	pid = nl_rule->cm.pid;
 	nss_nl_error("%d: device(%s)", pid, dev->name);
 
-	/* TODO: verify the flow parameters */
+	flow_tuple = &nl_rule->rule.flow.tuple;
+	sa_tuple = &nl_rule->rule.flow.sa;
 
-	inner = &nl_rule->data.flow;
-	outer = &nl_rule->outer;
-
-	if (nss_ipsecmgr_flow_add(dev, inner, outer)) {
-		nss_nl_error("%d: Failed to add subnet for net_device(%s)",
-			     pid, nl_rule->ifname);
+	if (nss_ipsecmgr_flow_add(dev, flow_tuple, sa_tuple)) {
+		nss_nl_error("%d: Failed to add subnet for net_device(%s)", pid, nl_rule->ifname);
 		error = -EINVAL;
 	}
 
+	/*
+	 *  dev_put for dev_get done on nss_nlipsec_get_rule
+	 */
 	dev_put(dev);
 	return error;
 }
@@ -504,11 +583,10 @@
  * nss_nlipsec_op_delete_flow()
  *	Delete a flow
  */
-static int nss_nlipsec_op_delete_flow(struct sk_buff *skb,
-				      struct genl_info *info)
+static int nss_nlipsec_op_delete_flow(struct sk_buff *skb, struct genl_info *info)
 {
-	struct nss_ipsecmgr_flow_inner *inner;
-	struct nss_ipsecmgr_flow_outer *outer;
+	struct nss_ipsecmgr_flow_tuple *flow_tuple;
+	struct nss_ipsecmgr_sa_tuple *sa_tuple;
 	struct nss_nlipsec_rule *nl_rule;
 	struct net_device *dev;
 	uint32_t pid;
@@ -523,13 +601,14 @@
 	pid = nl_rule->cm.pid;
 	nss_nl_error("%d: device(%s)", pid, dev->name);
 
-	/* TODO: verify the flow parameters */
+	flow_tuple = &nl_rule->rule.flow.tuple;
+	sa_tuple = &nl_rule->rule.flow.sa;
 
-	inner = &nl_rule->data.flow;
-	outer = &nl_rule->outer;
+	nss_ipsecmgr_flow_del(dev, flow_tuple, sa_tuple);
 
-	nss_ipsecmgr_flow_del(dev, inner, outer);
-
+	/*
+	 *  dev_put for dev_get done on nss_nlipsec_get_rule
+	 */
 	dev_put(dev);
 	return error;
 }
@@ -539,11 +618,11 @@
  */
 static struct genl_ops nss_nlipsec_ops[] = {
 	{ /* Create tunnel */
-		.cmd = NSS_NLIPSEC_CMD_CREATE_TUNNEL,
+		.cmd = NSS_NLIPSEC_CMD_ADD_TUNNEL,
 		.doit = nss_nlipsec_op_create_tunnel,
 	},
 	{ /* Destroy tunnel */
-		.cmd = NSS_NLIPSEC_CMD_DESTROY_TUNNEL,
+		.cmd = NSS_NLIPSEC_CMD_DEL_TUNNEL,
 		.doit = nss_nlipsec_op_destroy_tunnel,
 	},
 	{ /* Add Security Association */
@@ -588,9 +667,7 @@
 	/*
 	 * Register with the family
 	 */
-	error = genl_register_family_with_ops_groups(&nss_nlipsec_family,
-						     nss_nlipsec_ops,
-						     nss_nlipsec_mcgrp);
+	error = genl_register_family_with_ops_groups(&nss_nlipsec_family, nss_nlipsec_ops, nss_nlipsec_mcgrp);
 	if (error != 0) {
 		nss_nl_info_always("Error: unable to register IPsec family\n");
 		return false;
diff --git a/netlink/nss_nlipsec.h b/netlink/nss_nlipsec.h
index bfdafd2..3333865 100644
--- a/netlink/nss_nlipsec.h
+++ b/netlink/nss_nlipsec.h
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2014 - 2015, The Linux Foundation. All rights reserved.
+ * 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.
@@ -33,4 +33,23 @@
 #define NSS_NLIPSEC_EXIT 0
 #endif /* !CONFIG_NSS_NLIPSEC */
 
+/*
+ * @brief get dynamic interface number for inner/outer
+ * @param dev[IN] net device structure
+ * @param ip_ver[IN] IP version 4/6
+ * @param proto[IN] protocol number
+ * @param dest_port[IN] destination port
+ */
+int nss_nlipsec_get_ifnum(struct net_device *dev, uint8_t proto, uint16_t dest_port, uint16_t src_port);
+
+/*
+ * nss_nlipsec_get_mtu()
+ * @brief get mtu for IPsec tunnel
+ * @param dev[IN] net device structure
+ * @param ip_ver[IN] IP version 4/6
+ * @param proto[IN] protocol number
+ * @param dest_port[IN] destination port
+ */
+int nss_nlipsec_get_mtu(struct net_device *dev, uint8_t ip_ver, uint8_t proto, uint16_t dest_port, uint16_t src_port);
+
 #endif /* __NSS_NLIPSEC_H */
diff --git a/netlink/nss_nlipv4.c b/netlink/nss_nlipv4.c
index 0cd58e1..ba6a9de 100644
--- a/netlink/nss_nlipv4.c
+++ b/netlink/nss_nlipv4.c
@@ -50,8 +50,11 @@
 #include "nss_nl.h"
 #include "nss_nlcmn_if.h"
 #include "nss_nlipv4_if.h"
+#include "nss_nlipsec.h"
 #include "nss_ipsec.h"
+#include "nss_ipsec_cmn.h"
 #include "nss_ipsecmgr.h"
+#include "nss_nlipsec_if.h"
 
 /*
  * NSS NETLINK IPv4 context
@@ -233,14 +236,22 @@
 		return -EINVAL;
 	}
 
-	/* Validate the port number */
+	/*
+	 * Validate the port number
+	 */
 	switch (tuple->protocol) {
 	case IPPROTO_UDP:
 	case IPPROTO_TCP:
 	case IPPROTO_SCTP:
 		ident_check = true;
 		break;
+
 	default:
+		if (tuple->flow_ident || tuple->return_ident) {
+			nss_nl_error("Flow ident and return ident must be zero. Flow ident:%d return ident:%d protocol:%d\n",
+					tuple->flow_ident, tuple->return_ident, tuple->protocol);
+			return -EINVAL;
+		}
 		ident_check = false;
 		break;
 	}
@@ -258,111 +269,154 @@
  * 	verify and override connection rule entries
  */
 static int nss_nlipv4_verify_conn_rule(struct nss_ipv4_rule_create_msg *msg, struct net_device *flow_dev,
-					struct net_device *return_dev, uint16_t flow_dev_type, uint16_t return_dev_type)
+					struct net_device *return_dev, enum nss_nl_iftype flow_iftype,
+					enum nss_nl_iftype return_iftype)
 {
 	struct nss_ipv4_connection_rule *conn = &msg->conn_rule;
 	struct nss_ipv4_nexthop *nexthop = &msg->nexthop_rule;
+        struct nss_ipv4_5tuple *tuple = &msg->tuple;
 	const size_t rule_sz = sizeof(struct nss_ipv4_connection_rule);
-	bool override_mtu;
 	bool valid;
 
-	valid = msg->valid_flags & NSS_IPV4_RULE_CREATE_CONN_VALID;
-
 	/*
-	 * connection rule is not valid ignore rest of the checks
+	 * Connection rule is not valid ignore rest of the checks
 	 */
-	if (!valid){
+	valid = msg->valid_flags & NSS_IPV4_RULE_CREATE_CONN_VALID;
+	if (!valid) {
 		memset(conn, 0, rule_sz);
 		return -EINVAL;
 	}
 
+	if ((flow_iftype >= NSS_NL_IFTYPE_MAX) || (return_iftype >= NSS_NL_IFTYPE_MAX)) {
+		nss_nl_error("%p: Invalid interface type (flow:%d, return:%d)\n", msg, flow_iftype, return_iftype);
+		return -EINVAL;
+	}
+
 	/*
-	 * update the flow  & return MAC address
+	 * Update the flow  & return MAC address
 	 */
-	if (nss_nlipv4_get_macaddr(msg->tuple.flow_ip, (uint8_t *)conn->flow_mac)) {
+	if (nss_nlipv4_get_macaddr(tuple->flow_ip, (uint8_t *)conn->flow_mac)) {
 		nss_nl_info("Error in Updating the Flow MAC Address \n");
 		return -EINVAL;
 	}
 
-	if (nss_nlipv4_get_macaddr(msg->tuple.return_ip, (uint8_t *)conn->return_mac)) {
+	if (nss_nlipv4_get_macaddr(tuple->return_ip, (uint8_t *)conn->return_mac)) {
 		nss_nl_info("Error in Updating the Return MAC Address \n");
 		return -EINVAL;
 	}
 
 	/*
-	 * update flow and return interface numbers. Handle Ipsec interfaces seperately.
+	 * Update flow interface number and flow mtu
 	 */
-	if (flow_dev->type == NSS_IPSEC_ARPHRD_IPSEC)
-		conn->flow_interface_num = nss_ipsec_get_ifnum(nss_ipsec_get_data_interface());
-	else if (is_vlan_dev(flow_dev))
-		conn->flow_interface_num = nss_cmn_get_interface_number_by_dev(vlan_dev_real_dev(flow_dev));
-	else {
-		if (!flow_dev_type)
-			conn->flow_interface_num = nss_cmn_get_interface_number_by_dev(flow_dev);
-		else {
-			conn->flow_interface_num = nss_cmn_get_interface_number_by_dev_and_type(flow_dev, flow_dev_type);
+	switch (flow_iftype) {
+	case NSS_NL_IFTYPE_TUNNEL_IPSEC:
+		conn->flow_interface_num = nss_nlipsec_get_ifnum(flow_dev, tuple->protocol,
+								tuple->return_ident, tuple->flow_ident);
+		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);
+			return -EINVAL;
 		}
-                        nss_nl_info("flow_interface_num: %d flow_interface_type: %d\n", conn->flow_interface_num, flow_dev_type);
+
+		conn->flow_mtu = nss_nlipsec_get_mtu(flow_dev, 4, tuple->protocol,
+							tuple->return_ident, tuple->flow_ident);
+		break;
+
+	case NSS_NL_IFTYPE_VLAN:
+		conn->flow_interface_num = nss_cmn_get_interface_number_by_dev(vlan_dev_real_dev(flow_dev));
+		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);
+			return -EINVAL;
+		}
+
+		conn->flow_mtu = flow_dev->mtu;
+		break;
+
+	case NSS_NL_IFTYPE_PHYSICAL:
+		conn->flow_interface_num = nss_cmn_get_interface_number_by_dev(flow_dev);
+		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);
+			return -EINVAL;
+		}
+
+		conn->flow_mtu = flow_dev->mtu;
+		break;
+
+	default:
+		nss_nl_error("%p: Unsupported flow interface type (%d)\n", msg, flow_iftype);
+		return -EINVAL;
 	}
 
-	if (return_dev->type == NSS_IPSEC_ARPHRD_IPSEC)
-		conn->return_interface_num = nss_ipsec_get_ifnum(nss_ipsec_get_data_interface());
-	else if (is_vlan_dev(return_dev))
-		conn->return_interface_num = nss_cmn_get_interface_number_by_dev(vlan_dev_real_dev(return_dev));
-	else {
-		if (!return_dev_type)
-			conn->return_interface_num = nss_cmn_get_interface_number_by_dev(return_dev);
-		else {
-			conn->return_interface_num = nss_cmn_get_interface_number_by_dev_and_type(return_dev, return_dev_type);
+	nss_nl_info("%p: dev=%s flow_ifnum:0x%x flow_mtu=%d\n", msg, flow_dev->name,
+			conn->flow_interface_num, conn->flow_mtu);
+	/*
+	 * Update return interface number and return mtu
+	 */
+	switch (return_iftype) {
+	case NSS_NL_IFTYPE_TUNNEL_IPSEC:
+		conn->return_interface_num = nss_nlipsec_get_ifnum(return_dev, tuple->protocol,
+									tuple->return_ident, tuple->flow_ident);
+		if (conn->return_interface_num < 0 ) {
+			nss_nl_error("%p: Failed to get return interface number (dev:%s, type:%d)\n",
+					return_dev, return_dev->name, return_iftype);
+			return -EINVAL;
 		}
-                        nss_nl_info("return_interface_num: %d return_interface_type: %d\n", conn->return_interface_num, return_dev_type);
+
+		conn->return_mtu = nss_nlipsec_get_mtu(return_dev, 4, tuple->protocol,
+							tuple->return_ident, tuple->flow_ident);
+		break;
+
+	case NSS_NL_IFTYPE_VLAN:
+		conn->return_interface_num = nss_cmn_get_interface_number_by_dev(vlan_dev_real_dev(return_dev));
+		if (conn->return_interface_num < 0 ) {
+			nss_nl_error("%p: Failed to get return interface number (dev:%s, type:%d)\n",
+					return_dev, return_dev->name, return_iftype);
+			return -EINVAL;
+		}
+
+		conn->return_mtu = return_dev->mtu;
+		break;
+
+	case NSS_NL_IFTYPE_PHYSICAL:
+		conn->return_interface_num = nss_cmn_get_interface_number_by_dev(return_dev);
+		if (conn->return_interface_num < 0 ) {
+			nss_nl_error("%p: Failed to get return interface number (dev:%s, type:%d)\n",
+					return_dev, return_dev->name, return_iftype);
+			return -EINVAL;
+		}
+
+		conn->return_mtu = return_dev->mtu;
+		break;
+
+	default:
+		nss_nl_error("%p: Unsupported return interface type (%d)\n", msg, flow_iftype);
+		return -EINVAL;
 	}
 
+	nss_nl_info("%p: dev=%s return_ifnum:0x%x return_mtu=%d\n", msg, return_dev->name,
+			conn->return_interface_num, conn->return_mtu);
+
 	nexthop->flow_nexthop = conn->flow_interface_num;
 	nexthop->return_nexthop = conn->return_interface_num;
 
 	nss_nl_info("flow_nexthop:%d return_nexthop:%d\n", nexthop->flow_nexthop, nexthop->return_nexthop);
 
 	/*
-	 * update the flow & return MTU(s)
-	 */
-	conn->return_mtu = return_dev->mtu;
-
-	/*
-	 * If, flow device is IPsec tunnel and protocol is ESP or NAT-T (UDP@4500)
-	 * then the operation is Decapsulation. In this we would like to have the MTU
-	 * of the incoming physical/virtual device. This would avoid fragmenting the
-	 * packet in NSS before delivering it for IPsec decap
-	 */
-	switch (msg->tuple.protocol) {
-	case IPPROTO_UDP:
-		override_mtu = (flow_dev->type == NSS_IPSEC_ARPHRD_IPSEC) && (msg->tuple.flow_ident == NSS_IPSECMGR_NATT_PORT_DATA);
-		break;
-
-	case IPPROTO_ESP:
-		override_mtu = (flow_dev->type == NSS_IPSEC_ARPHRD_IPSEC);
-		break;
-
-	default:
-		override_mtu = false;
-		break;
-	}
-
-	conn->flow_mtu = override_mtu ? conn->return_mtu : flow_dev->mtu;
-
-	/*
 	 * update flow & return xlate info
 	 */
 	conn->flow_ip_xlate = msg->tuple.flow_ip;
 	conn->flow_ident_xlate = msg->tuple.flow_ident;
 	conn->return_ip_xlate = msg->tuple.return_ip;
 	conn->return_ident_xlate = msg->tuple.return_ident;
+
 	return 0;
 }
 
 /*
  * nss_nlipv4_verify_tcp_rule()
- * 	verify and override TCP protocol rule entries
+ *	verify and override TCP protocol rule entries
  */
 static int nss_nlipv4_verify_tcp_rule(struct nss_ipv4_rule_create_msg *msg)
 {
@@ -613,14 +667,14 @@
 	 */
 	flow_dev = dev_get_by_name(&init_net, nl_rule->flow_ifname);
 	if (!flow_dev) {
-		nss_nl_error("%d:flow interface is not available\n", pid);
+		nss_nl_error("%d:flow interface(%s) is not available\n", pid, nl_rule->flow_ifname);
 		return -EINVAL;
 	}
 
 	return_dev = dev_get_by_name(&init_net, nl_rule->return_ifname);
 	if (!return_dev) {
 		dev_put(flow_dev);
-		nss_nl_error("%d:return interface is not available\n", pid);
+		nss_nl_error("%d:return interface(%s) is not available\n", pid, nl_rule->return_ifname);
 		return -EINVAL;
 	}
 
@@ -633,11 +687,14 @@
 		goto done;
 	}
 
+	nss_nl_info("Checking rule for srcif(%s) src_type(%d) destif(%s) dest_type(%d)\n", nl_rule->flow_ifname,
+			nl_rule->flow_iftype, nl_rule->return_ifname, nl_rule->return_iftype);
+
 	/*
 	 * check connection rule
 	 */
 	error = nss_nlipv4_verify_conn_rule(&nim->msg.rule_create, flow_dev, return_dev,
-					nl_rule->flow_iftype, nl_rule->return_iftype);
+						nl_rule->flow_iftype, nl_rule->return_iftype);
 	if (error < 0) {
 		nss_nl_error("%d:invalid conn rule information passed\n", pid);
 		goto done;
diff --git a/netlink/nss_nlipv6.c b/netlink/nss_nlipv6.c
index 3d3fcbb..e01060b 100644
--- a/netlink/nss_nlipv6.c
+++ b/netlink/nss_nlipv6.c
@@ -34,6 +34,7 @@
 #include <linux/completion.h>
 #include <linux/semaphore.h>
 #include <net/addrconf.h>
+#include <linux/in.h>
 
 #include <net/genetlink.h>
 #include <net/route.h>
@@ -47,11 +48,15 @@
 #include <nss_api_if.h>
 #include <nss_cmn.h>
 #include <nss_ipsec.h>
+#include "nss_nlipsec.h"
+#include <nss_ipsec_cmn.h>
 #include <nss_nl_if.h>
 #include "nss_nl.h"
 #include "nss_nlipv6.h"
 #include "nss_nlcmn_if.h"
 #include "nss_nlipv6_if.h"
+#include "nss_ipsecmgr.h"
+#include "nss_nlipsec_if.h"
 
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
 #define DST_NEIGH_LOOKUP(dst, ip_addr) dst_neigh_lookup(dst, ip_addr)
@@ -247,21 +252,26 @@
 		return -EINVAL;
 	}
 
-	/* Validate the port number */
+	/*
+	 * Validate the port number
+	 */
 	switch (tuple->protocol) {
-	case NSS_NLIPV6_UDP:
-	case NSS_NLIPV6_TCP:
-	case NSS_NLIPV6_SCTP:
-		if (!tuple->flow_ident) {
-			nss_nl_info("Empty flow ident\n");
-			return -EINVAL;
-		}
-
-		if (!tuple->return_ident) {
-			nss_nl_info("Empty return ident\n");
+	case IPPROTO_UDP:
+	case IPPROTO_TCP:
+	case IPPROTO_SCTP:
+		if (!tuple->flow_ident || !tuple->return_ident) {
+			nss_nl_error("Empty flow ident or return ident. flow ident:%d return ident:%d protocol:%d\n",
+					tuple->flow_ident, tuple->return_ident, tuple->protocol);
 			return -EINVAL;
 		}
 		break;
+	default:
+		if (tuple->flow_ident || tuple->return_ident) {
+			nss_nl_error("Flow ident and return ident must be empty. flow ident:%u return ident:%u protocol:%u\n",
+					tuple->flow_ident, tuple->return_ident, tuple->protocol);
+
+			return -EINVAL;
+		}
 	}
 
 	return 0;
@@ -272,15 +282,17 @@
  * 	verify and override connection rule entries
  */
 static int nss_nlipv6_verify_conn_rule(struct nss_ipv6_rule_create_msg *msg, struct net_device *flow_dev,
-					struct net_device *return_dev, uint16_t flow_dev_type, uint16_t return_dev_type)
+					struct net_device *return_dev, enum nss_nl_iftype flow_iftype,
+					enum nss_nl_iftype return_iftype)
 {
 	struct nss_ipv6_connection_rule *conn = &msg->conn_rule;
 	struct nss_ipv6_nexthop *nexthop = &msg->nexthop_rule;
+	struct nss_ipv6_5tuple *tuple = &msg->tuple;
 	const size_t rule_sz = sizeof(struct nss_ipv6_connection_rule);
 	bool valid;
 
 	/*
-	 * connection rule is not valid ignore rest of the checks
+	 * Connection rule is not valid ignore rest of the checks
 	 */
 	valid = msg->valid_flags & NSS_IPV6_RULE_CREATE_CONN_VALID;
 	if (!valid) {
@@ -288,59 +300,123 @@
 		return -EINVAL;
 	}
 
+	if ((flow_iftype >= NSS_NL_IFTYPE_MAX) || (return_iftype >= NSS_NL_IFTYPE_MAX)) {
+		nss_nl_error("%p: Invalid interface type (flow:%d, return:%d)\n", msg, flow_iftype, return_iftype);
+		return -EINVAL;
+	}
+
 	/*
-	 * update the flow  & return MAC address
+	 * Update the flow  & return MAC address
 	 */
-	if (nss_nlipv6_get_macaddr(msg->tuple.flow_ip, (uint8_t *)conn->flow_mac)) {
+	if (nss_nlipv6_get_macaddr(tuple->flow_ip, (uint8_t *)conn->flow_mac)) {
 		nss_nl_info("Error in Updating the Flow MAC Address \n");
 		return -EINVAL;
 	}
 
-	if (nss_nlipv6_get_macaddr(msg->tuple.return_ip, (uint8_t *)conn->return_mac)) {
+	if (nss_nlipv6_get_macaddr(tuple->return_ip, (uint8_t *)conn->return_mac)) {
 		nss_nl_info("Error in Updating the Return MAC Address \n");
 		return -EINVAL;
 	}
 
 	/*
-	 * update flow and return interface numbers. Handle Ipsec and vlan interfaces seperately.
+	 * Update flow interface number and flow mtu
 	 */
-	if (flow_dev->type == NSS_IPSEC_ARPHRD_IPSEC)
-		conn->flow_interface_num = nss_ipsec_get_ifnum(nss_ipsec_get_data_interface());
-	else if (is_vlan_dev(flow_dev))
-		conn->flow_interface_num = nss_cmn_get_interface_number_by_dev(vlan_dev_real_dev(flow_dev));
-	else {
-		if (!flow_dev_type)
-			conn->flow_interface_num = nss_cmn_get_interface_number_by_dev(flow_dev);
-		else {
-			conn->flow_interface_num = nss_cmn_get_interface_number_by_dev_and_type(flow_dev, flow_dev_type);
+	switch (flow_iftype) {
+	case NSS_NL_IFTYPE_TUNNEL_IPSEC:
+		conn->flow_interface_num = nss_nlipsec_get_ifnum(flow_dev, tuple->protocol,
+								tuple->return_ident, tuple->flow_ident);
+		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);
+			return -EINVAL;
 		}
-			nss_nl_info("flow_interface_num: %d flow_interface_type: %d\n", conn->flow_interface_num, flow_dev_type);
-}
 
-	if (return_dev->type == NSS_IPSEC_ARPHRD_IPSEC)
-		conn->return_interface_num = nss_ipsec_get_ifnum(nss_ipsec_get_data_interface());
-	else if (is_vlan_dev(return_dev))
-		conn->return_interface_num = nss_cmn_get_interface_number_by_dev(vlan_dev_real_dev(return_dev));
-	else {
-		if (!return_dev_type)
-			conn->return_interface_num = nss_cmn_get_interface_number_by_dev(return_dev);
-		else {
-			conn->return_interface_num = nss_cmn_get_interface_number_by_dev_and_type(return_dev, return_dev_type);
+		conn->flow_mtu = nss_nlipsec_get_mtu(flow_dev, 6, tuple->protocol,
+							tuple->return_ident, tuple->flow_ident);
+		break;
+
+	case NSS_NL_IFTYPE_VLAN:
+		conn->flow_interface_num = nss_cmn_get_interface_number_by_dev(vlan_dev_real_dev(flow_dev));
+		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);
+			return -EINVAL;
 		}
-                        nss_nl_info("return_interface_num: %d return_interface_type: %d\n", conn->return_interface_num, return_dev_type);
+
+		conn->flow_mtu = flow_dev->mtu;
+		break;
+
+	case NSS_NL_IFTYPE_PHYSICAL:
+		conn->flow_interface_num = nss_cmn_get_interface_number_by_dev(flow_dev);
+		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);
+			return -EINVAL;
+		}
+
+		conn->flow_mtu = flow_dev->mtu;
+		break;
+
+	default:
+		nss_nl_error("%p: Unsupported flow interface type (%d)\n", msg, flow_iftype);
+		return -EINVAL;
 	}
 
+	nss_nl_info("%p: dev=%s flow_ifnum:0x%x flow_mtu=%d\n", msg, flow_dev->name,
+			conn->flow_interface_num, conn->flow_mtu);
+
+	/*
+	 * Update return interface number and return mtu
+	 */
+	switch (return_iftype) {
+	case NSS_NL_IFTYPE_TUNNEL_IPSEC:
+		conn->return_interface_num = nss_nlipsec_get_ifnum(return_dev, tuple->protocol,
+									tuple->return_ident, tuple->flow_ident);
+		if (conn->return_interface_num < 0 ) {
+			nss_nl_error("%p: Failed to get return interface number (dev:%s, type:%d)\n",
+					return_dev, return_dev->name, return_iftype);
+			return -EINVAL;
+		}
+
+		conn->return_mtu = nss_nlipsec_get_mtu(return_dev, 6, tuple->protocol,
+							tuple->return_ident, tuple->flow_ident);
+		break;
+
+	case NSS_NL_IFTYPE_VLAN:
+		conn->return_interface_num = nss_cmn_get_interface_number_by_dev(vlan_dev_real_dev(return_dev));
+		if (conn->return_interface_num < 0 ) {
+			nss_nl_error("%p: Failed to get return interface number (dev:%s, type:%d)\n",
+					return_dev, return_dev->name, return_iftype);
+			return -EINVAL;
+		}
+
+		conn->return_mtu = return_dev->mtu;
+		break;
+
+	case NSS_NL_IFTYPE_PHYSICAL:
+		conn->return_interface_num = nss_cmn_get_interface_number_by_dev(return_dev);
+		if (conn->return_interface_num < 0 ) {
+			nss_nl_error("%p: Failed to get return interface number (dev:%s, type:%d)\n",
+					return_dev, return_dev->name, return_iftype);
+			return -EINVAL;
+		}
+
+		conn->return_mtu = return_dev->mtu;
+		break;
+
+	default:
+		nss_nl_error("%p: Unsupported return interface type (%d)\n", msg, flow_iftype);
+		return -EINVAL;
+	}
+
+	nss_nl_info("%p: dev=%s return_ifnum:0x%x return_mtu=%d\n", msg, return_dev->name,
+			conn->return_interface_num, conn->return_mtu);
+
 	nexthop->flow_nexthop = conn->flow_interface_num;
 	nexthop->return_nexthop = conn->return_interface_num;
 
 	nss_nl_info("flow_nexthop:%d return_nexthop:%d\n", nexthop->flow_nexthop, nexthop->return_nexthop);
 
-	/*
-	 * update the flow & return MTU(s)
-	 */
-	conn->flow_mtu = flow_dev->mtu;
-	conn->return_mtu = return_dev->mtu;
-
 	return 0;
 }
 
@@ -449,8 +525,8 @@
  * nss_nlipv6_verify_vlan_rule()
  * 	verify and override vlan rule entries
  */
-static int nss_nlipv6_verify_vlan_rule(struct nss_ipv6_rule_create_msg *msg,
-		struct net_device *flow_dev, struct net_device *return_dev)
+static int nss_nlipv6_verify_vlan_rule(struct nss_ipv6_rule_create_msg *msg, struct net_device *flow_dev,
+					struct net_device *return_dev)
 {
 	struct nss_ipv6_vlan_rule *vlan_primary = &msg->vlan_primary_rule;
 	struct nss_ipv6_vlan_rule *vlan_secondary = &msg->vlan_secondary_rule;
@@ -586,14 +662,14 @@
 	 */
 	flow_dev = dev_get_by_name(&init_net, nl_rule->flow_ifname);
 	if (!flow_dev) {
-		nss_nl_error("%d:flow interface is not available\n", pid);
+		nss_nl_error("%d:flow interface is not available for dev=%s\n", pid, nl_rule->flow_ifname);
 		return -EINVAL;
 	}
 
 	return_dev = dev_get_by_name(&init_net, nl_rule->return_ifname);
 	if (!return_dev) {
 		dev_put(flow_dev);
-		nss_nl_error("%d:return interface is not available\n", pid);
+		nss_nl_error("%d:return interface is not available for dev=%s\n", pid, nl_rule->return_ifname);
 		return -EINVAL;
 	}
 
@@ -606,11 +682,14 @@
 		goto done;
 	}
 
+	nss_nl_info("Checking rule for flowdev=%s flow_type=%d returndev=%s return_type=%d\n",
+			nl_rule->flow_ifname, nl_rule->flow_iftype, nl_rule->return_ifname, nl_rule->return_iftype);
+
 	/*
 	 * check connection rule
 	 */
 	error = nss_nlipv6_verify_conn_rule(&nim->msg.rule_create, flow_dev, return_dev,
-				nl_rule->flow_iftype, nl_rule->return_iftype);
+						nl_rule->flow_iftype, nl_rule->return_iftype);
 	if (error < 0) {
 		nss_nl_error("%d:invalid conn rule information passed\n", pid);
 		goto done;
diff --git a/netlink/nss_nlipv6.h b/netlink/nss_nlipv6.h
index 70312a3..98185f9 100644
--- a/netlink/nss_nlipv6.h
+++ b/netlink/nss_nlipv6.h
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016, 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.
@@ -21,11 +21,6 @@
 #ifndef __NSS_NLIPV6_H
 #define __NSS_NLIPV6_H
 
-/*IP protocol type */
-#define NSS_NLIPV6_UDP 17
-#define NSS_NLIPV6_TCP 6
-#define NSS_NLIPV6_SCTP 132
-
 #define NSS_NLIPV6_VLAN_ID_NOT_CONFIGURED 0xFFF    /* Invalid vlan 4095 */
 
 bool nss_nlipv6_init(void);