Skip to content

Commit

Permalink
northd: Add option to enable conntrack for router port
Browse files Browse the repository at this point in the history
By default, OVN skips the conntrack process for router type
LSP within a LS. It seems unnecessary for the LSP whose peer
is l3dgw_port.

Therefore, we introduce an option named 'enable_conntrack',
which defaults to false and can be set to true to enable
conntrack for the LSP whose peer is l3dgw_port.

And then we can implement a gateway stateful firewall by
dgw with stateful ACL. For example:

 prelude: R1-S1 is a l3dgw_port
 ovn-nbctl pg-add pg_dgw
 ovn-nbctl pg-set-ports pg_dgw S1-R1
 ovn-nbctl acl-add pg_dgw from-lport 1002 "inport == @pg_dgw && ip4" allow-related
 ovn-nbctl acl-add pg_dgw to-lport 1003 "outport == @pg_dgw && ip4" allow-related
 ovn-nbctl lsp-set-options S1-R1 router-port=R1-S1 enable_conntrack=true

NOTE: this option only works for the LSP whose peer is l3dgw_port.

Signed-off-by: Xie Liu <[email protected]>
  • Loading branch information
shylou committed Dec 9, 2023
1 parent 96dd854 commit 518ec54
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 1 deletion.
2 changes: 2 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ Post v23.09.0
external_ids:ovn-openflow-probe-interval configuration option for
ovn-controller no longer matters and is ignored.
- Enable PMTU discovery on geneve tunnels for E/W traffic.
- A new LSP option "enable_conntrack" has been added to enable conntrack
for the router port whose peer is l3dgw_port if set it true.

OVN v23.09.0 - 15 Sep 2023
--------------------------
Expand Down
30 changes: 29 additions & 1 deletion northd/northd.c
Original file line number Diff line number Diff line change
Expand Up @@ -1605,6 +1605,9 @@ struct ovn_port {
* access it from any other nodes.
*/
struct ovs_list lflows;

/* Only used for the router type LSP whose peer is l3dgw_port */
bool enable_conntrack;
};

static bool lsp_can_be_inc_processed(const struct nbrec_logical_switch_port *);
Expand Down Expand Up @@ -2657,6 +2660,13 @@ join_logical_ports(const struct sbrec_port_binding_table *sbrec_pb_table,
od->has_vtep_lports = true;
}

if (smap_get(&nbsp->options, "enable_conntrack") &&
!lsp_is_router(nbsp)) {
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
VLOG_WARN_RL(&rl, "enable_conntrack option is not supported "
"on logical port %s", nbsp->name);
}

parse_lsp_addrs(op);

op->od = od;
Expand Down Expand Up @@ -2819,6 +2829,20 @@ join_logical_ports(const struct sbrec_port_binding_table *sbrec_pb_table,
arp_proxy, op->nbsp->name);
}
}

/* Only used for the router type LSP whose peer is l3dgw_port */
if (smap_get(&op->nbsp->options, "enable_conntrack")) {
if (op->peer && is_l3dgw_port(op->peer)) {
op->enable_conntrack = smap_get_bool(&op->nbsp->options,
"enable_conntrack", false);
} else {
static struct vlog_rate_limit rl =
VLOG_RATE_LIMIT_INIT(5, 1);
VLOG_WARN_RL(&rl, "enable_conntrack option is not "
"supported on logical port %s",
op->nbsp->name);
}
}
} else if (op->nbrp && op->nbrp->peer && !op->l3dgw_port) {
struct ovn_port *peer = ovn_port_find(ports, op->nbrp->peer);
if (peer) {
Expand Down Expand Up @@ -7202,7 +7226,11 @@ build_pre_acls(struct ovn_datapath *od,
* which handles defragmentation, in order to match L4 headers. */
if (od->has_stateful_acl) {
for (size_t i = 0; i < od->n_router_ports; i++) {
skip_port_from_conntrack(od, od->router_ports[i],
struct ovn_port *op = od->router_ports[i];
if (op->enable_conntrack) {
continue;
}
skip_port_from_conntrack(od, op,
S_SWITCH_IN_PRE_ACL, S_SWITCH_OUT_PRE_ACL,
110, lflows);
}
Expand Down
8 changes: 8 additions & 0 deletions ovn-nb.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1107,6 +1107,14 @@
should have a route to forward packets sent to configured proxy ARP
MAC/IPs to an appropriate destination.
</column>

<column name="options" key="enable_conntrack"
type='{"type": "boolean"}'>
Optional. Enable conntrack for the router port whose peer is
l3dgw_port if set to <code>true</code>. The default value is
<code>false</code>.
</column>

</group>

<group title="Options for localnet ports">
Expand Down
92 changes: 92 additions & 0 deletions tests/ovn-northd.at
Original file line number Diff line number Diff line change
Expand Up @@ -10966,3 +10966,95 @@ Status: active

AT_CLEANUP
])

OVN_FOR_EACH_NORTHD_NO_HV([
AT_SETUP([Distributed gw port enable conntrack option])
ovn_start

check ovn-sbctl chassis-add gw1 geneve 127.0.0.1

# Add a distributed router
check ovn-nbctl lr-add R1
check ovn-nbctl lrp-add R1 R1-S1 02:ac:10:01:00:01 172.16.1.1/24
check ovn-nbctl lrp-set-gateway-chassis R1-S1 gw1

# Add a external network connected to R1
check ovn-nbctl ls-add S1
check ovn-nbctl lsp-add S1 S1-R1
check ovn-nbctl lsp-set-type S1-R1 router
check ovn-nbctl lsp-set-addresses S1-R1 router
check ovn-nbctl --wait=sb lsp-set-options S1-R1 router-port=R1-S1
AT_CHECK([test x`ovn-nbctl lsp-get-up S1-R1` = xup])

# Add a external network vif
check ovn-nbctl lsp-add S1 S1-VIF
check ovn-nbctl lsp-set-addresses S1-VIF "02:ac:10:01:00:02 172.16.1.11"

# Add the router gw port and vif to one port_group which has stateful acls
check ovn-nbctl --wait=sb pg-add pg_dgw S1-R1 S1-VIF
check ovn-nbctl acl-add pg_dgw from-lport 1002 "inport == @pg_dgw && ip4" allow-related
check ovn-nbctl acl-add pg_dgw to-lport 1003 "outport == @pg_dgw && ip4" allow-related

# Check skip conntrack option with 'enable_conntrack' default (false)
AT_CHECK([ovn-sbctl dump-flows S1 | grep pre_acl | sed 's/table=./table=?/'], [0], [dnl
table=? (ls_in_pre_acl ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(next;)
table=? (ls_in_pre_acl ), priority=110 , match=(eth.mcast), action=(next;)
table=? (ls_in_pre_acl ), priority=110 , match=(ip && inport == "S1-R1"), action=(next;)
table=? (ls_in_pre_acl ), priority=110 , match=(nd || nd_rs || nd_ra || mldv1 || mldv2 || (udp && udp.src == 546 && udp.dst == 547)), action=(next;)
table=? (ls_in_pre_acl ), priority=100 , match=(ip), action=(reg0[[0]] = 1; next;)
table=? (ls_in_pre_acl ), priority=0 , match=(1), action=(next;)
table=? (ls_out_pre_acl ), priority=110 , match=(eth.mcast), action=(next;)
table=? (ls_out_pre_acl ), priority=110 , match=(eth.src == $svc_monitor_mac), action=(next;)
table=? (ls_out_pre_acl ), priority=110 , match=(ip && outport == "S1-R1"), action=(next;)
table=? (ls_out_pre_acl ), priority=110 , match=(nd || nd_rs || nd_ra || mldv1 || mldv2 || (udp && udp.src == 546 && udp.dst == 547)), action=(next;)
table=? (ls_out_pre_acl ), priority=100 , match=(ip), action=(reg0[[0]] = 1; next;)
table=? (ls_out_pre_acl ), priority=0 , match=(1), action=(next;)
])

# Enable 'enable_conntrack' and check the flows
AT_CHECK([ovn-nbctl --wait=sb lsp-set-options S1-R1 router-port=R1-S1 enable_conntrack=true])
AT_CHECK([ovn-sbctl dump-flows S1 | grep pre_acl | sed 's/table=./table=?/'], [0], [dnl
table=? (ls_in_pre_acl ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(next;)
table=? (ls_in_pre_acl ), priority=110 , match=(eth.mcast), action=(next;)
table=? (ls_in_pre_acl ), priority=110 , match=(nd || nd_rs || nd_ra || mldv1 || mldv2 || (udp && udp.src == 546 && udp.dst == 547)), action=(next;)
table=? (ls_in_pre_acl ), priority=100 , match=(ip), action=(reg0[[0]] = 1; next;)
table=? (ls_in_pre_acl ), priority=0 , match=(1), action=(next;)
table=? (ls_out_pre_acl ), priority=110 , match=(eth.mcast), action=(next;)
table=? (ls_out_pre_acl ), priority=110 , match=(eth.src == $svc_monitor_mac), action=(next;)
table=? (ls_out_pre_acl ), priority=110 , match=(nd || nd_rs || nd_ra || mldv1 || mldv2 || (udp && udp.src == 546 && udp.dst == 547)), action=(next;)
table=? (ls_out_pre_acl ), priority=100 , match=(ip), action=(reg0[[0]] = 1; next;)
table=? (ls_out_pre_acl ), priority=0 , match=(1), action=(next;)
])

# ICMP packets from router port to external network should go to conntrack
flow_eth_in='eth.src == 02:ac:10:01:00:01 && eth.dst == 02:ac:10:01:00:02'
flow_ip_in='ip.ttl==64 && ip4.src == 172.16.10.1 && ip4.dst == 172.16.10.11'
flow_icmp='icmp4.type == 8'
flow_in="inport == \"S1-R1\" && ${flow_eth_in} && ${flow_ip_in} && ${flow_icmp}"
AT_CHECK_UNQUOTED([ovn_trace --ct est --ct est --minimal S1 "${flow_in}"], [0], [dnl
ct_next(ct_state=est|trk) {
ct_next(ct_state=est|trk) {
output("S1-VIF");
};
};
])

# Disable 'enable_conntrack' and check the flows
AT_CHECK([ovn-nbctl --wait=sb lsp-set-options S1-R1 router-port=R1-S1 enable_conntrack=false])
AT_CHECK([ovn-sbctl dump-flows S1 | grep pre_acl | sed 's/table=./table=?/'], [0], [dnl
table=? (ls_in_pre_acl ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(next;)
table=? (ls_in_pre_acl ), priority=110 , match=(eth.mcast), action=(next;)
table=? (ls_in_pre_acl ), priority=110 , match=(ip && inport == "S1-R1"), action=(next;)
table=? (ls_in_pre_acl ), priority=110 , match=(nd || nd_rs || nd_ra || mldv1 || mldv2 || (udp && udp.src == 546 && udp.dst == 547)), action=(next;)
table=? (ls_in_pre_acl ), priority=100 , match=(ip), action=(reg0[[0]] = 1; next;)
table=? (ls_in_pre_acl ), priority=0 , match=(1), action=(next;)
table=? (ls_out_pre_acl ), priority=110 , match=(eth.mcast), action=(next;)
table=? (ls_out_pre_acl ), priority=110 , match=(eth.src == $svc_monitor_mac), action=(next;)
table=? (ls_out_pre_acl ), priority=110 , match=(ip && outport == "S1-R1"), action=(next;)
table=? (ls_out_pre_acl ), priority=110 , match=(nd || nd_rs || nd_ra || mldv1 || mldv2 || (udp && udp.src == 546 && udp.dst == 547)), action=(next;)
table=? (ls_out_pre_acl ), priority=100 , match=(ip), action=(reg0[[0]] = 1; next;)
table=? (ls_out_pre_acl ), priority=0 , match=(1), action=(next;)
])

AT_CLEANUP
])

0 comments on commit 518ec54

Please sign in to comment.