This option changes how logical switch ACL related flows are generated such that the following behavior is ensured:
a. If a logical switch has no ACL applied to it (either directly or indirectly via a port group) then traffic is always allowed in the ls_in_acl, ls_in_acl_after_lb, ls_out_acl stages. b. If a logical switch has ACLs applied (directly or indirectly) and NB_Global.options:default_acl_drop is set to 'false', then traffic that doesn't match any ACL in the ls_in_acl, ls_in_acl_after_lb, ls_out_acl stages is allowed to advance to the next step in the processing pipeline. c. If a logical switch has *any* ACL applied (directly or indirectly) and NB_Global.options:default_acl_drop is set to 'true', then a default lowest-priority rule is added to the ls_in_acl, ls_in_acl_after_lb, ls_out_acl stages to drop traffic that is not matched by any ACLs. The goal of the feature is to simplify the configuration of the ACLs and port groups for CMSs that require a default-deny firewall implementation. One such example is with OpenStack security groups which, when enabled, implicitly drop all not explicitly allowed traffic. Until now the CMS had to add all logical ports corresponding to VMs in a network to a single, huge, default-drop-port-group and apply a single drop ACL to the port group. With this new feature, the CMS can enable 'default_acl_drop', and punch holes for traffic that needs to be allowed. The resulting NB and SB configuration is also reduced in size. Reported-by: Daniel Alvarez Sanchez <[email protected]> Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=1947807 Signed-off-by: Dumitru Ceara <[email protected]> --- NOTE: I'm sending this patch as RFC because I'd like to discuss alternatives for the default behavior when the knob is enabled and logical switches don't have any ACLs set. Also, it would be interesting to see if this feature, or something similar would also be beneficial for other CMSs, e.g., ovn-kubernetes (CC-ing Tim Rozet). --- NEWS | 2 + northd/northd.c | 31 +++++-- ovn-nb.xml | 8 ++ tests/ovn-northd.at | 218 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 253 insertions(+), 6 deletions(-) diff --git a/NEWS b/NEWS index 3e8358723d..377d3f8cea 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,8 @@ Post v22.03.0 different OVN Interconnection availability zones. - Replaced the usage of masked ct_label by ct_mark in most cases to work better with hardware-offloading. + - Add global option (NB_Global.options:default_acl_drop) to enable + implicit drop behavior on logical switches with ACLs applied. OVN v22.03.0 - 11 Mar 2022 -------------------------- diff --git a/northd/northd.c b/northd/northd.c index 8dae72180d..77a2f49724 100644 --- a/northd/northd.c +++ b/northd/northd.c @@ -73,6 +73,12 @@ static struct eth_addr svc_monitor_mac_ea; * Otherwise, it will avoid using it. The default is true. */ static bool use_ct_inv_match = true; +/* If this option is 'true' northd will implicitly add a lowest-priority + * drop rule in the ACL stage of logical switches that have at least one + * ACL. + */ +static bool default_acl_drop; + #define MAX_OVN_TAGS 4096 /* Pipeline stages. */ @@ -6588,6 +6594,7 @@ static void build_acls(struct ovn_datapath *od, struct hmap *lflows, const struct hmap *port_groups, const struct shash *meter_groups) { + const char *default_acl_action = default_acl_drop ? "drop;" : "next;"; bool has_stateful = od->has_stateful_acl || od->has_lb_vip; struct ds match = DS_EMPTY_INITIALIZER; struct ds actions = DS_EMPTY_INITIALIZER; @@ -6599,15 +6606,26 @@ build_acls(struct ovn_datapath *od, struct hmap *lflows, * * A related rule at priority 1 is added below if there * are any stateful ACLs in this datapath. */ - if (!od->has_acls && !od->has_lb_vip) { - ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX, "1", "next;"); - ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX, "1", "next;"); + if (!od->has_acls) { + if (!od->has_lb_vip) { + ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX, "1", + "next;"); + ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX, "1", + "next;"); + } else { + ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, 1, "1", "next;"); + ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, 1, "1", "next;"); + } + ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB, 0, "1", "next;"); } else { - ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, 0, "1", "next;"); - ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, 0, "1", "next;"); + ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, 0, "1", + default_acl_action); + ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, 0, "1", + default_acl_action); + ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB, 0, "1", + default_acl_action); } - ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB, 0, "1", "next;"); if (has_stateful) { /* Ingress and Egress ACL Table (Priority 1). @@ -15190,6 +15208,7 @@ ovnnb_db_run(struct northd_input *input_data, "controller_event", false); check_lsp_is_up = !smap_get_bool(&nb->options, "ignore_lsp_down", true); + default_acl_drop = smap_get_bool(&nb->options, "default_acl_drop", false); build_datapaths(input_data, ovnsb_txn, &data->datapaths, &data->lr_list); build_lbs(input_data, &data->datapaths, &data->lbs); diff --git a/ovn-nb.xml b/ovn-nb.xml index 4d7a23c527..47347819f1 100644 --- a/ovn-nb.xml +++ b/ovn-nb.xml @@ -255,6 +255,14 @@ </p> </column> + <column name="options" key="default_acl_drop"> + <p> + If set to <code>true</code>., <code>ovn-northd</code> will + generate a logical flow to drop all traffic in the ACL stages. + By default this option is set to <code>false</code>. + </p> + </column> + <group title="Options for configuring interconnection route advertisement"> <p> These options control how routes are advertised between OVN diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at index 317f024f64..3699f5bd23 100644 --- a/tests/ovn-northd.at +++ b/tests/ovn-northd.at @@ -6480,3 +6480,221 @@ AT_CHECK([grep -e "ls_in_stateful" lsflows | sed 's/table=../table=??/' | sort], AT_CLEANUP ]) + +OVN_FOR_EACH_NORTHD([ +AT_SETUP([LS default ACL drop]) +AT_KEYWORDS([acl]) + +ovn_start + +check ovn-nbctl ls-add ls + +AS_BOX([No ACL, default_acl_drop not set]) +check ovn-nbctl --wait=sb sync +AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl + table=??(ls_in_acl ), priority=65535, match=(1), action=(next;) + table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;) + table=??(ls_in_acl_hint ), priority=65535, match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(next;) + table=??(ls_out_acl ), priority=65535, match=(1), action=(next;) + table=??(ls_out_acl_hint ), priority=65535, match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=110 , match=(eth.src == $svc_monitor_mac), action=(next;) +]) + +AS_BOX([No ACL, default_acl_drop false]) +check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=false +AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl + table=??(ls_in_acl ), priority=65535, match=(1), action=(next;) + table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;) + table=??(ls_in_acl_hint ), priority=65535, match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(next;) + table=??(ls_out_acl ), priority=65535, match=(1), action=(next;) + table=??(ls_out_acl_hint ), priority=65535, match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=110 , match=(eth.src == $svc_monitor_mac), action=(next;) +]) + +AS_BOX([No ACL, default_acl_drop true]) +check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=true +AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl + table=??(ls_in_acl ), priority=65535, match=(1), action=(next;) + table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;) + table=??(ls_in_acl_hint ), priority=65535, match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(next;) + table=??(ls_out_acl ), priority=65535, match=(1), action=(next;) + table=??(ls_out_acl_hint ), priority=65535, match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=110 , match=(eth.src == $svc_monitor_mac), action=(next;) +]) + +AS_BOX([from-lport ACL]) +check ovn-nbctl acl-del ls +check ovn-nbctl acl-add ls from-lport 1 "ip" allow + +AS_BOX([from-lport ACL, default_acl_drop not set]) +check ovn-nbctl --wait=sb remove NB_Global . options default_acl_drop +AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl + table=??(ls_in_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_in_acl ), priority=1001 , match=(ip), action=(next;) + table=??(ls_in_acl ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;) + table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;) + table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(next;) + table=??(ls_out_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_out_acl ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;) + table=??(ls_out_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=110 , match=(eth.src == $svc_monitor_mac), action=(next;) +]) + +AS_BOX([from-lport ACL, default_acl_drop false]) +check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=false +AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl + table=??(ls_in_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_in_acl ), priority=1001 , match=(ip), action=(next;) + table=??(ls_in_acl ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;) + table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;) + table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(next;) + table=??(ls_out_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_out_acl ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;) + table=??(ls_out_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=110 , match=(eth.src == $svc_monitor_mac), action=(next;) +]) + +AS_BOX([from-lport ACL, default_acl_drop true]) +check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=true +AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl + table=??(ls_in_acl ), priority=0 , match=(1), action=(drop;) + table=??(ls_in_acl ), priority=1001 , match=(ip), action=(next;) + table=??(ls_in_acl ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;) + table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(drop;) + table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(next;) + table=??(ls_out_acl ), priority=0 , match=(1), action=(drop;) + table=??(ls_out_acl ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;) + table=??(ls_out_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=110 , match=(eth.src == $svc_monitor_mac), action=(next;) +]) + +AS_BOX([from-lport --apply-after-lb ACL]) +check ovn-nbctl acl-del ls +check ovn-nbctl --apply-after-lb acl-add ls from-lport 1 "ip" allow + +AS_BOX([from-lport --apply-after-lb ACL, default_acl_drop not set]) +check ovn-nbctl --wait=sb remove NB_Global . options default_acl_drop +AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl + table=??(ls_in_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_in_acl ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;) + table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;) + table=??(ls_in_acl_after_lb ), priority=1001 , match=(ip), action=(next;) + table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(next;) + table=??(ls_out_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_out_acl ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;) + table=??(ls_out_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=110 , match=(eth.src == $svc_monitor_mac), action=(next;) +]) + +AS_BOX([from-lport --apply-after-lb ACL, default_acl_drop false]) +check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=false +AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl + table=??(ls_in_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_in_acl ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;) + table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;) + table=??(ls_in_acl_after_lb ), priority=1001 , match=(ip), action=(next;) + table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(next;) + table=??(ls_out_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_out_acl ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;) + table=??(ls_out_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=110 , match=(eth.src == $svc_monitor_mac), action=(next;) +]) + +AS_BOX([from-lport --apply-after-lb ACL, default_acl_drop true]) +check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=true +AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl + table=??(ls_in_acl ), priority=0 , match=(1), action=(drop;) + table=??(ls_in_acl ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;) + table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(drop;) + table=??(ls_in_acl_after_lb ), priority=1001 , match=(ip), action=(next;) + table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(next;) + table=??(ls_out_acl ), priority=0 , match=(1), action=(drop;) + table=??(ls_out_acl ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;) + table=??(ls_out_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=110 , match=(eth.src == $svc_monitor_mac), action=(next;) +]) + +AS_BOX([to-lport ACL]) +check ovn-nbctl acl-del ls +check ovn-nbctl acl-add ls to-lport 1 "ip" allow + +AS_BOX([to-lport ACL, default_acl_drop not set]) +check ovn-nbctl --wait=sb remove NB_Global . options default_acl_drop +AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl + table=??(ls_in_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_in_acl ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;) + table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;) + table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(next;) + table=??(ls_out_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_out_acl ), priority=1001 , match=(ip), action=(next;) + table=??(ls_out_acl ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;) + table=??(ls_out_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=110 , match=(eth.src == $svc_monitor_mac), action=(next;) +]) + +AS_BOX([to-lport ACL, default_acl_drop false]) +check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=false +AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl + table=??(ls_in_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_in_acl ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;) + table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;) + table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(next;) + table=??(ls_out_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_out_acl ), priority=1001 , match=(ip), action=(next;) + table=??(ls_out_acl ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;) + table=??(ls_out_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=110 , match=(eth.src == $svc_monitor_mac), action=(next;) +]) + +AS_BOX([to-lport ACL, default_acl_drop true]) +check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=true +AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl + table=??(ls_in_acl ), priority=0 , match=(1), action=(drop;) + table=??(ls_in_acl ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;) + table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(drop;) + table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(next;) + table=??(ls_out_acl ), priority=0 , match=(1), action=(drop;) + table=??(ls_out_acl ), priority=1001 , match=(ip), action=(next;) + table=??(ls_out_acl ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;) + table=??(ls_out_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=110 , match=(eth.src == $svc_monitor_mac), action=(next;) +]) + +AT_CLEANUP +]) -- 2.27.0 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
