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 <rbry...@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 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev