[ovs-dev] [RFC v2 11/11] ovn: Add "localnet" logical port type.
Russell Bryant
rbryant at redhat.com
Thu Jul 16 22:06:19 UTC 2015
Introduce a new logical port type called "localnet". A logical port
with this type also has an option called "network_name". A "localnet"
logical port represents a connection to a locally accessible network.
ovn-controller will use the ovn-bridge-mappings configuration to
figure out which patch port on br-int should be used for this port.
Signed-off-by: Russell Bryant <rbryant at redhat.com>
---
ovn/controller/physical.c | 123 +++++++++++++++++++++++++++++++++++-----------
ovn/ovn-nb.xml | 15 ++++--
ovn/ovn-sb.xml | 22 +++++++--
3 files changed, 124 insertions(+), 36 deletions(-)
diff --git a/ovn/controller/physical.c b/ovn/controller/physical.c
index 9e7f2f4..e7dd98b 100644
--- a/ovn/controller/physical.c
+++ b/ovn/controller/physical.c
@@ -22,6 +22,7 @@
#include "ovn-controller.h"
#include "ovn/lib/ovn-sb-idl.h"
#include "pipeline.h"
+#include "shash.h"
#include "simap.h"
#include "vswitch-idl.h"
@@ -42,11 +43,23 @@ physical_init(struct controller_ctx *ctx)
ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_interface_col_external_ids);
}
+static void
+init_input_match(struct match *match, ofp_port_t ofport, int tag)
+{
+ match_init_catchall(match);
+ match_set_in_port(match, ofport);
+ if (tag) {
+ match_set_dl_vlan(match, htons(tag));
+ }
+}
+
void
physical_run(struct controller_ctx *ctx)
{
struct simap lport_to_ofport = SIMAP_INITIALIZER(&lport_to_ofport);
struct simap chassis_to_ofport = SIMAP_INITIALIZER(&chassis_to_ofport);
+ struct simap localnet_to_ofport = SIMAP_INITIALIZER(&localnet_to_ofport);
+
for (int i = 0; i < ctx->br_int->n_ports; i++) {
const struct ovsrec_port *port_rec = ctx->br_int->ports[i];
if (!strcmp(port_rec->name, ctx->br_int_name)) {
@@ -71,8 +84,17 @@ physical_run(struct controller_ctx *ctx)
continue;
}
- /* Record as chassis or local logical port. */
- if (chassis_id) {
+ /* Record as patch to local net, chassis, or local logical port. */
+ if (!strcmp(iface_rec->type, "patch")) {
+ const char *peer = smap_get(&iface_rec->options, "peer");
+ if (!peer) {
+ continue;
+ }
+ const char *localnet = smap_get(&ctx->bridge_mappings, peer);
+ if (localnet) {
+ simap_put(&localnet_to_ofport, localnet, ofport);
+ }
+ } else if (chassis_id) {
simap_put(&chassis_to_ofport, chassis_id, ofport);
break;
} else {
@@ -88,6 +110,13 @@ physical_run(struct controller_ctx *ctx)
struct ofpbuf ofpacts;
ofpbuf_init(&ofpacts, 0);
+ struct localnet_flow {
+ struct shash_node node;
+ struct match match;
+ struct ofpbuf ofpacts;
+ };
+ struct shash localnet_inputs = SHASH_INITIALIZER(&localnet_inputs);
+
/* Set up flows in table 0 for physical-to-logical translation and in table
* 64 for logical-to-physical translation. */
const struct sbrec_binding *binding;
@@ -99,10 +128,15 @@ physical_run(struct controller_ctx *ctx)
* (and set 'local' to true). When 'parent_port' is set for a binding,
* it implies a container sitting inside a VM reachable via a 'tag'.
*/
-
int tag = 0;
ofp_port_t ofport;
- if (binding->parent_port) {
+ if (!strcmp(binding->type, "localnet")) {
+ const char *network = smap_get(&binding->options, "network_name");
+ if (!network) {
+ continue;
+ }
+ ofport = u16_to_ofp(simap_get(&localnet_to_ofport, network));
+ } else if (binding->parent_port) {
ofport = u16_to_ofp(simap_get(&lport_to_ofport,
binding->parent_port));
if (ofport && binding->tag) {
@@ -134,6 +168,9 @@ physical_run(struct controller_ctx *ctx)
struct match match;
if (local) {
+ struct ofpbuf *local_ofpacts = &ofpacts;
+ bool add_input_flow = true;
+
/* Packets that arrive from a vif can belong to a VM or
* to a container located inside that VM. Packets that
* arrive from containers have a tag (vlan) associated with them.
@@ -149,53 +186,67 @@ physical_run(struct controller_ctx *ctx)
* For both types of traffic: set MFF_LOG_INPORT to the
* logical input port, MFF_METADATA to the logical datapath, and
* resubmit into the logical pipeline starting at table 16. */
- match_init_catchall(&match);
- ofpbuf_clear(&ofpacts);
- match_set_in_port(&match, ofport);
- if (tag) {
- match_set_dl_vlan(&match, htons(tag));
+ if (!strcmp(binding->type, "localnet")) {
+ const char *network = smap_get(&binding->options, "network_name");
+ struct shash_node *node;
+ struct localnet_flow *ln_flow;
+ node = shash_find(&localnet_inputs, network);
+ if (!node) {
+ ln_flow = xmalloc(sizeof *ln_flow);
+ ofpbuf_init(&ln_flow->ofpacts, 0);
+ init_input_match(&ln_flow->match, ofport, tag);
+ node = shash_add(&localnet_inputs, network, ln_flow);
+ }
+ ln_flow = node->data;
+ local_ofpacts = &ln_flow->ofpacts;
+ add_input_flow = false;
+ } else {
+ ofpbuf_clear(local_ofpacts);
+ init_input_match(&match, ofport, tag);
}
/* Set MFF_METADATA. */
- struct ofpact_set_field *sf = ofpact_put_SET_FIELD(&ofpacts);
+ struct ofpact_set_field *sf = ofpact_put_SET_FIELD(local_ofpacts);
sf->field = mf_from_id(MFF_METADATA);
sf->value.be64 = htonll(ldp);
sf->mask.be64 = OVS_BE64_MAX;
/* Set MFF_LOG_INPORT. */
- sf = ofpact_put_SET_FIELD(&ofpacts);
+ sf = ofpact_put_SET_FIELD(local_ofpacts);
sf->field = mf_from_id(MFF_LOG_INPORT);
sf->value.be32 = htonl(binding->tunnel_key);
sf->mask.be32 = OVS_BE32_MAX;
/* Strip vlans. */
if (tag) {
- ofpact_put_STRIP_VLAN(&ofpacts);
+ ofpact_put_STRIP_VLAN(local_ofpacts);
}
/* Resubmit to first logical pipeline table. */
- struct ofpact_resubmit *resubmit = ofpact_put_RESUBMIT(&ofpacts);
+ struct ofpact_resubmit *resubmit = ofpact_put_RESUBMIT(local_ofpacts);
resubmit->in_port = OFPP_IN_PORT;
resubmit->table_id = 16;
- ofctrl_add_flow(0, tag ? 150 : 100, &match, &ofpacts);
+ if (add_input_flow) {
+ ofctrl_add_flow(0, tag ? 150 : 100, &match, &ofpacts);
- /* Table 0, Priority 50.
- * =====================
- *
- * For packets that arrive from a remote node destined to this
- * local vif: deliver directly to the vif. If the destination
- * is a container sitting behind a vif, tag the packets. */
- match_init_catchall(&match);
- ofpbuf_clear(&ofpacts);
- match_set_tun_id(&match, htonll(binding->tunnel_key));
- if (tag) {
- struct ofpact_vlan_vid *vlan_vid;
- vlan_vid = ofpact_put_SET_VLAN_VID(&ofpacts);
- vlan_vid->vlan_vid = tag;
- vlan_vid->push_vlan_if_needed = true;
+ /* Table 0, Priority 50.
+ * =====================
+ *
+ * For packets that arrive from a remote node destined to this
+ * local vif: deliver directly to the vif. If the destination
+ * is a container sitting behind a vif, tag the packets. */
+ match_init_catchall(&match);
+ ofpbuf_clear(&ofpacts);
+ match_set_tun_id(&match, htonll(binding->tunnel_key));
+ if (tag) {
+ struct ofpact_vlan_vid *vlan_vid;
+ vlan_vid = ofpact_put_SET_VLAN_VID(&ofpacts);
+ vlan_vid->vlan_vid = tag;
+ vlan_vid->push_vlan_if_needed = true;
+ }
+ ofpact_put_OUTPUT(&ofpacts)->port = ofport;
+ ofctrl_add_flow(0, 50, &match, &ofpacts);
}
- ofpact_put_OUTPUT(&ofpacts)->port = ofport;
- ofctrl_add_flow(0, 50, &match, &ofpacts);
}
/* Table 64, Priority 100.
@@ -244,7 +295,19 @@ physical_run(struct controller_ctx *ctx)
ofctrl_add_flow(64, 50, &match, &ofpacts);
}
+ struct shash_node *ln_flow_node, *ln_flow_node_next;
+ struct localnet_flow *ln_flow;
+ SHASH_FOR_EACH_SAFE (ln_flow_node, ln_flow_node_next, &localnet_inputs) {
+ ln_flow = ln_flow_node->data;
+ shash_delete(&localnet_inputs, ln_flow_node);
+ ofctrl_add_flow(0, 100, &ln_flow->match, &ln_flow->ofpacts);
+ ofpbuf_uninit(&ln_flow->ofpacts);
+ free(ln_flow);
+ }
+ shash_destroy(&localnet_inputs);
+
ofpbuf_uninit(&ofpacts);
simap_destroy(&lport_to_ofport);
simap_destroy(&chassis_to_ofport);
+ simap_destroy(&localnet_to_ofport);
}
diff --git a/ovn/ovn-nb.xml b/ovn/ovn-nb.xml
index fed6195..a3d1cd9 100644
--- a/ovn/ovn-nb.xml
+++ b/ovn/ovn-nb.xml
@@ -116,13 +116,22 @@
</p>
<p>
- There are no other logical port types implemented yet.
+ When this column is set to <em>localnet</em>, this logical port represents a
+ connection to a locally accessible network from each ovn-controller instance.
</p>
</column>
<column name="options">
- This column provides key/value settings specific to the logical port
- <ref column="type"/>.
+ <p>
+ This column provides key/value settings specific to the logical port
+ <ref column="type"/>.
+ </p>
+
+ <p>
+ When <ref column="type"/> is set to <em>localnet</em>, you must set the option
+ <em>network_name</em>. ovn-controller uses local configuration to determine
+ exactly how to connect to this locally accessible network.
+ </p>
</column>
<column name="parent_name">
diff --git a/ovn/ovn-sb.xml b/ovn/ovn-sb.xml
index 468cbe8..1915a60 100644
--- a/ovn/ovn-sb.xml
+++ b/ovn/ovn-sb.xml
@@ -681,13 +681,29 @@
</p>
<p>
- There are no other logical port types implemented yet.
+ When this column is set to <em>localnet</em>, this logical port represents a
+ connection to a locally accessible network from each ovn-controller instance.
</p>
</column>
<column name="options">
- This column provides key/value settings specific to the logical port
- <ref column="type"/>.
+ <p>
+ This column provides key/value settings specific to the logical port
+ <ref column="type"/>.
+ </p>
+
+ <p>
+ When <ref column="type"/> is set to <em>localnet</em>, you must set the option
+ <em>network_name</em>. ovn-controller uses the configuration entry
+ <em>ovn-bridge-mappings</em> to determine how to connect to this network.
+ <em>ovn-bridge-mappings</em> is a list of network names mapped to a local
+ OVS bridge that provides access to that network. An example of configuring
+ <em>ovn-bridge-mappings</em> would be:
+ </p>
+
+ <p>
+ <em>$ ovs-vsctl set open . external-ids:ovn-bridge-mappings=physnet1:br-eth0,physnet2:br-eth1</em>
+ </p>
</column>
<column name="tunnel_key">
--
2.4.3
More information about the dev
mailing list