Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/kaber/nf-next-2.6
Conflicts: Documentation/feature-removal-schedule.txt
This commit is contained in:
@@ -649,6 +649,17 @@ config NETFILTER_XT_TARGET_TCPOPTSTRIP
|
||||
|
||||
comment "Xtables matches"
|
||||
|
||||
config NETFILTER_XT_MATCH_ADDRTYPE
|
||||
tristate '"addrtype" address type match support'
|
||||
depends on NETFILTER_ADVANCED
|
||||
depends on (IPV6 || IPV6=n)
|
||||
---help---
|
||||
This option allows you to match what routing thinks of an address,
|
||||
eg. UNICAST, LOCAL, BROADCAST, ...
|
||||
|
||||
If you want to compile it as a module, say M here and read
|
||||
<file:Documentation/kbuild/modules.txt>. If unsure, say `N'.
|
||||
|
||||
config NETFILTER_XT_MATCH_CLUSTER
|
||||
tristate '"cluster" match support'
|
||||
depends on NF_CONNTRACK
|
||||
|
@@ -70,6 +70,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_TRACE) += xt_TRACE.o
|
||||
obj-$(CONFIG_NETFILTER_XT_TARGET_IDLETIMER) += xt_IDLETIMER.o
|
||||
|
||||
# matches
|
||||
obj-$(CONFIG_NETFILTER_XT_MATCH_ADDRTYPE) += xt_addrtype.o
|
||||
obj-$(CONFIG_NETFILTER_XT_MATCH_CLUSTER) += xt_cluster.o
|
||||
obj-$(CONFIG_NETFILTER_XT_MATCH_COMMENT) += xt_comment.o
|
||||
obj-$(CONFIG_NETFILTER_XT_MATCH_CONNBYTES) += xt_connbytes.o
|
||||
|
@@ -612,7 +612,7 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,
|
||||
const struct nlmsghdr *nlh,
|
||||
const struct nlattr * const attr[])
|
||||
{
|
||||
struct ip_set *set, *clash;
|
||||
struct ip_set *set, *clash = NULL;
|
||||
ip_set_id_t index = IPSET_INVALID_ID;
|
||||
struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1] = {};
|
||||
const char *name, *typename;
|
||||
|
@@ -680,6 +680,16 @@ static inline void ip_vs_unbind_dest(struct ip_vs_conn *cp)
|
||||
atomic_dec(&dest->refcnt);
|
||||
}
|
||||
|
||||
static int expire_quiescent_template(struct netns_ipvs *ipvs,
|
||||
struct ip_vs_dest *dest)
|
||||
{
|
||||
#ifdef CONFIG_SYSCTL
|
||||
return ipvs->sysctl_expire_quiescent_template &&
|
||||
(atomic_read(&dest->weight) == 0);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Checking if the destination of a connection template is available.
|
||||
@@ -696,8 +706,7 @@ int ip_vs_check_template(struct ip_vs_conn *ct)
|
||||
*/
|
||||
if ((dest == NULL) ||
|
||||
!(dest->flags & IP_VS_DEST_F_AVAILABLE) ||
|
||||
(ipvs->sysctl_expire_quiescent_template &&
|
||||
(atomic_read(&dest->weight) == 0))) {
|
||||
expire_quiescent_template(ipvs, dest)) {
|
||||
IP_VS_DBG_BUF(9, "check_template: dest not available for "
|
||||
"protocol %s s:%s:%d v:%s:%d "
|
||||
"-> d:%s:%d\n",
|
||||
|
@@ -132,7 +132,7 @@ ip_vs_in_stats(struct ip_vs_conn *cp, struct sk_buff *skb)
|
||||
s->ustats.inbytes += skb->len;
|
||||
u64_stats_update_end(&s->syncp);
|
||||
|
||||
s = this_cpu_ptr(ipvs->cpustats);
|
||||
s = this_cpu_ptr(ipvs->tot_stats.cpustats);
|
||||
s->ustats.inpkts++;
|
||||
u64_stats_update_begin(&s->syncp);
|
||||
s->ustats.inbytes += skb->len;
|
||||
@@ -162,7 +162,7 @@ ip_vs_out_stats(struct ip_vs_conn *cp, struct sk_buff *skb)
|
||||
s->ustats.outbytes += skb->len;
|
||||
u64_stats_update_end(&s->syncp);
|
||||
|
||||
s = this_cpu_ptr(ipvs->cpustats);
|
||||
s = this_cpu_ptr(ipvs->tot_stats.cpustats);
|
||||
s->ustats.outpkts++;
|
||||
u64_stats_update_begin(&s->syncp);
|
||||
s->ustats.outbytes += skb->len;
|
||||
@@ -183,7 +183,7 @@ ip_vs_conn_stats(struct ip_vs_conn *cp, struct ip_vs_service *svc)
|
||||
s = this_cpu_ptr(svc->stats.cpustats);
|
||||
s->ustats.conns++;
|
||||
|
||||
s = this_cpu_ptr(ipvs->cpustats);
|
||||
s = this_cpu_ptr(ipvs->tot_stats.cpustats);
|
||||
s->ustats.conns++;
|
||||
}
|
||||
|
||||
@@ -499,11 +499,13 @@ ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb,
|
||||
int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
|
||||
struct ip_vs_proto_data *pd)
|
||||
{
|
||||
struct net *net;
|
||||
struct netns_ipvs *ipvs;
|
||||
__be16 _ports[2], *pptr;
|
||||
struct ip_vs_iphdr iph;
|
||||
#ifdef CONFIG_SYSCTL
|
||||
struct net *net;
|
||||
struct netns_ipvs *ipvs;
|
||||
int unicast;
|
||||
#endif
|
||||
|
||||
ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph);
|
||||
|
||||
@@ -512,6 +514,8 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
|
||||
ip_vs_service_put(svc);
|
||||
return NF_DROP;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
net = skb_net(skb);
|
||||
|
||||
#ifdef CONFIG_IP_VS_IPV6
|
||||
@@ -563,6 +567,7 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
|
||||
ip_vs_conn_put(cp);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* When the virtual ftp service is presented, packets destined
|
||||
@@ -599,6 +604,33 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
|
||||
return NF_DROP;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
|
||||
static int sysctl_snat_reroute(struct sk_buff *skb)
|
||||
{
|
||||
struct netns_ipvs *ipvs = net_ipvs(skb_net(skb));
|
||||
return ipvs->sysctl_snat_reroute;
|
||||
}
|
||||
|
||||
static int sysctl_nat_icmp_send(struct net *net)
|
||||
{
|
||||
struct netns_ipvs *ipvs = net_ipvs(net);
|
||||
return ipvs->sysctl_nat_icmp_send;
|
||||
}
|
||||
|
||||
static int sysctl_expire_nodest_conn(struct netns_ipvs *ipvs)
|
||||
{
|
||||
return ipvs->sysctl_expire_nodest_conn;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int sysctl_snat_reroute(struct sk_buff *skb) { return 0; }
|
||||
static int sysctl_nat_icmp_send(struct net *net) { return 0; }
|
||||
static int sysctl_expire_nodest_conn(struct netns_ipvs *ipvs) { return 0; }
|
||||
|
||||
#endif
|
||||
|
||||
__sum16 ip_vs_checksum_complete(struct sk_buff *skb, int offset)
|
||||
{
|
||||
return csum_fold(skb_checksum(skb, offset, skb->len - offset, 0));
|
||||
@@ -631,6 +663,22 @@ static inline int ip_vs_gather_frags_v6(struct sk_buff *skb, u_int32_t user)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int ip_vs_route_me_harder(int af, struct sk_buff *skb)
|
||||
{
|
||||
#ifdef CONFIG_IP_VS_IPV6
|
||||
if (af == AF_INET6) {
|
||||
if (sysctl_snat_reroute(skb) && ip6_route_me_harder(skb) != 0)
|
||||
return 1;
|
||||
} else
|
||||
#endif
|
||||
if ((sysctl_snat_reroute(skb) ||
|
||||
skb_rtable(skb)->rt_flags & RTCF_LOCAL) &&
|
||||
ip_route_me_harder(skb, RTN_LOCAL) != 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Packet has been made sufficiently writable in caller
|
||||
* - inout: 1=in->out, 0=out->in
|
||||
@@ -737,7 +785,6 @@ static int handle_response_icmp(int af, struct sk_buff *skb,
|
||||
struct ip_vs_protocol *pp,
|
||||
unsigned int offset, unsigned int ihl)
|
||||
{
|
||||
struct netns_ipvs *ipvs;
|
||||
unsigned int verdict = NF_DROP;
|
||||
|
||||
if (IP_VS_FWD_METHOD(cp) != 0) {
|
||||
@@ -759,8 +806,6 @@ static int handle_response_icmp(int af, struct sk_buff *skb,
|
||||
if (!skb_make_writable(skb, offset))
|
||||
goto out;
|
||||
|
||||
ipvs = net_ipvs(skb_net(skb));
|
||||
|
||||
#ifdef CONFIG_IP_VS_IPV6
|
||||
if (af == AF_INET6)
|
||||
ip_vs_nat_icmp_v6(skb, pp, cp, 1);
|
||||
@@ -768,16 +813,8 @@ static int handle_response_icmp(int af, struct sk_buff *skb,
|
||||
#endif
|
||||
ip_vs_nat_icmp(skb, pp, cp, 1);
|
||||
|
||||
#ifdef CONFIG_IP_VS_IPV6
|
||||
if (af == AF_INET6) {
|
||||
if (ipvs->sysctl_snat_reroute && ip6_route_me_harder(skb) != 0)
|
||||
goto out;
|
||||
} else
|
||||
#endif
|
||||
if ((ipvs->sysctl_snat_reroute ||
|
||||
skb_rtable(skb)->rt_flags & RTCF_LOCAL) &&
|
||||
ip_route_me_harder(skb, RTN_LOCAL) != 0)
|
||||
goto out;
|
||||
if (ip_vs_route_me_harder(af, skb))
|
||||
goto out;
|
||||
|
||||
/* do the statistics and put it back */
|
||||
ip_vs_out_stats(cp, skb);
|
||||
@@ -985,7 +1022,6 @@ handle_response(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd,
|
||||
struct ip_vs_conn *cp, int ihl)
|
||||
{
|
||||
struct ip_vs_protocol *pp = pd->pp;
|
||||
struct netns_ipvs *ipvs;
|
||||
|
||||
IP_VS_DBG_PKT(11, af, pp, skb, 0, "Outgoing packet");
|
||||
|
||||
@@ -1021,18 +1057,8 @@ handle_response(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd,
|
||||
* if it came from this machine itself. So re-compute
|
||||
* the routing information.
|
||||
*/
|
||||
ipvs = net_ipvs(skb_net(skb));
|
||||
|
||||
#ifdef CONFIG_IP_VS_IPV6
|
||||
if (af == AF_INET6) {
|
||||
if (ipvs->sysctl_snat_reroute && ip6_route_me_harder(skb) != 0)
|
||||
goto drop;
|
||||
} else
|
||||
#endif
|
||||
if ((ipvs->sysctl_snat_reroute ||
|
||||
skb_rtable(skb)->rt_flags & RTCF_LOCAL) &&
|
||||
ip_route_me_harder(skb, RTN_LOCAL) != 0)
|
||||
goto drop;
|
||||
if (ip_vs_route_me_harder(af, skb))
|
||||
goto drop;
|
||||
|
||||
IP_VS_DBG_PKT(10, af, pp, skb, 0, "After SNAT");
|
||||
|
||||
@@ -1066,7 +1092,6 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb, int af)
|
||||
struct ip_vs_protocol *pp;
|
||||
struct ip_vs_proto_data *pd;
|
||||
struct ip_vs_conn *cp;
|
||||
struct netns_ipvs *ipvs;
|
||||
|
||||
EnterFunction(11);
|
||||
|
||||
@@ -1141,11 +1166,10 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb, int af)
|
||||
* Check if the packet belongs to an existing entry
|
||||
*/
|
||||
cp = pp->conn_out_get(af, skb, &iph, iph.len, 0);
|
||||
ipvs = net_ipvs(net);
|
||||
|
||||
if (likely(cp))
|
||||
return handle_response(af, skb, pd, cp, iph.len);
|
||||
if (ipvs->sysctl_nat_icmp_send &&
|
||||
if (sysctl_nat_icmp_send(net) &&
|
||||
(pp->protocol == IPPROTO_TCP ||
|
||||
pp->protocol == IPPROTO_UDP ||
|
||||
pp->protocol == IPPROTO_SCTP)) {
|
||||
@@ -1570,7 +1594,7 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af)
|
||||
if (cp->dest && !(cp->dest->flags & IP_VS_DEST_F_AVAILABLE)) {
|
||||
/* the destination server is not available */
|
||||
|
||||
if (ipvs->sysctl_expire_nodest_conn) {
|
||||
if (sysctl_expire_nodest_conn(ipvs)) {
|
||||
/* try to expire the connection immediately */
|
||||
ip_vs_conn_expire_now(cp);
|
||||
}
|
||||
@@ -1600,15 +1624,15 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af)
|
||||
*/
|
||||
|
||||
if (cp->flags & IP_VS_CONN_F_ONE_PACKET)
|
||||
pkts = ipvs->sysctl_sync_threshold[0];
|
||||
pkts = sysctl_sync_threshold(ipvs);
|
||||
else
|
||||
pkts = atomic_add_return(1, &cp->in_pkts);
|
||||
|
||||
if ((ipvs->sync_state & IP_VS_STATE_MASTER) &&
|
||||
cp->protocol == IPPROTO_SCTP) {
|
||||
if ((cp->state == IP_VS_SCTP_S_ESTABLISHED &&
|
||||
(pkts % ipvs->sysctl_sync_threshold[1]
|
||||
== ipvs->sysctl_sync_threshold[0])) ||
|
||||
(pkts % sysctl_sync_period(ipvs)
|
||||
== sysctl_sync_threshold(ipvs))) ||
|
||||
(cp->old_state != cp->state &&
|
||||
((cp->state == IP_VS_SCTP_S_CLOSED) ||
|
||||
(cp->state == IP_VS_SCTP_S_SHUT_ACK_CLI) ||
|
||||
@@ -1622,8 +1646,8 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af)
|
||||
else if ((ipvs->sync_state & IP_VS_STATE_MASTER) &&
|
||||
(((cp->protocol != IPPROTO_TCP ||
|
||||
cp->state == IP_VS_TCP_S_ESTABLISHED) &&
|
||||
(pkts % ipvs->sysctl_sync_threshold[1]
|
||||
== ipvs->sysctl_sync_threshold[0])) ||
|
||||
(pkts % sysctl_sync_period(ipvs)
|
||||
== sysctl_sync_threshold(ipvs))) ||
|
||||
((cp->protocol == IPPROTO_TCP) && (cp->old_state != cp->state) &&
|
||||
((cp->state == IP_VS_TCP_S_FIN_WAIT) ||
|
||||
(cp->state == IP_VS_TCP_S_CLOSE) ||
|
||||
|
@@ -86,6 +86,8 @@ static int __ip_vs_addr_is_local_v6(struct net *net,
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
/*
|
||||
* update_defense_level is called from keventd and from sysctl,
|
||||
* so it needs to protect itself from softirqs
|
||||
@@ -227,6 +229,7 @@ static void defense_work_handler(struct work_struct *work)
|
||||
ip_vs_random_dropentry(ipvs->net);
|
||||
schedule_delayed_work(&ipvs->defense_work, DEFENSE_TIMER_PERIOD);
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
ip_vs_use_count_inc(void)
|
||||
@@ -409,9 +412,11 @@ ip_vs_service_get(struct net *net, int af, __u32 fwmark, __u16 protocol,
|
||||
/*
|
||||
* Check the table hashed by fwmark first
|
||||
*/
|
||||
svc = __ip_vs_svc_fwm_find(net, af, fwmark);
|
||||
if (fwmark && svc)
|
||||
goto out;
|
||||
if (fwmark) {
|
||||
svc = __ip_vs_svc_fwm_find(net, af, fwmark);
|
||||
if (svc)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the table hashed by <protocol,addr,port>
|
||||
@@ -707,13 +712,39 @@ static void ip_vs_trash_cleanup(struct net *net)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ip_vs_copy_stats(struct ip_vs_stats_user *dst, struct ip_vs_stats *src)
|
||||
{
|
||||
#define IP_VS_SHOW_STATS_COUNTER(c) dst->c = src->ustats.c - src->ustats0.c
|
||||
|
||||
spin_lock_bh(&src->lock);
|
||||
|
||||
IP_VS_SHOW_STATS_COUNTER(conns);
|
||||
IP_VS_SHOW_STATS_COUNTER(inpkts);
|
||||
IP_VS_SHOW_STATS_COUNTER(outpkts);
|
||||
IP_VS_SHOW_STATS_COUNTER(inbytes);
|
||||
IP_VS_SHOW_STATS_COUNTER(outbytes);
|
||||
|
||||
ip_vs_read_estimator(dst, src);
|
||||
|
||||
spin_unlock_bh(&src->lock);
|
||||
}
|
||||
|
||||
static void
|
||||
ip_vs_zero_stats(struct ip_vs_stats *stats)
|
||||
{
|
||||
spin_lock_bh(&stats->lock);
|
||||
|
||||
memset(&stats->ustats, 0, sizeof(stats->ustats));
|
||||
/* get current counters as zero point, rates are zeroed */
|
||||
|
||||
#define IP_VS_ZERO_STATS_COUNTER(c) stats->ustats0.c = stats->ustats.c
|
||||
|
||||
IP_VS_ZERO_STATS_COUNTER(conns);
|
||||
IP_VS_ZERO_STATS_COUNTER(inpkts);
|
||||
IP_VS_ZERO_STATS_COUNTER(outpkts);
|
||||
IP_VS_ZERO_STATS_COUNTER(inbytes);
|
||||
IP_VS_ZERO_STATS_COUNTER(outbytes);
|
||||
|
||||
ip_vs_zero_estimator(stats);
|
||||
|
||||
spin_unlock_bh(&stats->lock);
|
||||
@@ -772,7 +803,7 @@ __ip_vs_update_dest(struct ip_vs_service *svc, struct ip_vs_dest *dest,
|
||||
spin_unlock_bh(&dest->dst_lock);
|
||||
|
||||
if (add)
|
||||
ip_vs_new_estimator(svc->net, &dest->stats);
|
||||
ip_vs_start_estimator(svc->net, &dest->stats);
|
||||
|
||||
write_lock_bh(&__ip_vs_svc_lock);
|
||||
|
||||
@@ -978,7 +1009,7 @@ static void __ip_vs_del_dest(struct net *net, struct ip_vs_dest *dest)
|
||||
{
|
||||
struct netns_ipvs *ipvs = net_ipvs(net);
|
||||
|
||||
ip_vs_kill_estimator(net, &dest->stats);
|
||||
ip_vs_stop_estimator(net, &dest->stats);
|
||||
|
||||
/*
|
||||
* Remove it from the d-linked list with the real services.
|
||||
@@ -1171,7 +1202,7 @@ ip_vs_add_service(struct net *net, struct ip_vs_service_user_kern *u,
|
||||
else if (svc->port == 0)
|
||||
atomic_inc(&ipvs->nullsvc_counter);
|
||||
|
||||
ip_vs_new_estimator(net, &svc->stats);
|
||||
ip_vs_start_estimator(net, &svc->stats);
|
||||
|
||||
/* Count only IPv4 services for old get/setsockopt interface */
|
||||
if (svc->af == AF_INET)
|
||||
@@ -1323,7 +1354,7 @@ static void __ip_vs_del_service(struct ip_vs_service *svc)
|
||||
if (svc->af == AF_INET)
|
||||
ipvs->num_services--;
|
||||
|
||||
ip_vs_kill_estimator(svc->net, &svc->stats);
|
||||
ip_vs_stop_estimator(svc->net, &svc->stats);
|
||||
|
||||
/* Unbind scheduler */
|
||||
old_sched = svc->scheduler;
|
||||
@@ -1477,11 +1508,11 @@ static int ip_vs_zero_all(struct net *net)
|
||||
}
|
||||
}
|
||||
|
||||
ip_vs_zero_stats(net_ipvs(net)->tot_stats);
|
||||
ip_vs_zero_stats(&net_ipvs(net)->tot_stats);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
static int
|
||||
proc_do_defense_mode(ctl_table *table, int write,
|
||||
void __user *buffer, size_t *lenp, loff_t *ppos)
|
||||
@@ -1503,7 +1534,6 @@ proc_do_defense_mode(ctl_table *table, int write,
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
proc_do_sync_threshold(ctl_table *table, int write,
|
||||
void __user *buffer, size_t *lenp, loff_t *ppos)
|
||||
@@ -1737,6 +1767,7 @@ const struct ctl_path net_vs_ctl_path[] = {
|
||||
{ }
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(net_vs_ctl_path);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
|
||||
@@ -1959,7 +1990,7 @@ static const struct file_operations ip_vs_info_fops = {
|
||||
static int ip_vs_stats_show(struct seq_file *seq, void *v)
|
||||
{
|
||||
struct net *net = seq_file_single_net(seq);
|
||||
struct ip_vs_stats *tot_stats = net_ipvs(net)->tot_stats;
|
||||
struct ip_vs_stats_user show;
|
||||
|
||||
/* 01234567 01234567 01234567 0123456701234567 0123456701234567 */
|
||||
seq_puts(seq,
|
||||
@@ -1967,22 +1998,18 @@ static int ip_vs_stats_show(struct seq_file *seq, void *v)
|
||||
seq_printf(seq,
|
||||
" Conns Packets Packets Bytes Bytes\n");
|
||||
|
||||
spin_lock_bh(&tot_stats->lock);
|
||||
seq_printf(seq, "%8X %8X %8X %16LX %16LX\n\n", tot_stats->ustats.conns,
|
||||
tot_stats->ustats.inpkts, tot_stats->ustats.outpkts,
|
||||
(unsigned long long) tot_stats->ustats.inbytes,
|
||||
(unsigned long long) tot_stats->ustats.outbytes);
|
||||
ip_vs_copy_stats(&show, &net_ipvs(net)->tot_stats);
|
||||
seq_printf(seq, "%8X %8X %8X %16LX %16LX\n\n", show.conns,
|
||||
show.inpkts, show.outpkts,
|
||||
(unsigned long long) show.inbytes,
|
||||
(unsigned long long) show.outbytes);
|
||||
|
||||
/* 01234567 01234567 01234567 0123456701234567 0123456701234567 */
|
||||
seq_puts(seq,
|
||||
" Conns/s Pkts/s Pkts/s Bytes/s Bytes/s\n");
|
||||
seq_printf(seq,"%8X %8X %8X %16X %16X\n",
|
||||
tot_stats->ustats.cps,
|
||||
tot_stats->ustats.inpps,
|
||||
tot_stats->ustats.outpps,
|
||||
tot_stats->ustats.inbps,
|
||||
tot_stats->ustats.outbps);
|
||||
spin_unlock_bh(&tot_stats->lock);
|
||||
seq_printf(seq, "%8X %8X %8X %16X %16X\n",
|
||||
show.cps, show.inpps, show.outpps,
|
||||
show.inbps, show.outbps);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -2003,7 +2030,9 @@ static const struct file_operations ip_vs_stats_fops = {
|
||||
static int ip_vs_stats_percpu_show(struct seq_file *seq, void *v)
|
||||
{
|
||||
struct net *net = seq_file_single_net(seq);
|
||||
struct ip_vs_stats *tot_stats = net_ipvs(net)->tot_stats;
|
||||
struct ip_vs_stats *tot_stats = &net_ipvs(net)->tot_stats;
|
||||
struct ip_vs_cpu_stats *cpustats = tot_stats->cpustats;
|
||||
struct ip_vs_stats_user rates;
|
||||
int i;
|
||||
|
||||
/* 01234567 01234567 01234567 0123456701234567 0123456701234567 */
|
||||
@@ -2013,30 +2042,43 @@ static int ip_vs_stats_percpu_show(struct seq_file *seq, void *v)
|
||||
"CPU Conns Packets Packets Bytes Bytes\n");
|
||||
|
||||
for_each_possible_cpu(i) {
|
||||
struct ip_vs_cpu_stats *u = per_cpu_ptr(net->ipvs->cpustats, i);
|
||||
struct ip_vs_cpu_stats *u = per_cpu_ptr(cpustats, i);
|
||||
unsigned int start;
|
||||
__u64 inbytes, outbytes;
|
||||
|
||||
do {
|
||||
start = u64_stats_fetch_begin_bh(&u->syncp);
|
||||
inbytes = u->ustats.inbytes;
|
||||
outbytes = u->ustats.outbytes;
|
||||
} while (u64_stats_fetch_retry_bh(&u->syncp, start));
|
||||
|
||||
seq_printf(seq, "%3X %8X %8X %8X %16LX %16LX\n",
|
||||
i, u->ustats.conns, u->ustats.inpkts,
|
||||
u->ustats.outpkts, (__u64)u->ustats.inbytes,
|
||||
(__u64)u->ustats.outbytes);
|
||||
i, u->ustats.conns, u->ustats.inpkts,
|
||||
u->ustats.outpkts, (__u64)inbytes,
|
||||
(__u64)outbytes);
|
||||
}
|
||||
|
||||
spin_lock_bh(&tot_stats->lock);
|
||||
|
||||
seq_printf(seq, " ~ %8X %8X %8X %16LX %16LX\n\n",
|
||||
tot_stats->ustats.conns, tot_stats->ustats.inpkts,
|
||||
tot_stats->ustats.outpkts,
|
||||
(unsigned long long) tot_stats->ustats.inbytes,
|
||||
(unsigned long long) tot_stats->ustats.outbytes);
|
||||
|
||||
ip_vs_read_estimator(&rates, tot_stats);
|
||||
|
||||
spin_unlock_bh(&tot_stats->lock);
|
||||
|
||||
/* 01234567 01234567 01234567 0123456701234567 0123456701234567 */
|
||||
seq_puts(seq,
|
||||
" Conns/s Pkts/s Pkts/s Bytes/s Bytes/s\n");
|
||||
seq_printf(seq, " %8X %8X %8X %16X %16X\n",
|
||||
tot_stats->ustats.cps,
|
||||
tot_stats->ustats.inpps,
|
||||
tot_stats->ustats.outpps,
|
||||
tot_stats->ustats.inbps,
|
||||
tot_stats->ustats.outbps);
|
||||
spin_unlock_bh(&tot_stats->lock);
|
||||
rates.cps,
|
||||
rates.inpps,
|
||||
rates.outpps,
|
||||
rates.inbps,
|
||||
rates.outbps);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -2283,14 +2325,6 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ip_vs_copy_stats(struct ip_vs_stats_user *dst, struct ip_vs_stats *src)
|
||||
{
|
||||
spin_lock_bh(&src->lock);
|
||||
memcpy(dst, &src->ustats, sizeof(*dst));
|
||||
spin_unlock_bh(&src->lock);
|
||||
}
|
||||
|
||||
static void
|
||||
ip_vs_copy_service(struct ip_vs_service_entry *dst, struct ip_vs_service *src)
|
||||
{
|
||||
@@ -2677,31 +2711,29 @@ static const struct nla_policy ip_vs_dest_policy[IPVS_DEST_ATTR_MAX + 1] = {
|
||||
static int ip_vs_genl_fill_stats(struct sk_buff *skb, int container_type,
|
||||
struct ip_vs_stats *stats)
|
||||
{
|
||||
struct ip_vs_stats_user ustats;
|
||||
struct nlattr *nl_stats = nla_nest_start(skb, container_type);
|
||||
if (!nl_stats)
|
||||
return -EMSGSIZE;
|
||||
|
||||
spin_lock_bh(&stats->lock);
|
||||
ip_vs_copy_stats(&ustats, stats);
|
||||
|
||||
NLA_PUT_U32(skb, IPVS_STATS_ATTR_CONNS, stats->ustats.conns);
|
||||
NLA_PUT_U32(skb, IPVS_STATS_ATTR_INPKTS, stats->ustats.inpkts);
|
||||
NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTPKTS, stats->ustats.outpkts);
|
||||
NLA_PUT_U64(skb, IPVS_STATS_ATTR_INBYTES, stats->ustats.inbytes);
|
||||
NLA_PUT_U64(skb, IPVS_STATS_ATTR_OUTBYTES, stats->ustats.outbytes);
|
||||
NLA_PUT_U32(skb, IPVS_STATS_ATTR_CPS, stats->ustats.cps);
|
||||
NLA_PUT_U32(skb, IPVS_STATS_ATTR_INPPS, stats->ustats.inpps);
|
||||
NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTPPS, stats->ustats.outpps);
|
||||
NLA_PUT_U32(skb, IPVS_STATS_ATTR_INBPS, stats->ustats.inbps);
|
||||
NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTBPS, stats->ustats.outbps);
|
||||
|
||||
spin_unlock_bh(&stats->lock);
|
||||
NLA_PUT_U32(skb, IPVS_STATS_ATTR_CONNS, ustats.conns);
|
||||
NLA_PUT_U32(skb, IPVS_STATS_ATTR_INPKTS, ustats.inpkts);
|
||||
NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTPKTS, ustats.outpkts);
|
||||
NLA_PUT_U64(skb, IPVS_STATS_ATTR_INBYTES, ustats.inbytes);
|
||||
NLA_PUT_U64(skb, IPVS_STATS_ATTR_OUTBYTES, ustats.outbytes);
|
||||
NLA_PUT_U32(skb, IPVS_STATS_ATTR_CPS, ustats.cps);
|
||||
NLA_PUT_U32(skb, IPVS_STATS_ATTR_INPPS, ustats.inpps);
|
||||
NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTPPS, ustats.outpps);
|
||||
NLA_PUT_U32(skb, IPVS_STATS_ATTR_INBPS, ustats.inbps);
|
||||
NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTBPS, ustats.outbps);
|
||||
|
||||
nla_nest_end(skb, nl_stats);
|
||||
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
spin_unlock_bh(&stats->lock);
|
||||
nla_nest_cancel(skb, nl_stats);
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
@@ -3480,7 +3512,8 @@ static void ip_vs_genl_unregister(void)
|
||||
/*
|
||||
* per netns intit/exit func.
|
||||
*/
|
||||
int __net_init __ip_vs_control_init(struct net *net)
|
||||
#ifdef CONFIG_SYSCTL
|
||||
int __net_init __ip_vs_control_init_sysctl(struct net *net)
|
||||
{
|
||||
int idx;
|
||||
struct netns_ipvs *ipvs = net_ipvs(net);
|
||||
@@ -3490,38 +3523,11 @@ int __net_init __ip_vs_control_init(struct net *net)
|
||||
spin_lock_init(&ipvs->dropentry_lock);
|
||||
spin_lock_init(&ipvs->droppacket_lock);
|
||||
spin_lock_init(&ipvs->securetcp_lock);
|
||||
ipvs->rs_lock = __RW_LOCK_UNLOCKED(ipvs->rs_lock);
|
||||
|
||||
/* Initialize rs_table */
|
||||
for (idx = 0; idx < IP_VS_RTAB_SIZE; idx++)
|
||||
INIT_LIST_HEAD(&ipvs->rs_table[idx]);
|
||||
|
||||
INIT_LIST_HEAD(&ipvs->dest_trash);
|
||||
atomic_set(&ipvs->ftpsvc_counter, 0);
|
||||
atomic_set(&ipvs->nullsvc_counter, 0);
|
||||
|
||||
/* procfs stats */
|
||||
ipvs->tot_stats = kzalloc(sizeof(struct ip_vs_stats), GFP_KERNEL);
|
||||
if (ipvs->tot_stats == NULL) {
|
||||
pr_err("%s(): no memory.\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
ipvs->cpustats = alloc_percpu(struct ip_vs_cpu_stats);
|
||||
if (!ipvs->cpustats) {
|
||||
pr_err("%s() alloc_percpu failed\n", __func__);
|
||||
goto err_alloc;
|
||||
}
|
||||
spin_lock_init(&ipvs->tot_stats->lock);
|
||||
|
||||
proc_net_fops_create(net, "ip_vs", 0, &ip_vs_info_fops);
|
||||
proc_net_fops_create(net, "ip_vs_stats", 0, &ip_vs_stats_fops);
|
||||
proc_net_fops_create(net, "ip_vs_stats_percpu", 0,
|
||||
&ip_vs_stats_percpu_fops);
|
||||
|
||||
if (!net_eq(net, &init_net)) {
|
||||
tbl = kmemdup(vs_vars, sizeof(vs_vars), GFP_KERNEL);
|
||||
if (tbl == NULL)
|
||||
goto err_dup;
|
||||
return -ENOMEM;
|
||||
} else
|
||||
tbl = vs_vars;
|
||||
/* Initialize sysctl defaults */
|
||||
@@ -3543,33 +3549,80 @@ int __net_init __ip_vs_control_init(struct net *net)
|
||||
tbl[idx++].data = &ipvs->sysctl_cache_bypass;
|
||||
tbl[idx++].data = &ipvs->sysctl_expire_nodest_conn;
|
||||
tbl[idx++].data = &ipvs->sysctl_expire_quiescent_template;
|
||||
ipvs->sysctl_sync_threshold[0] = 3;
|
||||
ipvs->sysctl_sync_threshold[1] = 50;
|
||||
ipvs->sysctl_sync_threshold[0] = DEFAULT_SYNC_THRESHOLD;
|
||||
ipvs->sysctl_sync_threshold[1] = DEFAULT_SYNC_PERIOD;
|
||||
tbl[idx].data = &ipvs->sysctl_sync_threshold;
|
||||
tbl[idx++].maxlen = sizeof(ipvs->sysctl_sync_threshold);
|
||||
tbl[idx++].data = &ipvs->sysctl_nat_icmp_send;
|
||||
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
ipvs->sysctl_hdr = register_net_sysctl_table(net, net_vs_ctl_path,
|
||||
tbl);
|
||||
if (ipvs->sysctl_hdr == NULL) {
|
||||
if (!net_eq(net, &init_net))
|
||||
kfree(tbl);
|
||||
goto err_dup;
|
||||
return -ENOMEM;
|
||||
}
|
||||
#endif
|
||||
ip_vs_new_estimator(net, ipvs->tot_stats);
|
||||
ip_vs_start_estimator(net, &ipvs->tot_stats);
|
||||
ipvs->sysctl_tbl = tbl;
|
||||
/* Schedule defense work */
|
||||
INIT_DELAYED_WORK(&ipvs->defense_work, defense_work_handler);
|
||||
schedule_delayed_work(&ipvs->defense_work, DEFENSE_TIMER_PERIOD);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __net_init __ip_vs_control_cleanup_sysctl(struct net *net)
|
||||
{
|
||||
struct netns_ipvs *ipvs = net_ipvs(net);
|
||||
|
||||
cancel_delayed_work_sync(&ipvs->defense_work);
|
||||
cancel_work_sync(&ipvs->defense_work.work);
|
||||
unregister_net_sysctl_table(ipvs->sysctl_hdr);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int __net_init __ip_vs_control_init_sysctl(struct net *net) { return 0; }
|
||||
void __net_init __ip_vs_control_cleanup_sysctl(struct net *net) { }
|
||||
|
||||
#endif
|
||||
|
||||
int __net_init __ip_vs_control_init(struct net *net)
|
||||
{
|
||||
int idx;
|
||||
struct netns_ipvs *ipvs = net_ipvs(net);
|
||||
|
||||
ipvs->rs_lock = __RW_LOCK_UNLOCKED(ipvs->rs_lock);
|
||||
|
||||
/* Initialize rs_table */
|
||||
for (idx = 0; idx < IP_VS_RTAB_SIZE; idx++)
|
||||
INIT_LIST_HEAD(&ipvs->rs_table[idx]);
|
||||
|
||||
INIT_LIST_HEAD(&ipvs->dest_trash);
|
||||
atomic_set(&ipvs->ftpsvc_counter, 0);
|
||||
atomic_set(&ipvs->nullsvc_counter, 0);
|
||||
|
||||
/* procfs stats */
|
||||
ipvs->tot_stats.cpustats = alloc_percpu(struct ip_vs_cpu_stats);
|
||||
if (ipvs->tot_stats.cpustats) {
|
||||
pr_err("%s(): alloc_percpu.\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
spin_lock_init(&ipvs->tot_stats.lock);
|
||||
|
||||
proc_net_fops_create(net, "ip_vs", 0, &ip_vs_info_fops);
|
||||
proc_net_fops_create(net, "ip_vs_stats", 0, &ip_vs_stats_fops);
|
||||
proc_net_fops_create(net, "ip_vs_stats_percpu", 0,
|
||||
&ip_vs_stats_percpu_fops);
|
||||
|
||||
if (__ip_vs_control_init_sysctl(net))
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
|
||||
err_dup:
|
||||
free_percpu(ipvs->cpustats);
|
||||
err_alloc:
|
||||
kfree(ipvs->tot_stats);
|
||||
err:
|
||||
free_percpu(ipvs->tot_stats.cpustats);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@@ -3578,17 +3631,12 @@ static void __net_exit __ip_vs_control_cleanup(struct net *net)
|
||||
struct netns_ipvs *ipvs = net_ipvs(net);
|
||||
|
||||
ip_vs_trash_cleanup(net);
|
||||
ip_vs_kill_estimator(net, ipvs->tot_stats);
|
||||
cancel_delayed_work_sync(&ipvs->defense_work);
|
||||
cancel_work_sync(&ipvs->defense_work.work);
|
||||
#ifdef CONFIG_SYSCTL
|
||||
unregister_net_sysctl_table(ipvs->sysctl_hdr);
|
||||
#endif
|
||||
ip_vs_stop_estimator(net, &ipvs->tot_stats);
|
||||
__ip_vs_control_cleanup_sysctl(net);
|
||||
proc_net_remove(net, "ip_vs_stats_percpu");
|
||||
proc_net_remove(net, "ip_vs_stats");
|
||||
proc_net_remove(net, "ip_vs");
|
||||
free_percpu(ipvs->cpustats);
|
||||
kfree(ipvs->tot_stats);
|
||||
free_percpu(ipvs->tot_stats.cpustats);
|
||||
}
|
||||
|
||||
static struct pernet_operations ipvs_control_ops = {
|
||||
|
@@ -69,10 +69,10 @@ static void ip_vs_read_cpu_stats(struct ip_vs_stats_user *sum,
|
||||
sum->inpkts += s->ustats.inpkts;
|
||||
sum->outpkts += s->ustats.outpkts;
|
||||
do {
|
||||
start = u64_stats_fetch_begin_bh(&s->syncp);
|
||||
start = u64_stats_fetch_begin(&s->syncp);
|
||||
inbytes = s->ustats.inbytes;
|
||||
outbytes = s->ustats.outbytes;
|
||||
} while (u64_stats_fetch_retry_bh(&s->syncp, start));
|
||||
} while (u64_stats_fetch_retry(&s->syncp, start));
|
||||
sum->inbytes += inbytes;
|
||||
sum->outbytes += outbytes;
|
||||
} else {
|
||||
@@ -80,10 +80,10 @@ static void ip_vs_read_cpu_stats(struct ip_vs_stats_user *sum,
|
||||
sum->inpkts = s->ustats.inpkts;
|
||||
sum->outpkts = s->ustats.outpkts;
|
||||
do {
|
||||
start = u64_stats_fetch_begin_bh(&s->syncp);
|
||||
start = u64_stats_fetch_begin(&s->syncp);
|
||||
sum->inbytes = s->ustats.inbytes;
|
||||
sum->outbytes = s->ustats.outbytes;
|
||||
} while (u64_stats_fetch_retry_bh(&s->syncp, start));
|
||||
} while (u64_stats_fetch_retry(&s->syncp, start));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -101,13 +101,12 @@ static void estimation_timer(unsigned long arg)
|
||||
struct netns_ipvs *ipvs;
|
||||
|
||||
ipvs = net_ipvs(net);
|
||||
ip_vs_read_cpu_stats(&ipvs->tot_stats->ustats, ipvs->cpustats);
|
||||
spin_lock(&ipvs->est_lock);
|
||||
list_for_each_entry(e, &ipvs->est_list, list) {
|
||||
s = container_of(e, struct ip_vs_stats, est);
|
||||
|
||||
ip_vs_read_cpu_stats(&s->ustats, s->cpustats);
|
||||
spin_lock(&s->lock);
|
||||
ip_vs_read_cpu_stats(&s->ustats, s->cpustats);
|
||||
n_conns = s->ustats.conns;
|
||||
n_inpkts = s->ustats.inpkts;
|
||||
n_outpkts = s->ustats.outpkts;
|
||||
@@ -118,61 +117,41 @@ static void estimation_timer(unsigned long arg)
|
||||
rate = (n_conns - e->last_conns) << 9;
|
||||
e->last_conns = n_conns;
|
||||
e->cps += ((long)rate - (long)e->cps) >> 2;
|
||||
s->ustats.cps = (e->cps + 0x1FF) >> 10;
|
||||
|
||||
rate = (n_inpkts - e->last_inpkts) << 9;
|
||||
e->last_inpkts = n_inpkts;
|
||||
e->inpps += ((long)rate - (long)e->inpps) >> 2;
|
||||
s->ustats.inpps = (e->inpps + 0x1FF) >> 10;
|
||||
|
||||
rate = (n_outpkts - e->last_outpkts) << 9;
|
||||
e->last_outpkts = n_outpkts;
|
||||
e->outpps += ((long)rate - (long)e->outpps) >> 2;
|
||||
s->ustats.outpps = (e->outpps + 0x1FF) >> 10;
|
||||
|
||||
rate = (n_inbytes - e->last_inbytes) << 4;
|
||||
e->last_inbytes = n_inbytes;
|
||||
e->inbps += ((long)rate - (long)e->inbps) >> 2;
|
||||
s->ustats.inbps = (e->inbps + 0xF) >> 5;
|
||||
|
||||
rate = (n_outbytes - e->last_outbytes) << 4;
|
||||
e->last_outbytes = n_outbytes;
|
||||
e->outbps += ((long)rate - (long)e->outbps) >> 2;
|
||||
s->ustats.outbps = (e->outbps + 0xF) >> 5;
|
||||
spin_unlock(&s->lock);
|
||||
}
|
||||
spin_unlock(&ipvs->est_lock);
|
||||
mod_timer(&ipvs->est_timer, jiffies + 2*HZ);
|
||||
}
|
||||
|
||||
void ip_vs_new_estimator(struct net *net, struct ip_vs_stats *stats)
|
||||
void ip_vs_start_estimator(struct net *net, struct ip_vs_stats *stats)
|
||||
{
|
||||
struct netns_ipvs *ipvs = net_ipvs(net);
|
||||
struct ip_vs_estimator *est = &stats->est;
|
||||
|
||||
INIT_LIST_HEAD(&est->list);
|
||||
|
||||
est->last_conns = stats->ustats.conns;
|
||||
est->cps = stats->ustats.cps<<10;
|
||||
|
||||
est->last_inpkts = stats->ustats.inpkts;
|
||||
est->inpps = stats->ustats.inpps<<10;
|
||||
|
||||
est->last_outpkts = stats->ustats.outpkts;
|
||||
est->outpps = stats->ustats.outpps<<10;
|
||||
|
||||
est->last_inbytes = stats->ustats.inbytes;
|
||||
est->inbps = stats->ustats.inbps<<5;
|
||||
|
||||
est->last_outbytes = stats->ustats.outbytes;
|
||||
est->outbps = stats->ustats.outbps<<5;
|
||||
|
||||
spin_lock_bh(&ipvs->est_lock);
|
||||
list_add(&est->list, &ipvs->est_list);
|
||||
spin_unlock_bh(&ipvs->est_lock);
|
||||
}
|
||||
|
||||
void ip_vs_kill_estimator(struct net *net, struct ip_vs_stats *stats)
|
||||
void ip_vs_stop_estimator(struct net *net, struct ip_vs_stats *stats)
|
||||
{
|
||||
struct netns_ipvs *ipvs = net_ipvs(net);
|
||||
struct ip_vs_estimator *est = &stats->est;
|
||||
@@ -185,13 +164,14 @@ void ip_vs_kill_estimator(struct net *net, struct ip_vs_stats *stats)
|
||||
void ip_vs_zero_estimator(struct ip_vs_stats *stats)
|
||||
{
|
||||
struct ip_vs_estimator *est = &stats->est;
|
||||
struct ip_vs_stats_user *u = &stats->ustats;
|
||||
|
||||
/* set counters zero, caller must hold the stats->lock lock */
|
||||
est->last_inbytes = 0;
|
||||
est->last_outbytes = 0;
|
||||
est->last_conns = 0;
|
||||
est->last_inpkts = 0;
|
||||
est->last_outpkts = 0;
|
||||
/* reset counters, caller must hold the stats->lock lock */
|
||||
est->last_inbytes = u->inbytes;
|
||||
est->last_outbytes = u->outbytes;
|
||||
est->last_conns = u->conns;
|
||||
est->last_inpkts = u->inpkts;
|
||||
est->last_outpkts = u->outpkts;
|
||||
est->cps = 0;
|
||||
est->inpps = 0;
|
||||
est->outpps = 0;
|
||||
@@ -199,6 +179,19 @@ void ip_vs_zero_estimator(struct ip_vs_stats *stats)
|
||||
est->outbps = 0;
|
||||
}
|
||||
|
||||
/* Get decoded rates */
|
||||
void ip_vs_read_estimator(struct ip_vs_stats_user *dst,
|
||||
struct ip_vs_stats *stats)
|
||||
{
|
||||
struct ip_vs_estimator *e = &stats->est;
|
||||
|
||||
dst->cps = (e->cps + 0x1FF) >> 10;
|
||||
dst->inpps = (e->inpps + 0x1FF) >> 10;
|
||||
dst->outpps = (e->outpps + 0x1FF) >> 10;
|
||||
dst->inbps = (e->inbps + 0xF) >> 5;
|
||||
dst->outbps = (e->outbps + 0xF) >> 5;
|
||||
}
|
||||
|
||||
static int __net_init __ip_vs_estimator_init(struct net *net)
|
||||
{
|
||||
struct netns_ipvs *ipvs = net_ipvs(net);
|
||||
|
@@ -63,6 +63,8 @@
|
||||
#define CHECK_EXPIRE_INTERVAL (60*HZ)
|
||||
#define ENTRY_TIMEOUT (6*60*HZ)
|
||||
|
||||
#define DEFAULT_EXPIRATION (24*60*60*HZ)
|
||||
|
||||
/*
|
||||
* It is for full expiration check.
|
||||
* When there is no partial expiration check (garbage collection)
|
||||
@@ -112,7 +114,7 @@ struct ip_vs_lblc_table {
|
||||
/*
|
||||
* IPVS LBLC sysctl table
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
static ctl_table vs_vars_table[] = {
|
||||
{
|
||||
.procname = "lblc_expiration",
|
||||
@@ -123,6 +125,7 @@ static ctl_table vs_vars_table[] = {
|
||||
},
|
||||
{ }
|
||||
};
|
||||
#endif
|
||||
|
||||
static inline void ip_vs_lblc_free(struct ip_vs_lblc_entry *en)
|
||||
{
|
||||
@@ -238,6 +241,15 @@ static void ip_vs_lblc_flush(struct ip_vs_lblc_table *tbl)
|
||||
}
|
||||
}
|
||||
|
||||
static int sysctl_lblc_expiration(struct ip_vs_service *svc)
|
||||
{
|
||||
#ifdef CONFIG_SYSCTL
|
||||
struct netns_ipvs *ipvs = net_ipvs(svc->net);
|
||||
return ipvs->sysctl_lblc_expiration;
|
||||
#else
|
||||
return DEFAULT_EXPIRATION;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void ip_vs_lblc_full_check(struct ip_vs_service *svc)
|
||||
{
|
||||
@@ -245,7 +257,6 @@ static inline void ip_vs_lblc_full_check(struct ip_vs_service *svc)
|
||||
struct ip_vs_lblc_entry *en, *nxt;
|
||||
unsigned long now = jiffies;
|
||||
int i, j;
|
||||
struct netns_ipvs *ipvs = net_ipvs(svc->net);
|
||||
|
||||
for (i=0, j=tbl->rover; i<IP_VS_LBLC_TAB_SIZE; i++) {
|
||||
j = (j + 1) & IP_VS_LBLC_TAB_MASK;
|
||||
@@ -254,7 +265,7 @@ static inline void ip_vs_lblc_full_check(struct ip_vs_service *svc)
|
||||
list_for_each_entry_safe(en, nxt, &tbl->bucket[j], list) {
|
||||
if (time_before(now,
|
||||
en->lastuse +
|
||||
ipvs->sysctl_lblc_expiration))
|
||||
sysctl_lblc_expiration(svc)))
|
||||
continue;
|
||||
|
||||
ip_vs_lblc_free(en);
|
||||
@@ -538,6 +549,7 @@ static struct ip_vs_scheduler ip_vs_lblc_scheduler =
|
||||
/*
|
||||
* per netns init.
|
||||
*/
|
||||
#ifdef CONFIG_SYSCTL
|
||||
static int __net_init __ip_vs_lblc_init(struct net *net)
|
||||
{
|
||||
struct netns_ipvs *ipvs = net_ipvs(net);
|
||||
@@ -550,10 +562,9 @@ static int __net_init __ip_vs_lblc_init(struct net *net)
|
||||
return -ENOMEM;
|
||||
} else
|
||||
ipvs->lblc_ctl_table = vs_vars_table;
|
||||
ipvs->sysctl_lblc_expiration = 24*60*60*HZ;
|
||||
ipvs->sysctl_lblc_expiration = DEFAULT_EXPIRATION;
|
||||
ipvs->lblc_ctl_table[0].data = &ipvs->sysctl_lblc_expiration;
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
ipvs->lblc_ctl_header =
|
||||
register_net_sysctl_table(net, net_vs_ctl_path,
|
||||
ipvs->lblc_ctl_table);
|
||||
@@ -562,7 +573,6 @@ static int __net_init __ip_vs_lblc_init(struct net *net)
|
||||
kfree(ipvs->lblc_ctl_table);
|
||||
return -ENOMEM;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -571,14 +581,19 @@ static void __net_exit __ip_vs_lblc_exit(struct net *net)
|
||||
{
|
||||
struct netns_ipvs *ipvs = net_ipvs(net);
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
unregister_net_sysctl_table(ipvs->lblc_ctl_header);
|
||||
#endif
|
||||
|
||||
if (!net_eq(net, &init_net))
|
||||
kfree(ipvs->lblc_ctl_table);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int __net_init __ip_vs_lblc_init(struct net *net) { return 0; }
|
||||
static void __net_exit __ip_vs_lblc_exit(struct net *net) { }
|
||||
|
||||
#endif
|
||||
|
||||
static struct pernet_operations ip_vs_lblc_ops = {
|
||||
.init = __ip_vs_lblc_init,
|
||||
.exit = __ip_vs_lblc_exit,
|
||||
|
@@ -63,6 +63,8 @@
|
||||
#define CHECK_EXPIRE_INTERVAL (60*HZ)
|
||||
#define ENTRY_TIMEOUT (6*60*HZ)
|
||||
|
||||
#define DEFAULT_EXPIRATION (24*60*60*HZ)
|
||||
|
||||
/*
|
||||
* It is for full expiration check.
|
||||
* When there is no partial expiration check (garbage collection)
|
||||
@@ -283,6 +285,7 @@ struct ip_vs_lblcr_table {
|
||||
};
|
||||
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
/*
|
||||
* IPVS LBLCR sysctl table
|
||||
*/
|
||||
@@ -297,6 +300,7 @@ static ctl_table vs_vars_table[] = {
|
||||
},
|
||||
{ }
|
||||
};
|
||||
#endif
|
||||
|
||||
static inline void ip_vs_lblcr_free(struct ip_vs_lblcr_entry *en)
|
||||
{
|
||||
@@ -410,6 +414,15 @@ static void ip_vs_lblcr_flush(struct ip_vs_lblcr_table *tbl)
|
||||
}
|
||||
}
|
||||
|
||||
static int sysctl_lblcr_expiration(struct ip_vs_service *svc)
|
||||
{
|
||||
#ifdef CONFIG_SYSCTL
|
||||
struct netns_ipvs *ipvs = net_ipvs(svc->net);
|
||||
return ipvs->sysctl_lblcr_expiration;
|
||||
#else
|
||||
return DEFAULT_EXPIRATION;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void ip_vs_lblcr_full_check(struct ip_vs_service *svc)
|
||||
{
|
||||
@@ -417,15 +430,14 @@ static inline void ip_vs_lblcr_full_check(struct ip_vs_service *svc)
|
||||
unsigned long now = jiffies;
|
||||
int i, j;
|
||||
struct ip_vs_lblcr_entry *en, *nxt;
|
||||
struct netns_ipvs *ipvs = net_ipvs(svc->net);
|
||||
|
||||
for (i=0, j=tbl->rover; i<IP_VS_LBLCR_TAB_SIZE; i++) {
|
||||
j = (j + 1) & IP_VS_LBLCR_TAB_MASK;
|
||||
|
||||
write_lock(&svc->sched_lock);
|
||||
list_for_each_entry_safe(en, nxt, &tbl->bucket[j], list) {
|
||||
if (time_after(en->lastuse
|
||||
+ ipvs->sysctl_lblcr_expiration, now))
|
||||
if (time_after(en->lastuse +
|
||||
sysctl_lblcr_expiration(svc), now))
|
||||
continue;
|
||||
|
||||
ip_vs_lblcr_free(en);
|
||||
@@ -650,7 +662,6 @@ ip_vs_lblcr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
|
||||
read_lock(&svc->sched_lock);
|
||||
en = ip_vs_lblcr_get(svc->af, tbl, &iph.daddr);
|
||||
if (en) {
|
||||
struct netns_ipvs *ipvs = net_ipvs(svc->net);
|
||||
/* We only hold a read lock, but this is atomic */
|
||||
en->lastuse = jiffies;
|
||||
|
||||
@@ -662,7 +673,7 @@ ip_vs_lblcr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
|
||||
/* More than one destination + enough time passed by, cleanup */
|
||||
if (atomic_read(&en->set.size) > 1 &&
|
||||
time_after(jiffies, en->set.lastmod +
|
||||
ipvs->sysctl_lblcr_expiration)) {
|
||||
sysctl_lblcr_expiration(svc))) {
|
||||
struct ip_vs_dest *m;
|
||||
|
||||
write_lock(&en->set.lock);
|
||||
@@ -734,6 +745,7 @@ static struct ip_vs_scheduler ip_vs_lblcr_scheduler =
|
||||
/*
|
||||
* per netns init.
|
||||
*/
|
||||
#ifdef CONFIG_SYSCTL
|
||||
static int __net_init __ip_vs_lblcr_init(struct net *net)
|
||||
{
|
||||
struct netns_ipvs *ipvs = net_ipvs(net);
|
||||
@@ -746,10 +758,9 @@ static int __net_init __ip_vs_lblcr_init(struct net *net)
|
||||
return -ENOMEM;
|
||||
} else
|
||||
ipvs->lblcr_ctl_table = vs_vars_table;
|
||||
ipvs->sysctl_lblcr_expiration = 24*60*60*HZ;
|
||||
ipvs->sysctl_lblcr_expiration = DEFAULT_EXPIRATION;
|
||||
ipvs->lblcr_ctl_table[0].data = &ipvs->sysctl_lblcr_expiration;
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
ipvs->lblcr_ctl_header =
|
||||
register_net_sysctl_table(net, net_vs_ctl_path,
|
||||
ipvs->lblcr_ctl_table);
|
||||
@@ -758,7 +769,6 @@ static int __net_init __ip_vs_lblcr_init(struct net *net)
|
||||
kfree(ipvs->lblcr_ctl_table);
|
||||
return -ENOMEM;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -767,14 +777,19 @@ static void __net_exit __ip_vs_lblcr_exit(struct net *net)
|
||||
{
|
||||
struct netns_ipvs *ipvs = net_ipvs(net);
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
unregister_net_sysctl_table(ipvs->lblcr_ctl_header);
|
||||
#endif
|
||||
|
||||
if (!net_eq(net, &init_net))
|
||||
kfree(ipvs->lblcr_ctl_table);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int __net_init __ip_vs_lblcr_init(struct net *net) { return 0; }
|
||||
static void __net_exit __ip_vs_lblcr_exit(struct net *net) { }
|
||||
|
||||
#endif
|
||||
|
||||
static struct pernet_operations ip_vs_lblcr_ops = {
|
||||
.init = __ip_vs_lblcr_init,
|
||||
.exit = __ip_vs_lblcr_exit,
|
||||
|
@@ -92,14 +92,13 @@ ip_vs_sip_fill_param(struct ip_vs_conn_param *p, struct sk_buff *skb)
|
||||
if (get_callid(dptr, dataoff, datalen, &matchoff, &matchlen))
|
||||
return -EINVAL;
|
||||
|
||||
p->pe_data = kmalloc(matchlen, GFP_ATOMIC);
|
||||
if (!p->pe_data)
|
||||
return -ENOMEM;
|
||||
|
||||
/* N.B: pe_data is only set on success,
|
||||
* this allows fallback to the default persistence logic on failure
|
||||
*/
|
||||
memcpy(p->pe_data, dptr + matchoff, matchlen);
|
||||
p->pe_data = kmemdup(dptr + matchoff, matchlen, GFP_ATOMIC);
|
||||
if (!p->pe_data)
|
||||
return -ENOMEM;
|
||||
|
||||
p->pe_data_len = matchlen;
|
||||
|
||||
return 0;
|
||||
|
@@ -394,7 +394,7 @@ void ip_vs_sync_switch_mode(struct net *net, int mode)
|
||||
|
||||
if (!(ipvs->sync_state & IP_VS_STATE_MASTER))
|
||||
return;
|
||||
if (mode == ipvs->sysctl_sync_ver || !ipvs->sync_buff)
|
||||
if (mode == sysctl_sync_ver(ipvs) || !ipvs->sync_buff)
|
||||
return;
|
||||
|
||||
spin_lock_bh(&ipvs->sync_buff_lock);
|
||||
@@ -521,7 +521,7 @@ void ip_vs_sync_conn(struct net *net, struct ip_vs_conn *cp)
|
||||
unsigned int len, pe_name_len, pad;
|
||||
|
||||
/* Handle old version of the protocol */
|
||||
if (ipvs->sysctl_sync_ver == 0) {
|
||||
if (sysctl_sync_ver(ipvs) == 0) {
|
||||
ip_vs_sync_conn_v0(net, cp);
|
||||
return;
|
||||
}
|
||||
@@ -650,7 +650,7 @@ control:
|
||||
if (cp->flags & IP_VS_CONN_F_TEMPLATE) {
|
||||
int pkts = atomic_add_return(1, &cp->in_pkts);
|
||||
|
||||
if (pkts % ipvs->sysctl_sync_threshold[1] != 1)
|
||||
if (pkts % sysctl_sync_period(ipvs) != 1)
|
||||
return;
|
||||
}
|
||||
goto sloop;
|
||||
@@ -697,13 +697,12 @@ ip_vs_conn_fill_param_sync(struct net *net, int af, union ip_vs_sync_conn *sc,
|
||||
return 1;
|
||||
}
|
||||
|
||||
p->pe_data = kmalloc(pe_data_len, GFP_ATOMIC);
|
||||
p->pe_data = kmemdup(pe_data, pe_data_len, GFP_ATOMIC);
|
||||
if (!p->pe_data) {
|
||||
if (p->pe->module)
|
||||
module_put(p->pe->module);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memcpy(p->pe_data, pe_data, pe_data_len);
|
||||
p->pe_data_len = pe_data_len;
|
||||
}
|
||||
return 0;
|
||||
@@ -795,7 +794,7 @@ static void ip_vs_proc_conn(struct net *net, struct ip_vs_conn_param *param,
|
||||
|
||||
if (opt)
|
||||
memcpy(&cp->in_seq, opt, sizeof(*opt));
|
||||
atomic_set(&cp->in_pkts, ipvs->sysctl_sync_threshold[0]);
|
||||
atomic_set(&cp->in_pkts, sysctl_sync_threshold(ipvs));
|
||||
cp->state = state;
|
||||
cp->old_state = cp->state;
|
||||
/*
|
||||
|
@@ -1301,6 +1301,7 @@ static void nf_conntrack_cleanup_net(struct net *net)
|
||||
|
||||
nf_ct_free_hashtable(net->ct.hash, net->ct.htable_size);
|
||||
nf_conntrack_ecache_fini(net);
|
||||
nf_conntrack_tstamp_fini(net);
|
||||
nf_conntrack_acct_fini(net);
|
||||
nf_conntrack_expect_fini(net);
|
||||
kmem_cache_destroy(net->ct.nf_conntrack_cachep);
|
||||
|
@@ -183,14 +183,14 @@ EXPORT_SYMBOL(xt_unregister_matches);
|
||||
/*
|
||||
* These are weird, but module loading must not be done with mutex
|
||||
* held (since they will register), and we have to have a single
|
||||
* function to use try_then_request_module().
|
||||
* function to use.
|
||||
*/
|
||||
|
||||
/* Find match, grabs ref. Returns ERR_PTR() on error. */
|
||||
struct xt_match *xt_find_match(u8 af, const char *name, u8 revision)
|
||||
{
|
||||
struct xt_match *m;
|
||||
int err = 0;
|
||||
int err = -ENOENT;
|
||||
|
||||
if (mutex_lock_interruptible(&xt[af].mutex) != 0)
|
||||
return ERR_PTR(-EINTR);
|
||||
@@ -221,9 +221,13 @@ xt_request_find_match(uint8_t nfproto, const char *name, uint8_t revision)
|
||||
{
|
||||
struct xt_match *match;
|
||||
|
||||
match = try_then_request_module(xt_find_match(nfproto, name, revision),
|
||||
"%st_%s", xt_prefix[nfproto], name);
|
||||
return (match != NULL) ? match : ERR_PTR(-ENOENT);
|
||||
match = xt_find_match(nfproto, name, revision);
|
||||
if (IS_ERR(match)) {
|
||||
request_module("%st_%s", xt_prefix[nfproto], name);
|
||||
match = xt_find_match(nfproto, name, revision);
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xt_request_find_match);
|
||||
|
||||
@@ -231,7 +235,7 @@ EXPORT_SYMBOL_GPL(xt_request_find_match);
|
||||
struct xt_target *xt_find_target(u8 af, const char *name, u8 revision)
|
||||
{
|
||||
struct xt_target *t;
|
||||
int err = 0;
|
||||
int err = -ENOENT;
|
||||
|
||||
if (mutex_lock_interruptible(&xt[af].mutex) != 0)
|
||||
return ERR_PTR(-EINTR);
|
||||
@@ -261,9 +265,13 @@ struct xt_target *xt_request_find_target(u8 af, const char *name, u8 revision)
|
||||
{
|
||||
struct xt_target *target;
|
||||
|
||||
target = try_then_request_module(xt_find_target(af, name, revision),
|
||||
"%st_%s", xt_prefix[af], name);
|
||||
return (target != NULL) ? target : ERR_PTR(-ENOENT);
|
||||
target = xt_find_target(af, name, revision);
|
||||
if (IS_ERR(target)) {
|
||||
request_module("%st_%s", xt_prefix[af], name);
|
||||
target = xt_find_target(af, name, revision);
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xt_request_find_target);
|
||||
|
||||
|
229
net/netfilter/xt_addrtype.c
Normal file
229
net/netfilter/xt_addrtype.c
Normal file
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* iptables module to match inet_addr_type() of an ip.
|
||||
*
|
||||
* Copyright (c) 2004 Patrick McHardy <kaber@trash.net>
|
||||
* (C) 2007 Laszlo Attila Toth <panther@balabit.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.
|
||||
*/
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/ip.h>
|
||||
#include <net/route.h>
|
||||
|
||||
#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
|
||||
#include <net/ipv6.h>
|
||||
#include <net/ip6_route.h>
|
||||
#include <net/ip6_fib.h>
|
||||
#endif
|
||||
|
||||
#include <linux/netfilter/xt_addrtype.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
|
||||
MODULE_DESCRIPTION("Xtables: address type match");
|
||||
MODULE_ALIAS("ipt_addrtype");
|
||||
MODULE_ALIAS("ip6t_addrtype");
|
||||
|
||||
#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
|
||||
static u32 xt_addrtype_rt6_to_type(const struct rt6_info *rt)
|
||||
{
|
||||
u32 ret;
|
||||
|
||||
if (!rt)
|
||||
return XT_ADDRTYPE_UNREACHABLE;
|
||||
|
||||
if (rt->rt6i_flags & RTF_REJECT)
|
||||
ret = XT_ADDRTYPE_UNREACHABLE;
|
||||
else
|
||||
ret = 0;
|
||||
|
||||
if (rt->rt6i_flags & RTF_LOCAL)
|
||||
ret |= XT_ADDRTYPE_LOCAL;
|
||||
if (rt->rt6i_flags & RTF_ANYCAST)
|
||||
ret |= XT_ADDRTYPE_ANYCAST;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool match_type6(struct net *net, const struct net_device *dev,
|
||||
const struct in6_addr *addr, u16 mask)
|
||||
{
|
||||
int addr_type = ipv6_addr_type(addr);
|
||||
|
||||
if ((mask & XT_ADDRTYPE_MULTICAST) &&
|
||||
!(addr_type & IPV6_ADDR_MULTICAST))
|
||||
return false;
|
||||
if ((mask & XT_ADDRTYPE_UNICAST) && !(addr_type & IPV6_ADDR_UNICAST))
|
||||
return false;
|
||||
if ((mask & XT_ADDRTYPE_UNSPEC) && addr_type != IPV6_ADDR_ANY)
|
||||
return false;
|
||||
|
||||
if ((XT_ADDRTYPE_LOCAL | XT_ADDRTYPE_ANYCAST |
|
||||
XT_ADDRTYPE_UNREACHABLE) & mask) {
|
||||
struct rt6_info *rt;
|
||||
u32 type;
|
||||
int ifindex = dev ? dev->ifindex : 0;
|
||||
|
||||
rt = rt6_lookup(net, addr, NULL, ifindex, !!dev);
|
||||
|
||||
type = xt_addrtype_rt6_to_type(rt);
|
||||
|
||||
dst_release(&rt->dst);
|
||||
return !!(mask & type);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
addrtype_mt6(struct net *net, const struct net_device *dev,
|
||||
const struct sk_buff *skb, const struct xt_addrtype_info_v1 *info)
|
||||
{
|
||||
const struct ipv6hdr *iph = ipv6_hdr(skb);
|
||||
bool ret = true;
|
||||
|
||||
if (info->source)
|
||||
ret &= match_type6(net, dev, &iph->saddr, info->source) ^
|
||||
(info->flags & XT_ADDRTYPE_INVERT_SOURCE);
|
||||
if (ret && info->dest)
|
||||
ret &= match_type6(net, dev, &iph->daddr, info->dest) ^
|
||||
!!(info->flags & XT_ADDRTYPE_INVERT_DEST);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline bool match_type(struct net *net, const struct net_device *dev,
|
||||
__be32 addr, u_int16_t mask)
|
||||
{
|
||||
return !!(mask & (1 << inet_dev_addr_type(net, dev, addr)));
|
||||
}
|
||||
|
||||
static bool
|
||||
addrtype_mt_v0(const struct sk_buff *skb, struct xt_action_param *par)
|
||||
{
|
||||
struct net *net = dev_net(par->in ? par->in : par->out);
|
||||
const struct xt_addrtype_info *info = par->matchinfo;
|
||||
const struct iphdr *iph = ip_hdr(skb);
|
||||
bool ret = true;
|
||||
|
||||
if (info->source)
|
||||
ret &= match_type(net, NULL, iph->saddr, info->source) ^
|
||||
info->invert_source;
|
||||
if (info->dest)
|
||||
ret &= match_type(net, NULL, iph->daddr, info->dest) ^
|
||||
info->invert_dest;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool
|
||||
addrtype_mt_v1(const struct sk_buff *skb, struct xt_action_param *par)
|
||||
{
|
||||
struct net *net = dev_net(par->in ? par->in : par->out);
|
||||
const struct xt_addrtype_info_v1 *info = par->matchinfo;
|
||||
const struct iphdr *iph;
|
||||
const struct net_device *dev = NULL;
|
||||
bool ret = true;
|
||||
|
||||
if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN)
|
||||
dev = par->in;
|
||||
else if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT)
|
||||
dev = par->out;
|
||||
|
||||
#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
|
||||
if (par->family == NFPROTO_IPV6)
|
||||
return addrtype_mt6(net, dev, skb, info);
|
||||
#endif
|
||||
iph = ip_hdr(skb);
|
||||
if (info->source)
|
||||
ret &= match_type(net, dev, iph->saddr, info->source) ^
|
||||
(info->flags & XT_ADDRTYPE_INVERT_SOURCE);
|
||||
if (ret && info->dest)
|
||||
ret &= match_type(net, dev, iph->daddr, info->dest) ^
|
||||
!!(info->flags & XT_ADDRTYPE_INVERT_DEST);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int addrtype_mt_checkentry_v1(const struct xt_mtchk_param *par)
|
||||
{
|
||||
struct xt_addrtype_info_v1 *info = par->matchinfo;
|
||||
|
||||
if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN &&
|
||||
info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT) {
|
||||
pr_info("both incoming and outgoing "
|
||||
"interface limitation cannot be selected\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (par->hook_mask & ((1 << NF_INET_PRE_ROUTING) |
|
||||
(1 << NF_INET_LOCAL_IN)) &&
|
||||
info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT) {
|
||||
pr_info("output interface limitation "
|
||||
"not valid in PREROUTING and INPUT\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (par->hook_mask & ((1 << NF_INET_POST_ROUTING) |
|
||||
(1 << NF_INET_LOCAL_OUT)) &&
|
||||
info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN) {
|
||||
pr_info("input interface limitation "
|
||||
"not valid in POSTROUTING and OUTPUT\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
|
||||
if (par->family == NFPROTO_IPV6) {
|
||||
if ((info->source | info->dest) & XT_ADDRTYPE_BLACKHOLE) {
|
||||
pr_err("ipv6 BLACKHOLE matching not supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if ((info->source | info->dest) >= XT_ADDRTYPE_PROHIBIT) {
|
||||
pr_err("ipv6 PROHIBT (THROW, NAT ..) matching not supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if ((info->source | info->dest) & XT_ADDRTYPE_BROADCAST) {
|
||||
pr_err("ipv6 does not support BROADCAST matching\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct xt_match addrtype_mt_reg[] __read_mostly = {
|
||||
{
|
||||
.name = "addrtype",
|
||||
.family = NFPROTO_IPV4,
|
||||
.match = addrtype_mt_v0,
|
||||
.matchsize = sizeof(struct xt_addrtype_info),
|
||||
.me = THIS_MODULE
|
||||
},
|
||||
{
|
||||
.name = "addrtype",
|
||||
.family = NFPROTO_UNSPEC,
|
||||
.revision = 1,
|
||||
.match = addrtype_mt_v1,
|
||||
.checkentry = addrtype_mt_checkentry_v1,
|
||||
.matchsize = sizeof(struct xt_addrtype_info_v1),
|
||||
.me = THIS_MODULE
|
||||
}
|
||||
};
|
||||
|
||||
static int __init addrtype_mt_init(void)
|
||||
{
|
||||
return xt_register_matches(addrtype_mt_reg,
|
||||
ARRAY_SIZE(addrtype_mt_reg));
|
||||
}
|
||||
|
||||
static void __exit addrtype_mt_exit(void)
|
||||
{
|
||||
xt_unregister_matches(addrtype_mt_reg, ARRAY_SIZE(addrtype_mt_reg));
|
||||
}
|
||||
|
||||
module_init(addrtype_mt_init);
|
||||
module_exit(addrtype_mt_exit);
|
@@ -33,17 +33,17 @@
|
||||
|
||||
/* we will save the tuples of all connections we care about */
|
||||
struct xt_connlimit_conn {
|
||||
struct list_head list;
|
||||
struct nf_conntrack_tuple tuple;
|
||||
struct hlist_node node;
|
||||
struct nf_conntrack_tuple tuple;
|
||||
union nf_inet_addr addr;
|
||||
};
|
||||
|
||||
struct xt_connlimit_data {
|
||||
struct list_head iphash[256];
|
||||
spinlock_t lock;
|
||||
struct hlist_head iphash[256];
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
static u_int32_t connlimit_rnd __read_mostly;
|
||||
static bool connlimit_rnd_inited __read_mostly;
|
||||
|
||||
static inline unsigned int connlimit_iphash(__be32 addr)
|
||||
{
|
||||
@@ -101,9 +101,9 @@ static int count_them(struct net *net,
|
||||
{
|
||||
const struct nf_conntrack_tuple_hash *found;
|
||||
struct xt_connlimit_conn *conn;
|
||||
struct xt_connlimit_conn *tmp;
|
||||
struct hlist_node *pos, *n;
|
||||
struct nf_conn *found_ct;
|
||||
struct list_head *hash;
|
||||
struct hlist_head *hash;
|
||||
bool addit = true;
|
||||
int matches = 0;
|
||||
|
||||
@@ -115,7 +115,7 @@ static int count_them(struct net *net,
|
||||
rcu_read_lock();
|
||||
|
||||
/* check the saved connections */
|
||||
list_for_each_entry_safe(conn, tmp, hash, list) {
|
||||
hlist_for_each_entry_safe(conn, pos, n, hash, node) {
|
||||
found = nf_conntrack_find_get(net, NF_CT_DEFAULT_ZONE,
|
||||
&conn->tuple);
|
||||
found_ct = NULL;
|
||||
@@ -135,7 +135,7 @@ static int count_them(struct net *net,
|
||||
|
||||
if (found == NULL) {
|
||||
/* this one is gone */
|
||||
list_del(&conn->list);
|
||||
hlist_del(&conn->node);
|
||||
kfree(conn);
|
||||
continue;
|
||||
}
|
||||
@@ -146,12 +146,12 @@ static int count_them(struct net *net,
|
||||
* closed already -> ditch it
|
||||
*/
|
||||
nf_ct_put(found_ct);
|
||||
list_del(&conn->list);
|
||||
hlist_del(&conn->node);
|
||||
kfree(conn);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (same_source_net(addr, mask, &conn->tuple.src.u3, family))
|
||||
if (same_source_net(addr, mask, &conn->addr, family))
|
||||
/* same source network -> be counted! */
|
||||
++matches;
|
||||
nf_ct_put(found_ct);
|
||||
@@ -161,11 +161,12 @@ static int count_them(struct net *net,
|
||||
|
||||
if (addit) {
|
||||
/* save the new connection in our list */
|
||||
conn = kzalloc(sizeof(*conn), GFP_ATOMIC);
|
||||
conn = kmalloc(sizeof(*conn), GFP_ATOMIC);
|
||||
if (conn == NULL)
|
||||
return -ENOMEM;
|
||||
conn->tuple = *tuple;
|
||||
list_add(&conn->list, hash);
|
||||
conn->addr = *addr;
|
||||
hlist_add_head(&conn->node, hash);
|
||||
++matches;
|
||||
}
|
||||
|
||||
@@ -185,15 +186,11 @@ connlimit_mt(const struct sk_buff *skb, struct xt_action_param *par)
|
||||
int connections;
|
||||
|
||||
ct = nf_ct_get(skb, &ctinfo);
|
||||
if (ct != NULL) {
|
||||
if (info->flags & XT_CONNLIMIT_DADDR)
|
||||
tuple_ptr = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;
|
||||
else
|
||||
tuple_ptr = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
|
||||
} else if (!nf_ct_get_tuplepr(skb, skb_network_offset(skb),
|
||||
par->family, &tuple)) {
|
||||
if (ct != NULL)
|
||||
tuple_ptr = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
|
||||
else if (!nf_ct_get_tuplepr(skb, skb_network_offset(skb),
|
||||
par->family, &tuple))
|
||||
goto hotdrop;
|
||||
}
|
||||
|
||||
if (par->family == NFPROTO_IPV6) {
|
||||
const struct ipv6hdr *iph = ipv6_hdr(skb);
|
||||
@@ -228,9 +225,13 @@ static int connlimit_mt_check(const struct xt_mtchk_param *par)
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
if (unlikely(!connlimit_rnd_inited)) {
|
||||
get_random_bytes(&connlimit_rnd, sizeof(connlimit_rnd));
|
||||
connlimit_rnd_inited = true;
|
||||
if (unlikely(!connlimit_rnd)) {
|
||||
u_int32_t rand;
|
||||
|
||||
do {
|
||||
get_random_bytes(&rand, sizeof(rand));
|
||||
} while (!rand);
|
||||
cmpxchg(&connlimit_rnd, 0, rand);
|
||||
}
|
||||
ret = nf_ct_l3proto_try_module_get(par->family);
|
||||
if (ret < 0) {
|
||||
@@ -248,7 +249,7 @@ static int connlimit_mt_check(const struct xt_mtchk_param *par)
|
||||
|
||||
spin_lock_init(&info->data->lock);
|
||||
for (i = 0; i < ARRAY_SIZE(info->data->iphash); ++i)
|
||||
INIT_LIST_HEAD(&info->data->iphash[i]);
|
||||
INIT_HLIST_HEAD(&info->data->iphash[i]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -257,15 +258,15 @@ static void connlimit_mt_destroy(const struct xt_mtdtor_param *par)
|
||||
{
|
||||
const struct xt_connlimit_info *info = par->matchinfo;
|
||||
struct xt_connlimit_conn *conn;
|
||||
struct xt_connlimit_conn *tmp;
|
||||
struct list_head *hash = info->data->iphash;
|
||||
struct hlist_node *pos, *n;
|
||||
struct hlist_head *hash = info->data->iphash;
|
||||
unsigned int i;
|
||||
|
||||
nf_ct_l3proto_module_put(par->family);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(info->data->iphash); ++i) {
|
||||
list_for_each_entry_safe(conn, tmp, &hash[i], list) {
|
||||
list_del(&conn->list);
|
||||
hlist_for_each_entry_safe(conn, pos, n, &hash[i], node) {
|
||||
hlist_del(&conn->node);
|
||||
kfree(conn);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user