blob: 28c7a433477111fdf688dc3d2d0f4b133f82bf9e [file] [log] [blame]
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +05301/*
2 * sfe_ipv4_udp.c
3 * Shortcut forwarding engine - IPv4 UDP implementation
4 *
5 * Copyright (c) 2013-2016, 2019-2020, The Linux Foundation. All rights reserved.
6 * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
7 *
8 * Permission to use, copy, modify, and/or distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
11 *
12 * 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
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 */
20
21#include <linux/skbuff.h>
22#include <net/udp.h>
23#include <linux/etherdevice.h>
24#include <linux/lockdep.h>
25
26#include "sfe_debug.h"
27#include "sfe_api.h"
28#include "sfe.h"
29#include "sfe_flow_cookie.h"
30#include "sfe_ipv4.h"
Guduri Prathyusha79a5fee2021-11-11 17:59:10 +053031#include "sfe_pppoe.h"
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +053032
33/*
34 * sfe_ipv4_recv_udp()
35 * Handle UDP packet receives and forwarding.
36 */
37int sfe_ipv4_recv_udp(struct sfe_ipv4 *si, struct sk_buff *skb, struct net_device *dev,
38 unsigned int len, struct iphdr *iph, unsigned int ihl, bool flush_on_find)
39{
40 struct udphdr *udph;
41 __be32 src_ip;
42 __be32 dest_ip;
43 __be16 src_port;
44 __be16 dest_port;
45 struct sfe_ipv4_connection_match *cm;
46 u8 ttl;
47 struct net_device *xmit_dev;
48 bool ret;
Ratheesh Kannotha3cf0e02021-12-09 09:44:10 +053049 bool hw_csum;
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +053050
51 /*
52 * Is our packet too short to contain a valid UDP header?
53 */
54 if (unlikely(!pskb_may_pull(skb, (sizeof(struct udphdr) + ihl)))) {
55 sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_UDP_HEADER_INCOMPLETE);
56 DEBUG_TRACE("packet too short for UDP header\n");
57 return 0;
58 }
59
60 /*
61 * Read the IP address and port information. Read the IP header data first
62 * because we've almost certainly got that in the cache. We may not yet have
63 * the UDP header cached though so allow more time for any prefetching.
64 */
65 src_ip = iph->saddr;
66 dest_ip = iph->daddr;
67
68 udph = (struct udphdr *)(skb->data + ihl);
69 src_port = udph->source;
70 dest_port = udph->dest;
71
72 rcu_read_lock();
73
74 /*
75 * Look for a connection match.
76 */
77#ifdef CONFIG_NF_FLOW_COOKIE
78 cm = si->sfe_flow_cookie_table[skb->flow_cookie & SFE_FLOW_COOKIE_MASK].match;
79 if (unlikely(!cm)) {
80 cm = sfe_ipv4_find_connection_match_rcu(si, dev, IPPROTO_UDP, src_ip, src_port, dest_ip, dest_port);
81 }
82#else
83 cm = sfe_ipv4_find_connection_match_rcu(si, dev, IPPROTO_UDP, src_ip, src_port, dest_ip, dest_port);
84#endif
85 if (unlikely(!cm)) {
86
87 rcu_read_unlock();
88 sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_UDP_NO_CONNECTION);
89 DEBUG_TRACE("no connection found\n");
90 return 0;
91 }
92
93 /*
94 * If our packet has beern marked as "flush on find" we can't actually
95 * forward it in the fast path, but now that we've found an associated
96 * connection we can flush that out before we process the packet.
97 */
98 if (unlikely(flush_on_find)) {
99 struct sfe_ipv4_connection *c = cm->connection;
100 spin_lock_bh(&si->lock);
101 ret = sfe_ipv4_remove_connection(si, c);
102 spin_unlock_bh(&si->lock);
103
104 if (ret) {
105 sfe_ipv4_flush_connection(si, c, SFE_SYNC_REASON_FLUSH);
106 }
107 rcu_read_unlock();
108 sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_UDP_IP_OPTIONS_OR_INITIAL_FRAGMENT);
109 DEBUG_TRACE("flush on find\n");
110 return 0;
111 }
112
113#ifdef CONFIG_XFRM
114 /*
115 * We can't accelerate the flow on this direction, just let it go
116 * through the slow path.
117 */
118 if (unlikely(!cm->flow_accel)) {
119 rcu_read_unlock();
120 this_cpu_inc(si->stats_pcpu->packets_not_forwarded64);
121 return 0;
122 }
123#endif
124
125 /*
126 * Does our TTL allow forwarding?
127 */
128 ttl = iph->ttl;
129 if (unlikely(ttl < 2)) {
130 struct sfe_ipv4_connection *c = cm->connection;
131 spin_lock_bh(&si->lock);
132 ret = sfe_ipv4_remove_connection(si, c);
133 spin_unlock_bh(&si->lock);
134
135 if (ret) {
136 sfe_ipv4_flush_connection(si, c, SFE_SYNC_REASON_FLUSH);
137 }
138 rcu_read_unlock();
139
140 DEBUG_TRACE("ttl too low\n");
141 sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_UDP_SMALL_TTL);
142 return 0;
143 }
144
145 /*
146 * If our packet is larger than the MTU of the transmit interface then
147 * we can't forward it easily.
148 */
149 if (unlikely(len > cm->xmit_dev_mtu)) {
150 struct sfe_ipv4_connection *c = cm->connection;
151 spin_lock_bh(&si->lock);
152 ret = sfe_ipv4_remove_connection(si, c);
153 spin_unlock_bh(&si->lock);
154
155 DEBUG_TRACE("larger than mtu\n");
156 if (ret) {
157 sfe_ipv4_flush_connection(si, c, SFE_SYNC_REASON_FLUSH);
158 }
159 rcu_read_unlock();
160 sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_UDP_NEEDS_FRAGMENTATION);
161 return 0;
162 }
163
164 /*
165 * From this point on we're good to modify the packet.
166 */
167
168 /*
169 * Check if skb was cloned. If it was, unshare it. Because
170 * the data area is going to be written in this path and we don't want to
171 * change the cloned skb's data section.
172 */
173 if (unlikely(skb_cloned(skb))) {
174 DEBUG_TRACE("%px: skb is a cloned skb\n", skb);
175 skb = skb_unshare(skb, GFP_ATOMIC);
176 if (!skb) {
177 DEBUG_WARN("Failed to unshare the cloned skb\n");
178 rcu_read_unlock();
179 return 0;
180 }
181
182 /*
183 * Update the iph and udph pointers with the unshared skb's data area.
184 */
185 iph = (struct iphdr *)skb->data;
186 udph = (struct udphdr *)(skb->data + ihl);
187 }
188
189 /*
190 * Update DSCP
191 */
192 if (unlikely(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_DSCP_REMARK)) {
193 iph->tos = (iph->tos & SFE_IPV4_DSCP_MASK) | cm->dscp;
194 }
195
196 /*
197 * Decrement our TTL.
198 */
199 iph->ttl = ttl - 1;
200
201 /*
Guduri Prathyusha79a5fee2021-11-11 17:59:10 +0530202 * For PPPoE flows, add PPPoE header before L2 header is added.
203 */
204 if (cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_PPPOE_ENCAP) {
205 if (unlikely(!sfe_pppoe_add_header(skb, cm->pppoe_session_id, PPP_IP))) {
206 rcu_read_unlock();
207 DEBUG_WARN("%px: PPPoE header addition failed\n", skb);
208 sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_PPPOE_HEADER_ENCAP_FAILED);
209 return 0;
210 }
211 this_cpu_inc(si->stats_pcpu->pppoe_encap_packets_forwarded64);
212 }
213
214 /*
215 * TODO: VLAN header should be added here when they are supported.
216 */
217
218 /*
Ratheesh Kannotha3cf0e02021-12-09 09:44:10 +0530219 * Enable HW csum if rx checksum is verified and xmit interface is CSUM offload capable.
220 * Note: If L4 csum at Rx was found to be incorrect, we (router) should use incremental L4 checksum here
221 * so that HW does not re-calculate/replace the L4 csum
222 */
223 hw_csum = !!(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_CSUM_OFFLOAD) && (skb->ip_summed == CHECKSUM_UNNECESSARY);
224
225 /*
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530226 * Do we have to perform translations of the source address/port?
227 */
228 if (unlikely(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_SRC)) {
229 u16 udp_csum;
230
231 iph->saddr = cm->xlate_src_ip;
232 udph->source = cm->xlate_src_port;
233
234 /*
235 * Do we have a non-zero UDP checksum? If we do then we need
236 * to update it.
237 */
Ratheesh Kannotha3cf0e02021-12-09 09:44:10 +0530238 if (unlikely(!hw_csum)) {
239 udp_csum = udph->check;
240 if (likely(udp_csum)) {
241 u32 sum;
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530242
Ratheesh Kannotha3cf0e02021-12-09 09:44:10 +0530243 if (unlikely(skb->ip_summed == CHECKSUM_PARTIAL)) {
244 sum = udp_csum + cm->xlate_src_partial_csum_adjustment;
245 } else {
246 sum = udp_csum + cm->xlate_src_csum_adjustment;
247 }
248
249 sum = (sum & 0xffff) + (sum >> 16);
250 udph->check = (u16)sum;
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530251 }
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530252 }
253 }
254
255 /*
256 * Do we have to perform translations of the destination address/port?
257 */
258 if (unlikely(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_XLATE_DEST)) {
259 u16 udp_csum;
260
261 iph->daddr = cm->xlate_dest_ip;
262 udph->dest = cm->xlate_dest_port;
263
264 /*
265 * Do we have a non-zero UDP checksum? If we do then we need
266 * to update it.
267 */
Ratheesh Kannotha3cf0e02021-12-09 09:44:10 +0530268 if (unlikely(!hw_csum)) {
269 udp_csum = udph->check;
270 if (likely(udp_csum)) {
271 u32 sum;
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530272
Ratheesh Kannotha3cf0e02021-12-09 09:44:10 +0530273 /*
274 * TODO: Use a common API for below incremental checksum calculation
275 * for IPv4/IPv6 UDP/TCP
276 */
277 if (unlikely(skb->ip_summed == CHECKSUM_PARTIAL)) {
278 sum = udp_csum + cm->xlate_dest_partial_csum_adjustment;
279 } else {
280 sum = udp_csum + cm->xlate_dest_csum_adjustment;
281 }
282
283 sum = (sum & 0xffff) + (sum >> 16);
284 udph->check = (u16)sum;
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530285 }
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530286 }
287 }
288
289 /*
Ratheesh Kannotha3cf0e02021-12-09 09:44:10 +0530290 * If HW checksum offload is not possible, full L3 checksum and incremental L4 checksum
291 * are used to update the packet. Setting ip_summed to CHECKSUM_UNNECESSARY ensures checksum is
292 * not recalculated further in packet path.
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530293 */
Ratheesh Kannotha3cf0e02021-12-09 09:44:10 +0530294 if (likely(hw_csum)) {
295 skb->ip_summed = CHECKSUM_PARTIAL;
296 } else {
297 iph->check = sfe_ipv4_gen_ip_csum(iph);
298 skb->ip_summed = CHECKSUM_UNNECESSARY;
299 }
Ratheesh Kannoth6307bec2021-11-25 08:26:39 +0530300
301 /*
302 * Update traffic stats.
303 */
304 atomic_inc(&cm->rx_packet_count);
305 atomic_add(len, &cm->rx_byte_count);
306
307 xmit_dev = cm->xmit_dev;
308 skb->dev = xmit_dev;
309
310 /*
311 * Check to see if we need to write a header.
312 */
313 if (likely(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_WRITE_L2_HDR)) {
314 if (unlikely(!(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_WRITE_FAST_ETH_HDR))) {
315 dev_hard_header(skb, xmit_dev, ETH_P_IP,
316 cm->xmit_dest_mac, cm->xmit_src_mac, len);
317 } else {
318 /*
319 * For the simple case we write this really fast.
320 */
321 struct ethhdr *eth = (struct ethhdr *)__skb_push(skb, ETH_HLEN);
322 eth->h_proto = htons(ETH_P_IP);
323 ether_addr_copy((u8 *)eth->h_dest, (u8 *)cm->xmit_dest_mac);
324 ether_addr_copy((u8 *)eth->h_source, (u8 *)cm->xmit_src_mac);
325 }
326 }
327
328 /*
329 * Update priority of skb.
330 */
331 if (unlikely(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_PRIORITY_REMARK)) {
332 skb->priority = cm->priority;
333 }
334
335 /*
336 * Mark outgoing packet.
337 */
338 skb->mark = cm->connection->mark;
339 if (skb->mark) {
340 DEBUG_TRACE("SKB MARK is NON ZERO %x\n", skb->mark);
341 }
342
343 rcu_read_unlock();
344
345 this_cpu_inc(si->stats_pcpu->packets_forwarded64);
346
347 /*
348 * We're going to check for GSO flags when we transmit the packet so
349 * start fetching the necessary cache line now.
350 */
351 prefetch(skb_shinfo(skb));
352
353 /*
354 * Mark that this packet has been fast forwarded.
355 */
356 skb->fast_forwarded = 1;
357
358 /*
359 * Send the packet on its way.
360 */
361 dev_queue_xmit(skb);
362
363 return 1;
364}