Page MenuHomeFreeBSD

tcp: implement throttling of challenge ACKs
ClosedPublic

Authored by tuexen on Jul 22 2024, 7:02 PM.
Tags
None
Referenced Files
F100667796: D46066.id.diff
Fri, Oct 18, 3:03 AM
F100665319: D46066.id141236.diff
Fri, Oct 18, 2:09 AM
F100665264: D46066.id141401.diff
Fri, Oct 18, 2:08 AM
F100665252: D46066.id141290.diff
Fri, Oct 18, 2:08 AM
Unknown Object (File)
Thu, Oct 3, 2:47 AM
Unknown Object (File)
Wed, Sep 25, 8:01 AM
Unknown Object (File)
Sep 9 2024, 5:19 AM
Unknown Object (File)
Sep 8 2024, 7:40 AM

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Skipped
Unit
Tests Skipped

Event Timeline

cc requested changes to this revision.Jul 23 2024, 6:18 PM
cc added a subscriber: cc.
cc added inline comments.
sys/netinet/tcp_subr.c
2186

typo: per TCP connections ==> per TCP connection

2194–2196

If ACK war protection is disabled, are we going to send challenge ACK or not?

I thought if ACK war protection is disabled, we should send unlimited challenge ACKs.

reference:
ctf_ack_war_checks()

This revision now requires changes to proceed.Jul 23 2024, 6:18 PM
tuexen marked 2 inline comments as done.

Address issues raised by cc@.

sys/netinet/tcp_subr.c
2186

Fixed.

2194–2196

Fixed.

sys/netinet/tcp_subr.c
2194

A little bit less than perfect, I think. For example, tcp_ack_war_time_window requires a zero check within the epoch check. It can be like this:

	if (tcp_ack_war_time_window > 0 && tcp_ack_war_cnt > 0) {
		// check rate limit
		// if under limit, pass through; else, just return
	} 
	// send challenge ACK
sys/netinet/tcp_subr.c
2194

I am using the negation of your condition. So were is the difference?

cc added inline comments.
sys/netinet/tcp_subr.c
2194

I am using the negation of your condition. So were is the difference?

On a second thought, you are right.

This revision is now accepted and ready to land.Jul 24 2024, 1:24 PM
sys/netinet/tcp_subr.c
2194

Still, I recommend the cleaner approach, which saves the local variable send_challenge_ack and the else branch.

Just saw https://reviews.freebsd.org/D46068. If this patch has not been committed, we can still further revise it, so that D46068 can be cleaner on function re-use.

I think the logic here can be split into two functions, such that the refined logic 1 on checking if we should send ACK can be re-used across multiple places.

logic 1:

bool
is_ack_unlimited(struct tcpcb *tp)
{
    /* focus on checking the epoch and
     * if should send ACK, return true; else return false
     */ 
}

logic 2:

void
tcp_send_challenge_ack(struct tcpcb *tp, struct tcphdr *th, struct mbuf *m)
{
    if (is_ack_unlimited(tp)) {.
       tcp_respond();
    ....
    }
}
In D46066#1050919, @cc wrote:

Just saw https://reviews.freebsd.org/D46068. If this patch has not been committed, we can still further revise it, so that D46068 can be cleaner on function re-use.

I think the logic here can be split into two functions, such that the refined logic 1 on checking if we should send ACK can be re-used across multiple places.

logic 1:

bool
is_ack_unlimited(struct tcpcb *tp)
{
    /* focus on checking the epoch and
     * if should send ACK, return true; else return false
     */ 
}

logic 2:

void
tcp_send_challenge_ack(struct tcpcb *tp, struct tcphdr *th, struct mbuf *m)
{
    if (is_ack_unlimited(tp)) {.
       tcp_respond();
    ....
    }
}

I don't get the point. Eventually, all places should use tcp_send_challenge_ack(), I think. But that is multiple commits away.

In D46066#1050919, @cc wrote:

Just saw https://reviews.freebsd.org/D46068. If this patch has not been committed, we can still further revise it, so that D46068 can be cleaner on function re-use.

I think the logic here can be split into two functions, such that the refined logic 1 on checking if we should send ACK can be re-used across multiple places.

logic 1:

bool
is_ack_unlimited(struct tcpcb *tp)
{
    /* focus on checking the epoch and
     * if should send ACK, return true; else return false
     */ 
}

logic 2:

void
tcp_send_challenge_ack(struct tcpcb *tp, struct tcphdr *th, struct mbuf *m)
{
    if (is_ack_unlimited(tp)) {.
       tcp_respond();
    ....
    }
}

I don't get the point. Eventually, all places should use tcp_send_challenge_ack(), I think. But that is multiple commits away.

For example, ctf_ack_war_checks() can be simply refined as this:

ctf_ack_war_checks()
{
    if (is_ack_unlimited(tp)) {
        tp->t_flags |= TF_ACKNOW;
    } else {
        tp->t_flags &= ~TF_ACKNOW;
    }
}