1/* 2 * connection tracking event cache. 3 */ 4 5#ifndef _NF_CONNTRACK_ECACHE_H 6#define _NF_CONNTRACK_ECACHE_H 7#include <net/netfilter/nf_conntrack.h> 8 9#include <net/net_namespace.h> 10#include <net/netfilter/nf_conntrack_expect.h> 11#include <linux/netfilter/nf_conntrack_common.h> 12#include <linux/netfilter/nf_conntrack_tuple_common.h> 13#include <net/netfilter/nf_conntrack_extend.h> 14 15struct nf_conntrack_ecache { 16 unsigned long cache; /* bitops want long */ 17 unsigned long missed; /* missed events */ 18 u16 ctmask; /* bitmask of ct events to be delivered */ 19 u16 expmask; /* bitmask of expect events to be delivered */ 20 u32 portid; /* netlink portid of destroyer */ 21}; 22 23static inline struct nf_conntrack_ecache * 24nf_ct_ecache_find(const struct nf_conn *ct) 25{ 26#ifdef CONFIG_NF_CONNTRACK_EVENTS 27 return nf_ct_ext_find(ct, NF_CT_EXT_ECACHE); 28#else 29 return NULL; 30#endif 31} 32 33static inline struct nf_conntrack_ecache * 34nf_ct_ecache_ext_add(struct nf_conn *ct, u16 ctmask, u16 expmask, gfp_t gfp) 35{ 36#ifdef CONFIG_NF_CONNTRACK_EVENTS 37 struct net *net = nf_ct_net(ct); 38 struct nf_conntrack_ecache *e; 39 40 if (!ctmask && !expmask && net->ct.sysctl_events) { 41 ctmask = ~0; 42 expmask = ~0; 43 } 44 if (!ctmask && !expmask) 45 return NULL; 46 47 e = nf_ct_ext_add(ct, NF_CT_EXT_ECACHE, gfp); 48 if (e) { 49 e->ctmask = ctmask; 50 e->expmask = expmask; 51 } 52 return e; 53#else 54 return NULL; 55#endif 56}; 57 58#ifdef CONFIG_NF_CONNTRACK_EVENTS 59/* This structure is passed to event handler */ 60struct nf_ct_event { 61 struct nf_conn *ct; 62 u32 portid; 63 int report; 64}; 65 66struct nf_ct_event_notifier { 67 int (*fcn)(unsigned int events, struct nf_ct_event *item); 68}; 69 70int nf_conntrack_register_notifier(struct net *net, 71 struct nf_ct_event_notifier *nb); 72void nf_conntrack_unregister_notifier(struct net *net, 73 struct nf_ct_event_notifier *nb); 74 75void nf_ct_deliver_cached_events(struct nf_conn *ct); 76 77static inline void 78nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct) 79{ 80 struct net *net = nf_ct_net(ct); 81 struct nf_conntrack_ecache *e; 82 83 if (!rcu_access_pointer(net->ct.nf_conntrack_event_cb)) 84 return; 85 86 e = nf_ct_ecache_find(ct); 87 if (e == NULL) 88 return; 89 90 set_bit(event, &e->cache); 91} 92 93static inline int 94nf_conntrack_eventmask_report(unsigned int eventmask, 95 struct nf_conn *ct, 96 u32 portid, 97 int report) 98{ 99 int ret = 0; 100 struct net *net = nf_ct_net(ct); 101 struct nf_ct_event_notifier *notify; 102 struct nf_conntrack_ecache *e; 103 104 rcu_read_lock(); 105 notify = rcu_dereference(net->ct.nf_conntrack_event_cb); 106 if (notify == NULL) 107 goto out_unlock; 108 109 e = nf_ct_ecache_find(ct); 110 if (e == NULL) 111 goto out_unlock; 112 113 if (nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct)) { 114 struct nf_ct_event item = { 115 .ct = ct, 116 .portid = e->portid ? e->portid : portid, 117 .report = report 118 }; 119 /* This is a resent of a destroy event? If so, skip missed */ 120 unsigned long missed = e->portid ? 0 : e->missed; 121 122 if (!((eventmask | missed) & e->ctmask)) 123 goto out_unlock; 124 125 ret = notify->fcn(eventmask | missed, &item); 126 if (unlikely(ret < 0 || missed)) { 127 spin_lock_bh(&ct->lock); 128 if (ret < 0) { 129 /* This is a destroy event that has been 130 * triggered by a process, we store the PORTID 131 * to include it in the retransmission. */ 132 if (eventmask & (1 << IPCT_DESTROY) && 133 e->portid == 0 && portid != 0) 134 e->portid = portid; 135 else 136 e->missed |= eventmask; 137 } else 138 e->missed &= ~missed; 139 spin_unlock_bh(&ct->lock); 140 } 141 } 142out_unlock: 143 rcu_read_unlock(); 144 return ret; 145} 146 147static inline int 148nf_conntrack_event_report(enum ip_conntrack_events event, struct nf_conn *ct, 149 u32 portid, int report) 150{ 151 return nf_conntrack_eventmask_report(1 << event, ct, portid, report); 152} 153 154static inline int 155nf_conntrack_event(enum ip_conntrack_events event, struct nf_conn *ct) 156{ 157 return nf_conntrack_eventmask_report(1 << event, ct, 0, 0); 158} 159 160struct nf_exp_event { 161 struct nf_conntrack_expect *exp; 162 u32 portid; 163 int report; 164}; 165 166struct nf_exp_event_notifier { 167 int (*fcn)(unsigned int events, struct nf_exp_event *item); 168}; 169 170int nf_ct_expect_register_notifier(struct net *net, 171 struct nf_exp_event_notifier *nb); 172void nf_ct_expect_unregister_notifier(struct net *net, 173 struct nf_exp_event_notifier *nb); 174 175static inline void 176nf_ct_expect_event_report(enum ip_conntrack_expect_events event, 177 struct nf_conntrack_expect *exp, 178 u32 portid, 179 int report) 180{ 181 struct net *net = nf_ct_exp_net(exp); 182 struct nf_exp_event_notifier *notify; 183 struct nf_conntrack_ecache *e; 184 185 rcu_read_lock(); 186 notify = rcu_dereference(net->ct.nf_expect_event_cb); 187 if (notify == NULL) 188 goto out_unlock; 189 190 e = nf_ct_ecache_find(exp->master); 191 if (e == NULL) 192 goto out_unlock; 193 194 if (e->expmask & (1 << event)) { 195 struct nf_exp_event item = { 196 .exp = exp, 197 .portid = portid, 198 .report = report 199 }; 200 notify->fcn(1 << event, &item); 201 } 202out_unlock: 203 rcu_read_unlock(); 204} 205 206static inline void 207nf_ct_expect_event(enum ip_conntrack_expect_events event, 208 struct nf_conntrack_expect *exp) 209{ 210 nf_ct_expect_event_report(event, exp, 0, 0); 211} 212 213int nf_conntrack_ecache_pernet_init(struct net *net); 214void nf_conntrack_ecache_pernet_fini(struct net *net); 215 216int nf_conntrack_ecache_init(void); 217void nf_conntrack_ecache_fini(void); 218 219static inline void nf_conntrack_ecache_delayed_work(struct net *net) 220{ 221 if (!delayed_work_pending(&net->ct.ecache_dwork)) { 222 schedule_delayed_work(&net->ct.ecache_dwork, HZ); 223 net->ct.ecache_dwork_pending = true; 224 } 225} 226 227static inline void nf_conntrack_ecache_work(struct net *net) 228{ 229 if (net->ct.ecache_dwork_pending) { 230 net->ct.ecache_dwork_pending = false; 231 mod_delayed_work(system_wq, &net->ct.ecache_dwork, 0); 232 } 233} 234#else /* CONFIG_NF_CONNTRACK_EVENTS */ 235static inline void nf_conntrack_event_cache(enum ip_conntrack_events event, 236 struct nf_conn *ct) {} 237static inline int nf_conntrack_eventmask_report(unsigned int eventmask, 238 struct nf_conn *ct, 239 u32 portid, 240 int report) { return 0; } 241static inline int nf_conntrack_event(enum ip_conntrack_events event, 242 struct nf_conn *ct) { return 0; } 243static inline int nf_conntrack_event_report(enum ip_conntrack_events event, 244 struct nf_conn *ct, 245 u32 portid, 246 int report) { return 0; } 247static inline void nf_ct_deliver_cached_events(const struct nf_conn *ct) {} 248static inline void nf_ct_expect_event(enum ip_conntrack_expect_events event, 249 struct nf_conntrack_expect *exp) {} 250static inline void nf_ct_expect_event_report(enum ip_conntrack_expect_events e, 251 struct nf_conntrack_expect *exp, 252 u32 portid, 253 int report) {} 254 255static inline int nf_conntrack_ecache_pernet_init(struct net *net) 256{ 257 return 0; 258} 259 260static inline void nf_conntrack_ecache_pernet_fini(struct net *net) 261{ 262} 263 264static inline int nf_conntrack_ecache_init(void) 265{ 266 return 0; 267} 268 269static inline void nf_conntrack_ecache_fini(void) 270{ 271} 272 273static inline void nf_conntrack_ecache_delayed_work(struct net *net) 274{ 275} 276 277static inline void nf_conntrack_ecache_work(struct net *net) 278{ 279} 280#endif /* CONFIG_NF_CONNTRACK_EVENTS */ 281 282#endif /*_NF_CONNTRACK_ECACHE_H*/ 283 284