Commit 14d3692f authored by David S. Miller's avatar David S. Miller

Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next

Pablo Neira Ayuso says:

====================
The following patchset contains relevant updates for the Netfilter
tree, they are:

* Enhancements for ipset: Add the counter extension for sets, this
  information can be used from the iptables set match, to change
  the matching behaviour. Jozsef required to add the extension
  infrastructure and moved the existing timeout support upon it.
  This also includes a change in net/sched/em_ipset to adapt it to
  the new extension structure.

* Enhancements for performance boosting in nfnetlink_queue: Add new
  configuration flags that allows user-space to receive big packets (GRO)
  and to disable checksumming calculation. This were proposed by Eric
  Dumazet during the Netfilter Workshop 2013 in Copenhagen. Florian
  Westphal was kind enough to find the time to materialize the proposal.

* A sparse fix from Simon, he noticed it in the SCTP NAT helper, the fix
  required a change in the interface of sctp_end_cksum.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 674853b2 eee1d5a1
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu> /* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
* Patrick Schaaf <bof@bof.de> * Patrick Schaaf <bof@bof.de>
* Martin Josefsson <gandalf@wlug.westbo.se> * Martin Josefsson <gandalf@wlug.westbo.se>
* Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> * Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
...@@ -47,10 +47,36 @@ enum ip_set_feature { ...@@ -47,10 +47,36 @@ enum ip_set_feature {
IPSET_DUMP_LAST = (1 << IPSET_DUMP_LAST_FLAG), IPSET_DUMP_LAST = (1 << IPSET_DUMP_LAST_FLAG),
}; };
/* Set extensions */
enum ip_set_extension {
IPSET_EXT_NONE = 0,
IPSET_EXT_BIT_TIMEOUT = 1,
IPSET_EXT_TIMEOUT = (1 << IPSET_EXT_BIT_TIMEOUT),
IPSET_EXT_BIT_COUNTER = 2,
IPSET_EXT_COUNTER = (1 << IPSET_EXT_BIT_COUNTER),
};
/* Extension offsets */
enum ip_set_offset {
IPSET_OFFSET_TIMEOUT = 0,
IPSET_OFFSET_COUNTER,
IPSET_OFFSET_MAX,
};
#define SET_WITH_TIMEOUT(s) ((s)->extensions & IPSET_EXT_TIMEOUT)
#define SET_WITH_COUNTER(s) ((s)->extensions & IPSET_EXT_COUNTER)
struct ip_set_ext {
unsigned long timeout;
u64 packets;
u64 bytes;
};
struct ip_set; struct ip_set;
typedef int (*ipset_adtfn)(struct ip_set *set, void *value, typedef int (*ipset_adtfn)(struct ip_set *set, void *value,
u32 timeout, u32 flags); const struct ip_set_ext *ext,
struct ip_set_ext *mext, u32 cmdflags);
/* Kernel API function options */ /* Kernel API function options */
struct ip_set_adt_opt { struct ip_set_adt_opt {
...@@ -58,7 +84,7 @@ struct ip_set_adt_opt { ...@@ -58,7 +84,7 @@ struct ip_set_adt_opt {
u8 dim; /* Dimension of match/target */ u8 dim; /* Dimension of match/target */
u8 flags; /* Direction and negation flags */ u8 flags; /* Direction and negation flags */
u32 cmdflags; /* Command-like flags */ u32 cmdflags; /* Command-like flags */
u32 timeout; /* Timeout value */ struct ip_set_ext ext; /* Extensions */
}; };
/* Set type, variant-specific part */ /* Set type, variant-specific part */
...@@ -69,7 +95,7 @@ struct ip_set_type_variant { ...@@ -69,7 +95,7 @@ struct ip_set_type_variant {
* positive for matching element */ * positive for matching element */
int (*kadt)(struct ip_set *set, const struct sk_buff *skb, int (*kadt)(struct ip_set *set, const struct sk_buff *skb,
const struct xt_action_param *par, const struct xt_action_param *par,
enum ipset_adt adt, const struct ip_set_adt_opt *opt); enum ipset_adt adt, struct ip_set_adt_opt *opt);
/* Userspace: test/add/del entries /* Userspace: test/add/del entries
* returns negative error code, * returns negative error code,
...@@ -151,10 +177,76 @@ struct ip_set { ...@@ -151,10 +177,76 @@ struct ip_set {
u8 family; u8 family;
/* The type revision */ /* The type revision */
u8 revision; u8 revision;
/* Extensions */
u8 extensions;
/* The type specific data */ /* The type specific data */
void *data; void *data;
}; };
struct ip_set_counter {
atomic64_t bytes;
atomic64_t packets;
};
static inline void
ip_set_add_bytes(u64 bytes, struct ip_set_counter *counter)
{
atomic64_add((long long)bytes, &(counter)->bytes);
}
static inline void
ip_set_add_packets(u64 packets, struct ip_set_counter *counter)
{
atomic64_add((long long)packets, &(counter)->packets);
}
static inline u64
ip_set_get_bytes(const struct ip_set_counter *counter)
{
return (u64)atomic64_read(&(counter)->bytes);
}
static inline u64
ip_set_get_packets(const struct ip_set_counter *counter)
{
return (u64)atomic64_read(&(counter)->packets);
}
static inline void
ip_set_update_counter(struct ip_set_counter *counter,
const struct ip_set_ext *ext,
struct ip_set_ext *mext, u32 flags)
{
if (ext->packets != ULLONG_MAX &&
!(flags & IPSET_FLAG_SKIP_COUNTER_UPDATE)) {
ip_set_add_bytes(ext->bytes, counter);
ip_set_add_packets(ext->packets, counter);
}
if (flags & IPSET_FLAG_MATCH_COUNTERS) {
mext->packets = ip_set_get_packets(counter);
mext->bytes = ip_set_get_bytes(counter);
}
}
static inline bool
ip_set_put_counter(struct sk_buff *skb, struct ip_set_counter *counter)
{
return nla_put_net64(skb, IPSET_ATTR_BYTES,
cpu_to_be64(ip_set_get_bytes(counter))) ||
nla_put_net64(skb, IPSET_ATTR_PACKETS,
cpu_to_be64(ip_set_get_packets(counter)));
}
static inline void
ip_set_init_counter(struct ip_set_counter *counter,
const struct ip_set_ext *ext)
{
if (ext->bytes != ULLONG_MAX)
atomic64_set(&(counter)->bytes, (long long)(ext->bytes));
if (ext->packets != ULLONG_MAX)
atomic64_set(&(counter)->packets, (long long)(ext->packets));
}
/* register and unregister set references */ /* register and unregister set references */
extern ip_set_id_t ip_set_get_byname(const char *name, struct ip_set **set); extern ip_set_id_t ip_set_get_byname(const char *name, struct ip_set **set);
extern void ip_set_put_byindex(ip_set_id_t index); extern void ip_set_put_byindex(ip_set_id_t index);
...@@ -167,19 +259,21 @@ extern void ip_set_nfnl_put(ip_set_id_t index); ...@@ -167,19 +259,21 @@ extern void ip_set_nfnl_put(ip_set_id_t index);
extern int ip_set_add(ip_set_id_t id, const struct sk_buff *skb, extern int ip_set_add(ip_set_id_t id, const struct sk_buff *skb,
const struct xt_action_param *par, const struct xt_action_param *par,
const struct ip_set_adt_opt *opt); struct ip_set_adt_opt *opt);
extern int ip_set_del(ip_set_id_t id, const struct sk_buff *skb, extern int ip_set_del(ip_set_id_t id, const struct sk_buff *skb,
const struct xt_action_param *par, const struct xt_action_param *par,
const struct ip_set_adt_opt *opt); struct ip_set_adt_opt *opt);
extern int ip_set_test(ip_set_id_t id, const struct sk_buff *skb, extern int ip_set_test(ip_set_id_t id, const struct sk_buff *skb,
const struct xt_action_param *par, const struct xt_action_param *par,
const struct ip_set_adt_opt *opt); struct ip_set_adt_opt *opt);
/* Utility functions */ /* Utility functions */
extern void *ip_set_alloc(size_t size); extern void *ip_set_alloc(size_t size);
extern void ip_set_free(void *members); extern void ip_set_free(void *members);
extern int ip_set_get_ipaddr4(struct nlattr *nla, __be32 *ipaddr); extern int ip_set_get_ipaddr4(struct nlattr *nla, __be32 *ipaddr);
extern int ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr); extern int ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr);
extern int ip_set_get_extensions(struct ip_set *set, struct nlattr *tb[],
struct ip_set_ext *ext);
static inline int static inline int
ip_set_get_hostipaddr4(struct nlattr *nla, u32 *ipaddr) ip_set_get_hostipaddr4(struct nlattr *nla, u32 *ipaddr)
...@@ -200,6 +294,14 @@ ip_set_eexist(int ret, u32 flags) ...@@ -200,6 +294,14 @@ ip_set_eexist(int ret, u32 flags)
return ret == -IPSET_ERR_EXIST && (flags & IPSET_FLAG_EXIST); return ret == -IPSET_ERR_EXIST && (flags & IPSET_FLAG_EXIST);
} }
/* Match elements marked with nomatch */
static inline bool
ip_set_enomatch(int ret, u32 flags, enum ipset_adt adt)
{
return adt == IPSET_TEST &&
ret == -ENOTEMPTY && ((flags >> 16) & IPSET_FLAG_NOMATCH);
}
/* Check the NLA_F_NET_BYTEORDER flag */ /* Check the NLA_F_NET_BYTEORDER flag */
static inline bool static inline bool
ip_set_attr_netorder(struct nlattr *tb[], int type) ip_set_attr_netorder(struct nlattr *tb[], int type)
...@@ -284,4 +386,14 @@ bitmap_bytes(u32 a, u32 b) ...@@ -284,4 +386,14 @@ bitmap_bytes(u32 a, u32 b)
return 4 * ((((b - a + 8) / 8) + 3) / 4); return 4 * ((((b - a + 8) / 8) + 3) / 4);
} }
#include <linux/netfilter/ipset/ip_set_timeout.h>
#define IP_SET_INIT_KEXT(skb, opt, map) \
{ .bytes = (skb)->len, .packets = 1, \
.timeout = ip_set_adt_opt_timeout(opt, map) }
#define IP_SET_INIT_UEXT(map) \
{ .bytes = ULLONG_MAX, .packets = ULLONG_MAX, \
.timeout = (map)->timeout }
#endif /*_IP_SET_H */ #endif /*_IP_SET_H */
...@@ -5,6 +5,12 @@ ...@@ -5,6 +5,12 @@
#define IPSET_BITMAP_MAX_RANGE 0x0000FFFF #define IPSET_BITMAP_MAX_RANGE 0x0000FFFF
enum {
IPSET_ADD_FAILED = 1,
IPSET_ADD_STORE_PLAIN_TIMEOUT,
IPSET_ADD_START_STORED_TIMEOUT,
};
/* Common functions */ /* Common functions */
static inline u32 static inline u32
......
#ifndef _IP_SET_TIMEOUT_H #ifndef _IP_SET_TIMEOUT_H
#define _IP_SET_TIMEOUT_H #define _IP_SET_TIMEOUT_H
/* Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> /* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
...@@ -17,13 +17,14 @@ ...@@ -17,13 +17,14 @@
#define IPSET_GC_PERIOD(timeout) \ #define IPSET_GC_PERIOD(timeout) \
((timeout/3) ? min_t(u32, (timeout)/3, IPSET_GC_TIME) : 1) ((timeout/3) ? min_t(u32, (timeout)/3, IPSET_GC_TIME) : 1)
/* Set is defined without timeout support: timeout value may be 0 */ /* Entry is set with no timeout value */
#define IPSET_NO_TIMEOUT UINT_MAX #define IPSET_ELEM_PERMANENT 0
#define with_timeout(timeout) ((timeout) != IPSET_NO_TIMEOUT) /* Set is defined with timeout support: timeout value may be 0 */
#define IPSET_NO_TIMEOUT UINT_MAX
#define opt_timeout(opt, map) \ #define ip_set_adt_opt_timeout(opt, map) \
(with_timeout((opt)->timeout) ? (opt)->timeout : (map)->timeout) ((opt)->ext.timeout != IPSET_NO_TIMEOUT ? (opt)->ext.timeout : (map)->timeout)
static inline unsigned int static inline unsigned int
ip_set_timeout_uget(struct nlattr *tb) ip_set_timeout_uget(struct nlattr *tb)
...@@ -38,61 +39,6 @@ ip_set_timeout_uget(struct nlattr *tb) ...@@ -38,61 +39,6 @@ ip_set_timeout_uget(struct nlattr *tb)
return timeout == IPSET_NO_TIMEOUT ? IPSET_NO_TIMEOUT - 1 : timeout; return timeout == IPSET_NO_TIMEOUT ? IPSET_NO_TIMEOUT - 1 : timeout;
} }
#ifdef IP_SET_BITMAP_TIMEOUT
/* Bitmap specific timeout constants and macros for the entries */
/* Bitmap entry is unset */
#define IPSET_ELEM_UNSET 0
/* Bitmap entry is set with no timeout value */
#define IPSET_ELEM_PERMANENT (UINT_MAX/2)
static inline bool
ip_set_timeout_test(unsigned long timeout)
{
return timeout != IPSET_ELEM_UNSET &&
(timeout == IPSET_ELEM_PERMANENT ||
time_is_after_jiffies(timeout));
}
static inline bool
ip_set_timeout_expired(unsigned long timeout)
{
return timeout != IPSET_ELEM_UNSET &&
timeout != IPSET_ELEM_PERMANENT &&
time_is_before_jiffies(timeout);
}
static inline unsigned long
ip_set_timeout_set(u32 timeout)
{
unsigned long t;
if (!timeout)
return IPSET_ELEM_PERMANENT;
t = msecs_to_jiffies(timeout * 1000) + jiffies;
if (t == IPSET_ELEM_UNSET || t == IPSET_ELEM_PERMANENT)
/* Bingo! */
t++;
return t;
}
static inline u32
ip_set_timeout_get(unsigned long timeout)
{
return timeout == IPSET_ELEM_PERMANENT ? 0 :
jiffies_to_msecs(timeout - jiffies)/1000;
}
#else
/* Hash specific timeout constants and macros for the entries */
/* Hash entry is set with no timeout value */
#define IPSET_ELEM_PERMANENT 0
static inline bool static inline bool
ip_set_timeout_test(unsigned long timeout) ip_set_timeout_test(unsigned long timeout)
{ {
...@@ -101,36 +47,32 @@ ip_set_timeout_test(unsigned long timeout) ...@@ -101,36 +47,32 @@ ip_set_timeout_test(unsigned long timeout)
} }
static inline bool static inline bool
ip_set_timeout_expired(unsigned long timeout) ip_set_timeout_expired(unsigned long *timeout)
{ {
return timeout != IPSET_ELEM_PERMANENT && return *timeout != IPSET_ELEM_PERMANENT &&
time_is_before_jiffies(timeout); time_is_before_jiffies(*timeout);
} }
static inline unsigned long static inline void
ip_set_timeout_set(u32 timeout) ip_set_timeout_set(unsigned long *timeout, u32 t)
{ {
unsigned long t; if (!t) {
*timeout = IPSET_ELEM_PERMANENT;
if (!timeout) return;
return IPSET_ELEM_PERMANENT; }
t = msecs_to_jiffies(timeout * 1000) + jiffies; *timeout = msecs_to_jiffies(t * 1000) + jiffies;
if (t == IPSET_ELEM_PERMANENT) if (*timeout == IPSET_ELEM_PERMANENT)
/* Bingo! :-) */ /* Bingo! :-) */
t++; (*timeout)--;
return t;
} }
static inline u32 static inline u32
ip_set_timeout_get(unsigned long timeout) ip_set_timeout_get(unsigned long *timeout)
{ {
return timeout == IPSET_ELEM_PERMANENT ? 0 : return *timeout == IPSET_ELEM_PERMANENT ? 0 :
jiffies_to_msecs(timeout - jiffies)/1000; jiffies_to_msecs(*timeout - jiffies)/1000;
} }
#endif /* ! IP_SET_BITMAP_TIMEOUT */
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* _IP_SET_TIMEOUT_H */ #endif /* _IP_SET_TIMEOUT_H */
...@@ -41,4 +41,13 @@ do { \ ...@@ -41,4 +41,13 @@ do { \
to = from | ~ip_set_hostmask(cidr); \ to = from | ~ip_set_hostmask(cidr); \
} while (0) } while (0)
static inline void
ip6_netmask(union nf_inet_addr *ip, u8 prefix)
{
ip->ip6[0] &= ip_set_netmask6(prefix)[0];
ip->ip6[1] &= ip_set_netmask6(prefix)[1];
ip->ip6[2] &= ip_set_netmask6(prefix)[2];
ip->ip6[3] &= ip_set_netmask6(prefix)[3];
}
#endif /*_PFXLEN_H */ #endif /*_PFXLEN_H */
...@@ -9,10 +9,13 @@ struct nf_queue_entry { ...@@ -9,10 +9,13 @@ struct nf_queue_entry {
struct nf_hook_ops *elem; struct nf_hook_ops *elem;
u_int8_t pf; u_int8_t pf;
u16 size; /* sizeof(entry) + saved route keys */
unsigned int hook; unsigned int hook;
struct net_device *indev; struct net_device *indev;
struct net_device *outdev; struct net_device *outdev;
int (*okfn)(struct sk_buff *); int (*okfn)(struct sk_buff *);
/* extra space to store route keys */
}; };
#define nf_queue_entry_reroute(x) ((void *)x + sizeof(struct nf_queue_entry)) #define nf_queue_entry_reroute(x) ((void *)x + sizeof(struct nf_queue_entry))
...@@ -27,4 +30,7 @@ void nf_register_queue_handler(const struct nf_queue_handler *qh); ...@@ -27,4 +30,7 @@ void nf_register_queue_handler(const struct nf_queue_handler *qh);
void nf_unregister_queue_handler(void); void nf_unregister_queue_handler(void);
extern void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict); extern void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict);
bool nf_queue_entry_get_refs(struct nf_queue_entry *entry);
void nf_queue_entry_release_refs(struct nf_queue_entry *entry);
#endif /* _NF_QUEUE_H */ #endif /* _NF_QUEUE_H */
...@@ -77,7 +77,7 @@ static inline __u32 sctp_update_cksum(__u8 *buffer, __u16 length, __u32 crc32) ...@@ -77,7 +77,7 @@ static inline __u32 sctp_update_cksum(__u8 *buffer, __u16 length, __u32 crc32)
return sctp_crc32c(crc32, buffer, length); return sctp_crc32c(crc32, buffer, length);
} }
static inline __le32 sctp_end_cksum(__be32 crc32) static inline __le32 sctp_end_cksum(__u32 crc32)
{ {
return cpu_to_le32(~crc32); return cpu_to_le32(~crc32);
} }
...@@ -108,6 +108,8 @@ enum { ...@@ -108,6 +108,8 @@ enum {
IPSET_ATTR_CIDR2, IPSET_ATTR_CIDR2,
IPSET_ATTR_IP2_TO, IPSET_ATTR_IP2_TO,
IPSET_ATTR_IFACE, IPSET_ATTR_IFACE,
IPSET_ATTR_BYTES,
IPSET_ATTR_PACKETS,
__IPSET_ATTR_ADT_MAX, __IPSET_ATTR_ADT_MAX,
}; };
#define IPSET_ATTR_ADT_MAX (__IPSET_ATTR_ADT_MAX - 1) #define IPSET_ATTR_ADT_MAX (__IPSET_ATTR_ADT_MAX - 1)
...@@ -137,12 +139,13 @@ enum ipset_errno { ...@@ -137,12 +139,13 @@ enum ipset_errno {
IPSET_ERR_REFERENCED, IPSET_ERR_REFERENCED,
IPSET_ERR_IPADDR_IPV4, IPSET_ERR_IPADDR_IPV4,
IPSET_ERR_IPADDR_IPV6, IPSET_ERR_IPADDR_IPV6,
IPSET_ERR_COUNTER,
/* Type specific error codes */ /* Type specific error codes */
IPSET_ERR_TYPE_SPECIFIC = 4352, IPSET_ERR_TYPE_SPECIFIC = 4352,
}; };
/* Flags at command level */ /* Flags at command level or match/target flags, lower half of cmdattrs*/
enum ipset_cmd_flags { enum ipset_cmd_flags {
IPSET_FLAG_BIT_EXIST = 0, IPSET_FLAG_BIT_EXIST = 0,
IPSET_FLAG_EXIST = (1 << IPSET_FLAG_BIT_EXIST), IPSET_FLAG_EXIST = (1 << IPSET_FLAG_BIT_EXIST),
...@@ -150,10 +153,20 @@ enum ipset_cmd_flags { ...@@ -150,10 +153,20 @@ enum ipset_cmd_flags {
IPSET_FLAG_LIST_SETNAME = (1 << IPSET_FLAG_BIT_LIST_SETNAME), IPSET_FLAG_LIST_SETNAME = (1 << IPSET_FLAG_BIT_LIST_SETNAME),
IPSET_FLAG_BIT_LIST_HEADER = 2, IPSET_FLAG_BIT_LIST_HEADER = 2,
IPSET_FLAG_LIST_HEADER = (1 << IPSET_FLAG_BIT_LIST_HEADER), IPSET_FLAG_LIST_HEADER = (1 << IPSET_FLAG_BIT_LIST_HEADER),
IPSET_FLAG_CMD_MAX = 15, /* Lower half */ IPSET_FLAG_BIT_SKIP_COUNTER_UPDATE = 3,
IPSET_FLAG_SKIP_COUNTER_UPDATE =
(1 << IPSET_FLAG_BIT_SKIP_COUNTER_UPDATE),
IPSET_FLAG_BIT_SKIP_SUBCOUNTER_UPDATE = 4,
IPSET_FLAG_SKIP_SUBCOUNTER_UPDATE =
(1 << IPSET_FLAG_BIT_SKIP_SUBCOUNTER_UPDATE),
IPSET_FLAG_BIT_MATCH_COUNTERS = 5,
IPSET_FLAG_MATCH_COUNTERS = (1 << IPSET_FLAG_BIT_MATCH_COUNTERS),
IPSET_FLAG_BIT_RETURN_NOMATCH = 7,
IPSET_FLAG_RETURN_NOMATCH = (1 << IPSET_FLAG_BIT_RETURN_NOMATCH),
IPSET_FLAG_CMD_MAX = 15,
}; };
/* Flags at CADT attribute level */ /* Flags at CADT attribute level, upper half of cmdattrs */
enum ipset_cadt_flags { enum ipset_cadt_flags {
IPSET_FLAG_BIT_BEFORE = 0, IPSET_FLAG_BIT_BEFORE = 0,
IPSET_FLAG_BEFORE = (1 << IPSET_FLAG_BIT_BEFORE), IPSET_FLAG_BEFORE = (1 << IPSET_FLAG_BIT_BEFORE),
...@@ -161,7 +174,9 @@ enum ipset_cadt_flags { ...@@ -161,7 +174,9 @@ enum ipset_cadt_flags {
IPSET_FLAG_PHYSDEV = (1 << IPSET_FLAG_BIT_PHYSDEV), IPSET_FLAG_PHYSDEV = (1 << IPSET_FLAG_BIT_PHYSDEV),
IPSET_FLAG_BIT_NOMATCH = 2, IPSET_FLAG_BIT_NOMATCH = 2,
IPSET_FLAG_NOMATCH = (1 << IPSET_FLAG_BIT_NOMATCH), IPSET_FLAG_NOMATCH = (1 << IPSET_FLAG_BIT_NOMATCH),
IPSET_FLAG_CADT_MAX = 15, /* Upper half */ IPSET_FLAG_BIT_WITH_COUNTERS = 3,
IPSET_FLAG_WITH_COUNTERS = (1 << IPSET_FLAG_BIT_WITH_COUNTERS),
IPSET_FLAG_CADT_MAX = 15,
}; };
/* Commands with settype-specific attributes */ /* Commands with settype-specific attributes */
...@@ -190,6 +205,7 @@ enum ip_set_dim { ...@@ -190,6 +205,7 @@ enum ip_set_dim {
* If changed, new revision of iptables match/target is required. * If changed, new revision of iptables match/target is required.
*/ */
IPSET_DIM_MAX = 6, IPSET_DIM_MAX = 6,
/* Backward compatibility: set match revision 2 */
IPSET_BIT_RETURN_NOMATCH = 7, IPSET_BIT_RETURN_NOMATCH = 7,
}; };
...@@ -202,6 +218,18 @@ enum ip_set_kopt { ...@@ -202,6 +218,18 @@ enum ip_set_kopt {
IPSET_RETURN_NOMATCH = (1 << IPSET_BIT_RETURN_NOMATCH), IPSET_RETURN_NOMATCH = (1 << IPSET_BIT_RETURN_NOMATCH),
}; };
enum {
IPSET_COUNTER_NONE = 0,
IPSET_COUNTER_EQ,
IPSET_COUNTER_NE,
IPSET_COUNTER_LT,
IPSET_COUNTER_GT,
};
struct ip_set_counter_match {
__u8 op;
__u64 value;
};
/* Interface to iptables/ip6tables */ /* Interface to iptables/ip6tables */
......
...@@ -45,6 +45,7 @@ enum nfqnl_attr_type { ...@@ -45,6 +45,7 @@ enum nfqnl_attr_type {
NFQA_CT, /* nf_conntrack_netlink.h */ NFQA_CT, /* nf_conntrack_netlink.h */
NFQA_CT_INFO, /* enum ip_conntrack_info */ NFQA_CT_INFO, /* enum ip_conntrack_info */
NFQA_CAP_LEN, /* __u32 length of captured packet */ NFQA_CAP_LEN, /* __u32 length of captured packet */
NFQA_SKB_INFO, /* __u32 skb meta information */
__NFQA_MAX __NFQA_MAX
}; };
...@@ -96,6 +97,13 @@ enum nfqnl_attr_config { ...@@ -96,6 +97,13 @@ enum nfqnl_attr_config {
/* Flags for NFQA_CFG_FLAGS */ /* Flags for NFQA_CFG_FLAGS */
#define NFQA_CFG_F_FAIL_OPEN (1 << 0) #define NFQA_CFG_F_FAIL_OPEN (1 << 0)
#define NFQA_CFG_F_CONNTRACK (1 << 1) #define NFQA_CFG_F_CONNTRACK (1 << 1)
#define NFQA_CFG_F_MAX (1 << 2) #define NFQA_CFG_F_GSO (1 << 2)
#define NFQA_CFG_F_MAX (1 << 3)
/* flags for NFQA_SKB_INFO */
/* packet appears to have wrong checksums, but they are ok */
#define NFQA_SKB_CSUMNOTREADY (1 << 0)
/* packet is GSO (i.e., exceeds device mtu) */
#define NFQA_SKB_GSO (1 << 1)
#endif /* _NFNETLINK_QUEUE_H */ #endif /* _NFNETLINK_QUEUE_H */
...@@ -62,4 +62,13 @@ struct xt_set_info_target_v2 { ...@@ -62,4 +62,13 @@ struct xt_set_info_target_v2 {
__u32 timeout; __u32 timeout;
}; };
/* Revision 3 match */
struct xt_set_info_match_v3 {
struct xt_set_info match_set;
struct ip_set_counter_match packets;
struct ip_set_counter_match bytes;
__u32 flags;
};
#endif /*_XT_SET_H*/ #endif /*_XT_SET_H*/
/* Copyright (C) 2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __IP_SET_BITMAP_IP_GEN_H
#define __IP_SET_BITMAP_IP_GEN_H
#define CONCAT(a, b) a##b
#define TOKEN(a,b) CONCAT(a, b)
#define mtype_do_test TOKEN(MTYPE, _do_test)
#define mtype_gc_test TOKEN(MTYPE, _gc_test)
#define mtype_is_filled TOKEN(MTYPE, _is_filled)
#define mtype_do_add TOKEN(MTYPE, _do_add)
#define mtype_do_del TOKEN(MTYPE, _do_del)
#define mtype_do_list TOKEN(MTYPE, _do_list)
#define mtype_do_head TOKEN(MTYPE, _do_head)
#define mtype_adt_elem TOKEN(MTYPE, _adt_elem)
#define mtype_add_timeout TOKEN(MTYPE, _add_timeout)
#define mtype_gc_init TOKEN(MTYPE, _gc_init)
#define mtype_kadt TOKEN(MTYPE, _kadt)
#define mtype_uadt TOKEN(MTYPE, _uadt)
#define mtype_destroy TOKEN(MTYPE, _destroy)
#define mtype_flush TOKEN(MTYPE, _flush)
#define mtype_head TOKEN(MTYPE, _head)
#define mtype_same_set TOKEN(MTYPE, _same_set)
#define mtype_elem TOKEN(MTYPE, _elem)
#define mtype_test TOKEN(MTYPE, _test)
#define mtype_add TOKEN(MTYPE, _add)
#define mtype_del TOKEN(MTYPE, _del)
#define mtype_list TOKEN(MTYPE, _list)
#define mtype_gc TOKEN(MTYPE, _gc)
#define mtype MTYPE
#define ext_timeout(e, m) \
(unsigned long *)((e) + (m)->offset[IPSET_OFFSET_TIMEOUT])
#define ext_counter(e, m) \
(struct ip_set_counter *)((e) + (m)->offset[IPSET_OFFSET_COUNTER])
#define get_ext(map, id) ((map)->extensions + (map)->dsize * (id))
static void
mtype_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set))
{
struct mtype *map = set->data;
init_timer(&map->gc);
map->gc.data = (unsigned long) set;
map->gc.function = gc;
map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
add_timer(&map->gc);
}
static void
mtype_destroy(struct ip_set *set)
{
struct mtype *map = set->data;
if (SET_WITH_TIMEOUT(set))
del_timer_sync(&map->gc);
ip_set_free(map->members);
if (map->dsize)
ip_set_free(map->extensions);
kfree(map);
set->data = NULL;
}
static void
mtype_flush(struct ip_set *set)
{
struct mtype *map = set->data;
memset(map->members, 0, map->memsize);
}
static int
mtype_head(struct ip_set *set, struct sk_buff *skb)
{
const struct mtype *map = set->data;
struct nlattr *nested;
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
if (!nested)
goto nla_put_failure;
if (mtype_do_head(skb, map) ||
nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) ||
nla_put_net32(skb, IPSET_ATTR_MEMSIZE,
htonl(sizeof(*map) +
map->memsize +
map->dsize * map->elements)) ||
(SET_WITH_TIMEOUT(set) &&
nla_put_net32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout))) ||
(SET_WITH_COUNTER(set) &&
nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS,
htonl(IPSET_FLAG_WITH_COUNTERS))))
goto nla_put_failure;
ipset_nest_end(skb, nested);
return 0;
nla_put_failure:
return -EMSGSIZE;
}
static int
mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext,
struct ip_set_ext *mext, u32 flags)
{
struct mtype *map = set->data;
const struct mtype_adt_elem *e = value;
void *x = get_ext(map, e->id);
int ret = mtype_do_test(e, map);
if (ret <= 0)
return ret;
if (SET_WITH_TIMEOUT(set) &&
ip_set_timeout_expired(ext_timeout(x, map)))
return 0;
if (SET_WITH_COUNTER(set))
ip_set_update_counter(ext_counter(x, map), ext, mext, flags);
return 1;
}
static int
mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
struct ip_set_ext *mext, u32 flags)
{
struct mtype *map = set->data;
const struct mtype_adt_elem *e = value;
void *x = get_ext(map, e->id);
int ret = mtype_do_add(e, map, flags);
if (ret == IPSET_ADD_FAILED) {
if (SET_WITH_TIMEOUT(set) &&
ip_set_timeout_expired(ext_timeout(x, map)))
ret = 0;
else if (!(flags & IPSET_FLAG_EXIST))
return -IPSET_ERR_EXIST;
}
if (SET_WITH_TIMEOUT(set))
#ifdef IP_SET_BITMAP_STORED_TIMEOUT
mtype_add_timeout(ext_timeout(x, map), e, ext, map, ret);
#else
ip_set_timeout_set(ext_timeout(x, map), ext->timeout);
#endif
if (SET_WITH_COUNTER(set))
ip_set_init_counter(ext_counter(x, map), ext);
return 0;
}
static int
mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,
struct ip_set_ext *mext, u32 flags)
{
struct mtype *map = set->data;
const struct mtype_adt_elem *e = value;
const void *x = get_ext(map, e->id);
if (mtype_do_del(e, map) ||
(SET_WITH_TIMEOUT(set) &&
ip_set_timeout_expired(ext_timeout(x, map))))
return -IPSET_ERR_EXIST;
return 0;
}
static int
mtype_list(const struct ip_set *set,
struct sk_buff *skb, struct netlink_callback *cb)
{
struct mtype *map = set->data;
struct nlattr *adt, *nested;
void *x;
u32 id, first = cb->args[2];
adt = ipset_nest_start(skb, IPSET_ATTR_ADT);
if (!adt)
return -EMSGSIZE;
for (; cb->args[2] < map->elements; cb->args[2]++) {
id = cb->args[2];
x = get_ext(map, id);
if (!test_bit(id, map->members) ||
(SET_WITH_TIMEOUT(set) &&
#ifdef IP_SET_BITMAP_STORED_TIMEOUT
mtype_is_filled((const struct mtype_elem *) x) &&
#endif
ip_set_timeout_expired(ext_timeout(x, map))))
continue;
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
if (!nested) {
if (id == first) {
nla_nest_cancel(skb, adt);
return -EMSGSIZE;
} else
goto nla_put_failure;
}
if (mtype_do_list(skb, map, id))
goto nla_put_failure;
if (SET_WITH_TIMEOUT(set)) {
#ifdef IP_SET_BITMAP_STORED_TIMEOUT
if (nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
htonl(ip_set_timeout_stored(map, id,
ext_timeout(x, map)))))
goto nla_put_failure;
#else
if (nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
htonl(ip_set_timeout_get(
ext_timeout(x, map)))))
goto nla_put_failure;
#endif
}
if (SET_WITH_COUNTER(set) &&
ip_set_put_counter(skb, ext_counter(x, map)))
goto nla_put_failure;
ipset_nest_end(skb, nested);
}
ipset_nest_end(skb, adt);
/* Set listing finished */
cb->args[2] = 0;
return 0;
nla_put_failure:
nla_nest_cancel(skb, nested);
ipset_nest_end(skb, adt);
if (unlikely(id == first)) {
cb->args[2] = 0;
return -EMSGSIZE;
}
return 0;
}
static void
mtype_gc(unsigned long ul_set)
{
struct ip_set *set = (struct ip_set *) ul_set;
struct mtype *map = set->data;
const void *x;
u32 id;
/* We run parallel with other readers (test element)
* but adding/deleting new entries is locked out */
read_lock_bh(&set->lock);
for (id = 0; id < map->elements; id++)
if (mtype_gc_test(id, map)) {
x = get_ext(map, id);
if (ip_set_timeout_expired(ext_timeout(x, map)))
clear_bit(id, map->members);
}
read_unlock_bh(&set->lock);
map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
add_timer(&map->gc);
}
static const struct ip_set_type_variant mtype = {
.kadt = mtype_kadt,
.uadt = mtype_uadt,
.adt = {
[IPSET_ADD] = mtype_add,
[IPSET_DEL] = mtype_del,
[IPSET_TEST] = mtype_test,
},
.destroy = mtype_destroy,
.flush = mtype_flush,
.head = mtype_head,
.list = mtype_list,
.same_set = mtype_same_set,
};
#endif /* __IP_SET_BITMAP_IP_GEN_H */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu> /* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
* Patrick Schaaf <bof@bof.de> * Patrick Schaaf <bof@bof.de>
* Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> * Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
...@@ -315,6 +315,29 @@ ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr) ...@@ -315,6 +315,29 @@ ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr)
} }
EXPORT_SYMBOL_GPL(ip_set_get_ipaddr6); EXPORT_SYMBOL_GPL(ip_set_get_ipaddr6);
int
ip_set_get_extensions(struct ip_set *set, struct nlattr *tb[],
struct ip_set_ext *ext)
{
if (tb[IPSET_ATTR_TIMEOUT]) {
if (!(set->extensions & IPSET_EXT_TIMEOUT))
return -IPSET_ERR_TIMEOUT;
ext->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
}
if (tb[IPSET_ATTR_BYTES] || tb[IPSET_ATTR_PACKETS]) {
if (!(set->extensions & IPSET_EXT_COUNTER))
return -IPSET_ERR_COUNTER;
if (tb[IPSET_ATTR_BYTES])
ext->bytes = be64_to_cpu(nla_get_be64(
tb[IPSET_ATTR_BYTES]));
if (tb[IPSET_ATTR_PACKETS])
ext->packets = be64_to_cpu(nla_get_be64(
tb[IPSET_ATTR_PACKETS]));
}
return 0;
}
EXPORT_SYMBOL_GPL(ip_set_get_extensions);
/* /*
* Creating/destroying/renaming/swapping affect the existence and * Creating/destroying/renaming/swapping affect the existence and
* the properties of a set. All of these can be executed from userspace * the properties of a set. All of these can be executed from userspace
...@@ -365,8 +388,7 @@ ip_set_rcu_get(ip_set_id_t index) ...@@ -365,8 +388,7 @@ ip_set_rcu_get(ip_set_id_t index)
int int
ip_set_test(ip_set_id_t index, const struct sk_buff *skb, ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
const struct xt_action_param *par, const struct xt_action_param *par, struct ip_set_adt_opt *opt)
const struct ip_set_adt_opt *opt)
{ {
struct ip_set *set = ip_set_rcu_get(index); struct ip_set *set = ip_set_rcu_get(index);
int ret = 0; int ret = 0;
...@@ -391,7 +413,7 @@ ip_set_test(ip_set_id_t index, const struct sk_buff *skb, ...@@ -391,7 +413,7 @@ ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
ret = 1; ret = 1;
} else { } else {
/* --return-nomatch: invert matched element */ /* --return-nomatch: invert matched element */
if ((opt->flags & IPSET_RETURN_NOMATCH) && if ((opt->cmdflags & IPSET_FLAG_RETURN_NOMATCH) &&
(set->type->features & IPSET_TYPE_NOMATCH) && (set->type->features & IPSET_TYPE_NOMATCH) &&
(ret > 0 || ret == -ENOTEMPTY)) (ret > 0 || ret == -ENOTEMPTY))
ret = -ret; ret = -ret;
...@@ -404,8 +426,7 @@ EXPORT_SYMBOL_GPL(ip_set_test); ...@@ -404,8 +426,7 @@ EXPORT_SYMBOL_GPL(ip_set_test);
int int
ip_set_add(ip_set_id_t index, const struct sk_buff *skb, ip_set_add(ip_set_id_t index, const struct sk_buff *skb,
const struct xt_action_param *par, const struct xt_action_param *par, struct ip_set_adt_opt *opt)
const struct ip_set_adt_opt *opt)
{ {
struct ip_set *set = ip_set_rcu_get(index); struct ip_set *set = ip_set_rcu_get(index);
int ret; int ret;
...@@ -427,8 +448,7 @@ EXPORT_SYMBOL_GPL(ip_set_add); ...@@ -427,8 +448,7 @@ EXPORT_SYMBOL_GPL(ip_set_add);
int int
ip_set_del(ip_set_id_t index, const struct sk_buff *skb, ip_set_del(ip_set_id_t index, const struct sk_buff *skb,
const struct xt_action_param *par, const struct xt_action_param *par, struct ip_set_adt_opt *opt)
const struct ip_set_adt_opt *opt)
{ {
struct ip_set *set = ip_set_rcu_get(index); struct ip_set *set = ip_set_rcu_get(index);
int ret = 0; int ret = 0;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -36,7 +36,7 @@ sctp_manip_pkt(struct sk_buff *skb, ...@@ -36,7 +36,7 @@ sctp_manip_pkt(struct sk_buff *skb,
{ {
struct sk_buff *frag; struct sk_buff *frag;
sctp_sctphdr_t *hdr; sctp_sctphdr_t *hdr;
__be32 crc32; __u32 crc32;
if (!skb_make_writable(skb, hdroff + sizeof(*hdr))) if (!skb_make_writable(skb, hdroff + sizeof(*hdr)))
return false; return false;
...@@ -55,8 +55,7 @@ sctp_manip_pkt(struct sk_buff *skb, ...@@ -55,8 +55,7 @@ sctp_manip_pkt(struct sk_buff *skb,
skb_walk_frags(skb, frag) skb_walk_frags(skb, frag)
crc32 = sctp_update_cksum((u8 *)frag->data, skb_headlen(frag), crc32 = sctp_update_cksum((u8 *)frag->data, skb_headlen(frag),
crc32); crc32);
crc32 = sctp_end_cksum(crc32); hdr->checksum = sctp_end_cksum(crc32);
hdr->checksum = crc32;
return true; return true;
} }
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -83,7 +83,7 @@ static int em_ipset_match(struct sk_buff *skb, struct tcf_ematch *em, ...@@ -83,7 +83,7 @@ static int em_ipset_match(struct sk_buff *skb, struct tcf_ematch *em,
opt.dim = set->dim; opt.dim = set->dim;
opt.flags = set->flags; opt.flags = set->flags;
opt.cmdflags = 0; opt.cmdflags = 0;
opt.timeout = ~0u; opt.ext.timeout = ~0u;
network_offset = skb_network_offset(skb); network_offset = skb_network_offset(skb);
skb_pull(skb, network_offset); skb_pull(skb, network_offset);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment