-
Notifications
You must be signed in to change notification settings - Fork 2.8k
/
edt.h
91 lines (78 loc) · 2.36 KB
/
edt.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
/* Copyright Authors of Cilium */
#pragma once
#include <bpf/ctx/ctx.h>
#include "common.h"
#include "time.h"
/* From XDP layer, we neither go through an egress hook nor qdisc
* from here, hence nothing to be set.
*/
#if defined(ENABLE_BANDWIDTH_MANAGER) && __ctx_is == __ctx_skb
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__type(key, struct edt_id);
__type(value, struct edt_info);
__uint(pinning, LIBBPF_PIN_BY_NAME);
__uint(max_entries, THROTTLE_MAP_SIZE);
__uint(map_flags, BPF_F_NO_PREALLOC);
} THROTTLE_MAP __section_maps_btf;
static __always_inline void edt_set_aggregate(struct __ctx_buff *ctx,
__u32 aggregate)
{
/* 16 bit as current used aggregate, and preserved in host ns. */
ctx->queue_mapping = aggregate;
}
static __always_inline __u32 edt_get_aggregate(struct __ctx_buff *ctx)
{
__u32 aggregate = ctx->queue_mapping;
/* We need to reset queue mapping here such that new mapping will
* be performed based on skb hash. See netdev_pick_tx().
*/
ctx->queue_mapping = 0;
return aggregate;
}
static __always_inline int
edt_sched_departure(struct __ctx_buff *ctx, __be16 proto)
{
__u64 delay, now, t, t_next;
struct edt_id aggregate;
struct edt_info *info;
if (!eth_is_supported_ethertype(proto))
return CTX_ACT_OK;
if (proto != bpf_htons(ETH_P_IP) &&
proto != bpf_htons(ETH_P_IPV6))
return CTX_ACT_OK;
aggregate.id = edt_get_aggregate(ctx);
if (!aggregate.id)
return CTX_ACT_OK;
info = map_lookup_elem(&THROTTLE_MAP, &aggregate);
if (!info)
return CTX_ACT_OK;
now = ktime_get_ns();
t = ctx->tstamp;
if (t < now)
t = now;
delay = ((__u64)ctx_wire_len(ctx)) * NSEC_PER_SEC / info->bps;
t_next = READ_ONCE(info->t_last) + delay;
if (t_next <= t) {
WRITE_ONCE(info->t_last, t);
return CTX_ACT_OK;
}
/* FQ implements a drop horizon, see also 39d010504e6b ("net_sched:
* sch_fq: add horizon attribute"). However, we explicitly need the
* drop horizon here to i) avoid having t_last messed up and ii) to
* potentially allow for per aggregate control.
*/
if (t_next - now >= info->t_horizon_drop)
return CTX_ACT_DROP;
WRITE_ONCE(info->t_last, t_next);
ctx->tstamp = t_next;
return CTX_ACT_OK;
}
#else
static __always_inline void
edt_set_aggregate(struct __ctx_buff *ctx __maybe_unused,
__u32 aggregate __maybe_unused)
{
}
#endif /* ENABLE_BANDWIDTH_MANAGER */