diff mbox series

[ovs-dev,v14,3/7] dpif-offload-provider: Introduce dpif-offload-provider layer

Message ID 20210715060140.3866-4-cmi@nvidia.com
State Changes Requested
Headers show
Series Add offload support for sFlow | expand

Checks

Context Check Description
ovsrobot/apply-robot success apply and check: success
ovsrobot/github-robot success github build: passed

Commit Message

Chris Mi July 15, 2021, 6:01 a.m. UTC
Some offload actions require functionality that is not netdev
based, but dpif. For example, sFlow action requires to create
a psample netlink socket to receive the sampled packets from
TC or kernel driver.

Create dpif-offload-provider layer to support such actions.

Signed-off-by: Chris Mi <cmi@nvidia.com>
Reviewed-by: Eli Britstein <elibr@nvidia.com>
---
 lib/automake.mk             |  2 ++
 lib/dpif-netdev.c           |  1 +
 lib/dpif-netlink.c          |  2 ++
 lib/dpif-offload-provider.h | 34 +++++++++++++++++++++++++++++
 lib/dpif-offload.c          | 43 +++++++++++++++++++++++++++++++++++++
 lib/dpif-provider.h         |  8 ++++++-
 lib/dpif.c                  | 10 +++++++++
 7 files changed, 99 insertions(+), 1 deletion(-)
 create mode 100644 lib/dpif-offload-provider.h
 create mode 100644 lib/dpif-offload.c

Comments

Eelco Chaudron Sept. 6, 2021, 10:56 a.m. UTC | #1
On 15 Jul 2021, at 8:01, Chris Mi wrote:

> Some offload actions require functionality that is not netdev
> based, but dpif. For example, sFlow action requires to create
> a psample netlink socket to receive the sampled packets from
> TC or kernel driver.
>
> Create dpif-offload-provider layer to support such actions.
>
> Signed-off-by: Chris Mi <cmi@nvidia.com>
> Reviewed-by: Eli Britstein <elibr@nvidia.com>
> ---
>  lib/automake.mk             |  2 ++
>  lib/dpif-netdev.c           |  1 +
>  lib/dpif-netlink.c          |  2 ++
>  lib/dpif-offload-provider.h | 34 +++++++++++++++++++++++++++++
>  lib/dpif-offload.c          | 43 +++++++++++++++++++++++++++++++++++++
>  lib/dpif-provider.h         |  8 ++++++-
>  lib/dpif.c                  | 10 +++++++++
>  7 files changed, 99 insertions(+), 1 deletion(-)
>  create mode 100644 lib/dpif-offload-provider.h
>  create mode 100644 lib/dpif-offload.c
>
> diff --git a/lib/automake.mk b/lib/automake.mk
> index 3c9523c1a..dc865b0ef 100644
> --- a/lib/automake.mk
> +++ b/lib/automake.mk
> @@ -123,6 +123,8 @@ lib_libopenvswitch_la_SOURCES = \
>  	lib/dpif-netdev-private.h \
>  	lib/dpif-netdev-perf.c \
>  	lib/dpif-netdev-perf.h \
> +	lib/dpif-offload.c \
> +	lib/dpif-offload-provider.h \
>  	lib/dpif-provider.h \
>  	lib/dpif.c \
>  	lib/dpif.h \
> diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
> index 610949f36..35d73542b 100644
> --- a/lib/dpif-netdev.c
> +++ b/lib/dpif-netdev.c
> @@ -8269,6 +8269,7 @@ const struct dpif_class dpif_netdev_class = {
>      dpif_netdev_bond_add,
>      dpif_netdev_bond_del,
>      dpif_netdev_bond_stats_get,
> +    NULL,                       /* dpif_offlod_api */

offlod -> offload

>  };
>
>  static void
> diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c
> index 39dc8300e..6a7defb95 100644
> --- a/lib/dpif-netlink.c
> +++ b/lib/dpif-netlink.c
> @@ -34,6 +34,7 @@
>
>  #include "bitmap.h"
>  #include "dpif-netlink-rtnl.h"
> +#include "dpif-offload-provider.h"
>  #include "dpif-provider.h"
>  #include "fat-rwlock.h"
>  #include "flow.h"
> @@ -4036,6 +4037,7 @@ const struct dpif_class dpif_netlink_class = {
>      NULL,                       /* bond_add */
>      NULL,                       /* bond_del */
>      NULL,                       /* bond_stats_get */
> +    NULL,                       /* dpif_offlod_api */

offlod -> offload

>  };
>
>  static int
> diff --git a/lib/dpif-offload-provider.h b/lib/dpif-offload-provider.h
> new file mode 100644
> index 000000000..97108402a
> --- /dev/null
> +++ b/lib/dpif-offload-provider.h
> @@ -0,0 +1,34 @@
> +/*
> + * 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:
> + *
> + *     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 DPIF_OFFLOAD_PROVIDER_H
> +#define DPIF_OFFLOAD_PROVIDER_H
> +
> +struct dpif;
> +struct dpif_offload_sflow;
> +
> +struct dpif_offload_api {

Can we add help details on each function below, preferably as in the netdev/dpif_class definitions? i.e., describe the function, its input parameters, and return value?

> +    void (*init)(void);

Do we want to think ahead and allow init to fail? Other init callbacks return int.

> +    void (*uninit)(void);

Don't really like the uninit() function name. I like destroy() as it sort of indicates we should no longer use this resource once called.
However, in other projects, they use deinit() a lot, but to me, it does not express the urgency to no use it after the call.

> +    void (*sflow_recv_wait)(void);
> +    int (*sflow_recv)(struct dpif_offload_sflow *sflow);
> +};
> +
> +void dpif_offload_sflow_recv_wait(const struct dpif *dpif);
> +int dpif_offload_sflow_recv(const struct dpif *dpif,
> +                            struct dpif_offload_sflow *sflow);
> +
> +#endif /* DPIF_OFFLOAD_PROVIDER_H */
> diff --git a/lib/dpif-offload.c b/lib/dpif-offload.c
> new file mode 100644
> index 000000000..842e05798
> --- /dev/null
> +++ b/lib/dpif-offload.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:
> + *
> + *     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 <errno.h>
> +
> +#include "dpif-provider.h"
> +
> +void
> +dpif_offload_sflow_recv_wait(const struct dpif *dpif)
> +{
> +    const struct dpif_offload_api *offload_api = dpif->dpif_class->offload_api;
> +
> +    if (offload_api && offload_api->sflow_recv_wait) {
> +        offload_api->sflow_recv_wait();
> +    }
> +}
> +
> +int
> +dpif_offload_sflow_recv(const struct dpif *dpif,
> +                        struct dpif_offload_sflow *sflow)
> +{
> +    const struct dpif_offload_api *offload_api = dpif->dpif_class->offload_api;
> +
> +    if (offload_api && offload_api->sflow_recv) {
> +        return offload_api->sflow_recv(sflow);
> +    }
> +
> +    return EOPNOTSUPP;
> +}
> diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h
> index 59e0a3a9d..7fb93d69d 100644
> --- a/lib/dpif-provider.h
> +++ b/lib/dpif-provider.h
> @@ -22,8 +22,9 @@
>   * exposed over OpenFlow as a single switch.  Datapaths and the collections of
>   * ports that they contain may be fixed or dynamic. */
>
> -#include "openflow/openflow.h"
>  #include "dpif.h"
> +#include "dpif-offload-provider.h"
> +#include "openflow/openflow.h"
>  #include "util.h"
>
>  #ifdef  __cplusplus
> @@ -633,6 +634,11 @@ struct dpif_class {
>       * sufficient to store BOND_BUCKETS number of elements. */
>      int (*bond_stats_get)(struct dpif *dpif, uint32_t bond_id,
>                            uint64_t *n_bytes);
> +
> +    /* Some offload actions require functionality that is not netdev based,
> +     * but dpif. Add dpif-offload-provider layer API to support such
> +     * offload actions. */
> +    const struct dpif_offload_api *offload_api;

Here you add the provider directly into the dpif class. Not sure if this is what Ilya had in mind. As in general, these get integrated into the dpif/netdev, not the class. Ilya can you comment on/review this?

>  };
>
>  extern const struct dpif_class dpif_netlink_class;
> diff --git a/lib/dpif.c b/lib/dpif.c
> index 26e8bfb7d..a0987988a 100644
> --- a/lib/dpif.c
> +++ b/lib/dpif.c
> @@ -153,6 +153,10 @@ dp_register_provider__(const struct dpif_class *new_class)
>          return error;
>      }
>
> +    if (new_class->offload_api && new_class->offload_api->init) {
> +        new_class->offload_api->init();
> +    }
> +
>      registered_class = xmalloc(sizeof *registered_class);
>      registered_class->dpif_class = new_class;
>      registered_class->refcount = 0;
> @@ -183,6 +187,7 @@ static int
>  dp_unregister_provider__(const char *type)
>  {
>      struct shash_node *node;
> +    const struct dpif_class *dpif_class;
>      struct registered_dpif_class *registered_class;
>
>      node = shash_find(&dpif_classes, type);
> @@ -196,6 +201,11 @@ dp_unregister_provider__(const char *type)
>          return EBUSY;
>      }
>
> +    dpif_class = registered_class->dpif_class;
> +    if (dpif_class->offload_api && dpif_class->offload_api->uninit) {
> +        dpif_class->offload_api->uninit();
> +    }
> +
>      shash_delete(&dpif_classes, node);
>      free(registered_class);
>
> -- 
> 2.21.0
Chris Mi Sept. 15, 2021, 9:10 a.m. UTC | #2
On 9/6/2021 6:56 PM, Eelco Chaudron wrote:
> On 15 Jul 2021, at 8:01, Chris Mi wrote:
>
>> Some offload actions require functionality that is not netdev
>> based, but dpif. For example, sFlow action requires to create
>> a psample netlink socket to receive the sampled packets from
>> TC or kernel driver.
>>
>> Create dpif-offload-provider layer to support such actions.
>>
>> Signed-off-by: Chris Mi <cmi@nvidia.com>
>> Reviewed-by: Eli Britstein <elibr@nvidia.com>
>> ---
>>   lib/automake.mk             |  2 ++
>>   lib/dpif-netdev.c           |  1 +
>>   lib/dpif-netlink.c          |  2 ++
>>   lib/dpif-offload-provider.h | 34 +++++++++++++++++++++++++++++
>>   lib/dpif-offload.c          | 43 +++++++++++++++++++++++++++++++++++++
>>   lib/dpif-provider.h         |  8 ++++++-
>>   lib/dpif.c                  | 10 +++++++++
>>   7 files changed, 99 insertions(+), 1 deletion(-)
>>   create mode 100644 lib/dpif-offload-provider.h
>>   create mode 100644 lib/dpif-offload.c
>>
>> diff --git a/lib/automake.mk b/lib/automake.mk
>> index 3c9523c1a..dc865b0ef 100644
>> --- a/lib/automake.mk
>> +++ b/lib/automake.mk
>> @@ -123,6 +123,8 @@ lib_libopenvswitch_la_SOURCES = \
>>   	lib/dpif-netdev-private.h \
>>   	lib/dpif-netdev-perf.c \
>>   	lib/dpif-netdev-perf.h \
>> +	lib/dpif-offload.c \
>> +	lib/dpif-offload-provider.h \
>>   	lib/dpif-provider.h \
>>   	lib/dpif.c \
>>   	lib/dpif.h \
>> diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
>> index 610949f36..35d73542b 100644
>> --- a/lib/dpif-netdev.c
>> +++ b/lib/dpif-netdev.c
>> @@ -8269,6 +8269,7 @@ const struct dpif_class dpif_netdev_class = {
>>       dpif_netdev_bond_add,
>>       dpif_netdev_bond_del,
>>       dpif_netdev_bond_stats_get,
>> +    NULL,                       /* dpif_offlod_api */
> offlod -> offload
>
>>   };
>>
>>   static void
>> diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c
>> index 39dc8300e..6a7defb95 100644
>> --- a/lib/dpif-netlink.c
>> +++ b/lib/dpif-netlink.c
>> @@ -34,6 +34,7 @@
>>
>>   #include "bitmap.h"
>>   #include "dpif-netlink-rtnl.h"
>> +#include "dpif-offload-provider.h"
>>   #include "dpif-provider.h"
>>   #include "fat-rwlock.h"
>>   #include "flow.h"
>> @@ -4036,6 +4037,7 @@ const struct dpif_class dpif_netlink_class = {
>>       NULL,                       /* bond_add */
>>       NULL,                       /* bond_del */
>>       NULL,                       /* bond_stats_get */
>> +    NULL,                       /* dpif_offlod_api */
> offlod -> offload
Done.
>
>>   };
>>
>>   static int
>> diff --git a/lib/dpif-offload-provider.h b/lib/dpif-offload-provider.h
>> new file mode 100644
>> index 000000000..97108402a
>> --- /dev/null
>> +++ b/lib/dpif-offload-provider.h
>> @@ -0,0 +1,34 @@
>> +/*
>> + * 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:
>> + *
>> + *     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 DPIF_OFFLOAD_PROVIDER_H
>> +#define DPIF_OFFLOAD_PROVIDER_H
>> +
>> +struct dpif;
>> +struct dpif_offload_sflow;
>> +
>> +struct dpif_offload_api {
> Can we add help details on each function below, preferably as in the netdev/dpif_class definitions? i.e., describe the function, its input parameters, and return value?
Done. In dpif_class, we only have:
     const struct dpif_offload_api *offload_api;

So it is better to add help details in the definition of struct 
dpif_offload_api.
>
>> +    void (*init)(void);
> Do we want to think ahead and allow init to fail? Other init callbacks return int.
We don't want to fail the whole offload if dpif offload fails to init. 
So we don't check the return value.
>
>> +    void (*uninit)(void);
> Don't really like the uninit() function name. I like destroy() as it sort of indicates we should no longer use this resource once called.
> However, in other projects, they use deinit() a lot, but to me, it does not express the urgency to no use it after the call.
Done.
>
>> +    void (*sflow_recv_wait)(void);
>> +    int (*sflow_recv)(struct dpif_offload_sflow *sflow);
>> +};
>> +
>> +void dpif_offload_sflow_recv_wait(const struct dpif *dpif);
>> +int dpif_offload_sflow_recv(const struct dpif *dpif,
>> +                            struct dpif_offload_sflow *sflow);
>> +
>> +#endif /* DPIF_OFFLOAD_PROVIDER_H */
>> diff --git a/lib/dpif-offload.c b/lib/dpif-offload.c
>> new file mode 100644
>> index 000000000..842e05798
>> --- /dev/null
>> +++ b/lib/dpif-offload.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:
>> + *
>> + *     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 <errno.h>
>> +
>> +#include "dpif-provider.h"
>> +
>> +void
>> +dpif_offload_sflow_recv_wait(const struct dpif *dpif)
>> +{
>> +    const struct dpif_offload_api *offload_api = dpif->dpif_class->offload_api;
>> +
>> +    if (offload_api && offload_api->sflow_recv_wait) {
>> +        offload_api->sflow_recv_wait();
>> +    }
>> +}
>> +
>> +int
>> +dpif_offload_sflow_recv(const struct dpif *dpif,
>> +                        struct dpif_offload_sflow *sflow)
>> +{
>> +    const struct dpif_offload_api *offload_api = dpif->dpif_class->offload_api;
>> +
>> +    if (offload_api && offload_api->sflow_recv) {
>> +        return offload_api->sflow_recv(sflow);
>> +    }
>> +
>> +    return EOPNOTSUPP;
>> +}
>> diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h
>> index 59e0a3a9d..7fb93d69d 100644
>> --- a/lib/dpif-provider.h
>> +++ b/lib/dpif-provider.h
>> @@ -22,8 +22,9 @@
>>    * exposed over OpenFlow as a single switch.  Datapaths and the collections of
>>    * ports that they contain may be fixed or dynamic. */
>>
>> -#include "openflow/openflow.h"
>>   #include "dpif.h"
>> +#include "dpif-offload-provider.h"
>> +#include "openflow/openflow.h"
>>   #include "util.h"
>>
>>   #ifdef  __cplusplus
>> @@ -633,6 +634,11 @@ struct dpif_class {
>>        * sufficient to store BOND_BUCKETS number of elements. */
>>       int (*bond_stats_get)(struct dpif *dpif, uint32_t bond_id,
>>                             uint64_t *n_bytes);
>> +
>> +    /* Some offload actions require functionality that is not netdev based,
>> +     * but dpif. Add dpif-offload-provider layer API to support such
>> +     * offload actions. */
>> +    const struct dpif_offload_api *offload_api;
> Here you add the provider directly into the dpif class. Not sure if this is what Ilya had in mind. As in general, these get integrated into the dpif/netdev, not the class. Ilya can you comment on/review this?
OK.
>
>>   };
>>
>>   extern const struct dpif_class dpif_netlink_class;
>> diff --git a/lib/dpif.c b/lib/dpif.c
>> index 26e8bfb7d..a0987988a 100644
>> --- a/lib/dpif.c
>> +++ b/lib/dpif.c
>> @@ -153,6 +153,10 @@ dp_register_provider__(const struct dpif_class *new_class)
>>           return error;
>>       }
>>
>> +    if (new_class->offload_api && new_class->offload_api->init) {
>> +        new_class->offload_api->init();
>> +    }
>> +
>>       registered_class = xmalloc(sizeof *registered_class);
>>       registered_class->dpif_class = new_class;
>>       registered_class->refcount = 0;
>> @@ -183,6 +187,7 @@ static int
>>   dp_unregister_provider__(const char *type)
>>   {
>>       struct shash_node *node;
>> +    const struct dpif_class *dpif_class;
>>       struct registered_dpif_class *registered_class;
>>
>>       node = shash_find(&dpif_classes, type);
>> @@ -196,6 +201,11 @@ dp_unregister_provider__(const char *type)
>>           return EBUSY;
>>       }
>>
>> +    dpif_class = registered_class->dpif_class;
>> +    if (dpif_class->offload_api && dpif_class->offload_api->uninit) {
>> +        dpif_class->offload_api->uninit();
>> +    }
>> +
>>       shash_delete(&dpif_classes, node);
>>       free(registered_class);
>>
>> -- 
>> 2.21.0
diff mbox series

Patch

diff --git a/lib/automake.mk b/lib/automake.mk
index 3c9523c1a..dc865b0ef 100644
--- a/lib/automake.mk
+++ b/lib/automake.mk
@@ -123,6 +123,8 @@  lib_libopenvswitch_la_SOURCES = \
 	lib/dpif-netdev-private.h \
 	lib/dpif-netdev-perf.c \
 	lib/dpif-netdev-perf.h \
+	lib/dpif-offload.c \
+	lib/dpif-offload-provider.h \
 	lib/dpif-provider.h \
 	lib/dpif.c \
 	lib/dpif.h \
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 610949f36..35d73542b 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -8269,6 +8269,7 @@  const struct dpif_class dpif_netdev_class = {
     dpif_netdev_bond_add,
     dpif_netdev_bond_del,
     dpif_netdev_bond_stats_get,
+    NULL,                       /* dpif_offlod_api */
 };
 
 static void
diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c
index 39dc8300e..6a7defb95 100644
--- a/lib/dpif-netlink.c
+++ b/lib/dpif-netlink.c
@@ -34,6 +34,7 @@ 
 
 #include "bitmap.h"
 #include "dpif-netlink-rtnl.h"
+#include "dpif-offload-provider.h"
 #include "dpif-provider.h"
 #include "fat-rwlock.h"
 #include "flow.h"
@@ -4036,6 +4037,7 @@  const struct dpif_class dpif_netlink_class = {
     NULL,                       /* bond_add */
     NULL,                       /* bond_del */
     NULL,                       /* bond_stats_get */
+    NULL,                       /* dpif_offlod_api */
 };
 
 static int
diff --git a/lib/dpif-offload-provider.h b/lib/dpif-offload-provider.h
new file mode 100644
index 000000000..97108402a
--- /dev/null
+++ b/lib/dpif-offload-provider.h
@@ -0,0 +1,34 @@ 
+/*
+ * 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:
+ *
+ *     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 DPIF_OFFLOAD_PROVIDER_H
+#define DPIF_OFFLOAD_PROVIDER_H
+
+struct dpif;
+struct dpif_offload_sflow;
+
+struct dpif_offload_api {
+    void (*init)(void);
+    void (*uninit)(void);
+    void (*sflow_recv_wait)(void);
+    int (*sflow_recv)(struct dpif_offload_sflow *sflow);
+};
+
+void dpif_offload_sflow_recv_wait(const struct dpif *dpif);
+int dpif_offload_sflow_recv(const struct dpif *dpif,
+                            struct dpif_offload_sflow *sflow);
+
+#endif /* DPIF_OFFLOAD_PROVIDER_H */
diff --git a/lib/dpif-offload.c b/lib/dpif-offload.c
new file mode 100644
index 000000000..842e05798
--- /dev/null
+++ b/lib/dpif-offload.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:
+ *
+ *     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 <errno.h>
+
+#include "dpif-provider.h"
+
+void
+dpif_offload_sflow_recv_wait(const struct dpif *dpif)
+{
+    const struct dpif_offload_api *offload_api = dpif->dpif_class->offload_api;
+
+    if (offload_api && offload_api->sflow_recv_wait) {
+        offload_api->sflow_recv_wait();
+    }
+}
+
+int
+dpif_offload_sflow_recv(const struct dpif *dpif,
+                        struct dpif_offload_sflow *sflow)
+{
+    const struct dpif_offload_api *offload_api = dpif->dpif_class->offload_api;
+
+    if (offload_api && offload_api->sflow_recv) {
+        return offload_api->sflow_recv(sflow);
+    }
+
+    return EOPNOTSUPP;
+}
diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h
index 59e0a3a9d..7fb93d69d 100644
--- a/lib/dpif-provider.h
+++ b/lib/dpif-provider.h
@@ -22,8 +22,9 @@ 
  * exposed over OpenFlow as a single switch.  Datapaths and the collections of
  * ports that they contain may be fixed or dynamic. */
 
-#include "openflow/openflow.h"
 #include "dpif.h"
+#include "dpif-offload-provider.h"
+#include "openflow/openflow.h"
 #include "util.h"
 
 #ifdef  __cplusplus
@@ -633,6 +634,11 @@  struct dpif_class {
      * sufficient to store BOND_BUCKETS number of elements. */
     int (*bond_stats_get)(struct dpif *dpif, uint32_t bond_id,
                           uint64_t *n_bytes);
+
+    /* Some offload actions require functionality that is not netdev based,
+     * but dpif. Add dpif-offload-provider layer API to support such
+     * offload actions. */
+    const struct dpif_offload_api *offload_api;
 };
 
 extern const struct dpif_class dpif_netlink_class;
diff --git a/lib/dpif.c b/lib/dpif.c
index 26e8bfb7d..a0987988a 100644
--- a/lib/dpif.c
+++ b/lib/dpif.c
@@ -153,6 +153,10 @@  dp_register_provider__(const struct dpif_class *new_class)
         return error;
     }
 
+    if (new_class->offload_api && new_class->offload_api->init) {
+        new_class->offload_api->init();
+    }
+
     registered_class = xmalloc(sizeof *registered_class);
     registered_class->dpif_class = new_class;
     registered_class->refcount = 0;
@@ -183,6 +187,7 @@  static int
 dp_unregister_provider__(const char *type)
 {
     struct shash_node *node;
+    const struct dpif_class *dpif_class;
     struct registered_dpif_class *registered_class;
 
     node = shash_find(&dpif_classes, type);
@@ -196,6 +201,11 @@  dp_unregister_provider__(const char *type)
         return EBUSY;
     }
 
+    dpif_class = registered_class->dpif_class;
+    if (dpif_class->offload_api && dpif_class->offload_api->uninit) {
+        dpif_class->offload_api->uninit();
+    }
+
     shash_delete(&dpif_classes, node);
     free(registered_class);