blob: 39b9ffe3b3f3b0558157947a9549631c8986fa14 [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 McClintock5f1b1d42014-01-17 14:43:00 -0600806 int offloaded = 0;
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600807
808 /*
809 * If we don't have a conntrack entry then we're done.
810 */
811 if (unlikely(!ct)) {
812 DEBUG_WARN("no ct in conntrack event callback\n");
813 return NOTIFY_DONE;
814 }
815
816 /*
817 * If this is an untracked connection then we can't have any state either.
818 */
819 if (unlikely(ct == &nf_conntrack_untracked)) {
820 DEBUG_TRACE("ignoring untracked conn\n");
821 return NOTIFY_DONE;
822 }
823
824 /*
825 * Ignore anything other than IPv4 connections.
826 */
827 if (unlikely(nf_ct_l3num(ct) != AF_INET)) {
828 DEBUG_TRACE("ignoring non-IPv4 conn\n");
829 return NOTIFY_DONE;
830 }
831
832 /*
Nicolas Costab5f377c2014-01-13 16:16:13 -0600833 * Check for an updated mark
834 */
835 if ((events & (1 << IPCT_MARK)) && (ct->mark != 0)) {
836 struct sfe_ipv4_mark mark;
837 orig_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
838
839 mark.protocol = (int32_t)orig_tuple.dst.protonum;
840 mark.src_ip = (__be32)orig_tuple.src.u3.ip;
841 mark.dest_ip = (__be32)orig_tuple.dst.u3.ip;
842 switch (mark.protocol) {
843 case IPPROTO_TCP:
844 mark.src_port = orig_tuple.src.u.tcp.port;
845 mark.dest_port = orig_tuple.dst.u.tcp.port;
846 break;
847 case IPPROTO_UDP:
848 mark.src_port = orig_tuple.src.u.udp.port;
849 mark.dest_port = orig_tuple.dst.u.udp.port;
850 break;
851 default:
852 break;
853 }
854
855 mark.mark = ct->mark;
856 sfe_ipv4_mark_rule(&mark);
Nicolas Costa21090402014-01-15 11:47:10 -0600857 fast_classifier_update_mark(&mark);
Nicolas Costab5f377c2014-01-13 16:16:13 -0600858 }
859
860 /*
Matthew McClintocke1cf6f22013-11-27 13:27:09 -0600861 * We're only interested in destroy events at this point
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600862 */
863 if (unlikely(!(events & (1 << IPCT_DESTROY)))) {
864 DEBUG_TRACE("ignoring non-destroy event\n");
865 return NOTIFY_DONE;
866 }
867
868 orig_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
869 sid.protocol = (int32_t)orig_tuple.dst.protonum;
870
871 /*
872 * Extract information from the conntrack connection. We're only interested
873 * in nominal connection information (i.e. we're ignoring any NAT information).
874 */
875 sid.src_ip = (__be32)orig_tuple.src.u3.ip;
876 sid.dest_ip = (__be32)orig_tuple.dst.u3.ip;
877
878 switch (sid.protocol) {
879 case IPPROTO_TCP:
880 sid.src_port = orig_tuple.src.u.tcp.port;
881 sid.dest_port = orig_tuple.dst.u.tcp.port;
882 break;
883
884 case IPPROTO_UDP:
885 sid.src_port = orig_tuple.src.u.udp.port;
886 sid.dest_port = orig_tuple.dst.u.udp.port;
887 break;
888
889 default:
890 DEBUG_TRACE("unhandled protocol: %d\n", sid.protocol);
891 return NOTIFY_DONE;
892 }
893
Matthew McClintockea00adf2013-11-25 19:24:30 -0600894 /*
895 * If we already have this connection in our list, skip it
896 * XXX: this may need to be optimized
897 */
898 DEBUG_TRACE("INFO: want to clean up: proto: %d src_ip: %d dst_ip: %d, src_port: %d, dst_port: %d\n",
899 sid.protocol, sid.src_ip, sid.dest_ip,
900 sid.src_port, sid.dest_port);
901 spin_lock_irqsave(&sfe_connections_lock, flags);
902 list_for_each_entry(conn, &sfe_connections, list) {
903 p_sic = conn->sic;
904 DEBUG_TRACE(" -> COMPARING: proto: %d src_ip: %d dst_ip: %d, src_port: %d, dst_port: %d...",
905 p_sic->protocol, p_sic->src_ip, p_sic->dest_ip,
906 p_sic->src_port, p_sic->dest_port);
907
908 if (p_sic->protocol == sid.protocol &&
909 p_sic->src_port == sid.src_port &&
910 p_sic->dest_port == sid.dest_port &&
911 p_sic->src_ip == sid.src_ip &&
912 p_sic->dest_ip == sid.dest_ip ) {
Matthew McClintocke4f9a672014-01-06 17:04:04 -0600913 fc_msg.proto = p_sic->protocol;
914 fc_msg.src_saddr = p_sic->src_ip;
915 fc_msg.dst_saddr = p_sic->dest_ip;
916 fc_msg.sport = p_sic->src_port;
917 fc_msg.dport = p_sic->dest_port;
Matthew McClintockd180a7d2014-01-17 11:21:35 -0600918 memcpy(fc_msg.smac, conn->smac, ETH_ALEN);
919 memcpy(fc_msg.dmac, conn->dmac, ETH_ALEN);
Matthew McClintockea00adf2013-11-25 19:24:30 -0600920 sfe_found_match = 1;
Matthew McClintock5f1b1d42014-01-17 14:43:00 -0600921 offloaded = conn->offloaded;
Matthew McClintockea00adf2013-11-25 19:24:30 -0600922 DEBUG_TRACE("FOUND, DELETING\n");
923 break;
Matthew McClintockea00adf2013-11-25 19:24:30 -0600924 }
Matthew McClintocke4f9a672014-01-06 17:04:04 -0600925 DEBUG_TRACE("SEARCH CONTINUES\n");
Matthew McClintockea00adf2013-11-25 19:24:30 -0600926 sfe_connections_size++;
927 }
928
929 if (sfe_found_match) {
930 DEBUG_TRACE("INFO: connection over proto: %d src_ip: %d dst_ip: %d, src_port: %d, dst_port: %d\n",
931 p_sic->protocol, p_sic->src_ip, p_sic->dest_ip,
932 p_sic->src_port, p_sic->dest_port);
933 kfree(conn->sic);
934 list_del(&(conn->list));
935 kfree(conn);
936 } else {
937 DEBUG_TRACE("NO MATCH FOUND IN %d ENTRIES!!\n", sfe_connections_size);
938 }
939 spin_unlock_irqrestore(&sfe_connections_lock, flags);
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600940
941 sfe_ipv4_destroy_rule(&sid);
Matthew McClintocke4f9a672014-01-06 17:04:04 -0600942
Matthew McClintock5f1b1d42014-01-17 14:43:00 -0600943 if (sfe_found_match && offloaded) {
Matthew McClintocke4f9a672014-01-06 17:04:04 -0600944 fast_classifier_send_genl_msg(FAST_CLASSIFIER_C_DONE, &fc_msg);
945 }
946
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600947 return NOTIFY_DONE;
948}
949
950/*
951 * Netfilter conntrack event system to monitor connection tracking changes
952 */
Matthew McClintock0680e9f2013-11-26 15:43:10 -0600953#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
954static struct notifier_block fast_classifier_conntrack_notifier = {
955 .notifier_call = fast_classifier_conntrack_event,
956};
957#else
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600958static struct nf_ct_event_notifier fast_classifier_conntrack_notifier = {
959 .fcn = fast_classifier_conntrack_event,
960};
961#endif
Matthew McClintock0680e9f2013-11-26 15:43:10 -0600962#endif
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600963
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600964/*
965 * Structure to establish a hook into the post routing netfilter point - this
966 * will pick up local outbound and packets going from one interface to another.
967 *
968 * Note: see include/linux/netfilter_ipv4.h for info related to priority levels.
969 * We want to examine packets after NAT translation and any ALG processing.
970 */
971static struct nf_hook_ops fast_classifier_ipv4_ops_post_routing[] __read_mostly = {
972 {
973 .hook = fast_classifier_ipv4_post_routing_hook,
974 .owner = THIS_MODULE,
975 .pf = PF_INET,
976 .hooknum = NF_INET_POST_ROUTING,
977 .priority = NF_IP_PRI_NAT_SRC + 1,
978 },
979};
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600980
981/*
982 * fast_classifier_sync_rule()
983 * Synchronize a connection's state.
984 */
985static void fast_classifier_sync_rule(struct sfe_ipv4_sync *sis)
986{
987 struct nf_conntrack_tuple_hash *h;
988 struct nf_conntrack_tuple tuple;
989 struct nf_conn *ct;
990 struct nf_conn_counter *acct;
991
992 /*
993 * Create a tuple so as to be able to look up a connection
994 */
995 memset(&tuple, 0, sizeof(tuple));
996 tuple.src.u3.ip = sis->src_ip;
997 tuple.src.u.all = (__be16)sis->src_port;
998 tuple.src.l3num = AF_INET;
999
1000 tuple.dst.u3.ip = sis->dest_ip;
1001 tuple.dst.dir = IP_CT_DIR_ORIGINAL;
1002 tuple.dst.protonum = (uint8_t)sis->protocol;
1003 tuple.dst.u.all = (__be16)sis->dest_port;
1004
1005 DEBUG_TRACE("update connection - p: %d, s: %pI4:%u, d: %pI4:%u\n",
1006 (int)tuple.dst.protonum,
1007 &tuple.src.u3.ip, (unsigned int)ntohs(tuple.src.u.all),
1008 &tuple.dst.u3.ip, (unsigned int)ntohs(tuple.dst.u.all));
1009
1010 /*
1011 * Look up conntrack connection
1012 */
1013 h = nf_conntrack_find_get(&init_net, NF_CT_DEFAULT_ZONE, &tuple);
1014 if (unlikely(!h)) {
1015 DEBUG_TRACE("no connection found\n");
1016 return;
1017 }
1018
1019 ct = nf_ct_tuplehash_to_ctrack(h);
1020 NF_CT_ASSERT(ct->timeout.data == (unsigned long)ct);
1021
1022 /*
1023 * Only update if this is not a fixed timeout
1024 */
1025 if (!test_bit(IPS_FIXED_TIMEOUT_BIT, &ct->status)) {
1026 ct->timeout.expires += sis->delta_jiffies;
1027 }
1028
1029 acct = nf_conn_acct_find(ct);
1030 if (acct) {
1031 spin_lock_bh(&ct->lock);
Matthew McClintock704b7a62013-12-19 16:13:01 -06001032 atomic64_set(&acct[IP_CT_DIR_ORIGINAL].packets, sis->src_packet_count);
1033 atomic64_set(&acct[IP_CT_DIR_ORIGINAL].bytes, sis->src_byte_count);
1034 atomic64_set(&acct[IP_CT_DIR_REPLY].packets, sis->dest_packet_count);
1035 atomic64_set(&acct[IP_CT_DIR_REPLY].bytes, sis->dest_byte_count);
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001036 spin_unlock_bh(&ct->lock);
1037 }
1038
1039 switch (sis->protocol) {
1040 case IPPROTO_TCP:
1041 spin_lock_bh(&ct->lock);
1042 if (ct->proto.tcp.seen[0].td_maxwin < sis->src_td_max_window) {
1043 ct->proto.tcp.seen[0].td_maxwin = sis->src_td_max_window;
1044 }
1045 if ((int32_t)(ct->proto.tcp.seen[0].td_end - sis->src_td_end) < 0) {
1046 ct->proto.tcp.seen[0].td_end = sis->src_td_end;
1047 }
1048 if ((int32_t)(ct->proto.tcp.seen[0].td_maxend - sis->src_td_max_end) < 0) {
1049 ct->proto.tcp.seen[0].td_maxend = sis->src_td_max_end;
1050 }
1051 if (ct->proto.tcp.seen[1].td_maxwin < sis->dest_td_max_window) {
1052 ct->proto.tcp.seen[1].td_maxwin = sis->dest_td_max_window;
1053 }
1054 if ((int32_t)(ct->proto.tcp.seen[1].td_end - sis->dest_td_end) < 0) {
1055 ct->proto.tcp.seen[1].td_end = sis->dest_td_end;
1056 }
1057 if ((int32_t)(ct->proto.tcp.seen[1].td_maxend - sis->dest_td_max_end) < 0) {
1058 ct->proto.tcp.seen[1].td_maxend = sis->dest_td_max_end;
1059 }
1060 spin_unlock_bh(&ct->lock);
1061 break;
1062 }
1063
1064 /*
1065 * Release connection
1066 */
1067 nf_ct_put(ct);
1068}
1069
1070/*
1071 * fast_classifier_device_event()
1072 */
1073static int fast_classifier_device_event(struct notifier_block *this, unsigned long event, void *ptr)
1074{
1075 struct net_device *dev = (struct net_device *)ptr;
1076
1077 switch (event) {
1078 case NETDEV_DOWN:
1079 if (dev) {
1080 sfe_ipv4_destroy_all_rules_for_dev(dev);
1081 }
1082 break;
1083 }
1084
1085 return NOTIFY_DONE;
1086}
1087
1088/*
1089 * fast_classifier_inet_event()
1090 */
1091static int fast_classifier_inet_event(struct notifier_block *this, unsigned long event, void *ptr)
1092{
1093 struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev;
1094 return fast_classifier_device_event(this, event, dev);
1095}
1096
1097/*
Matthew McClintock595ee8b2013-12-02 16:21:49 -06001098 * fast_classifier_get_offload_at_pkts()
1099 */
1100static ssize_t fast_classifier_get_offload_at_pkts(struct device *dev,
1101 struct device_attribute *attr,
1102 char *buf)
1103{
1104 return sprintf(buf, "%d\n", offload_at_pkts);
1105}
1106
1107/*
1108 * fast_classifier_set_offload_at_pkts()
1109 */
1110static ssize_t fast_classifier_set_offload_at_pkts(struct device *dev,
1111 struct device_attribute *attr,
1112 char *buf, size_t size)
1113{
Matthew McClintock8f4fcd22014-01-14 21:06:03 -06001114 long new;
1115 int ret;
Matthew McClintock595ee8b2013-12-02 16:21:49 -06001116
Matthew McClintock8f4fcd22014-01-14 21:06:03 -06001117 printk(KERN_EMERG "BUF: %s\n", buf);
1118 ret = strict_strtol(buf, 0, &new);
1119 if (ret == -EINVAL || ((int)new != new))
Matthew McClintock595ee8b2013-12-02 16:21:49 -06001120 return -EINVAL;
1121
1122 offload_at_pkts = new;
1123
1124 return size;
1125}
1126
1127/*
1128 * sysfs attributes.
1129 */
1130static const struct device_attribute fast_classifier_offload_at_pkts_attr =
1131 __ATTR(offload_at_pkts, S_IWUGO | S_IRUGO, fast_classifier_get_offload_at_pkts, fast_classifier_set_offload_at_pkts);
1132
1133/*
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001134 * fast_classifier_init()
1135 */
1136static int __init fast_classifier_init(void)
1137{
1138 struct fast_classifier *sc = &__sc;
1139 int result = -1;
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -06001140
1141 printk(KERN_ALERT "fast-classifier: starting up\n");
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001142 DEBUG_INFO("SFE CM init\n");
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -06001143
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001144 /*
1145 * Create sys/fast_classifier
1146 */
1147 sc->sys_fast_classifier = kobject_create_and_add("fast_classifier", NULL);
1148 if (!sc->sys_fast_classifier) {
1149 DEBUG_ERROR("failed to register fast_classifier\n");
1150 goto exit1;
1151 }
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -06001152
Matthew McClintock595ee8b2013-12-02 16:21:49 -06001153 result = sysfs_create_file(sc->sys_fast_classifier, &fast_classifier_offload_at_pkts_attr.attr);
1154 if (result) {
1155 DEBUG_ERROR("failed to register debug dev file: %d\n", result);
1156 goto exit2;
1157 }
1158
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001159 sc->dev_notifier.notifier_call = fast_classifier_device_event;
1160 sc->dev_notifier.priority = 1;
1161 register_netdevice_notifier(&sc->dev_notifier);
1162
1163 sc->inet_notifier.notifier_call = fast_classifier_inet_event;
1164 sc->inet_notifier.priority = 1;
1165 register_inetaddr_notifier(&sc->inet_notifier);
1166
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001167 /*
1168 * Register our netfilter hooks.
1169 */
1170 result = nf_register_hooks(fast_classifier_ipv4_ops_post_routing, ARRAY_SIZE(fast_classifier_ipv4_ops_post_routing));
1171 if (result < 0) {
1172 DEBUG_ERROR("can't register nf post routing hook: %d\n", result);
Matthew McClintock595ee8b2013-12-02 16:21:49 -06001173 goto exit3;
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001174 }
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001175
1176#ifdef CONFIG_NF_CONNTRACK_EVENTS
1177 /*
1178 * Register a notifier hook to get fast notifications of expired connections.
1179 */
1180 result = nf_conntrack_register_notifier(&init_net, &fast_classifier_conntrack_notifier);
1181 if (result < 0) {
1182 DEBUG_ERROR("can't register nf notifier hook: %d\n", result);
Matthew McClintock595ee8b2013-12-02 16:21:49 -06001183 goto exit4;
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001184 }
1185#endif
1186
Dave Hudsonfd7fd072013-12-07 22:34:18 +00001187 result = genl_register_family(&fast_classifier_gnl_family);
Matthew McClintocke4f9a672014-01-06 17:04:04 -06001188 if (result != 0) {
1189 printk(KERN_CRIT "unable to register genl family\n");
Dave Hudsonfd7fd072013-12-07 22:34:18 +00001190 goto exit5;
1191 }
1192
Matthew McClintocke4f9a672014-01-06 17:04:04 -06001193 result = genl_register_ops(&fast_classifier_gnl_family, fast_classifier_gnl_ops);
Dave Hudsonfd7fd072013-12-07 22:34:18 +00001194 if (result != 0) {
Matthew McClintocke4f9a672014-01-06 17:04:04 -06001195 printk(KERN_CRIT "unable to register ops\n");
1196 goto exit6;
1197 }
1198
1199 result = genl_register_mc_group(&fast_classifier_gnl_family,
1200 &fast_classifier_genl_mcgrp);
1201 if (result != 0) {
1202 printk(KERN_CRIT "unable to register multicast group\n");
Dave Hudsonfd7fd072013-12-07 22:34:18 +00001203 goto exit6;
1204 }
1205
1206 printk(KERN_ALERT "fast-classifier: registered\n");
1207
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001208 spin_lock_init(&sc->lock);
1209
1210 /*
1211 * Hook the receive path in the network stack.
1212 */
1213 BUG_ON(athrs_fast_nat_recv != NULL);
1214 RCU_INIT_POINTER(athrs_fast_nat_recv, fast_classifier_recv);
1215
1216 /*
1217 * Hook the shortcut sync callback.
1218 */
1219 sfe_ipv4_register_sync_rule_callback(fast_classifier_sync_rule);
1220
Matthew McClintock6f29aa12013-11-06 15:49:01 -06001221 return 0;
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -06001222
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001223exit6:
Matthew McClintock595ee8b2013-12-02 16:21:49 -06001224 genl_unregister_family(&fast_classifier_gnl_family);
1225
1226exit5:
1227#ifdef CONFIG_NF_CONNTRACK_EVENTS
Dave Hudsonfd7fd072013-12-07 22:34:18 +00001228 nf_conntrack_unregister_notifier(&init_net, &fast_classifier_conntrack_notifier);
Matthew McClintock595ee8b2013-12-02 16:21:49 -06001229#endif
1230
1231exit4:
Dave Hudsonfd7fd072013-12-07 22:34:18 +00001232 nf_unregister_hooks(fast_classifier_ipv4_ops_post_routing, ARRAY_SIZE(fast_classifier_ipv4_ops_post_routing));
Matthew McClintock595ee8b2013-12-02 16:21:49 -06001233
1234exit3:
Dave Hudsonfd7fd072013-12-07 22:34:18 +00001235 unregister_inetaddr_notifier(&sc->inet_notifier);
1236 unregister_netdevice_notifier(&sc->dev_notifier);
Matthew McClintock595ee8b2013-12-02 16:21:49 -06001237 sysfs_remove_file(sc->sys_fast_classifier, &fast_classifier_offload_at_pkts_attr.attr);
1238
1239exit2:
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001240 kobject_put(sc->sys_fast_classifier);
1241
1242exit1:
1243 return result;
Matthew McClintock6f29aa12013-11-06 15:49:01 -06001244}
1245
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001246/*
1247 * fast_classifier_exit()
1248 */
1249static void __exit fast_classifier_exit(void)
Matthew McClintock6f29aa12013-11-06 15:49:01 -06001250{
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001251 struct fast_classifier *sc = &__sc;
1252 int result = -1;
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -06001253
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001254 DEBUG_INFO("SFE CM exit\n");
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -06001255 printk(KERN_ALERT "fast-classifier: shutting down\n");
1256
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001257 /*
1258 * Unregister our sync callback.
1259 */
1260 sfe_ipv4_register_sync_rule_callback(NULL);
1261
1262 /*
1263 * Unregister our receive callback.
1264 */
1265 RCU_INIT_POINTER(athrs_fast_nat_recv, NULL);
1266
1267 /*
1268 * Wait for all callbacks to complete.
1269 */
1270 rcu_barrier();
1271
1272 /*
1273 * Destroy all connections.
1274 */
1275 sfe_ipv4_destroy_all_rules_for_dev(NULL);
1276
Matthew McClintocke4f9a672014-01-06 17:04:04 -06001277 result = genl_unregister_ops(&fast_classifier_gnl_family, fast_classifier_gnl_ops);
Dave Hudsonfd7fd072013-12-07 22:34:18 +00001278 if (result != 0) {
1279 printk(KERN_CRIT "Unable to unreigster genl_ops\n");
1280 }
1281
1282 result = genl_unregister_family(&fast_classifier_gnl_family);
1283 if (result != 0) {
1284 printk(KERN_CRIT "Unable to unreigster genl_family\n");
1285 }
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001286
1287#ifdef CONFIG_NF_CONNTRACK_EVENTS
1288 nf_conntrack_unregister_notifier(&init_net, &fast_classifier_conntrack_notifier);
1289
1290#endif
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001291 nf_unregister_hooks(fast_classifier_ipv4_ops_post_routing, ARRAY_SIZE(fast_classifier_ipv4_ops_post_routing));
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001292
1293 unregister_inetaddr_notifier(&sc->inet_notifier);
1294 unregister_netdevice_notifier(&sc->dev_notifier);
1295
1296 kobject_put(sc->sys_fast_classifier);
Matthew McClintock6f29aa12013-11-06 15:49:01 -06001297}
1298
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001299module_init(fast_classifier_init)
1300module_exit(fast_classifier_exit)
1301
1302MODULE_AUTHOR("Qualcomm Atheros Inc.");
1303MODULE_DESCRIPTION("Shortcut Forwarding Engine - Connection Manager");
Matthew McClintocka3221942014-01-16 11:44:26 -06001304MODULE_LICENSE("Dual BSD/GPL");
Matthew McClintock6f29aa12013-11-06 15:49:01 -06001305