Skip to content

Commit

Permalink
net/sched: Make etf report drops on error_queue
Browse files Browse the repository at this point in the history
Use the socket error queue for reporting dropped packets if the
socket has enabled that feature through the SO_TXTIME API.

Packets are dropped either on enqueue() if they aren't accepted by the
qdisc or on dequeue() if the system misses their deadline. Those are
reported as different errors so applications can react accordingly.

Userspace can retrieve the errors through the socket error queue and the
corresponding cmsg interfaces. A struct sock_extended_err* is used for
returning the error data, and the packet's timestamp can be retrieved by
adding both ee_data and ee_info fields as e.g.:

    ((__u64) serr->ee_data << 32) + serr->ee_info

This feature is disabled by default and must be explicitly enabled by
applications. Enabling it can bring some overhead for the Tx cycles
of the application.

Signed-off-by: Jesus Sanchez-Palencia <jesus.sanchez-palencia@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Jesus Sanchez-Palencia authored and David S. Miller committed Jul 4, 2018
1 parent 3048cf8 commit 4b15c70
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 4 deletions.
3 changes: 2 additions & 1 deletion include/net/sock.h
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,8 @@ struct sock {

u8 sk_clockid;
u8 sk_txtime_deadline_mode : 1,
sk_txtime_unused : 7;
sk_txtime_report_errors : 1,
sk_txtime_unused : 6;

struct socket *sk_socket;
void *sk_user_data;
Expand Down
4 changes: 4 additions & 0 deletions include/uapi/linux/errqueue.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,16 @@ struct sock_extended_err {
#define SO_EE_ORIGIN_ICMP6 3
#define SO_EE_ORIGIN_TXSTATUS 4
#define SO_EE_ORIGIN_ZEROCOPY 5
#define SO_EE_ORIGIN_TXTIME 6
#define SO_EE_ORIGIN_TIMESTAMPING SO_EE_ORIGIN_TXSTATUS

#define SO_EE_OFFENDER(ee) ((struct sockaddr*)((ee)+1))

#define SO_EE_CODE_ZEROCOPY_COPIED 1

#define SO_EE_CODE_TXTIME_INVALID_PARAM 1
#define SO_EE_CODE_TXTIME_MISSED 2

/**
* struct scm_timestamping - timestamps exposed through cmsg
*
Expand Down
5 changes: 4 additions & 1 deletion include/uapi/linux/net_tstamp.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,11 @@ struct scm_ts_pktinfo {
*/
enum txtime_flags {
SOF_TXTIME_DEADLINE_MODE = (1 << 0),
SOF_TXTIME_REPORT_ERRORS = (1 << 1),

SOF_TXTIME_FLAGS_MASK = (SOF_TXTIME_DEADLINE_MODE)
SOF_TXTIME_FLAGS_LAST = SOF_TXTIME_REPORT_ERRORS,
SOF_TXTIME_FLAGS_MASK = (SOF_TXTIME_FLAGS_LAST - 1) |
SOF_TXTIME_FLAGS_LAST
};

struct sock_txtime {
Expand Down
4 changes: 4 additions & 0 deletions net/core/sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -1087,6 +1087,8 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
sk->sk_clockid = sk_txtime.clockid;
sk->sk_txtime_deadline_mode =
!!(sk_txtime.flags & SOF_TXTIME_DEADLINE_MODE);
sk->sk_txtime_report_errors =
!!(sk_txtime.flags & SOF_TXTIME_REPORT_ERRORS);
}
break;

Expand Down Expand Up @@ -1429,6 +1431,8 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
v.txtime.clockid = sk->sk_clockid;
v.txtime.flags |= sk->sk_txtime_deadline_mode ?
SOF_TXTIME_DEADLINE_MODE : 0;
v.txtime.flags |= sk->sk_txtime_report_errors ?
SOF_TXTIME_REPORT_ERRORS : 0;
break;

default:
Expand Down
35 changes: 33 additions & 2 deletions net/sched/sch_etf.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/errqueue.h>
#include <linux/rbtree.h>
#include <linux/skbuff.h>
#include <linux/posix-timers.h>
Expand Down Expand Up @@ -123,15 +124,44 @@ static void reset_watchdog(struct Qdisc *sch)
qdisc_watchdog_schedule_ns(&q->watchdog, ktime_to_ns(next));
}

static void report_sock_error(struct sk_buff *skb, u32 err, u8 code)
{
struct sock_exterr_skb *serr;
struct sk_buff *clone;
ktime_t txtime = skb->tstamp;

if (!skb->sk || !(skb->sk->sk_txtime_report_errors))
return;

clone = skb_clone(skb, GFP_ATOMIC);
if (!clone)
return;

serr = SKB_EXT_ERR(clone);
serr->ee.ee_errno = err;
serr->ee.ee_origin = SO_EE_ORIGIN_TXTIME;
serr->ee.ee_type = 0;
serr->ee.ee_code = code;
serr->ee.ee_pad = 0;
serr->ee.ee_data = (txtime >> 32); /* high part of tstamp */
serr->ee.ee_info = txtime; /* low part of tstamp */

if (sock_queue_err_skb(skb->sk, clone))
kfree_skb(clone);
}

static int etf_enqueue_timesortedlist(struct sk_buff *nskb, struct Qdisc *sch,
struct sk_buff **to_free)
{
struct etf_sched_data *q = qdisc_priv(sch);
struct rb_node **p = &q->head.rb_node, *parent = NULL;
ktime_t txtime = nskb->tstamp;

if (!is_packet_valid(sch, nskb))
if (!is_packet_valid(sch, nskb)) {
report_sock_error(nskb, EINVAL,
SO_EE_CODE_TXTIME_INVALID_PARAM);
return qdisc_drop(nskb, sch, to_free);
}

while (*p) {
struct sk_buff *skb;
Expand Down Expand Up @@ -174,6 +204,8 @@ static void timesortedlist_erase(struct Qdisc *sch, struct sk_buff *skb,
if (drop) {
struct sk_buff *to_free = NULL;

report_sock_error(skb, ECANCELED, SO_EE_CODE_TXTIME_MISSED);

qdisc_drop(skb, sch, &to_free);
kfree_skb_list(to_free);
qdisc_qstats_overlimit(sch);
Expand All @@ -199,7 +231,6 @@ static struct sk_buff *etf_dequeue_timesortedlist(struct Qdisc *sch)
now = q->get_time();

/* Drop if packet has expired while in queue. */
/* FIXME: Must return error on the socket's error queue */
if (ktime_before(skb->tstamp, now)) {
timesortedlist_erase(sch, skb, true);
skb = NULL;
Expand Down

0 comments on commit 4b15c70

Please sign in to comment.