Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions doc/configuration.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1343,6 +1343,7 @@ The following keywords are supported in the "global" section :
- maxsslconn
- maxsslrate
- maxzlibmem
- mptcp
- no-memory-trimming
- noepoll
- noevports
Expand Down Expand Up @@ -2971,6 +2972,14 @@ maxzlibmem <number>
with "show info" on the line "MaxZlibMemUsage", the memory used by zlib is
"ZlibMemUsage" in bytes.

mptcp
Uses MPTCP instead of TCP. Multipath TCP or MPTCP is an extension to the
standard TCP and is described in RFC 8684. It allows a device to make use of
multiple interfaces at once to send and receive TCP packets over a single
MPTCP connection. MPTCP can aggregate the bandwidth of multiple interfaces or
prefer the one with the lowest latency, it also allows a fail-over if one path
is down, and the traffic is seamlessly reinjected on other paths.

no-memory-trimming
Disables memory trimming ("malloc_trim") at a few moments where attempts are
made to reclaim lots of memory (on memory shortage or on reload). Trimming
Expand Down Expand Up @@ -27664,6 +27673,27 @@ report this to the maintainers.
range can or must be specified.
It is considered as an alias of 'stream+ipv4@'.

'mptcp@<address>[:port1[-port2]]' following <address> is considered as an IPv4
or IPv6 address depending of the syntax but
socket type and transport method is forced to
"stream", with the MPTCP protocol. Depending
on the statement using this address, a port or
a port range can or must be specified.

'mptcp4@<address>[:port1[-port2]]' following <address> is always considered as
an IPv4 address but socket type and transport
method is forced to "stream", with the MPTCP
protocol. Depending on the statement using
this address, a port or port range can or
must be specified.

'mptcp6@<address>[:port1[-port2]]' following <address> is always considered as
an IPv6 address but socket type and transport
method is forced to "stream", with the MPTCP
protocol. Depending on the statement using
this address, a port or port range can or
must be specified.

'udp@<address>[:port1[-port2]]' following <address> is considered as an IPv4
or IPv6 address depending of the syntax but
socket type and transport method is forced to
Expand Down
2 changes: 2 additions & 0 deletions include/haproxy/proto_rhttp.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include <haproxy/listener-t.h>
#include <haproxy/receiver-t.h>

extern struct protocol proto_rhttp;

int rhttp_bind_receiver(struct receiver *rx, char **errmsg);

int rhttp_bind_listener(struct listener *listener, char *errmsg, int errlen);
Expand Down
5 changes: 5 additions & 0 deletions include/haproxy/protocol-t.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ enum proto_type {
#define PROTO_F_REUSEPORT_SUPPORTED 0x00000001 /* SO_REUSEPORT is supported */
#define PROTO_F_REUSEPORT_TESTED 0x00000002 /* SO_REUSEPORT support was tested */

/* Define IPPROTO_MPTCP if not defined by the libC */
#ifndef IPPROTO_MPTCP
#define IPPROTO_MPTCP 262
#endif

/* protocol families define standard functions acting on a given address family
* for a socket implementation, such as AF_INET/PF_INET for example.
*/
Expand Down
4 changes: 2 additions & 2 deletions include/haproxy/protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,10 @@ int protocol_enable_all(void);
* supported protocol types, and ctrl_type of either SOCK_STREAM or SOCK_DGRAM
* depending on the requested values, or NULL if not found.
*/
static inline struct protocol *protocol_lookup(int family, enum proto_type proto_type, int ctrl_dgram)
static inline struct protocol *protocol_lookup(int family, enum proto_type proto_type, int alt)
{
if (family >= 0 && family < AF_CUST_MAX)
return __protocol_by_family[family][proto_type][!!ctrl_dgram];
return __protocol_by_family[family][proto_type][!!alt];
return NULL;
}

Expand Down
65 changes: 65 additions & 0 deletions reg-tests/tcp-rules/default_rules_mptcp.vtc
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
varnishtest "Test declaration of TCP rules in default sections with mptcp in the config"

feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.5-dev0)'"
feature cmd "test \"$(cat /proc/sys/net/mptcp/enabled)\" = 1"
feature ignore_unknown_macro

server s1 {
rxreq
txresp
expect req.http.x-test1-frt == "def_front"
expect req.http.x-test1-bck == "def_back"
} -start

haproxy h1 -conf {
global
mptcp

defaults common
mode http
timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
timeout server "${HAPROXY_TEST_TIMEOUT-5s}"

defaults def_front from common
tcp-request connection accept
tcp-request session accept
tcp-request inspect-delay 5s
tcp-request content set-var(txn.test1) "str(def_front)"
tcp-request content accept

defaults def_back from common
tcp-request inspect-delay 5s
tcp-request content set-var(txn.test1) "str(def_back)"
tcp-request content accept

tcp-response inspect-delay 5s
tcp-response content set-var(txn.test2) "str(def_back)"
tcp-response content accept

frontend fe from def_front
bind "fd@${feh1}"
tcp-request connection reject
tcp-request session reject
tcp-request content reject

http-request set-header x-test1-frt "%[var(txn.test1)]"

default_backend be

backend be from def_back
tcp-response content reject

http-request set-header x-test1-bck "%[var(txn.test1)]"
http-response set-header x-test2 "%[var(txn.test2)]"

server s1 ${s1_addr}:${s1_port}

} -start

client c1 -connect ${h1_feh1_sock} {
txreq -req GET -url /
rxresp
expect resp.status == 200
expect resp.http.x-test2 == "def_back"
} -run
18 changes: 17 additions & 1 deletion src/cfgparse-global.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
#include <haproxy/log.h>
#include <haproxy/peers.h>
#include <haproxy/protocol.h>
#include <haproxy/proto_rhttp.h>
#include <haproxy/proto_tcp.h>
#include <haproxy/tools.h>

int cluster_secret_isset;
Expand Down Expand Up @@ -51,7 +53,7 @@ static const char *common_kw_list[] = {
"presetenv", "unsetenv", "resetenv", "strict-limits", "localpeer",
"numa-cpu-mapping", "defaults", "listen", "frontend", "backend",
"peers", "resolvers", "cluster-secret", "no-quic", "limited-quic",
"stats-file",
"stats-file", "mptcp",
NULL /* must be last */
};

Expand Down Expand Up @@ -1319,6 +1321,20 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
HA_ATOMIC_STORE(&global.anon_key, tmp);
}
}
else if (strcmp(args[0], "mptcp") == 0) {
if (alertif_too_many_args(0, file, linenum, args, &err_code))
goto out;
#ifdef __linux__
proto_tcpv4.sock_prot = IPPROTO_MPTCP;
proto_tcpv6.sock_prot = IPPROTO_MPTCP;
proto_rhttp.sock_prot = IPPROTO_MPTCP;
#else
ha_alert("parsing [%s:%d]: '%s' is only supported on Linux.\n",
file, linenum, args[0]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
#endif
}
else {
struct cfg_kw_list *kwl;
const char *best;
Expand Down
3 changes: 2 additions & 1 deletion src/cfgparse.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
#include <haproxy/peers.h>
#include <haproxy/pool.h>
#include <haproxy/protocol.h>
#include <haproxy/proto_tcp.h>
#include <haproxy/proxy.h>
#include <haproxy/resolvers.h>
#include <haproxy/sample.h>
Expand Down Expand Up @@ -1193,7 +1194,7 @@ int cfg_parse_mailers(const char *file, int linenum, char **args, int kwm)
goto out;
}

if (proto->sock_prot != IPPROTO_TCP) {
if (proto->sock_prot != proto_tcpv4.sock_prot) {
ha_alert("parsing [%s:%d] : '%s %s' : TCP not supported for this address family.\n",
file, linenum, args[0], args[1]);
err_code |= ERR_ALERT | ERR_FATAL;
Expand Down
29 changes: 29 additions & 0 deletions src/proto_tcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,35 @@ struct protocol proto_tcpv6 = {

INITCALL1(STG_REGISTER, protocol_register, &proto_tcpv6);

#ifdef __linux__
/* The content of TCP proto will be copied later */
struct protocol proto_mptcpv4 = {
.receivers = LIST_HEAD_INIT(proto_mptcpv4.receivers),
};
struct protocol proto_mptcpv6 = {
.receivers = LIST_HEAD_INIT(proto_mptcpv6.receivers),
};

static void mptcp_protocol_register(struct protocol *proto_mptcp,
struct protocol *proto_tcp, char *name)
{
struct list receivers = proto_mptcp->receivers;

memcpy(proto_mptcp, proto_tcp, sizeof(struct protocol));

strlcpy2(proto_mptcp->name, name, PROTO_NAME_LEN);
proto_mptcp->sock_prot = IPPROTO_MPTCP;
proto_mptcp->receivers = receivers;

protocol_register(proto_mptcp);
}

INITCALL3(STG_REGISTER, mptcp_protocol_register, &proto_mptcpv4, &proto_tcpv4,
"mptcpv4");
INITCALL3(STG_REGISTER, mptcp_protocol_register, &proto_mptcpv6, &proto_tcpv6,
"mptcpv6");
#endif

/* Binds ipv4/ipv6 address <local> to socket <fd>, unless <flags> is set, in which
* case we try to bind <remote>. <flags> is a 2-bit field consisting of :
* - 0 : ignore remote address (may even be a NULL pointer)
Expand Down
4 changes: 3 additions & 1 deletion src/protocol.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ void protocol_register(struct protocol *proto)
LIST_APPEND(&protocols, &proto->list);
__protocol_by_family[sock_domain]
[proto->proto_type]
[proto->xprt_type == PROTO_TYPE_DGRAM] = proto;
[proto->xprt_type == PROTO_TYPE_DGRAM ||
proto->sock_prot == IPPROTO_MPTCP] = proto;

HA_SPIN_UNLOCK(PROTO_LOCK, &proto_lock);
}

Expand Down
24 changes: 23 additions & 1 deletion src/tools.c
Original file line number Diff line number Diff line change
Expand Up @@ -972,6 +972,7 @@ struct sockaddr_storage *str2sa_range(const char *str, int *port, int *low, int
int new_fd = -1;
enum proto_type proto_type = 0; // to shut gcc warning
int ctrl_type = 0; // to shut gcc warning
int mptcp = 0;

portl = porth = porta = 0;
if (fqdn)
Expand Down Expand Up @@ -1058,6 +1059,13 @@ struct sockaddr_storage *str2sa_range(const char *str, int *port, int *low, int
proto_type = PROTO_TYPE_STREAM;
ctrl_type = SOCK_STREAM;
}
else if (strncmp(str2, "mptcp4@", 7) == 0) {
str2 += 7;
ss.ss_family = AF_INET;
proto_type = PROTO_TYPE_STREAM;
ctrl_type = SOCK_STREAM;
mptcp = 1;
}
else if (strncmp(str2, "udp4@", 5) == 0) {
str2 += 5;
ss.ss_family = AF_INET;
Expand All @@ -1070,6 +1078,13 @@ struct sockaddr_storage *str2sa_range(const char *str, int *port, int *low, int
proto_type = PROTO_TYPE_STREAM;
ctrl_type = SOCK_STREAM;
}
else if (strncmp(str2, "mptcp6@", 7) == 0) {
str2 += 7;
ss.ss_family = AF_INET;
proto_type = PROTO_TYPE_STREAM;
ctrl_type = SOCK_STREAM;
mptcp = 1;
}
else if (strncmp(str2, "udp6@", 5) == 0) {
str2 += 5;
ss.ss_family = AF_INET6;
Expand All @@ -1082,6 +1097,13 @@ struct sockaddr_storage *str2sa_range(const char *str, int *port, int *low, int
proto_type = PROTO_TYPE_STREAM;
ctrl_type = SOCK_STREAM;
}
else if (strncmp(str2, "mptcp@", 6) == 0) {
str2 += 6;
ss.ss_family = AF_UNSPEC;
proto_type = PROTO_TYPE_STREAM;
ctrl_type = SOCK_STREAM;
mptcp = 1;
}
else if (strncmp(str2, "udp@", 4) == 0) {
str2 += 4;
ss.ss_family = AF_UNSPEC;
Expand Down Expand Up @@ -1360,7 +1382,7 @@ struct sockaddr_storage *str2sa_range(const char *str, int *port, int *low, int
*/
new_proto = protocol_lookup(ss.ss_family,
proto_type,
ctrl_type == SOCK_DGRAM);
ctrl_type == SOCK_DGRAM || !!mptcp);

if (!new_proto && (!fqdn || !*fqdn) && (ss.ss_family != AF_CUST_EXISTING_FD)) {
memprintf(err, "unsupported %s protocol for %s family %d address '%s'%s",
Expand Down