--- a/include/linux/timer.h +++ b/include/linux/timer.h @@ -17,6 +17,7 @@ struct timer_list { unsigned long expires; void (*function)(struct timer_list *); u32 flags; + unsigned long cust_data; #ifdef CONFIG_LOCKDEP struct lockdep_map lockdep_map; --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h @@ -51,6 +51,8 @@ #define BR_DEFAULT_AGEING_TIME (300 * HZ) extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void __user *)); +extern void br_dev_update_stats(struct net_device *dev, + struct rtnl_link_stats64 *nlstats); #if IS_ENABLED(CONFIG_BRIDGE) && IS_ENABLED(CONFIG_BRIDGE_IGMP_SNOOPING) int br_multicast_list_adjacent(struct net_device *dev, --- a/include/net/netns/conntrack.h +++ b/include/net/netns/conntrack.h @@ -112,6 +112,9 @@ struct netns_ct { struct ct_pcpu __percpu *pcpu_lists; struct ip_conntrack_stat __percpu *stat; +#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS + struct atomic_notifier_head nf_conntrack_chain; +#endif struct nf_ct_event_notifier __rcu *nf_conntrack_event_cb; struct nf_exp_event_notifier __rcu *nf_expect_event_cb; struct nf_ip_net nf_ct_proto; --- a/include/net/netfilter/nf_conntrack_ecache.h +++ b/include/net/netfilter/nf_conntrack_ecache.h @@ -72,6 +72,11 @@ struct nf_ct_event { int report; }; +#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS +extern int nf_conntrack_register_chain_notifier(struct net *net, struct notifier_block *nb); +extern int nf_conntrack_unregister_chain_notifier(struct net *net, struct notifier_block *nb); +#endif + struct nf_ct_event_notifier { int (*fcn)(unsigned int events, struct nf_ct_event *item); }; @@ -105,11 +110,13 @@ static inline void nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct) { #ifdef CONFIG_NF_CONNTRACK_EVENTS - struct net *net = nf_ct_net(ct); struct nf_conntrack_ecache *e; +#ifndef CONFIG_NF_CONNTRACK_CHAIN_EVENTS + struct net *net = nf_ct_net(ct); if (!rcu_access_pointer(net->ct.nf_conntrack_event_cb)) return; +#endif e = nf_ct_ecache_find(ct); if (e == NULL) @@ -124,10 +131,12 @@ nf_conntrack_event_report(enum ip_conntr u32 portid, int report) { #ifdef CONFIG_NF_CONNTRACK_EVENTS +#ifndef CONFIG_NF_CONNTRACK_CHAIN_EVENTS const struct net *net = nf_ct_net(ct); if (!rcu_access_pointer(net->ct.nf_conntrack_event_cb)) return 0; +#endif return nf_conntrack_eventmask_report(1 << event, ct, portid, report); #else @@ -139,10 +148,12 @@ static inline int nf_conntrack_event(enum ip_conntrack_events event, struct nf_conn *ct) { #ifdef CONFIG_NF_CONNTRACK_EVENTS +#ifndef CONFIG_NF_CONNTRACK_CHAIN_EVENTS const struct net *net = nf_ct_net(ct); if (!rcu_access_pointer(net->ct.nf_conntrack_event_cb)) return 0; +#endif return nf_conntrack_eventmask_report(1 << event, ct, 0, 0); #else --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -33,11 +33,13 @@ /* Do not check the TCP window for incoming packets */ -static int nf_ct_tcp_no_window_check __read_mostly = 1; +int nf_ct_tcp_no_window_check __read_mostly = 1; +EXPORT_SYMBOL_GPL(nf_ct_tcp_no_window_check); /* "Be conservative in what you do, be liberal in what you accept from others." If it's non-zero, we mark only out of window RST segments as INVALID. */ -static int nf_ct_tcp_be_liberal __read_mostly = 0; +int nf_ct_tcp_be_liberal __read_mostly = 0; +EXPORT_SYMBOL_GPL(nf_ct_tcp_be_liberal); /* If it is set to zero, we disable picking up already established connections. */ --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -757,3 +757,26 @@ return p->flags & flag; } EXPORT_SYMBOL_GPL(br_port_flag_is_set); + +/* Update bridge statistics for bridge packets processed by offload engines */ +void br_dev_update_stats(struct net_device *dev, + struct rtnl_link_stats64 *nlstats) +{ + struct net_bridge *br; + struct pcpu_sw_netstats *stats; + + /* Is this a bridge? */ + if (!(dev->priv_flags & IFF_EBRIDGE)) + return; + + br = netdev_priv(dev); + stats = this_cpu_ptr(br->stats); + + u64_stats_update_begin(&stats->syncp); + stats->rx_packets += nlstats->rx_packets; + stats->rx_bytes += nlstats->rx_bytes; + stats->tx_packets += nlstats->tx_packets; + stats->tx_bytes += nlstats->tx_bytes; + u64_stats_update_end(&stats->syncp); +} +EXPORT_SYMBOL_GPL(br_dev_update_stats); --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -158,6 +158,14 @@ If unsure, say `N'. +config NF_CONNTRACK_CHAIN_EVENTS + bool "Register multiple callbacks to ct events" + depends on NF_CONNTRACK_EVENTS + help + Support multiple registrations. + + If unsure, say `N'. + config NF_CONNTRACK_TIMESTAMP bool 'Connection tracking timestamping' depends on NETFILTER_ADVANCED --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -2588,6 +2588,9 @@ int nf_conntrack_init_net(struct net *ne nf_conntrack_ecache_pernet_init(net); nf_conntrack_helper_pernet_init(net); nf_conntrack_proto_pernet_init(net); +#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS + ATOMIC_INIT_NOTIFIER_HEAD(&net->ct.nf_conntrack_chain); +#endif return 0; --- a/net/netfilter/nf_conntrack_ecache.c +++ b/net/netfilter/nf_conntrack_ecache.c @@ -17,6 +17,9 @@ #include #include #include +#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS +#include +#endif #include #include #include @@ -127,7 +130,11 @@ int nf_conntrack_eventmask_report(unsign rcu_read_lock(); notify = rcu_dereference(net->ct.nf_conntrack_event_cb); +#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS + if (!notify && !rcu_dereference_raw(net->ct.nf_conntrack_chain.head)) +#else if (!notify) +#endif goto out_unlock; e = nf_ct_ecache_find(ct); @@ -146,7 +153,15 @@ int nf_conntrack_eventmask_report(unsign if (!((eventmask | missed) & e->ctmask)) goto out_unlock; +#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS + ret = atomic_notifier_call_chain(&net->ct.nf_conntrack_chain, + eventmask | missed, &item); + + if (notify) + ret = notify->fcn(eventmask | missed, &item); +#else ret = notify->fcn(eventmask | missed, &item); +#endif if (unlikely(ret < 0 || missed)) { spin_lock_bh(&ct->lock); if (ret < 0) { @@ -186,7 +201,11 @@ void nf_ct_deliver_cached_events(struct rcu_read_lock(); notify = rcu_dereference(net->ct.nf_conntrack_event_cb); +#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS + if ((notify == NULL) && !rcu_dereference_raw(net->ct.nf_conntrack_chain.head)) +#else if (notify == NULL) +#endif goto out_unlock; e = nf_ct_ecache_find(ct); @@ -210,7 +229,16 @@ void nf_ct_deliver_cached_events(struct item.portid = 0; item.report = 0; +#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS + ret = atomic_notifier_call_chain(&net->ct.nf_conntrack_chain, + events | missed, + &item); + + if (notify != NULL) + ret = notify->fcn(events | missed, &item); +#else ret = notify->fcn(events | missed, &item); +#endif if (likely(ret == 0 && !missed)) goto out_unlock; @@ -257,6 +285,14 @@ out_unlock: rcu_read_unlock(); } +#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS +int nf_conntrack_register_chain_notifier(struct net *net, struct notifier_block *nb) +{ + return atomic_notifier_chain_register(&net->ct.nf_conntrack_chain, nb); +} +EXPORT_SYMBOL_GPL(nf_conntrack_register_chain_notifier); +#endif + int nf_conntrack_register_notifier(struct net *net, struct nf_ct_event_notifier *new) { @@ -279,6 +315,14 @@ out_unlock: } EXPORT_SYMBOL_GPL(nf_conntrack_register_notifier); +#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS +int nf_conntrack_unregister_chain_notifier(struct net *net, struct notifier_block *nb) +{ + return atomic_notifier_chain_unregister(&net->ct.nf_conntrack_chain, nb); +} +EXPORT_SYMBOL_GPL(nf_conntrack_unregister_chain_notifier); +#endif + void nf_conntrack_unregister_notifier(struct net *net, struct nf_ct_event_notifier *new) {