Skip to content

Commit

Permalink
conntrack: Add option to enable TCP liberal mode.
Browse files Browse the repository at this point in the history
Reported-at: https://mail.openvswitch.org/pipermail/ovs-dev/2019-May/359188.html
Signed-off-by: Darrell Ball <dlu998@gmail.com>
Signed-off-by: 0-day Robot <robot@bytheb.org>
  • Loading branch information
darball1 authored and ovsrobot committed May 30, 2019
1 parent eef8538 commit 983c252
Show file tree
Hide file tree
Showing 13 changed files with 299 additions and 16 deletions.
1 change: 1 addition & 0 deletions NEWS
Expand Up @@ -23,6 +23,7 @@ Post-v2.11.0
* New action "check_pkt_len".
* Port configuration with "other-config:priority-tags" now has a mode
that retains the 802.1Q header even if VLAN and priority are both zero.
* Add option to enable, disable and query TCP liberal mode in conntrack.
- OVSDB:
* OVSDB clients can now resynchronize with clustered servers much more
quickly after a brief disconnection, saving bandwidth and CPU time.
Expand Down
6 changes: 4 additions & 2 deletions lib/conntrack-private.h
Expand Up @@ -170,8 +170,10 @@ struct conntrack {
struct hindex alg_expectation_refs OVS_GUARDED; /* For lookup from
* control context. */

/* Fragmentation handling context. */
struct ipf *ipf;
struct ipf *ipf; /* Fragmentation handling context. */
atomic_bool tcp_liberal; /* TCP liberal mode sequence number verification;
when enabled, this disables most sequence
number verification; disabled by default. */
};

/* Lock acquisition order:
Expand Down
30 changes: 17 additions & 13 deletions lib/conntrack-tcp.c
Expand Up @@ -272,16 +272,18 @@ tcp_conn_update(struct conntrack *ct, struct conn *conn_,

int ackskew = check_ackskew ? dst->seqlo - ack : 0;
#define MAXACKWINDOW (0xffff + 1500) /* 1500 is an arbitrary fudge factor */
if (SEQ_GEQ(src->seqhi, end)
/* Last octet inside other's window space */
&& SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws))
/* Retrans: not more than one window back */
&& (ackskew >= -MAXACKWINDOW)
/* Acking not more than one reassembled fragment backwards */
&& (ackskew <= (MAXACKWINDOW << sws))
/* Acking not more than one window forward */
if (((SEQ_GEQ(src->seqhi, end)
/* Last octet inside other's window space */
&& SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws))
/* Retrans: not more than one window back */
&& ackskew >= -MAXACKWINDOW
/* Acking not more than one reassembled fragment backwards */
&& ackskew <= (MAXACKWINDOW << sws))
|| conntrack_get_tcp_liberal(ct))
/* Acking not more than one window forward */
&& ((tcp_flags & TCP_RST) == 0 || orig_seq == src->seqlo
|| (orig_seq == src->seqlo + 1) || (orig_seq + 1 == src->seqlo))) {
|| (orig_seq == src->seqlo + 1)
|| (orig_seq + 1 == src->seqlo))) {
/* Require an exact/+1 sequence match on resets when possible */

/* update max window */
Expand Down Expand Up @@ -333,10 +335,12 @@ tcp_conn_update(struct conntrack *ct, struct conn *conn_,
} else if ((dst->state < CT_DPIF_TCPS_SYN_SENT
|| dst->state >= CT_DPIF_TCPS_FIN_WAIT_2
|| src->state >= CT_DPIF_TCPS_FIN_WAIT_2)
&& SEQ_GEQ(src->seqhi + MAXACKWINDOW, end)
/* Within a window forward of the originating packet */
&& SEQ_GEQ(seq, src->seqlo - MAXACKWINDOW)) {
/* Within a window backward of the originating packet */
&& ((SEQ_GEQ(src->seqhi + MAXACKWINDOW, end)
/* Within a window forward of the originating packet */
&& SEQ_GEQ(seq, src->seqlo - MAXACKWINDOW))
/* Within a window backward of the originating packet */
|| (conntrack_get_tcp_liberal(ct)
&& (tcp_flags & TCP_RST) == 0))) {

/*
* This currently handles three situations:
Expand Down
15 changes: 15 additions & 0 deletions lib/conntrack.c
Expand Up @@ -2383,6 +2383,21 @@ conntrack_get_nconns(struct conntrack *ct, uint32_t *nconns)
return 0;
}

int
conntrack_set_tcp_liberal(struct conntrack *ct, bool enabled)
{
atomic_store_relaxed(&ct->tcp_liberal, enabled);
return 0;
}

bool
conntrack_get_tcp_liberal(struct conntrack *ct)
{
bool enabled;
atomic_read_relaxed(&ct->tcp_liberal, &enabled);
return enabled;
}

/* This function must be called with the ct->resources read lock taken. */
static struct alg_exp_node *
expectation_lookup(struct hmap *alg_expectations, const struct conn_key *key,
Expand Down
2 changes: 2 additions & 0 deletions lib/conntrack.h
Expand Up @@ -118,6 +118,8 @@ int conntrack_flush_tuple(struct conntrack *, const struct ct_dpif_tuple *,
int conntrack_set_maxconns(struct conntrack *ct, uint32_t maxconns);
int conntrack_get_maxconns(struct conntrack *ct, uint32_t *maxconns);
int conntrack_get_nconns(struct conntrack *ct, uint32_t *nconns);
int conntrack_set_tcp_liberal(struct conntrack *ct, bool enabled);
bool conntrack_get_tcp_liberal(struct conntrack *ct);
struct ipf *conntrack_ipf_ctx(struct conntrack *ct);

#endif /* conntrack.h */
16 changes: 16 additions & 0 deletions lib/ct-dpif.c
Expand Up @@ -164,6 +164,22 @@ ct_dpif_get_nconns(struct dpif *dpif, uint32_t *nconns)
: EOPNOTSUPP);
}

int
ct_dpif_set_tcp_liberal(struct dpif *dpif, bool enabled)
{
return (dpif->dpif_class->ct_set_tcp_liberal
? dpif->dpif_class->ct_set_tcp_liberal(dpif, enabled)
: EOPNOTSUPP);
}

int
ct_dpif_get_tcp_liberal(struct dpif *dpif, bool *enabled)
{
return (dpif->dpif_class->ct_get_tcp_liberal
? dpif->dpif_class->ct_get_tcp_liberal(dpif, enabled)
: EOPNOTSUPP);
}

int
ct_dpif_set_limits(struct dpif *dpif, const uint32_t *default_limit,
const struct ovs_list *zone_limits)
Expand Down
2 changes: 2 additions & 0 deletions lib/ct-dpif.h
Expand Up @@ -234,6 +234,8 @@ int ct_dpif_flush(struct dpif *, const uint16_t *zone,
int ct_dpif_set_maxconns(struct dpif *dpif, uint32_t maxconns);
int ct_dpif_get_maxconns(struct dpif *dpif, uint32_t *maxconns);
int ct_dpif_get_nconns(struct dpif *dpif, uint32_t *nconns);
int ct_dpif_set_tcp_liberal(struct dpif *dpif, bool enabled);
int ct_dpif_get_tcp_liberal(struct dpif *dpif, bool *enabled);
int ct_dpif_set_limits(struct dpif *dpif, const uint32_t *default_limit,
const struct ovs_list *);
int ct_dpif_get_limits(struct dpif *dpif, uint32_t *default_limit,
Expand Down
64 changes: 63 additions & 1 deletion lib/dpctl.c
Expand Up @@ -1759,6 +1759,62 @@ dpctl_ct_get_nconns(int argc, const char *argv[],
return error;
}

static int
dpctl_ct_set_tcp_liberal__(int argc, const char *argv[],
struct dpctl_params *dpctl_p, bool enabled)
{
struct dpif *dpif;
int error = opt_dpif_open(argc, argv, dpctl_p, 3, &dpif);
if (!error) {
error = ct_dpif_set_tcp_liberal(dpif, enabled);
if (!error) {
dpctl_print(dpctl_p,
"%s TCP liberal mode successful",
enabled ? "enabling" : "disabling");
} else {
dpctl_error(dpctl_p, error,
"%s TCP liberal mode failed",
enabled ? "enabling" : "disabling");
}
dpif_close(dpif);
}
return error;
}

static int
dpctl_ct_enable_tcp_liberal(int argc, const char *argv[],
struct dpctl_params *dpctl_p)
{
return dpctl_ct_set_tcp_liberal__(argc, argv, dpctl_p, true);
}

static int
dpctl_ct_disable_tcp_liberal(int argc, const char *argv[],
struct dpctl_params *dpctl_p)
{
return dpctl_ct_set_tcp_liberal__(argc, argv, dpctl_p, false);
}

static int
dpctl_ct_get_tcp_liberal(int argc, const char *argv[],
struct dpctl_params *dpctl_p)
{
struct dpif *dpif;
int error = opt_dpif_open(argc, argv, dpctl_p, 2, &dpif);
if (!error) {
bool enabled;
error = ct_dpif_get_tcp_liberal(dpif, &enabled);
if (!error) {
dpctl_print(dpctl_p, "TCP liberal mode: %s\n",
enabled ? "enabled" : "disabled");
} else {
dpctl_error(dpctl_p, error, "TCP liberal mode query failed");
}
dpif_close(dpif);
}
return error;
}

static int
dpctl_ct_set_limits(int argc, const char *argv[],
struct dpctl_params *dpctl_p)
Expand Down Expand Up @@ -2428,9 +2484,15 @@ static const struct dpctl_command all_commands[] = {
{ "ct-stats-show", "[dp] [zone=N]",
0, 3, dpctl_ct_stats_show, DP_RO },
{ "ct-bkts", "[dp] [gt=N]", 0, 2, dpctl_ct_bkts, DP_RO },
{ "ct-set-maxconns", "[dp] maxconns", 1, 2, dpctl_ct_set_maxconns, DP_RW },
{ "ct-set-maxconns", "[dp] maxconns", 1, 2, dpctl_ct_set_maxconns,
DP_RW },
{ "ct-get-maxconns", "[dp]", 0, 1, dpctl_ct_get_maxconns, DP_RO },
{ "ct-get-nconns", "[dp]", 0, 1, dpctl_ct_get_nconns, DP_RO },
{ "ct-enable-tcp-liberal", "[dp]", 0, 1, dpctl_ct_enable_tcp_liberal,
DP_RW },
{ "ct-disable-tcp-liberal", "[dp]", 0, 1, dpctl_ct_disable_tcp_liberal,
DP_RW },
{ "ct-get-tcp-liberal", "[dp]", 0, 1, dpctl_ct_get_tcp_liberal, DP_RO },
{ "ct-set-limits", "[dp] [default=L] [zone=N,limit=L]...", 1, INT_MAX,
dpctl_ct_set_limits, DP_RO },
{ "ct-del-limits", "[dp] zone=N1[,N2]...", 1, 2, dpctl_ct_del_limits,
Expand Down
16 changes: 16 additions & 0 deletions lib/dpctl.man
Expand Up @@ -318,6 +318,22 @@ Prints the current number of connection tracker entries on \fIdp\fR.
Only supported for userspace datapath.
.
.TP
\*(DX\fBct\-enable\-tcp\-liberal\fR [\fIdp\fR]
.TQ
\*(DX\fBct\-disable\-tcp\-liberal\fR [\fIdp\fR]
Enables or disables TCP liberal mode for the userspace connection tracker.
If enabled, TCP sequence number verification will be mostly disabled, except
for TCP resets. This is disabled by default to enforce better security and
should only be enabled if absolutely required. This command is only
supported for the userspace datapath, but can be otherwise enabled in the
Linux kernel datapath.
.
.TP
\*(DX\fBct\-get\-tcp\-liberal\fR [\fIdp\fR]
Prints whether TCP liberal mode is enabled or disabled on \fIdp\fR.
Only supported for userspace datapath.
.
.TP
\*(DX\fBct\-set\-limits\fR [\fIdp\fR] [\fBdefault=\fIdefault_limit\fR] [\fBzone=\fIzone\fR,\fBlimit=\fIlimit\fR]...
Sets the maximum allowed number of connections in a connection tracking
zone. A specific \fIzone\fR may be set to \fIlimit\fR, and multiple zones
Expand Down
18 changes: 18 additions & 0 deletions lib/dpif-netdev.c
Expand Up @@ -7351,6 +7351,22 @@ dpif_netdev_ct_get_nconns(struct dpif *dpif, uint32_t *nconns)
return conntrack_get_nconns(dp->conntrack, nconns);
}

static int
dpif_netdev_ct_set_tcp_liberal(struct dpif *dpif, bool enabled)
{
struct dp_netdev *dp = get_dp_netdev(dpif);

return conntrack_set_tcp_liberal(dp->conntrack, enabled);
}

static int
dpif_netdev_ct_get_tcp_liberal(struct dpif *dpif, bool *enabled)
{
struct dp_netdev *dp = get_dp_netdev(dpif);
*enabled = conntrack_get_tcp_liberal(dp->conntrack);
return 0;
}

static int
dpif_netdev_ipf_set_enabled(struct dpif *dpif, bool v6, bool enable)
{
Expand Down Expand Up @@ -7454,6 +7470,8 @@ const struct dpif_class dpif_netdev_class = {
dpif_netdev_ct_set_maxconns,
dpif_netdev_ct_get_maxconns,
dpif_netdev_ct_get_nconns,
dpif_netdev_ct_set_tcp_liberal,
dpif_netdev_ct_get_tcp_liberal,
NULL, /* ct_set_limits */
NULL, /* ct_get_limits */
NULL, /* ct_del_limits */
Expand Down
2 changes: 2 additions & 0 deletions lib/dpif-netlink.c
Expand Up @@ -3429,6 +3429,8 @@ const struct dpif_class dpif_netlink_class = {
NULL, /* ct_set_maxconns */
NULL, /* ct_get_maxconns */
NULL, /* ct_get_nconns */
NULL, /* ct_set_tcp_liberal */
NULL, /* ct_get_tcp_liberal */
dpif_netlink_ct_set_limits,
dpif_netlink_ct_get_limits,
dpif_netlink_ct_del_limits,
Expand Down
5 changes: 5 additions & 0 deletions lib/dpif-provider.h
Expand Up @@ -462,6 +462,11 @@ struct dpif_class {
int (*ct_get_maxconns)(struct dpif *, uint32_t *maxconns);
/* Get number of connections tracked. */
int (*ct_get_nconns)(struct dpif *, uint32_t *nconns);
/* Enable or disable TCP liberal mode. */
int (*ct_set_tcp_liberal)(struct dpif *, bool enabled);
/* Get the TCP liberal mode configuration. */
int (*ct_get_tcp_liberal)(struct dpif *, bool *enabled);


/* Connection tracking per zone limit */

Expand Down

0 comments on commit 983c252

Please sign in to comment.