#include "ovn/lib/actions.h"
#include "ovn/lib/expr.h"
#include "ovn/lib/ovn-sb-idl.h"
+#include "packets.h"
#include "simap.h"
VLOG_DEFINE_THIS_MODULE(lflow);
MFF_LOG_REGS;
#undef MFF_LOG_REG
+ /* Connection tracking state. */
+ expr_symtab_add_field(&symtab, "ct_state", MFF_CT_STATE, NULL, false);
+ char ct_state_str[16];
+ snprintf(ct_state_str, sizeof ct_state_str, "ct_state[%d]", CS_TRACKED_BIT);
+ expr_symtab_add_predicate(&symtab, "ct.trk", ct_state_str);
+ snprintf(ct_state_str, sizeof ct_state_str, "ct_state[%d]", CS_NEW_BIT);
+ expr_symtab_add_subfield(&symtab, "ct.new", "ct.trk", ct_state_str);
+ snprintf(ct_state_str, sizeof ct_state_str, "ct_state[%d]", CS_ESTABLISHED_BIT);
+ expr_symtab_add_subfield(&symtab, "ct.est", "ct.trk", ct_state_str);
+ snprintf(ct_state_str, sizeof ct_state_str, "ct_state[%d]", CS_RELATED_BIT);
+ expr_symtab_add_subfield(&symtab, "ct.rel", "ct.trk", ct_state_str);
+ snprintf(ct_state_str, sizeof ct_state_str, "ct_state[%d]", CS_REPLY_DIR_BIT);
+ expr_symtab_add_subfield(&symtab, "ct.rpl", "ct.trk", ct_state_str);
+ snprintf(ct_state_str, sizeof ct_state_str, "ct_state[%d]", CS_INVALID_BIT);
+ expr_symtab_add_subfield(&symtab, "ct.inv", "ct.trk", ct_state_str);
+
/* Data fields. */
expr_symtab_add_field(&symtab, "eth.src", MFF_ETH_SRC, NULL, false);
expr_symtab_add_field(&symtab, "eth.dst", MFF_ETH_DST, NULL, false);
expr_symtab_add_field(&symtab, "eth.type", MFF_ETH_TYPE, NULL, true);
+ expr_symtab_add_predicate(&symtab, "eth.bcast",
+ "eth.dst == ff:ff:ff:ff:ff:ff");
+ expr_symtab_add_subfield(&symtab, "eth.mcast", NULL, "eth.dst[40]");
expr_symtab_add_field(&symtab, "vlan.tci", MFF_VLAN_TCI, NULL, false);
expr_symtab_add_predicate(&symtab, "vlan.present", "vlan.tci[12]");
expr_symtab_add_field(&symtab, "ip4.src", MFF_IPV4_SRC, "ip4", false);
expr_symtab_add_field(&symtab, "ip4.dst", MFF_IPV4_DST, "ip4", false);
+ expr_symtab_add_predicate(&symtab, "ip4.mcast", "ip4.dst[28..31] == 0xe");
expr_symtab_add_predicate(&symtab, "icmp4", "ip4 && ip.proto == 1");
expr_symtab_add_field(&symtab, "icmp4.type", MFF_ICMPV4_TYPE, "icmp4",
\f
/* Logical datapaths and logical port numbers. */
+enum ldp_type {
+ LDP_TYPE_ROUTER,
+ LDP_TYPE_SWITCH,
+};
+
/* A logical datapath.
*
* 'ports' maps 'logical_port' names to 'tunnel_key' values in the OVN_SB
struct uuid uuid; /* UUID from Datapath_Binding row. */
uint32_t tunnel_key; /* 'tunnel_key' from Datapath_Binding row. */
struct simap ports; /* Logical port name to port number. */
+ enum ldp_type type; /* Type of logical datapath */
};
/* Contains "struct logical_datapath"s. */
uuid_hash(&binding->header_.uuid));
ldp->uuid = binding->header_.uuid;
ldp->tunnel_key = binding->tunnel_key;
+ const char *ls = smap_get(&binding->external_ids, "logical-switch");
+ ldp->type = ls ? LDP_TYPE_SWITCH : LDP_TYPE_ROUTER;
simap_init(&ldp->ports);
return ldp;
}
/* Translates logical flows in the Logical_Flow table in the OVN_SB database
* into OpenFlow flows. See ovn-architecture(7) for more information. */
void
-lflow_run(struct controller_ctx *ctx, struct hmap *flow_table)
+lflow_run(struct controller_ctx *ctx, struct hmap *flow_table,
+ const struct simap *ct_zones,
+ struct hmap *local_datapaths)
{
struct hmap flows = HMAP_INITIALIZER(&flows);
uint32_t conj_id_ofs = 1;
continue;
}
- /* Translate logical table ID to physical table ID. */
bool ingress = !strcmp(lflow->pipeline, "ingress");
- uint8_t phys_table = lflow->table_id + (ingress
- ? OFTABLE_LOG_INGRESS_PIPELINE
- : OFTABLE_LOG_EGRESS_PIPELINE);
- uint8_t next_phys_table
- = lflow->table_id + 1 < LOG_PIPELINE_LEN ? phys_table + 1 : 0;
- uint8_t output_phys_table = (ingress
- ? OFTABLE_REMOTE_OUTPUT
- : OFTABLE_LOG_TO_PHY);
+
+ if (ldp->type == LDP_TYPE_SWITCH && !ingress) {
+ /* For a logical switch datapath, local_datapaths tells us if there
+ * are any local ports for this datapath. If not, processing
+ * logical flows for the egress pipeline of this datapath is
+ * unnecessary.
+ *
+ * We still need the ingress pipeline because even if there are no
+ * local ports, we still may need to execute the ingress pipeline
+ * after a packet leaves a logical router. Further optimization
+ * is possible, but not based on what we know with local_datapaths
+ * right now.
+ */
+
+ struct hmap_node *ld;
+ ld = hmap_first_with_hash(local_datapaths, ldp->tunnel_key);
+ if (!ld) {
+ continue;
+ }
+ }
+
+ /* Determine translation of logical table IDs to physical table IDs. */
+ uint8_t first_ptable = (ingress
+ ? OFTABLE_LOG_INGRESS_PIPELINE
+ : OFTABLE_LOG_EGRESS_PIPELINE);
+ uint8_t ptable = first_ptable + lflow->table_id;
+ uint8_t output_ptable = (ingress
+ ? OFTABLE_REMOTE_OUTPUT
+ : OFTABLE_LOG_TO_PHY);
+
/* Translate OVN actions into OpenFlow actions.
*
* XXX Deny changes to 'outport' in egress pipeline. */
char *error;
ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);
- error = actions_parse_string(lflow->actions, &symtab, &ldp->ports,
- next_phys_table, output_phys_table,
- &ofpacts, &prereqs);
+ struct action_params ap = {
+ .symtab = &symtab,
+ .ports = &ldp->ports,
+ .ct_zones = ct_zones,
+
+ .n_tables = LOG_PIPELINE_LEN,
+ .first_ptable = first_ptable,
+ .cur_ltable = lflow->table_id,
+ .output_ptable = output_ptable,
+ };
+ error = actions_parse_string(lflow->actions, &ap, &ofpacts, &prereqs);
if (error) {
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
VLOG_WARN_RL(&rl, "error parsing actions \"%s\": %s",
m->match.flow.conj_id += conj_id_ofs;
}
if (!m->n) {
- ofctrl_add_flow(flow_table, phys_table, lflow->priority,
+ ofctrl_add_flow(flow_table, ptable, lflow->priority,
&m->match, &ofpacts);
} else {
uint64_t conj_stubs[64 / 8];
dst->clause = src->clause;
dst->n_clauses = src->n_clauses;
}
- ofctrl_add_flow(flow_table, phys_table, lflow->priority,
+ ofctrl_add_flow(flow_table, ptable, lflow->priority,
&m->match, &conj);
ofpbuf_uninit(&conj);
}