mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-05 18:39:59 +00:00
![Hannes Frederic Sowa](/assets/img/avatar_default.png)
net_get_random_once depends on the static keys infrastructure to patch up
the branch to the slow path during boot. This was realized by abusing the
static keys api and defining a new initializer to not enable the call
site while still indicating that the branch point should get patched
up. This was needed to have the fast path considered likely by gcc.
The static key initialization during boot up normally walks through all
the registered keys and either patches in ideal nops or enables the jump
site but omitted that step on x86 if ideal nops where already placed at
static_key branch points. Thus net_get_random_once branches not always
became active.
This patch switches net_get_random_once to the ordinary static_key
api and thus places the kernel fast path in the - by gcc considered -
unlikely path. Microbenchmarks on Intel and AMD x86-64 showed that
the unlikely path actually beats the likely path in terms of cycle cost
and that different nop patterns did not make much difference, thus this
switch should not be noticeable.
Fixes: a48e42920f
("net: introduce new macro net_get_random_once")
Reported-by: Tuomas Räsänen <tuomasjjrasanen@tjjr.fi>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
301 lines
10 KiB
C
301 lines
10 KiB
C
/*
|
|
* NET An implementation of the SOCKET network access protocol.
|
|
* This is the master header file for the Linux NET layer,
|
|
* or, in plain English: the networking handling part of the
|
|
* kernel.
|
|
*
|
|
* Version: @(#)net.h 1.0.3 05/25/93
|
|
*
|
|
* Authors: Orest Zborowski, <obz@Kodak.COM>
|
|
* Ross Biro
|
|
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version
|
|
* 2 of the License, or (at your option) any later version.
|
|
*/
|
|
#ifndef _LINUX_NET_H
|
|
#define _LINUX_NET_H
|
|
|
|
#include <linux/stringify.h>
|
|
#include <linux/random.h>
|
|
#include <linux/wait.h>
|
|
#include <linux/fcntl.h> /* For O_CLOEXEC and O_NONBLOCK */
|
|
#include <linux/kmemcheck.h>
|
|
#include <linux/rcupdate.h>
|
|
#include <linux/jump_label.h>
|
|
#include <uapi/linux/net.h>
|
|
|
|
struct poll_table_struct;
|
|
struct pipe_inode_info;
|
|
struct inode;
|
|
struct file;
|
|
struct net;
|
|
|
|
#define SOCK_ASYNC_NOSPACE 0
|
|
#define SOCK_ASYNC_WAITDATA 1
|
|
#define SOCK_NOSPACE 2
|
|
#define SOCK_PASSCRED 3
|
|
#define SOCK_PASSSEC 4
|
|
#define SOCK_EXTERNALLY_ALLOCATED 5
|
|
|
|
#ifndef ARCH_HAS_SOCKET_TYPES
|
|
/**
|
|
* enum sock_type - Socket types
|
|
* @SOCK_STREAM: stream (connection) socket
|
|
* @SOCK_DGRAM: datagram (conn.less) socket
|
|
* @SOCK_RAW: raw socket
|
|
* @SOCK_RDM: reliably-delivered message
|
|
* @SOCK_SEQPACKET: sequential packet socket
|
|
* @SOCK_DCCP: Datagram Congestion Control Protocol socket
|
|
* @SOCK_PACKET: linux specific way of getting packets at the dev level.
|
|
* For writing rarp and other similar things on the user level.
|
|
*
|
|
* When adding some new socket type please
|
|
* grep ARCH_HAS_SOCKET_TYPE include/asm-* /socket.h, at least MIPS
|
|
* overrides this enum for binary compat reasons.
|
|
*/
|
|
enum sock_type {
|
|
SOCK_STREAM = 1,
|
|
SOCK_DGRAM = 2,
|
|
SOCK_RAW = 3,
|
|
SOCK_RDM = 4,
|
|
SOCK_SEQPACKET = 5,
|
|
SOCK_DCCP = 6,
|
|
SOCK_PACKET = 10,
|
|
};
|
|
|
|
#define SOCK_MAX (SOCK_PACKET + 1)
|
|
/* Mask which covers at least up to SOCK_MASK-1. The
|
|
* remaining bits are used as flags. */
|
|
#define SOCK_TYPE_MASK 0xf
|
|
|
|
/* Flags for socket, socketpair, accept4 */
|
|
#define SOCK_CLOEXEC O_CLOEXEC
|
|
#ifndef SOCK_NONBLOCK
|
|
#define SOCK_NONBLOCK O_NONBLOCK
|
|
#endif
|
|
|
|
#endif /* ARCH_HAS_SOCKET_TYPES */
|
|
|
|
enum sock_shutdown_cmd {
|
|
SHUT_RD,
|
|
SHUT_WR,
|
|
SHUT_RDWR,
|
|
};
|
|
|
|
struct socket_wq {
|
|
/* Note: wait MUST be first field of socket_wq */
|
|
wait_queue_head_t wait;
|
|
struct fasync_struct *fasync_list;
|
|
struct rcu_head rcu;
|
|
} ____cacheline_aligned_in_smp;
|
|
|
|
/**
|
|
* struct socket - general BSD socket
|
|
* @state: socket state (%SS_CONNECTED, etc)
|
|
* @type: socket type (%SOCK_STREAM, etc)
|
|
* @flags: socket flags (%SOCK_ASYNC_NOSPACE, etc)
|
|
* @ops: protocol specific socket operations
|
|
* @file: File back pointer for gc
|
|
* @sk: internal networking protocol agnostic socket representation
|
|
* @wq: wait queue for several uses
|
|
*/
|
|
struct socket {
|
|
socket_state state;
|
|
|
|
kmemcheck_bitfield_begin(type);
|
|
short type;
|
|
kmemcheck_bitfield_end(type);
|
|
|
|
unsigned long flags;
|
|
|
|
struct socket_wq __rcu *wq;
|
|
|
|
struct file *file;
|
|
struct sock *sk;
|
|
const struct proto_ops *ops;
|
|
};
|
|
|
|
struct vm_area_struct;
|
|
struct page;
|
|
struct kiocb;
|
|
struct sockaddr;
|
|
struct msghdr;
|
|
struct module;
|
|
|
|
struct proto_ops {
|
|
int family;
|
|
struct module *owner;
|
|
int (*release) (struct socket *sock);
|
|
int (*bind) (struct socket *sock,
|
|
struct sockaddr *myaddr,
|
|
int sockaddr_len);
|
|
int (*connect) (struct socket *sock,
|
|
struct sockaddr *vaddr,
|
|
int sockaddr_len, int flags);
|
|
int (*socketpair)(struct socket *sock1,
|
|
struct socket *sock2);
|
|
int (*accept) (struct socket *sock,
|
|
struct socket *newsock, int flags);
|
|
int (*getname) (struct socket *sock,
|
|
struct sockaddr *addr,
|
|
int *sockaddr_len, int peer);
|
|
unsigned int (*poll) (struct file *file, struct socket *sock,
|
|
struct poll_table_struct *wait);
|
|
int (*ioctl) (struct socket *sock, unsigned int cmd,
|
|
unsigned long arg);
|
|
#ifdef CONFIG_COMPAT
|
|
int (*compat_ioctl) (struct socket *sock, unsigned int cmd,
|
|
unsigned long arg);
|
|
#endif
|
|
int (*listen) (struct socket *sock, int len);
|
|
int (*shutdown) (struct socket *sock, int flags);
|
|
int (*setsockopt)(struct socket *sock, int level,
|
|
int optname, char __user *optval, unsigned int optlen);
|
|
int (*getsockopt)(struct socket *sock, int level,
|
|
int optname, char __user *optval, int __user *optlen);
|
|
#ifdef CONFIG_COMPAT
|
|
int (*compat_setsockopt)(struct socket *sock, int level,
|
|
int optname, char __user *optval, unsigned int optlen);
|
|
int (*compat_getsockopt)(struct socket *sock, int level,
|
|
int optname, char __user *optval, int __user *optlen);
|
|
#endif
|
|
int (*sendmsg) (struct kiocb *iocb, struct socket *sock,
|
|
struct msghdr *m, size_t total_len);
|
|
/* Notes for implementing recvmsg:
|
|
* ===============================
|
|
* msg->msg_namelen should get updated by the recvmsg handlers
|
|
* iff msg_name != NULL. It is by default 0 to prevent
|
|
* returning uninitialized memory to user space. The recvfrom
|
|
* handlers can assume that msg.msg_name is either NULL or has
|
|
* a minimum size of sizeof(struct sockaddr_storage).
|
|
*/
|
|
int (*recvmsg) (struct kiocb *iocb, struct socket *sock,
|
|
struct msghdr *m, size_t total_len,
|
|
int flags);
|
|
int (*mmap) (struct file *file, struct socket *sock,
|
|
struct vm_area_struct * vma);
|
|
ssize_t (*sendpage) (struct socket *sock, struct page *page,
|
|
int offset, size_t size, int flags);
|
|
ssize_t (*splice_read)(struct socket *sock, loff_t *ppos,
|
|
struct pipe_inode_info *pipe, size_t len, unsigned int flags);
|
|
int (*set_peek_off)(struct sock *sk, int val);
|
|
};
|
|
|
|
#define DECLARE_SOCKADDR(type, dst, src) \
|
|
type dst = ({ __sockaddr_check_size(sizeof(*dst)); (type) src; })
|
|
|
|
struct net_proto_family {
|
|
int family;
|
|
int (*create)(struct net *net, struct socket *sock,
|
|
int protocol, int kern);
|
|
struct module *owner;
|
|
};
|
|
|
|
struct iovec;
|
|
struct kvec;
|
|
|
|
enum {
|
|
SOCK_WAKE_IO,
|
|
SOCK_WAKE_WAITD,
|
|
SOCK_WAKE_SPACE,
|
|
SOCK_WAKE_URG,
|
|
};
|
|
|
|
int sock_wake_async(struct socket *sk, int how, int band);
|
|
int sock_register(const struct net_proto_family *fam);
|
|
void sock_unregister(int family);
|
|
int __sock_create(struct net *net, int family, int type, int proto,
|
|
struct socket **res, int kern);
|
|
int sock_create(int family, int type, int proto, struct socket **res);
|
|
int sock_create_kern(int family, int type, int proto, struct socket **res);
|
|
int sock_create_lite(int family, int type, int proto, struct socket **res);
|
|
void sock_release(struct socket *sock);
|
|
int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t len);
|
|
int sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,
|
|
int flags);
|
|
struct file *sock_alloc_file(struct socket *sock, int flags, const char *dname);
|
|
struct socket *sockfd_lookup(int fd, int *err);
|
|
struct socket *sock_from_file(struct file *file, int *err);
|
|
#define sockfd_put(sock) fput(sock->file)
|
|
int net_ratelimit(void);
|
|
|
|
#define net_ratelimited_function(function, ...) \
|
|
do { \
|
|
if (net_ratelimit()) \
|
|
function(__VA_ARGS__); \
|
|
} while (0)
|
|
|
|
#define net_emerg_ratelimited(fmt, ...) \
|
|
net_ratelimited_function(pr_emerg, fmt, ##__VA_ARGS__)
|
|
#define net_alert_ratelimited(fmt, ...) \
|
|
net_ratelimited_function(pr_alert, fmt, ##__VA_ARGS__)
|
|
#define net_crit_ratelimited(fmt, ...) \
|
|
net_ratelimited_function(pr_crit, fmt, ##__VA_ARGS__)
|
|
#define net_err_ratelimited(fmt, ...) \
|
|
net_ratelimited_function(pr_err, fmt, ##__VA_ARGS__)
|
|
#define net_notice_ratelimited(fmt, ...) \
|
|
net_ratelimited_function(pr_notice, fmt, ##__VA_ARGS__)
|
|
#define net_warn_ratelimited(fmt, ...) \
|
|
net_ratelimited_function(pr_warn, fmt, ##__VA_ARGS__)
|
|
#define net_info_ratelimited(fmt, ...) \
|
|
net_ratelimited_function(pr_info, fmt, ##__VA_ARGS__)
|
|
#define net_dbg_ratelimited(fmt, ...) \
|
|
net_ratelimited_function(pr_debug, fmt, ##__VA_ARGS__)
|
|
|
|
bool __net_get_random_once(void *buf, int nbytes, bool *done,
|
|
struct static_key *done_key);
|
|
|
|
#define net_get_random_once(buf, nbytes) \
|
|
({ \
|
|
bool ___ret = false; \
|
|
static bool ___done = false; \
|
|
static struct static_key ___once_key = \
|
|
STATIC_KEY_INIT_TRUE; \
|
|
if (static_key_true(&___once_key)) \
|
|
___ret = __net_get_random_once(buf, \
|
|
nbytes, \
|
|
&___done, \
|
|
&___once_key); \
|
|
___ret; \
|
|
})
|
|
|
|
int kernel_sendmsg(struct socket *sock, struct msghdr *msg, struct kvec *vec,
|
|
size_t num, size_t len);
|
|
int kernel_recvmsg(struct socket *sock, struct msghdr *msg, struct kvec *vec,
|
|
size_t num, size_t len, int flags);
|
|
|
|
int kernel_bind(struct socket *sock, struct sockaddr *addr, int addrlen);
|
|
int kernel_listen(struct socket *sock, int backlog);
|
|
int kernel_accept(struct socket *sock, struct socket **newsock, int flags);
|
|
int kernel_connect(struct socket *sock, struct sockaddr *addr, int addrlen,
|
|
int flags);
|
|
int kernel_getsockname(struct socket *sock, struct sockaddr *addr,
|
|
int *addrlen);
|
|
int kernel_getpeername(struct socket *sock, struct sockaddr *addr,
|
|
int *addrlen);
|
|
int kernel_getsockopt(struct socket *sock, int level, int optname, char *optval,
|
|
int *optlen);
|
|
int kernel_setsockopt(struct socket *sock, int level, int optname, char *optval,
|
|
unsigned int optlen);
|
|
int kernel_sendpage(struct socket *sock, struct page *page, int offset,
|
|
size_t size, int flags);
|
|
int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg);
|
|
int kernel_sock_shutdown(struct socket *sock, enum sock_shutdown_cmd how);
|
|
|
|
#define MODULE_ALIAS_NETPROTO(proto) \
|
|
MODULE_ALIAS("net-pf-" __stringify(proto))
|
|
|
|
#define MODULE_ALIAS_NET_PF_PROTO(pf, proto) \
|
|
MODULE_ALIAS("net-pf-" __stringify(pf) "-proto-" __stringify(proto))
|
|
|
|
#define MODULE_ALIAS_NET_PF_PROTO_TYPE(pf, proto, type) \
|
|
MODULE_ALIAS("net-pf-" __stringify(pf) "-proto-" __stringify(proto) \
|
|
"-type-" __stringify(type))
|
|
|
|
#define MODULE_ALIAS_NET_PF_PROTO_NAME(pf, proto, name) \
|
|
MODULE_ALIAS("net-pf-" __stringify(pf) "-proto-" __stringify(proto) \
|
|
name)
|
|
#endif /* _LINUX_NET_H */
|