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);