blob: 28bcf094edfd313bfbf64836322bebd48fb8a37d [file] [log] [blame]
Matthew McClintock6f29aa12013-11-06 15:49:01 -06001/*
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06002 * fast-classifier.c
3 * Shortcut forwarding engine connection manager.
4 * fast-classifier style
5 *
6 * XXX - fill in the appropriate GPL notice.
Matthew McClintock6f29aa12013-11-06 15:49:01 -06007 */
Matthew McClintock6f29aa12013-11-06 15:49:01 -06008#include <linux/module.h>
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06009#include <linux/sysfs.h>
10#include <linux/skbuff.h>
11#include <net/route.h>
12#include <linux/inetdevice.h>
13#include <linux/netfilter_bridge.h>
14#include <net/netfilter/nf_conntrack_acct.h>
15#include <net/netfilter/nf_conntrack_helper.h>
16#include <net/netfilter/nf_conntrack_zones.h>
17#include <net/netfilter/nf_conntrack_core.h>
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -060018#include <net/genetlink.h>
Matthew McClintockea00adf2013-11-25 19:24:30 -060019#include <linux/list.h>
20#include <linux/spinlock.h>
Ben Menchaca0971b7a2014-01-10 14:43:02 -060021#include <linux/ratelimit.h>
22#include <linux/if_pppox.h>
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -060023
Matthew McClintocke1bcfe42013-11-22 15:33:09 -060024#include "../shortcut-fe/sfe.h"
25#include "../shortcut-fe/sfe_ipv4.h"
Matthew McClintock3abf38e2014-01-07 17:37:56 -060026#include "fast-classifier.h"
Matthew McClintocke1bcfe42013-11-22 15:33:09 -060027
28/*
29 * Per-module structure.
30 */
31struct fast_classifier {
32 spinlock_t lock; /* Lock for SMP correctness */
33
34 /*
35 * Control state.
36 */
37 struct kobject *sys_fast_classifier; /* sysfs linkage */
38
39 /*
40 * Callback notifiers.
41 */
42 struct notifier_block dev_notifier;
43 /* Device notifier */
44 struct notifier_block inet_notifier;
45 /* IP notifier */
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -060046};
Matthew McClintocke1bcfe42013-11-22 15:33:09 -060047
48struct fast_classifier __sc;
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -060049
50static struct nla_policy fast_classifier_genl_policy[FAST_CLASSIFIER_A_MAX + 1] = {
Matthew McClintocke4f9a672014-01-06 17:04:04 -060051 [FAST_CLASSIFIER_A_TUPLE] = { .type = NLA_UNSPEC,
52 .len = sizeof(struct fast_classifier_tuple)
53 },
54};
55
56static struct genl_multicast_group fast_classifier_genl_mcgrp = {
57 .name = FAST_CLASSIFIER_GENL_MCGRP,
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -060058};
59
60static struct genl_family fast_classifier_gnl_family = {
61 .id = GENL_ID_GENERATE,
Matthew McClintock28d75572014-01-03 11:54:08 -060062 .hdrsize = FAST_CLASSIFIER_GENL_HDRSIZE,
63 .name = FAST_CLASSIFIER_GENL_NAME,
64 .version = FAST_CLASSIFIER_GENL_VERSION,
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -060065 .maxattr = FAST_CLASSIFIER_A_MAX,
66};
67
Matthew McClintocke4f9a672014-01-06 17:04:04 -060068static int fast_classifier_offload_genl_msg(struct sk_buff *skb, struct genl_info *info);
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -060069
Matthew McClintocke4f9a672014-01-06 17:04:04 -060070static struct genl_ops fast_classifier_gnl_ops[] = {
71 {
72 .cmd = FAST_CLASSIFIER_C_OFFLOAD,
73 .flags = 0,
74 .policy = fast_classifier_genl_policy,
75 .doit = fast_classifier_offload_genl_msg,
76 .dumpit = NULL,
77 },
78 {
79 .cmd = FAST_CLASSIFIER_C_OFFLOADED,
80 .flags = 0,
81 .policy = fast_classifier_genl_policy,
82 .doit = NULL,
83 .dumpit = NULL,
84 },
85 {
86 .cmd = FAST_CLASSIFIER_C_DONE,
87 .flags = 0,
88 .policy = fast_classifier_genl_policy,
89 .doit = NULL,
90 .dumpit = NULL,
91 },
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -060092};
93
Matthew McClintocke1bcfe42013-11-22 15:33:09 -060094/*
95 * Expose the hook for the receive processing.
96 */
97extern int (*athrs_fast_nat_recv)(struct sk_buff *skb);
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -060098
Matthew McClintocke1bcfe42013-11-22 15:33:09 -060099/*
100 * Expose what should be a static flag in the TCP connection tracker.
101 */
102extern int nf_ct_tcp_no_window_check;
103
104/*
105 * fast_classifier_recv()
106 * Handle packet receives.
107 *
108 * Returns 1 if the packet is forwarded or 0 if it isn't.
109 */
110int fast_classifier_recv(struct sk_buff *skb)
111{
112 struct net_device *dev;
113#if (SFE_HOOK_ABOVE_BRIDGE)
114 struct in_device *in_dev;
115#endif
116
117 /*
118 * We know that for the vast majority of packets we need the transport
119 * layer header so we may as well start to fetch it now!
120 */
121 prefetch(skb->data + 32);
122 barrier();
123
124 dev = skb->dev;
125
Ben Menchaca0971b7a2014-01-10 14:43:02 -0600126 /*
127 * And PPPoE packets
128 */
129 if (htons(ETH_P_PPP_SES) == skb->protocol) {
130 return sfe_pppoe_recv(dev, skb);
131 }
132
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600133#if (SFE_HOOK_ABOVE_BRIDGE)
134 /*
135 * Does our input device support IP processing?
136 */
137 in_dev = (struct in_device *)dev->ip_ptr;
138 if (unlikely(!in_dev)) {
139 DEBUG_TRACE("no IP processing for device: %s\n", dev->name);
140 return 0;
141 }
142
143 /*
144 * Does it have an IP address? If it doesn't then we can't do anything
145 * interesting here!
146 */
147 if (unlikely(!in_dev->ifa_list)) {
148 DEBUG_TRACE("no IP address for device: %s\n", dev->name);
149 return 0;
150 }
151#endif
152
153 /*
154 * We're only interested in IP packets.
Nicolas Costaac2979c2014-01-14 10:35:24 -0600155 */
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600156 if (likely(htons(ETH_P_IP) == skb->protocol)) {
157 return sfe_ipv4_recv(dev, skb);
158 }
159
Ben Menchaca0971b7a2014-01-10 14:43:02 -0600160 DEBUG_TRACE("not IP or PPPoE packet\n");
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -0600161 return 0;
162}
Matthew McClintock6f29aa12013-11-06 15:49:01 -0600163
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600164/*
165 * fast_classifier_find_mac_addr()
166 * Find the MAC address for a given IPv4 address.
167 *
168 * Returns true if we find the MAC address, otherwise false.
169 *
170 * We look up the rtable entry for the address and, from its neighbour
171 * structure, obtain the hardware address. This means this function also
172 * works if the neighbours are routers too.
173 */
174static bool fast_classifier_find_mac_addr(uint32_t addr, uint8_t *mac_addr)
Matthew McClintock6f29aa12013-11-06 15:49:01 -0600175{
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600176 struct neighbour *neigh;
177 struct rtable *rt;
178 struct dst_entry *dst;
179 struct net_device *dev;
180
181 /*
182 * Look up the rtable entry for the IP address then get the hardware
183 * address from its neighbour structure. This means this work when the
184 * neighbours are routers too.
185 */
186 rt = ip_route_output(&init_net, addr, 0, 0, 0);
187 if (unlikely(IS_ERR(rt))) {
188 return false;
189 }
190
191 dst = (struct dst_entry *)rt;
192
193 rcu_read_lock();
194 neigh = dst_get_neighbour_noref(dst);
195 if (unlikely(!neigh)) {
196 rcu_read_unlock();
197 dst_release(dst);
Nicolas Costaac2979c2014-01-14 10:35:24 -0600198 return false;
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600199 }
200
201 if (unlikely(!(neigh->nud_state & NUD_VALID))) {
202 rcu_read_unlock();
203 dst_release(dst);
204 return false;
205 }
206
207 dev = neigh->dev;
208 if (!dev) {
209 rcu_read_unlock();
210 dst_release(dst);
211 return false;
212 }
213
214 memcpy(mac_addr, neigh->ha, (size_t)dev->addr_len);
215 rcu_read_unlock();
216
217 dst_release(dst);
218
219 /*
220 * We're only interested in unicast MAC addresses - if it's not a unicast
221 * address then our IP address mustn't be unicast either.
222 */
223 if (is_multicast_ether_addr(mac_addr)) {
224 DEBUG_TRACE("MAC is non-unicast - ignoring\n");
225 return false;
226 }
227
228 return true;
229}
230
Matthew McClintockea00adf2013-11-25 19:24:30 -0600231static DEFINE_SPINLOCK(sfe_connections_lock);
232
233struct sfe_connection {
234 struct list_head list;
235 struct sfe_ipv4_create *sic;
236 struct nf_conn *ct;
Matthew McClintockc5739382013-12-02 14:17:46 -0600237 int hits;
Matthew McClintock55c86982013-12-02 14:24:24 -0600238 int offloaded;
Matthew McClintockcf157352014-01-10 16:35:40 -0600239 unsigned char mac[ETH_ALEN];
Matthew McClintockea00adf2013-11-25 19:24:30 -0600240};
241
242static LIST_HEAD(sfe_connections);
243
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600244/*
Matthew McClintockc5739382013-12-02 14:17:46 -0600245 * fast_classifier_update_protocol()
246 * Update sfe_ipv4_create struct with new protocol information before we offload
247 */
248static int fast_classifier_update_protocol(struct sfe_ipv4_create *p_sic, struct nf_conn *ct)
249{
250 switch (p_sic->protocol) {
251 case IPPROTO_TCP:
252 p_sic->src_td_window_scale = ct->proto.tcp.seen[0].td_scale;
253 p_sic->src_td_max_window = ct->proto.tcp.seen[0].td_maxwin;
254 p_sic->src_td_end = ct->proto.tcp.seen[0].td_end;
255 p_sic->src_td_max_end = ct->proto.tcp.seen[0].td_maxend;
256 p_sic->dest_td_window_scale = ct->proto.tcp.seen[1].td_scale;
257 p_sic->dest_td_max_window = ct->proto.tcp.seen[1].td_maxwin;
258 p_sic->dest_td_end = ct->proto.tcp.seen[1].td_end;
259 p_sic->dest_td_max_end = ct->proto.tcp.seen[1].td_maxend;
260 if (nf_ct_tcp_no_window_check
261 || (ct->proto.tcp.seen[0].flags & IP_CT_TCP_FLAG_BE_LIBERAL)
262 || (ct->proto.tcp.seen[1].flags & IP_CT_TCP_FLAG_BE_LIBERAL)) {
263 p_sic->flags |= SFE_IPV4_CREATE_FLAG_NO_SEQ_CHECK;
264 }
265
266 /*
267 * If the connection is shutting down do not manage it.
268 * state can not be SYN_SENT, SYN_RECV because connection is assured
269 * Not managed states: FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE.
270 */
271 spin_lock(&ct->lock);
272 if (ct->proto.tcp.state != TCP_CONNTRACK_ESTABLISHED) {
273 spin_unlock(&ct->lock);
274 DEBUG_TRACE("connection in termination state: %#x, s: %pI4:%u, d: %pI4:%u\n",
275 ct->proto.tcp.state, &p_sic->src_ip, ntohs(p_sic->src_port),
276 &p_sic->dest_ip, ntohs(p_sic->dest_port));
277 return 0;
278 }
279 spin_unlock(&ct->lock);
280 break;
281
282 case IPPROTO_UDP:
283 break;
284
285 default:
286 DEBUG_TRACE("unhandled protocol %d\n", p_sic->protocol);
287 return 0;
288 }
289
290 return 1;
291}
292
Matthew McClintocke4f9a672014-01-06 17:04:04 -0600293/* fast_classifier_send_genl_msg()
294 * Function to send a generic netlink message
295 */
296static void fast_classifier_send_genl_msg(int msg, struct fast_classifier_tuple *fc_msg) {
297 struct sk_buff *skb;
298 int rc;
299 void *msg_head;
300
301 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC);
302 if (skb == NULL)
303 return;
304
305 msg_head = genlmsg_put(skb, 0, 0, &fast_classifier_gnl_family, 0, msg);
306 if (msg_head == NULL) {
307 nlmsg_free(skb);
308 return;
309 }
310
311 rc = nla_put(skb, FAST_CLASSIFIER_A_TUPLE, sizeof(struct fast_classifier_tuple), fc_msg);
312 if (rc != 0) {
313 genlmsg_cancel(skb, msg_head);
314 nlmsg_free(skb);
315 return;
316 }
317
318 rc = genlmsg_end(skb, msg_head);
319 if (rc < 0) {
320 genlmsg_cancel(skb, msg_head);
321 nlmsg_free(skb);
322 return;
323 }
324 genlmsg_multicast(skb, 0, fast_classifier_genl_mcgrp.id, GFP_ATOMIC);
325
Matthew McClintockcf157352014-01-10 16:35:40 -0600326 DEBUG_TRACE("INFO: %d : %d, %pI4, %pI4, %d, %d MAC=%pM\n",
327 msg, fc_msg->proto,
328 &(fc_msg->src_saddr),
329 &(fc_msg->dst_saddr),
330 fc_msg->sport, fc_msg->dport,
331 fc_msg->mac);
Matthew McClintocke4f9a672014-01-06 17:04:04 -0600332}
333
Matthew McClintockc5739382013-12-02 14:17:46 -0600334/*
Matthew McClintocke4f9a672014-01-06 17:04:04 -0600335 * fast_classifier_offload_genl_msg()
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600336 * Called from user space to offload a connection
337 */
Matthew McClintocke4f9a672014-01-06 17:04:04 -0600338static int fast_classifier_offload_genl_msg(struct sk_buff *skb, struct genl_info *info)
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600339{
Nicolas Costa514fde02014-01-13 15:50:29 -0600340 int ret;
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600341 struct nlattr *na;
Matthew McClintock28d75572014-01-03 11:54:08 -0600342 struct fast_classifier_tuple *fc_msg;
Matthew McClintockea00adf2013-11-25 19:24:30 -0600343 struct sfe_ipv4_create *p_sic;
344 struct sfe_connection *conn;
345 unsigned long flags;
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600346
Matthew McClintockd2854b72014-01-10 18:01:58 -0600347 na = info->attrs[FAST_CLASSIFIER_A_TUPLE];
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600348 fc_msg = nla_data(na);
Matthew McClintockea00adf2013-11-25 19:24:30 -0600349
Matthew McClintockcf157352014-01-10 16:35:40 -0600350 DEBUG_TRACE("INFO: want to offload: %d, %pI4, %pI4, %d, %d MAC=%pM\n",
351 fc_msg->proto,
352 &(fc_msg->src_saddr),
353 &(fc_msg->dst_saddr),
354 fc_msg->sport, fc_msg->dport,
355 fc_msg->mac);
Matthew McClintocke4f9a672014-01-06 17:04:04 -0600356
Matthew McClintockea00adf2013-11-25 19:24:30 -0600357 spin_lock_irqsave(&sfe_connections_lock, flags);
358 list_for_each_entry(conn, &sfe_connections, list) {
Matthew McClintockea00adf2013-11-25 19:24:30 -0600359 p_sic = conn->sic;
360
361 DEBUG_TRACE(" -> COMPARING: proto: %d src_ip: %d dst_ip: %d, src_port: %d, dst_port: %d...",
362 p_sic->protocol, p_sic->src_ip, p_sic->dest_ip,
363 p_sic->src_port, p_sic->dest_port);
364
365 if (p_sic->protocol == fc_msg->proto &&
366 p_sic->src_port == fc_msg->sport &&
367 p_sic->dest_port == fc_msg->dport &&
368 p_sic->src_ip == fc_msg->src_saddr &&
369 p_sic->dest_ip == fc_msg->dst_saddr ) {
Matthew McClintock55c86982013-12-02 14:24:24 -0600370 if (conn->offloaded == 0) {
371 DEBUG_TRACE("USERSPACE OFFLOAD REQUEST, MATCH FOUND, WILL OFFLOAD\n");
372 if (fast_classifier_update_protocol(p_sic, conn->ct) == 0) {
373 spin_unlock_irqrestore(&sfe_connections_lock, flags);
374 DEBUG_TRACE("UNKNOWN PROTOCOL OR CONNECTION CLOSING, SKIPPING\n");
375 return 0;
376 }
377 DEBUG_TRACE("INFO: calling sfe rule creation!\n");
Matthew McClintockc5739382013-12-02 14:17:46 -0600378 spin_unlock_irqrestore(&sfe_connections_lock, flags);
Nicolas Costa514fde02014-01-13 15:50:29 -0600379 ret = sfe_ipv4_create_rule(p_sic);
380 if ((ret == 0) || (ret == -EADDRINUSE)) {
381 conn->offloaded = 1;
382 fast_classifier_send_genl_msg(FAST_CLASSIFIER_C_OFFLOADED, fc_msg);
383 }
Matthew McClintockc5739382013-12-02 14:17:46 -0600384 return 0;
Matthew McClintockea00adf2013-11-25 19:24:30 -0600385 }
Matthew McClintocke4f9a672014-01-06 17:04:04 -0600386 /* conn->offloaded != 0 */
Matthew McClintock55c86982013-12-02 14:24:24 -0600387 DEBUG_TRACE("GOT REQUEST TO OFFLOAD ALREADY OFFLOADED CONN FROM USERSPACE\n");
Matthew McClintocke4f9a672014-01-06 17:04:04 -0600388 spin_unlock_irqrestore(&sfe_connections_lock, flags);
389 return 0;
Matthew McClintockea00adf2013-11-25 19:24:30 -0600390 }
391 DEBUG_TRACE("SEARCH CONTINUES\n");
392 }
393
394 spin_unlock_irqrestore(&sfe_connections_lock, flags);
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600395 return 0;
396}
397
Matthew McClintock595ee8b2013-12-02 16:21:49 -0600398/* auto offload connection once we have this many packets*/
399static int offload_at_pkts = 128;
400
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600401/*
402 * fast_classifier_ipv4_post_routing_hook()
403 * Called for packets about to leave the box - either locally generated or forwarded from another interface
404 */
405static unsigned int fast_classifier_ipv4_post_routing_hook(unsigned int hooknum,
406 struct sk_buff *skb,
407 const struct net_device *in_unused,
408 const struct net_device *out,
409 int (*okfn)(struct sk_buff *))
410{
Nicolas Costa514fde02014-01-13 15:50:29 -0600411 int ret;
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600412 struct sfe_ipv4_create sic;
Matthew McClintockea00adf2013-11-25 19:24:30 -0600413 struct sfe_ipv4_create *p_sic;
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600414 struct net_device *in;
415 struct nf_conn *ct;
416 enum ip_conntrack_info ctinfo;
417 struct net_device *src_dev;
418 struct net_device *dest_dev;
419 struct net_device *src_br_dev = NULL;
420 struct net_device *dest_br_dev = NULL;
421 struct nf_conntrack_tuple orig_tuple;
422 struct nf_conntrack_tuple reply_tuple;
Matthew McClintockea00adf2013-11-25 19:24:30 -0600423 struct sfe_connection *conn;
424 int sfe_connections_size = 0;
425 unsigned long flags;
Matthew McClintockcf157352014-01-10 16:35:40 -0600426 struct ethhdr *mh = eth_hdr(skb);
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600427
428 /*
429 * Don't process broadcast or multicast packets.
430 */
431 if (unlikely(skb->pkt_type == PACKET_BROADCAST)) {
432 DEBUG_TRACE("broadcast, ignoring\n");
433 return NF_ACCEPT;
434 }
435 if (unlikely(skb->pkt_type == PACKET_MULTICAST)) {
436 DEBUG_TRACE("multicast, ignoring\n");
437 return NF_ACCEPT;
438 }
439
440 /*
441 * Don't process packets that are not being forwarded.
442 */
443 in = dev_get_by_index(&init_net, skb->skb_iif);
444 if (!in) {
445 DEBUG_TRACE("packet not forwarding\n");
446 return NF_ACCEPT;
447 }
448
449 /*
450 * Don't process packets with non-standard 802.3 MAC address sizes.
451 */
452 if (unlikely(in->addr_len != ETH_ALEN)) {
453 DEBUG_TRACE("in device: %s not 802.3 hw addr len: %u, ignoring\n",
454 in->name, (unsigned)in->addr_len);
455 goto done1;
456 }
457 if (unlikely(out->addr_len != ETH_ALEN)) {
458 DEBUG_TRACE("out device: %s not 802.3 hw addr len: %u, ignoring\n",
459 out->name, (unsigned)out->addr_len);
460 goto done1;
461 }
462
463 /*
464 * Don't process packets that aren't being tracked by conntrack.
465 */
466 ct = nf_ct_get(skb, &ctinfo);
467 if (unlikely(!ct)) {
468 DEBUG_TRACE("no conntrack connection, ignoring\n");
469 goto done1;
470 }
471
472 /*
473 * Don't process untracked connections.
474 */
475 if (unlikely(ct == &nf_conntrack_untracked)) {
476 DEBUG_TRACE("untracked connection\n");
477 goto done1;
478 }
479
480 /*
481 * Don't process connections that require support from a 'helper' (typically a NAT ALG).
482 */
483 if (unlikely(nfct_help(ct))) {
484 DEBUG_TRACE("connection has helper\n");
485 goto done1;
486 }
487
488 /*
489 * Look up the details of our connection in conntrack.
490 *
491 * Note that the data we get from conntrack is for the "ORIGINAL" direction
492 * but our packet may actually be in the "REPLY" direction.
493 */
494 orig_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
495 reply_tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
496 sic.protocol = (int32_t)orig_tuple.dst.protonum;
497
498 /*
499 * Get addressing information, non-NAT first
500 */
501 sic.src_ip = (__be32)orig_tuple.src.u3.ip;
502 sic.dest_ip = (__be32)orig_tuple.dst.u3.ip;
503
504 /*
505 * NAT'ed addresses - note these are as seen from the 'reply' direction
506 * When NAT does not apply to this connection these will be identical to the above.
507 */
508 sic.src_ip_xlate = (__be32)reply_tuple.dst.u3.ip;
509 sic.dest_ip_xlate = (__be32)reply_tuple.src.u3.ip;
510
511 sic.flags = 0;
512
513 switch (sic.protocol) {
514 case IPPROTO_TCP:
515 sic.src_port = orig_tuple.src.u.tcp.port;
516 sic.dest_port = orig_tuple.dst.u.tcp.port;
517 sic.src_port_xlate = reply_tuple.dst.u.tcp.port;
518 sic.dest_port_xlate = reply_tuple.src.u.tcp.port;
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600519
520 /*
521 * Don't try to manage a non-established connection.
522 */
523 if (!test_bit(IPS_ASSURED_BIT, &ct->status)) {
524 DEBUG_TRACE("non-established connection\n");
525 goto done1;
526 }
527
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600528 break;
529
530 case IPPROTO_UDP:
531 sic.src_port = orig_tuple.src.u.udp.port;
532 sic.dest_port = orig_tuple.dst.u.udp.port;
533 sic.src_port_xlate = reply_tuple.dst.u.udp.port;
534 sic.dest_port_xlate = reply_tuple.src.u.udp.port;
535 break;
536
537 default:
538 DEBUG_TRACE("unhandled protocol %d\n", sic.protocol);
539 goto done1;
540 }
541
542 /*
Matthew McClintockea00adf2013-11-25 19:24:30 -0600543 * If we already have this connection in our list, skip it
544 * XXX: this may need to be optimized
545 */
546 DEBUG_TRACE("POST_ROUTE: checking new connection: %d src_ip: %d dst_ip: %d, src_port: %d, dst_port: %d\n",
547 sic.protocol, sic.src_ip, sic.dest_ip,
548 sic.src_port, sic.dest_port);
549 spin_lock_irqsave(&sfe_connections_lock, flags);
550 list_for_each_entry(conn, &sfe_connections, list) {
551 p_sic = conn->sic;
552 DEBUG_TRACE("\t\t-> COMPARING: proto: %d src_ip: %d dst_ip: %d, src_port: %d, dst_port: %d...",
553 p_sic->protocol, p_sic->src_ip, p_sic->dest_ip,
554 p_sic->src_port, p_sic->dest_port);
555
556 if (p_sic->protocol == sic.protocol &&
557 p_sic->src_port == sic.src_port &&
558 p_sic->dest_port == sic.dest_port &&
559 p_sic->src_ip == sic.src_ip &&
560 p_sic->dest_ip == sic.dest_ip ) {
Matthew McClintockc5739382013-12-02 14:17:46 -0600561 conn->hits++;
Matthew McClintock55c86982013-12-02 14:24:24 -0600562 if (conn->offloaded == 0) {
Matthew McClintock595ee8b2013-12-02 16:21:49 -0600563 if (conn->hits == offload_at_pkts) {
Nicolas Costa514fde02014-01-13 15:50:29 -0600564 struct fast_classifier_tuple fc_msg;
Matthew McClintock55c86982013-12-02 14:24:24 -0600565 DEBUG_TRACE("OFFLOADING CONNECTION, TOO MANY HITS\n");
566 if (fast_classifier_update_protocol(p_sic, conn->ct) == 0) {
567 spin_unlock_irqrestore(&sfe_connections_lock, flags);
568 DEBUG_TRACE("UNKNOWN PROTOCOL OR CONNECTION CLOSING, SKIPPING\n");
569 return 0;
570 }
571 DEBUG_TRACE("INFO: calling sfe rule creation!\n");
Matthew McClintockc5739382013-12-02 14:17:46 -0600572 spin_unlock_irqrestore(&sfe_connections_lock, flags);
Matthew McClintocke4f9a672014-01-06 17:04:04 -0600573
Nicolas Costa514fde02014-01-13 15:50:29 -0600574 ret = sfe_ipv4_create_rule(p_sic);
575 if ((ret == 0) || (ret == -EADDRINUSE)) {
576 conn->offloaded = 1;
577 fc_msg.proto = sic.protocol;
578 fc_msg.src_saddr = sic.src_ip;
579 fc_msg.dst_saddr = sic.dest_ip;
580 fc_msg.sport = sic.src_port;
581 fc_msg.dport = sic.dest_port;
582 memcpy(fc_msg.mac, conn->mac, ETH_ALEN);
583 fast_classifier_send_genl_msg(FAST_CLASSIFIER_C_OFFLOADED, &fc_msg);
584 }
585
Matthew McClintock16a47ec2013-12-05 17:03:15 -0600586 goto done1;
Matthew McClintock595ee8b2013-12-02 16:21:49 -0600587 } else if (conn->hits > offload_at_pkts) {
588 DEBUG_ERROR("ERROR: MORE THAN %d HITS AND NOT OFFLOADED\n", offload_at_pkts);
Matthew McClintock16a47ec2013-12-05 17:03:15 -0600589 spin_unlock_irqrestore(&sfe_connections_lock, flags);
590 goto done1;
Matthew McClintockc5739382013-12-02 14:17:46 -0600591 }
Matthew McClintock16a47ec2013-12-05 17:03:15 -0600592 }
593
Nicolas Costa514fde02014-01-13 15:50:29 -0600594 spin_unlock_irqrestore(&sfe_connections_lock, flags);
Matthew McClintock16a47ec2013-12-05 17:03:15 -0600595 if (conn->offloaded == 1) {
Nicolas Costa514fde02014-01-13 15:50:29 -0600596 sfe_ipv4_update_rule(p_sic);
Matthew McClintockc5739382013-12-02 14:17:46 -0600597 }
598
599 DEBUG_TRACE("FOUND, SKIPPING\n");
Matthew McClintockea00adf2013-11-25 19:24:30 -0600600 goto done1;
Matthew McClintockea00adf2013-11-25 19:24:30 -0600601 }
602
Matthew McClintock55c86982013-12-02 14:24:24 -0600603 DEBUG_TRACE("SEARCH CONTINUES");
Matthew McClintockea00adf2013-11-25 19:24:30 -0600604 sfe_connections_size++;
605 }
606 spin_unlock_irqrestore(&sfe_connections_lock, flags);
607
608 /*
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600609 * Get the MAC addresses that correspond to source and destination host addresses.
610 */
611 if (!fast_classifier_find_mac_addr(sic.src_ip, sic.src_mac)) {
612 DEBUG_TRACE("failed to find MAC address for src IP: %pI4\n", &sic.src_ip);
613 goto done1;
614 }
615
616 if (!fast_classifier_find_mac_addr(sic.src_ip_xlate, sic.src_mac_xlate)) {
617 DEBUG_TRACE("failed to find MAC address for xlate src IP: %pI4\n", &sic.src_ip_xlate);
618 goto done1;
619 }
620
621 /*
622 * Do dest now
623 */
624 if (!fast_classifier_find_mac_addr(sic.dest_ip, sic.dest_mac)) {
625 DEBUG_TRACE("failed to find MAC address for dest IP: %pI4\n", &sic.dest_ip);
626 goto done1;
627 }
628
629 if (!fast_classifier_find_mac_addr(sic.dest_ip_xlate, sic.dest_mac_xlate)) {
630 DEBUG_TRACE("failed to find MAC address for xlate dest IP: %pI4\n", &sic.dest_ip_xlate);
631 goto done1;
632 }
633
634 /*
635 * Get our device info. If we're dealing with the "reply" direction here then
636 * we'll need things swapped around.
637 */
638 if (ctinfo < IP_CT_IS_REPLY) {
639 src_dev = in;
640 dest_dev = (struct net_device *)out;
641 } else {
642 src_dev = (struct net_device *)out;
643 dest_dev = in;
644 }
645
646#if (!SFE_HOOK_ABOVE_BRIDGE)
647 /*
648 * Now our devices may actually be a bridge interface. If that's
649 * the case then we need to hunt down the underlying interface.
650 */
651 if (src_dev->priv_flags & IFF_EBRIDGE) {
652 src_br_dev = br_port_dev_get(src_dev, sic.src_mac);
653 if (!src_br_dev) {
654 DEBUG_TRACE("no port found on bridge\n");
655 goto done1;
656 }
657
658 src_dev = src_br_dev;
659 }
660
661 if (dest_dev->priv_flags & IFF_EBRIDGE) {
662 dest_br_dev = br_port_dev_get(dest_dev, sic.dest_mac_xlate);
663 if (!dest_br_dev) {
664 DEBUG_TRACE("no port found on bridge\n");
665 goto done2;
666 }
667
668 dest_dev = dest_br_dev;
669 }
670#else
671 /*
672 * Our devices may actually be part of a bridge interface. If that's
673 * the case then find the bridge interface instead.
674 */
675 if (src_dev->priv_flags & IFF_BRIDGE_PORT) {
676 src_br_dev = src_dev->master;
677 if (!src_br_dev) {
678 DEBUG_TRACE("no bridge found for: %s\n", src_dev->name);
679 goto done1;
680 }
681
682 dev_hold(src_br_dev);
683 src_dev = src_br_dev;
684 }
685
686 if (dest_dev->priv_flags & IFF_BRIDGE_PORT) {
687 dest_br_dev = dest_dev->master;
688 if (!dest_br_dev) {
689 DEBUG_TRACE("no bridge found for: %s\n", dest_dev->name);
690 goto done2;
691 }
692
693 dev_hold(dest_br_dev);
694 dest_dev = dest_br_dev;
695 }
696#endif
697
698 sic.src_dev = src_dev;
699 sic.dest_dev = dest_dev;
700
701// XXX - these MTUs need handling correctly!
702 sic.src_mtu = 1500;
703 sic.dest_mtu = 1500;
704
Matthew McClintocke1cf6f22013-11-27 13:27:09 -0600705 if (skb->mark) {
706 DEBUG_TRACE("SKB MARK NON ZERO %x\n", skb->mark);
707 }
708 sic.mark = skb->mark;
709
Matthew McClintock29cd6aa2014-01-14 18:27:10 -0600710 if (last_pppox_sock && last_pppox_sock->pppoe_dev == in->name) {
Ben Menchaca0971b7a2014-01-10 14:43:02 -0600711 struct sock *sk = &last_pppox_sock->sk;
712
713 if (sk->sk_family == PF_PPPOX && sk->sk_protocol == PX_PROTO_OE) {
714 sic.dest_pppoe_sk = sk;
715 }
716 } else {
717 sic.dest_pppoe_sk = NULL;
718 }
719 sic.src_pppoe_sk = NULL;
720
Matthew McClintockea00adf2013-11-25 19:24:30 -0600721 conn = kmalloc(sizeof(struct sfe_connection), GFP_KERNEL);
722 if (conn == NULL) {
723 printk(KERN_CRIT "ERROR: no memory for sfe\n");
724 goto done3;
725 }
Matthew McClintockc5739382013-12-02 14:17:46 -0600726 conn->hits = 0;
Matthew McClintock55c86982013-12-02 14:24:24 -0600727 conn->offloaded = 0;
Matthew McClintockcf157352014-01-10 16:35:40 -0600728 DEBUG_TRACE("Source MAC=%pM\n", mh->h_source);
729 memcpy(conn->mac, mh->h_source, ETH_ALEN);
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600730
Matthew McClintockea00adf2013-11-25 19:24:30 -0600731 p_sic = kmalloc(sizeof(struct sfe_ipv4_create), GFP_KERNEL);
732 if (p_sic == NULL) {
733 printk(KERN_CRIT "ERROR: no memory for sfe\n");
734 kfree(conn);
735 goto done3;
736 }
737
738 memcpy(p_sic, &sic, sizeof(sic));
739 conn->sic = p_sic;
740 conn->ct = ct;
741 DEBUG_TRACE(" -> adding item to sfe_connections, new size: %d\n", ++sfe_connections_size);
742 DEBUG_TRACE("POST_ROUTE: new offloadable connection: proto: %d src_ip: %d dst_ip: %d, src_port: %d, dst_port: %d\n",
743 p_sic->protocol, p_sic->src_ip, p_sic->dest_ip,
744 p_sic->src_port, p_sic->dest_port);
745 spin_lock_irqsave(&sfe_connections_lock, flags);
746 list_add_tail(&(conn->list), &sfe_connections);
747 spin_unlock_irqrestore(&sfe_connections_lock, flags);
748done3:
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600749 /*
750 * If we had bridge ports then release them too.
751 */
752 if (dest_br_dev) {
753 dev_put(dest_br_dev);
754 }
755
756done2:
757 if (src_br_dev) {
758 dev_put(src_br_dev);
759 }
760
761done1:
762 /*
763 * Release the interface on which this skb arrived
764 */
765 dev_put(in);
766
767 return NF_ACCEPT;
768}
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600769
Nicolas Costa21090402014-01-15 11:47:10 -0600770/*
771 * fast_classifier_update_mark()
772 * updates the mark for a fast-classifier connection
773 */
774static void fast_classifier_update_mark(struct sfe_ipv4_mark *mark)
775{
776 struct sfe_connection *conn;
777 struct sfe_ipv4_create *p_sic;
778 unsigned long flags;
779
780 spin_lock_irqsave(&sfe_connections_lock, flags);
781 list_for_each_entry(conn, &sfe_connections, list) {
782 p_sic = conn->sic;
783 if (p_sic->protocol == mark->protocol &&
784 p_sic->src_port == mark->src_port &&
785 p_sic->dest_port == mark->dest_port &&
786 p_sic->src_ip == mark->src_ip &&
787 p_sic->dest_ip == mark->dest_ip ) {
788
789 p_sic->mark = mark->mark;
790
791 break;
792 }
793 }
794 spin_unlock_irqrestore(&sfe_connections_lock, flags);
795}
796
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600797#ifdef CONFIG_NF_CONNTRACK_EVENTS
798/*
799 * fast_classifier_conntrack_event()
800 * Callback event invoked when a conntrack connection's state changes.
801 */
Matthew McClintock0680e9f2013-11-26 15:43:10 -0600802#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
803static int fast_classifier_conntrack_event(struct notifier_block *this,
804 unsigned int events, struct nf_ct_event *item)
805#else
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600806static int fast_classifier_conntrack_event(unsigned int events, struct nf_ct_event *item)
Matthew McClintock0680e9f2013-11-26 15:43:10 -0600807#endif
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600808{
809 struct sfe_ipv4_destroy sid;
810 struct nf_conn *ct = item->ct;
811 struct nf_conntrack_tuple orig_tuple;
Matthew McClintockea00adf2013-11-25 19:24:30 -0600812 struct sfe_connection *conn;
813 struct sfe_ipv4_create *p_sic;
814 int sfe_found_match = 0;
815 int sfe_connections_size = 0;
816 unsigned long flags;
Matthew McClintocke4f9a672014-01-06 17:04:04 -0600817 struct fast_classifier_tuple fc_msg;
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600818
819 /*
820 * If we don't have a conntrack entry then we're done.
821 */
822 if (unlikely(!ct)) {
823 DEBUG_WARN("no ct in conntrack event callback\n");
824 return NOTIFY_DONE;
825 }
826
827 /*
828 * If this is an untracked connection then we can't have any state either.
829 */
830 if (unlikely(ct == &nf_conntrack_untracked)) {
831 DEBUG_TRACE("ignoring untracked conn\n");
832 return NOTIFY_DONE;
833 }
834
835 /*
836 * Ignore anything other than IPv4 connections.
837 */
838 if (unlikely(nf_ct_l3num(ct) != AF_INET)) {
839 DEBUG_TRACE("ignoring non-IPv4 conn\n");
840 return NOTIFY_DONE;
841 }
842
843 /*
Nicolas Costab5f377c2014-01-13 16:16:13 -0600844 * Check for an updated mark
845 */
846 if ((events & (1 << IPCT_MARK)) && (ct->mark != 0)) {
847 struct sfe_ipv4_mark mark;
848 orig_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
849
850 mark.protocol = (int32_t)orig_tuple.dst.protonum;
851 mark.src_ip = (__be32)orig_tuple.src.u3.ip;
852 mark.dest_ip = (__be32)orig_tuple.dst.u3.ip;
853 switch (mark.protocol) {
854 case IPPROTO_TCP:
855 mark.src_port = orig_tuple.src.u.tcp.port;
856 mark.dest_port = orig_tuple.dst.u.tcp.port;
857 break;
858 case IPPROTO_UDP:
859 mark.src_port = orig_tuple.src.u.udp.port;
860 mark.dest_port = orig_tuple.dst.u.udp.port;
861 break;
862 default:
863 break;
864 }
865
866 mark.mark = ct->mark;
867 sfe_ipv4_mark_rule(&mark);
Nicolas Costa21090402014-01-15 11:47:10 -0600868 fast_classifier_update_mark(&mark);
Nicolas Costab5f377c2014-01-13 16:16:13 -0600869 }
870
871 /*
Matthew McClintocke1cf6f22013-11-27 13:27:09 -0600872 * We're only interested in destroy events at this point
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600873 */
874 if (unlikely(!(events & (1 << IPCT_DESTROY)))) {
875 DEBUG_TRACE("ignoring non-destroy event\n");
876 return NOTIFY_DONE;
877 }
878
879 orig_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
880 sid.protocol = (int32_t)orig_tuple.dst.protonum;
881
882 /*
883 * Extract information from the conntrack connection. We're only interested
884 * in nominal connection information (i.e. we're ignoring any NAT information).
885 */
886 sid.src_ip = (__be32)orig_tuple.src.u3.ip;
887 sid.dest_ip = (__be32)orig_tuple.dst.u3.ip;
888
889 switch (sid.protocol) {
890 case IPPROTO_TCP:
891 sid.src_port = orig_tuple.src.u.tcp.port;
892 sid.dest_port = orig_tuple.dst.u.tcp.port;
893 break;
894
895 case IPPROTO_UDP:
896 sid.src_port = orig_tuple.src.u.udp.port;
897 sid.dest_port = orig_tuple.dst.u.udp.port;
898 break;
899
900 default:
901 DEBUG_TRACE("unhandled protocol: %d\n", sid.protocol);
902 return NOTIFY_DONE;
903 }
904
Matthew McClintockea00adf2013-11-25 19:24:30 -0600905 /*
906 * If we already have this connection in our list, skip it
907 * XXX: this may need to be optimized
908 */
909 DEBUG_TRACE("INFO: want to clean up: proto: %d src_ip: %d dst_ip: %d, src_port: %d, dst_port: %d\n",
910 sid.protocol, sid.src_ip, sid.dest_ip,
911 sid.src_port, sid.dest_port);
912 spin_lock_irqsave(&sfe_connections_lock, flags);
913 list_for_each_entry(conn, &sfe_connections, list) {
914 p_sic = conn->sic;
915 DEBUG_TRACE(" -> COMPARING: proto: %d src_ip: %d dst_ip: %d, src_port: %d, dst_port: %d...",
916 p_sic->protocol, p_sic->src_ip, p_sic->dest_ip,
917 p_sic->src_port, p_sic->dest_port);
918
919 if (p_sic->protocol == sid.protocol &&
920 p_sic->src_port == sid.src_port &&
921 p_sic->dest_port == sid.dest_port &&
922 p_sic->src_ip == sid.src_ip &&
923 p_sic->dest_ip == sid.dest_ip ) {
Matthew McClintocke4f9a672014-01-06 17:04:04 -0600924 fc_msg.proto = p_sic->protocol;
925 fc_msg.src_saddr = p_sic->src_ip;
926 fc_msg.dst_saddr = p_sic->dest_ip;
927 fc_msg.sport = p_sic->src_port;
928 fc_msg.dport = p_sic->dest_port;
Matthew McClintockcf157352014-01-10 16:35:40 -0600929 memcpy(fc_msg.mac, conn->mac, ETH_ALEN);
Matthew McClintockea00adf2013-11-25 19:24:30 -0600930 sfe_found_match = 1;
931 DEBUG_TRACE("FOUND, DELETING\n");
932 break;
Matthew McClintockea00adf2013-11-25 19:24:30 -0600933 }
Matthew McClintocke4f9a672014-01-06 17:04:04 -0600934 DEBUG_TRACE("SEARCH CONTINUES\n");
Matthew McClintockea00adf2013-11-25 19:24:30 -0600935 sfe_connections_size++;
936 }
937
938 if (sfe_found_match) {
939 DEBUG_TRACE("INFO: connection over proto: %d src_ip: %d dst_ip: %d, src_port: %d, dst_port: %d\n",
940 p_sic->protocol, p_sic->src_ip, p_sic->dest_ip,
941 p_sic->src_port, p_sic->dest_port);
942 kfree(conn->sic);
943 list_del(&(conn->list));
944 kfree(conn);
945 } else {
946 DEBUG_TRACE("NO MATCH FOUND IN %d ENTRIES!!\n", sfe_connections_size);
947 }
948 spin_unlock_irqrestore(&sfe_connections_lock, flags);
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600949
950 sfe_ipv4_destroy_rule(&sid);
Matthew McClintocke4f9a672014-01-06 17:04:04 -0600951
952 if (sfe_found_match) {
953 fast_classifier_send_genl_msg(FAST_CLASSIFIER_C_DONE, &fc_msg);
954 }
955
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600956 return NOTIFY_DONE;
957}
958
959/*
960 * Netfilter conntrack event system to monitor connection tracking changes
961 */
Matthew McClintock0680e9f2013-11-26 15:43:10 -0600962#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
963static struct notifier_block fast_classifier_conntrack_notifier = {
964 .notifier_call = fast_classifier_conntrack_event,
965};
966#else
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600967static struct nf_ct_event_notifier fast_classifier_conntrack_notifier = {
968 .fcn = fast_classifier_conntrack_event,
969};
970#endif
Matthew McClintock0680e9f2013-11-26 15:43:10 -0600971#endif
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600972
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600973/*
974 * Structure to establish a hook into the post routing netfilter point - this
975 * will pick up local outbound and packets going from one interface to another.
976 *
977 * Note: see include/linux/netfilter_ipv4.h for info related to priority levels.
978 * We want to examine packets after NAT translation and any ALG processing.
979 */
980static struct nf_hook_ops fast_classifier_ipv4_ops_post_routing[] __read_mostly = {
981 {
982 .hook = fast_classifier_ipv4_post_routing_hook,
983 .owner = THIS_MODULE,
984 .pf = PF_INET,
985 .hooknum = NF_INET_POST_ROUTING,
986 .priority = NF_IP_PRI_NAT_SRC + 1,
987 },
988};
Matthew McClintocke1bcfe42013-11-22 15:33:09 -0600989
990/*
991 * fast_classifier_sync_rule()
992 * Synchronize a connection's state.
993 */
994static void fast_classifier_sync_rule(struct sfe_ipv4_sync *sis)
995{
996 struct nf_conntrack_tuple_hash *h;
997 struct nf_conntrack_tuple tuple;
998 struct nf_conn *ct;
999 struct nf_conn_counter *acct;
1000
1001 /*
1002 * Create a tuple so as to be able to look up a connection
1003 */
1004 memset(&tuple, 0, sizeof(tuple));
1005 tuple.src.u3.ip = sis->src_ip;
1006 tuple.src.u.all = (__be16)sis->src_port;
1007 tuple.src.l3num = AF_INET;
1008
1009 tuple.dst.u3.ip = sis->dest_ip;
1010 tuple.dst.dir = IP_CT_DIR_ORIGINAL;
1011 tuple.dst.protonum = (uint8_t)sis->protocol;
1012 tuple.dst.u.all = (__be16)sis->dest_port;
1013
1014 DEBUG_TRACE("update connection - p: %d, s: %pI4:%u, d: %pI4:%u\n",
1015 (int)tuple.dst.protonum,
1016 &tuple.src.u3.ip, (unsigned int)ntohs(tuple.src.u.all),
1017 &tuple.dst.u3.ip, (unsigned int)ntohs(tuple.dst.u.all));
1018
1019 /*
1020 * Look up conntrack connection
1021 */
1022 h = nf_conntrack_find_get(&init_net, NF_CT_DEFAULT_ZONE, &tuple);
1023 if (unlikely(!h)) {
1024 DEBUG_TRACE("no connection found\n");
1025 return;
1026 }
1027
1028 ct = nf_ct_tuplehash_to_ctrack(h);
1029 NF_CT_ASSERT(ct->timeout.data == (unsigned long)ct);
1030
1031 /*
1032 * Only update if this is not a fixed timeout
1033 */
1034 if (!test_bit(IPS_FIXED_TIMEOUT_BIT, &ct->status)) {
1035 ct->timeout.expires += sis->delta_jiffies;
1036 }
1037
1038 acct = nf_conn_acct_find(ct);
1039 if (acct) {
1040 spin_lock_bh(&ct->lock);
Matthew McClintock704b7a62013-12-19 16:13:01 -06001041 atomic64_set(&acct[IP_CT_DIR_ORIGINAL].packets, sis->src_packet_count);
1042 atomic64_set(&acct[IP_CT_DIR_ORIGINAL].bytes, sis->src_byte_count);
1043 atomic64_set(&acct[IP_CT_DIR_REPLY].packets, sis->dest_packet_count);
1044 atomic64_set(&acct[IP_CT_DIR_REPLY].bytes, sis->dest_byte_count);
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001045 spin_unlock_bh(&ct->lock);
1046 }
1047
1048 switch (sis->protocol) {
1049 case IPPROTO_TCP:
1050 spin_lock_bh(&ct->lock);
1051 if (ct->proto.tcp.seen[0].td_maxwin < sis->src_td_max_window) {
1052 ct->proto.tcp.seen[0].td_maxwin = sis->src_td_max_window;
1053 }
1054 if ((int32_t)(ct->proto.tcp.seen[0].td_end - sis->src_td_end) < 0) {
1055 ct->proto.tcp.seen[0].td_end = sis->src_td_end;
1056 }
1057 if ((int32_t)(ct->proto.tcp.seen[0].td_maxend - sis->src_td_max_end) < 0) {
1058 ct->proto.tcp.seen[0].td_maxend = sis->src_td_max_end;
1059 }
1060 if (ct->proto.tcp.seen[1].td_maxwin < sis->dest_td_max_window) {
1061 ct->proto.tcp.seen[1].td_maxwin = sis->dest_td_max_window;
1062 }
1063 if ((int32_t)(ct->proto.tcp.seen[1].td_end - sis->dest_td_end) < 0) {
1064 ct->proto.tcp.seen[1].td_end = sis->dest_td_end;
1065 }
1066 if ((int32_t)(ct->proto.tcp.seen[1].td_maxend - sis->dest_td_max_end) < 0) {
1067 ct->proto.tcp.seen[1].td_maxend = sis->dest_td_max_end;
1068 }
1069 spin_unlock_bh(&ct->lock);
1070 break;
1071 }
1072
1073 /*
1074 * Release connection
1075 */
1076 nf_ct_put(ct);
1077}
1078
1079/*
1080 * fast_classifier_device_event()
1081 */
1082static int fast_classifier_device_event(struct notifier_block *this, unsigned long event, void *ptr)
1083{
1084 struct net_device *dev = (struct net_device *)ptr;
1085
1086 switch (event) {
1087 case NETDEV_DOWN:
1088 if (dev) {
1089 sfe_ipv4_destroy_all_rules_for_dev(dev);
1090 }
1091 break;
1092 }
1093
1094 return NOTIFY_DONE;
1095}
1096
1097/*
1098 * fast_classifier_inet_event()
1099 */
1100static int fast_classifier_inet_event(struct notifier_block *this, unsigned long event, void *ptr)
1101{
1102 struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev;
1103 return fast_classifier_device_event(this, event, dev);
1104}
1105
1106/*
Matthew McClintock595ee8b2013-12-02 16:21:49 -06001107 * fast_classifier_get_offload_at_pkts()
1108 */
1109static ssize_t fast_classifier_get_offload_at_pkts(struct device *dev,
1110 struct device_attribute *attr,
1111 char *buf)
1112{
1113 return sprintf(buf, "%d\n", offload_at_pkts);
1114}
1115
1116/*
1117 * fast_classifier_set_offload_at_pkts()
1118 */
1119static ssize_t fast_classifier_set_offload_at_pkts(struct device *dev,
1120 struct device_attribute *attr,
1121 char *buf, size_t size)
1122{
Matthew McClintock8f4fcd22014-01-14 21:06:03 -06001123 long new;
1124 int ret;
Matthew McClintock595ee8b2013-12-02 16:21:49 -06001125
Matthew McClintock8f4fcd22014-01-14 21:06:03 -06001126 printk(KERN_EMERG "BUF: %s\n", buf);
1127 ret = strict_strtol(buf, 0, &new);
1128 if (ret == -EINVAL || ((int)new != new))
Matthew McClintock595ee8b2013-12-02 16:21:49 -06001129 return -EINVAL;
1130
1131 offload_at_pkts = new;
1132
1133 return size;
1134}
1135
1136/*
1137 * sysfs attributes.
1138 */
1139static const struct device_attribute fast_classifier_offload_at_pkts_attr =
1140 __ATTR(offload_at_pkts, S_IWUGO | S_IRUGO, fast_classifier_get_offload_at_pkts, fast_classifier_set_offload_at_pkts);
1141
1142/*
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001143 * fast_classifier_init()
1144 */
1145static int __init fast_classifier_init(void)
1146{
1147 struct fast_classifier *sc = &__sc;
1148 int result = -1;
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -06001149
1150 printk(KERN_ALERT "fast-classifier: starting up\n");
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001151 DEBUG_INFO("SFE CM init\n");
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -06001152
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001153 /*
1154 * Create sys/fast_classifier
1155 */
1156 sc->sys_fast_classifier = kobject_create_and_add("fast_classifier", NULL);
1157 if (!sc->sys_fast_classifier) {
1158 DEBUG_ERROR("failed to register fast_classifier\n");
1159 goto exit1;
1160 }
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -06001161
Matthew McClintock595ee8b2013-12-02 16:21:49 -06001162 result = sysfs_create_file(sc->sys_fast_classifier, &fast_classifier_offload_at_pkts_attr.attr);
1163 if (result) {
1164 DEBUG_ERROR("failed to register debug dev file: %d\n", result);
1165 goto exit2;
1166 }
1167
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001168 sc->dev_notifier.notifier_call = fast_classifier_device_event;
1169 sc->dev_notifier.priority = 1;
1170 register_netdevice_notifier(&sc->dev_notifier);
1171
1172 sc->inet_notifier.notifier_call = fast_classifier_inet_event;
1173 sc->inet_notifier.priority = 1;
1174 register_inetaddr_notifier(&sc->inet_notifier);
1175
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001176 /*
1177 * Register our netfilter hooks.
1178 */
1179 result = nf_register_hooks(fast_classifier_ipv4_ops_post_routing, ARRAY_SIZE(fast_classifier_ipv4_ops_post_routing));
1180 if (result < 0) {
1181 DEBUG_ERROR("can't register nf post routing hook: %d\n", result);
Matthew McClintock595ee8b2013-12-02 16:21:49 -06001182 goto exit3;
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001183 }
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001184
1185#ifdef CONFIG_NF_CONNTRACK_EVENTS
1186 /*
1187 * Register a notifier hook to get fast notifications of expired connections.
1188 */
1189 result = nf_conntrack_register_notifier(&init_net, &fast_classifier_conntrack_notifier);
1190 if (result < 0) {
1191 DEBUG_ERROR("can't register nf notifier hook: %d\n", result);
Matthew McClintock595ee8b2013-12-02 16:21:49 -06001192 goto exit4;
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001193 }
1194#endif
1195
Dave Hudsonfd7fd072013-12-07 22:34:18 +00001196 result = genl_register_family(&fast_classifier_gnl_family);
Matthew McClintocke4f9a672014-01-06 17:04:04 -06001197 if (result != 0) {
1198 printk(KERN_CRIT "unable to register genl family\n");
Dave Hudsonfd7fd072013-12-07 22:34:18 +00001199 goto exit5;
1200 }
1201
Matthew McClintocke4f9a672014-01-06 17:04:04 -06001202 result = genl_register_ops(&fast_classifier_gnl_family, fast_classifier_gnl_ops);
Dave Hudsonfd7fd072013-12-07 22:34:18 +00001203 if (result != 0) {
Matthew McClintocke4f9a672014-01-06 17:04:04 -06001204 printk(KERN_CRIT "unable to register ops\n");
1205 goto exit6;
1206 }
1207
1208 result = genl_register_mc_group(&fast_classifier_gnl_family,
1209 &fast_classifier_genl_mcgrp);
1210 if (result != 0) {
1211 printk(KERN_CRIT "unable to register multicast group\n");
Dave Hudsonfd7fd072013-12-07 22:34:18 +00001212 goto exit6;
1213 }
1214
1215 printk(KERN_ALERT "fast-classifier: registered\n");
1216
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001217 spin_lock_init(&sc->lock);
1218
1219 /*
1220 * Hook the receive path in the network stack.
1221 */
1222 BUG_ON(athrs_fast_nat_recv != NULL);
1223 RCU_INIT_POINTER(athrs_fast_nat_recv, fast_classifier_recv);
1224
1225 /*
1226 * Hook the shortcut sync callback.
1227 */
1228 sfe_ipv4_register_sync_rule_callback(fast_classifier_sync_rule);
1229
Matthew McClintock6f29aa12013-11-06 15:49:01 -06001230 return 0;
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -06001231
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001232exit6:
Matthew McClintock595ee8b2013-12-02 16:21:49 -06001233 genl_unregister_family(&fast_classifier_gnl_family);
1234
1235exit5:
1236#ifdef CONFIG_NF_CONNTRACK_EVENTS
Dave Hudsonfd7fd072013-12-07 22:34:18 +00001237 nf_conntrack_unregister_notifier(&init_net, &fast_classifier_conntrack_notifier);
Matthew McClintock595ee8b2013-12-02 16:21:49 -06001238#endif
1239
1240exit4:
Dave Hudsonfd7fd072013-12-07 22:34:18 +00001241 nf_unregister_hooks(fast_classifier_ipv4_ops_post_routing, ARRAY_SIZE(fast_classifier_ipv4_ops_post_routing));
Matthew McClintock595ee8b2013-12-02 16:21:49 -06001242
1243exit3:
Dave Hudsonfd7fd072013-12-07 22:34:18 +00001244 unregister_inetaddr_notifier(&sc->inet_notifier);
1245 unregister_netdevice_notifier(&sc->dev_notifier);
Matthew McClintock595ee8b2013-12-02 16:21:49 -06001246 sysfs_remove_file(sc->sys_fast_classifier, &fast_classifier_offload_at_pkts_attr.attr);
1247
1248exit2:
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001249 kobject_put(sc->sys_fast_classifier);
1250
1251exit1:
1252 return result;
Matthew McClintock6f29aa12013-11-06 15:49:01 -06001253}
1254
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001255/*
1256 * fast_classifier_exit()
1257 */
1258static void __exit fast_classifier_exit(void)
Matthew McClintock6f29aa12013-11-06 15:49:01 -06001259{
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001260 struct fast_classifier *sc = &__sc;
1261 int result = -1;
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -06001262
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001263 DEBUG_INFO("SFE CM exit\n");
Matthew McClintock6ab3b3f2013-11-14 15:39:15 -06001264 printk(KERN_ALERT "fast-classifier: shutting down\n");
1265
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001266 /*
1267 * Unregister our sync callback.
1268 */
1269 sfe_ipv4_register_sync_rule_callback(NULL);
1270
1271 /*
1272 * Unregister our receive callback.
1273 */
1274 RCU_INIT_POINTER(athrs_fast_nat_recv, NULL);
1275
1276 /*
1277 * Wait for all callbacks to complete.
1278 */
1279 rcu_barrier();
1280
1281 /*
1282 * Destroy all connections.
1283 */
1284 sfe_ipv4_destroy_all_rules_for_dev(NULL);
1285
Matthew McClintocke4f9a672014-01-06 17:04:04 -06001286 result = genl_unregister_ops(&fast_classifier_gnl_family, fast_classifier_gnl_ops);
Dave Hudsonfd7fd072013-12-07 22:34:18 +00001287 if (result != 0) {
1288 printk(KERN_CRIT "Unable to unreigster genl_ops\n");
1289 }
1290
1291 result = genl_unregister_family(&fast_classifier_gnl_family);
1292 if (result != 0) {
1293 printk(KERN_CRIT "Unable to unreigster genl_family\n");
1294 }
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001295
1296#ifdef CONFIG_NF_CONNTRACK_EVENTS
1297 nf_conntrack_unregister_notifier(&init_net, &fast_classifier_conntrack_notifier);
1298
1299#endif
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001300 nf_unregister_hooks(fast_classifier_ipv4_ops_post_routing, ARRAY_SIZE(fast_classifier_ipv4_ops_post_routing));
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001301
1302 unregister_inetaddr_notifier(&sc->inet_notifier);
1303 unregister_netdevice_notifier(&sc->dev_notifier);
1304
1305 kobject_put(sc->sys_fast_classifier);
Matthew McClintock6f29aa12013-11-06 15:49:01 -06001306}
1307
Matthew McClintocke1bcfe42013-11-22 15:33:09 -06001308module_init(fast_classifier_init)
1309module_exit(fast_classifier_exit)
1310
1311MODULE_AUTHOR("Qualcomm Atheros Inc.");
1312MODULE_DESCRIPTION("Shortcut Forwarding Engine - Connection Manager");
Matthew McClintock6f29aa12013-11-06 15:49:01 -06001313MODULE_LICENSE("GPL");
1314