Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fcfec335 authored by Willem de Bruijn's avatar Willem de Bruijn Committed by Gerrit - the friendly Code Review server
Browse files

udp: add gso segment cmsg



Allow specifying segment size in the send call.

The new control message performs the same function as socket option
UDP_SEGMENT while avoiding the extra system call.

Change-Id: I335dfba959d264ee181f6bc8da29cebb7685e7e1
Signed-off-by: default avatarWillem de Bruijn <willemb@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Git-commit: 2e8de8576343ab540856082916bfb84d17288b08
Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git


Signed-off-by: default avatarSean Tranchetti <stranche@codeaurora.org>
parent 8ca26b21
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -273,6 +273,7 @@ int udp_abort(struct sock *sk, int err);
int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len);
int udp_push_pending_frames(struct sock *sk);
void udp_flush_pending_frames(struct sock *sk);
int udp_cmsg_send(struct sock *sk, struct msghdr *msg, u16 *gso_size);
void udp4_hwcsum(struct sk_buff *skb, __be32 src, __be32 dst);
int udp_rcv(struct sk_buff *skb);
int udp_ioctl(struct sock *sk, int cmd, unsigned long arg);
+41 −2
Original line number Diff line number Diff line
@@ -884,6 +884,42 @@ int udp_push_pending_frames(struct sock *sk)
}
EXPORT_SYMBOL(udp_push_pending_frames);

static int __udp_cmsg_send(struct cmsghdr *cmsg, u16 *gso_size)
{
	switch (cmsg->cmsg_type) {
	case UDP_SEGMENT:
		if (cmsg->cmsg_len != CMSG_LEN(sizeof(__u16)))
			return -EINVAL;
		*gso_size = *(__u16 *)CMSG_DATA(cmsg);
		return 0;
	default:
		return -EINVAL;
	}
}

int udp_cmsg_send(struct sock *sk, struct msghdr *msg, u16 *gso_size)
{
	struct cmsghdr *cmsg;
	bool need_ip = false;
	int err;

	for_each_cmsghdr(cmsg, msg) {
		if (!CMSG_OK(msg, cmsg))
			return -EINVAL;

		if (cmsg->cmsg_level != SOL_UDP) {
			need_ip = true;
			continue;
		}

		err = __udp_cmsg_send(cmsg, gso_size);
		if (err)
			return err;
	}

	return need_ip;
}

int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
{
	struct inet_sock *inet = inet_sk(sk);
@@ -972,8 +1008,11 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
	ipc.gso_size = up->gso_size;

	if (msg->msg_controllen) {
		err = ip_cmsg_send(sk, msg, &ipc, sk->sk_family == AF_INET6);
		if (unlikely(err)) {
		err = udp_cmsg_send(sk, msg, &ipc.gso_size);
		if (err > 0)
			err = ip_cmsg_send(sk, msg, &ipc,
					   sk->sk_family == AF_INET6);
		if (unlikely(err < 0)) {
			kfree(ipc.opt);
			return err;
		}
+4 −1
Original line number Diff line number Diff line
@@ -1287,7 +1287,10 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
		opt->tot_len = sizeof(*opt);
		ipc6.opt = opt;

		err = ip6_datagram_send_ctl(sock_net(sk), sk, msg, &fl6, &ipc6, &sockc);
		err = udp_cmsg_send(sk, msg, &ipc6.gso_size);
		if (err > 0)
			err = ip6_datagram_send_ctl(sock_net(sk), sk, msg, &fl6,
						    &ipc6, &sockc);
		if (err < 0) {
			fl6_sock_release(flowlabel);
			return err;