In thread handler 0, add netdev offload recv in normal recv upcalls.
To avoid starvation, introduce a flag to alternate the order of
receiving normal upcalls and offload upcalls based on that flag.
Add similar change for recv_wait.
Signed-off-by: Chris Mi<c...@nvidia.com>
Reviewed-by: Roi Dayan<r...@nvidia.com>
---
lib/dpif-netlink.c | 46 ++++++++++++++++++++++++++++++++---
ofproto/ofproto-dpif-upcall.c | 23 +++++++++++++++---
2 files changed, 62 insertions(+), 7 deletions(-)
diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c
index 586fb8893..9f67db1be 100644
--- a/lib/dpif-netlink.c
+++ b/lib/dpif-netlink.c
@@ -201,6 +201,12 @@ struct dpif_handler {
struct nl_sock *sock; /* Each handler thread holds one netlink
socket. */
+ /* Thread handler 0 deals with both netdev offload recv and normal
+ * recv upcalls. To avoid starvation, introduce a flag to alternate
+ * the order.
+ */
+ bool recv_offload_first;
+
#ifdef _WIN32
/* Pool of sockets. */
struct dpif_windows_vport_sock *vport_sock_pool;
@@ -3130,13 +3136,12 @@ dpif_netlink_recv_vport_dispatch(struct dpif_netlink
*dpif,
#endif
static int
-dpif_netlink_recv(struct dpif *dpif_, uint32_t handler_id,
- struct dpif_upcall *upcall, struct ofpbuf *buf)
+dpif_netlink_recv__(struct dpif *dpif_, uint32_t handler_id,
+ struct dpif_upcall *upcall, struct ofpbuf *buf)
{
struct dpif_netlink *dpif = dpif_netlink_cast(dpif_);
int error;
- fat_rwlock_rdlock(&dpif->upcall_lock);
#ifdef _WIN32
error = dpif_netlink_recv_windows(dpif, handler_id, upcall, buf);
#else
@@ -3147,6 +3152,38 @@ dpif_netlink_recv(struct dpif *dpif_, uint32_t
handler_id,
handler_id, upcall, buf);
}
#endif
+
+ return error;
+}
+
+static int
+dpif_netlink_recv(struct dpif *dpif_, uint32_t handler_id,
+ struct dpif_upcall *upcall, struct ofpbuf *buf)
+{
+ struct dpif_netlink *dpif = dpif_netlink_cast(dpif_);
+ struct dpif_handler *handler;
+ int error;
+
+ fat_rwlock_rdlock(&dpif->upcall_lock);
+ if (handler_id) {
+ error = dpif_netlink_recv__(dpif_, handler_id, upcall, buf);
+ fat_rwlock_unlock(&dpif->upcall_lock);
+ return error;
+ }
+
+ handler = &dpif->handlers[handler_id];
+ if (handler->recv_offload_first) {
+ error = netdev_offload_recv(upcall, buf);
+ if (error == EAGAIN) {
+ error = dpif_netlink_recv__(dpif_, handler_id, upcall, buf);
+ }
+ } else {
+ error = dpif_netlink_recv__(dpif_, handler_id, upcall, buf);
+ if (error == EAGAIN) {
+ error = netdev_offload_recv(upcall, buf);
+ }
+ }
+ handler->recv_offload_first = !handler->recv_offload_first;
fat_rwlock_unlock(&dpif->upcall_lock);
return error;
@@ -3211,6 +3248,9 @@ dpif_netlink_recv_wait(struct dpif *dpif_, uint32_t
handler_id)
} else {
dpif_netlink_recv_wait_vport_dispatch(dpif, handler_id);
}
+ if (handler_id == 0) {
+ netdev_offload_recv_wait();
+ }
#endif
fat_rwlock_unlock(&dpif->upcall_lock);
}
diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c
index fc94078cb..273b576bd 100644
--- a/ofproto/ofproto-dpif-upcall.c
+++ b/ofproto/ofproto-dpif-upcall.c
@@ -840,10 +840,25 @@ recv_upcalls(struct handler *handler)
break;
}
- upcall->fitness = odp_flow_key_to_flow(dupcall->key, dupcall->key_len,
- flow, NULL);
- if (upcall->fitness == ODP_FIT_ERROR) {
- goto free_dupcall;
+ /* If it is normal upcalls, datapath will provide key and key_len
+ * to construct flow. But for netdev offload upcalls, key and
+ * key_len are not available. Construct partial flow using available
+ * info.> + */
+ if (dupcall->key && dupcall->key_len) {
+ upcall->fitness = odp_flow_key_to_flow(dupcall->key,
+ dupcall->key_len,
+ flow, NULL);
+ if (upcall->fitness == ODP_FIT_ERROR) {
+ goto free_dupcall;
+ }
+ } else {
+ memset(flow, 0, sizeof *flow);
+ if (dupcall->in_tun) {
+ memcpy(&flow->tunnel, dupcall->in_tun, sizeof flow->tunnel);
+ }
+ flow->in_port.odp_port =
+ netdev_ifindex_to_odp_port(dupcall->iifindex);