blob: abd36047ff286e4167bdd42360c77c84b62a3cf1 [file] [log] [blame]
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001/*
2 * sfe_ipv4.c
3 * Shortcut forwarding engine - IPv4 edition.
4 *
Ratheesh Kannoth24fb1db2021-10-20 07:28:06 +05305 * Copyright (c) 2013-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.
Dave Hudsonaaf97ca2013-06-13 17:52:29 +010019 */
Matthew McClintocka3221942014-01-16 11:44:26 -060020
Dave Hudsonaaf97ca2013-06-13 17:52:29 +010021#include <linux/module.h>
Dave Hudsondcd08fb2013-11-22 09:25:16 -060022#include <linux/sysfs.h>
Dave Hudsonaaf97ca2013-06-13 17:52:29 +010023#include <linux/skbuff.h>
24#include <linux/icmp.h>
Dave Hudsonaaf97ca2013-06-13 17:52:29 +010025#include <net/tcp.h>
Dave Hudsondcd08fb2013-11-22 09:25:16 -060026#include <linux/etherdevice.h>
Tian Yang45f39c82020-10-06 14:07:47 -070027#include <linux/version.h>
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +053028#include <linux/lockdep.h>
Dave Hudsonaaf97ca2013-06-13 17:52:29 +010029
Ratheesh Kannoth24fb1db2021-10-20 07:28:06 +053030#include "sfe_debug.h"
Ratheesh Kannoth89302a72021-10-20 08:10:37 +053031#include "sfe_api.h"
Dave Hudsondcd08fb2013-11-22 09:25:16 -060032#include "sfe.h"
Ratheesh Kannoth24fb1db2021-10-20 07:28:06 +053033#include "sfe_flow_cookie.h"
34#include "sfe_ipv4.h"
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +053035#include "sfe_ipv4_udp.h"
36#include "sfe_ipv4_tcp.h"
37#include "sfe_ipv4_icmp.h"
Dave Hudsonaaf97ca2013-06-13 17:52:29 +010038
39static char *sfe_ipv4_exception_events_string[SFE_IPV4_EXCEPTION_EVENT_LAST] = {
40 "UDP_HEADER_INCOMPLETE",
41 "UDP_NO_CONNECTION",
42 "UDP_IP_OPTIONS_OR_INITIAL_FRAGMENT",
43 "UDP_SMALL_TTL",
44 "UDP_NEEDS_FRAGMENTATION",
45 "TCP_HEADER_INCOMPLETE",
46 "TCP_NO_CONNECTION_SLOW_FLAGS",
47 "TCP_NO_CONNECTION_FAST_FLAGS",
48 "TCP_IP_OPTIONS_OR_INITIAL_FRAGMENT",
49 "TCP_SMALL_TTL",
50 "TCP_NEEDS_FRAGMENTATION",
51 "TCP_FLAGS",
52 "TCP_SEQ_EXCEEDS_RIGHT_EDGE",
53 "TCP_SMALL_DATA_OFFS",
54 "TCP_BAD_SACK",
55 "TCP_BIG_DATA_OFFS",
56 "TCP_SEQ_BEFORE_LEFT_EDGE",
57 "TCP_ACK_EXCEEDS_RIGHT_EDGE",
58 "TCP_ACK_BEFORE_LEFT_EDGE",
59 "ICMP_HEADER_INCOMPLETE",
60 "ICMP_UNHANDLED_TYPE",
61 "ICMP_IPV4_HEADER_INCOMPLETE",
62 "ICMP_IPV4_NON_V4",
63 "ICMP_IPV4_IP_OPTIONS_INCOMPLETE",
64 "ICMP_IPV4_UDP_HEADER_INCOMPLETE",
65 "ICMP_IPV4_TCP_HEADER_INCOMPLETE",
66 "ICMP_IPV4_UNHANDLED_PROTOCOL",
67 "ICMP_NO_CONNECTION",
68 "ICMP_FLUSHED_CONNECTION",
69 "HEADER_INCOMPLETE",
70 "BAD_TOTAL_LENGTH",
71 "NON_V4",
72 "NON_INITIAL_FRAGMENT",
73 "DATAGRAM_INCOMPLETE",
74 "IP_OPTIONS_INCOMPLETE",
75 "UNHANDLED_PROTOCOL"
76};
77
Xiaoping Fan6a1672f2016-08-17 19:58:12 -070078static struct sfe_ipv4 __si;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +010079
80/*
Dave Hudsonaaf97ca2013-06-13 17:52:29 +010081 * sfe_ipv4_gen_ip_csum()
82 * Generate the IP checksum for an IPv4 header.
83 *
84 * Note that this function assumes that we have only 20 bytes of IP header.
85 */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +053086u16 sfe_ipv4_gen_ip_csum(struct iphdr *iph)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +010087{
Xiaoping Fan6a1672f2016-08-17 19:58:12 -070088 u32 sum;
89 u16 *i = (u16 *)iph;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +010090
91 iph->check = 0;
92
93 /*
94 * Generate the sum.
95 */
96 sum = i[0] + i[1] + i[2] + i[3] + i[4] + i[5] + i[6] + i[7] + i[8] + i[9];
97
98 /*
99 * Fold it to ones-complement form.
100 */
101 sum = (sum & 0xffff) + (sum >> 16);
102 sum = (sum & 0xffff) + (sum >> 16);
103
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700104 return (u16)sum ^ 0xffff;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100105}
106
107/*
108 * sfe_ipv4_get_connection_match_hash()
109 * Generate the hash used in connection match lookups.
110 */
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700111static inline unsigned int sfe_ipv4_get_connection_match_hash(struct net_device *dev, u8 protocol,
Dave Hudson87973cd2013-10-22 16:00:04 +0100112 __be32 src_ip, __be16 src_port,
113 __be32 dest_ip, __be16 dest_port)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100114{
115 size_t dev_addr = (size_t)dev;
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700116 u32 hash = ((u32)dev_addr) ^ ntohl(src_ip ^ dest_ip) ^ protocol ^ ntohs(src_port ^ dest_port);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100117 return ((hash >> SFE_IPV4_CONNECTION_HASH_SHIFT) ^ hash) & SFE_IPV4_CONNECTION_HASH_MASK;
118}
119
120/*
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530121 * sfe_ipv4_find_connection_match_rcu()
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100122 * Get the IPv4 flow match info that corresponds to a particular 5-tuple.
123 *
124 * On entry we must be holding the lock that protects the hash table.
125 */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530126struct sfe_ipv4_connection_match *
127sfe_ipv4_find_connection_match_rcu(struct sfe_ipv4 *si, struct net_device *dev, u8 protocol,
Dave Hudson87973cd2013-10-22 16:00:04 +0100128 __be32 src_ip, __be16 src_port,
129 __be32 dest_ip, __be16 dest_port)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100130{
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530131 struct sfe_ipv4_connection_match *cm = NULL;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100132 unsigned int conn_match_idx;
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530133 struct hlist_head *lhead;
134
135 WARN_ON_ONCE(!rcu_read_lock_held());
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100136
137 conn_match_idx = sfe_ipv4_get_connection_match_hash(dev, protocol, src_ip, src_port, dest_ip, dest_port);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100138
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530139 lhead = &si->hlist_conn_match_hash_head[conn_match_idx];
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100140
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530141 hlist_for_each_entry_rcu(cm, lhead, hnode) {
142 if (cm->match_src_port != src_port
143 || cm->match_dest_port != dest_port
144 || cm->match_src_ip != src_ip
145 || cm->match_dest_ip != dest_ip
146 || cm->match_protocol != protocol
147 || cm->match_dev != dev) {
148 continue;
149 }
150
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +0530151 this_cpu_inc(si->stats_pcpu->connection_match_hash_hits64);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100152
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530153 break;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100154 }
155
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100156 return cm;
157}
158
159/*
160 * sfe_ipv4_connection_match_update_summary_stats()
161 * Update the summary stats for a connection match entry.
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530162 *
163 * Stats are incremented atomically. So use atomic substraction to update summary
164 * stats.
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100165 */
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530166static inline void sfe_ipv4_connection_match_update_summary_stats(struct sfe_ipv4_connection_match *cm,
167 u32 *packets, u32 *bytes)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100168{
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530169 u32 packet_count, byte_count;
170
171 packet_count = atomic_read(&cm->rx_packet_count);
172 cm->rx_packet_count64 += packet_count;
173 atomic_sub(packet_count, &cm->rx_packet_count);
174
175 byte_count = atomic_read(&cm->rx_byte_count);
176 cm->rx_byte_count64 += byte_count;
177 atomic_sub(byte_count, &cm->rx_byte_count);
178
179 *packets = packet_count;
180 *bytes = byte_count;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100181}
182
183/*
184 * sfe_ipv4_connection_match_compute_translations()
185 * Compute port and address translations for a connection match entry.
186 */
187static void sfe_ipv4_connection_match_compute_translations(struct sfe_ipv4_connection_match *cm)
188{
189 /*
190 * Before we insert the entry look to see if this is tagged as doing address
191 * translations. If it is then work out the adjustment that we need to apply
192 * to the transport checksum.
193 */
194 if (cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_SRC) {
195 /*
196 * Precompute an incremental checksum adjustment so we can
197 * edit packets in this stream very quickly. The algorithm is from RFC1624.
198 */
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700199 u16 src_ip_hi = cm->match_src_ip >> 16;
200 u16 src_ip_lo = cm->match_src_ip & 0xffff;
201 u32 xlate_src_ip = ~cm->xlate_src_ip;
202 u16 xlate_src_ip_hi = xlate_src_ip >> 16;
203 u16 xlate_src_ip_lo = xlate_src_ip & 0xffff;
204 u16 xlate_src_port = ~cm->xlate_src_port;
205 u32 adj;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100206
207 /*
208 * When we compute this fold it down to a 16-bit offset
209 * as that way we can avoid having to do a double
210 * folding of the twos-complement result because the
211 * addition of 2 16-bit values cannot cause a double
212 * wrap-around!
213 */
214 adj = src_ip_hi + src_ip_lo + cm->match_src_port
215 + xlate_src_ip_hi + xlate_src_ip_lo + xlate_src_port;
216 adj = (adj & 0xffff) + (adj >> 16);
217 adj = (adj & 0xffff) + (adj >> 16);
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700218 cm->xlate_src_csum_adjustment = (u16)adj;
Nicolas Costaac2979c2014-01-14 10:35:24 -0600219
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100220 }
221
222 if (cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_DEST) {
223 /*
224 * Precompute an incremental checksum adjustment so we can
225 * edit packets in this stream very quickly. The algorithm is from RFC1624.
226 */
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700227 u16 dest_ip_hi = cm->match_dest_ip >> 16;
228 u16 dest_ip_lo = cm->match_dest_ip & 0xffff;
229 u32 xlate_dest_ip = ~cm->xlate_dest_ip;
230 u16 xlate_dest_ip_hi = xlate_dest_ip >> 16;
231 u16 xlate_dest_ip_lo = xlate_dest_ip & 0xffff;
232 u16 xlate_dest_port = ~cm->xlate_dest_port;
233 u32 adj;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100234
235 /*
236 * When we compute this fold it down to a 16-bit offset
237 * as that way we can avoid having to do a double
238 * folding of the twos-complement result because the
239 * addition of 2 16-bit values cannot cause a double
240 * wrap-around!
241 */
242 adj = dest_ip_hi + dest_ip_lo + cm->match_dest_port
243 + xlate_dest_ip_hi + xlate_dest_ip_lo + xlate_dest_port;
244 adj = (adj & 0xffff) + (adj >> 16);
245 adj = (adj & 0xffff) + (adj >> 16);
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700246 cm->xlate_dest_csum_adjustment = (u16)adj;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100247 }
Xiaoping Fanad755af2015-04-01 16:58:46 -0700248
249 if (cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_SRC) {
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700250 u32 adj = ~cm->match_src_ip + cm->xlate_src_ip;
Xiaoping Fanad755af2015-04-01 16:58:46 -0700251 if (adj < cm->xlate_src_ip) {
252 adj++;
253 }
254
255 adj = (adj & 0xffff) + (adj >> 16);
256 adj = (adj & 0xffff) + (adj >> 16);
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700257 cm->xlate_src_partial_csum_adjustment = (u16)adj;
Xiaoping Fanad755af2015-04-01 16:58:46 -0700258 }
259
260 if (cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_DEST) {
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700261 u32 adj = ~cm->match_dest_ip + cm->xlate_dest_ip;
Xiaoping Fanad755af2015-04-01 16:58:46 -0700262 if (adj < cm->xlate_dest_ip) {
263 adj++;
264 }
265
266 adj = (adj & 0xffff) + (adj >> 16);
267 adj = (adj & 0xffff) + (adj >> 16);
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700268 cm->xlate_dest_partial_csum_adjustment = (u16)adj;
Xiaoping Fanad755af2015-04-01 16:58:46 -0700269 }
270
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100271}
272
273/*
274 * sfe_ipv4_update_summary_stats()
275 * Update the summary stats.
276 */
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +0530277static void sfe_ipv4_update_summary_stats(struct sfe_ipv4 *si, struct sfe_ipv4_stats *stats)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100278{
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +0530279 int i = 0;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100280
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +0530281 memset(stats, 0, sizeof(*stats));
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100282
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +0530283 for_each_possible_cpu(i) {
284 const struct sfe_ipv4_stats *s = per_cpu_ptr(si->stats_pcpu, i);
285
286 stats->connection_create_requests64 += s->connection_create_requests64;
287 stats->connection_create_collisions64 += s->connection_create_collisions64;
Ratheesh Kannoth89302a72021-10-20 08:10:37 +0530288 stats->connection_create_failures64 += s->connection_create_failures64;
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +0530289 stats->connection_destroy_requests64 += s->connection_destroy_requests64;
290 stats->connection_destroy_misses64 += s->connection_destroy_misses64;
291 stats->connection_match_hash_hits64 += s->connection_match_hash_hits64;
292 stats->connection_match_hash_reorders64 += s->connection_match_hash_reorders64;
293 stats->connection_flushes64 += s->connection_flushes64;
294 stats->packets_forwarded64 += s->packets_forwarded64;
295 stats->packets_not_forwarded64 += s->packets_not_forwarded64;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100296 }
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +0530297
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100298}
299
300/*
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530301 * sfe_ipv4_insert_connection_match()
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100302 * Insert a connection match into the hash.
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100303 */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530304static inline void sfe_ipv4_insert_connection_match(struct sfe_ipv4 *si,
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700305 struct sfe_ipv4_connection_match *cm)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100306{
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100307 unsigned int conn_match_idx
308 = sfe_ipv4_get_connection_match_hash(cm->match_dev, cm->match_protocol,
309 cm->match_src_ip, cm->match_src_port,
310 cm->match_dest_ip, cm->match_dest_port);
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700311
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530312 lockdep_assert_held(&si->lock);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100313
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530314 hlist_add_head_rcu(&cm->hnode, &si->hlist_conn_match_hash_head[conn_match_idx]);
Xiaoping Fand1dc7b22015-01-23 00:43:56 -0800315#ifdef CONFIG_NF_FLOW_COOKIE
Xiaoping Fan640faf42015-08-28 15:50:55 -0700316 if (!si->flow_cookie_enable)
317 return;
318
Xiaoping Fand1dc7b22015-01-23 00:43:56 -0800319 /*
320 * Configure hardware to put a flow cookie in packet of this flow,
321 * then we can accelerate the lookup process when we received this packet.
322 */
323 for (conn_match_idx = 1; conn_match_idx < SFE_FLOW_COOKIE_SIZE; conn_match_idx++) {
324 struct sfe_flow_cookie_entry *entry = &si->sfe_flow_cookie_table[conn_match_idx];
325
326 if ((NULL == entry->match) && time_is_before_jiffies(entry->last_clean_time + HZ)) {
327 flow_cookie_set_func_t func;
328
329 rcu_read_lock();
330 func = rcu_dereference(si->flow_cookie_set_func);
331 if (func) {
Xiaoping Fan59176422015-05-22 15:58:10 -0700332 if (!func(cm->match_protocol, cm->match_src_ip, cm->match_src_port,
Xiaoping Fand1dc7b22015-01-23 00:43:56 -0800333 cm->match_dest_ip, cm->match_dest_port, conn_match_idx)) {
334 entry->match = cm;
335 cm->flow_cookie = conn_match_idx;
336 }
337 }
338 rcu_read_unlock();
339
340 break;
341 }
342 }
343#endif
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100344}
345
346/*
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530347 * sfe_ipv4_remove_connection_match()
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100348 * Remove a connection match object from the hash.
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100349 */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530350static inline void sfe_ipv4_remove_connection_match(struct sfe_ipv4 *si, struct sfe_ipv4_connection_match *cm)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100351{
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530352
353 lockdep_assert_held(&si->lock);
354
Xiaoping Fand1dc7b22015-01-23 00:43:56 -0800355#ifdef CONFIG_NF_FLOW_COOKIE
Xiaoping Fan640faf42015-08-28 15:50:55 -0700356 if (si->flow_cookie_enable) {
357 /*
358 * Tell hardware that we no longer need a flow cookie in packet of this flow
359 */
360 unsigned int conn_match_idx;
Xiaoping Fand1dc7b22015-01-23 00:43:56 -0800361
Xiaoping Fan640faf42015-08-28 15:50:55 -0700362 for (conn_match_idx = 1; conn_match_idx < SFE_FLOW_COOKIE_SIZE; conn_match_idx++) {
363 struct sfe_flow_cookie_entry *entry = &si->sfe_flow_cookie_table[conn_match_idx];
Xiaoping Fand1dc7b22015-01-23 00:43:56 -0800364
Xiaoping Fan640faf42015-08-28 15:50:55 -0700365 if (cm == entry->match) {
366 flow_cookie_set_func_t func;
Xiaoping Fand1dc7b22015-01-23 00:43:56 -0800367
Xiaoping Fan640faf42015-08-28 15:50:55 -0700368 rcu_read_lock();
369 func = rcu_dereference(si->flow_cookie_set_func);
370 if (func) {
371 func(cm->match_protocol, cm->match_src_ip, cm->match_src_port,
372 cm->match_dest_ip, cm->match_dest_port, 0);
373 }
374 rcu_read_unlock();
375
376 cm->flow_cookie = 0;
377 entry->match = NULL;
378 entry->last_clean_time = jiffies;
379 break;
Xiaoping Fand1dc7b22015-01-23 00:43:56 -0800380 }
Xiaoping Fand1dc7b22015-01-23 00:43:56 -0800381 }
382 }
383#endif
384
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530385 hlist_del_init_rcu(&cm->hnode);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100386
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100387}
388
389/*
390 * sfe_ipv4_get_connection_hash()
391 * Generate the hash used in connection lookups.
392 */
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700393static inline unsigned int sfe_ipv4_get_connection_hash(u8 protocol, __be32 src_ip, __be16 src_port,
Dave Hudson87973cd2013-10-22 16:00:04 +0100394 __be32 dest_ip, __be16 dest_port)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100395{
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700396 u32 hash = ntohl(src_ip ^ dest_ip) ^ protocol ^ ntohs(src_port ^ dest_port);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100397 return ((hash >> SFE_IPV4_CONNECTION_HASH_SHIFT) ^ hash) & SFE_IPV4_CONNECTION_HASH_MASK;
398}
399
400/*
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530401 * sfe_ipv4_find_connection()
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100402 * Get the IPv4 connection info that corresponds to a particular 5-tuple.
403 *
404 * On entry we must be holding the lock that protects the hash table.
405 */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530406static inline struct sfe_ipv4_connection *sfe_ipv4_find_connection(struct sfe_ipv4 *si, u32 protocol,
Dave Hudson87973cd2013-10-22 16:00:04 +0100407 __be32 src_ip, __be16 src_port,
408 __be32 dest_ip, __be16 dest_port)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100409{
410 struct sfe_ipv4_connection *c;
411 unsigned int conn_idx = sfe_ipv4_get_connection_hash(protocol, src_ip, src_port, dest_ip, dest_port);
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530412
413 lockdep_assert_held(&si->lock);
414
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100415 c = si->conn_hash[conn_idx];
416
417 /*
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100418 * Will need connection entry for next create/destroy metadata,
419 * So no need to re-order entry for these requests
420 */
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530421 while (c) {
422 if ((c->src_port == src_port)
423 && (c->dest_port == dest_port)
424 && (c->src_ip == src_ip)
425 && (c->dest_ip == dest_ip)
426 && (c->protocol == protocol)) {
427 return c;
428 }
429
430 c = c->next;
431 }
432
433 return NULL;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100434}
435
436/*
Matthew McClintockbe7b47d2013-11-27 13:26:23 -0600437 * sfe_ipv4_mark_rule()
438 * Updates the mark for a current offloaded connection
439 *
440 * Will take hash lock upon entry
441 */
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700442void sfe_ipv4_mark_rule(struct sfe_connection_mark *mark)
Matthew McClintockbe7b47d2013-11-27 13:26:23 -0600443{
444 struct sfe_ipv4 *si = &__si;
445 struct sfe_ipv4_connection *c;
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600446
Xiaoping Fan3c423e32015-07-03 03:09:29 -0700447 spin_lock_bh(&si->lock);
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530448 c = sfe_ipv4_find_connection(si, mark->protocol,
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700449 mark->src_ip.ip, mark->src_port,
450 mark->dest_ip.ip, mark->dest_port);
Matthew McClintockbe7b47d2013-11-27 13:26:23 -0600451 if (c) {
Nicolas Costaf53d6fe2014-01-13 16:03:46 -0600452 WARN_ON((0 != c->mark) && (0 == mark->mark));
Matthew McClintockbe7b47d2013-11-27 13:26:23 -0600453 c->mark = mark->mark;
454 }
Xiaoping Fan3c423e32015-07-03 03:09:29 -0700455 spin_unlock_bh(&si->lock);
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700456
457 if (c) {
458 DEBUG_TRACE("Matching connection found for mark, "
459 "setting from %08x to %08x\n",
460 c->mark, mark->mark);
461 }
Matthew McClintockbe7b47d2013-11-27 13:26:23 -0600462}
463
464/*
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530465 * sfe_ipv4_insert_connection()
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100466 * Insert a connection into the hash.
467 *
468 * On entry we must be holding the lock that protects the hash table.
469 */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530470static void sfe_ipv4_insert_connection(struct sfe_ipv4 *si, struct sfe_ipv4_connection *c)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100471{
472 struct sfe_ipv4_connection **hash_head;
473 struct sfe_ipv4_connection *prev_head;
474 unsigned int conn_idx;
475
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530476 lockdep_assert_held(&si->lock);
477
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100478 /*
479 * Insert entry into the connection hash.
480 */
481 conn_idx = sfe_ipv4_get_connection_hash(c->protocol, c->src_ip, c->src_port,
482 c->dest_ip, c->dest_port);
483 hash_head = &si->conn_hash[conn_idx];
484 prev_head = *hash_head;
485 c->prev = NULL;
486 if (prev_head) {
487 prev_head->prev = c;
488 }
489
490 c->next = prev_head;
491 *hash_head = c;
492
493 /*
494 * Insert entry into the "all connections" list.
495 */
496 if (si->all_connections_tail) {
497 c->all_connections_prev = si->all_connections_tail;
498 si->all_connections_tail->all_connections_next = c;
499 } else {
500 c->all_connections_prev = NULL;
501 si->all_connections_head = c;
502 }
503
504 si->all_connections_tail = c;
505 c->all_connections_next = NULL;
506 si->num_connections++;
507
508 /*
509 * Insert the connection match objects too.
510 */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530511 sfe_ipv4_insert_connection_match(si, c->original_match);
512 sfe_ipv4_insert_connection_match(si, c->reply_match);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100513}
514
515/*
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530516 * sfe_ipv4_remove_connection()
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100517 * Remove a sfe_ipv4_connection object from the hash.
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100518 */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530519bool sfe_ipv4_remove_connection(struct sfe_ipv4 *si, struct sfe_ipv4_connection *c)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100520{
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530521 lockdep_assert_held(&si->lock);
522
523 if (c->removed) {
524 DEBUG_ERROR("%px: Connection has been removed already\n", c);
525 return false;
526 }
527
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100528 /*
529 * Remove the connection match objects.
530 */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530531 sfe_ipv4_remove_connection_match(si, c->reply_match);
532 sfe_ipv4_remove_connection_match(si, c->original_match);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100533
534 /*
535 * Unlink the connection.
536 */
537 if (c->prev) {
538 c->prev->next = c->next;
539 } else {
540 unsigned int conn_idx = sfe_ipv4_get_connection_hash(c->protocol, c->src_ip, c->src_port,
541 c->dest_ip, c->dest_port);
542 si->conn_hash[conn_idx] = c->next;
543 }
544
545 if (c->next) {
546 c->next->prev = c->prev;
547 }
Xiaoping Fan34586472015-07-03 02:20:35 -0700548
549 /*
550 * Unlink connection from all_connections list
551 */
552 if (c->all_connections_prev) {
553 c->all_connections_prev->all_connections_next = c->all_connections_next;
554 } else {
555 si->all_connections_head = c->all_connections_next;
556 }
557
558 if (c->all_connections_next) {
559 c->all_connections_next->all_connections_prev = c->all_connections_prev;
560 } else {
561 si->all_connections_tail = c->all_connections_prev;
562 }
563
Ken Zhudc423672021-09-02 18:27:01 -0700564 /*
565 * If I am the next sync connection, move the sync to my next or head.
566 */
567 if (unlikely(si->wc_next == c)) {
568 si->wc_next = c->all_connections_next;
569 }
570
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530571 c->removed = true;
Xiaoping Fan34586472015-07-03 02:20:35 -0700572 si->num_connections--;
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530573 return true;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100574}
575
576/*
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530577 * sfe_ipv4_gen_sync_connection()
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100578 * Sync a connection.
579 *
580 * On entry to this function we expect that the lock for the connection is either
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530581 * already held (while called from sfe_ipv4_periodic_sync() or isn't required
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530582 * (while called from sfe_ipv4_flush_connection())
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100583 */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530584static void sfe_ipv4_gen_sync_connection(struct sfe_ipv4 *si, struct sfe_ipv4_connection *c,
Xiaoping Fan99cb4c12015-08-21 19:07:32 -0700585 struct sfe_connection_sync *sis, sfe_sync_reason_t reason,
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700586 u64 now_jiffies)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100587{
588 struct sfe_ipv4_connection_match *original_cm;
589 struct sfe_ipv4_connection_match *reply_cm;
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530590 u32 packet_count, byte_count;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100591
592 /*
593 * Fill in the update message.
594 */
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700595 sis->is_v6 = 0;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100596 sis->protocol = c->protocol;
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700597 sis->src_ip.ip = c->src_ip;
Xiaoping Fan99cb4c12015-08-21 19:07:32 -0700598 sis->src_ip_xlate.ip = c->src_ip_xlate;
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700599 sis->dest_ip.ip = c->dest_ip;
Xiaoping Fan99cb4c12015-08-21 19:07:32 -0700600 sis->dest_ip_xlate.ip = c->dest_ip_xlate;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100601 sis->src_port = c->src_port;
Xiaoping Fan99cb4c12015-08-21 19:07:32 -0700602 sis->src_port_xlate = c->src_port_xlate;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100603 sis->dest_port = c->dest_port;
Xiaoping Fan99cb4c12015-08-21 19:07:32 -0700604 sis->dest_port_xlate = c->dest_port_xlate;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100605
606 original_cm = c->original_match;
607 reply_cm = c->reply_match;
608 sis->src_td_max_window = original_cm->protocol_state.tcp.max_win;
609 sis->src_td_end = original_cm->protocol_state.tcp.end;
610 sis->src_td_max_end = original_cm->protocol_state.tcp.max_end;
611 sis->dest_td_max_window = reply_cm->protocol_state.tcp.max_win;
612 sis->dest_td_end = reply_cm->protocol_state.tcp.end;
613 sis->dest_td_max_end = reply_cm->protocol_state.tcp.max_end;
614
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530615 sfe_ipv4_connection_match_update_summary_stats(original_cm, &packet_count, &byte_count);
616 sis->src_new_packet_count = packet_count;
617 sis->src_new_byte_count = byte_count;
Matthew McClintockd0cdb802014-02-24 16:30:35 -0600618
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530619 sfe_ipv4_connection_match_update_summary_stats(reply_cm, &packet_count, &byte_count);
620 sis->dest_new_packet_count = packet_count;
621 sis->dest_new_byte_count = byte_count;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100622
Matthew McClintockd0cdb802014-02-24 16:30:35 -0600623 sis->src_dev = original_cm->match_dev;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100624 sis->src_packet_count = original_cm->rx_packet_count64;
625 sis->src_byte_count = original_cm->rx_byte_count64;
Matthew McClintockd0cdb802014-02-24 16:30:35 -0600626
627 sis->dest_dev = reply_cm->match_dev;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100628 sis->dest_packet_count = reply_cm->rx_packet_count64;
629 sis->dest_byte_count = reply_cm->rx_byte_count64;
630
Xiaoping Fan99cb4c12015-08-21 19:07:32 -0700631 sis->reason = reason;
632
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100633 /*
634 * Get the time increment since our last sync.
635 */
636 sis->delta_jiffies = now_jiffies - c->last_sync_jiffies;
637 c->last_sync_jiffies = now_jiffies;
638}
639
640/*
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530641 * sfe_ipv4_free_connection_rcu()
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530642 * Called at RCU qs state to free the connection object.
643 */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530644static void sfe_ipv4_free_connection_rcu(struct rcu_head *head)
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530645{
646 struct sfe_ipv4_connection *c;
647
648 /*
649 * We dont need spin lock as the connection is already removed from link list
650 */
651 c = container_of(head, struct sfe_ipv4_connection, rcu);
652
653 BUG_ON(!c->removed);
654
655 DEBUG_TRACE("%px: connecton has been deleted\n", c);
656
657 /*
658 * Release our hold of the source and dest devices and free the memory
659 * for our connection objects.
660 */
661 dev_put(c->original_dev);
662 dev_put(c->reply_dev);
663 kfree(c->original_match);
664 kfree(c->reply_match);
665 kfree(c);
666}
667
668/*
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530669 * sfe_ipv4_flush_connection()
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100670 * Flush a connection and free all associated resources.
671 *
672 * We need to be called with bottom halves disabled locally as we need to acquire
673 * the connection hash lock and release it again. In general we're actually called
674 * from within a BH and so we're fine, but we're also called when connections are
675 * torn down.
676 */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530677void sfe_ipv4_flush_connection(struct sfe_ipv4 *si,
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700678 struct sfe_ipv4_connection *c,
679 sfe_sync_reason_t reason)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100680{
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700681 u64 now_jiffies;
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700682 sfe_sync_rule_callback_t sync_rule_callback;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100683
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530684 BUG_ON(!c->removed);
685
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +0530686 this_cpu_inc(si->stats_pcpu->connection_flushes64);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100687
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530688 rcu_read_lock();
689 sync_rule_callback = rcu_dereference(si->sync_rule_callback);
690
691 /*
692 * Generate a sync message and then sync.
693 */
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600694 if (sync_rule_callback) {
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530695 struct sfe_connection_sync sis;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600696 now_jiffies = get_jiffies_64();
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530697 sfe_ipv4_gen_sync_connection(si, c, &sis, reason, now_jiffies);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600698 sync_rule_callback(&sis);
699 }
700
701 rcu_read_unlock();
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100702
703 /*
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100704 * Release our hold of the source and dest devices and free the memory
705 * for our connection objects.
706 */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530707 call_rcu(&c->rcu, sfe_ipv4_free_connection_rcu);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100708}
709
710/*
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +0530711 * sfe_ipv4_exception_stats_inc()
712 * Increment exception stats.
713 */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530714void sfe_ipv4_exception_stats_inc(struct sfe_ipv4 *si, enum sfe_ipv4_exception_events reason)
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +0530715{
716 struct sfe_ipv4_stats *stats = this_cpu_ptr(si->stats_pcpu);
717 stats->exception_events64[reason]++;
718 stats->packets_not_forwarded64++;
719}
720
721/*
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100722 * sfe_ipv4_recv()
Matthew McClintocka8ad7962014-01-16 16:49:30 -0600723 * Handle packet receives and forwaring.
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100724 *
725 * Returns 1 if the packet is forwarded or 0 if it isn't.
726 */
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600727int sfe_ipv4_recv(struct net_device *dev, struct sk_buff *skb)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100728{
729 struct sfe_ipv4 *si = &__si;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100730 unsigned int len;
731 unsigned int tot_len;
732 unsigned int frag_off;
733 unsigned int ihl;
734 bool flush_on_find;
735 bool ip_options;
Ratheesh Kannoth741f7992021-10-20 07:39:52 +0530736 struct iphdr *iph;
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700737 u32 protocol;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100738
739 /*
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100740 * Check that we have space for an IP header here.
741 */
742 len = skb->len;
Ratheesh Kannoth741f7992021-10-20 07:39:52 +0530743 if (unlikely(!pskb_may_pull(skb, sizeof(struct iphdr)))) {
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +0530744 sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_HEADER_INCOMPLETE);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100745 DEBUG_TRACE("len: %u is too short\n", len);
746 return 0;
747 }
748
749 /*
750 * Check that our "total length" is large enough for an IP header.
751 */
Ratheesh Kannoth741f7992021-10-20 07:39:52 +0530752 iph = (struct iphdr *)skb->data;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100753 tot_len = ntohs(iph->tot_len);
Ratheesh Kannoth741f7992021-10-20 07:39:52 +0530754 if (unlikely(tot_len < sizeof(struct iphdr))) {
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100755
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +0530756 sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_BAD_TOTAL_LENGTH);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100757 DEBUG_TRACE("tot_len: %u is too short\n", tot_len);
758 return 0;
759 }
760
761 /*
762 * Is our IP version wrong?
763 */
764 if (unlikely(iph->version != 4)) {
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +0530765 sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_NON_V4);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100766 DEBUG_TRACE("IP version: %u\n", iph->version);
767 return 0;
768 }
769
770 /*
771 * Does our datagram fit inside the skb?
772 */
773 if (unlikely(tot_len > len)) {
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100774
775 DEBUG_TRACE("tot_len: %u, exceeds len: %u\n", tot_len, len);
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +0530776 sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_DATAGRAM_INCOMPLETE);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100777 return 0;
778 }
779
780 /*
781 * Do we have a non-initial fragment?
Nicolas Costaac2979c2014-01-14 10:35:24 -0600782 */
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100783 frag_off = ntohs(iph->frag_off);
784 if (unlikely(frag_off & IP_OFFSET)) {
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +0530785 sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_NON_INITIAL_FRAGMENT);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100786 DEBUG_TRACE("non-initial fragment\n");
787 return 0;
788 }
789
790 /*
791 * If we have a (first) fragment then mark it to cause any connection to flush.
792 */
793 flush_on_find = unlikely(frag_off & IP_MF) ? true : false;
794
795 /*
796 * Do we have any IP options? That's definite a slow path! If we do have IP
797 * options we need to recheck our header size.
798 */
799 ihl = iph->ihl << 2;
Ratheesh Kannoth741f7992021-10-20 07:39:52 +0530800 ip_options = unlikely(ihl != sizeof(struct iphdr)) ? true : false;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100801 if (unlikely(ip_options)) {
802 if (unlikely(len < ihl)) {
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100803
804 DEBUG_TRACE("len: %u is too short for header of size: %u\n", len, ihl);
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +0530805 sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_IP_OPTIONS_INCOMPLETE);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100806 return 0;
807 }
808
809 flush_on_find = true;
810 }
811
812 protocol = iph->protocol;
813 if (IPPROTO_UDP == protocol) {
814 return sfe_ipv4_recv_udp(si, skb, dev, len, iph, ihl, flush_on_find);
815 }
816
817 if (IPPROTO_TCP == protocol) {
818 return sfe_ipv4_recv_tcp(si, skb, dev, len, iph, ihl, flush_on_find);
819 }
820
821 if (IPPROTO_ICMP == protocol) {
822 return sfe_ipv4_recv_icmp(si, skb, dev, len, iph, ihl);
823 }
824
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +0530825 sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_UNHANDLED_PROTOCOL);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100826
827 DEBUG_TRACE("not UDP, TCP or ICMP: %u\n", protocol);
828 return 0;
829}
830
Nicolas Costa436926b2014-01-14 10:36:22 -0600831static void
832sfe_ipv4_update_tcp_state(struct sfe_ipv4_connection *c,
Ratheesh Kannoth89302a72021-10-20 08:10:37 +0530833 struct sfe_ipv4_rule_create_msg *msg)
Nicolas Costa436926b2014-01-14 10:36:22 -0600834{
835 struct sfe_ipv4_connection_match *orig_cm;
836 struct sfe_ipv4_connection_match *repl_cm;
837 struct sfe_ipv4_tcp_connection_match *orig_tcp;
838 struct sfe_ipv4_tcp_connection_match *repl_tcp;
839
840 orig_cm = c->original_match;
841 repl_cm = c->reply_match;
842 orig_tcp = &orig_cm->protocol_state.tcp;
843 repl_tcp = &repl_cm->protocol_state.tcp;
844
845 /* update orig */
Ratheesh Kannoth89302a72021-10-20 08:10:37 +0530846 if (orig_tcp->max_win < msg->tcp_rule.flow_max_window) {
847 orig_tcp->max_win = msg->tcp_rule.flow_max_window;
Nicolas Costa436926b2014-01-14 10:36:22 -0600848 }
Ratheesh Kannoth89302a72021-10-20 08:10:37 +0530849 if ((s32)(orig_tcp->end - msg->tcp_rule.flow_end) < 0) {
850 orig_tcp->end = msg->tcp_rule.flow_end;
Nicolas Costa436926b2014-01-14 10:36:22 -0600851 }
Ratheesh Kannoth89302a72021-10-20 08:10:37 +0530852 if ((s32)(orig_tcp->max_end - msg->tcp_rule.flow_max_end) < 0) {
853 orig_tcp->max_end = msg->tcp_rule.flow_max_end;
Nicolas Costa436926b2014-01-14 10:36:22 -0600854 }
855
856 /* update reply */
Ratheesh Kannoth89302a72021-10-20 08:10:37 +0530857 if (repl_tcp->max_win < msg->tcp_rule.return_max_window) {
858 repl_tcp->max_win = msg->tcp_rule.return_max_window;
Nicolas Costa436926b2014-01-14 10:36:22 -0600859 }
Ratheesh Kannoth89302a72021-10-20 08:10:37 +0530860 if ((s32)(repl_tcp->end - msg->tcp_rule.return_end) < 0) {
861 repl_tcp->end = msg->tcp_rule.return_end;
Nicolas Costa436926b2014-01-14 10:36:22 -0600862 }
Ratheesh Kannoth89302a72021-10-20 08:10:37 +0530863 if ((s32)(repl_tcp->max_end - msg->tcp_rule.return_max_end) < 0) {
864 repl_tcp->max_end = msg->tcp_rule.return_max_end;
Nicolas Costa436926b2014-01-14 10:36:22 -0600865 }
866
867 /* update match flags */
868 orig_cm->flags &= ~SFE_IPV4_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK;
869 repl_cm->flags &= ~SFE_IPV4_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK;
Ratheesh Kannoth89302a72021-10-20 08:10:37 +0530870 if (msg->rule_flags & SFE_RULE_CREATE_FLAG_NO_SEQ_CHECK) {
871
Nicolas Costa436926b2014-01-14 10:36:22 -0600872 orig_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK;
873 repl_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK;
874 }
875}
876
877static void
878sfe_ipv4_update_protocol_state(struct sfe_ipv4_connection *c,
Ratheesh Kannoth89302a72021-10-20 08:10:37 +0530879 struct sfe_ipv4_rule_create_msg *msg)
Nicolas Costa436926b2014-01-14 10:36:22 -0600880{
Ratheesh Kannoth89302a72021-10-20 08:10:37 +0530881 switch (msg->tuple.protocol) {
Nicolas Costa436926b2014-01-14 10:36:22 -0600882 case IPPROTO_TCP:
Ratheesh Kannoth89302a72021-10-20 08:10:37 +0530883 sfe_ipv4_update_tcp_state(c, msg);
Nicolas Costa436926b2014-01-14 10:36:22 -0600884 break;
885 }
886}
887
Ratheesh Kannoth89302a72021-10-20 08:10:37 +0530888void sfe_ipv4_update_rule(struct sfe_ipv4_rule_create_msg *msg)
Nicolas Costa436926b2014-01-14 10:36:22 -0600889{
890 struct sfe_ipv4_connection *c;
891 struct sfe_ipv4 *si = &__si;
892
893 spin_lock_bh(&si->lock);
894
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530895 c = sfe_ipv4_find_connection(si,
Ratheesh Kannoth89302a72021-10-20 08:10:37 +0530896 msg->tuple.protocol,
897 msg->tuple.flow_ip,
898 msg->tuple.flow_ident,
899 msg->tuple.return_ip,
900 msg->tuple.return_ident);
Nicolas Costa436926b2014-01-14 10:36:22 -0600901 if (c != NULL) {
Ratheesh Kannoth89302a72021-10-20 08:10:37 +0530902 sfe_ipv4_update_protocol_state(c, msg);
Nicolas Costa436926b2014-01-14 10:36:22 -0600903 }
904
905 spin_unlock_bh(&si->lock);
906}
907
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100908/*
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100909 * sfe_ipv4_create_rule()
910 * Create a forwarding rule.
911 */
Ratheesh Kannoth89302a72021-10-20 08:10:37 +0530912int sfe_ipv4_create_rule(struct sfe_ipv4_rule_create_msg *msg)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100913{
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600914 struct sfe_ipv4 *si = &__si;
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530915 struct sfe_ipv4_connection *c, *c_old;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100916 struct sfe_ipv4_connection_match *original_cm;
917 struct sfe_ipv4_connection_match *reply_cm;
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600918 struct net_device *dest_dev;
919 struct net_device *src_dev;
Ratheesh Kannoth89302a72021-10-20 08:10:37 +0530920 struct sfe_ipv4_5tuple *tuple = &msg->tuple;
Suruchi Sumanc1a4a612021-10-21 14:50:23 +0530921 s32 flow_interface_num = msg->conn_rule.flow_top_interface_num;
922 s32 return_interface_num = msg->conn_rule.return_top_interface_num;
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600923
Suruchi Sumanc1a4a612021-10-21 14:50:23 +0530924 if (msg->rule_flags & SFE_RULE_CREATE_FLAG_USE_FLOW_BOTTOM_INTERFACE) {
925 flow_interface_num = msg->conn_rule.flow_interface_num;
926 }
927
928 if (msg->rule_flags & SFE_RULE_CREATE_FLAG_USE_RETURN_BOTTOM_INTERFACE) {
929 return_interface_num = msg->conn_rule.return_interface_num;
930 }
931
932 src_dev = dev_get_by_index(&init_net, flow_interface_num);
Ratheesh Kannoth89302a72021-10-20 08:10:37 +0530933 if (!src_dev) {
934 DEBUG_WARN("%px: Unable to find src_dev corresponding to %d\n", msg,
Suruchi Sumanc1a4a612021-10-21 14:50:23 +0530935 flow_interface_num);
Ratheesh Kannoth89302a72021-10-20 08:10:37 +0530936 this_cpu_inc(si->stats_pcpu->connection_create_failures64);
937 return -EINVAL;
938 }
939
Suruchi Sumanc1a4a612021-10-21 14:50:23 +0530940 dest_dev = dev_get_by_index(&init_net, return_interface_num);
Ratheesh Kannoth89302a72021-10-20 08:10:37 +0530941 if (!dest_dev) {
942 DEBUG_WARN("%px: Unable to find dest_dev corresponding to %d\n", msg,
Suruchi Sumanc1a4a612021-10-21 14:50:23 +0530943 return_interface_num);
Ratheesh Kannoth89302a72021-10-20 08:10:37 +0530944 this_cpu_inc(si->stats_pcpu->connection_create_failures64);
945 dev_put(src_dev);
946 return -EINVAL;
947 }
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100948
Matthew McClintock389b42a2014-09-24 14:05:51 -0500949 if (unlikely((dest_dev->reg_state != NETREG_REGISTERED) ||
950 (src_dev->reg_state != NETREG_REGISTERED))) {
Ratheesh Kannoth89302a72021-10-20 08:10:37 +0530951 dev_put(src_dev);
952 dev_put(dest_dev);
953 DEBUG_WARN("%px: src_dev=%s and dest_dev=%s are unregistered\n", msg,
954 src_dev->name, dest_dev->name);
955 this_cpu_inc(si->stats_pcpu->connection_create_failures64);
Matthew McClintock389b42a2014-09-24 14:05:51 -0500956 return -EINVAL;
957 }
958
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530959 /*
960 * Allocate the various connection tracking objects.
961 */
962 c = (struct sfe_ipv4_connection *)kmalloc(sizeof(struct sfe_ipv4_connection), GFP_ATOMIC);
963 if (unlikely(!c)) {
Ratheesh Kannoth89302a72021-10-20 08:10:37 +0530964 DEBUG_WARN("%px: memory allocation of connection entry failed\n", msg);
965 this_cpu_inc(si->stats_pcpu->connection_create_failures64);
966 dev_put(src_dev);
967 dev_put(dest_dev);
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530968 return -ENOMEM;
969 }
970
971 original_cm = (struct sfe_ipv4_connection_match *)kmalloc(sizeof(struct sfe_ipv4_connection_match), GFP_ATOMIC);
972 if (unlikely(!original_cm)) {
Ratheesh Kannoth89302a72021-10-20 08:10:37 +0530973 DEBUG_WARN("%px: memory allocation of connection match entry failed\n", msg);
974 this_cpu_inc(si->stats_pcpu->connection_create_failures64);
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530975 kfree(c);
Ratheesh Kannoth89302a72021-10-20 08:10:37 +0530976 dev_put(src_dev);
977 dev_put(dest_dev);
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530978 return -ENOMEM;
979 }
980
981 reply_cm = (struct sfe_ipv4_connection_match *)kmalloc(sizeof(struct sfe_ipv4_connection_match), GFP_ATOMIC);
982 if (unlikely(!reply_cm)) {
Ratheesh Kannoth89302a72021-10-20 08:10:37 +0530983 DEBUG_WARN("%px: memory allocation of connection match entry failed\n", msg);
984 this_cpu_inc(si->stats_pcpu->connection_create_failures64);
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530985 kfree(original_cm);
986 kfree(c);
Ratheesh Kannoth89302a72021-10-20 08:10:37 +0530987 dev_put(src_dev);
988 dev_put(dest_dev);
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530989 return -ENOMEM;
990 }
991
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +0530992 this_cpu_inc(si->stats_pcpu->connection_create_requests64);
993
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100994 spin_lock_bh(&si->lock);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100995
996 /*
Nicolas Costa436926b2014-01-14 10:36:22 -0600997 * Check to see if there is already a flow that matches the rule we're
998 * trying to create. If there is then we can't create a new one.
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100999 */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05301000 c_old = sfe_ipv4_find_connection(si,
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301001 msg->tuple.protocol,
1002 msg->tuple.flow_ip,
1003 msg->tuple.flow_ident,
1004 msg->tuple.return_ip,
1005 msg->tuple.return_ident);
1006
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05301007 if (c_old != NULL) {
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +05301008 this_cpu_inc(si->stats_pcpu->connection_create_collisions64);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001009
1010 /*
Nicolas Costa436926b2014-01-14 10:36:22 -06001011 * If we already have the flow then it's likely that this
1012 * request to create the connection rule contains more
1013 * up-to-date information. Check and update accordingly.
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001014 */
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301015 sfe_ipv4_update_protocol_state(c, msg);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001016 spin_unlock_bh(&si->lock);
1017
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05301018 kfree(reply_cm);
1019 kfree(original_cm);
1020 kfree(c);
1021
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301022 dev_put(src_dev);
1023 dev_put(dest_dev);
1024
1025 DEBUG_TRACE("connection already exists - p:%d\n"
1026 " s: %s:%pM:%pI4:%u, d: %s:%pM:%pI4:%u\n",
1027 tuple->protocol,
1028 src_dev->name, msg->conn_rule.flow_mac, &tuple->flow_ip, ntohs(tuple->flow_ident),
1029 dest_dev->name, msg->conn_rule.return_mac, &tuple->return_ip, ntohs(tuple->return_ident));
1030
Nicolas Costa514fde02014-01-13 15:50:29 -06001031 return -EADDRINUSE;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001032 }
1033
1034 /*
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001035 * Fill in the "original" direction connection matching object.
1036 * Note that the transmit MAC address is "dest_mac_xlate" because
1037 * we always know both ends of a connection by their translated
1038 * addresses and not their public addresses.
1039 */
Matthew McClintockdb5ac512014-01-16 17:01:40 -06001040 original_cm->match_dev = src_dev;
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301041 original_cm->match_protocol = tuple->protocol;
1042 original_cm->match_src_ip = tuple->flow_ip;
1043 original_cm->match_src_port = tuple->flow_ident;
1044 original_cm->match_dest_ip = tuple->return_ip;
1045 original_cm->match_dest_port = tuple->return_ident;
1046
1047 original_cm->xlate_src_ip = msg->conn_rule.flow_ip_xlate;
1048 original_cm->xlate_src_port = msg->conn_rule.flow_ident_xlate;
1049 original_cm->xlate_dest_ip = msg->conn_rule.return_ip_xlate;
1050 original_cm->xlate_dest_port =msg->conn_rule.return_ident_xlate;
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05301051 atomic_set(&original_cm->rx_packet_count, 0);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001052 original_cm->rx_packet_count64 = 0;
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05301053 atomic_set(&original_cm->rx_byte_count, 0);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001054 original_cm->rx_byte_count64 = 0;
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301055
Matthew McClintockdb5ac512014-01-16 17:01:40 -06001056 original_cm->xmit_dev = dest_dev;
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301057 original_cm->xmit_dev_mtu = msg->conn_rule.return_mtu;
1058
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001059 original_cm->connection = c;
1060 original_cm->counter_match = reply_cm;
1061 original_cm->flags = 0;
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301062
1063 if (msg->valid_flags & SFE_RULE_CREATE_QOS_VALID) {
1064 original_cm->priority = msg->qos_rule.flow_qos_tag;
Xiaoping Fane1963d42015-08-25 17:06:19 -07001065 original_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_PRIORITY_REMARK;
1066 }
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301067
1068 if (msg->valid_flags & SFE_RULE_CREATE_DSCP_MARKING_VALID) {
1069 original_cm->dscp = msg->dscp_rule.flow_dscp << SFE_IPV4_DSCP_SHIFT;
Xiaoping Fane1963d42015-08-25 17:06:19 -07001070 original_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_DSCP_REMARK;
1071 }
Xiaoping Fand1dc7b22015-01-23 00:43:56 -08001072#ifdef CONFIG_NF_FLOW_COOKIE
1073 original_cm->flow_cookie = 0;
1074#endif
Zhi Chen8748eb32015-06-18 12:58:48 -07001075#ifdef CONFIG_XFRM
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301076 if (msg->valid_flags & SFE_RULE_CREATE_DIRECTION_VALID) {
1077 original_cm->flow_accel = msg->direction_rule.flow_accel;
1078 } else {
1079 original_cm->flow_accel = 1;
1080 }
1081
Zhi Chen8748eb32015-06-18 12:58:48 -07001082#endif
Matthew McClintockdb5ac512014-01-16 17:01:40 -06001083
1084 /*
Ken Zhubbf49652021-09-12 15:33:09 -07001085 * For the non-arp interface, we don't write L2 HDR.
Matthew McClintockdb5ac512014-01-16 17:01:40 -06001086 */
Ken Zhubbf49652021-09-12 15:33:09 -07001087 if (!(dest_dev->flags & IFF_NOARP)) {
Ratheesh Kannoth29140aa2021-10-20 08:25:02 +05301088
1089 /*
1090 * Check whether the rule has configured a specific source MAC address to use.
1091 * This is needed when virtual L3 interfaces such as br-lan, macvlan, vlan are used during egress
1092 */
1093 if ((msg->valid_flags & SFE_RULE_CREATE_SRC_MAC_VALID) &&
1094 (msg->src_mac_rule.mac_valid_flags & SFE_SRC_MAC_RETURN_VALID)) {
1095 ether_addr_copy((u8 *)original_cm->xmit_src_mac, (u8 *)msg->src_mac_rule.return_src_mac);
1096 } else {
1097 ether_addr_copy((u8 *)original_cm->xmit_src_mac, (u8 *)dest_dev->dev_addr);
1098 }
1099
1100 ether_addr_copy((u8 *)original_cm->xmit_dest_mac, (u8 *)msg->conn_rule.return_mac);
1101
Matthew McClintockdb5ac512014-01-16 17:01:40 -06001102 original_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_WRITE_L2_HDR;
1103
1104 /*
1105 * If our dev writes Ethernet headers then we can write a really fast
1106 * version.
1107 */
1108 if (dest_dev->header_ops) {
1109 if (dest_dev->header_ops->create == eth_header) {
1110 original_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_WRITE_FAST_ETH_HDR;
1111 }
1112 }
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001113 }
1114
1115 /*
1116 * Fill in the "reply" direction connection matching object.
1117 */
Matthew McClintockdb5ac512014-01-16 17:01:40 -06001118 reply_cm->match_dev = dest_dev;
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301119 reply_cm->match_protocol = tuple->protocol;
1120 reply_cm->match_src_ip = msg->conn_rule.return_ip_xlate;
1121 reply_cm->match_src_port = msg->conn_rule.return_ident_xlate;
1122 reply_cm->match_dest_ip = msg->conn_rule.flow_ip_xlate;
1123 reply_cm->match_dest_port = msg->conn_rule.flow_ident_xlate;
1124
1125 reply_cm->xlate_src_ip = tuple->return_ip;
1126 reply_cm->xlate_src_port = tuple->return_ident;
1127 reply_cm->xlate_dest_ip = tuple->flow_ip;
1128 reply_cm->xlate_dest_port = tuple->flow_ident;;
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05301129
1130 atomic_set(&reply_cm->rx_packet_count, 0);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001131 reply_cm->rx_packet_count64 = 0;
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05301132 atomic_set(&reply_cm->rx_byte_count, 0);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001133 reply_cm->rx_byte_count64 = 0;
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05301134
Matthew McClintockdb5ac512014-01-16 17:01:40 -06001135 reply_cm->xmit_dev = src_dev;
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301136 reply_cm->xmit_dev_mtu = msg->conn_rule.flow_mtu;
Ratheesh Kannoth29140aa2021-10-20 08:25:02 +05301137
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001138 reply_cm->connection = c;
1139 reply_cm->counter_match = original_cm;
1140 reply_cm->flags = 0;
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301141 if (msg->valid_flags & SFE_RULE_CREATE_QOS_VALID) {
1142 reply_cm->priority = msg->qos_rule.return_qos_tag;
Xiaoping Fane1963d42015-08-25 17:06:19 -07001143 reply_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_PRIORITY_REMARK;
1144 }
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301145 if (msg->valid_flags & SFE_RULE_CREATE_DSCP_MARKING_VALID) {
1146 reply_cm->dscp = msg->dscp_rule.return_dscp << SFE_IPV4_DSCP_SHIFT;
Xiaoping Fane1963d42015-08-25 17:06:19 -07001147 reply_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_DSCP_REMARK;
1148 }
Xiaoping Fand1dc7b22015-01-23 00:43:56 -08001149#ifdef CONFIG_NF_FLOW_COOKIE
1150 reply_cm->flow_cookie = 0;
1151#endif
Zhi Chen8748eb32015-06-18 12:58:48 -07001152#ifdef CONFIG_XFRM
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301153 if (msg->valid_flags & SFE_RULE_CREATE_DIRECTION_VALID) {
1154 reply_cm->flow_accel = msg->direction_rule.return_accel;
1155 } else {
1156 reply_cm->flow_accel = 1;
1157 }
1158
Zhi Chen8748eb32015-06-18 12:58:48 -07001159#endif
Matthew McClintockdb5ac512014-01-16 17:01:40 -06001160
1161 /*
Ken Zhubbf49652021-09-12 15:33:09 -07001162 * For the non-arp interface, we don't write L2 HDR.
Matthew McClintockdb5ac512014-01-16 17:01:40 -06001163 */
Ken Zhubbf49652021-09-12 15:33:09 -07001164 if (!(src_dev->flags & IFF_NOARP)) {
Ratheesh Kannoth29140aa2021-10-20 08:25:02 +05301165
1166 /*
1167 * Check whether the rule has configured a specific source MAC address to use.
1168 * This is needed when virtual L3 interfaces such as br-lan, macvlan, vlan are used during egress
1169 */
1170 if ((msg->valid_flags & SFE_RULE_CREATE_SRC_MAC_VALID) &&
1171 (msg->src_mac_rule.mac_valid_flags & SFE_SRC_MAC_FLOW_VALID)) {
1172 ether_addr_copy((u8 *)reply_cm->xmit_src_mac, (u8 *)msg->src_mac_rule.flow_src_mac);
1173 } else {
1174 ether_addr_copy((u8 *)reply_cm->xmit_src_mac, (u8 *)src_dev->dev_addr);
1175 }
1176 ether_addr_copy((u8 *)reply_cm->xmit_dest_mac, (u8 *)msg->conn_rule.flow_mac);
1177
Matthew McClintockdb5ac512014-01-16 17:01:40 -06001178 reply_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_WRITE_L2_HDR;
1179
1180 /*
1181 * If our dev writes Ethernet headers then we can write a really fast
1182 * version.
1183 */
1184 if (src_dev->header_ops) {
1185 if (src_dev->header_ops->create == eth_header) {
1186 reply_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_WRITE_FAST_ETH_HDR;
1187 }
1188 }
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001189 }
1190
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301191 if ((tuple->return_ip != msg->conn_rule.return_ip_xlate) ||
1192 (tuple->return_ident != msg->conn_rule.return_ident_xlate)) {
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001193 original_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_DEST;
1194 reply_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_SRC;
1195 }
1196
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301197 if ((tuple->flow_ip != msg->conn_rule.flow_ip_xlate) ||
1198 (tuple->flow_ident != msg->conn_rule.flow_ident_xlate)) {
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001199 original_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_SRC;
1200 reply_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_DEST;
1201 }
1202
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301203 c->protocol = tuple->protocol;
1204 c->src_ip = tuple->flow_ip;
1205 c->src_ip_xlate = msg->conn_rule.flow_ip_xlate;
1206 c->src_port = tuple->flow_ident;
1207 c->src_port_xlate = msg->conn_rule.flow_ident_xlate;
Matthew McClintockdb5ac512014-01-16 17:01:40 -06001208 c->original_dev = src_dev;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001209 c->original_match = original_cm;
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301210 c->dest_ip = tuple->return_ip;
1211 c->dest_ip_xlate = msg->conn_rule.return_ip_xlate;
1212 c->dest_port = tuple->return_ident;
1213 c->dest_port_xlate = msg->conn_rule.return_ident_xlate;
Matthew McClintockdb5ac512014-01-16 17:01:40 -06001214 c->reply_dev = dest_dev;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001215 c->reply_match = reply_cm;
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301216 c->mark = 0; /* TODO : no mark setting for create rule */
Xiaoping Fan34586472015-07-03 02:20:35 -07001217 c->debug_read_seq = 0;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001218 c->last_sync_jiffies = get_jiffies_64();
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05301219 c->removed = false;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001220
1221 /*
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001222 * Initialize the protocol-specific information that we track.
1223 */
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301224 switch (tuple->protocol) {
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001225 case IPPROTO_TCP:
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301226 original_cm->protocol_state.tcp.win_scale = msg->tcp_rule.flow_window_scale;
1227 original_cm->protocol_state.tcp.max_win = msg->tcp_rule.flow_max_window ? msg->tcp_rule.flow_max_window : 1;
1228 original_cm->protocol_state.tcp.end = msg->tcp_rule.flow_end;
1229 original_cm->protocol_state.tcp.max_end = msg->tcp_rule.flow_max_end;
1230
1231 reply_cm->protocol_state.tcp.win_scale = msg->tcp_rule.return_window_scale;
1232 reply_cm->protocol_state.tcp.max_win = msg->tcp_rule.return_max_window ? msg->tcp_rule.return_max_window : 1;
1233 reply_cm->protocol_state.tcp.end = msg->tcp_rule.return_end;
1234 reply_cm->protocol_state.tcp.max_end = msg->tcp_rule.return_max_end;
1235
1236 if (msg->rule_flags & SFE_RULE_CREATE_FLAG_NO_SEQ_CHECK) {
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001237 original_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK;
1238 reply_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK;
1239 }
1240 break;
1241 }
1242
1243 sfe_ipv4_connection_match_compute_translations(original_cm);
1244 sfe_ipv4_connection_match_compute_translations(reply_cm);
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05301245 sfe_ipv4_insert_connection(si, c);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001246
1247 spin_unlock_bh(&si->lock);
1248
1249 /*
1250 * We have everything we need!
1251 */
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301252 DEBUG_INFO("new connection - p: %d\n"
Tian Yang45f39c82020-10-06 14:07:47 -07001253 " s: %s:%pxM(%pxM):%pI4(%pI4):%u(%u)\n"
1254 " d: %s:%pxM(%pxM):%pI4(%pI4):%u(%u)\n",
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301255 tuple->protocol,
1256 src_dev->name, msg->conn_rule.flow_mac, NULL,
1257 &tuple->flow_ip, &msg->conn_rule.flow_ip_xlate, ntohs(tuple->flow_ident), ntohs(msg->conn_rule.flow_ident_xlate),
1258 dest_dev->name, NULL, msg->conn_rule.return_mac,
1259 &tuple->return_ip, &msg->conn_rule.return_ip_xlate, ntohs(tuple->return_ident), ntohs(msg->conn_rule.return_ident_xlate));
Nicolas Costa514fde02014-01-13 15:50:29 -06001260
1261 return 0;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001262}
1263
1264/*
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001265 * sfe_ipv4_destroy_rule()
1266 * Destroy a forwarding rule.
1267 */
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301268void sfe_ipv4_destroy_rule(struct sfe_ipv4_rule_destroy_msg *msg)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001269{
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001270 struct sfe_ipv4 *si = &__si;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001271 struct sfe_ipv4_connection *c;
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05301272 bool ret;
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301273 struct sfe_ipv4_5tuple *tuple = &msg->tuple;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001274
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +05301275 this_cpu_inc(si->stats_pcpu->connection_destroy_requests64);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001276 spin_lock_bh(&si->lock);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001277
1278 /*
1279 * Check to see if we have a flow that matches the rule we're trying
1280 * to destroy. If there isn't then we can't destroy it.
1281 */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05301282 c = sfe_ipv4_find_connection(si, tuple->protocol, tuple->flow_ip, tuple->flow_ident,
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301283 tuple->return_ip, tuple->return_ident);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001284 if (!c) {
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001285 spin_unlock_bh(&si->lock);
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +05301286 this_cpu_inc(si->stats_pcpu->connection_destroy_misses64);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001287
1288 DEBUG_TRACE("connection does not exist - p: %d, s: %pI4:%u, d: %pI4:%u\n",
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301289 tuple->protocol, &tuple->flow_ip, ntohs(tuple->flow_ident),
1290 &tuple->return_ip, ntohs(tuple->return_ident));
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001291 return;
1292 }
1293
1294 /*
1295 * Remove our connection details from the hash tables.
1296 */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05301297 ret = sfe_ipv4_remove_connection(si, c);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001298 spin_unlock_bh(&si->lock);
1299
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05301300 if (ret) {
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05301301 sfe_ipv4_flush_connection(si, c, SFE_SYNC_REASON_DESTROY);
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05301302 }
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001303
1304 DEBUG_INFO("connection destroyed - p: %d, s: %pI4:%u, d: %pI4:%u\n",
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301305 tuple->protocol, &tuple->flow_ip, ntohs(tuple->flow_ident),
1306 &tuple->return_ip, ntohs(tuple->return_ident));
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001307}
1308
1309/*
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001310 * sfe_ipv4_register_sync_rule_callback()
1311 * Register a callback for rule synchronization.
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001312 */
Xiaoping Fand44a5b42015-05-26 17:37:37 -07001313void sfe_ipv4_register_sync_rule_callback(sfe_sync_rule_callback_t sync_rule_callback)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001314{
1315 struct sfe_ipv4 *si = &__si;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001316
1317 spin_lock_bh(&si->lock);
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001318 rcu_assign_pointer(si->sync_rule_callback, sync_rule_callback);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001319 spin_unlock_bh(&si->lock);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001320}
1321
1322/*
1323 * sfe_ipv4_get_debug_dev()
1324 */
1325static ssize_t sfe_ipv4_get_debug_dev(struct device *dev,
1326 struct device_attribute *attr,
1327 char *buf)
1328{
1329 struct sfe_ipv4 *si = &__si;
1330 ssize_t count;
1331 int num;
1332
1333 spin_lock_bh(&si->lock);
1334 num = si->debug_dev;
1335 spin_unlock_bh(&si->lock);
1336
1337 count = snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", num);
1338 return count;
1339}
1340
1341/*
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001342 * sysfs attributes.
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001343 */
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001344static const struct device_attribute sfe_ipv4_debug_dev_attr =
Xiaoping Fane70da412016-02-26 16:47:57 -08001345 __ATTR(debug_dev, S_IWUSR | S_IRUGO, sfe_ipv4_get_debug_dev, NULL);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001346
1347/*
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001348 * sfe_ipv4_destroy_all_rules_for_dev()
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001349 * Destroy all connections that match a particular device.
1350 *
1351 * If we pass dev as NULL then this destroys all connections.
1352 */
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001353void sfe_ipv4_destroy_all_rules_for_dev(struct net_device *dev)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001354{
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001355 struct sfe_ipv4 *si = &__si;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001356 struct sfe_ipv4_connection *c;
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05301357 bool ret;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001358
Xiaoping Fan34586472015-07-03 02:20:35 -07001359another_round:
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001360 spin_lock_bh(&si->lock);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001361
Xiaoping Fan34586472015-07-03 02:20:35 -07001362 for (c = si->all_connections_head; c; c = c->all_connections_next) {
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001363 /*
Xiaoping Fan34586472015-07-03 02:20:35 -07001364 * Does this connection relate to the device we are destroying?
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001365 */
1366 if (!dev
1367 || (dev == c->original_dev)
1368 || (dev == c->reply_dev)) {
Xiaoping Fan34586472015-07-03 02:20:35 -07001369 break;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001370 }
Xiaoping Fan34586472015-07-03 02:20:35 -07001371 }
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001372
Xiaoping Fan34586472015-07-03 02:20:35 -07001373 if (c) {
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05301374 ret = sfe_ipv4_remove_connection(si, c);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001375 }
1376
1377 spin_unlock_bh(&si->lock);
Xiaoping Fan34586472015-07-03 02:20:35 -07001378
1379 if (c) {
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05301380 if (ret) {
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05301381 sfe_ipv4_flush_connection(si, c, SFE_SYNC_REASON_DESTROY);
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05301382 }
Xiaoping Fan34586472015-07-03 02:20:35 -07001383 goto another_round;
1384 }
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001385}
1386
1387/*
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001388 * sfe_ipv4_periodic_sync()
1389 */
Ken Zhu137722d2021-09-23 17:57:36 -07001390static void sfe_ipv4_periodic_sync(struct work_struct *work)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001391{
Ken Zhu137722d2021-09-23 17:57:36 -07001392 struct sfe_ipv4 *si = container_of((struct delayed_work *)work, struct sfe_ipv4, sync_dwork);
Xiaoping Fan6a1672f2016-08-17 19:58:12 -07001393 u64 now_jiffies;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001394 int quota;
Xiaoping Fand44a5b42015-05-26 17:37:37 -07001395 sfe_sync_rule_callback_t sync_rule_callback;
Ken Zhudc423672021-09-02 18:27:01 -07001396 struct sfe_ipv4_connection *c;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001397
1398 now_jiffies = get_jiffies_64();
1399
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001400 rcu_read_lock();
1401 sync_rule_callback = rcu_dereference(si->sync_rule_callback);
1402 if (!sync_rule_callback) {
1403 rcu_read_unlock();
1404 goto done;
1405 }
1406
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001407 spin_lock_bh(&si->lock);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001408
1409 /*
Ken Zhudc423672021-09-02 18:27:01 -07001410 * If we have reached the end of the connection list, walk from
1411 * the connection head.
1412 */
1413 c = si->wc_next;
1414 if (unlikely(!c)) {
1415 c = si->all_connections_head;
1416 }
1417
1418 /*
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001419 * Get an estimate of the number of connections to parse in this sync.
1420 */
1421 quota = (si->num_connections + 63) / 64;
1422
1423 /*
Ken Zhudc423672021-09-02 18:27:01 -07001424 * Walk the "all connection" list and sync the connection state.
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001425 */
Ken Zhudc423672021-09-02 18:27:01 -07001426 while (likely(c && quota)) {
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001427 struct sfe_ipv4_connection_match *cm;
1428 struct sfe_ipv4_connection_match *counter_cm;
Xiaoping Fand44a5b42015-05-26 17:37:37 -07001429 struct sfe_connection_sync sis;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001430
Ken Zhudc423672021-09-02 18:27:01 -07001431 cm = c->original_match;
1432 counter_cm = c->reply_match;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001433
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001434 /*
Ken Zhudc423672021-09-02 18:27:01 -07001435 * Didn't receive packets in the original direction or reply
1436 * direction, move to the next connection.
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001437 */
Ken Zhudc423672021-09-02 18:27:01 -07001438 if ((!atomic_read(&cm->rx_packet_count)) && !(atomic_read(&counter_cm->rx_packet_count))) {
1439 c = c->all_connections_next;
1440 continue;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001441 }
1442
Ken Zhudc423672021-09-02 18:27:01 -07001443 quota--;
Matthew McClintockaf48f1e2014-01-23 15:29:19 -06001444
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05301445 sfe_ipv4_gen_sync_connection(si, c, &sis, SFE_SYNC_REASON_STATS, now_jiffies);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001446
Ken Zhudc423672021-09-02 18:27:01 -07001447 si->wc_next = c->all_connections_next;
1448
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001449 /*
1450 * We don't want to be holding the lock when we sync!
1451 */
1452 spin_unlock_bh(&si->lock);
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001453 sync_rule_callback(&sis);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001454 spin_lock_bh(&si->lock);
Ken Zhudc423672021-09-02 18:27:01 -07001455
1456 /*
1457 * c must be set and used in the same lock/unlock window;
1458 * because c could be removed when we don't hold the lock,
1459 * so delay grabbing until after the callback and relock.
1460 */
1461 c = si->wc_next;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001462 }
1463
Ken Zhudc423672021-09-02 18:27:01 -07001464 /*
1465 * At the end of the sync, put the wc_next to the connection we left.
1466 */
1467 si->wc_next = c;
1468
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001469 spin_unlock_bh(&si->lock);
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001470 rcu_read_unlock();
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001471
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001472done:
Ken Zhu137722d2021-09-23 17:57:36 -07001473 schedule_delayed_work_on(si->work_cpu, (struct delayed_work *)work, ((HZ + 99) / 100));
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001474}
1475
1476#define CHAR_DEV_MSG_SIZE 768
1477
1478/*
1479 * sfe_ipv4_debug_dev_read_start()
1480 * Generate part of the XML output.
1481 */
1482static bool sfe_ipv4_debug_dev_read_start(struct sfe_ipv4 *si, char *buffer, char *msg, size_t *length,
1483 int *total_read, struct sfe_ipv4_debug_xml_write_state *ws)
1484{
1485 int bytes_read;
1486
Xiaoping Fan34586472015-07-03 02:20:35 -07001487 si->debug_read_seq++;
1488
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001489 bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "<sfe_ipv4>\n");
1490 if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) {
1491 return false;
1492 }
1493
1494 *length -= bytes_read;
1495 *total_read += bytes_read;
1496
1497 ws->state++;
1498 return true;
1499}
1500
1501/*
1502 * sfe_ipv4_debug_dev_read_connections_start()
1503 * Generate part of the XML output.
1504 */
1505static bool sfe_ipv4_debug_dev_read_connections_start(struct sfe_ipv4 *si, char *buffer, char *msg, size_t *length,
1506 int *total_read, struct sfe_ipv4_debug_xml_write_state *ws)
1507{
1508 int bytes_read;
1509
1510 bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t<connections>\n");
1511 if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) {
1512 return false;
1513 }
1514
1515 *length -= bytes_read;
1516 *total_read += bytes_read;
1517
1518 ws->state++;
1519 return true;
1520}
1521
1522/*
1523 * sfe_ipv4_debug_dev_read_connections_connection()
1524 * Generate part of the XML output.
1525 */
1526static bool sfe_ipv4_debug_dev_read_connections_connection(struct sfe_ipv4 *si, char *buffer, char *msg, size_t *length,
1527 int *total_read, struct sfe_ipv4_debug_xml_write_state *ws)
1528{
1529 struct sfe_ipv4_connection *c;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001530 struct sfe_ipv4_connection_match *original_cm;
1531 struct sfe_ipv4_connection_match *reply_cm;
1532 int bytes_read;
1533 int protocol;
1534 struct net_device *src_dev;
Dave Hudson87973cd2013-10-22 16:00:04 +01001535 __be32 src_ip;
1536 __be32 src_ip_xlate;
1537 __be16 src_port;
1538 __be16 src_port_xlate;
Xiaoping Fan6a1672f2016-08-17 19:58:12 -07001539 u64 src_rx_packets;
1540 u64 src_rx_bytes;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001541 struct net_device *dest_dev;
Dave Hudson87973cd2013-10-22 16:00:04 +01001542 __be32 dest_ip;
1543 __be32 dest_ip_xlate;
1544 __be16 dest_port;
1545 __be16 dest_port_xlate;
Xiaoping Fan6a1672f2016-08-17 19:58:12 -07001546 u64 dest_rx_packets;
1547 u64 dest_rx_bytes;
1548 u64 last_sync_jiffies;
1549 u32 mark, src_priority, dest_priority, src_dscp, dest_dscp;
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05301550 u32 packet, byte;
Xiaoping Fand1dc7b22015-01-23 00:43:56 -08001551#ifdef CONFIG_NF_FLOW_COOKIE
1552 int src_flow_cookie, dst_flow_cookie;
1553#endif
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001554
1555 spin_lock_bh(&si->lock);
Xiaoping Fan34586472015-07-03 02:20:35 -07001556
1557 for (c = si->all_connections_head; c; c = c->all_connections_next) {
1558 if (c->debug_read_seq < si->debug_read_seq) {
1559 c->debug_read_seq = si->debug_read_seq;
1560 break;
1561 }
1562 }
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001563
1564 /*
Xiaoping Fan34586472015-07-03 02:20:35 -07001565 * If there were no connections then move to the next state.
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001566 */
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05301567 if (!c || c->removed) {
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001568 spin_unlock_bh(&si->lock);
Xiaoping Fan34586472015-07-03 02:20:35 -07001569 ws->state++;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001570 return true;
1571 }
1572
1573 original_cm = c->original_match;
1574 reply_cm = c->reply_match;
1575
1576 protocol = c->protocol;
1577 src_dev = c->original_dev;
1578 src_ip = c->src_ip;
1579 src_ip_xlate = c->src_ip_xlate;
1580 src_port = c->src_port;
1581 src_port_xlate = c->src_port_xlate;
Xiaoping Fane1963d42015-08-25 17:06:19 -07001582 src_priority = original_cm->priority;
1583 src_dscp = original_cm->dscp >> SFE_IPV4_DSCP_SHIFT;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001584
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05301585 sfe_ipv4_connection_match_update_summary_stats(original_cm, &packet, &byte);
1586 sfe_ipv4_connection_match_update_summary_stats(reply_cm, &packet, &byte);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001587
1588 src_rx_packets = original_cm->rx_packet_count64;
1589 src_rx_bytes = original_cm->rx_byte_count64;
1590 dest_dev = c->reply_dev;
1591 dest_ip = c->dest_ip;
1592 dest_ip_xlate = c->dest_ip_xlate;
1593 dest_port = c->dest_port;
1594 dest_port_xlate = c->dest_port_xlate;
Xiaoping Fane1963d42015-08-25 17:06:19 -07001595 dest_priority = reply_cm->priority;
1596 dest_dscp = reply_cm->dscp >> SFE_IPV4_DSCP_SHIFT;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001597 dest_rx_packets = reply_cm->rx_packet_count64;
1598 dest_rx_bytes = reply_cm->rx_byte_count64;
1599 last_sync_jiffies = get_jiffies_64() - c->last_sync_jiffies;
Cristian Prundeanu592265e2013-12-26 11:01:22 -06001600 mark = c->mark;
Xiaoping Fand1dc7b22015-01-23 00:43:56 -08001601#ifdef CONFIG_NF_FLOW_COOKIE
1602 src_flow_cookie = original_cm->flow_cookie;
1603 dst_flow_cookie = reply_cm->flow_cookie;
1604#endif
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001605 spin_unlock_bh(&si->lock);
1606
1607 bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t\t<connection "
1608 "protocol=\"%u\" "
1609 "src_dev=\"%s\" "
1610 "src_ip=\"%pI4\" src_ip_xlate=\"%pI4\" "
1611 "src_port=\"%u\" src_port_xlate=\"%u\" "
Xiaoping Fane1963d42015-08-25 17:06:19 -07001612 "src_priority=\"%u\" src_dscp=\"%u\" "
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001613 "src_rx_pkts=\"%llu\" src_rx_bytes=\"%llu\" "
1614 "dest_dev=\"%s\" "
1615 "dest_ip=\"%pI4\" dest_ip_xlate=\"%pI4\" "
1616 "dest_port=\"%u\" dest_port_xlate=\"%u\" "
Xiaoping Fane1963d42015-08-25 17:06:19 -07001617 "dest_priority=\"%u\" dest_dscp=\"%u\" "
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001618 "dest_rx_pkts=\"%llu\" dest_rx_bytes=\"%llu\" "
Xiaoping Fand1dc7b22015-01-23 00:43:56 -08001619#ifdef CONFIG_NF_FLOW_COOKIE
1620 "src_flow_cookie=\"%d\" dst_flow_cookie=\"%d\" "
1621#endif
Cristian Prundeanu592265e2013-12-26 11:01:22 -06001622 "last_sync=\"%llu\" "
Nicolas Costabb85a2e2014-01-13 16:26:33 -06001623 "mark=\"%08x\" />\n",
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001624 protocol,
1625 src_dev->name,
1626 &src_ip, &src_ip_xlate,
Dave Hudson87973cd2013-10-22 16:00:04 +01001627 ntohs(src_port), ntohs(src_port_xlate),
Xiaoping Fane1963d42015-08-25 17:06:19 -07001628 src_priority, src_dscp,
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001629 src_rx_packets, src_rx_bytes,
1630 dest_dev->name,
1631 &dest_ip, &dest_ip_xlate,
Dave Hudson87973cd2013-10-22 16:00:04 +01001632 ntohs(dest_port), ntohs(dest_port_xlate),
Xiaoping Fane1963d42015-08-25 17:06:19 -07001633 dest_priority, dest_dscp,
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001634 dest_rx_packets, dest_rx_bytes,
Xiaoping Fand1dc7b22015-01-23 00:43:56 -08001635#ifdef CONFIG_NF_FLOW_COOKIE
1636 src_flow_cookie, dst_flow_cookie,
1637#endif
Cristian Prundeanu592265e2013-12-26 11:01:22 -06001638 last_sync_jiffies, mark);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001639
1640 if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) {
1641 return false;
1642 }
1643
1644 *length -= bytes_read;
1645 *total_read += bytes_read;
1646
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001647 return true;
1648}
1649
1650/*
1651 * sfe_ipv4_debug_dev_read_connections_end()
1652 * Generate part of the XML output.
1653 */
1654static bool sfe_ipv4_debug_dev_read_connections_end(struct sfe_ipv4 *si, char *buffer, char *msg, size_t *length,
1655 int *total_read, struct sfe_ipv4_debug_xml_write_state *ws)
1656{
1657 int bytes_read;
1658
1659 bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t</connections>\n");
1660 if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) {
1661 return false;
1662 }
1663
1664 *length -= bytes_read;
1665 *total_read += bytes_read;
1666
1667 ws->state++;
1668 return true;
1669}
1670
1671/*
1672 * sfe_ipv4_debug_dev_read_exceptions_start()
1673 * Generate part of the XML output.
1674 */
1675static bool sfe_ipv4_debug_dev_read_exceptions_start(struct sfe_ipv4 *si, char *buffer, char *msg, size_t *length,
1676 int *total_read, struct sfe_ipv4_debug_xml_write_state *ws)
1677{
1678 int bytes_read;
1679
1680 bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t<exceptions>\n");
1681 if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) {
1682 return false;
1683 }
1684
1685 *length -= bytes_read;
1686 *total_read += bytes_read;
1687
1688 ws->state++;
1689 return true;
1690}
1691
1692/*
1693 * sfe_ipv4_debug_dev_read_exceptions_exception()
1694 * Generate part of the XML output.
1695 */
1696static bool sfe_ipv4_debug_dev_read_exceptions_exception(struct sfe_ipv4 *si, char *buffer, char *msg, size_t *length,
1697 int *total_read, struct sfe_ipv4_debug_xml_write_state *ws)
1698{
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +05301699 int i;
1700 u64 val = 0;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001701
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +05301702 for_each_possible_cpu(i) {
1703 const struct sfe_ipv4_stats *s = per_cpu_ptr(si->stats_pcpu, i);
1704 val += s->exception_events64[ws->iter_exception];
1705 }
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001706
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +05301707 if (val) {
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001708 int bytes_read;
1709
1710 bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE,
1711 "\t\t<exception name=\"%s\" count=\"%llu\" />\n",
1712 sfe_ipv4_exception_events_string[ws->iter_exception],
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +05301713 val);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001714 if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) {
1715 return false;
1716 }
1717
1718 *length -= bytes_read;
1719 *total_read += bytes_read;
1720 }
1721
1722 ws->iter_exception++;
1723 if (ws->iter_exception >= SFE_IPV4_EXCEPTION_EVENT_LAST) {
1724 ws->iter_exception = 0;
1725 ws->state++;
1726 }
1727
1728 return true;
1729}
1730
1731/*
1732 * sfe_ipv4_debug_dev_read_exceptions_end()
1733 * Generate part of the XML output.
1734 */
1735static bool sfe_ipv4_debug_dev_read_exceptions_end(struct sfe_ipv4 *si, char *buffer, char *msg, size_t *length,
1736 int *total_read, struct sfe_ipv4_debug_xml_write_state *ws)
1737{
1738 int bytes_read;
1739
1740 bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t</exceptions>\n");
1741 if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) {
1742 return false;
1743 }
1744
1745 *length -= bytes_read;
1746 *total_read += bytes_read;
1747
1748 ws->state++;
1749 return true;
1750}
1751
1752/*
1753 * sfe_ipv4_debug_dev_read_stats()
1754 * Generate part of the XML output.
1755 */
1756static bool sfe_ipv4_debug_dev_read_stats(struct sfe_ipv4 *si, char *buffer, char *msg, size_t *length,
1757 int *total_read, struct sfe_ipv4_debug_xml_write_state *ws)
1758{
1759 int bytes_read;
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +05301760 struct sfe_ipv4_stats stats;
1761 unsigned int num_conn;
1762
1763 sfe_ipv4_update_summary_stats(si, &stats);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001764
1765 spin_lock_bh(&si->lock);
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +05301766 num_conn = si->num_connections;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001767 spin_unlock_bh(&si->lock);
1768
1769 bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t<stats "
1770 "num_connections=\"%u\" "
Xiaoping Fan59176422015-05-22 15:58:10 -07001771 "pkts_forwarded=\"%llu\" pkts_not_forwarded=\"%llu\" "
1772 "create_requests=\"%llu\" create_collisions=\"%llu\" "
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301773 "create_failures=\"%llu\" "
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001774 "destroy_requests=\"%llu\" destroy_misses=\"%llu\" "
1775 "flushes=\"%llu\" "
1776 "hash_hits=\"%llu\" hash_reorders=\"%llu\" />\n",
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +05301777 num_conn,
1778 stats.packets_forwarded64,
1779 stats.packets_not_forwarded64,
1780 stats.connection_create_requests64,
1781 stats.connection_create_collisions64,
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301782 stats.connection_create_failures64,
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +05301783 stats.connection_destroy_requests64,
1784 stats.connection_destroy_misses64,
1785 stats.connection_flushes64,
1786 stats.connection_match_hash_hits64,
1787 stats.connection_match_hash_reorders64);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001788 if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) {
1789 return false;
1790 }
1791
1792 *length -= bytes_read;
1793 *total_read += bytes_read;
1794
1795 ws->state++;
1796 return true;
1797}
1798
1799/*
1800 * sfe_ipv4_debug_dev_read_end()
1801 * Generate part of the XML output.
1802 */
1803static bool sfe_ipv4_debug_dev_read_end(struct sfe_ipv4 *si, char *buffer, char *msg, size_t *length,
1804 int *total_read, struct sfe_ipv4_debug_xml_write_state *ws)
1805{
1806 int bytes_read;
1807
1808 bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "</sfe_ipv4>\n");
1809 if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) {
1810 return false;
1811 }
1812
1813 *length -= bytes_read;
1814 *total_read += bytes_read;
1815
1816 ws->state++;
1817 return true;
1818}
1819
1820/*
1821 * Array of write functions that write various XML elements that correspond to
1822 * our XML output state machine.
1823 */
Xiaoping Fan6a1672f2016-08-17 19:58:12 -07001824static sfe_ipv4_debug_xml_write_method_t sfe_ipv4_debug_xml_write_methods[SFE_IPV4_DEBUG_XML_STATE_DONE] = {
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001825 sfe_ipv4_debug_dev_read_start,
1826 sfe_ipv4_debug_dev_read_connections_start,
1827 sfe_ipv4_debug_dev_read_connections_connection,
1828 sfe_ipv4_debug_dev_read_connections_end,
1829 sfe_ipv4_debug_dev_read_exceptions_start,
1830 sfe_ipv4_debug_dev_read_exceptions_exception,
1831 sfe_ipv4_debug_dev_read_exceptions_end,
1832 sfe_ipv4_debug_dev_read_stats,
1833 sfe_ipv4_debug_dev_read_end,
1834};
1835
1836/*
1837 * sfe_ipv4_debug_dev_read()
1838 * Send info to userspace upon read request from user
1839 */
1840static ssize_t sfe_ipv4_debug_dev_read(struct file *filp, char *buffer, size_t length, loff_t *offset)
1841{
1842 char msg[CHAR_DEV_MSG_SIZE];
1843 int total_read = 0;
1844 struct sfe_ipv4_debug_xml_write_state *ws;
1845 struct sfe_ipv4 *si = &__si;
1846
1847 ws = (struct sfe_ipv4_debug_xml_write_state *)filp->private_data;
1848 while ((ws->state != SFE_IPV4_DEBUG_XML_STATE_DONE) && (length > CHAR_DEV_MSG_SIZE)) {
1849 if ((sfe_ipv4_debug_xml_write_methods[ws->state])(si, buffer, msg, &length, &total_read, ws)) {
1850 continue;
1851 }
1852 }
1853
1854 return total_read;
1855}
1856
1857/*
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001858 * sfe_ipv4_debug_dev_open()
1859 */
1860static int sfe_ipv4_debug_dev_open(struct inode *inode, struct file *file)
1861{
1862 struct sfe_ipv4_debug_xml_write_state *ws;
1863
1864 ws = (struct sfe_ipv4_debug_xml_write_state *)file->private_data;
1865 if (!ws) {
1866 ws = kzalloc(sizeof(struct sfe_ipv4_debug_xml_write_state), GFP_KERNEL);
1867 if (!ws) {
1868 return -ENOMEM;
1869 }
1870
1871 ws->state = SFE_IPV4_DEBUG_XML_STATE_START;
1872 file->private_data = ws;
1873 }
1874
1875 return 0;
1876}
1877
1878/*
1879 * sfe_ipv4_debug_dev_release()
1880 */
1881static int sfe_ipv4_debug_dev_release(struct inode *inode, struct file *file)
1882{
1883 struct sfe_ipv4_debug_xml_write_state *ws;
1884
1885 ws = (struct sfe_ipv4_debug_xml_write_state *)file->private_data;
1886 if (ws) {
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001887 /*
1888 * We've finished with our output so free the write state.
1889 */
1890 kfree(ws);
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05301891 file->private_data = NULL;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001892 }
1893
1894 return 0;
1895}
1896
1897/*
1898 * File operations used in the debug char device
1899 */
1900static struct file_operations sfe_ipv4_debug_dev_fops = {
1901 .read = sfe_ipv4_debug_dev_read,
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001902 .open = sfe_ipv4_debug_dev_open,
1903 .release = sfe_ipv4_debug_dev_release
1904};
1905
Xiaoping Fand1dc7b22015-01-23 00:43:56 -08001906#ifdef CONFIG_NF_FLOW_COOKIE
1907/*
1908 * sfe_register_flow_cookie_cb
1909 * register a function in SFE to let SFE use this function to configure flow cookie for a flow
1910 *
1911 * Hardware driver which support flow cookie should register a callback function in SFE. Then SFE
1912 * can use this function to configure flow cookie for a flow.
1913 * return: 0, success; !=0, fail
1914 */
1915int sfe_register_flow_cookie_cb(flow_cookie_set_func_t cb)
1916{
1917 struct sfe_ipv4 *si = &__si;
1918
1919 BUG_ON(!cb);
1920
1921 if (si->flow_cookie_set_func) {
1922 return -1;
1923 }
1924
1925 rcu_assign_pointer(si->flow_cookie_set_func, cb);
1926 return 0;
1927}
1928
1929/*
1930 * sfe_unregister_flow_cookie_cb
1931 * unregister function which is used to configure flow cookie for a flow
1932 *
1933 * return: 0, success; !=0, fail
1934 */
1935int sfe_unregister_flow_cookie_cb(flow_cookie_set_func_t cb)
1936{
1937 struct sfe_ipv4 *si = &__si;
1938
1939 RCU_INIT_POINTER(si->flow_cookie_set_func, NULL);
1940 return 0;
1941}
Xiaoping Fan640faf42015-08-28 15:50:55 -07001942
1943/*
1944 * sfe_ipv4_get_flow_cookie()
1945 */
1946static ssize_t sfe_ipv4_get_flow_cookie(struct device *dev,
1947 struct device_attribute *attr,
1948 char *buf)
1949{
1950 struct sfe_ipv4 *si = &__si;
Xiaoping Fan01c67cc2015-11-09 11:31:57 -08001951 return snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", si->flow_cookie_enable);
Xiaoping Fan640faf42015-08-28 15:50:55 -07001952}
1953
1954/*
1955 * sfe_ipv4_set_flow_cookie()
1956 */
1957static ssize_t sfe_ipv4_set_flow_cookie(struct device *dev,
1958 struct device_attribute *attr,
1959 const char *buf, size_t size)
1960{
1961 struct sfe_ipv4 *si = &__si;
Ken Zhu137722d2021-09-23 17:57:36 -07001962 si->flow_cookie_enable = simple_strtol(buf, NULL, 0);
Xiaoping Fan640faf42015-08-28 15:50:55 -07001963
1964 return size;
1965}
1966
1967/*
1968 * sysfs attributes.
1969 */
1970static const struct device_attribute sfe_ipv4_flow_cookie_attr =
Xiaoping Fane70da412016-02-26 16:47:57 -08001971 __ATTR(flow_cookie_enable, S_IWUSR | S_IRUGO, sfe_ipv4_get_flow_cookie, sfe_ipv4_set_flow_cookie);
Xiaoping Fand1dc7b22015-01-23 00:43:56 -08001972#endif /*CONFIG_NF_FLOW_COOKIE*/
1973
Ken Zhu137722d2021-09-23 17:57:36 -07001974/*
1975 * sfe_ipv4_get_cpu()
1976 */
1977static ssize_t sfe_ipv4_get_cpu(struct device *dev,
1978 struct device_attribute *attr,
1979 char *buf)
1980{
1981 struct sfe_ipv4 *si = &__si;
1982 return snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", si->work_cpu);
1983}
1984
1985/*
1986 * sfe_ipv4_set_cpu()
1987 */
1988static ssize_t sfe_ipv4_set_cpu(struct device *dev,
1989 struct device_attribute *attr,
1990 const char *buf, size_t size)
1991{
1992 struct sfe_ipv4 *si = &__si;
1993 int work_cpu;
1994 work_cpu = simple_strtol(buf, NULL, 0);
1995 if ((work_cpu >= 0) && (work_cpu <= NR_CPUS)) {
1996 si->work_cpu = work_cpu;
1997 } else {
1998 dev_err(dev, "%s is not in valid range[0,%d]", buf, NR_CPUS);
1999 }
2000 return size;
2001}
2002/*
2003 * sysfs attributes.
2004 */
2005static const struct device_attribute sfe_ipv4_cpu_attr =
2006 __ATTR(stats_work_cpu, S_IWUSR | S_IRUGO, sfe_ipv4_get_cpu, sfe_ipv4_set_cpu);
2007
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05302008 /*
2009 * sfe_ipv4_conn_match_hash_init()
2010 * Initialize conn match hash lists
2011 */
2012static void sfe_ipv4_conn_match_hash_init(struct sfe_ipv4 *si, int len)
2013{
2014 struct hlist_head *hash_list = si->hlist_conn_match_hash_head;
2015 int i;
2016
2017 for (i = 0; i < len; i++) {
2018 INIT_HLIST_HEAD(&hash_list[i]);
2019 }
2020}
2021
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002022/*
Dave Hudson87973cd2013-10-22 16:00:04 +01002023 * sfe_ipv4_init()
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002024 */
Ratheesh Kannoth24fb1db2021-10-20 07:28:06 +05302025int sfe_ipv4_init(void)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002026{
2027 struct sfe_ipv4 *si = &__si;
2028 int result = -1;
2029
Dave Hudsondcd08fb2013-11-22 09:25:16 -06002030 DEBUG_INFO("SFE IPv4 init\n");
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002031
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05302032 sfe_ipv4_conn_match_hash_init(si, ARRAY_SIZE(si->hlist_conn_match_hash_head));
2033
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +05302034 si->stats_pcpu = alloc_percpu_gfp(struct sfe_ipv4_stats, GFP_KERNEL | __GFP_ZERO);
2035 if (!si->stats_pcpu) {
2036 DEBUG_ERROR("failed to allocate stats memory for sfe_ipv4\n");
2037 goto exit0;
2038 }
2039
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002040 /*
2041 * Create sys/sfe_ipv4
2042 */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05302043 si->sys_ipv4 = kobject_create_and_add("sfe_ipv4", NULL);
2044 if (!si->sys_ipv4) {
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002045 DEBUG_ERROR("failed to register sfe_ipv4\n");
2046 goto exit1;
2047 }
2048
2049 /*
2050 * Create files, one for each parameter supported by this module.
2051 */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05302052 result = sysfs_create_file(si->sys_ipv4, &sfe_ipv4_debug_dev_attr.attr);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002053 if (result) {
2054 DEBUG_ERROR("failed to register debug dev file: %d\n", result);
Xiaoping Fan640faf42015-08-28 15:50:55 -07002055 goto exit2;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002056 }
2057
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05302058 result = sysfs_create_file(si->sys_ipv4, &sfe_ipv4_cpu_attr.attr);
Ken Zhu137722d2021-09-23 17:57:36 -07002059 if (result) {
2060 DEBUG_ERROR("failed to register debug dev file: %d\n", result);
2061 goto exit3;
2062 }
2063
Xiaoping Fan640faf42015-08-28 15:50:55 -07002064#ifdef CONFIG_NF_FLOW_COOKIE
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05302065 result = sysfs_create_file(si->sys_ipv4, &sfe_ipv4_flow_cookie_attr.attr);
Xiaoping Fan640faf42015-08-28 15:50:55 -07002066 if (result) {
2067 DEBUG_ERROR("failed to register flow cookie enable file: %d\n", result);
Ken Zhu137722d2021-09-23 17:57:36 -07002068 goto exit4;
Xiaoping Fan640faf42015-08-28 15:50:55 -07002069 }
2070#endif /* CONFIG_NF_FLOW_COOKIE */
2071
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002072 /*
2073 * Register our debug char device.
2074 */
2075 result = register_chrdev(0, "sfe_ipv4", &sfe_ipv4_debug_dev_fops);
2076 if (result < 0) {
2077 DEBUG_ERROR("Failed to register chrdev: %d\n", result);
Ken Zhu137722d2021-09-23 17:57:36 -07002078 goto exit5;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002079 }
2080
2081 si->debug_dev = result;
Ken Zhu137722d2021-09-23 17:57:36 -07002082 si->work_cpu = WORK_CPU_UNBOUND;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002083
2084 /*
Ken Zhu137722d2021-09-23 17:57:36 -07002085 * Create a work to handle periodic statistics.
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002086 */
Ken Zhu137722d2021-09-23 17:57:36 -07002087 INIT_DELAYED_WORK(&(si->sync_dwork), sfe_ipv4_periodic_sync);
2088 schedule_delayed_work_on(si->work_cpu, &(si->sync_dwork), ((HZ + 99) / 100));
2089
Dave Hudson87973cd2013-10-22 16:00:04 +01002090 spin_lock_init(&si->lock);
Dave Hudson87973cd2013-10-22 16:00:04 +01002091 return 0;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002092
Ken Zhu137722d2021-09-23 17:57:36 -07002093exit5:
Xiaoping Fan640faf42015-08-28 15:50:55 -07002094#ifdef CONFIG_NF_FLOW_COOKIE
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05302095 sysfs_remove_file(si->sys_ipv4, &sfe_ipv4_flow_cookie_attr.attr);
Xiaoping Fan640faf42015-08-28 15:50:55 -07002096
Ken Zhu137722d2021-09-23 17:57:36 -07002097exit4:
Xiaoping Fan640faf42015-08-28 15:50:55 -07002098#endif /* CONFIG_NF_FLOW_COOKIE */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05302099 sysfs_remove_file(si->sys_ipv4, &sfe_ipv4_cpu_attr.attr);
Ken Zhu137722d2021-09-23 17:57:36 -07002100exit3:
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05302101 sysfs_remove_file(si->sys_ipv4, &sfe_ipv4_debug_dev_attr.attr);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002102
Xiaoping Fan640faf42015-08-28 15:50:55 -07002103exit2:
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05302104 kobject_put(si->sys_ipv4);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002105
2106exit1:
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +05302107 free_percpu(si->stats_pcpu);
2108
2109exit0:
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002110 return result;
2111}
2112
2113/*
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002114 * sfe_ipv4_exit()
2115 */
Ratheesh Kannoth24fb1db2021-10-20 07:28:06 +05302116void sfe_ipv4_exit(void)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002117{
Dave Hudson87973cd2013-10-22 16:00:04 +01002118 struct sfe_ipv4 *si = &__si;
2119
Dave Hudsondcd08fb2013-11-22 09:25:16 -06002120 DEBUG_INFO("SFE IPv4 exit\n");
Dave Hudson87973cd2013-10-22 16:00:04 +01002121 /*
2122 * Destroy all connections.
2123 */
Dave Hudsondcd08fb2013-11-22 09:25:16 -06002124 sfe_ipv4_destroy_all_rules_for_dev(NULL);
Dave Hudson87973cd2013-10-22 16:00:04 +01002125
Ken Zhu137722d2021-09-23 17:57:36 -07002126 cancel_delayed_work_sync(&si->sync_dwork);
Dave Hudson87973cd2013-10-22 16:00:04 +01002127
Dave Hudson87973cd2013-10-22 16:00:04 +01002128 unregister_chrdev(si->debug_dev, "sfe_ipv4");
2129
Xiaoping Fan640faf42015-08-28 15:50:55 -07002130#ifdef CONFIG_NF_FLOW_COOKIE
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05302131 sysfs_remove_file(si->sys_ipv4, &sfe_ipv4_flow_cookie_attr.attr);
Xiaoping Fan640faf42015-08-28 15:50:55 -07002132#endif /* CONFIG_NF_FLOW_COOKIE */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05302133 sysfs_remove_file(si->sys_ipv4, &sfe_ipv4_debug_dev_attr.attr);
2134 sysfs_remove_file(si->sys_ipv4, &sfe_ipv4_cpu_attr.attr);
Dave Hudson87973cd2013-10-22 16:00:04 +01002135
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05302136 kobject_put(si->sys_ipv4);
Dave Hudson87973cd2013-10-22 16:00:04 +01002137
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +05302138 free_percpu(si->stats_pcpu);
2139
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002140}
2141
Xiaoping Fand1dc7b22015-01-23 00:43:56 -08002142#ifdef CONFIG_NF_FLOW_COOKIE
2143EXPORT_SYMBOL(sfe_register_flow_cookie_cb);
2144EXPORT_SYMBOL(sfe_unregister_flow_cookie_cb);
2145#endif