static const char *default_db(void);
+
+/* Ingress pipeline stages.
+ *
+ * These must be listed in the order that the stages will be executed. */
+#define INGRESS_STAGES \
+ INGRESS_STAGE(PORT_SEC, port_sec) \
+ INGRESS_STAGE(ACL, acl) \
+ INGRESS_STAGE(L2_LKUP, l2_lkup)
+
+enum ingress_stage {
+#define INGRESS_STAGE(NAME, STR) S_IN_##NAME,
+ INGRESS_STAGES
+#undef INGRESS_STAGE
+ INGRESS_N_STAGES
+};
+
+/* Egress pipeline stages.
+ *
+ * These must be listed in the order that the stages will be executed. */
+#define EGRESS_STAGES \
+ EGRESS_STAGE(ACL, acl) \
+ EGRESS_STAGE(PORT_SEC, port_sec)
+
+enum egress_stage {
+#define EGRESS_STAGE(NAME, STR) S_OUT_##NAME,
+ EGRESS_STAGES
+#undef EGRESS_STAGE
+ EGRESS_N_STAGES
+};
+
static void
usage(void)
{
od->sb = sbrec_datapath_binding_insert(ctx->ovnsb_txn);
- struct smap external_ids = SMAP_INITIALIZER(&external_ids);
char uuid_s[UUID_LEN + 1];
sprintf(uuid_s, UUID_FMT, UUID_ARGS(&od->nb->header_.uuid));
- smap_add(&external_ids, "logical-switch", uuid_s);
- sbrec_datapath_binding_set_external_ids(od->sb, &external_ids);
- smap_destroy(&external_ids);
+ const struct smap id = SMAP_CONST1(&id, "logical-switch", uuid_s);
+ sbrec_datapath_binding_set_external_ids(od->sb, &id);
sbrec_datapath_binding_set_tunnel_key(od->sb, tunnel_key);
}
static void
ovn_port_update_sbrec(const struct ovn_port *op)
{
+ sbrec_port_binding_set_type(op->sb, op->nb->type);
+ sbrec_port_binding_set_options(op->sb, &op->nb->options);
sbrec_port_binding_set_datapath(op->sb, op->od->sb);
sbrec_port_binding_set_parent_port(op->sb, op->nb->parent_name);
sbrec_port_binding_set_tag(op->sb, op->nb->tag, op->nb->n_tag);
lflow->actions = actions;
}
+static const char *
+ingress_stage_to_str(int stage) {
+ switch (stage) {
+#define INGRESS_STAGE(NAME, STR) case S_IN_##NAME: return #STR;
+ INGRESS_STAGES
+#undef INGRESS_STAGE
+ default: return "<unknown>";
+ }
+}
+
+static const char *
+egress_stage_to_str(int stage) {
+ switch (stage) {
+#define EGRESS_STAGE(NAME, STR) case S_OUT_##NAME: return #STR;
+ EGRESS_STAGES
+#undef EGRESS_STAGE
+ default: return "<unknown>";
+ }
+}
+
/* Adds a row with the specified contents to the Logical_Flow table. */
static void
ovn_lflow_add(struct hmap *lflow_map, struct ovn_datapath *od,
size_t n = 0;
for (size_t i = 0; i < n_port_security; i++) {
- uint8_t ea[ETH_ADDR_LEN];
+ struct eth_addr ea;
- if (eth_addr_from_string(port_security[i], ea)) {
+ if (eth_addr_from_string(port_security[i], &ea)) {
ds_put_format(match, ETH_ADDR_FMT, ETH_ADDR_ARGS(ea));
ds_put_char(match, ' ');
n++;
build_lflows(struct northd_context *ctx, struct hmap *datapaths,
struct hmap *ports)
{
+ /* This flow table structure is documented in ovn-northd(8), so please
+ * update ovn-northd.8.xml if you change anything. */
+
struct hmap lflows = HMAP_INITIALIZER(&lflows);
struct hmap mcgroups = HMAP_INITIALIZER(&mcgroups);
struct ovn_datapath *od;
HMAP_FOR_EACH (od, key_node, datapaths) {
/* Logical VLANs not supported. */
- ovn_lflow_add(&lflows, od, P_IN, 0, 100, "vlan.present", "drop;");
+ ovn_lflow_add(&lflows, od, P_IN, S_IN_PORT_SEC, 100, "vlan.present",
+ "drop;");
/* Broadcast/multicast source address is invalid. */
- ovn_lflow_add(&lflows, od, P_IN, 0, 100, "eth.src[40]", "drop;");
+ ovn_lflow_add(&lflows, od, P_IN, S_IN_PORT_SEC, 100, "eth.src[40]",
+ "drop;");
/* Port security flows have priority 50 (see below) and will continue
* to the next table if packet source is acceptable. */
-
- /* Otherwise drop the packet. */
- ovn_lflow_add(&lflows, od, P_IN, 0, 0, "1", "drop;");
}
/* Ingress table 0: Ingress port security (priority 50). */
struct ovn_port *op;
HMAP_FOR_EACH (op, key_node, ports) {
+ if (!lport_is_enabled(op->nb)) {
+ /* Drop packets from disabled logical ports (since logical flow
+ * tables are default-drop). */
+ continue;
+ }
+
struct ds match = DS_EMPTY_INITIALIZER;
ds_put_cstr(&match, "inport == ");
json_string_escape(op->key, &match);
build_port_security("eth.src",
op->nb->port_security, op->nb->n_port_security,
&match);
- ovn_lflow_add(&lflows, op->od, P_IN, 0, 50, ds_cstr(&match),
- lport_is_enabled(op->nb) ? "next;" : "drop;");
+ ovn_lflow_add(&lflows, op->od, P_IN, S_IN_PORT_SEC, 50,
+ ds_cstr(&match), "next;");
ds_destroy(&match);
}
- /* Ingress table 1: Destination lookup, broadcast and multicast handling
+ /* Ingress table 1: ACLs (any priority). */
+ HMAP_FOR_EACH (od, key_node, datapaths) {
+ for (size_t i = 0; i < od->nb->n_acls; i++) {
+ const struct nbrec_acl *acl = od->nb->acls[i];
+ const char *action;
+
+ if (strcmp(acl->direction, "from-lport")) {
+ continue;
+ }
+
+ action = (!strcmp(acl->action, "allow") ||
+ !strcmp(acl->action, "allow-related"))
+ ? "next;" : "drop;";
+ ovn_lflow_add(&lflows, od, P_IN, S_IN_ACL, acl->priority,
+ acl->match, action);
+ }
+ }
+ HMAP_FOR_EACH (od, key_node, datapaths) {
+ ovn_lflow_add(&lflows, od, P_IN, S_IN_ACL, 0, "1", "next;");
+ }
+
+ /* Ingress table 2: Destination lookup, broadcast and multicast handling
* (priority 100). */
HMAP_FOR_EACH (op, key_node, ports) {
if (lport_is_enabled(op->nb)) {
}
}
HMAP_FOR_EACH (od, key_node, datapaths) {
- ovn_lflow_add(&lflows, od, P_IN, 1, 100, "eth.dst[40]",
+ ovn_lflow_add(&lflows, od, P_IN, S_IN_L2_LKUP, 100, "eth.dst[40]",
"outport = \""MC_FLOOD"\"; output;");
}
- /* Ingress table 1: Destination lookup, unicast handling (priority 50), */
+ /* Ingress table 2: Destination lookup, unicast handling (priority 50), */
HMAP_FOR_EACH (op, key_node, ports) {
for (size_t i = 0; i < op->nb->n_macs; i++) {
- uint8_t mac[ETH_ADDR_LEN];
+ struct eth_addr mac;
- if (eth_addr_from_string(op->nb->macs[i], mac)) {
+ if (eth_addr_from_string(op->nb->macs[i], &mac)) {
struct ds match, actions;
ds_init(&match);
ds_put_cstr(&actions, "outport = ");
json_string_escape(op->nb->name, &actions);
ds_put_cstr(&actions, "; output;");
- ovn_lflow_add(&lflows, op->od, P_IN, 1, 50,
+ ovn_lflow_add(&lflows, op->od, P_IN, S_IN_L2_LKUP, 50,
ds_cstr(&match), ds_cstr(&actions));
ds_destroy(&actions);
ds_destroy(&match);
} else if (!strcmp(op->nb->macs[i], "unknown")) {
- ovn_multicast_add(&mcgroups, &mc_unknown, op);
- op->od->has_unknown = true;
+ if (lport_is_enabled(op->nb)) {
+ ovn_multicast_add(&mcgroups, &mc_unknown, op);
+ op->od->has_unknown = true;
+ }
} else {
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
}
}
- /* Ingress table 1: Destination lookup for unknown MACs (priority 0). */
+ /* Ingress table 2: Destination lookup for unknown MACs (priority 0). */
HMAP_FOR_EACH (od, key_node, datapaths) {
if (od->has_unknown) {
- ovn_lflow_add(&lflows, od, P_IN, 1, 0, "1",
+ ovn_lflow_add(&lflows, od, P_IN, S_IN_L2_LKUP, 0, "1",
"outport = \""MC_UNKNOWN"\"; output;");
}
}
const struct nbrec_acl *acl = od->nb->acls[i];
const char *action;
+ if (strcmp(acl->direction, "to-lport")) {
+ continue;
+ }
+
action = (!strcmp(acl->action, "allow") ||
!strcmp(acl->action, "allow-related"))
? "next;" : "drop;";
- ovn_lflow_add(&lflows, od, P_OUT, 0, acl->priority, acl->match,
- action);
+ ovn_lflow_add(&lflows, od, P_OUT, S_OUT_ACL, acl->priority,
+ acl->match, action);
}
}
HMAP_FOR_EACH (od, key_node, datapaths) {
- ovn_lflow_add(&lflows, od, P_OUT, 0, 0, "1", "next;");
+ ovn_lflow_add(&lflows, od, P_OUT, S_OUT_ACL, 0, "1", "next;");
}
/* Egress table 1: Egress port security multicast/broadcast (priority
* 100). */
HMAP_FOR_EACH (od, key_node, datapaths) {
- ovn_lflow_add(&lflows, od, P_OUT, 1, 100, "eth.dst[40]", "output;");
+ ovn_lflow_add(&lflows, od, P_OUT, S_OUT_PORT_SEC, 100, "eth.dst[40]",
+ "output;");
}
- /* Egress table 1: Egress port security (priority 50). */
+ /* Egress table 1: Egress port security (priorities 50 and 150).
+ *
+ * Priority 50 rules implement port security for enabled logical port.
+ *
+ * Priority 150 rules drop packets to disabled logical ports, so that they
+ * don't even receive multicast or broadcast packets. */
HMAP_FOR_EACH (op, key_node, ports) {
struct ds match;
ds_init(&match);
ds_put_cstr(&match, "outport == ");
json_string_escape(op->key, &match);
- build_port_security("eth.dst",
- op->nb->port_security, op->nb->n_port_security,
- &match);
-
- ovn_lflow_add(&lflows, op->od, P_OUT, 1, 50, ds_cstr(&match),
- lport_is_enabled(op->nb) ? "output;" : "drop;");
+ if (lport_is_enabled(op->nb)) {
+ build_port_security("eth.dst",
+ op->nb->port_security, op->nb->n_port_security,
+ &match);
+ ovn_lflow_add(&lflows, op->od, P_OUT, S_OUT_PORT_SEC, 50,
+ ds_cstr(&match), "output;");
+ } else {
+ ovn_lflow_add(&lflows, op->od, P_OUT, S_OUT_PORT_SEC, 150,
+ ds_cstr(&match), "drop;");
+ }
ds_destroy(&match);
}
sbrec_logical_flow_set_priority(sbflow, lflow->priority);
sbrec_logical_flow_set_match(sbflow, lflow->match);
sbrec_logical_flow_set_actions(sbflow, lflow->actions);
+
+ const struct smap ids = SMAP_CONST1(
+ &ids, "stage-name",
+ (lflow->pipeline == P_IN
+ ? ingress_stage_to_str(lflow->table_id)
+ : egress_stage_to_str(lflow->table_id)));
+ sbrec_logical_flow_set_external_ids(sbflow, &ids);
+
ovn_lflow_destroy(&lflows, lflow);
}
hmap_destroy(&lflows);
hmap_destroy(&lports_hmap);
}
\f
+
+static char *default_db_;
+
static const char *
default_db(void)
{
- static char *def;
- if (!def) {
- def = xasprintf("unix:%s/db.sock", ovs_rundir());
+ if (!default_db_) {
+ default_db_ = xasprintf("unix:%s/db.sock", ovs_rundir());
}
- return def;
+ return default_db_;
}
static void
fatal_ignore_sigpipe();
set_program_name(argv[0]);
+ service_start(&argc, &argv);
vlog_set_levels(NULL, VLF_CONSOLE, VLL_WARN);
vlog_set_levels(&VLM_reconnect, VLF_ANY_DESTINATION, VLL_WARN);
parse_options(argc, argv);
- daemonize_start();
+ daemonize_start(false);
retval = unixctl_server_create(NULL, &unixctl);
if (retval) {
}
poll_block();
}
+ if (should_service_stop()) {
+ exiting = true;
+ }
}
unixctl_server_destroy(unixctl);
ovsdb_idl_destroy(ovnsb_idl);
ovsdb_idl_destroy(ovnnb_idl);
+ service_stop();
+
+ free(default_db_);
exit(res);
}