@@ -192,7 +192,9 @@ next_hook:
ret = -EPERM;
} else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) {
int err = nf_queue(skb, elem, pf, hook, indev, outdev, okfn,
- verdict >> NF_VERDICT_QBITS);
+ verdict >> NF_VERDICT_QBITS,
+ verdict & NF_VERDICT_FLAG_FAIL_OPEN);
+
if (err < 0) {
if (err == -ECANCELED)
goto next_hook;
@@ -29,7 +29,8 @@ extern int nf_queue(struct sk_buff *skb,
struct net_device *indev,
struct net_device *outdev,
int (*okfn)(struct sk_buff *),
- unsigned int queuenum);
+ unsigned int queuenum,
+ int flags);
extern int __init netfilter_queue_init(void);
/* nf_log.c */
@@ -123,7 +123,8 @@ static int __nf_queue(struct sk_buff *sk
struct net_device *indev,
struct net_device *outdev,
int (*okfn)(struct sk_buff *),
- unsigned int queuenum)
+ unsigned int queuenum,
+ int flags)
{
int status = -ENOENT;
struct nf_queue_entry *entry = NULL;
@@ -185,11 +186,11 @@ static int __nf_queue(struct sk_buff *sk
#endif
skb_dst_force(skb);
afinfo->saveroute(skb, entry);
- status = qh->outfn(entry, queuenum, 0);
+ status = qh->outfn(entry, queuenum, flags);
rcu_read_unlock();
- if (status < 0) {
+ if (status) {
nf_queue_entry_release_refs(entry);
goto err;
}
@@ -230,15 +231,25 @@ int nf_queue(struct sk_buff *skb,
struct net_device *indev,
struct net_device *outdev,
int (*okfn)(struct sk_buff *),
- unsigned int queuenum)
+ unsigned int queuenum,
+ int flags)
{
struct sk_buff *segs;
int err = -EINVAL;
unsigned int queued;
- if (!skb_is_gso(skb))
- return __nf_queue(skb, elem, pf, hook, indev, outdev, okfn,
- queuenum);
+ if (!skb_is_gso(skb)) {
+ err = __nf_queue(skb, elem, pf, hook, indev, outdev, okfn,
+ queuenum, flags);
+ if (err > 0) {
+ /* Queue failed due to queue-full and handler
+ * returned >0 indicating fail-open - temporarily
+ * accept packets.
+ */
+ err = okfn(skb);
+ }
+ return err;
+ }
switch (pf) {
case NFPROTO_IPV4:
@@ -266,16 +277,28 @@ int nf_queue(struct sk_buff *skb,
if (err == 0) {
nf_bridge_adjust_segmented_data(segs);
err = __nf_queue(segs, elem, pf, hook, indev,
- outdev, okfn, queuenum);
+ outdev, okfn, queuenum, flags);
}
- if (err == 0)
+
+ if (err == 0) {
queued++;
- else
+ } else if (err > 0) {
+ /* Queue failed due to queue-full and handler
+ * returned >0 indicating fail-open - accept
+ * this and remaining segments.
+ */
+ okfn(segs);
+ } else {
+ /* Queue failed due to queue-full and handler
+ * returned <0 - free this and remaining skb
+ * segments.
+ */
kfree_skb(segs);
+ }
segs = nskb;
} while (segs);
- if (queued) {
+ if (queued || err > 0) {
kfree_skb(skb);
return 0;
}
@@ -325,7 +348,7 @@ void nf_reinject(struct nf_queue_entry *
case NF_QUEUE:
err = __nf_queue(skb, elem, entry->pf, entry->hook,
entry->indev, entry->outdev, entry->okfn,
- verdict >> NF_VERDICT_QBITS);
+ verdict >> NF_VERDICT_QBITS, 0);
if (err < 0) {
if (err == -ECANCELED)
goto next_hook;
Pass FAILOPEN flags, add support for fail-open, add support for GSO skb. If __nf_queue() returns >0 to indicate fail-open, we call okfn() immediately and return 0 to caller. Signed-off-by: Krishna Kumar <krkumar2@in.ibm.com> --- net/netfilter/core.c | 4 ++ net/netfilter/nf_internals.h | 3 +- net/netfilter/nf_queue.c | 47 ++++++++++++++++++++++++--------- 3 files changed, 40 insertions(+), 14 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html