source: src/linux/universal/linux-3.10/net/shortcut-fe/fast-classifier.c @ 32776

Last change on this file since 32776 was 32776, checked in by brainslayer, 4 weeks ago

missed one

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