+ /* Ingress and Egress Pre-ACL Table (Priority 100).
+ *
+ * Regardless of whether the ACL is "from-lport" or "to-lport",
+ * we need rules in both the ingress and egress table, because
+ * the return traffic needs to be followed. */
+ ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 100, "ip", "ct_next;");
+ ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 100, "ip", "ct_next;");
+
+ /* Ingress and Egress ACL Table (Priority 1).
+ *
+ * By default, traffic is allowed. This is partially handled by
+ * the Priority 0 ACL flows added earlier, but we also need to
+ * commit IP flows. This is because, while the initiater's
+ * direction may not have any stateful rules, the server's may
+ * and then its return traffic would not have an associated
+ * conntrack entry and would return "+invalid". */
+ ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, 1, "ip",
+ "ct_commit; next;");
+ ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, 1, "ip",
+ "ct_commit; next;");
+
+ /* Ingress and Egress ACL Table (Priority 65535).
+ *
+ * Always drop traffic that's in an invalid state. This is
+ * enforced at a higher priority than ACLs can be defined. */
+ ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX,
+ "ct.inv", "drop;");
+ ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX,
+ "ct.inv", "drop;");
+
+ /* Ingress and Egress ACL Table (Priority 65535).
+ *
+ * Always allow traffic that is established to a committed
+ * conntrack entry. This is enforced at a higher priority than
+ * ACLs can be defined. */
+ ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX,
+ "ct.est && !ct.rel && !ct.new && !ct.inv",
+ "next;");
+ ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX,
+ "ct.est && !ct.rel && !ct.new && !ct.inv",
+ "next;");
+
+ /* Ingress and Egress ACL Table (Priority 65535).
+ *
+ * Always allow traffic that is related to an existing conntrack
+ * entry. This is enforced at a higher priority than ACLs can
+ * be defined.
+ *
+ * NOTE: This does not support related data sessions (eg,
+ * a dynamically negotiated FTP data channel), but will allow
+ * related traffic such as an ICMP Port Unreachable through
+ * that's generated from a non-listening UDP port. */
+ ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX,
+ "!ct.est && ct.rel && !ct.new && !ct.inv",
+ "next;");
+ ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX,
+ "!ct.est && ct.rel && !ct.new && !ct.inv",
+ "next;");
+ }
+
+ /* Ingress or Egress ACL Table (Various priorities). */
+ for (size_t i = 0; i < od->nbs->n_acls; i++) {
+ struct nbrec_acl *acl = od->nbs->acls[i];
+ bool ingress = !strcmp(acl->direction, "from-lport") ? true :false;
+ enum ovn_stage stage = ingress ? S_SWITCH_IN_ACL : S_SWITCH_OUT_ACL;
+
+ if (!strcmp(acl->action, "allow")) {
+ /* If there are any stateful flows, we must even commit "allow"
+ * actions. This is because, while the initiater's
+ * direction may not have any stateful rules, the server's
+ * may and then its return traffic would not have an
+ * associated conntrack entry and would return "+invalid". */
+ const char *actions = has_stateful ? "ct_commit; next;" : "next;";
+ ovn_lflow_add(lflows, od, stage,
+ acl->priority + OVN_ACL_PRI_OFFSET,
+ acl->match, actions);
+ } else if (!strcmp(acl->action, "allow-related")) {
+ struct ds match = DS_EMPTY_INITIALIZER;
+
+ /* Commit the connection tracking entry, which allows all
+ * other traffic related to this entry to flow due to the
+ * 65535 priority flow defined earlier. */
+ ds_put_format(&match, "ct.new && (%s)", acl->match);
+ ovn_lflow_add(lflows, od, stage,
+ acl->priority + OVN_ACL_PRI_OFFSET,
+ ds_cstr(&match), "ct_commit; next;");
+
+ ds_destroy(&match);
+ } else if (!strcmp(acl->action, "drop")) {
+ ovn_lflow_add(lflows, od, stage,
+ acl->priority + OVN_ACL_PRI_OFFSET,
+ acl->match, "drop;");
+ } else if (!strcmp(acl->action, "reject")) {
+ /* xxx Need to support "reject". */
+ VLOG_INFO("reject is not a supported action");
+ ovn_lflow_add(lflows, od, stage,
+ acl->priority + OVN_ACL_PRI_OFFSET,
+ acl->match, "drop;");
+ }
+ }
+}
+
+static void
+build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
+ struct hmap *lflows, struct hmap *mcgroups)
+{
+ /* This flow table structure is documented in ovn-northd(8), so please
+ * update ovn-northd.8.xml if you change anything. */
+
+ /* Build pre-ACL and ACL tables for both ingress and egress.
+ * Ingress tables 1 and 2. Egress tables 0 and 1. */