Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix cobalt_should_drop() and reduce memory reallocations #136

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 11 additions & 3 deletions cobalt_compat.h
Expand Up @@ -87,7 +87,8 @@ static inline void qdisc_qstats_drop(struct Qdisc *sch)
(config_enabled(option##_MODULE) && config_enabled(MODULE)))
#endif

#if KERNEL_VERSION(4, 4, 114) > LINUX_VERSION_CODE
#if ((KERNEL_VERSION(4, 4, 114) > LINUX_VERSION_CODE) && \
((KERNEL_VERSION(4, 1, 50) > LINUX_VERSION_CODE) || (KERNEL_VERSION(4, 2, 0) <= LINUX_VERSION_CODE)))
static inline unsigned int __tcp_hdrlen(const struct tcphdr *th)
{
return th->doff * 4;
Expand All @@ -103,6 +104,13 @@ static inline int skb_try_make_writable(struct sk_buff *skb,
}
#endif

#if KERNEL_VERSION(4, 11, 0) > LINUX_VERSION_CODE
static inline int skb_mac_offset(const struct sk_buff *skb)
{
return skb_mac_header(skb) - skb->data;
}
#endif

#if KERNEL_VERSION(4, 7, 0) > LINUX_VERSION_CODE
#define nla_put_u64_64bit(skb, attrtype, value, padattr) nla_put_u64(skb, attrtype, value)
#endif
Expand Down Expand Up @@ -134,15 +142,15 @@ not in 3.17
3.18.37
not in 3.19
not in 4.0
4.1.27 onward
4.1.28 onward
not in 4.2
not in 4.3
4.4.11 onward
4.5.5 onward
*/
#if ((KERNEL_VERSION(3, 0, 0) <= LINUX_VERSION_CODE) && (KERNEL_VERSION(3, 16, 37) > LINUX_VERSION_CODE)) || \
((KERNEL_VERSION(3, 18, 0) <= LINUX_VERSION_CODE) && (KERNEL_VERSION(3, 18, 37) > LINUX_VERSION_CODE)) || \
((KERNEL_VERSION(4, 1, 0) <= LINUX_VERSION_CODE) && (KERNEL_VERSION(4, 1, 27) > LINUX_VERSION_CODE)) || \
((KERNEL_VERSION(4, 1, 0) <= LINUX_VERSION_CODE) && (KERNEL_VERSION(4, 1, 28) > LINUX_VERSION_CODE)) || \
((KERNEL_VERSION(4, 4, 0) <= LINUX_VERSION_CODE) && (KERNEL_VERSION(4, 4, 11) > LINUX_VERSION_CODE)) || \
((KERNEL_VERSION(4, 5, 0) <= LINUX_VERSION_CODE) && (KERNEL_VERSION(4, 5, 5) > LINUX_VERSION_CODE))
#define qdisc_tree_reduce_backlog(_a, _b, _c) qdisc_tree_decrease_qlen(_a, _b)
Expand Down
99 changes: 81 additions & 18 deletions sch_cake.c
Expand Up @@ -508,6 +508,52 @@ static bool cobalt_queue_empty(struct cobalt_vars *vars,
return down;
}

static __be16 cake_skb_proto(const struct sk_buff *skb)
{
unsigned int offset = skb_mac_offset(skb) + sizeof(struct ethhdr);
__be16 proto = skb->protocol;
struct vlan_hdr vhdr, *vh;

while (proto == htons(ETH_P_8021Q) || proto == htons(ETH_P_8021AD)) {
vh = skb_header_pointer(skb, offset, sizeof(vhdr), &vhdr);
if (!vh)
break;

proto = vh->h_vlan_encapsulated_proto;
offset += sizeof(vhdr);
}

return proto;
}

static int cobalt_set_ce(struct sk_buff *skb)
{
int wlen = skb_network_offset(skb);

switch (cake_skb_proto(skb)) {
case htons(ETH_P_IP):
wlen += sizeof(struct iphdr);
if (!pskb_may_pull(skb, wlen) ||
skb_try_make_writable(skb, wlen))
return 0;

return IP_ECN_set_ce(ip_hdr(skb));

case htons(ETH_P_IPV6):
wlen += sizeof(struct ipv6hdr);
if (!pskb_may_pull(skb, wlen) ||
skb_try_make_writable(skb, wlen))
return 0;

return IP6_ECN_set_ce(skb, ipv6_hdr(skb));

default:
return 0;
}

return 0;
}

/* Call this with a freshly dequeued packet for possible congestion marking.
* Returns true as an instruction to drop the packet, false for delivery.
*/
Expand Down Expand Up @@ -560,7 +606,7 @@ static bool cobalt_should_drop(struct cobalt_vars *vars,

if (next_due && vars->dropping) {
/* Use ECN mark if possible, otherwise drop */
drop = !(vars->ecn_marked = INET_ECN_set_ce(skb));
drop = !(vars->ecn_marked = cobalt_set_ce(skb));

vars->count++;
if (!vars->count)
Expand Down Expand Up @@ -596,10 +642,6 @@ static bool cobalt_should_drop(struct cobalt_vars *vars,
}

#if IS_REACHABLE(CONFIG_NF_CONNTRACK)
#if KERNEL_VERSION(4, 0, 0) > LINUX_VERSION_CODE
#define tc_skb_protocol(_skb) \
(vlan_tx_tag_present(_skb) ? _skb->vlan_proto : _skb->protocol)
#endif

static void cake_update_flowkeys(struct flow_keys *keys,
const struct sk_buff *skb)
Expand All @@ -609,7 +651,7 @@ static void cake_update_flowkeys(struct flow_keys *keys,
struct nf_conn *ct;
bool rev = false;

if (tc_skb_protocol(skb) != htons(ETH_P_IP))
if (cake_skb_proto(skb) != htons(ETH_P_IP))
return;

ct = nf_ct_get(skb, &ctinfo);
Expand Down Expand Up @@ -1621,30 +1663,51 @@ static unsigned int cake_drop(struct Qdisc *sch, struct sk_buff **to_free)

static u8 cake_handle_diffserv(struct sk_buff *skb, u16 wash)
{
int wlen = skb_network_offset(skb);
const int offset = skb_network_offset(skb);
u8 dscp;
u16 *buf, buf_;

switch (tc_skb_protocol(skb)) {
switch (cake_skb_proto(skb)) {
case htons(ETH_P_IP):
wlen += sizeof(struct iphdr);
if (!pskb_may_pull(skb, wlen) ||
skb_try_make_writable(skb, wlen))
buf = skb_header_pointer(skb, offset, sizeof(buf_), &buf_);

if (unlikely(buf == NULL))
return 0;

dscp = ipv4_get_dsfield(ip_hdr(skb)) >> 2;
if (wash && dscp)
/* ToS is in the second byte of iphdr
*/
dscp = ipv4_get_dsfield((struct iphdr *)buf) >> 2;

if (wash && dscp) {
const int wlen = offset + sizeof(struct iphdr);
if (!pskb_may_pull(skb, wlen) ||
skb_try_make_writable(skb, wlen))
return 0;

ipv4_change_dsfield(ip_hdr(skb), INET_ECN_MASK, 0);
}

return dscp;

case htons(ETH_P_IPV6):
wlen += sizeof(struct ipv6hdr);
if (!pskb_may_pull(skb, wlen) ||
skb_try_make_writable(skb, wlen))
buf = skb_header_pointer(skb, offset, sizeof(buf_), &buf_);

if (unlikely(buf == NULL))
return 0;

dscp = ipv6_get_dsfield(ipv6_hdr(skb)) >> 2;
if (wash && dscp)
/* Traffic class is in the first and the second bytes of ipv6hdr
*/
dscp = ipv6_get_dsfield((struct ipv6hdr *)buf) >> 2;

if (wash && dscp) {
const int wlen = offset + sizeof(struct ipv6hdr);
if (!pskb_may_pull(skb, wlen) ||
skb_try_make_writable(skb, wlen))
return 0;

ipv6_change_dsfield(ipv6_hdr(skb), INET_ECN_MASK, 0);
}

return dscp;

case htons(ETH_P_ARP):
Expand Down