Skip to content

Commit 4b15c70

Browse files
Jesus Sanchez-Palenciadavem330
authored andcommitted
net/sched: Make etf report drops on error_queue
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 <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 3048cf8 commit 4b15c70

File tree

5 files changed

+47
-4
lines changed

5 files changed

+47
-4
lines changed

include/net/sock.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,8 @@ struct sock {
481481

482482
u8 sk_clockid;
483483
u8 sk_txtime_deadline_mode : 1,
484-
sk_txtime_unused : 7;
484+
sk_txtime_report_errors : 1,
485+
sk_txtime_unused : 6;
485486

486487
struct socket *sk_socket;
487488
void *sk_user_data;

include/uapi/linux/errqueue.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,16 @@ struct sock_extended_err {
2020
#define SO_EE_ORIGIN_ICMP6 3
2121
#define SO_EE_ORIGIN_TXSTATUS 4
2222
#define SO_EE_ORIGIN_ZEROCOPY 5
23+
#define SO_EE_ORIGIN_TXTIME 6
2324
#define SO_EE_ORIGIN_TIMESTAMPING SO_EE_ORIGIN_TXSTATUS
2425

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

2728
#define SO_EE_CODE_ZEROCOPY_COPIED 1
2829

30+
#define SO_EE_CODE_TXTIME_INVALID_PARAM 1
31+
#define SO_EE_CODE_TXTIME_MISSED 2
32+
2933
/**
3034
* struct scm_timestamping - timestamps exposed through cmsg
3135
*

include/uapi/linux/net_tstamp.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,11 @@ struct scm_ts_pktinfo {
147147
*/
148148
enum txtime_flags {
149149
SOF_TXTIME_DEADLINE_MODE = (1 << 0),
150+
SOF_TXTIME_REPORT_ERRORS = (1 << 1),
150151

151-
SOF_TXTIME_FLAGS_MASK = (SOF_TXTIME_DEADLINE_MODE)
152+
SOF_TXTIME_FLAGS_LAST = SOF_TXTIME_REPORT_ERRORS,
153+
SOF_TXTIME_FLAGS_MASK = (SOF_TXTIME_FLAGS_LAST - 1) |
154+
SOF_TXTIME_FLAGS_LAST
152155
};
153156

154157
struct sock_txtime {

net/core/sock.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1087,6 +1087,8 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
10871087
sk->sk_clockid = sk_txtime.clockid;
10881088
sk->sk_txtime_deadline_mode =
10891089
!!(sk_txtime.flags & SOF_TXTIME_DEADLINE_MODE);
1090+
sk->sk_txtime_report_errors =
1091+
!!(sk_txtime.flags & SOF_TXTIME_REPORT_ERRORS);
10901092
}
10911093
break;
10921094

@@ -1429,6 +1431,8 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
14291431
v.txtime.clockid = sk->sk_clockid;
14301432
v.txtime.flags |= sk->sk_txtime_deadline_mode ?
14311433
SOF_TXTIME_DEADLINE_MODE : 0;
1434+
v.txtime.flags |= sk->sk_txtime_report_errors ?
1435+
SOF_TXTIME_REPORT_ERRORS : 0;
14321436
break;
14331437

14341438
default:

net/sched/sch_etf.c

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <linux/kernel.h>
1212
#include <linux/string.h>
1313
#include <linux/errno.h>
14+
#include <linux/errqueue.h>
1415
#include <linux/rbtree.h>
1516
#include <linux/skbuff.h>
1617
#include <linux/posix-timers.h>
@@ -123,15 +124,44 @@ static void reset_watchdog(struct Qdisc *sch)
123124
qdisc_watchdog_schedule_ns(&q->watchdog, ktime_to_ns(next));
124125
}
125126

127+
static void report_sock_error(struct sk_buff *skb, u32 err, u8 code)
128+
{
129+
struct sock_exterr_skb *serr;
130+
struct sk_buff *clone;
131+
ktime_t txtime = skb->tstamp;
132+
133+
if (!skb->sk || !(skb->sk->sk_txtime_report_errors))
134+
return;
135+
136+
clone = skb_clone(skb, GFP_ATOMIC);
137+
if (!clone)
138+
return;
139+
140+
serr = SKB_EXT_ERR(clone);
141+
serr->ee.ee_errno = err;
142+
serr->ee.ee_origin = SO_EE_ORIGIN_TXTIME;
143+
serr->ee.ee_type = 0;
144+
serr->ee.ee_code = code;
145+
serr->ee.ee_pad = 0;
146+
serr->ee.ee_data = (txtime >> 32); /* high part of tstamp */
147+
serr->ee.ee_info = txtime; /* low part of tstamp */
148+
149+
if (sock_queue_err_skb(skb->sk, clone))
150+
kfree_skb(clone);
151+
}
152+
126153
static int etf_enqueue_timesortedlist(struct sk_buff *nskb, struct Qdisc *sch,
127154
struct sk_buff **to_free)
128155
{
129156
struct etf_sched_data *q = qdisc_priv(sch);
130157
struct rb_node **p = &q->head.rb_node, *parent = NULL;
131158
ktime_t txtime = nskb->tstamp;
132159

133-
if (!is_packet_valid(sch, nskb))
160+
if (!is_packet_valid(sch, nskb)) {
161+
report_sock_error(nskb, EINVAL,
162+
SO_EE_CODE_TXTIME_INVALID_PARAM);
134163
return qdisc_drop(nskb, sch, to_free);
164+
}
135165

136166
while (*p) {
137167
struct sk_buff *skb;
@@ -174,6 +204,8 @@ static void timesortedlist_erase(struct Qdisc *sch, struct sk_buff *skb,
174204
if (drop) {
175205
struct sk_buff *to_free = NULL;
176206

207+
report_sock_error(skb, ECANCELED, SO_EE_CODE_TXTIME_MISSED);
208+
177209
qdisc_drop(skb, sch, &to_free);
178210
kfree_skb_list(to_free);
179211
qdisc_qstats_overlimit(sch);
@@ -199,7 +231,6 @@ static struct sk_buff *etf_dequeue_timesortedlist(struct Qdisc *sch)
199231
now = q->get_time();
200232

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

0 commit comments

Comments
 (0)