2
* Copyright (c) 2014 VMware, Inc.
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
* you may not use this file except in compliance with the License.
6
* You may obtain a copy of the License at:
8
* http://www.apache.org/licenses/LICENSE-2.0
10
* Unless required by applicable law or agreed to in writing, software
11
* distributed under the License is distributed on an "AS IS" BASIS,
12
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
* See the License for the specific language governing permissions and
14
* limitations under the License.
32
#define OVS_DBG_MOD OVS_DBG_VPORT
35
#define VPORT_NIC_ENTER(_nic) \
36
OVS_LOG_TRACE("Enter: PortId: %x, NicIndex: %d", _nic->PortId, \
39
#define VPORT_NIC_EXIT(_nic) \
40
OVS_LOG_TRACE("Exit: PortId: %x, NicIndex: %d", _nic->PortId, \
43
#define VPORT_PORT_ENTER(_port) \
44
OVS_LOG_TRACE("Enter: PortId: %x", _port->PortId)
46
#define VPORT_PORT_EXIT(_port) \
47
OVS_LOG_TRACE("Exit: PortId: %x", _port->PortId)
49
#define OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC 100
51
/* Context structure used to pass back and forth information to the tunnel
53
typedef struct _OVS_TUNFLT_INIT_CONTEXT {
54
POVS_SWITCH_CONTEXT switchContext;
58
POVS_VPORT_ENTRY vport;
62
} OVS_TUNFLT_INIT_CONTEXT, *POVS_TUNFLT_INIT_CONTEXT;
65
extern POVS_SWITCH_CONTEXT gOvsSwitchContext;
67
static VOID OvsInitVportWithPortParam(POVS_VPORT_ENTRY vport,
68
PNDIS_SWITCH_PORT_PARAMETERS portParam);
69
static VOID OvsInitVportWithNicParam(POVS_SWITCH_CONTEXT switchContext,
70
POVS_VPORT_ENTRY vport, PNDIS_SWITCH_NIC_PARAMETERS nicParam);
71
static VOID OvsInitPhysNicVport(POVS_VPORT_ENTRY physExtVPort,
72
POVS_VPORT_ENTRY virtExtVport, UINT32 nicIndex);
73
static __inline VOID OvsWaitActivate(POVS_SWITCH_CONTEXT switchContext,
75
static NTSTATUS OvsGetExtInfoIoctl(POVS_VPORT_GET vportGet,
76
POVS_VPORT_EXT_INFO extInfo);
77
static NTSTATUS CreateNetlinkMesgForNetdev(POVS_VPORT_EXT_INFO info,
82
static POVS_VPORT_ENTRY OvsFindVportByHvNameW(POVS_SWITCH_CONTEXT switchContext,
83
PWSTR wsName, SIZE_T wstrSize);
84
static NDIS_STATUS InitHvVportCommon(POVS_SWITCH_CONTEXT switchContext,
85
POVS_VPORT_ENTRY vport,
87
static NTSTATUS OvsRemoveTunnelVport(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
88
POVS_SWITCH_CONTEXT switchContext,
89
POVS_VPORT_ENTRY vport,
92
static VOID OvsTunnelVportPendingInit(PVOID context,
95
static VOID OvsTunnelVportPendingRemove(PVOID context,
101
* Functions implemented in relaton to NDIS port manipulation.
104
HvCreatePort(POVS_SWITCH_CONTEXT switchContext,
105
PNDIS_SWITCH_PORT_PARAMETERS portParam)
107
POVS_VPORT_ENTRY vport;
108
LOCK_STATE_EX lockState;
109
NDIS_STATUS status = NDIS_STATUS_SUCCESS;
110
BOOLEAN newPort = FALSE;
112
VPORT_PORT_ENTER(portParam);
114
NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
115
/* Lookup by port ID. */
116
vport = OvsFindVportByPortIdAndNicIndex(switchContext,
117
portParam->PortId, 0);
119
OVS_LOG_ERROR("Port add failed due to duplicate port name, "
120
"port Id: %u", portParam->PortId);
121
status = STATUS_DATA_NOT_ACCEPTED;
122
goto create_port_done;
126
* Lookup by port name to see if this port with this name had been added
127
* (and deleted) previously.
129
vport = OvsFindVportByHvNameW(gOvsSwitchContext,
130
portParam->PortFriendlyName.String,
131
portParam->PortFriendlyName.Length);
132
if (vport && vport->isAbsentOnHv == FALSE) {
133
OVS_LOG_ERROR("Port add failed since a port already exists on "
134
"the specified port Id: %u, ovsName: %s",
135
portParam->PortId, vport->ovsName);
136
status = STATUS_DATA_NOT_ACCEPTED;
137
goto create_port_done;
141
ASSERT(vport->isAbsentOnHv);
142
ASSERT(vport->portNo != OVS_DPPORT_NUMBER_INVALID);
145
* It should be possible to simply just mark this port as "not deleted"
146
* given that the port Id and the name are the same and also provided
147
* that the other properties that we cache have not changed.
149
if (vport->portType != portParam->PortType) {
150
OVS_LOG_INFO("Port add failed due to PortType change, port Id: %u"
151
" old: %u, new: %u", portParam->PortId,
152
vport->portType, portParam->PortType);
153
status = STATUS_DATA_NOT_ACCEPTED;
154
goto create_port_done;
156
vport->isAbsentOnHv = FALSE;
158
vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
160
status = NDIS_STATUS_RESOURCES;
161
goto create_port_done;
165
OvsInitVportWithPortParam(vport, portParam);
166
InitHvVportCommon(switchContext, vport, newPort);
169
NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
170
VPORT_PORT_EXIT(portParam);
176
* Function updating the port properties
179
HvUpdatePort(POVS_SWITCH_CONTEXT switchContext,
180
PNDIS_SWITCH_PORT_PARAMETERS portParam)
182
POVS_VPORT_ENTRY vport;
183
LOCK_STATE_EX lockState;
184
OVS_VPORT_STATE ovsState;
185
NDIS_SWITCH_NIC_STATE nicState;
187
VPORT_PORT_ENTER(portParam);
189
NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
190
vport = OvsFindVportByPortIdAndNicIndex(switchContext,
191
portParam->PortId, 0);
193
* Update properties only for NETDEV ports for supprting PS script
194
* We don't allow changing the names of the internal or external ports
196
if (vport == NULL || (( vport->portType != NdisSwitchPortTypeSynthetic) &&
197
( vport->portType != NdisSwitchPortTypeEmulated))) {
198
goto update_port_done;
201
/* Store the nic and the OVS states as Nic Create won't be called */
202
ovsState = vport->ovsState;
203
nicState = vport->nicState;
206
* Currently only the port friendly name is being updated
207
* Make sure that no other properties are changed
209
ASSERT(portParam->PortId == vport->portId);
210
ASSERT(portParam->PortState == vport->portState);
211
ASSERT(portParam->PortType == vport->portType);
214
* Call the set parameters function the handle all properties
215
* change in a single place in case future version supports change of
218
OvsInitVportWithPortParam(vport, portParam);
219
/* Retore the nic and OVS states */
220
vport->nicState = nicState;
221
vport->ovsState = ovsState;
224
NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
225
VPORT_PORT_EXIT(portParam);
227
/* Must always return success */
228
return NDIS_STATUS_SUCCESS;
232
HvTeardownPort(POVS_SWITCH_CONTEXT switchContext,
233
PNDIS_SWITCH_PORT_PARAMETERS portParam)
235
POVS_VPORT_ENTRY vport;
236
LOCK_STATE_EX lockState;
238
VPORT_PORT_ENTER(portParam);
240
NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
241
vport = OvsFindVportByPortIdAndNicIndex(switchContext,
242
portParam->PortId, 0);
244
/* add assertion here */
245
vport->portState = NdisSwitchPortStateTeardown;
246
vport->ovsState = OVS_STATE_PORT_TEAR_DOWN;
248
OVS_LOG_WARN("Vport not present.");
250
NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
252
VPORT_PORT_EXIT(portParam);
257
HvDeletePort(POVS_SWITCH_CONTEXT switchContext,
258
PNDIS_SWITCH_PORT_PARAMETERS portParams)
260
POVS_VPORT_ENTRY vport;
261
LOCK_STATE_EX lockState;
263
VPORT_PORT_ENTER(portParams);
265
NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
266
vport = OvsFindVportByPortIdAndNicIndex(switchContext,
267
portParams->PortId, 0);
270
* XXX: we can only destroy and remove the port if its datapath port
271
* counterpart was deleted. If the datapath port counterpart is present,
272
* we only mark the vport for deletion, so that a netlink command vport
273
* delete will delete the vport.
276
OvsRemoveAndDeleteVport(NULL, switchContext, vport, TRUE, FALSE);
278
OVS_LOG_WARN("Vport not present.");
280
NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
282
VPORT_PORT_EXIT(portParams);
287
* Functions implemented in relaton to NDIS NIC manipulation.
290
HvCreateNic(POVS_SWITCH_CONTEXT switchContext,
291
PNDIS_SWITCH_NIC_PARAMETERS nicParam)
293
POVS_VPORT_ENTRY vport;
296
NDIS_STATUS status = NDIS_STATUS_SUCCESS;
298
LOCK_STATE_EX lockState;
300
VPORT_NIC_ENTER(nicParam);
302
/* Wait for lists to be initialized. */
303
OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
305
if (!switchContext->isActivated) {
306
OVS_LOG_WARN("Switch is not activated yet.");
307
/* Veto the creation of nic */
308
status = NDIS_STATUS_NOT_SUPPORTED;
312
NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
313
vport = OvsFindVportByPortIdAndNicIndex(switchContext, nicParam->PortId, 0);
315
OVS_LOG_ERROR("Create NIC without Switch Port,"
316
" PortId: %x, NicIndex: %d",
317
nicParam->PortId, nicParam->NicIndex);
318
status = NDIS_STATUS_INVALID_PARAMETER;
322
if (nicParam->NicType == NdisSwitchNicTypeExternal &&
323
nicParam->NicIndex != 0) {
324
POVS_VPORT_ENTRY virtExtVport =
325
(POVS_VPORT_ENTRY)switchContext->virtualExternalVport;
327
vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
329
status = NDIS_STATUS_RESOURCES;
332
OvsInitPhysNicVport(vport, virtExtVport, nicParam->NicIndex);
333
status = InitHvVportCommon(switchContext, vport, TRUE);
334
if (status != NDIS_STATUS_SUCCESS) {
335
OvsFreeMemoryWithTag(vport, OVS_VPORT_POOL_TAG);
339
OvsInitVportWithNicParam(switchContext, vport, nicParam);
340
portNo = vport->portNo;
341
if (vport->ovsState == OVS_STATE_CONNECTED) {
342
event = OVS_EVENT_CONNECT | OVS_EVENT_LINK_UP;
343
} else if (vport->ovsState == OVS_STATE_NIC_CREATED) {
344
event = OVS_EVENT_CONNECT;
348
NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
349
if (portNo != OVS_DPPORT_NUMBER_INVALID && event) {
350
OvsPostEvent(portNo, event);
354
VPORT_NIC_EXIT(nicParam);
355
OVS_LOG_TRACE("Exit: status %8x.\n", status);
361
/* Mark already created NIC as connected. */
363
HvConnectNic(POVS_SWITCH_CONTEXT switchContext,
364
PNDIS_SWITCH_NIC_PARAMETERS nicParam)
366
LOCK_STATE_EX lockState;
367
POVS_VPORT_ENTRY vport;
370
VPORT_NIC_ENTER(nicParam);
372
/* Wait for lists to be initialized. */
373
OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
375
if (!switchContext->isActivated) {
376
OVS_LOG_WARN("Switch is not activated yet.");
380
NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
381
vport = OvsFindVportByPortIdAndNicIndex(switchContext,
386
OVS_LOG_WARN("Vport not present.");
387
NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
392
vport->ovsState = OVS_STATE_CONNECTED;
393
vport->nicState = NdisSwitchNicStateConnected;
394
portNo = vport->portNo;
396
NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
398
/* XXX only if portNo != INVALID or always? */
399
OvsPostEvent(portNo, OVS_EVENT_LINK_UP);
401
if (nicParam->NicType == NdisSwitchNicTypeInternal) {
402
OvsInternalAdapterUp(portNo, &nicParam->NetCfgInstanceId);
406
VPORT_NIC_EXIT(nicParam);
410
HvUpdateNic(POVS_SWITCH_CONTEXT switchContext,
411
PNDIS_SWITCH_NIC_PARAMETERS nicParam)
413
POVS_VPORT_ENTRY vport;
414
LOCK_STATE_EX lockState;
416
UINT32 status = 0, portNo = 0;
418
VPORT_NIC_ENTER(nicParam);
420
/* Wait for lists to be initialized. */
421
OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
423
if (!switchContext->isActivated) {
424
OVS_LOG_WARN("Switch is not activated yet.");
425
goto update_nic_done;
428
NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
429
vport = OvsFindVportByPortIdAndNicIndex(switchContext,
433
NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
434
OVS_LOG_WARN("Vport search failed.");
435
goto update_nic_done;
437
switch (nicParam->NicType) {
438
case NdisSwitchNicTypeExternal:
439
case NdisSwitchNicTypeInternal:
440
RtlCopyMemory(&vport->netCfgInstanceId, &nicParam->NetCfgInstanceId,
443
case NdisSwitchNicTypeSynthetic:
444
case NdisSwitchNicTypeEmulated:
445
if (!RtlEqualMemory(vport->vmMacAddress, nicParam->VMMacAddress,
446
sizeof (vport->vmMacAddress))) {
447
status |= OVS_EVENT_MAC_CHANGE;
448
RtlCopyMemory(vport->vmMacAddress, nicParam->VMMacAddress,
449
sizeof (vport->vmMacAddress));
455
if (!RtlEqualMemory(vport->permMacAddress, nicParam->PermanentMacAddress,
456
sizeof (vport->permMacAddress))) {
457
RtlCopyMemory(vport->permMacAddress, nicParam->PermanentMacAddress,
458
sizeof (vport->permMacAddress));
459
status |= OVS_EVENT_MAC_CHANGE;
461
if (!RtlEqualMemory(vport->currMacAddress, nicParam->CurrentMacAddress,
462
sizeof (vport->currMacAddress))) {
463
RtlCopyMemory(vport->currMacAddress, nicParam->CurrentMacAddress,
464
sizeof (vport->currMacAddress));
465
status |= OVS_EVENT_MAC_CHANGE;
468
if (vport->mtu != nicParam->MTU) {
469
vport->mtu = nicParam->MTU;
470
status |= OVS_EVENT_MTU_CHANGE;
472
vport->numaNodeId = nicParam->NumaNodeId;
473
portNo = vport->portNo;
475
NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
476
if (status && portNo) {
477
OvsPostEvent(portNo, status);
480
VPORT_NIC_EXIT(nicParam);
485
HvDisconnectNic(POVS_SWITCH_CONTEXT switchContext,
486
PNDIS_SWITCH_NIC_PARAMETERS nicParam)
488
POVS_VPORT_ENTRY vport;
490
LOCK_STATE_EX lockState;
491
BOOLEAN isInternalPort = FALSE;
493
VPORT_NIC_ENTER(nicParam);
495
/* Wait for lists to be initialized. */
496
OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
498
if (!switchContext->isActivated) {
499
OVS_LOG_WARN("Switch is not activated yet.");
503
NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
504
vport = OvsFindVportByPortIdAndNicIndex(switchContext,
509
OVS_LOG_WARN("Vport not present.");
510
NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
514
vport->nicState = NdisSwitchNicStateDisconnected;
515
vport->ovsState = OVS_STATE_NIC_CREATED;
516
portNo = vport->portNo;
518
if (vport->ovsType == OVS_VPORT_TYPE_INTERNAL) {
519
isInternalPort = TRUE;
522
NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
524
/* XXX if portNo != INVALID or always? */
525
OvsPostEvent(portNo, OVS_EVENT_LINK_DOWN);
527
if (isInternalPort) {
528
OvsInternalAdapterDown();
532
VPORT_NIC_EXIT(nicParam);
537
HvDeleteNic(POVS_SWITCH_CONTEXT switchContext,
538
PNDIS_SWITCH_NIC_PARAMETERS nicParam)
540
LOCK_STATE_EX lockState;
541
POVS_VPORT_ENTRY vport;
544
VPORT_NIC_ENTER(nicParam);
545
/* Wait for lists to be initialized. */
546
OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
548
if (!switchContext->isActivated) {
549
OVS_LOG_WARN("Switch is not activated yet.");
553
NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
554
vport = OvsFindVportByPortIdAndNicIndex(switchContext,
559
OVS_LOG_WARN("Vport not present.");
560
NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
564
vport->nicState = NdisSwitchNicStateUnknown;
565
vport->ovsState = OVS_STATE_PORT_CREATED;
567
portNo = vport->portNo;
568
if (vport->portType == NdisSwitchPortTypeExternal &&
569
vport->nicIndex != 0) {
570
OvsRemoveAndDeleteVport(NULL, switchContext, vport, TRUE, FALSE);
573
NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
574
/* XXX if portNo != INVALID or always? */
575
OvsPostEvent(portNo, OVS_EVENT_DISCONNECT);
578
VPORT_NIC_EXIT(nicParam);
583
* OVS Vport related functionality.
586
OvsFindVportByPortNo(POVS_SWITCH_CONTEXT switchContext,
589
POVS_VPORT_ENTRY vport;
590
PLIST_ENTRY head, link;
591
UINT32 hash = OvsJhashBytes((const VOID *)&portNo, sizeof(portNo),
593
head = &(switchContext->portNoHashArray[hash & OVS_VPORT_MASK]);
594
LIST_FORALL(head, link) {
595
vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portNoLink);
596
if (vport->portNo == portNo) {
605
OvsFindTunnelVportByDstPort(POVS_SWITCH_CONTEXT switchContext,
607
OVS_VPORT_TYPE ovsPortType)
609
POVS_VPORT_ENTRY vport;
610
PLIST_ENTRY head, link;
611
UINT32 hash = OvsJhashBytes((const VOID *)&dstPort, sizeof(dstPort),
613
head = &(switchContext->tunnelVportsArray[hash & OVS_VPORT_MASK]);
614
LIST_FORALL(head, link) {
615
vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, tunnelVportLink);
616
if (GetPortFromPriv(vport) == dstPort &&
617
vport->ovsType == ovsPortType) {
626
OvsFindVportByOvsName(POVS_SWITCH_CONTEXT switchContext,
629
POVS_VPORT_ENTRY vport;
630
PLIST_ENTRY head, link;
632
SIZE_T length = strlen(name) + 1;
634
hash = OvsJhashBytes((const VOID *)name, length, OVS_HASH_BASIS);
635
head = &(switchContext->ovsPortNameHashArray[hash & OVS_VPORT_MASK]);
637
LIST_FORALL(head, link) {
638
vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, ovsNameLink);
639
if (!strcmp(name, vport->ovsName)) {
647
/* OvsFindVportByHvName: "name" is assumed to be null-terminated */
649
OvsFindVportByHvNameW(POVS_SWITCH_CONTEXT switchContext,
650
PWSTR wsName, SIZE_T wstrSize)
652
POVS_VPORT_ENTRY vport = NULL;
653
PLIST_ENTRY head, link;
656
for (i = 0; i < OVS_MAX_VPORT_ARRAY_SIZE; i++) {
657
head = &(switchContext->portIdHashArray[i]);
658
LIST_FORALL(head, link) {
659
vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portIdLink);
662
* NOTE about portFriendlyName:
663
* If the string is NULL-terminated, the Length member does not
664
* include the terminating NULL character.
666
if (vport->portFriendlyName.Length == wstrSize &&
667
RtlEqualMemory(wsName, vport->portFriendlyName.String,
668
vport->portFriendlyName.Length)) {
677
* Look in the list of ports that were added from the Hyper-V switch and
681
for (i = 0; i < OVS_MAX_VPORT_ARRAY_SIZE; i++) {
682
head = &(switchContext->portNoHashArray[i]);
683
LIST_FORALL(head, link) {
684
vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portNoLink);
685
if (vport->portFriendlyName.Length == wstrSize &&
686
RtlEqualMemory(wsName, vport->portFriendlyName.String,
687
vport->portFriendlyName.Length)) {
701
OvsFindVportByHvNameA(POVS_SWITCH_CONTEXT switchContext,
704
POVS_VPORT_ENTRY vport = NULL;
705
/* 'portFriendlyName' is not NUL-terminated. */
706
SIZE_T length = strlen(name);
707
SIZE_T wstrSize = length * sizeof(WCHAR);
710
PWSTR wsName = OvsAllocateMemoryWithTag(wstrSize, OVS_VPORT_POOL_TAG);
714
for (i = 0; i < length; i++) {
717
vport = OvsFindVportByHvNameW(switchContext, wsName, wstrSize);
718
OvsFreeMemoryWithTag(wsName, OVS_VPORT_POOL_TAG);
723
OvsFindVportByPortIdAndNicIndex(POVS_SWITCH_CONTEXT switchContext,
724
NDIS_SWITCH_PORT_ID portId,
725
NDIS_SWITCH_NIC_INDEX index)
727
if (switchContext->virtualExternalVport &&
728
portId == switchContext->virtualExternalPortId &&
729
index == switchContext->virtualExternalVport->nicIndex) {
730
return (POVS_VPORT_ENTRY)switchContext->virtualExternalVport;
731
} else if (switchContext->internalVport &&
732
portId == switchContext->internalPortId &&
733
index == switchContext->internalVport->nicIndex) {
734
return (POVS_VPORT_ENTRY)switchContext->internalVport;
736
PLIST_ENTRY head, link;
737
POVS_VPORT_ENTRY vport;
739
hash = OvsJhashWords((UINT32 *)&portId, 1, OVS_HASH_BASIS);
740
head = &(switchContext->portIdHashArray[hash & OVS_VPORT_MASK]);
741
LIST_FORALL(head, link) {
742
vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portIdLink);
743
if (portId == vport->portId && index == vport->nicIndex) {
752
OvsAllocateVport(VOID)
754
POVS_VPORT_ENTRY vport;
755
vport = (POVS_VPORT_ENTRY)OvsAllocateMemoryWithTag(
756
sizeof(OVS_VPORT_ENTRY), OVS_VPORT_POOL_TAG);
760
RtlZeroMemory(vport, sizeof (OVS_VPORT_ENTRY));
761
vport->ovsState = OVS_STATE_UNKNOWN;
762
vport->isAbsentOnHv = FALSE;
763
vport->portNo = OVS_DPPORT_NUMBER_INVALID;
765
InitializeListHead(&vport->ovsNameLink);
766
InitializeListHead(&vport->portIdLink);
767
InitializeListHead(&vport->portNoLink);
773
OvsInitVportWithPortParam(POVS_VPORT_ENTRY vport,
774
PNDIS_SWITCH_PORT_PARAMETERS portParam)
776
vport->portType = portParam->PortType;
777
vport->portState = portParam->PortState;
778
vport->portId = portParam->PortId;
779
vport->nicState = NdisSwitchNicStateUnknown;
780
vport->isExternal = FALSE;
781
vport->isBridgeInternal = FALSE;
783
switch (vport->portType) {
784
case NdisSwitchPortTypeExternal:
785
vport->isExternal = TRUE;
786
vport->ovsType = OVS_VPORT_TYPE_NETDEV;
788
case NdisSwitchPortTypeInternal:
789
vport->ovsType = OVS_VPORT_TYPE_INTERNAL;
791
case NdisSwitchPortTypeSynthetic:
792
case NdisSwitchPortTypeEmulated:
793
vport->ovsType = OVS_VPORT_TYPE_NETDEV;
796
RtlCopyMemory(&vport->hvPortName, &portParam->PortName,
797
sizeof (NDIS_SWITCH_PORT_NAME));
798
/* For external and internal ports, 'portFriendlyName' is overwritten
800
RtlCopyMemory(&vport->portFriendlyName, &portParam->PortFriendlyName,
801
sizeof(NDIS_SWITCH_PORT_FRIENDLYNAME));
803
switch (vport->portState) {
804
case NdisSwitchPortStateCreated:
805
vport->ovsState = OVS_STATE_PORT_CREATED;
807
case NdisSwitchPortStateTeardown:
808
vport->ovsState = OVS_STATE_PORT_TEAR_DOWN;
810
case NdisSwitchPortStateDeleted:
811
vport->ovsState = OVS_STATE_PORT_DELETED;
818
OvsInitVportWithNicParam(POVS_SWITCH_CONTEXT switchContext,
819
POVS_VPORT_ENTRY vport,
820
PNDIS_SWITCH_NIC_PARAMETERS nicParam)
822
ASSERT(vport->portId == nicParam->PortId);
823
ASSERT(vport->ovsState == OVS_STATE_PORT_CREATED);
825
UNREFERENCED_PARAMETER(switchContext);
827
RtlCopyMemory(vport->permMacAddress, nicParam->PermanentMacAddress,
828
sizeof (nicParam->PermanentMacAddress));
829
RtlCopyMemory(vport->currMacAddress, nicParam->CurrentMacAddress,
830
sizeof (nicParam->CurrentMacAddress));
832
if (nicParam->NicType == NdisSwitchNicTypeSynthetic ||
833
nicParam->NicType == NdisSwitchNicTypeEmulated) {
834
RtlCopyMemory(vport->vmMacAddress, nicParam->VMMacAddress,
835
sizeof (nicParam->VMMacAddress));
836
RtlCopyMemory(&vport->vmName, &nicParam->VmName,
837
sizeof (nicParam->VmName));
839
RtlCopyMemory(&vport->netCfgInstanceId, &nicParam->NetCfgInstanceId,
840
sizeof (nicParam->NetCfgInstanceId));
842
RtlCopyMemory(&vport->nicName, &nicParam->NicName,
843
sizeof (nicParam->NicName));
844
vport->mtu = nicParam->MTU;
845
vport->nicState = nicParam->NicState;
846
vport->nicIndex = nicParam->NicIndex;
847
vport->numaNodeId = nicParam->NumaNodeId;
849
switch (vport->nicState) {
850
case NdisSwitchNicStateCreated:
851
vport->ovsState = OVS_STATE_NIC_CREATED;
853
case NdisSwitchNicStateConnected:
854
vport->ovsState = OVS_STATE_CONNECTED;
856
case NdisSwitchNicStateDisconnected:
857
vport->ovsState = OVS_STATE_NIC_CREATED;
859
case NdisSwitchNicStateDeleted:
860
vport->ovsState = OVS_STATE_PORT_CREATED;
866
* --------------------------------------------------------------------------
867
* Copies the relevant NDIS port properties from a virtual (pseudo) external
868
* NIC to a physical (real) external NIC.
869
* --------------------------------------------------------------------------
872
OvsInitPhysNicVport(POVS_VPORT_ENTRY physExtVport,
873
POVS_VPORT_ENTRY virtExtVport,
876
physExtVport->portType = virtExtVport->portType;
877
physExtVport->portState = virtExtVport->portState;
878
physExtVport->portId = virtExtVport->portId;
879
physExtVport->nicState = NdisSwitchNicStateUnknown;
880
physExtVport->ovsType = OVS_VPORT_TYPE_NETDEV;
881
physExtVport->isExternal = TRUE;
882
physExtVport->isBridgeInternal = FALSE;
883
physExtVport->nicIndex = (NDIS_SWITCH_NIC_INDEX)physNicIndex;
885
RtlCopyMemory(&physExtVport->hvPortName, &virtExtVport->hvPortName,
886
sizeof (NDIS_SWITCH_PORT_NAME));
888
/* 'portFriendlyName' is overwritten later. */
889
RtlCopyMemory(&physExtVport->portFriendlyName,
890
&virtExtVport->portFriendlyName,
891
sizeof(NDIS_SWITCH_PORT_FRIENDLYNAME));
893
physExtVport->ovsState = OVS_STATE_PORT_CREATED;
897
* --------------------------------------------------------------------------
898
* Initializes a tunnel vport.
899
* --------------------------------------------------------------------------
902
OvsInitTunnelVport(PVOID userContext,
903
POVS_VPORT_ENTRY vport,
904
OVS_VPORT_TYPE ovsType,
907
NTSTATUS status = STATUS_SUCCESS;
908
POVS_USER_PARAMS_CONTEXT usrParamsCtx =
909
(POVS_USER_PARAMS_CONTEXT)userContext;
911
vport->isBridgeInternal = FALSE;
912
vport->ovsType = ovsType;
913
vport->ovsState = OVS_STATE_PORT_CREATED;
915
case OVS_VPORT_TYPE_GRE:
917
case OVS_VPORT_TYPE_GRE64:
919
case OVS_VPORT_TYPE_VXLAN:
921
POVS_TUNFLT_INIT_CONTEXT tunnelContext = NULL;
923
tunnelContext = OvsAllocateMemoryWithTag(sizeof(*tunnelContext),
925
if (tunnelContext == NULL) {
926
status = STATUS_INSUFFICIENT_RESOURCES;
929
tunnelContext->inputBuffer = usrParamsCtx->inputBuffer;
930
tunnelContext->outputBuffer = usrParamsCtx->outputBuffer;
931
tunnelContext->outputLength = usrParamsCtx->outputLength;
932
tunnelContext->vport = vport;
934
status = OvsInitVxlanTunnel(usrParamsCtx->irp,
937
OvsTunnelVportPendingInit,
938
(PVOID)tunnelContext);
939
if (status != STATUS_PENDING) {
940
OvsFreeMemoryWithTag(tunnelContext, OVS_VPORT_POOL_TAG);
941
tunnelContext = NULL;
945
case OVS_VPORT_TYPE_STT:
946
status = OvsInitSttTunnel(vport, dstPort);
955
* --------------------------------------------------------------------------
956
* Initializes a bridge internal vport ie. a port of type
957
* OVS_VPORT_TYPE_INTERNAL but not present on the Hyper-V switch.
958
* --------------------------------------------------------------------------
961
OvsInitBridgeInternalVport(POVS_VPORT_ENTRY vport)
963
vport->isBridgeInternal = TRUE;
964
vport->ovsType = OVS_VPORT_TYPE_INTERNAL;
965
/* Mark the status to be connected, since there is no other initialization
967
vport->ovsState = OVS_STATE_CONNECTED;
968
return STATUS_SUCCESS;
972
* --------------------------------------------------------------------------
973
* For external vports 'portFriendlyName' provided by Hyper-V is over-written
974
* by synthetic names.
975
* --------------------------------------------------------------------------
978
AssignNicNameSpecial(POVS_VPORT_ENTRY vport)
982
if (vport->portType == NdisSwitchPortTypeExternal) {
983
if (vport->nicIndex == 0) {
984
ASSERT(vport->nicIndex == 0);
985
RtlStringCbPrintfW(vport->portFriendlyName.String,
987
L"%s.virtualAdapter", OVS_DPPORT_EXTERNAL_NAME_W);
989
RtlStringCbPrintfW(vport->portFriendlyName.String,
991
L"%s.%lu", OVS_DPPORT_EXTERNAL_NAME_W,
992
(UINT32)vport->nicIndex);
995
RtlStringCbPrintfW(vport->portFriendlyName.String,
997
L"%s", OVS_DPPORT_INTERNAL_NAME_W);
1000
RtlStringCbLengthW(vport->portFriendlyName.String, IF_MAX_STRING_SIZE,
1002
vport->portFriendlyName.Length = (USHORT)len;
1007
* --------------------------------------------------------------------------
1008
* Functionality common to any port on the Hyper-V switch. This function is not
1009
* to be called for a port that is not on the Hyper-V switch.
1011
* Inserts the port into 'portIdHashArray' and caches the pointer in the
1012
* 'switchContext' if needed.
1014
* For external NIC, assigns the name for the NIC.
1015
* --------------------------------------------------------------------------
1018
InitHvVportCommon(POVS_SWITCH_CONTEXT switchContext,
1019
POVS_VPORT_ENTRY vport,
1024
switch (vport->portType) {
1025
case NdisSwitchPortTypeExternal:
1027
* Overwrite the 'portFriendlyName' of this external vport. The reason
1028
* for having this in common code is to be able to call it from the NDIS
1029
* Port callback as well as the NDIS NIC callback.
1031
AssignNicNameSpecial(vport);
1033
if (vport->nicIndex == 0) {
1034
switchContext->virtualExternalPortId = vport->portId;
1035
switchContext->virtualExternalVport = vport;
1037
switchContext->numPhysicalNics++;
1040
case NdisSwitchPortTypeInternal:
1041
ASSERT(vport->isBridgeInternal == FALSE);
1043
/* Overwrite the 'portFriendlyName' of the internal vport. */
1044
AssignNicNameSpecial(vport);
1045
switchContext->internalPortId = vport->portId;
1046
switchContext->internalVport = vport;
1048
case NdisSwitchPortTypeSynthetic:
1049
case NdisSwitchPortTypeEmulated:
1054
* It is important to not insert vport corresponding to virtual external
1055
* port into the 'portIdHashArray' since the port should not be exposed to
1058
if (vport->portType == NdisSwitchPortTypeExternal &&
1059
vport->nicIndex == 0) {
1060
return NDIS_STATUS_SUCCESS;
1064
* NOTE: OvsJhashWords has portId as "1" word. This should be ok, even
1065
* though sizeof(NDIS_SWITCH_PORT_ID) = 4, not 2, because the
1066
* hyper-v switch seems to use only 2 bytes out of 4.
1068
hash = OvsJhashWords(&vport->portId, 1, OVS_HASH_BASIS);
1069
InsertHeadList(&switchContext->portIdHashArray[hash & OVS_VPORT_MASK],
1070
&vport->portIdLink);
1072
switchContext->numHvVports++;
1074
return NDIS_STATUS_SUCCESS;
1078
* --------------------------------------------------------------------------
1079
* Functionality common to any port added from OVS userspace.
1081
* Inserts the port into 'portNoHashArray', 'ovsPortNameHashArray' and in
1082
* 'tunnelVportsArray' if appropriate.
1083
* --------------------------------------------------------------------------
1086
InitOvsVportCommon(POVS_SWITCH_CONTEXT switchContext,
1087
POVS_VPORT_ENTRY vport)
1091
switch(vport->ovsType) {
1092
case OVS_VPORT_TYPE_VXLAN:
1093
case OVS_VPORT_TYPE_STT:
1095
UINT16 dstPort = GetPortFromPriv(vport);
1096
hash = OvsJhashBytes(&dstPort,
1100
&gOvsSwitchContext->tunnelVportsArray[hash & OVS_VPORT_MASK],
1101
&vport->tunnelVportLink);
1102
switchContext->numNonHvVports++;
1105
case OVS_VPORT_TYPE_INTERNAL:
1106
if (vport->isBridgeInternal) {
1107
switchContext->numNonHvVports++;
1114
* Insert the port into the hash array of ports: by port number and ovs
1115
* and ovs (datapath) port name.
1116
* NOTE: OvsJhashWords has portNo as "1" word. This is ok, because the
1117
* portNo is stored in 2 bytes only (max port number = MAXUINT16).
1119
hash = OvsJhashWords(&vport->portNo, 1, OVS_HASH_BASIS);
1120
InsertHeadList(&gOvsSwitchContext->portNoHashArray[hash & OVS_VPORT_MASK],
1121
&vport->portNoLink);
1123
hash = OvsJhashBytes(vport->ovsName, strlen(vport->ovsName) + 1,
1126
&gOvsSwitchContext->ovsPortNameHashArray[hash & OVS_VPORT_MASK],
1127
&vport->ovsNameLink);
1129
return STATUS_SUCCESS;
1134
* --------------------------------------------------------------------------
1135
* Provides functionality that is partly complementatry to
1136
* InitOvsVportCommon()/InitHvVportCommon().
1138
* 'hvDelete' indicates if caller is removing the vport as a result of the
1139
* port being removed on the Hyper-V switch.
1140
* 'ovsDelete' indicates if caller is removing the vport as a result of the
1141
* port being removed from OVS userspace.
1142
* --------------------------------------------------------------------------
1145
OvsRemoveAndDeleteVport(PVOID usrParamsContext,
1146
POVS_SWITCH_CONTEXT switchContext,
1147
POVS_VPORT_ENTRY vport,
1151
POVS_USER_PARAMS_CONTEXT usrParamsCtx =
1152
(POVS_USER_PARAMS_CONTEXT)usrParamsContext;
1153
BOOLEAN hvSwitchPort = FALSE;
1154
BOOLEAN deletedOnOvs = FALSE;
1155
BOOLEAN deletedOnHv = FALSE;
1157
switch (vport->ovsType) {
1158
case OVS_VPORT_TYPE_INTERNAL:
1159
if (!vport->isBridgeInternal) {
1160
if (hvDelete && vport->isAbsentOnHv == FALSE) {
1161
switchContext->internalPortId = 0;
1162
switchContext->internalVport = NULL;
1163
OvsInternalAdapterDown();
1165
hvSwitchPort = TRUE;
1168
case OVS_VPORT_TYPE_VXLAN:
1171
status = OvsRemoveTunnelVport(usrParamsCtx, switchContext, vport,
1172
hvDelete, ovsDelete);
1173
if (status != STATUS_SUCCESS) {
1177
case OVS_VPORT_TYPE_STT:
1178
OvsCleanupSttTunnel(vport);
1180
case OVS_VPORT_TYPE_GRE:
1181
case OVS_VPORT_TYPE_GRE64:
1183
case OVS_VPORT_TYPE_NETDEV:
1184
if (vport->isExternal) {
1185
if (vport->nicIndex == 0) {
1186
/* Such a vport is not part of any of the hash tables, since it
1187
* is not exposed to userspace. See Vport.h for explanation. */
1188
ASSERT(hvDelete == TRUE);
1189
ASSERT(switchContext->numPhysicalNics == 0);
1190
switchContext->virtualExternalPortId = 0;
1191
switchContext->virtualExternalVport = NULL;
1192
OvsFreeMemoryWithTag(vport, OVS_VPORT_POOL_TAG);
1193
return STATUS_SUCCESS;
1196
hvSwitchPort = TRUE;
1202
* 'hvDelete' == TRUE indicates that the port should be removed from the
1203
* 'portIdHashArray', while 'ovsDelete' == TRUE indicates that the port
1204
* should be removed from 'portNoHashArray' and the 'ovsPortNameHashArray'.
1206
* Both 'hvDelete' and 'ovsDelete' can be set to TRUE by the caller.
1208
if (vport->isAbsentOnHv == TRUE) {
1211
if (vport->portNo == OVS_DPPORT_NUMBER_INVALID) {
1212
deletedOnOvs = TRUE;
1215
if (hvDelete && !deletedOnHv) {
1216
vport->isAbsentOnHv = TRUE;
1218
if (vport->isExternal) {
1219
ASSERT(vport->nicIndex != 0);
1220
ASSERT(switchContext->numPhysicalNics);
1221
switchContext->numPhysicalNics--;
1224
/* Remove the port from the relevant lists. */
1225
RemoveEntryList(&vport->portIdLink);
1226
InitializeListHead(&vport->portIdLink);
1229
if (ovsDelete && !deletedOnOvs) {
1230
vport->portNo = OVS_DPPORT_NUMBER_INVALID;
1231
vport->ovsName[0] = '\0';
1233
/* Remove the port from the relevant lists. */
1234
RemoveEntryList(&vport->ovsNameLink);
1235
InitializeListHead(&vport->ovsNameLink);
1236
RemoveEntryList(&vport->portNoLink);
1237
InitializeListHead(&vport->portNoLink);
1238
if (OVS_VPORT_TYPE_VXLAN == vport->ovsType ||
1239
OVS_VPORT_TYPE_STT == vport->ovsType) {
1240
RemoveEntryList(&vport->tunnelVportLink);
1241
InitializeListHead(&vport->tunnelVportLink);
1244
deletedOnOvs = TRUE;
1248
* Deallocate the port if it has been deleted on the Hyper-V switch as well
1251
if (deletedOnHv && deletedOnOvs) {
1253
switchContext->numHvVports--;
1255
switchContext->numNonHvVports--;
1257
OvsFreeMemoryWithTag(vport, OVS_VPORT_POOL_TAG);
1260
return STATUS_SUCCESS;
1264
OvsRemoveTunnelVport(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1265
POVS_SWITCH_CONTEXT switchContext,
1266
POVS_VPORT_ENTRY vport,
1270
POVS_TUNFLT_INIT_CONTEXT tunnelContext = NULL;
1273
tunnelContext = OvsAllocateMemory(sizeof(*tunnelContext));
1274
if (tunnelContext == NULL) {
1275
return STATUS_INSUFFICIENT_RESOURCES;
1277
RtlZeroMemory(tunnelContext, sizeof(*tunnelContext));
1279
tunnelContext->switchContext = switchContext;
1280
tunnelContext->hvSwitchPort = FALSE;
1281
tunnelContext->hvDelete = hvDelete;
1282
tunnelContext->ovsDelete = ovsDelete;
1283
tunnelContext->vport = vport;
1286
tunnelContext->inputBuffer = usrParamsCtx->inputBuffer;
1287
tunnelContext->outputBuffer = usrParamsCtx->outputBuffer;
1288
tunnelContext->outputLength = usrParamsCtx->outputLength;
1289
irp = usrParamsCtx->irp;
1292
return OvsCleanupVxlanTunnel(irp, vport, OvsTunnelVportPendingRemove,
1299
OvsAddConfiguredSwitchPorts(POVS_SWITCH_CONTEXT switchContext)
1301
NDIS_STATUS status = NDIS_STATUS_SUCCESS;
1303
PNDIS_SWITCH_PORT_PARAMETERS portParam;
1304
PNDIS_SWITCH_PORT_ARRAY portArray = NULL;
1305
POVS_VPORT_ENTRY vport;
1307
OVS_LOG_TRACE("Enter: switchContext:%p", switchContext);
1309
status = OvsGetPortsOnSwitch(switchContext, &portArray);
1310
if (status != NDIS_STATUS_SUCCESS) {
1314
for (arrIndex = 0; arrIndex < portArray->NumElements; arrIndex++) {
1315
portParam = NDIS_SWITCH_PORT_AT_ARRAY_INDEX(portArray, arrIndex);
1317
if (portParam->IsValidationPort) {
1321
vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
1322
if (vport == NULL) {
1323
status = NDIS_STATUS_RESOURCES;
1326
OvsInitVportWithPortParam(vport, portParam);
1327
status = InitHvVportCommon(switchContext, vport, TRUE);
1328
if (status != NDIS_STATUS_SUCCESS) {
1329
OvsFreeMemoryWithTag(vport, OVS_VPORT_POOL_TAG);
1335
if (status != NDIS_STATUS_SUCCESS) {
1336
OvsClearAllSwitchVports(switchContext);
1339
OvsFreeSwitchPortsArray(portArray);
1341
OVS_LOG_TRACE("Exit: status: %x", status);
1348
OvsInitConfiguredSwitchNics(POVS_SWITCH_CONTEXT switchContext)
1350
NDIS_STATUS status = NDIS_STATUS_SUCCESS;
1351
PNDIS_SWITCH_NIC_ARRAY nicArray = NULL;
1353
PNDIS_SWITCH_NIC_PARAMETERS nicParam;
1354
POVS_VPORT_ENTRY vport;
1356
OVS_LOG_TRACE("Enter: switchContext: %p", switchContext);
1358
* Now, get NIC list.
1360
status = OvsGetNicsOnSwitch(switchContext, &nicArray);
1361
if (status != NDIS_STATUS_SUCCESS) {
1364
for (arrIndex = 0; arrIndex < nicArray->NumElements; ++arrIndex) {
1366
nicParam = NDIS_SWITCH_NIC_AT_ARRAY_INDEX(nicArray, arrIndex);
1369
* XXX: Check if the port is configured with a VLAN. Disallow such a
1370
* configuration, since we don't support tag-in-tag.
1374
* XXX: Check if the port is connected to a VF. Disconnect the VF in
1378
if (nicParam->NicType == NdisSwitchNicTypeExternal &&
1379
nicParam->NicIndex != 0) {
1380
POVS_VPORT_ENTRY virtExtVport =
1381
(POVS_VPORT_ENTRY)switchContext->virtualExternalVport;
1383
vport = OvsAllocateVport();
1385
OvsInitPhysNicVport(vport, virtExtVport,
1386
nicParam->NicIndex);
1387
status = InitHvVportCommon(switchContext, vport, TRUE);
1388
if (status != NDIS_STATUS_SUCCESS) {
1389
OvsFreeMemoryWithTag(vport, OVS_VPORT_POOL_TAG);
1394
vport = OvsFindVportByPortIdAndNicIndex(switchContext,
1396
nicParam->NicIndex);
1398
if (vport == NULL) {
1399
OVS_LOG_ERROR("Fail to allocate vport");
1402
OvsInitVportWithNicParam(switchContext, vport, nicParam);
1403
if (nicParam->NicType == NdisSwitchNicTypeInternal) {
1404
OvsInternalAdapterUp(vport->portNo, &nicParam->NetCfgInstanceId);
1409
OvsFreeSwitchNicsArray(nicArray);
1411
OVS_LOG_TRACE("Exit: status: %x", status);
1416
* --------------------------------------------------------------------------
1417
* Deletes ports added from the Hyper-V switch as well as OVS usersapce. The
1418
* function deletes ports in 'portIdHashArray'. This will delete most of the
1419
* ports that are in the 'portNoHashArray' as well. Any remaining ports
1420
* are deleted by walking the the 'portNoHashArray'.
1421
* --------------------------------------------------------------------------
1424
OvsClearAllSwitchVports(POVS_SWITCH_CONTEXT switchContext)
1426
for (UINT hash = 0; hash < OVS_MAX_VPORT_ARRAY_SIZE; hash++) {
1427
PLIST_ENTRY head, link, next;
1429
head = &(switchContext->portIdHashArray[hash & OVS_VPORT_MASK]);
1430
LIST_FORALL_SAFE(head, link, next) {
1431
POVS_VPORT_ENTRY vport;
1432
vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portIdLink);
1433
OvsRemoveAndDeleteVport(NULL, switchContext, vport, TRUE, TRUE);
1438
* Remove 'virtualExternalVport' as well. This port is not part of the
1439
* 'portIdHashArray'.
1441
if (switchContext->virtualExternalVport) {
1442
OvsRemoveAndDeleteVport(NULL, switchContext,
1443
(POVS_VPORT_ENTRY)switchContext->virtualExternalVport, TRUE, TRUE);
1447
for (UINT hash = 0; hash < OVS_MAX_VPORT_ARRAY_SIZE; hash++) {
1448
PLIST_ENTRY head, link, next;
1449
head = &(switchContext->portNoHashArray[hash & OVS_VPORT_MASK]);
1450
LIST_FORALL_SAFE(head, link, next) {
1451
POVS_VPORT_ENTRY vport;
1452
vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portNoLink);
1453
ASSERT(OvsIsTunnelVportType(vport->ovsType) ||
1454
(vport->ovsType == OVS_VPORT_TYPE_INTERNAL &&
1455
vport->isBridgeInternal) || vport->isAbsentOnHv == TRUE);
1456
OvsRemoveAndDeleteVport(NULL, switchContext, vport, TRUE, TRUE);
1460
ASSERT(switchContext->virtualExternalVport == NULL);
1461
ASSERT(switchContext->internalVport == NULL);
1466
OvsConvertIfCountedStrToAnsiStr(PIF_COUNTED_STRING wStr,
1471
UNICODE_STRING ustr;
1475
ustr.Buffer = wStr->String;
1476
ustr.Length = wStr->Length;
1477
ustr.MaximumLength = IF_MAX_STRING_SIZE;
1480
astr.MaximumLength = maxStrLen;
1483
size = RtlUnicodeStringToAnsiSize(&ustr);
1484
if (size > maxStrLen) {
1485
return STATUS_BUFFER_OVERFLOW;
1488
status = RtlUnicodeStringToAnsiString(&astr, &ustr, FALSE);
1490
ASSERT(status == STATUS_SUCCESS);
1491
if (status != STATUS_SUCCESS) {
1494
ASSERT(astr.Length <= maxStrLen);
1495
str[astr.Length] = 0;
1496
return STATUS_SUCCESS;
1500
* --------------------------------------------------------------------------
1501
* Utility function that populates a 'OVS_VPORT_EXT_INFO' structure for the
1503
* --------------------------------------------------------------------------
1506
OvsGetExtInfoIoctl(POVS_VPORT_GET vportGet,
1507
POVS_VPORT_EXT_INFO extInfo)
1509
POVS_VPORT_ENTRY vport;
1511
LOCK_STATE_EX lockState;
1512
NTSTATUS status = STATUS_SUCCESS;
1513
BOOLEAN doConvert = FALSE;
1515
RtlZeroMemory(extInfo, sizeof (POVS_VPORT_EXT_INFO));
1516
NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState, 0);
1517
if (vportGet->portNo == 0) {
1518
StringCbLengthA(vportGet->name, OVS_MAX_PORT_NAME_LENGTH - 1, &len);
1519
vport = OvsFindVportByHvNameA(gOvsSwitchContext, vportGet->name);
1520
if (vport != NULL) {
1521
/* If the port is not a Hyper-V port and it has been added earlier,
1522
* we'll find it in 'ovsPortNameHashArray'. */
1523
vport = OvsFindVportByOvsName(gOvsSwitchContext, vportGet->name);
1526
vport = OvsFindVportByPortNo(gOvsSwitchContext, vportGet->portNo);
1528
if (vport == NULL || (vport->ovsState != OVS_STATE_CONNECTED &&
1529
vport->ovsState != OVS_STATE_NIC_CREATED)) {
1530
NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1531
if (vportGet->portNo) {
1532
OVS_LOG_WARN("vport %u does not exist any more", vportGet->portNo);
1534
OVS_LOG_WARN("vport %s does not exist any more", vportGet->name);
1536
status = STATUS_DEVICE_DOES_NOT_EXIST;
1539
extInfo->dpNo = vportGet->dpNo;
1540
extInfo->portNo = vport->portNo;
1541
RtlCopyMemory(extInfo->macAddress, vport->currMacAddress,
1542
sizeof (vport->currMacAddress));
1543
RtlCopyMemory(extInfo->permMACAddress, vport->permMacAddress,
1544
sizeof (vport->permMacAddress));
1545
if (vport->ovsType == OVS_VPORT_TYPE_NETDEV) {
1546
RtlCopyMemory(extInfo->vmMACAddress, vport->vmMacAddress,
1547
sizeof (vport->vmMacAddress));
1549
extInfo->nicIndex = vport->nicIndex;
1550
extInfo->portId = vport->portId;
1551
extInfo->type = vport->ovsType;
1552
extInfo->mtu = vport->mtu;
1556
if (vport->ovsState == OVS_STATE_NIC_CREATED) {
1557
extInfo->status = OVS_EVENT_CONNECT | OVS_EVENT_LINK_DOWN;
1558
} else if (vport->ovsState == OVS_STATE_CONNECTED) {
1559
extInfo->status = OVS_EVENT_CONNECT | OVS_EVENT_LINK_UP;
1561
extInfo->status = OVS_EVENT_DISCONNECT;
1563
if (extInfo->type == OVS_VPORT_TYPE_NETDEV &&
1564
(vport->ovsState == OVS_STATE_NIC_CREATED ||
1565
vport->ovsState == OVS_STATE_CONNECTED)) {
1568
extInfo->vmUUID[0] = 0;
1569
extInfo->vifUUID[0] = 0;
1571
NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1573
status = OvsConvertIfCountedStrToAnsiStr(&vport->portFriendlyName,
1575
OVS_MAX_PORT_NAME_LENGTH);
1576
if (status != STATUS_SUCCESS) {
1577
OVS_LOG_INFO("Fail to convert NIC name.");
1578
extInfo->vmUUID[0] = 0;
1581
status = OvsConvertIfCountedStrToAnsiStr(&vport->vmName,
1583
OVS_MAX_VM_UUID_LEN);
1584
if (status != STATUS_SUCCESS) {
1585
OVS_LOG_INFO("Fail to convert VM name.");
1586
extInfo->vmUUID[0] = 0;
1589
status = OvsConvertIfCountedStrToAnsiStr(&vport->nicName,
1591
OVS_MAX_VIF_UUID_LEN);
1592
if (status != STATUS_SUCCESS) {
1593
OVS_LOG_INFO("Fail to convert nic UUID");
1594
extInfo->vifUUID[0] = 0;
1597
* for now ignore status
1599
status = STATUS_SUCCESS;
1607
* --------------------------------------------------------------------------
1608
* Command Handler for 'OVS_WIN_NETDEV_CMD_GET'.
1609
* --------------------------------------------------------------------------
1612
OvsGetNetdevCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1615
NTSTATUS status = STATUS_SUCCESS;
1616
POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1617
POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
1618
NL_ERROR nlError = NL_ERROR_SUCCESS;
1619
OVS_VPORT_GET vportGet;
1620
OVS_VPORT_EXT_INFO info;
1622
static const NL_POLICY ovsNetdevPolicy[] = {
1623
[OVS_WIN_NETDEV_ATTR_NAME] = { .type = NL_A_STRING,
1625
.maxLen = IFNAMSIZ },
1627
PNL_ATTR netdevAttrs[ARRAY_SIZE(ovsNetdevPolicy)];
1629
/* input buffer has been validated while validating transaction dev op. */
1630
ASSERT(usrParamsCtx->inputBuffer != NULL &&
1631
usrParamsCtx->inputLength > sizeof *msgIn);
1633
if (msgOut == NULL || usrParamsCtx->outputLength < sizeof *msgOut) {
1634
return STATUS_INVALID_BUFFER_SIZE;
1637
if (!NlAttrParse((PNL_MSG_HDR)msgIn,
1638
NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
1639
NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
1640
ovsNetdevPolicy, netdevAttrs, ARRAY_SIZE(netdevAttrs))) {
1641
return STATUS_INVALID_PARAMETER;
1644
vportGet.portNo = 0;
1645
RtlCopyMemory(&vportGet.name, NlAttrGet(netdevAttrs[OVS_VPORT_ATTR_NAME]),
1646
NlAttrGetSize(netdevAttrs[OVS_VPORT_ATTR_NAME]));
1648
status = OvsGetExtInfoIoctl(&vportGet, &info);
1649
if (status == STATUS_DEVICE_DOES_NOT_EXIST) {
1650
nlError = NL_ERROR_NODEV;
1654
status = CreateNetlinkMesgForNetdev(&info, msgIn,
1655
usrParamsCtx->outputBuffer, usrParamsCtx->outputLength,
1656
gOvsSwitchContext->dpNo);
1657
if (status == STATUS_SUCCESS) {
1658
*replyLen = msgOut->nlMsg.nlmsgLen;
1662
if (nlError != NL_ERROR_SUCCESS) {
1663
POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
1664
usrParamsCtx->outputBuffer;
1666
NlBuildErrorMsg(msgIn, msgError, nlError);
1667
*replyLen = msgError->nlMsg.nlmsgLen;
1670
return STATUS_SUCCESS;
1675
* --------------------------------------------------------------------------
1676
* Utility function to construct an OVS_MESSAGE for the specified vport. The
1677
* OVS_MESSAGE contains the output of a netdev command.
1678
* --------------------------------------------------------------------------
1681
CreateNetlinkMesgForNetdev(POVS_VPORT_EXT_INFO info,
1690
UINT32 netdevFlags = 0;
1692
NlBufInit(&nlBuffer, outBuffer, outBufLen);
1694
ok = NlFillOvsMsg(&nlBuffer, msgIn->nlMsg.nlmsgType, NLM_F_MULTI,
1695
msgIn->nlMsg.nlmsgSeq, msgIn->nlMsg.nlmsgPid,
1696
msgIn->genlMsg.cmd, msgIn->genlMsg.version,
1699
return STATUS_INVALID_BUFFER_SIZE;
1702
ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_PORT_NO,
1705
return STATUS_INVALID_BUFFER_SIZE;
1708
ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_TYPE, info->type);
1710
return STATUS_INVALID_BUFFER_SIZE;
1713
ok = NlMsgPutTailString(&nlBuffer, OVS_WIN_NETDEV_ATTR_NAME,
1716
return STATUS_INVALID_BUFFER_SIZE;
1719
ok = NlMsgPutTailUnspec(&nlBuffer, OVS_WIN_NETDEV_ATTR_MAC_ADDR,
1720
(PCHAR)info->macAddress, sizeof (info->macAddress));
1722
return STATUS_INVALID_BUFFER_SIZE;
1725
ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_MTU, info->mtu);
1727
return STATUS_INVALID_BUFFER_SIZE;
1730
if (info->status != OVS_EVENT_CONNECT) {
1731
netdevFlags = OVS_WIN_NETDEV_IFF_UP;
1733
ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_IF_FLAGS,
1736
return STATUS_INVALID_BUFFER_SIZE;
1740
* XXX: add netdev_stats when we have the definition available in the
1744
nlMsg = (PNL_MSG_HDR)NlBufAt(&nlBuffer, 0, 0);
1745
nlMsg->nlmsgLen = NlBufSize(&nlBuffer);
1747
return STATUS_SUCCESS;
1750
static __inline VOID
1751
OvsWaitActivate(POVS_SWITCH_CONTEXT switchContext, ULONG sleepMicroSec)
1753
while ((!switchContext->isActivated) &&
1754
(!switchContext->isActivateFailed)) {
1755
/* Wait for the switch to be active and
1756
* the list of ports in OVS to be initialized. */
1757
NdisMSleep(sleepMicroSec);
1762
OvsCreateMsgFromVport(POVS_VPORT_ENTRY vport,
1769
OVS_VPORT_FULL_STATS vportStats;
1773
NlBufInit(&nlBuffer, outBuffer, outBufLen);
1775
ok = NlFillOvsMsg(&nlBuffer, msgIn->nlMsg.nlmsgType, NLM_F_MULTI,
1776
msgIn->nlMsg.nlmsgSeq, msgIn->nlMsg.nlmsgPid,
1777
msgIn->genlMsg.cmd, msgIn->genlMsg.version,
1780
return STATUS_INVALID_BUFFER_SIZE;
1783
ok = NlMsgPutTailU32(&nlBuffer, OVS_VPORT_ATTR_PORT_NO, vport->portNo);
1785
return STATUS_INVALID_BUFFER_SIZE;
1788
ok = NlMsgPutTailU32(&nlBuffer, OVS_VPORT_ATTR_TYPE, vport->ovsType);
1790
return STATUS_INVALID_BUFFER_SIZE;
1793
ok = NlMsgPutTailString(&nlBuffer, OVS_VPORT_ATTR_NAME, vport->ovsName);
1795
return STATUS_INVALID_BUFFER_SIZE;
1799
* XXX: when we implement OVS_DP_ATTR_USER_FEATURES in datapath,
1800
* we'll need to check the OVS_DP_F_VPORT_PIDS flag: if it is set,
1801
* it means we have an array of pids, instead of a single pid.
1802
* ATM we assume we have one pid only.
1805
ok = NlMsgPutTailU32(&nlBuffer, OVS_VPORT_ATTR_UPCALL_PID,
1808
return STATUS_INVALID_BUFFER_SIZE;
1812
vportStats.rxPackets = vport->stats.rxPackets;
1813
vportStats.rxBytes = vport->stats.rxBytes;
1814
vportStats.txPackets = vport->stats.txPackets;
1815
vportStats.txBytes = vport->stats.txBytes;
1816
vportStats.rxErrors = vport->errStats.rxErrors;
1817
vportStats.txErrors = vport->errStats.txErrors;
1818
vportStats.rxDropped = vport->errStats.rxDropped;
1819
vportStats.txDropped = vport->errStats.txDropped;
1821
ok = NlMsgPutTailUnspec(&nlBuffer, OVS_VPORT_ATTR_STATS,
1823
sizeof(OVS_VPORT_FULL_STATS));
1825
return STATUS_INVALID_BUFFER_SIZE;
1829
* XXX: when vxlan udp dest port becomes configurable, we will also need
1830
* to add vport options
1833
nlMsg = (PNL_MSG_HDR)NlBufAt(&nlBuffer, 0, 0);
1834
nlMsg->nlmsgLen = NlBufSize(&nlBuffer);
1836
return STATUS_SUCCESS;
1840
OvsGetVportDumpNext(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1844
POVS_OPEN_INSTANCE instance =
1845
(POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
1846
LOCK_STATE_EX lockState;
1847
UINT32 i = OVS_MAX_VPORT_ARRAY_SIZE;
1850
* XXX: this function shares some code with other dump command(s).
1851
* In the future, we will need to refactor the dump functions
1854
ASSERT(usrParamsCtx->devOp == OVS_READ_DEV_OP);
1856
if (instance->dumpState.ovsMsg == NULL) {
1858
return STATUS_INVALID_DEVICE_STATE;
1861
/* Output buffer has been validated while validating read dev op. */
1862
ASSERT(usrParamsCtx->outputBuffer != NULL);
1864
msgIn = instance->dumpState.ovsMsg;
1867
* XXX: when we implement OVS_DP_ATTR_USER_FEATURES in datapath,
1868
* we'll need to check the OVS_DP_F_VPORT_PIDS flag: if it is set,
1869
* it means we have an array of pids, instead of a single pid.
1870
* ATM we assume we have one pid only.
1872
NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState, 0);
1874
if (gOvsSwitchContext->numHvVports > 0 ||
1875
gOvsSwitchContext->numNonHvVports > 0) {
1876
/* inBucket: the bucket, used for lookup */
1877
UINT32 inBucket = instance->dumpState.index[0];
1878
/* inIndex: index within the given bucket, used for lookup */
1879
UINT32 inIndex = instance->dumpState.index[1];
1880
/* the bucket to be used for the next dump operation */
1881
UINT32 outBucket = 0;
1882
/* the index within the outBucket to be used for the next dump */
1883
UINT32 outIndex = 0;
1885
for (i = inBucket; i < OVS_MAX_VPORT_ARRAY_SIZE; i++) {
1886
PLIST_ENTRY head, link;
1887
head = &(gOvsSwitchContext->portNoHashArray[i]);
1888
POVS_VPORT_ENTRY vport = NULL;
1891
LIST_FORALL(head, link) {
1894
* if one or more dumps were previously done on this same bucket,
1895
* inIndex will be > 0, so we'll need to reply with the
1896
* inIndex + 1 vport from the bucket.
1898
if (outIndex >= inIndex) {
1899
vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portNoLink);
1901
ASSERT(vport->portNo != OVS_DPPORT_NUMBER_INVALID);
1902
OvsCreateMsgFromVport(vport, msgIn,
1903
usrParamsCtx->outputBuffer,
1904
usrParamsCtx->outputLength,
1905
gOvsSwitchContext->dpNo);
1918
* if no vport was found above, check the next bucket, beginning
1919
* with the first (i.e. index 0) elem from within that bucket
1926
/* XXX: what about NLMSG_DONE (as msg type)? */
1927
instance->dumpState.index[0] = outBucket;
1928
instance->dumpState.index[1] = outIndex;
1931
NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1933
/* if i < OVS_MAX_VPORT_ARRAY_SIZE => vport was found */
1934
if (i < OVS_MAX_VPORT_ARRAY_SIZE) {
1935
POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
1936
*replyLen = msgOut->nlMsg.nlmsgLen;
1939
* if i >= OVS_MAX_VPORT_ARRAY_SIZE => vport was not found =>
1943
/* Free up the dump state, since there's no more data to continue. */
1944
FreeUserDumpState(instance);
1947
return STATUS_SUCCESS;
1951
OvsGetVport(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1954
NTSTATUS status = STATUS_SUCCESS;
1955
LOCK_STATE_EX lockState;
1957
POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1958
POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
1959
POVS_VPORT_ENTRY vport = NULL;
1960
NL_ERROR nlError = NL_ERROR_SUCCESS;
1961
PCHAR portName = NULL;
1962
UINT32 portNameLen = 0;
1963
UINT32 portNumber = OVS_DPPORT_NUMBER_INVALID;
1965
static const NL_POLICY ovsVportPolicy[] = {
1966
[OVS_VPORT_ATTR_PORT_NO] = { .type = NL_A_U32, .optional = TRUE },
1967
[OVS_VPORT_ATTR_NAME] = { .type = NL_A_STRING,
1972
PNL_ATTR vportAttrs[ARRAY_SIZE(ovsVportPolicy)];
1974
/* input buffer has been validated while validating write dev op. */
1975
ASSERT(usrParamsCtx->inputBuffer != NULL);
1977
if (!NlAttrParse((PNL_MSG_HDR)msgIn,
1978
NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
1979
NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
1980
ovsVportPolicy, vportAttrs, ARRAY_SIZE(vportAttrs))) {
1981
return STATUS_INVALID_PARAMETER;
1984
/* Output buffer has been validated while validating transact dev op. */
1985
ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
1987
NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState, 0);
1988
if (vportAttrs[OVS_VPORT_ATTR_NAME] != NULL) {
1989
portName = NlAttrGet(vportAttrs[OVS_VPORT_ATTR_NAME]);
1990
portNameLen = NlAttrGetSize(vportAttrs[OVS_VPORT_ATTR_NAME]);
1992
/* the port name is expected to be null-terminated */
1993
ASSERT(portName[portNameLen - 1] == '\0');
1995
vport = OvsFindVportByOvsName(gOvsSwitchContext, portName);
1996
} else if (vportAttrs[OVS_VPORT_ATTR_PORT_NO] != NULL) {
1997
portNumber = NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_PORT_NO]);
1999
vport = OvsFindVportByPortNo(gOvsSwitchContext, portNumber);
2001
nlError = NL_ERROR_INVAL;
2002
NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
2007
nlError = NL_ERROR_NODEV;
2008
NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
2012
status = OvsCreateMsgFromVport(vport, msgIn, usrParamsCtx->outputBuffer,
2013
usrParamsCtx->outputLength,
2014
gOvsSwitchContext->dpNo);
2015
NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
2017
*replyLen = msgOut->nlMsg.nlmsgLen;
2020
if (nlError != NL_ERROR_SUCCESS) {
2021
POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
2022
usrParamsCtx->outputBuffer;
2024
NlBuildErrorMsg(msgIn, msgError, nlError);
2025
*replyLen = msgError->nlMsg.nlmsgLen;
2028
return STATUS_SUCCESS;
2032
* --------------------------------------------------------------------------
2033
* Command Handler for 'OVS_VPORT_CMD_GET'.
2035
* The function handles the initial call to setup the dump state, as well as
2036
* subsequent calls to continue dumping data.
2037
* --------------------------------------------------------------------------
2040
OvsGetVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
2045
switch (usrParamsCtx->devOp) {
2046
case OVS_WRITE_DEV_OP:
2047
return OvsSetupDumpStart(usrParamsCtx);
2049
case OVS_READ_DEV_OP:
2050
return OvsGetVportDumpNext(usrParamsCtx, replyLen);
2052
case OVS_TRANSACTION_DEV_OP:
2053
return OvsGetVport(usrParamsCtx, replyLen);
2056
return STATUS_INVALID_DEVICE_REQUEST;
2062
OvsComputeVportNo(POVS_SWITCH_CONTEXT switchContext)
2064
/* we are not allowed to create the port OVS_DPPORT_NUMBER_LOCAL */
2065
for (ULONG i = OVS_DPPORT_NUMBER_LOCAL + 1; i < MAXUINT16; ++i) {
2066
POVS_VPORT_ENTRY vport;
2068
vport = OvsFindVportByPortNo(switchContext, i);
2074
return OVS_DPPORT_NUMBER_INVALID;
2078
* --------------------------------------------------------------------------
2079
* Command Handler for 'OVS_VPORT_CMD_NEW'.
2080
* --------------------------------------------------------------------------
2083
OvsNewVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
2086
NDIS_STATUS status = STATUS_SUCCESS;
2087
LOCK_STATE_EX lockState;
2089
NL_ERROR nlError = NL_ERROR_SUCCESS;
2090
POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
2091
POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
2092
POVS_VPORT_ENTRY vport = NULL;
2096
BOOLEAN isBridgeInternal = FALSE;
2097
BOOLEAN vportAllocated = FALSE, vportInitialized = FALSE;
2098
BOOLEAN addInternalPortAsNetdev = FALSE;
2100
static const NL_POLICY ovsVportPolicy[] = {
2101
[OVS_VPORT_ATTR_PORT_NO] = { .type = NL_A_U32, .optional = TRUE },
2102
[OVS_VPORT_ATTR_TYPE] = { .type = NL_A_U32, .optional = FALSE },
2103
[OVS_VPORT_ATTR_NAME] = { .type = NL_A_STRING, .maxLen = IFNAMSIZ,
2105
[OVS_VPORT_ATTR_UPCALL_PID] = { .type = NL_A_UNSPEC,
2106
.optional = FALSE },
2107
[OVS_VPORT_ATTR_OPTIONS] = { .type = NL_A_NESTED, .optional = TRUE },
2110
PNL_ATTR vportAttrs[ARRAY_SIZE(ovsVportPolicy)];
2112
/* input buffer has been validated while validating write dev op. */
2113
ASSERT(usrParamsCtx->inputBuffer != NULL);
2115
/* Output buffer has been validated while validating transact dev op. */
2116
ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
2118
if (!NlAttrParse((PNL_MSG_HDR)msgIn,
2119
NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
2120
NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
2121
ovsVportPolicy, vportAttrs, ARRAY_SIZE(vportAttrs))) {
2122
return STATUS_INVALID_PARAMETER;
2125
portName = NlAttrGet(vportAttrs[OVS_VPORT_ATTR_NAME]);
2126
portNameLen = NlAttrGetSize(vportAttrs[OVS_VPORT_ATTR_NAME]);
2127
portType = NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_TYPE]);
2129
/* we are expecting null terminated strings to be passed */
2130
ASSERT(portName[portNameLen - 1] == '\0');
2132
NdisAcquireRWLockWrite(gOvsSwitchContext->dispatchLock, &lockState, 0);
2134
vport = OvsFindVportByOvsName(gOvsSwitchContext, portName);
2136
nlError = NL_ERROR_EXIST;
2140
if (portName && portType == OVS_VPORT_TYPE_NETDEV &&
2141
!strcmp(OVS_DPPORT_INTERNAL_NAME_A, portName)) {
2142
addInternalPortAsNetdev = TRUE;
2145
if (portName && portType == OVS_VPORT_TYPE_INTERNAL &&
2146
strcmp(OVS_DPPORT_INTERNAL_NAME_A, portName)) {
2147
isBridgeInternal = TRUE;
2150
if (portType == OVS_VPORT_TYPE_INTERNAL && !isBridgeInternal) {
2151
vport = gOvsSwitchContext->internalVport;
2152
} else if (portType == OVS_VPORT_TYPE_NETDEV) {
2153
/* External ports can also be looked up like VIF ports. */
2154
vport = OvsFindVportByHvNameA(gOvsSwitchContext, portName);
2156
ASSERT(OvsIsTunnelVportType(portType) ||
2157
(portType == OVS_VPORT_TYPE_INTERNAL && isBridgeInternal));
2159
vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
2160
if (vport == NULL) {
2161
nlError = NL_ERROR_NOMEM;
2164
vportAllocated = TRUE;
2166
if (OvsIsTunnelVportType(portType)) {
2167
UINT16 transportPortDest = 0;
2170
case OVS_VPORT_TYPE_VXLAN:
2171
transportPortDest = VXLAN_UDP_PORT;
2173
case OVS_VPORT_TYPE_STT:
2174
transportPortDest = STT_TCP_PORT;
2180
PNL_ATTR attr = NlAttrFindNested(vportAttrs[OVS_VPORT_ATTR_OPTIONS],
2181
OVS_TUNNEL_ATTR_DST_PORT);
2183
transportPortDest = NlAttrGetU16(attr);
2186
status = OvsInitTunnelVport(usrParamsCtx,
2191
nlError = NlMapStatusToNlErr(status);
2193
OvsInitBridgeInternalVport(vport);
2196
vportInitialized = TRUE;
2198
if (nlError == NL_ERROR_SUCCESS) {
2199
vport->ovsState = OVS_STATE_CONNECTED;
2200
vport->nicState = NdisSwitchNicStateConnected;
2203
* Allow the vport to be deleted, because there is no
2204
* corresponding hyper-v switch part.
2206
vport->isAbsentOnHv = TRUE;
2213
nlError = NL_ERROR_INVAL;
2216
if (vport->portNo != OVS_DPPORT_NUMBER_INVALID) {
2217
nlError = NL_ERROR_EXIST;
2221
/* Initialize the vport with OVS specific properties. */
2222
if (addInternalPortAsNetdev != TRUE) {
2223
vport->ovsType = portType;
2225
if (vportAttrs[OVS_VPORT_ATTR_PORT_NO] != NULL) {
2227
* XXX: when we implement the limit for ovs port number to be
2228
* MAXUINT16, we'll need to check the port number received from the
2231
vport->portNo = NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_PORT_NO]);
2233
vport->portNo = OvsComputeVportNo(gOvsSwitchContext);
2234
if (vport->portNo == OVS_DPPORT_NUMBER_INVALID) {
2235
nlError = NL_ERROR_NOMEM;
2240
/* The ovs port name must be uninitialized. */
2241
ASSERT(vport->ovsName[0] == '\0');
2242
ASSERT(portNameLen <= OVS_MAX_PORT_NAME_LENGTH);
2244
RtlCopyMemory(vport->ovsName, portName, portNameLen);
2245
/* if we don't have options, then vport->portOptions will be NULL */
2246
vport->portOptions = vportAttrs[OVS_VPORT_ATTR_OPTIONS];
2249
* XXX: when we implement OVS_DP_ATTR_USER_FEATURES in datapath,
2250
* we'll need to check the OVS_DP_F_VPORT_PIDS flag: if it is set,
2251
* it means we have an array of pids, instead of a single pid.
2252
* ATM we assume we have one pid only.
2254
vport->upcallPid = NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_UPCALL_PID]);
2256
status = InitOvsVportCommon(gOvsSwitchContext, vport);
2257
ASSERT(status == STATUS_SUCCESS);
2259
status = OvsCreateMsgFromVport(vport, msgIn, usrParamsCtx->outputBuffer,
2260
usrParamsCtx->outputLength,
2261
gOvsSwitchContext->dpNo);
2263
*replyLen = msgOut->nlMsg.nlmsgLen;
2266
NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
2268
if ((nlError != NL_ERROR_SUCCESS) && (nlError != NL_ERROR_PENDING)) {
2269
POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
2270
usrParamsCtx->outputBuffer;
2272
if (vport && vportAllocated == TRUE) {
2273
if (vportInitialized == TRUE) {
2274
if (OvsIsTunnelVportType(portType)) {
2275
switch (vport->ovsType) {
2276
case OVS_VPORT_TYPE_VXLAN:
2277
OvsCleanupVxlanTunnel(NULL, vport, NULL, NULL);
2279
case OVS_VPORT_TYPE_STT:
2280
OvsCleanupSttTunnel(vport);
2283
ASSERT(!"Invalid tunnel port type");
2287
OvsFreeMemoryWithTag(vport, OVS_VPORT_POOL_TAG);
2290
NlBuildErrorMsg(msgIn, msgError, nlError);
2291
*replyLen = msgError->nlMsg.nlmsgLen;
2294
return (status == STATUS_PENDING) ? STATUS_PENDING : STATUS_SUCCESS;
2299
* --------------------------------------------------------------------------
2300
* Command Handler for 'OVS_VPORT_CMD_SET'.
2301
* --------------------------------------------------------------------------
2304
OvsSetVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
2307
NDIS_STATUS status = STATUS_SUCCESS;
2308
LOCK_STATE_EX lockState;
2310
POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
2311
POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
2312
POVS_VPORT_ENTRY vport = NULL;
2313
NL_ERROR nlError = NL_ERROR_SUCCESS;
2315
static const NL_POLICY ovsVportPolicy[] = {
2316
[OVS_VPORT_ATTR_PORT_NO] = { .type = NL_A_U32, .optional = TRUE },
2317
[OVS_VPORT_ATTR_TYPE] = { .type = NL_A_U32, .optional = TRUE },
2318
[OVS_VPORT_ATTR_NAME] = { .type = NL_A_STRING, .maxLen = IFNAMSIZ,
2320
[OVS_VPORT_ATTR_UPCALL_PID] = { .type = NL_A_UNSPEC,
2322
[OVS_VPORT_ATTR_STATS] = { .type = NL_A_UNSPEC,
2323
.minLen = sizeof(OVS_VPORT_FULL_STATS),
2324
.maxLen = sizeof(OVS_VPORT_FULL_STATS),
2326
[OVS_VPORT_ATTR_OPTIONS] = { .type = NL_A_NESTED, .optional = TRUE },
2328
PNL_ATTR vportAttrs[ARRAY_SIZE(ovsVportPolicy)];
2330
ASSERT(usrParamsCtx->inputBuffer != NULL);
2332
if (!NlAttrParse((PNL_MSG_HDR)msgIn,
2333
NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
2334
NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
2335
ovsVportPolicy, vportAttrs, ARRAY_SIZE(vportAttrs))) {
2336
return STATUS_INVALID_PARAMETER;
2339
/* Output buffer has been validated while validating transact dev op. */
2340
ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
2342
NdisAcquireRWLockWrite(gOvsSwitchContext->dispatchLock, &lockState, 0);
2343
if (vportAttrs[OVS_VPORT_ATTR_NAME] != NULL) {
2344
PSTR portName = NlAttrGet(vportAttrs[OVS_VPORT_ATTR_NAME]);
2346
UINT32 portNameLen = NlAttrGetSize(vportAttrs[OVS_VPORT_ATTR_NAME]);
2348
/* the port name is expected to be null-terminated */
2349
ASSERT(portName[portNameLen - 1] == '\0');
2351
vport = OvsFindVportByOvsName(gOvsSwitchContext, portName);
2352
} else if (vportAttrs[OVS_VPORT_ATTR_PORT_NO] != NULL) {
2353
vport = OvsFindVportByPortNo(gOvsSwitchContext,
2354
NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_PORT_NO]));
2358
nlError = NL_ERROR_NODEV;
2363
* XXX: when we implement OVS_DP_ATTR_USER_FEATURES in datapath,
2364
* we'll need to check the OVS_DP_F_VPORT_PIDS flag: if it is set,
2365
* it means we have an array of pids, instead of a single pid.
2366
* Currently, we support only one pid.
2368
if (vportAttrs[OVS_VPORT_ATTR_UPCALL_PID]) {
2369
vport->upcallPid = NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_UPCALL_PID]);
2372
if (vportAttrs[OVS_VPORT_ATTR_TYPE]) {
2373
OVS_VPORT_TYPE type = NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_TYPE]);
2374
if (type != vport->ovsType) {
2375
nlError = NL_ERROR_INVAL;
2380
if (vportAttrs[OVS_VPORT_ATTR_OPTIONS]) {
2381
OVS_LOG_ERROR("Vport options not supported");
2382
nlError = NL_ERROR_NOTSUPP;
2386
status = OvsCreateMsgFromVport(vport, msgIn, usrParamsCtx->outputBuffer,
2387
usrParamsCtx->outputLength,
2388
gOvsSwitchContext->dpNo);
2390
*replyLen = msgOut->nlMsg.nlmsgLen;
2393
NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
2395
if (nlError != NL_ERROR_SUCCESS) {
2396
POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
2397
usrParamsCtx->outputBuffer;
2399
NlBuildErrorMsg(msgIn, msgError, nlError);
2400
*replyLen = msgError->nlMsg.nlmsgLen;
2403
return STATUS_SUCCESS;
2407
* --------------------------------------------------------------------------
2408
* Command Handler for 'OVS_VPORT_CMD_DEL'.
2409
* --------------------------------------------------------------------------
2412
OvsDeleteVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
2415
NDIS_STATUS status = STATUS_SUCCESS;
2416
LOCK_STATE_EX lockState;
2418
POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
2419
POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
2420
POVS_VPORT_ENTRY vport = NULL;
2421
NL_ERROR nlError = NL_ERROR_SUCCESS;
2422
PSTR portName = NULL;
2423
UINT32 portNameLen = 0;
2425
static const NL_POLICY ovsVportPolicy[] = {
2426
[OVS_VPORT_ATTR_PORT_NO] = { .type = NL_A_U32, .optional = TRUE },
2427
[OVS_VPORT_ATTR_NAME] = { .type = NL_A_STRING, .maxLen = IFNAMSIZ,
2430
PNL_ATTR vportAttrs[ARRAY_SIZE(ovsVportPolicy)];
2432
ASSERT(usrParamsCtx->inputBuffer != NULL);
2434
if (!NlAttrParse((PNL_MSG_HDR)msgIn,
2435
NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
2436
NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
2437
ovsVportPolicy, vportAttrs, ARRAY_SIZE(vportAttrs))) {
2438
return STATUS_INVALID_PARAMETER;
2441
/* Output buffer has been validated while validating transact dev op. */
2442
ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
2444
NdisAcquireRWLockWrite(gOvsSwitchContext->dispatchLock, &lockState, 0);
2445
if (vportAttrs[OVS_VPORT_ATTR_NAME] != NULL) {
2446
portName = NlAttrGet(vportAttrs[OVS_VPORT_ATTR_NAME]);
2447
portNameLen = NlAttrGetSize(vportAttrs[OVS_VPORT_ATTR_NAME]);
2449
/* the port name is expected to be null-terminated */
2450
ASSERT(portName[portNameLen - 1] == '\0');
2452
vport = OvsFindVportByOvsName(gOvsSwitchContext, portName);
2454
else if (vportAttrs[OVS_VPORT_ATTR_PORT_NO] != NULL) {
2455
vport = OvsFindVportByPortNo(gOvsSwitchContext,
2456
NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_PORT_NO]));
2460
nlError = NL_ERROR_NODEV;
2464
status = OvsCreateMsgFromVport(vport, msgIn, usrParamsCtx->outputBuffer,
2465
usrParamsCtx->outputLength,
2466
gOvsSwitchContext->dpNo);
2468
*replyLen = msgOut->nlMsg.nlmsgLen;
2471
* Mark the port as deleted from OVS userspace. If the port does not exist
2472
* on the Hyper-V switch, it gets deallocated. Otherwise, it stays.
2474
status = OvsRemoveAndDeleteVport(usrParamsCtx,
2480
nlError = NlMapStatusToNlErr(status);
2484
NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
2486
if ((nlError != NL_ERROR_SUCCESS) && (nlError != NL_ERROR_PENDING)) {
2487
POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
2488
usrParamsCtx->outputBuffer;
2490
NlBuildErrorMsg(msgIn, msgError, nlError);
2491
*replyLen = msgError->nlMsg.nlmsgLen;
2494
return (status == STATUS_PENDING) ? STATUS_PENDING : STATUS_SUCCESS;
2498
OvsTunnelVportPendingRemove(PVOID context,
2502
POVS_TUNFLT_INIT_CONTEXT tunnelContext =
2503
(POVS_TUNFLT_INIT_CONTEXT) context;
2504
POVS_SWITCH_CONTEXT switchContext = tunnelContext->switchContext;
2505
POVS_VPORT_ENTRY vport = tunnelContext->vport;
2506
POVS_MESSAGE msgIn = (POVS_MESSAGE)tunnelContext->inputBuffer;
2507
POVS_MESSAGE msgOut = (POVS_MESSAGE)tunnelContext->outputBuffer;
2508
NL_ERROR nlError = NlMapStatusToNlErr(status);
2509
LOCK_STATE_EX lockState;
2511
NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
2513
if (msgIn && msgOut) {
2514
/* Check the received status to reply to the caller. */
2515
if (STATUS_SUCCESS == status) {
2516
OvsCreateMsgFromVport(vport,
2519
tunnelContext->outputLength,
2520
switchContext->dpNo);
2522
*replyLen = msgOut->nlMsg.nlmsgLen;
2524
POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)msgOut;
2526
NlBuildErrorMsg(msgIn, msgError, nlError);
2527
*replyLen = msgError->nlMsg.nlmsgLen;
2531
ASSERT(vport->isAbsentOnHv == TRUE);
2532
ASSERT(vport->portNo != OVS_DPPORT_NUMBER_INVALID);
2534
/* Remove the port from the relevant lists. */
2535
switchContext->numNonHvVports--;
2536
RemoveEntryList(&vport->ovsNameLink);
2537
RemoveEntryList(&vport->portNoLink);
2538
RemoveEntryList(&vport->tunnelVportLink);
2541
OvsFreeMemoryWithTag(vport->priv, OVS_VXLAN_POOL_TAG);
2545
OvsFreeMemoryWithTag(vport, OVS_VPORT_POOL_TAG);
2547
NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
2551
OvsTunnelVportPendingInit(PVOID context,
2555
POVS_TUNFLT_INIT_CONTEXT tunnelContext =
2556
(POVS_TUNFLT_INIT_CONTEXT) context;
2557
POVS_VPORT_ENTRY vport = tunnelContext->vport;
2558
POVS_MESSAGE msgIn = (POVS_MESSAGE)tunnelContext->inputBuffer;
2559
POVS_MESSAGE msgOut = (POVS_MESSAGE)tunnelContext->outputBuffer;
2561
ULONG portNameLen = 0;
2562
UINT32 portType = 0;
2563
NL_ERROR nlError = NL_ERROR_SUCCESS;
2564
BOOLEAN error = TRUE;
2567
if (!NT_SUCCESS(status)) {
2568
nlError = NlMapStatusToNlErr(status);
2572
static const NL_POLICY ovsVportPolicy[] = {
2573
[OVS_VPORT_ATTR_PORT_NO] = { .type = NL_A_U32, .optional = TRUE },
2574
[OVS_VPORT_ATTR_TYPE] = { .type = NL_A_U32, .optional = FALSE },
2575
[OVS_VPORT_ATTR_NAME] = { .type = NL_A_STRING, .maxLen = IFNAMSIZ,
2576
.optional = FALSE },
2577
[OVS_VPORT_ATTR_UPCALL_PID] = { .type = NL_A_UNSPEC,
2578
.optional = FALSE },
2579
[OVS_VPORT_ATTR_OPTIONS] = { .type = NL_A_NESTED, .optional = TRUE },
2582
PNL_ATTR vportAttrs[ARRAY_SIZE(ovsVportPolicy)];
2584
/* input buffer has been validated while validating write dev op. */
2585
ASSERT(msgIn != NULL);
2587
/* Output buffer has been validated while validating transact dev op. */
2588
ASSERT(msgOut != NULL && tunnelContext->outputLength >= sizeof *msgOut);
2590
if (!NlAttrParse((PNL_MSG_HDR)msgIn,
2591
NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
2592
NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
2593
ovsVportPolicy, vportAttrs, ARRAY_SIZE(vportAttrs))) {
2594
nlError = NL_ERROR_INVAL;
2598
portName = NlAttrGet(vportAttrs[OVS_VPORT_ATTR_NAME]);
2599
portNameLen = NlAttrGetSize(vportAttrs[OVS_VPORT_ATTR_NAME]);
2600
portType = NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_TYPE]);
2602
if (vport->portNo != OVS_DPPORT_NUMBER_INVALID) {
2603
nlError = NL_ERROR_EXIST;
2607
vport->ovsState = OVS_STATE_CONNECTED;
2608
vport->nicState = NdisSwitchNicStateConnected;
2611
* Allow the vport to be deleted, because there is no
2612
* corresponding hyper-v switch part.
2614
vport->isAbsentOnHv = TRUE;
2616
if (vportAttrs[OVS_VPORT_ATTR_PORT_NO] != NULL) {
2618
* XXX: when we implement the limit for OVS port number to be
2619
* MAXUINT16, we'll need to check the port number received from the
2623
NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_PORT_NO]);
2626
OvsComputeVportNo(gOvsSwitchContext);
2627
if (vport->portNo == OVS_DPPORT_NUMBER_INVALID) {
2628
nlError = NL_ERROR_NOMEM;
2633
/* The ovs port name must be uninitialized. */
2634
ASSERT(vport->ovsName[0] == '\0');
2635
ASSERT(portNameLen <= OVS_MAX_PORT_NAME_LENGTH);
2637
RtlCopyMemory(vport->ovsName, portName, portNameLen);
2638
/* if we don't have options, then vport->portOptions will be NULL */
2639
vport->portOptions = vportAttrs[OVS_VPORT_ATTR_OPTIONS];
2642
* XXX: when we implement OVS_DP_ATTR_USER_FEATURES in datapath,
2643
* we'll need to check the OVS_DP_F_VPORT_PIDS flag: if it is set,
2644
* it means we have an array of pids, instead of a single pid.
2645
* ATM we assume we have one pid only.
2648
NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_UPCALL_PID]);
2650
status = InitOvsVportCommon(gOvsSwitchContext, vport);
2651
ASSERT(status == STATUS_SUCCESS);
2653
OvsCreateMsgFromVport(vport,
2656
tunnelContext->outputLength,
2657
gOvsSwitchContext->dpNo);
2659
*replyLen = msgOut->nlMsg.nlmsgLen;
2665
POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR) msgOut;
2667
OvsCleanupVxlanTunnel(NULL, vport, NULL, NULL);
2668
OvsFreeMemory(vport);
2670
NlBuildErrorMsg(msgIn, msgError, nlError);
2671
*replyLen = msgError->nlMsg.nlmsgLen;