blob: cc691041c72c1a33bcda9002ea6da0c6c88ceca0 [file] [log] [blame]
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001/*
2 * sfe-cm.c
3 * Shortcut forwarding engine connection manager.
4 *
Xiaoping Fana42c68b2015-08-07 18:00:39 -07005 * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved.
6 * Permission to use, copy, modify, and/or distribute this software for
7 * any purpose with or without fee is hereby granted, provided that the
8 * above copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Dave Hudsondcd08fb2013-11-22 09:25:16 -060016 */
Matthew McClintocka3221942014-01-16 11:44:26 -060017
Dave Hudsondcd08fb2013-11-22 09:25:16 -060018#include <linux/module.h>
19#include <linux/sysfs.h>
20#include <linux/skbuff.h>
21#include <net/route.h>
Xiaoping Fan978b3772015-05-27 14:15:18 -070022#include <net/ip6_route.h>
23#include <net/addrconf.h>
Dave Hudsondcd08fb2013-11-22 09:25:16 -060024#include <linux/inetdevice.h>
25#include <linux/netfilter_bridge.h>
Xiaoping Fan978b3772015-05-27 14:15:18 -070026#include <linux/netfilter_ipv6.h>
Dave Hudsondcd08fb2013-11-22 09:25:16 -060027#include <net/netfilter/nf_conntrack_acct.h>
28#include <net/netfilter/nf_conntrack_helper.h>
29#include <net/netfilter/nf_conntrack_zones.h>
30#include <net/netfilter/nf_conntrack_core.h>
Matthew McClintockbf6b5bc2014-02-24 12:27:14 -060031#include <linux/if_bridge.h>
Dave Hudsondcd08fb2013-11-22 09:25:16 -060032
33#include "sfe.h"
Xiaoping Fand44a5b42015-05-26 17:37:37 -070034#include "sfe_cm.h"
Xiaoping Fan3f1fe512014-11-05 12:14:57 -080035#include "sfe_backport.h"
Dave Hudsondcd08fb2013-11-22 09:25:16 -060036
Xiaoping Fan82c21512015-06-30 01:15:23 -070037typedef enum sfe_cm_exception {
38 SFE_CM_EXCEPTION_PACKET_BROADCAST,
39 SFE_CM_EXCEPTION_PACKET_MULTICAST,
40 SFE_CM_EXCEPTION_NO_IIF,
41 SFE_CM_EXCEPTION_NO_CT,
42 SFE_CM_EXCEPTION_CT_NO_TRACK,
43 SFE_CM_EXCEPTION_CT_NO_CONFIRM,
44 SFE_CM_EXCEPTION_CT_IS_ALG,
45 SFE_CM_EXCEPTION_IS_IPV4_MCAST,
46 SFE_CM_EXCEPTION_IS_IPV6_MCAST,
47 SFE_CM_EXCEPTION_TCP_NOT_ASSURED,
48 SFE_CM_EXCEPTION_TCP_NOT_ESTABLISHED,
49 SFE_CM_EXCEPTION_UNKNOW_PROTOCOL,
50 SFE_CM_EXCEPTION_NO_SRC_DEV,
51 SFE_CM_EXCEPTION_NO_SRC_XLATE_DEV,
52 SFE_CM_EXCEPTION_NO_DEST_DEV,
53 SFE_CM_EXCEPTION_NO_DEST_XLATE_DEV,
54 SFE_CM_EXCEPTION_NO_BRIDGE,
Xiaoping Fan1d8d69d2015-08-03 13:36:01 -070055 SFE_CM_EXCEPTION_LOCAL_OUT,
Xiaoping Fan82c21512015-06-30 01:15:23 -070056 SFE_CM_EXCEPTION_MAX
57} sfe_cm_exception_t;
58
59static char *sfe_cm_exception_events_string[SFE_CM_EXCEPTION_MAX] = {
60 "PACKET_BROADCAST",
61 "PACKET_MULTICAST",
62 "NO_IIF",
63 "NO_CT",
64 "CT_NO_TRACK",
65 "CT_NO_CONFIRM",
66 "CT_IS_ALG",
67 "IS_IPV4_MCAST",
68 "IS_IPV6_MCAST",
69 "TCP_NOT_ASSURED",
70 "TCP_NOT_ESTABLISHED",
71 "UNKNOW_PROTOCOL",
72 "NO_SRC_DEV",
73 "NO_SRC_XLATE_DEV",
74 "NO_DEST_DEV",
75 "NO_DEST_XLATE_DEV",
Xiaoping Fan1d8d69d2015-08-03 13:36:01 -070076 "NO_BRIDGE",
77 "LOCAL_OUT"
Xiaoping Fan82c21512015-06-30 01:15:23 -070078};
79
Dave Hudsondcd08fb2013-11-22 09:25:16 -060080/*
81 * Per-module structure.
82 */
83struct sfe_cm {
84 spinlock_t lock; /* Lock for SMP correctness */
85
86 /*
87 * Control state.
88 */
89 struct kobject *sys_sfe_cm; /* sysfs linkage */
90
91 /*
92 * Callback notifiers.
93 */
94 struct notifier_block dev_notifier;
95 /* Device notifier */
96 struct notifier_block inet_notifier;
Xiaoping Fan978b3772015-05-27 14:15:18 -070097 /* IPv4 notifier */
98 struct notifier_block inet6_notifier;
99 /* IPv6 notifier */
Xiaoping Fan82c21512015-06-30 01:15:23 -0700100 uint32_t exceptions[SFE_CM_EXCEPTION_MAX];
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600101};
102
103struct sfe_cm __sc;
104
105/*
106 * Expose the hook for the receive processing.
107 */
108extern int (*athrs_fast_nat_recv)(struct sk_buff *skb);
109
110/*
111 * Expose what should be a static flag in the TCP connection tracker.
112 */
113extern int nf_ct_tcp_no_window_check;
114
115/*
Xiaoping Fan82c21512015-06-30 01:15:23 -0700116 * sfe_cm_incr_exceptions()
117 * increase an exception counter.
118 */
119static inline void sfe_cm_incr_exceptions(sfe_cm_exception_t except)
120{
121 struct sfe_cm *sc = &__sc;
122
123 spin_lock_bh(&sc->lock);
124 sc->exceptions[except]++;
125 spin_unlock_bh(&sc->lock);
126}
127
128/*
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600129 * sfe_cm_recv()
130 * Handle packet receives.
131 *
132 * Returns 1 if the packet is forwarded or 0 if it isn't.
133 */
134int sfe_cm_recv(struct sk_buff *skb)
135{
136 struct net_device *dev;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600137
138 /*
139 * We know that for the vast majority of packets we need the transport
140 * layer header so we may as well start to fetch it now!
141 */
142 prefetch(skb->data + 32);
143 barrier();
144
145 dev = skb->dev;
146
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600147 /*
Xiaoping Fan978b3772015-05-27 14:15:18 -0700148 * We're only interested in IPv4 and IPv6 packets.
Xiaoping Fan59176422015-05-22 15:58:10 -0700149 */
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600150 if (likely(htons(ETH_P_IP) == skb->protocol)) {
Xiaoping Fan978b3772015-05-27 14:15:18 -0700151#if (SFE_HOOK_ABOVE_BRIDGE)
152 struct in_device *in_dev;
153
154 /*
155 * Does our input device support IP processing?
156 */
157 in_dev = (struct in_device *)dev->ip_ptr;
158 if (unlikely(!in_dev)) {
159 DEBUG_TRACE("no IP processing for device: %s\n", dev->name);
160 return 0;
161 }
162
163 /*
164 * Does it have an IP address? If it doesn't then we can't do anything
165 * interesting here!
166 */
167 if (unlikely(!in_dev->ifa_list)) {
168 DEBUG_TRACE("no IP address for device: %s\n", dev->name);
169 return 0;
170 }
171#endif
172
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600173 return sfe_ipv4_recv(dev, skb);
174 }
175
Xiaoping Fan978b3772015-05-27 14:15:18 -0700176 if (likely(htons(ETH_P_IPV6) == skb->protocol)) {
177#if (SFE_HOOK_ABOVE_BRIDGE)
178 struct inet6_dev *in_dev;
179
180 /*
181 * Does our input device support IPv6 processing?
182 */
183 in_dev = (struct inet6_dev *)dev->ip6_ptr;
184 if (unlikely(!in_dev)) {
185 DEBUG_TRACE("no IPv6 processing for device: %s\n", dev->name);
186 return 0;
187 }
188
189 /*
190 * Does it have an IPv6 address? If it doesn't then we can't do anything
191 * interesting here!
192 */
193 if (unlikely(list_empty(&in_dev->addr_list))) {
194 DEBUG_TRACE("no IPv6 address for device: %s\n", dev->name);
195 return 0;
196 }
197#endif
198
199 return sfe_ipv6_recv(dev, skb);
200 }
201
Matthew McClintocka8ad7962014-01-16 16:49:30 -0600202 DEBUG_TRACE("not IP packet\n");
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600203 return 0;
204}
205
206/*
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600207 * sfe_cm_find_dev_and_mac_addr()
Xiaoping Fan978b3772015-05-27 14:15:18 -0700208 * Find the device and MAC address for a given IPv4/IPv6 address.
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600209 *
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600210 * Returns true if we find the device and MAC address, otherwise false.
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600211 *
212 * We look up the rtable entry for the address and, from its neighbour
213 * structure, obtain the hardware address. This means this function also
214 * works if the neighbours are routers too.
215 */
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700216static bool sfe_cm_find_dev_and_mac_addr(sfe_ip_addr_t *addr, struct net_device **dev, uint8_t *mac_addr, int is_v4)
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600217{
218 struct neighbour *neigh;
219 struct rtable *rt;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700220 struct rt6_info *rt6;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600221 struct dst_entry *dst;
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600222 struct net_device *mac_dev;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600223
224 /*
225 * Look up the rtable entry for the IP address then get the hardware
226 * address from its neighbour structure. This means this work when the
227 * neighbours are routers too.
228 */
Xiaoping Fan978b3772015-05-27 14:15:18 -0700229 if (likely(is_v4)) {
230 rt = ip_route_output(&init_net, addr->ip, 0, 0, 0);
231 if (unlikely(IS_ERR(rt))) {
232 goto ret_fail;
233 }
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600234
Xiaoping Fan978b3772015-05-27 14:15:18 -0700235 dst = (struct dst_entry *)rt;
236 } else {
237 rt6 = rt6_lookup(&init_net, (struct in6_addr *)addr->ip6, 0, 0, 0);
238 if (!rt6) {
239 goto ret_fail;
240 }
241
242 dst = (struct dst_entry *)rt6;
243 }
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600244
245 rcu_read_lock();
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700246 neigh = dst_neigh_lookup(dst, addr);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600247 if (unlikely(!neigh)) {
248 rcu_read_unlock();
249 dst_release(dst);
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700250 goto ret_fail;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600251 }
252
253 if (unlikely(!(neigh->nud_state & NUD_VALID))) {
254 rcu_read_unlock();
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700255 neigh_release(neigh);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600256 dst_release(dst);
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700257 goto ret_fail;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600258 }
259
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600260 mac_dev = neigh->dev;
261 if (!mac_dev) {
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600262 rcu_read_unlock();
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700263 neigh_release(neigh);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600264 dst_release(dst);
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700265 goto ret_fail;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600266 }
267
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600268 memcpy(mac_addr, neigh->ha, (size_t)mac_dev->addr_len);
269
270 dev_hold(mac_dev);
271 *dev = mac_dev;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600272 rcu_read_unlock();
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700273 neigh_release(neigh);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600274 dst_release(dst);
275
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600276 return true;
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700277
278ret_fail:
279 if (is_v4) {
280 DEBUG_TRACE("failed to find MAC address for IP: %pI4\n", &addr->ip);
281
282 } else {
283 DEBUG_TRACE("failed to find MAC address for IP: %pI6\n", addr->ip6);
284 }
285
286 return false;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600287}
288
289/*
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700290 * sfe_cm_post_routing()
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600291 * Called for packets about to leave the box - either locally generated or forwarded from another interface
292 */
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700293static unsigned int sfe_cm_post_routing(struct sk_buff *skb, int is_v4)
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600294{
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700295 struct sfe_connection_create sic;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600296 struct net_device *in;
297 struct nf_conn *ct;
298 enum ip_conntrack_info ctinfo;
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600299 struct net_device *dev;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600300 struct net_device *src_dev;
301 struct net_device *dest_dev;
302 struct net_device *src_br_dev = NULL;
303 struct net_device *dest_br_dev = NULL;
304 struct nf_conntrack_tuple orig_tuple;
305 struct nf_conntrack_tuple reply_tuple;
306
307 /*
308 * Don't process broadcast or multicast packets.
309 */
310 if (unlikely(skb->pkt_type == PACKET_BROADCAST)) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700311 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_PACKET_BROADCAST);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600312 DEBUG_TRACE("broadcast, ignoring\n");
313 return NF_ACCEPT;
314 }
315 if (unlikely(skb->pkt_type == PACKET_MULTICAST)) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700316 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_PACKET_MULTICAST);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600317 DEBUG_TRACE("multicast, ignoring\n");
318 return NF_ACCEPT;
319 }
320
Zhi Chen8748eb32015-06-18 12:58:48 -0700321#ifdef CONFIG_XFRM
322 /*
323 * Packet to xfrm for encapsulation, we can't process it
324 */
325 if (unlikely(skb_dst(skb)->xfrm)) {
326 DEBUG_TRACE("packet to xfrm, ignoring\n");
327 return NF_ACCEPT;
328 }
329#endif
330
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600331 /*
Xiaoping Fan1d8d69d2015-08-03 13:36:01 -0700332 * Don't process locally generated packets.
333 */
334 if (skb->sk) {
335 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_LOCAL_OUT);
336 DEBUG_TRACE("skip local out packet\n");
337 return NF_ACCEPT;
338 }
339
340 /*
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600341 * Don't process packets that are not being forwarded.
342 */
343 in = dev_get_by_index(&init_net, skb->skb_iif);
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600344 if (!in) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700345 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_IIF);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600346 DEBUG_TRACE("packet not forwarding\n");
347 return NF_ACCEPT;
348 }
349
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600350 dev_put(in);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600351
352 /*
353 * Don't process packets that aren't being tracked by conntrack.
354 */
355 ct = nf_ct_get(skb, &ctinfo);
356 if (unlikely(!ct)) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700357 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_CT);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600358 DEBUG_TRACE("no conntrack connection, ignoring\n");
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600359 return NF_ACCEPT;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600360 }
361
362 /*
363 * Don't process untracked connections.
364 */
365 if (unlikely(ct == &nf_conntrack_untracked)) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700366 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_CT_NO_TRACK);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600367 DEBUG_TRACE("untracked connection\n");
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600368 return NF_ACCEPT;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600369 }
370
371 /*
Xiaoping Fan956461e2015-06-25 17:35:13 -0700372 * Unconfirmed connection may be dropped by Linux at the final step,
373 * So we don't process unconfirmed connections.
374 */
375 if (!nf_ct_is_confirmed(ct)) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700376 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_CT_NO_CONFIRM);
Xiaoping Fan956461e2015-06-25 17:35:13 -0700377 DEBUG_TRACE("unconfirmed connection\n");
378 return NF_ACCEPT;
379 }
380
381 /*
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600382 * Don't process connections that require support from a 'helper' (typically a NAT ALG).
383 */
384 if (unlikely(nfct_help(ct))) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700385 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_CT_IS_ALG);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600386 DEBUG_TRACE("connection has helper\n");
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600387 return NF_ACCEPT;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600388 }
389
390 /*
391 * Look up the details of our connection in conntrack.
392 *
393 * Note that the data we get from conntrack is for the "ORIGINAL" direction
394 * but our packet may actually be in the "REPLY" direction.
395 */
396 orig_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
397 reply_tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
398 sic.protocol = (int32_t)orig_tuple.dst.protonum;
399
400 /*
401 * Get addressing information, non-NAT first
402 */
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700403 if (likely(is_v4)) {
404 sic.src_ip.ip = (__be32)orig_tuple.src.u3.ip;
405 sic.dest_ip.ip = (__be32)orig_tuple.dst.u3.ip;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600406
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700407 if (ipv4_is_multicast(sic.src_ip.ip) || ipv4_is_multicast(sic.dest_ip.ip)) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700408 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_IS_IPV4_MCAST);
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700409 DEBUG_TRACE("multicast address\n");
410 return NF_ACCEPT;
411 }
412
413 /*
414 * NAT'ed addresses - note these are as seen from the 'reply' direction
415 * When NAT does not apply to this connection these will be identical to the above.
416 */
417 sic.src_ip_xlate.ip = (__be32)reply_tuple.dst.u3.ip;
418 sic.dest_ip_xlate.ip = (__be32)reply_tuple.src.u3.ip;
419 } else {
Xiaoping Fan978b3772015-05-27 14:15:18 -0700420 sic.src_ip.ip6[0] = *((struct sfe_ipv6_addr *)&orig_tuple.src.u3.in6);
421 sic.dest_ip.ip6[0] = *((struct sfe_ipv6_addr *)&orig_tuple.dst.u3.in6);
422
423 if (ipv6_addr_is_multicast((struct in6_addr *)sic.src_ip.ip6) ||
424 ipv6_addr_is_multicast((struct in6_addr *)sic.dest_ip.ip6)) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700425 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_IS_IPV6_MCAST);
Xiaoping Fan978b3772015-05-27 14:15:18 -0700426 DEBUG_TRACE("multicast address\n");
427 return NF_ACCEPT;
428 }
429
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700430 /*
Xiaoping Fan978b3772015-05-27 14:15:18 -0700431 * NAT'ed addresses - note these are as seen from the 'reply' direction
432 * When NAT does not apply to this connection these will be identical to the above.
433 */
434 sic.src_ip_xlate.ip6[0] = *((struct sfe_ipv6_addr *)&reply_tuple.dst.u3.in6);
435 sic.dest_ip_xlate.ip6[0] = *((struct sfe_ipv6_addr *)&reply_tuple.src.u3.in6);
Matthew McClintocka11c7cd2014-08-06 16:41:30 -0500436 }
437
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600438 sic.flags = 0;
439
440 switch (sic.protocol) {
441 case IPPROTO_TCP:
442 sic.src_port = orig_tuple.src.u.tcp.port;
443 sic.dest_port = orig_tuple.dst.u.tcp.port;
444 sic.src_port_xlate = reply_tuple.dst.u.tcp.port;
445 sic.dest_port_xlate = reply_tuple.src.u.tcp.port;
446 sic.src_td_window_scale = ct->proto.tcp.seen[0].td_scale;
447 sic.src_td_max_window = ct->proto.tcp.seen[0].td_maxwin;
448 sic.src_td_end = ct->proto.tcp.seen[0].td_end;
449 sic.src_td_max_end = ct->proto.tcp.seen[0].td_maxend;
450 sic.dest_td_window_scale = ct->proto.tcp.seen[1].td_scale;
451 sic.dest_td_max_window = ct->proto.tcp.seen[1].td_maxwin;
452 sic.dest_td_end = ct->proto.tcp.seen[1].td_end;
453 sic.dest_td_max_end = ct->proto.tcp.seen[1].td_maxend;
454 if (nf_ct_tcp_no_window_check
455 || (ct->proto.tcp.seen[0].flags & IP_CT_TCP_FLAG_BE_LIBERAL)
456 || (ct->proto.tcp.seen[1].flags & IP_CT_TCP_FLAG_BE_LIBERAL)) {
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700457 sic.flags |= SFE_CREATE_FLAG_NO_SEQ_CHECK;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600458 }
459
460 /*
461 * Don't try to manage a non-established connection.
462 */
463 if (!test_bit(IPS_ASSURED_BIT, &ct->status)) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700464 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_TCP_NOT_ASSURED);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600465 DEBUG_TRACE("non-established connection\n");
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600466 return NF_ACCEPT;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600467 }
468
469 /*
470 * If the connection is shutting down do not manage it.
471 * state can not be SYN_SENT, SYN_RECV because connection is assured
472 * Not managed states: FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE.
473 */
474 spin_lock_bh(&ct->lock);
475 if (ct->proto.tcp.state != TCP_CONNTRACK_ESTABLISHED) {
476 spin_unlock_bh(&ct->lock);
Xiaoping Fan82c21512015-06-30 01:15:23 -0700477 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_TCP_NOT_ESTABLISHED);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600478 DEBUG_TRACE("connection in termination state: %#x, s: %pI4:%u, d: %pI4:%u\n",
479 ct->proto.tcp.state, &sic.src_ip, ntohs(sic.src_port),
480 &sic.dest_ip, ntohs(sic.dest_port));
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600481 return NF_ACCEPT;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600482 }
483 spin_unlock_bh(&ct->lock);
484 break;
485
486 case IPPROTO_UDP:
487 sic.src_port = orig_tuple.src.u.udp.port;
488 sic.dest_port = orig_tuple.dst.u.udp.port;
489 sic.src_port_xlate = reply_tuple.dst.u.udp.port;
490 sic.dest_port_xlate = reply_tuple.src.u.udp.port;
491 break;
492
493 default:
Xiaoping Fan82c21512015-06-30 01:15:23 -0700494 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_UNKNOW_PROTOCOL);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600495 DEBUG_TRACE("unhandled protocol %d\n", sic.protocol);
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600496 return NF_ACCEPT;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600497 }
498
Zhi Chen8748eb32015-06-18 12:58:48 -0700499#ifdef CONFIG_XFRM
500 sic.original_accel = 1;
501 sic.reply_accel = 1;
502
503 /*
504 * For packets de-capsulated from xfrm, we still can accelerate it
505 * on the direction we just received the packet.
506 */
507 if (unlikely(skb->sp)) {
508 if (sic.protocol == IPPROTO_TCP &&
509 !(sic.flags & SFE_CREATE_FLAG_NO_SEQ_CHECK)) {
510 return NF_ACCEPT;
511 }
512
513 if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) {
514 sic.reply_accel = 0;
515 } else {
516 sic.original_accel = 0;
517 }
518 }
519#endif
520
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600521 /*
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600522 * Get the net device and MAC addresses that correspond to the various source and
523 * destination host addresses.
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600524 */
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700525 if (!sfe_cm_find_dev_and_mac_addr(&sic.src_ip, &src_dev, sic.src_mac, is_v4)) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700526 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_SRC_DEV);
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600527 return NF_ACCEPT;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600528 }
529
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700530 if (!sfe_cm_find_dev_and_mac_addr(&sic.src_ip_xlate, &dev, sic.src_mac_xlate, is_v4)) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700531 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_SRC_XLATE_DEV);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600532 goto done1;
533 }
534
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600535 dev_put(dev);
536
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700537 if (!sfe_cm_find_dev_and_mac_addr(&sic.dest_ip, &dev, sic.dest_mac, is_v4)) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700538 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_DEST_DEV);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600539 goto done1;
540 }
541
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600542 dev_put(dev);
543
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700544 if (!sfe_cm_find_dev_and_mac_addr(&sic.dest_ip_xlate, &dest_dev, sic.dest_mac_xlate, is_v4)) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700545 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_DEST_XLATE_DEV);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600546 goto done1;
547 }
548
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600549#if (!SFE_HOOK_ABOVE_BRIDGE)
550 /*
551 * Now our devices may actually be a bridge interface. If that's
552 * the case then we need to hunt down the underlying interface.
553 */
554 if (src_dev->priv_flags & IFF_EBRIDGE) {
555 src_br_dev = br_port_dev_get(src_dev, sic.src_mac);
556 if (!src_br_dev) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700557 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_BRIDGE);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600558 DEBUG_TRACE("no port found on bridge\n");
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600559 goto done2;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600560 }
561
562 src_dev = src_br_dev;
563 }
564
565 if (dest_dev->priv_flags & IFF_EBRIDGE) {
566 dest_br_dev = br_port_dev_get(dest_dev, sic.dest_mac_xlate);
567 if (!dest_br_dev) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700568 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_BRIDGE);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600569 DEBUG_TRACE("no port found on bridge\n");
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600570 goto done3;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600571 }
572
573 dest_dev = dest_br_dev;
574 }
575#else
576 /*
577 * Our devices may actually be part of a bridge interface. If that's
578 * the case then find the bridge interface instead.
579 */
580 if (src_dev->priv_flags & IFF_BRIDGE_PORT) {
Xiaoping Fan79ed7292015-03-27 16:47:19 -0700581 src_br_dev = sfe_dev_get_master(src_dev);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600582 if (!src_br_dev) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700583 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_BRIDGE);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600584 DEBUG_TRACE("no bridge found for: %s\n", src_dev->name);
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600585 goto done2;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600586 }
587
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600588 src_dev = src_br_dev;
589 }
590
591 if (dest_dev->priv_flags & IFF_BRIDGE_PORT) {
Xiaoping Fan79ed7292015-03-27 16:47:19 -0700592 dest_br_dev = sfe_dev_get_master(dest_dev);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600593 if (!dest_br_dev) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700594 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_BRIDGE);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600595 DEBUG_TRACE("no bridge found for: %s\n", dest_dev->name);
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600596 goto done3;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600597 }
598
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600599 dest_dev = dest_br_dev;
600 }
601#endif
602
603 sic.src_dev = src_dev;
604 sic.dest_dev = dest_dev;
605
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600606 sic.src_mtu = src_dev->mtu;
607 sic.dest_mtu = dest_dev->mtu;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600608
Xiaoping Fan978b3772015-05-27 14:15:18 -0700609 if (likely(is_v4)) {
610 sfe_ipv4_create_rule(&sic);
611 } else {
612 sfe_ipv6_create_rule(&sic);
613 }
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600614
615 /*
616 * If we had bridge ports then release them too.
617 */
618 if (dest_br_dev) {
619 dev_put(dest_br_dev);
620 }
621
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600622done3:
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600623 if (src_br_dev) {
624 dev_put(src_br_dev);
625 }
626
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600627done2:
628 dev_put(dest_dev);
629
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600630done1:
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600631 dev_put(src_dev);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600632
633 return NF_ACCEPT;
634}
635
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700636/*
637 * sfe_cm_ipv4_post_routing_hook()
638 * Called for packets about to leave the box - either locally generated or forwarded from another interface
639 */
640sfe_cm_ipv4_post_routing_hook(hooknum, ops, skb, in_unused, out, okfn)
641{
642 return sfe_cm_post_routing(skb, true);
643}
644
Xiaoping Fan978b3772015-05-27 14:15:18 -0700645/*
646 * sfe_cm_ipv6_post_routing_hook()
647 * Called for packets about to leave the box - either locally generated or forwarded from another interface
648 */
649sfe_cm_ipv6_post_routing_hook(hooknum, ops, skb, in_unused, out, okfn)
650{
651 return sfe_cm_post_routing(skb, false);
652}
653
654
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600655#ifdef CONFIG_NF_CONNTRACK_EVENTS
656/*
657 * sfe_cm_conntrack_event()
658 * Callback event invoked when a conntrack connection's state changes.
659 */
Matthew McClintock0680e9f2013-11-26 15:43:10 -0600660#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
661static int sfe_cm_conntrack_event(struct notifier_block *this,
Matthew McClintock0f5c0592014-02-12 11:17:11 -0600662 unsigned long events, void *ptr)
Matthew McClintock0680e9f2013-11-26 15:43:10 -0600663#else
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600664static int sfe_cm_conntrack_event(unsigned int events, struct nf_ct_event *item)
Matthew McClintock0680e9f2013-11-26 15:43:10 -0600665#endif
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600666{
Matthew McClintock0f5c0592014-02-12 11:17:11 -0600667#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
668 struct nf_ct_event *item = ptr;
669#endif
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700670 struct sfe_connection_destroy sid;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600671 struct nf_conn *ct = item->ct;
672 struct nf_conntrack_tuple orig_tuple;
673
674 /*
675 * If we don't have a conntrack entry then we're done.
676 */
677 if (unlikely(!ct)) {
678 DEBUG_WARN("no ct in conntrack event callback\n");
679 return NOTIFY_DONE;
680 }
681
682 /*
683 * If this is an untracked connection then we can't have any state either.
684 */
685 if (unlikely(ct == &nf_conntrack_untracked)) {
686 DEBUG_TRACE("ignoring untracked conn\n");
687 return NOTIFY_DONE;
688 }
689
690 /*
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600691 * We're only interested in destroy events.
692 */
693 if (unlikely(!(events & (1 << IPCT_DESTROY)))) {
694 DEBUG_TRACE("ignoring non-destroy event\n");
695 return NOTIFY_DONE;
696 }
697
698 orig_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
699 sid.protocol = (int32_t)orig_tuple.dst.protonum;
700
701 /*
702 * Extract information from the conntrack connection. We're only interested
703 * in nominal connection information (i.e. we're ignoring any NAT information).
704 */
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600705 switch (sid.protocol) {
706 case IPPROTO_TCP:
707 sid.src_port = orig_tuple.src.u.tcp.port;
708 sid.dest_port = orig_tuple.dst.u.tcp.port;
709 break;
710
711 case IPPROTO_UDP:
712 sid.src_port = orig_tuple.src.u.udp.port;
713 sid.dest_port = orig_tuple.dst.u.udp.port;
714 break;
715
716 default:
717 DEBUG_TRACE("unhandled protocol: %d\n", sid.protocol);
718 return NOTIFY_DONE;
719 }
720
Xiaoping Fan978b3772015-05-27 14:15:18 -0700721 if (likely(nf_ct_l3num(ct) == AF_INET)) {
722 sid.src_ip.ip = (__be32)orig_tuple.src.u3.ip;
723 sid.dest_ip.ip = (__be32)orig_tuple.dst.u3.ip;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600724
Xiaoping Fan978b3772015-05-27 14:15:18 -0700725 sfe_ipv4_destroy_rule(&sid);
726 } else if (likely(nf_ct_l3num(ct) == AF_INET6)) {
727 sid.src_ip.ip6[0] = *((struct sfe_ipv6_addr *)&orig_tuple.src.u3.in6);
728 sid.dest_ip.ip6[0] = *((struct sfe_ipv6_addr *)&orig_tuple.dst.u3.in6);
729
730 sfe_ipv6_destroy_rule(&sid);
731 } else {
732 DEBUG_TRACE("ignoring non-IPv4 and non-IPv6 connection\n");
733 }
734
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600735 return NOTIFY_DONE;
736}
737
738/*
739 * Netfilter conntrack event system to monitor connection tracking changes
740 */
Matthew McClintock0680e9f2013-11-26 15:43:10 -0600741#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
742static struct notifier_block sfe_cm_conntrack_notifier = {
743 .notifier_call = sfe_cm_conntrack_event,
744};
745#else
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600746static struct nf_ct_event_notifier sfe_cm_conntrack_notifier = {
747 .fcn = sfe_cm_conntrack_event,
748};
749#endif
Matthew McClintock0680e9f2013-11-26 15:43:10 -0600750#endif
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600751
752/*
753 * Structure to establish a hook into the post routing netfilter point - this
754 * will pick up local outbound and packets going from one interface to another.
755 *
756 * Note: see include/linux/netfilter_ipv4.h for info related to priority levels.
757 * We want to examine packets after NAT translation and any ALG processing.
758 */
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700759static struct nf_hook_ops sfe_cm_ops_post_routing[] __read_mostly = {
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600760 {
Xiaoping Fan3f1fe512014-11-05 12:14:57 -0800761 .hook = __sfe_cm_ipv4_post_routing_hook,
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600762 .owner = THIS_MODULE,
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700763 .pf = NFPROTO_IPV4,
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600764 .hooknum = NF_INET_POST_ROUTING,
765 .priority = NF_IP_PRI_NAT_SRC + 1,
766 },
Xiaoping Fan978b3772015-05-27 14:15:18 -0700767#ifdef SFE_SUPPORT_IPV6
768 {
769 .hook = __sfe_cm_ipv6_post_routing_hook,
770 .owner = THIS_MODULE,
771 .pf = NFPROTO_IPV6,
772 .hooknum = NF_INET_POST_ROUTING,
773 .priority = NF_IP6_PRI_NAT_SRC + 1,
774 },
775#endif
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600776};
777
778/*
779 * sfe_cm_sync_rule()
780 * Synchronize a connection's state.
781 */
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700782static void sfe_cm_sync_rule(struct sfe_connection_sync *sis)
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600783{
784 struct nf_conntrack_tuple_hash *h;
785 struct nf_conntrack_tuple tuple;
786 struct nf_conn *ct;
Xiaoping Fan3f1fe512014-11-05 12:14:57 -0800787 SFE_NF_CONN_ACCT(acct);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600788
789 /*
790 * Create a tuple so as to be able to look up a connection
791 */
792 memset(&tuple, 0, sizeof(tuple));
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600793 tuple.src.u.all = (__be16)sis->src_port;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600794 tuple.dst.dir = IP_CT_DIR_ORIGINAL;
795 tuple.dst.protonum = (uint8_t)sis->protocol;
796 tuple.dst.u.all = (__be16)sis->dest_port;
797
Xiaoping Fan978b3772015-05-27 14:15:18 -0700798 if (sis->is_v6) {
799 tuple.src.u3.in6 = *((struct in6_addr *)sis->src_ip.ip6);
800 tuple.dst.u3.in6 = *((struct in6_addr *)sis->dest_ip.ip6);
801 tuple.src.l3num = AF_INET6;
802
803 DEBUG_TRACE("update connection - p: %d, s: %pI6:%u, d: %pI6:%u\n",
804 (int)tuple.dst.protonum,
805 &tuple.src.u3.in6, (unsigned int)ntohs(tuple.src.u.all),
806 &tuple.dst.u3.in6, (unsigned int)ntohs(tuple.dst.u.all));
807 } else {
808 tuple.src.u3.ip = sis->src_ip.ip;
809 tuple.dst.u3.ip = sis->dest_ip.ip;
810 tuple.src.l3num = AF_INET;
811
812 DEBUG_TRACE("update connection - p: %d, s: %pI4:%u, d: %pI4:%u\n",
813 (int)tuple.dst.protonum,
814 &tuple.src.u3.ip, (unsigned int)ntohs(tuple.src.u.all),
815 &tuple.dst.u3.ip, (unsigned int)ntohs(tuple.dst.u.all));
816 }
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600817
818 /*
819 * Look up conntrack connection
820 */
821 h = nf_conntrack_find_get(&init_net, NF_CT_DEFAULT_ZONE, &tuple);
822 if (unlikely(!h)) {
823 DEBUG_TRACE("no connection found\n");
824 return;
825 }
826
827 ct = nf_ct_tuplehash_to_ctrack(h);
828 NF_CT_ASSERT(ct->timeout.data == (unsigned long)ct);
829
830 /*
831 * Only update if this is not a fixed timeout
832 */
833 if (!test_bit(IPS_FIXED_TIMEOUT_BIT, &ct->status)) {
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700834 spin_lock_bh(&ct->lock);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600835 ct->timeout.expires += sis->delta_jiffies;
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700836 spin_unlock_bh(&ct->lock);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600837 }
838
839 acct = nf_conn_acct_find(ct);
840 if (acct) {
841 spin_lock_bh(&ct->lock);
Xiaoping Fan3f1fe512014-11-05 12:14:57 -0800842 atomic64_set(&SFE_ACCT_COUNTER(acct)[IP_CT_DIR_ORIGINAL].packets, sis->src_packet_count);
843 atomic64_set(&SFE_ACCT_COUNTER(acct)[IP_CT_DIR_ORIGINAL].bytes, sis->src_byte_count);
844 atomic64_set(&SFE_ACCT_COUNTER(acct)[IP_CT_DIR_REPLY].packets, sis->dest_packet_count);
845 atomic64_set(&SFE_ACCT_COUNTER(acct)[IP_CT_DIR_REPLY].bytes, sis->dest_byte_count);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600846 spin_unlock_bh(&ct->lock);
847 }
848
849 switch (sis->protocol) {
850 case IPPROTO_TCP:
851 spin_lock_bh(&ct->lock);
852 if (ct->proto.tcp.seen[0].td_maxwin < sis->src_td_max_window) {
853 ct->proto.tcp.seen[0].td_maxwin = sis->src_td_max_window;
854 }
855 if ((int32_t)(ct->proto.tcp.seen[0].td_end - sis->src_td_end) < 0) {
856 ct->proto.tcp.seen[0].td_end = sis->src_td_end;
857 }
858 if ((int32_t)(ct->proto.tcp.seen[0].td_maxend - sis->src_td_max_end) < 0) {
859 ct->proto.tcp.seen[0].td_maxend = sis->src_td_max_end;
860 }
861 if (ct->proto.tcp.seen[1].td_maxwin < sis->dest_td_max_window) {
862 ct->proto.tcp.seen[1].td_maxwin = sis->dest_td_max_window;
863 }
864 if ((int32_t)(ct->proto.tcp.seen[1].td_end - sis->dest_td_end) < 0) {
865 ct->proto.tcp.seen[1].td_end = sis->dest_td_end;
866 }
867 if ((int32_t)(ct->proto.tcp.seen[1].td_maxend - sis->dest_td_max_end) < 0) {
868 ct->proto.tcp.seen[1].td_maxend = sis->dest_td_max_end;
869 }
870 spin_unlock_bh(&ct->lock);
871 break;
872 }
873
874 /*
875 * Release connection
876 */
877 nf_ct_put(ct);
878}
879
880/*
881 * sfe_cm_device_event()
882 */
Xiaoping Fan20f04cc2015-03-30 10:14:20 -0700883int sfe_cm_device_event(struct notifier_block *this, unsigned long event, void *ptr)
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600884{
Xiaoping Fan20f04cc2015-03-30 10:14:20 -0700885 struct net_device *dev = SFE_DEV_EVENT_PTR(ptr);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600886
887 switch (event) {
888 case NETDEV_DOWN:
889 if (dev) {
890 sfe_ipv4_destroy_all_rules_for_dev(dev);
Xiaoping Fan978b3772015-05-27 14:15:18 -0700891 sfe_ipv6_destroy_all_rules_for_dev(dev);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600892 }
893 break;
894 }
895
896 return NOTIFY_DONE;
897}
898
899/*
900 * sfe_cm_inet_event()
901 */
902static int sfe_cm_inet_event(struct notifier_block *this, unsigned long event, void *ptr)
903{
904 struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev;
Xiaoping Fan20f04cc2015-03-30 10:14:20 -0700905 return sfe_cm_propagate_event(this, event, dev);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600906}
907
908/*
Xiaoping Fan978b3772015-05-27 14:15:18 -0700909 * sfe_cm_inet6_event()
910 */
911static int sfe_cm_inet6_event(struct notifier_block *this, unsigned long event, void *ptr)
912{
913 struct net_device *dev = ((struct inet6_ifaddr *)ptr)->idev->dev;
Xiaoping Fan20f04cc2015-03-30 10:14:20 -0700914 return sfe_cm_propagate_event(this, event, dev);
Xiaoping Fan978b3772015-05-27 14:15:18 -0700915}
916
917/*
Xiaoping Fan82c21512015-06-30 01:15:23 -0700918 * sfe_cm_get_exceptions
919 * dump exception counters
920 */
921static ssize_t sfe_cm_get_exceptions(struct device *dev,
922 struct device_attribute *attr,
923 char *buf)
924{
925 int idx, len;
926 struct sfe_cm *sc = &__sc;
927
928 spin_lock_bh(&sc->lock);
929 for (len = 0, idx = 0; idx < SFE_CM_EXCEPTION_MAX; idx++) {
930 if (sc->exceptions[idx]) {
931 len += sprintf(buf + len, "%s = %d\n", sfe_cm_exception_events_string[idx], sc->exceptions[idx]);
932 }
933 }
934 spin_unlock_bh(&sc->lock);
935
936 return len;
937}
938
939/*
940 * sysfs attributes.
941 */
942static const struct device_attribute sfe_cm_exceptions_attr =
943 __ATTR(exceptions, S_IRUGO, sfe_cm_get_exceptions, NULL);
944
945/*
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600946 * sfe_cm_init()
947 */
948static int __init sfe_cm_init(void)
949{
950 struct sfe_cm *sc = &__sc;
951 int result = -1;
952
953 DEBUG_INFO("SFE CM init\n");
954
955 /*
956 * Create sys/sfe_cm
957 */
958 sc->sys_sfe_cm = kobject_create_and_add("sfe_cm", NULL);
959 if (!sc->sys_sfe_cm) {
960 DEBUG_ERROR("failed to register sfe_cm\n");
961 goto exit1;
962 }
963
Xiaoping Fan82c21512015-06-30 01:15:23 -0700964 /*
965 * Create sys/sfe_cm/exceptions
966 */
967 result = sysfs_create_file(sc->sys_sfe_cm, &sfe_cm_exceptions_attr.attr);
968 if (result) {
969 DEBUG_ERROR("failed to register exceptions file: %d\n", result);
970 goto exit2;
971 }
972
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600973 sc->dev_notifier.notifier_call = sfe_cm_device_event;
974 sc->dev_notifier.priority = 1;
975 register_netdevice_notifier(&sc->dev_notifier);
976
977 sc->inet_notifier.notifier_call = sfe_cm_inet_event;
978 sc->inet_notifier.priority = 1;
979 register_inetaddr_notifier(&sc->inet_notifier);
980
Xiaoping Fan978b3772015-05-27 14:15:18 -0700981 sc->inet6_notifier.notifier_call = sfe_cm_inet6_event;
982 sc->inet6_notifier.priority = 1;
983 register_inet6addr_notifier(&sc->inet6_notifier);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600984 /*
985 * Register our netfilter hooks.
986 */
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700987 result = nf_register_hooks(sfe_cm_ops_post_routing, ARRAY_SIZE(sfe_cm_ops_post_routing));
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600988 if (result < 0) {
989 DEBUG_ERROR("can't register nf post routing hook: %d\n", result);
Xiaoping Fan82c21512015-06-30 01:15:23 -0700990 goto exit3;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600991 }
992
993#ifdef CONFIG_NF_CONNTRACK_EVENTS
994 /*
995 * Register a notifier hook to get fast notifications of expired connections.
996 */
997 result = nf_conntrack_register_notifier(&init_net, &sfe_cm_conntrack_notifier);
998 if (result < 0) {
999 DEBUG_ERROR("can't register nf notifier hook: %d\n", result);
Xiaoping Fan82c21512015-06-30 01:15:23 -07001000 goto exit4;
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001001 }
1002#endif
1003
1004 spin_lock_init(&sc->lock);
1005
1006 /*
1007 * Hook the receive path in the network stack.
1008 */
1009 BUG_ON(athrs_fast_nat_recv != NULL);
1010 RCU_INIT_POINTER(athrs_fast_nat_recv, sfe_cm_recv);
1011
1012 /*
1013 * Hook the shortcut sync callback.
1014 */
1015 sfe_ipv4_register_sync_rule_callback(sfe_cm_sync_rule);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001016 sfe_ipv6_register_sync_rule_callback(sfe_cm_sync_rule);
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001017 return 0;
1018
1019#ifdef CONFIG_NF_CONNTRACK_EVENTS
Xiaoping Fan82c21512015-06-30 01:15:23 -07001020exit4:
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001021#endif
Xiaoping Fand44a5b42015-05-26 17:37:37 -07001022 nf_unregister_hooks(sfe_cm_ops_post_routing, ARRAY_SIZE(sfe_cm_ops_post_routing));
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001023
Xiaoping Fan82c21512015-06-30 01:15:23 -07001024exit3:
Xiaoping Fan978b3772015-05-27 14:15:18 -07001025 unregister_inet6addr_notifier(&sc->inet6_notifier);
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001026 unregister_inetaddr_notifier(&sc->inet_notifier);
1027 unregister_netdevice_notifier(&sc->dev_notifier);
Xiaoping Fan82c21512015-06-30 01:15:23 -07001028exit2:
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001029 kobject_put(sc->sys_sfe_cm);
1030
1031exit1:
1032 return result;
1033}
1034
1035/*
1036 * sfe_cm_exit()
1037 */
1038static void __exit sfe_cm_exit(void)
1039{
1040 struct sfe_cm *sc = &__sc;
1041
1042 DEBUG_INFO("SFE CM exit\n");
1043
1044 /*
1045 * Unregister our sync callback.
1046 */
1047 sfe_ipv4_register_sync_rule_callback(NULL);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001048 sfe_ipv6_register_sync_rule_callback(NULL);
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001049
1050 /*
1051 * Unregister our receive callback.
1052 */
1053 RCU_INIT_POINTER(athrs_fast_nat_recv, NULL);
1054
1055 /*
1056 * Wait for all callbacks to complete.
1057 */
1058 rcu_barrier();
1059
1060 /*
1061 * Destroy all connections.
1062 */
1063 sfe_ipv4_destroy_all_rules_for_dev(NULL);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001064 sfe_ipv6_destroy_all_rules_for_dev(NULL);
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001065
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001066#ifdef CONFIG_NF_CONNTRACK_EVENTS
1067 nf_conntrack_unregister_notifier(&init_net, &sfe_cm_conntrack_notifier);
1068
1069#endif
Xiaoping Fand44a5b42015-05-26 17:37:37 -07001070 nf_unregister_hooks(sfe_cm_ops_post_routing, ARRAY_SIZE(sfe_cm_ops_post_routing));
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001071
Xiaoping Fan978b3772015-05-27 14:15:18 -07001072 unregister_inet6addr_notifier(&sc->inet6_notifier);
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001073 unregister_inetaddr_notifier(&sc->inet_notifier);
1074 unregister_netdevice_notifier(&sc->dev_notifier);
1075
1076 kobject_put(sc->sys_sfe_cm);
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001077}
1078
1079module_init(sfe_cm_init)
1080module_exit(sfe_cm_exit)
1081
1082MODULE_AUTHOR("Qualcomm Atheros Inc.");
1083MODULE_DESCRIPTION("Shortcut Forwarding Engine - Connection Manager");
Matthew McClintocka3221942014-01-16 11:44:26 -06001084MODULE_LICENSE("Dual BSD/GPL");
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001085