On Mon, Apr 10, 2023 at 7:26 PM Mark Michelson <[email protected]> wrote:
> With this commit, ACLs can now be arranged in hierarchical tiers. A tier > number can be assigned to an ACL. When evaluating ACLs, we first will > consider ACLs at tier 0. If no matching ACL is found, then we move to > tier 1. This continues until a matching ACL is found, or we reach the > maximum tier. If no match is found, then the default acl action is > applied. > > Signed-off-by: Mark Michelson <[email protected]> > Hi Mark, I have some small comments below. > --- > northd/northd.c | 96 +++++++++++++++++++------- > northd/northd.h | 1 + > ovn-nb.ovsschema | 5 +- > ovn-nb.xml | 20 ++++++ > tests/ovn-northd.at | 162 +++++++++++++++++++++++++++++++++++++++----- > tests/system-ovn.at | 107 +++++++++++++++++++++++++++++ > 6 files changed, 347 insertions(+), 44 deletions(-) > > diff --git a/northd/northd.c b/northd/northd.c > index 39de54e5b..36ca94ebb 100644 > --- a/northd/northd.c > +++ b/northd/northd.c > @@ -242,6 +242,7 @@ enum ovn_stage { > #define REGBIT_ACL_VERDICT_ALLOW "reg8[16]" > #define REGBIT_ACL_VERDICT_DROP "reg8[17]" > #define REGBIT_ACL_VERDICT_REJECT "reg8[18]" > +#define REG_ACL_TIER "reg8[30..31]" > > /* Indicate that this packet has been recirculated using egress > * loopback. This allows certain checks to be bypassed, such as a > @@ -5704,36 +5705,51 @@ ovn_ls_port_group_destroy(struct hmap *nb_pgs) > hmap_destroy(nb_pgs); > } > > +static bool > +od_set_acl_flags(struct ovn_datapath *od, struct nbrec_acl **acls, > + size_t n_acls) > +{ > + /* A true return indicates that there are no possible ACL flags > + * left to set on od. A false return indicates that further ACLs > + * should be explored in case more flags need to be set on od > + */ > + if (!n_acls) { > + return false; > + } > + > + od->has_acls = true; > + for (size_t i = 0; i < n_acls; i++) { > + const struct nbrec_acl *acl = acls[i]; > + if (acl->tier > od->max_acl_tier) { > + od->max_acl_tier = acl->tier; > + } > + if (!od->has_stateful_acl && !strcmp(acl->action, > "allow-related")) { > + od->has_stateful_acl = true; > + } > + if (od->has_stateful_acl && > + od->max_acl_tier == > nbrec_acl_col_tier.type.value.integer.max) { > + return true; > + } > + } > + > + return false; > +} > + > static void > ls_get_acl_flags(struct ovn_datapath *od) > { > od->has_acls = false; > od->has_stateful_acl = false; > + od->max_acl_tier = 0; > > - if (od->nbs->n_acls) { > - od->has_acls = true; > - > - for (size_t i = 0; i < od->nbs->n_acls; i++) { > - struct nbrec_acl *acl = od->nbs->acls[i]; > - if (!strcmp(acl->action, "allow-related")) { > - od->has_stateful_acl = true; > - return; > - } > - } > + if (od_set_acl_flags(od, od->nbs->acls, od->nbs->n_acls)) { > + return; > } > > struct ovn_ls_port_group *ls_pg; > HMAP_FOR_EACH (ls_pg, key_node, &od->nb_pgs) { > - if (ls_pg->nb_pg->n_acls) { > - od->has_acls = true; > - > - for (size_t i = 0; i < ls_pg->nb_pg->n_acls; i++) { > - struct nbrec_acl *acl = ls_pg->nb_pg->acls[i]; > - if (!strcmp(acl->action, "allow-related")) { > - od->has_stateful_acl = true; > - return; > - } > - } > + if (od_set_acl_flags(od, ls_pg->nb_pg->acls, > ls_pg->nb_pg->n_acls)) { > + return; > } > } > } > @@ -6448,10 +6464,19 @@ consider_acl(struct hmap *lflows, struct > ovn_datapath *od, > size_t log_verdict_len = actions->length; > uint16_t priority = acl->priority + OVN_ACL_PRI_OFFSET; > > + /* All ACLS will start by matching on their respective tier. */ > + size_t match_tier_len = 0; > + ds_clear(match); > + if (od->max_acl_tier) { > + ds_put_format(match, REG_ACL_TIER " == %"PRId64" && ", acl->tier); > + match_tier_len = match->length; > + } > + > if (!has_stateful || !strcmp(acl->action, "allow-stateless")) { > ds_put_cstr(actions, "next;"); > + ds_put_format(match, "(%s)", acl->match); > ovn_lflow_add_with_hint(lflows, od, stage, priority, > - acl->match, ds_cstr(actions), > + ds_cstr(match), ds_cstr(actions), > &acl->header_); > return; > } > @@ -6476,7 +6501,7 @@ consider_acl(struct hmap *lflows, struct > ovn_datapath *od, > * by ct_commit in the "stateful" stage) to indicate that the > * connection should be allowed to resume. > */ > - ds_clear(match); > + ds_truncate(match, match_tier_len); > ds_put_format(match, REGBIT_ACL_HINT_ALLOW_NEW " == 1 && (%s)", > acl->match); > > @@ -6499,7 +6524,7 @@ consider_acl(struct hmap *lflows, struct > ovn_datapath *od, > * Commit the connection only if the ACL has a label. This is done > * to update the connection tracking entry label in case the ACL > * allowing the connection changes. */ > - ds_clear(match); > + ds_truncate(match, match_tier_len); > ds_truncate(actions, log_verdict_len); > ds_put_format(match, REGBIT_ACL_HINT_ALLOW " == 1 && (%s)", > acl->match); > @@ -6520,7 +6545,7 @@ consider_acl(struct hmap *lflows, struct > ovn_datapath *od, > * to the connection tracker with ct_commit. */ > /* If the packet is not tracked or not part of an established > * connection, then we can simply reject/drop it. */ > - ds_clear(match); > + ds_truncate(match, match_tier_len); > ds_put_cstr(match, REGBIT_ACL_HINT_DROP " == 1"); > ds_put_format(match, " && (%s)", acl->match); > > @@ -6540,7 +6565,7 @@ consider_acl(struct hmap *lflows, struct > ovn_datapath *od, > * ct_commit() to the "stateful" stage, but since we're > * rejecting/dropping the packet, we go ahead and do it here. > */ > - ds_clear(match); > + ds_truncate(match, match_tier_len); > ds_put_cstr(match, REGBIT_ACL_HINT_BLOCK " == 1"); > ds_put_format(match, " && (%s)", acl->match); > > @@ -6692,6 +6717,7 @@ static void > build_acl_action_lflows(struct ovn_datapath *od, struct hmap *lflows, > const char *default_acl_action, > const struct shash *meter_groups, > + struct ds *match, > struct ds *actions) > { > enum ovn_stage stages [] = { > @@ -6704,6 +6730,10 @@ build_acl_action_lflows(struct ovn_datapath *od, > struct hmap *lflows, > ds_put_cstr(actions, REGBIT_ACL_VERDICT_ALLOW " = 0; " > REGBIT_ACL_VERDICT_DROP " = 0; " > REGBIT_ACL_VERDICT_REJECT " = 0; "); > + if (od->max_acl_tier) { > + ds_put_cstr(actions, REG_ACL_TIER " = 0; "); > + } > + > size_t verdict_len = actions->length; > > for (size_t i = 0; i < ARRAY_SIZE(stages); i++) { > @@ -6744,6 +6774,20 @@ build_acl_action_lflows(struct ovn_datapath *od, > struct hmap *lflows, > ds_truncate(actions, verdict_len); > ds_put_cstr(actions, default_acl_action); > ovn_lflow_add(lflows, od, stage, 0, "1", ds_cstr(actions)); > + > + struct ds tier_actions = DS_EMPTY_INITIALIZER; > I don't think we actually need to allocate another ds. The "actions" variable is not used at this point anymore, it can be used instead. > + for (size_t j = 0; j < od->max_acl_tier; j++) { > + ds_clear(match); > + ds_put_format(match, REG_ACL_TIER " == %"PRIuSIZE, j); > + ds_clear(&tier_actions); > + ds_put_format(&tier_actions, REG_ACL_TIER " = %"PRIuSIZE"; " > + "next(pipeline=%s,table=%"PRIu8");", > + j + 1, ingress ? "ingress" : "egress", > + ovn_stage_get_table(stage) - 1); > nit: This formatting is not uniform. > + ovn_lflow_add(lflows, od, stage, 500, ds_cstr(match), > + ds_cstr(&tier_actions)); > + } > + ds_destroy(&tier_actions); > } > } > > @@ -7107,7 +7151,7 @@ build_acls(struct ovn_datapath *od, const struct > chassis_features *features, > } > > build_acl_action_lflows(od, lflows, default_acl_action, meter_groups, > - &actions); > + &match, &actions); > > ds_destroy(&match); > ds_destroy(&actions); > diff --git a/northd/northd.h b/northd/northd.h > index a503f4a66..ad6ccef5e 100644 > --- a/northd/northd.h > +++ b/northd/northd.h > @@ -230,6 +230,7 @@ struct ovn_datapath { > bool has_lb_vip; > bool has_unknown; > bool has_acls; > + uint64_t max_acl_tier; > bool has_vtep_lports; > bool has_arp_proxy_port; > > diff --git a/ovn-nb.ovsschema b/ovn-nb.ovsschema > index 4836a219f..f12d39542 100644 > --- a/ovn-nb.ovsschema > +++ b/ovn-nb.ovsschema > @@ -1,7 +1,7 @@ > { > "name": "OVN_Northbound", > "version": "7.0.0", > - "cksum": "94023179 33468", > + "cksum": "3195094080 33650", > "tables": { > "NB_Global": { > "columns": { > @@ -272,6 +272,9 @@ > "label": {"type": {"key": {"type": "integer", > "minInteger": 0, > "maxInteger": 4294967295}}}, > + "tier": {"type": {"key": {"type": "integer", > + "minInteger": 0, > + "maxInteger": 3}}}, > "options": { > "type": {"key": "string", > "value": "string", > diff --git a/ovn-nb.xml b/ovn-nb.xml > index d6694778f..19cbd191d 100644 > --- a/ovn-nb.xml > +++ b/ovn-nb.xml > @@ -2257,6 +2257,26 @@ or > </ul> > </column> > > + <column name="tier"> > + <p>The hierarchical tier that this ACL belongs to.</p> > + > + <p> > + ACLs can be assigned to numerical tiers. When evaluating ACLs, an > + internal counter is used to determine which tier of ACLs should be > + evaluated. Tier 0 ACLs are evaluated first. If no verdict can be > + determined, then tier 1 ACLs are evaluated next. This continues > + until the maximum tier value is reached. If all tiers of ACLs are > + evaluated and no verdict is reached, then the <ref > column="options" > + key="default_acl_drop" table="NB_Global" /> option from table > + <ref table="NB_Global" /> is used to determine how to proceed. > + </p> > + > + <p> > + In this version of OVN, the maximum tier value for ACLs is 3, > + meaning there are 4 tiers of ACLs allowed (0-3). > + </p> > + </column> > + > <group title="options"> > <p> > ACLs options. > diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at > index 19a0e630f..507db7e7a 100644 > --- a/tests/ovn-northd.at > +++ b/tests/ovn-northd.at > @@ -2165,10 +2165,10 @@ AT_CAPTURE_FILE([sw1flows]) > > AT_CHECK( > [grep -E 'ls_(in|out)_acl' sw0flows sw1flows | grep pg0 | sort], [0], > [dnl > -sw0flows: table=4 (ls_out_acl_eval ), priority=2003 , match=(outport > == @pg0 && ip6 && udp), action=(reg8[[18]] = 1; next;) > -sw0flows: table=8 (ls_in_acl_eval ), priority=2002 , match=(inport > == @pg0 && ip4 && tcp && tcp.dst == 80), action=(reg8[[18]] = 1; next;) > -sw1flows: table=4 (ls_out_acl_eval ), priority=2003 , match=(outport > == @pg0 && ip6 && udp), action=(reg8[[18]] = 1; next;) > -sw1flows: table=8 (ls_in_acl_eval ), priority=2002 , match=(inport > == @pg0 && ip4 && tcp && tcp.dst == 80), action=(reg8[[18]] = 1; next;) > +sw0flows: table=4 (ls_out_acl_eval ), priority=2003 , match=((outport > == @pg0 && ip6 && udp)), action=(reg8[[18]] = 1; next;) > +sw0flows: table=8 (ls_in_acl_eval ), priority=2002 , match=((inport > == @pg0 && ip4 && tcp && tcp.dst == 80)), action=(reg8[[18]] = 1; next;) > +sw1flows: table=4 (ls_out_acl_eval ), priority=2003 , match=((outport > == @pg0 && ip6 && udp)), action=(reg8[[18]] = 1; next;) > +sw1flows: table=8 (ls_in_acl_eval ), priority=2002 , match=((inport > == @pg0 && ip4 && tcp && tcp.dst == 80)), action=(reg8[[18]] = 1; next;) > ]) > > AS_BOX([2]) > @@ -2181,10 +2181,10 @@ ovn-sbctl dump-flows sw1 > sw1flows2 > AT_CAPTURE_FILE([sw1flows2]) > > AT_CHECK([grep "ls_out_acl" sw0flows2 sw1flows2 | grep pg0 | sort], [0], > [dnl > -sw0flows2: table=4 (ls_out_acl_eval ), priority=2002 , match=(outport > == @pg0 && ip4 && udp), action=(reg8[[18]] = 1; next;) > -sw0flows2: table=4 (ls_out_acl_eval ), priority=2003 , match=(outport > == @pg0 && ip6 && udp), action=(reg8[[18]] = 1; next;) > -sw1flows2: table=4 (ls_out_acl_eval ), priority=2002 , match=(outport > == @pg0 && ip4 && udp), action=(reg8[[18]] = 1; next;) > -sw1flows2: table=4 (ls_out_acl_eval ), priority=2003 , match=(outport > == @pg0 && ip6 && udp), action=(reg8[[18]] = 1; next;) > +sw0flows2: table=4 (ls_out_acl_eval ), priority=2002 , > match=((outport == @pg0 && ip4 && udp)), action=(reg8[[18]] = 1; next;) > +sw0flows2: table=4 (ls_out_acl_eval ), priority=2003 , > match=((outport == @pg0 && ip6 && udp)), action=(reg8[[18]] = 1; next;) > +sw1flows2: table=4 (ls_out_acl_eval ), priority=2002 , > match=((outport == @pg0 && ip4 && udp)), action=(reg8[[18]] = 1; next;) > +sw1flows2: table=4 (ls_out_acl_eval ), priority=2003 , > match=((outport == @pg0 && ip6 && udp)), action=(reg8[[18]] = 1; next;) > ]) > > AS_BOX([3]) > @@ -7324,7 +7324,7 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" > | sed 's/table=../table=??/ > table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[18]] > == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; > reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport > <-> inport; next(pipeline=egress,table=6); };) > table=??(ls_in_acl_after_lb_eval), priority=0 , match=(1), > action=(next;) > table=??(ls_in_acl_eval ), priority=0 , match=(1), action=(next;) > - table=??(ls_in_acl_eval ), priority=1001 , match=(ip4 && tcp), > action=(reg8[[16]] = 1; next;) > + table=??(ls_in_acl_eval ), priority=1001 , match=((ip4 && tcp)), > action=(reg8[[16]] = 1; next;) > table=??(ls_in_acl_eval ), priority=34000, match=(eth.dst == > $svc_monitor_mac), action=(reg8[[16]] = 1; next;) > table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;) > table=??(ls_in_pre_acl ), priority=0 , match=(1), action=(next;) > @@ -7358,7 +7358,7 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" > | sed 's/table=../table=??/ > table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[18]] > == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; > reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport > <-> inport; next(pipeline=egress,table=6); };) > table=??(ls_in_acl_after_lb_eval), priority=0 , match=(1), > action=(next;) > table=??(ls_in_acl_eval ), priority=0 , match=(1), action=(next;) > - table=??(ls_in_acl_eval ), priority=1001 , match=(ip4 && tcp), > action=(reg8[[16]] = 1; next;) > + table=??(ls_in_acl_eval ), priority=1001 , match=((ip4 && tcp)), > action=(reg8[[16]] = 1; next;) > table=??(ls_in_acl_eval ), priority=34000, match=(eth.dst == > $svc_monitor_mac), action=(reg8[[16]] = 1; next;) > table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;) > table=??(ls_in_pre_acl ), priority=0 , match=(1), action=(next;) > @@ -7392,7 +7392,7 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" > | sed 's/table=../table=??/ > table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[18]] > == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; > reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport > <-> inport; next(pipeline=egress,table=6); };) > table=??(ls_in_acl_after_lb_eval), priority=0 , match=(1), > action=(next;) > table=??(ls_in_acl_eval ), priority=0 , match=(1), action=(next;) > - table=??(ls_in_acl_eval ), priority=1001 , match=(ip4 && tcp), > action=(reg8[[16]] = 1; next;) > + table=??(ls_in_acl_eval ), priority=1001 , match=((ip4 && tcp)), > action=(reg8[[16]] = 1; next;) > table=??(ls_in_acl_eval ), priority=34000, match=(eth.dst == > $svc_monitor_mac), action=(reg8[[16]] = 1; next;) > table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;) > table=??(ls_in_pre_acl ), priority=0 , match=(1), action=(next;) > @@ -7497,7 +7497,7 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" > | sed 's/table=../table=??/ > table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[17]] > == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */) > table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[18]] > == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; > reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport > <-> inport; next(pipeline=egress,table=6); };) > table=??(ls_in_acl_after_lb_eval), priority=0 , match=(1), > action=(next;) > - table=??(ls_in_acl_after_lb_eval), priority=1001 , match=(ip4 && tcp), > action=(reg8[[16]] = 1; next;) > + table=??(ls_in_acl_after_lb_eval), priority=1001 , match=((ip4 && > tcp)), action=(reg8[[16]] = 1; next;) > table=??(ls_in_acl_eval ), priority=0 , match=(1), action=(next;) > table=??(ls_in_acl_eval ), priority=34000, match=(eth.dst == > $svc_monitor_mac), action=(reg8[[16]] = 1; next;) > table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;) > @@ -7531,7 +7531,7 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" > | sed 's/table=../table=??/ > table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[17]] > == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */) > table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[18]] > == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; > reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport > <-> inport; next(pipeline=egress,table=6); };) > table=??(ls_in_acl_after_lb_eval), priority=0 , match=(1), > action=(next;) > - table=??(ls_in_acl_after_lb_eval), priority=1001 , match=(ip4 && tcp), > action=(reg8[[16]] = 1; next;) > + table=??(ls_in_acl_after_lb_eval), priority=1001 , match=((ip4 && > tcp)), action=(reg8[[16]] = 1; next;) > table=??(ls_in_acl_eval ), priority=0 , match=(1), action=(next;) > table=??(ls_in_acl_eval ), priority=34000, match=(eth.dst == > $svc_monitor_mac), action=(reg8[[16]] = 1; next;) > table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;) > @@ -7565,7 +7565,7 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" > | sed 's/table=../table=??/ > table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[17]] > == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */) > table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[18]] > == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; > reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport > <-> inport; next(pipeline=egress,table=6); };) > table=??(ls_in_acl_after_lb_eval), priority=0 , match=(1), > action=(next;) > - table=??(ls_in_acl_after_lb_eval), priority=1001 , match=(ip4 && tcp), > action=(reg8[[16]] = 1; next;) > + table=??(ls_in_acl_after_lb_eval), priority=1001 , match=((ip4 && > tcp)), action=(reg8[[16]] = 1; next;) > table=??(ls_in_acl_eval ), priority=0 , match=(1), action=(next;) > table=??(ls_in_acl_eval ), priority=34000, match=(eth.dst == > $svc_monitor_mac), action=(reg8[[16]] = 1; next;) > table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;) > @@ -7681,7 +7681,7 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" > | sed 's/table=../table=??/ > table=??(ls_out_acl_action ), priority=1000 , match=(reg8[[17]] == 1), > action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */) > table=??(ls_out_acl_action ), priority=1000 , match=(reg8[[18]] == 1), > action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { > /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> > inport; next(pipeline=ingress,table=27); };) > table=??(ls_out_acl_eval ), priority=0 , match=(1), action=(next;) > - table=??(ls_out_acl_eval ), priority=1001 , match=(ip4 && tcp), > action=(reg8[[16]] = 1; next;) > + table=??(ls_out_acl_eval ), priority=1001 , match=((ip4 && tcp)), > action=(reg8[[16]] = 1; next;) > table=??(ls_out_acl_eval ), priority=34000, match=(eth.src == > $svc_monitor_mac), action=(reg8[[16]] = 1; next;) > table=??(ls_out_acl_hint ), priority=0 , match=(1), action=(next;) > table=??(ls_out_pre_acl ), priority=0 , match=(1), action=(next;) > @@ -7715,7 +7715,7 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" > | sed 's/table=../table=??/ > table=??(ls_out_acl_action ), priority=1000 , match=(reg8[[17]] == 1), > action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */) > table=??(ls_out_acl_action ), priority=1000 , match=(reg8[[18]] == 1), > action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { > /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> > inport; next(pipeline=ingress,table=27); };) > table=??(ls_out_acl_eval ), priority=0 , match=(1), action=(next;) > - table=??(ls_out_acl_eval ), priority=1001 , match=(ip4 && tcp), > action=(reg8[[16]] = 1; next;) > + table=??(ls_out_acl_eval ), priority=1001 , match=((ip4 && tcp)), > action=(reg8[[16]] = 1; next;) > table=??(ls_out_acl_eval ), priority=34000, match=(eth.src == > $svc_monitor_mac), action=(reg8[[16]] = 1; next;) > table=??(ls_out_acl_hint ), priority=0 , match=(1), action=(next;) > table=??(ls_out_pre_acl ), priority=0 , match=(1), action=(next;) > @@ -7749,7 +7749,7 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" > | sed 's/table=../table=??/ > table=??(ls_out_acl_action ), priority=1000 , match=(reg8[[17]] == 1), > action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */) > table=??(ls_out_acl_action ), priority=1000 , match=(reg8[[18]] == 1), > action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { > /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> > inport; next(pipeline=ingress,table=27); };) > table=??(ls_out_acl_eval ), priority=0 , match=(1), action=(next;) > - table=??(ls_out_acl_eval ), priority=1001 , match=(ip4 && tcp), > action=(reg8[[16]] = 1; next;) > + table=??(ls_out_acl_eval ), priority=1001 , match=((ip4 && tcp)), > action=(reg8[[16]] = 1; next;) > table=??(ls_out_acl_eval ), priority=34000, match=(eth.src == > $svc_monitor_mac), action=(reg8[[16]] = 1; next;) > table=??(ls_out_acl_hint ), priority=0 , match=(1), action=(next;) > table=??(ls_out_pre_acl ), priority=0 , match=(1), action=(next;) > @@ -8998,3 +8998,131 @@ mac_binding_timestamp: true > > AT_CLEANUP > ]) > + > +OVN_FOR_EACH_NORTHD_NO_HV([ > +AT_SETUP([Tiered ACL logical flows]) > +AT_KEYWORDS([acl]) > + > +ovn_start > + > +check ovn-nbctl ls-add ls > +check ovn-nbctl lsp-add ls lsp > +check ovn-nbctl pg-add pg lsp > + > +m4_define([ACL_FLOWS], [grep -w $1 lflows | grep "$2" | sed > 's/table=../table=??/' | sed "s/\($1[[^)]]*\)/$1/" | sort]) > + > +acl_test() { > + direction=$1 > + options=$2 > + thing=$3 > + eval_stage=$4 > + action_stage=$5 > + eval_stage_table=$6 > + > + if test "$direction" = "from-lport" ; then > + pipeline=ingress > + else > + pipeline=egress > + fi > + > + # Baseline test. Ensure that no ACL evaluation or tier-related flows > are > + # installed. > + ovn-sbctl lflow-list ls > lflows > + AT_CHECK([ACL_FLOWS([$eval_stage], [priority=2000])], [0], []) > + > + AT_CHECK([ACL_FLOWS([$action_stage], [priority=500])], [0], []) > + > + # Add an untiered ACL. Ensure that the ACL appears in the eval stage, > and > + # that no tier-related flows appear in the action stage. > + check ovn-nbctl --wait=sb $options acl-add $thing $direction 1000 > "ip4.addr == 80.111.111.112" drop > + acl1_uuid=$(ovn-nbctl --bare --columns _uuid find ACL priority=1000) > + > + ovn-sbctl lflow-list ls > lflows > + AT_CAPTURE_FILE([lflows]) > + AT_CHECK_UNQUOTED([ACL_FLOWS([$eval_stage], [priority=2000])], [0], > [dnl > + table=??($eval_stage), priority=2000 , match=((ip4.addr == > 80.111.111.112)), action=(reg8[[17]] = 1; next;) > +]) > + > + AT_CHECK([ACL_FLOWS([$action_stage], [priority=500])], [0], []) > + > + # Explicitly name the tier on the ACL to be tier 0. This should have > no > + # effect on the logical flows. > + check ovn-nbctl --wait=sb set ACL $acl1_uuid tier=0 > + ovn-sbctl lflow-list ls > lflows > + AT_CHECK_UNQUOTED([ACL_FLOWS([$eval_stage], [priority=2000])], [0], > [dnl > + table=??($eval_stage), priority=2000 , match=((ip4.addr == > 80.111.111.112)), action=(reg8[[17]] = 1; next;) > +]) > + AT_CHECK([ACL_FLOWS([$action_stage], [priority=500])], [0], []) > + > + # Change the ACL to tier 1. Now we should see the tier as part of the > ACL > + # match, and we should see a flow in the action stage to bump the tier > + # to 1 if there was no match on tier 0. > + check ovn-nbctl --wait=sb set ACL $acl1_uuid tier=1 > + ovn-sbctl lflow-list ls > lflows > + AT_CHECK_UNQUOTED([ACL_FLOWS([$eval_stage], [priority=2000])], [0], > [dnl > + table=??($eval_stage), priority=2000 , match=(reg8[[30..31]] == 1 && > (ip4.addr == 80.111.111.112)), action=(reg8[[17]] = 1; next;) > +]) > + > + AT_CHECK_UNQUOTED([ACL_FLOWS([$action_stage], [priority=500])], [0], > [dnl > + table=??($action_stage), priority=500 , match=(reg8[[30..31]] == 0), > action=(reg8[[30..31]] = 1; > next(pipeline=$pipeline,table=$eval_stage_table);) > +]) > + > + # Change the ACL to tier 3. Ensure the tier match on the ACL has been > + # updated, and ensure we see three flows present for incrementing the > + # tier value in the action stage. > + check ovn-nbctl --wait=sb set ACL $acl1_uuid tier=3 > + ovn-sbctl lflow-list ls > lflows > + AT_CHECK_UNQUOTED([ACL_FLOWS([$eval_stage], [priority=2000])], [0], > [dnl > + table=??($eval_stage), priority=2000 , match=(reg8[[30..31]] == 3 && > (ip4.addr == 80.111.111.112)), action=(reg8[[17]] = 1; next;) > +]) > + > + AT_CHECK_UNQUOTED([ACL_FLOWS([$action_stage], [priority=500])], [0], > [dnl > + table=??($action_stage), priority=500 , match=(reg8[[30..31]] == 0), > action=(reg8[[30..31]] = 1; > next(pipeline=$pipeline,table=$eval_stage_table);) > + table=??($action_stage), priority=500 , match=(reg8[[30..31]] == 1), > action=(reg8[[30..31]] = 2; > next(pipeline=$pipeline,table=$eval_stage_table);) > + table=??($action_stage), priority=500 , match=(reg8[[30..31]] == 2), > action=(reg8[[30..31]] = 3; > next(pipeline=$pipeline,table=$eval_stage_table);) > +]) > + > + # Add an untiered ACL. Ensure that it matches on tier 0, but > otherwise, > + # nothing else should have changed in the logical flows. > + check ovn-nbctl --wait=sb $options acl-add $thing $direction 1000 > "ip4.addr == 83.104.105.116" allow > + ovn-sbctl lflow-list ls > lflows > + AT_CHECK_UNQUOTED([ACL_FLOWS([$eval_stage], [priority=2000])], [0], > [dnl > + table=??($eval_stage), priority=2000 , match=(reg8[[30..31]] == 0 && > (ip4.addr == 83.104.105.116)), action=(reg8[[16]] = 1; next;) > + table=??($eval_stage), priority=2000 , match=(reg8[[30..31]] == 3 && > (ip4.addr == 80.111.111.112)), action=(reg8[[17]] = 1; next;) > +]) > + > + AT_CHECK_UNQUOTED([ACL_FLOWS([$action_stage], [priority=500])], [0], > [dnl > + table=??($action_stage), priority=500 , match=(reg8[[30..31]] == 0), > action=(reg8[[30..31]] = 1; > next(pipeline=$pipeline,table=$eval_stage_table);) > + table=??($action_stage), priority=500 , match=(reg8[[30..31]] == 1), > action=(reg8[[30..31]] = 2; > next(pipeline=$pipeline,table=$eval_stage_table);) > + table=??($action_stage), priority=500 , match=(reg8[[30..31]] == 2), > action=(reg8[[30..31]] = 3; > next(pipeline=$pipeline,table=$eval_stage_table);) > +]) > + > + # Remove the tier 3 ACL. The remaining ACL is untiered, and there are > no > + # other tiered ACLs. So we should go back to not checking the tier > + # number in the ACL match, and there should be no tier-related flows > + # in the action stage. > + check ovn-nbctl --wait=sb acl-del $thing $direction 1000 "ip4.addr == > 80.111.111.112" > + ovn-sbctl lflow-list ls > lflows > + AT_CHECK_UNQUOTED([ACL_FLOWS([$eval_stage], [priority=2000])], [0], > [dnl > + table=??($eval_stage), priority=2000 , match=((ip4.addr == > 83.104.105.116)), action=(reg8[[16]] = 1; next;) > +]) > + > + AT_CHECK([ACL_FLOWS([$action_stage], [priority=500])], [0], []) > + > + check ovn-nbctl --wait=sb acl-del $thing > + ovn-sbctl lflow-list ls > lflows > + > + AT_CHECK([ACL_FLOWS([$eval_stage], [priority=2000])], [0], []) > + > + AT_CHECK([ACL_FLOWS([$action_stage], [priority=500])], [0], []) > +} > + > +acl_test from-lport "" ls ls_in_acl_eval ls_in_acl_action 8 > +acl_test from-lport "--apply-after-lb" ls ls_in_acl_after_lb_eval > ls_in_acl_after_lb_action 18 > +acl_test to-lport "" ls ls_out_acl_eval ls_out_acl_action 4 > +acl_test from-lport "" pg ls_in_acl_eval ls_in_acl_action 8 > +acl_test from-lport "--apply-after-lb" pg ls_in_acl_after_lb_eval > ls_in_acl_after_lb_action 18 > +acl_test to-lport "" pg ls_out_acl_eval ls_out_acl_action 4 > + > +AT_CLEANUP > +]) > diff --git a/tests/system-ovn.at b/tests/system-ovn.at > index 6d1ce9577..620e29cf6 100644 > --- a/tests/system-ovn.at > +++ b/tests/system-ovn.at > @@ -10784,3 +10784,110 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query > port patch-.*/d > /connection dropped.*/d"]) > AT_CLEANUP > ]) > + > +OVN_FOR_EACH_NORTHD([ > +AT_SETUP([Tiered ACLs]) > +AT_KEYWORDS([acl]) > + > +ovn_start > +OVS_TRAFFIC_VSWITCHD_START() > +ADD_BR([br-int]) > + > +# Set external-ids in br-int needed for ovn-controller > +check ovs-vsctl \ > + -- set Open_vSwitch . external-ids:system-id=hv1 \ > + -- set Open_vSwitch . > external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \ > + -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \ > + -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \ > + -- set bridge br-int fail-mode=secure > other-config:disable-in-band=true > + > +# Start ovn-controller > +start_daemon ovn-controller > + > +check ovn-nbctl ls-add ls > +check ovn-nbctl lsp-add ls lsp1 -- lsp-set-addresses lsp1 > "00:00:00:00:00:01 10.0.0.1" > +check ovn-nbctl lsp-add ls lsp2 -- lsp-set-addresses lsp2 > "00:00:00:00:00:02 10.0.0.2" > + > +check ovn-nbctl pg-add pg lsp1 lsp2 > + > +ADD_NAMESPACES(lsp1) > +ADD_VETH(lsp1, lsp1, br-int, "10.0.0.1/24", "00:00:00:00:00:01") > +ADD_NAMESPACES(lsp2) > +ADD_VETH(lsp2, lsp2, br-int, "10.0.0.2/24", "00:00:00:00:00:02") > + > +m4_define([PING_PCT], [grep -o "[[0-9]]\{1,3\}% packet loss"]) > + > +acl_test() { > + direction=$1 > + options=$2 > + thing=$3 > + > + # First a baseline. If traffic isn't being allowed, then something is > + # very wrong. > + NS_CHECK_EXEC([lsp1], [ping -q -c 3 -i 0.3 -w 2 10.0.0.2 | PING_PCT], > \ > +[0], [dnl > +0% packet loss > +]) > + # Add an untiered drop ACL. This should cause pings to fail. > + check ovn-nbctl --wait=sb $options acl-add $thing $direction 1000 > "ip4.dst == 10.0.0.2" drop > + acl1_uuid=$(ovn-nbctl --bare --columns _uuid find ACL priority=1000) > + > + NS_CHECK_EXEC([lsp1], [ping -q -c 3 -i 0.3 -w 2 10.0.0.2 | PING_PCT], > \ > +[0], [dnl > +100% packet loss > +]) > + > + # Change the tier to 3. Despite there being "holes" in tiers 0, 1, > and 2, > + # the ACL should still apply, and pings should fail. > + check ovn-nbctl --wait=sb set ACL $acl1_uuid tier=3 > + NS_CHECK_EXEC([lsp1], [ping -q -c 3 -i 0.3 -w 2 10.0.0.2 | PING_PCT], > \ > +[0], [dnl > +100% packet loss > +]) > + > + # Add a tier-0 ACL that allows the traffic. The priority is only 4, > but > + # since it is a higher tier, the traffic should be allowed. > + check ovn-nbctl --wait=sb $options acl-add $thing $direction 4 > "ip4.dst == 10.0.0.2" allow > + NS_CHECK_EXEC([lsp1], [ping -q -c 3 -i 0.3 -w 2 10.0.0.2 | PING_PCT], > \ > +[0], [dnl > +0% packet loss > +]) > + > + # Removing the 0-tier ACL should make traffic go back to being > dropped. > + check ovn-nbctl --wait=sb acl-del $thing $direction 4 "ip4.dst == > 10.0.0.2" > + NS_CHECK_EXEC([lsp1], [ping -q -c 3 -i 0.3 -w 2 10.0.0.2 | PING_PCT], > \ > +[0], [dnl > +100% packet loss > +]) > + > + # Removing all ACLs should make traffic go back to passing. > + check ovn-nbctl --wait=sb acl-del $thing > + NS_CHECK_EXEC([lsp1], [ping -q -c 3 -i 0.3 -w 2 10.0.0.2 | PING_PCT], > \ > +[0], [dnl > +0% packet loss > +]) > +} > + > +acl_test from-lport "" ls > +acl_test from-lport "--apply-after-lb" ls > +acl_test to-lport "" ls > +acl_test from-lport "" pg > +acl_test from-lport "--apply-after-lb" pg > +acl_test to-lport "" pg > + > +OVS_APP_EXIT_AND_WAIT([ovn-controller]) > + > +as ovn-sb > +OVS_APP_EXIT_AND_WAIT([ovsdb-server]) > + > +as ovn-nb > +OVS_APP_EXIT_AND_WAIT([ovsdb-server]) > + > +as northd > +OVS_APP_EXIT_AND_WAIT([NORTHD_TYPE]) > + > +as > +OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d > +/connection dropped.*/d"]) > +AT_CLEANUP > +]) > -- > 2.38.1 > > _______________________________________________ > dev mailing list > [email protected] > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > > Other than that and the error that causes the CI failure it looks good. Thanks, Ales -- Ales Musil Senior Software Engineer - OVN Core Red Hat EMEA <https://www.redhat.com> [email protected] IM: amusil <https://red.ht/sig> _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
