[ovs-dev] [PATCH ovn v2] Add a northbound interface to program MAC_Binding table

svc.eng.git-mail svc.eng.git-mail at nutanix.com
Wed Nov 3 19:16:46 UTC 2021


Hi Lorenzo,

> what will it happen if pinctrl learns a different MAC for the given IP after the CMS has
configured the static binding? Will it be overwritten? If so I guess we need a
flag to avoid it.

1. Static binding will be overwritten by pinctrl.
2. Northd will again overwrite this and propagate the value that is statically configured. Eventual state of the system is the configuration from CMS.

If I have to introduce a flag to prioritize one over the other, I also need to remember the state as to which entries are static.

Option 1:
- NB MAC_Binding has new columns: is_static: boolean, options:allow_override=boolean
- SB MAC_Binding has new columns: is_static: boolean, options:allow_override=boolean
- pinctrl logic would look something like
sb->is_static && sb->allow_override {
  update_mac
}
- build_mac_binding_table will have to change. When an entry is removed from NB it has to also cleanup the corresponding SB entry in order to not leave behind and static entries. Something like what build_datapaths is doing. I think this iteration is expensive. Linear in terms of the number of MAC_Binding entries.

Option 2:
- Add a separate SB Static_MAC_Binding table. Now the iteration is linear in terms of the number of Static_MAC_Binding entries.
- Have the get_arp function look at both SB tables and prioritize based on some flag.

What do you recommend? Do you have any alternatives in mind?

Thank You,
Karthik C

On 11/3/21, 10:13 AM, "Lorenzo Bianconi" <lorenzo.bianconi at redhat.com> wrote:
> Hi Lorenzo,
>
> Thanks for the review. Do we need a flag to control statically added MACs from CMS vs dynamically learnt MAC from pinctrl for a given IP?

Yes, I think so.

>
> Typically static configurations for a MAC Table override dynamically learnt MACs. In this patch even if pinctrl learns a different MAC for the given IP, statically configured MAC will eventually be programmed.

what will it happen if pinctrl learns a different MAC for the given IP after the CMS has
configured the static binding? Will it be overwritten? If so I guess we need a
flag to avoid it.

Regards,
Lorenzo

>
> Thank You,
> Karthik C
>
> On 10/25/21, 2:53 AM, "Lorenzo Bianconi" <lorenzo.bianconi at redhat.com<mailto:lorenzo.bianconi at redhat.com>> wrote:
> > From: Karthik Chandrashekar <karthik.c at nutanix.com<mailto:karthik.c at nutanix.com><mailto:karthik.c at nutanix.com><mailto:karthik.c at nutanix.com%3e>>
> >
>
> [...]
> >
> > +static void
> > +build_mac_binding_table(struct northd_context *ctx, struct hmap *ports)
> > +{
> > +    const struct nbrec_mac_binding *nb_mac_binding;
> > +    NBREC_MAC_BINDING_FOR_EACH (nb_mac_binding, ctx->ovnnb_idl) {
> > +        struct ovn_port *op = ovn_port_find(
> > +            ports, nb_mac_binding->logical_port);
> > +        if (op && op->nbrp) {
> > +            struct ovn_datapath *od = op->od;
> > +            if (od && od->sb) {
> > +                const struct sbrec_mac_binding *mb =
> > +                    mac_binding_lookup(ctx->sbrec_mac_binding_by_lport_ip,
> > +                                       nb_mac_binding->logical_port,
> > +                                       nb_mac_binding->ip);
> > +                if (!mb) {
> > +                    mb = sbrec_mac_binding_insert(ctx->ovnsb_txn);
> > +                    sbrec_mac_binding_set_logical_port(
> > +                        mb, nb_mac_binding->logical_port);
> > +                    sbrec_mac_binding_set_ip(mb, nb_mac_binding->ip);
> > +                    sbrec_mac_binding_set_mac(mb, nb_mac_binding->mac);
> > +                    sbrec_mac_binding_set_datapath(mb, od->sb);
> > +                } else {
> > +                    sbrec_mac_binding_set_mac(mb, nb_mac_binding->mac);
> > +                }
>
> I guess we should add some flags here to consider the case both the user/CMS
> adds a static mac binding and pinctrl discovers the same IP address. What do
> you think?
>
> > +            }
> > +        }
> > +    }
> > +}
> > +
> >  /* Returns a string of the IP address of the router port 'op' that
> >   * overlaps with 'ip_s".  If one is not found, returns NULL.
> >   *
> > @@ -14465,6 +14495,7 @@ ovnnb_db_run(struct northd_context *ctx,
> >      build_mcast_groups(ctx, datapaths, ports, &mcast_groups, &igmp_groups);
> >      build_meter_groups(ctx, &meter_groups);
> >      build_bfd_table(ctx, &bfd_connections, ports);
> > +    build_mac_binding_table(ctx, ports);
> >      stopwatch_stop(BUILD_LFLOWS_CTX_STOPWATCH_NAME, time_msec());
> >      stopwatch_start(BUILD_LFLOWS_STOPWATCH_NAME, time_msec());
> >      build_lflows(ctx, datapaths, ports, &port_groups, &mcast_groups,
> > diff --git a/northd/northd.h b/northd/northd.h
> > index ffa2bbb4e..59f407332 100644
> > --- a/northd/northd.h
> > +++ b/northd/northd.h
> > @@ -27,6 +27,7 @@ struct northd_context {
> >      struct ovsdb_idl_index *sbrec_ha_chassis_grp_by_name;
> >      struct ovsdb_idl_index *sbrec_mcast_group_by_name_dp;
> >      struct ovsdb_idl_index *sbrec_ip_mcast_by_dp;
> > +    struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip;
> >
> >      bool use_parallel_build;
> >  };
> > diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
> > index 39aa96055..5fba98812 100644
> > --- a/northd/ovn-northd.c
> > +++ b/northd/ovn-northd.c
> > @@ -23,6 +23,7 @@
> >  #include "daemon.h"
> >  #include "fatal-signal.h"
> >  #include "lib/ip-mcast-index.h"
> > +#include "lib/mac-binding-index.h"
> >  #include "lib/mcast-group-index.h"
> >  #include "memory.h"
> >  #include "northd.h"
> > @@ -904,6 +905,9 @@ main(int argc, char *argv[])
> >      struct ovsdb_idl_index *sbrec_ip_mcast_by_dp
> >          = ip_mcast_index_create(ovnsb_idl_loop.idl);
> >
> > +    struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip
> > +        = mac_binding_index_create(ovnsb_idl_loop.idl);
> > +
> >      unixctl_command_register("sb-connection-status", "", 0, 0,
> >                               ovn_conn_show, ovnsb_idl_loop.idl);
> >
> > @@ -959,6 +963,7 @@ main(int argc, char *argv[])
> >                  .sbrec_ha_chassis_grp_by_name = sbrec_ha_chassis_grp_by_name,
> >                  .sbrec_mcast_group_by_name_dp = sbrec_mcast_group_by_name_dp,
> >                  .sbrec_ip_mcast_by_dp = sbrec_ip_mcast_by_dp,
> > +                .sbrec_mac_binding_by_lport_ip = sbrec_mac_binding_by_lport_ip,
> >                  .use_parallel_build = use_parallel_build,
> >              };
> >
> > diff --git a/northd/ovn_northd.dl b/northd/ovn_northd.dl
> > index 99772932d..0e96b5de1 100644
> > --- a/northd/ovn_northd.dl
> > +++ b/northd/ovn_northd.dl
> > @@ -1018,6 +1018,15 @@ sb::Out_MAC_Binding (._uuid        = mb._uuid,
> >      sb::Out_Port_Binding(.logical_port = mb.logical_port),
> >      sb::Out_Datapath_Binding(._uuid = mb.datapath).
> >
> > +sb::Out_MAC_Binding (._uuid        = hash,
> > +                    .logical_port = nb.logical_port,
> > +                    .ip           = nb.ip,
> > +                    .mac          = nb.mac,
> > +                    .datapath     = router._uuid) :-
> > +    nb in nb::MAC_Binding(),
> > +    rp in &RouterPort(.router = router, .json_name = json_escape(nb.logical_port)),
> > +    var hash = hash128((nb.logical_port, nb.ip)).
> > +
> >  /*
> >   * DHCP options: fixed table
> >   */
> > diff --git a/ovn-nb.ovsschema b/ovn-nb.ovsschema
> > index 5dee04fe9..27dc91438 100644
> > --- a/ovn-nb.ovsschema
> > +++ b/ovn-nb.ovsschema
> > @@ -1,7 +1,7 @@
> >  {
> >      "name": "OVN_Northbound",
> > -    "version": "5.33.1",
> > -    "cksum": "1931852754 30731",
> > +    "version": "5.34.0",
> > +    "cksum": "1872933846 30998",
> >      "tables": {
> >          "NB_Global": {
> >              "columns": {
> > @@ -595,5 +595,12 @@
> >                      "type": {"key": "string", "value": "string",
> >                               "min": 0, "max": "unlimited"}}},
> >              "indexes": [["logical_port", "dst_ip"]],
> > -            "isRoot": true}}
> > +            "isRoot": true},
> > +        "MAC_Binding": {
> > +            "columns": {
> > +                "logical_port": {"type": "string"},
> > +                "ip": {"type": "string"},
> > +                "mac": {"type": "string"}},
> > +            "indexes": [["logical_port", "ip"]],
> > +             "isRoot": true}}
>
> nit: fix indentation here
>
> > Add a new NB MAC_Binding table. This allows programming of
> > static mac_bindings for a logical_router. OVN northd is
> > responsible for propagating these static entries to the
> > existing SB MAC_Binding table.
> >
> > Signed-off-by: Karthik Chandrashekar <karthik.c at nutanix.com<mailto:karthik.c at nutanix.com><mailto:karthik.c at nutanix.com><mailto:karthik.c at nutanix.com%3e>>
> > ---
> >  controller/pinctrl.c    |  20 +----
> >  lib/automake.mk         |   2 +
> >  lib/mac-binding-index.c |  43 +++++++++
> >  lib/mac-binding-index.h |  29 ++++++
> >  northd/northd.c         |  31 +++++++
> >  northd/northd.h         |   1 +
> >  northd/ovn-northd.c     |   5 ++
> >  northd/ovn_northd.dl    |   9 ++
> >  ovn-nb.ovsschema        |  13 ++-
> >  ovn-nb.xml              |  25 ++++++
> >  tests/ovn-nbctl.at      |  69 ++++++++++++++
> >  tests/ovn-northd.at     |  26 ++++++
> >  utilities/ovn-nbctl.c   | 193 +++++++++++++++++++++++++++++++++++++++-
> >  13 files changed, 441 insertions(+), 25 deletions(-)
> >  create mode 100644 lib/mac-binding-index.c
> >  create mode 100644 lib/mac-binding-index.h
> >
> > diff --git a/controller/pinctrl.c b/controller/pinctrl.c
> > index 7d01b18a3..af12909fa 100644
> > --- a/controller/pinctrl.c
> > +++ b/controller/pinctrl.c
> > @@ -48,6 +48,7 @@
> >  #include "ovn/lex.h"
> >  #include "lib/acl-log.h"
> >  #include "lib/ip-mcast-index.h"
> > +#include "lib/mac-binding-index.h"
> >  #include "lib/mcast-group-index.h"
> >  #include "lib/ovn-l7.h"
> >  #include "lib/ovn-util.h"
> > @@ -4090,25 +4091,6 @@ send_mac_binding_buffered_pkts(struct rconn *swconn)
> >      ovs_list_init(&buffered_mac_bindings);
> >  }
> >
> > -static const struct sbrec_mac_binding *
> > -mac_binding_lookup(struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip,
> > -                   const char *logical_port,
> > -                   const char *ip)
> > -{
> > -    struct sbrec_mac_binding *mb = sbrec_mac_binding_index_init_row(
> > -        sbrec_mac_binding_by_lport_ip);
> > -    sbrec_mac_binding_index_set_logical_port(mb, logical_port);
> > -    sbrec_mac_binding_index_set_ip(mb, ip);
> > -
> > -    const struct sbrec_mac_binding *retval
> > -        = sbrec_mac_binding_index_find(sbrec_mac_binding_by_lport_ip,
> > -                                       mb);
> > -
> > -    sbrec_mac_binding_index_destroy_row(mb);
> > -
> > -    return retval;
> > -}
> > -
> >  /* Update or add an IP-MAC binding for 'logical_port'.
> >   * Caller should make sure that 'ovnsb_idl_txn' is valid. */
> >  static void
> > diff --git a/lib/automake.mk b/lib/automake.mk
> > index 9f9f447d5..b58acf1d0 100644
> > --- a/lib/automake.mk
> > +++ b/lib/automake.mk
> > @@ -21,6 +21,8 @@ lib_libovn_la_SOURCES = \
> >             lib/ovn-parallel-hmap.c \
> >             lib/ip-mcast-index.c \
> >             lib/ip-mcast-index.h \
> > +          lib/mac-binding-index.c \
> > +          lib/mac-binding-index.h \
> >             lib/mcast-group-index.c \
> >             lib/mcast-group-index.h \
> >             lib/lex.c \
> > diff --git a/lib/mac-binding-index.c b/lib/mac-binding-index.c
> > new file mode 100644
> > index 000000000..1d34dfbdc
> > --- /dev/null
> > +++ b/lib/mac-binding-index.c
> > @@ -0,0 +1,43 @@
> > +/* Copyright (c) 2021
> > + *
> > + * Licensed under the Apache License, Version 2.0 (the "License");
> > + * you may not use this file except in compliance with the License.
> > + * You may obtain a copy of the License at:
> > + *
> > + *     http://www.apache.org/licenses/LICENSE-2.0
> > + *
> > + * Unless required by applicable law or agreed to in writing, software
> > + * distributed under the License is distributed on an "AS IS" BASIS,
> > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> > + * See the License for the specific language governing permissions and
> > + * limitations under the License.
> > + */
> > +
> > +#include <config.h>
> > +
> > +#include "lib/mac-binding-index.h"
> > +#include "lib/ovn-sb-idl.h"
> > +
> > +struct ovsdb_idl_index *
> > +mac_binding_index_create(struct ovsdb_idl *idl)
> > +{
> > +    return ovsdb_idl_index_create2(idl,
> > +                                   &sbrec_mac_binding_col_logical_port,
> > +                                   &sbrec_mac_binding_col_ip);
> > +}
> > +
> > +const struct sbrec_mac_binding *
> > +mac_binding_lookup(struct ovsdb_idl_index *mac_binding_index,
> > +                   const char *logical_port, const char *ip)
> > +{
> > +    struct sbrec_mac_binding *target = sbrec_mac_binding_index_init_row(
> > +        mac_binding_index);
> > +    sbrec_mac_binding_index_set_logical_port(target, logical_port);
> > +    sbrec_mac_binding_index_set_ip(target, ip);
> > +
> > +    struct sbrec_mac_binding *mac_binding =
> > +        sbrec_mac_binding_index_find(mac_binding_index, target);
> > +    sbrec_mac_binding_index_destroy_row(target);
> > +
> > +    return mac_binding;
> > +}
> > diff --git a/lib/mac-binding-index.h b/lib/mac-binding-index.h
> > new file mode 100644
> > index 000000000..d7434f688
> > --- /dev/null
> > +++ b/lib/mac-binding-index.h
> > @@ -0,0 +1,29 @@
> > +/* Copyright (c) 2021
> > + *
> > + * Licensed under the Apache License, Version 2.0 (the "License");
> > + * you may not use this file except in compliance with the License.
> > + * You may obtain a copy of the License at:
> > + *
> > + *     http://www.apache.org/licenses/LICENSE-2.0
> > + *
> > + * Unless required by applicable law or agreed to in writing, software
> > + * distributed under the License is distributed on an "AS IS" BASIS,
> > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> > + * See the License for the specific language governing permissions and
> > + * limitations under the License.
> > + */
> > +
> > +#ifndef OVN_MAC_BINDING_INDEX_H
> > +#define OVN_MAC_BINDING_INDEX_H 1
> > +
> > +struct ovsdb_idl;
> > +
> > +struct sbrec_datapath_binding;
> > +
> > +struct ovsdb_idl_index *mac_binding_index_create(struct ovsdb_idl *);
> > +const struct sbrec_mac_binding *mac_binding_lookup(
> > +    struct ovsdb_idl_index *mac_binding_index,
> > +    const char *logical_port,
> > +    const char *ip);
> > +
> > +#endif /* lib/mac-binding-index.h */
> > diff --git a/northd/northd.c b/northd/northd.c
> > index 0bf66e0b2..b2270fd0e 100644
> > --- a/northd/northd.c
> > +++ b/northd/northd.c
> > @@ -29,6 +29,7 @@
> >  #include "lib/chassis-index.h"
> >  #include "lib/ip-mcast-index.h"
> >  #include "lib/copp.h"
> > +#include "lib/mac-binding-index.h"
> >  #include "lib/mcast-group-index.h"
> >  #include "lib/ovn-l7.h"
> >  #include "lib/ovn-nb-idl.h"
> > @@ -8368,6 +8369,35 @@ build_bfd_table(struct northd_context *ctx, struct hmap *bfd_connections,
> >      bitmap_free(bfd_src_ports);
> >  }
> >      }
> > diff --git a/ovn-nb.xml b/ovn-nb.xml
> > index e31578fb6..327039d95 100644
> > --- a/ovn-nb.xml
> > +++ b/ovn-nb.xml
> > @@ -4130,4 +4130,29 @@
> >        </column>
> >      </group>
> >    </table>
> > +
> > +  <table name="MAC_Binding">
> > +    <p>
> > +      Each record represents a MAC Binding entry.
> > +    </p>
> > +
> > +    <group title="Configuration">
> > +      <p>
> > +        <code>ovn-northd</code> reads configuration from these columns
> > +        and propagates the value to SBDB.
> > +      </p>
> > +
> > +      <column name="logical_port">
> > +        The logical port on which the binding was discovered.
> > +      </column>
> > +
> > +      <column name="ip">
> > +        The bound IP address.
> > +      </column>
> > +
> > +      <column name="mac">
> > +        The Ethernet address to which the IP is bound.
> > +      </column>
> > +    </group>
> > +  </table>
> >  </database>
> > diff --git a/tests/ovn-nbctl.at b/tests/ovn-nbctl.at
> > index 9b80ae410..673c9637d 100644
> > --- a/tests/ovn-nbctl.at
> > +++ b/tests/ovn-nbctl.at
> > @@ -2057,6 +2057,75 @@ AT_CHECK([ovn-nbctl list forwarding_group], [0], [])
> >
> >  dnl ---------------------------------------------------------------------
> >
> > +OVN_NBCTL_TEST([ovn_nbctl_mac_binding], [lr mac_binding], [
> > +
> > +AT_CHECK([ovn-nbctl lr-add lr0])
> > +AT_CHECK([ovn-nbctl lrp-add lr0 lr0-p0 00:00:01:01:02:03 192.168.10.1/24])
> > +AT_CHECK([ovn-nbctl lrp-add lr0 lr0-p1 00:00:02:02:03:04 192.168.11.1/24])
> > +
> > +AT_CHECK([ovn-nbctl mac-binding-add lr0-p0 192.168.10.10 00:00:11:22:33:44])
> > +AT_CHECK([ovn-nbctl mac-binding-add lr0-p0 192.168.10.100 00:00:22:33:44:55])
> > +AT_CHECK([ovn-nbctl mac-binding-add lr0-p0 10.0.0.10 00:00:33:44:55:66])
> > +AT_CHECK([ovn-nbctl mac-binding-add lr0-p0 172.16.0.11 00:00:44:55:66:88])
> > +
> > +AT_CHECK([ovn-nbctl mac-binding-add lr0-p0 foo 00:00:44:55:66:88], [1], [],
> > +  [ovn-nbctl: foo: Not a valid IPv4 or IPv6 address.
> > +])
> > +AT_CHECK([ovn-nbctl mac-binding-add lr0-p0 172.16.0.200 foo], [1], [],
> > +  [ovn-nbctl: invalid mac address foo.
> > +])
> > +AT_CHECK([ovn-nbctl mac-binding-add lr0-p0 172.16.0.11 00:00:44:55:66:77], [1], [],
> > +  [ovn-nbctl: lr0-p0, 172.16.0.11: a MAC_Binding with this logical_port and ip already exists
> > +])
> > +
> > +AT_CHECK([ovn-nbctl --may-exist mac-binding-add lr0-p0 172.16.0.11 00:00:44:55:66:77])
> > +
> > +AT_CHECK([ovn-nbctl mac-binding-add lr0-p1 10.0.0.10 00:00:33:44:55:66])
> > +AT_CHECK([ovn-nbctl mac-binding-add lr0-p1 172.16.0.11 00:00:44:55:66:88])
> > +
> > +AT_CHECK([ovn-nbctl mac-binding-list], [0], [dnl
> > +LOGICAL_PORT             IP                       MAC
> > +lr0-p0                   10.0.0.10                00:00:33:44:55:66
> > +lr0-p0                   172.16.0.11              00:00:44:55:66:77
> > +lr0-p0                   192.168.10.10            00:00:11:22:33:44
> > +lr0-p0                   192.168.10.100           00:00:22:33:44:55
> > +lr0-p1                   10.0.0.10                00:00:33:44:55:66
> > +lr0-p1                   172.16.0.11              00:00:44:55:66:88
> > +])
> > +
> > +AT_CHECK([ovn-nbctl mac-binding-del lr0-p0 foo], [1], [],
> > +  [ovn-nbctl: foo: Not a valid IPv4 or IPv6 address.
> > +])
> > +
> > +AT_CHECK([ovn-nbctl mac-binding-del lr0-p1 10.0.0.100], [1], [],
> > +  [ovn-nbctl: no matching MAC_Binding with port (lr0-p1) and ip (10.0.0.100)
> > +])
> > +
> > +AT_CHECK([ovn-nbctl --if-exists mac-binding-del lr0-p1 10.0.0.100])
> > +
> > +AT_CHECK([ovn-nbctl mac-binding-del lr0-p0 10.0.0.10])
> > +AT_CHECK([ovn-nbctl mac-binding-del lr0-p0 192.168.10.100])
> > +
> > +AT_CHECK([ovn-nbctl mac-binding-list], [0], [dnl
> > +LOGICAL_PORT             IP                       MAC
> > +lr0-p0                   172.16.0.11              00:00:44:55:66:77
> > +lr0-p0                   192.168.10.10            00:00:11:22:33:44
> > +lr0-p1                   10.0.0.10                00:00:33:44:55:66
> > +lr0-p1                   172.16.0.11              00:00:44:55:66:88
> > +])
> > +
> > +AT_CHECK([ovn-nbctl mac-binding-del lr0-p1 10.0.0.10])
> > +AT_CHECK([ovn-nbctl mac-binding-list], [0], [dnl
> > +LOGICAL_PORT             IP                       MAC
> > +lr0-p0                   172.16.0.11              00:00:44:55:66:77
> > +lr0-p0                   192.168.10.10            00:00:11:22:33:44
> > +lr0-p1                   172.16.0.11              00:00:44:55:66:88
> > +])
> > +
> > +])
> > +
> > +dnl ---------------------------------------------------------------------
> > +
> >  OVN_NBCTL_TEST([ovn_nbctl_negative], [basic negative tests], [
> >  AT_CHECK([ovn-nbctl --id=@ls create logical_switch name=foo -- \
> >            set logical_switch foo1 name=bar],
> > diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
> > index 8b9049899..2e6a51f2e 100644
> > --- a/tests/ovn-northd.at
> > +++ b/tests/ovn-northd.at
> > @@ -5401,3 +5401,29 @@ AT_CHECK([grep lr_in_gw_redirect lrflows | grep cr-DR | sed 's/table=../table=??
> >
> >  AT_CLEANUP
> >  ])
> > +
> > +OVN_FOR_EACH_NORTHD([
> > +AT_SETUP([LR NB MAC_Binding table])
> > +ovn_start
> > +
> > +# Create logical routers
> > +ovn-nbctl lr-add lr0
> > +ovn-nbctl lrp-add lr0 lr0-p0 00:00:01:01:02:03 192.168.10.1/24
> > +ovn-nbctl lrp-add lr0 lr0-p1 00:00:02:02:03:04 192.168.11.1/24
> > +
> > +ovn-nbctl mac-binding-add lr0-p0 192.168.10.10 00:00:11:22:33:44
> > +ovn-nbctl mac-binding-add lr0-p0 192.168.10.100 00:00:22:33:44:55
> > +
> > +wait_row_count nb:MAC_Binding 2 logical_port=lr0-p0
> > +wait_row_count MAC_Binding 1 logical_port=lr0-p0 ip=192.168.10.10 mac="00\:00\:11\:22\:33\:44"
> > +wait_row_count MAC_Binding 1 logical_port=lr0-p0 ip=192.168.10.100 mac="00\:00\:22\:33\:44\:55"
> > +
> > +ovn-nbctl mac-binding-add lr0-p1 10.0.0.10 00:00:33:44:55:66
> > +wait_row_count nb:MAC_Binding 1 logical_port=lr0-p1
> > +wait_row_count MAC_Binding 1 logical_port=lr0-p1 ip=10.0.0.10 mac="00\:00\:33\:44\:55\:66"
> > +
> > +ovn-nbctl --may-exist mac-binding-add lr0-p0 192.168.10.100 00:00:22:33:55:66
> > +wait_row_count MAC_Binding 1 logical_port=lr0-p0 ip=192.168.10.100 mac="00\:00\:22\:33\:55\:66"
> > +
> > +AT_CLEANUP
> > +])
> > diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c
> > index b04b24d4b..527fe1644 100644
> > --- a/utilities/ovn-nbctl.c
> > +++ b/utilities/ovn-nbctl.c
> > @@ -365,7 +365,8 @@ Policy commands:\n\
> >    lr-policy-del ROUTER [{PRIORITY | UUID} [MATCH]]\n\
> >                              remove policies from ROUTER\n\
> >    lr-policy-list ROUTER     print policies for ROUTER\n\
> > -\n\
> > +\n\n",program_name, program_name);
> > +    printf("\
> >  NAT commands:\n\
> >    [--stateless]\n\
> >    [--portrange]\n\
> > @@ -408,8 +409,7 @@ Connection commands:\n\
> >    del-connection             delete the connections\n\
> >    [--inactivity-probe=MSECS]\n\
> >    set-connection TARGET...   set the list of connections to TARGET...\n\
> > -\n\n",program_name, program_name);
> > -    printf("\
> > +\n\
> >  SSL commands:\n\
> >    get-ssl                     print the SSL configuration\n\
> >    del-ssl                     delete the SSL configuration\n\
> > @@ -450,6 +450,13 @@ Control Plane Protection Policy commands:\n\
> >                              List all copp policies defined for control\n\
> >                              protocols on ROUTER.\n\
> >  \n\
> > +MAC_Binding commands:\n\
> > +  mac-binding-add LOGICAL_PORT IP MAC \n\
> > +                                    Add a MAC_Binding entry\n\
> > +  mac-binding-del LOGICAL_PORT IP \n\
> > +                                    Delete MAC_Binding entry\n\
> > +  mac-binding-list                  List all MAC_Binding \n\
> > +\n\
> >  %s\
> >  %s\
> >  \n\
> > @@ -5602,6 +5609,176 @@ nbctl_lrp_get_redirect_type(struct ctl_context *ctx)
> >                    !redirect_type ? "overlay": redirect_type);
> >  }
> >
> > +static const struct nbrec_mac_binding *
> > +mac_binding_by_port_ip(struct ctl_context *ctx,
> > +                           const char *logical_port, const char *ip)
> > +{
> > +    const struct nbrec_mac_binding *nb_mac_binding = NULL;
> > +
> > +    NBREC_MAC_BINDING_FOR_EACH(nb_mac_binding, ctx->idl) {
> > +        if (!strcmp(nb_mac_binding->logical_port, logical_port) &&
> > +            !strcmp(nb_mac_binding->ip, ip)) {
> > +            break;
> > +        }
> > +    }
> > +
> > +    return nb_mac_binding;
> > +}
> > +
> > +static void
> > +nbctl_pre_mac_binding_add(struct ctl_context *ctx)
> > +{
> > +    ovsdb_idl_add_column(ctx->idl, &nbrec_logical_router_port_col_name);
> > +
> > +    ovsdb_idl_add_column(ctx->idl, &nbrec_mac_binding_col_logical_port);
> > +    ovsdb_idl_add_column(ctx->idl, &nbrec_mac_binding_col_ip);
> > +    ovsdb_idl_add_column(ctx->idl, &nbrec_mac_binding_col_mac);
> > +}
> > +
> > +static void
> > +nbctl_mac_binding_add(struct ctl_context *ctx)
> > +{
> > +    const char *logical_port = ctx->argv[1];
> > +    const char *ip = ctx->argv[2];
> > +    const char *mac = ctx->argv[3];
> > +    char *new_ip = NULL;
> > +
> > +    const struct nbrec_logical_router_port *lrp;
> > +    char *error = lrp_by_name_or_uuid(ctx, logical_port, true, &lrp);
> > +    if (error) {
> > +        ctx->error = error;
> > +        goto cleanup;
> > +    }
> > +
> > +    new_ip = normalize_addr_str(ip);
> > +    if (!new_ip) {
> > +        ctl_error(ctx, "%s: Not a valid IPv4 or IPv6 address.", ip);
> > +        return;
> > +    }
> > +
> > +    struct eth_addr ea;
> > +    if (!eth_addr_from_string(mac, &ea)) {
> > +        ctl_error(ctx, "invalid mac address %s.", mac);
> > +        goto cleanup;
> > +    }
> > +
> > +    bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
> > +    const struct nbrec_mac_binding *nb_mac_binding = mac_binding_by_port_ip(
> > +        ctx, logical_port, ip);
> > +    if (nb_mac_binding) {
> > +        char *old_ip;
> > +        bool should_return = false;
> > +        old_ip = normalize_addr_str(nb_mac_binding->ip);
> > +
> > +        if (!strcmp(nb_mac_binding->logical_port, logical_port)) {
> > +            if (!strcmp(old_ip, new_ip)) {
> > +                if (may_exist) {
> > +                    nbrec_mac_binding_verify_mac(nb_mac_binding);
> > +                    nbrec_mac_binding_set_mac(nb_mac_binding, mac);
> > +                    should_return = true;
> > +                } else {
> > +                    ctl_error(ctx, "%s, %s: a MAC_Binding with this "
> > +                              "logical_port and ip already exists",
> > +                              logical_port, new_ip);
> > +                    should_return = true;
> > +                }
> > +            }
> > +        }
> > +        free(old_ip);
> > +        if (should_return) {
> > +            goto cleanup;
> > +        }
> > +    }
> > +
> > +    /* Create MAC_Binding entry */
> > +    nb_mac_binding = nbrec_mac_binding_insert(ctx->txn);
> > +    nbrec_mac_binding_set_logical_port(nb_mac_binding, logical_port);
> > +    nbrec_mac_binding_set_ip(nb_mac_binding, new_ip);
> > +    nbrec_mac_binding_set_mac(nb_mac_binding, mac);
> > +
> > +cleanup:
> > +    free(new_ip);
> > +}
> > +
> > +static void
> > +nbctl_pre_mac_binding_del(struct ctl_context *ctx)
> > +{
> > +    ovsdb_idl_add_column(ctx->idl, &nbrec_logical_router_port_col_name);
> > +
> > +    ovsdb_idl_add_column(ctx->idl, &nbrec_mac_binding_col_logical_port);
> > +    ovsdb_idl_add_column(ctx->idl, &nbrec_mac_binding_col_ip);
> > +    ovsdb_idl_add_column(ctx->idl, &nbrec_mac_binding_col_mac);
> > +}
> > +
> > +static void
> > +nbctl_mac_binding_del(struct ctl_context *ctx)
> > +{
> > +    bool must_exist = !shash_find(&ctx->options, "--if-exists");
> > +    const char *logical_port = ctx->argv[1];
> > +    const struct nbrec_logical_router_port *lrp;
> > +    char *error = lrp_by_name_or_uuid(ctx, logical_port, true, &lrp);
> > +    if (error) {
> > +        ctx->error = error;
> > +        return;
> > +    }
> > +
> > +    char *ip = normalize_addr_str(ctx->argv[2]);
> > +    if (!ip) {
> > +        ctl_error(ctx, "%s: Not a valid IPv4 or IPv6 address.", ctx->argv[2]);
> > +        return;
> > +    }
> > +
> > +    const struct nbrec_mac_binding *nb_mac_binding = mac_binding_by_port_ip(
> > +        ctx, logical_port, ip);
> > +
> > +    if (nb_mac_binding) {
> > +        /* Remove the matching MAC_Binding. */
> > +        nbrec_mac_binding_delete(nb_mac_binding);
> > +        goto cleanup;
> > +    }
> > +
> > +    if (must_exist) {
> > +        ctl_error(ctx, "no matching MAC_Binding with port (%s) and ip (%s)",
> > +                  logical_port, ip);
> > +    }
> > +
> > +cleanup:
> > +    free(ip);
> > +}
> > +
> > +static void
> > +nbctl_pre_mac_binding_list(struct ctl_context *ctx)
> > +{
> > +    ovsdb_idl_add_column(ctx->idl, &nbrec_logical_router_col_name);
> > +
> > +    ovsdb_idl_add_column(ctx->idl, &nbrec_mac_binding_col_logical_port);
> > +    ovsdb_idl_add_column(ctx->idl, &nbrec_mac_binding_col_ip);
> > +    ovsdb_idl_add_column(ctx->idl, &nbrec_mac_binding_col_mac);
> > +}
> > +
> > +static void
> > +nbctl_mac_binding_list(struct ctl_context *ctx)
> > +{
> > +    struct smap lr_mac_bindings = SMAP_INITIALIZER(&lr_mac_bindings);
> > +    const struct nbrec_mac_binding *nb_mac_binding = NULL;
> > +    NBREC_MAC_BINDING_FOR_EACH(nb_mac_binding, ctx->idl) {
> > +        char *key = xasprintf("%-25s%-25s", nb_mac_binding->logical_port,
> > +                              nb_mac_binding->ip);
> > +        smap_add_format(&lr_mac_bindings, key, "%s", nb_mac_binding->mac);
> > +        free(key);
> > +    }
> > +
> > +    const struct smap_node **nodes = smap_sort(&lr_mac_bindings);
> > +    if (nodes) {
> > +        ds_put_format(&ctx->output, "%-25s%-25s%s\n",
> > +                      "LOGICAL_PORT", "IP", "MAC");
> > +        for (size_t i = 0; i < smap_count(&lr_mac_bindings); i++) {
> > +            const struct smap_node *node = nodes[i];
> > +            ds_put_format(&ctx->output, "%-25s%s\n", node->key, node->value);
> > +        }
> > +    }
> > +}
> > +
> >  static const struct nbrec_forwarding_group *
> >  fwd_group_by_name_or_uuid(struct ctl_context *ctx, const char *id)
> >  {
> > @@ -7063,6 +7240,16 @@ static const struct ctl_command_syntax nbctl_commands[] = {
> >       pre_ha_ch_grp_set_chassis_prio, cmd_ha_ch_grp_set_chassis_prio, NULL,
> >       "", RW },
> >
> > +    /* MAC_Binding commands */
> > +    { "mac-binding-add", 3, 3, "LOGICAL_PORT IP MAC",
> > +      nbctl_pre_mac_binding_add, nbctl_mac_binding_add, NULL,
> > +      "--may-exist", RW },
> > +    { "mac-binding-del", 2, 2, "LOGICAL_PORT IP",
> > +      nbctl_pre_mac_binding_del, nbctl_mac_binding_del,
> > +      NULL, "--if-exists", RW },
> > +    { "mac-binding-list", 0, 1, "[LOGICAL_PORT]",
> > +      nbctl_pre_mac_binding_list, nbctl_mac_binding_list, NULL, "", RO },
> > +
> >      {NULL, 0, 0, NULL, NULL, NULL, NULL, "", RO},
> >  };
> >
> > --
> > 2.25.1
> >
> > _______________________________________________
> > dev mailing list
> > dev at openvswitch.org<mailto:dev at openvswitch.org><mailto:dev at openvswitch.org>
> > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
> >
>



More information about the dev mailing list