summaryrefslogtreecommitdiff
path: root/datapath-windows
diff options
context:
space:
mode:
authorSamuel Ghinet <sghinet@cloudbasesolutions.com>2014-09-25 21:21:33 +0000
committerBen Pfaff <blp@nicira.com>2014-09-26 10:22:11 -0700
commit17c6a05f08a7570dba05a171b08068a71966f11f (patch)
tree2d7ddc471c81eed7f564459453484cdbcca40c1d /datapath-windows
parente00afcf6427ab3b99c6ad0867c2a22bfe9ead180 (diff)
downloadopenvswitch-17c6a05f08a7570dba05a171b08068a71966f11f.tar.gz
datapath-windows: Implement vport dump Netlink command.
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 now. 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@cloudbasesolutions.com> Acked-by: Alin Gabriel Serdean <aserdean@cloudbasesolutions.com> Acked-by: Nithin Raju <nithin@vmware.com> Signed-off-by: Ben Pfaff <blp@nicira.com>
Diffstat (limited to 'datapath-windows')
-rw-r--r--datapath-windows/ovsext/Datapath.c273
-rw-r--r--datapath-windows/ovsext/Vport.h11
2 files changed, 276 insertions, 8 deletions
diff --git a/datapath-windows/ovsext/Datapath.c b/datapath-windows/ovsext/Datapath.c
index 0dfdd57d7..25d6f874a 100644
--- a/datapath-windows/ovsext/Datapath.c
+++ b/datapath-windows/ovsext/Datapath.c
@@ -99,7 +99,8 @@ static NetlinkCmdHandler OvsGetPidCmdHandler,
OvsGetDpCmdHandler,
OvsPendEventCmdHandler,
OvsSubscribeEventCmdHandler,
- OvsSetDpCmdHandler;
+ OvsSetDpCmdHandler,
+ OvsGetVportCmdHandler;
static NTSTATUS HandleGetDpTransaction(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
UINT32 *replyLen);
@@ -180,14 +181,22 @@ NETLINK_FAMILY nlPacketFamilyOps = {
};
/* Netlink vport family. */
-/* XXX: Add commands here. */
+NETLINK_CMD nlVportFamilyCmdOps[] = {
+ { .cmd = OVS_VPORT_CMD_GET,
+ .handler = OvsGetVportCmdHandler,
+ .supportedDevOp = OVS_WRITE_DEV_OP | OVS_READ_DEV_OP |
+ OVS_TRANSACTION_DEV_OP,
+ .validateDpIndex = TRUE
+ }
+};
+
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. */
@@ -691,10 +700,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;
@@ -1179,6 +1189,257 @@ OvsSetupDumpStart(POVS_USER_PARAMS_CONTEXT usrParamsCtx)
return InitUserDumpState(instance, msgIn);
}
+static VOID
+BuildMsgOut(POVS_MESSAGE msgIn, POVS_MESSAGE msgOut, UINT16 type,
+ UINT32 length, UINT16 flags)
+{
+ msgOut->nlMsg.nlmsgType = type;
+ msgOut->nlMsg.nlmsgFlags = flags;
+ msgOut->nlMsg.nlmsgSeq = msgIn->nlMsg.nlmsgSeq;
+ msgOut->nlMsg.nlmsgPid = msgIn->nlMsg.nlmsgPid;
+ msgOut->nlMsg.nlmsgLen = length;
+
+ msgOut->genlMsg.cmd = msgIn->genlMsg.cmd;
+ msgOut->genlMsg.version = nlDatapathFamilyOps.version;
+ msgOut->genlMsg.reserved = 0;
+}
+
+static VOID
+BuildReplyMsgFromMsgIn(POVS_MESSAGE msgIn, POVS_MESSAGE msgOut, UINT16 flags)
+{
+ BuildMsgOut(msgIn, msgOut, msgIn->nlMsg.nlmsgType, sizeof(OVS_MESSAGE),
+ flags);
+}
+
+static NTSTATUS
+OvsCreateMsgFromVport(POVS_VPORT_ENTRY vport,
+ POVS_MESSAGE msgIn,
+ PVOID outBuffer,
+ UINT32 outBufLen,
+ int dpIfIndex)
+{
+ NL_BUFFER nlBuffer;
+ OVS_VPORT_FULL_STATS vportStats;
+ BOOLEAN ok;
+ OVS_MESSAGE msgOut;
+ PNL_MSG_HDR nlMsg;
+
+ NlBufInit(&nlBuffer, outBuffer, outBufLen);
+
+ BuildReplyMsgFromMsgIn(msgIn, &msgOut, NLM_F_MULTI);
+ msgOut.ovsHdr.dp_ifindex = dpIfIndex;
+
+ ok = NlMsgPutHead(&nlBuffer, (PCHAR)&msgOut, sizeof msgOut);
+ if (!ok) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ ok = NlMsgPutTailU32(&nlBuffer, OVS_VPORT_ATTR_PORT_NO, vport->portNo);
+ if (!ok) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ ok = NlMsgPutTailU32(&nlBuffer, OVS_VPORT_ATTR_TYPE, vport->ovsType);
+ if (!ok) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ ok = NlMsgPutTailString(&nlBuffer, OVS_VPORT_ATTR_NAME, vport->ovsName);
+ if (!ok) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /*
+ * 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.
+ */
+
+ ok = NlMsgPutTailU32(&nlBuffer, OVS_VPORT_ATTR_UPCALL_PID,
+ vport->upcallPid);
+ if (!ok) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /*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;
+
+ ok = NlMsgPutTailUnspec(&nlBuffer, OVS_VPORT_ATTR_STATS,
+ (PCHAR)&vportStats,
+ sizeof(OVS_VPORT_FULL_STATS));
+ if (!ok) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /*
+ * XXX: when vxlan udp dest port becomes configurable, we will also need
+ * to add vport options
+ */
+
+ nlMsg = (PNL_MSG_HDR)NlBufAt(&nlBuffer, 0, 0);
+ nlMsg->nlmsgLen = NlBufSize(&nlBuffer);
+
+ return STATUS_SUCCESS;
+}
+
+static NTSTATUS
+OvsGetVportDumpNext(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
+ UINT32 *replyLen)
+{
+ POVS_MESSAGE msgIn;
+ POVS_OPEN_INSTANCE instance =
+ (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
+ LOCK_STATE_EX lockState;
+ UINT32 i = OVS_MAX_VPORT_ARRAY_SIZE;
+
+ /*
+ * 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(usrParamsCtx->outputBuffer != NULL);
+
+ msgIn = instance->dumpState.ovsMsg;
+
+ OvsAcquireCtrlLock();
+ if (!gOvsSwitchContext) {
+ /* Treat this as a dump done. */
+ OvsReleaseCtrlLock();
+ *replyLen = 0;
+ FreeUserDumpState(instance);
+ return STATUS_SUCCESS;
+ }
+
+ /*
+ * 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;
+
+ 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);
+
+ if (vport->portNo != 0) {
+ OvsCreateMsgFromVport(vport, msgIn,
+ usrParamsCtx->outputBuffer,
+ usrParamsCtx->outputLength,
+ gOvsSwitchContext->dpNo);
+ ++outIndex;
+ break;
+ } else {
+ vport = NULL;
+ }
+ }
+
+ ++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();
+
+ /* if i < OVS_MAX_VPORT_ARRAY_SIZE => vport was found */
+ if (i < OVS_MAX_VPORT_ARRAY_SIZE) {
+ POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
+ *replyLen = msgOut->nlMsg.nlmsgLen;
+ } else {
+ /*
+ * if i >= OVS_MAX_VPORT_ARRAY_SIZE => vport was not found =>
+ * it's dump done
+ */
+ *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)
+{
+ switch (usrParamsCtx->devOp)
+ {
+ case OVS_WRITE_DEV_OP:
+ *replyLen = 0;
+ return OvsSetupDumpStart(usrParamsCtx);
+
+ case OVS_READ_DEV_OP:
+ return OvsGetVportDumpNext(usrParamsCtx, replyLen);
+
+ default:
+ return STATUS_INVALID_DEVICE_REQUEST;
+ }
+
+}
+
/*
* --------------------------------------------------------------------------
* Utility function to map the output buffer in an IRP. The buffer is assumed
diff --git a/datapath-windows/ovsext/Vport.h b/datapath-windows/ovsext/Vport.h
index fe48d1e61..5450fcab5 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
@@ -87,6 +93,7 @@ typedef struct _OVS_VPORT_ENTRY {
NDIS_VM_NAME vmName;
GUID netCfgInstanceId;
BOOLEAN isExternal;
+ UINT32 upcallPid; /* netlink upcall port id */
} OVS_VPORT_ENTRY, *POVS_VPORT_ENTRY;
struct _OVS_SWITCH_CONTEXT;