On Wed, Oct 28, 2020 at 3:32 AM Numan Siddique <num...@ovn.org> wrote: > > On Wed, Oct 28, 2020 at 6:08 AM Ihar Hrachyshka <ihrac...@redhat.com> wrote: > > > > On Wed, Sep 23, 2020 at 10:28 AM Numan Siddique <num...@ovn.org> wrote: > > > > > > > > > > > > On Wed, Sep 23, 2020 at 6:13 PM Numan Siddique <num...@ovn.org> wrote: > > >> > > >> > > >> > > >> On Wed, Sep 23, 2020 at 1:00 PM Han Zhou <zhou...@gmail.com> wrote: > > >>> > > >>> On Tue, Sep 22, 2020 at 12:46 PM Ihar Hrachyshka <ihrac...@redhat.com> > > >>> wrote: > > >>> > > > >>> > User stories: > > >>> > 1) NFV: an admin wants to run two separate instances of OVN controller > > >>> > using the same database but configuring ports on different bridges. > > >>> > Some of these bridges may use DPDK while others may not. > > >>> > > > >>> > 2) Parallel OVN instances: an admin wants to run two separate > > >>> > instances of OVN controller using different databases. The > > >>> > instances are completely independent and serve different consumers. > > >>> > For example, the same machine runs both OpenStack and OpenShift > > >>> > stacks, each running its own separate OVN stack. > > >>> > > > >>> > To serve these use cases, several features should be added to > > >>> > ovn-controller: > > >>> > > > >>> > - use different database configuration for multiple controllers; > > >>> > - customize chassis name used by controller. > > >>> > > > >>> > ===== > > >>> > > > >>> > For each of the following database configuration options, their > > >>> > extended chassis specific counterparts are introduced: > > >>> > > > >>> > external_ids:hostname > > >>> > external_ids:ovn-bridge > > >>> > external_ids:ovn-bridge-datapath-type > > >>> > external_ids:ovn-bridge-mappings > > >>> > external_ids:ovn-chassis-mac-mappings > > >>> > external_ids:ovn-cms-options > > >>> > external_ids:ovn-encap-csum > > >>> > external_ids:ovn-encap-ip > > >>> > external_ids:ovn-encap-type > > >>> > external_ids:ovn-is-interconn > > >>> > external_ids:ovn-monitor-all > > >>> > external_ids:ovn-openflow-probe-interval > > >>> > external_ids:ovn-remote > > >>> > external_ids:ovn-remote-probe-interval > > >>> > > > >>> > For example, > > >>> > > > >>> > external_ids:ovn-bridge -> external_ids:ovn-bridge-<chassis-name>= > > >>> > external_ids:ovn-encap-ip -> external_ids:ovn-encap-ip-<chassis-name>= > > >>> > external_ids:ovn-remote -> external_ids:ovn-remote-<chassis-name>= > > >>> > > > >>> > Priority wise, <chassis-name> specific options take precedence. > > >>> > > > >>> > ===== > > >>> > > > >>> > For system-id, > > >>> > > > >>> > You can now pass intended chassis name via CLI argument: > > >>> > > > >>> > $ ovn-controller ... -n <chassis_name> > > >>> > > > >>> > Alternatively, you can configure a chassis name by putting it into the > > >>> > ${ovn_sysconfdir}/system-id-override file before running the > > >>> > controller. > > >>> > > > >>> > The latter option may be more useful in container environment where > > >>> > the same image may be reused for multiple controller instances, where > > >>> > ovs_sysconfigdir/ovn/system-id-override is a volume mounted into this > > >>> > generic image. The override file is read once on startup. If you want > > >>> > to apply a new chassis name to a controller instance, restart it to > > >>> > reread the file. > > >>> > > > >>> > Priority wise, this is the order in which different means to configure > > >>> > the chassis name are used: > > >>> > > > >>> > - ovn-controller ... -n <chassis_name> CLI argument. > > >>> > - ${ovs_sysconfdir}/ovn/system-id-override file; > > >>> > - external_ids:system-id= ovsdb option; > > >>> > > > >>> > ===== > > >>> > > > >>> > Concurrent chassis running on the same host may inadvertantly remove > > >>> > patch ports that belong to their peer chassis. To avoid that, patch > > >>> > ports are now tagged in external-ids:ovn-chassis-id with the > > >>> > appropriate chassis name, and only patch ports that belong to the > > >>> > chassis are touched when cleaning up. Also, now only tunnels on the > > >>> > active integration bridge are being cleaned up. > > >>> > > > >>> > Note that external-ids:ovn-chassis-id key is already used for tunnel > > >>> > ports to identify the remote tunnel endpoint. We can reuse the same > > >>> > key for patch ports because the key usage is not overlapping. > > >>> > > > >>> > Alternatively, we could introduce a new key with a similar but > > >>> > different name. This would simplify code changes needed but would > > >>> > arguably introduce even more confusion. Since the key name is not > > >>> > entirely self-descriptive for tunnel ports (a better name would be > > >>> > e.g. ovn-remote-chassis or ovn-peer-chassis), the ideal scenario would > > >>> > be to rename the key for tunnel endpoints but reuse it for patch > > >>> > ports. This would involve additional migration steps and is probably > > >>> > not worth the hassle. > > >>> > > > >>> Hi Ihar, > > >>> > > >>> Thanks for your patience on this. From my perspective, even if similar > > >>> key > > >>> names can be confusing, using exactly the same name is definitely *more* > > >>> confusing. Since we already know there is a conflict, why not just > > >>> picking > > >>> a different name for the new one? Whatever key we use, documentation is > > >>> still needed and will be helpful to avoid confusion. What do you think? > > >>> > > >>> Thanks, > > >>> Han > > >>> > > >> > > >> Hi Ihar, > > >> > > >> Thanks for the patch and for the patience. I did not review the code. > > >> But I did some testing > > >> with this patch and below are the comments. > > >> > > >> > > >> 1. The patch needs a rebase as it doesn't apply cleanly. I was able to > > >> resolve it locally though. > > >> > > >> 2. The below system test fails with this patch > > >> > > >> ******** > > >> ## ------------------------ ## > > >> ## ovn 20.09.90 test suite. ## > > >> ## ------------------------ ## > > >> 34: ovn -- ARP resolution for SNAT IP FAILED > > >> (system-ovn.at:5397) > > >> ************************** > > >> > > >> 3. It will be good to display the newly added command line option : -n > > >> in the help command. > > >> > > > > Aye. > > > > >> 4. I did some testing and found some strange behavior. I started ovs > > >> on my laptop. Created 2 containers mounting the proper ovs rundirs so > > >> that ovn-controllers running on these containers can access ovs > > >> sockets. Started ovn-controllers on each container with "-n > > >> controller-1" and "-n controller-2" > > >> respectively. > > >> > > >> In one instance I found that when I create an ovs port on > > >> controller-1' bridge - br-ctrl1, both the ovn-controllers start fighting > > >> for the port. > > > > > > > > > To add a bit more on this issue, the issue goes away when I run > > > 'ovn-appctl -t ovn-controller recompute'. > > > As I mentioned in point (6), the incremental handling for OVS interface > > > changes doesn't look if that interface belongs to the integration bridge > > > or some other bridge. I have almost the patch ready to fix this issue. I > > > will submit it in some time. > > > > > > > Thanks for the patch, makes sense. > > > > > > > >> > > >> In another instance I see that both the ovn-controllers try to > > >> create the same tunnel interface. > > > > > > > I would like to understand how the issue reveals itself. > > > > There's a test in the test suite "ovn -- concurrent controllers avoid > > fighting for each others' resources" that starts multiple > > ovn-controllers on the same host, each with its own IP address and > > chassis name. I've checked the logs of controllers and I can't find > > any errors related to tunnel ports being created, and I see distinct > > tunnel ports created for each of them. > > > > The ports have chassis names encoded as part of their distinct names > > (e.g. ovn-hv-1-0 for hv-1 chassis name), and their IP addresses are > > distinct too. Assuming they do the right thing, the instances should > > not fight on tunnel port creation. > > > > Do you have log errors to see for the issue? Or how do you detect it? > > > I was to reproduce using the steps mentioned here - > https://gist.github.com/numansiddique/f3798dd7b0f749e4d07844df6958693c > > #ovs-vsctl show > root@4456a2647bec ovn]# /data/ovs-vsctl show > b61dc0f0-0b74-4d19-b26f-6677e19d3d8d > Bridge br-ctrl1 > fail_mode: secure > Port br-ctrl1 > Interface br-ctrl1 > type: internal > Bridge br-ctrl2 > fail_mode: secure > Port ovn-contro-0 > Interface ovn-contro-0 > type: geneve > options: {csum="true", key=flow, remote_ip="172.17.0.2"} > Port br-ctrl2 > Interface br-ctrl2 > type: internal > ovs_version: "2.14.90" > > > # ovs-vsctl get open . external_ids > {hostname=nusiddiq.home.org, hostname-controller-1=ctrl1.home.orh, > hostname-controller-2=ctrl2.home.orh, > ovn-bridge-controller-1=br-ctrl1, ovn-bridge-controller-2=br-ctrl2, > ovn-encap-ip-controller-1="172.17.0.2", > ovn-encap-ip-controller-2="172.17.0.3", > ovn-encap-type-controller-1=geneve, > ovn-encap-type-controller-2=geneve, > ovn-remote-controller-1="tcp:172.17.0.1:6642", > ovn-remote-controller-2="tcp:172.17.0.1:6642", > rundir="/usr/local/var/run/openvswitch", system-id=nummac} > > # ovn-sbctl show > Chassis controller-2 > hostname: ctrl2.home.orh > Encap geneve > ip: "172.17.0.3" > options: {csum="true"} > Chassis controller-1 > hostname: ctrl1.home.orh > Encap geneve > ip: "172.17.0.2" > options: {csum="true"} > > > You can find the ovn-controller log of controller-1 here - > https://paste.centos.org/view/044a8946 >
I think the reason the error is not reproduced in the test case I referred to is because the chassis name used there is short (hv-[12]) and is not truncated, so port names are unique; in your case the names are long (controller-[01]) and, truncated, result in the same name. Once I replaced the chassis names used in the test case with longer ones, the test started to fail. I'll send an update for the patch tomorrow. > Thanks > Numan > > > > > > > > > But I still see this issue. > > > > > >> > > >> This is how I did the setup - > > >> https://gist.github.com/numansiddique/f3798dd7b0f749e4d07844df6958693c > > > > > > > > >> > > >> > > >> Let me know if you have any questions on the setup commands I > > >> shared. > > >> > > >> 5. Suppose If I start ovn-controller with the "-n" option, but if there > > >> are no corresponding entries in the ovs db (i.e > > >> ovn-encap-type-<chassis_name> etc) > > >> it falls back to the global config option. I think it better not > > >> to do this. If ovn-controller is started with either a "-n" option or > > >> chassis name is provided using the ovn system id file, > > >> that ovn-controller instance should always try to look for its own > > >> config options. This would give consistent behaviour. > > >> > > > > The problem with this approach is that it requires duplicating all > > options for each instance, even if they are common (e.g. interval > > values or tunnel types). I think it's better to fall back for them. > > What do you think? > > I don't have any strong preference. I'm ok to fall back. But I think > there are more chances of misconfiguration/errors because of this. > > Thanks > Numan > > > > > > >> 6. When 2 ovn-controllers are started sharing the same ovs db and same > > >> ovn DBs, when an ovs port is created with (external_ids:iface-id set ) > > >> in the integration bridge of controller-1, > > >> controller-2 also sees this and It will allocate the "struct > > >> local_binding" object (see binding.c). I think this could have side > > >> effects. And the 2nd controller may try to bind the port. > > >> Even if the ovn-controllers connect to their own ovn dbs, we could > > >> see this issue if a logical port is present with the same name on both > > >> the OVN dbs. > > >> > > >> I think binding.c should be enhanced to better handle this situation. > > >> Maybe it can check which ovs bridge the interface belongs to in the > > >> binding_handle_ovs_interface_changes(). > > >> If you see binding_run(), it looks for ovs interfaces on the proper > > >> integration bridge. But when an ovs interface change is handled in > > >> binding_handle_ovs_interface_changes(), it doesn't > > >> do so. > > >> > > >> > > >> Thanks > > >> Numan > > >> > > >> > > >>> > ===== > > >>> > > > >>> > Note: this patch assumes that each chassis has its own unique IP. > > >>> > Future work may consider adding support to specify custom port numbers > > >>> > for tunneling that would allow to reuse the same IP address for > > >>> > multiple chassis running on the same host. This work is out of scope > > >>> > for this patch. > > >>> > > > >>> > Signed-off-by: Ihar Hrachyshka <ihrac...@redhat.com> > > >>> > > > >>> > --- > > >>> > > > >>> > v1: initial implementation. > > >>> > v2: fixed test case to check ports are claimed by proper chassis. > > >>> > v2: added NEWS entry. > > >>> > v2: fixed some compiler warnings. > > >>> > v2: moved file_system_id declaration inside a function that uses it. > > >>> > v2: removed unneeded binding.h #include. > > >>> > v2: docs: better explanation of alternatives to select chassis name. > > >>> > v3: reverted priority order for chassis configuration: first CLI, then > > >>> > system-id file, then ovsdb. > > >>> > v4: introduce helpers to extract external-ids (per-chassis or global). > > >>> > v4: introduce per-chassis config options for all keys. > > >>> > v4: introduce -M (--concurrent) CLI argument to avoid patch ports > > >>> > removed by concurrent chassis. > > >>> > v5: rebased. > > >>> > v6: switched from -M (--concurrent) to external-ids:ovn-is-concurrent. > > >>> > v6: with ovn-is-concurrent=true, also avoid removing unknown tunnel > > >>> > endpoints. > > >>> > v7: don't clean up tunnel endpoints from other bridges. > > >>> > v7: don't clean up patch ports that don't belong to the chassis. > > >>> > v7: remove ovn-is-concurrent that is no longer needed. > > >>> > v7: rebased. > > >>> > v8: rename system-id -> /etc/ovn/system-id-override > > >>> > v8: read the system-id-override file just once on startup > > >>> > v8: free() controller_chassis (CLI arg value) on exit > > >>> > v9: updated commit message, removed notion of ovn-is-concurrent. > > >>> > v10: rename external-ids:owner -> ovn-chassis-id in patch ports. > > >>> > v10: use ovn_sysconfdir for system-id-override file location. > > >>> > v10: clean up patch ports with no ovn-chassis-id tag. > > >>> > v10: simplify encaps_run to only iterate over br-int ports, not all > > >>> > bridges (and then explicitly skipping them). > > >>> > v10: added test case to validate cleanup for patch and tunnel ports. > > >>> > v10: minor adjustment in ovn-sb.xml. > > >>> > --- > > >>> > NEWS | 5 + > > >>> > controller/chassis.c | 77 +++++++++------ > > >>> > controller/chassis.h | 3 +- > > >>> > controller/encaps.c | 74 +++++++++----- > > >>> > controller/encaps.h | 1 - > > >>> > controller/ovn-controller.8.xml | 17 +++- > > >>> > controller/ovn-controller.c | 105 ++++++++++++++++---- > > >>> > controller/ovn-controller.h | 4 + > > >>> > controller/patch.c | 20 +++- > > >>> > controller/physical.c | 2 +- > > >>> > lib/ovn-util.c | 50 ++++++++++ > > >>> > lib/ovn-util.h | 18 ++++ > > >>> > ovn-sb.xml | 10 +- > > >>> > tests/ovn-controller.at | 9 +- > > >>> > tests/ovn-macros.at | 49 ++++++++-- > > >>> > tests/ovn.at | 168 > > >>> > +++++++++++++++++++++++++++++++- > > >>> > tests/ovs-macros.at | 1 + > > >>> > 17 files changed, 510 insertions(+), 103 deletions(-) > > >>> > > > >>> > diff --git a/NEWS b/NEWS > > >>> > index ee5c2c393..c22466818 100644 > > >>> > --- a/NEWS > > >>> > +++ b/NEWS > > >>> > @@ -18,6 +18,11 @@ OVN v20.09.0 - xx xxx xxxx > > >>> > - Added support for external ip based NAT. Now, besides the > > >>> > logical > > >>> ip, > > >>> > external ips will also decide if a packet will be NATed or not. > > >>> > - Added support for VXLAN encapsulation (not just for ramp/VTEP > > >>> switches). > > >>> > + - Added support for multiple ovn-controller instances on the same > > >>> > host > > >>> > + (virtual chassis). Now all external-ids:* configuration options > > >>> > can > > >>> be > > >>> > + customized for each controller instance running on the same > > >>> > host. > > >>> The only > > >>> > + option that is not available per chassis is > > >>> > external-ids:system-id, > > >>> which > > >>> > + stands for the chassis name and can be passed via config file or > > >>> CLI (-n). > > >>> > > > >>> > OVN v20.06.0 > > >>> > -------------------------- > > >>> > diff --git a/controller/chassis.c b/controller/chassis.c > > >>> > index a365188e8..989ec5e1a 100644 > > >>> > --- a/controller/chassis.c > > >>> > +++ b/controller/chassis.c > > >>> > @@ -125,9 +125,10 @@ chassis_register_ovs_idl(struct ovsdb_idl > > >>> > *ovs_idl) > > >>> > } > > >>> > > > >>> > static const char * > > >>> > -get_hostname(const struct smap *ext_ids) > > >>> > +get_hostname(const struct smap *ext_ids, const char *chassis_id) > > >>> > { > > >>> > - const char *hostname = smap_get_def(ext_ids, "hostname", ""); > > >>> > + const char *hostname = get_chassis_external_id_value( > > >>> > + ext_ids, chassis_id, "hostname", ""); > > >>> > > > >>> > if (strlen(hostname) == 0) { > > >>> > static char hostname_[HOST_NAME_MAX + 1]; > > >>> > @@ -143,39 +144,45 @@ get_hostname(const struct smap *ext_ids) > > >>> > } > > >>> > > > >>> > static const char * > > >>> > -get_bridge_mappings(const struct smap *ext_ids) > > >>> > +get_bridge_mappings(const struct smap *ext_ids, const char > > >>> > *chassis_id) > > >>> > { > > >>> > - return smap_get_def(ext_ids, "ovn-bridge-mappings", ""); > > >>> > + return get_chassis_external_id_value( > > >>> > + ext_ids, chassis_id, "ovn-bridge-mappings", ""); > > >>> > } > > >>> > > > >>> > const char * > > >>> > -get_chassis_mac_mappings(const struct smap *ext_ids) > > >>> > +get_chassis_mac_mappings(const struct smap *ext_ids, const char > > >>> *chassis_id) > > >>> > { > > >>> > - return smap_get_def(ext_ids, "ovn-chassis-mac-mappings", ""); > > >>> > + return get_chassis_external_id_value( > > >>> > + ext_ids, chassis_id, "ovn-chassis-mac-mappings", ""); > > >>> > } > > >>> > > > >>> > static const char * > > >>> > -get_cms_options(const struct smap *ext_ids) > > >>> > +get_cms_options(const struct smap *ext_ids, const char *chassis_id) > > >>> > { > > >>> > - return smap_get_def(ext_ids, "ovn-cms-options", ""); > > >>> > + return get_chassis_external_id_value( > > >>> > + ext_ids, chassis_id, "ovn-cms-options", ""); > > >>> > } > > >>> > > > >>> > static const char * > > >>> > -get_monitor_all(const struct smap *ext_ids) > > >>> > +get_monitor_all(const struct smap *ext_ids, const char *chassis_id) > > >>> > { > > >>> > - return smap_get_def(ext_ids, "ovn-monitor-all", "false"); > > >>> > + return get_chassis_external_id_value( > > >>> > + ext_ids, chassis_id, "ovn-monitor-all", "false"); > > >>> > } > > >>> > > > >>> > static const char * > > >>> > -get_enable_lflow_cache(const struct smap *ext_ids) > > >>> > +get_enable_lflow_cache(const struct smap *ext_ids, const char > > >>> *chassis_id) > > >>> > { > > >>> > - return smap_get_def(ext_ids, "ovn-enable-lflow-cache", "true"); > > >>> > + return get_chassis_external_id_value( > > >>> > + ext_ids, chassis_id, "ovn-enable-lflow-cache", "true"); > > >>> > } > > >>> > > > >>> > static const char * > > >>> > -get_encap_csum(const struct smap *ext_ids) > > >>> > +get_encap_csum(const struct smap *ext_ids, const char *chassis_id) > > >>> > { > > >>> > - return smap_get_def(ext_ids, "ovn-encap-csum", "true"); > > >>> > + return get_chassis_external_id_value( > > >>> > + ext_ids, chassis_id, "ovn-encap-csum", "true"); > > >>> > } > > >>> > > > >>> > static const char * > > >>> > @@ -189,9 +196,10 @@ get_datapath_type(const struct ovsrec_bridge > > >>> > *br_int) > > >>> > } > > >>> > > > >>> > static bool > > >>> > -get_is_interconn(const struct smap *ext_ids) > > >>> > +get_is_interconn(const struct smap *ext_ids, const char *chassis_id) > > >>> > { > > >>> > - return smap_get_bool(ext_ids, "ovn-is-interconn", false); > > >>> > + return get_chassis_external_id_value_bool( > > >>> > + ext_ids, chassis_id, "ovn-is-interconn", false); > > >>> > } > > >>> > > > >>> > static void > > >>> > @@ -278,22 +286,27 @@ chassis_parse_ovs_config(const struct > > >>> ovsrec_open_vswitch_table *ovs_table, > > >>> > return false; > > >>> > } > > >>> > > > >>> > - const char *encap_type = smap_get(&cfg->external_ids, > > >>> "ovn-encap-type"); > > >>> > - const char *encap_ips = smap_get(&cfg->external_ids, > > >>> > "ovn-encap-ip"); > > >>> > + const char *chassis_id = get_ovs_chassis_id(cfg); > > >>> > + const struct smap *ext_ids = &cfg->external_ids; > > >>> > + > > >>> > + const char *encap_type = get_chassis_external_id_value( > > >>> > + ext_ids, chassis_id, "ovn-encap-type", NULL); > > >>> > + const char *encap_ips = get_chassis_external_id_value( > > >>> > + ext_ids, chassis_id, "ovn-encap-ip", NULL); > > >>> > if (!encap_type || !encap_ips) { > > >>> > static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, > > >>> > 5); > > >>> > VLOG_INFO_RL(&rl, "Need to specify an encap type and ip"); > > >>> > return false; > > >>> > } > > >>> > > > >>> > - ovs_cfg->hostname = get_hostname(&cfg->external_ids); > > >>> > - ovs_cfg->bridge_mappings = > > >>> > get_bridge_mappings(&cfg->external_ids); > > >>> > + ovs_cfg->hostname = get_hostname(ext_ids, chassis_id); > > >>> > + ovs_cfg->bridge_mappings = get_bridge_mappings(ext_ids, > > >>> > chassis_id); > > >>> > ovs_cfg->datapath_type = get_datapath_type(br_int); > > >>> > - ovs_cfg->encap_csum = get_encap_csum(&cfg->external_ids); > > >>> > - ovs_cfg->cms_options = get_cms_options(&cfg->external_ids); > > >>> > - ovs_cfg->monitor_all = get_monitor_all(&cfg->external_ids); > > >>> > - ovs_cfg->chassis_macs = > > >>> > get_chassis_mac_mappings(&cfg->external_ids); > > >>> > - ovs_cfg->enable_lflow_cache = > > >>> get_enable_lflow_cache(&cfg->external_ids); > > >>> > + ovs_cfg->encap_csum = get_encap_csum(ext_ids, chassis_id); > > >>> > + ovs_cfg->cms_options = get_cms_options(ext_ids, chassis_id); > > >>> > + ovs_cfg->monitor_all = get_monitor_all(ext_ids, chassis_id); > > >>> > + ovs_cfg->chassis_macs = get_chassis_mac_mappings(ext_ids, > > >>> chassis_id); > > >>> > + ovs_cfg->enable_lflow_cache = get_enable_lflow_cache(ext_ids, > > >>> chassis_id); > > >>> > > > >>> > if (!chassis_parse_ovs_encap_type(encap_type, > > >>> &ovs_cfg->encap_type_set)) { > > >>> > return false; > > >>> > @@ -311,7 +324,7 @@ chassis_parse_ovs_config(const struct > > >>> ovsrec_open_vswitch_table *ovs_table, > > >>> > sset_destroy(&ovs_cfg->encap_ip_set); > > >>> > } > > >>> > > > >>> > - ovs_cfg->is_interconn = get_is_interconn(&cfg->external_ids); > > >>> > + ovs_cfg->is_interconn = get_is_interconn(ext_ids, chassis_id); > > >>> > > > >>> > return true; > > >>> > } > > >>> > @@ -348,7 +361,7 @@ chassis_other_config_changed(const char > > >>> *bridge_mappings, > > >>> > const struct sbrec_chassis *chassis_rec) > > >>> > { > > >>> > const char *chassis_bridge_mappings = > > >>> > - get_bridge_mappings(&chassis_rec->other_config); > > >>> > + get_bridge_mappings(&chassis_rec->other_config, NULL); > > >>> > > > >>> > if (strcmp(bridge_mappings, chassis_bridge_mappings)) { > > >>> > return true; > > >>> > @@ -362,28 +375,28 @@ chassis_other_config_changed(const char > > >>> *bridge_mappings, > > >>> > } > > >>> > > > >>> > const char *chassis_cms_options = > > >>> > - get_cms_options(&chassis_rec->other_config); > > >>> > + get_cms_options(&chassis_rec->other_config, NULL); > > >>> > > > >>> > if (strcmp(cms_options, chassis_cms_options)) { > > >>> > return true; > > >>> > } > > >>> > > > >>> > const char *chassis_monitor_all = > > >>> > - get_monitor_all(&chassis_rec->other_config); > > >>> > + get_monitor_all(&chassis_rec->other_config, NULL); > > >>> > > > >>> > if (strcmp(monitor_all, chassis_monitor_all)) { > > >>> > return true; > > >>> > } > > >>> > > > >>> > const char *chassis_enable_lflow_cache = > > >>> > - get_enable_lflow_cache(&chassis_rec->other_config); > > >>> > + get_enable_lflow_cache(&chassis_rec->other_config, NULL); > > >>> > > > >>> > if (strcmp(enable_lflow_cache, chassis_enable_lflow_cache)) { > > >>> > return true; > > >>> > } > > >>> > > > >>> > const char *chassis_mac_mappings = > > >>> > - get_chassis_mac_mappings(&chassis_rec->other_config); > > >>> > + get_chassis_mac_mappings(&chassis_rec->other_config, NULL); > > >>> > if (strcmp(chassis_macs, chassis_mac_mappings)) { > > >>> > return true; > > >>> > } > > >>> > @@ -791,7 +804,7 @@ chassis_get_mac(const struct sbrec_chassis > > >>> *chassis_rec, > > >>> > struct eth_addr *chassis_mac) > > >>> > { > > >>> > const char *tokens > > >>> > - = get_chassis_mac_mappings(&chassis_rec->other_config); > > >>> > + = get_chassis_mac_mappings(&chassis_rec->other_config, NULL); > > >>> > if (!tokens[0]) { > > >>> > return false; > > >>> > } > > >>> > diff --git a/controller/chassis.h b/controller/chassis.h > > >>> > index 220f726b9..c7345f0fa 100644 > > >>> > --- a/controller/chassis.h > > >>> > +++ b/controller/chassis.h > > >>> > @@ -49,7 +49,8 @@ bool chassis_get_mac(const struct sbrec_chassis > > >>> *chassis, > > >>> > const char *bridge_mapping, > > >>> > struct eth_addr *chassis_mac); > > >>> > const char *chassis_get_id(void); > > >>> > -const char * get_chassis_mac_mappings(const struct smap *ext_ids); > > >>> > +const char * get_chassis_mac_mappings(const struct smap *ext_ids, > > >>> > + const char *chassis_id); > > >>> > > > >>> > > > >>> > #endif /* controller/chassis.h */ > > >>> > diff --git a/controller/encaps.c b/controller/encaps.c > > >>> > index 7eac4bb06..7387d4d5d 100644 > > >>> > --- a/controller/encaps.c > > >>> > +++ b/controller/encaps.c > > >>> > @@ -291,9 +291,31 @@ chassis_tzones_overlap(const struct sset > > >>> *transport_zones, > > >>> > return false; > > >>> > } > > >>> > > > >>> > +static bool > > >>> > +is_tunnel_type(const char *port_type) > > >>> > +{ > > >>> > + static const char *tunnel_types[3] = { "geneve", "vxlan", "stt" > > >>> > }; > > >>> > + for (size_t t = 0; t < 3; t++) { > > >>> > + if (!strcmp(port_type, tunnel_types[t])) { > > >>> > + return true; > > >>> > + } > > >>> > + } > > >>> > + return false; > > >>> > +} > > >>> > + > > >>> > +static bool > > >>> > +is_tunnel_port(const struct ovsrec_port *port) > > >>> > +{ > > >>> > + for (size_t i = 0; i < port->n_interfaces; i++) { > > >>> > + if (is_tunnel_type(port->interfaces[i]->type)) { > > >>> > + return true; > > >>> > + } > > >>> > + } > > >>> > + return false; > > >>> > +} > > >>> > + > > >>> > void > > >>> > encaps_run(struct ovsdb_idl_txn *ovs_idl_txn, > > >>> > - const struct ovsrec_bridge_table *bridge_table, > > >>> > const struct ovsrec_bridge *br_int, > > >>> > const struct sbrec_chassis_table *chassis_table, > > >>> > const struct sbrec_chassis *this_chassis, > > >>> > @@ -305,7 +327,6 @@ encaps_run(struct ovsdb_idl_txn *ovs_idl_txn, > > >>> > } > > >>> > > > >>> > const struct sbrec_chassis *chassis_rec; > > >>> > - const struct ovsrec_bridge *br; > > >>> > > > >>> > struct tunnel_ctx tc = { > > >>> > .chassis = SHASH_INITIALIZER(&tc.chassis), > > >>> > @@ -320,28 +341,29 @@ encaps_run(struct ovsdb_idl_txn *ovs_idl_txn, > > >>> > > > >>> > /* Collect all port names into tc.port_names. > > >>> > * > > >>> > - * Collect all the OVN-created tunnels into tc.tunnel_hmap. */ > > >>> > - OVSREC_BRIDGE_TABLE_FOR_EACH (br, bridge_table) { > > >>> > - for (size_t i = 0; i < br->n_ports; i++) { > > >>> > - const struct ovsrec_port *port = br->ports[i]; > > >>> > - sset_add(&tc.port_names, port->name); > > >>> > - > > >>> > - /* > > >>> > - * note that the id here is not just the chassis name, > > >>> > but > > >>> the > > >>> > - * combination of <chassis_name><delim><encap_ip> > > >>> > - */ > > >>> > - const char *id = smap_get(&port->external_ids, > > >>> "ovn-chassis-id"); > > >>> > - if (id) { > > >>> > - if (!shash_find(&tc.chassis, id)) { > > >>> > - struct chassis_node *chassis = xzalloc(sizeof > > >>> *chassis); > > >>> > - chassis->bridge = br; > > >>> > - chassis->port = port; > > >>> > - shash_add_assert(&tc.chassis, id, chassis); > > >>> > - } else { > > >>> > - /* Duplicate port for ovn-chassis-id. > > >>> > Arbitrarily > > >>> choose > > >>> > - * to delete this one. */ > > >>> > - ovsrec_bridge_update_ports_delvalue(br, port); > > >>> > - } > > >>> > + * Collect all OVN-created tunnels of the bridge into > > >>> tc.tunnel_hmap. */ > > >>> > + for (size_t i = 0; i < br_int->n_ports; i++) { > > >>> > + const struct ovsrec_port *port = br_int->ports[i]; > > >>> > + if (!is_tunnel_port(port)) { > > >>> > + continue; > > >>> > + } > > >>> > + sset_add(&tc.port_names, port->name); > > >>> > + > > >>> > + /* > > >>> > + * note that the id here is not just the chassis name, but > > >>> > the > > >>> > + * combination of <chassis_name><delim><encap_ip> > > >>> > + */ > > >>> > + const char *id = smap_get(&port->external_ids, > > >>> > "ovn-chassis-id"); > > >>> > + if (id) { > > >>> > + if (!shash_find(&tc.chassis, id)) { > > >>> > + struct chassis_node *chassis = xzalloc(sizeof > > >>> > *chassis); > > >>> > + chassis->bridge = br_int; > > >>> > + chassis->port = port; > > >>> > + shash_add_assert(&tc.chassis, id, chassis); > > >>> > + } else { > > >>> > + /* Duplicate port for ovn-chassis-id. Arbitrarily > > >>> > choose > > >>> > + * to delete this one. */ > > >>> > + ovsrec_bridge_update_ports_delvalue(br_int, port); > > >>> > } > > >>> > } > > >>> > } > > >>> > @@ -381,6 +403,7 @@ encaps_run(struct ovsdb_idl_txn *ovs_idl_txn, > > >>> > shash_delete(&tc.chassis, node); > > >>> > free(chassis); > > >>> > } > > >>> > + > > >>> > shash_destroy(&tc.chassis); > > >>> > sset_destroy(&tc.port_names); > > >>> > } > > >>> > @@ -400,6 +423,9 @@ encaps_cleanup(struct ovsdb_idl_txn *ovs_idl_txn, > > >>> > = xmalloc(sizeof *br_int->ports * br_int->n_ports); > > >>> > size_t n = 0; > > >>> > for (size_t i = 0; i < br_int->n_ports; i++) { > > >>> > + if (!is_tunnel_port(br_int->ports[i])) { > > >>> > + continue; > > >>> > + } > > >>> > if (!smap_get(&br_int->ports[i]->external_ids, > > >>> "ovn-chassis-id")) { > > >>> > ports[n++] = br_int->ports[i]; > > >>> > } > > >>> > diff --git a/controller/encaps.h b/controller/encaps.h > > >>> > index f488393c4..aff85097f 100644 > > >>> > --- a/controller/encaps.h > > >>> > +++ b/controller/encaps.h > > >>> > @@ -30,7 +30,6 @@ struct sset; > > >>> > > > >>> > void encaps_register_ovs_idl(struct ovsdb_idl *); > > >>> > void encaps_run(struct ovsdb_idl_txn *ovs_idl_txn, > > >>> > - const struct ovsrec_bridge_table *, > > >>> > const struct ovsrec_bridge *br_int, > > >>> > const struct sbrec_chassis_table *, > > >>> > const struct sbrec_chassis *, > > >>> > diff --git a/controller/ovn-controller.8.xml > > >>> b/controller/ovn-controller.8.xml > > >>> > index 16bc47b20..c181a0fa6 100644 > > >>> > --- a/controller/ovn-controller.8.xml > > >>> > +++ b/controller/ovn-controller.8.xml > > >>> > @@ -235,6 +235,19 @@ > > >>> > </dd> > > >>> > </dl> > > >>> > > > >>> > + <p> > > >>> > + Note that every <code>external_ids:*</code> key listed above > > >>> > has > > >>> its > > >>> > + <code>external_ids:*-chassis_name</code> counterpart keys that > > >>> allow to > > >>> > + configure values specific to chassis running on the same > > >>> > OVSDB. For > > >>> > + example, if two chassis named <code>blue</code> and > > >>> <code>red</code> are > > >>> > + available on the same host, then an admin may configure > > >>> > different > > >>> > + <code>ovn-cms-options</code> for each of them by setting > > >>> > + <code>external_ids:ovn-cms-options-blue</code> and > > >>> > + <code>external_ids:ovn-cms-options-red</code> keys in the > > >>> database. The > > >>> > + only key that is not available for per-chassis configuration is > > >>> > + <code>external_ids:system-id</code>. > > >>> > + </p> > > >>> > + > > >>> > <p> > > >>> > <code>ovn-controller</code> reads the following values from the > > >>> > <code>Open_vSwitch</code> database of the local OVS instance: > > >>> > @@ -286,7 +299,9 @@ > > >>> > The presence of this key identifies a tunnel port within the > > >>> > integration bridge as one created by > > >>> > <code>ovn-controller</code> > > >>> to > > >>> > reach a remote chassis. Its value is the chassis ID of the > > >>> remote > > >>> > - chassis. > > >>> > + chassis. Alternatively, for patch ports, the key identifies > > >>> > the > > >>> name of > > >>> > + the chassis that owns it, in case of multiple virtual chassis > > >>> running > > >>> > + on the same host. > > >>> > </dd> > > >>> > > > >>> > <dt> > > >>> > diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c > > >>> > index 8d8c678e5..16dc9e28f 100644 > > >>> > --- a/controller/ovn-controller.c > > >>> > +++ b/controller/ovn-controller.c > > >>> > @@ -18,10 +18,14 @@ > > >>> > #include "ovn-controller.h" > > >>> > > > >>> > #include <errno.h> > > >>> > +#include <fcntl.h> > > >>> > #include <getopt.h> > > >>> > #include <signal.h> > > >>> > #include <stdlib.h> > > >>> > #include <string.h> > > >>> > +#include <sys/types.h> > > >>> > +#include <sys/stat.h> > > >>> > +#include <unistd.h> > > >>> > > > >>> > #include "bfd.h" > > >>> > #include "binding.h" > > >>> > @@ -46,6 +50,7 @@ > > >>> > #include "lib/extend-table.h" > > >>> > #include "lib/ip-mcast-index.h" > > >>> > #include "lib/mcast-group-index.h" > > >>> > +#include "lib/ovn-dirs.h" > > >>> > #include "lib/ovn-sb-idl.h" > > >>> > #include "lib/ovn-util.h" > > >>> > #include "patch.h" > > >>> > @@ -85,6 +90,12 @@ static unixctl_cb_func debug_delay_nb_cfg_report; > > >>> > > > >>> > #define CONTROLLER_LOOP_STOPWATCH_NAME > > >>> > "ovn-controller-flow-generation" > > >>> > > > >>> > +/* These variables never change after initialization and can be > > >>> > safely > > >>> used in > > >>> > + * I-P engine. If later we decide to allow to dynamically change > > >>> > them, > > >>> I-P > > >>> > + * machinery will need some adjustments. */ > > >>> > +static char *controller_chassis = NULL; > > >>> > +static char *system_id_override = NULL; > > >>> > + > > >>> > static char *parse_options(int argc, char *argv[]); > > >>> > OVS_NO_RETURN static void usage(void); > > >>> > > > >>> > @@ -260,7 +271,9 @@ out: > > >>> > static const char * > > >>> > br_int_name(const struct ovsrec_open_vswitch *cfg) > > >>> > { > > >>> > - return smap_get_def(&cfg->external_ids, "ovn-bridge", > > >>> DEFAULT_BRIDGE_NAME); > > >>> > + return get_chassis_external_id_value( > > >>> > + &cfg->external_ids, get_ovs_chassis_id(cfg), > > >>> > + "ovn-bridge", DEFAULT_BRIDGE_NAME); > > >>> > } > > >>> > > > >>> > static const struct ovsrec_bridge * > > >>> > @@ -361,8 +374,9 @@ process_br_int(struct ovsdb_idl_txn *ovs_idl_txn, > > >>> > const struct ovsrec_open_vswitch *cfg; > > >>> > cfg = ovsrec_open_vswitch_table_first(ovs_table); > > >>> > ovs_assert(cfg); > > >>> > - const char *datapath_type = smap_get(&cfg->external_ids, > > >>> > - > > >>> > "ovn-bridge-datapath-type"); > > >>> > + const char *datapath_type = get_chassis_external_id_value( > > >>> > + &cfg->external_ids, get_ovs_chassis_id(cfg), > > >>> > + "ovn-bridge-datapath-type", NULL); > > >>> > /* Check for the datapath_type and set it only if it is > > >>> > defined > > >>> in > > >>> > * cfg. */ > > >>> > if (datapath_type && strcmp(br_int->datapath_type, > > >>> datapath_type)) { > > >>> > @@ -372,17 +386,46 @@ process_br_int(struct ovsdb_idl_txn > > >>> > *ovs_idl_txn, > > >>> > return br_int; > > >>> > } > > >>> > > > >>> > -static const char * > > >>> > -get_ovs_chassis_id(const struct ovsrec_open_vswitch_table *ovs_table) > > >>> > +static char *get_file_system_id_override(void) > > >>> > { > > >>> > - const struct ovsrec_open_vswitch *cfg > > >>> > - = ovsrec_open_vswitch_table_first(ovs_table); > > >>> > + char *ret = NULL; > > >>> > + char *filename = xasprintf("%s/system-id-override", > > >>> ovn_sysconfdir()); > > >>> > + errno = 0; > > >>> > + int fd = open(filename, O_RDONLY); > > >>> > + if (fd != -1) { > > >>> > + char file_system_id[64]; > > >>> > + int nread = read(fd, file_system_id, sizeof file_system_id); > > >>> > + if (nread) { > > >>> > + file_system_id[nread] = '\0'; > > >>> > + if (file_system_id[nread - 1] == '\n') { > > >>> > + file_system_id[nread - 1] = '\0'; > > >>> > + } > > >>> > + ret = xstrdup(file_system_id); > > >>> > + } > > >>> > + close(fd); > > >>> > + } > > >>> > + > > >>> > + free(filename); > > >>> > + return ret; > > >>> > +} > > >>> > + > > >>> > +const char * > > >>> > +get_ovs_chassis_id(const struct ovsrec_open_vswitch *cfg) > > >>> > +{ > > >>> > + if (controller_chassis) { > > >>> > + return controller_chassis; > > >>> > + } > > >>> > + > > >>> > + if (system_id_override) { > > >>> > + return system_id_override; > > >>> > + } > > >>> > + > > >>> > const char *chassis_id = cfg ? smap_get(&cfg->external_ids, > > >>> "system-id") > > >>> > : NULL; > > >>> > - > > >>> > if (!chassis_id) { > > >>> > static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, > > >>> > 1); > > >>> > - VLOG_WARN_RL(&rl, "'system-id' in Open_vSwitch database is > > >>> missing."); > > >>> > + VLOG_WARN_RL(&rl, "Failed to detect system-id, " > > >>> > + "configuration not found."); > > >>> > } > > >>> > > > >>> > return chassis_id; > > >>> > @@ -477,10 +520,12 @@ static int > > >>> > get_ofctrl_probe_interval(struct ovsdb_idl *ovs_idl) > > >>> > { > > >>> > const struct ovsrec_open_vswitch *cfg = > > >>> ovsrec_open_vswitch_first(ovs_idl); > > >>> > - return !cfg ? OFCTRL_DEFAULT_PROBE_INTERVAL_SEC : > > >>> > - smap_get_int(&cfg->external_ids, > > >>> > - "ovn-openflow-probe-interval", > > >>> > - OFCTRL_DEFAULT_PROBE_INTERVAL_SEC); > > >>> > + if (!cfg) { > > >>> > + return OFCTRL_DEFAULT_PROBE_INTERVAL_SEC; > > >>> > + } > > >>> > + return get_chassis_external_id_value_int( > > >>> > + &cfg->external_ids, get_ovs_chassis_id(cfg), > > >>> > + "ovn-openflow-probe-interval", > > >>> OFCTRL_DEFAULT_PROBE_INTERVAL_SEC); > > >>> > } > > >>> > > > >>> > /* Retrieves the pointer to the OVN Southbound database from > > >>> > 'ovs_idl' > > >>> and > > >>> > @@ -496,18 +541,21 @@ update_sb_db(struct ovsdb_idl *ovs_idl, struct > > >>> ovsdb_idl *ovnsb_idl, > > >>> > } > > >>> > > > >>> > /* Set remote based on user configuration. */ > > >>> > - const char *remote = smap_get(&cfg->external_ids, "ovn-remote"); > > >>> > + const char *chassis_id = get_ovs_chassis_id(cfg); > > >>> > + const char *remote = get_chassis_external_id_value( > > >>> > + &cfg->external_ids, chassis_id, "ovn-remote", NULL); > > >>> > ovsdb_idl_set_remote(ovnsb_idl, remote, true); > > >>> > > > >>> > /* Set probe interval, based on user configuration and the > > >>> > remote. */ > > >>> > int default_interval = (remote && > > >>> !stream_or_pstream_needs_probes(remote) > > >>> > ? 0 : DEFAULT_PROBE_INTERVAL_MSEC); > > >>> > - int interval = smap_get_int(&cfg->external_ids, > > >>> > - "ovn-remote-probe-interval", > > >>> default_interval); > > >>> > + int interval = get_chassis_external_id_value_int( > > >>> > + &cfg->external_ids, chassis_id, "ovn-remote-probe-interval", > > >>> > + default_interval); > > >>> > ovsdb_idl_set_probe_interval(ovnsb_idl, interval); > > >>> > > > >>> > - bool monitor_all = smap_get_bool(&cfg->external_ids, > > >>> "ovn-monitor-all", > > >>> > - false); > > >>> > + bool monitor_all = get_chassis_external_id_value_bool( > > >>> > + &cfg->external_ids, chassis_id, "ovn-monitor-all", false); > > >>> > if (monitor_all) { > > >>> > /* Always call update_sb_monitors when monitor_all is true. > > >>> > * Otherwise, don't call it here, because there would be > > >>> unnecessary > > >>> > @@ -1166,7 +1214,9 @@ init_binding_ctx(struct engine_node *node, > > >>> > struct ovsrec_bridge_table *bridge_table = > > >>> > (struct ovsrec_bridge_table *)EN_OVSDB_GET( > > >>> > engine_get_input("OVS_bridge", node)); > > >>> > - const char *chassis_id = get_ovs_chassis_id(ovs_table); > > >>> > + const struct ovsrec_open_vswitch *cfg = > > >>> > + ovsrec_open_vswitch_table_first(ovs_table); > > >>> > + const char *chassis_id = get_ovs_chassis_id(cfg); > > >>> > const struct ovsrec_bridge *br_int = get_br_int(bridge_table, > > >>> ovs_table); > > >>> > > > >>> > ovs_assert(br_int && chassis_id); > > >>> > @@ -2432,6 +2482,10 @@ main(int argc, char *argv[]) > > >>> > exiting = false; > > >>> > restart = false; > > >>> > bool sb_monitor_all = false; > > >>> > + > > >>> > + /* Read from system-id-override file once on startup. */ > > >>> > + system_id_override = get_file_system_id_override(); > > >>> > + > > >>> > while (!exiting) { > > >>> > /* If we're paused just run the unixctl server and skip most > > >>> > of > > >>> the > > >>> > * processing loop. > > >>> > @@ -2498,7 +2552,9 @@ main(int argc, char *argv[]) > > >>> > sbrec_chassis_private_table_get(ovnsb_idl_loop.idl); > > >>> > const struct ovsrec_bridge *br_int = > > >>> > process_br_int(ovs_idl_txn, bridge_table, ovs_table); > > >>> > - const char *chassis_id = get_ovs_chassis_id(ovs_table); > > >>> > + const struct ovsrec_open_vswitch *cfg = > > >>> > + ovsrec_open_vswitch_table_first(ovs_table); > > >>> > + const char *chassis_id = get_ovs_chassis_id(cfg); > > >>> > const struct sbrec_chassis *chassis = NULL; > > >>> > const struct sbrec_chassis_private *chassis_private = > > >>> > NULL; > > >>> > if (chassis_id) { > > >>> > @@ -2518,7 +2574,7 @@ main(int argc, char *argv[]) > > >>> > > > >>> > if (chassis) { > > >>> > encaps_run(ovs_idl_txn, > > >>> > - bridge_table, br_int, > > >>> > + br_int, > > >>> > > > >>> sbrec_chassis_table_get(ovnsb_idl_loop.idl), > > >>> > chassis, > > >>> > > > >>> > sbrec_sb_global_first(ovnsb_idl_loop.idl), > > >>> > @@ -2779,6 +2835,8 @@ loop_done: > > >>> > ovsdb_idl_loop_destroy(&ovs_idl_loop); > > >>> > ovsdb_idl_loop_destroy(&ovnsb_idl_loop); > > >>> > > > >>> > + free(controller_chassis); > > >>> > + free(system_id_override); > > >>> > free(ovs_remote); > > >>> > service_stop(); > > >>> > > > >>> > @@ -2804,6 +2862,7 @@ parse_options(int argc, char *argv[]) > > >>> > STREAM_SSL_LONG_OPTIONS, > > >>> > {"peer-ca-cert", required_argument, NULL, OPT_PEER_CA_CERT}, > > >>> > {"bootstrap-ca-cert", required_argument, NULL, > > >>> OPT_BOOTSTRAP_CA_CERT}, > > >>> > + {"chassis", required_argument, NULL, 'n'}, > > >>> > {NULL, 0, NULL, 0} > > >>> > }; > > >>> > char *short_options = > > >>> ovs_cmdl_long_options_to_short_options(long_options); > > >>> > @@ -2836,6 +2895,10 @@ parse_options(int argc, char *argv[]) > > >>> > stream_ssl_set_ca_cert_file(optarg, true); > > >>> > break; > > >>> > > > >>> > + case 'n': > > >>> > + controller_chassis = xstrdup(optarg); > > >>> > + break; > > >>> > + > > >>> > case '?': > > >>> > exit(EXIT_FAILURE); > > >>> > > > >>> > diff --git a/controller/ovn-controller.h b/controller/ovn-controller.h > > >>> > index 5d9466880..9994dd777 100644 > > >>> > --- a/controller/ovn-controller.h > > >>> > +++ b/controller/ovn-controller.h > > >>> > @@ -21,6 +21,7 @@ > > >>> > #include "lib/ovn-sb-idl.h" > > >>> > > > >>> > struct ovsrec_bridge_table; > > >>> > +struct ovsrec_open_vswitch; > > >>> > > > >>> > /* Linux supports a maximum of 64K zones, which seems like a fine > > >>> default. */ > > >>> > #define MAX_CT_ZONES 65535 > > >>> > @@ -87,4 +88,7 @@ enum chassis_tunnel_type { > > >>> > > > >>> > uint32_t get_tunnel_type(const char *name); > > >>> > > > >>> > +const char *get_ovs_chassis_id(const struct ovsrec_open_vswitch > > >>> > *cfg); > > >>> > +bool is_concurrent_chassis(const struct ovsrec_open_vswitch *cfg); > > >>> > + > > >>> > #endif /* controller/ovn-controller.h */ > > >>> > diff --git a/controller/patch.c b/controller/patch.c > > >>> > index a2a7bcd79..3b3df278c 100644 > > >>> > --- a/controller/patch.c > > >>> > +++ b/controller/patch.c > > >>> > @@ -76,6 +76,7 @@ create_patch_port(struct ovsdb_idl_txn *ovs_idl_txn, > > >>> > const char *key, const char *value, > > >>> > const struct ovsrec_bridge *src, const char > > >>> > *src_name, > > >>> > const struct ovsrec_bridge *dst, const char > > >>> > *dst_name, > > >>> > + const char *chassis_name, > > >>> > struct shash *existing_ports) > > >>> > { > > >>> > for (size_t i = 0; i < src->n_ports; i++) { > > >>> > @@ -101,7 +102,8 @@ create_patch_port(struct ovsdb_idl_txn > > >>> > *ovs_idl_txn, > > >>> > port = ovsrec_port_insert(ovs_idl_txn); > > >>> > ovsrec_port_set_name(port, src_name); > > >>> > ovsrec_port_set_interfaces(port, &iface, 1); > > >>> > - const struct smap ids = SMAP_CONST1(&ids, key, value); > > >>> > + const struct smap ids = SMAP_CONST2(&ids, key, value, > > >>> > + "ovn-chassis-id", > > >>> > chassis_name); > > >>> > ovsrec_port_set_external_ids(port, &ids); > > >>> > > > >>> > struct ovsrec_port **ports; > > >>> > @@ -157,7 +159,9 @@ add_ovs_bridge_mappings(const struct > > >>> ovsrec_open_vswitch_table *ovs_table, > > >>> > const char *mappings_cfg; > > >>> > char *cur, *next, *start; > > >>> > > > >>> > - mappings_cfg = smap_get(&cfg->external_ids, > > >>> "ovn-bridge-mappings"); > > >>> > + mappings_cfg = get_chassis_external_id_value( > > >>> > + &cfg->external_ids, get_ovs_chassis_id(cfg), > > >>> > + "ovn-bridge-mappings", NULL); > > >>> > if (!mappings_cfg || !mappings_cfg[0]) { > > >>> > return; > > >>> > } > > >>> > @@ -269,9 +273,11 @@ add_bridge_mappings(struct ovsdb_idl_txn > > >>> *ovs_idl_txn, > > >>> > char *name1 = patch_port_name(br_int->name, > > >>> binding->logical_port); > > >>> > char *name2 = patch_port_name(binding->logical_port, > > >>> br_int->name); > > >>> > create_patch_port(ovs_idl_txn, patch_port_id, > > >>> binding->logical_port, > > >>> > - br_int, name1, br_ln, name2, > > >>> > existing_ports); > > >>> > + br_int, name1, br_ln, name2, chassis->name, > > >>> > + existing_ports); > > >>> > create_patch_port(ovs_idl_txn, patch_port_id, > > >>> binding->logical_port, > > >>> > - br_ln, name2, br_int, name1, > > >>> > existing_ports); > > >>> > + br_ln, name2, br_int, name1, chassis->name, > > >>> > + existing_ports); > > >>> > free(name1); > > >>> > free(name2); > > >>> > } > > >>> > @@ -323,6 +329,12 @@ patch_run(struct ovsdb_idl_txn *ovs_idl_txn, > > >>> > SHASH_FOR_EACH_SAFE (port_node, port_next_node, &existing_ports) > > >>> > { > > >>> > port = port_node->data; > > >>> > shash_delete(&existing_ports, port_node); > > >>> > + > > >>> > + const char *port_chassis = smap_get(&port->external_ids, > > >>> > + "ovn-chassis-id"); > > >>> > + if (port_chassis && strcmp(port_chassis, chassis->name)) { > > >>> > + continue; > > >>> > + } > > >>> > remove_port(bridge_table, port); > > >>> > } > > >>> > shash_destroy(&existing_ports); > > >>> > diff --git a/controller/physical.c b/controller/physical.c > > >>> > index a7f3efd2f..306f7f912 100644 > > >>> > --- a/controller/physical.c > > >>> > +++ b/controller/physical.c > > >>> > @@ -432,7 +432,7 @@ populate_remote_chassis_macs(const struct > > >>> sbrec_chassis *my_chassis, > > >>> > } > > >>> > > > >>> > const char *tokens > > >>> > - = get_chassis_mac_mappings(&chassis->other_config); > > >>> > + = get_chassis_mac_mappings(&chassis->other_config, NULL); > > >>> > > > >>> > if (!strlen(tokens)) { > > >>> > continue; > > >>> > diff --git a/lib/ovn-util.c b/lib/ovn-util.c > > >>> > index cdb5e18fb..3193b73db 100644 > > >>> > --- a/lib/ovn-util.c > > >>> > +++ b/lib/ovn-util.c > > >>> > @@ -641,3 +641,53 @@ str_tolower(const char *orig) > > >>> > > > >>> > return copy; > > >>> > } > > >>> > + > > >>> > +const char * > > >>> > +get_chassis_external_id_value(const struct smap *external_ids, > > >>> > + const char *chassis_id, const char > > >>> *option_key, > > >>> > + const char *def) > > >>> > +{ > > >>> > + const char *option_value = NULL; > > >>> > + if (chassis_id != NULL) { > > >>> > + char *chassis_option_key = xasprintf("%s-%s", option_key, > > >>> chassis_id); > > >>> > + option_value = smap_get(external_ids, chassis_option_key); > > >>> > + free(chassis_option_key); > > >>> > + } > > >>> > + if (!option_value) { > > >>> > + option_value = smap_get_def(external_ids, option_key, def); > > >>> > + } > > >>> > + return option_value; > > >>> > +} > > >>> > + > > >>> > +int > > >>> > +get_chassis_external_id_value_int(const struct smap *external_ids, > > >>> > + const char *chassis_id, > > >>> > + const char *option_key, > > >>> > + int def) > > >>> > +{ > > >>> > + const char *value = get_chassis_external_id_value( > > >>> > + external_ids, chassis_id, option_key, NULL); > > >>> > + > > >>> > + int i_value; > > >>> > + if (!value || !str_to_int(value, 10, &i_value)) { > > >>> > + return def; > > >>> > + } > > >>> > + > > >>> > + return i_value; > > >>> > +} > > >>> > + > > >>> > +bool > > >>> > +get_chassis_external_id_value_bool(const struct smap *external_ids, > > >>> > + const char *chassis_id, > > >>> > + const char *option_key, > > >>> > + bool def) > > >>> > +{ > > >>> > + const char *value = get_chassis_external_id_value( > > >>> > + external_ids, chassis_id, option_key, ""); > > >>> > + > > >>> > + if (def) { > > >>> > + return strcasecmp("false", value) != 0; > > >>> > + } else { > > >>> > + return !strcasecmp("true", value); > > >>> > + } > > >>> > +} > > >>> > diff --git a/lib/ovn-util.h b/lib/ovn-util.h > > >>> > index d9aadcbc0..a1b8f47b5 100644 > > >>> > --- a/lib/ovn-util.h > > >>> > +++ b/lib/ovn-util.h > > >>> > @@ -18,6 +18,7 @@ > > >>> > > > >>> > #include "lib/packets.h" > > >>> > #include "include/ovn/version.h" > > >>> > +#include "smap.h" > > >>> > > > >>> > #define ovn_set_program_name(name) \ > > >>> > ovs_set_program_name(name, OVN_PACKAGE_VERSION) > > >>> > @@ -152,6 +153,23 @@ char *normalize_ipv4_prefix(ovs_be32 ipv4, > > >>> > unsigned > > >>> int plen); > > >>> > char *normalize_ipv6_prefix(struct in6_addr ipv6, unsigned int plen); > > >>> > char *normalize_v46_prefix(const struct v46_ip *prefix, unsigned int > > >>> plen); > > >>> > > > >>> > +const char * > > >>> > +get_chassis_external_id_value(const struct smap *external_ids, > > >>> > + const char *chassis_id, const char > > >>> *option_key, > > >>> > + const char *def); > > >>> > + > > >>> > +int > > >>> > +get_chassis_external_id_value_int(const struct smap *external_ids, > > >>> > + const char *chassis_id, > > >>> > + const char *option_key, > > >>> > + int def); > > >>> > + > > >>> > +bool > > >>> > +get_chassis_external_id_value_bool(const struct smap *external_ids, > > >>> > + const char *chassis_id, > > >>> > + const char *option_key, > > >>> > + bool def); > > >>> > + > > >>> > /* Returns a lowercase copy of orig. > > >>> > * Caller must free the returned string. > > >>> > */ > > >>> > diff --git a/ovn-sb.xml b/ovn-sb.xml > > >>> > index 59888a155..3fe75b723 100644 > > >>> > --- a/ovn-sb.xml > > >>> > +++ b/ovn-sb.xml > > >>> > @@ -240,10 +240,12 @@ > > >>> > > > >>> > <column name="name"> > > >>> > OVN does not prescribe a particular format for chassis names. > > >>> > - ovn-controller populates this column using <ref key="system-id" > > >>> > - table="Open_vSwitch" column="external_ids" db="Open_vSwitch"/> > > >>> > - in the Open_vSwitch database's <ref table="Open_vSwitch" > > >>> > - db="Open_vSwitch"/> table. ovn-controller-vtep populates this > > >>> > + ovn-controller populates this column using the <code>-n</code> > > >>> > + CLI argument, or <code>system-id-override</code> configuration > > >>> file, or > > >>> > + <ref key="system-id" table="Open_vSwitch" column="external_ids" > > >>> > + db="Open_vSwitch"/> in the Open_vSwitch database's > > >>> > + <ref table="Open_vSwitch" db="Open_vSwitch"/> table. > > >>> > + ovn-controller-vtep populates this > > >>> > column with <ref table="Physical_Switch" column="name" > > >>> > db="hardware_vtep"/> in the hardware_vtep database's > > >>> > <ref table="Physical_Switch" db="hardware_vtep"/> table. > > >>> > diff --git a/tests/ovn-controller.at b/tests/ovn-controller.at > > >>> > index d8061345f..efb48c057 100644 > > >>> > --- a/tests/ovn-controller.at > > >>> > +++ b/tests/ovn-controller.at > > >>> > @@ -50,8 +50,7 @@ patch > > >>> > # is mirrored into the Chassis record in the OVN_Southbound db. > > >>> > check_bridge_mappings () { > > >>> > local_mappings=$1 > > >>> > - sysid=$(ovs-vsctl get Open_vSwitch . external_ids:system-id) > > >>> > - OVS_WAIT_UNTIL([test x"${local_mappings}" = x$(ovn-sbctl get > > >>> > Chassis > > >>> ${sysid} other_config:ovn-bridge-mappings | sed -e 's/\"//g')]) > > >>> > + OVS_WAIT_UNTIL([test x"${local_mappings}" = x$(ovn-sbctl get > > >>> > Chassis > > >>> ${sandbox} other_config:ovn-bridge-mappings | sed -e 's/\"//g')]) > > >>> > } > > >>> > > > >>> > # Initially there should be no patch ports. > > >>> > @@ -133,13 +132,13 @@ ovs-vsctl \ > > >>> > -- add-br br-eth2 > > >>> > ovn_attach n1 br-phys 192.168.0.1 > > >>> > > > >>> > -sysid=$(ovs-vsctl get Open_vSwitch . external_ids:system-id) > > >>> > +sysid=${sandbox} > > >>> > > > >>> > # Make sure that the datapath_type set in the Bridge table > > >>> > # is mirrored into the Chassis record in the OVN_Southbound db. > > >>> > check_datapath_type () { > > >>> > datapath_type=$1 > > >>> > - chassis_datapath_type=$(ovn-sbctl get Chassis ${sysid} > > >>> other_config:datapath-type | sed -e 's/"//g') #" > > >>> > + chassis_datapath_type=$(ovn-sbctl get Chassis ${sandbox} > > >>> other_config:datapath-type | sed -e 's/"//g') #" > > >>> > test "${datapath_type}" = "${chassis_datapath_type}" > > >>> > } > > >>> > > > >>> > @@ -187,7 +186,7 @@ OVS_WAIT_UNTIL([ > > >>> > test "${expected_iface_types}" = "${chassis_iface_types}" > > >>> > ]) > > >>> > > > >>> > -# Change the value of external_ids:system-id and make sure it's > > >>> > mirrored > > >>> > +# Set the value of external_ids:system-id and make sure it's mirrored > > >>> > # in the Chassis record in the OVN_Southbound database. > > >>> > sysid=${sysid}-foo > > >>> > ovs-vsctl set Open_vSwitch . external-ids:system-id="${sysid}" > > >>> > diff --git a/tests/ovn-macros.at b/tests/ovn-macros.at > > >>> > index a6719be83..f846c6336 100644 > > >>> > --- a/tests/ovn-macros.at > > >>> > +++ b/tests/ovn-macros.at > > >>> > @@ -215,7 +215,7 @@ net_attach () { > > >>> > > > >>> > # ovn_az_attach AZ NETWORK BRIDGE IP [MASKLEN] > > >>> > ovn_az_attach() { > > >>> > - local az=$1 net=$2 bridge=$3 ip=$4 masklen=${5-24} > > >>> encap=${6-geneve,vxlan} > > >>> > + local az=$1 net=$2 bridge=$3 ip=$4 masklen=${5-24} > > >>> encap=${6-geneve,vxlan} intbr=${7-br-int} chassis=$8 > > >>> > net_attach $net $bridge || return 1 > > >>> > > > >>> > mac=`ovs-vsctl get Interface $bridge mac_in_use | sed s/\"//g` > > >>> > @@ -229,15 +229,48 @@ ovn_az_attach() { > > >>> > else > > >>> > ovn_remote=unix:$ovs_base/$az/ovn-sb/ovn-sb.sock > > >>> > fi > > >>> > + > > >>> > + if [[ -n "${chassis}" ]]; then > > >>> > + bridge_key=ovn-bridge-${chassis} > > >>> > + remote_key=ovn-remote-${chassis} > > >>> > + encap_type_key=ovn-encap-type-${chassis} > > >>> > + encap_ip_key=ovn-encap-ip-${chassis} > > >>> > + chassis_args="-n $chassis" > > >>> > + chassis_vsctl_args= > > >>> > + else > > >>> > + bridge_key=ovn-bridge > > >>> > + remote_key=ovn-remote > > >>> > + encap_type_key=ovn-encap-type > > >>> > + encap_ip_key=ovn-encap-ip > > >>> > + chassis=$sandbox > > >>> > + chassis_args= > > >>> > + chassis_vsctl_args="-- set Open_vSwitch . > > >>> external-ids:system-id=$chassis" > > >>> > + fi > > >>> > + > > >>> > ovs-vsctl \ > > >>> > - -- set Open_vSwitch . external-ids:system-id=$sandbox \ > > >>> > - -- set Open_vSwitch . external-ids:ovn-remote=$ovn_remote \ > > >>> > - -- set Open_vSwitch . external-ids:ovn-encap-type=$encap \ > > >>> > - -- set Open_vSwitch . external-ids:ovn-encap-ip=$ip \ > > >>> > - -- --may-exist add-br br-int \ > > >>> > - -- set bridge br-int fail-mode=secure > > >>> other-config:disable-in-band=true \ > > >>> > + $chassis_vsctl_args \ > > >>> > + -- set Open_vSwitch . external-ids:$bridge_key=$intbr \ > > >>> > + -- set Open_vSwitch . external-ids:$remote_key=$ovn_remote \ > > >>> > + -- set Open_vSwitch . external-ids:$encap_type_key=$encap \ > > >>> > + -- set Open_vSwitch . external-ids:$encap_ip_key=$ip \ > > >>> > + -- --may-exist add-br ${intbr} \ > > >>> > + -- set bridge ${intbr} fail-mode=secure > > >>> other-config:disable-in-band=true \ > > >>> > || return 1 > > >>> > - start_daemon ovn-controller || return 1 > > >>> > + > > >>> > + if [[ "${intbr}" = br-int ]]; then > > >>> > + pidfile="${OVS_RUNDIR}/ovn-controller.pid" > > >>> > + logfile="${OVS_LOGDIR}/ovn-controller.log" > > >>> > + else > > >>> > + pidfile="${OVS_RUNDIR}/ovn-controller-${intbr}.pid" > > >>> > + logfile="${OVS_LOGDIR}/ovn-controller-${chassis}.log" > > >>> > + fi > > >>> > + > > >>> > + ovn-controller \ > > >>> > + ${chassis_args} \ > > >>> > + -vconsole:off --detach --no-chdir \ > > >>> > + --pidfile=${pidfile} \ > > >>> > + --log-file=${logfile} || return 1 > > >>> > + on_exit "test -e \"$pidfile\" && kill \`cat \"$pidfile\"\`" > > >>> > } > > >>> > > > >>> > # ovn_attach NETWORK BRIDGE IP [MASKLEN] > > >>> > diff --git a/tests/ovn.at b/tests/ovn.at > > >>> > index de1df3b6a..3bac087a4 100644 > > >>> > --- a/tests/ovn.at > > >>> > +++ b/tests/ovn.at > > >>> > @@ -1727,7 +1727,107 @@ AT_CLEANUP > > >>> > > > >>> > AT_BANNER([OVN end-to-end tests]) > > >>> > > > >>> > -# 3 hypervisors, one logical switch, 3 logical ports per hypervisor > > >>> > +AT_SETUP([ovn -- 3 virtual hosts, same node]) > > >>> > +AT_KEYWORDS([ovn]) > > >>> > +ovn_start > > >>> > +ovn-nbctl ls-add lsw0 > > >>> > +net_add n1 > > >>> > +sim_add hv > > >>> > + > > >>> > +as hv > > >>> > +for i in 1 2 3; do > > >>> > + chassis=host-$i > > >>> > + ovs-vsctl add-br br-phys-$i > > >>> > + ovn_attach n1 br-phys-$i 192.168.0.$i 24 geneve br-int-$i > > >>> > $chassis > > >>> > + > > >>> > + for j in 1 2 3; do > > >>> > + lpname=lp$i$j > > >>> > + ovn-nbctl lsp-add lsw0 $lpname > > >>> > + ovn-nbctl --wait=hv --timeout=3 lsp-set-options $lpname > > >>> requested-chassis=$chassis > > >>> > + ovs-vsctl add-port br-int-$i vif$i$j -- set Interface vif$i$j > > >>> external-ids:iface-id=$lpname > > >>> > + OVS_WAIT_UNTIL([test x`ovn-nbctl lsp-get-up $lpname` = xup]) > > >>> > + > > >>> > + pb_chassis_id=$(ovn-sbctl --bare --columns chassis list > > >>> port_binding $lpname) > > >>> > + pb_chassis_name=$(ovn-sbctl get chassis $pb_chassis_id name) > > >>> > + AT_FAIL_IF([test x$pb_chassis_name != x$chassis]) > > >>> > + done > > >>> > +done > > >>> > + > > >>> > +for i in 1 2 3; do > > >>> > + > expout > > >>> > + for vif in 1 2 3; do > > >>> > + echo vif$i$vif >> expout > > >>> > + done > > >>> > + AT_CHECK([ovs-vsctl list-ports br-int-$i | grep vif], [0], > > >>> > [expout]) > > >>> > +done > > >>> > + > > >>> > +AT_CLEANUP > > >>> > + > > >>> > +AT_SETUP([ovn -- system-id in file]) > > >>> > +AT_KEYWORDS([ovn]) > > >>> > + > > >>> > +ovn_start > > >>> > +net_add n1 > > >>> > +sim_add hv > > >>> > + > > >>> > +as hv > > >>> > + > > >>> > +echo otherid > ${OVN_SYSCONFDIR}/system-id-override > > >>> > +ovs-vsctl add-br br-phys > > >>> > +ovn_attach n1 br-phys 192.168.0.1 > > >>> > + > > >>> > +# system-id-override file overrides chassis name selected via cli > > >>> > +echo otherid > expout > > >>> > +AT_CHECK([ovn-sbctl --bare --columns name list chassis], [0], > > >>> > [expout]) > > >>> > + > > >>> > +AT_CLEANUP > > >>> > + > > >>> > +AT_SETUP([ovn -- concurrent controllers avoid fighting for each > > >>> > others' > > >>> resources]) > > >>> > +AT_KEYWORDS([ovn]) > > >>> > + > > >>> > +ovn_start > > >>> > +sim_add hv > > >>> > + > > >>> > +for i in 1 2; do > > >>> > + net_add n-$i > > >>> > +done > > >>> > + > > >>> > +as hv > > >>> > +for i in 1 2; do > > >>> > + AT_CHECK([ovn-nbctl ls-add ls-$i]) > > >>> > + AT_CHECK([ovn-nbctl lsp-add ls-$i ln_port-$i]) > > >>> > + AT_CHECK([ovn-nbctl lsp-set-addresses ln_port-$i unknown]) > > >>> > + AT_CHECK([ovn-nbctl lsp-set-type ln_port-$i localnet]) > > >>> > + AT_CHECK([ovn-nbctl --wait=hv lsp-set-options ln_port-$i > > >>> network_name=phys-$i]) > > >>> > +done > > >>> > + > > >>> > +for i in 1 2; do > > >>> > + as hv > > >>> > + ovs-vsctl add-br br-phys-$i > > >>> > + ovs-vsctl set open . > > >>> external-ids:ovn-bridge-mappings-hv-$i=phys-$i:br-phys-$i > > >>> > + ovn_attach n-$i br-phys-$i 192.168.0.$i 24 geneve br-int-$i hv-$i > > >>> > + > > >>> > + ovs-vsctl add-port br-int-$i vif-$i -- set Interface vif-$i > > >>> external-ids:iface-id=lp-$i > > >>> > + ovn-nbctl lsp-add ls-$i lp-$i > > >>> > + OVS_WAIT_UNTIL([test x`ovn-nbctl lsp-get-up lp-$i` = xup]) > > >>> > +done > > >>> > + > > >>> > +# check that both patch ports are present > > >>> > +AT_CHECK([ovs-vsctl --bare --columns=name find interface > > >>> > type="patch" | > > >>> awk NF | sort], [0], > > >>> > +[[patch-br-int-1-to-ln_port-1 > > >>> > +patch-br-int-2-to-ln_port-2 > > >>> > +patch-ln_port-1-to-br-int-1 > > >>> > +patch-ln_port-2-to-br-int-2 > > >>> > +]]) > > >>> > + > > >>> > +# check that both tunnel endpoints are present > > >>> > +AT_CHECK([ovs-vsctl --bare --columns=name find interface > > >>> > type="geneve" | > > >>> awk NF | sort], [0], > > >>> > +[[ovn-hv-1-0 > > >>> > +ovn-hv-2-0 > > >>> > +]]) > > >>> > + > > >>> > +AT_CLEANUP > > >>> > + > > >>> > AT_SETUP([ovn -- 3 HVs, 1 LS, 3 lports/HV]) > > >>> > AT_KEYWORDS([ovnarp]) > > >>> > ovn_start > > >>> > @@ -6967,6 +7067,72 @@ OVN_CLEANUP([hv1]) > > >>> > > > >>> > AT_CLEANUP > > >>> > > > >>> > +AT_SETUP([ovn -- obsolete patch ports and tunnel endpoints removed]) > > >>> > +AT_KEYWORDS([cleanup-test]) > > >>> > +ovn_start > > >>> > + > > >>> > +net_add n1 > > >>> > +net_add n2 > > >>> > + > > >>> > +for i in 1 2; do > > >>> > + ovs-vsctl add-br br-phys$i > > >>> > + ovs-vsctl set open . > > >>> external-ids:ovn-bridge-mappings-hv$i=physnet$i:br-phys$i > > >>> > + ovn_attach n$i br-phys$i 192.168.0.$i 24 geneve br-int$i hv$i > > >>> > +done > > >>> > + > > >>> > +# create irrelevant patch and tunnel ports > > >>> > +for i in 1 2; do > > >>> > + # patch without chassis owner set > > >>> > + ovs-vsctl add-port br-int$i fakepatch$i > > >>> external-ids:ovn-logical-patch-port=fakeport$i -- \ > > >>> > + set Interface fakepatch$i type=patch > > >>> > + > > >>> > + # patch marked as owned by the chassis > > >>> > + ovs-vsctl add-port br-int$i owned_fakepatch$i > > >>> external-ids:ovn-logical-patch-port=owned_fakeport$i \ > > >>> > + > > >>> external-ids:ovn-chassis-id=hv$i -- \ > > >>> > + set Interface owned_fakepatch$i type=patch > > >>> > + > > >>> > + # patch marked as owned by some other chassis > > >>> > + ovs-vsctl add-port br-int$i alien_fakepatch$i > > >>> external-ids:ovn-logical-patch-port=alien_fakeport$i \ > > >>> > + > > >>> external-ids:ovn-chassis-id=alien_hv$i -- \ > > >>> > + set Interface alien_fakepatch$i type=patch > > >>> > + > > >>> > + # OVN tunnel endpoint on a bridge owned by a controller > > >>> > + ovs-vsctl add-port br-int$i faketunnel$i > > >>> external-ids:ovn-chassis-id=fakechassis -- \ > > >>> > + set Interface faketunnel$i type=geneve > > >>> > +done > > >>> > + > > >>> > +# tunnel endpoint on a bridge NOT owned by a controller > > >>> > +ovs-vsctl add-br alien_br > > >>> > +ovs-vsctl add-port alien_br alien_tunnel > > >>> external-ids:ovn-chassis-id=fakechassis -- \ > > >>> > + set Interface alien_tunnel type=geneve > > >>> > + > > >>> > +AT_CHECK([ovn-nbctl ls-add lsw0]) > > >>> > +AT_CHECK([ovn-nbctl lsp-add lsw0 lnport]) > > >>> > +AT_CHECK([ovn-nbctl lsp-set-addresses lnport unknown]) > > >>> > +AT_CHECK([ovn-nbctl lsp-set-type lnport localnet]) > > >>> > +AT_CHECK([ovn-nbctl --wait=hv lsp-set-options lnport > > >>> network_name=physnet1]) > > >>> > + > > >>> > +ovs-vsctl add-port br-int1 vif -- set Interface vif > > >>> external-ids:iface-id=lp0 > > >>> > +ovn-nbctl lsp-add lsw0 lp0 > > >>> > +OVS_WAIT_UNTIL([test x`ovn-nbctl lsp-get-up lp0` = xup]) > > >>> > + > > >>> > +# check that only patch ports that belong to some other chassis and > > >>> those for localnet ports are present > > >>> > +AT_CHECK([ovs-vsctl --bare --columns=name find interface > > >>> > type="patch" | > > >>> awk NF | sort], [0], > > >>> > +[[alien_fakepatch1 > > >>> > +alien_fakepatch2 > > >>> > +patch-br-int1-to-lnport > > >>> > +patch-lnport-to-br-int1 > > >>> > +]]) > > >>> > + > > >>> > +# check that only controller tunnel endpoints and a tunnel on another > > >>> bridge are present > > >>> > +AT_CHECK([ovs-vsctl --bare --columns=name find interface > > >>> > type="geneve" | > > >>> awk NF | sort], [0], > > >>> > +[[alien_tunnel > > >>> > +ovn-hv1-0 > > >>> > +ovn-hv2-0 > > >>> > +]]) > > >>> > + > > >>> > +AT_CLEANUP > > >>> > + > > >>> > AT_SETUP([ovn -- nd_na ]) > > >>> > ovn_start > > >>> > > > >>> > diff --git a/tests/ovs-macros.at b/tests/ovs-macros.at > > >>> > index 3dcf8f96d..7b812e5dd 100644 > > >>> > --- a/tests/ovs-macros.at > > >>> > +++ b/tests/ovs-macros.at > > >>> > @@ -53,6 +53,7 @@ ovs_setenv() { > > >>> > OVS_LOGDIR=$ovs_dir; export OVS_LOGDIR > > >>> > OVS_DBDIR=$ovs_dir; export OVS_DBDIR > > >>> > OVS_SYSCONFDIR=$ovs_dir; export OVS_SYSCONFDIR > > >>> > + OVN_SYSCONFDIR=$ovs_dir; export OVN_SYSCONFDIR > > >>> > OVS_PKGDATADIR=$ovs_dir; export OVS_PKGDATADIR > > >>> > } > > >>> > > > >>> > -- > > >>> > 2.26.2 > > >>> > > > >>> > _______________________________________________ > > >>> > dev mailing list > > >>> > d...@openvswitch.org > > >>> > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > > >>> _______________________________________________ > > >>> dev mailing list > > >>> d...@openvswitch.org > > >>> https://mail.openvswitch.org/mailman/listinfo/ovs-dev > > >>> > > > > _______________________________________________ > > dev mailing list > > d...@openvswitch.org > > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > > > _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev