[ovs-dev] [PATCH v2] datapath-windows: Netlink command: vport dump
Eitan Eliahu
eliahue at vmware.com
Wed Sep 17 16:30:54 UTC 2014
Hi Sam,
Looks good. Some comments:
Shouldn't we check the return code from NlMsgPutTailU32() ?
Do we check the size of the out message before we populate it with the port NL attributes?
Thanks,
Eitan
-----Original Message-----
From: Samuel Ghinet [mailto:sghinet at cloudbasesolutions.com]
Sent: Wednesday, September 17, 2014 6:09 AM
To: dev at openvswitch.org
Cc: Nithin Raju; Eitan Eliahu; Saurabh Shah; Ankur Sharma; Alin Serdean
Subject: [PATCH v2] datapath-windows: Netlink command: vport dump
Functionality for vport dump.
Later, when we will add more netlink dump commands, some common code will need to be split to functions.
Notes:
a) the current implementation of vport assumes the datapath feature "multiple upcall pids" is not used. A single upcall pid is used instead.
c) the vxlan destination udp port is currently a constant. When it will become configurable, the vport options netlink attribute will become relevant.
Signed-off-by: Samuel Ghinet <sghinet at cloudbasesolutions.com>
---
datapath-windows/ovsext/Datapath.c | 222 ++++++++++++++++++++++++++++++++++++-
datapath-windows/ovsext/Vport.h | 11 +-
2 files changed, 227 insertions(+), 6 deletions(-)
diff --git a/datapath-windows/ovsext/Datapath.c b/datapath-windows/ovsext/Datapath.c
index d90ae23..5e9aadf 100644
--- a/datapath-windows/ovsext/Datapath.c
+++ b/datapath-windows/ovsext/Datapath.c
@@ -101,6 +101,9 @@ static NTSTATUS OvsGetPidCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx, static NTSTATUS OvsGetDpCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
UINT32 *replyLen);
+static NTSTATUS OvsGetVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
+ UINT32 *replyLen);
+
/*
* The various netlink families, along with the supported commands. Most of
* these families and commands are part of the openvswitch specification for a @@ -156,14 +159,20 @@ NETLINK_FAMILY nlPacketFamilyOps = { };
/* Netlink vport family. */
+NETLINK_CMD nlVportFamilyCmdOps[] = {
+ { OVS_VPORT_CMD_GET, OvsGetVportCmdHandler,
+ OVS_WRITE_DEV_OP | OVS_READ_DEV_OP, FALSE } };
+
+/* Netlink vport family. */
/* XXX: Add commands here. */
NETLINK_FAMILY nlVportFamilyOps = {
.name = OVS_VPORT_FAMILY,
.id = OVS_WIN_NL_VPORT_FAMILY_ID,
.version = OVS_VPORT_VERSION,
.maxAttr = OVS_VPORT_ATTR_MAX,
- .cmds = NULL, /* XXX: placeholder. */
- .opsCount = 0
+ .cmds = nlVportFamilyCmdOps,
+ .opsCount = ARRAY_SIZE(nlVportFamilyCmdOps)
};
/* Netlink flow family. */
@@ -668,10 +677,11 @@ OvsDeviceControl(PDEVICE_OBJECT deviceObject,
break;
case OVS_WIN_NL_PACKET_FAMILY_ID:
case OVS_WIN_NL_FLOW_FAMILY_ID:
- case OVS_WIN_NL_VPORT_FAMILY_ID:
status = STATUS_NOT_IMPLEMENTED;
goto done;
-
+ case OVS_WIN_NL_VPORT_FAMILY_ID:
+ nlFamilyOps = &nlVportFamilyOps;
+ break;
default:
status = STATUS_INVALID_PARAMETER;
goto done;
@@ -966,6 +976,210 @@ OvsSetupDumpStart(POVS_USER_PARAMS_CONTEXT usrParamsCtx) }
/*
+* XXX: When "dump done" and "error" netlink types will be implemented,
+we will
+* need a few more BuildMsgOut functions, which would ultimately call a
+generic
+* BuildMsgOutFromMsgIn.
+*/
+
+static VOID
+BuildMsgOutFromMsgIn(POVS_MESSAGE msgIn, POVS_MESSAGE msgOut, UINT16
+flags) {
+ msgOut->nlMsg.nlmsgType = msgIn->nlMsg.nlmsgType;
+ msgOut->nlMsg.nlmsgFlags = flags;
+ msgOut->nlMsg.nlmsgSeq = msgIn->nlMsg.nlmsgSeq;
+ msgOut->nlMsg.nlmsgPid = msgIn->nlMsg.nlmsgPid;
+ msgOut->nlMsg.nlmsgLen = sizeof *msgOut;
+
+ msgOut->genlMsg.cmd = msgIn->genlMsg.cmd;
+ msgOut->genlMsg.version = nlDatapathFamilyOps.version;
+ msgOut->genlMsg.reserved = 0;
+}
+
+static NTSTATUS
+OvsCreateMsgFromVport(POVS_VPORT_ENTRY vport,
+ POVS_MESSAGE msgOut,
+ UINT32 maxPayloadSize) {
+ NL_BUFFER nlBuffer;
+ OVS_VPORT_FULL_STATS vportStats;
+
+ NlBufInit(&nlBuffer, (PCHAR)msgOut + sizeof (*msgOut),
+ maxPayloadSize);
+
+ NlMsgPutTailU32(&nlBuffer, OVS_VPORT_ATTR_PORT_NO, vport->portNo);
+ NlMsgPutTailU32(&nlBuffer, OVS_VPORT_ATTR_TYPE, vport->ovsType);
+
+ NlMsgPutTailString(&nlBuffer, OVS_VPORT_ATTR_NAME, vport->ovsName);
+
+ /*
+ * XXX: when we implement OVS_DP_ATTR_USER_FEATURES in datapath,
+ * we'll need to check the OVS_DP_F_VPORT_PIDS flag: if it is set,
+ * it means we have an array of pids, instead of a single pid.
+ * ATM we assume we have one pid only.
+ */
+
+ NlMsgPutTailU32(&nlBuffer, OVS_VPORT_ATTR_UPCALL_PID,
+ vport->upcallPid);
+
+ /*stats*/
+ vportStats.rxPackets = vport->stats.rxPackets;
+ vportStats.rxBytes = vport->stats.rxBytes;
+ vportStats.txPackets = vport->stats.txPackets;
+ vportStats.txBytes = vport->stats.txBytes;
+ vportStats.rxErrors = vport->errStats.rxErrors;
+ vportStats.txErrors = vport->errStats.txErrors;
+ vportStats.rxDropped = vport->errStats.rxDropped;
+ vportStats.txDropped = vport->errStats.txDropped;
+
+ NlMsgPutTailUnspec(&nlBuffer, OVS_VPORT_ATTR_STATS, (PCHAR)&vportStats,
+ sizeof(OVS_VPORT_FULL_STATS));
+
+ /*
+ * XXX: when vxlan udp dest port becomes configurable, we will also need
+ * to add vport options
+ */
+
+ msgOut->nlMsg.nlmsgLen = NlBufSize(&nlBuffer) +
+ sizeof(OVS_MESSAGE);
+
+ return STATUS_SUCCESS;
+}
+
+static NTSTATUS
+OvsGetVportDumpNext(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
+ UINT32 *replyLen)
+{
+ POVS_MESSAGE msgIn;
+ POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
+ POVS_OPEN_INSTANCE instance =
+ (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
+ LOCK_STATE_EX lockState;
+ UINT32 i = 0;
+
+ /*
+ * XXX: this function shares some code with other dump command(s).
+ * In the future, we will need to refactor the dump functions
+ */
+
+ ASSERT(usrParamsCtx->devOp == OVS_READ_DEV_OP);
+
+ if (instance->dumpState.ovsMsg == NULL) {
+ ASSERT(FALSE);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ /* Output buffer has been validated while validating read dev op. */
+ ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof
+ *msgOut);
+
+ msgIn = instance->dumpState.ovsMsg;
+ BuildMsgOutFromMsgIn(msgIn, msgOut, NLM_F_MULTI);
+
+ OvsAcquireCtrlLock();
+ if (!gOvsSwitchContext) {
+ /* Treat this as a dump done. */
+ OvsReleaseCtrlLock();
+ *replyLen = 0;
+ FreeUserDumpState(instance);
+ return STATUS_SUCCESS;
+ }
+
+ msgOut->ovsHdr.dp_ifindex = gOvsSwitchContext->dpNo;
+
+ /*
+ * XXX: when we implement OVS_DP_ATTR_USER_FEATURES in datapath,
+ * we'll need to check the OVS_DP_F_VPORT_PIDS flag: if it is set,
+ * it means we have an array of pids, instead of a single pid.
+ * ATM we assume we have one pid only.
+ */
+
+ NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState,
+ 0);
+
+ if (gOvsSwitchContext->numVports > 0) {
+ /* inBucket: the bucket, used for lookup */
+ UINT32 inBucket = instance->dumpState.index[0];
+ /* inIndex: index within the given bucket, used for lookup */
+ UINT32 inIndex = instance->dumpState.index[1];
+ /* the bucket to be used for the next dump operation */
+ UINT32 outBucket = 0;
+ /* the index within the outBucket to be used for the next dump */
+ UINT32 outIndex = 0;
+ UINT32 maxSize = usrParamsCtx->outputLength;
+
+ for (i = inBucket; i < OVS_MAX_VPORT_ARRAY_SIZE; i++) {
+ PLIST_ENTRY head, link;
+ head = &(gOvsSwitchContext->portHashArray[i]);
+ POVS_VPORT_ENTRY vport = NULL;
+
+ outIndex = 0;
+ LIST_FORALL(head, link) {
+
+ /*
+ * if one or more dumps were previously done on this same bucket,
+ * inIndex will be > 0, so we'll need to reply with the
+ * inIndex + 1 vport from the bucket.
+ */
+ if (outIndex >= inIndex) {
+ vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portLink);
+ OvsCreateMsgFromVport(vport, msgOut, maxSize);
+ ++outIndex;
+ break;
+ }
+
+ ++outIndex;
+ }
+
+ if (vport) {
+ break;
+ }
+
+ /*
+ * if no vport was found above, check the next bucket, beginning
+ * with the first (i.e. index 0) elem from within that bucket
+ */
+ inIndex = 0;
+ }
+
+ outBucket = i;
+
+ /* XXX: what about NLMSG_DONE (as msg type)? */
+ instance->dumpState.index[0] = outBucket;
+ instance->dumpState.index[1] = outIndex;
+ }
+
+ NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
+
+ OvsReleaseCtrlLock();
+
+ *replyLen = msgOut->nlMsg.nlmsgLen;
+
+ /* if i is OVS_MAX_VPORT_ARRAY_SIZE => no vport was found => dump done*/
+ if (i == OVS_MAX_VPORT_ARRAY_SIZE) {
+ *replyLen = 0;
+ /* Free up the dump state, since there's no more data to continue. */
+ FreeUserDumpState(instance);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+/*
+*
+-----------------------------------------------------------------------
+---
+* Handler for the get vport command. The function handles the initial
+call to
+* setup the dump state, as well as subsequent calls to continue dumping data.
+*
+-----------------------------------------------------------------------
+---
+*/
+static NTSTATUS
+OvsGetVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
+ UINT32 *replyLen) {
+ if (usrParamsCtx->devOp == OVS_WRITE_DEV_OP) {
+ *replyLen = 0;
+ OvsSetupDumpStart(usrParamsCtx);
+ } else {
+ return OvsGetVportDumpNext(usrParamsCtx, replyLen);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+/*
* --------------------------------------------------------------------------
* Utility function to map the output buffer in an IRP. The buffer is assumed
* to have been passed down using METHOD_OUT_DIRECT (Direct I/O).
diff --git a/datapath-windows/ovsext/Vport.h b/datapath-windows/ovsext/Vport.h index 80bdea8..0305d35 100644
--- a/datapath-windows/ovsext/Vport.h
+++ b/datapath-windows/ovsext/Vport.h
@@ -39,10 +39,10 @@ typedef enum {
} OVS_VPORT_STATE;
typedef struct _OVS_VPORT_STATS {
- UINT64 rxBytes;
UINT64 rxPackets;
- UINT64 txBytes;
UINT64 txPackets;
+ UINT64 rxBytes;
+ UINT64 txBytes;
} OVS_VPORT_STATS;
typedef struct _OVS_VPORT_ERR_STATS {
@@ -51,6 +51,12 @@ typedef struct _OVS_VPORT_ERR_STATS {
UINT64 rxDropped;
UINT64 txDropped;
} OVS_VPORT_ERR_STATS;
+
+/* used for vport netlink commands. */
+typedef struct _OVS_VPORT_FULL_STATS {
+ OVS_VPORT_STATS;
+ OVS_VPORT_ERR_STATS;
+}OVS_VPORT_FULL_STATS;
/*
* Each internal, external adapter or vritual adapter has
* one vport entry. In addition, we have one vport for each @@ -86,6 +92,7 @@ typedef struct _OVS_VPORT_ENTRY {
NDIS_SWITCH_NIC_NAME nicName;
NDIS_VM_NAME vmName;
GUID netCfgInstanceId;
+ UINT32 upcallPid; /* netlink upcall port id */
} OVS_VPORT_ENTRY, *POVS_VPORT_ENTRY;
struct _OVS_SWITCH_CONTEXT;
--
1.8.3.msysgit.0
More information about the dev
mailing list