On 11 Mar 2022, at 3:14, Chris Mi wrote:

> On 2022-03-04 6:50 PM, Eelco Chaudron wrote:
>> I’m re-adding some of my v18 comments, which I know are depending on Ilya’s 
>> feedback, although I still think we should have provider classes, i.e., not 
>> based on the datapath class.
>>
>> Some other questions could still be answered regardless of Ilya’s feedback 
>> (will mark them with **). Please answer them inline, before sending another 
>> revision so we can have some discussion around them if needed.
> OK.
>>
>> //Eelco
>>
>> On 15 Feb 2022, at 10:17, Chris Mi wrote:
>>
>>> Implement dpif-offload API for netlink datapath. And implement a
>>> dummy dpif-offload API for netdev datapath to make tests pass.
>>
>> ** Why do we need a dummy? If there is no hardware offload class we should 
>> just pass, shouldn’t we?
> According to one of your below comment, I moved dp_offload_class_lookup from 
> dpif to dpif-netlink.
> After that, dpif-offload for dummy is not needed.
>>
>>> Issue: 2181036
>>> Change-Id: I950c3cc3c7092c3d87602da8928ad4aa2df4f38a
>>> Signed-off-by: Chris Mi <c...@nvidia.com>
>>> Reviewed-by: Eli Britstein <el...@nvidia.com>
>>> ---
>>>   lib/automake.mk             |   2 +
>>>   lib/dpif-netdev.c           |   8 +-
>>>   lib/dpif-netlink.c          |   4 +-
>>>   lib/dpif-offload-netdev.c   |  43 +++++++
>>>   lib/dpif-offload-netlink.c  | 221 ++++++++++++++++++++++++++++++++++++
>>>   lib/dpif-offload-provider.h |  25 +++-
>>>   lib/dpif-offload.c          | 157 +++++++++++++++++++++++++
>>>   lib/dpif-provider.h         |   6 +-
>>>   lib/dpif.c                  |  17 ++-
>>>   9 files changed, 476 insertions(+), 7 deletions(-)
>>>   create mode 100644 lib/dpif-offload-netdev.c
>>>   create mode 100644 lib/dpif-offload-netlink.c
>>>
>>> diff --git a/lib/automake.mk b/lib/automake.mk
>>> index 781fba47a..9ed61029a 100644
>>> --- a/lib/automake.mk
>>> +++ b/lib/automake.mk
>>> @@ -130,6 +130,7 @@ lib_libopenvswitch_la_SOURCES = \
>>>     lib/dpif-netdev-perf.c \
>>>     lib/dpif-netdev-perf.h \
>>>     lib/dpif-offload.c \
>>> +   lib/dpif-offload-netdev.c \
>>>     lib/dpif-offload-provider.h \
>>>     lib/dpif-provider.h \
>>>     lib/dpif.c \
>>> @@ -453,6 +454,7 @@ lib_libopenvswitch_la_SOURCES += \
>>>     lib/dpif-netlink.h \
>>>     lib/dpif-netlink-rtnl.c \
>>>     lib/dpif-netlink-rtnl.h \
>>> +   lib/dpif-offload-netlink.c \
>>>     lib/if-notifier.c \
>>>     lib/netdev-linux.c \
>>>     lib/netdev-linux.h \
>>> diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
>>> index e28e0b554..5ebd127b9 100644
>>> --- a/lib/dpif-netdev.c
>>> +++ b/lib/dpif-netdev.c
>>> @@ -1683,7 +1683,8 @@ create_dpif_netdev(struct dp_netdev *dp)
>>>       ovs_refcount_ref(&dp->ref_cnt);
>>>
>>>       dpif = xmalloc(sizeof *dpif);
>>> -    dpif_init(&dpif->dpif, dp->class, dp->name, netflow_id >> 8, 
>>> netflow_id);
>>> +    dpif_init(&dpif->dpif, dp->class, NULL, dp->name, netflow_id >> 8,
>>> +              netflow_id);
>>>       dpif->dp = dp;
>>>       dpif->last_port_seq = seq_read(dp->port_seq);
>>>
>>> @@ -9639,6 +9640,10 @@ dpif_dummy_override(const char *type)
>>>       if (error == 0 || error == EAFNOSUPPORT) {
>>>           dpif_dummy_register__(type);
>>>       }
>>> +    error = dp_offload_unregister_provider(type);
>>> +    if (error == 0 || error == EAFNOSUPPORT) {
>>> +        dpif_offload_dummy_register(type);
>>> +    }
>>>   }
>>>
>>>   void
>>> @@ -9659,6 +9664,7 @@ dpif_dummy_register(enum dummy_level level)
>>>       }
>>>
>>>       dpif_dummy_register__("dummy");
>>> +    dpif_offload_dummy_register("dummy");
>>>
>>>       unixctl_command_register("dpif-dummy/change-port-number",
>>>                                "dp port new-number",
>>> diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c
>>> index 71e35ccdd..75f85c254 100644
>>> --- a/lib/dpif-netlink.c
>>> +++ b/lib/dpif-netlink.c
>>> @@ -461,8 +461,8 @@ open_dpif(const struct dpif_netlink_dp *dp, struct dpif 
>>> **dpifp)
>>>       dpif->port_notifier = NULL;
>>>       fat_rwlock_init(&dpif->upcall_lock);
>>>
>>> -    dpif_init(&dpif->dpif, &dpif_netlink_class, dp->name,
>>> -              dp->dp_ifindex, dp->dp_ifindex);
>>> +    dpif_init(&dpif->dpif, &dpif_netlink_class, 
>>> &dpif_offload_netlink_class,
>>> +              dp->name, dp->dp_ifindex, dp->dp_ifindex);
>>>
>>>       dpif->dp_ifindex = dp->dp_ifindex;
>>>       dpif->user_features = dp->user_features;
>>> diff --git a/lib/dpif-offload-netdev.c b/lib/dpif-offload-netdev.c
>>> new file mode 100644
>>> index 000000000..35dac2cc3
>>> --- /dev/null
>>> +++ b/lib/dpif-offload-netdev.c
>>> @@ -0,0 +1,43 @@
>>> +/*
>>> + * Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights 
>>> reserved.
>>> + *
>>> + * 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:
>>> + *
>>> + *     
>>> https://nam11.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.apache.org%2Flicenses%2FLICENSE-2.0&amp;data=04%7C01%7Ccmi%40nvidia.com%7Cadd31a18c66c46ea056408d9fdccd97d%7C43083d15727340c1b7db39efd9ccc17a%7C0%7C0%7C637819878551136144%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;sdata=A5fNu%2BjqL48flvxwkfz1BHOAiu6LLuBTdp%2F4HkYVEdw%3D&amp;reserved=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 "dpif.h"
>>> +#include "dpif-offload-provider.h"
>>> +#include "openvswitch/vlog.h"
>>> +
>>> +VLOG_DEFINE_THIS_MODULE(dpif_offload_netdev);
>>> +
>>> +/* Currently, it is used only for dummy netdev to make tests pass. */
>>> +const struct dpif_offload_class dpif_offload_netdev_class = {
>>> +    .type = "netdev",
>>> +    .init = NULL,
>>> +    .destroy = NULL,
>>> +    .sflow_recv_wait = NULL,
>>> +    .sflow_recv = NULL,
>>> +};
>>> +
>>> +void
>>> +dpif_offload_dummy_register(const char *type)
>>> +{
>>> +    struct dpif_offload_class *class;
>>> +
>>> +    class = xmalloc(sizeof *class);
>>> +    *class = dpif_offload_netdev_class;
>>> +    class->type = xstrdup(type);
>>> +    dp_offload_register_provider(class);
>>> +}
>> ** So here I assume you can not use the one defined in 
>> dpif-offload-netlink.c as it will fail initialization.
>> ** If this is not true, please use the one in dpif-offload-netlink.c like 
>> dpif-netlink.c does.
>>
>> ** However assuming this is the case, why is this in dpif-offload-netdev.c? 
>> I would just add it to the dpif-offload.c as a new dummy class.
>>
>>
>> Also because we should not have netlink/netdev classes, but real offload 
>> classes like: TC, rte_flow, etc., etc.
>> Somehting like:
>>
>> +/* Currently, it is used only for dummy netdev to make tests pass. */
>> +const struct dpif_offload_class dpif_offload_dummy_class = {
>> +    .type = “dummy”,
>> +    .init = NULL,
>> +    .destroy = NULL,
>> +    .sflow_recv_wait = NULL,
>> +    .sflow_recv = NULL,
>> +};
>> +
>> +void
>> +dpif_offload_dummy_register()
>> +{
>> +    dp_offload_register_provider(dpif_offload_dummy_class);
>> +}
>>
>> ** I’m also wondering, why you need this only for the dummy netdev to make 
>> the tests pass, but not for real live netdev devices?
> The above code can be deleted.
>>
>>> diff --git a/lib/dpif-offload-netlink.c b/lib/dpif-offload-netlink.c
>> As mentioned before this should be offload classes, so for this example, I 
>> would think it should be called dpif-offload-tc.c
> I think I need Ilya's feedback to change this code.
>>
>>> new file mode 100644
>>> index 000000000..02aea7e2d
>>> --- /dev/null
>>> +++ b/lib/dpif-offload-netlink.c
>>> @@ -0,0 +1,221 @@
>>> +/*
>>> + * Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights 
>>> reserved.
>>> + *
>>> + * 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:
>>> + *
>>> + *     
>>> https://nam11.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.apache.org%2Flicenses%2FLICENSE-2.0&amp;data=04%7C01%7Ccmi%40nvidia.com%7Cadd31a18c66c46ea056408d9fdccd97d%7C43083d15727340c1b7db39efd9ccc17a%7C0%7C0%7C637819878551136144%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;sdata=A5fNu%2BjqL48flvxwkfz1BHOAiu6LLuBTdp%2F4HkYVEdw%3D&amp;reserved=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 <errno.h>
>>> +#include <linux/psample.h>
>>> +#include <sys/poll.h>
>>> +
>>> +#include "dpif-offload-provider.h"
>>> +#include "netdev-offload.h"
>>> +#include "netlink-protocol.h"
>>> +#include "netlink-socket.h"
>>> +#include "openvswitch/vlog.h"
>>> +
>>> +VLOG_DEFINE_THIS_MODULE(dpif_offload_netlink);
>>> +
>>> +static struct nl_sock *psample_sock;
>>> +static int psample_family;
>>> +
>>> +/* Receive psample netlink message and save the attributes. */
>>> +struct offload_psample {
>>> +    struct nlattr *packet;      /* Packet data. */
>>> +    int dp_group_id;            /* Mapping id for sFlow offload. */
>>> +    int iifindex;               /* Input ifindex. */
>>> +};
>>> +
>>> +/* In order to keep compatibility with kernels without psample module,
>>> + * return success even if psample is not initialized successfully. */
>>> +static void
>>> +psample_init(void)
>>> +{
>>> +    unsigned int psample_mcgroup;
>>> +    int err;
>>> +
>>> +    if (!netdev_is_flow_api_enabled()) {
>>> +        VLOG_DBG("Flow API is not enabled.");
>>> +        return;
>>> +    }
>>> +
>>> +    if (psample_sock) {
>>> +        VLOG_DBG("Psample socket is already initialized.");
>>> +        return;
>>> +    }
>>> +
>>> +    err = nl_lookup_genl_family(PSAMPLE_GENL_NAME,
>>> +                                &psample_family);
>>> +    if (err) {
>>> +        VLOG_WARN("Generic Netlink family '%s' does not exist: %s\n"
>>> +                  "Please make sure the kernel module psample is loaded.",
>>> +                  PSAMPLE_GENL_NAME, ovs_strerror(err));
>>> +        return;
>>> +    }
>>> +
>>> +    err = nl_lookup_genl_mcgroup(PSAMPLE_GENL_NAME,
>>> +                                 PSAMPLE_NL_MCGRP_SAMPLE_NAME,
>>> +                                 &psample_mcgroup);
>>> +    if (err) {
>>> +        VLOG_WARN("Failed to join Netlink multicast group '%s': %s",
>>> +                  PSAMPLE_NL_MCGRP_SAMPLE_NAME, ovs_strerror(err));
>>> +        return;
>>> +    }
>>> +
>>> +    err = nl_sock_create(NETLINK_GENERIC, &psample_sock);
>>> +    if (err) {
>>> +        VLOG_WARN("Failed to create psample socket: %s", 
>>> ovs_strerror(err));
>>> +        return;
>>> +    }
>>> +
>>> +    err = nl_sock_join_mcgroup(psample_sock, psample_mcgroup);
>>> +    if (err) {
>>> +        VLOG_WARN("Failed to join psample mcgroup: %s", ovs_strerror(err));
>>> +        nl_sock_destroy(psample_sock);
>>> +        psample_sock = NULL;
>>> +        return;
>>> +    }
>>> +}
>>> +
>>> +static int
>>> +dpif_offload_netlink_init(void)
>>> +{
>>> +    psample_init();
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +static void
>>> +psample_destroy(void)
>>> +{
>>> +    if (!psample_sock) {
>>> +        return;
>>> +    }
>>> +
>>> +    nl_sock_destroy(psample_sock);
>>> +    psample_sock = NULL;
>>> +}
>>> +
>>> +static void
>>> +dpif_offload_netlink_destroy(void)
>>> +{
>>> +    psample_destroy();
>>> +}
>>> +
>>> +static void
>>> +dpif_offload_netlink_sflow_recv_wait(void)
>>> +{
>>> +    if (psample_sock) {
>>> +        nl_sock_wait(psample_sock, POLLIN);
>>> +    }
>>> +}
>>> +
>>> +static int
>>> +psample_from_ofpbuf(struct offload_psample *psample,
>>> +                    const struct ofpbuf *buf)
>>> +{
>>> +    static const struct nl_policy ovs_psample_policy[] = {
>>> +        [PSAMPLE_ATTR_IIFINDEX] = { .type = NL_A_U16 },
>>> +        [PSAMPLE_ATTR_SAMPLE_GROUP] = { .type = NL_A_U32 },
>>> +        [PSAMPLE_ATTR_GROUP_SEQ] = { .type = NL_A_U32 },
>>> +        [PSAMPLE_ATTR_DATA] = { .type = NL_A_UNSPEC },
>>> +    };
>>> +    struct nlattr *a[ARRAY_SIZE(ovs_psample_policy)];
>>> +    struct genlmsghdr *genl;
>>> +    struct nlmsghdr *nlmsg;
>>> +    struct ofpbuf b;
>>> +
>>> +    b = ofpbuf_const_initializer(buf->data, buf->size);
>>> +    nlmsg = ofpbuf_try_pull(&b, sizeof *nlmsg);
>>> +    genl = ofpbuf_try_pull(&b, sizeof *genl);
>>> +    if (!nlmsg || !genl || nlmsg->nlmsg_type != psample_family
>>> +        || !nl_policy_parse(&b, 0, ovs_psample_policy, a,
>>> +                            ARRAY_SIZE(ovs_psample_policy))) {
>>> +        return EINVAL;
>>> +    }
>>> +
>>> +    psample->iifindex = nl_attr_get_u16(a[PSAMPLE_ATTR_IIFINDEX]);
>>> +    psample->dp_group_id = nl_attr_get_u32(a[PSAMPLE_ATTR_SAMPLE_GROUP]);
>>> +    psample->packet = a[PSAMPLE_ATTR_DATA];
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +static int
>>> +psample_parse_packet(struct offload_psample *psample,
>>> +                     struct dpif_offload_sflow *sflow)
>>> +{
>>> +    dp_packet_use_stub(&sflow->packet,
>>> +                       CONST_CAST(struct nlattr *,
>>> +                                  nl_attr_get(psample->packet)) - 1,
>>> +                       nl_attr_get_size(psample->packet) +
>>> +                       sizeof(struct nlattr));
>>> +    dp_packet_set_data(&sflow->packet,
>>> +                       (char *) dp_packet_data(&sflow->packet) +
>>> +                       sizeof(struct nlattr));
>>> +    dp_packet_set_size(&sflow->packet, nl_attr_get_size(psample->packet));
>>> +
>>> +    sflow->attr = dpif_offload_sflow_attr_find(psample->dp_group_id);
>>> +    if (!sflow->attr) {
>>> +        return ENOENT;
>>> +    }
>>> +    sflow->iifindex = psample->iifindex;
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +static int
>>> +dpif_offload_netlink_sflow_recv(struct dpif_offload_sflow *sflow)
>>> +{
>>> +    if (!psample_sock) {
>>> +        return ENOENT;
>>> +    }
>>> +
>>> +    for (;;) {
>>> +        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
>>> +        struct offload_psample psample;
>>> +        struct ofpbuf buf;
>>> +        int error;
>>> +
>>> +        ofpbuf_use_stub(&buf, sflow->buf_stub, sizeof sflow->buf_stub);
>>> +        error = nl_sock_recv(psample_sock, &buf, NULL, false);
>>> +
>>> +        if (!error) {
>>> +            error = psample_from_ofpbuf(&psample, &buf);
>>> +            if (!error) {
>>> +                    ofpbuf_uninit(&buf);
>>> +                    error = psample_parse_packet(&psample, sflow);
>>> +                    return error;
>>> +            }
>>> +        } else if (error != EAGAIN) {
>>> +            VLOG_WARN_RL(&rl, "Error reading or parsing netlink (%s).",
>>> +                         ovs_strerror(error));
>>> +            nl_sock_drain(psample_sock);
>>> +            error = ENOBUFS;
>>> +        }
>>> +
>>> +        ofpbuf_uninit(&buf);
>>> +        if (error) {
>>> +            return error;
>>> +        }
>>> +    }
>>> +}
>>> +
>>> +const struct dpif_offload_class dpif_offload_netlink_class = {
>>> +    .type = "system",
>>> +    .init = dpif_offload_netlink_init,
>>> +    .destroy = dpif_offload_netlink_destroy,
>>> +    .sflow_recv_wait = dpif_offload_netlink_sflow_recv_wait,
>>> +    .sflow_recv = dpif_offload_netlink_sflow_recv,
>>> +};
>>> diff --git a/lib/dpif-offload-provider.h b/lib/dpif-offload-provider.h
>>> index af49eedb9..ac13601b5 100644
>>> --- a/lib/dpif-offload-provider.h
>>> +++ b/lib/dpif-offload-provider.h
>>> @@ -17,12 +17,18 @@
>>>   #ifndef DPIF_OFFLOAD_PROVIDER_H
>>>   #define DPIF_OFFLOAD_PROVIDER_H
>>>
>>> +#include "dp-packet.h"
>>>   #include "netlink-protocol.h"
>>>   #include "openvswitch/packets.h"
>>>   #include "openvswitch/types.h"
>>>
>>>   struct dpif;
>>> -struct dpif_offload_sflow;
>>> +struct registered_dpif_offload_class;
>>> +
>>> +#ifdef __linux__
>>> +extern const struct dpif_offload_class dpif_offload_netlink_class;
>>> +#endif
>>> +extern const struct dpif_offload_class dpif_offload_netdev_class;
>>>
>>>   /* When offloading sample action, userspace creates a unique ID to map
>>>    * sFlow action and tunnel info and passes this ID to datapath instead
>>> @@ -37,6 +43,14 @@ struct dpif_sflow_attr {
>>>       ovs_u128 ufid;                  /* Flow ufid. */
>>>   };
>>>
>>> +/* Parse the specific dpif message to sFlow. So OVS can process it. */
>>> +struct dpif_offload_sflow {
>>> +    struct dp_packet packet;            /* Packet data. */
>>> +    uint64_t buf_stub[4096 / 8];        /* Buffer stub for packet data. */
>>> +    uint32_t iifindex;                  /* Input ifindex. */
>>> +    const struct dpif_sflow_attr *attr; /* SFlow attribute. */
>>> +};
>>> +
>>>   /* Datapath interface offload structure, to be defined by each 
>>> implementation
>>>    * of a datapath interface.
>>>    */
>>> @@ -62,6 +76,15 @@ struct dpif_offload_class {
>>>       int (*sflow_recv)(struct dpif_offload_sflow *sflow);
>>>   };
>>>
>>> +void dp_offload_initialize(void);
>>> +void dpif_offload_close(struct dpif *);
>>> +
>>> +int dp_offload_register_provider(const struct dpif_offload_class *);
>>> +int dp_offload_unregister_provider(const char *type);
>>> +void dpif_offload_dummy_register(const char *type);
>>> +void dp_offload_class_unref(struct registered_dpif_offload_class *rc);
>>> +struct registered_dpif_offload_class *dp_offload_class_lookup(const char 
>>> *);
>>> +
>>>   void dpif_offload_sflow_recv_wait(const struct dpif *dpif);
>>>   int dpif_offload_sflow_recv(const struct dpif *dpif,
>>>                               struct dpif_offload_sflow *sflow);
>>> diff --git a/lib/dpif-offload.c b/lib/dpif-offload.c
>>> index f2bf3e634..f3ac539ab 100644
>>> --- a/lib/dpif-offload.c
>>> +++ b/lib/dpif-offload.c
>>> @@ -18,6 +18,163 @@
>>>   #include <errno.h>
>>>
>>>   #include "dpif-provider.h"
>>> +#include "openvswitch/shash.h"
>>> +#include "openvswitch/vlog.h"
>>> +
>>> +VLOG_DEFINE_THIS_MODULE(dpif_offload);
>>> +
>>> +static const struct dpif_offload_class *base_dpif_offload_classes[] = {
>>> +#if defined(__linux__)
>>> +    &dpif_offload_netlink_class,
>>> +#endif
>>> +    &dpif_offload_netdev_class,
>>> +};
>>> +
>>> +struct registered_dpif_offload_class {
>>> +    const struct dpif_offload_class *offload_class;
>>> +    int refcount;
>>> +};
>>> +static struct shash dpif_offload_classes =
>>> +    SHASH_INITIALIZER(&dpif_offload_classes);
>>> +
>>> +/* Protects 'dpif_offload_classes', including the refcount. */
>>> +static struct ovs_mutex dpif_offload_mutex = OVS_MUTEX_INITIALIZER;
>>> +
>>> +void
>>> +dp_offload_initialize(void)
>>> +{
>>> +    static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
>>> +
>>> +    if (ovsthread_once_start(&once)) {
>>> +        for (int i = 0; i < ARRAY_SIZE(base_dpif_offload_classes); i++) {
>>> +            dp_offload_register_provider(base_dpif_offload_classes[i]);
>>> +        }
>>> +        ovsthread_once_done(&once);
>>> +    }
>>> +}
>>> +
>>> +static int
>>> +dp_offload_register_provider__(const struct dpif_offload_class *new_class)
>>> +    OVS_REQUIRES(dpif_offload_mutex)
>>> +{
>>> +    struct registered_dpif_offload_class *registered_class;
>>> +    int error;
>>> +
>>> +    if (shash_find(&dpif_offload_classes, new_class->type)) {
>>> +        VLOG_WARN("Attempted to register duplicate datapath offload "
>>> +                  "provider: %s", new_class->type);
>>> +        return EEXIST;
>>> +    }
>>> +
>>> +    error = new_class->init ? new_class->init() : 0;
>>> +    if (error) {
>>> +        VLOG_WARN("Failed to initialize %s datapath offload class: %s",
>>> +                  new_class->type, ovs_strerror(error));
>>> +        return error;
>>> +    }
>>> +
>>> +    registered_class = xmalloc(sizeof *registered_class);
>>> +    registered_class->offload_class = new_class;
>>> +    registered_class->refcount = 0;
>>> +
>>> +    shash_add(&dpif_offload_classes, new_class->type, registered_class);
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +void dpif_offload_close(struct dpif *dpif)
>>> +{
>>> +    if (dpif->offload_class) {
>>> +        struct registered_dpif_offload_class *rc;
>>> +
>>> +        rc = shash_find_data(&dpif_offload_classes, 
>>> dpif->offload_class->type);
>>> +        dp_offload_class_unref(rc);
>>> +    }
>>> +}
>>> +
>>> +int
>>> +dp_offload_register_provider(const struct dpif_offload_class *new_class)
>>> +{
>>> +    int error;
>>> +
>>> +    ovs_mutex_lock(&dpif_offload_mutex);
>>> +    error = dp_offload_register_provider__(new_class);
>>> +    ovs_mutex_unlock(&dpif_offload_mutex);
>>> +
>>> +    return error;
>>> +}
>>> +
>>> +/* Unregisters an offload datapath provider.  'type' must have been 
>>> previously
>>> + * registered and not currently be in use by any dpifs.  After 
>>> unregistration
>>> + * new offload datapaths of that type cannot be opened using dpif_open(). 
>>> */
>>> +static int
>>> +dp_offload_unregister_provider__(const char *type)
>>> +    OVS_REQUIRES(dpif_offload_mutex)
>>> +{
>>> +    struct shash_node *node;
>>> +    struct registered_dpif_offload_class *registered_class;
>>> +
>>> +    node = shash_find(&dpif_offload_classes, type);
>>> +    if (!node) {
>>> +        return EAFNOSUPPORT;
>>> +    }
>>> +
>>> +    registered_class = node->data;
>>> +    if (registered_class->refcount) {
>>> +        VLOG_WARN("Attempted to unregister in use offload datapath 
>>> provider: "
>>> +                  "%s", type);
>>> +        return EBUSY;
>>> +    }
>>> +
>>> +    if (registered_class->offload_class->destroy) {
>>> +        registered_class->offload_class->destroy();
>>> +    }
>>> +    shash_delete(&dpif_offload_classes, node);
>>> +    free(registered_class);
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +/* Unregisters an offload datapath provider.  'type' must have been 
>>> previously
>>> + * registered and not currently be in use by any dpifs.  After 
>>> unregistration
>>> + * new offload datapaths of that type cannot be opened using dpif_open(). 
>>> */
>>> +int
>>> +dp_offload_unregister_provider(const char *type)
>>> +{
>>> +    int error;
>>> +
>>> +    dp_offload_initialize();
>> ** Why do we call this?
> Removed. And since this function is only called by dummy, it is also removed.
>>
>>> +
>>> +    ovs_mutex_lock(&dpif_offload_mutex);
>>> +    error = dp_offload_unregister_provider__(type);
>>> +    ovs_mutex_unlock(&dpif_offload_mutex);
>>> +
>>> +    return error;
>>> +}
>>> +
>>> +void
>>> +dp_offload_class_unref(struct registered_dpif_offload_class *rc)
>>> +{
>>> +    ovs_mutex_lock(&dpif_offload_mutex);
>>> +    ovs_assert(rc->refcount);
>>> +    rc->refcount--;
>>> +    ovs_mutex_unlock(&dpif_offload_mutex);
>>> +}
>>> +
>>> +struct registered_dpif_offload_class *
>>> +dp_offload_class_lookup(const char *type)
>>> +{
>>> +    struct registered_dpif_offload_class *rc;
>>> +
>>> +    ovs_mutex_lock(&dpif_offload_mutex);
>>> +    rc = shash_find_data(&dpif_offload_classes, type);
>>> +    if (rc) {
>>> +        rc->refcount++;
>>> +    }
>>> +    ovs_mutex_unlock(&dpif_offload_mutex);
>>> +
>>> +    return rc;
>>> +}
>>>
>>>   void
>>>   dpif_offload_sflow_recv_wait(const struct dpif *dpif)
>>> diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h
>>> index 99009722a..c8ed385a1 100644
>>> --- a/lib/dpif-provider.h
>>> +++ b/lib/dpif-provider.h
>>> @@ -47,8 +47,10 @@ struct dpif {
>>>   struct dpif_ipf_status;
>>>   struct ipf_dump_ctx;
>>>
>>> -void dpif_init(struct dpif *, const struct dpif_class *, const char *name,
>>> -               uint8_t netflow_engine_type, uint8_t netflow_engine_id);
>>> +void dpif_init(struct dpif *, const struct dpif_class *,
>>> +               const struct dpif_offload_class *offload_class,
>>> +               const char *name, uint8_t netflow_engine_type,
>>> +               uint8_t netflow_engine_id);
>>>   void dpif_uninit(struct dpif *dpif, bool close);
>>>
>>>   static inline void dpif_assert_class(const struct dpif *dpif,
>>> diff --git a/lib/dpif.c b/lib/dpif.c
>>> index 40f5fe446..00c1a7e65 100644
>>> --- a/lib/dpif.c
>>> +++ b/lib/dpif.c
>>> @@ -333,6 +333,7 @@ do_open(const char *name, const char *type, bool 
>>> create, struct dpif **dpifp)
>>>       struct dpif *dpif = NULL;
>>>       int error;
>>>       struct registered_dpif_class *registered_class;
>>> +    struct registered_dpif_offload_class *registered_offload_class;
>>>
>>>       dp_initialize();
>>>
>>> @@ -345,6 +346,17 @@ do_open(const char *name, const char *type, bool 
>>> create, struct dpif **dpifp)
>>>           goto exit;
>>>       }
>>>
>>> +    dp_offload_initialize();
>>> +
>>> +    registered_offload_class = dp_offload_class_lookup(type);
>> Don’t think we need to do this here, do we? The offload class is initialized 
>> as part of dpif we query below.
>> So if the dpif is found you could do 
>> dp_offload_class_lookup(dpif->offload_class->type)?
>>
>> However, is this function the right place to do this? You assign an 
>> offload_class as part of dpif_init() so whoever is calling dpif_init() 
>> should that not be responsible for calling dp_offload_class_lookup() before 
>> using it?
> Done.
>>
>>> +    if (!registered_offload_class) {
>>> +        VLOG_WARN("Could not create offload datapath %s of unknown type 
>>> %s",
>>> +                  name, type);
>>> +        error = EAFNOSUPPORT;
>>> +        dp_class_unref(registered_class);
>>> +        goto exit;
>>> +    }
>>> +
>>>       error = 
>>> registered_class->dpif_class->open(registered_class->dpif_class,
>>>                                                  name, create, &dpif);
>>>       if (!error) {
>>> @@ -374,6 +386,7 @@ do_open(const char *name, const char *type, bool 
>>> create, struct dpif **dpifp)
>>>               }
>>>           }
>>>       } else {
>>> +        dp_offload_class_unref(registered_offload_class);
>>>           dp_class_unref(registered_class);
>>>       }
>>>
>>> @@ -449,6 +462,7 @@ dpif_close(struct dpif *dpif)
>>>       if (dpif) {
>>>           struct registered_dpif_class *rc;
>>>
>>> +        dpif_offload_close(dpif);
>> ** Not sure I understand, but why are we destroying the offload dpif class 
>> here, it can be used by another dpif type.
>>
>> ** I guess this is all because your design has a 1:1 mapping? Guess it 
>> should be two dpif_types that could share the same offload class type.
> Now it is moved to dpif_netlink_close().
>
> Except the 1:1 mapping comment which I think need Ilya's feedback, I have 
> addressed your other comments.
> Thanks for your comments. The dpif-offload for dummy is not needed and 
> removed.
> If needed, I can send v21.


Thanks for taking care of the questions and fixing them in your sandbox.
I would prefer for you to not send any more revisions until we have a clear 
answer from Ilya.

//Eelco

>>
>>>           rc = shash_find_data(&dpif_classes, dpif->dpif_class->type);
>>>
>>>           if (rc->refcount == 1) {
>>> @@ -1699,10 +1713,11 @@ dpif_queue_to_priority(const struct dpif *dpif, 
>>> uint32_t queue_id,
>>>   
>>>   void
>>>   dpif_init(struct dpif *dpif, const struct dpif_class *dpif_class,
>>> -          const char *name,
>>> +          const struct dpif_offload_class *offload_class, const char *name,
>>>             uint8_t netflow_engine_type, uint8_t netflow_engine_id)
>>>   {
>>>       dpif->dpif_class = dpif_class;
>>> +    dpif->offload_class = offload_class;
>>>       dpif->base_name = xstrdup(name);
>>>       dpif->full_name = xasprintf("%s@%s", dpif_class->type, name);
>>>       dpif->netflow_engine_type = netflow_engine_type;
>>> -- 
>>> 2.30.2

_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to