add return code to sfe_ipv4_create_rule

sfe_ipv4_create_rule returns nothing (void), but the function has a
chance for failure.  if the function fails, this could cause the
fast-classifier to become out-of-sync with respect to the offloaded
state of the connection.

this causes two issues:
	1. this is partially handled by repeatedly calling
	   _create_rule for the connection, which seems inefficient.
	2. offloaded state is propagated back to userspace

Change-Id: I6184344a8278379e064b128d6d4086e2c2fa169a
Signed-off-by: Nicolas Costa <ncosta@codeaurora.org>
diff --git a/fast-classifier/fast-classifier.c b/fast-classifier/fast-classifier.c
index 7aab34d..91db303 100644
--- a/fast-classifier/fast-classifier.c
+++ b/fast-classifier/fast-classifier.c
@@ -337,6 +337,7 @@
  */
 static int fast_classifier_offload_genl_msg(struct sk_buff *skb, struct genl_info *info)
 {
+	int ret;
 	struct nlattr *na;
 	struct fast_classifier_tuple *fc_msg;
 	struct sfe_ipv4_create *p_sic;
@@ -374,10 +375,12 @@
 					return 0;
 				}
 				DEBUG_TRACE("INFO: calling sfe rule creation!\n");
-				conn->offloaded = 1;
 				spin_unlock_irqrestore(&sfe_connections_lock, flags);
-				sfe_ipv4_create_rule(p_sic);
-				fast_classifier_send_genl_msg(FAST_CLASSIFIER_C_OFFLOADED, fc_msg);
+				ret = sfe_ipv4_create_rule(p_sic);
+				if ((ret == 0) || (ret == -EADDRINUSE)) {
+					conn->offloaded = 1;
+					fast_classifier_send_genl_msg(FAST_CLASSIFIER_C_OFFLOADED, fc_msg);
+				}
 				return 0;
 			}
 			/* conn->offloaded != 0 */
@@ -405,6 +408,7 @@
 						  const struct net_device *out,
 						  int (*okfn)(struct sk_buff *))
 {
+	int ret;
 	struct sfe_ipv4_create sic;
 	struct sfe_ipv4_create *p_sic;
 	struct net_device *in;
@@ -563,26 +567,28 @@
 			conn->hits++;
 			if (conn->offloaded == 0) {
 				if (conn->hits == offload_at_pkts) {
-				struct fast_classifier_tuple fc_msg;
+					struct fast_classifier_tuple fc_msg;
 					DEBUG_TRACE("OFFLOADING CONNECTION, TOO MANY HITS\n");
 					if (fast_classifier_update_protocol(p_sic, conn->ct) == 0) {
 						spin_unlock_irqrestore(&sfe_connections_lock, flags);
 						DEBUG_TRACE("UNKNOWN PROTOCOL OR CONNECTION CLOSING, SKIPPING\n");
-						sfe_ipv4_create_rule(p_sic);
 						return 0;
 					}
 					DEBUG_TRACE("INFO: calling sfe rule creation!\n");
-					conn->offloaded = 1;
 					spin_unlock_irqrestore(&sfe_connections_lock, flags);
-					sfe_ipv4_create_rule(p_sic);
 
-					fc_msg.proto = sic.protocol;
-					fc_msg.src_saddr = sic.src_ip;
-					fc_msg.dst_saddr = sic.dest_ip;
-					fc_msg.sport = sic.src_port;
-					fc_msg.dport = sic.dest_port;
-					memcpy(fc_msg.mac, conn->mac, ETH_ALEN);
-					fast_classifier_send_genl_msg(FAST_CLASSIFIER_C_OFFLOADED, &fc_msg);
+					ret = sfe_ipv4_create_rule(p_sic);
+					if ((ret == 0) || (ret == -EADDRINUSE)) {
+						conn->offloaded = 1;
+						fc_msg.proto = sic.protocol;
+						fc_msg.src_saddr = sic.src_ip;
+						fc_msg.dst_saddr = sic.dest_ip;
+						fc_msg.sport = sic.src_port;
+						fc_msg.dport = sic.dest_port;
+						memcpy(fc_msg.mac, conn->mac, ETH_ALEN);
+						fast_classifier_send_genl_msg(FAST_CLASSIFIER_C_OFFLOADED, &fc_msg);
+					}
+
 					goto done1;
 				} else if (conn->hits > offload_at_pkts) {
 					DEBUG_ERROR("ERROR: MORE THAN %d HITS AND NOT OFFLOADED\n", offload_at_pkts);
@@ -591,24 +597,12 @@
 				}
 			}
 
+			spin_unlock_irqrestore(&sfe_connections_lock, flags);
 			if (conn->offloaded == 1) {
-				struct sfe_ipv4_mark mark;
-
-				DEBUG_TRACE("CONNECTION ALREADY OFFLOADED, UPDATING MARK\n");
-				mark.protocol = p_sic->protocol;
-				mark.src_ip = p_sic->src_ip;
-				mark.src_port = p_sic->src_port;
-				mark.dest_ip = p_sic->dest_ip;
-				mark.dest_port = p_sic->dest_port;
-				mark.mark = skb->mark;
-				sfe_ipv4_mark_rule(&mark);
-				spin_unlock_irqrestore(&sfe_connections_lock, flags);
-				sfe_ipv4_create_rule(p_sic);
-				goto done1;
+				sfe_ipv4_update_rule(p_sic);
 			}
 
 			DEBUG_TRACE("FOUND, SKIPPING\n");
-			spin_unlock_irqrestore(&sfe_connections_lock, flags);
 			goto done1;
 		}
 
diff --git a/shortcut-fe/sfe_ipv4.c b/shortcut-fe/sfe_ipv4.c
index 780b4d2..2b56319 100644
--- a/shortcut-fe/sfe_ipv4.c
+++ b/shortcut-fe/sfe_ipv4.c
@@ -2360,7 +2360,7 @@
  * sfe_ipv4_create_rule()
  *	Create a forwarding rule.
  */
-void sfe_ipv4_create_rule(struct sfe_ipv4_create *sic)
+int sfe_ipv4_create_rule(struct sfe_ipv4_create *sic)
 {
 	struct sfe_ipv4 *si = &__si;
 	struct sfe_ipv4_connection *c;
@@ -2395,7 +2395,7 @@
 			    "  s: %s:%pM:%pI4:%u, d: %s:%pM:%pI4:%u\n",
 			    sic->protocol, sic->src_dev->name, sic->src_mac, &sic->src_ip, ntohs(sic->src_port),
 			    sic->dest_dev->name, sic->dest_mac, &sic->dest_ip, ntohs(sic->dest_port));
-		return;
+		return -EADDRINUSE;
 	}
 
 	/*
@@ -2404,14 +2404,14 @@
 	c = (struct sfe_ipv4_connection *)kmalloc(sizeof(struct sfe_ipv4_connection), GFP_ATOMIC);
 	if (unlikely(!c)) {
 		spin_unlock_bh(&si->lock);
-		return;
+		return -ENOMEM;
 	}
 
 	original_cm = (struct sfe_ipv4_connection_match *)kmalloc(sizeof(struct sfe_ipv4_connection_match), GFP_ATOMIC);
 	if (unlikely(!original_cm)) {
 		spin_unlock_bh(&si->lock);
 		kfree(c);
-		return;
+		return -ENOMEM;
 	}
 
 	reply_cm = (struct sfe_ipv4_connection_match *)kmalloc(sizeof(struct sfe_ipv4_connection_match), GFP_ATOMIC);
@@ -2419,7 +2419,7 @@
 		spin_unlock_bh(&si->lock);
 		kfree(original_cm);
 		kfree(c);
-		return;
+		return -ENOMEM;
 	}
 
 	/*
@@ -2572,6 +2572,8 @@
 		   &sic->src_ip, &sic->src_ip_xlate, ntohs(sic->src_port), ntohs(sic->src_port_xlate),
 		   sic->dest_dev->name, sic->dest_mac, sic->dest_mac_xlate,
 		   &sic->dest_ip, &sic->dest_ip_xlate, ntohs(sic->dest_port), ntohs(sic->dest_port_xlate));
+
+	return 0;
 }
 
 /*
diff --git a/shortcut-fe/sfe_ipv4.h b/shortcut-fe/sfe_ipv4.h
index dc50efa..d7d87fc 100644
--- a/shortcut-fe/sfe_ipv4.h
+++ b/shortcut-fe/sfe_ipv4.h
@@ -89,7 +89,7 @@
 
 extern int sfe_ipv4_recv(struct net_device *dev, struct sk_buff *skb);
 extern int sfe_pppoe_recv(struct net_device *dev, struct sk_buff *skb);
-extern void sfe_ipv4_create_rule(struct sfe_ipv4_create *sic);
+extern int sfe_ipv4_create_rule(struct sfe_ipv4_create *sic);
 extern void sfe_ipv4_destroy_rule(struct sfe_ipv4_destroy *sid);
 extern void sfe_ipv4_destroy_all_rules_for_dev(struct net_device *dev);
 extern void sfe_ipv4_register_sync_rule_callback(sfe_ipv4_sync_rule_callback_t callback);