[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <6d52098964b54d848cbfd1957f093bd8@AcuMS.aculab.com>
Date: Sun, 10 May 2020 16:00:41 +0000
From: David Laight <David.Laight@...LAB.COM>
To: "netdev@...r.kernel.org" <netdev@...r.kernel.org>
Subject: [PATCH net-next] net/ipv4/raw Optimise ipv4 raw sends when IP_HDRINCL
set.
The final routing for ipv4 packets may be done with the IP address
from the message header not that from the address buffer.
If the addresses are different FLOWI_FLAG_KNOWN_NH must be set so
that a temporary 'struct rtable' entry is created to send the message.
However the allocate + free (under RCU) is relatively expensive
and can be avoided by a quick check shows the addresses match.
Signed-off-by: David Laight <david.laight@...lab.com>
---
This makes a considerable difference when we are sending a lot
of RTP streams from a raw socket.
IP_HDRINCL has to be set so that the calculated UDP checksum is right.
net/ipv4/raw.c | 30 ++++++++++++++++++++++++++++--
1 file changed, 28 insertions(+), 2 deletions(-)
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index 3183413..0a81376 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -495,6 +495,27 @@ static int raw_getfrag(void *from, char *to, int offset, int len, int odd,
return ip_generic_getfrag(rfv->msg, to, offset, len, odd, skb);
}
+static bool raw_msg_addr_matches(struct msghdr *msg, __be32 daddr)
+{
+ const struct iovec *iov;
+ __be32 msg_daddr;
+
+ /* Check common case of user buffer with header in the first fragment.
+ * If we return false the message is still sent.
+ */
+
+ if (!iter_is_iovec(&msg->msg_iter))
+ return false;
+ iov = msg->msg_iter.iov;
+ if (!iov || iov->iov_len < 20)
+ return false;
+
+ if (get_user(msg_daddr, (__be32 __user *)(iov->iov_base + 16)))
+ return false;
+
+ return daddr == msg_daddr;
+}
+
static int raw_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
{
struct inet_sock *inet = inet_sk(sk);
@@ -626,9 +647,14 @@ static int raw_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
flowi4_init_output(&fl4, ipc.oif, ipc.sockc.mark, tos,
RT_SCOPE_UNIVERSE,
hdrincl ? IPPROTO_RAW : sk->sk_protocol,
- inet_sk_flowi_flags(sk) |
- (hdrincl ? FLOWI_FLAG_KNOWN_NH : 0),
+ inet_sk_flowi_flags(sk),
daddr, saddr, 0, 0, sk->sk_uid);
+ /* The final message routing may be done with the destination address
+ * in the user-supplied ipv4 header. If this differs from 'daddr' then
+ * a temporary destination table entry has to be created.
+ */
+ if (hdrincl && !raw_msg_addr_matches(msg, daddr))
+ fl4.flowi4_flags |= FLOWI_FLAG_KNOWN_NH;
if (!hdrincl) {
rfv.msg = msg;
--
1.8.1.2
-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)
Powered by blists - more mailing lists