On Tue, Sep 28, 2021 at 11:54 AM Frode Nordahl
<frode.nord...@canonical.com> wrote:
>
> Up until now the controller patch module has been the only
> consumer of functions to maintain OVS ports and interfaces.
>
> With the introduction of infrastructure for plugging providers
> these functions will also be consumed by the controller binding
> module.
>
> As such we introduce a new module called ovsport where these
> shared utility functions can live and be consumed by multiple
> modules.
>
> Signed-off-by: Frode Nordahl <frode.nord...@canonical.com>

Acked-by: Numan Siddique <num...@ovn.org>


Numan

> ---
>  controller/automake.mk |   4 +-
>  controller/ovsport.c   | 266 +++++++++++++++++++++++++++++++++++++++++
>  controller/ovsport.h   |  60 ++++++++++
>  3 files changed, 329 insertions(+), 1 deletion(-)
>  create mode 100644 controller/ovsport.c
>  create mode 100644 controller/ovsport.h
>
> diff --git a/controller/automake.mk b/controller/automake.mk
> index 41f907d6e..ad2d68af2 100644
> --- a/controller/automake.mk
> +++ b/controller/automake.mk
> @@ -35,7 +35,9 @@ controller_ovn_controller_SOURCES = \
>         controller/mac-learn.c \
>         controller/mac-learn.h \
>         controller/local_data.c \
> -       controller/local_data.h
> +       controller/local_data.h \
> +       controller/ovsport.h \
> +       controller/ovsport.c
>
>  controller_ovn_controller_LDADD = lib/libovn.la 
> $(OVS_LIBDIR)/libopenvswitch.la
>  man_MANS += controller/ovn-controller.8
> diff --git a/controller/ovsport.c b/controller/ovsport.c
> new file mode 100644
> index 000000000..ec38c3fca
> --- /dev/null
> +++ b/controller/ovsport.c
> @@ -0,0 +1,266 @@
> +/* Copyright (c) 2021 Canonical
> + *
> + * 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 "ovsport.h"
> +
> +#include "lib/vswitch-idl.h"
> +#include "openvswitch/vlog.h"
> +
> +VLOG_DEFINE_THIS_MODULE(ovsport);
> +
> +/* Create a port and interface record and add it to 'bridge' in the Open
> + * vSwitch database represented by 'ovs_idl_txn'.
> + *
> + * 'name' is required and is used both for the name of the port and interface
> + * records.  Depending on the contents of the optional 'iface_type' parameter
> + * the name may need to refer to an existing interface in the system.  It is
> + * the caller's responsibility to ensure that no other port with the desired
> + * name already exists.
> + *
> + * 'iface_type' optionally specifies the type of interface, otherwise set it 
> to
> + * NULL.
> + *
> + * 'port_external_ids' - the contents of the map will be used to fill the
> + * external_ids column of the created port record, otherwise set it to NULL.
> + *
> + * 'iface_external_ids' - the contents of the map will be used to fill the
> + * external_ids column of the created interface record, otherwise set it to
> + * NULL.
> + *
> + * 'iface_options' - the contents of the map will be used to fill the options
> + * column of the created interface record, otherwise set it to NULL.
> + *
> + * 'iface_mtu_request' - if a value > 0 is provided it will be filled into 
> the
> + * mtu_request column of the created interface record. */
> +void
> +ovsport_create(struct ovsdb_idl_txn *ovs_idl_txn,
> +               const struct ovsrec_bridge *bridge,
> +               const char *name,
> +               const char *iface_type,
> +               const struct smap *port_external_ids,
> +               const struct smap *iface_external_ids,
> +               const struct smap *iface_options,
> +               const int64_t iface_mtu_request)
> +{
> +    struct ovsrec_interface *iface;
> +    iface = ovsrec_interface_insert(ovs_idl_txn);
> +    ovsrec_interface_set_name(iface, name);
> +    if (iface_type) {
> +        ovsrec_interface_set_type(iface, iface_type);
> +    }
> +    ovsrec_interface_set_external_ids(iface, iface_external_ids);
> +    ovsrec_interface_set_options(iface, iface_options);
> +    ovsrec_interface_set_mtu_request(
> +            iface, &iface_mtu_request, iface_mtu_request > 0);
> +
> +    struct ovsrec_port *port;
> +    port = ovsrec_port_insert(ovs_idl_txn);
> +    ovsrec_port_set_name(port, name);
> +    ovsrec_port_set_interfaces(port, &iface, 1);
> +    ovsrec_port_set_external_ids(port, port_external_ids);
> +
> +    ovsrec_bridge_verify_ports(bridge);
> +    ovsrec_bridge_update_ports_addvalue(bridge, port);
> +}
> +
> +/* Remove 'port' from 'bridge' and delete the 'port' record and any records
> + * with a weakRef to it. */
> +void
> +ovsport_remove(const struct ovsrec_bridge *bridge,
> +               const struct ovsrec_port *port)
> +{
> +    ovsrec_bridge_verify_ports(bridge);
> +    ovsrec_port_verify_interfaces(port);
> +    for (struct ovsrec_interface *iface = *port->interfaces;
> +         iface - *port->interfaces < port->n_interfaces;
> +         iface++) {
> +        ovsrec_interface_delete(iface);
> +    }
> +    ovsrec_bridge_update_ports_delvalue(bridge, port);
> +    ovsrec_port_delete(port);
> +}
> +
> +static void update_interface_smap_column(
> +        const struct ovsrec_interface *, const struct smap *,
> +        const struct smap *, void (*fsetkey)(const struct ovsrec_interface *,
> +                                             const char *, const char *));
> +static void maintain_interface_smap_column(
> +        const struct ovsrec_interface *, const struct sset *,
> +        const struct smap *, const struct smap *,
> +        void (*fsetkey)(const struct ovsrec_interface *, const char *,
> +                        const char *),
> +        void (*fdelkey)(const struct ovsrec_interface *,
> +                         const char *));
> +
> +/* Update interface record as represented by 'iface'.
> + *
> + * 'type' optionally specifies the type of interface, to unset type set to an
> + * empty string, to not update type set to NULL.
> + *
> + * 'external_ids' optionally provide a map of external_ids to update, to not
> + * update external_ids set to NULL.
> + *
> + * 'mnt_external_ids' optionally provide set of 'external_ids' to maintain.
> + * When set the function will make sure that all keys in the 
> 'mnt_external_ids'
> + * set have values from the 'external_ids' map in the database.  Every key 
> that
> + * exists in 'mnt_external_ids' with no corresponding key in 'external_ids'
> + * will be removed from the database if present.  Set to NULL to not maintain
> + * the record in this way.
> + *
> + * 'options' optionally provide a map of options to update, to not
> + * update options set to NULL.
> + *
> + * 'mnt_options' optionally provide set of 'options' to maintain.
> + * When set the function will make sure that all keys in the 'mnt_options' 
> set
> + * have values from the 'options' map in the database.  Every key that exists
> + * in 'mnt_options' with no corresponding key in 'options' will be removed 
> from
> + * the database if present.  Set to NULL to not maintain the record in this
> + * way.
> + *
> + * 'iface_mtu_request' - if a value > 0 is provided it will be filled into 
> the
> + * mtu_request column of the created interface record. */
> +void
> +ovsport_update_iface(const struct ovsrec_interface *iface,
> +                     const char *type,
> +                     const struct smap *external_ids,
> +                     const struct sset *mnt_external_ids,
> +                     const struct smap *options,
> +                     const struct sset *mnt_options,
> +                     const int64_t mtu_request)
> +{
> +    if (type && strcmp(iface->type, type)) {
> +        ovsrec_interface_verify_type(iface);
> +        ovsrec_interface_set_type(iface, type);
> +    }
> +
> +    if (external_ids && mnt_external_ids) {
> +        ovsrec_interface_verify_external_ids(iface);
> +        maintain_interface_smap_column(
> +                iface, mnt_external_ids, external_ids, &iface->external_ids,
> +                ovsrec_interface_update_external_ids_setkey,
> +                ovsrec_interface_update_external_ids_delkey);
> +    } else if (external_ids) {
> +        ovsrec_interface_verify_external_ids(iface);
> +        update_interface_smap_column(
> +                iface, external_ids, &iface->external_ids,
> +                ovsrec_interface_update_external_ids_setkey);
> +    }
> +
> +    if (options && mnt_options) {
> +        ovsrec_interface_verify_options(iface);
> +        maintain_interface_smap_column(
> +                iface, mnt_options, options, &iface->options,
> +                ovsrec_interface_update_options_setkey,
> +                ovsrec_interface_update_options_delkey);
> +    } else if (options) {
> +        ovsrec_interface_verify_options(iface);
> +        update_interface_smap_column(
> +                iface, options, &iface->options,
> +                ovsrec_interface_update_options_setkey);
> +    }
> +
> +    if (mtu_request > 0) {
> +        if ((iface->mtu_request && *iface->mtu_request != mtu_request)
> +            || !iface->mtu_request)
> +        {
> +            ovsrec_interface_verify_mtu_request(iface);
> +            ovsrec_interface_set_mtu_request(
> +                    iface, &mtu_request, mtu_request > 0);
> +        }
> +    } else if (iface->mtu_request) {
> +        ovsrec_interface_verify_mtu_request(iface);
> +        ovsrec_interface_update_mtu_request_delvalue(iface,
> +                                                     *iface->mtu_request);
> +    }
> +}
> +
> +const struct ovsrec_port *
> +ovsport_lookup_by_interfaces(
> +        struct ovsdb_idl_index *ovsrec_port_by_interfaces,
> +        struct ovsrec_interface **interfaces,
> +        const size_t n_interfaces)
> +{
> +    struct ovsrec_port *port = ovsrec_port_index_init_row(
> +            ovsrec_port_by_interfaces);
> +    ovsrec_port_index_set_interfaces(port, interfaces, n_interfaces);
> +
> +    const struct ovsrec_port *retval = ovsrec_port_index_find(
> +            ovsrec_port_by_interfaces, port);
> +
> +    ovsrec_port_index_destroy_row(port);
> +
> +    return retval;
> +}
> +
> +const struct
> +ovsrec_port * ovsport_lookup_by_interface(
> +        struct ovsdb_idl_index *ovsrec_port_by_interfaces,
> +        struct ovsrec_interface *interface)
> +{
> +    struct ovsrec_interface *interfaces[] = {interface};
> +
> +    return ovsport_lookup_by_interfaces(ovsrec_port_by_interfaces,
> +                                        interfaces, 1);
> +}
> +
> +/* Update an interface map column with the key/value pairs present in the
> + * provided smap, only applying changes when necessary. */
> +static void
> +update_interface_smap_column(
> +        const struct ovsrec_interface *iface,
> +        const struct smap *smap,
> +        const struct smap *db_smap,
> +        void (*fsetkey)(const struct ovsrec_interface *,
> +                         const char *, const char *))
> +{
> +    struct smap_node *node;
> +
> +    SMAP_FOR_EACH (node, smap) {
> +        const char *db_value = smap_get(db_smap, node->key);
> +
> +        if (!db_value || strcmp(db_value, node->value)) {
> +            fsetkey(iface, node->key, node->value);
> +        }
> +    }
> +}
> +
> +/* Like update_interface_smap_column, but also takes an sset with all the 
> keys
> + * we want to maintain.  Any key present in the sset but not in the provided
> + * smap will be removed from the database if present there. */
> +static void
> +maintain_interface_smap_column(
> +        const struct ovsrec_interface *iface,
> +        const struct sset *mnt_items,
> +        const struct smap *smap,
> +        const struct smap *db_smap,
> +        void (*fsetkey)(const struct ovsrec_interface *,
> +                         const char *, const char *),
> +        void (*fdelkey)(const struct ovsrec_interface *,
> +                         const char *))
> +{
> +    const char *ref_name;
> +
> +    SSET_FOR_EACH (ref_name, mnt_items) {
> +        const char *value = smap_get(smap, ref_name);
> +        const char *db_value = smap_get(db_smap, ref_name);
> +        if (!value && db_value) {
> +            fdelkey(iface, ref_name);
> +        } else if (value && (!db_value || strcmp(db_value, value)))
> +        {
> +            fsetkey(iface, ref_name, value);
> +        }
> +    }
> +}
> diff --git a/controller/ovsport.h b/controller/ovsport.h
> new file mode 100644
> index 000000000..e355ff7ff
> --- /dev/null
> +++ b/controller/ovsport.h
> @@ -0,0 +1,60 @@
> +/* Copyright (c) 2021 Canonical
> + *
> + * 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 OVSPORT_H
> +#define OVSPORT_H 1
> +
> +/* OVS Ports
> + * =========
> + *
> + * This module contains utility functions for adding, removing and 
> maintaining
> + * ports and their interface records on OVS bridges. */
> +
> +#include "smap.h"
> +#include "sset.h"
> +
> +#include <stdbool.h>
> +#include <stdint.h>
> +
> +struct ovsdb_idl_txn;
> +struct ovsrec_bridge;
> +struct ovsrec_port;
> +struct ovsrec_interface;
> +struct ovsdb_idl_index;
> +
> +void ovsport_create(struct ovsdb_idl_txn *ovs_idl_txn,
> +                    const struct ovsrec_bridge *bridge,
> +                    const char *name,
> +                    const char *iface_type,
> +                    const struct smap *port_external_ids,
> +                    const struct smap *iface_external_ids,
> +                    const struct smap *iface_options,
> +                    const int64_t iface_mtu_request);
> +void ovsport_remove(const struct ovsrec_bridge *bridge,
> +                    const struct ovsrec_port *port);
> +void ovsport_update_iface(const struct ovsrec_interface *iface,
> +                          const char *type,
> +                          const struct smap *external_ids,
> +                          const struct sset *mnt_external_ids,
> +                          const struct smap *options,
> +                          const struct sset *mnt_options,
> +                          const int64_t mtu_request);
> +const struct ovsrec_port * ovsport_lookup_by_interfaces(
> +        struct ovsdb_idl_index *, struct ovsrec_interface **,
> +        const size_t n_interfaces);
> +const struct ovsrec_port * ovsport_lookup_by_interface(
> +        struct ovsdb_idl_index *, struct ovsrec_interface *);
> +
> +#endif /* lib/ovsport.h */
> --
> 2.32.0
>
> _______________________________________________
> 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

Reply via email to