summaryrefslogtreecommitdiff
path: root/datapath-windows/ovsext
diff options
context:
space:
mode:
authorAnand Kumar <kumaranand@vmware.com>2018-09-19 11:39:21 -0700
committerAlin Gabriel Serdean <aserdean@ovn.org>2018-09-20 14:31:34 +0300
commita1d4207e2c8a751d03b45fa21e5d8370713b9047 (patch)
tree8efce3a3b1d7ef71f8fcc8b3c0b73a31bf1b7b45 /datapath-windows/ovsext
parent37ed637239bed0102037d6df2752fc515d6b4ed9 (diff)
downloadopenvswitch-a1d4207e2c8a751d03b45fa21e5d8370713b9047.tar.gz
datapath-windows: Add support to configure ct zone limits
This patch implements limiting conntrack entries per zone using dpctl commands. Example: ovs-appctl dpctl/ct-set-limits default=5 zone=1,limit=2 zone=1,limit=3 ovs-appctl dpct/ct-del-limits zone=4 ovs-appctl dpct/ct-get-limits zone=1,2,3 - Also update the netlink-socket.c to support netlink family 'OVS_WIN_NL_CTLIMIT_FAMILY_ID' for conntrack zone limit. Signed-off-by: Anand Kumar <kumaranand@vmware.com> Acked-by: Alin Gabriel Serdean <aserdean@ovn.org> Signed-off-by: Alin Gabriel Serdean <aserdean@ovn.org>
Diffstat (limited to 'datapath-windows/ovsext')
-rw-r--r--datapath-windows/ovsext/Conntrack.c167
-rw-r--r--datapath-windows/ovsext/Conntrack.h12
-rw-r--r--datapath-windows/ovsext/Datapath.c34
3 files changed, 210 insertions, 3 deletions
diff --git a/datapath-windows/ovsext/Conntrack.c b/datapath-windows/ovsext/Conntrack.c
index dd1660218..5be8e4d66 100644
--- a/datapath-windows/ovsext/Conntrack.c
+++ b/datapath-windows/ovsext/Conntrack.c
@@ -27,13 +27,17 @@
#define WINDOWS_TICK 10000000
#define SEC_TO_UNIX_EPOCH 11644473600LL
#define SEC_TO_NANOSEC 1000000000LL
+#define CT_MAX_ZONE (UINT16_MAX + 1)
KSTART_ROUTINE OvsConntrackEntryCleaner;
static PLIST_ENTRY ovsConntrackTable;
static OVS_CT_THREAD_CTX ctThreadCtx;
static PNDIS_RW_LOCK_EX *ovsCtBucketLock = NULL;
+static NDIS_SPIN_LOCK ovsCtZoneLock;
+static POVS_CT_ZONE_INFO zoneInfo = NULL;
extern POVS_SWITCH_CONTEXT gOvsSwitchContext;
static ULONG ctTotalEntries;
+static ULONG defaultCtLimit;
static __inline OvsCtFlush(UINT16 zone, struct ovs_key_ct_tuple_ipv4 *tuple);
static __inline NDIS_STATUS
@@ -94,6 +98,20 @@ OvsInitConntrack(POVS_SWITCH_CONTEXT context)
ZwClose(threadHandle);
threadHandle = NULL;
+ zoneInfo = OvsAllocateMemoryWithTag(sizeof(OVS_CT_ZONE_INFO) *
+ CT_MAX_ZONE, OVS_CT_POOL_TAG);
+ if (zoneInfo == NULL) {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto freeBucketLock;
+ }
+
+ NdisAllocateSpinLock(&ovsCtZoneLock);
+ defaultCtLimit = CT_MAX_ENTRIES;
+ for (UINT32 i = 0; i < CT_MAX_ZONE; i++) {
+ zoneInfo[i].entries = 0;
+ zoneInfo[i].limit = defaultCtLimit;
+ }
+
status = OvsNatInit();
if (status != STATUS_SUCCESS) {
@@ -149,6 +167,25 @@ OvsCleanupConntrack(VOID)
OvsFreeMemoryWithTag(ovsCtBucketLock, OVS_CT_POOL_TAG);
ovsCtBucketLock = NULL;
OvsNatCleanup();
+ NdisFreeSpinLock(&ovsCtZoneLock);
+ if (zoneInfo) {
+ OvsFreeMemoryWithTag(zoneInfo, OVS_CT_POOL_TAG);
+ }
+}
+
+VOID
+OvsCtSetZoneLimit(int zone, ULONG value) {
+ NdisAcquireSpinLock(&ovsCtZoneLock);
+ if (zone == -1) {
+ /* Set default limit for all zones. */
+ defaultCtLimit = value;
+ for (UINT32 i = 0; i < CT_MAX_ZONE; i++) {
+ zoneInfo[i].limit = value;
+ }
+ } else {
+ zoneInfo[(UINT16)zone].limit = value;
+ }
+ NdisReleaseSpinLock(&ovsCtZoneLock);
}
/*
@@ -263,6 +300,7 @@ OvsCtAddEntry(POVS_CT_ENTRY entry,
&entry->link);
NdisInterlockedIncrement((PLONG)&ctTotalEntries);
+ NdisInterlockedIncrement((PLONG)&zoneInfo[ctx->key.zone].entries);
NdisReleaseRWLock(ovsCtBucketLock[bucketIdx], &lockState);
return TRUE;
}
@@ -437,6 +475,7 @@ OvsCtEntryDelete(POVS_CT_ENTRY entry, BOOLEAN forceDelete)
if (entry->natInfo.natAction) {
OvsNatDeleteKey(&entry->key);
}
+ NdisInterlockedDecrement((PLONG)&zoneInfo[entry->key.zone].entries);
OvsPostCtEventEntry(entry, OVS_EVENT_CT_DELETE);
RemoveEntryList(&entry->link);
OVS_RELEASE_SPIN_LOCK(&(entry->lock), irql);
@@ -877,12 +916,16 @@ OvsCtExecute_(OvsForwardingContext *fwdCtx,
&entryCreated);
} else {
- if (commit && ctTotalEntries >= CT_MAX_ENTRIES) {
+ if (commit && (ctTotalEntries >= CT_MAX_ENTRIES ||
+ zoneInfo[ctx.key.zone].entries >= zoneInfo[ctx.key.zone].limit)) {
/* Don't proceed with processing if the max limit has been hit.
* This blocks only new entries from being created and doesn't
* affect existing connections.
*/
- OVS_LOG_ERROR("Conntrack Limit hit: %lu", ctTotalEntries);
+ OVS_LOG_ERROR("Conntrack Limit hit: zone(%u), zoneLimit(%lu),"
+ "zoneEntries(%lu), ctTotalEntries(%lu)",
+ zone, zoneInfo[ctx.key.zone].limit,
+ zoneInfo[ctx.key.zone].entries, ctTotalEntries);
return NDIS_STATUS_RESOURCES;
}
/* If no matching entry was found, create one and add New state */
@@ -1783,4 +1826,124 @@ OvsCtDumpCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
return STATUS_SUCCESS;
}
+static NTSTATUS
+OvsCreateNlMsgFromCtLimit(POVS_MESSAGE msgIn,
+ PVOID outBuffer,
+ UINT32 outBufLen,
+ PCHAR attr,
+ UINT32 numAttrs,
+ int dpIfIndex)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ NL_BUFFER nlBuffer;
+ PNL_MSG_HDR nlMsg;
+ PGENL_MSG_HDR genlMsgHdr = &(msgIn->genlMsg);
+
+ NlBufInit(&nlBuffer, outBuffer, outBufLen);
+
+ if (!NlFillOvsMsg(&nlBuffer, msgIn->nlMsg.nlmsgType, NLM_F_MULTI,
+ msgIn->nlMsg.nlmsgSeq, msgIn->nlMsg.nlmsgPid,
+ msgIn->genlMsg.cmd, msgIn->genlMsg.version,
+ dpIfIndex)) {
+ return STATUS_INVALID_BUFFER_SIZE;
+ }
+
+ if (genlMsgHdr->cmd == OVS_CT_LIMIT_CMD_GET && numAttrs) {
+ POVS_CT_ZONE_LIMIT zoneLimitAttr = (POVS_CT_ZONE_LIMIT) attr;
+ UINT32 offset = NlMsgStartNested(&nlBuffer, OVS_CT_LIMIT_ATTR_ZONE_LIMIT);
+ if (!offset) {
+ /* Starting the nested attribute failed. */
+ status = STATUS_INVALID_BUFFER_SIZE;
+ goto done;
+ }
+
+ /* Insert OVS_CT_ZONE_LIMIT attributes.*/
+ for (UINT32 i = 0; i < numAttrs; i++) {
+ if (zoneLimitAttr) {
+ zoneLimitAttr->limit = zoneInfo[zoneLimitAttr->zone_id].limit;
+ zoneLimitAttr->count = zoneInfo[zoneLimitAttr->zone_id].entries;
+ if (zoneLimitAttr->zone_id == -1) {
+ zoneLimitAttr->limit = defaultCtLimit;
+ }
+ NlMsgPutTail(&nlBuffer, (const PCHAR)zoneLimitAttr,
+ sizeof(OVS_CT_ZONE_LIMIT));
+ } else {
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+ zoneLimitAttr = (POVS_CT_ZONE_LIMIT)((PCHAR) zoneLimitAttr +
+ sizeof(OVS_CT_ZONE_LIMIT));
+ }
+ NlMsgEndNested(&nlBuffer, offset);
+ }
+
+done:
+ nlMsg = (PNL_MSG_HDR)NlBufAt(&nlBuffer, 0, 0);
+ nlMsg->nlmsgLen = NlBufSize(&nlBuffer);
+
+ return status;
+}
+
+NTSTATUS
+OvsCtLimitHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
+ UINT32 *replyLen)
+{
+ NTSTATUS status;
+ POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
+ POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
+ PNL_MSG_HDR nlMsgHdr = &(msgIn->nlMsg);
+ PGENL_MSG_HDR genlMsgHdr = &(msgIn->genlMsg);
+ POVS_HDR ovsHdr = &(msgIn->ovsHdr);
+ PCHAR attr = NULL;
+ UINT32 numAttrs = 0;
+ UINT32 attrOffset = NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN;
+
+ static const NL_POLICY ovsCtLimitPolicy[] = {
+ [OVS_CT_LIMIT_ATTR_ZONE_LIMIT] = { .type = NL_A_NESTED, .optional = TRUE }
+ };
+ PNL_ATTR nlAttrs[ARRAY_SIZE(ovsCtLimitPolicy)];
+
+ if ((NlAttrParse(nlMsgHdr, attrOffset, NlMsgAttrsLen(nlMsgHdr),
+ ovsCtLimitPolicy, ARRAY_SIZE(ovsCtLimitPolicy),
+ nlAttrs, ARRAY_SIZE(nlAttrs)))
+ != TRUE) {
+ OVS_LOG_ERROR("Attr Parsing failed for msg: %p", nlMsgHdr);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (nlAttrs[OVS_CT_LIMIT_ATTR_ZONE_LIMIT]) {
+ numAttrs = NlAttrGetSize(nlAttrs[OVS_CT_LIMIT_ATTR_ZONE_LIMIT])/sizeof(OVS_CT_ZONE_LIMIT);
+ attr = NlAttrGet(nlAttrs[OVS_CT_LIMIT_ATTR_ZONE_LIMIT]);
+ }
+
+ if (genlMsgHdr->cmd == OVS_CT_LIMIT_CMD_SET ||
+ genlMsgHdr->cmd == OVS_CT_LIMIT_CMD_DEL) {
+ POVS_CT_ZONE_LIMIT zoneLimitAttr = (POVS_CT_ZONE_LIMIT)attr;
+ for (UINT32 i = 0; i < numAttrs; i++) {
+ /* Parse zone limit attributes. */
+ if (zoneLimitAttr) {
+ if (genlMsgHdr->cmd == OVS_CT_LIMIT_CMD_DEL) {
+ zoneLimitAttr->limit = CT_MAX_ENTRIES;
+ }
+ OvsCtSetZoneLimit(zoneLimitAttr->zone_id, zoneLimitAttr->limit);
+ } else {
+ OVS_LOG_ERROR("Failed to get zone limit attribute at index(%u),"
+ " numAttrs(%u)", i, numAttrs);
+ return STATUS_INVALID_PARAMETER;
+ }
+ zoneLimitAttr = (POVS_CT_ZONE_LIMIT)((PCHAR) zoneLimitAttr +
+ sizeof(OVS_CT_ZONE_LIMIT));
+ }
+ }
+
+ /* Output buffer has been validated while validating transact dev op. */
+ ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
+ status = OvsCreateNlMsgFromCtLimit(msgIn, msgOut,
+ usrParamsCtx->outputLength,
+ attr, numAttrs, ovsHdr->dp_ifindex);
+ *replyLen = msgOut->nlMsg.nlmsgLen;
+
+ return status;
+}
+
#pragma warning(pop)
diff --git a/datapath-windows/ovsext/Conntrack.h b/datapath-windows/ovsext/Conntrack.h
index d4152b33a..4678ed028 100644
--- a/datapath-windows/ovsext/Conntrack.h
+++ b/datapath-windows/ovsext/Conntrack.h
@@ -132,6 +132,18 @@ typedef struct OvsConntrackKeyLookupCtx {
BOOLEAN related;
} OvsConntrackKeyLookupCtx;
+/* Per zone strucuture. */
+typedef struct _OVS_CT_ZONE_INFO {
+ ULONG limit;
+ ULONG entries;
+} OVS_CT_ZONE_INFO, *POVS_CT_ZONE_INFO;
+
+typedef struct _OVS_CT_ZONE_LIMIT {
+ int zone_id;
+ ULONG limit;
+ ULONG count;
+} OVS_CT_ZONE_LIMIT, *POVS_CT_ZONE_LIMIT;
+
#define CT_MAX_ENTRIES 1 << 21
#define CT_HASH_TABLE_SIZE ((UINT32)1 << 10)
#define CT_HASH_TABLE_MASK (CT_HASH_TABLE_SIZE - 1)
diff --git a/datapath-windows/ovsext/Datapath.c b/datapath-windows/ovsext/Datapath.c
index 34ef2b40a..fa994840a 100644
--- a/datapath-windows/ovsext/Datapath.c
+++ b/datapath-windows/ovsext/Datapath.c
@@ -99,7 +99,8 @@ NetlinkCmdHandler OvsGetNetdevCmdHandler,
OvsSubscribePacketCmdHandler,
OvsReadPacketCmdHandler,
OvsCtDeleteCmdHandler,
- OvsCtDumpCmdHandler;
+ OvsCtDumpCmdHandler,
+ OvsCtLimitHandler;
static NTSTATUS HandleGetDpTransaction(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
UINT32 *replyLen);
@@ -324,6 +325,34 @@ NETLINK_FAMILY nlNetdevFamilyOps = {
.opsCount = ARRAY_SIZE(nlNetdevFamilyCmdOps)
};
+
+/* Netlink conntrack limit family. */
+NETLINK_CMD nlCtLimitFamilyCmdOps[] = {
+ { .cmd = OVS_CT_LIMIT_CMD_GET,
+ .handler = OvsCtLimitHandler,
+ .supportedDevOp = OVS_TRANSACTION_DEV_OP,
+ .validateDpIndex = FALSE
+ },
+ { .cmd = OVS_CT_LIMIT_CMD_SET,
+ .handler = OvsCtLimitHandler,
+ .supportedDevOp = OVS_TRANSACTION_DEV_OP,
+ .validateDpIndex = FALSE
+ },
+ { .cmd = OVS_CT_LIMIT_CMD_DEL,
+ .handler = OvsCtLimitHandler,
+ .supportedDevOp = OVS_TRANSACTION_DEV_OP,
+ .validateDpIndex = FALSE
+ },
+};
+
+NETLINK_FAMILY nlCtLimitFamilyOps = {
+ .name = OVS_CT_LIMIT_FAMILY,
+ .id = OVS_WIN_NL_CTLIMIT_FAMILY_ID,
+ .version = OVS_CT_LIMIT_VERSION,
+ .maxAttr = OVS_CT_LIMIT_ATTR_MAX,
+ .cmds = nlCtLimitFamilyCmdOps,
+ .opsCount = ARRAY_SIZE(nlCtLimitFamilyCmdOps)
+};
static NTSTATUS MapIrpOutputBuffer(PIRP irp,
UINT32 bufferLength,
UINT32 requiredLength,
@@ -941,6 +970,9 @@ OvsDeviceControl(PDEVICE_OBJECT deviceObject,
case OVS_WIN_NL_NETDEV_FAMILY_ID:
nlFamilyOps = &nlNetdevFamilyOps;
break;
+ case OVS_WIN_NL_CTLIMIT_FAMILY_ID:
+ nlFamilyOps = &nlCtLimitFamilyOps;
+ break;
default:
status = STATUS_INVALID_PARAMETER;
goto done;