blob: 4f8da0b022d3cb91ae9025952db5990a4e10c92a [file] [log] [blame]
Xiaoping Fan978b3772015-05-27 14:15:18 -07001/*
2 * sfe_ipv6.c
3 * Shortcut forwarding engine - IPv6 support.
4 *
Ratheesh Kannoth24fb1db2021-10-20 07:28:06 +05305 * Copyright (c) 2015-2016, 2019-2020, The Linux Foundation. All rights reserved.
6 * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
7 *
8 * Permission to use, copy, modify, and/or distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
11 *
Xiaoping Fana42c68b2015-08-07 18:00:39 -070012 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
Ratheesh Kannoth24fb1db2021-10-20 07:28:06 +053017 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Xiaoping Fan978b3772015-05-27 14:15:18 -070019 */
20
21#include <linux/module.h>
22#include <linux/sysfs.h>
23#include <linux/skbuff.h>
24#include <linux/icmp.h>
25#include <net/tcp.h>
26#include <linux/etherdevice.h>
Tian Yang45f39c82020-10-06 14:07:47 -070027#include <linux/version.h>
Xiaoping Fan978b3772015-05-27 14:15:18 -070028
Ratheesh Kannoth24fb1db2021-10-20 07:28:06 +053029#include "sfe_debug.h"
Xiaoping Fan978b3772015-05-27 14:15:18 -070030#include "sfe.h"
Ratheesh Kannoth24fb1db2021-10-20 07:28:06 +053031#include "sfe_flow_cookie.h"
32#include "sfe_ipv6.h"
Xiaoping Fan978b3772015-05-27 14:15:18 -070033
34static char *sfe_ipv6_exception_events_string[SFE_IPV6_EXCEPTION_EVENT_LAST] = {
35 "UDP_HEADER_INCOMPLETE",
36 "UDP_NO_CONNECTION",
37 "UDP_IP_OPTIONS_OR_INITIAL_FRAGMENT",
38 "UDP_SMALL_TTL",
39 "UDP_NEEDS_FRAGMENTATION",
40 "TCP_HEADER_INCOMPLETE",
41 "TCP_NO_CONNECTION_SLOW_FLAGS",
42 "TCP_NO_CONNECTION_FAST_FLAGS",
43 "TCP_IP_OPTIONS_OR_INITIAL_FRAGMENT",
44 "TCP_SMALL_TTL",
45 "TCP_NEEDS_FRAGMENTATION",
46 "TCP_FLAGS",
47 "TCP_SEQ_EXCEEDS_RIGHT_EDGE",
48 "TCP_SMALL_DATA_OFFS",
49 "TCP_BAD_SACK",
50 "TCP_BIG_DATA_OFFS",
51 "TCP_SEQ_BEFORE_LEFT_EDGE",
52 "TCP_ACK_EXCEEDS_RIGHT_EDGE",
53 "TCP_ACK_BEFORE_LEFT_EDGE",
54 "ICMP_HEADER_INCOMPLETE",
55 "ICMP_UNHANDLED_TYPE",
56 "ICMP_IPV6_HEADER_INCOMPLETE",
57 "ICMP_IPV6_NON_V6",
58 "ICMP_IPV6_IP_OPTIONS_INCOMPLETE",
59 "ICMP_IPV6_UDP_HEADER_INCOMPLETE",
60 "ICMP_IPV6_TCP_HEADER_INCOMPLETE",
61 "ICMP_IPV6_UNHANDLED_PROTOCOL",
62 "ICMP_NO_CONNECTION",
63 "ICMP_FLUSHED_CONNECTION",
64 "HEADER_INCOMPLETE",
65 "BAD_TOTAL_LENGTH",
66 "NON_V6",
67 "NON_INITIAL_FRAGMENT",
68 "DATAGRAM_INCOMPLETE",
69 "IP_OPTIONS_INCOMPLETE",
70 "UNHANDLED_PROTOCOL",
71 "FLOW_COOKIE_ADD_FAIL"
72};
73
Xiaoping Fan6a1672f2016-08-17 19:58:12 -070074static struct sfe_ipv6 __si6;
Xiaoping Fan978b3772015-05-27 14:15:18 -070075
76/*
77 * sfe_ipv6_get_debug_dev()
78 */
79static ssize_t sfe_ipv6_get_debug_dev(struct device *dev, struct device_attribute *attr, char *buf);
80
81/*
82 * sysfs attributes.
83 */
84static const struct device_attribute sfe_ipv6_debug_dev_attr =
Xiaoping Fane70da412016-02-26 16:47:57 -080085 __ATTR(debug_dev, S_IWUSR | S_IRUGO, sfe_ipv6_get_debug_dev, NULL);
Xiaoping Fan978b3772015-05-27 14:15:18 -070086
87/*
Xiaoping Fan978b3772015-05-27 14:15:18 -070088 * sfe_ipv6_is_ext_hdr()
89 * check if we recognize ipv6 extension header
90 */
Xiaoping Fan6a1672f2016-08-17 19:58:12 -070091static inline bool sfe_ipv6_is_ext_hdr(u8 hdr)
Xiaoping Fan978b3772015-05-27 14:15:18 -070092{
Ratheesh Kannoth741f7992021-10-20 07:39:52 +053093 return (hdr == NEXTHDR_HOP) ||
94 (hdr == NEXTHDR_ROUTING) ||
95 (hdr == NEXTHDR_FRAGMENT) ||
96 (hdr == NEXTHDR_AUTH) ||
97 (hdr == NEXTHDR_DEST) ||
98 (hdr == NEXTHDR_MOBILITY);
Xiaoping Fan978b3772015-05-27 14:15:18 -070099}
100
101/*
Xiaoping Fane1963d42015-08-25 17:06:19 -0700102 * sfe_ipv6_change_dsfield()
103 * change dscp field in IPv6 packet
104 */
Ratheesh Kannoth741f7992021-10-20 07:39:52 +0530105static inline void sfe_ipv6_change_dsfield(struct ipv6hdr *iph, u8 dscp)
Xiaoping Fane1963d42015-08-25 17:06:19 -0700106{
107 __be16 *p = (__be16 *)iph;
108
109 *p = ((*p & htons(SFE_IPV6_DSCP_MASK)) | htons((u16)dscp << 4));
110}
111
112/*
Xiaoping Fan978b3772015-05-27 14:15:18 -0700113 * sfe_ipv6_get_connection_match_hash()
114 * Generate the hash used in connection match lookups.
115 */
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700116static inline unsigned int sfe_ipv6_get_connection_match_hash(struct net_device *dev, u8 protocol,
Xiaoping Fan978b3772015-05-27 14:15:18 -0700117 struct sfe_ipv6_addr *src_ip, __be16 src_port,
118 struct sfe_ipv6_addr *dest_ip, __be16 dest_port)
119{
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700120 u32 idx, hash = 0;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700121 size_t dev_addr = (size_t)dev;
122
123 for (idx = 0; idx < 4; idx++) {
124 hash ^= src_ip->addr[idx] ^ dest_ip->addr[idx];
125 }
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700126 hash = ((u32)dev_addr) ^ hash ^ protocol ^ ntohs(src_port ^ dest_port);
Xiaoping Fan978b3772015-05-27 14:15:18 -0700127 return ((hash >> SFE_IPV6_CONNECTION_HASH_SHIFT) ^ hash) & SFE_IPV6_CONNECTION_HASH_MASK;
128}
129
130/*
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530131 * sfe_ipv6_find_connection_match_rcu()
Xiaoping Fan978b3772015-05-27 14:15:18 -0700132 * Get the IPv6 flow match info that corresponds to a particular 5-tuple.
Xiaoping Fan978b3772015-05-27 14:15:18 -0700133 */
134static struct sfe_ipv6_connection_match *
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530135sfe_ipv6_find_connection_match_rcu(struct sfe_ipv6 *si, struct net_device *dev, u8 protocol,
Xiaoping Fan978b3772015-05-27 14:15:18 -0700136 struct sfe_ipv6_addr *src_ip, __be16 src_port,
137 struct sfe_ipv6_addr *dest_ip, __be16 dest_port)
138{
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530139 struct sfe_ipv6_connection_match *cm = NULL;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700140 unsigned int conn_match_idx;
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530141 struct hlist_head *lhead;
142 WARN_ON_ONCE(!rcu_read_lock_held());
Xiaoping Fan978b3772015-05-27 14:15:18 -0700143
144 conn_match_idx = sfe_ipv6_get_connection_match_hash(dev, protocol, src_ip, src_port, dest_ip, dest_port);
Xiaoping Fan978b3772015-05-27 14:15:18 -0700145
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530146 lhead = &si->hlist_conn_match_hash_head[conn_match_idx];
Xiaoping Fan978b3772015-05-27 14:15:18 -0700147
148 /*
149 * Hopefully the first entry is the one we want.
150 */
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530151 hlist_for_each_entry_rcu(cm, lhead, hnode) {
152 if ((cm->match_dest_port != dest_port) ||
153 (!sfe_ipv6_addr_equal(cm->match_src_ip, src_ip)) ||
154 (!sfe_ipv6_addr_equal(cm->match_dest_ip, dest_ip)) ||
155 (cm->match_protocol != protocol) ||
156 (cm->match_dev != dev)) {
157 continue;
158 }
159
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +0530160 this_cpu_inc(si->stats_pcpu->connection_match_hash_hits64);
Xiaoping Fan978b3772015-05-27 14:15:18 -0700161
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530162 break;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700163
Xiaoping Fan978b3772015-05-27 14:15:18 -0700164 }
165
Xiaoping Fan978b3772015-05-27 14:15:18 -0700166 return cm;
167}
168
169/*
170 * sfe_ipv6_connection_match_update_summary_stats()
171 * Update the summary stats for a connection match entry.
172 */
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530173static inline void sfe_ipv6_connection_match_update_summary_stats(struct sfe_ipv6_connection_match *cm,
174 u32 *packets, u32 *bytes)
175
Xiaoping Fan978b3772015-05-27 14:15:18 -0700176{
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530177 u32 packet_count, byte_count;
178
179 packet_count = atomic_read(&cm->rx_packet_count);
180 cm->rx_packet_count64 += packet_count;
181 atomic_sub(packet_count, &cm->rx_packet_count);
182
183 byte_count = atomic_read(&cm->rx_byte_count);
184 cm->rx_byte_count64 += byte_count;
185 atomic_sub(byte_count, &cm->rx_byte_count);
186
187 *packets = packet_count;
188 *bytes = byte_count;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700189}
190
191/*
192 * sfe_ipv6_connection_match_compute_translations()
193 * Compute port and address translations for a connection match entry.
194 */
195static void sfe_ipv6_connection_match_compute_translations(struct sfe_ipv6_connection_match *cm)
196{
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700197 u32 diff[9];
198 u32 *idx_32;
199 u16 *idx_16;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700200
201 /*
202 * Before we insert the entry look to see if this is tagged as doing address
203 * translations. If it is then work out the adjustment that we need to apply
204 * to the transport checksum.
205 */
206 if (cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_XLATE_SRC) {
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700207 u32 adj = 0;
208 u32 carry = 0;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700209
210 /*
211 * Precompute an incremental checksum adjustment so we can
212 * edit packets in this stream very quickly. The algorithm is from RFC1624.
213 */
214 idx_32 = diff;
Ratheesh Kannoth741f7992021-10-20 07:39:52 +0530215 *(idx_32++) = cm->match_src_ip[0].addr[0];
216 *(idx_32++) = cm->match_src_ip[0].addr[1];
217 *(idx_32++) = cm->match_src_ip[0].addr[2];
218 *(idx_32++) = cm->match_src_ip[0].addr[3];
Xiaoping Fan978b3772015-05-27 14:15:18 -0700219
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700220 idx_16 = (u16 *)idx_32;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700221 *(idx_16++) = cm->match_src_port;
222 *(idx_16++) = ~cm->xlate_src_port;
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700223 idx_32 = (u32 *)idx_16;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700224
Ratheesh Kannoth741f7992021-10-20 07:39:52 +0530225 *(idx_32++) = ~cm->xlate_src_ip[0].addr[0];
226 *(idx_32++) = ~cm->xlate_src_ip[0].addr[1];
227 *(idx_32++) = ~cm->xlate_src_ip[0].addr[2];
228 *(idx_32++) = ~cm->xlate_src_ip[0].addr[3];
Xiaoping Fan978b3772015-05-27 14:15:18 -0700229
230 /*
231 * When we compute this fold it down to a 16-bit offset
232 * as that way we can avoid having to do a double
233 * folding of the twos-complement result because the
234 * addition of 2 16-bit values cannot cause a double
235 * wrap-around!
236 */
237 for (idx_32 = diff; idx_32 < diff + 9; idx_32++) {
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700238 u32 w = *idx_32;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700239 adj += carry;
240 adj += w;
241 carry = (w > adj);
242 }
243 adj += carry;
244 adj = (adj & 0xffff) + (adj >> 16);
245 adj = (adj & 0xffff) + (adj >> 16);
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700246 cm->xlate_src_csum_adjustment = (u16)adj;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700247 }
248
249 if (cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_XLATE_DEST) {
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700250 u32 adj = 0;
251 u32 carry = 0;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700252
253 /*
254 * Precompute an incremental checksum adjustment so we can
255 * edit packets in this stream very quickly. The algorithm is from RFC1624.
256 */
257 idx_32 = diff;
Ratheesh Kannoth741f7992021-10-20 07:39:52 +0530258 *(idx_32++) = cm->match_dest_ip[0].addr[0];
259 *(idx_32++) = cm->match_dest_ip[0].addr[1];
260 *(idx_32++) = cm->match_dest_ip[0].addr[2];
261 *(idx_32++) = cm->match_dest_ip[0].addr[3];
Xiaoping Fan978b3772015-05-27 14:15:18 -0700262
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700263 idx_16 = (u16 *)idx_32;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700264 *(idx_16++) = cm->match_dest_port;
265 *(idx_16++) = ~cm->xlate_dest_port;
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700266 idx_32 = (u32 *)idx_16;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700267
Ratheesh Kannoth741f7992021-10-20 07:39:52 +0530268 *(idx_32++) = ~cm->xlate_dest_ip[0].addr[0];
269 *(idx_32++) = ~cm->xlate_dest_ip[0].addr[1];
270 *(idx_32++) = ~cm->xlate_dest_ip[0].addr[2];
271 *(idx_32++) = ~cm->xlate_dest_ip[0].addr[3];
Xiaoping Fan978b3772015-05-27 14:15:18 -0700272
273 /*
274 * When we compute this fold it down to a 16-bit offset
275 * as that way we can avoid having to do a double
276 * folding of the twos-complement result because the
277 * addition of 2 16-bit values cannot cause a double
278 * wrap-around!
279 */
280 for (idx_32 = diff; idx_32 < diff + 9; idx_32++) {
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700281 u32 w = *idx_32;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700282 adj += carry;
283 adj += w;
284 carry = (w > adj);
285 }
286 adj += carry;
287 adj = (adj & 0xffff) + (adj >> 16);
288 adj = (adj & 0xffff) + (adj >> 16);
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700289 cm->xlate_dest_csum_adjustment = (u16)adj;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700290 }
291}
292
293/*
294 * sfe_ipv6_update_summary_stats()
295 * Update the summary stats.
296 */
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +0530297static void sfe_ipv6_update_summary_stats(struct sfe_ipv6 *si, struct sfe_ipv6_stats *stats)
Xiaoping Fan978b3772015-05-27 14:15:18 -0700298{
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +0530299 int i = 0;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700300
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +0530301 memset(stats, 0, sizeof(*stats));
Xiaoping Fan978b3772015-05-27 14:15:18 -0700302
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +0530303 for_each_possible_cpu(i) {
304 const struct sfe_ipv6_stats *s = per_cpu_ptr(si->stats_pcpu, i);
305
306 stats->connection_create_requests64 += s->connection_create_requests64;
307 stats->connection_create_collisions64 += s->connection_create_collisions64;
308 stats->connection_destroy_requests64 += s->connection_destroy_requests64;
309 stats->connection_destroy_misses64 += s->connection_destroy_misses64;
310 stats->connection_match_hash_hits64 += s->connection_match_hash_hits64;
311 stats->connection_match_hash_reorders64 += s->connection_match_hash_reorders64;
312 stats->connection_flushes64 += s->connection_flushes64;
313 stats->packets_forwarded64 += s->packets_forwarded64;
314 stats->packets_not_forwarded64 += s->packets_not_forwarded64;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700315 }
316}
317
318/*
319 * sfe_ipv6_insert_connection_match()
320 * Insert a connection match into the hash.
321 *
322 * On entry we must be holding the lock that protects the hash table.
323 */
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700324static inline void sfe_ipv6_insert_connection_match(struct sfe_ipv6 *si,
325 struct sfe_ipv6_connection_match *cm)
Xiaoping Fan978b3772015-05-27 14:15:18 -0700326{
Xiaoping Fan978b3772015-05-27 14:15:18 -0700327 unsigned int conn_match_idx
328 = sfe_ipv6_get_connection_match_hash(cm->match_dev, cm->match_protocol,
329 cm->match_src_ip, cm->match_src_port,
330 cm->match_dest_ip, cm->match_dest_port);
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700331
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530332 lockdep_assert_held(&si->lock);
Xiaoping Fan978b3772015-05-27 14:15:18 -0700333
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530334 hlist_add_head_rcu(&cm->hnode, &si->hlist_conn_match_hash_head[conn_match_idx]);
Xiaoping Fan978b3772015-05-27 14:15:18 -0700335#ifdef CONFIG_NF_FLOW_COOKIE
Xiaoping Fan640faf42015-08-28 15:50:55 -0700336 if (!si->flow_cookie_enable || !(cm->flags & (SFE_IPV6_CONNECTION_MATCH_FLAG_XLATE_SRC | SFE_IPV6_CONNECTION_MATCH_FLAG_XLATE_DEST)))
Xiaoping Fan978b3772015-05-27 14:15:18 -0700337 return;
338
339 /*
340 * Configure hardware to put a flow cookie in packet of this flow,
341 * then we can accelerate the lookup process when we received this packet.
342 */
343 for (conn_match_idx = 1; conn_match_idx < SFE_FLOW_COOKIE_SIZE; conn_match_idx++) {
344 struct sfe_ipv6_flow_cookie_entry *entry = &si->sfe_flow_cookie_table[conn_match_idx];
345
346 if ((NULL == entry->match) && time_is_before_jiffies(entry->last_clean_time + HZ)) {
347 sfe_ipv6_flow_cookie_set_func_t func;
348
349 rcu_read_lock();
350 func = rcu_dereference(si->flow_cookie_set_func);
351 if (func) {
352 if (!func(cm->match_protocol, cm->match_src_ip->addr, cm->match_src_port,
353 cm->match_dest_ip->addr, cm->match_dest_port, conn_match_idx)) {
354 entry->match = cm;
355 cm->flow_cookie = conn_match_idx;
356 } else {
357 si->exception_events[SFE_IPV6_EXCEPTION_EVENT_FLOW_COOKIE_ADD_FAIL]++;
358 }
359 }
360 rcu_read_unlock();
361
362 break;
363 }
364 }
365#endif
Xiaoping Fan978b3772015-05-27 14:15:18 -0700366}
367
368/*
369 * sfe_ipv6_remove_connection_match()
370 * Remove a connection match object from the hash.
Xiaoping Fan978b3772015-05-27 14:15:18 -0700371 */
372static inline void sfe_ipv6_remove_connection_match(struct sfe_ipv6 *si, struct sfe_ipv6_connection_match *cm)
373{
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530374
375 lockdep_assert_held(&si->lock);
Xiaoping Fan978b3772015-05-27 14:15:18 -0700376#ifdef CONFIG_NF_FLOW_COOKIE
Xiaoping Fan640faf42015-08-28 15:50:55 -0700377 if (si->flow_cookie_enable) {
378 /*
379 * Tell hardware that we no longer need a flow cookie in packet of this flow
380 */
381 unsigned int conn_match_idx;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700382
Xiaoping Fan640faf42015-08-28 15:50:55 -0700383 for (conn_match_idx = 1; conn_match_idx < SFE_FLOW_COOKIE_SIZE; conn_match_idx++) {
384 struct sfe_ipv6_flow_cookie_entry *entry = &si->sfe_flow_cookie_table[conn_match_idx];
Xiaoping Fan978b3772015-05-27 14:15:18 -0700385
Xiaoping Fan640faf42015-08-28 15:50:55 -0700386 if (cm == entry->match) {
387 sfe_ipv6_flow_cookie_set_func_t func;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700388
Xiaoping Fan640faf42015-08-28 15:50:55 -0700389 rcu_read_lock();
390 func = rcu_dereference(si->flow_cookie_set_func);
391 if (func) {
392 func(cm->match_protocol, cm->match_src_ip->addr, cm->match_src_port,
393 cm->match_dest_ip->addr, cm->match_dest_port, 0);
394 }
395 rcu_read_unlock();
396
397 cm->flow_cookie = 0;
398 entry->match = NULL;
399 entry->last_clean_time = jiffies;
400 break;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700401 }
Xiaoping Fan978b3772015-05-27 14:15:18 -0700402 }
403 }
404#endif
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530405 hlist_del_init_rcu(&cm->hnode);
Xiaoping Fan978b3772015-05-27 14:15:18 -0700406
407 /*
408 * If the connection match entry is in the active list remove it.
409 */
410 if (cm->active) {
411 if (likely(cm->active_prev)) {
412 cm->active_prev->active_next = cm->active_next;
413 } else {
414 si->active_head = cm->active_next;
415 }
416
417 if (likely(cm->active_next)) {
418 cm->active_next->active_prev = cm->active_prev;
419 } else {
420 si->active_tail = cm->active_prev;
421 }
422 }
423}
424
425/*
426 * sfe_ipv6_get_connection_hash()
427 * Generate the hash used in connection lookups.
428 */
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700429static inline unsigned int sfe_ipv6_get_connection_hash(u8 protocol, struct sfe_ipv6_addr *src_ip, __be16 src_port,
Xiaoping Fan978b3772015-05-27 14:15:18 -0700430 struct sfe_ipv6_addr *dest_ip, __be16 dest_port)
431{
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700432 u32 idx, hash = 0;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700433
434 for (idx = 0; idx < 4; idx++) {
435 hash ^= src_ip->addr[idx] ^ dest_ip->addr[idx];
436 }
437 hash = hash ^ protocol ^ ntohs(src_port ^ dest_port);
438 return ((hash >> SFE_IPV6_CONNECTION_HASH_SHIFT) ^ hash) & SFE_IPV6_CONNECTION_HASH_MASK;
439}
440
441/*
442 * sfe_ipv6_find_connection()
443 * Get the IPv6 connection info that corresponds to a particular 5-tuple.
444 *
445 * On entry we must be holding the lock that protects the hash table.
446 */
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700447static inline struct sfe_ipv6_connection *sfe_ipv6_find_connection(struct sfe_ipv6 *si, u32 protocol,
Xiaoping Fan978b3772015-05-27 14:15:18 -0700448 struct sfe_ipv6_addr *src_ip, __be16 src_port,
449 struct sfe_ipv6_addr *dest_ip, __be16 dest_port)
450{
451 struct sfe_ipv6_connection *c;
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530452
Xiaoping Fan978b3772015-05-27 14:15:18 -0700453 unsigned int conn_idx = sfe_ipv6_get_connection_hash(protocol, src_ip, src_port, dest_ip, dest_port);
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530454
455 lockdep_assert_held(&si->lock);
Xiaoping Fan978b3772015-05-27 14:15:18 -0700456 c = si->conn_hash[conn_idx];
457
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530458 while (c) {
459 if ((c->src_port == src_port)
460 && (c->dest_port == dest_port)
461 && (sfe_ipv6_addr_equal(c->src_ip, src_ip))
462 && (sfe_ipv6_addr_equal(c->dest_ip, dest_ip))
463 && (c->protocol == protocol)) {
464 return c;
465 }
Xiaoping Fan978b3772015-05-27 14:15:18 -0700466 c = c->next;
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530467 }
Xiaoping Fan978b3772015-05-27 14:15:18 -0700468
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530469 return NULL;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700470}
471
472/*
473 * sfe_ipv6_mark_rule()
474 * Updates the mark for a current offloaded connection
475 *
476 * Will take hash lock upon entry
477 */
478void sfe_ipv6_mark_rule(struct sfe_connection_mark *mark)
479{
480 struct sfe_ipv6 *si = &__si6;
481 struct sfe_ipv6_connection *c;
482
Xiaoping Fan3c423e32015-07-03 03:09:29 -0700483 spin_lock_bh(&si->lock);
Xiaoping Fan978b3772015-05-27 14:15:18 -0700484 c = sfe_ipv6_find_connection(si, mark->protocol,
485 mark->src_ip.ip6, mark->src_port,
486 mark->dest_ip.ip6, mark->dest_port);
487 if (c) {
Xiaoping Fan978b3772015-05-27 14:15:18 -0700488 WARN_ON((0 != c->mark) && (0 == mark->mark));
489 c->mark = mark->mark;
490 }
Xiaoping Fan3c423e32015-07-03 03:09:29 -0700491 spin_unlock_bh(&si->lock);
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700492
493 if (c) {
494 DEBUG_TRACE("Matching connection found for mark, "
495 "setting from %08x to %08x\n",
496 c->mark, mark->mark);
497 }
Xiaoping Fan978b3772015-05-27 14:15:18 -0700498}
499
500/*
501 * sfe_ipv6_insert_connection()
502 * Insert a connection into the hash.
503 *
504 * On entry we must be holding the lock that protects the hash table.
505 */
506static void sfe_ipv6_insert_connection(struct sfe_ipv6 *si, struct sfe_ipv6_connection *c)
507{
508 struct sfe_ipv6_connection **hash_head;
509 struct sfe_ipv6_connection *prev_head;
510 unsigned int conn_idx;
511
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530512 lockdep_assert_held(&si->lock);
513
Xiaoping Fan978b3772015-05-27 14:15:18 -0700514 /*
515 * Insert entry into the connection hash.
516 */
517 conn_idx = sfe_ipv6_get_connection_hash(c->protocol, c->src_ip, c->src_port,
518 c->dest_ip, c->dest_port);
519 hash_head = &si->conn_hash[conn_idx];
520 prev_head = *hash_head;
521 c->prev = NULL;
522 if (prev_head) {
523 prev_head->prev = c;
524 }
525
526 c->next = prev_head;
527 *hash_head = c;
528
529 /*
530 * Insert entry into the "all connections" list.
531 */
532 if (si->all_connections_tail) {
533 c->all_connections_prev = si->all_connections_tail;
534 si->all_connections_tail->all_connections_next = c;
535 } else {
536 c->all_connections_prev = NULL;
537 si->all_connections_head = c;
538 }
539
540 si->all_connections_tail = c;
541 c->all_connections_next = NULL;
542 si->num_connections++;
543
544 /*
545 * Insert the connection match objects too.
546 */
547 sfe_ipv6_insert_connection_match(si, c->original_match);
548 sfe_ipv6_insert_connection_match(si, c->reply_match);
549}
550
551/*
552 * sfe_ipv6_remove_connection()
553 * Remove a sfe_ipv6_connection object from the hash.
554 *
555 * On entry we must be holding the lock that protects the hash table.
556 */
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530557static bool sfe_ipv6_remove_connection(struct sfe_ipv6 *si, struct sfe_ipv6_connection *c)
Xiaoping Fan978b3772015-05-27 14:15:18 -0700558{
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530559
560 lockdep_assert_held(&si->lock);
561 if (c->removed) {
562 DEBUG_ERROR("%px: Connection has been removed already\n", c);
563 return false;
564 }
565
Xiaoping Fan978b3772015-05-27 14:15:18 -0700566 /*
567 * Remove the connection match objects.
568 */
569 sfe_ipv6_remove_connection_match(si, c->reply_match);
570 sfe_ipv6_remove_connection_match(si, c->original_match);
571
572 /*
573 * Unlink the connection.
574 */
575 if (c->prev) {
576 c->prev->next = c->next;
577 } else {
578 unsigned int conn_idx = sfe_ipv6_get_connection_hash(c->protocol, c->src_ip, c->src_port,
579 c->dest_ip, c->dest_port);
580 si->conn_hash[conn_idx] = c->next;
581 }
582
583 if (c->next) {
584 c->next->prev = c->prev;
585 }
Xiaoping Fan34586472015-07-03 02:20:35 -0700586
587 /*
588 * Unlink connection from all_connections list
589 */
590 if (c->all_connections_prev) {
591 c->all_connections_prev->all_connections_next = c->all_connections_next;
592 } else {
593 si->all_connections_head = c->all_connections_next;
594 }
595
596 if (c->all_connections_next) {
597 c->all_connections_next->all_connections_prev = c->all_connections_prev;
598 } else {
599 si->all_connections_tail = c->all_connections_prev;
600 }
601
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530602 c->removed = true;
Xiaoping Fan34586472015-07-03 02:20:35 -0700603 si->num_connections--;
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530604 return true;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700605}
606
607/*
608 * sfe_ipv6_gen_sync_connection()
609 * Sync a connection.
610 *
611 * On entry to this function we expect that the lock for the connection is either
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530612 * already held (while called from sfe_ipv6_periodic_sync() or isn't required
613 * (while called from sfe_ipv6_flush_sfe_ipv6_connection())
Xiaoping Fan978b3772015-05-27 14:15:18 -0700614 */
615static void sfe_ipv6_gen_sync_connection(struct sfe_ipv6 *si, struct sfe_ipv6_connection *c,
Xiaoping Fan99cb4c12015-08-21 19:07:32 -0700616 struct sfe_connection_sync *sis, sfe_sync_reason_t reason,
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700617 u64 now_jiffies)
Xiaoping Fan978b3772015-05-27 14:15:18 -0700618{
619 struct sfe_ipv6_connection_match *original_cm;
620 struct sfe_ipv6_connection_match *reply_cm;
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530621 u32 packet_count, byte_count;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700622
623 /*
624 * Fill in the update message.
625 */
Murat Sezgin53509a12016-12-27 16:57:34 -0800626 sis->is_v6 = 1;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700627 sis->protocol = c->protocol;
628 sis->src_ip.ip6[0] = c->src_ip[0];
Xiaoping Fan99cb4c12015-08-21 19:07:32 -0700629 sis->src_ip_xlate.ip6[0] = c->src_ip_xlate[0];
Xiaoping Fan978b3772015-05-27 14:15:18 -0700630 sis->dest_ip.ip6[0] = c->dest_ip[0];
Xiaoping Fan99cb4c12015-08-21 19:07:32 -0700631 sis->dest_ip_xlate.ip6[0] = c->dest_ip_xlate[0];
Xiaoping Fan978b3772015-05-27 14:15:18 -0700632 sis->src_port = c->src_port;
Xiaoping Fan99cb4c12015-08-21 19:07:32 -0700633 sis->src_port_xlate = c->src_port_xlate;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700634 sis->dest_port = c->dest_port;
Xiaoping Fan99cb4c12015-08-21 19:07:32 -0700635 sis->dest_port_xlate = c->dest_port_xlate;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700636
637 original_cm = c->original_match;
638 reply_cm = c->reply_match;
639 sis->src_td_max_window = original_cm->protocol_state.tcp.max_win;
640 sis->src_td_end = original_cm->protocol_state.tcp.end;
641 sis->src_td_max_end = original_cm->protocol_state.tcp.max_end;
642 sis->dest_td_max_window = reply_cm->protocol_state.tcp.max_win;
643 sis->dest_td_end = reply_cm->protocol_state.tcp.end;
644 sis->dest_td_max_end = reply_cm->protocol_state.tcp.max_end;
645
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530646 sfe_ipv6_connection_match_update_summary_stats(original_cm, &packet_count, &byte_count);
647 sis->src_new_packet_count = packet_count;
648 sis->src_new_byte_count = byte_count;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700649
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530650 sfe_ipv6_connection_match_update_summary_stats(reply_cm, &packet_count, &byte_count);
651 sis->dest_new_packet_count = packet_count;
652 sis->dest_new_byte_count = byte_count;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700653
654 sis->src_dev = original_cm->match_dev;
655 sis->src_packet_count = original_cm->rx_packet_count64;
656 sis->src_byte_count = original_cm->rx_byte_count64;
657
658 sis->dest_dev = reply_cm->match_dev;
659 sis->dest_packet_count = reply_cm->rx_packet_count64;
660 sis->dest_byte_count = reply_cm->rx_byte_count64;
661
Xiaoping Fan99cb4c12015-08-21 19:07:32 -0700662 sis->reason = reason;
663
Xiaoping Fan978b3772015-05-27 14:15:18 -0700664 /*
665 * Get the time increment since our last sync.
666 */
667 sis->delta_jiffies = now_jiffies - c->last_sync_jiffies;
668 c->last_sync_jiffies = now_jiffies;
669}
670
671/*
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530672 * sfe_ipv6_free_sfe_ipv6_connection_rcu()
673 * Called at RCU qs state to free the connection object.
674 */
675static void sfe_ipv6_free_sfe_ipv6_connection_rcu(struct rcu_head *head)
676{
677 struct sfe_ipv6_connection *c;
678
679 /*
680 * We dont need spin lock as the connection is already removed from link list
681 */
682 c = container_of(head, struct sfe_ipv6_connection, rcu);
683 BUG_ON(!c->removed);
684
685 DEBUG_TRACE("%px: connecton has been deleted\n", c);
686
687 /*
688 * Release our hold of the source and dest devices and free the memory
689 * for our connection objects.
690 */
691 dev_put(c->original_dev);
692 dev_put(c->reply_dev);
693 kfree(c->original_match);
694 kfree(c->reply_match);
695 kfree(c);
696}
697
698/*
Xiaoping Fan978b3772015-05-27 14:15:18 -0700699 * sfe_ipv6_flush_connection()
700 * Flush a connection and free all associated resources.
701 *
702 * We need to be called with bottom halves disabled locally as we need to acquire
703 * the connection hash lock and release it again. In general we're actually called
704 * from within a BH and so we're fine, but we're also called when connections are
705 * torn down.
706 */
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700707static void sfe_ipv6_flush_connection(struct sfe_ipv6 *si,
708 struct sfe_ipv6_connection *c,
709 sfe_sync_reason_t reason)
Xiaoping Fan978b3772015-05-27 14:15:18 -0700710{
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700711 u64 now_jiffies;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700712 sfe_sync_rule_callback_t sync_rule_callback;
713
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530714 BUG_ON(!c->removed);
715
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +0530716 this_cpu_inc(si->stats_pcpu->connection_flushes64);
Xiaoping Fan978b3772015-05-27 14:15:18 -0700717
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530718 rcu_read_lock();
719
720 sync_rule_callback = rcu_dereference(si->sync_rule_callback);
721
722 /*
723 * Generate a sync message and then sync.
724 */
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +0530725
Xiaoping Fan978b3772015-05-27 14:15:18 -0700726 if (sync_rule_callback) {
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530727 struct sfe_connection_sync sis;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700728 now_jiffies = get_jiffies_64();
Xiaoping Fan99cb4c12015-08-21 19:07:32 -0700729 sfe_ipv6_gen_sync_connection(si, c, &sis, reason, now_jiffies);
Xiaoping Fan978b3772015-05-27 14:15:18 -0700730 sync_rule_callback(&sis);
731 }
732
733 rcu_read_unlock();
734
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530735 call_rcu(&c->rcu, sfe_ipv6_free_sfe_ipv6_connection_rcu);
Xiaoping Fan978b3772015-05-27 14:15:18 -0700736}
737
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +0530738 /*
739 * sfe_ipv6_exception_stats_inc()
740 * Increment exception stats.
741 */
742static inline void sfe_ipv6_exception_stats_inc(struct sfe_ipv6 *si, enum sfe_ipv6_exception_events reason)
743{
744 struct sfe_ipv6_stats *stats = this_cpu_ptr(si->stats_pcpu);
745
746 stats->exception_events64[reason]++;
747 stats->packets_not_forwarded64++;
748}
749
Xiaoping Fan978b3772015-05-27 14:15:18 -0700750/*
751 * sfe_ipv6_recv_udp()
752 * Handle UDP packet receives and forwarding.
753 */
754static int sfe_ipv6_recv_udp(struct sfe_ipv6 *si, struct sk_buff *skb, struct net_device *dev,
Ratheesh Kannoth741f7992021-10-20 07:39:52 +0530755 unsigned int len, struct ipv6hdr *iph, unsigned int ihl, bool flush_on_find)
Xiaoping Fan978b3772015-05-27 14:15:18 -0700756{
Ratheesh Kannoth741f7992021-10-20 07:39:52 +0530757 struct udphdr *udph;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700758 struct sfe_ipv6_addr *src_ip;
759 struct sfe_ipv6_addr *dest_ip;
760 __be16 src_port;
761 __be16 dest_port;
762 struct sfe_ipv6_connection_match *cm;
763 struct net_device *xmit_dev;
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530764 bool ret;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700765
766 /*
767 * Is our packet too short to contain a valid UDP header?
768 */
Ratheesh Kannoth741f7992021-10-20 07:39:52 +0530769 if (!pskb_may_pull(skb, (sizeof(struct udphdr) + ihl))) {
Xiaoping Fan978b3772015-05-27 14:15:18 -0700770
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +0530771 sfe_ipv6_exception_stats_inc(si,SFE_IPV6_EXCEPTION_EVENT_UDP_HEADER_INCOMPLETE);
Xiaoping Fan978b3772015-05-27 14:15:18 -0700772 DEBUG_TRACE("packet too short for UDP header\n");
773 return 0;
774 }
775
776 /*
777 * Read the IP address and port information. Read the IP header data first
778 * because we've almost certainly got that in the cache. We may not yet have
779 * the UDP header cached though so allow more time for any prefetching.
780 */
Ratheesh Kannoth741f7992021-10-20 07:39:52 +0530781 src_ip = (struct sfe_ipv6_addr *)iph->saddr.s6_addr32;
782 dest_ip = (struct sfe_ipv6_addr *)iph->daddr.s6_addr32;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700783
Ratheesh Kannoth741f7992021-10-20 07:39:52 +0530784 udph = (struct udphdr *)(skb->data + ihl);
Xiaoping Fan978b3772015-05-27 14:15:18 -0700785 src_port = udph->source;
786 dest_port = udph->dest;
787
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530788 rcu_read_lock();
Xiaoping Fan978b3772015-05-27 14:15:18 -0700789
790 /*
791 * Look for a connection match.
792 */
793#ifdef CONFIG_NF_FLOW_COOKIE
794 cm = si->sfe_flow_cookie_table[skb->flow_cookie & SFE_FLOW_COOKIE_MASK].match;
795 if (unlikely(!cm)) {
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530796 cm = sfe_ipv6_find_connection_match_rcu(si, dev, IPPROTO_UDP, src_ip, src_port, dest_ip, dest_port);
Xiaoping Fan978b3772015-05-27 14:15:18 -0700797 }
798#else
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530799 cm = sfe_ipv6_find_connection_match_rcu(si, dev, IPPROTO_UDP, src_ip, src_port, dest_ip, dest_port);
Xiaoping Fan978b3772015-05-27 14:15:18 -0700800#endif
801 if (unlikely(!cm)) {
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530802 rcu_read_unlock();
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +0530803 sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_UDP_NO_CONNECTION);
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530804
Xiaoping Fan978b3772015-05-27 14:15:18 -0700805 DEBUG_TRACE("no connection found\n");
806 return 0;
807 }
808
809 /*
810 * If our packet has beern marked as "flush on find" we can't actually
811 * forward it in the fast path, but now that we've found an associated
812 * connection we can flush that out before we process the packet.
813 */
814 if (unlikely(flush_on_find)) {
815 struct sfe_ipv6_connection *c = cm->connection;
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530816 spin_lock_bh(&si->lock);
817 ret = sfe_ipv6_remove_connection(si, c);
Xiaoping Fan3c423e32015-07-03 03:09:29 -0700818 spin_unlock_bh(&si->lock);
Xiaoping Fan978b3772015-05-27 14:15:18 -0700819
820 DEBUG_TRACE("flush on find\n");
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530821 if (ret) {
822 sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH);
823 }
824 rcu_read_unlock();
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +0530825
826 sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_UDP_IP_OPTIONS_OR_INITIAL_FRAGMENT);
Xiaoping Fan978b3772015-05-27 14:15:18 -0700827 return 0;
828 }
829
Zhi Chen8748eb32015-06-18 12:58:48 -0700830#ifdef CONFIG_XFRM
831 /*
832 * We can't accelerate the flow on this direction, just let it go
833 * through the slow path.
834 */
835 if (unlikely(!cm->flow_accel)) {
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530836 rcu_read_unlock();
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +0530837 this_cpu_inc(si->stats_pcpu->packets_not_forwarded64);
Zhi Chen8748eb32015-06-18 12:58:48 -0700838 return 0;
839 }
840#endif
841
Xiaoping Fan978b3772015-05-27 14:15:18 -0700842 /*
843 * Does our hop_limit allow forwarding?
844 */
845 if (unlikely(iph->hop_limit < 2)) {
846 struct sfe_ipv6_connection *c = cm->connection;
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530847 spin_lock_bh(&si->lock);
848 ret = sfe_ipv6_remove_connection(si, c);
Xiaoping Fan3c423e32015-07-03 03:09:29 -0700849 spin_unlock_bh(&si->lock);
Xiaoping Fan978b3772015-05-27 14:15:18 -0700850
851 DEBUG_TRACE("hop_limit too low\n");
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530852 if (ret) {
853 sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH);
854 }
855 rcu_read_unlock();
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +0530856
857 sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_UDP_SMALL_TTL);
Xiaoping Fan978b3772015-05-27 14:15:18 -0700858 return 0;
859 }
860
861 /*
862 * If our packet is larger than the MTU of the transmit interface then
863 * we can't forward it easily.
864 */
865 if (unlikely(len > cm->xmit_dev_mtu)) {
866 struct sfe_ipv6_connection *c = cm->connection;
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530867 spin_lock_bh(&si->lock);
868 ret = sfe_ipv6_remove_connection(si, c);
Xiaoping Fan3c423e32015-07-03 03:09:29 -0700869 spin_unlock_bh(&si->lock);
Xiaoping Fan978b3772015-05-27 14:15:18 -0700870
871 DEBUG_TRACE("larger than mtu\n");
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530872 if (ret) {
873 sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH);
874 }
875 rcu_read_unlock();
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +0530876
877 sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_UDP_NEEDS_FRAGMENTATION);
Xiaoping Fan978b3772015-05-27 14:15:18 -0700878 return 0;
879 }
880
881 /*
882 * From this point on we're good to modify the packet.
883 */
884
885 /*
Murat Sezginc7dd8172019-02-27 15:23:50 -0800886 * Check if skb was cloned. If it was, unshare it. Because
887 * the data area is going to be written in this path and we don't want to
888 * change the cloned skb's data section.
889 */
890 if (unlikely(skb_cloned(skb))) {
Tian Yang45f39c82020-10-06 14:07:47 -0700891 DEBUG_TRACE("%px: skb is a cloned skb\n", skb);
Murat Sezginc7dd8172019-02-27 15:23:50 -0800892 skb = skb_unshare(skb, GFP_ATOMIC);
893 if (!skb) {
894 DEBUG_WARN("Failed to unshare the cloned skb\n");
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530895 rcu_read_unlock();
Murat Sezginc7dd8172019-02-27 15:23:50 -0800896 return 0;
897 }
898
899 /*
900 * Update the iph and udph pointers with the unshared skb's data area.
901 */
Ratheesh Kannoth741f7992021-10-20 07:39:52 +0530902 iph = (struct ipv6hdr *)skb->data;
903 udph = (struct udphdr *)(skb->data + ihl);
Murat Sezginc7dd8172019-02-27 15:23:50 -0800904 }
905
906 /*
Xiaoping Fane1963d42015-08-25 17:06:19 -0700907 * Update DSCP
908 */
909 if (unlikely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_DSCP_REMARK)) {
910 sfe_ipv6_change_dsfield(iph, cm->dscp);
911 }
912
913 /*
Xiaoping Fan978b3772015-05-27 14:15:18 -0700914 * Decrement our hop_limit.
915 */
916 iph->hop_limit -= 1;
917
918 /*
919 * Do we have to perform translations of the source address/port?
920 */
921 if (unlikely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_XLATE_SRC)) {
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700922 u16 udp_csum;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700923
Ratheesh Kannoth741f7992021-10-20 07:39:52 +0530924 iph->saddr.s6_addr32[0] = cm->xlate_src_ip[0].addr[0];
925 iph->saddr.s6_addr32[1] = cm->xlate_src_ip[0].addr[1];
926 iph->saddr.s6_addr32[2] = cm->xlate_src_ip[0].addr[2];
927 iph->saddr.s6_addr32[3] = cm->xlate_src_ip[0].addr[3];
Xiaoping Fan978b3772015-05-27 14:15:18 -0700928 udph->source = cm->xlate_src_port;
929
930 /*
931 * Do we have a non-zero UDP checksum? If we do then we need
932 * to update it.
933 */
934 udp_csum = udph->check;
935 if (likely(udp_csum)) {
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700936 u32 sum = udp_csum + cm->xlate_src_csum_adjustment;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700937 sum = (sum & 0xffff) + (sum >> 16);
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700938 udph->check = (u16)sum;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700939 }
940 }
941
942 /*
943 * Do we have to perform translations of the destination address/port?
944 */
945 if (unlikely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_XLATE_DEST)) {
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700946 u16 udp_csum;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700947
Ratheesh Kannoth741f7992021-10-20 07:39:52 +0530948 iph->daddr.s6_addr32[0] = cm->xlate_dest_ip[0].addr[0];
949 iph->daddr.s6_addr32[1] = cm->xlate_dest_ip[0].addr[1];
950 iph->daddr.s6_addr32[2] = cm->xlate_dest_ip[0].addr[2];
951 iph->daddr.s6_addr32[3] = cm->xlate_dest_ip[0].addr[3];
Xiaoping Fan978b3772015-05-27 14:15:18 -0700952 udph->dest = cm->xlate_dest_port;
953
954 /*
955 * Do we have a non-zero UDP checksum? If we do then we need
956 * to update it.
957 */
958 udp_csum = udph->check;
959 if (likely(udp_csum)) {
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700960 u32 sum = udp_csum + cm->xlate_dest_csum_adjustment;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700961 sum = (sum & 0xffff) + (sum >> 16);
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700962 udph->check = (u16)sum;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700963 }
964 }
965
966 /*
967 * Update traffic stats.
968 */
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530969 atomic_inc(&cm->rx_packet_count);
970 atomic_add(len, &cm->rx_byte_count);
Xiaoping Fan978b3772015-05-27 14:15:18 -0700971
972 /*
973 * If we're not already on the active list then insert ourselves at the tail
974 * of the current list.
975 */
976 if (unlikely(!cm->active)) {
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530977 spin_lock_bh(&si->lock);
978 if (unlikely(!cm->active)) {
979 cm->active = true;
980 cm->active_prev = si->active_tail;
981 if (likely(si->active_tail)) {
982 si->active_tail->active_next = cm;
983 } else {
984 si->active_head = cm;
985 }
986 si->active_tail = cm;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700987 }
Ratheesh Kannotha212fc52021-10-20 07:50:32 +0530988 spin_unlock_bh(&si->lock);
Xiaoping Fan978b3772015-05-27 14:15:18 -0700989 }
990
991 xmit_dev = cm->xmit_dev;
992 skb->dev = xmit_dev;
993
994 /*
995 * Check to see if we need to write a header.
996 */
997 if (likely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_WRITE_L2_HDR)) {
998 if (unlikely(!(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_WRITE_FAST_ETH_HDR))) {
Xiaoping Fan2784e612015-06-25 17:57:41 -0700999 dev_hard_header(skb, xmit_dev, ETH_P_IPV6,
1000 cm->xmit_dest_mac, cm->xmit_src_mac, len);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001001 } else {
1002 /*
1003 * For the simple case we write this really fast.
1004 */
Ratheesh Kannoth741f7992021-10-20 07:39:52 +05301005 struct ethhdr *eth = (struct ethhdr *)__skb_push(skb, ETH_HLEN);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001006 eth->h_proto = htons(ETH_P_IPV6);
Ratheesh Kannoth741f7992021-10-20 07:39:52 +05301007 ether_addr_copy((u8 *)eth->h_dest, (u8 *)cm->xmit_dest_mac);
1008 ether_addr_copy((u8 *)eth->h_source, (u8 *)cm->xmit_src_mac);
1009
Xiaoping Fan978b3772015-05-27 14:15:18 -07001010 }
1011 }
1012
1013 /*
Xiaoping Fane1963d42015-08-25 17:06:19 -07001014 * Update priority of skb.
1015 */
1016 if (unlikely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_PRIORITY_REMARK)) {
1017 skb->priority = cm->priority;
1018 }
1019
1020 /*
Xiaoping Fan978b3772015-05-27 14:15:18 -07001021 * Mark outgoing packet.
1022 */
1023 skb->mark = cm->connection->mark;
1024 if (skb->mark) {
1025 DEBUG_TRACE("SKB MARK is NON ZERO %x\n", skb->mark);
1026 }
1027
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301028 rcu_read_unlock();
1029
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05301030 this_cpu_inc(si->stats_pcpu->packets_forwarded64);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001031
1032 /*
1033 * We're going to check for GSO flags when we transmit the packet so
1034 * start fetching the necessary cache line now.
1035 */
1036 prefetch(skb_shinfo(skb));
1037
1038 /*
1039 * Mark that this packet has been fast forwarded.
1040 */
1041 skb->fast_forwarded = 1;
1042
1043 /*
1044 * Send the packet on its way.
1045 */
1046 dev_queue_xmit(skb);
1047
1048 return 1;
1049}
1050
1051/*
1052 * sfe_ipv6_process_tcp_option_sack()
1053 * Parse TCP SACK option and update ack according
1054 */
Ratheesh Kannoth741f7992021-10-20 07:39:52 +05301055static bool sfe_ipv6_process_tcp_option_sack(const struct tcphdr *th, const u32 data_offs,
Xiaoping Fan6a1672f2016-08-17 19:58:12 -07001056 u32 *ack)
Xiaoping Fan978b3772015-05-27 14:15:18 -07001057{
Ratheesh Kannoth741f7992021-10-20 07:39:52 +05301058 u32 length = sizeof(struct tcphdr);
Xiaoping Fan6a1672f2016-08-17 19:58:12 -07001059 u8 *ptr = (u8 *)th + length;
Xiaoping Fan978b3772015-05-27 14:15:18 -07001060
1061 /*
Xiaoping Fan6a1672f2016-08-17 19:58:12 -07001062 * Ignore processing if TCP packet has only TIMESTAMP option.
Xiaoping Fan978b3772015-05-27 14:15:18 -07001063 */
1064 if (likely(data_offs == length + TCPOLEN_TIMESTAMP + 1 + 1)
1065 && likely(ptr[0] == TCPOPT_NOP)
1066 && likely(ptr[1] == TCPOPT_NOP)
1067 && likely(ptr[2] == TCPOPT_TIMESTAMP)
1068 && likely(ptr[3] == TCPOLEN_TIMESTAMP)) {
1069 return true;
1070 }
1071
1072 /*
1073 * TCP options. Parse SACK option.
1074 */
1075 while (length < data_offs) {
Xiaoping Fan6a1672f2016-08-17 19:58:12 -07001076 u8 size;
1077 u8 kind;
Xiaoping Fan978b3772015-05-27 14:15:18 -07001078
Xiaoping Fan6a1672f2016-08-17 19:58:12 -07001079 ptr = (u8 *)th + length;
Xiaoping Fan978b3772015-05-27 14:15:18 -07001080 kind = *ptr;
1081
1082 /*
1083 * NOP, for padding
1084 * Not in the switch because to fast escape and to not calculate size
1085 */
1086 if (kind == TCPOPT_NOP) {
1087 length++;
1088 continue;
1089 }
1090
1091 if (kind == TCPOPT_SACK) {
Xiaoping Fan6a1672f2016-08-17 19:58:12 -07001092 u32 sack = 0;
1093 u8 re = 1 + 1;
Xiaoping Fan978b3772015-05-27 14:15:18 -07001094
1095 size = *(ptr + 1);
1096 if ((size < (1 + 1 + TCPOLEN_SACK_PERBLOCK))
1097 || ((size - (1 + 1)) % (TCPOLEN_SACK_PERBLOCK))
1098 || (size > (data_offs - length))) {
1099 return false;
1100 }
1101
1102 re += 4;
1103 while (re < size) {
Xiaoping Fan6a1672f2016-08-17 19:58:12 -07001104 u32 sack_re;
1105 u8 *sptr = ptr + re;
Xiaoping Fan978b3772015-05-27 14:15:18 -07001106 sack_re = (sptr[0] << 24) | (sptr[1] << 16) | (sptr[2] << 8) | sptr[3];
1107 if (sack_re > sack) {
1108 sack = sack_re;
1109 }
1110 re += TCPOLEN_SACK_PERBLOCK;
1111 }
1112 if (sack > *ack) {
1113 *ack = sack;
1114 }
1115 length += size;
1116 continue;
1117 }
1118 if (kind == TCPOPT_EOL) {
1119 return true;
1120 }
1121 size = *(ptr + 1);
1122 if (size < 2) {
1123 return false;
1124 }
1125 length += size;
1126 }
1127
1128 return true;
1129}
1130
1131/*
1132 * sfe_ipv6_recv_tcp()
1133 * Handle TCP packet receives and forwarding.
1134 */
1135static int sfe_ipv6_recv_tcp(struct sfe_ipv6 *si, struct sk_buff *skb, struct net_device *dev,
Ratheesh Kannoth741f7992021-10-20 07:39:52 +05301136 unsigned int len, struct ipv6hdr *iph, unsigned int ihl, bool flush_on_find)
Xiaoping Fan978b3772015-05-27 14:15:18 -07001137{
Ratheesh Kannoth741f7992021-10-20 07:39:52 +05301138 struct tcphdr *tcph;
Xiaoping Fan978b3772015-05-27 14:15:18 -07001139 struct sfe_ipv6_addr *src_ip;
1140 struct sfe_ipv6_addr *dest_ip;
1141 __be16 src_port;
1142 __be16 dest_port;
1143 struct sfe_ipv6_connection_match *cm;
1144 struct sfe_ipv6_connection_match *counter_cm;
Xiaoping Fan6a1672f2016-08-17 19:58:12 -07001145 u32 flags;
Xiaoping Fan978b3772015-05-27 14:15:18 -07001146 struct net_device *xmit_dev;
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301147 bool ret;
Xiaoping Fan978b3772015-05-27 14:15:18 -07001148
1149 /*
1150 * Is our packet too short to contain a valid UDP header?
1151 */
Ratheesh Kannoth741f7992021-10-20 07:39:52 +05301152 if (!pskb_may_pull(skb, (sizeof(struct tcphdr) + ihl))) {
Xiaoping Fan978b3772015-05-27 14:15:18 -07001153
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05301154 sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_TCP_HEADER_INCOMPLETE);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001155 DEBUG_TRACE("packet too short for TCP header\n");
1156 return 0;
1157 }
1158
1159 /*
1160 * Read the IP address and port information. Read the IP header data first
1161 * because we've almost certainly got that in the cache. We may not yet have
1162 * the TCP header cached though so allow more time for any prefetching.
1163 */
Ratheesh Kannoth741f7992021-10-20 07:39:52 +05301164 src_ip = (struct sfe_ipv6_addr *)iph->saddr.s6_addr32;
1165 dest_ip = (struct sfe_ipv6_addr *)iph->daddr.s6_addr32;
Xiaoping Fan978b3772015-05-27 14:15:18 -07001166
Ratheesh Kannoth741f7992021-10-20 07:39:52 +05301167 tcph = (struct tcphdr *)(skb->data + ihl);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001168 src_port = tcph->source;
1169 dest_port = tcph->dest;
1170 flags = tcp_flag_word(tcph);
1171
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301172 rcu_read_lock();
Xiaoping Fan978b3772015-05-27 14:15:18 -07001173
1174 /*
1175 * Look for a connection match.
1176 */
1177#ifdef CONFIG_NF_FLOW_COOKIE
1178 cm = si->sfe_flow_cookie_table[skb->flow_cookie & SFE_FLOW_COOKIE_MASK].match;
1179 if (unlikely(!cm)) {
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301180 cm = sfe_ipv6_find_connection_match_rcu(si, dev, IPPROTO_TCP, src_ip, src_port, dest_ip, dest_port);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001181 }
1182#else
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301183 cm = sfe_ipv6_find_connection_match_rcu(si, dev, IPPROTO_TCP, src_ip, src_port, dest_ip, dest_port);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001184#endif
1185 if (unlikely(!cm)) {
1186 /*
1187 * We didn't get a connection but as TCP is connection-oriented that
1188 * may be because this is a non-fast connection (not running established).
1189 * For diagnostic purposes we differentiate this here.
1190 */
1191 if (likely((flags & (TCP_FLAG_SYN | TCP_FLAG_RST | TCP_FLAG_FIN | TCP_FLAG_ACK)) == TCP_FLAG_ACK)) {
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301192 rcu_read_unlock();
Xiaoping Fan978b3772015-05-27 14:15:18 -07001193
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05301194 sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_TCP_NO_CONNECTION_FAST_FLAGS);
1195
Xiaoping Fan978b3772015-05-27 14:15:18 -07001196 DEBUG_TRACE("no connection found - fast flags\n");
1197 return 0;
1198 }
Xiaoping Fan978b3772015-05-27 14:15:18 -07001199
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301200 rcu_read_unlock();
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05301201
1202 sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_TCP_NO_CONNECTION_SLOW_FLAGS);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001203 DEBUG_TRACE("no connection found - slow flags: 0x%x\n",
1204 flags & (TCP_FLAG_SYN | TCP_FLAG_RST | TCP_FLAG_FIN | TCP_FLAG_ACK));
1205 return 0;
1206 }
1207
1208 /*
1209 * If our packet has beern marked as "flush on find" we can't actually
1210 * forward it in the fast path, but now that we've found an associated
1211 * connection we can flush that out before we process the packet.
1212 */
1213 if (unlikely(flush_on_find)) {
1214 struct sfe_ipv6_connection *c = cm->connection;
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301215 spin_lock_bh(&si->lock);
1216 ret = sfe_ipv6_remove_connection(si, c);
Xiaoping Fan3c423e32015-07-03 03:09:29 -07001217 spin_unlock_bh(&si->lock);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001218
1219 DEBUG_TRACE("flush on find\n");
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301220 if (ret) {
1221 sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH);
1222 }
1223 rcu_read_unlock();
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05301224
1225 sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_TCP_IP_OPTIONS_OR_INITIAL_FRAGMENT);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001226 return 0;
1227 }
1228
Zhi Chen8748eb32015-06-18 12:58:48 -07001229#ifdef CONFIG_XFRM
1230 /*
1231 * We can't accelerate the flow on this direction, just let it go
1232 * through the slow path.
1233 */
1234 if (unlikely(!cm->flow_accel)) {
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301235 rcu_read_unlock();
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05301236 this_cpu_inc(si->stats_pcpu->packets_not_forwarded64);
Zhi Chen8748eb32015-06-18 12:58:48 -07001237 return 0;
1238 }
1239#endif
1240
Xiaoping Fan978b3772015-05-27 14:15:18 -07001241 /*
1242 * Does our hop_limit allow forwarding?
1243 */
1244 if (unlikely(iph->hop_limit < 2)) {
1245 struct sfe_ipv6_connection *c = cm->connection;
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301246 spin_lock_bh(&si->lock);
1247 ret = sfe_ipv6_remove_connection(si, c);
Xiaoping Fan3c423e32015-07-03 03:09:29 -07001248 spin_unlock_bh(&si->lock);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001249
1250 DEBUG_TRACE("hop_limit too low\n");
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301251 if (ret) {
1252 sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH);
1253 }
1254 rcu_read_unlock();
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05301255
1256 sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_TCP_SMALL_TTL);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001257 return 0;
1258 }
1259
1260 /*
1261 * If our packet is larger than the MTU of the transmit interface then
1262 * we can't forward it easily.
1263 */
1264 if (unlikely((len > cm->xmit_dev_mtu) && !skb_is_gso(skb))) {
1265 struct sfe_ipv6_connection *c = cm->connection;
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301266 spin_lock_bh(&si->lock);
1267 ret = sfe_ipv6_remove_connection(si, c);
Xiaoping Fan3c423e32015-07-03 03:09:29 -07001268 spin_unlock_bh(&si->lock);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001269
1270 DEBUG_TRACE("larger than mtu\n");
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301271 if (ret) {
1272 sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH);
1273 }
1274 rcu_read_unlock();
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05301275
1276 sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_TCP_NEEDS_FRAGMENTATION);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001277 return 0;
1278 }
1279
1280 /*
1281 * Look at our TCP flags. Anything missing an ACK or that has RST, SYN or FIN
1282 * set is not a fast path packet.
1283 */
1284 if (unlikely((flags & (TCP_FLAG_SYN | TCP_FLAG_RST | TCP_FLAG_FIN | TCP_FLAG_ACK)) != TCP_FLAG_ACK)) {
1285 struct sfe_ipv6_connection *c = cm->connection;
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301286 spin_lock_bh(&si->lock);
1287 ret = sfe_ipv6_remove_connection(si, c);
Xiaoping Fan3c423e32015-07-03 03:09:29 -07001288 spin_unlock_bh(&si->lock);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001289
1290 DEBUG_TRACE("TCP flags: 0x%x are not fast\n",
1291 flags & (TCP_FLAG_SYN | TCP_FLAG_RST | TCP_FLAG_FIN | TCP_FLAG_ACK));
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301292 if (ret) {
1293 sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH);
1294 }
1295 rcu_read_unlock();
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05301296
1297 sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_TCP_FLAGS);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001298 return 0;
1299 }
1300
1301 counter_cm = cm->counter_match;
1302
1303 /*
1304 * Are we doing sequence number checking?
1305 */
1306 if (likely(!(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK))) {
Xiaoping Fan6a1672f2016-08-17 19:58:12 -07001307 u32 seq;
1308 u32 ack;
1309 u32 sack;
1310 u32 data_offs;
1311 u32 end;
1312 u32 left_edge;
1313 u32 scaled_win;
1314 u32 max_end;
Xiaoping Fan978b3772015-05-27 14:15:18 -07001315
1316 /*
1317 * Is our sequence fully past the right hand edge of the window?
1318 */
1319 seq = ntohl(tcph->seq);
Xiaoping Fan6a1672f2016-08-17 19:58:12 -07001320 if (unlikely((s32)(seq - (cm->protocol_state.tcp.max_end + 1)) > 0)) {
Xiaoping Fan978b3772015-05-27 14:15:18 -07001321 struct sfe_ipv6_connection *c = cm->connection;
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301322 spin_lock_bh(&si->lock);
1323 ret = sfe_ipv6_remove_connection(si, c);
Xiaoping Fan3c423e32015-07-03 03:09:29 -07001324 spin_unlock_bh(&si->lock);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001325
1326 DEBUG_TRACE("seq: %u exceeds right edge: %u\n",
1327 seq, cm->protocol_state.tcp.max_end + 1);
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301328 if (ret) {
1329 sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH);
1330 }
1331 rcu_read_unlock();
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05301332
1333 sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_TCP_SEQ_EXCEEDS_RIGHT_EDGE);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001334 return 0;
1335 }
1336
1337 /*
1338 * Check that our TCP data offset isn't too short.
1339 */
1340 data_offs = tcph->doff << 2;
Ratheesh Kannoth741f7992021-10-20 07:39:52 +05301341 if (unlikely(data_offs < sizeof(struct tcphdr))) {
Xiaoping Fan978b3772015-05-27 14:15:18 -07001342 struct sfe_ipv6_connection *c = cm->connection;
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301343 spin_lock_bh(&si->lock);
1344 ret = sfe_ipv6_remove_connection(si, c);
Xiaoping Fan3c423e32015-07-03 03:09:29 -07001345 spin_unlock_bh(&si->lock);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001346
1347 DEBUG_TRACE("TCP data offset: %u, too small\n", data_offs);
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301348 if (ret) {
1349 sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH);
1350 }
1351 rcu_read_unlock();
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05301352
1353 sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_TCP_SMALL_DATA_OFFS);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001354 return 0;
1355 }
1356
1357 /*
1358 * Update ACK according to any SACK option.
1359 */
1360 ack = ntohl(tcph->ack_seq);
1361 sack = ack;
1362 if (unlikely(!sfe_ipv6_process_tcp_option_sack(tcph, data_offs, &sack))) {
1363 struct sfe_ipv6_connection *c = cm->connection;
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301364 spin_lock_bh(&si->lock);
1365 ret = sfe_ipv6_remove_connection(si, c);
Xiaoping Fan3c423e32015-07-03 03:09:29 -07001366 spin_unlock_bh(&si->lock);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001367
1368 DEBUG_TRACE("TCP option SACK size is wrong\n");
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301369 if (ret) {
1370 sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH);
1371 }
1372 rcu_read_unlock();
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05301373
1374 sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_TCP_BAD_SACK);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001375 return 0;
1376 }
1377
1378 /*
1379 * Check that our TCP data offset isn't past the end of the packet.
1380 */
Ratheesh Kannoth741f7992021-10-20 07:39:52 +05301381 data_offs += sizeof(struct ipv6hdr);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001382 if (unlikely(len < data_offs)) {
1383 struct sfe_ipv6_connection *c = cm->connection;
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301384 spin_lock_bh(&si->lock);
1385 ret = sfe_ipv6_remove_connection(si, c);
Xiaoping Fan3c423e32015-07-03 03:09:29 -07001386 spin_unlock_bh(&si->lock);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001387
1388 DEBUG_TRACE("TCP data offset: %u, past end of packet: %u\n",
1389 data_offs, len);
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301390 if (ret) {
1391 sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH);
1392 }
1393 rcu_read_unlock();
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05301394
1395 sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_TCP_BIG_DATA_OFFS);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001396 return 0;
1397 }
1398
1399 end = seq + len - data_offs;
1400
1401 /*
1402 * Is our sequence fully before the left hand edge of the window?
1403 */
Xiaoping Fan6a1672f2016-08-17 19:58:12 -07001404 if (unlikely((s32)(end - (cm->protocol_state.tcp.end
Xiaoping Fan978b3772015-05-27 14:15:18 -07001405 - counter_cm->protocol_state.tcp.max_win - 1)) < 0)) {
1406 struct sfe_ipv6_connection *c = cm->connection;
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301407 spin_lock_bh(&si->lock);
1408 ret = sfe_ipv6_remove_connection(si, c);
Xiaoping Fan3c423e32015-07-03 03:09:29 -07001409 spin_unlock_bh(&si->lock);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001410
1411 DEBUG_TRACE("seq: %u before left edge: %u\n",
1412 end, cm->protocol_state.tcp.end - counter_cm->protocol_state.tcp.max_win - 1);
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301413 if (ret) {
1414 sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH);
1415 }
1416 rcu_read_unlock();
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05301417
1418 sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_TCP_SEQ_BEFORE_LEFT_EDGE);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001419 return 0;
1420 }
1421
1422 /*
1423 * Are we acking data that is to the right of what has been sent?
1424 */
Xiaoping Fan6a1672f2016-08-17 19:58:12 -07001425 if (unlikely((s32)(sack - (counter_cm->protocol_state.tcp.end + 1)) > 0)) {
Xiaoping Fan978b3772015-05-27 14:15:18 -07001426 struct sfe_ipv6_connection *c = cm->connection;
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301427 spin_lock_bh(&si->lock);
1428 ret = sfe_ipv6_remove_connection(si, c);
Xiaoping Fan3c423e32015-07-03 03:09:29 -07001429 spin_unlock_bh(&si->lock);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001430
1431 DEBUG_TRACE("ack: %u exceeds right edge: %u\n",
1432 sack, counter_cm->protocol_state.tcp.end + 1);
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301433 if (ret) {
1434 sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH);
1435 }
1436 rcu_read_unlock();
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05301437
1438 sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_TCP_ACK_EXCEEDS_RIGHT_EDGE);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001439 return 0;
1440 }
1441
1442 /*
1443 * Is our ack too far before the left hand edge of the window?
1444 */
1445 left_edge = counter_cm->protocol_state.tcp.end
1446 - cm->protocol_state.tcp.max_win
1447 - SFE_IPV6_TCP_MAX_ACK_WINDOW
1448 - 1;
Xiaoping Fan6a1672f2016-08-17 19:58:12 -07001449 if (unlikely((s32)(sack - left_edge) < 0)) {
Xiaoping Fan978b3772015-05-27 14:15:18 -07001450 struct sfe_ipv6_connection *c = cm->connection;
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301451 spin_lock_bh(&si->lock);
1452 ret = sfe_ipv6_remove_connection(si, c);
Xiaoping Fan3c423e32015-07-03 03:09:29 -07001453 spin_unlock_bh(&si->lock);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001454
1455 DEBUG_TRACE("ack: %u before left edge: %u\n", sack, left_edge);
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301456 if (ret) {
1457 sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH);
1458 }
1459 rcu_read_unlock();
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05301460
1461 sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_TCP_ACK_BEFORE_LEFT_EDGE);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001462 return 0;
1463 }
1464
1465 /*
1466 * Have we just seen the largest window size yet for this connection? If yes
1467 * then we need to record the new value.
1468 */
1469 scaled_win = ntohs(tcph->window) << cm->protocol_state.tcp.win_scale;
1470 scaled_win += (sack - ack);
1471 if (unlikely(cm->protocol_state.tcp.max_win < scaled_win)) {
1472 cm->protocol_state.tcp.max_win = scaled_win;
1473 }
1474
1475 /*
1476 * If our sequence and/or ack numbers have advanced then record the new state.
1477 */
Xiaoping Fan6a1672f2016-08-17 19:58:12 -07001478 if (likely((s32)(end - cm->protocol_state.tcp.end) >= 0)) {
Xiaoping Fan978b3772015-05-27 14:15:18 -07001479 cm->protocol_state.tcp.end = end;
1480 }
1481
1482 max_end = sack + scaled_win;
Xiaoping Fan6a1672f2016-08-17 19:58:12 -07001483 if (likely((s32)(max_end - counter_cm->protocol_state.tcp.max_end) >= 0)) {
Xiaoping Fan978b3772015-05-27 14:15:18 -07001484 counter_cm->protocol_state.tcp.max_end = max_end;
1485 }
1486 }
1487
1488 /*
1489 * From this point on we're good to modify the packet.
1490 */
1491
1492 /*
Murat Sezginc7dd8172019-02-27 15:23:50 -08001493 * Check if skb was cloned. If it was, unshare it. Because
1494 * the data area is going to be written in this path and we don't want to
1495 * change the cloned skb's data section.
1496 */
1497 if (unlikely(skb_cloned(skb))) {
Tian Yang45f39c82020-10-06 14:07:47 -07001498 DEBUG_TRACE("%px: skb is a cloned skb\n", skb);
Murat Sezginc7dd8172019-02-27 15:23:50 -08001499 skb = skb_unshare(skb, GFP_ATOMIC);
1500 if (!skb) {
1501 DEBUG_WARN("Failed to unshare the cloned skb\n");
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301502 rcu_read_unlock();
Murat Sezginc7dd8172019-02-27 15:23:50 -08001503 return 0;
1504 }
1505
1506 /*
1507 * Update the iph and tcph pointers with the unshared skb's data area.
1508 */
Ratheesh Kannoth741f7992021-10-20 07:39:52 +05301509 iph = (struct ipv6hdr *)skb->data;
1510 tcph = (struct tcphdr *)(skb->data + ihl);
Murat Sezginc7dd8172019-02-27 15:23:50 -08001511 }
1512
1513 /*
Xiaoping Fane1963d42015-08-25 17:06:19 -07001514 * Update DSCP
1515 */
1516 if (unlikely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_DSCP_REMARK)) {
1517 sfe_ipv6_change_dsfield(iph, cm->dscp);
1518 }
1519
1520 /*
Xiaoping Fan978b3772015-05-27 14:15:18 -07001521 * Decrement our hop_limit.
1522 */
1523 iph->hop_limit -= 1;
1524
1525 /*
1526 * Do we have to perform translations of the source address/port?
1527 */
1528 if (unlikely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_XLATE_SRC)) {
Xiaoping Fan6a1672f2016-08-17 19:58:12 -07001529 u16 tcp_csum;
1530 u32 sum;
Xiaoping Fan978b3772015-05-27 14:15:18 -07001531
Ratheesh Kannoth741f7992021-10-20 07:39:52 +05301532 iph->saddr.s6_addr32[0] = cm->xlate_src_ip[0].addr[0];
1533 iph->saddr.s6_addr32[1] = cm->xlate_src_ip[0].addr[1];
1534 iph->saddr.s6_addr32[2] = cm->xlate_src_ip[0].addr[2];
1535 iph->saddr.s6_addr32[3] = cm->xlate_src_ip[0].addr[3];
Xiaoping Fan978b3772015-05-27 14:15:18 -07001536 tcph->source = cm->xlate_src_port;
1537
1538 /*
1539 * Do we have a non-zero UDP checksum? If we do then we need
1540 * to update it.
1541 */
1542 tcp_csum = tcph->check;
1543 sum = tcp_csum + cm->xlate_src_csum_adjustment;
1544 sum = (sum & 0xffff) + (sum >> 16);
Xiaoping Fan6a1672f2016-08-17 19:58:12 -07001545 tcph->check = (u16)sum;
Xiaoping Fan978b3772015-05-27 14:15:18 -07001546 }
1547
1548 /*
1549 * Do we have to perform translations of the destination address/port?
1550 */
1551 if (unlikely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_XLATE_DEST)) {
Xiaoping Fan6a1672f2016-08-17 19:58:12 -07001552 u16 tcp_csum;
1553 u32 sum;
Xiaoping Fan978b3772015-05-27 14:15:18 -07001554
Ratheesh Kannoth741f7992021-10-20 07:39:52 +05301555 iph->daddr.s6_addr32[0] = cm->xlate_dest_ip[0].addr[0];
1556 iph->daddr.s6_addr32[1] = cm->xlate_dest_ip[0].addr[1];
1557 iph->daddr.s6_addr32[2] = cm->xlate_dest_ip[0].addr[2];
1558 iph->daddr.s6_addr32[3] = cm->xlate_dest_ip[0].addr[3];
Xiaoping Fan978b3772015-05-27 14:15:18 -07001559 tcph->dest = cm->xlate_dest_port;
1560
1561 /*
1562 * Do we have a non-zero UDP checksum? If we do then we need
1563 * to update it.
1564 */
1565 tcp_csum = tcph->check;
1566 sum = tcp_csum + cm->xlate_dest_csum_adjustment;
1567 sum = (sum & 0xffff) + (sum >> 16);
Xiaoping Fan6a1672f2016-08-17 19:58:12 -07001568 tcph->check = (u16)sum;
Xiaoping Fan978b3772015-05-27 14:15:18 -07001569 }
1570
1571 /*
1572 * Update traffic stats.
1573 */
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301574 atomic_inc(&cm->rx_packet_count);
1575 atomic_add(len, &cm->rx_byte_count);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001576
1577 /*
1578 * If we're not already on the active list then insert ourselves at the tail
1579 * of the current list.
1580 */
1581 if (unlikely(!cm->active)) {
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301582 spin_lock_bh(&si->lock);
1583 if (unlikely(!cm->active)) {
1584 cm->active = true;
1585 cm->active_prev = si->active_tail;
1586 if (likely(si->active_tail)) {
1587 si->active_tail->active_next = cm;
1588 } else {
1589 si->active_head = cm;
1590 }
1591 si->active_tail = cm;
Xiaoping Fan978b3772015-05-27 14:15:18 -07001592 }
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301593 spin_unlock_bh(&si->lock);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001594 }
1595
1596 xmit_dev = cm->xmit_dev;
1597 skb->dev = xmit_dev;
1598
1599 /*
1600 * Check to see if we need to write a header.
1601 */
1602 if (likely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_WRITE_L2_HDR)) {
1603 if (unlikely(!(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_WRITE_FAST_ETH_HDR))) {
Xiaoping Fan2784e612015-06-25 17:57:41 -07001604 dev_hard_header(skb, xmit_dev, ETH_P_IPV6,
1605 cm->xmit_dest_mac, cm->xmit_src_mac, len);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001606 } else {
1607 /*
1608 * For the simple case we write this really fast.
1609 */
Ratheesh Kannoth741f7992021-10-20 07:39:52 +05301610 struct ethhdr *eth = (struct ethhdr *)__skb_push(skb, ETH_HLEN);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001611 eth->h_proto = htons(ETH_P_IPV6);
Ratheesh Kannoth741f7992021-10-20 07:39:52 +05301612 ether_addr_copy((u8 *)eth->h_dest, (u8 *)cm->xmit_dest_mac);
1613 ether_addr_copy((u8 *)eth->h_source, (u8 *)cm->xmit_src_mac);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001614 }
1615 }
1616
1617 /*
Xiaoping Fane1963d42015-08-25 17:06:19 -07001618 * Update priority of skb.
1619 */
1620 if (unlikely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_PRIORITY_REMARK)) {
1621 skb->priority = cm->priority;
1622 }
1623
1624 /*
Xiaoping Fan978b3772015-05-27 14:15:18 -07001625 * Mark outgoing packet
1626 */
1627 skb->mark = cm->connection->mark;
1628 if (skb->mark) {
1629 DEBUG_TRACE("SKB MARK is NON ZERO %x\n", skb->mark);
1630 }
1631
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301632 rcu_read_unlock();
1633
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05301634 this_cpu_inc(si->stats_pcpu->packets_forwarded64);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001635
1636 /*
1637 * We're going to check for GSO flags when we transmit the packet so
1638 * start fetching the necessary cache line now.
1639 */
1640 prefetch(skb_shinfo(skb));
1641
1642 /*
1643 * Mark that this packet has been fast forwarded.
1644 */
1645 skb->fast_forwarded = 1;
1646
1647 /*
1648 * Send the packet on its way.
1649 */
1650 dev_queue_xmit(skb);
1651
1652 return 1;
1653}
1654
1655/*
1656 * sfe_ipv6_recv_icmp()
1657 * Handle ICMP packet receives.
1658 *
1659 * ICMP packets aren't handled as a "fast path" and always have us process them
1660 * through the default Linux stack. What we do need to do is look for any errors
1661 * about connections we are handling in the fast path. If we find any such
1662 * connections then we want to flush their state so that the ICMP error path
1663 * within Linux has all of the correct state should it need it.
1664 */
1665static int sfe_ipv6_recv_icmp(struct sfe_ipv6 *si, struct sk_buff *skb, struct net_device *dev,
Ratheesh Kannoth741f7992021-10-20 07:39:52 +05301666 unsigned int len, struct ipv6hdr *iph, unsigned int ihl)
Xiaoping Fan978b3772015-05-27 14:15:18 -07001667{
1668 struct icmp6hdr *icmph;
Ratheesh Kannoth741f7992021-10-20 07:39:52 +05301669 struct ipv6hdr *icmp_iph;
1670 struct udphdr *icmp_udph;
1671 struct tcphdr *icmp_tcph;
Xiaoping Fan978b3772015-05-27 14:15:18 -07001672 struct sfe_ipv6_addr *src_ip;
1673 struct sfe_ipv6_addr *dest_ip;
1674 __be16 src_port;
1675 __be16 dest_port;
1676 struct sfe_ipv6_connection_match *cm;
1677 struct sfe_ipv6_connection *c;
Xiaoping Fan6a1672f2016-08-17 19:58:12 -07001678 u8 next_hdr;
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301679 bool ret;
Xiaoping Fan978b3772015-05-27 14:15:18 -07001680
1681 /*
Xiaoping Fan6a1672f2016-08-17 19:58:12 -07001682 * Is our packet too short to contain a valid ICMP header?
Xiaoping Fan978b3772015-05-27 14:15:18 -07001683 */
1684 len -= ihl;
1685 if (!pskb_may_pull(skb, ihl + sizeof(struct icmp6hdr))) {
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05301686 sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_ICMP_HEADER_INCOMPLETE);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001687
1688 DEBUG_TRACE("packet too short for ICMP header\n");
1689 return 0;
1690 }
1691
1692 /*
1693 * We only handle "destination unreachable" and "time exceeded" messages.
1694 */
1695 icmph = (struct icmp6hdr *)(skb->data + ihl);
1696 if ((icmph->icmp6_type != ICMPV6_DEST_UNREACH)
1697 && (icmph->icmp6_type != ICMPV6_TIME_EXCEED)) {
Xiaoping Fan978b3772015-05-27 14:15:18 -07001698
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05301699 sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_ICMP_UNHANDLED_TYPE);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001700 DEBUG_TRACE("unhandled ICMP type: 0x%x\n", icmph->icmp6_type);
1701 return 0;
1702 }
1703
1704 /*
1705 * Do we have the full embedded IP header?
1706 * We should have 8 bytes of next L4 header - that's enough to identify
1707 * the connection.
1708 */
1709 len -= sizeof(struct icmp6hdr);
1710 ihl += sizeof(struct icmp6hdr);
Ratheesh Kannoth741f7992021-10-20 07:39:52 +05301711 if (!pskb_may_pull(skb, ihl + sizeof(struct ipv6hdr) + sizeof(struct sfe_ipv6_ext_hdr))) {
Xiaoping Fan978b3772015-05-27 14:15:18 -07001712
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05301713 sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_ICMP_IPV6_HEADER_INCOMPLETE);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001714 DEBUG_TRACE("Embedded IP header not complete\n");
1715 return 0;
1716 }
1717
1718 /*
1719 * Is our embedded IP version wrong?
1720 */
Ratheesh Kannoth741f7992021-10-20 07:39:52 +05301721 icmp_iph = (struct ipv6hdr *)(icmph + 1);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001722 if (unlikely(icmp_iph->version != 6)) {
Xiaoping Fan978b3772015-05-27 14:15:18 -07001723
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05301724 sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_ICMP_IPV6_NON_V6);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001725 DEBUG_TRACE("IP version: %u\n", icmp_iph->version);
1726 return 0;
1727 }
1728
Ratheesh Kannoth741f7992021-10-20 07:39:52 +05301729 len -= sizeof(struct ipv6hdr);
1730 ihl += sizeof(struct ipv6hdr);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001731 next_hdr = icmp_iph->nexthdr;
1732 while (unlikely(sfe_ipv6_is_ext_hdr(next_hdr))) {
1733 struct sfe_ipv6_ext_hdr *ext_hdr;
1734 unsigned int ext_hdr_len;
1735
1736 ext_hdr = (struct sfe_ipv6_ext_hdr *)(skb->data + ihl);
Ratheesh Kannoth741f7992021-10-20 07:39:52 +05301737 if (next_hdr == NEXTHDR_FRAGMENT) {
1738 struct frag_hdr *frag_hdr = (struct frag_hdr *)ext_hdr;
Xiaoping Fan978b3772015-05-27 14:15:18 -07001739 unsigned int frag_off = ntohs(frag_hdr->frag_off);
1740
1741 if (frag_off & SFE_IPV6_FRAG_OFFSET) {
Xiaoping Fan978b3772015-05-27 14:15:18 -07001742
1743 DEBUG_TRACE("non-initial fragment\n");
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05301744 sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_NON_INITIAL_FRAGMENT);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001745 return 0;
1746 }
1747 }
1748
1749 ext_hdr_len = ext_hdr->hdr_len;
1750 ext_hdr_len <<= 3;
1751 ext_hdr_len += sizeof(struct sfe_ipv6_ext_hdr);
1752 len -= ext_hdr_len;
1753 ihl += ext_hdr_len;
1754 /*
1755 * We should have 8 bytes of next header - that's enough to identify
1756 * the connection.
1757 */
1758 if (!pskb_may_pull(skb, ihl + sizeof(struct sfe_ipv6_ext_hdr))) {
Xiaoping Fan978b3772015-05-27 14:15:18 -07001759
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05301760 sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_HEADER_INCOMPLETE);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001761 DEBUG_TRACE("extension header %d not completed\n", next_hdr);
1762 return 0;
1763 }
1764
1765 next_hdr = ext_hdr->next_hdr;
1766 }
1767
1768 /*
1769 * Handle the embedded transport layer header.
1770 */
1771 switch (next_hdr) {
1772 case IPPROTO_UDP:
Ratheesh Kannoth741f7992021-10-20 07:39:52 +05301773 icmp_udph = (struct udphdr *)(skb->data + ihl);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001774 src_port = icmp_udph->source;
1775 dest_port = icmp_udph->dest;
1776 break;
1777
1778 case IPPROTO_TCP:
Ratheesh Kannoth741f7992021-10-20 07:39:52 +05301779 icmp_tcph = (struct tcphdr *)(skb->data + ihl);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001780 src_port = icmp_tcph->source;
1781 dest_port = icmp_tcph->dest;
1782 break;
1783
1784 default:
Xiaoping Fan978b3772015-05-27 14:15:18 -07001785
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05301786 sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_ICMP_IPV6_UNHANDLED_PROTOCOL);
Ryan Sherlock47c5a702016-01-12 07:27:05 -06001787 DEBUG_TRACE("Unhandled embedded IP protocol: %u\n", next_hdr);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001788 return 0;
1789 }
1790
Ratheesh Kannoth741f7992021-10-20 07:39:52 +05301791 src_ip = (struct sfe_ipv6_addr *)icmp_iph->saddr.s6_addr32;
1792 dest_ip = (struct sfe_ipv6_addr *)icmp_iph->daddr.s6_addr32;
Xiaoping Fan978b3772015-05-27 14:15:18 -07001793
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301794 rcu_read_lock();
Xiaoping Fan978b3772015-05-27 14:15:18 -07001795 /*
1796 * Look for a connection match. Note that we reverse the source and destination
1797 * here because our embedded message contains a packet that was sent in the
1798 * opposite direction to the one in which we just received it. It will have
1799 * been sent on the interface from which we received it though so that's still
1800 * ok to use.
1801 */
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301802 cm = sfe_ipv6_find_connection_match_rcu(si, dev, icmp_iph->nexthdr, dest_ip, dest_port, src_ip, src_port);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001803 if (unlikely(!cm)) {
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301804 rcu_read_unlock();
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05301805 sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_ICMP_NO_CONNECTION);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001806 DEBUG_TRACE("no connection found\n");
1807 return 0;
1808 }
1809
1810 /*
1811 * We found a connection so now remove it from the connection list and flush
1812 * its state.
1813 */
1814 c = cm->connection;
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301815 spin_lock_bh(&si->lock);
1816 ret = sfe_ipv6_remove_connection(si, c);
Xiaoping Fan3c423e32015-07-03 03:09:29 -07001817 spin_unlock_bh(&si->lock);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001818
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05301819 if (ret) {
1820 sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_FLUSH);
1821 }
1822
1823 rcu_read_unlock();
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05301824
1825 sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_ICMP_FLUSHED_CONNECTION);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001826 return 0;
1827}
1828
1829/*
1830 * sfe_ipv6_recv()
1831 * Handle packet receives and forwaring.
1832 *
1833 * Returns 1 if the packet is forwarded or 0 if it isn't.
1834 */
1835int sfe_ipv6_recv(struct net_device *dev, struct sk_buff *skb)
1836{
1837 struct sfe_ipv6 *si = &__si6;
1838 unsigned int len;
1839 unsigned int payload_len;
Ratheesh Kannoth741f7992021-10-20 07:39:52 +05301840 unsigned int ihl = sizeof(struct ipv6hdr);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001841 bool flush_on_find = false;
Ratheesh Kannoth741f7992021-10-20 07:39:52 +05301842 struct ipv6hdr *iph;
Xiaoping Fan6a1672f2016-08-17 19:58:12 -07001843 u8 next_hdr;
Xiaoping Fan978b3772015-05-27 14:15:18 -07001844
1845 /*
1846 * Check that we have space for an IP header and an uplayer header here.
1847 */
1848 len = skb->len;
1849 if (!pskb_may_pull(skb, ihl + sizeof(struct sfe_ipv6_ext_hdr))) {
Xiaoping Fan978b3772015-05-27 14:15:18 -07001850
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05301851 sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_HEADER_INCOMPLETE);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001852 DEBUG_TRACE("len: %u is too short\n", len);
1853 return 0;
1854 }
1855
1856 /*
1857 * Is our IP version wrong?
1858 */
Ratheesh Kannoth741f7992021-10-20 07:39:52 +05301859 iph = (struct ipv6hdr *)skb->data;
Xiaoping Fan978b3772015-05-27 14:15:18 -07001860 if (unlikely(iph->version != 6)) {
Xiaoping Fan978b3772015-05-27 14:15:18 -07001861
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05301862 sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_NON_V6);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001863 DEBUG_TRACE("IP version: %u\n", iph->version);
1864 return 0;
1865 }
1866
1867 /*
1868 * Does our datagram fit inside the skb?
1869 */
1870 payload_len = ntohs(iph->payload_len);
1871 if (unlikely(payload_len > (len - ihl))) {
Xiaoping Fan978b3772015-05-27 14:15:18 -07001872
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05301873 sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_DATAGRAM_INCOMPLETE);
Ratheesh Kannoth741f7992021-10-20 07:39:52 +05301874 DEBUG_TRACE("payload_len: %u, exceeds len: %u\n", payload_len, (len - (unsigned int)sizeof(struct ipv6hdr)));
Xiaoping Fan978b3772015-05-27 14:15:18 -07001875 return 0;
1876 }
1877
1878 next_hdr = iph->nexthdr;
1879 while (unlikely(sfe_ipv6_is_ext_hdr(next_hdr))) {
1880 struct sfe_ipv6_ext_hdr *ext_hdr;
1881 unsigned int ext_hdr_len;
1882
1883 ext_hdr = (struct sfe_ipv6_ext_hdr *)(skb->data + ihl);
Ratheesh Kannoth741f7992021-10-20 07:39:52 +05301884 if (next_hdr == NEXTHDR_FRAGMENT) {
1885 struct frag_hdr *frag_hdr = (struct frag_hdr *)ext_hdr;
Xiaoping Fan978b3772015-05-27 14:15:18 -07001886 unsigned int frag_off = ntohs(frag_hdr->frag_off);
1887
1888 if (frag_off & SFE_IPV6_FRAG_OFFSET) {
Xiaoping Fan978b3772015-05-27 14:15:18 -07001889
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05301890 sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_NON_INITIAL_FRAGMENT);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001891 DEBUG_TRACE("non-initial fragment\n");
1892 return 0;
1893 }
1894 }
1895
1896 ext_hdr_len = ext_hdr->hdr_len;
1897 ext_hdr_len <<= 3;
1898 ext_hdr_len += sizeof(struct sfe_ipv6_ext_hdr);
1899 ihl += ext_hdr_len;
1900 if (!pskb_may_pull(skb, ihl + sizeof(struct sfe_ipv6_ext_hdr))) {
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05301901 sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_HEADER_INCOMPLETE);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001902
1903 DEBUG_TRACE("extension header %d not completed\n", next_hdr);
1904 return 0;
1905 }
1906
1907 flush_on_find = true;
1908 next_hdr = ext_hdr->next_hdr;
1909 }
1910
1911 if (IPPROTO_UDP == next_hdr) {
1912 return sfe_ipv6_recv_udp(si, skb, dev, len, iph, ihl, flush_on_find);
1913 }
1914
1915 if (IPPROTO_TCP == next_hdr) {
1916 return sfe_ipv6_recv_tcp(si, skb, dev, len, iph, ihl, flush_on_find);
1917 }
1918
1919 if (IPPROTO_ICMPV6 == next_hdr) {
1920 return sfe_ipv6_recv_icmp(si, skb, dev, len, iph, ihl);
1921 }
1922
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05301923 sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_UNHANDLED_PROTOCOL);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001924 DEBUG_TRACE("not UDP, TCP or ICMP: %u\n", next_hdr);
1925 return 0;
1926}
1927
1928/*
1929 * sfe_ipv6_update_tcp_state()
1930 * update TCP window variables.
1931 */
1932static void
1933sfe_ipv6_update_tcp_state(struct sfe_ipv6_connection *c,
1934 struct sfe_connection_create *sic)
1935{
1936 struct sfe_ipv6_connection_match *orig_cm;
1937 struct sfe_ipv6_connection_match *repl_cm;
1938 struct sfe_ipv6_tcp_connection_match *orig_tcp;
1939 struct sfe_ipv6_tcp_connection_match *repl_tcp;
1940
1941 orig_cm = c->original_match;
1942 repl_cm = c->reply_match;
1943 orig_tcp = &orig_cm->protocol_state.tcp;
1944 repl_tcp = &repl_cm->protocol_state.tcp;
1945
1946 /* update orig */
1947 if (orig_tcp->max_win < sic->src_td_max_window) {
1948 orig_tcp->max_win = sic->src_td_max_window;
1949 }
Xiaoping Fan6a1672f2016-08-17 19:58:12 -07001950 if ((s32)(orig_tcp->end - sic->src_td_end) < 0) {
Xiaoping Fan978b3772015-05-27 14:15:18 -07001951 orig_tcp->end = sic->src_td_end;
1952 }
Xiaoping Fan6a1672f2016-08-17 19:58:12 -07001953 if ((s32)(orig_tcp->max_end - sic->src_td_max_end) < 0) {
Xiaoping Fan978b3772015-05-27 14:15:18 -07001954 orig_tcp->max_end = sic->src_td_max_end;
1955 }
1956
1957 /* update reply */
1958 if (repl_tcp->max_win < sic->dest_td_max_window) {
1959 repl_tcp->max_win = sic->dest_td_max_window;
1960 }
Xiaoping Fan6a1672f2016-08-17 19:58:12 -07001961 if ((s32)(repl_tcp->end - sic->dest_td_end) < 0) {
Xiaoping Fan978b3772015-05-27 14:15:18 -07001962 repl_tcp->end = sic->dest_td_end;
1963 }
Xiaoping Fan6a1672f2016-08-17 19:58:12 -07001964 if ((s32)(repl_tcp->max_end - sic->dest_td_max_end) < 0) {
Xiaoping Fan978b3772015-05-27 14:15:18 -07001965 repl_tcp->max_end = sic->dest_td_max_end;
1966 }
1967
1968 /* update match flags */
1969 orig_cm->flags &= ~SFE_IPV6_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK;
1970 repl_cm->flags &= ~SFE_IPV6_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK;
1971 if (sic->flags & SFE_CREATE_FLAG_NO_SEQ_CHECK) {
1972 orig_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK;
1973 repl_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK;
1974 }
1975}
1976
1977/*
1978 * sfe_ipv6_update_protocol_state()
1979 * update protocol specified state machine.
1980 */
1981static void
1982sfe_ipv6_update_protocol_state(struct sfe_ipv6_connection *c,
1983 struct sfe_connection_create *sic)
1984{
1985 switch (sic->protocol) {
1986 case IPPROTO_TCP:
1987 sfe_ipv6_update_tcp_state(c, sic);
1988 break;
1989 }
1990}
1991
1992/*
1993 * sfe_ipv6_update_rule()
1994 * update forwarding rule after rule is created.
1995 */
1996void sfe_ipv6_update_rule(struct sfe_connection_create *sic)
1997{
1998 struct sfe_ipv6_connection *c;
1999 struct sfe_ipv6 *si = &__si6;
2000
2001 spin_lock_bh(&si->lock);
2002
2003 c = sfe_ipv6_find_connection(si,
2004 sic->protocol,
2005 sic->src_ip.ip6,
2006 sic->src_port,
2007 sic->dest_ip.ip6,
2008 sic->dest_port);
2009 if (c != NULL) {
2010 sfe_ipv6_update_protocol_state(c, sic);
2011 }
2012
2013 spin_unlock_bh(&si->lock);
2014}
2015
2016/*
2017 * sfe_ipv6_create_rule()
2018 * Create a forwarding rule.
2019 */
2020int sfe_ipv6_create_rule(struct sfe_connection_create *sic)
2021{
2022 struct sfe_ipv6 *si = &__si6;
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05302023 struct sfe_ipv6_connection *c, *old_c;
Xiaoping Fan978b3772015-05-27 14:15:18 -07002024 struct sfe_ipv6_connection_match *original_cm;
2025 struct sfe_ipv6_connection_match *reply_cm;
2026 struct net_device *dest_dev;
2027 struct net_device *src_dev;
2028
2029 dest_dev = sic->dest_dev;
2030 src_dev = sic->src_dev;
2031
2032 if (unlikely((dest_dev->reg_state != NETREG_REGISTERED) ||
2033 (src_dev->reg_state != NETREG_REGISTERED))) {
2034 return -EINVAL;
2035 }
2036
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05302037 /*
2038 * Allocate the various connection tracking objects.
2039 */
2040 c = (struct sfe_ipv6_connection *)kmalloc(sizeof(struct sfe_ipv6_connection), GFP_ATOMIC);
2041 if (unlikely(!c)) {
2042 return -ENOMEM;
2043 }
2044
2045 original_cm = (struct sfe_ipv6_connection_match *)kmalloc(sizeof(struct sfe_ipv6_connection_match), GFP_ATOMIC);
2046 if (unlikely(!original_cm)) {
2047 kfree(c);
2048 return -ENOMEM;
2049 }
2050
2051 reply_cm = (struct sfe_ipv6_connection_match *)kmalloc(sizeof(struct sfe_ipv6_connection_match), GFP_ATOMIC);
2052 if (unlikely(!reply_cm)) {
2053 kfree(original_cm);
2054 kfree(c);
2055 return -ENOMEM;
2056 }
2057
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05302058 this_cpu_inc(si->stats_pcpu->connection_create_requests64);
2059
Xiaoping Fan978b3772015-05-27 14:15:18 -07002060 spin_lock_bh(&si->lock);
Xiaoping Fan978b3772015-05-27 14:15:18 -07002061
2062 /*
2063 * Check to see if there is already a flow that matches the rule we're
2064 * trying to create. If there is then we can't create a new one.
2065 */
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05302066 old_c = sfe_ipv6_find_connection(si,
Xiaoping Fan978b3772015-05-27 14:15:18 -07002067 sic->protocol,
2068 sic->src_ip.ip6,
2069 sic->src_port,
2070 sic->dest_ip.ip6,
2071 sic->dest_port);
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05302072 if (old_c != NULL) {
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05302073 this_cpu_inc(si->stats_pcpu->connection_create_collisions64);
Xiaoping Fan978b3772015-05-27 14:15:18 -07002074
2075 /*
2076 * If we already have the flow then it's likely that this
2077 * request to create the connection rule contains more
2078 * up-to-date information. Check and update accordingly.
2079 */
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05302080 sfe_ipv6_update_protocol_state(old_c, sic);
Xiaoping Fan978b3772015-05-27 14:15:18 -07002081 spin_unlock_bh(&si->lock);
2082
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05302083 kfree(reply_cm);
2084 kfree(original_cm);
2085 kfree(c);
2086
Xiaoping Fan978b3772015-05-27 14:15:18 -07002087 DEBUG_TRACE("connection already exists - mark: %08x, p: %d\n"
Tian Yang45f39c82020-10-06 14:07:47 -07002088 " s: %s:%pxM:%pI6:%u, d: %s:%pxM:%pI6:%u\n",
Xiaoping Fan978b3772015-05-27 14:15:18 -07002089 sic->mark, sic->protocol,
2090 sic->src_dev->name, sic->src_mac, sic->src_ip.ip6, ntohs(sic->src_port),
2091 sic->dest_dev->name, sic->dest_mac, sic->dest_ip.ip6, ntohs(sic->dest_port));
2092 return -EADDRINUSE;
2093 }
2094
2095 /*
Xiaoping Fan978b3772015-05-27 14:15:18 -07002096 * Fill in the "original" direction connection matching object.
2097 * Note that the transmit MAC address is "dest_mac_xlate" because
2098 * we always know both ends of a connection by their translated
2099 * addresses and not their public addresses.
2100 */
2101 original_cm->match_dev = src_dev;
2102 original_cm->match_protocol = sic->protocol;
2103 original_cm->match_src_ip[0] = sic->src_ip.ip6[0];
2104 original_cm->match_src_port = sic->src_port;
2105 original_cm->match_dest_ip[0] = sic->dest_ip.ip6[0];
2106 original_cm->match_dest_port = sic->dest_port;
2107 original_cm->xlate_src_ip[0] = sic->src_ip_xlate.ip6[0];
2108 original_cm->xlate_src_port = sic->src_port_xlate;
2109 original_cm->xlate_dest_ip[0] = sic->dest_ip_xlate.ip6[0];
2110 original_cm->xlate_dest_port = sic->dest_port_xlate;
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05302111 atomic_set(&original_cm->rx_packet_count, 0);
Xiaoping Fan978b3772015-05-27 14:15:18 -07002112 original_cm->rx_packet_count64 = 0;
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05302113 atomic_set(&original_cm->rx_byte_count, 0);
Xiaoping Fan978b3772015-05-27 14:15:18 -07002114 original_cm->rx_byte_count64 = 0;
2115 original_cm->xmit_dev = dest_dev;
2116 original_cm->xmit_dev_mtu = sic->dest_mtu;
2117 memcpy(original_cm->xmit_src_mac, dest_dev->dev_addr, ETH_ALEN);
2118 memcpy(original_cm->xmit_dest_mac, sic->dest_mac_xlate, ETH_ALEN);
2119 original_cm->connection = c;
2120 original_cm->counter_match = reply_cm;
2121 original_cm->flags = 0;
Xiaoping Fane1963d42015-08-25 17:06:19 -07002122 if (sic->flags & SFE_CREATE_FLAG_REMARK_PRIORITY) {
2123 original_cm->priority = sic->src_priority;
2124 original_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_PRIORITY_REMARK;
2125 }
2126 if (sic->flags & SFE_CREATE_FLAG_REMARK_DSCP) {
2127 original_cm->dscp = sic->src_dscp << SFE_IPV6_DSCP_SHIFT;
2128 original_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_DSCP_REMARK;
2129 }
Xiaoping Fan978b3772015-05-27 14:15:18 -07002130#ifdef CONFIG_NF_FLOW_COOKIE
2131 original_cm->flow_cookie = 0;
2132#endif
Zhi Chen8748eb32015-06-18 12:58:48 -07002133#ifdef CONFIG_XFRM
2134 original_cm->flow_accel = sic->original_accel;
2135#endif
Xiaoping Fan978b3772015-05-27 14:15:18 -07002136 original_cm->active_next = NULL;
2137 original_cm->active_prev = NULL;
2138 original_cm->active = false;
2139
2140 /*
2141 * For PPP links we don't write an L2 header. For everything else we do.
2142 */
2143 if (!(dest_dev->flags & IFF_POINTOPOINT)) {
2144 original_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_WRITE_L2_HDR;
2145
2146 /*
2147 * If our dev writes Ethernet headers then we can write a really fast
2148 * version.
2149 */
2150 if (dest_dev->header_ops) {
2151 if (dest_dev->header_ops->create == eth_header) {
2152 original_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_WRITE_FAST_ETH_HDR;
2153 }
2154 }
2155 }
2156
2157 /*
2158 * Fill in the "reply" direction connection matching object.
2159 */
2160 reply_cm->match_dev = dest_dev;
2161 reply_cm->match_protocol = sic->protocol;
2162 reply_cm->match_src_ip[0] = sic->dest_ip_xlate.ip6[0];
2163 reply_cm->match_src_port = sic->dest_port_xlate;
2164 reply_cm->match_dest_ip[0] = sic->src_ip_xlate.ip6[0];
2165 reply_cm->match_dest_port = sic->src_port_xlate;
2166 reply_cm->xlate_src_ip[0] = sic->dest_ip.ip6[0];
2167 reply_cm->xlate_src_port = sic->dest_port;
2168 reply_cm->xlate_dest_ip[0] = sic->src_ip.ip6[0];
2169 reply_cm->xlate_dest_port = sic->src_port;
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05302170 atomic_set(&original_cm->rx_byte_count, 0);
Xiaoping Fan978b3772015-05-27 14:15:18 -07002171 reply_cm->rx_packet_count64 = 0;
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05302172 atomic_set(&reply_cm->rx_byte_count, 0);
Xiaoping Fan978b3772015-05-27 14:15:18 -07002173 reply_cm->rx_byte_count64 = 0;
2174 reply_cm->xmit_dev = src_dev;
2175 reply_cm->xmit_dev_mtu = sic->src_mtu;
2176 memcpy(reply_cm->xmit_src_mac, src_dev->dev_addr, ETH_ALEN);
2177 memcpy(reply_cm->xmit_dest_mac, sic->src_mac, ETH_ALEN);
2178 reply_cm->connection = c;
2179 reply_cm->counter_match = original_cm;
2180 reply_cm->flags = 0;
Xiaoping Fane1963d42015-08-25 17:06:19 -07002181 if (sic->flags & SFE_CREATE_FLAG_REMARK_PRIORITY) {
2182 reply_cm->priority = sic->dest_priority;
2183 reply_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_PRIORITY_REMARK;
2184 }
2185 if (sic->flags & SFE_CREATE_FLAG_REMARK_DSCP) {
2186 reply_cm->dscp = sic->dest_dscp << SFE_IPV6_DSCP_SHIFT;
2187 reply_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_DSCP_REMARK;
2188 }
Xiaoping Fan978b3772015-05-27 14:15:18 -07002189#ifdef CONFIG_NF_FLOW_COOKIE
2190 reply_cm->flow_cookie = 0;
2191#endif
Zhi Chen8748eb32015-06-18 12:58:48 -07002192#ifdef CONFIG_XFRM
2193 reply_cm->flow_accel = sic->reply_accel;
2194#endif
Xiaoping Fan978b3772015-05-27 14:15:18 -07002195 reply_cm->active_next = NULL;
2196 reply_cm->active_prev = NULL;
2197 reply_cm->active = false;
2198
2199 /*
2200 * For PPP links we don't write an L2 header. For everything else we do.
2201 */
2202 if (!(src_dev->flags & IFF_POINTOPOINT)) {
2203 reply_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_WRITE_L2_HDR;
2204
2205 /*
2206 * If our dev writes Ethernet headers then we can write a really fast
2207 * version.
2208 */
2209 if (src_dev->header_ops) {
2210 if (src_dev->header_ops->create == eth_header) {
2211 reply_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_WRITE_FAST_ETH_HDR;
2212 }
2213 }
2214 }
2215
Xiaoping Fan978b3772015-05-27 14:15:18 -07002216 if (!sfe_ipv6_addr_equal(sic->dest_ip.ip6, sic->dest_ip_xlate.ip6) || sic->dest_port != sic->dest_port_xlate) {
2217 original_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_XLATE_DEST;
2218 reply_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_XLATE_SRC;
2219 }
2220
2221 if (!sfe_ipv6_addr_equal(sic->src_ip.ip6, sic->src_ip_xlate.ip6) || sic->src_port != sic->src_port_xlate) {
2222 original_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_XLATE_SRC;
2223 reply_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_XLATE_DEST;
2224 }
2225
2226 c->protocol = sic->protocol;
2227 c->src_ip[0] = sic->src_ip.ip6[0];
2228 c->src_ip_xlate[0] = sic->src_ip_xlate.ip6[0];
2229 c->src_port = sic->src_port;
2230 c->src_port_xlate = sic->src_port_xlate;
2231 c->original_dev = src_dev;
2232 c->original_match = original_cm;
2233 c->dest_ip[0] = sic->dest_ip.ip6[0];
2234 c->dest_ip_xlate[0] = sic->dest_ip_xlate.ip6[0];
2235 c->dest_port = sic->dest_port;
2236 c->dest_port_xlate = sic->dest_port_xlate;
2237 c->reply_dev = dest_dev;
2238 c->reply_match = reply_cm;
2239 c->mark = sic->mark;
Xiaoping Fan34586472015-07-03 02:20:35 -07002240 c->debug_read_seq = 0;
Xiaoping Fan978b3772015-05-27 14:15:18 -07002241 c->last_sync_jiffies = get_jiffies_64();
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05302242 c->removed = false;
Xiaoping Fan978b3772015-05-27 14:15:18 -07002243
2244 /*
2245 * Take hold of our source and dest devices for the duration of the connection.
2246 */
2247 dev_hold(c->original_dev);
2248 dev_hold(c->reply_dev);
2249
2250 /*
2251 * Initialize the protocol-specific information that we track.
2252 */
2253 switch (sic->protocol) {
2254 case IPPROTO_TCP:
2255 original_cm->protocol_state.tcp.win_scale = sic->src_td_window_scale;
2256 original_cm->protocol_state.tcp.max_win = sic->src_td_max_window ? sic->src_td_max_window : 1;
2257 original_cm->protocol_state.tcp.end = sic->src_td_end;
2258 original_cm->protocol_state.tcp.max_end = sic->src_td_max_end;
2259 reply_cm->protocol_state.tcp.win_scale = sic->dest_td_window_scale;
2260 reply_cm->protocol_state.tcp.max_win = sic->dest_td_max_window ? sic->dest_td_max_window : 1;
2261 reply_cm->protocol_state.tcp.end = sic->dest_td_end;
2262 reply_cm->protocol_state.tcp.max_end = sic->dest_td_max_end;
2263 if (sic->flags & SFE_CREATE_FLAG_NO_SEQ_CHECK) {
2264 original_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK;
2265 reply_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK;
2266 }
2267 break;
2268 }
2269
2270 sfe_ipv6_connection_match_compute_translations(original_cm);
2271 sfe_ipv6_connection_match_compute_translations(reply_cm);
2272 sfe_ipv6_insert_connection(si, c);
2273
2274 spin_unlock_bh(&si->lock);
2275
2276 /*
2277 * We have everything we need!
2278 */
2279 DEBUG_INFO("new connection - mark: %08x, p: %d\n"
Tian Yang45f39c82020-10-06 14:07:47 -07002280 " s: %s:%pxM(%pxM):%pI6(%pI6):%u(%u)\n"
2281 " d: %s:%pxM(%pxM):%pI6(%pI6):%u(%u)\n",
Xiaoping Fan978b3772015-05-27 14:15:18 -07002282 sic->mark, sic->protocol,
2283 sic->src_dev->name, sic->src_mac, sic->src_mac_xlate,
2284 sic->src_ip.ip6, sic->src_ip_xlate.ip6, ntohs(sic->src_port), ntohs(sic->src_port_xlate),
2285 dest_dev->name, sic->dest_mac, sic->dest_mac_xlate,
2286 sic->dest_ip.ip6, sic->dest_ip_xlate.ip6, ntohs(sic->dest_port), ntohs(sic->dest_port_xlate));
2287
2288 return 0;
2289}
2290
2291/*
2292 * sfe_ipv6_destroy_rule()
2293 * Destroy a forwarding rule.
2294 */
2295void sfe_ipv6_destroy_rule(struct sfe_connection_destroy *sid)
2296{
2297 struct sfe_ipv6 *si = &__si6;
2298 struct sfe_ipv6_connection *c;
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05302299 bool ret;
Xiaoping Fan978b3772015-05-27 14:15:18 -07002300
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05302301 this_cpu_inc(si->stats_pcpu->connection_destroy_requests64);
2302
Xiaoping Fan978b3772015-05-27 14:15:18 -07002303 spin_lock_bh(&si->lock);
Xiaoping Fan978b3772015-05-27 14:15:18 -07002304
2305 /*
2306 * Check to see if we have a flow that matches the rule we're trying
2307 * to destroy. If there isn't then we can't destroy it.
2308 */
2309 c = sfe_ipv6_find_connection(si, sid->protocol, sid->src_ip.ip6, sid->src_port,
2310 sid->dest_ip.ip6, sid->dest_port);
2311 if (!c) {
Xiaoping Fan978b3772015-05-27 14:15:18 -07002312 spin_unlock_bh(&si->lock);
2313
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05302314 this_cpu_inc(si->stats_pcpu->connection_destroy_misses64);
2315
Xiaoping Fan978b3772015-05-27 14:15:18 -07002316 DEBUG_TRACE("connection does not exist - p: %d, s: %pI6:%u, d: %pI6:%u\n",
2317 sid->protocol, sid->src_ip.ip6, ntohs(sid->src_port),
2318 sid->dest_ip.ip6, ntohs(sid->dest_port));
2319 return;
2320 }
2321
2322 /*
2323 * Remove our connection details from the hash tables.
2324 */
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05302325 ret = sfe_ipv6_remove_connection(si, c);
Xiaoping Fan978b3772015-05-27 14:15:18 -07002326 spin_unlock_bh(&si->lock);
2327
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05302328 if (ret) {
2329 sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_DESTROY);
2330 }
Xiaoping Fan978b3772015-05-27 14:15:18 -07002331
2332 DEBUG_INFO("connection destroyed - p: %d, s: %pI6:%u, d: %pI6:%u\n",
2333 sid->protocol, sid->src_ip.ip6, ntohs(sid->src_port),
2334 sid->dest_ip.ip6, ntohs(sid->dest_port));
2335}
2336
2337/*
2338 * sfe_ipv6_register_sync_rule_callback()
2339 * Register a callback for rule synchronization.
2340 */
2341void sfe_ipv6_register_sync_rule_callback(sfe_sync_rule_callback_t sync_rule_callback)
2342{
2343 struct sfe_ipv6 *si = &__si6;
2344
2345 spin_lock_bh(&si->lock);
2346 rcu_assign_pointer(si->sync_rule_callback, sync_rule_callback);
2347 spin_unlock_bh(&si->lock);
2348}
2349
2350/*
2351 * sfe_ipv6_get_debug_dev()
2352 */
2353static ssize_t sfe_ipv6_get_debug_dev(struct device *dev,
2354 struct device_attribute *attr,
2355 char *buf)
2356{
2357 struct sfe_ipv6 *si = &__si6;
2358 ssize_t count;
2359 int num;
2360
2361 spin_lock_bh(&si->lock);
2362 num = si->debug_dev;
2363 spin_unlock_bh(&si->lock);
2364
2365 count = snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", num);
2366 return count;
2367}
2368
2369/*
2370 * sfe_ipv6_destroy_all_rules_for_dev()
2371 * Destroy all connections that match a particular device.
2372 *
2373 * If we pass dev as NULL then this destroys all connections.
2374 */
2375void sfe_ipv6_destroy_all_rules_for_dev(struct net_device *dev)
2376{
2377 struct sfe_ipv6 *si = &__si6;
2378 struct sfe_ipv6_connection *c;
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05302379 bool ret;
Xiaoping Fan978b3772015-05-27 14:15:18 -07002380
Xiaoping Fan34586472015-07-03 02:20:35 -07002381another_round:
Xiaoping Fan978b3772015-05-27 14:15:18 -07002382 spin_lock_bh(&si->lock);
Xiaoping Fan978b3772015-05-27 14:15:18 -07002383
Xiaoping Fan34586472015-07-03 02:20:35 -07002384 for (c = si->all_connections_head; c; c = c->all_connections_next) {
Xiaoping Fan978b3772015-05-27 14:15:18 -07002385 /*
Xiaoping Fan34586472015-07-03 02:20:35 -07002386 * Does this connection relate to the device we are destroying?
Xiaoping Fan978b3772015-05-27 14:15:18 -07002387 */
2388 if (!dev
2389 || (dev == c->original_dev)
2390 || (dev == c->reply_dev)) {
Xiaoping Fan34586472015-07-03 02:20:35 -07002391 break;
Xiaoping Fan978b3772015-05-27 14:15:18 -07002392 }
Xiaoping Fan34586472015-07-03 02:20:35 -07002393 }
Xiaoping Fan978b3772015-05-27 14:15:18 -07002394
Xiaoping Fan34586472015-07-03 02:20:35 -07002395 if (c) {
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05302396 ret = sfe_ipv6_remove_connection(si, c);
Xiaoping Fan978b3772015-05-27 14:15:18 -07002397 }
2398
2399 spin_unlock_bh(&si->lock);
Xiaoping Fan34586472015-07-03 02:20:35 -07002400
2401 if (c) {
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05302402 if (ret) {
2403 sfe_ipv6_flush_connection(si, c, SFE_SYNC_REASON_DESTROY);
2404 }
Xiaoping Fan34586472015-07-03 02:20:35 -07002405 goto another_round;
2406 }
Xiaoping Fan978b3772015-05-27 14:15:18 -07002407}
2408
2409/*
2410 * sfe_ipv6_periodic_sync()
2411 */
Tian Yang45f39c82020-10-06 14:07:47 -07002412#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0))
Xiaoping Fan978b3772015-05-27 14:15:18 -07002413static void sfe_ipv6_periodic_sync(unsigned long arg)
Tian Yang45f39c82020-10-06 14:07:47 -07002414#else
2415static void sfe_ipv6_periodic_sync(struct timer_list *tl)
2416#endif
Xiaoping Fan978b3772015-05-27 14:15:18 -07002417{
Tian Yang45f39c82020-10-06 14:07:47 -07002418#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0))
Xiaoping Fan978b3772015-05-27 14:15:18 -07002419 struct sfe_ipv6 *si = (struct sfe_ipv6 *)arg;
Tian Yang45f39c82020-10-06 14:07:47 -07002420#else
2421 struct sfe_ipv6 *si = from_timer(si, tl, timer);
2422#endif
Xiaoping Fan6a1672f2016-08-17 19:58:12 -07002423 u64 now_jiffies;
Xiaoping Fan978b3772015-05-27 14:15:18 -07002424 int quota;
2425 sfe_sync_rule_callback_t sync_rule_callback;
2426
2427 now_jiffies = get_jiffies_64();
2428
2429 rcu_read_lock();
2430 sync_rule_callback = rcu_dereference(si->sync_rule_callback);
2431 if (!sync_rule_callback) {
2432 rcu_read_unlock();
2433 goto done;
2434 }
2435
2436 spin_lock_bh(&si->lock);
Xiaoping Fan978b3772015-05-27 14:15:18 -07002437
2438 /*
2439 * Get an estimate of the number of connections to parse in this sync.
2440 */
2441 quota = (si->num_connections + 63) / 64;
2442
2443 /*
2444 * Walk the "active" list and sync the connection state.
2445 */
2446 while (quota--) {
2447 struct sfe_ipv6_connection_match *cm;
2448 struct sfe_ipv6_connection_match *counter_cm;
2449 struct sfe_ipv6_connection *c;
2450 struct sfe_connection_sync sis;
2451
2452 cm = si->active_head;
2453 if (!cm) {
2454 break;
2455 }
2456
2457 /*
2458 * There's a possibility that our counter match is in the active list too.
2459 * If it is then remove it.
2460 */
2461 counter_cm = cm->counter_match;
2462 if (counter_cm->active) {
2463 counter_cm->active = false;
2464
2465 /*
2466 * We must have a connection preceding this counter match
2467 * because that's the one that got us to this point, so we don't have
2468 * to worry about removing the head of the list.
2469 */
2470 counter_cm->active_prev->active_next = counter_cm->active_next;
2471
2472 if (likely(counter_cm->active_next)) {
2473 counter_cm->active_next->active_prev = counter_cm->active_prev;
2474 } else {
2475 si->active_tail = counter_cm->active_prev;
2476 }
2477
2478 counter_cm->active_next = NULL;
2479 counter_cm->active_prev = NULL;
2480 }
2481
2482 /*
2483 * Now remove the head of the active scan list.
2484 */
2485 cm->active = false;
2486 si->active_head = cm->active_next;
2487 if (likely(cm->active_next)) {
2488 cm->active_next->active_prev = NULL;
2489 } else {
2490 si->active_tail = NULL;
2491 }
2492 cm->active_next = NULL;
2493
2494 /*
2495 * Sync the connection state.
2496 */
2497 c = cm->connection;
Xiaoping Fan99cb4c12015-08-21 19:07:32 -07002498 sfe_ipv6_gen_sync_connection(si, c, &sis, SFE_SYNC_REASON_STATS, now_jiffies);
Xiaoping Fan978b3772015-05-27 14:15:18 -07002499
2500 /*
2501 * We don't want to be holding the lock when we sync!
2502 */
2503 spin_unlock_bh(&si->lock);
2504 sync_rule_callback(&sis);
2505 spin_lock_bh(&si->lock);
2506 }
2507
2508 spin_unlock_bh(&si->lock);
2509 rcu_read_unlock();
2510
2511done:
2512 mod_timer(&si->timer, jiffies + ((HZ + 99) / 100));
2513}
2514
2515/*
2516 * sfe_ipv6_debug_dev_read_start()
2517 * Generate part of the XML output.
2518 */
2519static bool sfe_ipv6_debug_dev_read_start(struct sfe_ipv6 *si, char *buffer, char *msg, size_t *length,
2520 int *total_read, struct sfe_ipv6_debug_xml_write_state *ws)
2521{
2522 int bytes_read;
2523
Xiaoping Fan34586472015-07-03 02:20:35 -07002524 si->debug_read_seq++;
2525
Xiaoping Fan978b3772015-05-27 14:15:18 -07002526 bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "<sfe_ipv6>\n");
2527 if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) {
2528 return false;
2529 }
2530
2531 *length -= bytes_read;
2532 *total_read += bytes_read;
2533
2534 ws->state++;
2535 return true;
2536}
2537
2538/*
2539 * sfe_ipv6_debug_dev_read_connections_start()
2540 * Generate part of the XML output.
2541 */
2542static bool sfe_ipv6_debug_dev_read_connections_start(struct sfe_ipv6 *si, char *buffer, char *msg, size_t *length,
2543 int *total_read, struct sfe_ipv6_debug_xml_write_state *ws)
2544{
2545 int bytes_read;
2546
2547 bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t<connections>\n");
2548 if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) {
2549 return false;
2550 }
2551
2552 *length -= bytes_read;
2553 *total_read += bytes_read;
2554
2555 ws->state++;
2556 return true;
2557}
2558
2559/*
2560 * sfe_ipv6_debug_dev_read_connections_connection()
2561 * Generate part of the XML output.
2562 */
2563static bool sfe_ipv6_debug_dev_read_connections_connection(struct sfe_ipv6 *si, char *buffer, char *msg, size_t *length,
2564 int *total_read, struct sfe_ipv6_debug_xml_write_state *ws)
2565{
2566 struct sfe_ipv6_connection *c;
Xiaoping Fan978b3772015-05-27 14:15:18 -07002567 struct sfe_ipv6_connection_match *original_cm;
2568 struct sfe_ipv6_connection_match *reply_cm;
2569 int bytes_read;
2570 int protocol;
2571 struct net_device *src_dev;
2572 struct sfe_ipv6_addr src_ip;
2573 struct sfe_ipv6_addr src_ip_xlate;
2574 __be16 src_port;
2575 __be16 src_port_xlate;
Xiaoping Fan6a1672f2016-08-17 19:58:12 -07002576 u64 src_rx_packets;
2577 u64 src_rx_bytes;
Xiaoping Fan978b3772015-05-27 14:15:18 -07002578 struct net_device *dest_dev;
2579 struct sfe_ipv6_addr dest_ip;
2580 struct sfe_ipv6_addr dest_ip_xlate;
2581 __be16 dest_port;
2582 __be16 dest_port_xlate;
Xiaoping Fan6a1672f2016-08-17 19:58:12 -07002583 u64 dest_rx_packets;
2584 u64 dest_rx_bytes;
2585 u64 last_sync_jiffies;
2586 u32 mark, src_priority, dest_priority, src_dscp, dest_dscp;
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05302587 u32 packet, byte;
Xiaoping Fan978b3772015-05-27 14:15:18 -07002588#ifdef CONFIG_NF_FLOW_COOKIE
2589 int src_flow_cookie, dst_flow_cookie;
2590#endif
2591
2592 spin_lock_bh(&si->lock);
Xiaoping Fan34586472015-07-03 02:20:35 -07002593
2594 for (c = si->all_connections_head; c; c = c->all_connections_next) {
2595 if (c->debug_read_seq < si->debug_read_seq) {
2596 c->debug_read_seq = si->debug_read_seq;
2597 break;
2598 }
2599 }
Xiaoping Fan978b3772015-05-27 14:15:18 -07002600
2601 /*
Xiaoping Fan34586472015-07-03 02:20:35 -07002602 * If there were no connections then move to the next state.
Xiaoping Fan978b3772015-05-27 14:15:18 -07002603 */
2604 if (!c) {
Xiaoping Fan978b3772015-05-27 14:15:18 -07002605 spin_unlock_bh(&si->lock);
Xiaoping Fan34586472015-07-03 02:20:35 -07002606 ws->state++;
Xiaoping Fan978b3772015-05-27 14:15:18 -07002607 return true;
2608 }
2609
2610 original_cm = c->original_match;
2611 reply_cm = c->reply_match;
2612
2613 protocol = c->protocol;
2614 src_dev = c->original_dev;
2615 src_ip = c->src_ip[0];
2616 src_ip_xlate = c->src_ip_xlate[0];
2617 src_port = c->src_port;
2618 src_port_xlate = c->src_port_xlate;
Xiaoping Fane1963d42015-08-25 17:06:19 -07002619 src_priority = original_cm->priority;
2620 src_dscp = original_cm->dscp >> SFE_IPV6_DSCP_SHIFT;
Xiaoping Fan978b3772015-05-27 14:15:18 -07002621
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05302622 sfe_ipv6_connection_match_update_summary_stats(original_cm, &packet, &byte);
2623 sfe_ipv6_connection_match_update_summary_stats(reply_cm, &packet, &byte);
Xiaoping Fan978b3772015-05-27 14:15:18 -07002624
2625 src_rx_packets = original_cm->rx_packet_count64;
2626 src_rx_bytes = original_cm->rx_byte_count64;
2627 dest_dev = c->reply_dev;
2628 dest_ip = c->dest_ip[0];
2629 dest_ip_xlate = c->dest_ip_xlate[0];
2630 dest_port = c->dest_port;
2631 dest_port_xlate = c->dest_port_xlate;
Xiaoping Fane1963d42015-08-25 17:06:19 -07002632 dest_priority = reply_cm->priority;
2633 dest_dscp = reply_cm->dscp >> SFE_IPV6_DSCP_SHIFT;
Xiaoping Fan978b3772015-05-27 14:15:18 -07002634 dest_rx_packets = reply_cm->rx_packet_count64;
2635 dest_rx_bytes = reply_cm->rx_byte_count64;
2636 last_sync_jiffies = get_jiffies_64() - c->last_sync_jiffies;
2637 mark = c->mark;
2638#ifdef CONFIG_NF_FLOW_COOKIE
2639 src_flow_cookie = original_cm->flow_cookie;
2640 dst_flow_cookie = reply_cm->flow_cookie;
2641#endif
2642 spin_unlock_bh(&si->lock);
2643
2644 bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t\t<connection "
2645 "protocol=\"%u\" "
2646 "src_dev=\"%s\" "
2647 "src_ip=\"%pI6\" src_ip_xlate=\"%pI6\" "
2648 "src_port=\"%u\" src_port_xlate=\"%u\" "
Xiaoping Fane1963d42015-08-25 17:06:19 -07002649 "src_priority=\"%u\" src_dscp=\"%u\" "
Xiaoping Fan978b3772015-05-27 14:15:18 -07002650 "src_rx_pkts=\"%llu\" src_rx_bytes=\"%llu\" "
2651 "dest_dev=\"%s\" "
2652 "dest_ip=\"%pI6\" dest_ip_xlate=\"%pI6\" "
2653 "dest_port=\"%u\" dest_port_xlate=\"%u\" "
Xiaoping Fane1963d42015-08-25 17:06:19 -07002654 "dest_priority=\"%u\" dest_dscp=\"%u\" "
Xiaoping Fan978b3772015-05-27 14:15:18 -07002655 "dest_rx_pkts=\"%llu\" dest_rx_bytes=\"%llu\" "
2656#ifdef CONFIG_NF_FLOW_COOKIE
2657 "src_flow_cookie=\"%d\" dst_flow_cookie=\"%d\" "
2658#endif
2659 "last_sync=\"%llu\" "
2660 "mark=\"%08x\" />\n",
2661 protocol,
2662 src_dev->name,
2663 &src_ip, &src_ip_xlate,
2664 ntohs(src_port), ntohs(src_port_xlate),
Xiaoping Fane1963d42015-08-25 17:06:19 -07002665 src_priority, src_dscp,
Xiaoping Fan978b3772015-05-27 14:15:18 -07002666 src_rx_packets, src_rx_bytes,
2667 dest_dev->name,
2668 &dest_ip, &dest_ip_xlate,
2669 ntohs(dest_port), ntohs(dest_port_xlate),
Xiaoping Fane1963d42015-08-25 17:06:19 -07002670 dest_priority, dest_dscp,
Xiaoping Fan978b3772015-05-27 14:15:18 -07002671 dest_rx_packets, dest_rx_bytes,
2672#ifdef CONFIG_NF_FLOW_COOKIE
2673 src_flow_cookie, dst_flow_cookie,
2674#endif
2675 last_sync_jiffies, mark);
2676
2677 if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) {
2678 return false;
2679 }
2680
2681 *length -= bytes_read;
2682 *total_read += bytes_read;
2683
Xiaoping Fan978b3772015-05-27 14:15:18 -07002684 return true;
2685}
2686
2687/*
2688 * sfe_ipv6_debug_dev_read_connections_end()
2689 * Generate part of the XML output.
2690 */
2691static bool sfe_ipv6_debug_dev_read_connections_end(struct sfe_ipv6 *si, char *buffer, char *msg, size_t *length,
2692 int *total_read, struct sfe_ipv6_debug_xml_write_state *ws)
2693{
2694 int bytes_read;
2695
2696 bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t</connections>\n");
2697 if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) {
2698 return false;
2699 }
2700
2701 *length -= bytes_read;
2702 *total_read += bytes_read;
2703
2704 ws->state++;
2705 return true;
2706}
2707
2708/*
2709 * sfe_ipv6_debug_dev_read_exceptions_start()
2710 * Generate part of the XML output.
2711 */
2712static bool sfe_ipv6_debug_dev_read_exceptions_start(struct sfe_ipv6 *si, char *buffer, char *msg, size_t *length,
2713 int *total_read, struct sfe_ipv6_debug_xml_write_state *ws)
2714{
2715 int bytes_read;
2716
2717 bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t<exceptions>\n");
2718 if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) {
2719 return false;
2720 }
2721
2722 *length -= bytes_read;
2723 *total_read += bytes_read;
2724
2725 ws->state++;
2726 return true;
2727}
2728
2729/*
2730 * sfe_ipv6_debug_dev_read_exceptions_exception()
2731 * Generate part of the XML output.
2732 */
2733static bool sfe_ipv6_debug_dev_read_exceptions_exception(struct sfe_ipv6 *si, char *buffer, char *msg, size_t *length,
2734 int *total_read, struct sfe_ipv6_debug_xml_write_state *ws)
2735{
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05302736 int i;
2737 u64 val = 0;
Xiaoping Fan978b3772015-05-27 14:15:18 -07002738
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05302739 for_each_possible_cpu(i) {
2740 const struct sfe_ipv6_stats *s = per_cpu_ptr(si->stats_pcpu, i);
2741 val += s->exception_events64[ws->iter_exception];
2742 }
Xiaoping Fan978b3772015-05-27 14:15:18 -07002743
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05302744 if (val) {
Xiaoping Fan978b3772015-05-27 14:15:18 -07002745 int bytes_read;
2746
2747 bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE,
2748 "\t\t<exception name=\"%s\" count=\"%llu\" />\n",
2749 sfe_ipv6_exception_events_string[ws->iter_exception],
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05302750 val);
2751
Xiaoping Fan978b3772015-05-27 14:15:18 -07002752 if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) {
2753 return false;
2754 }
2755
2756 *length -= bytes_read;
2757 *total_read += bytes_read;
2758 }
2759
2760 ws->iter_exception++;
2761 if (ws->iter_exception >= SFE_IPV6_EXCEPTION_EVENT_LAST) {
2762 ws->iter_exception = 0;
2763 ws->state++;
2764 }
2765
2766 return true;
2767}
2768
2769/*
2770 * sfe_ipv6_debug_dev_read_exceptions_end()
2771 * Generate part of the XML output.
2772 */
2773static bool sfe_ipv6_debug_dev_read_exceptions_end(struct sfe_ipv6 *si, char *buffer, char *msg, size_t *length,
2774 int *total_read, struct sfe_ipv6_debug_xml_write_state *ws)
2775{
2776 int bytes_read;
2777
2778 bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t</exceptions>\n");
2779 if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) {
2780 return false;
2781 }
2782
2783 *length -= bytes_read;
2784 *total_read += bytes_read;
2785
2786 ws->state++;
2787 return true;
2788}
2789
2790/*
2791 * sfe_ipv6_debug_dev_read_stats()
2792 * Generate part of the XML output.
2793 */
2794static bool sfe_ipv6_debug_dev_read_stats(struct sfe_ipv6 *si, char *buffer, char *msg, size_t *length,
2795 int *total_read, struct sfe_ipv6_debug_xml_write_state *ws)
2796{
2797 int bytes_read;
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05302798 struct sfe_ipv6_stats stats;
2799 unsigned int num_conn;
2800
2801 sfe_ipv6_update_summary_stats(si, &stats);
Xiaoping Fan978b3772015-05-27 14:15:18 -07002802
2803 spin_lock_bh(&si->lock);
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05302804 num_conn = si->num_connections;
Xiaoping Fan978b3772015-05-27 14:15:18 -07002805 spin_unlock_bh(&si->lock);
2806
2807 bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t<stats "
2808 "num_connections=\"%u\" "
2809 "pkts_forwarded=\"%llu\" pkts_not_forwarded=\"%llu\" "
2810 "create_requests=\"%llu\" create_collisions=\"%llu\" "
2811 "destroy_requests=\"%llu\" destroy_misses=\"%llu\" "
2812 "flushes=\"%llu\" "
2813 "hash_hits=\"%llu\" hash_reorders=\"%llu\" />\n",
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05302814
2815 num_conn,
2816 stats.packets_forwarded64,
2817 stats.packets_not_forwarded64,
2818 stats.connection_create_requests64,
2819 stats.connection_create_collisions64,
2820 stats.connection_destroy_requests64,
2821 stats.connection_destroy_misses64,
2822 stats.connection_flushes64,
2823 stats.connection_match_hash_hits64,
2824 stats.connection_match_hash_reorders64);
Xiaoping Fan978b3772015-05-27 14:15:18 -07002825 if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) {
2826 return false;
2827 }
2828
2829 *length -= bytes_read;
2830 *total_read += bytes_read;
2831
2832 ws->state++;
2833 return true;
2834}
2835
2836/*
2837 * sfe_ipv6_debug_dev_read_end()
2838 * Generate part of the XML output.
2839 */
2840static bool sfe_ipv6_debug_dev_read_end(struct sfe_ipv6 *si, char *buffer, char *msg, size_t *length,
2841 int *total_read, struct sfe_ipv6_debug_xml_write_state *ws)
2842{
2843 int bytes_read;
2844
2845 bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "</sfe_ipv6>\n");
2846 if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) {
2847 return false;
2848 }
2849
2850 *length -= bytes_read;
2851 *total_read += bytes_read;
2852
2853 ws->state++;
2854 return true;
2855}
2856
2857/*
2858 * Array of write functions that write various XML elements that correspond to
2859 * our XML output state machine.
2860 */
2861static sfe_ipv6_debug_xml_write_method_t sfe_ipv6_debug_xml_write_methods[SFE_IPV6_DEBUG_XML_STATE_DONE] = {
2862 sfe_ipv6_debug_dev_read_start,
2863 sfe_ipv6_debug_dev_read_connections_start,
2864 sfe_ipv6_debug_dev_read_connections_connection,
2865 sfe_ipv6_debug_dev_read_connections_end,
2866 sfe_ipv6_debug_dev_read_exceptions_start,
2867 sfe_ipv6_debug_dev_read_exceptions_exception,
2868 sfe_ipv6_debug_dev_read_exceptions_end,
2869 sfe_ipv6_debug_dev_read_stats,
2870 sfe_ipv6_debug_dev_read_end,
2871};
2872
2873/*
2874 * sfe_ipv6_debug_dev_read()
2875 * Send info to userspace upon read request from user
2876 */
2877static ssize_t sfe_ipv6_debug_dev_read(struct file *filp, char *buffer, size_t length, loff_t *offset)
2878{
2879 char msg[CHAR_DEV_MSG_SIZE];
2880 int total_read = 0;
2881 struct sfe_ipv6_debug_xml_write_state *ws;
2882 struct sfe_ipv6 *si = &__si6;
2883
2884 ws = (struct sfe_ipv6_debug_xml_write_state *)filp->private_data;
2885 while ((ws->state != SFE_IPV6_DEBUG_XML_STATE_DONE) && (length > CHAR_DEV_MSG_SIZE)) {
2886 if ((sfe_ipv6_debug_xml_write_methods[ws->state])(si, buffer, msg, &length, &total_read, ws)) {
2887 continue;
2888 }
2889 }
Xiaoping Fan978b3772015-05-27 14:15:18 -07002890 return total_read;
2891}
2892
2893/*
Xiaoping Fan978b3772015-05-27 14:15:18 -07002894 * sfe_ipv6_debug_dev_open()
2895 */
2896static int sfe_ipv6_debug_dev_open(struct inode *inode, struct file *file)
2897{
2898 struct sfe_ipv6_debug_xml_write_state *ws;
2899
2900 ws = (struct sfe_ipv6_debug_xml_write_state *)file->private_data;
2901 if (ws) {
2902 return 0;
2903 }
2904
2905 ws = kzalloc(sizeof(struct sfe_ipv6_debug_xml_write_state), GFP_KERNEL);
2906 if (!ws) {
2907 return -ENOMEM;
2908 }
2909
2910 ws->state = SFE_IPV6_DEBUG_XML_STATE_START;
2911 file->private_data = ws;
2912
2913 return 0;
2914}
2915
2916/*
2917 * sfe_ipv6_debug_dev_release()
2918 */
2919static int sfe_ipv6_debug_dev_release(struct inode *inode, struct file *file)
2920{
2921 struct sfe_ipv6_debug_xml_write_state *ws;
Xiaoping Fan978b3772015-05-27 14:15:18 -07002922
2923 ws = (struct sfe_ipv6_debug_xml_write_state *)file->private_data;
Xiaoping Fan34586472015-07-03 02:20:35 -07002924 if (ws) {
2925 /*
2926 * We've finished with our output so free the write state.
2927 */
2928 kfree(ws);
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05302929 file->private_data = NULL;
Xiaoping Fan978b3772015-05-27 14:15:18 -07002930 }
2931
Xiaoping Fan978b3772015-05-27 14:15:18 -07002932 return 0;
2933}
2934
2935/*
2936 * File operations used in the debug char device
2937 */
2938static struct file_operations sfe_ipv6_debug_dev_fops = {
2939 .read = sfe_ipv6_debug_dev_read,
Xiaoping Fan978b3772015-05-27 14:15:18 -07002940 .open = sfe_ipv6_debug_dev_open,
2941 .release = sfe_ipv6_debug_dev_release
2942};
2943
2944#ifdef CONFIG_NF_FLOW_COOKIE
2945/*
2946 * sfe_ipv6_register_flow_cookie_cb
2947 * register a function in SFE to let SFE use this function to configure flow cookie for a flow
2948 *
2949 * Hardware driver which support flow cookie should register a callback function in SFE. Then SFE
2950 * can use this function to configure flow cookie for a flow.
2951 * return: 0, success; !=0, fail
2952 */
2953int sfe_ipv6_register_flow_cookie_cb(sfe_ipv6_flow_cookie_set_func_t cb)
2954{
2955 struct sfe_ipv6 *si = &__si6;
2956
2957 BUG_ON(!cb);
2958
2959 if (si->flow_cookie_set_func) {
2960 return -1;
2961 }
2962
2963 rcu_assign_pointer(si->flow_cookie_set_func, cb);
2964 return 0;
2965}
2966
2967/*
2968 * sfe_ipv6_unregister_flow_cookie_cb
2969 * unregister function which is used to configure flow cookie for a flow
2970 *
2971 * return: 0, success; !=0, fail
2972 */
2973int sfe_ipv6_unregister_flow_cookie_cb(sfe_ipv6_flow_cookie_set_func_t cb)
2974{
2975 struct sfe_ipv6 *si = &__si6;
2976
2977 RCU_INIT_POINTER(si->flow_cookie_set_func, NULL);
2978 return 0;
2979}
Xiaoping Fan640faf42015-08-28 15:50:55 -07002980
2981/*
2982 * sfe_ipv6_get_flow_cookie()
2983 */
2984static ssize_t sfe_ipv6_get_flow_cookie(struct device *dev,
2985 struct device_attribute *attr,
2986 char *buf)
2987{
2988 struct sfe_ipv6 *si = &__si6;
Xiaoping Fan01c67cc2015-11-09 11:31:57 -08002989 return snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", si->flow_cookie_enable);
Xiaoping Fan640faf42015-08-28 15:50:55 -07002990}
2991
2992/*
2993 * sfe_ipv6_set_flow_cookie()
2994 */
2995static ssize_t sfe_ipv6_set_flow_cookie(struct device *dev,
2996 struct device_attribute *attr,
2997 const char *buf, size_t size)
2998{
2999 struct sfe_ipv6 *si = &__si6;
3000 strict_strtol(buf, 0, (long int *)&si->flow_cookie_enable);
3001
3002 return size;
3003}
3004
3005/*
3006 * sysfs attributes.
3007 */
3008static const struct device_attribute sfe_ipv6_flow_cookie_attr =
Xiaoping Fane70da412016-02-26 16:47:57 -08003009 __ATTR(flow_cookie_enable, S_IWUSR | S_IRUGO, sfe_ipv6_get_flow_cookie, sfe_ipv6_set_flow_cookie);
Xiaoping Fan978b3772015-05-27 14:15:18 -07003010#endif /*CONFIG_NF_FLOW_COOKIE*/
3011
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05303012 /*
3013 * sfe_ipv6_hash_init()
3014 * Initialize conn match hash lists
3015 */
3016static void sfe_ipv6_conn_match_hash_init(struct sfe_ipv6 *si, int len)
3017{
3018 struct hlist_head *hash_list = si->hlist_conn_match_hash_head;
3019 int i;
3020
3021 for (i = 0; i < len; i++) {
3022 INIT_HLIST_HEAD(&hash_list[i]);
3023 }
3024}
3025
Xiaoping Fan978b3772015-05-27 14:15:18 -07003026/*
3027 * sfe_ipv6_init()
3028 */
Ratheesh Kannoth24fb1db2021-10-20 07:28:06 +05303029int sfe_ipv6_init(void)
Xiaoping Fan978b3772015-05-27 14:15:18 -07003030{
3031 struct sfe_ipv6 *si = &__si6;
3032 int result = -1;
3033
3034 DEBUG_INFO("SFE IPv6 init\n");
3035
Ratheesh Kannotha212fc52021-10-20 07:50:32 +05303036 sfe_ipv6_conn_match_hash_init(si, ARRAY_SIZE(si->hlist_conn_match_hash_head));
3037
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05303038 si->stats_pcpu = alloc_percpu_gfp(struct sfe_ipv6_stats, GFP_KERNEL | __GFP_ZERO);
3039 if (!si->stats_pcpu) {
3040 DEBUG_ERROR("failed to allocate stats memory for sfe_ipv6\n");
3041 goto exit0;
3042 }
3043
Xiaoping Fan978b3772015-05-27 14:15:18 -07003044 /*
3045 * Create sys/sfe_ipv6
3046 */
3047 si->sys_sfe_ipv6 = kobject_create_and_add("sfe_ipv6", NULL);
3048 if (!si->sys_sfe_ipv6) {
3049 DEBUG_ERROR("failed to register sfe_ipv6\n");
3050 goto exit1;
3051 }
3052
3053 /*
3054 * Create files, one for each parameter supported by this module.
3055 */
3056 result = sysfs_create_file(si->sys_sfe_ipv6, &sfe_ipv6_debug_dev_attr.attr);
3057 if (result) {
3058 DEBUG_ERROR("failed to register debug dev file: %d\n", result);
3059 goto exit2;
3060 }
3061
Xiaoping Fan640faf42015-08-28 15:50:55 -07003062#ifdef CONFIG_NF_FLOW_COOKIE
3063 result = sysfs_create_file(si->sys_sfe_ipv6, &sfe_ipv6_flow_cookie_attr.attr);
3064 if (result) {
3065 DEBUG_ERROR("failed to register flow cookie enable file: %d\n", result);
3066 goto exit3;
3067 }
3068#endif /* CONFIG_NF_FLOW_COOKIE */
3069
Xiaoping Fan978b3772015-05-27 14:15:18 -07003070 /*
3071 * Register our debug char device.
3072 */
3073 result = register_chrdev(0, "sfe_ipv6", &sfe_ipv6_debug_dev_fops);
3074 if (result < 0) {
3075 DEBUG_ERROR("Failed to register chrdev: %d\n", result);
Xiaoping Fan640faf42015-08-28 15:50:55 -07003076 goto exit4;
Xiaoping Fan978b3772015-05-27 14:15:18 -07003077 }
3078
3079 si->debug_dev = result;
3080
3081 /*
3082 * Create a timer to handle periodic statistics.
3083 */
Tian Yang45f39c82020-10-06 14:07:47 -07003084#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0))
Xiaoping Fan978b3772015-05-27 14:15:18 -07003085 setup_timer(&si->timer, sfe_ipv6_periodic_sync, (unsigned long)si);
Tian Yang45f39c82020-10-06 14:07:47 -07003086#else
3087 timer_setup(&si->timer, sfe_ipv6_periodic_sync, 0);
3088#endif
Xiaoping Fan978b3772015-05-27 14:15:18 -07003089 mod_timer(&si->timer, jiffies + ((HZ + 99) / 100));
3090
3091 spin_lock_init(&si->lock);
3092
3093 return 0;
3094
Xiaoping Fan640faf42015-08-28 15:50:55 -07003095exit4:
3096#ifdef CONFIG_NF_FLOW_COOKIE
3097 sysfs_remove_file(si->sys_sfe_ipv6, &sfe_ipv6_flow_cookie_attr.attr);
3098
Xiaoping Fan978b3772015-05-27 14:15:18 -07003099exit3:
Xiaoping Fan640faf42015-08-28 15:50:55 -07003100#endif /* CONFIG_NF_FLOW_COOKIE */
Xiaoping Fan978b3772015-05-27 14:15:18 -07003101 sysfs_remove_file(si->sys_sfe_ipv6, &sfe_ipv6_debug_dev_attr.attr);
3102
3103exit2:
3104 kobject_put(si->sys_sfe_ipv6);
3105
3106exit1:
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05303107 free_percpu(si->stats_pcpu);
3108
3109exit0:
Xiaoping Fan978b3772015-05-27 14:15:18 -07003110 return result;
3111}
3112
3113/*
3114 * sfe_ipv6_exit()
3115 */
Ratheesh Kannoth24fb1db2021-10-20 07:28:06 +05303116void sfe_ipv6_exit(void)
Xiaoping Fan978b3772015-05-27 14:15:18 -07003117{
3118 struct sfe_ipv6 *si = &__si6;
3119
3120 DEBUG_INFO("SFE IPv6 exit\n");
3121
3122 /*
3123 * Destroy all connections.
3124 */
3125 sfe_ipv6_destroy_all_rules_for_dev(NULL);
3126
3127 del_timer_sync(&si->timer);
3128
3129 unregister_chrdev(si->debug_dev, "sfe_ipv6");
3130
Ratheesh Kannoth1ed95462021-10-20 07:57:45 +05303131 free_percpu(si->stats_pcpu);
3132
Xiaoping Fan640faf42015-08-28 15:50:55 -07003133#ifdef CONFIG_NF_FLOW_COOKIE
3134 sysfs_remove_file(si->sys_sfe_ipv6, &sfe_ipv6_flow_cookie_attr.attr);
3135#endif /* CONFIG_NF_FLOW_COOKIE */
Xiaoping Fan978b3772015-05-27 14:15:18 -07003136 sysfs_remove_file(si->sys_sfe_ipv6, &sfe_ipv6_debug_dev_attr.attr);
3137
3138 kobject_put(si->sys_sfe_ipv6);
Xiaoping Fan978b3772015-05-27 14:15:18 -07003139}
3140
Xiaoping Fan978b3772015-05-27 14:15:18 -07003141EXPORT_SYMBOL(sfe_ipv6_recv);
3142EXPORT_SYMBOL(sfe_ipv6_create_rule);
3143EXPORT_SYMBOL(sfe_ipv6_destroy_rule);
3144EXPORT_SYMBOL(sfe_ipv6_destroy_all_rules_for_dev);
3145EXPORT_SYMBOL(sfe_ipv6_register_sync_rule_callback);
3146EXPORT_SYMBOL(sfe_ipv6_mark_rule);
3147EXPORT_SYMBOL(sfe_ipv6_update_rule);
3148#ifdef CONFIG_NF_FLOW_COOKIE
3149EXPORT_SYMBOL(sfe_ipv6_register_flow_cookie_cb);
3150EXPORT_SYMBOL(sfe_ipv6_unregister_flow_cookie_cb);
3151#endif
3152
Xiaoping Fan978b3772015-05-27 14:15:18 -07003153MODULE_DESCRIPTION("Shortcut Forwarding Engine - IPv6 support");
3154MODULE_LICENSE("Dual BSD/GPL");