blob: 860dcf3622c73e9c8116d7b463d8d00d6979c986 [file] [log] [blame]
Matthew McClintock6f29aa12013-11-06 15:49:01 -06001/*
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06002 * fast-classifier.c
3 * Shortcut forwarding engine connection manager.
4 * fast-classifier style
5 *
6 * XXX - fill in the appropriate GPL notice.
Matthew McClintock6f29aa12013-11-06 15:49:01 -06007 */
Matthew McClintock6f29aa12013-11-06 15:49:01 -06008#include <linux/module.h>
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06009#include <linux/sysfs.h>
10#include <linux/skbuff.h>
11#include <net/route.h>
12#include <linux/inetdevice.h>
13#include <linux/netfilter_bridge.h>
14#include <net/netfilter/nf_conntrack_acct.h>
15#include <net/netfilter/nf_conntrack_helper.h>
16#include <net/netfilter/nf_conntrack_zones.h>
17#include <net/netfilter/nf_conntrack_core.h>
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -060018#include <net/genetlink.h>
19
Matthew McClintocke1bcfe42013-11-22 15:33:09 -060020#include "../shortcut-fe/sfe.h"
21#include "../shortcut-fe/sfe_ipv4.h"
22#include "fast-classifier-priv.h"
23
24/*
25 * Per-module structure.
26 */
27struct fast_classifier {
28 spinlock_t lock; /* Lock for SMP correctness */
29
30 /*
31 * Control state.
32 */
33 struct kobject *sys_fast_classifier; /* sysfs linkage */
34
35 /*
36 * Callback notifiers.
37 */
38 struct notifier_block dev_notifier;
39 /* Device notifier */
40 struct notifier_block inet_notifier;
41 /* IP notifier */
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -060042};
Matthew McClintocke1bcfe42013-11-22 15:33:09 -060043
44struct fast_classifier __sc;
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -060045
46static struct nla_policy fast_classifier_genl_policy[FAST_CLASSIFIER_A_MAX + 1] = {
47 [FAST_CLASSIFIER_A_MSG] = { .type = NLA_NUL_STRING },
48};
49
50static struct genl_family fast_classifier_gnl_family = {
51 .id = GENL_ID_GENERATE,
52 .hdrsize = 0,
53 .name = "FAST_CLASSIFIER",
54 .version = 1,
55 .maxattr = FAST_CLASSIFIER_A_MAX,
56};
57
Matthew McClintocke1bcfe42013-11-22 15:33:09 -060058
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -060059#define FAST_CLASSIFIER_C_MAX (__FAST_CLASSIFIER_C_MAX - 1)
60
Matthew McClintocke1bcfe42013-11-22 15:33:09 -060061static int fast_classifier_recv_genl_msg(struct sk_buff *skb, struct genl_info *info);
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -060062
63static struct genl_ops fast_classifier_gnl_ops_recv = {
64 .cmd = FAST_CLASSIFIER_C_RECV,
65 .flags = 0,
66 .policy = fast_classifier_genl_policy,
Matthew McClintocke1bcfe42013-11-22 15:33:09 -060067 .doit = fast_classifier_recv_genl_msg,
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -060068 .dumpit = NULL,
69};
70
Matthew McClintocke1bcfe42013-11-22 15:33:09 -060071/*
72 * Expose the hook for the receive processing.
73 */
74extern int (*athrs_fast_nat_recv)(struct sk_buff *skb);
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -060075
Matthew McClintocke1bcfe42013-11-22 15:33:09 -060076/*
77 * Expose what should be a static flag in the TCP connection tracker.
78 */
79extern int nf_ct_tcp_no_window_check;
80
81/*
82 * fast_classifier_recv()
83 * Handle packet receives.
84 *
85 * Returns 1 if the packet is forwarded or 0 if it isn't.
86 */
87int fast_classifier_recv(struct sk_buff *skb)
88{
89 struct net_device *dev;
90#if (SFE_HOOK_ABOVE_BRIDGE)
91 struct in_device *in_dev;
92#endif
93
94 /*
95 * We know that for the vast majority of packets we need the transport
96 * layer header so we may as well start to fetch it now!
97 */
98 prefetch(skb->data + 32);
99 barrier();
100
101 dev = skb->dev;
102
103#if (SFE_HOOK_ABOVE_BRIDGE)
104 /*
105 * Does our input device support IP processing?
106 */
107 in_dev = (struct in_device *)dev->ip_ptr;
108 if (unlikely(!in_dev)) {
109 DEBUG_TRACE("no IP processing for device: %s\n", dev->name);
110 return 0;
111 }
112
113 /*
114 * Does it have an IP address? If it doesn't then we can't do anything
115 * interesting here!
116 */
117 if (unlikely(!in_dev->ifa_list)) {
118 DEBUG_TRACE("no IP address for device: %s\n", dev->name);
119 return 0;
120 }
121#endif
122
123 /*
124 * We're only interested in IP packets.
125 */
126 if (likely(htons(ETH_P_IP) == skb->protocol)) {
127 return sfe_ipv4_recv(dev, skb);
128 }
129
130 DEBUG_TRACE("not IP packet\n");
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -0600131 return 0;
132}
Matthew McClintock6f29aa12013-11-06 15:49:01 -0600133
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600134/*
135 * fast_classifier_find_mac_addr()
136 * Find the MAC address for a given IPv4 address.
137 *
138 * Returns true if we find the MAC address, otherwise false.
139 *
140 * We look up the rtable entry for the address and, from its neighbour
141 * structure, obtain the hardware address. This means this function also
142 * works if the neighbours are routers too.
143 */
144static bool fast_classifier_find_mac_addr(uint32_t addr, uint8_t *mac_addr)
Matthew McClintock6f29aa12013-11-06 15:49:01 -0600145{
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600146 struct neighbour *neigh;
147 struct rtable *rt;
148 struct dst_entry *dst;
149 struct net_device *dev;
150
151 /*
152 * Look up the rtable entry for the IP address then get the hardware
153 * address from its neighbour structure. This means this work when the
154 * neighbours are routers too.
155 */
156 rt = ip_route_output(&init_net, addr, 0, 0, 0);
157 if (unlikely(IS_ERR(rt))) {
158 return false;
159 }
160
161 dst = (struct dst_entry *)rt;
162
163 rcu_read_lock();
164 neigh = dst_get_neighbour_noref(dst);
165 if (unlikely(!neigh)) {
166 rcu_read_unlock();
167 dst_release(dst);
168 return false;
169 }
170
171 if (unlikely(!(neigh->nud_state & NUD_VALID))) {
172 rcu_read_unlock();
173 dst_release(dst);
174 return false;
175 }
176
177 dev = neigh->dev;
178 if (!dev) {
179 rcu_read_unlock();
180 dst_release(dst);
181 return false;
182 }
183
184 memcpy(mac_addr, neigh->ha, (size_t)dev->addr_len);
185 rcu_read_unlock();
186
187 dst_release(dst);
188
189 /*
190 * We're only interested in unicast MAC addresses - if it's not a unicast
191 * address then our IP address mustn't be unicast either.
192 */
193 if (is_multicast_ether_addr(mac_addr)) {
194 DEBUG_TRACE("MAC is non-unicast - ignoring\n");
195 return false;
196 }
197
198 return true;
199}
200
201/*
202 * fast_classifier_recv_genl_msg()
203 * Called from user space to offload a connection
204 */
205static int fast_classifier_recv_genl_msg(struct sk_buff *skb, struct genl_info *info)
206{
207 struct nlattr *na;
208 struct fast_classifier_msg *fc_msg;
209
210 na = info->attrs[FAST_CLASSIFIER_C_RECV];
211 fc_msg = nla_data(na);
212 printk("DEBUG: would offload: %d, %d, %d, %d, %d\n", fc_msg->proto,
213 fc_msg->src_saddr,
214 fc_msg->dst_saddr,
215 fc_msg->sport, fc_msg->dport);
216 return 0;
217}
218
219#if 1
220
221/*
222 * fast_classifier_ipv4_post_routing_hook()
223 * Called for packets about to leave the box - either locally generated or forwarded from another interface
224 */
225static unsigned int fast_classifier_ipv4_post_routing_hook(unsigned int hooknum,
226 struct sk_buff *skb,
227 const struct net_device *in_unused,
228 const struct net_device *out,
229 int (*okfn)(struct sk_buff *))
230{
231 struct sfe_ipv4_create sic;
232 struct net_device *in;
233 struct nf_conn *ct;
234 enum ip_conntrack_info ctinfo;
235 struct net_device *src_dev;
236 struct net_device *dest_dev;
237 struct net_device *src_br_dev = NULL;
238 struct net_device *dest_br_dev = NULL;
239 struct nf_conntrack_tuple orig_tuple;
240 struct nf_conntrack_tuple reply_tuple;
241
242 /*
243 * Don't process broadcast or multicast packets.
244 */
245 if (unlikely(skb->pkt_type == PACKET_BROADCAST)) {
246 DEBUG_TRACE("broadcast, ignoring\n");
247 return NF_ACCEPT;
248 }
249 if (unlikely(skb->pkt_type == PACKET_MULTICAST)) {
250 DEBUG_TRACE("multicast, ignoring\n");
251 return NF_ACCEPT;
252 }
253
254 /*
255 * Don't process packets that are not being forwarded.
256 */
257 in = dev_get_by_index(&init_net, skb->skb_iif);
258 if (!in) {
259 DEBUG_TRACE("packet not forwarding\n");
260 return NF_ACCEPT;
261 }
262
263 /*
264 * Don't process packets with non-standard 802.3 MAC address sizes.
265 */
266 if (unlikely(in->addr_len != ETH_ALEN)) {
267 DEBUG_TRACE("in device: %s not 802.3 hw addr len: %u, ignoring\n",
268 in->name, (unsigned)in->addr_len);
269 goto done1;
270 }
271 if (unlikely(out->addr_len != ETH_ALEN)) {
272 DEBUG_TRACE("out device: %s not 802.3 hw addr len: %u, ignoring\n",
273 out->name, (unsigned)out->addr_len);
274 goto done1;
275 }
276
277 /*
278 * Don't process packets that aren't being tracked by conntrack.
279 */
280 ct = nf_ct_get(skb, &ctinfo);
281 if (unlikely(!ct)) {
282 DEBUG_TRACE("no conntrack connection, ignoring\n");
283 goto done1;
284 }
285
286 /*
287 * Don't process untracked connections.
288 */
289 if (unlikely(ct == &nf_conntrack_untracked)) {
290 DEBUG_TRACE("untracked connection\n");
291 goto done1;
292 }
293
294 /*
295 * Don't process connections that require support from a 'helper' (typically a NAT ALG).
296 */
297 if (unlikely(nfct_help(ct))) {
298 DEBUG_TRACE("connection has helper\n");
299 goto done1;
300 }
301
302 /*
303 * Look up the details of our connection in conntrack.
304 *
305 * Note that the data we get from conntrack is for the "ORIGINAL" direction
306 * but our packet may actually be in the "REPLY" direction.
307 */
308 orig_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
309 reply_tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
310 sic.protocol = (int32_t)orig_tuple.dst.protonum;
311
312 /*
313 * Get addressing information, non-NAT first
314 */
315 sic.src_ip = (__be32)orig_tuple.src.u3.ip;
316 sic.dest_ip = (__be32)orig_tuple.dst.u3.ip;
317
318 /*
319 * NAT'ed addresses - note these are as seen from the 'reply' direction
320 * When NAT does not apply to this connection these will be identical to the above.
321 */
322 sic.src_ip_xlate = (__be32)reply_tuple.dst.u3.ip;
323 sic.dest_ip_xlate = (__be32)reply_tuple.src.u3.ip;
324
325 sic.flags = 0;
326
327 switch (sic.protocol) {
328 case IPPROTO_TCP:
329 sic.src_port = orig_tuple.src.u.tcp.port;
330 sic.dest_port = orig_tuple.dst.u.tcp.port;
331 sic.src_port_xlate = reply_tuple.dst.u.tcp.port;
332 sic.dest_port_xlate = reply_tuple.src.u.tcp.port;
333 sic.src_td_window_scale = ct->proto.tcp.seen[0].td_scale;
334 sic.src_td_max_window = ct->proto.tcp.seen[0].td_maxwin;
335 sic.src_td_end = ct->proto.tcp.seen[0].td_end;
336 sic.src_td_max_end = ct->proto.tcp.seen[0].td_maxend;
337 sic.dest_td_window_scale = ct->proto.tcp.seen[1].td_scale;
338 sic.dest_td_max_window = ct->proto.tcp.seen[1].td_maxwin;
339 sic.dest_td_end = ct->proto.tcp.seen[1].td_end;
340 sic.dest_td_max_end = ct->proto.tcp.seen[1].td_maxend;
341 if (nf_ct_tcp_no_window_check
342 || (ct->proto.tcp.seen[0].flags & IP_CT_TCP_FLAG_BE_LIBERAL)
343 || (ct->proto.tcp.seen[1].flags & IP_CT_TCP_FLAG_BE_LIBERAL)) {
344 sic.flags |= SFE_IPV4_CREATE_FLAG_NO_SEQ_CHECK;
345 }
346
347 /*
348 * Don't try to manage a non-established connection.
349 */
350 if (!test_bit(IPS_ASSURED_BIT, &ct->status)) {
351 DEBUG_TRACE("non-established connection\n");
352 goto done1;
353 }
354
355 /*
356 * If the connection is shutting down do not manage it.
357 * state can not be SYN_SENT, SYN_RECV because connection is assured
358 * Not managed states: FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE.
359 */
360 spin_lock_bh(&ct->lock);
361 if (ct->proto.tcp.state != TCP_CONNTRACK_ESTABLISHED) {
362 spin_unlock_bh(&ct->lock);
363 DEBUG_TRACE("connection in termination state: %#x, s: %pI4:%u, d: %pI4:%u\n",
364 ct->proto.tcp.state, &sic.src_ip, ntohs(sic.src_port),
365 &sic.dest_ip, ntohs(sic.dest_port));
366 goto done1;
367 }
368 spin_unlock_bh(&ct->lock);
369 break;
370
371 case IPPROTO_UDP:
372 sic.src_port = orig_tuple.src.u.udp.port;
373 sic.dest_port = orig_tuple.dst.u.udp.port;
374 sic.src_port_xlate = reply_tuple.dst.u.udp.port;
375 sic.dest_port_xlate = reply_tuple.src.u.udp.port;
376 break;
377
378 default:
379 DEBUG_TRACE("unhandled protocol %d\n", sic.protocol);
380 goto done1;
381 }
382
383 /*
384 * Get the MAC addresses that correspond to source and destination host addresses.
385 */
386 if (!fast_classifier_find_mac_addr(sic.src_ip, sic.src_mac)) {
387 DEBUG_TRACE("failed to find MAC address for src IP: %pI4\n", &sic.src_ip);
388 goto done1;
389 }
390
391 if (!fast_classifier_find_mac_addr(sic.src_ip_xlate, sic.src_mac_xlate)) {
392 DEBUG_TRACE("failed to find MAC address for xlate src IP: %pI4\n", &sic.src_ip_xlate);
393 goto done1;
394 }
395
396 /*
397 * Do dest now
398 */
399 if (!fast_classifier_find_mac_addr(sic.dest_ip, sic.dest_mac)) {
400 DEBUG_TRACE("failed to find MAC address for dest IP: %pI4\n", &sic.dest_ip);
401 goto done1;
402 }
403
404 if (!fast_classifier_find_mac_addr(sic.dest_ip_xlate, sic.dest_mac_xlate)) {
405 DEBUG_TRACE("failed to find MAC address for xlate dest IP: %pI4\n", &sic.dest_ip_xlate);
406 goto done1;
407 }
408
409 /*
410 * Get our device info. If we're dealing with the "reply" direction here then
411 * we'll need things swapped around.
412 */
413 if (ctinfo < IP_CT_IS_REPLY) {
414 src_dev = in;
415 dest_dev = (struct net_device *)out;
416 } else {
417 src_dev = (struct net_device *)out;
418 dest_dev = in;
419 }
420
421#if (!SFE_HOOK_ABOVE_BRIDGE)
422 /*
423 * Now our devices may actually be a bridge interface. If that's
424 * the case then we need to hunt down the underlying interface.
425 */
426 if (src_dev->priv_flags & IFF_EBRIDGE) {
427 src_br_dev = br_port_dev_get(src_dev, sic.src_mac);
428 if (!src_br_dev) {
429 DEBUG_TRACE("no port found on bridge\n");
430 goto done1;
431 }
432
433 src_dev = src_br_dev;
434 }
435
436 if (dest_dev->priv_flags & IFF_EBRIDGE) {
437 dest_br_dev = br_port_dev_get(dest_dev, sic.dest_mac_xlate);
438 if (!dest_br_dev) {
439 DEBUG_TRACE("no port found on bridge\n");
440 goto done2;
441 }
442
443 dest_dev = dest_br_dev;
444 }
445#else
446 /*
447 * Our devices may actually be part of a bridge interface. If that's
448 * the case then find the bridge interface instead.
449 */
450 if (src_dev->priv_flags & IFF_BRIDGE_PORT) {
451 src_br_dev = src_dev->master;
452 if (!src_br_dev) {
453 DEBUG_TRACE("no bridge found for: %s\n", src_dev->name);
454 goto done1;
455 }
456
457 dev_hold(src_br_dev);
458 src_dev = src_br_dev;
459 }
460
461 if (dest_dev->priv_flags & IFF_BRIDGE_PORT) {
462 dest_br_dev = dest_dev->master;
463 if (!dest_br_dev) {
464 DEBUG_TRACE("no bridge found for: %s\n", dest_dev->name);
465 goto done2;
466 }
467
468 dev_hold(dest_br_dev);
469 dest_dev = dest_br_dev;
470 }
471#endif
472
473 sic.src_dev = src_dev;
474 sic.dest_dev = dest_dev;
475
476// XXX - these MTUs need handling correctly!
477 sic.src_mtu = 1500;
478 sic.dest_mtu = 1500;
479
480 sfe_ipv4_create_rule(&sic);
481
482 /*
483 * If we had bridge ports then release them too.
484 */
485 if (dest_br_dev) {
486 dev_put(dest_br_dev);
487 }
488
489done2:
490 if (src_br_dev) {
491 dev_put(src_br_dev);
492 }
493
494done1:
495 /*
496 * Release the interface on which this skb arrived
497 */
498 dev_put(in);
499
500 return NF_ACCEPT;
501}
502#endif
503
504#ifdef CONFIG_NF_CONNTRACK_EVENTS
505/*
506 * fast_classifier_conntrack_event()
507 * Callback event invoked when a conntrack connection's state changes.
508 */
509static int fast_classifier_conntrack_event(unsigned int events, struct nf_ct_event *item)
510{
511 struct sfe_ipv4_destroy sid;
512 struct nf_conn *ct = item->ct;
513 struct nf_conntrack_tuple orig_tuple;
514
515 /*
516 * If we don't have a conntrack entry then we're done.
517 */
518 if (unlikely(!ct)) {
519 DEBUG_WARN("no ct in conntrack event callback\n");
520 return NOTIFY_DONE;
521 }
522
523 /*
524 * If this is an untracked connection then we can't have any state either.
525 */
526 if (unlikely(ct == &nf_conntrack_untracked)) {
527 DEBUG_TRACE("ignoring untracked conn\n");
528 return NOTIFY_DONE;
529 }
530
531 /*
532 * Ignore anything other than IPv4 connections.
533 */
534 if (unlikely(nf_ct_l3num(ct) != AF_INET)) {
535 DEBUG_TRACE("ignoring non-IPv4 conn\n");
536 return NOTIFY_DONE;
537 }
538
539 /*
540 * We're only interested in destroy events.
541 */
542 if (unlikely(!(events & (1 << IPCT_DESTROY)))) {
543 DEBUG_TRACE("ignoring non-destroy event\n");
544 return NOTIFY_DONE;
545 }
546
547 orig_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
548 sid.protocol = (int32_t)orig_tuple.dst.protonum;
549
550 /*
551 * Extract information from the conntrack connection. We're only interested
552 * in nominal connection information (i.e. we're ignoring any NAT information).
553 */
554 sid.src_ip = (__be32)orig_tuple.src.u3.ip;
555 sid.dest_ip = (__be32)orig_tuple.dst.u3.ip;
556
557 switch (sid.protocol) {
558 case IPPROTO_TCP:
559 sid.src_port = orig_tuple.src.u.tcp.port;
560 sid.dest_port = orig_tuple.dst.u.tcp.port;
561 break;
562
563 case IPPROTO_UDP:
564 sid.src_port = orig_tuple.src.u.udp.port;
565 sid.dest_port = orig_tuple.dst.u.udp.port;
566 break;
567
568 default:
569 DEBUG_TRACE("unhandled protocol: %d\n", sid.protocol);
570 return NOTIFY_DONE;
571 }
572
573
574 sfe_ipv4_destroy_rule(&sid);
575 return NOTIFY_DONE;
576}
577
578/*
579 * Netfilter conntrack event system to monitor connection tracking changes
580 */
581static struct nf_ct_event_notifier fast_classifier_conntrack_notifier = {
582 .fcn = fast_classifier_conntrack_event,
583};
584#endif
585
586#if 1
587/*
588 * Structure to establish a hook into the post routing netfilter point - this
589 * will pick up local outbound and packets going from one interface to another.
590 *
591 * Note: see include/linux/netfilter_ipv4.h for info related to priority levels.
592 * We want to examine packets after NAT translation and any ALG processing.
593 */
594static struct nf_hook_ops fast_classifier_ipv4_ops_post_routing[] __read_mostly = {
595 {
596 .hook = fast_classifier_ipv4_post_routing_hook,
597 .owner = THIS_MODULE,
598 .pf = PF_INET,
599 .hooknum = NF_INET_POST_ROUTING,
600 .priority = NF_IP_PRI_NAT_SRC + 1,
601 },
602};
603#endif
604
605/*
606 * fast_classifier_sync_rule()
607 * Synchronize a connection's state.
608 */
609static void fast_classifier_sync_rule(struct sfe_ipv4_sync *sis)
610{
611 struct nf_conntrack_tuple_hash *h;
612 struct nf_conntrack_tuple tuple;
613 struct nf_conn *ct;
614 struct nf_conn_counter *acct;
615
616 /*
617 * Create a tuple so as to be able to look up a connection
618 */
619 memset(&tuple, 0, sizeof(tuple));
620 tuple.src.u3.ip = sis->src_ip;
621 tuple.src.u.all = (__be16)sis->src_port;
622 tuple.src.l3num = AF_INET;
623
624 tuple.dst.u3.ip = sis->dest_ip;
625 tuple.dst.dir = IP_CT_DIR_ORIGINAL;
626 tuple.dst.protonum = (uint8_t)sis->protocol;
627 tuple.dst.u.all = (__be16)sis->dest_port;
628
629 DEBUG_TRACE("update connection - p: %d, s: %pI4:%u, d: %pI4:%u\n",
630 (int)tuple.dst.protonum,
631 &tuple.src.u3.ip, (unsigned int)ntohs(tuple.src.u.all),
632 &tuple.dst.u3.ip, (unsigned int)ntohs(tuple.dst.u.all));
633
634 /*
635 * Look up conntrack connection
636 */
637 h = nf_conntrack_find_get(&init_net, NF_CT_DEFAULT_ZONE, &tuple);
638 if (unlikely(!h)) {
639 DEBUG_TRACE("no connection found\n");
640 return;
641 }
642
643 ct = nf_ct_tuplehash_to_ctrack(h);
644 NF_CT_ASSERT(ct->timeout.data == (unsigned long)ct);
645
646 /*
647 * Only update if this is not a fixed timeout
648 */
649 if (!test_bit(IPS_FIXED_TIMEOUT_BIT, &ct->status)) {
650 ct->timeout.expires += sis->delta_jiffies;
651 }
652
653 acct = nf_conn_acct_find(ct);
654 if (acct) {
655 spin_lock_bh(&ct->lock);
656 atomic64_add(sis->src_packet_count, &acct[IP_CT_DIR_ORIGINAL].packets);
657 atomic64_add(sis->src_byte_count, &acct[IP_CT_DIR_ORIGINAL].bytes);
658 atomic64_add(sis->dest_packet_count, &acct[IP_CT_DIR_REPLY].packets);
659 atomic64_add(sis->dest_byte_count, &acct[IP_CT_DIR_REPLY].bytes);
660 spin_unlock_bh(&ct->lock);
661 }
662
663 switch (sis->protocol) {
664 case IPPROTO_TCP:
665 spin_lock_bh(&ct->lock);
666 if (ct->proto.tcp.seen[0].td_maxwin < sis->src_td_max_window) {
667 ct->proto.tcp.seen[0].td_maxwin = sis->src_td_max_window;
668 }
669 if ((int32_t)(ct->proto.tcp.seen[0].td_end - sis->src_td_end) < 0) {
670 ct->proto.tcp.seen[0].td_end = sis->src_td_end;
671 }
672 if ((int32_t)(ct->proto.tcp.seen[0].td_maxend - sis->src_td_max_end) < 0) {
673 ct->proto.tcp.seen[0].td_maxend = sis->src_td_max_end;
674 }
675 if (ct->proto.tcp.seen[1].td_maxwin < sis->dest_td_max_window) {
676 ct->proto.tcp.seen[1].td_maxwin = sis->dest_td_max_window;
677 }
678 if ((int32_t)(ct->proto.tcp.seen[1].td_end - sis->dest_td_end) < 0) {
679 ct->proto.tcp.seen[1].td_end = sis->dest_td_end;
680 }
681 if ((int32_t)(ct->proto.tcp.seen[1].td_maxend - sis->dest_td_max_end) < 0) {
682 ct->proto.tcp.seen[1].td_maxend = sis->dest_td_max_end;
683 }
684 spin_unlock_bh(&ct->lock);
685 break;
686 }
687
688 /*
689 * Release connection
690 */
691 nf_ct_put(ct);
692}
693
694/*
695 * fast_classifier_device_event()
696 */
697static int fast_classifier_device_event(struct notifier_block *this, unsigned long event, void *ptr)
698{
699 struct net_device *dev = (struct net_device *)ptr;
700
701 switch (event) {
702 case NETDEV_DOWN:
703 if (dev) {
704 sfe_ipv4_destroy_all_rules_for_dev(dev);
705 }
706 break;
707 }
708
709 return NOTIFY_DONE;
710}
711
712/*
713 * fast_classifier_inet_event()
714 */
715static int fast_classifier_inet_event(struct notifier_block *this, unsigned long event, void *ptr)
716{
717 struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev;
718 return fast_classifier_device_event(this, event, dev);
719}
720
721/*
722 * fast_classifier_init()
723 */
724static int __init fast_classifier_init(void)
725{
726 struct fast_classifier *sc = &__sc;
727 int result = -1;
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -0600728
729 printk(KERN_ALERT "fast-classifier: starting up\n");
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600730 DEBUG_INFO("SFE CM init\n");
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -0600731
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600732 /*
733 * Create sys/fast_classifier
734 */
735 sc->sys_fast_classifier = kobject_create_and_add("fast_classifier", NULL);
736 if (!sc->sys_fast_classifier) {
737 DEBUG_ERROR("failed to register fast_classifier\n");
738 goto exit1;
739 }
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -0600740
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600741 sc->dev_notifier.notifier_call = fast_classifier_device_event;
742 sc->dev_notifier.priority = 1;
743 register_netdevice_notifier(&sc->dev_notifier);
744
745 sc->inet_notifier.notifier_call = fast_classifier_inet_event;
746 sc->inet_notifier.priority = 1;
747 register_inetaddr_notifier(&sc->inet_notifier);
748
749#if 1
750 /*
751 * Register our netfilter hooks.
752 */
753 result = nf_register_hooks(fast_classifier_ipv4_ops_post_routing, ARRAY_SIZE(fast_classifier_ipv4_ops_post_routing));
754 if (result < 0) {
755 DEBUG_ERROR("can't register nf post routing hook: %d\n", result);
756 goto exit6;
757 }
758#endif
759
760#ifdef CONFIG_NF_CONNTRACK_EVENTS
761 /*
762 * Register a notifier hook to get fast notifications of expired connections.
763 */
764 result = nf_conntrack_register_notifier(&init_net, &fast_classifier_conntrack_notifier);
765 if (result < 0) {
766 DEBUG_ERROR("can't register nf notifier hook: %d\n", result);
767 goto exit7;
768 }
769#endif
770
771 spin_lock_init(&sc->lock);
772
773 /*
774 * Hook the receive path in the network stack.
775 */
776 BUG_ON(athrs_fast_nat_recv != NULL);
777 RCU_INIT_POINTER(athrs_fast_nat_recv, fast_classifier_recv);
778
779 /*
780 * Hook the shortcut sync callback.
781 */
782 sfe_ipv4_register_sync_rule_callback(fast_classifier_sync_rule);
783
784 result = genl_register_family(&fast_classifier_gnl_family);
785 if (result!= 0)
786 goto exit8;
787
788 result = genl_register_ops(&fast_classifier_gnl_family, &fast_classifier_gnl_ops_recv);
789 if (result != 0)
790 goto exit9;
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -0600791
792 printk(KERN_ALERT "fast-classifier: registered\n");
Matthew McClintock6f29aa12013-11-06 15:49:01 -0600793
794 return 0;
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -0600795
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600796exit9:
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -0600797 genl_unregister_family(&fast_classifier_gnl_family);
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600798exit8:
799
800#ifdef CONFIG_NF_CONNTRACK_EVENTS
801exit7:
802#endif
803#if 1
804 nf_unregister_hooks(fast_classifier_ipv4_ops_post_routing, ARRAY_SIZE(fast_classifier_ipv4_ops_post_routing));
805#endif
806
807exit6:
808 unregister_inetaddr_notifier(&sc->inet_notifier);
809 unregister_netdevice_notifier(&sc->dev_notifier);
810 kobject_put(sc->sys_fast_classifier);
811
812exit1:
813 return result;
Matthew McClintock6f29aa12013-11-06 15:49:01 -0600814}
815
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600816/*
817 * fast_classifier_exit()
818 */
819static void __exit fast_classifier_exit(void)
Matthew McClintock6f29aa12013-11-06 15:49:01 -0600820{
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600821 struct fast_classifier *sc = &__sc;
822 int result = -1;
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -0600823
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600824 DEBUG_INFO("SFE CM exit\n");
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -0600825 printk(KERN_ALERT "fast-classifier: shutting down\n");
826
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600827 /*
828 * Unregister our sync callback.
829 */
830 sfe_ipv4_register_sync_rule_callback(NULL);
831
832 /*
833 * Unregister our receive callback.
834 */
835 RCU_INIT_POINTER(athrs_fast_nat_recv, NULL);
836
837 /*
838 * Wait for all callbacks to complete.
839 */
840 rcu_barrier();
841
842 /*
843 * Destroy all connections.
844 */
845 sfe_ipv4_destroy_all_rules_for_dev(NULL);
846
847// XXX - this is where we need to unregister with any lower level offload services.
848
849#ifdef CONFIG_NF_CONNTRACK_EVENTS
850 nf_conntrack_unregister_notifier(&init_net, &fast_classifier_conntrack_notifier);
851
852#endif
853#if 1
854 nf_unregister_hooks(fast_classifier_ipv4_ops_post_routing, ARRAY_SIZE(fast_classifier_ipv4_ops_post_routing));
855#endif
856
857 unregister_inetaddr_notifier(&sc->inet_notifier);
858 unregister_netdevice_notifier(&sc->dev_notifier);
859
860 kobject_put(sc->sys_fast_classifier);
861
862 result = genl_register_family(&fast_classifier_gnl_family);
863 if (result != 0)
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -0600864 printk(KERN_CRIT "Unable to unreigster genl_family\n");
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -0600865
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600866 result = genl_register_ops(&fast_classifier_gnl_family, &fast_classifier_gnl_ops_recv);
867 if (result != 0)
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -0600868 printk(KERN_CRIT "Unable to unreigster genl_ops\n");
Matthew McClintock6f29aa12013-11-06 15:49:01 -0600869}
870
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600871module_init(fast_classifier_init)
872module_exit(fast_classifier_exit)
873
874MODULE_AUTHOR("Qualcomm Atheros Inc.");
875MODULE_DESCRIPTION("Shortcut Forwarding Engine - Connection Manager");
Matthew McClintock6f29aa12013-11-06 15:49:01 -0600876MODULE_LICENSE("GPL");
877