net-timestamp: no-payload option
Add timestamping option SOF_TIMESTAMPING_OPT_TSONLY. For transmit timestamps, this loops timestamps on top of empty packets. Doing so reduces the pressure on SO_RCVBUF. Payload inspection and cmsg reception (aside from timestamps) are no longer possible. This works together with a follow on patch that allows administrators to only allow tx timestamping if it does not loop payload or metadata. Signed-off-by: Willem de Bruijn <willemb@google.com> ---- Changes (rfc -> v1) - add documentation - remove unnecessary skb->len test (thanks to Richard Cochran) Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
9766e97af1
commit
49ca0d8bfa
@ -162,6 +162,27 @@ SOF_TIMESTAMPING_OPT_CMSG:
|
|||||||
option IP_PKTINFO simultaneously.
|
option IP_PKTINFO simultaneously.
|
||||||
|
|
||||||
|
|
||||||
|
SOF_TIMESTAMPING_OPT_TSONLY:
|
||||||
|
|
||||||
|
Applies to transmit timestamps only. Makes the kernel return the
|
||||||
|
timestamp as a cmsg alongside an empty packet, as opposed to
|
||||||
|
alongside the original packet. This reduces the amount of memory
|
||||||
|
charged to the socket's receive budget (SO_RCVBUF) and delivers
|
||||||
|
the timestamp even if sysctl net.core.tstamp_allow_data is 0.
|
||||||
|
This option disables SOF_TIMESTAMPING_OPT_CMSG.
|
||||||
|
|
||||||
|
|
||||||
|
New applications are encouraged to pass SOF_TIMESTAMPING_OPT_ID to
|
||||||
|
disambiguate timestamps and SOF_TIMESTAMPING_OPT_TSONLY to operate
|
||||||
|
regardless of the setting of sysctl net.core.tstamp_allow_data.
|
||||||
|
|
||||||
|
An exception is when a process needs additional cmsg data, for
|
||||||
|
instance SOL_IP/IP_PKTINFO to detect the egress network interface.
|
||||||
|
Then pass option SOF_TIMESTAMPING_OPT_CMSG. This option depends on
|
||||||
|
having access to the contents of the original packet, so cannot be
|
||||||
|
combined with SOF_TIMESTAMPING_OPT_TSONLY.
|
||||||
|
|
||||||
|
|
||||||
1.4 Bytestream Timestamps
|
1.4 Bytestream Timestamps
|
||||||
|
|
||||||
The SO_TIMESTAMPING interface supports timestamping of bytes in a
|
The SO_TIMESTAMPING interface supports timestamping of bytes in a
|
||||||
|
@ -24,8 +24,9 @@ enum {
|
|||||||
SOF_TIMESTAMPING_TX_SCHED = (1<<8),
|
SOF_TIMESTAMPING_TX_SCHED = (1<<8),
|
||||||
SOF_TIMESTAMPING_TX_ACK = (1<<9),
|
SOF_TIMESTAMPING_TX_ACK = (1<<9),
|
||||||
SOF_TIMESTAMPING_OPT_CMSG = (1<<10),
|
SOF_TIMESTAMPING_OPT_CMSG = (1<<10),
|
||||||
|
SOF_TIMESTAMPING_OPT_TSONLY = (1<<11),
|
||||||
|
|
||||||
SOF_TIMESTAMPING_LAST = SOF_TIMESTAMPING_OPT_CMSG,
|
SOF_TIMESTAMPING_LAST = SOF_TIMESTAMPING_OPT_TSONLY,
|
||||||
SOF_TIMESTAMPING_MASK = (SOF_TIMESTAMPING_LAST - 1) |
|
SOF_TIMESTAMPING_MASK = (SOF_TIMESTAMPING_LAST - 1) |
|
||||||
SOF_TIMESTAMPING_LAST
|
SOF_TIMESTAMPING_LAST
|
||||||
};
|
};
|
||||||
|
@ -3710,19 +3710,28 @@ void __skb_tstamp_tx(struct sk_buff *orig_skb,
|
|||||||
struct sock *sk, int tstype)
|
struct sock *sk, int tstype)
|
||||||
{
|
{
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
|
bool tsonly = sk->sk_tsflags & SOF_TIMESTAMPING_OPT_TSONLY;
|
||||||
|
|
||||||
if (!sk)
|
if (!sk)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (hwtstamps)
|
if (tsonly)
|
||||||
*skb_hwtstamps(orig_skb) = *hwtstamps;
|
skb = alloc_skb(0, GFP_ATOMIC);
|
||||||
else
|
else
|
||||||
orig_skb->tstamp = ktime_get_real();
|
skb = skb_clone(orig_skb, GFP_ATOMIC);
|
||||||
|
|
||||||
skb = skb_clone(orig_skb, GFP_ATOMIC);
|
|
||||||
if (!skb)
|
if (!skb)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (tsonly) {
|
||||||
|
skb_shinfo(skb)->tx_flags = skb_shinfo(orig_skb)->tx_flags;
|
||||||
|
skb_shinfo(skb)->tskey = skb_shinfo(orig_skb)->tskey;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hwtstamps)
|
||||||
|
*skb_hwtstamps(skb) = *hwtstamps;
|
||||||
|
else
|
||||||
|
skb->tstamp = ktime_get_real();
|
||||||
|
|
||||||
__skb_complete_tx_timestamp(skb, sk, tstype);
|
__skb_complete_tx_timestamp(skb, sk, tstype);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(__skb_tstamp_tx);
|
EXPORT_SYMBOL_GPL(__skb_tstamp_tx);
|
||||||
|
@ -483,7 +483,7 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
|
|||||||
|
|
||||||
serr = SKB_EXT_ERR(skb);
|
serr = SKB_EXT_ERR(skb);
|
||||||
|
|
||||||
if (sin) {
|
if (sin && skb->len) {
|
||||||
sin->sin_family = AF_INET;
|
sin->sin_family = AF_INET;
|
||||||
sin->sin_addr.s_addr = *(__be32 *)(skb_network_header(skb) +
|
sin->sin_addr.s_addr = *(__be32 *)(skb_network_header(skb) +
|
||||||
serr->addr_offset);
|
serr->addr_offset);
|
||||||
@ -496,8 +496,9 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
|
|||||||
sin = &errhdr.offender;
|
sin = &errhdr.offender;
|
||||||
memset(sin, 0, sizeof(*sin));
|
memset(sin, 0, sizeof(*sin));
|
||||||
|
|
||||||
if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP ||
|
if (skb->len &&
|
||||||
ipv4_pktinfo_prepare_errqueue(sk, skb, serr->ee.ee_origin)) {
|
(serr->ee.ee_origin == SO_EE_ORIGIN_ICMP ||
|
||||||
|
ipv4_pktinfo_prepare_errqueue(sk, skb, serr->ee.ee_origin))) {
|
||||||
sin->sin_family = AF_INET;
|
sin->sin_family = AF_INET;
|
||||||
sin->sin_addr.s_addr = ip_hdr(skb)->saddr;
|
sin->sin_addr.s_addr = ip_hdr(skb)->saddr;
|
||||||
if (inet_sk(sk)->cmsg_flags)
|
if (inet_sk(sk)->cmsg_flags)
|
||||||
|
@ -369,7 +369,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
|
|||||||
|
|
||||||
serr = SKB_EXT_ERR(skb);
|
serr = SKB_EXT_ERR(skb);
|
||||||
|
|
||||||
if (sin) {
|
if (sin && skb->len) {
|
||||||
const unsigned char *nh = skb_network_header(skb);
|
const unsigned char *nh = skb_network_header(skb);
|
||||||
sin->sin6_family = AF_INET6;
|
sin->sin6_family = AF_INET6;
|
||||||
sin->sin6_flowinfo = 0;
|
sin->sin6_flowinfo = 0;
|
||||||
@ -394,8 +394,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
|
|||||||
memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err));
|
memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err));
|
||||||
sin = &errhdr.offender;
|
sin = &errhdr.offender;
|
||||||
memset(sin, 0, sizeof(*sin));
|
memset(sin, 0, sizeof(*sin));
|
||||||
|
if (serr->ee.ee_origin != SO_EE_ORIGIN_LOCAL && skb->len) {
|
||||||
if (serr->ee.ee_origin != SO_EE_ORIGIN_LOCAL) {
|
|
||||||
sin->sin6_family = AF_INET6;
|
sin->sin6_family = AF_INET6;
|
||||||
if (np->rxopt.all) {
|
if (np->rxopt.all) {
|
||||||
if (serr->ee.ee_origin != SO_EE_ORIGIN_ICMP &&
|
if (serr->ee.ee_origin != SO_EE_ORIGIN_ICMP &&
|
||||||
|
@ -42,6 +42,11 @@ void rxrpc_UDP_error_report(struct sock *sk)
|
|||||||
_leave("UDP socket errqueue empty");
|
_leave("UDP socket errqueue empty");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!skb->len) {
|
||||||
|
_leave("UDP empty message");
|
||||||
|
kfree_skb(skb);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
rxrpc_new_skb(skb);
|
rxrpc_new_skb(skb);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user