blob: 21683bc5bd450bc4f675c24e0cbb7f31ac225414 [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.
Guduri Prathyusha5f27e232022-01-06 14:39:04 +05306 * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
Ratheesh Kannoth24fb1db2021-10-20 07:28:06 +05307 *
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>
Amitesh Anand63be37d2021-12-24 20:51:48 +053026#include <net/udp.h>
27#include <net/vxlan.h>
Dave Hudsondcd08fb2013-11-22 09:25:16 -060028#include <linux/etherdevice.h>
Tian Yang45f39c82020-10-06 14:07:47 -070029#include <linux/version.h>
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +053030#include <linux/lockdep.h>
Amitesh Anand63be37d2021-12-24 20:51:48 +053031#include <linux/refcount.h>
32#include <linux/netfilter.h>
33#include <linux/inetdevice.h>
34#include <linux/netfilter_ipv4.h>
Parikshit Guned31a8202022-01-05 22:15:04 +053035#include <linux/seqlock.h>
Nitin Shettye6ed5b52021-12-27 14:50:11 +053036#include <net/protocol.h>
37#include <net/gre.h>
Dave Hudsonaaf97ca2013-06-13 17:52:29 +010038
Ratheesh Kannoth24fb1db2021-10-20 07:28:06 +053039#include "sfe_debug.h"
Ratheesh Kannoth89302a72021-10-20 08:10:37 +053040#include "sfe_api.h"
Dave Hudsondcd08fb2013-11-22 09:25:16 -060041#include "sfe.h"
Ratheesh Kannoth24fb1db2021-10-20 07:28:06 +053042#include "sfe_flow_cookie.h"
43#include "sfe_ipv4.h"
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +053044#include "sfe_ipv4_udp.h"
45#include "sfe_ipv4_tcp.h"
46#include "sfe_ipv4_icmp.h"
Wayne Tanbb7f1782021-12-13 11:16:04 -080047#include "sfe_pppoe.h"
Wayne Tan1cabbf12022-05-01 13:01:45 -070048#include "sfe_pppoe_mgr.h"
49#include "sfe_ipv4_pppoe_br.h"
Nitin Shettye6ed5b52021-12-27 14:50:11 +053050#include "sfe_ipv4_gre.h"
Tian Yangd98d91b2022-03-09 14:50:12 -080051#include "sfe_ipv4_tun6rd.h"
Dave Hudsonaaf97ca2013-06-13 17:52:29 +010052
53static char *sfe_ipv4_exception_events_string[SFE_IPV4_EXCEPTION_EVENT_LAST] = {
54 "UDP_HEADER_INCOMPLETE",
55 "UDP_NO_CONNECTION",
56 "UDP_IP_OPTIONS_OR_INITIAL_FRAGMENT",
57 "UDP_SMALL_TTL",
58 "UDP_NEEDS_FRAGMENTATION",
59 "TCP_HEADER_INCOMPLETE",
60 "TCP_NO_CONNECTION_SLOW_FLAGS",
61 "TCP_NO_CONNECTION_FAST_FLAGS",
62 "TCP_IP_OPTIONS_OR_INITIAL_FRAGMENT",
63 "TCP_SMALL_TTL",
64 "TCP_NEEDS_FRAGMENTATION",
65 "TCP_FLAGS",
66 "TCP_SEQ_EXCEEDS_RIGHT_EDGE",
67 "TCP_SMALL_DATA_OFFS",
68 "TCP_BAD_SACK",
69 "TCP_BIG_DATA_OFFS",
70 "TCP_SEQ_BEFORE_LEFT_EDGE",
71 "TCP_ACK_EXCEEDS_RIGHT_EDGE",
72 "TCP_ACK_BEFORE_LEFT_EDGE",
73 "ICMP_HEADER_INCOMPLETE",
74 "ICMP_UNHANDLED_TYPE",
75 "ICMP_IPV4_HEADER_INCOMPLETE",
76 "ICMP_IPV4_NON_V4",
77 "ICMP_IPV4_IP_OPTIONS_INCOMPLETE",
78 "ICMP_IPV4_UDP_HEADER_INCOMPLETE",
79 "ICMP_IPV4_TCP_HEADER_INCOMPLETE",
80 "ICMP_IPV4_UNHANDLED_PROTOCOL",
81 "ICMP_NO_CONNECTION",
82 "ICMP_FLUSHED_CONNECTION",
83 "HEADER_INCOMPLETE",
Ratheesh Kannoth43d64f82021-10-20 08:23:29 +053084 "HEADER_CSUM_BAD",
Dave Hudsonaaf97ca2013-06-13 17:52:29 +010085 "BAD_TOTAL_LENGTH",
86 "NON_V4",
87 "NON_INITIAL_FRAGMENT",
88 "DATAGRAM_INCOMPLETE",
89 "IP_OPTIONS_INCOMPLETE",
Ratheesh Kannoth5dee3772022-01-18 11:27:14 +053090 "UNHANDLED_PROTOCOL",
Nitin Shetty16ab38d2022-02-09 01:26:19 +053091 "NO_HEADROOM",
92 "INVALID_PPPOE_SESSION",
93 "INCORRECT_PPPOE_PARSING",
94 "PPPOE_NOT_SET_IN_CME",
Wayne Tan1cabbf12022-05-01 13:01:45 -070095 "PPPOE_BR_NOT_IN_CME",
Nitin Shetty16ab38d2022-02-09 01:26:19 +053096 "INGRESS_VLAN_TAG_MISMATCH",
Ratheesh Kannoth5dee3772022-01-18 11:27:14 +053097 "INVALID_SOURCE_INTERFACE",
Tian Yangd98d91b2022-03-09 14:50:12 -080098 "TUN6RD_NO_CONNECTION",
99 "TUN6RD_NEEDS_FRAGMENTATION",
100 "TUN6RD_SYNC_ON_FIND",
Nitin Shettye6ed5b52021-12-27 14:50:11 +0530101 "GRE_HEADER_INCOMPLETE",
102 "GRE_NO_CONNECTION",
103 "GRE_IP_OPTIONS_OR_INITIAL_FRAGMENT",
104 "GRE_SMALL_TTL",
105 "GRE_NEEDS_FRAGMENTATION"
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100106};
107
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700108static struct sfe_ipv4 __si;
Ken Zhu7a43d882022-01-04 10:51:44 -0800109struct sfe_ipv4_msg *sfe_ipv4_sync_many_msg;
110uint32_t sfe_ipv4_sync_max_number;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100111
112/*
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100113 * sfe_ipv4_gen_ip_csum()
114 * Generate the IP checksum for an IPv4 header.
115 *
116 * Note that this function assumes that we have only 20 bytes of IP header.
117 */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530118u16 sfe_ipv4_gen_ip_csum(struct iphdr *iph)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100119{
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700120 u32 sum;
121 u16 *i = (u16 *)iph;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100122
123 iph->check = 0;
124
125 /*
126 * Generate the sum.
127 */
128 sum = i[0] + i[1] + i[2] + i[3] + i[4] + i[5] + i[6] + i[7] + i[8] + i[9];
129
130 /*
131 * Fold it to ones-complement form.
132 */
133 sum = (sum & 0xffff) + (sum >> 16);
134 sum = (sum & 0xffff) + (sum >> 16);
135
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700136 return (u16)sum ^ 0xffff;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100137}
138
139/*
140 * sfe_ipv4_get_connection_match_hash()
141 * Generate the hash used in connection match lookups.
142 */
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700143static inline unsigned int sfe_ipv4_get_connection_match_hash(struct net_device *dev, u8 protocol,
Dave Hudson87973cd2013-10-22 16:00:04 +0100144 __be32 src_ip, __be16 src_port,
145 __be32 dest_ip, __be16 dest_port)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100146{
Ratheesh Kannoth5dee3772022-01-18 11:27:14 +0530147 u32 hash = ntohl(src_ip ^ dest_ip) ^ protocol ^ ntohs(src_port ^ dest_port);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100148 return ((hash >> SFE_IPV4_CONNECTION_HASH_SHIFT) ^ hash) & SFE_IPV4_CONNECTION_HASH_MASK;
149}
150
151/*
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530152 * sfe_ipv4_find_connection_match_rcu()
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100153 * Get the IPv4 flow match info that corresponds to a particular 5-tuple.
154 *
155 * On entry we must be holding the lock that protects the hash table.
156 */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530157struct sfe_ipv4_connection_match *
158sfe_ipv4_find_connection_match_rcu(struct sfe_ipv4 *si, struct net_device *dev, u8 protocol,
Dave Hudson87973cd2013-10-22 16:00:04 +0100159 __be32 src_ip, __be16 src_port,
160 __be32 dest_ip, __be16 dest_port)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100161{
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530162 struct sfe_ipv4_connection_match *cm = NULL;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100163 unsigned int conn_match_idx;
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530164 struct hlist_head *lhead;
165
166 WARN_ON_ONCE(!rcu_read_lock_held());
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100167
168 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 +0100169
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530170 lhead = &si->hlist_conn_match_hash_head[conn_match_idx];
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100171
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530172 hlist_for_each_entry_rcu(cm, lhead, hnode) {
173 if (cm->match_src_port != src_port
174 || cm->match_dest_port != dest_port
175 || cm->match_src_ip != src_ip
176 || cm->match_dest_ip != dest_ip
Ratheesh Kannoth5dee3772022-01-18 11:27:14 +0530177 || cm->match_protocol != protocol) {
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530178 continue;
179 }
180
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +0530181 this_cpu_inc(si->stats_pcpu->connection_match_hash_hits64);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100182
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530183 break;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100184 }
185
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100186 return cm;
187}
188
189/*
190 * sfe_ipv4_connection_match_update_summary_stats()
191 * Update the summary stats for a connection match entry.
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530192 *
193 * Stats are incremented atomically. So use atomic substraction to update summary
194 * stats.
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100195 */
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530196static inline void sfe_ipv4_connection_match_update_summary_stats(struct sfe_ipv4_connection_match *cm,
197 u32 *packets, u32 *bytes)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100198{
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530199 u32 packet_count, byte_count;
200
201 packet_count = atomic_read(&cm->rx_packet_count);
202 cm->rx_packet_count64 += packet_count;
203 atomic_sub(packet_count, &cm->rx_packet_count);
204
205 byte_count = atomic_read(&cm->rx_byte_count);
206 cm->rx_byte_count64 += byte_count;
207 atomic_sub(byte_count, &cm->rx_byte_count);
208
209 *packets = packet_count;
210 *bytes = byte_count;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100211}
212
213/*
214 * sfe_ipv4_connection_match_compute_translations()
215 * Compute port and address translations for a connection match entry.
216 */
217static void sfe_ipv4_connection_match_compute_translations(struct sfe_ipv4_connection_match *cm)
218{
219 /*
220 * Before we insert the entry look to see if this is tagged as doing address
221 * translations. If it is then work out the adjustment that we need to apply
222 * to the transport checksum.
223 */
224 if (cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_SRC) {
225 /*
226 * Precompute an incremental checksum adjustment so we can
227 * edit packets in this stream very quickly. The algorithm is from RFC1624.
228 */
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700229 u16 src_ip_hi = cm->match_src_ip >> 16;
230 u16 src_ip_lo = cm->match_src_ip & 0xffff;
231 u32 xlate_src_ip = ~cm->xlate_src_ip;
232 u16 xlate_src_ip_hi = xlate_src_ip >> 16;
233 u16 xlate_src_ip_lo = xlate_src_ip & 0xffff;
234 u16 xlate_src_port = ~cm->xlate_src_port;
235 u32 adj;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100236
237 /*
238 * When we compute this fold it down to a 16-bit offset
239 * as that way we can avoid having to do a double
240 * folding of the twos-complement result because the
241 * addition of 2 16-bit values cannot cause a double
242 * wrap-around!
243 */
244 adj = src_ip_hi + src_ip_lo + cm->match_src_port
245 + xlate_src_ip_hi + xlate_src_ip_lo + xlate_src_port;
246 adj = (adj & 0xffff) + (adj >> 16);
247 adj = (adj & 0xffff) + (adj >> 16);
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700248 cm->xlate_src_csum_adjustment = (u16)adj;
Nicolas Costaac2979c2014-01-14 10:35:24 -0600249
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100250 }
251
252 if (cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_DEST) {
253 /*
254 * Precompute an incremental checksum adjustment so we can
255 * edit packets in this stream very quickly. The algorithm is from RFC1624.
256 */
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700257 u16 dest_ip_hi = cm->match_dest_ip >> 16;
258 u16 dest_ip_lo = cm->match_dest_ip & 0xffff;
259 u32 xlate_dest_ip = ~cm->xlate_dest_ip;
260 u16 xlate_dest_ip_hi = xlate_dest_ip >> 16;
261 u16 xlate_dest_ip_lo = xlate_dest_ip & 0xffff;
262 u16 xlate_dest_port = ~cm->xlate_dest_port;
263 u32 adj;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100264
265 /*
266 * When we compute this fold it down to a 16-bit offset
267 * as that way we can avoid having to do a double
268 * folding of the twos-complement result because the
269 * addition of 2 16-bit values cannot cause a double
270 * wrap-around!
271 */
272 adj = dest_ip_hi + dest_ip_lo + cm->match_dest_port
273 + xlate_dest_ip_hi + xlate_dest_ip_lo + xlate_dest_port;
274 adj = (adj & 0xffff) + (adj >> 16);
275 adj = (adj & 0xffff) + (adj >> 16);
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700276 cm->xlate_dest_csum_adjustment = (u16)adj;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100277 }
Xiaoping Fanad755af2015-04-01 16:58:46 -0700278
279 if (cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_SRC) {
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700280 u32 adj = ~cm->match_src_ip + cm->xlate_src_ip;
Xiaoping Fanad755af2015-04-01 16:58:46 -0700281 if (adj < cm->xlate_src_ip) {
282 adj++;
283 }
284
285 adj = (adj & 0xffff) + (adj >> 16);
286 adj = (adj & 0xffff) + (adj >> 16);
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700287 cm->xlate_src_partial_csum_adjustment = (u16)adj;
Xiaoping Fanad755af2015-04-01 16:58:46 -0700288 }
289
290 if (cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_DEST) {
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700291 u32 adj = ~cm->match_dest_ip + cm->xlate_dest_ip;
Xiaoping Fanad755af2015-04-01 16:58:46 -0700292 if (adj < cm->xlate_dest_ip) {
293 adj++;
294 }
295
296 adj = (adj & 0xffff) + (adj >> 16);
297 adj = (adj & 0xffff) + (adj >> 16);
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700298 cm->xlate_dest_partial_csum_adjustment = (u16)adj;
Xiaoping Fanad755af2015-04-01 16:58:46 -0700299 }
300
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100301}
302
303/*
304 * sfe_ipv4_update_summary_stats()
305 * Update the summary stats.
306 */
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +0530307static void sfe_ipv4_update_summary_stats(struct sfe_ipv4 *si, struct sfe_ipv4_stats *stats)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100308{
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +0530309 int i = 0;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100310
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +0530311 memset(stats, 0, sizeof(*stats));
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100312
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +0530313 for_each_possible_cpu(i) {
314 const struct sfe_ipv4_stats *s = per_cpu_ptr(si->stats_pcpu, i);
315
316 stats->connection_create_requests64 += s->connection_create_requests64;
317 stats->connection_create_collisions64 += s->connection_create_collisions64;
Ratheesh Kannoth89302a72021-10-20 08:10:37 +0530318 stats->connection_create_failures64 += s->connection_create_failures64;
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +0530319 stats->connection_destroy_requests64 += s->connection_destroy_requests64;
320 stats->connection_destroy_misses64 += s->connection_destroy_misses64;
321 stats->connection_match_hash_hits64 += s->connection_match_hash_hits64;
322 stats->connection_match_hash_reorders64 += s->connection_match_hash_reorders64;
323 stats->connection_flushes64 += s->connection_flushes64;
Amitesh Anand63be37d2021-12-24 20:51:48 +0530324 stats->packets_dropped64 += s->packets_dropped64;
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +0530325 stats->packets_forwarded64 += s->packets_forwarded64;
Ken Zhu7e38d1a2021-11-30 17:31:46 -0800326 stats->packets_fast_xmited64 += s->packets_fast_xmited64;
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +0530327 stats->packets_not_forwarded64 += s->packets_not_forwarded64;
Guduri Prathyusha647fe3e2021-11-22 19:17:51 +0530328 stats->pppoe_encap_packets_forwarded64 += s->pppoe_encap_packets_forwarded64;
329 stats->pppoe_decap_packets_forwarded64 += s->pppoe_decap_packets_forwarded64;
Guduri Prathyusha034d6352022-01-12 16:49:04 +0530330 stats->pppoe_bridge_packets_forwarded64 += s->pppoe_bridge_packets_forwarded64;
Wayne Tan1cabbf12022-05-01 13:01:45 -0700331 stats->pppoe_bridge_packets_3tuple_forwarded64 += s->pppoe_bridge_packets_3tuple_forwarded64;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100332 }
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +0530333
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100334}
335
336/*
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530337 * sfe_ipv4_insert_connection_match()
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100338 * Insert a connection match into the hash.
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100339 */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530340static inline void sfe_ipv4_insert_connection_match(struct sfe_ipv4 *si,
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700341 struct sfe_ipv4_connection_match *cm)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100342{
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100343 unsigned int conn_match_idx
344 = sfe_ipv4_get_connection_match_hash(cm->match_dev, cm->match_protocol,
345 cm->match_src_ip, cm->match_src_port,
346 cm->match_dest_ip, cm->match_dest_port);
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700347
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530348 lockdep_assert_held(&si->lock);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100349
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530350 hlist_add_head_rcu(&cm->hnode, &si->hlist_conn_match_hash_head[conn_match_idx]);
Xiaoping Fand1dc7b22015-01-23 00:43:56 -0800351#ifdef CONFIG_NF_FLOW_COOKIE
Xiaoping Fan640faf42015-08-28 15:50:55 -0700352 if (!si->flow_cookie_enable)
353 return;
354
Xiaoping Fand1dc7b22015-01-23 00:43:56 -0800355 /*
356 * Configure hardware to put a flow cookie in packet of this flow,
357 * then we can accelerate the lookup process when we received this packet.
358 */
359 for (conn_match_idx = 1; conn_match_idx < SFE_FLOW_COOKIE_SIZE; conn_match_idx++) {
360 struct sfe_flow_cookie_entry *entry = &si->sfe_flow_cookie_table[conn_match_idx];
361
362 if ((NULL == entry->match) && time_is_before_jiffies(entry->last_clean_time + HZ)) {
363 flow_cookie_set_func_t func;
364
365 rcu_read_lock();
366 func = rcu_dereference(si->flow_cookie_set_func);
367 if (func) {
Xiaoping Fan59176422015-05-22 15:58:10 -0700368 if (!func(cm->match_protocol, cm->match_src_ip, cm->match_src_port,
Xiaoping Fand1dc7b22015-01-23 00:43:56 -0800369 cm->match_dest_ip, cm->match_dest_port, conn_match_idx)) {
370 entry->match = cm;
371 cm->flow_cookie = conn_match_idx;
372 }
373 }
374 rcu_read_unlock();
375
376 break;
377 }
378 }
379#endif
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100380}
381
382/*
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530383 * sfe_ipv4_remove_connection_match()
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100384 * Remove a connection match object from the hash.
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100385 */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530386static inline void sfe_ipv4_remove_connection_match(struct sfe_ipv4 *si, struct sfe_ipv4_connection_match *cm)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100387{
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530388
389 lockdep_assert_held(&si->lock);
390
Xiaoping Fand1dc7b22015-01-23 00:43:56 -0800391#ifdef CONFIG_NF_FLOW_COOKIE
Xiaoping Fan640faf42015-08-28 15:50:55 -0700392 if (si->flow_cookie_enable) {
393 /*
394 * Tell hardware that we no longer need a flow cookie in packet of this flow
395 */
396 unsigned int conn_match_idx;
Xiaoping Fand1dc7b22015-01-23 00:43:56 -0800397
Xiaoping Fan640faf42015-08-28 15:50:55 -0700398 for (conn_match_idx = 1; conn_match_idx < SFE_FLOW_COOKIE_SIZE; conn_match_idx++) {
399 struct sfe_flow_cookie_entry *entry = &si->sfe_flow_cookie_table[conn_match_idx];
Xiaoping Fand1dc7b22015-01-23 00:43:56 -0800400
Xiaoping Fan640faf42015-08-28 15:50:55 -0700401 if (cm == entry->match) {
402 flow_cookie_set_func_t func;
Xiaoping Fand1dc7b22015-01-23 00:43:56 -0800403
Xiaoping Fan640faf42015-08-28 15:50:55 -0700404 rcu_read_lock();
405 func = rcu_dereference(si->flow_cookie_set_func);
406 if (func) {
407 func(cm->match_protocol, cm->match_src_ip, cm->match_src_port,
408 cm->match_dest_ip, cm->match_dest_port, 0);
409 }
410 rcu_read_unlock();
411
412 cm->flow_cookie = 0;
413 entry->match = NULL;
414 entry->last_clean_time = jiffies;
415 break;
Xiaoping Fand1dc7b22015-01-23 00:43:56 -0800416 }
Xiaoping Fand1dc7b22015-01-23 00:43:56 -0800417 }
418 }
419#endif
420
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530421 hlist_del_init_rcu(&cm->hnode);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100422
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100423}
424
425/*
426 * sfe_ipv4_get_connection_hash()
427 * Generate the hash used in connection lookups.
428 */
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700429static inline unsigned int sfe_ipv4_get_connection_hash(u8 protocol, __be32 src_ip, __be16 src_port,
Dave Hudson87973cd2013-10-22 16:00:04 +0100430 __be32 dest_ip, __be16 dest_port)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100431{
Wayne Tan1cabbf12022-05-01 13:01:45 -0700432 u32 hash = ntohl(src_ip ^ dest_ip) ^ protocol ^ ntohs(src_port) ^ dest_port;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100433 return ((hash >> SFE_IPV4_CONNECTION_HASH_SHIFT) ^ hash) & SFE_IPV4_CONNECTION_HASH_MASK;
434}
435
436/*
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530437 * sfe_ipv4_find_connection()
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100438 * Get the IPv4 connection info that corresponds to a particular 5-tuple.
439 *
440 * On entry we must be holding the lock that protects the hash table.
441 */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530442static inline struct sfe_ipv4_connection *sfe_ipv4_find_connection(struct sfe_ipv4 *si, u32 protocol,
Dave Hudson87973cd2013-10-22 16:00:04 +0100443 __be32 src_ip, __be16 src_port,
444 __be32 dest_ip, __be16 dest_port)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100445{
446 struct sfe_ipv4_connection *c;
447 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 +0530448
449 lockdep_assert_held(&si->lock);
450
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100451 c = si->conn_hash[conn_idx];
452
453 /*
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100454 * Will need connection entry for next create/destroy metadata,
455 * So no need to re-order entry for these requests
456 */
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530457 while (c) {
458 if ((c->src_port == src_port)
459 && (c->dest_port == dest_port)
460 && (c->src_ip == src_ip)
461 && (c->dest_ip == dest_ip)
462 && (c->protocol == protocol)) {
463 return c;
464 }
465
466 c = c->next;
467 }
468
469 return NULL;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100470}
471
472/*
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530473 * sfe_ipv4_insert_connection()
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100474 * Insert a connection into the hash.
475 *
476 * On entry we must be holding the lock that protects the hash table.
477 */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530478static void sfe_ipv4_insert_connection(struct sfe_ipv4 *si, struct sfe_ipv4_connection *c)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100479{
480 struct sfe_ipv4_connection **hash_head;
481 struct sfe_ipv4_connection *prev_head;
482 unsigned int conn_idx;
483
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530484 lockdep_assert_held(&si->lock);
485
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100486 /*
487 * Insert entry into the connection hash.
488 */
489 conn_idx = sfe_ipv4_get_connection_hash(c->protocol, c->src_ip, c->src_port,
490 c->dest_ip, c->dest_port);
491 hash_head = &si->conn_hash[conn_idx];
492 prev_head = *hash_head;
493 c->prev = NULL;
494 if (prev_head) {
495 prev_head->prev = c;
496 }
497
498 c->next = prev_head;
499 *hash_head = c;
500
501 /*
502 * Insert entry into the "all connections" list.
503 */
504 if (si->all_connections_tail) {
505 c->all_connections_prev = si->all_connections_tail;
506 si->all_connections_tail->all_connections_next = c;
507 } else {
508 c->all_connections_prev = NULL;
509 si->all_connections_head = c;
510 }
511
512 si->all_connections_tail = c;
513 c->all_connections_next = NULL;
514 si->num_connections++;
515
516 /*
517 * Insert the connection match objects too.
518 */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530519 sfe_ipv4_insert_connection_match(si, c->original_match);
520 sfe_ipv4_insert_connection_match(si, c->reply_match);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100521}
522
523/*
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530524 * sfe_ipv4_remove_connection()
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100525 * Remove a sfe_ipv4_connection object from the hash.
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100526 */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530527bool sfe_ipv4_remove_connection(struct sfe_ipv4 *si, struct sfe_ipv4_connection *c)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100528{
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530529 lockdep_assert_held(&si->lock);
530
531 if (c->removed) {
532 DEBUG_ERROR("%px: Connection has been removed already\n", c);
533 return false;
534 }
535
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100536 /*
Tian Yang46d6eb02022-03-31 10:26:16 -0700537 * dereference the decap direction top_interface_dev
538 */
539 if (c->reply_match->top_interface_dev) {
540 dev_put(c->reply_match->top_interface_dev);
541 }
542
543 /*
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100544 * Remove the connection match objects.
545 */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530546 sfe_ipv4_remove_connection_match(si, c->reply_match);
547 sfe_ipv4_remove_connection_match(si, c->original_match);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100548
549 /*
550 * Unlink the connection.
551 */
552 if (c->prev) {
553 c->prev->next = c->next;
554 } else {
555 unsigned int conn_idx = sfe_ipv4_get_connection_hash(c->protocol, c->src_ip, c->src_port,
556 c->dest_ip, c->dest_port);
557 si->conn_hash[conn_idx] = c->next;
558 }
559
560 if (c->next) {
561 c->next->prev = c->prev;
562 }
Xiaoping Fan34586472015-07-03 02:20:35 -0700563
564 /*
565 * Unlink connection from all_connections list
566 */
567 if (c->all_connections_prev) {
568 c->all_connections_prev->all_connections_next = c->all_connections_next;
569 } else {
570 si->all_connections_head = c->all_connections_next;
571 }
572
573 if (c->all_connections_next) {
574 c->all_connections_next->all_connections_prev = c->all_connections_prev;
575 } else {
576 si->all_connections_tail = c->all_connections_prev;
577 }
578
Ken Zhudc423672021-09-02 18:27:01 -0700579 /*
580 * If I am the next sync connection, move the sync to my next or head.
581 */
582 if (unlikely(si->wc_next == c)) {
583 si->wc_next = c->all_connections_next;
584 }
585
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530586 c->removed = true;
Xiaoping Fan34586472015-07-03 02:20:35 -0700587 si->num_connections--;
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530588 return true;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100589}
590
591/*
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530592 * sfe_ipv4_gen_sync_connection()
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100593 * Sync a connection.
594 *
595 * On entry to this function we expect that the lock for the connection is either
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530596 * already held (while called from sfe_ipv4_periodic_sync() or isn't required
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530597 * (while called from sfe_ipv4_flush_connection())
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100598 */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530599static void sfe_ipv4_gen_sync_connection(struct sfe_ipv4 *si, struct sfe_ipv4_connection *c,
Xiaoping Fan99cb4c12015-08-21 19:07:32 -0700600 struct sfe_connection_sync *sis, sfe_sync_reason_t reason,
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700601 u64 now_jiffies)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100602{
603 struct sfe_ipv4_connection_match *original_cm;
604 struct sfe_ipv4_connection_match *reply_cm;
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530605 u32 packet_count, byte_count;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100606
607 /*
608 * Fill in the update message.
609 */
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700610 sis->is_v6 = 0;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100611 sis->protocol = c->protocol;
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700612 sis->src_ip.ip = c->src_ip;
Xiaoping Fan99cb4c12015-08-21 19:07:32 -0700613 sis->src_ip_xlate.ip = c->src_ip_xlate;
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700614 sis->dest_ip.ip = c->dest_ip;
Xiaoping Fan99cb4c12015-08-21 19:07:32 -0700615 sis->dest_ip_xlate.ip = c->dest_ip_xlate;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100616 sis->src_port = c->src_port;
Xiaoping Fan99cb4c12015-08-21 19:07:32 -0700617 sis->src_port_xlate = c->src_port_xlate;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100618 sis->dest_port = c->dest_port;
Xiaoping Fan99cb4c12015-08-21 19:07:32 -0700619 sis->dest_port_xlate = c->dest_port_xlate;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100620
621 original_cm = c->original_match;
622 reply_cm = c->reply_match;
623 sis->src_td_max_window = original_cm->protocol_state.tcp.max_win;
624 sis->src_td_end = original_cm->protocol_state.tcp.end;
625 sis->src_td_max_end = original_cm->protocol_state.tcp.max_end;
626 sis->dest_td_max_window = reply_cm->protocol_state.tcp.max_win;
627 sis->dest_td_end = reply_cm->protocol_state.tcp.end;
628 sis->dest_td_max_end = reply_cm->protocol_state.tcp.max_end;
629
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530630 sfe_ipv4_connection_match_update_summary_stats(original_cm, &packet_count, &byte_count);
631 sis->src_new_packet_count = packet_count;
632 sis->src_new_byte_count = byte_count;
Matthew McClintockd0cdb802014-02-24 16:30:35 -0600633
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530634 sfe_ipv4_connection_match_update_summary_stats(reply_cm, &packet_count, &byte_count);
635 sis->dest_new_packet_count = packet_count;
636 sis->dest_new_byte_count = byte_count;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100637
Matthew McClintockd0cdb802014-02-24 16:30:35 -0600638 sis->src_dev = original_cm->match_dev;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100639 sis->src_packet_count = original_cm->rx_packet_count64;
640 sis->src_byte_count = original_cm->rx_byte_count64;
Matthew McClintockd0cdb802014-02-24 16:30:35 -0600641
642 sis->dest_dev = reply_cm->match_dev;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100643 sis->dest_packet_count = reply_cm->rx_packet_count64;
644 sis->dest_byte_count = reply_cm->rx_byte_count64;
645
Xiaoping Fan99cb4c12015-08-21 19:07:32 -0700646 sis->reason = reason;
647
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100648 /*
649 * Get the time increment since our last sync.
650 */
651 sis->delta_jiffies = now_jiffies - c->last_sync_jiffies;
652 c->last_sync_jiffies = now_jiffies;
653}
654
655/*
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530656 * sfe_ipv4_free_connection_rcu()
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530657 * Called at RCU qs state to free the connection object.
658 */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530659static void sfe_ipv4_free_connection_rcu(struct rcu_head *head)
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530660{
661 struct sfe_ipv4_connection *c;
Amitesh Anand63be37d2021-12-24 20:51:48 +0530662 struct udp_sock *up;
663 struct sock *sk;
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530664
665 /*
666 * We dont need spin lock as the connection is already removed from link list
667 */
668 c = container_of(head, struct sfe_ipv4_connection, rcu);
669
670 BUG_ON(!c->removed);
671
672 DEBUG_TRACE("%px: connecton has been deleted\n", c);
673
674 /*
Amitesh Anand63be37d2021-12-24 20:51:48 +0530675 * Decrease the refcount taken in function sfe_ipv4_create_rule(),
676 * during call of __udp4_lib_lookup()
677 */
678 up = c->reply_match->up;
679 if (up) {
680 sk = (struct sock *)up;
681 sock_put(sk);
682 }
683
684 /*
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530685 * Release our hold of the source and dest devices and free the memory
686 * for our connection objects.
687 */
688 dev_put(c->original_dev);
689 dev_put(c->reply_dev);
690 kfree(c->original_match);
691 kfree(c->reply_match);
692 kfree(c);
693}
694
695/*
Ken Zhu88c58152021-12-09 15:12:06 -0800696 * sfe_ipv4_sync_status()
697 * update a connection status to its connection manager.
698 *
699 * si: the ipv4 context
700 * c: which connection to be notified
701 * reason: what kind of notification: flush, stats or destroy
702 */
703void sfe_ipv4_sync_status(struct sfe_ipv4 *si,
704 struct sfe_ipv4_connection *c,
705 sfe_sync_reason_t reason)
706{
707 struct sfe_connection_sync sis;
708 u64 now_jiffies;
709 sfe_sync_rule_callback_t sync_rule_callback;
710
711 rcu_read_lock();
712 sync_rule_callback = rcu_dereference(si->sync_rule_callback);
Ken Zhu7a43d882022-01-04 10:51:44 -0800713 rcu_read_unlock();
Ken Zhu88c58152021-12-09 15:12:06 -0800714 if (!sync_rule_callback) {
Ken Zhu88c58152021-12-09 15:12:06 -0800715 return;
716 }
717
718 /*
719 * Generate a sync message and then sync.
720 */
721 now_jiffies = get_jiffies_64();
722 sfe_ipv4_gen_sync_connection(si, c, &sis, reason, now_jiffies);
723 sync_rule_callback(&sis);
Ken Zhu88c58152021-12-09 15:12:06 -0800724}
725
726/*
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530727 * sfe_ipv4_flush_connection()
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100728 * Flush a connection and free all associated resources.
729 *
730 * We need to be called with bottom halves disabled locally as we need to acquire
731 * the connection hash lock and release it again. In general we're actually called
732 * from within a BH and so we're fine, but we're also called when connections are
733 * torn down.
734 */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530735void sfe_ipv4_flush_connection(struct sfe_ipv4 *si,
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700736 struct sfe_ipv4_connection *c,
737 sfe_sync_reason_t reason)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100738{
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +0530739 BUG_ON(!c->removed);
740
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +0530741 this_cpu_inc(si->stats_pcpu->connection_flushes64);
Ken Zhu88c58152021-12-09 15:12:06 -0800742 sfe_ipv4_sync_status(si, c, reason);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100743
744 /*
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100745 * Release our hold of the source and dest devices and free the memory
746 * for our connection objects.
747 */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530748 call_rcu(&c->rcu, sfe_ipv4_free_connection_rcu);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100749}
750
751/*
Parikshit Guned31a8202022-01-05 22:15:04 +0530752 * sfe_ipv4_service_class_stats_inc()
753 * Increment per cpu per service class stats.
754 */
755void sfe_ipv4_service_class_stats_inc(struct sfe_ipv4 *si, uint8_t sid, uint64_t bytes)
756{
757 struct sfe_ipv4_service_class_stats_db *sc_stats_db = this_cpu_ptr(si->stats_pcpu_psc);
758 struct sfe_ipv4_per_service_class_stats *sc_stats = &sc_stats_db->psc_stats[sid];
759
760 write_seqcount_begin(&sc_stats->seq);
761 sc_stats->tx_bytes += bytes;
762 sc_stats->tx_packets++;
763 write_seqcount_end(&sc_stats->seq);
764}
765
766/*
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +0530767 * sfe_ipv4_exception_stats_inc()
768 * Increment exception stats.
769 */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530770void sfe_ipv4_exception_stats_inc(struct sfe_ipv4 *si, enum sfe_ipv4_exception_events reason)
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +0530771{
772 struct sfe_ipv4_stats *stats = this_cpu_ptr(si->stats_pcpu);
773 stats->exception_events64[reason]++;
774 stats->packets_not_forwarded64++;
775}
776
777/*
Nitin Shettye6ed5b52021-12-27 14:50:11 +0530778 * sfe_ipv4_is_loal_ip()
779 * Returns true if IP is local; returns false otherwise.
780 */
781static bool sfe_ipv4_is_local_ip(struct sfe_ipv4 *si, __be32 ip_addr)
782{
783 struct net_device *dev;
784
785 dev = ip_dev_find(&init_net, ip_addr);
786 if (dev) {
787 dev_put(dev);
788 return true;
789 }
790
791 return false;
792}
793
794/*
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100795 * sfe_ipv4_recv()
Matthew McClintocka8ad7962014-01-16 16:49:30 -0600796 * Handle packet receives and forwaring.
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100797 *
798 * Returns 1 if the packet is forwarded or 0 if it isn't.
799 */
Amitesh Anand63be37d2021-12-24 20:51:48 +0530800int sfe_ipv4_recv(struct net_device *dev, struct sk_buff *skb, struct sfe_l2_info *l2_info, bool tun_outer)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100801{
802 struct sfe_ipv4 *si = &__si;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100803 unsigned int len;
804 unsigned int tot_len;
805 unsigned int frag_off;
806 unsigned int ihl;
Ken Zhu88c58152021-12-09 15:12:06 -0800807 bool sync_on_find;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100808 bool ip_options;
Ratheesh Kannoth741f7992021-10-20 07:39:52 +0530809 struct iphdr *iph;
Xiaoping Fan6a1672f2016-08-17 19:58:12 -0700810 u32 protocol;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100811
812 /*
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100813 * Check that we have space for an IP header here.
814 */
815 len = skb->len;
Ratheesh Kannoth741f7992021-10-20 07:39:52 +0530816 if (unlikely(!pskb_may_pull(skb, sizeof(struct iphdr)))) {
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +0530817 sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_HEADER_INCOMPLETE);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100818 DEBUG_TRACE("len: %u is too short\n", len);
819 return 0;
820 }
821
822 /*
Ratheesh Kannotha3cf0e02021-12-09 09:44:10 +0530823 * Validate ip csum if necessary. If ip_summed is set to CHECKSUM_UNNECESSARY, it is assumed
824 * that the L3 checksum is validated by the Rx interface or the tunnel interface that has
825 * generated the packet.
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100826 */
Ratheesh Kannoth741f7992021-10-20 07:39:52 +0530827 iph = (struct iphdr *)skb->data;
Ratheesh Kannoth43d64f82021-10-20 08:23:29 +0530828 if (unlikely(skb->ip_summed != CHECKSUM_UNNECESSARY) && (ip_fast_csum((u8 *)iph, iph->ihl))) {
829 sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_HEADER_CSUM_BAD);
830
831 DEBUG_TRACE("Bad IPv4 header csum: 0x%x\n", iph->check);
832 return 0;
833 }
834
835 /*
836 * Check that our "total length" is large enough for an IP header.
837 */
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100838 tot_len = ntohs(iph->tot_len);
Ratheesh Kannoth741f7992021-10-20 07:39:52 +0530839 if (unlikely(tot_len < sizeof(struct iphdr))) {
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100840
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +0530841 sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_BAD_TOTAL_LENGTH);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100842 DEBUG_TRACE("tot_len: %u is too short\n", tot_len);
843 return 0;
844 }
845
846 /*
847 * Is our IP version wrong?
848 */
849 if (unlikely(iph->version != 4)) {
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +0530850 sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_NON_V4);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100851 DEBUG_TRACE("IP version: %u\n", iph->version);
852 return 0;
853 }
854
855 /*
856 * Does our datagram fit inside the skb?
857 */
858 if (unlikely(tot_len > len)) {
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100859 DEBUG_TRACE("tot_len: %u, exceeds len: %u\n", tot_len, len);
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +0530860 sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_DATAGRAM_INCOMPLETE);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100861 return 0;
862 }
863
864 /*
865 * Do we have a non-initial fragment?
Nicolas Costaac2979c2014-01-14 10:35:24 -0600866 */
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100867 frag_off = ntohs(iph->frag_off);
868 if (unlikely(frag_off & IP_OFFSET)) {
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +0530869 sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_NON_INITIAL_FRAGMENT);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100870 DEBUG_TRACE("non-initial fragment\n");
871 return 0;
872 }
873
874 /*
875 * If we have a (first) fragment then mark it to cause any connection to flush.
876 */
Ken Zhu88c58152021-12-09 15:12:06 -0800877 sync_on_find = unlikely(frag_off & IP_MF) ? true : false;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100878
879 /*
880 * Do we have any IP options? That's definite a slow path! If we do have IP
881 * options we need to recheck our header size.
882 */
883 ihl = iph->ihl << 2;
Ratheesh Kannoth741f7992021-10-20 07:39:52 +0530884 ip_options = unlikely(ihl != sizeof(struct iphdr)) ? true : false;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100885 if (unlikely(ip_options)) {
886 if (unlikely(len < ihl)) {
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100887
888 DEBUG_TRACE("len: %u is too short for header of size: %u\n", len, ihl);
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +0530889 sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_IP_OPTIONS_INCOMPLETE);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100890 return 0;
891 }
892
Ken Zhu88c58152021-12-09 15:12:06 -0800893 sync_on_find = true;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100894 }
895
Wayne Tan1cabbf12022-05-01 13:01:45 -0700896 /*
897 * Handle PPPoE bridge packets using 3-tuple acceleration if SFE_PPPOE_BR_ACCEL_MODE_EN_3T
898 */
899 if (unlikely(sfe_l2_parse_flag_check(l2_info, SFE_L2_PARSE_FLAGS_PPPOE_INGRESS)) &&
900 unlikely(sfe_pppoe_get_br_accel_mode() == SFE_PPPOE_BR_ACCEL_MODE_EN_3T)) {
901 struct ethhdr *eth = eth_hdr(skb);
902 if (!sfe_pppoe_mgr_find_session(l2_info->pppoe_session_id, eth->h_source)) {
903 return sfe_ipv4_recv_pppoe_bridge(si, skb, dev, len, iph, ihl, l2_info);
904 }
905 }
906
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100907 protocol = iph->protocol;
908 if (IPPROTO_UDP == protocol) {
Ken Zhu88c58152021-12-09 15:12:06 -0800909 return sfe_ipv4_recv_udp(si, skb, dev, len, iph, ihl, sync_on_find, l2_info, tun_outer);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100910 }
911
912 if (IPPROTO_TCP == protocol) {
Ken Zhu88c58152021-12-09 15:12:06 -0800913 return sfe_ipv4_recv_tcp(si, skb, dev, len, iph, ihl, sync_on_find, l2_info);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100914 }
915
916 if (IPPROTO_ICMP == protocol) {
917 return sfe_ipv4_recv_icmp(si, skb, dev, len, iph, ihl);
918 }
919
Nitin Shettye6ed5b52021-12-27 14:50:11 +0530920#ifdef SFE_GRE_TUN_ENABLE
921 if (IPPROTO_GRE == protocol) {
Nitin Shetty2114a892022-01-28 20:03:56 +0530922 return sfe_ipv4_recv_gre(si, skb, dev, len, iph, ihl, sync_on_find, l2_info, tun_outer);
Nitin Shettye6ed5b52021-12-27 14:50:11 +0530923 }
924#endif
Tian Yangd98d91b2022-03-09 14:50:12 -0800925 if (IPPROTO_IPV6 == protocol) {
926 return sfe_ipv4_recv_tun6rd(si, skb, dev, len, iph, ihl, sync_on_find, l2_info, true);
927 }
Nitin Shettye6ed5b52021-12-27 14:50:11 +0530928
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +0530929 sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_UNHANDLED_PROTOCOL);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +0100930
931 DEBUG_TRACE("not UDP, TCP or ICMP: %u\n", protocol);
932 return 0;
933}
934
Nicolas Costa436926b2014-01-14 10:36:22 -0600935static void
936sfe_ipv4_update_tcp_state(struct sfe_ipv4_connection *c,
Ratheesh Kannoth89302a72021-10-20 08:10:37 +0530937 struct sfe_ipv4_rule_create_msg *msg)
Nicolas Costa436926b2014-01-14 10:36:22 -0600938{
939 struct sfe_ipv4_connection_match *orig_cm;
940 struct sfe_ipv4_connection_match *repl_cm;
941 struct sfe_ipv4_tcp_connection_match *orig_tcp;
942 struct sfe_ipv4_tcp_connection_match *repl_tcp;
943
944 orig_cm = c->original_match;
945 repl_cm = c->reply_match;
946 orig_tcp = &orig_cm->protocol_state.tcp;
947 repl_tcp = &repl_cm->protocol_state.tcp;
948
949 /* update orig */
Ratheesh Kannoth89302a72021-10-20 08:10:37 +0530950 if (orig_tcp->max_win < msg->tcp_rule.flow_max_window) {
951 orig_tcp->max_win = msg->tcp_rule.flow_max_window;
Nicolas Costa436926b2014-01-14 10:36:22 -0600952 }
Ratheesh Kannoth89302a72021-10-20 08:10:37 +0530953 if ((s32)(orig_tcp->end - msg->tcp_rule.flow_end) < 0) {
954 orig_tcp->end = msg->tcp_rule.flow_end;
Nicolas Costa436926b2014-01-14 10:36:22 -0600955 }
Ratheesh Kannoth89302a72021-10-20 08:10:37 +0530956 if ((s32)(orig_tcp->max_end - msg->tcp_rule.flow_max_end) < 0) {
957 orig_tcp->max_end = msg->tcp_rule.flow_max_end;
Nicolas Costa436926b2014-01-14 10:36:22 -0600958 }
959
960 /* update reply */
Ratheesh Kannoth89302a72021-10-20 08:10:37 +0530961 if (repl_tcp->max_win < msg->tcp_rule.return_max_window) {
962 repl_tcp->max_win = msg->tcp_rule.return_max_window;
Nicolas Costa436926b2014-01-14 10:36:22 -0600963 }
Ratheesh Kannoth89302a72021-10-20 08:10:37 +0530964 if ((s32)(repl_tcp->end - msg->tcp_rule.return_end) < 0) {
965 repl_tcp->end = msg->tcp_rule.return_end;
Nicolas Costa436926b2014-01-14 10:36:22 -0600966 }
Ratheesh Kannoth89302a72021-10-20 08:10:37 +0530967 if ((s32)(repl_tcp->max_end - msg->tcp_rule.return_max_end) < 0) {
968 repl_tcp->max_end = msg->tcp_rule.return_max_end;
Nicolas Costa436926b2014-01-14 10:36:22 -0600969 }
970
971 /* update match flags */
972 orig_cm->flags &= ~SFE_IPV4_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK;
973 repl_cm->flags &= ~SFE_IPV4_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK;
Ratheesh Kannoth89302a72021-10-20 08:10:37 +0530974 if (msg->rule_flags & SFE_RULE_CREATE_FLAG_NO_SEQ_CHECK) {
975
Nicolas Costa436926b2014-01-14 10:36:22 -0600976 orig_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK;
977 repl_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK;
978 }
979}
980
981static void
982sfe_ipv4_update_protocol_state(struct sfe_ipv4_connection *c,
Ratheesh Kannoth89302a72021-10-20 08:10:37 +0530983 struct sfe_ipv4_rule_create_msg *msg)
Nicolas Costa436926b2014-01-14 10:36:22 -0600984{
Ratheesh Kannoth89302a72021-10-20 08:10:37 +0530985 switch (msg->tuple.protocol) {
Nicolas Costa436926b2014-01-14 10:36:22 -0600986 case IPPROTO_TCP:
Ratheesh Kannoth89302a72021-10-20 08:10:37 +0530987 sfe_ipv4_update_tcp_state(c, msg);
Nicolas Costa436926b2014-01-14 10:36:22 -0600988 break;
989 }
990}
991
Wayne Tanbb7f1782021-12-13 11:16:04 -0800992/*
993 * sfe_ipv4_match_entry_set_vlan()
994 */
995static void sfe_ipv4_match_entry_set_vlan(
996 struct sfe_ipv4_connection_match *cm,
997 u32 primary_ingress_vlan_tag,
998 u32 primary_egress_vlan_tag,
999 u32 secondary_ingress_vlan_tag,
1000 u32 secondary_egress_vlan_tag)
1001{
1002 u16 tpid;
1003 /*
1004 * Prevent stacking header counts when updating.
1005 */
1006 cm->ingress_vlan_hdr_cnt = 0;
1007 cm->egress_vlan_hdr_cnt = 0;
1008 memset(cm->ingress_vlan_hdr, 0, sizeof(cm->ingress_vlan_hdr));
1009 memset(cm->egress_vlan_hdr, 0, sizeof(cm->egress_vlan_hdr));
1010
1011 /*
1012 * vlan_hdr[0] corresponds to outer tag
1013 * vlan_hdr[1] corresponds to inner tag
1014 * Extract the vlan information (tpid and tci) from rule message
1015 */
1016 if ((primary_ingress_vlan_tag & VLAN_VID_MASK) != SFE_VLAN_ID_NOT_CONFIGURED) {
1017 tpid = (u16)(primary_ingress_vlan_tag >> 16);
1018 cm->ingress_vlan_hdr[0].tpid = ntohs(tpid);
1019 cm->ingress_vlan_hdr[0].tci = (u16)primary_ingress_vlan_tag;
1020 cm->ingress_vlan_hdr_cnt++;
1021 }
1022
1023 if ((secondary_ingress_vlan_tag & VLAN_VID_MASK) != SFE_VLAN_ID_NOT_CONFIGURED) {
1024 tpid = (u16)(secondary_ingress_vlan_tag >> 16);
1025 cm->ingress_vlan_hdr[1].tpid = ntohs(tpid);
1026 cm->ingress_vlan_hdr[1].tci = (u16)secondary_ingress_vlan_tag;
1027 cm->ingress_vlan_hdr_cnt++;
1028 }
1029
1030 if ((primary_egress_vlan_tag & VLAN_VID_MASK) != SFE_VLAN_ID_NOT_CONFIGURED) {
1031 tpid = (u16)(primary_egress_vlan_tag >> 16);
1032 cm->egress_vlan_hdr[0].tpid = ntohs(tpid);
1033 cm->egress_vlan_hdr[0].tci = (u16)primary_egress_vlan_tag;
1034 cm->egress_vlan_hdr_cnt++;
1035 }
1036
1037 if ((secondary_egress_vlan_tag & VLAN_VID_MASK) != SFE_VLAN_ID_NOT_CONFIGURED) {
1038 tpid = (u16)(secondary_egress_vlan_tag >> 16);
1039 cm->egress_vlan_hdr[1].tpid = ntohs(tpid);
1040 cm->egress_vlan_hdr[1].tci = (u16)secondary_egress_vlan_tag;
1041 cm->egress_vlan_hdr_cnt++;
1042 }
1043}
1044
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301045void sfe_ipv4_update_rule(struct sfe_ipv4_rule_create_msg *msg)
Nicolas Costa436926b2014-01-14 10:36:22 -06001046{
1047 struct sfe_ipv4_connection *c;
1048 struct sfe_ipv4 *si = &__si;
1049
1050 spin_lock_bh(&si->lock);
1051
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05301052 c = sfe_ipv4_find_connection(si,
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301053 msg->tuple.protocol,
1054 msg->tuple.flow_ip,
1055 msg->tuple.flow_ident,
1056 msg->tuple.return_ip,
1057 msg->tuple.return_ident);
Nicolas Costa436926b2014-01-14 10:36:22 -06001058 if (c != NULL) {
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301059 sfe_ipv4_update_protocol_state(c, msg);
Nicolas Costa436926b2014-01-14 10:36:22 -06001060 }
1061
1062 spin_unlock_bh(&si->lock);
1063}
1064
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001065/*
Murat Sezginef190392022-04-04 17:56:31 -07001066 * sfe_ipv4_mark_rule_update()
1067 * Updates the mark values of match entries.
1068 */
1069void sfe_ipv4_mark_rule_update(struct sfe_connection_mark *mark)
1070{
1071 struct sfe_ipv4_connection *c;
1072 struct sfe_ipv4 *si = &__si;
1073
1074 spin_lock_bh(&si->lock);
1075 c = sfe_ipv4_find_connection(si, mark->protocol,
1076 mark->src_ip[0],
1077 mark->src_port,
1078 mark->dest_ip[0],
1079 mark->dest_port);
1080 if (!c) {
1081 spin_unlock_bh(&si->lock);
1082 DEBUG_WARN("%px: connection not found for mark update\n", mark);
1083 return;
1084 }
1085 c->original_match->mark = mark->mark;
1086 c->reply_match->mark = mark->mark;
1087 spin_unlock_bh(&si->lock);
1088 DEBUG_TRACE("%px: connection mark updated with %d\n", mark, mark->mark);
1089}
1090EXPORT_SYMBOL(sfe_ipv4_mark_rule_update);
1091
1092/*
Guduri Prathyusha79a5fee2021-11-11 17:59:10 +05301093 * sfe_ipv4_xmit_eth_type_check()
1094 * Checking if MAC header has to be written.
1095 */
1096static inline bool sfe_ipv4_xmit_eth_type_check(struct net_device *dev, u32 cm_flags)
1097{
1098 if (!(dev->flags & IFF_NOARP)) {
1099 return true;
1100 }
1101
1102 /*
1103 * For PPPoE, since we are now supporting PPPoE encapsulation, we are writing L2 header.
1104 */
1105 if (unlikely(cm_flags & SFE_IPV4_CONNECTION_MATCH_FLAG_PPPOE_ENCAP)) {
1106 return true;
1107 }
1108
1109 return false;
1110}
1111
1112/*
Jackson Bockus3fafbf32022-02-13 17:15:26 -08001113 * sfe_ipv4_service_class_stats_pcpu_get()
1114 * Gets one CPU's service class statistics.
1115 */
1116static inline bool sfe_ipv4_service_class_stats_pcpu_get(struct sfe_ipv4_per_service_class_stats *sc_stats, uint64_t *bytes, uint64_t *packets)
1117{
1118 uint32_t retries = 0;
1119 uint32_t seq;
1120 uint64_t bytes_tmp, packets_tmp;
1121
1122 do {
1123 seq = read_seqcount_begin(&sc_stats->seq);
1124 bytes_tmp = sc_stats->tx_bytes;
1125 packets_tmp = sc_stats->tx_packets;
1126 } while (read_seqcount_retry(&sc_stats->seq, seq) && ++retries < SFE_SERVICE_CLASS_STATS_MAX_RETRY);
1127
1128 *bytes += bytes_tmp;
1129 *packets += packets_tmp;
1130
1131 return retries < SFE_SERVICE_CLASS_STATS_MAX_RETRY;
1132}
1133
1134/*
1135 * sfe_ipv4_service_class_stats_get()
1136 * Copy the ipv4 statistics for the given service class.
1137 */
1138bool sfe_ipv4_service_class_stats_get(uint8_t sid, uint64_t *bytes, uint64_t *packets)
1139{
1140 struct sfe_ipv4 *si = &__si;
1141 uint32_t cpu = 0;
1142
1143 for_each_possible_cpu(cpu) {
1144 struct sfe_ipv4_service_class_stats_db *stats_db = per_cpu_ptr(si->stats_pcpu_psc, cpu);
1145 struct sfe_ipv4_per_service_class_stats *sc_stats = &stats_db->psc_stats[sid];
1146
1147 if (!sfe_ipv4_service_class_stats_pcpu_get(sc_stats, bytes, packets)) {
1148 return false;
1149 }
1150 }
1151
1152 return true;
1153}
1154
1155/*
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001156 * sfe_ipv4_create_rule()
1157 * Create a forwarding rule.
1158 */
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301159int sfe_ipv4_create_rule(struct sfe_ipv4_rule_create_msg *msg)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001160{
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001161 struct sfe_ipv4 *si = &__si;
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05301162 struct sfe_ipv4_connection *c, *c_old;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001163 struct sfe_ipv4_connection_match *original_cm;
1164 struct sfe_ipv4_connection_match *reply_cm;
Matthew McClintockdb5ac512014-01-16 17:01:40 -06001165 struct net_device *dest_dev;
1166 struct net_device *src_dev;
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301167 struct sfe_ipv4_5tuple *tuple = &msg->tuple;
Suruchi Sumanc1a4a612021-10-21 14:50:23 +05301168 s32 flow_interface_num = msg->conn_rule.flow_top_interface_num;
1169 s32 return_interface_num = msg->conn_rule.return_top_interface_num;
Amitesh Anand63be37d2021-12-24 20:51:48 +05301170 struct net *net;
1171 struct sock *sk;
1172 unsigned int src_if_idx;
Parikshit Guned31a8202022-01-05 22:15:04 +05301173 u32 flow_sawf_tag;
1174 u32 return_sawf_tag;
Matthew McClintockdb5ac512014-01-16 17:01:40 -06001175
Suruchi Sumanc1a4a612021-10-21 14:50:23 +05301176 if (msg->rule_flags & SFE_RULE_CREATE_FLAG_USE_FLOW_BOTTOM_INTERFACE) {
1177 flow_interface_num = msg->conn_rule.flow_interface_num;
1178 }
1179
1180 if (msg->rule_flags & SFE_RULE_CREATE_FLAG_USE_RETURN_BOTTOM_INTERFACE) {
1181 return_interface_num = msg->conn_rule.return_interface_num;
1182 }
1183
1184 src_dev = dev_get_by_index(&init_net, flow_interface_num);
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301185 if (!src_dev) {
1186 DEBUG_WARN("%px: Unable to find src_dev corresponding to %d\n", msg,
Suruchi Sumanc1a4a612021-10-21 14:50:23 +05301187 flow_interface_num);
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301188 this_cpu_inc(si->stats_pcpu->connection_create_failures64);
1189 return -EINVAL;
1190 }
1191
Suruchi Sumanc1a4a612021-10-21 14:50:23 +05301192 dest_dev = dev_get_by_index(&init_net, return_interface_num);
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301193 if (!dest_dev) {
1194 DEBUG_WARN("%px: Unable to find dest_dev corresponding to %d\n", msg,
Suruchi Sumanc1a4a612021-10-21 14:50:23 +05301195 return_interface_num);
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301196 this_cpu_inc(si->stats_pcpu->connection_create_failures64);
1197 dev_put(src_dev);
1198 return -EINVAL;
1199 }
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001200
Matthew McClintock389b42a2014-09-24 14:05:51 -05001201 if (unlikely((dest_dev->reg_state != NETREG_REGISTERED) ||
1202 (src_dev->reg_state != NETREG_REGISTERED))) {
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301203 dev_put(src_dev);
1204 dev_put(dest_dev);
1205 DEBUG_WARN("%px: src_dev=%s and dest_dev=%s are unregistered\n", msg,
1206 src_dev->name, dest_dev->name);
1207 this_cpu_inc(si->stats_pcpu->connection_create_failures64);
Matthew McClintock389b42a2014-09-24 14:05:51 -05001208 return -EINVAL;
1209 }
1210
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05301211 /*
1212 * Allocate the various connection tracking objects.
1213 */
Parikshit Guneef1664c2022-03-24 14:15:42 +05301214 c = (struct sfe_ipv4_connection *)kzalloc(sizeof(struct sfe_ipv4_connection), GFP_ATOMIC);
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05301215 if (unlikely(!c)) {
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301216 DEBUG_WARN("%px: memory allocation of connection entry failed\n", msg);
1217 this_cpu_inc(si->stats_pcpu->connection_create_failures64);
1218 dev_put(src_dev);
1219 dev_put(dest_dev);
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05301220 return -ENOMEM;
1221 }
1222
Parikshit Guneef1664c2022-03-24 14:15:42 +05301223 original_cm = (struct sfe_ipv4_connection_match *)kzalloc(sizeof(struct sfe_ipv4_connection_match), GFP_ATOMIC);
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05301224 if (unlikely(!original_cm)) {
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301225 DEBUG_WARN("%px: memory allocation of connection match entry failed\n", msg);
1226 this_cpu_inc(si->stats_pcpu->connection_create_failures64);
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05301227 kfree(c);
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301228 dev_put(src_dev);
1229 dev_put(dest_dev);
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05301230 return -ENOMEM;
1231 }
1232
Parikshit Guneef1664c2022-03-24 14:15:42 +05301233 reply_cm = (struct sfe_ipv4_connection_match *)kzalloc(sizeof(struct sfe_ipv4_connection_match), GFP_ATOMIC);
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05301234 if (unlikely(!reply_cm)) {
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301235 DEBUG_WARN("%px: memory allocation of connection match entry failed\n", msg);
1236 this_cpu_inc(si->stats_pcpu->connection_create_failures64);
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05301237 kfree(original_cm);
1238 kfree(c);
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301239 dev_put(src_dev);
1240 dev_put(dest_dev);
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05301241 return -ENOMEM;
1242 }
1243
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +05301244 this_cpu_inc(si->stats_pcpu->connection_create_requests64);
1245
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001246 spin_lock_bh(&si->lock);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001247
1248 /*
Nicolas Costa436926b2014-01-14 10:36:22 -06001249 * Check to see if there is already a flow that matches the rule we're
1250 * trying to create. If there is then we can't create a new one.
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001251 */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05301252 c_old = sfe_ipv4_find_connection(si,
Wayne Tanbb7f1782021-12-13 11:16:04 -08001253 msg->tuple.protocol,
1254 msg->tuple.flow_ip,
1255 msg->tuple.flow_ident,
1256 msg->tuple.return_ip,
1257 msg->tuple.return_ident);
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301258
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05301259 if (c_old != NULL) {
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +05301260 this_cpu_inc(si->stats_pcpu->connection_create_collisions64);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001261
1262 /*
Nicolas Costa436926b2014-01-14 10:36:22 -06001263 * If we already have the flow then it's likely that this
1264 * request to create the connection rule contains more
1265 * up-to-date information. Check and update accordingly.
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001266 */
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301267 sfe_ipv4_update_protocol_state(c, msg);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001268 spin_unlock_bh(&si->lock);
1269
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05301270 kfree(reply_cm);
1271 kfree(original_cm);
1272 kfree(c);
1273
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301274 dev_put(src_dev);
1275 dev_put(dest_dev);
1276
Amitesh Anand63be37d2021-12-24 20:51:48 +05301277 DEBUG_TRACE("%px: connection already exists - p:%d\n"
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301278 " s: %s:%pM:%pI4:%u, d: %s:%pM:%pI4:%u\n",
Amitesh Anand63be37d2021-12-24 20:51:48 +05301279 msg, tuple->protocol,
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301280 src_dev->name, msg->conn_rule.flow_mac, &tuple->flow_ip, ntohs(tuple->flow_ident),
1281 dest_dev->name, msg->conn_rule.return_mac, &tuple->return_ip, ntohs(tuple->return_ident));
1282
Nicolas Costa514fde02014-01-13 15:50:29 -06001283 return -EADDRINUSE;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001284 }
1285
1286 /*
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001287 * Fill in the "original" direction connection matching object.
1288 * Note that the transmit MAC address is "dest_mac_xlate" because
1289 * we always know both ends of a connection by their translated
1290 * addresses and not their public addresses.
1291 */
Matthew McClintockdb5ac512014-01-16 17:01:40 -06001292 original_cm->match_dev = src_dev;
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301293 original_cm->match_protocol = tuple->protocol;
1294 original_cm->match_src_ip = tuple->flow_ip;
Suruchi Suman66609a72022-01-20 02:34:25 +05301295 original_cm->match_src_port = netif_is_vxlan(src_dev) ? 0 : tuple->flow_ident;
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301296 original_cm->match_dest_ip = tuple->return_ip;
1297 original_cm->match_dest_port = tuple->return_ident;
1298
1299 original_cm->xlate_src_ip = msg->conn_rule.flow_ip_xlate;
1300 original_cm->xlate_src_port = msg->conn_rule.flow_ident_xlate;
1301 original_cm->xlate_dest_ip = msg->conn_rule.return_ip_xlate;
Nitin Shettye6ed5b52021-12-27 14:50:11 +05301302 original_cm->xlate_dest_port = msg->conn_rule.return_ident_xlate;
1303
1304 if (tuple->protocol == IPPROTO_GRE) {
1305 /*
1306 * the PPTP is 4 tuple lookup.
1307 * During th rule lookup destination call id from packet
1308 * is matched against destination port in cm.
1309 */
1310 original_cm->match_src_port = 0;
1311 original_cm->xlate_src_port = 0;
1312 }
Wayne Tanbb7f1782021-12-13 11:16:04 -08001313
Matthew McClintockdb5ac512014-01-16 17:01:40 -06001314 original_cm->xmit_dev = dest_dev;
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301315 original_cm->xmit_dev_mtu = msg->conn_rule.return_mtu;
1316
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001317 original_cm->connection = c;
1318 original_cm->counter_match = reply_cm;
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301319
Amitesh Anand63be37d2021-12-24 20:51:48 +05301320 /*
1321 * UDP Socket is valid only in decap direction.
1322 */
1323 RCU_INIT_POINTER(original_cm->up, NULL);
1324
Ken Zhu37040ea2021-09-09 21:11:15 -07001325 if (msg->valid_flags & SFE_RULE_CREATE_MARK_VALID) {
1326 original_cm->mark = msg->mark_rule.flow_mark;
1327 original_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_MARK;
1328 }
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301329 if (msg->valid_flags & SFE_RULE_CREATE_QOS_VALID) {
1330 original_cm->priority = msg->qos_rule.flow_qos_tag;
Xiaoping Fane1963d42015-08-25 17:06:19 -07001331 original_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_PRIORITY_REMARK;
1332 }
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301333 if (msg->valid_flags & SFE_RULE_CREATE_DSCP_MARKING_VALID) {
1334 original_cm->dscp = msg->dscp_rule.flow_dscp << SFE_IPV4_DSCP_SHIFT;
Xiaoping Fane1963d42015-08-25 17:06:19 -07001335 original_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_DSCP_REMARK;
1336 }
Ratheesh Kannoth71fc51e2022-01-05 10:02:47 +05301337 if (msg->rule_flags & SFE_RULE_CREATE_FLAG_BRIDGE_FLOW) {
1338 original_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_BRIDGE_FLOW;
1339 }
Ken Zhu7e38d1a2021-11-30 17:31:46 -08001340 if (msg->rule_flags & SFE_RULE_CREATE_FLAG_FLOW_TRANSMIT_FAST) {
1341 original_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_FAST_XMIT_DEV_ADMISSION;
1342 }
Ratheesh Kannoth71fc51e2022-01-05 10:02:47 +05301343
Wayne Tanbb7f1782021-12-13 11:16:04 -08001344 /*
Parikshit Guned31a8202022-01-05 22:15:04 +05301345 * Mark SAWF metadata if the sawf tag is valid and set.
1346 */
1347 original_cm->sawf_valid = false;
1348 flow_sawf_tag = SFE_GET_SAWF_TAG(msg->sawf_rule.flow_mark);
1349 if (likely(SFE_SAWF_TAG_IS_VALID(flow_sawf_tag))) {
1350 original_cm->mark = msg->sawf_rule.flow_mark;
1351 original_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_MARK;
1352 original_cm->sawf_valid = true;
1353 }
1354
1355 /*
Wayne Tanbb7f1782021-12-13 11:16:04 -08001356 * Add VLAN rule to original_cm
1357 */
1358 if (msg->valid_flags & SFE_RULE_CREATE_VLAN_VALID) {
1359 struct sfe_vlan_rule *vlan_primary_rule = &msg->vlan_primary_rule;
1360 struct sfe_vlan_rule *vlan_secondary_rule = &msg->vlan_secondary_rule;
1361 sfe_ipv4_match_entry_set_vlan(original_cm,
1362 vlan_primary_rule->ingress_vlan_tag,
1363 vlan_primary_rule->egress_vlan_tag,
1364 vlan_secondary_rule->ingress_vlan_tag,
1365 vlan_secondary_rule->egress_vlan_tag);
1366
1367 if ((msg->rule_flags & SFE_RULE_CREATE_FLAG_USE_RETURN_BOTTOM_INTERFACE) &&
1368 original_cm->egress_vlan_hdr_cnt > 0) {
1369 original_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_INSERT_EGRESS_VLAN_TAG;
1370 original_cm->l2_hdr_size += original_cm->egress_vlan_hdr_cnt * VLAN_HLEN;
1371 }
1372 }
1373
Nitin Shettye6ed5b52021-12-27 14:50:11 +05301374 if ((IPPROTO_GRE == tuple->protocol) && !sfe_ipv4_is_local_ip(si, original_cm->match_dest_ip)) {
1375 original_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_PASSTHROUGH;
1376 }
1377
Xiaoping Fand1dc7b22015-01-23 00:43:56 -08001378#ifdef CONFIG_NF_FLOW_COOKIE
1379 original_cm->flow_cookie = 0;
1380#endif
Zhi Chen8748eb32015-06-18 12:58:48 -07001381#ifdef CONFIG_XFRM
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301382 if (msg->valid_flags & SFE_RULE_CREATE_DIRECTION_VALID) {
1383 original_cm->flow_accel = msg->direction_rule.flow_accel;
1384 } else {
1385 original_cm->flow_accel = 1;
1386 }
Zhi Chen8748eb32015-06-18 12:58:48 -07001387#endif
Tian Yangd98d91b2022-03-09 14:50:12 -08001388
Ratheesh Kannotha3cf0e02021-12-09 09:44:10 +05301389 /*
1390 * If l2_features are disabled and flow uses l2 features such as macvlan/bridge/pppoe/vlan,
1391 * bottom interfaces are expected to be disabled in the flow rule and always top interfaces
1392 * are used. In such cases, do not use HW csum offload. csum offload is used only when we
1393 * are sending directly to the destination interface that supports it.
1394 */
Nitin Shettye6ed5b52021-12-27 14:50:11 +05301395 if (likely(dest_dev->features & NETIF_F_HW_CSUM) && sfe_dev_has_hw_csum(dest_dev)) {
Ratheesh Kannotha3cf0e02021-12-09 09:44:10 +05301396 if ((msg->conn_rule.return_top_interface_num == msg->conn_rule.return_interface_num) ||
1397 (msg->rule_flags & SFE_RULE_CREATE_FLAG_USE_RETURN_BOTTOM_INTERFACE)) {
Ratheesh Kannoth48445532022-02-07 16:19:00 +05301398
1399 /*
1400 * Dont enable CSUM offload
1401 */
1402#if 0
Suruchi Sumanf2077182022-01-13 21:35:23 +05301403 original_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_CSUM_OFFLOAD;
Ratheesh Kannoth48445532022-02-07 16:19:00 +05301404#endif
Ratheesh Kannotha3cf0e02021-12-09 09:44:10 +05301405 }
1406 }
Matthew McClintockdb5ac512014-01-16 17:01:40 -06001407
Murat Sezgin9c538972022-05-17 13:33:17 -07001408 if (msg->rule_flags & SFE_RULE_CREATE_FLAG_FLOW_SRC_INTERFACE_CHECK) {
Ratheesh Kannoth5dee3772022-01-18 11:27:14 +05301409 original_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_SRC_INTERFACE_CHECK;
1410 }
1411
Murat Sezgin9c538972022-05-17 13:33:17 -07001412 if (msg->rule_flags & SFE_RULE_CREATE_FLAG_FLOW_SRC_INTERFACE_CHECK_NO_FLUSH) {
1413 original_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_SRC_INTERFACE_CHECK_NO_FLUSH;
1414 }
1415
Matthew McClintockdb5ac512014-01-16 17:01:40 -06001416 /*
Guduri Prathyushaeb31c902021-11-10 20:18:50 +05301417 * Adding PPPoE parameters to original and reply entries based on the direction where
1418 * PPPoE header is valid in ECM rule.
1419 *
1420 * If PPPoE is valid in flow direction (from interface is PPPoE), then
1421 * original cm will have PPPoE at ingress (strip PPPoE header)
1422 * reply cm will have PPPoE at egress (add PPPoE header)
1423 *
1424 * If PPPoE is valid in return direction (to interface is PPPoE), then
1425 * original cm will have PPPoE at egress (add PPPoE header)
1426 * reply cm will have PPPoE at ingress (strip PPPoE header)
1427 */
1428 if (msg->valid_flags & SFE_RULE_CREATE_PPPOE_DECAP_VALID) {
1429 original_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_PPPOE_DECAP;
1430 original_cm->pppoe_session_id = msg->pppoe_rule.flow_pppoe_session_id;
1431 ether_addr_copy(original_cm->pppoe_remote_mac, msg->pppoe_rule.flow_pppoe_remote_mac);
1432
1433 reply_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_PPPOE_ENCAP;
Wayne Tan1cabbf12022-05-01 13:01:45 -07001434 reply_cm->l2_hdr_size += PPPOE_SES_HLEN;
Guduri Prathyushaeb31c902021-11-10 20:18:50 +05301435 reply_cm->pppoe_session_id = msg->pppoe_rule.flow_pppoe_session_id;
1436 ether_addr_copy(reply_cm->pppoe_remote_mac, msg->pppoe_rule.flow_pppoe_remote_mac);
1437 }
1438
1439 if (msg->valid_flags & SFE_RULE_CREATE_PPPOE_ENCAP_VALID) {
1440 original_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_PPPOE_ENCAP;
Wayne Tan1cabbf12022-05-01 13:01:45 -07001441 original_cm->l2_hdr_size += PPPOE_SES_HLEN;
Guduri Prathyushaeb31c902021-11-10 20:18:50 +05301442 original_cm->pppoe_session_id = msg->pppoe_rule.return_pppoe_session_id;
1443 ether_addr_copy(original_cm->pppoe_remote_mac, msg->pppoe_rule.return_pppoe_remote_mac);
1444
1445 reply_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_PPPOE_DECAP;
1446 reply_cm->pppoe_session_id = msg->pppoe_rule.return_pppoe_session_id;
1447 ether_addr_copy(reply_cm->pppoe_remote_mac, msg->pppoe_rule.return_pppoe_remote_mac);
1448 }
1449
Murat Sezgin9c538972022-05-17 13:33:17 -07001450 if (msg->rule_flags & SFE_RULE_CREATE_FLAG_RETURN_SRC_INTERFACE_CHECK) {
Ratheesh Kannoth5dee3772022-01-18 11:27:14 +05301451 reply_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_SRC_INTERFACE_CHECK;
1452 }
1453
Murat Sezgin9c538972022-05-17 13:33:17 -07001454 if (msg->rule_flags & SFE_RULE_CREATE_FLAG_RETURN_SRC_INTERFACE_CHECK_NO_FLUSH) {
1455 reply_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_SRC_INTERFACE_CHECK_NO_FLUSH;
1456 }
1457
Guduri Prathyushaeb31c902021-11-10 20:18:50 +05301458 /*
Ken Zhubbf49652021-09-12 15:33:09 -07001459 * For the non-arp interface, we don't write L2 HDR.
Matthew McClintockdb5ac512014-01-16 17:01:40 -06001460 */
Guduri Prathyusha79a5fee2021-11-11 17:59:10 +05301461 if (sfe_ipv4_xmit_eth_type_check(dest_dev, original_cm->flags)) {
Ratheesh Kannoth29140aa2021-10-20 08:25:02 +05301462
1463 /*
1464 * Check whether the rule has configured a specific source MAC address to use.
1465 * This is needed when virtual L3 interfaces such as br-lan, macvlan, vlan are used during egress
1466 */
Ratheesh Kannoth71fc51e2022-01-05 10:02:47 +05301467
1468 if (msg->rule_flags & SFE_RULE_CREATE_FLAG_BRIDGE_FLOW) {
1469 ether_addr_copy((u8 *)original_cm->xmit_src_mac, (u8 *)msg->conn_rule.flow_mac);
Ratheesh Kannoth29140aa2021-10-20 08:25:02 +05301470 } else {
Ratheesh Kannoth71fc51e2022-01-05 10:02:47 +05301471 if ((msg->valid_flags & SFE_RULE_CREATE_SRC_MAC_VALID) &&
1472 (msg->src_mac_rule.mac_valid_flags & SFE_SRC_MAC_RETURN_VALID)) {
1473 ether_addr_copy((u8 *)original_cm->xmit_src_mac, (u8 *)msg->src_mac_rule.return_src_mac);
1474 } else {
1475 ether_addr_copy((u8 *)original_cm->xmit_src_mac, (u8 *)dest_dev->dev_addr);
1476 }
Ratheesh Kannoth29140aa2021-10-20 08:25:02 +05301477 }
1478
1479 ether_addr_copy((u8 *)original_cm->xmit_dest_mac, (u8 *)msg->conn_rule.return_mac);
1480
Matthew McClintockdb5ac512014-01-16 17:01:40 -06001481 original_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_WRITE_L2_HDR;
Wayne Tanbb7f1782021-12-13 11:16:04 -08001482 original_cm->l2_hdr_size += ETH_HLEN;
Matthew McClintockdb5ac512014-01-16 17:01:40 -06001483
1484 /*
1485 * If our dev writes Ethernet headers then we can write a really fast
1486 * version.
1487 */
1488 if (dest_dev->header_ops) {
1489 if (dest_dev->header_ops->create == eth_header) {
1490 original_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_WRITE_FAST_ETH_HDR;
1491 }
1492 }
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001493 }
1494
1495 /*
1496 * Fill in the "reply" direction connection matching object.
1497 */
Matthew McClintockdb5ac512014-01-16 17:01:40 -06001498 reply_cm->match_dev = dest_dev;
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301499 reply_cm->match_protocol = tuple->protocol;
1500 reply_cm->match_src_ip = msg->conn_rule.return_ip_xlate;
Amitesh Anand63be37d2021-12-24 20:51:48 +05301501
1502 /*
1503 * Keep source port as 0 for VxLAN tunnels.
1504 */
1505 if (netif_is_vxlan(src_dev) || netif_is_vxlan(dest_dev)) {
1506 reply_cm->match_src_port = 0;
1507 } else {
1508 reply_cm->match_src_port = msg->conn_rule.return_ident_xlate;
1509 }
1510
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301511 reply_cm->match_dest_ip = msg->conn_rule.flow_ip_xlate;
1512 reply_cm->match_dest_port = msg->conn_rule.flow_ident_xlate;
1513
1514 reply_cm->xlate_src_ip = tuple->return_ip;
1515 reply_cm->xlate_src_port = tuple->return_ident;
1516 reply_cm->xlate_dest_ip = tuple->flow_ip;
Nitin Shettye6ed5b52021-12-27 14:50:11 +05301517 reply_cm->xlate_dest_port = tuple->flow_ident;
1518
1519 if (tuple->protocol == IPPROTO_GRE) {
1520 /*
1521 * the PPTP is 4 tuple lookup.
1522 * During th rule lookup destination call id from packet
1523 * is matched against destination port in cm.
1524 */
1525 reply_cm->match_src_port = 0;
1526 reply_cm->xlate_src_port = 0;
1527 }
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05301528
Matthew McClintockdb5ac512014-01-16 17:01:40 -06001529 reply_cm->xmit_dev = src_dev;
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301530 reply_cm->xmit_dev_mtu = msg->conn_rule.flow_mtu;
Ratheesh Kannoth29140aa2021-10-20 08:25:02 +05301531
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001532 reply_cm->connection = c;
1533 reply_cm->counter_match = original_cm;
Ken Zhu37040ea2021-09-09 21:11:15 -07001534
Ken Zhu37040ea2021-09-09 21:11:15 -07001535 if (msg->valid_flags & SFE_RULE_CREATE_MARK_VALID) {
1536 reply_cm->mark = msg->mark_rule.return_mark;
1537 reply_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_MARK;
1538 }
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301539 if (msg->valid_flags & SFE_RULE_CREATE_QOS_VALID) {
1540 reply_cm->priority = msg->qos_rule.return_qos_tag;
Xiaoping Fane1963d42015-08-25 17:06:19 -07001541 reply_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_PRIORITY_REMARK;
1542 }
Wayne Tanbb7f1782021-12-13 11:16:04 -08001543
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301544 if (msg->valid_flags & SFE_RULE_CREATE_DSCP_MARKING_VALID) {
1545 reply_cm->dscp = msg->dscp_rule.return_dscp << SFE_IPV4_DSCP_SHIFT;
Xiaoping Fane1963d42015-08-25 17:06:19 -07001546 reply_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_DSCP_REMARK;
1547 }
Ratheesh Kannoth71fc51e2022-01-05 10:02:47 +05301548 if (msg->rule_flags & SFE_RULE_CREATE_FLAG_BRIDGE_FLOW) {
1549 reply_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_BRIDGE_FLOW;
1550 }
Ken Zhu7e38d1a2021-11-30 17:31:46 -08001551 if (msg->rule_flags & SFE_RULE_CREATE_FLAG_RETURN_TRANSMIT_FAST) {
1552 reply_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_FAST_XMIT_DEV_ADMISSION;
1553 }
Ratheesh Kannoth71fc51e2022-01-05 10:02:47 +05301554
Nitin Shettye6ed5b52021-12-27 14:50:11 +05301555 if ((IPPROTO_GRE == tuple->protocol) && !sfe_ipv4_is_local_ip(si, reply_cm->match_dest_ip)) {
1556 reply_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_PASSTHROUGH;
1557 }
1558
Amitesh Anand63be37d2021-12-24 20:51:48 +05301559 /*
Parikshit Guned31a8202022-01-05 22:15:04 +05301560 * Mark SAWF metadata in reply match if the sawf tag is valid.
1561 */
1562 reply_cm->sawf_valid = false;
1563 return_sawf_tag = SFE_GET_SAWF_TAG(msg->sawf_rule.return_mark);
1564 if (likely(SFE_SAWF_TAG_IS_VALID(return_sawf_tag))) {
1565 reply_cm->mark = msg->sawf_rule.return_mark;
1566 reply_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_MARK;
1567 reply_cm->sawf_valid = true;
1568 }
1569
1570 /*
Amitesh Anand63be37d2021-12-24 20:51:48 +05301571 * Setup UDP Socket if found to be valid for decap.
1572 */
1573 RCU_INIT_POINTER(reply_cm->up, NULL);
1574 net = dev_net(reply_cm->match_dev);
1575 src_if_idx = src_dev->ifindex;
1576
1577 rcu_read_lock();
1578
1579 /*
1580 * Look for the associated sock object.
1581 * __udp4_lib_lookup() holds a reference for this sock object,
1582 * which will be released in sfe_ipv4_free_connection_rcu()
1583 */
1584#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0))
1585 sk = __udp4_lib_lookup(net, reply_cm->match_dest_ip, reply_cm->match_dest_port,
1586 reply_cm->xlate_src_ip, reply_cm->xlate_src_port, src_if_idx, &udp_table);
1587#else
1588 sk = __udp4_lib_lookup(net, reply_cm->match_dest_ip, reply_cm->match_dest_port,
1589 reply_cm->xlate_src_ip, reply_cm->xlate_src_port, src_if_idx, 0, &udp_table, NULL);
1590#endif
1591
1592 rcu_read_unlock();
1593
1594 /*
1595 * We set the UDP sock pointer as valid only for decap direction.
1596 */
1597 if (sk && udp_sk(sk)->encap_type) {
1598#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0))
1599 if (!atomic_add_unless(&sk->sk_refcnt, 1, 0)) {
1600#else
1601 if (!refcount_inc_not_zero(&sk->sk_refcnt)) {
1602#endif
Nitin Shetty9ab15622022-04-11 08:04:06 +05301603 this_cpu_inc(si->stats_pcpu->connection_create_failures64);
Wayne Tanbb7f1782021-12-13 11:16:04 -08001604 spin_unlock_bh(&si->lock);
Amitesh Anand63be37d2021-12-24 20:51:48 +05301605 kfree(reply_cm);
1606 kfree(original_cm);
1607 kfree(c);
1608
1609 DEBUG_TRACE("%px: sfe: unable to take reference for socket(%px) p:%d\n"
1610 " s: %s:%pM:%pI4:%u, d: %s:%pM:%pI4:%u\n",
1611 msg, sk, tuple->protocol,
1612 src_dev->name, msg->conn_rule.flow_mac, &tuple->flow_ip, ntohs(tuple->flow_ident),
1613 dest_dev->name, msg->conn_rule.return_mac, &tuple->return_ip, ntohs(tuple->return_ident));
1614
1615 dev_put(src_dev);
1616 dev_put(dest_dev);
1617
1618 return -ESHUTDOWN;
1619 }
1620
1621 rcu_assign_pointer(reply_cm->up, udp_sk(sk));
1622
1623 DEBUG_INFO("%px: Sock(%px) lookup success with reply_cm direction\n", msg, sk);
1624 DEBUG_INFO("%px: SFE connection -\n"
1625 " s: %s:%pI4(%pI4):%u(%u)\n"
1626 " d: %s:%pI4(%pI4):%u(%u)\n",
1627 msg, reply_cm->match_dev->name, &reply_cm->match_src_ip, &reply_cm->xlate_src_ip,
1628 ntohs(reply_cm->match_src_port), ntohs(reply_cm->xlate_src_port),
1629 reply_cm->xmit_dev->name, &reply_cm->match_dest_ip, &reply_cm->xlate_dest_ip,
1630 ntohs(reply_cm->match_dest_port), ntohs(reply_cm->xlate_dest_port));
1631 }
1632
Wayne Tanbb7f1782021-12-13 11:16:04 -08001633 /*
1634 * Add VLAN rule to reply_cm
1635 */
1636 if (msg->valid_flags & SFE_RULE_CREATE_VLAN_VALID) {
1637 struct sfe_vlan_rule *vlan_primary_rule = &msg->vlan_primary_rule;
1638 struct sfe_vlan_rule *vlan_secondary_rule = &msg->vlan_secondary_rule;
1639 sfe_ipv4_match_entry_set_vlan(reply_cm,
1640 vlan_primary_rule->egress_vlan_tag,
1641 vlan_primary_rule->ingress_vlan_tag,
1642 vlan_secondary_rule->egress_vlan_tag,
1643 vlan_secondary_rule->ingress_vlan_tag);
1644
1645 if ((msg->rule_flags & SFE_RULE_CREATE_FLAG_USE_FLOW_BOTTOM_INTERFACE) &&
1646 reply_cm->egress_vlan_hdr_cnt > 0) {
1647 reply_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_INSERT_EGRESS_VLAN_TAG;
1648 reply_cm->l2_hdr_size += reply_cm->egress_vlan_hdr_cnt * VLAN_HLEN;
1649 }
1650 }
1651
Nitin Shettye6ed5b52021-12-27 14:50:11 +05301652 /*
1653 * the net_protocol handler will be used only in decap path
1654 * for non passthrough case.
1655 */
1656 original_cm->proto = NULL;
1657 reply_cm->proto = NULL;
Tian Yang46d6eb02022-03-31 10:26:16 -07001658 original_cm->top_interface_dev = NULL;
1659 reply_cm->top_interface_dev = NULL;
Nitin Shettye6ed5b52021-12-27 14:50:11 +05301660
1661#ifdef SFE_GRE_TUN_ENABLE
1662 if ((IPPROTO_GRE == tuple->protocol) && !(reply_cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_PASSTHROUGH)) {
1663 rcu_read_lock();
1664 reply_cm->proto = rcu_dereference(inet_protos[IPPROTO_GRE]);
1665 rcu_read_unlock();
1666
1667 if (unlikely(!reply_cm->proto)) {
Nitin Shetty9ab15622022-04-11 08:04:06 +05301668 this_cpu_inc(si->stats_pcpu->connection_create_failures64);
1669 spin_unlock_bh(&si->lock);
Nitin Shettye6ed5b52021-12-27 14:50:11 +05301670 kfree(reply_cm);
1671 kfree(original_cm);
1672 kfree(c);
1673 dev_put(src_dev);
1674 dev_put(dest_dev);
1675 DEBUG_WARN("sfe: GRE proto handler is not registered\n");
1676 return -EPERM;
1677 }
1678 }
1679#endif
1680
Tian Yangd98d91b2022-03-09 14:50:12 -08001681 if (IPPROTO_IPV6 == tuple->protocol) {
1682 original_cm->proto = NULL;
1683 rcu_read_lock();
1684 reply_cm->proto = rcu_dereference(inet_protos[IPPROTO_IPV6]);
1685 rcu_read_unlock();
Tian Yang46d6eb02022-03-31 10:26:16 -07001686 reply_cm->top_interface_dev = dev_get_by_index(&init_net, msg->conn_rule.return_top_interface_num);
1687
1688 if (unlikely(!reply_cm->top_interface_dev)) {
1689 DEBUG_WARN("%px: Unable to find top_interface_dev corresponding to %d\n", msg,
1690 msg->conn_rule.return_top_interface_num);
1691 this_cpu_inc(si->stats_pcpu->connection_create_failures64);
1692 spin_unlock_bh(&si->lock);
1693 kfree(reply_cm);
1694 kfree(original_cm);
1695 kfree(c);
1696 dev_put(src_dev);
1697 dev_put(dest_dev);
1698 return -EINVAL;
1699 }
Tian Yangd98d91b2022-03-09 14:50:12 -08001700 }
1701
Xiaoping Fand1dc7b22015-01-23 00:43:56 -08001702#ifdef CONFIG_NF_FLOW_COOKIE
1703 reply_cm->flow_cookie = 0;
1704#endif
Zhi Chen8748eb32015-06-18 12:58:48 -07001705#ifdef CONFIG_XFRM
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301706 if (msg->valid_flags & SFE_RULE_CREATE_DIRECTION_VALID) {
1707 reply_cm->flow_accel = msg->direction_rule.return_accel;
1708 } else {
1709 reply_cm->flow_accel = 1;
1710 }
1711
Zhi Chen8748eb32015-06-18 12:58:48 -07001712#endif
Ratheesh Kannotha3cf0e02021-12-09 09:44:10 +05301713 /*
1714 * If l2_features are disabled and flow uses l2 features such as macvlan/bridge/pppoe/vlan,
1715 * bottom interfaces are expected to be disabled in the flow rule and always top interfaces
1716 * are used. In such cases, do not use HW csum offload. csum offload is used only when we
1717 * are sending directly to the destination interface that supports it.
1718 */
Nitin Shettye6ed5b52021-12-27 14:50:11 +05301719 if (likely(src_dev->features & NETIF_F_HW_CSUM) && sfe_dev_has_hw_csum(src_dev)) {
Ratheesh Kannotha3cf0e02021-12-09 09:44:10 +05301720 if ((msg->conn_rule.flow_top_interface_num == msg->conn_rule.flow_interface_num) ||
1721 (msg->rule_flags & SFE_RULE_CREATE_FLAG_USE_FLOW_BOTTOM_INTERFACE)) {
Ratheesh Kannoth48445532022-02-07 16:19:00 +05301722 /*
1723 * Dont enable CSUM offload
1724 */
1725#if 0
Ratheesh Kannotha3cf0e02021-12-09 09:44:10 +05301726 reply_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_CSUM_OFFLOAD;
Ratheesh Kannoth48445532022-02-07 16:19:00 +05301727#endif
Ratheesh Kannotha3cf0e02021-12-09 09:44:10 +05301728 }
1729 }
Matthew McClintockdb5ac512014-01-16 17:01:40 -06001730
1731 /*
Ken Zhubbf49652021-09-12 15:33:09 -07001732 * For the non-arp interface, we don't write L2 HDR.
Matthew McClintockdb5ac512014-01-16 17:01:40 -06001733 */
Guduri Prathyusha79a5fee2021-11-11 17:59:10 +05301734 if (sfe_ipv4_xmit_eth_type_check(src_dev, reply_cm->flags)) {
Ratheesh Kannoth29140aa2021-10-20 08:25:02 +05301735
1736 /*
1737 * Check whether the rule has configured a specific source MAC address to use.
1738 * This is needed when virtual L3 interfaces such as br-lan, macvlan, vlan are used during egress
1739 */
Ratheesh Kannoth71fc51e2022-01-05 10:02:47 +05301740
1741 if (msg->rule_flags & SFE_RULE_CREATE_FLAG_BRIDGE_FLOW) {
1742 ether_addr_copy((u8 *)reply_cm->xmit_src_mac, (u8 *)msg->conn_rule.return_mac);
Ratheesh Kannoth29140aa2021-10-20 08:25:02 +05301743 } else {
Ratheesh Kannoth71fc51e2022-01-05 10:02:47 +05301744 if ((msg->valid_flags & SFE_RULE_CREATE_SRC_MAC_VALID) &&
1745 (msg->src_mac_rule.mac_valid_flags & SFE_SRC_MAC_FLOW_VALID)) {
1746 ether_addr_copy((u8 *)reply_cm->xmit_src_mac, (u8 *)msg->src_mac_rule.flow_src_mac);
1747 } else {
1748 ether_addr_copy((u8 *)reply_cm->xmit_src_mac, (u8 *)src_dev->dev_addr);
1749 }
Ratheesh Kannoth29140aa2021-10-20 08:25:02 +05301750 }
Ratheesh Kannoth71fc51e2022-01-05 10:02:47 +05301751
Ratheesh Kannoth29140aa2021-10-20 08:25:02 +05301752 ether_addr_copy((u8 *)reply_cm->xmit_dest_mac, (u8 *)msg->conn_rule.flow_mac);
1753
Matthew McClintockdb5ac512014-01-16 17:01:40 -06001754 reply_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_WRITE_L2_HDR;
Wayne Tanbb7f1782021-12-13 11:16:04 -08001755 reply_cm->l2_hdr_size += ETH_HLEN;
Matthew McClintockdb5ac512014-01-16 17:01:40 -06001756
1757 /*
1758 * If our dev writes Ethernet headers then we can write a really fast
1759 * version.
1760 */
1761 if (src_dev->header_ops) {
1762 if (src_dev->header_ops->create == eth_header) {
1763 reply_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_WRITE_FAST_ETH_HDR;
1764 }
1765 }
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001766 }
1767
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301768 if ((tuple->return_ip != msg->conn_rule.return_ip_xlate) ||
1769 (tuple->return_ident != msg->conn_rule.return_ident_xlate)) {
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001770 original_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_DEST;
1771 reply_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_SRC;
1772 }
1773
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301774 if ((tuple->flow_ip != msg->conn_rule.flow_ip_xlate) ||
1775 (tuple->flow_ident != msg->conn_rule.flow_ident_xlate)) {
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001776 original_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_SRC;
1777 reply_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_DEST;
1778 }
1779
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001780 /*
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001781 * Initialize the protocol-specific information that we track.
1782 */
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301783 switch (tuple->protocol) {
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001784 case IPPROTO_TCP:
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301785 original_cm->protocol_state.tcp.win_scale = msg->tcp_rule.flow_window_scale;
1786 original_cm->protocol_state.tcp.max_win = msg->tcp_rule.flow_max_window ? msg->tcp_rule.flow_max_window : 1;
1787 original_cm->protocol_state.tcp.end = msg->tcp_rule.flow_end;
1788 original_cm->protocol_state.tcp.max_end = msg->tcp_rule.flow_max_end;
1789
1790 reply_cm->protocol_state.tcp.win_scale = msg->tcp_rule.return_window_scale;
1791 reply_cm->protocol_state.tcp.max_win = msg->tcp_rule.return_max_window ? msg->tcp_rule.return_max_window : 1;
1792 reply_cm->protocol_state.tcp.end = msg->tcp_rule.return_end;
1793 reply_cm->protocol_state.tcp.max_end = msg->tcp_rule.return_max_end;
1794
1795 if (msg->rule_flags & SFE_RULE_CREATE_FLAG_NO_SEQ_CHECK) {
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001796 original_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK;
1797 reply_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_NO_SEQ_CHECK;
1798 }
1799 break;
Wayne Tan1cabbf12022-05-01 13:01:45 -07001800
1801 case IPPROTO_RAW:
1802 /*
1803 * Set src_port to 0 to avoid hash collision in connection match lookups.
1804 */
1805 original_cm->match_src_port = 0;
1806 original_cm->xlate_src_port = 0;
1807 reply_cm->match_src_port = 0;
1808 reply_cm->xlate_src_port = 0;
1809 break;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001810 }
1811
Wayne Tanbb7f1782021-12-13 11:16:04 -08001812 /*
1813 * Fill in the ipv4_connection object.
1814 */
1815 c->protocol = tuple->protocol;
1816 c->src_ip = tuple->flow_ip;
1817 c->src_ip_xlate = msg->conn_rule.flow_ip_xlate;
1818 c->src_port = tuple->flow_ident;
1819 c->src_port_xlate = msg->conn_rule.flow_ident_xlate;
1820 c->original_dev = src_dev;
1821 c->original_match = original_cm;
1822 c->dest_ip = tuple->return_ip;
1823 c->dest_ip_xlate = msg->conn_rule.return_ip_xlate;
1824 c->dest_port = tuple->return_ident;
1825 c->dest_port_xlate = msg->conn_rule.return_ident_xlate;
1826 c->reply_dev = dest_dev;
1827 c->reply_match = reply_cm;
1828 c->debug_read_seq = 0;
1829 c->last_sync_jiffies = get_jiffies_64();
1830 c->removed = false;
1831
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001832 sfe_ipv4_connection_match_compute_translations(original_cm);
1833 sfe_ipv4_connection_match_compute_translations(reply_cm);
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05301834 sfe_ipv4_insert_connection(si, c);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001835
1836 spin_unlock_bh(&si->lock);
1837
1838 /*
1839 * We have everything we need!
1840 */
Wayne Tan1cabbf12022-05-01 13:01:45 -07001841 DEBUG_INFO("%px: NEW connection - p: %d\n"
Wayne Tanbb7f1782021-12-13 11:16:04 -08001842 "original_cm: match_dev=src_dev: %s %d %pM\n"
1843 " xmit_dev=dest_dev: %s %d %pM\n"
1844 " xmit_src_mac: %pM\n"
1845 " xmit_dest_mac: %pM\n"
1846 " flags: %x l2_hdr: %u\n"
1847 "flow_ip: %pI4:%u\n"
1848 "flow_ip_xlate: %pI4:%u\n"
1849 "flow_mac: %pM\n"
1850 "reply_cm: match_dev=dest_dev: %s %d %pM\n"
1851 " xmit_dev=src_dev: %s %d %pM\n"
1852 " xmit_src_mac: %pM\n"
1853 " xmit_dest_mac: %pM\n"
1854 " flags: %x l2_hdr: %u\n"
1855 "return_ip: %pI4:%u\n"
1856 "return_ip_xlate: %pI4:%u\n"
1857 "return_mac: %pM\n"
1858 "flags: valid=%x src_mac_valid=%x\n",
Wayne Tan1cabbf12022-05-01 13:01:45 -07001859 c, tuple->protocol,
Wayne Tanbb7f1782021-12-13 11:16:04 -08001860 original_cm->match_dev->name, original_cm->match_dev->ifindex, original_cm->match_dev->dev_addr,
1861 original_cm->xmit_dev->name, original_cm->xmit_dev->ifindex, original_cm->xmit_dev->dev_addr,
1862 original_cm->xmit_src_mac, original_cm->xmit_dest_mac, original_cm->flags, original_cm->l2_hdr_size,
1863 &tuple->flow_ip, ntohs(tuple->flow_ident),
1864 &msg->conn_rule.flow_ip_xlate, ntohs(msg->conn_rule.flow_ident_xlate),
1865 msg->conn_rule.flow_mac,
1866 reply_cm->match_dev->name, reply_cm->match_dev->ifindex, reply_cm->match_dev->dev_addr,
1867 reply_cm->xmit_dev->name, reply_cm->xmit_dev->ifindex, reply_cm->xmit_dev->dev_addr,
1868 reply_cm->xmit_src_mac, reply_cm->xmit_dest_mac, reply_cm->flags, reply_cm->l2_hdr_size,
1869 &tuple->return_ip, ntohs(tuple->return_ident),
1870 &msg->conn_rule.return_ip_xlate, ntohs(msg->conn_rule.return_ident_xlate),
1871 msg->conn_rule.return_mac,
1872 msg->valid_flags, msg->src_mac_rule.mac_valid_flags);
Nicolas Costa514fde02014-01-13 15:50:29 -06001873
1874 return 0;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001875}
1876
1877/*
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001878 * sfe_ipv4_destroy_rule()
1879 * Destroy a forwarding rule.
1880 */
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301881void sfe_ipv4_destroy_rule(struct sfe_ipv4_rule_destroy_msg *msg)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001882{
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001883 struct sfe_ipv4 *si = &__si;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001884 struct sfe_ipv4_connection *c;
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05301885 bool ret;
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301886 struct sfe_ipv4_5tuple *tuple = &msg->tuple;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001887
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +05301888 this_cpu_inc(si->stats_pcpu->connection_destroy_requests64);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001889 spin_lock_bh(&si->lock);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001890
1891 /*
1892 * Check to see if we have a flow that matches the rule we're trying
1893 * to destroy. If there isn't then we can't destroy it.
1894 */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05301895 c = sfe_ipv4_find_connection(si, tuple->protocol, tuple->flow_ip, tuple->flow_ident,
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301896 tuple->return_ip, tuple->return_ident);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001897 if (!c) {
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001898 spin_unlock_bh(&si->lock);
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +05301899 this_cpu_inc(si->stats_pcpu->connection_destroy_misses64);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001900
1901 DEBUG_TRACE("connection does not exist - p: %d, s: %pI4:%u, d: %pI4:%u\n",
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301902 tuple->protocol, &tuple->flow_ip, ntohs(tuple->flow_ident),
1903 &tuple->return_ip, ntohs(tuple->return_ident));
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001904 return;
1905 }
1906
1907 /*
1908 * Remove our connection details from the hash tables.
1909 */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05301910 ret = sfe_ipv4_remove_connection(si, c);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001911 spin_unlock_bh(&si->lock);
1912
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05301913 if (ret) {
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05301914 sfe_ipv4_flush_connection(si, c, SFE_SYNC_REASON_DESTROY);
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05301915 }
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001916
1917 DEBUG_INFO("connection destroyed - p: %d, s: %pI4:%u, d: %pI4:%u\n",
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05301918 tuple->protocol, &tuple->flow_ip, ntohs(tuple->flow_ident),
1919 &tuple->return_ip, ntohs(tuple->return_ident));
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001920}
1921
1922/*
Ken Zhu7a43d882022-01-04 10:51:44 -08001923 * sfe_ipv4_sync_invoke()
1924 * Schedule many sync stats.
1925 */
1926bool sfe_ipv4_sync_invoke(uint16_t index)
1927{
1928 struct sfe_ipv4 *si = &__si;
1929 DEBUG_INFO("Request for a sync with index[%d]\n", index);
1930 return schedule_delayed_work_on(si->work_cpu, &(si->sync_dwork), 0);
1931}
1932
1933/*
1934 * sfe_ipv4_register_sync_rule_callback()
1935 * Register a callback for many rule synchronization.
1936 */
1937void sfe_ipv4_register_many_sync_callback(sfe_ipv4_many_sync_callback_t cb)
1938{
1939 struct sfe_ipv4 *si = &__si;
1940
1941 spin_lock_bh(&si->lock);
1942 rcu_assign_pointer(si->many_sync_callback, cb);
1943 spin_unlock_bh(&si->lock);
1944}
1945
1946/*
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001947 * sfe_ipv4_register_sync_rule_callback()
1948 * Register a callback for rule synchronization.
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001949 */
Xiaoping Fand44a5b42015-05-26 17:37:37 -07001950void sfe_ipv4_register_sync_rule_callback(sfe_sync_rule_callback_t sync_rule_callback)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001951{
1952 struct sfe_ipv4 *si = &__si;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001953
1954 spin_lock_bh(&si->lock);
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001955 rcu_assign_pointer(si->sync_rule_callback, sync_rule_callback);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001956 spin_unlock_bh(&si->lock);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001957}
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001958/*
1959 * sfe_ipv4_get_debug_dev()
1960 */
1961static ssize_t sfe_ipv4_get_debug_dev(struct device *dev,
1962 struct device_attribute *attr,
1963 char *buf)
1964{
1965 struct sfe_ipv4 *si = &__si;
1966 ssize_t count;
1967 int num;
1968
1969 spin_lock_bh(&si->lock);
1970 num = si->debug_dev;
1971 spin_unlock_bh(&si->lock);
1972
1973 count = snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", num);
1974 return count;
1975}
1976
1977/*
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001978 * sysfs attributes.
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001979 */
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001980static const struct device_attribute sfe_ipv4_debug_dev_attr =
Xiaoping Fane70da412016-02-26 16:47:57 -08001981 __ATTR(debug_dev, S_IWUSR | S_IRUGO, sfe_ipv4_get_debug_dev, NULL);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001982
1983/*
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001984 * sfe_ipv4_destroy_all_rules_for_dev()
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001985 * Destroy all connections that match a particular device.
1986 *
1987 * If we pass dev as NULL then this destroys all connections.
1988 */
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001989void sfe_ipv4_destroy_all_rules_for_dev(struct net_device *dev)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001990{
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001991 struct sfe_ipv4 *si = &__si;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001992 struct sfe_ipv4_connection *c;
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05301993 bool ret;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001994
Xiaoping Fan34586472015-07-03 02:20:35 -07001995another_round:
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001996 spin_lock_bh(&si->lock);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001997
Xiaoping Fan34586472015-07-03 02:20:35 -07001998 for (c = si->all_connections_head; c; c = c->all_connections_next) {
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01001999 /*
Xiaoping Fan34586472015-07-03 02:20:35 -07002000 * Does this connection relate to the device we are destroying?
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002001 */
2002 if (!dev
2003 || (dev == c->original_dev)
2004 || (dev == c->reply_dev)) {
Xiaoping Fan34586472015-07-03 02:20:35 -07002005 break;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002006 }
Xiaoping Fan34586472015-07-03 02:20:35 -07002007 }
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002008
Xiaoping Fan34586472015-07-03 02:20:35 -07002009 if (c) {
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05302010 ret = sfe_ipv4_remove_connection(si, c);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002011 }
2012
2013 spin_unlock_bh(&si->lock);
Xiaoping Fan34586472015-07-03 02:20:35 -07002014
2015 if (c) {
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05302016 if (ret) {
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05302017 sfe_ipv4_flush_connection(si, c, SFE_SYNC_REASON_DESTROY);
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05302018 }
Xiaoping Fan34586472015-07-03 02:20:35 -07002019 goto another_round;
2020 }
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002021}
2022
2023/*
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002024 * sfe_ipv4_periodic_sync()
2025 */
Ken Zhu137722d2021-09-23 17:57:36 -07002026static void sfe_ipv4_periodic_sync(struct work_struct *work)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002027{
Ken Zhu137722d2021-09-23 17:57:36 -07002028 struct sfe_ipv4 *si = container_of((struct delayed_work *)work, struct sfe_ipv4, sync_dwork);
Xiaoping Fan6a1672f2016-08-17 19:58:12 -07002029 u64 now_jiffies;
Ken Zhu7a43d882022-01-04 10:51:44 -08002030 int quota,count;
2031 sfe_ipv4_many_sync_callback_t sync_rule_callback;
Ken Zhudc423672021-09-02 18:27:01 -07002032 struct sfe_ipv4_connection *c;
Ken Zhu7a43d882022-01-04 10:51:44 -08002033 struct sfe_ipv4_conn_sync *conn_sync;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002034
2035 now_jiffies = get_jiffies_64();
2036
Dave Hudsondcd08fb2013-11-22 09:25:16 -06002037 rcu_read_lock();
Ken Zhu7a43d882022-01-04 10:51:44 -08002038 sync_rule_callback = rcu_dereference(si->many_sync_callback);
2039 rcu_read_unlock();
Dave Hudsondcd08fb2013-11-22 09:25:16 -06002040 if (!sync_rule_callback) {
Ken Zhu7a43d882022-01-04 10:51:44 -08002041 return;
Dave Hudsondcd08fb2013-11-22 09:25:16 -06002042 }
2043
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002044 spin_lock_bh(&si->lock);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002045
2046 /*
Ken Zhudc423672021-09-02 18:27:01 -07002047 * If we have reached the end of the connection list, walk from
2048 * the connection head.
2049 */
2050 c = si->wc_next;
2051 if (unlikely(!c)) {
2052 c = si->all_connections_head;
2053 }
2054
2055 /*
Ken Zhu7a43d882022-01-04 10:51:44 -08002056 * Get the max number of connections to be put in this sync msg.
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002057 */
Ken Zhu7a43d882022-01-04 10:51:44 -08002058 quota = sfe_ipv4_sync_max_number;
2059 conn_sync = sfe_ipv4_sync_many_msg->msg.conn_stats_many.conn_sync;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002060
2061 /*
Ken Zhudc423672021-09-02 18:27:01 -07002062 * Walk the "all connection" list and sync the connection state.
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002063 */
Ken Zhudc423672021-09-02 18:27:01 -07002064 while (likely(c && quota)) {
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002065 struct sfe_ipv4_connection_match *cm;
2066 struct sfe_ipv4_connection_match *counter_cm;
Xiaoping Fand44a5b42015-05-26 17:37:37 -07002067 struct sfe_connection_sync sis;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002068
Ken Zhudc423672021-09-02 18:27:01 -07002069 cm = c->original_match;
2070 counter_cm = c->reply_match;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002071
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002072 /*
Ken Zhudc423672021-09-02 18:27:01 -07002073 * Didn't receive packets in the original direction or reply
2074 * direction, move to the next connection.
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002075 */
Ken Zhudc423672021-09-02 18:27:01 -07002076 if ((!atomic_read(&cm->rx_packet_count)) && !(atomic_read(&counter_cm->rx_packet_count))) {
2077 c = c->all_connections_next;
2078 continue;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002079 }
2080
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05302081 sfe_ipv4_gen_sync_connection(si, c, &sis, SFE_SYNC_REASON_STATS, now_jiffies);
Ken Zhu7a43d882022-01-04 10:51:44 -08002082 sfe_ipv4_stats_convert(conn_sync, &sis);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002083
Ken Zhu7a43d882022-01-04 10:51:44 -08002084 quota--;
2085 conn_sync++;
2086 c = c->all_connections_next;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002087 }
2088
Ken Zhudc423672021-09-02 18:27:01 -07002089 /*
2090 * At the end of the sync, put the wc_next to the connection we left.
2091 */
2092 si->wc_next = c;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002093 spin_unlock_bh(&si->lock);
2094
Ken Zhu7a43d882022-01-04 10:51:44 -08002095 count = sfe_ipv4_sync_max_number - quota;
2096 /*
2097 * Tell ecm sync round done if at the end of all connection
2098 * otherwise tell the number in the msg.
2099 */
2100 if (c == NULL) {
2101 DEBUG_INFO("Synced all connections.\n");
2102 sfe_ipv4_sync_many_msg->msg.conn_stats_many.next = 0;
2103 } else {
2104 DEBUG_INFO("Some connections left.\n");
2105 sfe_ipv4_sync_many_msg->msg.conn_stats_many.next = count;
2106 }
2107 DEBUG_INFO("Sync %d connections\n", count);
2108 sfe_ipv4_sync_many_msg->msg.conn_stats_many.count = count;
2109 sfe_ipv4_sync_many_msg->cm.response = SFE_CMN_RESPONSE_ACK;
2110
2111 sync_rule_callback(sfe_ipv4_sync_many_msg);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002112}
2113
2114#define CHAR_DEV_MSG_SIZE 768
2115
2116/*
2117 * sfe_ipv4_debug_dev_read_start()
2118 * Generate part of the XML output.
2119 */
2120static bool sfe_ipv4_debug_dev_read_start(struct sfe_ipv4 *si, char *buffer, char *msg, size_t *length,
Ken Zhu7a43d882022-01-04 10:51:44 -08002121 int *total_read, struct sfe_ipv4_debug_xml_write_state *ws)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002122{
2123 int bytes_read;
2124
Xiaoping Fan34586472015-07-03 02:20:35 -07002125 si->debug_read_seq++;
2126
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002127 bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "<sfe_ipv4>\n");
2128 if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) {
2129 return false;
2130 }
2131
2132 *length -= bytes_read;
2133 *total_read += bytes_read;
2134
2135 ws->state++;
2136 return true;
2137}
2138
2139/*
2140 * sfe_ipv4_debug_dev_read_connections_start()
2141 * Generate part of the XML output.
2142 */
2143static bool sfe_ipv4_debug_dev_read_connections_start(struct sfe_ipv4 *si, char *buffer, char *msg, size_t *length,
2144 int *total_read, struct sfe_ipv4_debug_xml_write_state *ws)
2145{
2146 int bytes_read;
2147
2148 bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t<connections>\n");
2149 if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) {
2150 return false;
2151 }
2152
2153 *length -= bytes_read;
2154 *total_read += bytes_read;
2155
2156 ws->state++;
2157 return true;
2158}
2159
2160/*
2161 * sfe_ipv4_debug_dev_read_connections_connection()
2162 * Generate part of the XML output.
2163 */
2164static bool sfe_ipv4_debug_dev_read_connections_connection(struct sfe_ipv4 *si, char *buffer, char *msg, size_t *length,
2165 int *total_read, struct sfe_ipv4_debug_xml_write_state *ws)
2166{
2167 struct sfe_ipv4_connection *c;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002168 struct sfe_ipv4_connection_match *original_cm;
2169 struct sfe_ipv4_connection_match *reply_cm;
2170 int bytes_read;
2171 int protocol;
2172 struct net_device *src_dev;
Dave Hudson87973cd2013-10-22 16:00:04 +01002173 __be32 src_ip;
2174 __be32 src_ip_xlate;
2175 __be16 src_port;
2176 __be16 src_port_xlate;
Xiaoping Fan6a1672f2016-08-17 19:58:12 -07002177 u64 src_rx_packets;
2178 u64 src_rx_bytes;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002179 struct net_device *dest_dev;
Dave Hudson87973cd2013-10-22 16:00:04 +01002180 __be32 dest_ip;
2181 __be32 dest_ip_xlate;
2182 __be16 dest_port;
2183 __be16 dest_port_xlate;
Xiaoping Fan6a1672f2016-08-17 19:58:12 -07002184 u64 dest_rx_packets;
2185 u64 dest_rx_bytes;
2186 u64 last_sync_jiffies;
Ken Zhu37040ea2021-09-09 21:11:15 -07002187 u32 src_mark, dest_mark, src_priority, dest_priority, src_dscp, dest_dscp;
Parikshit Guned31a8202022-01-05 22:15:04 +05302188 bool original_cm_sawf_valid, reply_cm_sawf_valid;
2189 u32 flow_service_class, return_service_class;
2190 u32 flow_msduq, return_msduq;
Guduri Prathyushaeb31c902021-11-10 20:18:50 +05302191 u32 packet, byte, original_cm_flags;
2192 u16 pppoe_session_id;
2193 u8 pppoe_remote_mac[ETH_ALEN];
Ken Zhu7e38d1a2021-11-30 17:31:46 -08002194 u32 original_fast_xmit, reply_fast_xmit;
Xiaoping Fand1dc7b22015-01-23 00:43:56 -08002195#ifdef CONFIG_NF_FLOW_COOKIE
2196 int src_flow_cookie, dst_flow_cookie;
2197#endif
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002198
2199 spin_lock_bh(&si->lock);
Xiaoping Fan34586472015-07-03 02:20:35 -07002200
2201 for (c = si->all_connections_head; c; c = c->all_connections_next) {
2202 if (c->debug_read_seq < si->debug_read_seq) {
2203 c->debug_read_seq = si->debug_read_seq;
2204 break;
2205 }
2206 }
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002207
2208 /*
Xiaoping Fan34586472015-07-03 02:20:35 -07002209 * If there were no connections then move to the next state.
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002210 */
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05302211 if (!c || c->removed) {
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002212 spin_unlock_bh(&si->lock);
Xiaoping Fan34586472015-07-03 02:20:35 -07002213 ws->state++;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002214 return true;
2215 }
2216
2217 original_cm = c->original_match;
2218 reply_cm = c->reply_match;
2219
2220 protocol = c->protocol;
2221 src_dev = c->original_dev;
2222 src_ip = c->src_ip;
2223 src_ip_xlate = c->src_ip_xlate;
2224 src_port = c->src_port;
2225 src_port_xlate = c->src_port_xlate;
Xiaoping Fane1963d42015-08-25 17:06:19 -07002226 src_priority = original_cm->priority;
2227 src_dscp = original_cm->dscp >> SFE_IPV4_DSCP_SHIFT;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002228
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05302229 sfe_ipv4_connection_match_update_summary_stats(original_cm, &packet, &byte);
2230 sfe_ipv4_connection_match_update_summary_stats(reply_cm, &packet, &byte);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002231
2232 src_rx_packets = original_cm->rx_packet_count64;
2233 src_rx_bytes = original_cm->rx_byte_count64;
Ken Zhu37040ea2021-09-09 21:11:15 -07002234 src_mark = original_cm->mark;
Ken Zhu7e38d1a2021-11-30 17:31:46 -08002235 original_fast_xmit = (original_cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_FAST_XMIT);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002236 dest_dev = c->reply_dev;
2237 dest_ip = c->dest_ip;
2238 dest_ip_xlate = c->dest_ip_xlate;
2239 dest_port = c->dest_port;
2240 dest_port_xlate = c->dest_port_xlate;
Xiaoping Fane1963d42015-08-25 17:06:19 -07002241 dest_priority = reply_cm->priority;
2242 dest_dscp = reply_cm->dscp >> SFE_IPV4_DSCP_SHIFT;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002243 dest_rx_packets = reply_cm->rx_packet_count64;
2244 dest_rx_bytes = reply_cm->rx_byte_count64;
Ken Zhu37040ea2021-09-09 21:11:15 -07002245 dest_mark = reply_cm->mark;
Ken Zhu7e38d1a2021-11-30 17:31:46 -08002246 reply_fast_xmit = (reply_cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_FAST_XMIT);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002247 last_sync_jiffies = get_jiffies_64() - c->last_sync_jiffies;
Guduri Prathyushaeb31c902021-11-10 20:18:50 +05302248 original_cm_flags = original_cm->flags;
2249 pppoe_session_id = original_cm->pppoe_session_id;
2250 ether_addr_copy(pppoe_remote_mac, original_cm->pppoe_remote_mac);
Parikshit Guned31a8202022-01-05 22:15:04 +05302251 original_cm_sawf_valid = original_cm->sawf_valid;
2252 reply_cm_sawf_valid = reply_cm->sawf_valid;
2253 flow_service_class = SFE_GET_SAWF_SERVICE_CLASS(original_cm->mark);
2254 flow_msduq = SFE_GET_SAWF_MSDUQ(original_cm->mark);
2255 return_service_class = SFE_GET_SAWF_SERVICE_CLASS(reply_cm->mark);
2256 return_msduq = SFE_GET_SAWF_MSDUQ(reply_cm->mark);
Xiaoping Fand1dc7b22015-01-23 00:43:56 -08002257#ifdef CONFIG_NF_FLOW_COOKIE
2258 src_flow_cookie = original_cm->flow_cookie;
2259 dst_flow_cookie = reply_cm->flow_cookie;
2260#endif
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002261 spin_unlock_bh(&si->lock);
2262
2263 bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t\t<connection "
2264 "protocol=\"%u\" "
2265 "src_dev=\"%s\" "
2266 "src_ip=\"%pI4\" src_ip_xlate=\"%pI4\" "
2267 "src_port=\"%u\" src_port_xlate=\"%u\" "
Xiaoping Fane1963d42015-08-25 17:06:19 -07002268 "src_priority=\"%u\" src_dscp=\"%u\" "
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002269 "src_rx_pkts=\"%llu\" src_rx_bytes=\"%llu\" "
Ken Zhu37040ea2021-09-09 21:11:15 -07002270 "src_mark=\"%08x\" "
Ken Zhu7e38d1a2021-11-30 17:31:46 -08002271 "src_fast_xmit=\"%s\" "
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002272 "dest_dev=\"%s\" "
2273 "dest_ip=\"%pI4\" dest_ip_xlate=\"%pI4\" "
2274 "dest_port=\"%u\" dest_port_xlate=\"%u\" "
Xiaoping Fane1963d42015-08-25 17:06:19 -07002275 "dest_priority=\"%u\" dest_dscp=\"%u\" "
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002276 "dest_rx_pkts=\"%llu\" dest_rx_bytes=\"%llu\" "
Ken Zhu37040ea2021-09-09 21:11:15 -07002277 "dest_mark=\"%08x\" "
Ken Zhu7e38d1a2021-11-30 17:31:46 -08002278 "reply_fast_xmit=\"%s\" "
Xiaoping Fand1dc7b22015-01-23 00:43:56 -08002279#ifdef CONFIG_NF_FLOW_COOKIE
2280 "src_flow_cookie=\"%d\" dst_flow_cookie=\"%d\" "
2281#endif
Ken Zhu37040ea2021-09-09 21:11:15 -07002282 "last_sync=\"%llu\" ",
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002283 protocol,
2284 src_dev->name,
2285 &src_ip, &src_ip_xlate,
Dave Hudson87973cd2013-10-22 16:00:04 +01002286 ntohs(src_port), ntohs(src_port_xlate),
Xiaoping Fane1963d42015-08-25 17:06:19 -07002287 src_priority, src_dscp,
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002288 src_rx_packets, src_rx_bytes,
Ken Zhu37040ea2021-09-09 21:11:15 -07002289 src_mark,
Ken Zhu7e38d1a2021-11-30 17:31:46 -08002290 original_fast_xmit ? "Yes" : "No",
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002291 dest_dev->name,
2292 &dest_ip, &dest_ip_xlate,
Dave Hudson87973cd2013-10-22 16:00:04 +01002293 ntohs(dest_port), ntohs(dest_port_xlate),
Xiaoping Fane1963d42015-08-25 17:06:19 -07002294 dest_priority, dest_dscp,
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002295 dest_rx_packets, dest_rx_bytes,
Ken Zhu37040ea2021-09-09 21:11:15 -07002296 dest_mark,
Ken Zhu7e38d1a2021-11-30 17:31:46 -08002297 reply_fast_xmit ? "Yes" : "No",
Xiaoping Fand1dc7b22015-01-23 00:43:56 -08002298#ifdef CONFIG_NF_FLOW_COOKIE
2299 src_flow_cookie, dst_flow_cookie,
2300#endif
Ken Zhu37040ea2021-09-09 21:11:15 -07002301 last_sync_jiffies);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002302
Guduri Prathyushaeb31c902021-11-10 20:18:50 +05302303 if (original_cm_flags &= (SFE_IPV4_CONNECTION_MATCH_FLAG_PPPOE_DECAP | SFE_IPV4_CONNECTION_MATCH_FLAG_PPPOE_ENCAP)) {
Guduri Prathyusha79a5fee2021-11-11 17:59:10 +05302304 bytes_read += snprintf(msg + bytes_read, CHAR_DEV_MSG_SIZE, "pppoe_session_id=\"%u\" pppoe_server MAC=\"%pM\" ",
Guduri Prathyushaeb31c902021-11-10 20:18:50 +05302305 pppoe_session_id, pppoe_remote_mac);
2306 }
2307
Parikshit Guned31a8202022-01-05 22:15:04 +05302308 if (original_cm_sawf_valid) {
Parikshit Gunefdd98652022-03-14 17:33:01 +05302309 bytes_read += snprintf(msg + bytes_read, CHAR_DEV_MSG_SIZE, "flow_service_class=\"%d\" flow_msduq = \"0x%x\" ",
Parikshit Guned31a8202022-01-05 22:15:04 +05302310 flow_service_class, flow_msduq);
2311 }
2312
2313 if (reply_cm_sawf_valid) {
Parikshit Gunefdd98652022-03-14 17:33:01 +05302314 bytes_read += snprintf(msg + bytes_read, CHAR_DEV_MSG_SIZE, "return_service_class=\"%d\" return_msduq = \"0x%x\" ",
Parikshit Guned31a8202022-01-05 22:15:04 +05302315 return_service_class, return_msduq);
2316 }
2317
Guduri Prathyushaeb31c902021-11-10 20:18:50 +05302318 bytes_read += snprintf(msg + bytes_read, CHAR_DEV_MSG_SIZE, "/>\n");
2319
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002320 if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) {
2321 return false;
2322 }
2323
2324 *length -= bytes_read;
2325 *total_read += bytes_read;
2326
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002327 return true;
2328}
2329
2330/*
2331 * sfe_ipv4_debug_dev_read_connections_end()
2332 * Generate part of the XML output.
2333 */
2334static bool sfe_ipv4_debug_dev_read_connections_end(struct sfe_ipv4 *si, char *buffer, char *msg, size_t *length,
2335 int *total_read, struct sfe_ipv4_debug_xml_write_state *ws)
2336{
2337 int bytes_read;
2338
2339 bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t</connections>\n");
2340 if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) {
2341 return false;
2342 }
2343
2344 *length -= bytes_read;
2345 *total_read += bytes_read;
2346
2347 ws->state++;
2348 return true;
2349}
2350
2351/*
2352 * sfe_ipv4_debug_dev_read_exceptions_start()
2353 * Generate part of the XML output.
2354 */
2355static bool sfe_ipv4_debug_dev_read_exceptions_start(struct sfe_ipv4 *si, char *buffer, char *msg, size_t *length,
2356 int *total_read, struct sfe_ipv4_debug_xml_write_state *ws)
2357{
2358 int bytes_read;
2359
2360 bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t<exceptions>\n");
2361 if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) {
2362 return false;
2363 }
2364
2365 *length -= bytes_read;
2366 *total_read += bytes_read;
2367
2368 ws->state++;
2369 return true;
2370}
2371
2372/*
2373 * sfe_ipv4_debug_dev_read_exceptions_exception()
2374 * Generate part of the XML output.
2375 */
2376static bool sfe_ipv4_debug_dev_read_exceptions_exception(struct sfe_ipv4 *si, char *buffer, char *msg, size_t *length,
2377 int *total_read, struct sfe_ipv4_debug_xml_write_state *ws)
2378{
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +05302379 int i;
2380 u64 val = 0;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002381
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +05302382 for_each_possible_cpu(i) {
2383 const struct sfe_ipv4_stats *s = per_cpu_ptr(si->stats_pcpu, i);
2384 val += s->exception_events64[ws->iter_exception];
2385 }
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002386
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +05302387 if (val) {
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002388 int bytes_read;
2389
2390 bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE,
2391 "\t\t<exception name=\"%s\" count=\"%llu\" />\n",
2392 sfe_ipv4_exception_events_string[ws->iter_exception],
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +05302393 val);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002394 if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) {
2395 return false;
2396 }
2397
2398 *length -= bytes_read;
2399 *total_read += bytes_read;
2400 }
2401
2402 ws->iter_exception++;
2403 if (ws->iter_exception >= SFE_IPV4_EXCEPTION_EVENT_LAST) {
2404 ws->iter_exception = 0;
2405 ws->state++;
2406 }
2407
2408 return true;
2409}
2410
2411/*
2412 * sfe_ipv4_debug_dev_read_exceptions_end()
2413 * Generate part of the XML output.
2414 */
2415static bool sfe_ipv4_debug_dev_read_exceptions_end(struct sfe_ipv4 *si, char *buffer, char *msg, size_t *length,
2416 int *total_read, struct sfe_ipv4_debug_xml_write_state *ws)
2417{
2418 int bytes_read;
2419
2420 bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t</exceptions>\n");
2421 if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) {
2422 return false;
2423 }
2424
2425 *length -= bytes_read;
2426 *total_read += bytes_read;
2427
2428 ws->state++;
2429 return true;
2430}
2431
2432/*
2433 * sfe_ipv4_debug_dev_read_stats()
2434 * Generate part of the XML output.
2435 */
2436static bool sfe_ipv4_debug_dev_read_stats(struct sfe_ipv4 *si, char *buffer, char *msg, size_t *length,
2437 int *total_read, struct sfe_ipv4_debug_xml_write_state *ws)
2438{
2439 int bytes_read;
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +05302440 struct sfe_ipv4_stats stats;
2441 unsigned int num_conn;
2442
2443 sfe_ipv4_update_summary_stats(si, &stats);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002444
2445 spin_lock_bh(&si->lock);
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +05302446 num_conn = si->num_connections;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002447 spin_unlock_bh(&si->lock);
2448
2449 bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "\t<stats "
2450 "num_connections=\"%u\" "
Amitesh Anand63be37d2021-12-24 20:51:48 +05302451 "pkts_dropped=\"%llu\" "
Ken Zhu7e38d1a2021-11-30 17:31:46 -08002452 "pkts_fast_xmited=\"%llu\" "
Xiaoping Fan59176422015-05-22 15:58:10 -07002453 "pkts_forwarded=\"%llu\" pkts_not_forwarded=\"%llu\" "
2454 "create_requests=\"%llu\" create_collisions=\"%llu\" "
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05302455 "create_failures=\"%llu\" "
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002456 "destroy_requests=\"%llu\" destroy_misses=\"%llu\" "
2457 "flushes=\"%llu\" "
Guduri Prathyusha647fe3e2021-11-22 19:17:51 +05302458 "hash_hits=\"%llu\" hash_reorders=\"%llu\" "
2459 "pppoe_encap_pkts_fwded=\"%llu\" "
Guduri Prathyusha034d6352022-01-12 16:49:04 +05302460 "pppoe_decap_pkts_fwded=\"%llu\" "
Wayne Tan1cabbf12022-05-01 13:01:45 -07002461 "pppoe_bridge_pkts_fwded=\"%llu\" "
2462 "pppoe_bridge_pkts_3tuple_fwded=\"%llu\" />\n",
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +05302463 num_conn,
Amitesh Anand63be37d2021-12-24 20:51:48 +05302464 stats.packets_dropped64,
Ken Zhu7e38d1a2021-11-30 17:31:46 -08002465 stats.packets_fast_xmited64,
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +05302466 stats.packets_forwarded64,
2467 stats.packets_not_forwarded64,
2468 stats.connection_create_requests64,
2469 stats.connection_create_collisions64,
Ratheesh Kannoth89302a72021-10-20 08:10:37 +05302470 stats.connection_create_failures64,
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +05302471 stats.connection_destroy_requests64,
2472 stats.connection_destroy_misses64,
2473 stats.connection_flushes64,
2474 stats.connection_match_hash_hits64,
Guduri Prathyusha647fe3e2021-11-22 19:17:51 +05302475 stats.connection_match_hash_reorders64,
2476 stats.pppoe_encap_packets_forwarded64,
Guduri Prathyusha034d6352022-01-12 16:49:04 +05302477 stats.pppoe_decap_packets_forwarded64,
Wayne Tan1cabbf12022-05-01 13:01:45 -07002478 stats.pppoe_bridge_packets_forwarded64,
2479 stats.pppoe_bridge_packets_3tuple_forwarded64);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002480 if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) {
2481 return false;
2482 }
2483
2484 *length -= bytes_read;
2485 *total_read += bytes_read;
2486
2487 ws->state++;
2488 return true;
2489}
2490
2491/*
2492 * sfe_ipv4_debug_dev_read_end()
2493 * Generate part of the XML output.
2494 */
2495static bool sfe_ipv4_debug_dev_read_end(struct sfe_ipv4 *si, char *buffer, char *msg, size_t *length,
2496 int *total_read, struct sfe_ipv4_debug_xml_write_state *ws)
2497{
2498 int bytes_read;
2499
2500 bytes_read = snprintf(msg, CHAR_DEV_MSG_SIZE, "</sfe_ipv4>\n");
2501 if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) {
2502 return false;
2503 }
2504
2505 *length -= bytes_read;
2506 *total_read += bytes_read;
2507
2508 ws->state++;
2509 return true;
2510}
2511
2512/*
2513 * Array of write functions that write various XML elements that correspond to
2514 * our XML output state machine.
2515 */
Xiaoping Fan6a1672f2016-08-17 19:58:12 -07002516static 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 +01002517 sfe_ipv4_debug_dev_read_start,
2518 sfe_ipv4_debug_dev_read_connections_start,
2519 sfe_ipv4_debug_dev_read_connections_connection,
2520 sfe_ipv4_debug_dev_read_connections_end,
2521 sfe_ipv4_debug_dev_read_exceptions_start,
2522 sfe_ipv4_debug_dev_read_exceptions_exception,
2523 sfe_ipv4_debug_dev_read_exceptions_end,
2524 sfe_ipv4_debug_dev_read_stats,
2525 sfe_ipv4_debug_dev_read_end,
2526};
2527
2528/*
2529 * sfe_ipv4_debug_dev_read()
2530 * Send info to userspace upon read request from user
2531 */
2532static ssize_t sfe_ipv4_debug_dev_read(struct file *filp, char *buffer, size_t length, loff_t *offset)
2533{
2534 char msg[CHAR_DEV_MSG_SIZE];
2535 int total_read = 0;
2536 struct sfe_ipv4_debug_xml_write_state *ws;
2537 struct sfe_ipv4 *si = &__si;
2538
2539 ws = (struct sfe_ipv4_debug_xml_write_state *)filp->private_data;
2540 while ((ws->state != SFE_IPV4_DEBUG_XML_STATE_DONE) && (length > CHAR_DEV_MSG_SIZE)) {
2541 if ((sfe_ipv4_debug_xml_write_methods[ws->state])(si, buffer, msg, &length, &total_read, ws)) {
2542 continue;
2543 }
2544 }
2545
2546 return total_read;
2547}
2548
2549/*
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002550 * sfe_ipv4_debug_dev_open()
2551 */
2552static int sfe_ipv4_debug_dev_open(struct inode *inode, struct file *file)
2553{
2554 struct sfe_ipv4_debug_xml_write_state *ws;
2555
2556 ws = (struct sfe_ipv4_debug_xml_write_state *)file->private_data;
2557 if (!ws) {
2558 ws = kzalloc(sizeof(struct sfe_ipv4_debug_xml_write_state), GFP_KERNEL);
2559 if (!ws) {
2560 return -ENOMEM;
2561 }
2562
2563 ws->state = SFE_IPV4_DEBUG_XML_STATE_START;
2564 file->private_data = ws;
2565 }
2566
2567 return 0;
2568}
2569
2570/*
2571 * sfe_ipv4_debug_dev_release()
2572 */
2573static int sfe_ipv4_debug_dev_release(struct inode *inode, struct file *file)
2574{
2575 struct sfe_ipv4_debug_xml_write_state *ws;
2576
2577 ws = (struct sfe_ipv4_debug_xml_write_state *)file->private_data;
2578 if (ws) {
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002579 /*
2580 * We've finished with our output so free the write state.
2581 */
2582 kfree(ws);
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05302583 file->private_data = NULL;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002584 }
2585
2586 return 0;
2587}
2588
2589/*
2590 * File operations used in the debug char device
2591 */
2592static struct file_operations sfe_ipv4_debug_dev_fops = {
2593 .read = sfe_ipv4_debug_dev_read,
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002594 .open = sfe_ipv4_debug_dev_open,
2595 .release = sfe_ipv4_debug_dev_release
2596};
2597
Xiaoping Fand1dc7b22015-01-23 00:43:56 -08002598#ifdef CONFIG_NF_FLOW_COOKIE
2599/*
2600 * sfe_register_flow_cookie_cb
2601 * register a function in SFE to let SFE use this function to configure flow cookie for a flow
2602 *
2603 * Hardware driver which support flow cookie should register a callback function in SFE. Then SFE
2604 * can use this function to configure flow cookie for a flow.
2605 * return: 0, success; !=0, fail
2606 */
2607int sfe_register_flow_cookie_cb(flow_cookie_set_func_t cb)
2608{
2609 struct sfe_ipv4 *si = &__si;
2610
2611 BUG_ON(!cb);
2612
2613 if (si->flow_cookie_set_func) {
2614 return -1;
2615 }
2616
2617 rcu_assign_pointer(si->flow_cookie_set_func, cb);
2618 return 0;
2619}
2620
2621/*
2622 * sfe_unregister_flow_cookie_cb
2623 * unregister function which is used to configure flow cookie for a flow
2624 *
2625 * return: 0, success; !=0, fail
2626 */
2627int sfe_unregister_flow_cookie_cb(flow_cookie_set_func_t cb)
2628{
2629 struct sfe_ipv4 *si = &__si;
2630
2631 RCU_INIT_POINTER(si->flow_cookie_set_func, NULL);
2632 return 0;
2633}
Xiaoping Fan640faf42015-08-28 15:50:55 -07002634
2635/*
2636 * sfe_ipv4_get_flow_cookie()
2637 */
2638static ssize_t sfe_ipv4_get_flow_cookie(struct device *dev,
2639 struct device_attribute *attr,
2640 char *buf)
2641{
2642 struct sfe_ipv4 *si = &__si;
Xiaoping Fan01c67cc2015-11-09 11:31:57 -08002643 return snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", si->flow_cookie_enable);
Xiaoping Fan640faf42015-08-28 15:50:55 -07002644}
2645
2646/*
2647 * sfe_ipv4_set_flow_cookie()
2648 */
2649static ssize_t sfe_ipv4_set_flow_cookie(struct device *dev,
2650 struct device_attribute *attr,
2651 const char *buf, size_t size)
2652{
2653 struct sfe_ipv4 *si = &__si;
Ken Zhu137722d2021-09-23 17:57:36 -07002654 si->flow_cookie_enable = simple_strtol(buf, NULL, 0);
Xiaoping Fan640faf42015-08-28 15:50:55 -07002655
2656 return size;
2657}
2658
2659/*
2660 * sysfs attributes.
2661 */
2662static const struct device_attribute sfe_ipv4_flow_cookie_attr =
Xiaoping Fane70da412016-02-26 16:47:57 -08002663 __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 -08002664#endif /*CONFIG_NF_FLOW_COOKIE*/
2665
Ken Zhu137722d2021-09-23 17:57:36 -07002666/*
2667 * sfe_ipv4_get_cpu()
2668 */
2669static ssize_t sfe_ipv4_get_cpu(struct device *dev,
2670 struct device_attribute *attr,
2671 char *buf)
2672{
2673 struct sfe_ipv4 *si = &__si;
2674 return snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", si->work_cpu);
2675}
2676
2677/*
2678 * sfe_ipv4_set_cpu()
2679 */
2680static ssize_t sfe_ipv4_set_cpu(struct device *dev,
2681 struct device_attribute *attr,
2682 const char *buf, size_t size)
2683{
2684 struct sfe_ipv4 *si = &__si;
2685 int work_cpu;
2686 work_cpu = simple_strtol(buf, NULL, 0);
2687 if ((work_cpu >= 0) && (work_cpu <= NR_CPUS)) {
2688 si->work_cpu = work_cpu;
2689 } else {
2690 dev_err(dev, "%s is not in valid range[0,%d]", buf, NR_CPUS);
2691 }
2692 return size;
2693}
Ken Zhu7e38d1a2021-11-30 17:31:46 -08002694
Ken Zhu137722d2021-09-23 17:57:36 -07002695/*
2696 * sysfs attributes.
2697 */
2698static const struct device_attribute sfe_ipv4_cpu_attr =
2699 __ATTR(stats_work_cpu, S_IWUSR | S_IRUGO, sfe_ipv4_get_cpu, sfe_ipv4_set_cpu);
2700
Ken Zhu7e38d1a2021-11-30 17:31:46 -08002701/*
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05302702 * sfe_ipv4_conn_match_hash_init()
2703 * Initialize conn match hash lists
2704 */
2705static void sfe_ipv4_conn_match_hash_init(struct sfe_ipv4 *si, int len)
2706{
2707 struct hlist_head *hash_list = si->hlist_conn_match_hash_head;
2708 int i;
2709
2710 for (i = 0; i < len; i++) {
2711 INIT_HLIST_HEAD(&hash_list[i]);
2712 }
2713}
2714
Amitesh Anand63be37d2021-12-24 20:51:48 +05302715#ifdef SFE_PROCESS_LOCAL_OUT
2716/*
2717 * sfe_ipv4_local_out()
2718 * Called for packets from ip_local_out() - post encapsulation & other packets
2719 */
2720static unsigned int sfe_ipv4_local_out(void *priv, struct sk_buff *skb, const struct nf_hook_state *nhs)
2721{
Nitin Shettyc28f8172022-02-04 16:23:46 +05302722 struct sfe_l2_info l2_info = {0};
Guduri Prathyusha5f27e232022-01-06 14:39:04 +05302723
Amitesh Anand63be37d2021-12-24 20:51:48 +05302724 DEBUG_TRACE("%px: sfe: sfe_ipv4_local_out hook called.\n", skb);
2725
2726 if (likely(skb->skb_iif)) {
Guduri Prathyusha5f27e232022-01-06 14:39:04 +05302727 return sfe_ipv4_recv(skb->dev, skb, &l2_info, true) ? NF_STOLEN : NF_ACCEPT;
Amitesh Anand63be37d2021-12-24 20:51:48 +05302728 }
2729
2730 return NF_ACCEPT;
2731}
2732
2733/*
2734 * struct nf_hook_ops sfe_ipv4_ops_local_out[]
2735 * Hooks into netfilter local out packet monitoring points.
2736 */
2737static struct nf_hook_ops sfe_ipv4_ops_local_out[] __read_mostly = {
2738
2739 /*
2740 * Local out routing hook is used to monitor packets.
2741 */
2742 {
2743 .hook = sfe_ipv4_local_out,
2744 .pf = PF_INET,
2745 .hooknum = NF_INET_LOCAL_OUT,
2746 .priority = NF_IP_PRI_FIRST,
2747 },
2748};
2749#endif
2750
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002751/*
Dave Hudson87973cd2013-10-22 16:00:04 +01002752 * sfe_ipv4_init()
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002753 */
Ratheesh Kannoth24fb1db2021-10-20 07:28:06 +05302754int sfe_ipv4_init(void)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002755{
2756 struct sfe_ipv4 *si = &__si;
2757 int result = -1;
2758
Dave Hudsondcd08fb2013-11-22 09:25:16 -06002759 DEBUG_INFO("SFE IPv4 init\n");
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002760
Ratheesh Kannoth94fc5b82021-10-20 07:45:06 +05302761 sfe_ipv4_conn_match_hash_init(si, ARRAY_SIZE(si->hlist_conn_match_hash_head));
2762
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +05302763 si->stats_pcpu = alloc_percpu_gfp(struct sfe_ipv4_stats, GFP_KERNEL | __GFP_ZERO);
2764 if (!si->stats_pcpu) {
2765 DEBUG_ERROR("failed to allocate stats memory for sfe_ipv4\n");
2766 goto exit0;
2767 }
2768
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002769 /*
Parikshit Guned31a8202022-01-05 22:15:04 +05302770 * Allocate per cpu per service class memory.
2771 */
2772 si->stats_pcpu_psc = alloc_percpu_gfp(struct sfe_ipv4_service_class_stats_db,
2773 GFP_KERNEL | __GFP_ZERO);
2774 if (!si->stats_pcpu_psc) {
2775 DEBUG_ERROR("failed to allocate per cpu per service clas stats memory\n");
2776 goto exit1;
2777 }
2778
2779 /*
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002780 * Create sys/sfe_ipv4
2781 */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05302782 si->sys_ipv4 = kobject_create_and_add("sfe_ipv4", NULL);
2783 if (!si->sys_ipv4) {
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002784 DEBUG_ERROR("failed to register sfe_ipv4\n");
Parikshit Guned31a8202022-01-05 22:15:04 +05302785 goto exit2;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002786 }
2787
2788 /*
2789 * Create files, one for each parameter supported by this module.
2790 */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05302791 result = sysfs_create_file(si->sys_ipv4, &sfe_ipv4_debug_dev_attr.attr);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002792 if (result) {
2793 DEBUG_ERROR("failed to register debug dev file: %d\n", result);
Parikshit Guned31a8202022-01-05 22:15:04 +05302794 goto exit3;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002795 }
2796
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05302797 result = sysfs_create_file(si->sys_ipv4, &sfe_ipv4_cpu_attr.attr);
Ken Zhu137722d2021-09-23 17:57:36 -07002798 if (result) {
2799 DEBUG_ERROR("failed to register debug dev file: %d\n", result);
Parikshit Guned31a8202022-01-05 22:15:04 +05302800 goto exit4;
Ken Zhu137722d2021-09-23 17:57:36 -07002801 }
2802
Xiaoping Fan640faf42015-08-28 15:50:55 -07002803#ifdef CONFIG_NF_FLOW_COOKIE
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05302804 result = sysfs_create_file(si->sys_ipv4, &sfe_ipv4_flow_cookie_attr.attr);
Xiaoping Fan640faf42015-08-28 15:50:55 -07002805 if (result) {
2806 DEBUG_ERROR("failed to register flow cookie enable file: %d\n", result);
Parikshit Guned31a8202022-01-05 22:15:04 +05302807 goto exit5;
Xiaoping Fan640faf42015-08-28 15:50:55 -07002808 }
2809#endif /* CONFIG_NF_FLOW_COOKIE */
2810
Amitesh Anand63be37d2021-12-24 20:51:48 +05302811#ifdef SFE_PROCESS_LOCAL_OUT
2812#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0))
2813 result = nf_register_hooks(sfe_ipv4_ops_local_out, ARRAY_SIZE(sfe_ipv4_ops_local_out));
2814#else
2815 result = nf_register_net_hooks(&init_net, sfe_ipv4_ops_local_out, ARRAY_SIZE(sfe_ipv4_ops_local_out));
2816#endif
2817 if (result < 0) {
2818 DEBUG_ERROR("can't register nf local out hook: %d\n", result);
Parikshit Guned31a8202022-01-05 22:15:04 +05302819 goto exit6;
Amitesh Anand63be37d2021-12-24 20:51:48 +05302820 }
2821 DEBUG_INFO("Register nf local out hook success: %d\n", result);
2822#endif
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002823 /*
2824 * Register our debug char device.
2825 */
2826 result = register_chrdev(0, "sfe_ipv4", &sfe_ipv4_debug_dev_fops);
2827 if (result < 0) {
2828 DEBUG_ERROR("Failed to register chrdev: %d\n", result);
Parikshit Guned31a8202022-01-05 22:15:04 +05302829 goto exit7;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002830 }
2831
2832 si->debug_dev = result;
Ken Zhu137722d2021-09-23 17:57:36 -07002833 si->work_cpu = WORK_CPU_UNBOUND;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002834
2835 /*
Ken Zhu7a43d882022-01-04 10:51:44 -08002836 * Create a work to handle pull message from ecm.
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002837 */
Ken Zhu137722d2021-09-23 17:57:36 -07002838 INIT_DELAYED_WORK(&(si->sync_dwork), sfe_ipv4_periodic_sync);
Ken Zhu7a43d882022-01-04 10:51:44 -08002839 /*
2840 * Allocate a message for stats sync many
2841 */
2842 sfe_ipv4_sync_many_msg = kzalloc(PAGE_SIZE, GFP_KERNEL);
2843 if(!sfe_ipv4_sync_many_msg) {
2844 goto exit8;
2845 }
2846
2847 sfe_ipv4_msg_init(sfe_ipv4_sync_many_msg, SFE_SPECIAL_INTERFACE_IPV4,
2848 SFE_TX_CONN_STATS_SYNC_MANY_MSG,
2849 sizeof(struct sfe_ipv4_conn_sync_many_msg),
2850 NULL,
2851 NULL);
2852 sfe_ipv4_sync_max_number = (PAGE_SIZE - sizeof(struct sfe_ipv4_msg)) / sizeof(struct sfe_ipv4_conn_sync);
Ken Zhu137722d2021-09-23 17:57:36 -07002853
Dave Hudson87973cd2013-10-22 16:00:04 +01002854 spin_lock_init(&si->lock);
Dave Hudson87973cd2013-10-22 16:00:04 +01002855 return 0;
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002856
Ken Zhu7a43d882022-01-04 10:51:44 -08002857exit8:
2858 unregister_chrdev(si->debug_dev, "sfe_ipv4");
2859
Parikshit Guned31a8202022-01-05 22:15:04 +05302860exit7:
Amitesh Anand63be37d2021-12-24 20:51:48 +05302861#ifdef SFE_PROCESS_LOCAL_OUT
2862 DEBUG_TRACE("sfe: Unregister local out hook\n");
2863#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0))
2864 nf_unregister_hooks(sfe_ipv4_ops_local_out, ARRAY_SIZE(sfe_ipv4_ops_local_out));
2865#else
2866 nf_unregister_net_hooks(&init_net, sfe_ipv4_ops_local_out, ARRAY_SIZE(sfe_ipv4_ops_local_out));
2867#endif
Parikshit Guned31a8202022-01-05 22:15:04 +05302868exit6:
Amitesh Anand63be37d2021-12-24 20:51:48 +05302869#endif
Xiaoping Fan640faf42015-08-28 15:50:55 -07002870#ifdef CONFIG_NF_FLOW_COOKIE
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05302871 sysfs_remove_file(si->sys_ipv4, &sfe_ipv4_flow_cookie_attr.attr);
Xiaoping Fan640faf42015-08-28 15:50:55 -07002872
Parikshit Guned31a8202022-01-05 22:15:04 +05302873exit5:
Xiaoping Fan640faf42015-08-28 15:50:55 -07002874#endif /* CONFIG_NF_FLOW_COOKIE */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05302875 sysfs_remove_file(si->sys_ipv4, &sfe_ipv4_cpu_attr.attr);
Parikshit Guned31a8202022-01-05 22:15:04 +05302876exit4:
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05302877 sysfs_remove_file(si->sys_ipv4, &sfe_ipv4_debug_dev_attr.attr);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002878
Parikshit Guned31a8202022-01-05 22:15:04 +05302879exit3:
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05302880 kobject_put(si->sys_ipv4);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002881
Parikshit Guned31a8202022-01-05 22:15:04 +05302882exit2:
2883 free_percpu(si->stats_pcpu_psc);
2884
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002885exit1:
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +05302886 free_percpu(si->stats_pcpu);
2887
2888exit0:
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002889 return result;
2890}
2891
2892/*
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002893 * sfe_ipv4_exit()
2894 */
Ratheesh Kannoth24fb1db2021-10-20 07:28:06 +05302895void sfe_ipv4_exit(void)
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002896{
Dave Hudson87973cd2013-10-22 16:00:04 +01002897 struct sfe_ipv4 *si = &__si;
2898
Dave Hudsondcd08fb2013-11-22 09:25:16 -06002899 DEBUG_INFO("SFE IPv4 exit\n");
Dave Hudson87973cd2013-10-22 16:00:04 +01002900 /*
2901 * Destroy all connections.
2902 */
Dave Hudsondcd08fb2013-11-22 09:25:16 -06002903 sfe_ipv4_destroy_all_rules_for_dev(NULL);
Dave Hudson87973cd2013-10-22 16:00:04 +01002904
Ken Zhu137722d2021-09-23 17:57:36 -07002905 cancel_delayed_work_sync(&si->sync_dwork);
Dave Hudson87973cd2013-10-22 16:00:04 +01002906
Dave Hudson87973cd2013-10-22 16:00:04 +01002907 unregister_chrdev(si->debug_dev, "sfe_ipv4");
2908
Amitesh Anand63be37d2021-12-24 20:51:48 +05302909#ifdef SFE_PROCESS_LOCAL_OUT
2910 DEBUG_TRACE("sfe: Unregister local out hook\n");
2911#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0))
2912 nf_unregister_hooks(sfe_ipv4_ops_local_out, ARRAY_SIZE(sfe_ipv4_ops_local_out));
2913#else
2914 nf_unregister_net_hooks(&init_net, sfe_ipv4_ops_local_out, ARRAY_SIZE(sfe_ipv4_ops_local_out));
2915#endif
2916#endif
2917
Xiaoping Fan640faf42015-08-28 15:50:55 -07002918#ifdef CONFIG_NF_FLOW_COOKIE
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05302919 sysfs_remove_file(si->sys_ipv4, &sfe_ipv4_flow_cookie_attr.attr);
Xiaoping Fan640faf42015-08-28 15:50:55 -07002920#endif /* CONFIG_NF_FLOW_COOKIE */
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05302921 sysfs_remove_file(si->sys_ipv4, &sfe_ipv4_debug_dev_attr.attr);
Ken Zhu7e38d1a2021-11-30 17:31:46 -08002922
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05302923 sysfs_remove_file(si->sys_ipv4, &sfe_ipv4_cpu_attr.attr);
Dave Hudson87973cd2013-10-22 16:00:04 +01002924
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05302925 kobject_put(si->sys_ipv4);
Dave Hudson87973cd2013-10-22 16:00:04 +01002926
Ratheesh Kannoth3aeb2892021-10-20 07:57:15 +05302927 free_percpu(si->stats_pcpu);
Parikshit Guned31a8202022-01-05 22:15:04 +05302928 free_percpu(si->stats_pcpu_psc);
Dave Hudsonaaf97ca2013-06-13 17:52:29 +01002929}
2930
Xiaoping Fand1dc7b22015-01-23 00:43:56 -08002931#ifdef CONFIG_NF_FLOW_COOKIE
2932EXPORT_SYMBOL(sfe_register_flow_cookie_cb);
2933EXPORT_SYMBOL(sfe_unregister_flow_cookie_cb);
2934#endif