blob: 4db7c71556d175a930dc218fdb70e7d9ea6372cd [file] [log] [blame]
Matthew McClintock6f29aa12013-11-06 15:49:01 -06001/*
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06002 * fast-classifier.c
3 * Shortcut forwarding engine connection manager.
4 * fast-classifier style
5 *
Matthew McClintocka3221942014-01-16 11:44:26 -06006 * Copyright (c) 2013 Qualcomm Atheros, Inc.
7 *
8 * All Rights Reserved.
9 * Qualcomm Atheros Confidential and Proprietary.
Matthew McClintock6f29aa12013-11-06 15:49:01 -060010 */
Matthew McClintock6f29aa12013-11-06 15:49:01 -060011#include <linux/module.h>
Matthew McClintocke1bcfe42013-11-22 15:33:09 -060012#include <linux/sysfs.h>
13#include <linux/skbuff.h>
14#include <net/route.h>
15#include <linux/inetdevice.h>
16#include <linux/netfilter_bridge.h>
17#include <net/netfilter/nf_conntrack_acct.h>
18#include <net/netfilter/nf_conntrack_helper.h>
19#include <net/netfilter/nf_conntrack_zones.h>
20#include <net/netfilter/nf_conntrack_core.h>
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -060021#include <net/genetlink.h>
Matthew McClintockea00adf2013-11-25 19:24:30 -060022#include <linux/list.h>
23#include <linux/spinlock.h>
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -060024
Matthew McClintocke1bcfe42013-11-22 15:33:09 -060025#include "../shortcut-fe/sfe.h"
26#include "../shortcut-fe/sfe_ipv4.h"
Matthew McClintock3abf38e2014-01-07 17:37:56 -060027#include "fast-classifier.h"
Matthew McClintocke1bcfe42013-11-22 15:33:09 -060028
29/*
30 * Per-module structure.
31 */
32struct fast_classifier {
33 spinlock_t lock; /* Lock for SMP correctness */
34
35 /*
36 * Control state.
37 */
38 struct kobject *sys_fast_classifier; /* sysfs linkage */
39
40 /*
41 * Callback notifiers.
42 */
43 struct notifier_block dev_notifier;
44 /* Device notifier */
45 struct notifier_block inet_notifier;
46 /* IP notifier */
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -060047};
Matthew McClintocke1bcfe42013-11-22 15:33:09 -060048
49struct fast_classifier __sc;
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -060050
51static struct nla_policy fast_classifier_genl_policy[FAST_CLASSIFIER_A_MAX + 1] = {
Matthew McClintocke4f9a672014-01-06 17:04:04 -060052 [FAST_CLASSIFIER_A_TUPLE] = { .type = NLA_UNSPEC,
53 .len = sizeof(struct fast_classifier_tuple)
54 },
55};
56
57static struct genl_multicast_group fast_classifier_genl_mcgrp = {
58 .name = FAST_CLASSIFIER_GENL_MCGRP,
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -060059};
60
61static struct genl_family fast_classifier_gnl_family = {
62 .id = GENL_ID_GENERATE,
Matthew McClintock28d75572014-01-03 11:54:08 -060063 .hdrsize = FAST_CLASSIFIER_GENL_HDRSIZE,
64 .name = FAST_CLASSIFIER_GENL_NAME,
65 .version = FAST_CLASSIFIER_GENL_VERSION,
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -060066 .maxattr = FAST_CLASSIFIER_A_MAX,
67};
68
Matthew McClintocke4f9a672014-01-06 17:04:04 -060069static int fast_classifier_offload_genl_msg(struct sk_buff *skb, struct genl_info *info);
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -060070
Matthew McClintocke4f9a672014-01-06 17:04:04 -060071static struct genl_ops fast_classifier_gnl_ops[] = {
72 {
73 .cmd = FAST_CLASSIFIER_C_OFFLOAD,
74 .flags = 0,
75 .policy = fast_classifier_genl_policy,
76 .doit = fast_classifier_offload_genl_msg,
77 .dumpit = NULL,
78 },
79 {
80 .cmd = FAST_CLASSIFIER_C_OFFLOADED,
81 .flags = 0,
82 .policy = fast_classifier_genl_policy,
83 .doit = NULL,
84 .dumpit = NULL,
85 },
86 {
87 .cmd = FAST_CLASSIFIER_C_DONE,
88 .flags = 0,
89 .policy = fast_classifier_genl_policy,
90 .doit = NULL,
91 .dumpit = NULL,
92 },
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -060093};
94
Matthew McClintocke1bcfe42013-11-22 15:33:09 -060095/*
96 * Expose the hook for the receive processing.
97 */
98extern int (*athrs_fast_nat_recv)(struct sk_buff *skb);
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -060099
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600100/*
101 * Expose what should be a static flag in the TCP connection tracker.
102 */
103extern int nf_ct_tcp_no_window_check;
104
105/*
106 * fast_classifier_recv()
107 * Handle packet receives.
108 *
109 * Returns 1 if the packet is forwarded or 0 if it isn't.
110 */
111int fast_classifier_recv(struct sk_buff *skb)
112{
113 struct net_device *dev;
114#if (SFE_HOOK_ABOVE_BRIDGE)
115 struct in_device *in_dev;
116#endif
117
118 /*
119 * We know that for the vast majority of packets we need the transport
120 * layer header so we may as well start to fetch it now!
121 */
122 prefetch(skb->data + 32);
123 barrier();
124
125 dev = skb->dev;
126
127#if (SFE_HOOK_ABOVE_BRIDGE)
128 /*
129 * Does our input device support IP processing?
130 */
131 in_dev = (struct in_device *)dev->ip_ptr;
132 if (unlikely(!in_dev)) {
133 DEBUG_TRACE("no IP processing for device: %s\n", dev->name);
134 return 0;
135 }
136
137 /*
138 * Does it have an IP address? If it doesn't then we can't do anything
139 * interesting here!
140 */
141 if (unlikely(!in_dev->ifa_list)) {
142 DEBUG_TRACE("no IP address for device: %s\n", dev->name);
143 return 0;
144 }
145#endif
146
147 /*
148 * We're only interested in IP packets.
Nicolas Costaac2979c2014-01-14 10:35:24 -0600149 */
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600150 if (likely(htons(ETH_P_IP) == skb->protocol)) {
151 return sfe_ipv4_recv(dev, skb);
152 }
153
Matthew McClintocka8ad7962014-01-16 16:49:30 -0600154 DEBUG_TRACE("not IP packet\n");
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -0600155 return 0;
156}
Matthew McClintock6f29aa12013-11-06 15:49:01 -0600157
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600158/*
159 * fast_classifier_find_mac_addr()
160 * Find the MAC address for a given IPv4 address.
161 *
162 * Returns true if we find the MAC address, otherwise false.
163 *
164 * We look up the rtable entry for the address and, from its neighbour
165 * structure, obtain the hardware address. This means this function also
166 * works if the neighbours are routers too.
167 */
168static bool fast_classifier_find_mac_addr(uint32_t addr, uint8_t *mac_addr)
Matthew McClintock6f29aa12013-11-06 15:49:01 -0600169{
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600170 struct neighbour *neigh;
171 struct rtable *rt;
172 struct dst_entry *dst;
173 struct net_device *dev;
174
175 /*
176 * Look up the rtable entry for the IP address then get the hardware
177 * address from its neighbour structure. This means this work when the
178 * neighbours are routers too.
179 */
180 rt = ip_route_output(&init_net, addr, 0, 0, 0);
181 if (unlikely(IS_ERR(rt))) {
182 return false;
183 }
184
185 dst = (struct dst_entry *)rt;
186
187 rcu_read_lock();
188 neigh = dst_get_neighbour_noref(dst);
189 if (unlikely(!neigh)) {
190 rcu_read_unlock();
191 dst_release(dst);
Nicolas Costaac2979c2014-01-14 10:35:24 -0600192 return false;
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600193 }
194
195 if (unlikely(!(neigh->nud_state & NUD_VALID))) {
196 rcu_read_unlock();
197 dst_release(dst);
198 return false;
199 }
200
201 dev = neigh->dev;
202 if (!dev) {
203 rcu_read_unlock();
204 dst_release(dst);
205 return false;
206 }
207
208 memcpy(mac_addr, neigh->ha, (size_t)dev->addr_len);
209 rcu_read_unlock();
210
211 dst_release(dst);
212
213 /*
214 * We're only interested in unicast MAC addresses - if it's not a unicast
215 * address then our IP address mustn't be unicast either.
216 */
217 if (is_multicast_ether_addr(mac_addr)) {
218 DEBUG_TRACE("MAC is non-unicast - ignoring\n");
219 return false;
220 }
221
222 return true;
223}
224
Matthew McClintockea00adf2013-11-25 19:24:30 -0600225static DEFINE_SPINLOCK(sfe_connections_lock);
226
227struct sfe_connection {
228 struct list_head list;
229 struct sfe_ipv4_create *sic;
230 struct nf_conn *ct;
Matthew McClintockc5739382013-12-02 14:17:46 -0600231 int hits;
Matthew McClintock55c86982013-12-02 14:24:24 -0600232 int offloaded;
Matthew McClintockd180a7d2014-01-17 11:21:35 -0600233 unsigned char smac[ETH_ALEN];
234 unsigned char dmac[ETH_ALEN];
Matthew McClintockea00adf2013-11-25 19:24:30 -0600235};
236
237static LIST_HEAD(sfe_connections);
238
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600239/*
Matthew McClintockc5739382013-12-02 14:17:46 -0600240 * fast_classifier_update_protocol()
241 * Update sfe_ipv4_create struct with new protocol information before we offload
242 */
243static int fast_classifier_update_protocol(struct sfe_ipv4_create *p_sic, struct nf_conn *ct)
244{
245 switch (p_sic->protocol) {
246 case IPPROTO_TCP:
247 p_sic->src_td_window_scale = ct->proto.tcp.seen[0].td_scale;
248 p_sic->src_td_max_window = ct->proto.tcp.seen[0].td_maxwin;
249 p_sic->src_td_end = ct->proto.tcp.seen[0].td_end;
250 p_sic->src_td_max_end = ct->proto.tcp.seen[0].td_maxend;
251 p_sic->dest_td_window_scale = ct->proto.tcp.seen[1].td_scale;
252 p_sic->dest_td_max_window = ct->proto.tcp.seen[1].td_maxwin;
253 p_sic->dest_td_end = ct->proto.tcp.seen[1].td_end;
254 p_sic->dest_td_max_end = ct->proto.tcp.seen[1].td_maxend;
255 if (nf_ct_tcp_no_window_check
256 || (ct->proto.tcp.seen[0].flags & IP_CT_TCP_FLAG_BE_LIBERAL)
257 || (ct->proto.tcp.seen[1].flags & IP_CT_TCP_FLAG_BE_LIBERAL)) {
258 p_sic->flags |= SFE_IPV4_CREATE_FLAG_NO_SEQ_CHECK;
259 }
260
261 /*
262 * If the connection is shutting down do not manage it.
263 * state can not be SYN_SENT, SYN_RECV because connection is assured
264 * Not managed states: FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE.
265 */
266 spin_lock(&ct->lock);
267 if (ct->proto.tcp.state != TCP_CONNTRACK_ESTABLISHED) {
268 spin_unlock(&ct->lock);
269 DEBUG_TRACE("connection in termination state: %#x, s: %pI4:%u, d: %pI4:%u\n",
270 ct->proto.tcp.state, &p_sic->src_ip, ntohs(p_sic->src_port),
271 &p_sic->dest_ip, ntohs(p_sic->dest_port));
272 return 0;
273 }
274 spin_unlock(&ct->lock);
275 break;
276
277 case IPPROTO_UDP:
278 break;
279
280 default:
281 DEBUG_TRACE("unhandled protocol %d\n", p_sic->protocol);
282 return 0;
283 }
284
285 return 1;
286}
287
Matthew McClintocke4f9a672014-01-06 17:04:04 -0600288/* fast_classifier_send_genl_msg()
289 * Function to send a generic netlink message
290 */
291static void fast_classifier_send_genl_msg(int msg, struct fast_classifier_tuple *fc_msg) {
292 struct sk_buff *skb;
293 int rc;
294 void *msg_head;
295
296 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC);
297 if (skb == NULL)
298 return;
299
300 msg_head = genlmsg_put(skb, 0, 0, &fast_classifier_gnl_family, 0, msg);
301 if (msg_head == NULL) {
302 nlmsg_free(skb);
303 return;
304 }
305
306 rc = nla_put(skb, FAST_CLASSIFIER_A_TUPLE, sizeof(struct fast_classifier_tuple), fc_msg);
307 if (rc != 0) {
308 genlmsg_cancel(skb, msg_head);
309 nlmsg_free(skb);
310 return;
311 }
312
313 rc = genlmsg_end(skb, msg_head);
314 if (rc < 0) {
315 genlmsg_cancel(skb, msg_head);
316 nlmsg_free(skb);
317 return;
318 }
319 genlmsg_multicast(skb, 0, fast_classifier_genl_mcgrp.id, GFP_ATOMIC);
320
Matthew McClintockd180a7d2014-01-17 11:21:35 -0600321 DEBUG_TRACE("INFO: %d : %d, %pI4, %pI4, %d, %d SMAC=%pM DMAC=%pM\n",
Matthew McClintockcf157352014-01-10 16:35:40 -0600322 msg, fc_msg->proto,
323 &(fc_msg->src_saddr),
324 &(fc_msg->dst_saddr),
325 fc_msg->sport, fc_msg->dport,
Matthew McClintockd180a7d2014-01-17 11:21:35 -0600326 fc_msg->smac,
327 fc_msg->dmac);
Matthew McClintocke4f9a672014-01-06 17:04:04 -0600328}
329
Matthew McClintockc5739382013-12-02 14:17:46 -0600330/*
Matthew McClintocke4f9a672014-01-06 17:04:04 -0600331 * fast_classifier_offload_genl_msg()
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600332 * Called from user space to offload a connection
333 */
Matthew McClintocke4f9a672014-01-06 17:04:04 -0600334static int fast_classifier_offload_genl_msg(struct sk_buff *skb, struct genl_info *info)
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600335{
Nicolas Costa514fde02014-01-13 15:50:29 -0600336 int ret;
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600337 struct nlattr *na;
Matthew McClintock28d75572014-01-03 11:54:08 -0600338 struct fast_classifier_tuple *fc_msg;
Matthew McClintockea00adf2013-11-25 19:24:30 -0600339 struct sfe_ipv4_create *p_sic;
340 struct sfe_connection *conn;
341 unsigned long flags;
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600342
Matthew McClintockd2854b72014-01-10 18:01:58 -0600343 na = info->attrs[FAST_CLASSIFIER_A_TUPLE];
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600344 fc_msg = nla_data(na);
Matthew McClintockea00adf2013-11-25 19:24:30 -0600345
Matthew McClintockd180a7d2014-01-17 11:21:35 -0600346 DEBUG_TRACE("INFO: want to offload: %d, %pI4, %pI4, %d, %d SMAC=%pM DMAC=%pM\n",
Matthew McClintockcf157352014-01-10 16:35:40 -0600347 fc_msg->proto,
348 &(fc_msg->src_saddr),
349 &(fc_msg->dst_saddr),
350 fc_msg->sport, fc_msg->dport,
Matthew McClintockd180a7d2014-01-17 11:21:35 -0600351 fc_msg->smac,
352 fc_msg->dmac);
Matthew McClintocke4f9a672014-01-06 17:04:04 -0600353
Matthew McClintockea00adf2013-11-25 19:24:30 -0600354 spin_lock_irqsave(&sfe_connections_lock, flags);
355 list_for_each_entry(conn, &sfe_connections, list) {
Matthew McClintockea00adf2013-11-25 19:24:30 -0600356 p_sic = conn->sic;
357
358 DEBUG_TRACE(" -> COMPARING: proto: %d src_ip: %d dst_ip: %d, src_port: %d, dst_port: %d...",
359 p_sic->protocol, p_sic->src_ip, p_sic->dest_ip,
360 p_sic->src_port, p_sic->dest_port);
361
362 if (p_sic->protocol == fc_msg->proto &&
363 p_sic->src_port == fc_msg->sport &&
364 p_sic->dest_port == fc_msg->dport &&
365 p_sic->src_ip == fc_msg->src_saddr &&
366 p_sic->dest_ip == fc_msg->dst_saddr ) {
Matthew McClintock55c86982013-12-02 14:24:24 -0600367 if (conn->offloaded == 0) {
368 DEBUG_TRACE("USERSPACE OFFLOAD REQUEST, MATCH FOUND, WILL OFFLOAD\n");
369 if (fast_classifier_update_protocol(p_sic, conn->ct) == 0) {
370 spin_unlock_irqrestore(&sfe_connections_lock, flags);
371 DEBUG_TRACE("UNKNOWN PROTOCOL OR CONNECTION CLOSING, SKIPPING\n");
372 return 0;
373 }
374 DEBUG_TRACE("INFO: calling sfe rule creation!\n");
Matthew McClintockc5739382013-12-02 14:17:46 -0600375 spin_unlock_irqrestore(&sfe_connections_lock, flags);
Nicolas Costa514fde02014-01-13 15:50:29 -0600376 ret = sfe_ipv4_create_rule(p_sic);
377 if ((ret == 0) || (ret == -EADDRINUSE)) {
378 conn->offloaded = 1;
379 fast_classifier_send_genl_msg(FAST_CLASSIFIER_C_OFFLOADED, fc_msg);
380 }
Matthew McClintockc5739382013-12-02 14:17:46 -0600381 return 0;
Matthew McClintockea00adf2013-11-25 19:24:30 -0600382 }
Matthew McClintocke4f9a672014-01-06 17:04:04 -0600383 /* conn->offloaded != 0 */
Matthew McClintock55c86982013-12-02 14:24:24 -0600384 DEBUG_TRACE("GOT REQUEST TO OFFLOAD ALREADY OFFLOADED CONN FROM USERSPACE\n");
Matthew McClintocke4f9a672014-01-06 17:04:04 -0600385 spin_unlock_irqrestore(&sfe_connections_lock, flags);
386 return 0;
Matthew McClintockea00adf2013-11-25 19:24:30 -0600387 }
388 DEBUG_TRACE("SEARCH CONTINUES\n");
389 }
390
391 spin_unlock_irqrestore(&sfe_connections_lock, flags);
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600392 return 0;
393}
394
Matthew McClintock595ee8b2013-12-02 16:21:49 -0600395/* auto offload connection once we have this many packets*/
396static int offload_at_pkts = 128;
397
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600398/*
399 * fast_classifier_ipv4_post_routing_hook()
400 * Called for packets about to leave the box - either locally generated or forwarded from another interface
401 */
402static unsigned int fast_classifier_ipv4_post_routing_hook(unsigned int hooknum,
403 struct sk_buff *skb,
404 const struct net_device *in_unused,
405 const struct net_device *out,
406 int (*okfn)(struct sk_buff *))
407{
Nicolas Costa514fde02014-01-13 15:50:29 -0600408 int ret;
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600409 struct sfe_ipv4_create sic;
Matthew McClintockea00adf2013-11-25 19:24:30 -0600410 struct sfe_ipv4_create *p_sic;
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600411 struct net_device *in;
412 struct nf_conn *ct;
413 enum ip_conntrack_info ctinfo;
414 struct net_device *src_dev;
415 struct net_device *dest_dev;
416 struct net_device *src_br_dev = NULL;
417 struct net_device *dest_br_dev = NULL;
418 struct nf_conntrack_tuple orig_tuple;
419 struct nf_conntrack_tuple reply_tuple;
Matthew McClintockea00adf2013-11-25 19:24:30 -0600420 struct sfe_connection *conn;
421 int sfe_connections_size = 0;
422 unsigned long flags;
Matthew McClintockcf157352014-01-10 16:35:40 -0600423 struct ethhdr *mh = eth_hdr(skb);
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600424
425 /*
426 * Don't process broadcast or multicast packets.
427 */
428 if (unlikely(skb->pkt_type == PACKET_BROADCAST)) {
429 DEBUG_TRACE("broadcast, ignoring\n");
430 return NF_ACCEPT;
431 }
432 if (unlikely(skb->pkt_type == PACKET_MULTICAST)) {
433 DEBUG_TRACE("multicast, ignoring\n");
434 return NF_ACCEPT;
435 }
436
437 /*
438 * Don't process packets that are not being forwarded.
439 */
440 in = dev_get_by_index(&init_net, skb->skb_iif);
441 if (!in) {
442 DEBUG_TRACE("packet not forwarding\n");
443 return NF_ACCEPT;
444 }
445
446 /*
447 * Don't process packets with non-standard 802.3 MAC address sizes.
448 */
449 if (unlikely(in->addr_len != ETH_ALEN)) {
450 DEBUG_TRACE("in device: %s not 802.3 hw addr len: %u, ignoring\n",
451 in->name, (unsigned)in->addr_len);
452 goto done1;
453 }
454 if (unlikely(out->addr_len != ETH_ALEN)) {
455 DEBUG_TRACE("out device: %s not 802.3 hw addr len: %u, ignoring\n",
456 out->name, (unsigned)out->addr_len);
457 goto done1;
458 }
459
460 /*
461 * Don't process packets that aren't being tracked by conntrack.
462 */
463 ct = nf_ct_get(skb, &ctinfo);
464 if (unlikely(!ct)) {
465 DEBUG_TRACE("no conntrack connection, ignoring\n");
466 goto done1;
467 }
468
469 /*
470 * Don't process untracked connections.
471 */
472 if (unlikely(ct == &nf_conntrack_untracked)) {
473 DEBUG_TRACE("untracked connection\n");
474 goto done1;
475 }
476
477 /*
478 * Don't process connections that require support from a 'helper' (typically a NAT ALG).
479 */
480 if (unlikely(nfct_help(ct))) {
481 DEBUG_TRACE("connection has helper\n");
482 goto done1;
483 }
484
485 /*
486 * Look up the details of our connection in conntrack.
487 *
488 * Note that the data we get from conntrack is for the "ORIGINAL" direction
489 * but our packet may actually be in the "REPLY" direction.
490 */
491 orig_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
492 reply_tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
493 sic.protocol = (int32_t)orig_tuple.dst.protonum;
494
495 /*
496 * Get addressing information, non-NAT first
497 */
498 sic.src_ip = (__be32)orig_tuple.src.u3.ip;
499 sic.dest_ip = (__be32)orig_tuple.dst.u3.ip;
500
501 /*
502 * NAT'ed addresses - note these are as seen from the 'reply' direction
503 * When NAT does not apply to this connection these will be identical to the above.
504 */
505 sic.src_ip_xlate = (__be32)reply_tuple.dst.u3.ip;
506 sic.dest_ip_xlate = (__be32)reply_tuple.src.u3.ip;
507
508 sic.flags = 0;
509
510 switch (sic.protocol) {
511 case IPPROTO_TCP:
512 sic.src_port = orig_tuple.src.u.tcp.port;
513 sic.dest_port = orig_tuple.dst.u.tcp.port;
514 sic.src_port_xlate = reply_tuple.dst.u.tcp.port;
515 sic.dest_port_xlate = reply_tuple.src.u.tcp.port;
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600516
517 /*
518 * Don't try to manage a non-established connection.
519 */
520 if (!test_bit(IPS_ASSURED_BIT, &ct->status)) {
521 DEBUG_TRACE("non-established connection\n");
522 goto done1;
523 }
524
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600525 break;
526
527 case IPPROTO_UDP:
528 sic.src_port = orig_tuple.src.u.udp.port;
529 sic.dest_port = orig_tuple.dst.u.udp.port;
530 sic.src_port_xlate = reply_tuple.dst.u.udp.port;
531 sic.dest_port_xlate = reply_tuple.src.u.udp.port;
532 break;
533
534 default:
535 DEBUG_TRACE("unhandled protocol %d\n", sic.protocol);
536 goto done1;
537 }
538
539 /*
Matthew McClintockea00adf2013-11-25 19:24:30 -0600540 * If we already have this connection in our list, skip it
541 * XXX: this may need to be optimized
542 */
543 DEBUG_TRACE("POST_ROUTE: checking new connection: %d src_ip: %d dst_ip: %d, src_port: %d, dst_port: %d\n",
544 sic.protocol, sic.src_ip, sic.dest_ip,
545 sic.src_port, sic.dest_port);
546 spin_lock_irqsave(&sfe_connections_lock, flags);
547 list_for_each_entry(conn, &sfe_connections, list) {
548 p_sic = conn->sic;
549 DEBUG_TRACE("\t\t-> COMPARING: proto: %d src_ip: %d dst_ip: %d, src_port: %d, dst_port: %d...",
550 p_sic->protocol, p_sic->src_ip, p_sic->dest_ip,
551 p_sic->src_port, p_sic->dest_port);
552
553 if (p_sic->protocol == sic.protocol &&
554 p_sic->src_port == sic.src_port &&
555 p_sic->dest_port == sic.dest_port &&
556 p_sic->src_ip == sic.src_ip &&
557 p_sic->dest_ip == sic.dest_ip ) {
Matthew McClintockc5739382013-12-02 14:17:46 -0600558 conn->hits++;
Matthew McClintock55c86982013-12-02 14:24:24 -0600559 if (conn->offloaded == 0) {
Matthew McClintock595ee8b2013-12-02 16:21:49 -0600560 if (conn->hits == offload_at_pkts) {
Nicolas Costa514fde02014-01-13 15:50:29 -0600561 struct fast_classifier_tuple fc_msg;
Matthew McClintock55c86982013-12-02 14:24:24 -0600562 DEBUG_TRACE("OFFLOADING CONNECTION, TOO MANY HITS\n");
563 if (fast_classifier_update_protocol(p_sic, conn->ct) == 0) {
564 spin_unlock_irqrestore(&sfe_connections_lock, flags);
565 DEBUG_TRACE("UNKNOWN PROTOCOL OR CONNECTION CLOSING, SKIPPING\n");
566 return 0;
567 }
568 DEBUG_TRACE("INFO: calling sfe rule creation!\n");
Matthew McClintockc5739382013-12-02 14:17:46 -0600569 spin_unlock_irqrestore(&sfe_connections_lock, flags);
Matthew McClintocke4f9a672014-01-06 17:04:04 -0600570
Nicolas Costa514fde02014-01-13 15:50:29 -0600571 ret = sfe_ipv4_create_rule(p_sic);
572 if ((ret == 0) || (ret == -EADDRINUSE)) {
573 conn->offloaded = 1;
574 fc_msg.proto = sic.protocol;
575 fc_msg.src_saddr = sic.src_ip;
576 fc_msg.dst_saddr = sic.dest_ip;
577 fc_msg.sport = sic.src_port;
578 fc_msg.dport = sic.dest_port;
Matthew McClintockd180a7d2014-01-17 11:21:35 -0600579 memcpy(fc_msg.smac, conn->smac, ETH_ALEN);
580 memcpy(fc_msg.dmac, conn->dmac, ETH_ALEN);
Nicolas Costa514fde02014-01-13 15:50:29 -0600581 fast_classifier_send_genl_msg(FAST_CLASSIFIER_C_OFFLOADED, &fc_msg);
582 }
583
Matthew McClintock16a47ec2013-12-05 17:03:15 -0600584 goto done1;
Matthew McClintock595ee8b2013-12-02 16:21:49 -0600585 } else if (conn->hits > offload_at_pkts) {
586 DEBUG_ERROR("ERROR: MORE THAN %d HITS AND NOT OFFLOADED\n", offload_at_pkts);
Matthew McClintock16a47ec2013-12-05 17:03:15 -0600587 spin_unlock_irqrestore(&sfe_connections_lock, flags);
588 goto done1;
Matthew McClintockc5739382013-12-02 14:17:46 -0600589 }
Matthew McClintock16a47ec2013-12-05 17:03:15 -0600590 }
591
Nicolas Costa514fde02014-01-13 15:50:29 -0600592 spin_unlock_irqrestore(&sfe_connections_lock, flags);
Matthew McClintock16a47ec2013-12-05 17:03:15 -0600593 if (conn->offloaded == 1) {
Nicolas Costa514fde02014-01-13 15:50:29 -0600594 sfe_ipv4_update_rule(p_sic);
Matthew McClintockc5739382013-12-02 14:17:46 -0600595 }
596
597 DEBUG_TRACE("FOUND, SKIPPING\n");
Matthew McClintockea00adf2013-11-25 19:24:30 -0600598 goto done1;
Matthew McClintockea00adf2013-11-25 19:24:30 -0600599 }
600
Matthew McClintock55c86982013-12-02 14:24:24 -0600601 DEBUG_TRACE("SEARCH CONTINUES");
Matthew McClintockea00adf2013-11-25 19:24:30 -0600602 sfe_connections_size++;
603 }
604 spin_unlock_irqrestore(&sfe_connections_lock, flags);
605
606 /*
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600607 * Get the MAC addresses that correspond to source and destination host addresses.
608 */
609 if (!fast_classifier_find_mac_addr(sic.src_ip, sic.src_mac)) {
610 DEBUG_TRACE("failed to find MAC address for src IP: %pI4\n", &sic.src_ip);
611 goto done1;
612 }
613
614 if (!fast_classifier_find_mac_addr(sic.src_ip_xlate, sic.src_mac_xlate)) {
615 DEBUG_TRACE("failed to find MAC address for xlate src IP: %pI4\n", &sic.src_ip_xlate);
616 goto done1;
617 }
618
619 /*
620 * Do dest now
621 */
622 if (!fast_classifier_find_mac_addr(sic.dest_ip, sic.dest_mac)) {
623 DEBUG_TRACE("failed to find MAC address for dest IP: %pI4\n", &sic.dest_ip);
624 goto done1;
625 }
626
627 if (!fast_classifier_find_mac_addr(sic.dest_ip_xlate, sic.dest_mac_xlate)) {
628 DEBUG_TRACE("failed to find MAC address for xlate dest IP: %pI4\n", &sic.dest_ip_xlate);
629 goto done1;
630 }
631
632 /*
633 * Get our device info. If we're dealing with the "reply" direction here then
634 * we'll need things swapped around.
635 */
636 if (ctinfo < IP_CT_IS_REPLY) {
637 src_dev = in;
638 dest_dev = (struct net_device *)out;
639 } else {
640 src_dev = (struct net_device *)out;
641 dest_dev = in;
642 }
643
644#if (!SFE_HOOK_ABOVE_BRIDGE)
645 /*
646 * Now our devices may actually be a bridge interface. If that's
647 * the case then we need to hunt down the underlying interface.
648 */
649 if (src_dev->priv_flags & IFF_EBRIDGE) {
650 src_br_dev = br_port_dev_get(src_dev, sic.src_mac);
651 if (!src_br_dev) {
652 DEBUG_TRACE("no port found on bridge\n");
653 goto done1;
654 }
655
656 src_dev = src_br_dev;
657 }
658
659 if (dest_dev->priv_flags & IFF_EBRIDGE) {
660 dest_br_dev = br_port_dev_get(dest_dev, sic.dest_mac_xlate);
661 if (!dest_br_dev) {
662 DEBUG_TRACE("no port found on bridge\n");
663 goto done2;
664 }
665
666 dest_dev = dest_br_dev;
667 }
668#else
669 /*
670 * Our devices may actually be part of a bridge interface. If that's
671 * the case then find the bridge interface instead.
672 */
673 if (src_dev->priv_flags & IFF_BRIDGE_PORT) {
674 src_br_dev = src_dev->master;
675 if (!src_br_dev) {
676 DEBUG_TRACE("no bridge found for: %s\n", src_dev->name);
677 goto done1;
678 }
679
680 dev_hold(src_br_dev);
681 src_dev = src_br_dev;
682 }
683
684 if (dest_dev->priv_flags & IFF_BRIDGE_PORT) {
685 dest_br_dev = dest_dev->master;
686 if (!dest_br_dev) {
687 DEBUG_TRACE("no bridge found for: %s\n", dest_dev->name);
688 goto done2;
689 }
690
691 dev_hold(dest_br_dev);
692 dest_dev = dest_br_dev;
693 }
694#endif
695
696 sic.src_dev = src_dev;
697 sic.dest_dev = dest_dev;
698
699// XXX - these MTUs need handling correctly!
700 sic.src_mtu = 1500;
701 sic.dest_mtu = 1500;
702
Matthew McClintocke1cf6f22013-11-27 13:27:09 -0600703 if (skb->mark) {
704 DEBUG_TRACE("SKB MARK NON ZERO %x\n", skb->mark);
705 }
706 sic.mark = skb->mark;
707
Matthew McClintockea00adf2013-11-25 19:24:30 -0600708 conn = kmalloc(sizeof(struct sfe_connection), GFP_KERNEL);
709 if (conn == NULL) {
710 printk(KERN_CRIT "ERROR: no memory for sfe\n");
711 goto done3;
712 }
Matthew McClintockc5739382013-12-02 14:17:46 -0600713 conn->hits = 0;
Matthew McClintock55c86982013-12-02 14:24:24 -0600714 conn->offloaded = 0;
Matthew McClintockcf157352014-01-10 16:35:40 -0600715 DEBUG_TRACE("Source MAC=%pM\n", mh->h_source);
Matthew McClintockd180a7d2014-01-17 11:21:35 -0600716 memcpy(conn->smac, mh->h_source, ETH_ALEN);
717 memcpy(conn->dmac, mh->h_dest, ETH_ALEN);
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600718
Matthew McClintockea00adf2013-11-25 19:24:30 -0600719 p_sic = kmalloc(sizeof(struct sfe_ipv4_create), GFP_KERNEL);
720 if (p_sic == NULL) {
721 printk(KERN_CRIT "ERROR: no memory for sfe\n");
722 kfree(conn);
723 goto done3;
724 }
725
726 memcpy(p_sic, &sic, sizeof(sic));
727 conn->sic = p_sic;
728 conn->ct = ct;
729 DEBUG_TRACE(" -> adding item to sfe_connections, new size: %d\n", ++sfe_connections_size);
730 DEBUG_TRACE("POST_ROUTE: new offloadable connection: proto: %d src_ip: %d dst_ip: %d, src_port: %d, dst_port: %d\n",
731 p_sic->protocol, p_sic->src_ip, p_sic->dest_ip,
732 p_sic->src_port, p_sic->dest_port);
733 spin_lock_irqsave(&sfe_connections_lock, flags);
734 list_add_tail(&(conn->list), &sfe_connections);
735 spin_unlock_irqrestore(&sfe_connections_lock, flags);
736done3:
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600737 /*
738 * If we had bridge ports then release them too.
739 */
740 if (dest_br_dev) {
741 dev_put(dest_br_dev);
742 }
743
744done2:
745 if (src_br_dev) {
746 dev_put(src_br_dev);
747 }
748
749done1:
750 /*
751 * Release the interface on which this skb arrived
752 */
753 dev_put(in);
754
755 return NF_ACCEPT;
756}
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600757
Nicolas Costa21090402014-01-15 11:47:10 -0600758/*
759 * fast_classifier_update_mark()
760 * updates the mark for a fast-classifier connection
761 */
762static void fast_classifier_update_mark(struct sfe_ipv4_mark *mark)
763{
764 struct sfe_connection *conn;
765 struct sfe_ipv4_create *p_sic;
766 unsigned long flags;
767
768 spin_lock_irqsave(&sfe_connections_lock, flags);
769 list_for_each_entry(conn, &sfe_connections, list) {
770 p_sic = conn->sic;
771 if (p_sic->protocol == mark->protocol &&
772 p_sic->src_port == mark->src_port &&
773 p_sic->dest_port == mark->dest_port &&
774 p_sic->src_ip == mark->src_ip &&
775 p_sic->dest_ip == mark->dest_ip ) {
776
777 p_sic->mark = mark->mark;
778
779 break;
780 }
781 }
782 spin_unlock_irqrestore(&sfe_connections_lock, flags);
783}
784
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600785#ifdef CONFIG_NF_CONNTRACK_EVENTS
786/*
787 * fast_classifier_conntrack_event()
788 * Callback event invoked when a conntrack connection's state changes.
789 */
Matthew McClintock0680e9f2013-11-26 15:43:10 -0600790#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
791static int fast_classifier_conntrack_event(struct notifier_block *this,
792 unsigned int events, struct nf_ct_event *item)
793#else
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600794static int fast_classifier_conntrack_event(unsigned int events, struct nf_ct_event *item)
Matthew McClintock0680e9f2013-11-26 15:43:10 -0600795#endif
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600796{
797 struct sfe_ipv4_destroy sid;
798 struct nf_conn *ct = item->ct;
799 struct nf_conntrack_tuple orig_tuple;
Matthew McClintockea00adf2013-11-25 19:24:30 -0600800 struct sfe_connection *conn;
801 struct sfe_ipv4_create *p_sic;
802 int sfe_found_match = 0;
803 int sfe_connections_size = 0;
804 unsigned long flags;
Matthew McClintocke4f9a672014-01-06 17:04:04 -0600805 struct fast_classifier_tuple fc_msg;
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600806
807 /*
808 * If we don't have a conntrack entry then we're done.
809 */
810 if (unlikely(!ct)) {
811 DEBUG_WARN("no ct in conntrack event callback\n");
812 return NOTIFY_DONE;
813 }
814
815 /*
816 * If this is an untracked connection then we can't have any state either.
817 */
818 if (unlikely(ct == &nf_conntrack_untracked)) {
819 DEBUG_TRACE("ignoring untracked conn\n");
820 return NOTIFY_DONE;
821 }
822
823 /*
824 * Ignore anything other than IPv4 connections.
825 */
826 if (unlikely(nf_ct_l3num(ct) != AF_INET)) {
827 DEBUG_TRACE("ignoring non-IPv4 conn\n");
828 return NOTIFY_DONE;
829 }
830
831 /*
Nicolas Costab5f377c2014-01-13 16:16:13 -0600832 * Check for an updated mark
833 */
834 if ((events & (1 << IPCT_MARK)) && (ct->mark != 0)) {
835 struct sfe_ipv4_mark mark;
836 orig_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
837
838 mark.protocol = (int32_t)orig_tuple.dst.protonum;
839 mark.src_ip = (__be32)orig_tuple.src.u3.ip;
840 mark.dest_ip = (__be32)orig_tuple.dst.u3.ip;
841 switch (mark.protocol) {
842 case IPPROTO_TCP:
843 mark.src_port = orig_tuple.src.u.tcp.port;
844 mark.dest_port = orig_tuple.dst.u.tcp.port;
845 break;
846 case IPPROTO_UDP:
847 mark.src_port = orig_tuple.src.u.udp.port;
848 mark.dest_port = orig_tuple.dst.u.udp.port;
849 break;
850 default:
851 break;
852 }
853
854 mark.mark = ct->mark;
855 sfe_ipv4_mark_rule(&mark);
Nicolas Costa21090402014-01-15 11:47:10 -0600856 fast_classifier_update_mark(&mark);
Nicolas Costab5f377c2014-01-13 16:16:13 -0600857 }
858
859 /*
Matthew McClintocke1cf6f22013-11-27 13:27:09 -0600860 * We're only interested in destroy events at this point
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600861 */
862 if (unlikely(!(events & (1 << IPCT_DESTROY)))) {
863 DEBUG_TRACE("ignoring non-destroy event\n");
864 return NOTIFY_DONE;
865 }
866
867 orig_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
868 sid.protocol = (int32_t)orig_tuple.dst.protonum;
869
870 /*
871 * Extract information from the conntrack connection. We're only interested
872 * in nominal connection information (i.e. we're ignoring any NAT information).
873 */
874 sid.src_ip = (__be32)orig_tuple.src.u3.ip;
875 sid.dest_ip = (__be32)orig_tuple.dst.u3.ip;
876
877 switch (sid.protocol) {
878 case IPPROTO_TCP:
879 sid.src_port = orig_tuple.src.u.tcp.port;
880 sid.dest_port = orig_tuple.dst.u.tcp.port;
881 break;
882
883 case IPPROTO_UDP:
884 sid.src_port = orig_tuple.src.u.udp.port;
885 sid.dest_port = orig_tuple.dst.u.udp.port;
886 break;
887
888 default:
889 DEBUG_TRACE("unhandled protocol: %d\n", sid.protocol);
890 return NOTIFY_DONE;
891 }
892
Matthew McClintockea00adf2013-11-25 19:24:30 -0600893 /*
894 * If we already have this connection in our list, skip it
895 * XXX: this may need to be optimized
896 */
897 DEBUG_TRACE("INFO: want to clean up: proto: %d src_ip: %d dst_ip: %d, src_port: %d, dst_port: %d\n",
898 sid.protocol, sid.src_ip, sid.dest_ip,
899 sid.src_port, sid.dest_port);
900 spin_lock_irqsave(&sfe_connections_lock, flags);
901 list_for_each_entry(conn, &sfe_connections, list) {
902 p_sic = conn->sic;
903 DEBUG_TRACE(" -> COMPARING: proto: %d src_ip: %d dst_ip: %d, src_port: %d, dst_port: %d...",
904 p_sic->protocol, p_sic->src_ip, p_sic->dest_ip,
905 p_sic->src_port, p_sic->dest_port);
906
907 if (p_sic->protocol == sid.protocol &&
908 p_sic->src_port == sid.src_port &&
909 p_sic->dest_port == sid.dest_port &&
910 p_sic->src_ip == sid.src_ip &&
911 p_sic->dest_ip == sid.dest_ip ) {
Matthew McClintocke4f9a672014-01-06 17:04:04 -0600912 fc_msg.proto = p_sic->protocol;
913 fc_msg.src_saddr = p_sic->src_ip;
914 fc_msg.dst_saddr = p_sic->dest_ip;
915 fc_msg.sport = p_sic->src_port;
916 fc_msg.dport = p_sic->dest_port;
Matthew McClintockd180a7d2014-01-17 11:21:35 -0600917 memcpy(fc_msg.smac, conn->smac, ETH_ALEN);
918 memcpy(fc_msg.dmac, conn->dmac, ETH_ALEN);
Matthew McClintockea00adf2013-11-25 19:24:30 -0600919 sfe_found_match = 1;
920 DEBUG_TRACE("FOUND, DELETING\n");
921 break;
Matthew McClintockea00adf2013-11-25 19:24:30 -0600922 }
Matthew McClintocke4f9a672014-01-06 17:04:04 -0600923 DEBUG_TRACE("SEARCH CONTINUES\n");
Matthew McClintockea00adf2013-11-25 19:24:30 -0600924 sfe_connections_size++;
925 }
926
927 if (sfe_found_match) {
928 DEBUG_TRACE("INFO: connection over proto: %d src_ip: %d dst_ip: %d, src_port: %d, dst_port: %d\n",
929 p_sic->protocol, p_sic->src_ip, p_sic->dest_ip,
930 p_sic->src_port, p_sic->dest_port);
931 kfree(conn->sic);
932 list_del(&(conn->list));
933 kfree(conn);
934 } else {
935 DEBUG_TRACE("NO MATCH FOUND IN %d ENTRIES!!\n", sfe_connections_size);
936 }
937 spin_unlock_irqrestore(&sfe_connections_lock, flags);
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600938
939 sfe_ipv4_destroy_rule(&sid);
Matthew McClintocke4f9a672014-01-06 17:04:04 -0600940
941 if (sfe_found_match) {
942 fast_classifier_send_genl_msg(FAST_CLASSIFIER_C_DONE, &fc_msg);
943 }
944
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600945 return NOTIFY_DONE;
946}
947
948/*
949 * Netfilter conntrack event system to monitor connection tracking changes
950 */
Matthew McClintock0680e9f2013-11-26 15:43:10 -0600951#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
952static struct notifier_block fast_classifier_conntrack_notifier = {
953 .notifier_call = fast_classifier_conntrack_event,
954};
955#else
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600956static struct nf_ct_event_notifier fast_classifier_conntrack_notifier = {
957 .fcn = fast_classifier_conntrack_event,
958};
959#endif
Matthew McClintock0680e9f2013-11-26 15:43:10 -0600960#endif
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600961
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600962/*
963 * Structure to establish a hook into the post routing netfilter point - this
964 * will pick up local outbound and packets going from one interface to another.
965 *
966 * Note: see include/linux/netfilter_ipv4.h for info related to priority levels.
967 * We want to examine packets after NAT translation and any ALG processing.
968 */
969static struct nf_hook_ops fast_classifier_ipv4_ops_post_routing[] __read_mostly = {
970 {
971 .hook = fast_classifier_ipv4_post_routing_hook,
972 .owner = THIS_MODULE,
973 .pf = PF_INET,
974 .hooknum = NF_INET_POST_ROUTING,
975 .priority = NF_IP_PRI_NAT_SRC + 1,
976 },
977};
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600978
979/*
980 * fast_classifier_sync_rule()
981 * Synchronize a connection's state.
982 */
983static void fast_classifier_sync_rule(struct sfe_ipv4_sync *sis)
984{
985 struct nf_conntrack_tuple_hash *h;
986 struct nf_conntrack_tuple tuple;
987 struct nf_conn *ct;
988 struct nf_conn_counter *acct;
989
990 /*
991 * Create a tuple so as to be able to look up a connection
992 */
993 memset(&tuple, 0, sizeof(tuple));
994 tuple.src.u3.ip = sis->src_ip;
995 tuple.src.u.all = (__be16)sis->src_port;
996 tuple.src.l3num = AF_INET;
997
998 tuple.dst.u3.ip = sis->dest_ip;
999 tuple.dst.dir = IP_CT_DIR_ORIGINAL;
1000 tuple.dst.protonum = (uint8_t)sis->protocol;
1001 tuple.dst.u.all = (__be16)sis->dest_port;
1002
1003 DEBUG_TRACE("update connection - p: %d, s: %pI4:%u, d: %pI4:%u\n",
1004 (int)tuple.dst.protonum,
1005 &tuple.src.u3.ip, (unsigned int)ntohs(tuple.src.u.all),
1006 &tuple.dst.u3.ip, (unsigned int)ntohs(tuple.dst.u.all));
1007
1008 /*
1009 * Look up conntrack connection
1010 */
1011 h = nf_conntrack_find_get(&init_net, NF_CT_DEFAULT_ZONE, &tuple);
1012 if (unlikely(!h)) {
1013 DEBUG_TRACE("no connection found\n");
1014 return;
1015 }
1016
1017 ct = nf_ct_tuplehash_to_ctrack(h);
1018 NF_CT_ASSERT(ct->timeout.data == (unsigned long)ct);
1019
1020 /*
1021 * Only update if this is not a fixed timeout
1022 */
1023 if (!test_bit(IPS_FIXED_TIMEOUT_BIT, &ct->status)) {
1024 ct->timeout.expires += sis->delta_jiffies;
1025 }
1026
1027 acct = nf_conn_acct_find(ct);
1028 if (acct) {
1029 spin_lock_bh(&ct->lock);
Matthew McClintock704b7a62013-12-19 16:13:01 -06001030 atomic64_set(&acct[IP_CT_DIR_ORIGINAL].packets, sis->src_packet_count);
1031 atomic64_set(&acct[IP_CT_DIR_ORIGINAL].bytes, sis->src_byte_count);
1032 atomic64_set(&acct[IP_CT_DIR_REPLY].packets, sis->dest_packet_count);
1033 atomic64_set(&acct[IP_CT_DIR_REPLY].bytes, sis->dest_byte_count);
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001034 spin_unlock_bh(&ct->lock);
1035 }
1036
1037 switch (sis->protocol) {
1038 case IPPROTO_TCP:
1039 spin_lock_bh(&ct->lock);
1040 if (ct->proto.tcp.seen[0].td_maxwin < sis->src_td_max_window) {
1041 ct->proto.tcp.seen[0].td_maxwin = sis->src_td_max_window;
1042 }
1043 if ((int32_t)(ct->proto.tcp.seen[0].td_end - sis->src_td_end) < 0) {
1044 ct->proto.tcp.seen[0].td_end = sis->src_td_end;
1045 }
1046 if ((int32_t)(ct->proto.tcp.seen[0].td_maxend - sis->src_td_max_end) < 0) {
1047 ct->proto.tcp.seen[0].td_maxend = sis->src_td_max_end;
1048 }
1049 if (ct->proto.tcp.seen[1].td_maxwin < sis->dest_td_max_window) {
1050 ct->proto.tcp.seen[1].td_maxwin = sis->dest_td_max_window;
1051 }
1052 if ((int32_t)(ct->proto.tcp.seen[1].td_end - sis->dest_td_end) < 0) {
1053 ct->proto.tcp.seen[1].td_end = sis->dest_td_end;
1054 }
1055 if ((int32_t)(ct->proto.tcp.seen[1].td_maxend - sis->dest_td_max_end) < 0) {
1056 ct->proto.tcp.seen[1].td_maxend = sis->dest_td_max_end;
1057 }
1058 spin_unlock_bh(&ct->lock);
1059 break;
1060 }
1061
1062 /*
1063 * Release connection
1064 */
1065 nf_ct_put(ct);
1066}
1067
1068/*
1069 * fast_classifier_device_event()
1070 */
1071static int fast_classifier_device_event(struct notifier_block *this, unsigned long event, void *ptr)
1072{
1073 struct net_device *dev = (struct net_device *)ptr;
1074
1075 switch (event) {
1076 case NETDEV_DOWN:
1077 if (dev) {
1078 sfe_ipv4_destroy_all_rules_for_dev(dev);
1079 }
1080 break;
1081 }
1082
1083 return NOTIFY_DONE;
1084}
1085
1086/*
1087 * fast_classifier_inet_event()
1088 */
1089static int fast_classifier_inet_event(struct notifier_block *this, unsigned long event, void *ptr)
1090{
1091 struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev;
1092 return fast_classifier_device_event(this, event, dev);
1093}
1094
1095/*
Matthew McClintock595ee8b2013-12-02 16:21:49 -06001096 * fast_classifier_get_offload_at_pkts()
1097 */
1098static ssize_t fast_classifier_get_offload_at_pkts(struct device *dev,
1099 struct device_attribute *attr,
1100 char *buf)
1101{
1102 return sprintf(buf, "%d\n", offload_at_pkts);
1103}
1104
1105/*
1106 * fast_classifier_set_offload_at_pkts()
1107 */
1108static ssize_t fast_classifier_set_offload_at_pkts(struct device *dev,
1109 struct device_attribute *attr,
1110 char *buf, size_t size)
1111{
Matthew McClintock8f4fcd22014-01-14 21:06:03 -06001112 long new;
1113 int ret;
Matthew McClintock595ee8b2013-12-02 16:21:49 -06001114
Matthew McClintock8f4fcd22014-01-14 21:06:03 -06001115 printk(KERN_EMERG "BUF: %s\n", buf);
1116 ret = strict_strtol(buf, 0, &new);
1117 if (ret == -EINVAL || ((int)new != new))
Matthew McClintock595ee8b2013-12-02 16:21:49 -06001118 return -EINVAL;
1119
1120 offload_at_pkts = new;
1121
1122 return size;
1123}
1124
1125/*
1126 * sysfs attributes.
1127 */
1128static const struct device_attribute fast_classifier_offload_at_pkts_attr =
1129 __ATTR(offload_at_pkts, S_IWUGO | S_IRUGO, fast_classifier_get_offload_at_pkts, fast_classifier_set_offload_at_pkts);
1130
1131/*
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001132 * fast_classifier_init()
1133 */
1134static int __init fast_classifier_init(void)
1135{
1136 struct fast_classifier *sc = &__sc;
1137 int result = -1;
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -06001138
1139 printk(KERN_ALERT "fast-classifier: starting up\n");
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001140 DEBUG_INFO("SFE CM init\n");
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -06001141
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001142 /*
1143 * Create sys/fast_classifier
1144 */
1145 sc->sys_fast_classifier = kobject_create_and_add("fast_classifier", NULL);
1146 if (!sc->sys_fast_classifier) {
1147 DEBUG_ERROR("failed to register fast_classifier\n");
1148 goto exit1;
1149 }
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -06001150
Matthew McClintock595ee8b2013-12-02 16:21:49 -06001151 result = sysfs_create_file(sc->sys_fast_classifier, &fast_classifier_offload_at_pkts_attr.attr);
1152 if (result) {
1153 DEBUG_ERROR("failed to register debug dev file: %d\n", result);
1154 goto exit2;
1155 }
1156
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001157 sc->dev_notifier.notifier_call = fast_classifier_device_event;
1158 sc->dev_notifier.priority = 1;
1159 register_netdevice_notifier(&sc->dev_notifier);
1160
1161 sc->inet_notifier.notifier_call = fast_classifier_inet_event;
1162 sc->inet_notifier.priority = 1;
1163 register_inetaddr_notifier(&sc->inet_notifier);
1164
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001165 /*
1166 * Register our netfilter hooks.
1167 */
1168 result = nf_register_hooks(fast_classifier_ipv4_ops_post_routing, ARRAY_SIZE(fast_classifier_ipv4_ops_post_routing));
1169 if (result < 0) {
1170 DEBUG_ERROR("can't register nf post routing hook: %d\n", result);
Matthew McClintock595ee8b2013-12-02 16:21:49 -06001171 goto exit3;
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001172 }
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001173
1174#ifdef CONFIG_NF_CONNTRACK_EVENTS
1175 /*
1176 * Register a notifier hook to get fast notifications of expired connections.
1177 */
1178 result = nf_conntrack_register_notifier(&init_net, &fast_classifier_conntrack_notifier);
1179 if (result < 0) {
1180 DEBUG_ERROR("can't register nf notifier hook: %d\n", result);
Matthew McClintock595ee8b2013-12-02 16:21:49 -06001181 goto exit4;
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001182 }
1183#endif
1184
Dave Hudsonfd7fd072013-12-07 22:34:18 +00001185 result = genl_register_family(&fast_classifier_gnl_family);
Matthew McClintocke4f9a672014-01-06 17:04:04 -06001186 if (result != 0) {
1187 printk(KERN_CRIT "unable to register genl family\n");
Dave Hudsonfd7fd072013-12-07 22:34:18 +00001188 goto exit5;
1189 }
1190
Matthew McClintocke4f9a672014-01-06 17:04:04 -06001191 result = genl_register_ops(&fast_classifier_gnl_family, fast_classifier_gnl_ops);
Dave Hudsonfd7fd072013-12-07 22:34:18 +00001192 if (result != 0) {
Matthew McClintocke4f9a672014-01-06 17:04:04 -06001193 printk(KERN_CRIT "unable to register ops\n");
1194 goto exit6;
1195 }
1196
1197 result = genl_register_mc_group(&fast_classifier_gnl_family,
1198 &fast_classifier_genl_mcgrp);
1199 if (result != 0) {
1200 printk(KERN_CRIT "unable to register multicast group\n");
Dave Hudsonfd7fd072013-12-07 22:34:18 +00001201 goto exit6;
1202 }
1203
1204 printk(KERN_ALERT "fast-classifier: registered\n");
1205
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001206 spin_lock_init(&sc->lock);
1207
1208 /*
1209 * Hook the receive path in the network stack.
1210 */
1211 BUG_ON(athrs_fast_nat_recv != NULL);
1212 RCU_INIT_POINTER(athrs_fast_nat_recv, fast_classifier_recv);
1213
1214 /*
1215 * Hook the shortcut sync callback.
1216 */
1217 sfe_ipv4_register_sync_rule_callback(fast_classifier_sync_rule);
1218
Matthew McClintock6f29aa12013-11-06 15:49:01 -06001219 return 0;
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -06001220
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001221exit6:
Matthew McClintock595ee8b2013-12-02 16:21:49 -06001222 genl_unregister_family(&fast_classifier_gnl_family);
1223
1224exit5:
1225#ifdef CONFIG_NF_CONNTRACK_EVENTS
Dave Hudsonfd7fd072013-12-07 22:34:18 +00001226 nf_conntrack_unregister_notifier(&init_net, &fast_classifier_conntrack_notifier);
Matthew McClintock595ee8b2013-12-02 16:21:49 -06001227#endif
1228
1229exit4:
Dave Hudsonfd7fd072013-12-07 22:34:18 +00001230 nf_unregister_hooks(fast_classifier_ipv4_ops_post_routing, ARRAY_SIZE(fast_classifier_ipv4_ops_post_routing));
Matthew McClintock595ee8b2013-12-02 16:21:49 -06001231
1232exit3:
Dave Hudsonfd7fd072013-12-07 22:34:18 +00001233 unregister_inetaddr_notifier(&sc->inet_notifier);
1234 unregister_netdevice_notifier(&sc->dev_notifier);
Matthew McClintock595ee8b2013-12-02 16:21:49 -06001235 sysfs_remove_file(sc->sys_fast_classifier, &fast_classifier_offload_at_pkts_attr.attr);
1236
1237exit2:
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001238 kobject_put(sc->sys_fast_classifier);
1239
1240exit1:
1241 return result;
Matthew McClintock6f29aa12013-11-06 15:49:01 -06001242}
1243
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001244/*
1245 * fast_classifier_exit()
1246 */
1247static void __exit fast_classifier_exit(void)
Matthew McClintock6f29aa12013-11-06 15:49:01 -06001248{
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001249 struct fast_classifier *sc = &__sc;
1250 int result = -1;
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -06001251
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001252 DEBUG_INFO("SFE CM exit\n");
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -06001253 printk(KERN_ALERT "fast-classifier: shutting down\n");
1254
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001255 /*
1256 * Unregister our sync callback.
1257 */
1258 sfe_ipv4_register_sync_rule_callback(NULL);
1259
1260 /*
1261 * Unregister our receive callback.
1262 */
1263 RCU_INIT_POINTER(athrs_fast_nat_recv, NULL);
1264
1265 /*
1266 * Wait for all callbacks to complete.
1267 */
1268 rcu_barrier();
1269
1270 /*
1271 * Destroy all connections.
1272 */
1273 sfe_ipv4_destroy_all_rules_for_dev(NULL);
1274
Matthew McClintocke4f9a672014-01-06 17:04:04 -06001275 result = genl_unregister_ops(&fast_classifier_gnl_family, fast_classifier_gnl_ops);
Dave Hudsonfd7fd072013-12-07 22:34:18 +00001276 if (result != 0) {
1277 printk(KERN_CRIT "Unable to unreigster genl_ops\n");
1278 }
1279
1280 result = genl_unregister_family(&fast_classifier_gnl_family);
1281 if (result != 0) {
1282 printk(KERN_CRIT "Unable to unreigster genl_family\n");
1283 }
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001284
1285#ifdef CONFIG_NF_CONNTRACK_EVENTS
1286 nf_conntrack_unregister_notifier(&init_net, &fast_classifier_conntrack_notifier);
1287
1288#endif
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001289 nf_unregister_hooks(fast_classifier_ipv4_ops_post_routing, ARRAY_SIZE(fast_classifier_ipv4_ops_post_routing));
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001290
1291 unregister_inetaddr_notifier(&sc->inet_notifier);
1292 unregister_netdevice_notifier(&sc->dev_notifier);
1293
1294 kobject_put(sc->sys_fast_classifier);
Matthew McClintock6f29aa12013-11-06 15:49:01 -06001295}
1296
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001297module_init(fast_classifier_init)
1298module_exit(fast_classifier_exit)
1299
1300MODULE_AUTHOR("Qualcomm Atheros Inc.");
1301MODULE_DESCRIPTION("Shortcut Forwarding Engine - Connection Manager");
Matthew McClintocka3221942014-01-16 11:44:26 -06001302MODULE_LICENSE("Dual BSD/GPL");
Matthew McClintock6f29aa12013-11-06 15:49:01 -06001303