source: src/linux/universal/linux-3.18/net/shortcut-fe/fast-classifier.c @ 33046

Last change on this file since 33046 was 33046, checked in by brainslayer, 10 days ago

dissent: sfe: support qos ingress shaping

File size: 52.2 KB
Line 
1/*
2 * fast-classifier.c
3 *      Shortcut forwarding engine connection manager.
4 *      fast-classifier
5 *
6 * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved.
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
16 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18#include <linux/module.h>
19#include <linux/sysfs.h>
20#include <linux/skbuff.h>
21#include <net/route.h>
22#include <net/ip6_route.h>
23#include <net/addrconf.h>
24#include <net/dsfield.h>
25#include <linux/inetdevice.h>
26#include <linux/netfilter_bridge.h>
27#include <linux/netfilter_ipv6.h>
28#include <net/netfilter/nf_conntrack_acct.h>
29#include <net/netfilter/nf_conntrack_helper.h>
30#include <net/netfilter/nf_conntrack_zones.h>
31#include <net/netfilter/nf_conntrack_core.h>
32#include <linux/netfilter/xt_dscp.h>
33#include <net/genetlink.h>
34#include <linux/spinlock.h>
35#include <linux/if_bridge.h>
36#include <linux/hashtable.h>
37#include <net/pkt_sched.h>
38
39#include "sfe_backport.h"
40#include "sfe.h"
41#include "sfe_cm.h"
42#include "fast-classifier.h"
43
44typedef enum fast_classifier_exception {
45        FAST_CL_EXCEPTION_PACKET_BROADCAST,
46        FAST_CL_EXCEPTION_PACKET_MULTICAST,
47        FAST_CL_EXCEPTION_NO_IIF,
48        FAST_CL_EXCEPTION_NO_CT,
49        FAST_CL_EXCEPTION_CT_NO_TRACK,
50        FAST_CL_EXCEPTION_CT_NO_CONFIRM,
51        FAST_CL_EXCEPTION_CT_IS_ALG,
52        FAST_CL_EXCEPTION_IS_IPV4_MCAST,
53        FAST_CL_EXCEPTION_IS_IPV6_MCAST,
54        FAST_CL_EXCEPTION_TCP_NOT_ASSURED,
55        FAST_CL_EXCEPTION_TCP_NOT_ESTABLISHED,
56        FAST_CL_EXCEPTION_UNKNOW_PROTOCOL,
57        FAST_CL_EXCEPTION_NO_SRC_DEV,
58        FAST_CL_EXCEPTION_NO_SRC_XLATE_DEV,
59        FAST_CL_EXCEPTION_NO_DEST_DEV,
60        FAST_CL_EXCEPTION_NO_DEST_XLATE_DEV,
61        FAST_CL_EXCEPTION_NO_BRIDGE,
62        FAST_CL_EXCEPTION_LOCAL_OUT,
63        FAST_CL_EXCEPTION_WAIT_FOR_ACCELERATION,
64        FAST_CL_EXCEPTION_UPDATE_PROTOCOL_FAIL,
65        FAST_CL_EXCEPTION_CT_DESTROY_MISS,
66        FAST_CL_EXCEPTION_MAX
67} fast_classifier_exception_t;
68
69static char *fast_classifier_exception_events_string[FAST_CL_EXCEPTION_MAX] = {
70        "PACKET_BROADCAST",
71        "PACKET_MULTICAST",
72        "NO_IIF",
73        "NO_CT",
74        "CT_NO_TRACK",
75        "CT_NO_CONFIRM",
76        "CT_IS_ALG",
77        "IS_IPV4_MCAST",
78        "IS_IPV6_MCAST",
79        "TCP_NOT_ASSURED",
80        "TCP_NOT_ESTABLISHED",
81        "UNKNOW_PROTOCOL",
82        "NO_SRC_DEV",
83        "NO_SRC_XLATE_DEV",
84        "NO_DEST_DEV",
85        "NO_DEST_XLATE_DEV",
86        "NO_BRIDGE",
87        "LOCAL_OUT",
88        "WAIT_FOR_ACCELERATION",
89        "UPDATE_PROTOCOL_FAIL",
90        "CT_DESTROY_MISS",
91};
92
93/*
94 * Per-module structure.
95 */
96struct fast_classifier {
97        spinlock_t lock;                /* Lock for SMP correctness */
98
99        /*
100         * Control state.
101         */
102        struct kobject *sys_fast_classifier;    /* sysfs linkage */
103
104        /*
105         * Callback notifiers.
106         */
107        struct notifier_block dev_notifier;     /* Device notifier */
108        struct notifier_block inet_notifier;    /* IPv4 notifier */
109#ifdef SFE_SUPPORT_IPV6
110        struct notifier_block inet6_notifier;   /* IPv6 notifier */
111#endif
112        u32 exceptions[FAST_CL_EXCEPTION_MAX];
113};
114
115static struct fast_classifier __fsc;
116
117static struct nla_policy fast_classifier_genl_policy[FAST_CLASSIFIER_A_MAX + 1] = {
118        [FAST_CLASSIFIER_A_TUPLE] = {
119                .type = NLA_UNSPEC,
120                .len = sizeof(struct fast_classifier_tuple)
121        },
122};
123
124static struct genl_multicast_group fast_classifier_genl_mcgrp[] = {
125        {
126                .name = FAST_CLASSIFIER_GENL_MCGRP,
127        },
128};
129
130static struct genl_family fast_classifier_gnl_family = {
131        .id = GENL_ID_GENERATE,
132        .hdrsize = FAST_CLASSIFIER_GENL_HDRSIZE,
133        .name = FAST_CLASSIFIER_GENL_NAME,
134        .version = FAST_CLASSIFIER_GENL_VERSION,
135        .maxattr = FAST_CLASSIFIER_A_MAX,
136};
137
138static int fast_classifier_offload_genl_msg(struct sk_buff *skb, struct genl_info *info);
139static int fast_classifier_nl_genl_msg_DUMP(struct sk_buff *skb, struct netlink_callback *cb);
140
141static struct genl_ops fast_classifier_gnl_ops[] = {
142        {
143                .cmd = FAST_CLASSIFIER_C_OFFLOAD,
144                .flags = 0,
145                .policy = fast_classifier_genl_policy,
146                .doit = fast_classifier_offload_genl_msg,
147                .dumpit = NULL,
148        },
149        {
150                .cmd = FAST_CLASSIFIER_C_OFFLOADED,
151                .flags = 0,
152                .policy = fast_classifier_genl_policy,
153                .doit = NULL,
154                .dumpit = fast_classifier_nl_genl_msg_DUMP,
155        },
156        {
157                .cmd = FAST_CLASSIFIER_C_DONE,
158                .flags = 0,
159                .policy = fast_classifier_genl_policy,
160                .doit = NULL,
161                .dumpit = fast_classifier_nl_genl_msg_DUMP,
162        },
163};
164
165static atomic_t offload_msgs = ATOMIC_INIT(0);
166static atomic_t offload_no_match_msgs = ATOMIC_INIT(0);
167static atomic_t offloaded_msgs = ATOMIC_INIT(0);
168static atomic_t done_msgs = ATOMIC_INIT(0);
169
170static atomic_t offloaded_fail_msgs = ATOMIC_INIT(0);
171static atomic_t done_fail_msgs = ATOMIC_INIT(0);
172
173/*
174 * Accelerate incoming packets destined for bridge device
175 *      If a incoming packet is ultimatly destined for
176 *      a bridge device we will first see the packet coming
177 *      from the phyiscal device, we can skip straight to
178 *      processing the packet like it came from the bridge
179 *      for some more performance gains
180 *
181 *      This only works when the hook is above the bridge. We
182 *      only implement ingress for now, because for egress we
183 *      want to have the bridge devices qdiscs be used.
184 */
185static bool skip_to_bridge_ingress;
186
187/*
188 * fast_classifier_incr_exceptions()
189 *      increase an exception counter.
190 */
191static inline void fast_classifier_incr_exceptions(fast_classifier_exception_t except)
192{
193        struct fast_classifier *sc = &__fsc;
194
195        spin_lock_bh(&sc->lock);
196        sc->exceptions[except]++;
197        spin_unlock_bh(&sc->lock);
198}
199
200/*
201 * fast_classifier_recv()
202 *      Handle packet receives.
203 *
204 * Returns 1 if the packet is forwarded or 0 if it isn't.
205 */
206static int fast_classifier_recv(struct sk_buff *skb)
207{
208        struct net_device *dev;
209        struct net_device *master_dev = NULL;
210        int ret = 0;
211
212        /*
213         * We know that for the vast majority of packets we need the transport
214         * layer header so we may as well start to fetch it now!
215         */
216        prefetch(skb->data + 32);
217        barrier();
218
219        dev = skb->dev;
220
221        /*
222         * Process packet like it arrived on the bridge device
223         */
224        if (skip_to_bridge_ingress &&
225            (dev->priv_flags & IFF_BRIDGE_PORT)) {
226                master_dev = sfe_dev_get_master(dev);
227                if (!master_dev) {
228                        DEBUG_WARN("master dev is NULL %s\n");
229                        goto rx_exit;
230                }
231                dev = master_dev;
232        }
233
234#ifdef CONFIG_NET_CLS_ACT
235        /*
236         * If ingress Qdisc configured, and packet not processed by ingress Qdisc yet
237         * We cannot accelerate this packet.
238         */
239        if (dev->ingress_queue && !(skb->tc_verd & TC_NCLS)) {
240                goto rx_exit;
241        }
242#endif
243
244        /*
245         * We're only interested in IPv4 and IPv6 packets.
246         */
247        if (likely(htons(ETH_P_IP) == skb->protocol)) {
248                struct in_device *in_dev;
249
250                /*
251                 * Does our input device support IP processing?
252                 */
253                in_dev = (struct in_device *)dev->ip_ptr;
254                if (unlikely(!in_dev)) {
255                        DEBUG_TRACE("no IP processing for device: %s\n", dev->name);
256                        goto rx_exit;
257                }
258
259                /*
260                 * Does it have an IP address?  If it doesn't then we can't do anything
261                 * interesting here!
262                 */
263                if (unlikely(!in_dev->ifa_list)) {
264                        DEBUG_TRACE("no IP address for device: %s\n", dev->name);
265                        goto rx_exit;
266                }
267
268                ret = sfe_ipv4_recv(dev, skb);
269
270        }
271#ifdef SFE_SUPPORT_IPV6
272        else if (likely(htons(ETH_P_IPV6) == skb->protocol)) {
273                struct inet6_dev *in_dev;
274
275                /*
276                 * Does our input device support IPv6 processing?
277                 */
278                in_dev = (struct inet6_dev *)dev->ip6_ptr;
279                if (unlikely(!in_dev)) {
280                        DEBUG_TRACE("no IPv6 processing for device: %s\n", dev->name);
281                        goto rx_exit;
282                }
283
284                /*
285                 * Does it have an IPv6 address?  If it doesn't then we can't do anything
286                 * interesting here!
287                 */
288                if (unlikely(list_empty(&in_dev->addr_list))) {
289                        DEBUG_TRACE("no IPv6 address for device: %s\n", dev->name);
290                        goto rx_exit;
291                }
292
293                ret = sfe_ipv6_recv(dev, skb);
294
295        }
296#endif
297        else {
298                DEBUG_TRACE("not IP packet\n");
299        }
300
301rx_exit:
302        if (master_dev) {
303                dev_put(master_dev);
304        }
305
306        return ret;
307}
308
309/*
310 * fast_classifier_find_dev_and_mac_addr()
311 *      Find the device and MAC address for a given IPv4 address.
312 *
313 * Returns true if we find the device and MAC address, otherwise false.
314 *
315 * We look up the rtable entry for the address and, from its neighbour
316 * structure, obtain the hardware address.  This means this function also
317 * works if the neighbours are routers too.
318 */
319static bool fast_classifier_find_dev_and_mac_addr(sfe_ip_addr_t *addr, struct net_device **dev, u8 *mac_addr, bool is_v4)
320{
321        struct neighbour *neigh;
322        struct rtable *rt;
323        struct rt6_info *rt6 = NULL;
324        struct dst_entry *dst;
325        struct net_device *mac_dev;
326
327        /*
328         * Look up the rtable entry for the IP address then get the hardware
329         * address from its neighbour structure.  This means this works when the
330         * neighbours are routers too.
331         */
332        if (likely(is_v4)) {
333                rt = ip_route_output(&init_net, addr->ip, 0, 0, 0);
334                if (unlikely(IS_ERR(rt))) {
335                        goto ret_fail;
336                }
337
338                dst = (struct dst_entry *)rt;
339        } else {
340                if (rt6_lookup)
341                        rt6 = rt6_lookup(&init_net, (struct in6_addr *)addr->ip6, 0, 0, 0);
342                if (!rt6) {
343                        goto ret_fail;
344                }
345
346                dst = (struct dst_entry *)rt6;
347        }
348
349        rcu_read_lock();
350        neigh = sfe_dst_get_neighbour(dst, addr);
351        if (unlikely(!neigh)) {
352                rcu_read_unlock();
353                dst_release(dst);
354                goto ret_fail;
355        }
356
357        if (unlikely(!(neigh->nud_state & NUD_VALID))) {
358                rcu_read_unlock();
359                neigh_release(neigh);
360                dst_release(dst);
361                goto ret_fail;
362        }
363
364        mac_dev = neigh->dev;
365        if (!mac_dev) {
366                rcu_read_unlock();
367                neigh_release(neigh);
368                dst_release(dst);
369                goto ret_fail;
370        }
371
372        memcpy(mac_addr, neigh->ha, (size_t)mac_dev->addr_len);
373
374        dev_hold(mac_dev);
375        *dev = mac_dev;
376        rcu_read_unlock();
377        neigh_release(neigh);
378        dst_release(dst);
379
380        return true;
381
382ret_fail:
383        if (is_v4) {
384                DEBUG_TRACE("failed to find MAC address for IP: %pI4\n", addr);
385
386        } else {
387                DEBUG_TRACE("failed to find MAC address for IP: %pI6\n", addr);
388        }
389
390        return false;
391}
392
393static DEFINE_SPINLOCK(sfe_connections_lock);
394
395struct sfe_connection {
396        struct hlist_node hl;
397        struct sfe_connection_create *sic;
398        struct nf_conn *ct;
399        int hits;
400        int offload_permit;
401        int offloaded;
402        bool is_v4;
403        unsigned char smac[ETH_ALEN];
404        unsigned char dmac[ETH_ALEN];
405};
406
407static int sfe_connections_size;
408
409#define FC_CONN_HASH_ORDER 13
410static DEFINE_HASHTABLE(fc_conn_ht, FC_CONN_HASH_ORDER);
411
412static u32 fc_conn_hash(sfe_ip_addr_t *saddr, sfe_ip_addr_t *daddr,
413                        unsigned short sport, unsigned short dport, bool is_v4)
414{
415        u32 idx, cnt = ((is_v4 ? sizeof(saddr->ip) : sizeof(saddr->ip6))/sizeof(u32));
416        u32 hash = 0;
417
418        for (idx = 0; idx < cnt; idx++) {
419                hash ^= ((u32 *)saddr)[idx] ^ ((u32 *)daddr)[idx];
420        }
421
422        return hash ^ (sport | (dport << 16));
423}
424
425/*
426 * fast_classifier_update_protocol()
427 *      Update sfe_ipv4_create struct with new protocol information before we offload
428 */
429static int fast_classifier_update_protocol(struct sfe_connection_create *p_sic, struct nf_conn *ct)
430{
431        switch (p_sic->protocol) {
432        case IPPROTO_TCP:
433                p_sic->src_td_window_scale = ct->proto.tcp.seen[0].td_scale;
434                p_sic->src_td_max_window = ct->proto.tcp.seen[0].td_maxwin;
435                p_sic->src_td_end = ct->proto.tcp.seen[0].td_end;
436                p_sic->src_td_max_end = ct->proto.tcp.seen[0].td_maxend;
437                p_sic->dest_td_window_scale = ct->proto.tcp.seen[1].td_scale;
438                p_sic->dest_td_max_window = ct->proto.tcp.seen[1].td_maxwin;
439                p_sic->dest_td_end = ct->proto.tcp.seen[1].td_end;
440                p_sic->dest_td_max_end = ct->proto.tcp.seen[1].td_maxend;
441
442                if (nf_ct_tcp_no_window_check
443                    || (ct->proto.tcp.seen[0].flags & IP_CT_TCP_FLAG_BE_LIBERAL)
444                    || (ct->proto.tcp.seen[1].flags & IP_CT_TCP_FLAG_BE_LIBERAL)) {
445                        p_sic->flags |= SFE_CREATE_FLAG_NO_SEQ_CHECK;
446                }
447
448                /*
449                 * If the connection is shutting down do not manage it.
450                 * state can not be SYN_SENT, SYN_RECV because connection is assured
451                 * Not managed states: FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE.
452                 */
453                spin_lock_bh(&ct->lock);
454                if (ct->proto.tcp.state != TCP_CONNTRACK_ESTABLISHED) {
455                        spin_unlock_bh(&ct->lock);
456                        fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_TCP_NOT_ESTABLISHED);
457                        DEBUG_TRACE("connection in termination state: %#x, s: %pI4:%u, d: %pI4:%u\n",
458                                    ct->proto.tcp.state, &p_sic->src_ip, ntohs(p_sic->src_port),
459                                    &p_sic->dest_ip, ntohs(p_sic->dest_port));
460                        return 0;
461                }
462                spin_unlock_bh(&ct->lock);
463                break;
464
465        case IPPROTO_UDP:
466                break;
467
468        default:
469                fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_UNKNOW_PROTOCOL);
470                DEBUG_TRACE("unhandled protocol %d\n", p_sic->protocol);
471                return 0;
472        }
473
474        return 1;
475}
476
477/* fast_classifier_send_genl_msg()
478 *      Function to send a generic netlink message
479 */
480static void fast_classifier_send_genl_msg(int msg, struct fast_classifier_tuple *fc_msg)
481{
482        struct sk_buff *skb;
483        int rc;
484        int buf_len;
485        int total_len;
486        void *msg_head;
487
488        /*
489         * Calculate our packet payload size.
490         * Start with our family header.
491         */
492        buf_len = fast_classifier_gnl_family.hdrsize;
493
494        /*
495         * Add the nla_total_size of each attribute we're going to nla_put().
496         */
497        buf_len += nla_total_size(sizeof(*fc_msg));
498
499        /*
500         * Lastly we need to add space for the NL message header since
501         * genlmsg_new only accounts for the GENL header and not the
502         * outer NL header. To do this, we use a NL helper function which
503         * calculates the total size of a netlink message given a payload size.
504         * Note this value does not include the GENL header, but that's
505         * added automatically by genlmsg_new.
506         */
507        total_len = nlmsg_total_size(buf_len);
508        skb = genlmsg_new(total_len, GFP_ATOMIC);
509        if (!skb)
510                return;
511
512        msg_head = genlmsg_put(skb, 0, 0, &fast_classifier_gnl_family, 0, msg);
513        if (!msg_head) {
514                nlmsg_free(skb);
515                return;
516        }
517
518        rc = nla_put(skb, FAST_CLASSIFIER_A_TUPLE, sizeof(struct fast_classifier_tuple), fc_msg);
519        if (rc != 0) {
520                genlmsg_cancel(skb, msg_head);
521                nlmsg_free(skb);
522                return;
523        }
524
525#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 19 , 0))
526        rc = genlmsg_end(skb, msg_head);
527        if (rc < 0) {
528                genlmsg_cancel(skb, msg_head);
529                nlmsg_free(skb);
530                return;
531        }
532#else
533        genlmsg_end(skb, msg_head);
534
535#endif
536
537#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0))
538        rc = genlmsg_multicast(&fast_classifier_gnl_family, skb, 0, 0, GFP_ATOMIC);
539#else
540        rc = genlmsg_multicast(skb, 0, fast_classifier_genl_mcgrp[0].id, GFP_ATOMIC);
541#endif
542        switch (msg) {
543        case FAST_CLASSIFIER_C_OFFLOADED:
544                if (rc == 0) {
545                        atomic_inc(&offloaded_msgs);
546                } else {
547                        atomic_inc(&offloaded_fail_msgs);
548                }
549                break;
550        case FAST_CLASSIFIER_C_DONE:
551                if (rc == 0) {
552                        atomic_inc(&done_msgs);
553                } else {
554                        atomic_inc(&done_fail_msgs);
555                }
556                break;
557        default:
558                DEBUG_ERROR("fast-classifer: Unknown message type sent!\n");
559                break;
560        }
561
562        DEBUG_TRACE("Notify NL message %d ", msg);
563        if (fc_msg->ethertype == AF_INET) {
564                DEBUG_TRACE("sip=%pI4 dip=%pI4 ", &fc_msg->src_saddr, &fc_msg->dst_saddr);
565        } else {
566                DEBUG_TRACE("sip=%pI6 dip=%pI6 ", &fc_msg->src_saddr, &fc_msg->dst_saddr);
567        }
568        DEBUG_TRACE("protocol=%d sport=%d dport=%d smac=%pM dmac=%pM\n",
569                    fc_msg->proto, fc_msg->sport, fc_msg->dport, fc_msg->smac, fc_msg->dmac);
570}
571
572/*
573 * fast_classifier_find_conn()
574 *      find a connection object in the hash table
575 *      @pre the sfe_connection_lock must be held before calling this function
576 */
577static struct sfe_connection *
578fast_classifier_find_conn(sfe_ip_addr_t *saddr, sfe_ip_addr_t *daddr,
579                          unsigned short sport, unsigned short dport,
580                          unsigned char proto, bool is_v4)
581{
582        struct sfe_connection_create *p_sic;
583        struct sfe_connection *conn;
584        u32 key;
585#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
586        struct hlist_node *node;
587#endif
588
589        key = fc_conn_hash(saddr, daddr, sport, dport, is_v4);
590
591        sfe_hash_for_each_possible(fc_conn_ht, conn, node, hl, key) {
592                if (conn->is_v4 != is_v4) {
593                        continue;
594                }
595
596                p_sic = conn->sic;
597
598                if (p_sic->protocol == proto &&
599                    p_sic->src_port == sport &&
600                    p_sic->dest_port == dport &&
601                    sfe_addr_equal(&p_sic->src_ip, saddr, is_v4) &&
602                    sfe_addr_equal(&p_sic->dest_ip, daddr, is_v4)) {
603                        return conn;
604                }
605        }
606
607        DEBUG_TRACE("connection not found\n");
608        return NULL;
609}
610
611/*
612 * fast_classifier_sb_find_conn()
613 *      find a connection object in the hash table according to information of packet
614 *      if not found, reverse the tuple and try again.
615 *      @pre the sfe_connection_lock must be held before calling this function
616 */
617static struct sfe_connection *
618fast_classifier_sb_find_conn(sfe_ip_addr_t *saddr, sfe_ip_addr_t *daddr,
619                          unsigned short sport, unsigned short dport,
620                          unsigned char proto, bool is_v4)
621{
622        struct sfe_connection_create *p_sic;
623        struct sfe_connection *conn;
624        u32 key;
625#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
626        struct hlist_node *node;
627#endif
628
629        key = fc_conn_hash(saddr, daddr, sport, dport, is_v4);
630
631        sfe_hash_for_each_possible(fc_conn_ht, conn, node, hl, key) {
632                if (conn->is_v4 != is_v4) {
633                        continue;
634                }
635
636                p_sic = conn->sic;
637
638                if (p_sic->protocol == proto &&
639                    p_sic->src_port == sport &&
640                    p_sic->dest_port_xlate == dport &&
641                    sfe_addr_equal(&p_sic->src_ip, saddr, is_v4) &&
642                    sfe_addr_equal(&p_sic->dest_ip_xlate, daddr, is_v4)) {
643                        return conn;
644                }
645        }
646
647        /*
648         * Reverse the tuple and try again
649         */
650        key = fc_conn_hash(daddr, saddr, dport, sport, is_v4);
651
652        sfe_hash_for_each_possible(fc_conn_ht, conn, node, hl, key) {
653                if (conn->is_v4 != is_v4) {
654                        continue;
655                }
656
657                p_sic = conn->sic;
658
659                if (p_sic->protocol == proto &&
660                    p_sic->src_port == dport &&
661                    p_sic->dest_port_xlate == sport &&
662                    sfe_addr_equal(&p_sic->src_ip, daddr, is_v4) &&
663                    sfe_addr_equal(&p_sic->dest_ip_xlate, saddr, is_v4)) {
664                        return conn;
665                }
666        }
667
668        DEBUG_TRACE("connection not found\n");
669        return NULL;
670}
671
672/*
673 * fast_classifier_add_conn()
674 *      add a connection object in the hash table if no duplicate
675 *      @conn connection to add
676 *      @return conn if successful, NULL if duplicate
677 */
678static struct sfe_connection *
679fast_classifier_add_conn(struct sfe_connection *conn)
680{
681        struct sfe_connection_create *sic = conn->sic;
682        u32 key;
683
684        spin_lock_bh(&sfe_connections_lock);
685        if (fast_classifier_find_conn(&sic->src_ip, &sic->dest_ip, sic->src_port,
686                                        sic->dest_port, sic->protocol, conn->is_v4)) {
687                spin_unlock_bh(&sfe_connections_lock);
688                return NULL;
689        }
690
691        key = fc_conn_hash(&sic->src_ip, &sic->dest_ip,
692                           sic->src_port, sic->dest_port, conn->is_v4);
693
694        hash_add(fc_conn_ht, &conn->hl, key);
695        sfe_connections_size++;
696        spin_unlock_bh(&sfe_connections_lock);
697
698        DEBUG_TRACE(" -> adding item to sfe_connections, new size: %d\n", sfe_connections_size);
699
700        if (conn->is_v4) {
701                DEBUG_TRACE("new offloadable: key: %u proto: %d src_ip: %pI4 dst_ip: %pI4, src_port: %d, dst_port: %d\n",
702                                key, sic->protocol, &(sic->src_ip), &(sic->dest_ip), sic->src_port, sic->dest_port);
703        } else {
704                DEBUG_TRACE("new offloadable: key: %u proto: %d src_ip: %pI6 dst_ip: %pI6, src_port: %d, dst_port: %d\n",
705                                key, sic->protocol, &(sic->src_ip), &(sic->dest_ip), sic->src_port, sic->dest_port);
706        }
707
708        return conn;
709}
710
711/*
712 * fast_classifier_offload_genl_msg()
713 *      Called from user space to offload a connection
714 */
715static int
716fast_classifier_offload_genl_msg(struct sk_buff *skb, struct genl_info *info)
717{
718        struct nlattr *na;
719        struct fast_classifier_tuple *fc_msg;
720        struct sfe_connection *conn;
721
722        na = info->attrs[FAST_CLASSIFIER_A_TUPLE];
723        fc_msg = nla_data(na);
724
725        DEBUG_TRACE((fc_msg->ethertype == AF_INET ?
726                "want to offload: %d-%d, %pI4, %pI4, %d, %d SMAC=%pM DMAC=%pM\n" :
727                "want to offload: %d-%d, %pI6, %pI6, %d, %d SMAC=%pM DMAC=%pM\n"),
728                    fc_msg->ethertype,
729                    fc_msg->proto,
730                    &fc_msg->src_saddr,
731                    &fc_msg->dst_saddr,
732                    fc_msg->sport,
733                    fc_msg->dport,
734                    fc_msg->smac,
735                    fc_msg->dmac);
736
737        spin_lock_bh(&sfe_connections_lock);
738        conn = fast_classifier_sb_find_conn((sfe_ip_addr_t *)&fc_msg->src_saddr,
739                                         (sfe_ip_addr_t *)&fc_msg->dst_saddr,
740                                         fc_msg->sport,
741                                         fc_msg->dport,
742                                         fc_msg->proto,
743                                         (fc_msg->ethertype == AF_INET));
744        if (!conn) {
745                spin_unlock_bh(&sfe_connections_lock);
746                DEBUG_TRACE("REQUEST OFFLOAD NO MATCH\n");
747                atomic_inc(&offload_no_match_msgs);
748                return 0;
749        }
750
751        conn->offload_permit = 1;
752        spin_unlock_bh(&sfe_connections_lock);
753        atomic_inc(&offload_msgs);
754
755        DEBUG_TRACE("INFO: calling sfe rule creation!\n");
756        return 0;
757}
758
759/*
760 * fast_classifier_nl_genl_msg_DUMP()
761 *      ignore fast_classifier_messages OFFLOADED and DONE
762 */
763static int fast_classifier_nl_genl_msg_DUMP(struct sk_buff *skb,
764                                            struct netlink_callback *cb)
765{
766        return 0;
767}
768
769/* auto offload connection once we have this many packets*/
770static int offload_at_pkts = 128;
771
772/*
773 * fast_classifier_post_routing()
774 *      Called for packets about to leave the box - either locally generated or forwarded from another interface
775 */
776static unsigned int fast_classifier_post_routing(struct sk_buff *skb, bool is_v4)
777{
778        int ret;
779        struct sfe_connection_create sic;
780        struct sfe_connection_create *p_sic;
781        struct net_device *in;
782        struct nf_conn *ct;
783        enum ip_conntrack_info ctinfo;
784        struct net_device *dev;
785        struct net_device *src_dev;
786        struct net_device *dest_dev;
787        struct net_device *src_br_dev = NULL;
788        struct net_device *dest_br_dev = NULL;
789        struct nf_conntrack_tuple orig_tuple;
790        struct nf_conntrack_tuple reply_tuple;
791        struct sfe_connection *conn;
792
793        /*
794         * Don't process broadcast or multicast packets.
795         */
796        if (unlikely(skb->pkt_type == PACKET_BROADCAST)) {
797                fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_PACKET_BROADCAST);
798                DEBUG_TRACE("broadcast, ignoring\n");
799                return NF_ACCEPT;
800        }
801        if (unlikely(skb->pkt_type == PACKET_MULTICAST)) {
802                fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_PACKET_MULTICAST);
803                DEBUG_TRACE("multicast, ignoring\n");
804                return NF_ACCEPT;
805        }
806
807        /*
808         * Don't process packets that are not being forwarded.
809         */
810        in = dev_get_by_index(&init_net, skb->skb_iif);
811        if (!in) {
812                fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_NO_IIF);
813                DEBUG_TRACE("packet not forwarding\n");
814                return NF_ACCEPT;
815        }
816
817        dev_put(in);
818
819        /*
820         * Don't process packets that aren't being tracked by conntrack.
821         */
822        ct = nf_ct_get(skb, &ctinfo);
823        if (unlikely(!ct)) {
824                fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_NO_CT);
825                DEBUG_TRACE("no conntrack connection, ignoring\n");
826                return NF_ACCEPT;
827        }
828
829        /*
830         * Don't process untracked connections.
831         */
832        if (unlikely(nf_ct_is_untracked(ct))) {
833                fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_CT_NO_TRACK);
834                DEBUG_TRACE("untracked connection\n");
835                return NF_ACCEPT;
836        }
837
838        /*
839         * Unconfirmed connection may be dropped by Linux at the final step,
840         * So we don't process unconfirmed connections.
841         */
842        if (!nf_ct_is_confirmed(ct)) {
843                fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_CT_NO_CONFIRM);
844                DEBUG_TRACE("unconfirmed connection\n");
845                return NF_ACCEPT;
846        }
847
848        /*
849         * Don't process connections that require support from a 'helper' (typically a NAT ALG).
850         */
851        if (unlikely(nfct_help(ct))) {
852                fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_CT_IS_ALG);
853                DEBUG_TRACE("connection has helper\n");
854                return NF_ACCEPT;
855        }
856
857        memset(&sic, 0, sizeof(sic));
858
859        /*
860         * Look up the details of our connection in conntrack.
861         *
862         * Note that the data we get from conntrack is for the "ORIGINAL" direction
863         * but our packet may actually be in the "REPLY" direction.
864         */
865        orig_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
866        reply_tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
867        sic.protocol = (s32)orig_tuple.dst.protonum;
868
869        sic.flags = 0;
870
871        /*
872         * Get addressing information, non-NAT first
873         */
874        if (likely(is_v4)) {
875                u32 dscp;
876
877                sic.src_ip.ip = (__be32)orig_tuple.src.u3.ip;
878                sic.dest_ip.ip = (__be32)orig_tuple.dst.u3.ip;
879
880                if (ipv4_is_multicast(sic.src_ip.ip) || ipv4_is_multicast(sic.dest_ip.ip)) {
881                        fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_IS_IPV4_MCAST);
882                        DEBUG_TRACE("multicast address\n");
883                        return NF_ACCEPT;
884                }
885
886                /*
887                 * NAT'ed addresses - note these are as seen from the 'reply' direction
888                 * When NAT does not apply to this connection these will be identical to the above.
889                 */
890                sic.src_ip_xlate.ip = (__be32)reply_tuple.dst.u3.ip;
891                sic.dest_ip_xlate.ip = (__be32)reply_tuple.src.u3.ip;
892
893                dscp = ipv4_get_dsfield(ip_hdr(skb)) >> XT_DSCP_SHIFT;
894                if (dscp) {
895                        sic.dest_dscp = dscp;
896                        sic.src_dscp = sic.dest_dscp;
897                        sic.flags |= SFE_CREATE_FLAG_REMARK_DSCP;
898                }
899        }
900#ifdef SFE_SUPPORT_IPV6
901        else {
902                u32 dscp;
903
904                sic.src_ip.ip6[0] = *((struct sfe_ipv6_addr *)&orig_tuple.src.u3.in6);
905                sic.dest_ip.ip6[0] = *((struct sfe_ipv6_addr *)&orig_tuple.dst.u3.in6);
906
907                if (ipv6_addr_is_multicast((struct in6_addr *)sic.src_ip.ip6) ||
908                    ipv6_addr_is_multicast((struct in6_addr *)sic.dest_ip.ip6)) {
909                        fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_IS_IPV6_MCAST);
910                        DEBUG_TRACE("multicast address\n");
911                        return NF_ACCEPT;
912                }
913
914                /*
915                 * NAT'ed addresses - note these are as seen from the 'reply' direction
916                 * When NAT does not apply to this connection these will be identical to the above.
917                 */
918                sic.src_ip_xlate.ip6[0] = *((struct sfe_ipv6_addr *)&reply_tuple.dst.u3.in6);
919                sic.dest_ip_xlate.ip6[0] = *((struct sfe_ipv6_addr *)&reply_tuple.src.u3.in6);
920
921                dscp = ipv6_get_dsfield(ipv6_hdr(skb)) >> XT_DSCP_SHIFT;
922                if (dscp) {
923                        sic.dest_dscp = dscp;
924                        sic.src_dscp = sic.dest_dscp;
925                        sic.flags |= SFE_CREATE_FLAG_REMARK_DSCP;
926                }
927        }
928#endif
929
930        switch (sic.protocol) {
931        case IPPROTO_TCP:
932                sic.src_port = orig_tuple.src.u.tcp.port;
933                sic.dest_port = orig_tuple.dst.u.tcp.port;
934                sic.src_port_xlate = reply_tuple.dst.u.tcp.port;
935                sic.dest_port_xlate = reply_tuple.src.u.tcp.port;
936
937                /*
938                 * Don't try to manage a non-established connection.
939                 */
940                if (!test_bit(IPS_ASSURED_BIT, &ct->status)) {
941                        fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_TCP_NOT_ASSURED);
942                        DEBUG_TRACE("non-established connection\n");
943                        return NF_ACCEPT;
944                }
945
946                break;
947
948        case IPPROTO_UDP:
949                sic.src_port = orig_tuple.src.u.udp.port;
950                sic.dest_port = orig_tuple.dst.u.udp.port;
951                sic.src_port_xlate = reply_tuple.dst.u.udp.port;
952                sic.dest_port_xlate = reply_tuple.src.u.udp.port;
953                break;
954
955        default:
956                fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_UNKNOW_PROTOCOL);
957                DEBUG_TRACE("unhandled protocol %d\n", sic.protocol);
958                return NF_ACCEPT;
959        }
960
961#ifdef CONFIG_XFRM
962        sic.original_accel = 1;
963        sic.reply_accel = 1;
964#endif
965
966        /*
967         * Get QoS information
968         */
969        if (skb->priority) {
970                sic.dest_priority = skb->priority;
971                sic.src_priority = sic.dest_priority;
972                sic.flags |= SFE_CREATE_FLAG_REMARK_PRIORITY;
973        }
974
975        if (is_v4) {
976                DEBUG_TRACE("POST_ROUTE: checking new connection: %d src_ip: %pI4 dst_ip: %pI4, src_port: %d, dst_port: %d\n",
977                            sic.protocol, &sic.src_ip, &sic.dest_ip, sic.src_port, sic.dest_port);
978        } else {
979                DEBUG_TRACE("POST_ROUTE: checking new connection: %d src_ip: %pI6 dst_ip: %pI6, src_port: %d, dst_port: %d\n",
980                            sic.protocol, &sic.src_ip, &sic.dest_ip, sic.src_port, sic.dest_port);
981        }
982
983        /*
984         * If we already have this connection in our list, skip it
985         * XXX: this may need to be optimized
986         */
987        spin_lock_bh(&sfe_connections_lock);
988
989        conn = fast_classifier_find_conn(&sic.src_ip, &sic.dest_ip, sic.src_port, sic.dest_port, sic.protocol, is_v4);
990        if (conn) {
991                conn->hits++;
992
993                if (!conn->offloaded) {
994                        if (conn->offload_permit || conn->hits >= offload_at_pkts) {
995                                DEBUG_TRACE("OFFLOADING CONNECTION, TOO MANY HITS\n");
996
997                                if (fast_classifier_update_protocol(conn->sic, conn->ct) == 0) {
998                                        spin_unlock_bh(&sfe_connections_lock);
999                                        fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_UPDATE_PROTOCOL_FAIL);
1000                                        DEBUG_TRACE("UNKNOWN PROTOCOL OR CONNECTION CLOSING, SKIPPING\n");
1001                                        return NF_ACCEPT;
1002                                }
1003
1004                                DEBUG_TRACE("INFO: calling sfe rule creation!\n");
1005                                spin_unlock_bh(&sfe_connections_lock);
1006
1007                                ret = is_v4 ? sfe_ipv4_create_rule(conn->sic) : sfe_ipv6_create_rule(conn->sic);
1008                                if ((ret == 0) || (ret == -EADDRINUSE)) {
1009                                        struct fast_classifier_tuple fc_msg;
1010
1011                                        if (is_v4) {
1012                                                fc_msg.ethertype = AF_INET;
1013                                                fc_msg.src_saddr.in = *((struct in_addr *)&sic.src_ip);
1014                                                fc_msg.dst_saddr.in = *((struct in_addr *)&sic.dest_ip_xlate);
1015                                        }
1016#ifdef SFE_SUPPORT_IPV6
1017                                        else {
1018                                                fc_msg.ethertype = AF_INET6;
1019                                                fc_msg.src_saddr.in6 = *((struct in6_addr *)&sic.src_ip);
1020                                                fc_msg.dst_saddr.in6 = *((struct in6_addr *)&sic.dest_ip_xlate);
1021                                        }
1022#endif
1023                                        fc_msg.proto = sic.protocol;
1024                                        fc_msg.sport = sic.src_port;
1025                                        fc_msg.dport = sic.dest_port_xlate;
1026                                        memcpy(fc_msg.smac, conn->smac, ETH_ALEN);
1027                                        memcpy(fc_msg.dmac, conn->dmac, ETH_ALEN);
1028                                        fast_classifier_send_genl_msg(FAST_CLASSIFIER_C_OFFLOADED, &fc_msg);
1029                                        conn->offloaded = 1;
1030                                }
1031
1032                                return NF_ACCEPT;
1033                        }
1034                }
1035
1036                spin_unlock_bh(&sfe_connections_lock);
1037                if (conn->offloaded) {
1038                        is_v4 ? sfe_ipv4_update_rule(conn->sic) : sfe_ipv6_update_rule(conn->sic);
1039                }
1040
1041                DEBUG_TRACE("FOUND, SKIPPING\n");
1042                fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_WAIT_FOR_ACCELERATION);
1043                return NF_ACCEPT;
1044        }
1045
1046        spin_unlock_bh(&sfe_connections_lock);
1047
1048        /*
1049         * Get the net device and MAC addresses that correspond to the various source and
1050         * destination host addresses.
1051         */
1052        if (!fast_classifier_find_dev_and_mac_addr(&sic.src_ip, &src_dev, sic.src_mac, is_v4)) {
1053                fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_NO_SRC_DEV);
1054                return NF_ACCEPT;
1055        }
1056
1057        if (!fast_classifier_find_dev_and_mac_addr(&sic.src_ip_xlate, &dev, sic.src_mac_xlate, is_v4)) {
1058                fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_NO_SRC_XLATE_DEV);
1059                goto done1;
1060        }
1061
1062        dev_put(dev);
1063
1064        if (!fast_classifier_find_dev_and_mac_addr(&sic.dest_ip, &dev, sic.dest_mac, is_v4)) {
1065                fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_NO_DEST_DEV);
1066                goto done1;
1067        }
1068
1069        dev_put(dev);
1070
1071        if (!fast_classifier_find_dev_and_mac_addr(&sic.dest_ip_xlate, &dest_dev, sic.dest_mac_xlate, is_v4)) {
1072                fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_NO_DEST_XLATE_DEV);
1073                goto done1;
1074        }
1075
1076        /*
1077         * Our devices may actually be part of a bridge interface.  If that's
1078         * the case then find the bridge interface instead.
1079         */
1080        if (src_dev->priv_flags & IFF_BRIDGE_PORT) {
1081                src_br_dev = sfe_dev_get_master(src_dev);
1082                if (!src_br_dev) {
1083                        fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_NO_BRIDGE);
1084                        DEBUG_TRACE("no bridge found for: %s\n", src_dev->name);
1085                        goto done2;
1086                }
1087
1088                src_dev = src_br_dev;
1089        }
1090
1091        if (dest_dev->priv_flags & IFF_BRIDGE_PORT) {
1092                dest_br_dev = sfe_dev_get_master(dest_dev);
1093                if (!dest_br_dev) {
1094                        fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_NO_BRIDGE);
1095                        DEBUG_TRACE("no bridge found for: %s\n", dest_dev->name);
1096                        goto done3;
1097                }
1098
1099                dest_dev = dest_br_dev;
1100        }
1101
1102        sic.src_dev = src_dev;
1103        sic.dest_dev = dest_dev;
1104
1105        sic.src_mtu = src_dev->mtu;
1106        sic.dest_mtu = dest_dev->mtu;
1107
1108        if (skb->mark) {
1109                DEBUG_TRACE("SKB MARK NON ZERO %x\n", skb->mark);
1110        }
1111        sic.mark = skb->mark;
1112
1113        conn = kmalloc(sizeof(*conn), GFP_ATOMIC);
1114        if (!conn) {
1115                printk(KERN_CRIT "ERROR: no memory for sfe\n");
1116                goto done3;
1117        }
1118        conn->hits = 0;
1119        conn->offload_permit = 0;
1120        conn->offloaded = 0;
1121        conn->is_v4 = is_v4;
1122        DEBUG_TRACE("Source MAC=%pM\n", sic.src_mac);
1123        memcpy(conn->smac, sic.src_mac, ETH_ALEN);
1124        memcpy(conn->dmac, sic.dest_mac_xlate, ETH_ALEN);
1125
1126        p_sic = kmalloc(sizeof(*p_sic), GFP_ATOMIC);
1127        if (!p_sic) {
1128                printk(KERN_CRIT "ERROR: no memory for sfe\n");
1129                kfree(conn);
1130                goto done3;
1131        }
1132
1133        memcpy(p_sic, &sic, sizeof(sic));
1134        conn->sic = p_sic;
1135        conn->ct = ct;
1136
1137        if (!fast_classifier_add_conn(conn)) {
1138                kfree(conn->sic);
1139                kfree(conn);
1140        }
1141
1142        /*
1143         * If we had bridge ports then release them too.
1144         */
1145        if (dest_br_dev) {
1146                dev_put(dest_br_dev);
1147        }
1148
1149done3:
1150        if (src_br_dev) {
1151                dev_put(src_br_dev);
1152        }
1153
1154done2:
1155        dev_put(dest_dev);
1156
1157done1:
1158        dev_put(src_dev);
1159
1160        return NF_ACCEPT;
1161}
1162
1163/*
1164 * fast_classifier_ipv4_post_routing_hook()
1165 *      Called for packets about to leave the box - either locally generated or forwarded from another interface
1166 */
1167fast_classifier_ipv4_post_routing_hook(hooknum, ops, skb, in_unused, out, okfn)
1168{
1169        return fast_classifier_post_routing(skb, true);
1170}
1171
1172#ifdef SFE_SUPPORT_IPV6
1173
1174/*
1175 * fast_classifier_ipv6_post_routing_hook()
1176 *      Called for packets about to leave the box - either locally generated or forwarded from another interface
1177 */
1178fast_classifier_ipv6_post_routing_hook(hooknum, ops, skb, in_unused, out, okfn)
1179{
1180        return fast_classifier_post_routing(skb, false);
1181}
1182#endif
1183/*
1184 * fast_classifier_update_mark()
1185 *      updates the mark for a fast-classifier connection
1186 */
1187static void fast_classifier_update_mark(struct sfe_connection_mark *mark, bool is_v4)
1188{
1189        struct sfe_connection *conn;
1190
1191        spin_lock_bh(&sfe_connections_lock);
1192
1193        conn = fast_classifier_find_conn(&mark->src_ip, &mark->dest_ip,
1194                                         mark->src_port, mark->dest_port,
1195                                         mark->protocol, is_v4);
1196        if (conn) {
1197                conn->sic->mark = mark->mark;
1198        }
1199
1200        spin_unlock_bh(&sfe_connections_lock);
1201}
1202
1203#ifdef CONFIG_NF_CONNTRACK_EVENTS
1204/*
1205 * fast_classifier_conntrack_event()
1206 *      Callback event invoked when a conntrack connection's state changes.
1207 */
1208static int fast_classifier_conntrack_event(struct notifier_block *this,
1209                                           unsigned long events, void *ptr)
1210{
1211        struct nf_ct_event *item = ptr;
1212        struct sfe_connection_destroy sid;
1213        struct nf_conn *ct = item->ct;
1214        struct nf_conntrack_tuple orig_tuple;
1215        struct sfe_connection *conn;
1216        struct fast_classifier_tuple fc_msg;
1217        int offloaded = 0;
1218        bool is_v4;
1219
1220        /*
1221         * If we don't have a conntrack entry then we're done.
1222         */
1223        if (unlikely(!ct)) {
1224                DEBUG_WARN("no ct in conntrack event callback\n");
1225                return NOTIFY_DONE;
1226        }
1227
1228        /*
1229         * If this is an untracked connection then we can't have any state either.
1230         */
1231        if (unlikely(nf_ct_is_untracked(ct))) {
1232                DEBUG_TRACE("ignoring untracked conn\n");
1233                return NOTIFY_DONE;
1234        }
1235
1236        orig_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
1237        sid.protocol = (s32)orig_tuple.dst.protonum;
1238
1239        /*
1240         * Extract information from the conntrack connection.  We're only interested
1241         * in nominal connection information (i.e. we're ignoring any NAT information).
1242         */
1243        if (likely(nf_ct_l3num(ct) == AF_INET)) {
1244                sid.src_ip.ip = (__be32)orig_tuple.src.u3.ip;
1245                sid.dest_ip.ip = (__be32)orig_tuple.dst.u3.ip;
1246                is_v4 = true;
1247        }
1248#ifdef SFE_SUPPORT_IPV6
1249        else if (likely(nf_ct_l3num(ct) == AF_INET6)) {
1250                sid.src_ip.ip6[0] = *((struct sfe_ipv6_addr *)&orig_tuple.src.u3.in6);
1251                sid.dest_ip.ip6[0] = *((struct sfe_ipv6_addr *)&orig_tuple.dst.u3.in6);
1252                is_v4 = false;
1253        }
1254#endif
1255        else {
1256                DEBUG_TRACE("ignoring non-IPv4 and non-IPv6 connection\n");
1257                return NOTIFY_DONE;
1258        }
1259
1260        switch (sid.protocol) {
1261        case IPPROTO_TCP:
1262                sid.src_port = orig_tuple.src.u.tcp.port;
1263                sid.dest_port = orig_tuple.dst.u.tcp.port;
1264                break;
1265
1266        case IPPROTO_UDP:
1267                sid.src_port = orig_tuple.src.u.udp.port;
1268                sid.dest_port = orig_tuple.dst.u.udp.port;
1269                break;
1270
1271        default:
1272                DEBUG_TRACE("unhandled protocol: %d\n", sid.protocol);
1273                return NOTIFY_DONE;
1274        }
1275
1276        /*
1277         * Check for an updated mark
1278         */
1279        if ((events & (1 << IPCT_MARK)) && (ct->mark != 0)) {
1280                struct sfe_connection_mark mark;
1281
1282                mark.protocol = sid.protocol;
1283                mark.src_ip = sid.src_ip;
1284                mark.dest_ip = sid.dest_ip;
1285                mark.src_port = sid.src_port;
1286                mark.dest_port = sid.dest_port;
1287                mark.mark = ct->mark;
1288
1289                is_v4 ? sfe_ipv4_mark_rule(&mark) : sfe_ipv6_mark_rule(&mark);
1290                fast_classifier_update_mark(&mark, is_v4);
1291        }
1292
1293        /*
1294         * We're only interested in destroy events at this point
1295         */
1296        if (unlikely(!(events & (1 << IPCT_DESTROY)))) {
1297                DEBUG_TRACE("ignoring non-destroy event\n");
1298                return NOTIFY_DONE;
1299        }
1300
1301        if (is_v4) {
1302                DEBUG_TRACE("Try to clean up: proto: %d src_ip: %pI4 dst_ip: %pI4, src_port: %d, dst_port: %d\n",
1303                            sid.protocol, &sid.src_ip, &sid.dest_ip, sid.src_port, sid.dest_port);
1304        } else {
1305                DEBUG_TRACE("Try to clean up: proto: %d src_ip: %pI6 dst_ip: %pI6, src_port: %d, dst_port: %d\n",
1306                            sid.protocol, &sid.src_ip, &sid.dest_ip, sid.src_port, sid.dest_port);
1307        }
1308
1309        spin_lock_bh(&sfe_connections_lock);
1310
1311        conn = fast_classifier_find_conn(&sid.src_ip, &sid.dest_ip, sid.src_port, sid.dest_port, sid.protocol, is_v4);
1312        if (conn && conn->offloaded) {
1313                if (is_v4) {
1314                        fc_msg.ethertype = AF_INET;
1315                        fc_msg.src_saddr.in = *((struct in_addr *)&conn->sic->src_ip);
1316                        fc_msg.dst_saddr.in = *((struct in_addr *)&conn->sic->dest_ip_xlate);
1317                } else
1318#ifdef SFE_SUPPORT_IPV6
1319                {
1320                        fc_msg.ethertype = AF_INET6;
1321                        fc_msg.src_saddr.in6 = *((struct in6_addr *)&conn->sic->src_ip);
1322                        fc_msg.dst_saddr.in6 = *((struct in6_addr *)&conn->sic->dest_ip_xlate);
1323                }
1324#endif
1325                fc_msg.proto = conn->sic->protocol;
1326                fc_msg.sport = conn->sic->src_port;
1327                fc_msg.dport = conn->sic->dest_port_xlate;
1328                memcpy(fc_msg.smac, conn->smac, ETH_ALEN);
1329                memcpy(fc_msg.dmac, conn->dmac, ETH_ALEN);
1330                offloaded = 1;
1331        }
1332
1333        if (conn) {
1334                DEBUG_TRACE("Free connection\n");
1335
1336                hash_del(&conn->hl);
1337                sfe_connections_size--;
1338                kfree(conn->sic);
1339                kfree(conn);
1340        } else {
1341                fast_classifier_incr_exceptions(FAST_CL_EXCEPTION_CT_DESTROY_MISS);
1342        }
1343
1344        spin_unlock_bh(&sfe_connections_lock);
1345
1346        is_v4 ? sfe_ipv4_destroy_rule(&sid) : sfe_ipv6_destroy_rule(&sid);
1347
1348        if (offloaded) {
1349                fast_classifier_send_genl_msg(FAST_CLASSIFIER_C_DONE, &fc_msg);
1350        }
1351
1352        return NOTIFY_DONE;
1353}
1354
1355/*
1356 * Netfilter conntrack event system to monitor connection tracking changes
1357 */
1358static struct notifier_block fast_classifier_conntrack_notifier = {
1359        .notifier_call = fast_classifier_conntrack_event,
1360};
1361#endif
1362
1363/*
1364 * Structure to establish a hook into the post routing netfilter point - this
1365 * will pick up local outbound and packets going from one interface to another.
1366 *
1367 * Note: see include/linux/netfilter_ipv4.h for info related to priority levels.
1368 * We want to examine packets after NAT translation and any ALG processing.
1369 */
1370static struct nf_hook_ops fast_classifier_ops_post_routing[] __read_mostly = {
1371        SFE_IPV4_NF_POST_ROUTING_HOOK(__fast_classifier_ipv4_post_routing_hook),
1372#ifdef SFE_SUPPORT_IPV6
1373        SFE_IPV6_NF_POST_ROUTING_HOOK(__fast_classifier_ipv6_post_routing_hook),
1374#endif
1375};
1376
1377/*
1378 * fast_classifier_sync_rule()
1379 *      Synchronize a connection's state.
1380 */
1381static void fast_classifier_sync_rule(struct sfe_connection_sync *sis)
1382{
1383        struct nf_conntrack_tuple_hash *h;
1384        struct nf_conntrack_tuple tuple;
1385        struct nf_conn *ct;
1386        SFE_NF_CONN_ACCT(acct);
1387
1388        /*
1389         * Create a tuple so as to be able to look up a connection
1390         */
1391        memset(&tuple, 0, sizeof(tuple));
1392        tuple.src.u.all = (__be16)sis->src_port;
1393        tuple.dst.dir = IP_CT_DIR_ORIGINAL;
1394        tuple.dst.protonum = (u8)sis->protocol;
1395        tuple.dst.u.all = (__be16)sis->dest_port;
1396
1397#ifdef SFE_SUPPORT_IPV6
1398        if (sis->is_v6) {
1399                tuple.src.u3.in6 = *((struct in6_addr *)sis->src_ip.ip6);
1400                tuple.dst.u3.in6 = *((struct in6_addr *)sis->dest_ip.ip6);
1401                tuple.src.l3num = AF_INET6;
1402
1403                DEBUG_TRACE("update connection - p: %d, s: %pI6:%u, d: %pI6:%u\n",
1404                            (int)tuple.dst.protonum,
1405                            &tuple.src.u3.in6, (unsigned int)ntohs(tuple.src.u.all),
1406                            &tuple.dst.u3.in6, (unsigned int)ntohs(tuple.dst.u.all));
1407        } else
1408#endif
1409        {
1410                tuple.src.u3.ip = sis->src_ip.ip;
1411                tuple.dst.u3.ip = sis->dest_ip.ip;
1412                tuple.src.l3num = AF_INET;
1413
1414                DEBUG_TRACE("update connection - p: %d, s: %pI4:%u, d: %pI4:%u\n",
1415                            (int)tuple.dst.protonum,
1416                            &tuple.src.u3.ip, (unsigned int)ntohs(tuple.src.u.all),
1417                            &tuple.dst.u3.ip, (unsigned int)ntohs(tuple.dst.u.all));
1418        }
1419
1420        /*
1421         * Update packet count for ingress on bridge device
1422         */
1423        if (skip_to_bridge_ingress) {
1424                struct rtnl_link_stats64 nlstats;
1425                nlstats.tx_packets = 0;
1426                nlstats.tx_bytes = 0;
1427
1428                if (sis->src_dev && IFF_EBRIDGE &&
1429                    (sis->src_new_packet_count || sis->src_new_byte_count)) {
1430                        nlstats.rx_packets = sis->src_new_packet_count;
1431                        nlstats.rx_bytes = sis->src_new_byte_count;
1432                        spin_lock_bh(&sfe_connections_lock);
1433                        br_dev_update_stats(sis->src_dev, &nlstats);
1434                        spin_unlock_bh(&sfe_connections_lock);
1435                }
1436                if (sis->dest_dev && IFF_EBRIDGE &&
1437                    (sis->dest_new_packet_count || sis->dest_new_byte_count)) {
1438                        nlstats.rx_packets = sis->dest_new_packet_count;
1439                        nlstats.rx_bytes = sis->dest_new_byte_count;
1440                        spin_lock_bh(&sfe_connections_lock);
1441                        br_dev_update_stats(sis->dest_dev, &nlstats);
1442                        spin_unlock_bh(&sfe_connections_lock);
1443                }
1444        }
1445
1446        /*
1447         * Look up conntrack connection
1448         */
1449        h = nf_conntrack_find_get(&init_net, SFE_NF_CT_DEFAULT_ZONE, &tuple);
1450        if (unlikely(!h)) {
1451                DEBUG_TRACE("no connection found\n");
1452                return;
1453        }
1454
1455        ct = nf_ct_tuplehash_to_ctrack(h);
1456        NF_CT_ASSERT(ct->timeout.data == (unsigned long)ct);
1457
1458        /*
1459         * Only update if this is not a fixed timeout
1460         */
1461        if (!test_bit(IPS_FIXED_TIMEOUT_BIT, &ct->status)) {
1462                spin_lock_bh(&ct->lock);
1463                ct->timeout.expires += sis->delta_jiffies;
1464                spin_unlock_bh(&ct->lock);
1465        }
1466
1467        acct = nf_conn_acct_find(ct);
1468        if (acct) {
1469                spin_lock_bh(&ct->lock);
1470                atomic64_add(sis->src_new_packet_count, &SFE_ACCT_COUNTER(acct)[IP_CT_DIR_ORIGINAL].packets);
1471                atomic64_add(sis->src_new_byte_count, &SFE_ACCT_COUNTER(acct)[IP_CT_DIR_ORIGINAL].bytes);
1472                atomic64_add(sis->dest_new_packet_count, &SFE_ACCT_COUNTER(acct)[IP_CT_DIR_REPLY].packets);
1473                atomic64_add(sis->dest_new_byte_count, &SFE_ACCT_COUNTER(acct)[IP_CT_DIR_REPLY].bytes);
1474                spin_unlock_bh(&ct->lock);
1475        }
1476
1477        switch (sis->protocol) {
1478        case IPPROTO_TCP:
1479                spin_lock_bh(&ct->lock);
1480                if (ct->proto.tcp.seen[0].td_maxwin < sis->src_td_max_window) {
1481                        ct->proto.tcp.seen[0].td_maxwin = sis->src_td_max_window;
1482                }
1483                if ((s32)(ct->proto.tcp.seen[0].td_end - sis->src_td_end) < 0) {
1484                        ct->proto.tcp.seen[0].td_end = sis->src_td_end;
1485                }
1486                if ((s32)(ct->proto.tcp.seen[0].td_maxend - sis->src_td_max_end) < 0) {
1487                        ct->proto.tcp.seen[0].td_maxend = sis->src_td_max_end;
1488                }
1489                if (ct->proto.tcp.seen[1].td_maxwin < sis->dest_td_max_window) {
1490                        ct->proto.tcp.seen[1].td_maxwin = sis->dest_td_max_window;
1491                }
1492                if ((s32)(ct->proto.tcp.seen[1].td_end - sis->dest_td_end) < 0) {
1493                        ct->proto.tcp.seen[1].td_end = sis->dest_td_end;
1494                }
1495                if ((s32)(ct->proto.tcp.seen[1].td_maxend - sis->dest_td_max_end) < 0) {
1496                        ct->proto.tcp.seen[1].td_maxend = sis->dest_td_max_end;
1497                }
1498                spin_unlock_bh(&ct->lock);
1499                break;
1500        }
1501
1502        /*
1503         * Release connection
1504         */
1505        nf_ct_put(ct);
1506}
1507
1508/*
1509 * fast_classifier_device_event()
1510 */
1511static int fast_classifier_device_event(struct notifier_block *this, unsigned long event, void *ptr)
1512{
1513        struct net_device *dev = SFE_DEV_EVENT_PTR(ptr);
1514
1515        if (dev && (event == NETDEV_DOWN)) {
1516                sfe_ipv4_destroy_all_rules_for_dev(dev);
1517#ifdef SFE_SUPPORT_IPV6
1518                sfe_ipv6_destroy_all_rules_for_dev(dev);
1519#endif
1520        }
1521
1522        return NOTIFY_DONE;
1523}
1524
1525/*
1526 * fast_classifier_inet_event()
1527 */
1528static int fast_classifier_inet_event(struct notifier_block *this, unsigned long event, void *ptr)
1529{
1530        struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev;
1531
1532        if (dev && (event == NETDEV_DOWN)) {
1533                sfe_ipv4_destroy_all_rules_for_dev(dev);
1534        }
1535
1536        return NOTIFY_DONE;
1537}
1538
1539#ifdef SFE_SUPPORT_IPV6
1540/*
1541 * fast_classifier_inet6_event()
1542 */
1543static int fast_classifier_inet6_event(struct notifier_block *this, unsigned long event, void *ptr)
1544{
1545        struct net_device *dev = ((struct inet6_ifaddr *)ptr)->idev->dev;
1546
1547        if (dev && (event == NETDEV_DOWN)) {
1548                sfe_ipv6_destroy_all_rules_for_dev(dev);
1549        }
1550
1551        return NOTIFY_DONE;
1552}
1553#endif
1554/*
1555 * fast_classifier_get_offload_at_pkts()
1556 */
1557static ssize_t fast_classifier_get_offload_at_pkts(struct device *dev,
1558                                                   struct device_attribute *attr,
1559                                                   char *buf)
1560{
1561        return snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", offload_at_pkts);
1562}
1563
1564/*
1565 * fast_classifier_set_offload_at_pkts()
1566 */
1567static ssize_t fast_classifier_set_offload_at_pkts(struct device *dev,
1568                                                   struct device_attribute *attr,
1569                                                   const char *buf, size_t size)
1570{
1571        long new;
1572        int ret;
1573
1574        ret = kstrtol(buf, 0, &new);
1575        if (ret == -EINVAL || ((int)new != new))
1576                return -EINVAL;
1577
1578        offload_at_pkts = new;
1579
1580        return size;
1581}
1582
1583/*
1584 * fast_classifier_get_debug_info()
1585 */
1586static ssize_t fast_classifier_get_debug_info(struct device *dev,
1587                                      struct device_attribute *attr,
1588                                      char *buf)
1589{
1590        size_t len = 0;
1591        struct sfe_connection *conn;
1592        u32 i;
1593#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
1594        struct hlist_node *node;
1595#endif
1596
1597        spin_lock_bh(&sfe_connections_lock);
1598        len += scnprintf(buf, PAGE_SIZE - len, "size=%d offload=%d offload_no_match=%d"
1599                        " offloaded=%d done=%d offloaded_fail=%d done_fail=%d\n",
1600                        sfe_connections_size,
1601                        atomic_read(&offload_msgs),
1602                        atomic_read(&offload_no_match_msgs),
1603                        atomic_read(&offloaded_msgs),
1604                        atomic_read(&done_msgs),
1605                        atomic_read(&offloaded_fail_msgs),
1606                        atomic_read(&done_fail_msgs));
1607        sfe_hash_for_each(fc_conn_ht, i, node, conn, hl) {
1608                len += scnprintf(buf + len, PAGE_SIZE - len,
1609                                (conn->is_v4 ? "o=%d, p=%d [%pM]:%pI4:%u %pI4:%u:[%pM] m=%08x h=%d\n" : "o=%d, p=%d [%pM]:%pI6:%u %pI6:%u:[%pM] m=%08x h=%d\n"),
1610                                conn->offloaded,
1611                                conn->sic->protocol,
1612                                conn->sic->src_mac,
1613                                &conn->sic->src_ip,
1614                                conn->sic->src_port,
1615                                &conn->sic->dest_ip,
1616                                conn->sic->dest_port,
1617                                conn->sic->dest_mac_xlate,
1618                                conn->sic->mark,
1619                                conn->hits);
1620        }
1621        spin_unlock_bh(&sfe_connections_lock);
1622
1623        return len;
1624}
1625
1626/*
1627 * fast_classifier_get_skip_bridge_ingress()
1628 */
1629static ssize_t fast_classifier_get_skip_bridge_ingress(struct device *dev,
1630                                                       struct device_attribute *attr,
1631                                                       char *buf)
1632{
1633        return snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", skip_to_bridge_ingress);
1634}
1635
1636/*
1637 * fast_classifier_set_skip_bridge_ingress()
1638 */
1639static ssize_t fast_classifier_set_skip_bridge_ingress(struct device *dev,
1640                                                       struct device_attribute *attr,
1641                                                       const char *buf, size_t size)
1642{
1643        long new;
1644        int ret;
1645
1646        ret = kstrtol(buf, 0, &new);
1647        if (ret == -EINVAL || ((int)new != new))
1648                return -EINVAL;
1649
1650        skip_to_bridge_ingress = new ? 1 : 0;
1651
1652        return size;
1653}
1654
1655/*
1656 * fast_classifier_get_exceptions
1657 *      dump exception counters
1658 */
1659static ssize_t fast_classifier_get_exceptions(struct device *dev,
1660                                     struct device_attribute *attr,
1661                                     char *buf)
1662{
1663        int idx, len;
1664        struct fast_classifier *sc = &__fsc;
1665
1666        spin_lock_bh(&sc->lock);
1667        for (len = 0, idx = 0; idx < FAST_CL_EXCEPTION_MAX; idx++) {
1668                if (sc->exceptions[idx]) {
1669                        len += snprintf(buf + len, (ssize_t)(PAGE_SIZE - len), "%s = %d\n", fast_classifier_exception_events_string[idx], sc->exceptions[idx]);
1670                }
1671        }
1672        spin_unlock_bh(&sc->lock);
1673
1674        return len;
1675}
1676
1677/*
1678 * sysfs attributes.
1679 */
1680static const struct device_attribute fast_classifier_offload_at_pkts_attr =
1681        __ATTR(offload_at_pkts, S_IWUSR | S_IRUGO, fast_classifier_get_offload_at_pkts, fast_classifier_set_offload_at_pkts);
1682static const struct device_attribute fast_classifier_debug_info_attr =
1683        __ATTR(debug_info, S_IRUGO, fast_classifier_get_debug_info, NULL);
1684static const struct device_attribute fast_classifier_skip_bridge_ingress =
1685        __ATTR(skip_to_bridge_ingress, S_IWUSR | S_IRUGO, fast_classifier_get_skip_bridge_ingress, fast_classifier_set_skip_bridge_ingress);
1686static const struct device_attribute fast_classifier_exceptions_attr =
1687        __ATTR(exceptions, S_IRUGO, fast_classifier_get_exceptions, NULL);
1688
1689/*
1690 * fast_classifier_init()
1691 */
1692static int fast_classifier_init(void)
1693{
1694        struct fast_classifier *sc = &__fsc;
1695        int result = -1;
1696
1697        printk(KERN_ALERT "fast-classifier: starting up\n");
1698        DEBUG_INFO("SFE CM init\n");
1699
1700        hash_init(fc_conn_ht);
1701
1702        /*
1703         * Create sys/fast_classifier
1704         */
1705        sc->sys_fast_classifier = kobject_create_and_add("fast_classifier", NULL);
1706        if (!sc->sys_fast_classifier) {
1707                DEBUG_ERROR("failed to register fast_classifier\n");
1708                goto exit1;
1709        }
1710
1711        result = sysfs_create_file(sc->sys_fast_classifier, &fast_classifier_offload_at_pkts_attr.attr);
1712        if (result) {
1713                DEBUG_ERROR("failed to register offload at pkgs: %d\n", result);
1714                goto exit2;
1715        }
1716
1717        result = sysfs_create_file(sc->sys_fast_classifier, &fast_classifier_debug_info_attr.attr);
1718        if (result) {
1719                DEBUG_ERROR("failed to register debug dev: %d\n", result);
1720                sysfs_remove_file(sc->sys_fast_classifier, &fast_classifier_offload_at_pkts_attr.attr);
1721                goto exit2;
1722        }
1723
1724        result = sysfs_create_file(sc->sys_fast_classifier, &fast_classifier_skip_bridge_ingress.attr);
1725        if (result) {
1726                DEBUG_ERROR("failed to register skip bridge on ingress: %d\n", result);
1727                sysfs_remove_file(sc->sys_fast_classifier, &fast_classifier_offload_at_pkts_attr.attr);
1728                sysfs_remove_file(sc->sys_fast_classifier, &fast_classifier_debug_info_attr.attr);
1729                goto exit2;
1730        }
1731
1732        result = sysfs_create_file(sc->sys_fast_classifier, &fast_classifier_exceptions_attr.attr);
1733        if (result) {
1734                DEBUG_ERROR("failed to register exceptions file: %d\n", result);
1735                sysfs_remove_file(sc->sys_fast_classifier, &fast_classifier_offload_at_pkts_attr.attr);
1736                sysfs_remove_file(sc->sys_fast_classifier, &fast_classifier_debug_info_attr.attr);
1737                sysfs_remove_file(sc->sys_fast_classifier, &fast_classifier_skip_bridge_ingress.attr);
1738                goto exit2;
1739        }
1740
1741        sc->dev_notifier.notifier_call = fast_classifier_device_event;
1742        sc->dev_notifier.priority = 1;
1743        register_netdevice_notifier(&sc->dev_notifier);
1744
1745        sc->inet_notifier.notifier_call = fast_classifier_inet_event;
1746        sc->inet_notifier.priority = 1;
1747        register_inetaddr_notifier(&sc->inet_notifier);
1748
1749#ifdef SFE_SUPPORT_IPV6
1750        sc->inet6_notifier.notifier_call = fast_classifier_inet6_event;
1751        sc->inet6_notifier.priority = 1;
1752        if (register_inet6addr_notifier)
1753                register_inet6addr_notifier(&sc->inet6_notifier);
1754#endif
1755        /*
1756         * Register our netfilter hooks.
1757         */
1758        result = nf_register_hooks(fast_classifier_ops_post_routing, ARRAY_SIZE(fast_classifier_ops_post_routing));
1759        if (result < 0) {
1760                DEBUG_ERROR("can't register nf post routing hook: %d\n", result);
1761                goto exit3;
1762        }
1763
1764#ifdef CONFIG_NF_CONNTRACK_EVENTS
1765        /*
1766         * Register a notifier hook to get fast notifications of expired connections.
1767         */
1768        result = nf_conntrack_register_notifier(&init_net, &fast_classifier_conntrack_notifier);
1769        if (result < 0) {
1770                DEBUG_ERROR("can't register nf notifier hook: %d\n", result);
1771                goto exit4;
1772        }
1773#endif
1774
1775#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0))
1776        result = genl_register_family_with_ops_groups(&fast_classifier_gnl_family,
1777                                                      fast_classifier_gnl_ops,
1778                                                      fast_classifier_genl_mcgrp);
1779        if (result) {
1780                DEBUG_ERROR("failed to register genl ops: %d\n", result);
1781                goto exit5;
1782        }
1783#else
1784        result = genl_register_family(&fast_classifier_gnl_family);
1785        if (result) {
1786                printk(KERN_CRIT "unable to register genl family\n");
1787                goto exit5;
1788        }
1789
1790        result = genl_register_ops(&fast_classifier_gnl_family, fast_classifier_gnl_ops);
1791        if (result) {
1792                printk(KERN_CRIT "unable to register ops\n");
1793                goto exit6;
1794        }
1795
1796        result = genl_register_mc_group(&fast_classifier_gnl_family,
1797                                        fast_classifier_genl_mcgrp);
1798        if (result) {
1799                printk(KERN_CRIT "unable to register multicast group\n");
1800                goto exit6;
1801        }
1802#endif
1803
1804        printk(KERN_ALERT "fast-classifier: registered\n");
1805
1806        spin_lock_init(&sc->lock);
1807
1808        /*
1809         * Hook the receive path in the network stack.
1810         */
1811        BUG_ON(fast_nat_recv);
1812        RCU_INIT_POINTER(fast_nat_recv, fast_classifier_recv);
1813
1814        /*
1815         * Hook the shortcut sync callback.
1816         */
1817        sfe_ipv4_register_sync_rule_callback(fast_classifier_sync_rule);
1818#ifdef SFE_SUPPORT_IPV6
1819        sfe_ipv6_register_sync_rule_callback(fast_classifier_sync_rule);
1820#endif
1821        return 0;
1822
1823#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
1824exit6:
1825        genl_unregister_family(&fast_classifier_gnl_family);
1826#endif
1827
1828exit5:
1829#ifdef CONFIG_NF_CONNTRACK_EVENTS
1830        nf_conntrack_unregister_notifier(&init_net, &fast_classifier_conntrack_notifier);
1831
1832exit4:
1833#endif
1834        nf_unregister_hooks(fast_classifier_ops_post_routing, ARRAY_SIZE(fast_classifier_ops_post_routing));
1835
1836exit3:
1837        unregister_inetaddr_notifier(&sc->inet_notifier);
1838#ifdef SFE_SUPPORT_IPV6
1839        if (unregister_inet6addr_notifier)
1840                unregister_inet6addr_notifier(&sc->inet6_notifier);
1841#endif
1842        unregister_netdevice_notifier(&sc->dev_notifier);
1843        sysfs_remove_file(sc->sys_fast_classifier, &fast_classifier_offload_at_pkts_attr.attr);
1844        sysfs_remove_file(sc->sys_fast_classifier, &fast_classifier_debug_info_attr.attr);
1845        sysfs_remove_file(sc->sys_fast_classifier, &fast_classifier_skip_bridge_ingress.attr);
1846        sysfs_remove_file(sc->sys_fast_classifier, &fast_classifier_exceptions_attr.attr);
1847
1848exit2:
1849        kobject_put(sc->sys_fast_classifier);
1850
1851exit1:
1852        return result;
1853}
1854
1855/*
1856 * fast_classifier_exit()
1857 */
1858static void fast_classifier_exit(void)
1859{
1860        struct fast_classifier *sc = &__fsc;
1861        int result = -1;
1862
1863        DEBUG_INFO("SFE CM exit\n");
1864        printk(KERN_ALERT "fast-classifier: shutting down\n");
1865
1866        /*
1867         * Unregister our sync callback.
1868         */
1869        sfe_ipv4_register_sync_rule_callback(NULL);
1870#ifdef SFE_SUPPORT_IPV6
1871        sfe_ipv6_register_sync_rule_callback(NULL);
1872#endif
1873
1874        /*
1875         * Unregister our receive callback.
1876         */
1877        RCU_INIT_POINTER(fast_nat_recv, NULL);
1878
1879        /*
1880         * Wait for all callbacks to complete.
1881         */
1882        rcu_barrier();
1883
1884        /*
1885         * Destroy all connections.
1886         */
1887        sfe_ipv4_destroy_all_rules_for_dev(NULL);
1888#ifdef SFE_SUPPORT_IPV6
1889        sfe_ipv6_destroy_all_rules_for_dev(NULL);
1890#endif
1891
1892#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
1893        result = genl_unregister_ops(&fast_classifier_gnl_family, fast_classifier_gnl_ops);
1894        if (result != 0) {
1895                printk(KERN_CRIT "Unable to unreigster genl_ops\n");
1896        }
1897#endif
1898
1899        result = genl_unregister_family(&fast_classifier_gnl_family);
1900        if (result != 0) {
1901                printk(KERN_CRIT "Unable to unreigster genl_family\n");
1902        }
1903
1904#ifdef CONFIG_NF_CONNTRACK_EVENTS
1905        nf_conntrack_unregister_notifier(&init_net, &fast_classifier_conntrack_notifier);
1906
1907#endif
1908        nf_unregister_hooks(fast_classifier_ops_post_routing, ARRAY_SIZE(fast_classifier_ops_post_routing));
1909
1910#ifdef SFE_SUPPORT_IPV6
1911        if (unregister_inet6addr_notifier)
1912                unregister_inet6addr_notifier(&sc->inet6_notifier);
1913#endif
1914        unregister_inetaddr_notifier(&sc->inet_notifier);
1915        unregister_netdevice_notifier(&sc->dev_notifier);
1916
1917        kobject_put(sc->sys_fast_classifier);
1918}
Note: See TracBrowser for help on using the repository browser.