[ovs-dev] [RFC PATCH v1 3/6] L3 E-W Support in ovn, replace router port mac with chassis mac.

Numan Siddique nusiddiq at redhat.com
Sat Mar 16 06:26:44 UTC 2019


On Wed, Mar 6, 2019 at 3:15 AM Ankur Sharma <ankur.sharma at nutanix.com>
wrote:

> Hi Numan,
>
> Thank you so much for review and initial comments.
> Please find my response inline.
>
> Please go through the explanations and we can discuss further from there.
>
>
> Thanks again for review.
>
> Regards,
> Ankur
>
> *From:* Numan Siddique <nusiddiq at redhat.com>
> *Sent:* Wednesday, February 27, 2019 6:00 AM
> *To:* Ankur Sharma <ankur.sharma at nutanix.com>
> *Cc:* ovs-dev at openvswitch.org
> *Subject:* Re: [ovs-dev] [RFC PATCH v1 3/6] L3 E-W Support in ovn,
> replace router port mac with chassis mac.
>
>
>
>
>
>
>
> On Thu, Feb 21, 2019 at 4:10 AM Ankur Sharma <ankur.sharma at nutanix.com>
> wrote:
>
> Background:
> [1] https://mail.openvswitch.org/pipermail/ovs-dev/2018-October/353066.html
> [mail.openvswitch.org]
> <https://urldefense.proofpoint.com/v2/url?u=https-3A__mail.openvswitch.org_pipermail_ovs-2Ddev_2018-2DOctober_353066.html&d=DwMFaQ&c=s883GpUCOChKOHiocYtGcg&r=mZwX9gFQgeJHzTg-68aCJgsODyUEVsHGFOfL90J6MJY&m=loh6pMwgaWsIa-IhZIQPE1Ar3vWj_gufFqEu-KCDtrY&s=H_XhzdGFWY5TNEkoXHLE2FTd67qwGcdvtMLNysKD2ng&e=>
> [2] https://docs.google.com/document/d/1uoQH478wM1OZ16HrxzbOUvk5LvFnfNEWbkPT6Zmm9OU/edit?usp=sharing
> [docs.google.com]
> <https://urldefense.proofpoint.com/v2/url?u=https-3A__docs.google.com_document_d_1uoQH478wM1OZ16HrxzbOUvk5LvFnfNEWbkPT6Zmm9OU_edit-3Fusp-3Dsharing&d=DwMFaQ&c=s883GpUCOChKOHiocYtGcg&r=mZwX9gFQgeJHzTg-68aCJgsODyUEVsHGFOfL90J6MJY&m=loh6pMwgaWsIa-IhZIQPE1Ar3vWj_gufFqEu-KCDtrY&s=HjTglktnxsL-Hi1RzVFn7AOWganM1qYaEgX5I320Euk&e=>
>
> This Series:
> Layer 2, Layer 3 E-W and Layer 3 N-S (NO NAT) changes for vlan
> backed distributed logical router.
>
> This Patch:
>  a. Introduce per physical network chassic mac bindings in ovs.
>     For example:
>
> ovn-chassis-mac-mappings="physnet1:aa:bb:cc:dd:ee:ff,physnet2:a1:b2:c3:d4:e5:f6"
>
>
>
> I had a quick look on this patch. I have few concerns.
>
>
>
>   - The approach taken here adding
> "ovn-chassis-mac-mappings="physnet1:aa:bb:cc:dd:ee:ff,physnet2:a1:b2:c3:d4:e5:f6""
> in the
>
>     ovs db of each chassis could be problematic. This requires that CMS
> execute this command when ever a logical switch of type vlan is created.
>
>     In the case of OpenStack, a user can create a provider network of type
> vlan any time and delete it any time. It would require
>
>    for the customer/CMS to set this value on all chassis. This would not
> be feasible.
>
>
> [ANKUR]: Sorry, may be the documentation or patch did not clarify it
> properly.
> Chassis mac is not tied with logical entities, i.e Logical switch of type
> vlan creation will not need an additional step of chassis mac
> configuration. Chassis mac is a one time configuration (per chassis) and
> should be seen as equivalent to “ovn-encap-ip”.
> Consumption of chassis-mac is backward compatible, i.e existing deployment
> need not program it and there deployments will continue to use router port
> mac , when packet goes on wire.
>
>
>
>  - In the present approach, the flows to set the mac address of the
> chassis is added in table 65. Probably that's not the right place.
>
>    And these flows will not be transparent and we cant map it to any
> logical flows or to any of the OVN DB contents.
>
>    Utilities like ovn-trace cannot really trace the packet since the
> mac-mappings are not visible to it.
>
> [ANKUR]: The reason for doing it in table=65 are following:
> a. Replacing router port mac with a chassis mac is done ONLY before
> sending the packet on wire.
> b. For above reason, logical pipeline need not see this mac at all,
> logical pipelines should operation on router port mac only.
>
> c. We should see this operation (replacing router port mac with chassis
> mac) as equivalent to overlay encapsulation or vlan tagging by localnet
> ports.
>
> d. i.e Encapsulation is done in table=32 (just before sending the packet
> on wire during ingress pipeline)  or tagging the packet with vlan (for
> localnet ports) is done in table=65 (just before sending the packet on wire
> in egress pipeline).
> e. You have raised a very good point about ovn-trace. How do we  represent
> overlay encapsulation or vlan tagging by localnet port in ovn-trace output.
> If we do, then its my bad, I should have had changes for ovn-trace as well.
>
>
Sorry for the late reply. Thanks for the detailed explanation.
I get your point now.
I still feel it would be better if it can be expressed from Northbound DB.
If we take deployment tools like Tripleo for openstack, it needs
to set the "ovn-chassis-mac-mappings" for each chassis during deployment
(and it needs to generate the macs). CMS like networking-ovn
(Openstack neutron plugin) can easily generate the MACs and set it when
ever a logical switch with localnet port is created.
If you see, when a localnet port is created we need to define the "physical
network name". In the above example, it would be "phsynet1 and physnet2".

It would be good to get other's opinion on this.

Thanks
Numan




I think we can express the mac-mappings in the OVN Northbound DB. My
> suggestion would be to do the following
>
>  - Add a new column 'mac-mappings' (or a better appropriate name) in
> Logical_Switch_Port  of type map.
>
>
>
>  -  This column should be set by CMS for logical port of type 'localnet'.
> The key of this map would be "chassis name" and the value would be mac
> address to use.
>
>      Eg.    "chassis1": "aa:bb:cc:dd:ee:01"
>
>                "chassis2": "aa:bb:cc:dd:ee:02"
>
>
>
>  - With the above column probably we don't need patch 1/2 of this series.
> Each localnet port will have a differenet "network_name".
>
>    OVN doesn't need to know if the network type is vlan or geneve for a
> logical switch. If a logical switch has a localnet port, it means
>
>    it corresponds to a physical network.
>
>
>
> - CMS can easily set these values. It can read the Southbound DB to know
> the chasiss names.
>
>
>
> - ovn-northd  can read this and add appropriate logical flows to set the
> chassis specific mac addresses. It could be similar to "get_arp()" OVN
> action in which case
>
> ovn-controller can add flows in table 67 (or appropriate) which will set
> eth.dst.
>
>
>
>   Or
>
>   we can add a new action "is_chassis(chassis1)" which will be true only
> on that chassis.
>
>   And we can have logical flows in the logical switch pipeline something
> like
>
>
>
>     match=... && is_chassis(chassis1), action = (eth.dst =
> aa:bb:cc:dd:ee:01; ...)
>
>     match=... && is_chassis(chassis2), action = (eth.dst =
> aa:bb:cc:dd:ee:02; ...)
>
>
> [ANKUR]:
> We can discuss further on this. Please go through my replies  (looks like
> some concepts were not well documented by me and hence the confusion) and
> we can take it forward from there.
>
>
>
> Any Thoughts or comments ?
>
>
>
> Thanks
>
> Numan
>
>
>
>
>
>
>
>
>
>  b. Replace router port mac with a chassis specific mac,
>     read from a. above.
>     For example:
>     cookie=0x0, duration=67765.830s, table=65, n_packets=0, n_bytes=0,
>     idle_age=65534, hard_age=65534, priority=150,reg15=0x1,metadata=0x4,
>     dl_src=00:00:01:01:02:03 actions=mod_dl_src:aa:bb:cc:dd:ee:ff,
>     mod_vlan_vid:1000,output:16
>
> Signed-off-by: Ankur Sharma <ankur.sharma at nutanix.com>
> ---
>  ovn/controller/bfd.c                |   5 +-
>  ovn/controller/binding.c            |  12 +--
>  ovn/controller/chassis.c            |  66 +++++++++++-
>  ovn/controller/chassis.h            |   4 +
>  ovn/controller/ovn-controller.8.xml |   7 ++
>  ovn/controller/ovn-controller.c     |   2 +-
>  ovn/controller/ovn-controller.h     |   5 +-
>  ovn/controller/physical.c           |  96 +++++++++++++++++
>  ovn/ovn-sb.xml                      |   8 ++
>  tests/ovn.at [ovn.at]
> <https://urldefense.proofpoint.com/v2/url?u=http-3A__ovn.at&d=DwMFaQ&c=s883GpUCOChKOHiocYtGcg&r=mZwX9gFQgeJHzTg-68aCJgsODyUEVsHGFOfL90J6MJY&m=loh6pMwgaWsIa-IhZIQPE1Ar3vWj_gufFqEu-KCDtrY&s=UMr17hvb7f_HksiQoi98N7CVc2uV8cVEf4UxuZz5mAA&e=>
>                       | 199 +++++++++++++++++++++++++++++++++++-
>  10 files changed, 390 insertions(+), 14 deletions(-)
>
> diff --git a/ovn/controller/bfd.c b/ovn/controller/bfd.c
> index 94dad23..1ee48a5 100644
> --- a/ovn/controller/bfd.c
> +++ b/ovn/controller/bfd.c
> @@ -121,8 +121,9 @@ bfd_travel_gw_related_chassis(
>      LIST_FOR_EACH_POP (dp_binding, node, &dp_list) {
>          dp = dp_binding->dp;
>          free(dp_binding);
> -        for (size_t i = 0; i < dp->n_peer_dps; i++) {
> -            const struct sbrec_datapath_binding *pdp = dp->peer_dps[i];
> +        for (size_t i = 0; i < dp->n_peer_ports; i++) {
> +            const struct sbrec_datapath_binding *pdp =
> +                dp->peer_ports[i]->datapath;
>              if (!pdp) {
>                  continue;
>              }
> diff --git a/ovn/controller/binding.c b/ovn/controller/binding.c
> index 021ecdd..53ee032 100644
> --- a/ovn/controller/binding.c
> +++ b/ovn/controller/binding.c
> @@ -159,13 +159,11 @@ add_local_datapath__(struct ovsdb_idl_index
> *sbrec_datapath_binding_by_key,
>                                           sbrec_port_binding_by_name,
>                                           peer->datapath, false,
>                                           depth + 1, local_datapaths);
> -                    ld->n_peer_dps++;
> -                    ld->peer_dps = xrealloc(
> -                            ld->peer_dps,
> -                            ld->n_peer_dps * sizeof *ld->peer_dps);
> -                    ld->peer_dps[ld->n_peer_dps - 1] =
> datapath_lookup_by_key(
> -                        sbrec_datapath_binding_by_key,
> -                        peer->datapath->tunnel_key);
> +                    ld->n_peer_ports++;
> +                    ld->peer_ports = xrealloc(ld->peer_ports,
> +                                              ld->n_peer_ports *
> +                                              sizeof *ld->peer_ports);
> +                    ld->peer_ports[ld->n_peer_ports - 1] = peer;
>                  }
>              }
>          }
> diff --git a/ovn/controller/chassis.c b/ovn/controller/chassis.c
> index 797c16c..88e3630 100644
> --- a/ovn/controller/chassis.c
> +++ b/ovn/controller/chassis.c
> @@ -22,6 +22,7 @@
>  #include "lib/vswitch-idl.h"
>  #include "openvswitch/dynamic-string.h"
>  #include "openvswitch/vlog.h"
> +#include "openvswitch/ofp-parse.h"
>  #include "ovn/lib/chassis-index.h"
>  #include "ovn/lib/ovn-sb-idl.h"
>  #include "ovn-controller.h"
> @@ -68,6 +69,12 @@ get_bridge_mappings(const struct smap *ext_ids)
>  }
>
>  static const char *
> +get_chassis_mac_mappings(const struct smap *ext_ids)
> +{
> +    return smap_get_def(ext_ids, "ovn-chassis-mac-mappings", "");
> +}
> +
> +static const char *
>  get_cms_options(const struct smap *ext_ids)
>  {
>      return smap_get_def(ext_ids, "ovn-cms-options", "");
> @@ -130,6 +137,7 @@ chassis_run(struct ovsdb_idl_txn *ovnsb_idl_txn,
>      const char *datapath_type =
>          br_int && br_int->datapath_type ? br_int->datapath_type : "";
>      const char *cms_options = get_cms_options(&cfg->external_ids);
> +    const char *chassis_macs =
> get_chassis_mac_mappings(&cfg->external_ids);
>
>      struct ds iface_types = DS_EMPTY_INITIALIZER;
>      ds_put_cstr(&iface_types, "");
> @@ -157,18 +165,22 @@ chassis_run(struct ovsdb_idl_txn *ovnsb_idl_txn,
>              = smap_get_def(&chassis_rec->external_ids, "iface-types", "");
>          const char *chassis_cms_options
>              = get_cms_options(&chassis_rec->external_ids);
> +        const char *chassis_mac_mappings
> +            = get_chassis_mac_mappings(&chassis_rec->external_ids);
>
>          /* If any of the external-ids should change, update them. */
>          if (strcmp(bridge_mappings, chassis_bridge_mappings) ||
>              strcmp(datapath_type, chassis_datapath_type) ||
>              strcmp(iface_types_str, chassis_iface_types) ||
> -            strcmp(cms_options, chassis_cms_options)) {
> +            strcmp(cms_options, chassis_cms_options) ||
> +            strcmp(chassis_macs, chassis_mac_mappings)) {
>              struct smap new_ids;
>              smap_clone(&new_ids, &chassis_rec->external_ids);
>              smap_replace(&new_ids, "ovn-bridge-mappings",
> bridge_mappings);
>              smap_replace(&new_ids, "datapath-type", datapath_type);
>              smap_replace(&new_ids, "iface-types", iface_types_str);
>              smap_replace(&new_ids, "ovn-cms-options", cms_options);
> +            smap_replace(&new_ids, "ovn-chassis-mac-mappings",
> chassis_macs);
>              sbrec_chassis_verify_external_ids(chassis_rec);
>              sbrec_chassis_set_external_ids(chassis_rec, &new_ids);
>              smap_destroy(&new_ids);
> @@ -246,6 +258,58 @@ chassis_run(struct ovsdb_idl_txn *ovnsb_idl_txn,
>      return chassis_rec;
>  }
>
> +bool
> +chassis_get_mac(const struct sbrec_chassis *chassis_rec,
> +                const char *bridge_mapping,
> +                struct eth_addr *chassis_mac)
> +{
> +    const char *tokens
> +        = get_chassis_mac_mappings(&chassis_rec->external_ids);
> +    char *save_ptr = NULL;
> +    char *token;
> +    bool ret = false;
> +
> +    if (!strlen(tokens)) {
> +       return false;
> +    }
> +
> +    char *tokstr = xstrdup(tokens);
> +
> +    /* Format for a chassis mac configuration is:
> +     * ovn-chassis-mac-mappings="bridge-name1:MAC1,bridge-name2:MAC2"
> +     */
> +    for (token = strtok_r(tokstr, ",", &save_ptr);
> +         token != NULL;
> +         token = strtok_r(NULL, ",", &save_ptr)) {
> +        char *save_ptr2 = NULL;
> +        char *chassis_mac_bridge = strtok_r(token, ":", &save_ptr2);
> +        char *chassis_mac_str = strtok_r(NULL, "", &save_ptr2);
> +
> +        if (!strcmp(chassis_mac_bridge, bridge_mapping)) {
> +            struct eth_addr temp_mac;
> +            char *err_str = NULL;
> +
> +            ret = true;
> +
> +            // Return the first chassis mac.
> +            if ((err_str = str_to_mac(chassis_mac_str, &temp_mac))) {
> +                free(err_str);
> +                ret = false;
> +                continue;
> +            }
> +
> +            memcpy(chassis_mac, &temp_mac, sizeof(struct eth_addr));
> +
> +            goto done;
> +        }
> +    }
> +
> +done:
> +    free(tokstr);
> +
> +    return ret;
> +}
> +
>  /* Returns true if the database is all cleaned up, false if more work is
>   * required. */
>  bool
> diff --git a/ovn/controller/chassis.h b/ovn/controller/chassis.h
> index 6b1c357..b61e87f 100644
> --- a/ovn/controller/chassis.h
> +++ b/ovn/controller/chassis.h
> @@ -17,6 +17,7 @@
>  #define OVN_CHASSIS_H 1
>
>  #include <stdbool.h>
> +#include "openvswitch/types.h"
>
>  struct ovsdb_idl;
>  struct ovsdb_idl_index;
> @@ -32,6 +33,9 @@ const struct sbrec_chassis *chassis_run(
>      struct ovsdb_idl_index *sbrec_chassis_by_name,
>      const struct ovsrec_open_vswitch_table *,
>      const char *chassis_id, const struct ovsrec_bridge *br_int);
> +bool chassis_get_mac(const struct sbrec_chassis *chassis,
> +                     const char *bridge_mapping,
> +                     struct eth_addr *chassis_mac);
>  bool chassis_cleanup(struct ovsdb_idl_txn *ovnsb_idl_txn,
>                       const struct sbrec_chassis *);
>
> diff --git a/ovn/controller/ovn-controller.8.xml
> b/ovn/controller/ovn-controller.8.xml
> index 8035638..3baa6c9 100644
> --- a/ovn/controller/ovn-controller.8.xml
> +++ b/ovn/controller/ovn-controller.8.xml
> @@ -159,6 +159,13 @@
>          specific to this particular chassis. An example would be:
>          <code>cms_option1,cms_option2:foo</code>.
>        </dd>
> +      <dt><code>external_ids:ovn-chassis-mac-mappings</code></dt>
> +      <dd>
> +        A list of key-value pairs that map a chassis specific mac to
> +        a physical network name. An example
> +        value mapping two chassis macs to two physical network names
> would be:
> +
> <code>physnet1:aa:bb:cc:dd:ee:ff,physnet2:a1:b2:c3:d4:e5:f6</code>.
> +      </dd>
>      </dl>
>
>      <p>
> diff --git a/ovn/controller/ovn-controller.c
> b/ovn/controller/ovn-controller.c
> index 2098f28..e8d002e 100644
> --- a/ovn/controller/ovn-controller.c
> +++ b/ovn/controller/ovn-controller.c
> @@ -840,7 +840,7 @@ main(int argc, char *argv[])
>              struct local_datapath *cur_node, *next_node;
>              HMAP_FOR_EACH_SAFE (cur_node, next_node, hmap_node,
>                                  &local_datapaths) {
> -                free(cur_node->peer_dps);
> +                free(cur_node->peer_ports);
>                  hmap_remove(&local_datapaths, &cur_node->hmap_node);
>                  free(cur_node);
>              }
> diff --git a/ovn/controller/ovn-controller.h
> b/ovn/controller/ovn-controller.h
> index b13b371..9f02162 100644
> --- a/ovn/controller/ovn-controller.h
> +++ b/ovn/controller/ovn-controller.h
> @@ -59,8 +59,9 @@ struct local_datapath {
>      /* True if this datapath contains an l3gateway port located on this
>       * hypervisor. */
>      bool has_local_l3gateway;
> -    const struct sbrec_datapath_binding **peer_dps;
> -    size_t n_peer_dps;
> +
> +    const struct sbrec_port_binding **peer_ports;
> +    size_t n_peer_ports;
>  };
>
>  struct local_datapath *get_local_datapath(const struct hmap *,
> diff --git a/ovn/controller/physical.c b/ovn/controller/physical.c
> index ab3b02a..fad68e4 100644
> --- a/ovn/controller/physical.c
> +++ b/ovn/controller/physical.c
> @@ -20,6 +20,7 @@
>  #include "gchassis.h"
>  #include "lflow.h"
>  #include "lport.h"
> +#include "chassis.h"
>  #include "lib/bundle.h"
>  #include "openvswitch/poll-loop.h"
>  #include "lib/uuid.h"
> @@ -30,6 +31,7 @@
>  #include "openvswitch/ofp-actions.h"
>  #include "openvswitch/ofpbuf.h"
>  #include "openvswitch/vlog.h"
> +#include "openvswitch/ofp-parse.h"
>  #include "ovn-controller.h"
>  #include "ovn/lib/chassis-index.h"
>  #include "ovn/lib/ovn-sb-idl.h"
> @@ -188,6 +190,94 @@ get_zone_ids(const struct sbrec_port_binding *binding,
>  }
>
>  static void
> +put_replace_router_port_mac_flows(const struct sbrec_port_binding
> *localnet_port,
> +                                  const struct sbrec_chassis *chassis,
> +                                  const struct hmap *local_datapaths,
> +                                  struct ofpbuf *ofpacts_p,
> +                                  ofp_port_t ofport,
> +                                  struct hmap *flow_table)
> +{
> +    struct local_datapath *ld = get_local_datapath(local_datapaths,
> +
>  localnet_port->datapath->
> +                                                   tunnel_key);
> +    uint32_t dp_key = localnet_port->datapath->tunnel_key;
> +    uint32_t port_key = localnet_port->tunnel_key;
> +    int tag = *localnet_port->tag;
> +    const char *network = smap_get(&localnet_port->options,
> "network_name");
> +    struct eth_addr chassis_mac;
> +
> +    ovs_assert(ld);
> +
> +    if (!network) {
> +        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
> +        VLOG_WARN_RL(&rl, "Physical network not configured for datapath:
> %ld "
> +                     "with localnet port",
> +                     localnet_port->datapath->tunnel_key);
> +        return;
> +    }
> +
> +    // Get chassis mac
> +    if (chassis_get_mac(chassis, network, &chassis_mac) == false) {
> +        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
> +        /* Keeping the log level low for backward compatibility.
> +         * Chassis mac is a new configuration.
> +         */
> +        VLOG_DBG_RL(&rl, "Could not get chassis mac for network: %s",
> network);
> +        return;
> +    }
> +
> +    for (int i = 0; i < ld->n_peer_ports; i++) {
> +        const struct sbrec_port_binding *rport_binding =
> ld->peer_ports[i];
> +        struct eth_addr router_port_mac;
> +        char *err_str = NULL;
> +        struct match match;
> +        struct ofpact_mac *replace_mac;
> +
> +        /* Table 65, priority 150.
> +         * =======================
> +         *
> +         * Implements output to localnet port.
> +         * a. Flow replaces ingress router port mac with a chassis mac.
> +         * b. Flow appends the vlan id localnet port is configured with.
> +         */
> +        match_init_catchall(&match);
> +        ofpbuf_clear(ofpacts_p);
> +
> +        ovs_assert(rport_binding->n_mac == 1);
> +        if ((err_str = str_to_mac(rport_binding->mac[0],
> &router_port_mac))) {
> +            // Parsing of mac failed.
> +            VLOG_WARN("Parsing or router port mac failed for router port:
> %s, "
> +                      "with error: %s", rport_binding->logical_port,
> err_str);
> +            free(err_str);
> +            return;
> +        }
> +
> +        // Replace Mac flow
> +
> +        replace_mac = ofpact_put_SET_ETH_SRC(ofpacts_p);
> +        replace_mac->mac = chassis_mac;
> +
> +        match_set_metadata(&match, htonll(dp_key));
> +        match_set_reg(&match, MFF_LOG_OUTPORT - MFF_REG0, port_key);
> +        match_set_dl_src(&match, router_port_mac);
> +
> +        if (tag) {
> +            struct ofpact_vlan_vid *vlan_vid;
> +            vlan_vid = ofpact_put_SET_VLAN_VID(ofpacts_p);
> +            vlan_vid->vlan_vid = tag;
> +            vlan_vid->push_vlan_if_needed = true;
> +        }
> +
> +        ofpact_put_OUTPUT(ofpacts_p)->port = ofport;
> +
> +        ofctrl_add_flow(flow_table, OFTABLE_LOG_TO_PHY, 150, 0,
> +                        &match, ofpacts_p);
> +    }
> +
> +    return;
> +}
> +
> +static void
>  put_local_common_flows(uint32_t dp_key, uint32_t port_key,
>                         uint32_t parent_port_key,
>                         const struct zone_ids *zone_ids,
> @@ -656,6 +746,12 @@ consider_port_binding(struct ovsdb_idl_index
> *sbrec_chassis_by_name,
>          }
>          ofctrl_add_flow(flow_table, OFTABLE_LOG_TO_PHY, 100, 0,
>                          &match, ofpacts_p);
> +
> +        if (!strcmp(binding->type, "localnet")) {
> +            put_replace_router_port_mac_flows(binding, chassis,
> local_datapaths,
> +                                              ofpacts_p, ofport,
> flow_table);
> +        }
> +
>      } else if (!tun && !is_ha_remote) {
>          /* Remote port connected by localnet port */
>          /* Table 33, priority 100.
> diff --git a/ovn/ovn-sb.xml b/ovn/ovn-sb.xml
> index 01ef892..059f1a2 100644
> --- a/ovn/ovn-sb.xml
> +++ b/ovn/ovn-sb.xml
> @@ -293,6 +293,14 @@
>        See <code>ovn-controller</code>(8) for more information.
>      </column>
>
> +    <column name="external_ids" key="ovn-chassis-mac-mappings">
> +      <code>ovn-controller</code> populates this key with the set of
> options
> +      configured in the <ref table="Open_vSwitch"
> +      column="external_ids:ovn-chassis-mac-mappings"/> column of the
> Open_vSwitch
> +      database's <ref table="Open_vSwitch" db="Open_vSwitch"/> table.
> +      See <code>ovn-controller</code>(8) for more information.
> +    </column>
> +
>      <group title="Common Columns">
>        The overall purpose of these columns is described under <code>Common
>        Columns</code> at the beginning of this document.
> diff --git a/tests/ovn.at [ovn.at]
> <https://urldefense.proofpoint.com/v2/url?u=http-3A__ovn.at&d=DwMFaQ&c=s883GpUCOChKOHiocYtGcg&r=mZwX9gFQgeJHzTg-68aCJgsODyUEVsHGFOfL90J6MJY&m=loh6pMwgaWsIa-IhZIQPE1Ar3vWj_gufFqEu-KCDtrY&s=UMr17hvb7f_HksiQoi98N7CVc2uV8cVEf4UxuZz5mAA&e=>
> b/tests/ovn.at [ovn.at]
> <https://urldefense.proofpoint.com/v2/url?u=http-3A__ovn.at&d=DwMFaQ&c=s883GpUCOChKOHiocYtGcg&r=mZwX9gFQgeJHzTg-68aCJgsODyUEVsHGFOfL90J6MJY&m=loh6pMwgaWsIa-IhZIQPE1Ar3vWj_gufFqEu-KCDtrY&s=UMr17hvb7f_HksiQoi98N7CVc2uV8cVEf4UxuZz5mAA&e=>
> index cfdbf41..138e58b 100644
> --- a/tests/ovn.at [ovn.at]
> <https://urldefense.proofpoint.com/v2/url?u=http-3A__ovn.at&d=DwMFaQ&c=s883GpUCOChKOHiocYtGcg&r=mZwX9gFQgeJHzTg-68aCJgsODyUEVsHGFOfL90J6MJY&m=loh6pMwgaWsIa-IhZIQPE1Ar3vWj_gufFqEu-KCDtrY&s=UMr17hvb7f_HksiQoi98N7CVc2uV8cVEf4UxuZz5mAA&e=>
> +++ b/tests/ovn.at [ovn.at]
> <https://urldefense.proofpoint.com/v2/url?u=http-3A__ovn.at&d=DwMFaQ&c=s883GpUCOChKOHiocYtGcg&r=mZwX9gFQgeJHzTg-68aCJgsODyUEVsHGFOfL90J6MJY&m=loh6pMwgaWsIa-IhZIQPE1Ar3vWj_gufFqEu-KCDtrY&s=UMr17hvb7f_HksiQoi98N7CVc2uV8cVEf4UxuZz5mAA&e=>
> @@ -2911,7 +2911,7 @@ test_ip() {
>      local
> packet=${dst_mac}${src_mac}08004500001c0000000040110000${src_ip}${dst_ip}0035111100080000
>      shift; shift; shift; shift; shift
>      hv=hv`vif_to_hv $inport`
> -    as $hv ovs-appctl netdev-dummy/receive vif$inport $packet
> +    as $hv ovs-appctl netdev-dummy/receive $inport $packet
>      in_ls=`vif_to_ls $inport`
>      in_lrp=`vif_to_lrp $inport`
>      for outport; do
> @@ -12088,3 +12088,200 @@ ovn-nbctl list logical_switch_port
>  ovn-nbctl list logical_router_port
>
>  AT_CLEANUP
> +
> +AT_SETUP([ovn -- 2 HVs, 2 lports/HV, localnet ports, DVR chassis mac])
> +ovn_start
> +
> +
> +# In this test cases we create 2 switches, all connected to same
> +# physical network (through br-phys on each HV). Each switch has
> +# 1 VIF. Each HV has 1 VIF port. The first digit
> +# of VIF port name indicates the hypervisor it is bound to, e.g.
> +# lp23 means VIF 3 on hv2.
> +#
> +# Each switch's VLAN tag and their logical switch ports are:
> +#   - ls1:
> +#       - tagged with VLAN 101
> +#       - ports: lp11
> +#   - ls2:
> +#       - tagged with VLAN 201
> +#       - ports: lp22
> +#
> +# Note: a localnet port is created for each switch to connect to
> +# physical network.
> +
> +for i in 1 2; do
> +    ls_name=ls$i
> +    ovn-nbctl ls-add $ls_name vlan
> +    ln_port_name=ln$i
> +    if test $i -eq 1; then
> +        ovn-nbctl lsp-add $ls_name $ln_port_name "" 101
> +    elif test $i -eq 2; then
> +        ovn-nbctl lsp-add $ls_name $ln_port_name "" 201
> +    fi
> +    ovn-nbctl lsp-set-addresses $ln_port_name unknown
> +    ovn-nbctl lsp-set-type $ln_port_name localnet
> +    ovn-nbctl lsp-set-options $ln_port_name network_name=phys
> +done
> +
> +# lsp_to_ls LSP
> +#
> +# Prints the name of the logical switch that contains LSP.
> +lsp_to_ls () {
> +    case $1 in dnl (
> +        lp?[[11]]) echo ls1 ;; dnl (
> +        lp?[[12]]) echo ls2 ;; dnl (
> +        *) AT_FAIL_IF([:]) ;;
> +    esac
> +}
> +
> +vif_to_ls () {
> +    case $1 in dnl (
> +        vif?[[11]]) echo ls1 ;; dnl (
> +        vif?[[12]]) echo ls2 ;; dnl (
> +        *) AT_FAIL_IF([:]) ;;
> +    esac
> +}
> +
> +hv_to_num () {
> +    case $1 in dnl (
> +        hv1) echo 1 ;; dnl (
> +        hv2) echo 2 ;; dnl (
> +        *) AT_FAIL_IF([:]) ;;
> +    esac
> +}
> +
> +vif_to_num () {
> +    case $1 in dnl (
> +        vif22) echo 22 ;; dnl (
> +        vif21) echo 21 ;; dnl (
> +        *) AT_FAIL_IF([:]) ;;
> +    esac
> +}
> +
> +vif_to_hv () {
> +    case $1 in dnl (
> +        vif[[1]]?) echo hv1 ;; dnl (
> +        vif[[2]]?) echo hv2 ;; dnl (
> +        *) AT_FAIL_IF([:]) ;;
> +    esac
> +}
> +
> +vif_to_lrp () {
> +    echo router-to-`vif_to_ls $1`
> +}
> +
> +hv_to_chassis_mac () {
> +     case $1 in dnl (
> +        hv[[1]]) echo aa:bb:cc:dd:ee:11 ;; dnl (
> +        hv[[2]]) echo aa:bb:cc:dd:ee:22 ;; dnl (
> +        *) AT_FAIL_IF([:]) ;;
> +    esac
> +}
> +
> +ip_to_hex() {
> +       printf "%02x%02x%02x%02x" "$@"
> +}
> +
> +net_add n1
> +for i in 1 2; do
> +    sim_add hv$i
> +    as hv$i
> +    ovs-vsctl add-br br-phys
> +    ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys
> +    ovs-vsctl set open .
> external-ids:ovn-chassis-mac-mappings="phys:aa:bb:cc:dd:ee:$i$i"
> +    ovn_attach n1 br-phys 192.168.0.$i
> +
> +    ovs-vsctl add-port br-int vif$i$i -- \
> +        set Interface vif$i$i external-ids:iface-id=lp$i$i \
> +                              options:tx_pcap=hv$i/vif$i$i-tx.pcap \
> +                              options:rxq_pcap=hv$i/vif$i$i-rx.pcap \
> +                              ofport-request=$i$i
> +
> +    lsp_name=lp$i$i
> +    ls_name=$(lsp_to_ls $lsp_name)
> +
> +    ovn-nbctl lsp-add $ls_name $lsp_name
> +    ovn-nbctl lsp-set-addresses $lsp_name "f0:00:00:00:00:$i$i
> 192.168.$i.$i"
> +    ovn-nbctl lsp-set-port-security $lsp_name f0:00:00:00:00:$i$i
> +
> +    OVS_WAIT_UNTIL([test x`ovn-nbctl lsp-get-up $lsp_name` = xup])
> +
> +done
> +
> +ovn-nbctl lr-add router
> +ovn-nbctl lrp-add router router-to-ls1 00:00:01:01:02:03 192.168.1.3/24
> +ovn-nbctl [192.168.1.3]
> <https://urldefense.proofpoint.com/v2/url?u=http-3A__192.168.1.3_24-2Bovn-2Dnbctl&d=DwMFaQ&c=s883GpUCOChKOHiocYtGcg&r=mZwX9gFQgeJHzTg-68aCJgsODyUEVsHGFOfL90J6MJY&m=loh6pMwgaWsIa-IhZIQPE1Ar3vWj_gufFqEu-KCDtrY&s=J6zHmqz8BNYqbuWqlQDuktQcKOMCkEeOeMe9frPw3l4&e=>
> lrp-add router router-to-ls2 00:00:01:01:02:05 192.168.2.3/24
> [192.168.2.3]
> <https://urldefense.proofpoint.com/v2/url?u=http-3A__192.168.2.3_24&d=DwMFaQ&c=s883GpUCOChKOHiocYtGcg&r=mZwX9gFQgeJHzTg-68aCJgsODyUEVsHGFOfL90J6MJY&m=loh6pMwgaWsIa-IhZIQPE1Ar3vWj_gufFqEu-KCDtrY&s=-2eThN-BA2d0Th6gEAU487Y-Zs_4JvegAFK95EpZ-MM&e=>
> +
> +ovn-nbctl lsp-add ls1 ls1-to-router -- set Logical_Switch_Port
> ls1-to-router type=router options:router-port=router-to-ls1 --
> lsp-set-addresses ls1-to-router router
> +ovn-nbctl lsp-add ls2 ls2-to-router -- set Logical_Switch_Port
> ls2-to-router type=router options:router-port=router-to-ls2 --
> lsp-set-addresses ls2-to-router router
> +
> +ovn-nbctl --wait=sb sync
> +#ovn-sbctl dump-flows
> +
> +ovn-nbctl show
> +ovn-sbctl show
> +
> +OVN_POPULATE_ARP
> +
> +test_ip() {
> +    # This packet has bad checksums but logical L3 routing doesn't check.
> +    local inport=$1 src_mac=$2 dst_mac=$3 src_ip=$4 dst_ip=$5
> +    local
> packet=${dst_mac}${src_mac}08004500001c0000000040110000${src_ip}${dst_ip}0035111100080000
> +    shift; shift; shift; shift; shift
> +    hv=`vif_to_hv $inport`
> +    hv_num=`hv_to_num $hv`
> +    chassis_mac=`hv_to_chassis_mac $hv`
> +    as $hv ovs-appctl netdev-dummy/receive $inport $packet
> +    #as $hv ovs-appctl ofproto/trace br-int in_port=$inport $packet
> +    in_ls=`vif_to_ls $inport`
> +    in_lrp=`vif_to_lrp $inport`
> +    for outport; do
> +        out_ls=`vif_to_ls $outport`
> +        if test $in_ls = $out_ls; then
> +            # Ports on the same logical switch receive exactly the same
> packet.
> +            echo $packet
> +        else
> +            # Routing decrements TTL and updates source and dest MAC
> +            # (and checksum).
> +            outport_num=`vif_to_num $outport`
> +            out_lrp=`vif_to_lrp $outport`
> +            echo
> f000000000${outport_num}aabbccddee${hv_num}${hv_num}08004500001c00000000"3f1101"00${src_ip}${dst_ip}0035111100080000
> +        fi >> $outport.expected
> +    done
> +}
> +
> +# Dump a bunch of info helpful for debugging if there's a failure.
> +
> +echo "------ OVN dump ------"
> +ovn-nbctl show
> +ovn-sbctl show
> +
> +echo "------ hv1 dump ------"
> +as hv1 ovs-vsctl show
> +as hv1 ovs-vsctl list Open_Vswitch
> +
> +echo "------ hv2 dump ------"
> +as hv2 ovs-vsctl show
> +as hv2 ovs-vsctl list Open_Vswitch
> +
> +echo "Send traffic"
> +sip=`ip_to_hex 192 168 1 1`
> +dip=`ip_to_hex 192 168 2 2`
> +test_ip vif11 f00000000011  000001010203 $sip $dip vif22
> +
> +sleep 1
> +
> +echo "----------- Post Traffic hv1 dump -----------"
> +as hv1 ovs-ofctl -O OpenFlow13 dump-flows br-int
> +as hv1 ovs-appctl fdb/show br-phys
> +
> +echo "----------- Post Traffic hv2 dump -----------"
> +as hv2 ovs-ofctl -O OpenFlow13 dump-flows br-int
> +as hv2 ovs-appctl fdb/show br-phys
> +
> +OVN_CHECK_PACKETS([hv2/vif22-tx.pcap], [vif22.expected])
> +
> +OVN_CLEANUP([hv1],[hv2])
> +
> +AT_CLEANUP
> --
> 1.8.3.1
>
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
> [mail.openvswitch.org]
> <https://urldefense.proofpoint.com/v2/url?u=https-3A__mail.openvswitch.org_mailman_listinfo_ovs-2Ddev&d=DwMFaQ&c=s883GpUCOChKOHiocYtGcg&r=mZwX9gFQgeJHzTg-68aCJgsODyUEVsHGFOfL90J6MJY&m=loh6pMwgaWsIa-IhZIQPE1Ar3vWj_gufFqEu-KCDtrY&s=hVfkPQDzo6FwvQ11oDcQN9YyY_A_gIcTi9uGsqq3Stg&e=>
>
>


More information about the dev mailing list