Skip to content

Commit

Permalink
[NETFILTER]: nf_queue: move list_head/skb/id to struct nf_info
Browse files Browse the repository at this point in the history
Move common fields for queue management to struct nf_info and rename it
to struct nf_queue_entry. The avoids one allocation/free per packet and
simplifies the code a bit.

Alternatively we could add some private room at the tail, but since
all current users use identical structs this seems easier.

Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Patrick McHardy authored and David S. Miller committed Jan 28, 2008
1 parent 7a6c665 commit 02f014d
Show file tree
Hide file tree
Showing 8 changed files with 132 additions and 190 deletions.
6 changes: 3 additions & 3 deletions include/linux/netfilter.h
Original file line number Diff line number Diff line change
Expand Up @@ -270,17 +270,17 @@ extern void nf_invalidate_cache(int pf);
extern int skb_make_writable(struct sk_buff *skb, unsigned int writable_len);

struct flowi;
struct nf_info;
struct nf_queue_entry;

struct nf_afinfo {
unsigned short family;
__sum16 (*checksum)(struct sk_buff *skb, unsigned int hook,
unsigned int dataoff, u_int8_t protocol);
int (*route)(struct dst_entry **dst, struct flowi *fl);
void (*saveroute)(const struct sk_buff *skb,
struct nf_info *info);
struct nf_queue_entry *entry);
int (*reroute)(struct sk_buff *skb,
const struct nf_info *info);
const struct nf_queue_entry *entry);
int route_key_size;
};

Expand Down
14 changes: 8 additions & 6 deletions include/net/netfilter/nf_queue.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@
#define _NF_QUEUE_H

/* Each queued (to userspace) skbuff has one of these. */
struct nf_info {
struct nf_queue_entry {
struct list_head list;
struct sk_buff *skb;
unsigned int id;

struct nf_hook_ops *elem;
int pf;
unsigned int hook;
Expand All @@ -11,12 +15,11 @@ struct nf_info {
int (*okfn)(struct sk_buff *);
};

#define nf_info_reroute(x) ((void *)x + sizeof(struct nf_info))
#define nf_queue_entry_reroute(x) ((void *)x + sizeof(struct nf_queue_entry))

/* Packet queuing */
struct nf_queue_handler {
int (*outfn)(struct sk_buff *skb,
struct nf_info *info,
int (*outfn)(struct nf_queue_entry *entry,
unsigned int queuenum);
char *name;
};
Expand All @@ -26,7 +29,6 @@ extern int nf_register_queue_handler(int pf,
extern int nf_unregister_queue_handler(int pf,
const struct nf_queue_handler *qh);
extern void nf_unregister_queue_handlers(const struct nf_queue_handler *qh);
extern void nf_reinject(struct sk_buff *skb, struct nf_info *info,
unsigned int verdict);
extern void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict);

#endif /* _NF_QUEUE_H */
14 changes: 8 additions & 6 deletions net/ipv4/netfilter.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,12 @@ struct ip_rt_info {
u_int8_t tos;
};

static void nf_ip_saveroute(const struct sk_buff *skb, struct nf_info *info)
static void nf_ip_saveroute(const struct sk_buff *skb,
struct nf_queue_entry *entry)
{
struct ip_rt_info *rt_info = nf_info_reroute(info);
struct ip_rt_info *rt_info = nf_queue_entry_reroute(entry);

if (info->hook == NF_INET_LOCAL_OUT) {
if (entry->hook == NF_INET_LOCAL_OUT) {
const struct iphdr *iph = ip_hdr(skb);

rt_info->tos = iph->tos;
Expand All @@ -136,11 +137,12 @@ static void nf_ip_saveroute(const struct sk_buff *skb, struct nf_info *info)
}
}

static int nf_ip_reroute(struct sk_buff *skb, const struct nf_info *info)
static int nf_ip_reroute(struct sk_buff *skb,
const struct nf_queue_entry *entry)
{
const struct ip_rt_info *rt_info = nf_info_reroute(info);
const struct ip_rt_info *rt_info = nf_queue_entry_reroute(entry);

if (info->hook == NF_INET_LOCAL_OUT) {
if (entry->hook == NF_INET_LOCAL_OUT) {
const struct iphdr *iph = ip_hdr(skb);

if (!(iph->tos == rt_info->tos
Expand Down
68 changes: 23 additions & 45 deletions net/ipv4/netfilter/ip_queue.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,7 @@
#define NET_IPQ_QMAX 2088
#define NET_IPQ_QMAX_NAME "ip_queue_maxlen"

struct ipq_queue_entry {
struct list_head list;
struct nf_info *info;
struct sk_buff *skb;
};

typedef int (*ipq_cmpfn)(struct ipq_queue_entry *, unsigned long);
typedef int (*ipq_cmpfn)(struct nf_queue_entry *, unsigned long);

static unsigned char copy_mode __read_mostly = IPQ_COPY_NONE;
static unsigned int queue_maxlen __read_mostly = IPQ_QMAX_DEFAULT;
Expand All @@ -56,22 +50,20 @@ static LIST_HEAD(queue_list);
static DEFINE_MUTEX(ipqnl_mutex);

static void
ipq_issue_verdict(struct ipq_queue_entry *entry, int verdict)
ipq_issue_verdict(struct nf_queue_entry *entry, int verdict)
{
/* TCP input path (and probably other bits) assume to be called
* from softirq context, not from syscall, like ipq_issue_verdict is
* called. TCP input path deadlocks with locks taken from timer
* softirq, e.g. We therefore emulate this by local_bh_disable() */

local_bh_disable();
nf_reinject(entry->skb, entry->info, verdict);
nf_reinject(entry, verdict);
local_bh_enable();

kfree(entry);
}

static inline void
__ipq_enqueue_entry(struct ipq_queue_entry *entry)
__ipq_enqueue_entry(struct nf_queue_entry *entry)
{
list_add_tail(&entry->list, &queue_list);
queue_total++;
Expand Down Expand Up @@ -114,10 +106,10 @@ __ipq_reset(void)
__ipq_flush(NULL, 0);
}

static struct ipq_queue_entry *
static struct nf_queue_entry *
ipq_find_dequeue_entry(unsigned long id)
{
struct ipq_queue_entry *entry = NULL, *i;
struct nf_queue_entry *entry = NULL, *i;

write_lock_bh(&queue_lock);

Expand All @@ -140,7 +132,7 @@ ipq_find_dequeue_entry(unsigned long id)
static void
__ipq_flush(ipq_cmpfn cmpfn, unsigned long data)
{
struct ipq_queue_entry *entry, *next;
struct nf_queue_entry *entry, *next;

list_for_each_entry_safe(entry, next, &queue_list, list) {
if (!cmpfn || cmpfn(entry, data)) {
Expand All @@ -160,7 +152,7 @@ ipq_flush(ipq_cmpfn cmpfn, unsigned long data)
}

static struct sk_buff *
ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp)
ipq_build_packet_message(struct nf_queue_entry *entry, int *errp)
{
sk_buff_data_t old_tail;
size_t size = 0;
Expand Down Expand Up @@ -217,20 +209,20 @@ ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp)
pmsg->timestamp_sec = tv.tv_sec;
pmsg->timestamp_usec = tv.tv_usec;
pmsg->mark = entry->skb->mark;
pmsg->hook = entry->info->hook;
pmsg->hook = entry->hook;
pmsg->hw_protocol = entry->skb->protocol;

if (entry->info->indev)
strcpy(pmsg->indev_name, entry->info->indev->name);
if (entry->indev)
strcpy(pmsg->indev_name, entry->indev->name);
else
pmsg->indev_name[0] = '\0';

if (entry->info->outdev)
strcpy(pmsg->outdev_name, entry->info->outdev->name);
if (entry->outdev)
strcpy(pmsg->outdev_name, entry->outdev->name);
else
pmsg->outdev_name[0] = '\0';

if (entry->info->indev && entry->skb->dev) {
if (entry->indev && entry->skb->dev) {
pmsg->hw_type = entry->skb->dev->type;
pmsg->hw_addrlen = dev_parse_header(entry->skb,
pmsg->hw_addr);
Expand All @@ -252,28 +244,17 @@ ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp)
}

static int
ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info,
unsigned int queuenum)
ipq_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
{
int status = -EINVAL;
struct sk_buff *nskb;
struct ipq_queue_entry *entry;

if (copy_mode == IPQ_COPY_NONE)
return -EAGAIN;

entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
if (entry == NULL) {
printk(KERN_ERR "ip_queue: OOM in ipq_enqueue_packet()\n");
return -ENOMEM;
}

entry->info = info;
entry->skb = skb;

nskb = ipq_build_packet_message(entry, &status);
if (nskb == NULL)
goto err_out_free;
return status;

write_lock_bh(&queue_lock);

Expand Down Expand Up @@ -307,14 +288,11 @@ ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info,

err_out_unlock:
write_unlock_bh(&queue_lock);

err_out_free:
kfree(entry);
return status;
}

static int
ipq_mangle_ipv4(ipq_verdict_msg_t *v, struct ipq_queue_entry *e)
ipq_mangle_ipv4(ipq_verdict_msg_t *v, struct nf_queue_entry *e)
{
int diff;
int err;
Expand Down Expand Up @@ -352,7 +330,7 @@ ipq_mangle_ipv4(ipq_verdict_msg_t *v, struct ipq_queue_entry *e)
static int
ipq_set_verdict(struct ipq_verdict_msg *vmsg, unsigned int len)
{
struct ipq_queue_entry *entry;
struct nf_queue_entry *entry;

if (vmsg->value > NF_MAX_VERDICT)
return -EINVAL;
Expand Down Expand Up @@ -412,13 +390,13 @@ ipq_receive_peer(struct ipq_peer_msg *pmsg,
}

static int
dev_cmp(struct ipq_queue_entry *entry, unsigned long ifindex)
dev_cmp(struct nf_queue_entry *entry, unsigned long ifindex)
{
if (entry->info->indev)
if (entry->info->indev->ifindex == ifindex)
if (entry->indev)
if (entry->indev->ifindex == ifindex)
return 1;
if (entry->info->outdev)
if (entry->info->outdev->ifindex == ifindex)
if (entry->outdev)
if (entry->outdev->ifindex == ifindex)
return 1;
#ifdef CONFIG_BRIDGE_NETFILTER
if (entry->skb->nf_bridge) {
Expand Down
14 changes: 8 additions & 6 deletions net/ipv6/netfilter.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,23 +57,25 @@ struct ip6_rt_info {
struct in6_addr saddr;
};

static void nf_ip6_saveroute(const struct sk_buff *skb, struct nf_info *info)
static void nf_ip6_saveroute(const struct sk_buff *skb,
struct nf_queue_entry *entry)
{
struct ip6_rt_info *rt_info = nf_info_reroute(info);
struct ip6_rt_info *rt_info = nf_queue_entry_reroute(entry);

if (info->hook == NF_INET_LOCAL_OUT) {
if (entry->hook == NF_INET_LOCAL_OUT) {
struct ipv6hdr *iph = ipv6_hdr(skb);

rt_info->daddr = iph->daddr;
rt_info->saddr = iph->saddr;
}
}

static int nf_ip6_reroute(struct sk_buff *skb, const struct nf_info *info)
static int nf_ip6_reroute(struct sk_buff *skb,
const struct nf_queue_entry *entry)
{
struct ip6_rt_info *rt_info = nf_info_reroute(info);
struct ip6_rt_info *rt_info = nf_queue_entry_reroute(entry);

if (info->hook == NF_INET_LOCAL_OUT) {
if (entry->hook == NF_INET_LOCAL_OUT) {
struct ipv6hdr *iph = ipv6_hdr(skb);
if (!ipv6_addr_equal(&iph->daddr, &rt_info->daddr) ||
!ipv6_addr_equal(&iph->saddr, &rt_info->saddr))
Expand Down
Loading

0 comments on commit 02f014d

Please sign in to comment.