Currently TCP and UDP each have their own forwarding tables. This is
awkward in a few places, where we need switch statements to select the
correct table. More importantly, it would make things awkward and messy to
extend to other protocols in future, which we're likely to want to do.
Merge the TCP and UDP tables into a single table per (source) pif, with the
protocol given in each rule entry.
Signed-off-by: David Gibson
---
conf.c | 65 +++++++++++------------
flow.c | 22 +++-----
fwd.c | 157 ++++++++++++++++++++++++++++++++++----------------------
fwd.h | 14 +++--
passt.c | 3 ++
passt.h | 5 ++
tcp.c | 9 +---
tcp.h | 2 -
udp.c | 10 +---
udp.h | 4 --
10 files changed, 152 insertions(+), 139 deletions(-)
diff --git a/conf.c b/conf.c
index 80d8106d..00b56161 100644
--- a/conf.c
+++ b/conf.c
@@ -149,12 +149,20 @@ static void conf_ports_range_except(const struct ctx *c, char optname,
{
unsigned delta = to - first;
unsigned base, i;
+ uint8_t proto;
if (first == 0) {
die("Can't forward port 0 for option '-%c %s'",
optname, optarg);
}
+ if (optname == 't' || optname == 'T')
+ proto = IPPROTO_TCP;
+ else if (optname == 'u' || optname == 'U')
+ proto = IPPROTO_UDP;
+ else
+ ASSERT(0);
+
if (addr) {
if (!c->ifi4 && inany_v4(addr)) {
die("IPv4 is disabled, can't use -%c %s",
@@ -184,15 +192,17 @@ static void conf_ports_range_except(const struct ctx *c, char optname,
optname, optarg);
if (c->ifi4) {
- fwd_rule_add(fwd, flags, &inany_loopback4, NULL,
+ fwd_rule_add(fwd, proto, flags,
+ &inany_loopback4, NULL,
base, i - 1, base + delta);
}
if (c->ifi6) {
- fwd_rule_add(fwd, flags, &inany_loopback6, NULL,
+ fwd_rule_add(fwd, proto, flags,
+ &inany_loopback6, NULL,
base, i - 1, base + delta);
}
} else {
- fwd_rule_add(fwd, flags, addr, ifname,
+ fwd_rule_add(fwd, proto, flags, addr, ifname,
base, i - 1, base + delta);
}
base = i - 1;
@@ -1237,15 +1247,11 @@ dns6:
}
}
- info("Inbound TCP forwarding:");
- fwd_rules_print(&c->tcp.fwd_in);
- info("Inbound UDP forwarding:");
- fwd_rules_print(&c->udp.fwd_in);
+ info("Inbound forwarding:");
+ fwd_rules_print(&c->fwd_in);
if (c->mode == MODE_PASTA) {
- info("Outbound TCP forwarding:");
- fwd_rules_print(&c->tcp.fwd_out);
- info("Outbound UDP forwarding:");
- fwd_rules_print(&c->tcp.fwd_out);
+ info("Outbound forwarding:");
+ fwd_rules_print(&c->fwd_out);
}
}
@@ -2115,11 +2121,9 @@ void conf(struct ctx *c, int argc, char **argv)
name = getopt_long(argc, argv, optstring, options, NULL);
if (name == 't') {
- conf_ports(c, name, optarg,
- &c->tcp.fwd_in, &tcp_in_mode);
+ conf_ports(c, name, optarg, &c->fwd_in, &tcp_in_mode);
} else if (name == 'u') {
- conf_ports(c, name, optarg,
- &c->udp.fwd_in, &udp_in_mode);
+ conf_ports(c, name, optarg, &c->fwd_in, &udp_in_mode);
} else if (name == 'D') {
struct in6_addr dns6_tmp;
struct in_addr dns4_tmp;
@@ -2189,13 +2193,10 @@ void conf(struct ctx *c, int argc, char **argv)
do {
name = getopt_long(argc, argv, optstring, options, NULL);
- if (name == 'T') {
- conf_ports(c, name, optarg,
- &c->tcp.fwd_out, &tcp_out_mode);
- } else if (name == 'U') {
- conf_ports(c, name, optarg,
- &c->udp.fwd_out, &udp_out_mode);
- }
+ if (name == 'T')
+ conf_ports(c, name, optarg, &c->fwd_out, &tcp_out_mode);
+ else if (name == 'U')
+ conf_ports(c, name, optarg, &c->fwd_out, &udp_out_mode);
} while (name != -1);
if (!c->ifi4)
@@ -2227,24 +2228,20 @@ void conf(struct ctx *c, int argc, char **argv)
udp_out_mode = fwd_default;
if (tcp_in_mode == FWD_MODE_AUTO) {
- conf_ports_range_except(c, 't', "auto", &c->tcp.fwd_in,
- NULL, NULL, 1, NUM_PORTS - 1,
- NULL, 1, FWD_SCAN);
+ conf_ports_range_except(c, 't', "auto", &c->fwd_in, NULL, NULL,
+ 1, NUM_PORTS - 1, NULL, 1, FWD_SCAN);
}
if (tcp_out_mode == FWD_MODE_AUTO) {
- conf_ports_range_except(c, 'T', "auto", &c->tcp.fwd_out,
- NULL, "lo", 1, NUM_PORTS - 1,
- NULL, 1, FWD_SCAN);
+ conf_ports_range_except(c, 'T', "auto", &c->fwd_out, NULL, "lo",
+ 1, NUM_PORTS - 1, NULL, 1, FWD_SCAN);
}
if (udp_in_mode == FWD_MODE_AUTO) {
- conf_ports_range_except(c, 'u', "auto", &c->udp.fwd_in,
- NULL, NULL, 1, NUM_PORTS - 1,
- NULL, 1, FWD_SCAN);
+ conf_ports_range_except(c, 'u', "auto", &c->fwd_in, NULL, NULL,
+ 1, NUM_PORTS - 1, NULL, 1, FWD_SCAN);
}
if (udp_out_mode == FWD_MODE_AUTO) {
- conf_ports_range_except(c, 'U', "auto", &c->udp.fwd_out,
- NULL, "lo", 1, NUM_PORTS - 1,
- NULL, 1, FWD_SCAN);
+ conf_ports_range_except(c, 'U', "auto", &c->fwd_out, NULL, "lo",
+ 1, NUM_PORTS - 1, NULL, 1, FWD_SCAN);
}
if (!c->quiet)
diff --git a/flow.c b/flow.c
index 4b07697e..edcbf838 100644
--- a/flow.c
+++ b/flow.c
@@ -520,28 +520,18 @@ struct flowside *flow_target(const struct ctx *c, union flow *flow,
break;
case PIF_SPLICE:
- if (proto == IPPROTO_TCP)
- fwd = &c->tcp.fwd_out;
- else if (proto == IPPROTO_UDP)
- fwd = &c->udp.fwd_out;
- else
- goto nofwd;
+ fwd = &c->fwd_out;
- if (!(rule = fwd_rule_search(fwd, ini, rule_hint)))
+ if (!(rule = fwd_rule_search(fwd, ini, proto, rule_hint)))
goto norule;
tgtpif = fwd_nat_from_splice(rule, proto, ini, tgt);
break;
case PIF_HOST:
- if (proto == IPPROTO_TCP)
- fwd = &c->tcp.fwd_in;
- else if (proto == IPPROTO_UDP)
- fwd = &c->udp.fwd_in;
- else
- goto nofwd;
+ fwd = &c->fwd_in;
- if (!(rule = fwd_rule_search(fwd, ini, rule_hint)))
+ if (!(rule = fwd_rule_search(fwd, ini, proto, rule_hint)))
goto norule;
tgtpif = fwd_nat_from_host(c, rule, proto, ini, tgt);
@@ -1023,8 +1013,8 @@ static int flow_migrate_source_rollback(struct ctx *c, unsigned bound, int ret)
debug("...roll back migration");
- if (fwd_listen_sync(c, &c->tcp.fwd_in, &c->tcp.scan_in,
- PIF_HOST, IPPROTO_TCP) < 0)
+ if (fwd_listen_sync(c, &c->fwd_in, PIF_HOST,
+ &c->tcp.scan_in, &c->udp.scan_in) < 0)
die("Failed to re-establish listening sockets");
foreach_established_tcp_flow(flow) {
diff --git a/fwd.c b/fwd.c
index 3e0e1063..75605cba 100644
--- a/fwd.c
+++ b/fwd.c
@@ -334,6 +334,7 @@ bool fwd_port_is_ephemeral(in_port_t port)
/**
* fwd_rule_add() - Add a rule to a forwarding table
* @fwd: Table to add to
+ * @proto: Protocol to forward
* @flags: Flags for this entry
* @addr: Our address to forward (NULL for both 0.0.0.0 and ::)
* @ifname: Only forward from this interface name, if non-empty
@@ -341,7 +342,7 @@ bool fwd_port_is_ephemeral(in_port_t port)
* @last: Last port number to forward
* @to: First port of target port range to map to
*/
-void fwd_rule_add(struct fwd_table *fwd, uint8_t flags,
+void fwd_rule_add(struct fwd_table *fwd, uint8_t proto, uint8_t flags,
const union inany_addr *addr, const char *ifname,
in_port_t first, in_port_t last, in_port_t to)
{
@@ -363,6 +364,10 @@ void fwd_rule_add(struct fwd_table *fwd, uint8_t flags,
char newstr[INANY_ADDRSTRLEN], rulestr[INANY_ADDRSTRLEN];
struct fwd_rule *rule = &fwd->rules[i];
+ if (proto != rule->proto)
+ /* Non-conflicting protocols */
+ continue;
+
if (!inany_matches(addr, fwd_rule_addr(rule)))
/* Non-conflicting addresses */
continue;
@@ -378,6 +383,7 @@ void fwd_rule_add(struct fwd_table *fwd, uint8_t flags,
}
new = &fwd->rules[fwd->count++];
+ new->proto = proto;
new->flags = flags;
if (addr) {
@@ -413,27 +419,30 @@ void fwd_rule_add(struct fwd_table *fwd, uint8_t flags,
* fwd_rule_match() - Does a prospective flow match a given forwarding rule?
* @rule: Forwarding rule
* @ini: Initiating side flow information
+ * @proto: Protocol to match
*
* Returns: true if the rule applies to the flow, false otherwise
*/
static bool fwd_rule_match(const struct fwd_rule *rule,
- const struct flowside *ini)
+ const struct flowside *ini, uint8_t proto)
{
- return inany_matches(&ini->oaddr, fwd_rule_addr(rule)) &&
- ini->oport >= rule->first && ini->oport <= rule->last;
+ return rule->proto == proto &&
+ inany_matches(&ini->oaddr, fwd_rule_addr(rule)) &&
+ ini->oport >= rule->first && ini->oport <= rule->last;
}
/**
* fwd_rule_search() - Find a rule which matches a prospective flow
* @fwd: Forwarding table
* @ini: Initiating side flow information
+ * @proto: Protocol to match
* @hint: Index of the rule in table, if known, otherwise FWD_NO_HINT
*
* Returns: first matching rule, or NULL if there is none
*/
const struct fwd_rule *fwd_rule_search(const struct fwd_table *fwd,
const struct flowside *ini,
- int hint)
+ uint8_t proto, int hint)
{
unsigned i;
@@ -442,7 +451,7 @@ const struct fwd_rule *fwd_rule_search(const struct fwd_table *fwd,
const struct fwd_rule *rule = &fwd->rules[hint];
ASSERT((unsigned)hint < fwd->count);
- if (fwd_rule_match(rule, ini))
+ if (fwd_rule_match(rule, ini, proto))
return rule;
debug("Incorrect rule hint: %s:%hu does not match %s:%hu-%hu",
@@ -453,7 +462,7 @@ const struct fwd_rule *fwd_rule_search(const struct fwd_table *fwd,
}
for (i = 0; i < fwd->count; i++) {
- if (fwd_rule_match(&fwd->rules[i], ini))
+ if (fwd_rule_match(&fwd->rules[i], ini, proto))
return &fwd->rules[i];
}
@@ -481,13 +490,13 @@ void fwd_rules_print(const struct fwd_table *fwd)
scan = " (auto-scan)";
if (rule->first == rule->last) {
- info(" [%s]%s%s:%hu => %hu %s%s",
- addr, percent, rule->ifname,
- rule->first, rule->to, weak, scan);
+ info(" %s [%s]%s%s:%hu => %hu %s%s",
+ ipproto_name(rule->proto), addr, percent,
+ rule->ifname, rule->first, rule->to, weak, scan);
} else {
- info(" [%s]%s%s:%hu-%hu => %hu-%hu %s%s",
- addr, percent, rule->ifname,
- rule->first, rule->last,
+ info(" %s [%s]%s%s:%hu-%hu => %hu-%hu %s%s",
+ ipproto_name(rule->proto), addr, percent,
+ rule->ifname, rule->first, rule->last,
rule->to, rule->last - rule->first + rule->to,
weak, scan);
}
@@ -499,14 +508,13 @@ void fwd_rules_print(const struct fwd_table *fwd)
* @fwd: Forwarding table
* @rule: Forwarding rule
* @pif: Interface to create listening sockets for
- * @proto: Protocol to listen for
* @scanmap: Bitmap of ports to listen for on FWD_SCAN entries
*
* Return: 0 on success, -1 on failure
*/
static int fwd_sync_one(const struct ctx *c, const struct fwd_table *fwd,
- const struct fwd_rule *rule,
- uint8_t pif, uint8_t proto, const uint8_t *scanmap)
+ const struct fwd_rule *rule, uint8_t pif,
+ const uint8_t *scanmap)
{
const union inany_addr *addr = fwd_rule_addr(rule);
const char *ifname = rule->ifname;
@@ -520,6 +528,7 @@ static int fwd_sync_one(const struct ctx *c, const struct fwd_table *fwd,
idx = rule - fwd->rules;
ASSERT(idx < MAX_FWD_RULES);
+ ASSERT(!(rule->flags & FWD_SCAN && !scanmap));
for (port = rule->first; port <= rule->last; port++) {
int fd = rule->socks[port - rule->first];
@@ -540,9 +549,9 @@ static int fwd_sync_one(const struct ctx *c, const struct fwd_table *fwd,
continue;
}
- if (proto == IPPROTO_TCP)
+ if (rule->proto == IPPROTO_TCP)
fd = tcp_listen(c, pif, idx, addr, ifname, port);
- else if (proto == IPPROTO_UDP)
+ else if (rule->proto == IPPROTO_UDP)
fd = udp_listen(c, pif, idx, addr, ifname, port);
else
ASSERT(0);
@@ -551,7 +560,7 @@ static int fwd_sync_one(const struct ctx *c, const struct fwd_table *fwd,
char astr[INANY_ADDRSTRLEN];
warn("Listen failed for %s %s port %s%s%s/%u: %s",
- pif_name(pif), ipproto_name(proto),
+ pif_name(pif), ipproto_name(rule->proto),
inany_ntop(addr, astr, sizeof(astr)),
ifname ? "%" : "", ifname ? ifname : "",
port, strerror_(-fd));
@@ -570,7 +579,7 @@ static int fwd_sync_one(const struct ctx *c, const struct fwd_table *fwd,
char astr[INANY_ADDRSTRLEN];
warn("All listens failed for %s %s %s%s%s/%u-%u",
- pif_name(pif), ipproto_name(proto),
+ pif_name(pif), ipproto_name(rule->proto),
inany_ntop(addr, astr, sizeof(astr)),
ifname ? "%" : "", ifname ? ifname : "",
rule->first, rule->last);
@@ -583,17 +592,16 @@ static int fwd_sync_one(const struct ctx *c, const struct fwd_table *fwd,
/** struct fwd_listen_args - arguments for fwd_listen_init_()
* @c: Execution context
* @fwd: Forwarding table
- * @scanmap: Bitmap of ports to auto-forward
+ * @tcpmap: Bitmap of TCP ports to auto-forward
+ * @udpmap: Bitmap of TCP ports to auto-forward
* @pif: Interface to create listening sockets for
- * @proto: Protocol
* @ret: Return code
*/
struct fwd_listen_args {
const struct ctx *c;
const struct fwd_table *fwd;
- const uint8_t *scanmap;
+ const uint8_t *tcpmap, *udpmap;
uint8_t pif;
- uint8_t proto;
int ret;
};
@@ -611,8 +619,15 @@ static int fwd_listen_sync_(void *arg)
ns_enter(a->c);
for (i = 0; i < a->fwd->count; i++) {
+ const uint8_t *scanmap = NULL;
+
+ if (a->fwd->rules[i].proto == IPPROTO_TCP)
+ scanmap = a->tcpmap;
+ else if (a->fwd->rules[i].proto == IPPROTO_UDP)
+ scanmap = a->udpmap;
+
a->ret = fwd_sync_one(a->c, a->fwd, &a->fwd->rules[i],
- a->pif, a->proto, a->scanmap);
+ a->pif, scanmap);
if (a->ret < 0)
break;
}
@@ -623,18 +638,20 @@ static int fwd_listen_sync_(void *arg)
/** fwd_listen_sync() - Call fwd_listen_sync_() in correct namespace
* @c: Execution context
* @fwd: Forwarding information
- * @scan: Scanning state for direction and protocol
* @pif: Interface to create listening sockets for
- * @proto: Protocol
+ * @tcp: Scanning state for TCP
+ * @udp: Scanning state for UDP
*
* Return: 0 on success, -1 on failure
*/
int fwd_listen_sync(const struct ctx *c, const struct fwd_table *fwd,
- const struct fwd_scan *scan, uint8_t pif, uint8_t proto)
+ uint8_t pif,
+ const struct fwd_scan *tcp, const struct fwd_scan *udp)
{
struct fwd_listen_args a = {
- .c = c, .fwd = fwd, .scanmap = scan->map,
- .pif = pif, .proto = proto,
+ .c = c, .fwd = fwd,
+ .tcpmap = tcp->map, .udpmap = udp->map,
+ .pif = pif,
};
if (pif == PIF_SPLICE)
@@ -643,8 +660,7 @@ int fwd_listen_sync(const struct ctx *c, const struct fwd_table *fwd,
fwd_listen_sync_(&a);
if (a.ret < 0) {
- err("Couldn't listen on requested %s ports",
- ipproto_name(proto));
+ err("Couldn't listen on requested ports");
return -1;
}
@@ -672,6 +688,26 @@ void fwd_listen_close(const struct fwd_table *fwd)
}
}
+/** fwd_listen_init() - Set up listening sockets at start up
+ * @c: Execution context
+ *
+ * Return: 0 on success, -1 on failure
+ */
+int fwd_listen_init(const struct ctx *c)
+{
+ if (fwd_listen_sync(c, &c->fwd_in, PIF_HOST,
+ &c->tcp.scan_in, &c->udp.scan_in) < 0)
+ return -1;
+
+ if (c->mode == MODE_PASTA) {
+ if (fwd_listen_sync(c, &c->fwd_out, PIF_SPLICE,
+ &c->tcp.scan_out, &c->udp.scan_out) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
/* See enum in kernel's include/net/tcp_states.h */
#define UDP_LISTEN 0x07
#define TCP_LISTEN 0x0a
@@ -717,13 +753,15 @@ static void procfs_scan_listen(int fd, unsigned int lstate, uint8_t *map)
/**
* has_scan_rules() - Does the given table have any FWD_SCAN rules?
* @fwd: Forwarding table
+ * @proto: Protocol to consider
*/
-static bool has_scan_rules(const struct fwd_table *fwd)
+static bool has_scan_rules(const struct fwd_table *fwd, uint8_t proto)
{
unsigned i;
for (i = 0; i < fwd->count; i++) {
- if (fwd->rules[i].flags & FWD_SCAN)
+ if (fwd->rules[i].proto == proto &&
+ fwd->rules[i].flags & FWD_SCAN)
return true;
}
return false;
@@ -738,7 +776,7 @@ static bool has_scan_rules(const struct fwd_table *fwd)
static void fwd_scan_ports_tcp(const struct fwd_table *fwd,
struct fwd_scan *scan, const uint8_t *exclude)
{
- if (!has_scan_rules(fwd))
+ if (!has_scan_rules(fwd, IPPROTO_TCP))
return;
memset(scan->map, 0, PORT_BITMAP_SIZE);
@@ -759,7 +797,7 @@ static void fwd_scan_ports_udp(const struct fwd_table *fwd,
const struct fwd_scan *tcp_scan,
const uint8_t *exclude)
{
- if (!has_scan_rules(fwd))
+ if (!has_scan_rules(fwd, IPPROTO_UDP))
return;
memset(scan->map, 0, PORT_BITMAP_SIZE);
@@ -781,8 +819,10 @@ static void fwd_scan_ports_udp(const struct fwd_table *fwd,
* current_listen_map() - Get bitmap of which ports we're already listening on
* @map: Bitmap to populate
* @fwd: Forwarding table to consider
+ * @proto: IP protocol to consider
*/
-static void current_listen_map(uint8_t *map, const struct fwd_table *fwd)
+static void current_listen_map(uint8_t *map, const struct fwd_table *fwd,
+ uint8_t proto)
{
unsigned i;
@@ -792,6 +832,9 @@ static void current_listen_map(uint8_t *map, const struct fwd_table *fwd)
const struct fwd_rule *rule = &fwd->rules[i];
unsigned port;
+ if (rule->proto != proto)
+ continue;
+
for (port = rule->first; port <= rule->last; port++) {
if (rule->socks[port - rule->first] >= 0)
bitmap_set(map, port);
@@ -808,16 +851,16 @@ static void fwd_scan_ports(struct ctx *c)
uint8_t excl_tcp_out[PORT_BITMAP_SIZE], excl_udp_out[PORT_BITMAP_SIZE];
uint8_t excl_tcp_in[PORT_BITMAP_SIZE], excl_udp_in[PORT_BITMAP_SIZE];
- current_listen_map(excl_tcp_out, &c->tcp.fwd_in);
- current_listen_map(excl_tcp_in, &c->tcp.fwd_out);
- current_listen_map(excl_udp_out, &c->udp.fwd_in);
- current_listen_map(excl_udp_in, &c->udp.fwd_out);
+ current_listen_map(excl_tcp_out, &c->fwd_in, IPPROTO_TCP);
+ current_listen_map(excl_tcp_in, &c->fwd_out, IPPROTO_TCP);
+ current_listen_map(excl_udp_out, &c->fwd_in, IPPROTO_UDP);
+ current_listen_map(excl_udp_in, &c->fwd_out, IPPROTO_UDP);
- fwd_scan_ports_tcp(&c->tcp.fwd_out, &c->tcp.scan_out, excl_tcp_out);
- fwd_scan_ports_tcp(&c->tcp.fwd_in, &c->tcp.scan_in, excl_tcp_in);
- fwd_scan_ports_udp(&c->udp.fwd_out, &c->udp.scan_out,
+ fwd_scan_ports_tcp(&c->fwd_out, &c->tcp.scan_out, excl_tcp_out);
+ fwd_scan_ports_tcp(&c->fwd_in, &c->tcp.scan_in, excl_tcp_in);
+ fwd_scan_ports_udp(&c->fwd_out, &c->udp.scan_out,
&c->tcp.scan_out, excl_udp_out);
- fwd_scan_ports_udp(&c->udp.fwd_in, &c->udp.scan_in,
+ fwd_scan_ports_udp(&c->fwd_in, &c->udp.scan_in,
&c->tcp.scan_in, excl_udp_in);
}
@@ -834,19 +877,19 @@ void fwd_scan_ports_init(struct ctx *c)
c->udp.scan_in.scan4 = c->udp.scan_in.scan6 = -1;
c->udp.scan_out.scan4 = c->udp.scan_out.scan6 = -1;
- if (has_scan_rules(&c->tcp.fwd_in)) {
+ if (has_scan_rules(&c->fwd_in, IPPROTO_TCP)) {
c->tcp.scan_in.scan4 = open_in_ns(c, "/proc/net/tcp", flags);
c->tcp.scan_in.scan6 = open_in_ns(c, "/proc/net/tcp6", flags);
}
- if (has_scan_rules(&c->udp.fwd_in)) {
+ if (has_scan_rules(&c->fwd_in, IPPROTO_UDP)) {
c->udp.scan_in.scan4 = open_in_ns(c, "/proc/net/udp", flags);
c->udp.scan_in.scan6 = open_in_ns(c, "/proc/net/udp6", flags);
}
- if (has_scan_rules(&c->udp.fwd_out)) {
+ if (has_scan_rules(&c->fwd_out, IPPROTO_TCP)) {
c->tcp.scan_out.scan4 = open("/proc/net/tcp", flags);
c->tcp.scan_out.scan6 = open("/proc/net/tcp6", flags);
}
- if (has_scan_rules(&c->udp.fwd_out)) {
+ if (has_scan_rules(&c->fwd_out, IPPROTO_UDP)) {
c->udp.scan_out.scan4 = open("/proc/net/udp", flags);
c->udp.scan_out.scan6 = open("/proc/net/udp6", flags);
}
@@ -873,18 +916,10 @@ void fwd_scan_ports_timer(struct ctx *c, const struct timespec *now)
fwd_scan_ports(c);
- if (!c->no_tcp) {
- fwd_listen_sync(c, &c->tcp.fwd_in, &c->tcp.scan_in,
- PIF_HOST, IPPROTO_TCP);
- fwd_listen_sync(c, &c->tcp.fwd_out, &c->tcp.scan_out,
- PIF_SPLICE, IPPROTO_TCP);
- }
- if (!c->no_udp) {
- fwd_listen_sync(c, &c->udp.fwd_in, &c->udp.scan_in,
- PIF_HOST, IPPROTO_UDP);
- fwd_listen_sync(c, &c->udp.fwd_out, &c->udp.scan_out,
- PIF_SPLICE, IPPROTO_UDP);
- }
+ fwd_listen_sync(c, &c->fwd_in, PIF_HOST,
+ &c->tcp.scan_in, &c->udp.scan_in);
+ fwd_listen_sync(c, &c->fwd_out, PIF_SPLICE,
+ &c->tcp.scan_out, &c->udp.scan_out);
}
/**
diff --git a/fwd.h b/fwd.h
index 1af13ad4..f6f0fa81 100644
--- a/fwd.h
+++ b/fwd.h
@@ -31,11 +31,12 @@ bool fwd_port_is_ephemeral(in_port_t port);
* @first: First port number to forward
* @last: Last port number to forward
* @to: Target port for @first, port n goes to @to + (n - @first)
- * @socks: Array of listening sockets for this entry
+ * @proto: Protocol to forward
* @flags: Flag mask
* FWD_DUAL_STACK_ANY - match any IPv4 or IPv6 address (@addr should be ::)
* FWD_WEAK - Don't give an error if binds fail for some forwards
* FWD_SCAN - Only forward if the matching port in the target is listening
+ * @socks: Array of listening sockets for this entry
*
* FIXME: @addr and @ifname currently ignored for outbound tables
*/
@@ -45,11 +46,12 @@ struct fwd_rule {
in_port_t first;
in_port_t last;
in_port_t to;
- int *socks;
+ uint8_t proto;
#define FWD_DUAL_STACK_ANY BIT(0)
#define FWD_WEAK BIT(1)
#define FWD_SCAN BIT(2)
uint8_t flags;
+ int *socks;
};
#define FWD_RULE_BITS 8
@@ -105,20 +107,22 @@ struct fwd_scan {
#define FWD_PORT_SCAN_INTERVAL 1000 /* ms */
-void fwd_rule_add(struct fwd_table *fwd, uint8_t flags,
+void fwd_rule_add(struct fwd_table *fwd, uint8_t proto, uint8_t flags,
const union inany_addr *addr, const char *ifname,
in_port_t first, in_port_t last, in_port_t to);
const struct fwd_rule *fwd_rule_search(const struct fwd_table *fwd,
const struct flowside *ini,
- int hint);
+ uint8_t proto, int hint);
void fwd_rules_print(const struct fwd_table *fwd);
void fwd_scan_ports_init(struct ctx *c);
void fwd_scan_ports_timer(struct ctx * c, const struct timespec *now);
int fwd_listen_sync(const struct ctx *c, const struct fwd_table *fwd,
- const struct fwd_scan *scan, uint8_t pif, uint8_t proto);
+ uint8_t pif,
+ const struct fwd_scan *tcp, const struct fwd_scan *udp);
void fwd_listen_close(const struct fwd_table *fwd);
+int fwd_listen_init(const struct ctx *c);
bool nat_inbound(const struct ctx *c, const union inany_addr *addr,
union inany_addr *translated);
diff --git a/passt.c b/passt.c
index 7488a84c..fc3b89b8 100644
--- a/passt.c
+++ b/passt.c
@@ -401,6 +401,9 @@ int main(int argc, char **argv)
if ((!c.no_udp && udp_init(&c)) || (!c.no_tcp && tcp_init(&c)))
passt_exit(EXIT_FAILURE);
+ if (fwd_listen_init(&c))
+ passt_exit(EXIT_FAILURE);
+
proto_update_l2_buf(c.guest_mac);
if (c.ifi4 && !c.no_dhcp)
diff --git a/passt.h b/passt.h
index 0548dacd..b614bdf0 100644
--- a/passt.h
+++ b/passt.h
@@ -184,6 +184,8 @@ struct ip6_ctx {
* @pasta_ifn: Name of namespace interface for pasta
* @pasta_ifi: Index of namespace interface for pasta
* @pasta_conf_ns: Configure namespace after creating it
+ * @fwd_in: Forwarding table for inbound flows
+ * @fwd_out: Forwarding table for outbound flows
* @no_tcp: Disable TCP operation
* @tcp: Context for TCP protocol handler
* @no_udp: Disable UDP operation
@@ -262,6 +264,9 @@ struct ctx {
unsigned int pasta_ifi;
int pasta_conf_ns;
+ struct fwd_table fwd_in;
+ struct fwd_table fwd_out;
+
int no_tcp;
struct tcp_ctx tcp;
int no_udp;
diff --git a/tcp.c b/tcp.c
index 29355c0c..77d128da 100644
--- a/tcp.c
+++ b/tcp.c
@@ -2863,15 +2863,8 @@ int tcp_init(struct ctx *c)
tcp_sock_refill_init(c);
- if (fwd_listen_sync(c, &c->tcp.fwd_in, &c->tcp.scan_in,
- PIF_HOST, IPPROTO_TCP) < 0)
- return -1;
- if (c->mode == MODE_PASTA) {
+ if (c->mode == MODE_PASTA)
tcp_splice_init(c);
- if (fwd_listen_sync(c, &c->tcp.fwd_out, &c->tcp.scan_out,
- PIF_SPLICE, IPPROTO_TCP) < 0)
- return -1;
- }
peek_offset_cap = (!c->ifi4 || tcp_probe_peek_offset_cap(AF_INET)) &&
(!c->ifi6 || tcp_probe_peek_offset_cap(AF_INET6));
diff --git a/tcp.h b/tcp.h
index c4f200c1..c992496a 100644
--- a/tcp.h
+++ b/tcp.h
@@ -38,9 +38,7 @@ extern bool peek_offset_cap;
/**
* struct tcp_ctx - Execution context for TCP routines
- * @fwd_in: Forwarding table for inbound flows
* @scan_in: Port scanning state for inbound packets
- * @fwd_out: Forwarding table for outbound flows
* @scan_out: Port scanning state for outbound packets
* @timer_run: Timestamp of most recent timer run
* @pipe_size: Size of pipes for spliced connections
diff --git a/udp.c b/udp.c
index ed23ab7c..2275c16b 100644
--- a/udp.c
+++ b/udp.c
@@ -1215,16 +1215,8 @@ int udp_init(struct ctx *c)
udp_iov_init(c);
- if (fwd_listen_sync(c, &c->udp.fwd_in, &c->udp.scan_in,
- PIF_HOST, IPPROTO_UDP) < 0)
- return -1;
-
- if (c->mode == MODE_PASTA) {
+ if (c->mode == MODE_PASTA)
udp_splice_iov_init();
- if (fwd_listen_sync(c, &c->udp.fwd_out, &c->udp.scan_out,
- PIF_SPLICE, IPPROTO_UDP) < 0)
- return -1;
- }
return 0;
}
diff --git a/udp.h b/udp.h
index 785133ef..a75d5aea 100644
--- a/udp.h
+++ b/udp.h
@@ -26,18 +26,14 @@ void udp_update_l2_buf(const unsigned char *eth_d);
/**
* struct udp_ctx - Execution context for UDP
- * @fwd_in: Forwarding table for inbound flows
* @scan_in: Port scanning state for inbound packets
- * @fwd_out: Forwarding table for outbound flows
* @scan_out: Port scanning state for outbound packets
* @timer_run: Timestamp of most recent timer run
* @timeout: Timeout for unidirectional flows (in s)
* @stream_timeout: Timeout for stream-like flows (in s)
*/
struct udp_ctx {
- struct fwd_table fwd_in;
struct fwd_scan scan_in;
- struct fwd_table fwd_out;
struct fwd_scan scan_out;
struct timespec timer_run;
int timeout;
--
2.53.0