]> git.proxmox.com Git - mirror_ovs.git/blob - datapath-windows/ovsext/Vport.c
datapath-windows: loop iterator fixes in Vport.c
[mirror_ovs.git] / datapath-windows / ovsext / Vport.c
1 /*
2 * Copyright (c) 2014 VMware, Inc.
3 *
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:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17 #include "precomp.h"
18 #include "Jhash.h"
19 #include "Switch.h"
20 #include "Vport.h"
21 #include "Event.h"
22 #include "User.h"
23 #include "Vxlan.h"
24 #include "IpHelper.h"
25 #include "Oid.h"
26 #include "Datapath.h"
27
28 #ifdef OVS_DBG_MOD
29 #undef OVS_DBG_MOD
30 #endif
31 #define OVS_DBG_MOD OVS_DBG_VPORT
32 #include "Debug.h"
33
34 #define VPORT_NIC_ENTER(_nic) \
35 OVS_LOG_TRACE("Enter: PortId: %x, NicIndex: %d", _nic->PortId, \
36 _nic->NicIndex)
37
38 #define VPORT_NIC_EXIT(_nic) \
39 OVS_LOG_TRACE("Exit: PortId: %x, NicIndex: %d", _nic->PortId, \
40 _nic->NicIndex)
41
42 #define VPORT_PORT_ENTER(_port) \
43 OVS_LOG_TRACE("Enter: PortId: %x", _port->PortId)
44
45 #define VPORT_PORT_EXIT(_port) \
46 OVS_LOG_TRACE("Exit: PortId: %x", _port->PortId)
47
48 #define OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC 100
49
50 extern POVS_SWITCH_CONTEXT gOvsSwitchContext;
51 extern PNDIS_SPIN_LOCK gOvsCtrlLock;
52
53 static VOID OvsInitVportWithPortParam(POVS_VPORT_ENTRY vport,
54 PNDIS_SWITCH_PORT_PARAMETERS portParam);
55 static VOID OvsInitVportWithNicParam(POVS_SWITCH_CONTEXT switchContext,
56 POVS_VPORT_ENTRY vport, PNDIS_SWITCH_NIC_PARAMETERS nicParam);
57 static VOID OvsInitPhysNicVport(POVS_VPORT_ENTRY vport, POVS_VPORT_ENTRY
58 virtVport, UINT32 nicIndex);
59 static VOID OvsInitPhysNicVport(POVS_VPORT_ENTRY vport, POVS_VPORT_ENTRY
60 virtVport, UINT32 nicIndex);
61 static __inline VOID OvsWaitActivate(POVS_SWITCH_CONTEXT switchContext,
62 ULONG sleepMicroSec);
63 static NTSTATUS OvsGetExtInfoIoctl(POVS_VPORT_GET vportGet,
64 POVS_VPORT_EXT_INFO extInfo);
65 static NTSTATUS CreateNetlinkMesgForNetdev(POVS_VPORT_EXT_INFO info,
66 POVS_MESSAGE msgIn,
67 PVOID outBuffer,
68 UINT32 outBufLen,
69 int dpIfIndex);
70
71 /*
72 * Functions implemented in relaton to NDIS port manipulation.
73 */
74 NDIS_STATUS
75 HvCreatePort(POVS_SWITCH_CONTEXT switchContext,
76 PNDIS_SWITCH_PORT_PARAMETERS portParam)
77 {
78 POVS_VPORT_ENTRY vport;
79 LOCK_STATE_EX lockState;
80 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
81
82 VPORT_PORT_ENTER(portParam);
83
84 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
85 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
86 portParam->PortId, 0);
87 if (vport != NULL && !vport->hvDeleted) {
88 status = STATUS_DATA_NOT_ACCEPTED;
89 goto create_port_done;
90 } else if (!vport) {
91 vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
92 if (vport == NULL) {
93 status = NDIS_STATUS_RESOURCES;
94 goto create_port_done;
95 }
96 }
97
98 OvsInitVportWithPortParam(vport, portParam);
99 OvsInitVportCommon(switchContext, vport);
100
101 create_port_done:
102 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
103 VPORT_PORT_EXIT(portParam);
104 return status;
105 }
106
107 VOID
108 HvTeardownPort(POVS_SWITCH_CONTEXT switchContext,
109 PNDIS_SWITCH_PORT_PARAMETERS portParam)
110 {
111 POVS_VPORT_ENTRY vport;
112 LOCK_STATE_EX lockState;
113
114 VPORT_PORT_ENTER(portParam);
115
116 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
117 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
118 portParam->PortId, 0);
119 if (vport) {
120 /* add assertion here
121 */
122 vport->portState = NdisSwitchPortStateTeardown;
123 vport->ovsState = OVS_STATE_PORT_TEAR_DOWN;
124 } else {
125 OVS_LOG_WARN("Vport not present.");
126 }
127 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
128
129 VPORT_PORT_EXIT(portParam);
130 }
131
132
133
134 VOID
135 HvDeletePort(POVS_SWITCH_CONTEXT switchContext,
136 PNDIS_SWITCH_PORT_PARAMETERS portParams)
137 {
138 POVS_VPORT_ENTRY vport;
139 LOCK_STATE_EX lockState;
140
141 VPORT_PORT_ENTER(portParams);
142
143 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
144 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
145 portParams->PortId, 0);
146
147 /*
148 * XXX: we can only destroy and remove the port if its datapath port
149 * counterpart was deleted. If the datapath port counterpart is present,
150 * we only mark the vport for deletion, so that a netlink command vport
151 * delete will delete the vport.
152 */
153 if (vport) {
154 if (vport->portNo == OVS_DPPORT_NUMBER_INVALID) {
155 OvsRemoveAndDeleteVport(switchContext, vport);
156 } else {
157 vport->hvDeleted = TRUE;
158 }
159 } else {
160 OVS_LOG_WARN("Vport not present.");
161 }
162 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
163
164 VPORT_PORT_EXIT(portParams);
165 }
166
167
168 /*
169 * Functions implemented in relaton to NDIS NIC manipulation.
170 */
171 NDIS_STATUS
172 HvCreateNic(POVS_SWITCH_CONTEXT switchContext,
173 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
174 {
175 POVS_VPORT_ENTRY vport;
176 UINT32 portNo = 0;
177 UINT32 event = 0;
178 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
179
180 LOCK_STATE_EX lockState;
181
182 VPORT_NIC_ENTER(nicParam);
183
184 /* Wait for lists to be initialized. */
185 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
186
187 if (!switchContext->isActivated) {
188 OVS_LOG_WARN("Switch is not activated yet.");
189 /* Veto the creation of nic */
190 status = NDIS_STATUS_NOT_SUPPORTED;
191 goto done;
192 }
193
194 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
195 vport = OvsFindVportByPortIdAndNicIndex(switchContext, nicParam->PortId, 0);
196 if (vport == NULL) {
197 OVS_LOG_ERROR("Create NIC without Switch Port,"
198 " PortId: %x, NicIndex: %d",
199 nicParam->PortId, nicParam->NicIndex);
200 status = NDIS_STATUS_INVALID_PARAMETER;
201 goto add_nic_done;
202 }
203
204 if (nicParam->NicType == NdisSwitchNicTypeExternal &&
205 nicParam->NicIndex != 0) {
206 POVS_VPORT_ENTRY virtVport =
207 (POVS_VPORT_ENTRY)switchContext->externalVport;
208 vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
209 if (vport == NULL) {
210 status = NDIS_STATUS_RESOURCES;
211 goto add_nic_done;
212 }
213 OvsInitPhysNicVport(vport, virtVport, nicParam->NicIndex);
214 status = OvsInitVportCommon(switchContext, vport);
215 if (status != NDIS_STATUS_SUCCESS) {
216 OvsFreeMemory(vport);
217 goto add_nic_done;
218 }
219 }
220 OvsInitVportWithNicParam(switchContext, vport, nicParam);
221 portNo = vport->portNo;
222 if (vport->ovsState == OVS_STATE_CONNECTED) {
223 event = OVS_EVENT_CONNECT | OVS_EVENT_LINK_UP;
224 } else if (vport->ovsState == OVS_STATE_NIC_CREATED) {
225 event = OVS_EVENT_CONNECT;
226 }
227
228 add_nic_done:
229 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
230 if (portNo != OVS_DPPORT_NUMBER_INVALID && event) {
231 OvsPostEvent(portNo, event);
232 }
233
234 done:
235 VPORT_NIC_EXIT(nicParam);
236 OVS_LOG_TRACE("Exit: status %8x.\n", status);
237
238 return status;
239 }
240
241
242 /* Mark already created NIC as connected. */
243 VOID
244 HvConnectNic(POVS_SWITCH_CONTEXT switchContext,
245 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
246 {
247 LOCK_STATE_EX lockState;
248 POVS_VPORT_ENTRY vport;
249 UINT32 portNo = 0;
250
251 VPORT_NIC_ENTER(nicParam);
252
253 /* Wait for lists to be initialized. */
254 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
255
256 if (!switchContext->isActivated) {
257 OVS_LOG_WARN("Switch is not activated yet.");
258 goto done;
259 }
260
261 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
262 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
263 nicParam->PortId,
264 nicParam->NicIndex);
265
266 if (!vport) {
267 OVS_LOG_WARN("Vport not present.");
268 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
269 ASSERT(0);
270 goto done;
271 }
272
273 vport->ovsState = OVS_STATE_CONNECTED;
274 vport->nicState = NdisSwitchNicStateConnected;
275 portNo = vport->portNo;
276
277 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
278
279 /* XXX only if portNo != INVALID or always? */
280 OvsPostEvent(portNo, OVS_EVENT_LINK_UP);
281
282 if (nicParam->NicType == NdisSwitchNicTypeInternal) {
283 OvsInternalAdapterUp(portNo, &nicParam->NetCfgInstanceId);
284 }
285
286 done:
287 VPORT_NIC_EXIT(nicParam);
288 }
289
290 VOID
291 HvUpdateNic(POVS_SWITCH_CONTEXT switchContext,
292 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
293 {
294 POVS_VPORT_ENTRY vport;
295 LOCK_STATE_EX lockState;
296
297 UINT32 status = 0, portNo = 0;
298
299 VPORT_NIC_ENTER(nicParam);
300
301 /* Wait for lists to be initialized. */
302 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
303
304 if (!switchContext->isActivated) {
305 OVS_LOG_WARN("Switch is not activated yet.");
306 goto update_nic_done;
307 }
308
309 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
310 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
311 nicParam->PortId,
312 nicParam->NicIndex);
313 if (vport == NULL) {
314 OVS_LOG_WARN("Vport search failed.");
315 goto update_nic_done;
316 }
317 switch (nicParam->NicType) {
318 case NdisSwitchNicTypeExternal:
319 case NdisSwitchNicTypeInternal:
320 RtlCopyMemory(&vport->netCfgInstanceId, &nicParam->NetCfgInstanceId,
321 sizeof (GUID));
322 break;
323 case NdisSwitchNicTypeSynthetic:
324 case NdisSwitchNicTypeEmulated:
325 if (!RtlEqualMemory(vport->vmMacAddress, nicParam->VMMacAddress,
326 sizeof (vport->vmMacAddress))) {
327 status |= OVS_EVENT_MAC_CHANGE;
328 RtlCopyMemory(vport->vmMacAddress, nicParam->VMMacAddress,
329 sizeof (vport->vmMacAddress));
330 }
331 break;
332 default:
333 ASSERT(0);
334 }
335 if (!RtlEqualMemory(vport->permMacAddress, nicParam->PermanentMacAddress,
336 sizeof (vport->permMacAddress))) {
337 RtlCopyMemory(vport->permMacAddress, nicParam->PermanentMacAddress,
338 sizeof (vport->permMacAddress));
339 status |= OVS_EVENT_MAC_CHANGE;
340 }
341 if (!RtlEqualMemory(vport->currMacAddress, nicParam->CurrentMacAddress,
342 sizeof (vport->currMacAddress))) {
343 RtlCopyMemory(vport->currMacAddress, nicParam->CurrentMacAddress,
344 sizeof (vport->currMacAddress));
345 status |= OVS_EVENT_MAC_CHANGE;
346 }
347
348 if (vport->mtu != nicParam->MTU) {
349 vport->mtu = nicParam->MTU;
350 status |= OVS_EVENT_MTU_CHANGE;
351 }
352 vport->numaNodeId = nicParam->NumaNodeId;
353 portNo = vport->portNo;
354
355 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
356 if (status && portNo) {
357 OvsPostEvent(portNo, status);
358 }
359 update_nic_done:
360 VPORT_NIC_EXIT(nicParam);
361 }
362
363
364 VOID
365 HvDisconnectNic(POVS_SWITCH_CONTEXT switchContext,
366 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
367 {
368 POVS_VPORT_ENTRY vport;
369 UINT32 portNo = 0;
370 LOCK_STATE_EX lockState;
371 BOOLEAN isInternalPort = FALSE;
372
373 VPORT_NIC_ENTER(nicParam);
374
375 /* Wait for lists to be initialized. */
376 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
377
378 if (!switchContext->isActivated) {
379 OVS_LOG_WARN("Switch is not activated yet.");
380 goto done;
381 }
382
383 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
384 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
385 nicParam->PortId,
386 nicParam->NicIndex);
387
388 if (!vport) {
389 OVS_LOG_WARN("Vport not present.");
390 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
391 goto done;
392 }
393
394 vport->nicState = NdisSwitchNicStateDisconnected;
395 vport->ovsState = OVS_STATE_NIC_CREATED;
396 portNo = vport->portNo;
397
398 if (vport->ovsType == OVS_VPORT_TYPE_INTERNAL) {
399 isInternalPort = TRUE;
400 }
401
402 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
403
404 /* XXX if portNo != INVALID or always? */
405 OvsPostEvent(portNo, OVS_EVENT_LINK_DOWN);
406
407 if (isInternalPort) {
408 OvsInternalAdapterDown();
409 }
410
411 done:
412 VPORT_NIC_EXIT(nicParam);
413 }
414
415
416 VOID
417 HvDeleteNic(POVS_SWITCH_CONTEXT switchContext,
418 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
419 {
420 LOCK_STATE_EX lockState;
421 POVS_VPORT_ENTRY vport;
422 UINT32 portNo = 0;
423
424 VPORT_NIC_ENTER(nicParam);
425 /* Wait for lists to be initialized. */
426 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
427
428 if (!switchContext->isActivated) {
429 OVS_LOG_WARN("Switch is not activated yet.");
430 goto done;
431 }
432
433 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
434 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
435 nicParam->PortId,
436 nicParam->NicIndex);
437
438 if (!vport) {
439 OVS_LOG_WARN("Vport not present.");
440 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
441 goto done;
442 }
443
444 portNo = vport->portNo;
445 if (vport->portType == NdisSwitchPortTypeExternal &&
446 vport->nicIndex != 0) {
447 OvsRemoveAndDeleteVport(switchContext, vport);
448 }
449 vport->nicState = NdisSwitchNicStateUnknown;
450 vport->ovsState = OVS_STATE_PORT_CREATED;
451
452 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
453 /* XXX if portNo != INVALID or always? */
454 OvsPostEvent(portNo, OVS_EVENT_DISCONNECT);
455
456 done:
457 VPORT_NIC_EXIT(nicParam);
458 }
459
460
461 /*
462 * OVS Vport related functionality.
463 */
464 POVS_VPORT_ENTRY
465 OvsFindVportByPortNo(POVS_SWITCH_CONTEXT switchContext,
466 UINT32 portNo)
467 {
468 POVS_VPORT_ENTRY vport;
469 PLIST_ENTRY head, link;
470 UINT32 hash = OvsJhashBytes((const VOID *)&portNo, sizeof(portNo),
471 OVS_HASH_BASIS);
472 head = &(switchContext->portNoHashArray[hash & OVS_VPORT_MASK]);
473 LIST_FORALL(head, link) {
474 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portNoLink);
475 if (vport->portNo == portNo) {
476 return vport;
477 }
478 }
479 return NULL;
480 }
481
482
483 POVS_VPORT_ENTRY
484 OvsFindVportByOvsName(POVS_SWITCH_CONTEXT switchContext,
485 PSTR name)
486 {
487 POVS_VPORT_ENTRY vport;
488 PLIST_ENTRY head, link;
489 UINT32 hash;
490 SIZE_T length = strlen(name) + 1;
491
492 hash = OvsJhashBytes((const VOID *)name, length, OVS_HASH_BASIS);
493 head = &(switchContext->ovsPortNameHashArray[hash & OVS_VPORT_MASK]);
494
495 LIST_FORALL(head, link) {
496 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, ovsNameLink);
497 if (!strcmp(name, vport->ovsName)) {
498 return vport;
499 }
500 }
501
502 return NULL;
503 }
504
505 /* OvsFindVportByHvName: "name" is assumed to be null-terminated */
506 POVS_VPORT_ENTRY
507 OvsFindVportByHvName(POVS_SWITCH_CONTEXT switchContext,
508 PSTR name)
509 {
510 POVS_VPORT_ENTRY vport = NULL;
511 PLIST_ENTRY head, link;
512 /* 'portFriendlyName' is not NUL-terminated. */
513 SIZE_T length = strlen(name);
514 SIZE_T wstrSize = length * sizeof(WCHAR);
515 UINT i;
516
517 PWSTR wsName = OvsAllocateMemory(wstrSize);
518 if (!wsName) {
519 return NULL;
520 }
521 for (i = 0; i < length; i++) {
522 wsName[i] = name[i];
523 }
524
525 for (i = 0; i < OVS_MAX_VPORT_ARRAY_SIZE; i++) {
526 head = &(switchContext->portIdHashArray[i]);
527 LIST_FORALL(head, link) {
528 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portIdLink);
529
530 /*
531 * NOTE about portFriendlyName:
532 * If the string is NULL-terminated, the Length member does not
533 * include the terminating NULL character.
534 */
535 if (vport->portFriendlyName.Length == wstrSize &&
536 RtlEqualMemory(wsName, vport->portFriendlyName.String,
537 vport->portFriendlyName.Length)) {
538 goto Cleanup;
539 }
540
541 vport = NULL;
542 }
543 }
544
545 Cleanup:
546 OvsFreeMemory(wsName);
547
548 return vport;
549 }
550
551 POVS_VPORT_ENTRY
552 OvsFindVportByPortIdAndNicIndex(POVS_SWITCH_CONTEXT switchContext,
553 NDIS_SWITCH_PORT_ID portId,
554 NDIS_SWITCH_NIC_INDEX index)
555 {
556 if (portId == switchContext->externalPortId) {
557 return (POVS_VPORT_ENTRY)switchContext->externalVport;
558 } else if (switchContext->internalPortId == portId) {
559 return (POVS_VPORT_ENTRY)switchContext->internalVport;
560 } else {
561 PLIST_ENTRY head, link;
562 POVS_VPORT_ENTRY vport;
563 UINT32 hash;
564 hash = OvsJhashWords((UINT32 *)&portId, 1, OVS_HASH_BASIS);
565 head = &(switchContext->portIdHashArray[hash & OVS_VPORT_MASK]);
566 LIST_FORALL(head, link) {
567 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portIdLink);
568 if (portId == vport->portId && index == vport->nicIndex) {
569 return vport;
570 }
571 }
572 return NULL;
573 }
574 }
575
576 POVS_VPORT_ENTRY
577 OvsAllocateVport(VOID)
578 {
579 POVS_VPORT_ENTRY vport;
580 vport = (POVS_VPORT_ENTRY)OvsAllocateMemory(sizeof (OVS_VPORT_ENTRY));
581 if (vport == NULL) {
582 return NULL;
583 }
584 RtlZeroMemory(vport, sizeof (OVS_VPORT_ENTRY));
585 vport->ovsState = OVS_STATE_UNKNOWN;
586 vport->hvDeleted = FALSE;
587 vport->portNo = OVS_DPPORT_NUMBER_INVALID;
588
589 InitializeListHead(&vport->ovsNameLink);
590 InitializeListHead(&vport->portIdLink);
591 InitializeListHead(&vport->portNoLink);
592
593 return vport;
594 }
595
596 static VOID
597 OvsInitVportWithPortParam(POVS_VPORT_ENTRY vport,
598 PNDIS_SWITCH_PORT_PARAMETERS portParam)
599 {
600 vport->portType = portParam->PortType;
601 vport->portState = portParam->PortState;
602 vport->portId = portParam->PortId;
603 vport->nicState = NdisSwitchNicStateUnknown;
604 vport->isExternal = FALSE;
605
606 switch (vport->portType) {
607 case NdisSwitchPortTypeExternal:
608 vport->isExternal = TRUE;
609 vport->ovsType = OVS_VPORT_TYPE_NETDEV;
610 break;
611 case NdisSwitchPortTypeInternal:
612 vport->ovsType = OVS_VPORT_TYPE_INTERNAL;
613 break;
614 case NdisSwitchPortTypeSynthetic:
615 case NdisSwitchPortTypeEmulated:
616 vport->ovsType = OVS_VPORT_TYPE_NETDEV;
617 break;
618 }
619 RtlCopyMemory(&vport->hvPortName, &portParam->PortName,
620 sizeof (NDIS_SWITCH_PORT_NAME));
621
622 RtlCopyMemory(&vport->portFriendlyName, &portParam->PortFriendlyName,
623 sizeof(NDIS_SWITCH_PORT_FRIENDLYNAME));
624
625 switch (vport->portState) {
626 case NdisSwitchPortStateCreated:
627 vport->ovsState = OVS_STATE_PORT_CREATED;
628 break;
629 case NdisSwitchPortStateTeardown:
630 vport->ovsState = OVS_STATE_PORT_TEAR_DOWN;
631 break;
632 case NdisSwitchPortStateDeleted:
633 vport->ovsState = OVS_STATE_PORT_DELETED;
634 break;
635 }
636 }
637
638
639 static VOID
640 OvsInitVportWithNicParam(POVS_SWITCH_CONTEXT switchContext,
641 POVS_VPORT_ENTRY vport,
642 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
643 {
644 ASSERT(vport->portId == nicParam->PortId);
645 ASSERT(vport->ovsState == OVS_STATE_PORT_CREATED);
646
647 UNREFERENCED_PARAMETER(switchContext);
648
649 RtlCopyMemory(vport->permMacAddress, nicParam->PermanentMacAddress,
650 sizeof (nicParam->PermanentMacAddress));
651 RtlCopyMemory(vport->currMacAddress, nicParam->CurrentMacAddress,
652 sizeof (nicParam->CurrentMacAddress));
653
654 if (nicParam->NicType == NdisSwitchNicTypeSynthetic ||
655 nicParam->NicType == NdisSwitchNicTypeEmulated) {
656 RtlCopyMemory(vport->vmMacAddress, nicParam->VMMacAddress,
657 sizeof (nicParam->VMMacAddress));
658 RtlCopyMemory(&vport->vmName, &nicParam->VmName,
659 sizeof (nicParam->VmName));
660 } else {
661 RtlCopyMemory(&vport->netCfgInstanceId, &nicParam->NetCfgInstanceId,
662 sizeof (nicParam->NetCfgInstanceId));
663 }
664 RtlCopyMemory(&vport->nicName, &nicParam->NicName,
665 sizeof (nicParam->NicName));
666 vport->mtu = nicParam->MTU;
667 vport->nicState = nicParam->NicState;
668 vport->nicIndex = nicParam->NicIndex;
669 vport->numaNodeId = nicParam->NumaNodeId;
670
671 switch (vport->nicState) {
672 case NdisSwitchNicStateCreated:
673 vport->ovsState = OVS_STATE_NIC_CREATED;
674 break;
675 case NdisSwitchNicStateConnected:
676 vport->ovsState = OVS_STATE_CONNECTED;
677 break;
678 case NdisSwitchNicStateDisconnected:
679 vport->ovsState = OVS_STATE_NIC_CREATED;
680 break;
681 case NdisSwitchNicStateDeleted:
682 vport->ovsState = OVS_STATE_PORT_CREATED;
683 break;
684 }
685 }
686
687 static VOID
688 OvsInitPhysNicVport(POVS_VPORT_ENTRY vport,
689 POVS_VPORT_ENTRY virtVport,
690 UINT32 nicIndex)
691 {
692 vport->portType = virtVport->portType;
693 vport->portState = virtVport->portState;
694 vport->portId = virtVport->portId;
695 vport->nicState = NdisSwitchNicStateUnknown;
696 vport->ovsType = OVS_VPORT_TYPE_NETDEV;
697 vport->isExternal = TRUE;
698 vport->nicIndex = (NDIS_SWITCH_NIC_INDEX)nicIndex;
699
700 RtlCopyMemory(&vport->hvPortName, &virtVport->hvPortName,
701 sizeof (NDIS_SWITCH_PORT_NAME));
702
703 RtlCopyMemory(&vport->portFriendlyName, &virtVport->portFriendlyName,
704 sizeof(NDIS_SWITCH_PORT_FRIENDLYNAME));
705
706 vport->ovsState = OVS_STATE_PORT_CREATED;
707 }
708
709 NDIS_STATUS
710 OvsInitVportCommon(POVS_SWITCH_CONTEXT switchContext,
711 POVS_VPORT_ENTRY vport)
712 {
713 UINT32 hash;
714 ASSERT(vport->portNo == OVS_DPPORT_NUMBER_INVALID);
715
716 switch (vport->portType) {
717 case NdisSwitchPortTypeExternal:
718 if (vport->nicIndex == 0) {
719 switchContext->externalPortId = vport->portId;
720 switchContext->externalVport = vport;
721 RtlStringCbPrintfA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1,
722 "external.virtualAdapter");
723 } else {
724 switchContext->numPhysicalNics++;
725 RtlStringCbPrintfA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1,
726 "external.%lu", (UINT32)vport->nicIndex);
727 }
728 break;
729 case NdisSwitchPortTypeInternal:
730 switchContext->internalPortId = vport->portId;
731 switchContext->internalVport = vport;
732 break;
733 case NdisSwitchPortTypeSynthetic:
734 break;
735 case NdisSwitchPortTypeEmulated:
736 break;
737 }
738
739 if (vport->portType == NdisSwitchPortTypeExternal &&
740 vport->nicIndex == 0) {
741 return NDIS_STATUS_SUCCESS;
742 }
743
744 /*
745 * NOTE: OvsJhashWords has portId as "1" word. This should be ok, even
746 * though sizeof(NDIS_SWITCH_PORT_ID) = 4, not 2, because the
747 * hyper-v switch seems to use only 2 bytes out of 4.
748 */
749 hash = OvsJhashWords(&vport->portId, 1, OVS_HASH_BASIS);
750 InsertHeadList(&switchContext->portIdHashArray[hash & OVS_VPORT_MASK],
751 &vport->portIdLink);
752 switchContext->numVports++;
753 return NDIS_STATUS_SUCCESS;
754 }
755
756 VOID
757 OvsRemoveAndDeleteVport(POVS_SWITCH_CONTEXT switchContext,
758 POVS_VPORT_ENTRY vport)
759 {
760 if (vport->isExternal) {
761 if (vport->nicIndex == 0) {
762 ASSERT(switchContext->numPhysicalNics == 0);
763 switchContext->externalPortId = 0;
764 switchContext->externalVport = NULL;
765 OvsFreeMemory(vport);
766 return;
767 } else {
768 ASSERT(switchContext->numPhysicalNics);
769 switchContext->numPhysicalNics--;
770 }
771 }
772
773 switch (vport->ovsType) {
774 case OVS_VPORT_TYPE_INTERNAL:
775 switchContext->internalPortId = 0;
776 switchContext->internalVport = NULL;
777 OvsInternalAdapterDown();
778 break;
779 case OVS_VPORT_TYPE_VXLAN:
780 OvsCleanupVxlanTunnel(vport);
781 break;
782 case OVS_VPORT_TYPE_GRE:
783 case OVS_VPORT_TYPE_GRE64:
784 break;
785 case OVS_VPORT_TYPE_NETDEV:
786 default:
787 break;
788 }
789
790 RemoveEntryList(&vport->ovsNameLink);
791 RemoveEntryList(&vport->portIdLink);
792 RemoveEntryList(&vport->portNoLink);
793 switchContext->numVports--;
794 OvsFreeMemory(vport);
795 }
796
797
798 NDIS_STATUS
799 OvsAddConfiguredSwitchPorts(POVS_SWITCH_CONTEXT switchContext)
800 {
801 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
802 ULONG arrIndex;
803 PNDIS_SWITCH_PORT_PARAMETERS portParam;
804 PNDIS_SWITCH_PORT_ARRAY portArray = NULL;
805 POVS_VPORT_ENTRY vport;
806
807 OVS_LOG_TRACE("Enter: switchContext:%p", switchContext);
808
809 status = OvsGetPortsOnSwitch(switchContext, &portArray);
810 if (status != NDIS_STATUS_SUCCESS) {
811 goto cleanup;
812 }
813
814 for (arrIndex = 0; arrIndex < portArray->NumElements; arrIndex++) {
815 portParam = NDIS_SWITCH_PORT_AT_ARRAY_INDEX(portArray, arrIndex);
816
817 if (portParam->IsValidationPort) {
818 continue;
819 }
820
821 vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
822 if (vport == NULL) {
823 status = NDIS_STATUS_RESOURCES;
824 goto cleanup;
825 }
826 OvsInitVportWithPortParam(vport, portParam);
827 status = OvsInitVportCommon(switchContext, vport);
828 if (status != NDIS_STATUS_SUCCESS) {
829 OvsFreeMemory(vport);
830 goto cleanup;
831 }
832 }
833 cleanup:
834 if (status != NDIS_STATUS_SUCCESS) {
835 OvsClearAllSwitchVports(switchContext);
836 }
837
838 if (portArray != NULL) {
839 OvsFreeMemory(portArray);
840 }
841 OVS_LOG_TRACE("Exit: status: %x", status);
842 return status;
843 }
844
845
846 NDIS_STATUS
847 OvsInitConfiguredSwitchNics(POVS_SWITCH_CONTEXT switchContext)
848 {
849 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
850 PNDIS_SWITCH_NIC_ARRAY nicArray = NULL;
851 ULONG arrIndex;
852 PNDIS_SWITCH_NIC_PARAMETERS nicParam;
853 POVS_VPORT_ENTRY vport;
854
855 OVS_LOG_TRACE("Enter: switchContext: %p", switchContext);
856 /*
857 * Now, get NIC list.
858 */
859 status = OvsGetNicsOnSwitch(switchContext, &nicArray);
860 if (status != NDIS_STATUS_SUCCESS) {
861 goto cleanup;
862 }
863 for (arrIndex = 0; arrIndex < nicArray->NumElements; ++arrIndex) {
864
865 nicParam = NDIS_SWITCH_NIC_AT_ARRAY_INDEX(nicArray, arrIndex);
866
867 /*
868 * XXX: Check if the port is configured with a VLAN. Disallow such a
869 * configuration, since we don't support tag-in-tag.
870 */
871
872 /*
873 * XXX: Check if the port is connected to a VF. Disconnect the VF in
874 * such a case.
875 */
876
877 if (nicParam->NicType == NdisSwitchNicTypeExternal &&
878 nicParam->NicIndex != 0) {
879 POVS_VPORT_ENTRY virtVport =
880 (POVS_VPORT_ENTRY)switchContext->externalVport;
881 vport = OvsAllocateVport();
882 if (vport) {
883 OvsInitPhysNicVport(vport, virtVport, nicParam->NicIndex);
884 status = OvsInitVportCommon(switchContext, vport);
885 if (status != NDIS_STATUS_SUCCESS) {
886 OvsFreeMemory(vport);
887 vport = NULL;
888 }
889 }
890 } else {
891 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
892 nicParam->PortId,
893 nicParam->NicIndex);
894 }
895 if (vport == NULL) {
896 OVS_LOG_ERROR("Fail to allocate vport");
897 continue;
898 }
899 OvsInitVportWithNicParam(switchContext, vport, nicParam);
900 if (nicParam->NicType == NdisSwitchNicTypeInternal) {
901 OvsInternalAdapterUp(vport->portNo, &nicParam->NetCfgInstanceId);
902 }
903 }
904 cleanup:
905
906 if (nicArray != NULL) {
907 OvsFreeMemory(nicArray);
908 }
909 OVS_LOG_TRACE("Exit: status: %x", status);
910 return status;
911 }
912
913 VOID
914 OvsClearAllSwitchVports(POVS_SWITCH_CONTEXT switchContext)
915 {
916 for (UINT hash = 0; hash < OVS_MAX_VPORT_ARRAY_SIZE; hash++) {
917 PLIST_ENTRY head, link, next;
918
919 head = &(switchContext->portIdHashArray[hash & OVS_VPORT_MASK]);
920 LIST_FORALL_SAFE(head, link, next) {
921 POVS_VPORT_ENTRY vport;
922 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portIdLink);
923 OvsRemoveAndDeleteVport(switchContext, vport);
924 }
925 }
926
927 if (switchContext->externalVport) {
928 OvsRemoveAndDeleteVport(switchContext,
929 (POVS_VPORT_ENTRY)switchContext->externalVport);
930 }
931 }
932
933
934 NTSTATUS
935 OvsConvertIfCountedStrToAnsiStr(PIF_COUNTED_STRING wStr,
936 CHAR *str,
937 UINT16 maxStrLen)
938 {
939 ANSI_STRING astr;
940 UNICODE_STRING ustr;
941 NTSTATUS status;
942 UINT32 size;
943
944 ustr.Buffer = wStr->String;
945 ustr.Length = wStr->Length;
946 ustr.MaximumLength = IF_MAX_STRING_SIZE;
947
948 astr.Buffer = str;
949 astr.MaximumLength = maxStrLen;
950 astr.Length = 0;
951
952 size = RtlUnicodeStringToAnsiSize(&ustr);
953 if (size > maxStrLen) {
954 return STATUS_BUFFER_OVERFLOW;
955 }
956
957 status = RtlUnicodeStringToAnsiString(&astr, &ustr, FALSE);
958
959 ASSERT(status == STATUS_SUCCESS);
960 if (status != STATUS_SUCCESS) {
961 return status;
962 }
963 ASSERT(astr.Length <= maxStrLen);
964 str[astr.Length] = 0;
965 return STATUS_SUCCESS;
966 }
967
968
969 /*
970 * XXX: Get rid of USE_NEW_VPORT_ADD_WORKFLOW while checking in the code for
971 * new vport add workflow, or set USE_NEW_VPORT_ADD_WORKFLOW to 1.
972 */
973 #define USE_NEW_VPORT_ADD_WORKFLOW 1
974 NTSTATUS
975 OvsGetExtInfoIoctl(POVS_VPORT_GET vportGet,
976 POVS_VPORT_EXT_INFO extInfo)
977 {
978 POVS_VPORT_ENTRY vport;
979 size_t len;
980 LOCK_STATE_EX lockState;
981 NTSTATUS status = STATUS_SUCCESS;
982 BOOLEAN doConvert = FALSE;
983
984 RtlZeroMemory(extInfo, sizeof (POVS_VPORT_EXT_INFO));
985 NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState,
986 NDIS_RWL_AT_DISPATCH_LEVEL);
987 if (vportGet->portNo == 0) {
988 StringCbLengthA(vportGet->name, OVS_MAX_PORT_NAME_LENGTH - 1, &len);
989 #if USE_NEW_VPORT_ADD_WORKFLOW == 0
990 vport = OvsFindVportByOvsName(gOvsSwitchContext, vportGet->name,
991 (UINT32)len);
992 #else
993 vport = OvsFindVportByHvName(gOvsSwitchContext, vportGet->name);
994 #endif
995 } else {
996 vport = OvsFindVportByPortNo(gOvsSwitchContext, vportGet->portNo);
997 }
998 if (vport == NULL || (vport->ovsState != OVS_STATE_CONNECTED &&
999 vport->ovsState != OVS_STATE_NIC_CREATED)) {
1000 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1001 NdisReleaseSpinLock(gOvsCtrlLock);
1002 if (vportGet->portNo) {
1003 OVS_LOG_WARN("vport %u does not exist any more", vportGet->portNo);
1004 } else {
1005 OVS_LOG_WARN("vport %s does not exist any more", vportGet->name);
1006 }
1007 status = STATUS_DEVICE_DOES_NOT_EXIST;
1008 goto ext_info_done;
1009 }
1010 extInfo->dpNo = vportGet->dpNo;
1011 extInfo->portNo = vport->portNo;
1012 RtlCopyMemory(extInfo->macAddress, vport->currMacAddress,
1013 sizeof (vport->currMacAddress));
1014 RtlCopyMemory(extInfo->permMACAddress, vport->permMacAddress,
1015 sizeof (vport->permMacAddress));
1016 if (vport->ovsType == OVS_VPORT_TYPE_NETDEV) {
1017 RtlCopyMemory(extInfo->vmMACAddress, vport->vmMacAddress,
1018 sizeof (vport->vmMacAddress));
1019 }
1020 extInfo->nicIndex = vport->nicIndex;
1021 extInfo->portId = vport->portId;
1022 extInfo->type = vport->ovsType;
1023 extInfo->mtu = vport->mtu;
1024 /*
1025 * TO be revisit XXX
1026 */
1027 if (vport->ovsState == OVS_STATE_NIC_CREATED) {
1028 extInfo->status = OVS_EVENT_CONNECT | OVS_EVENT_LINK_DOWN;
1029 } else if (vport->ovsState == OVS_STATE_CONNECTED) {
1030 extInfo->status = OVS_EVENT_CONNECT | OVS_EVENT_LINK_UP;
1031 } else {
1032 extInfo->status = OVS_EVENT_DISCONNECT;
1033 }
1034 if (extInfo->type == OVS_VPORT_TYPE_NETDEV &&
1035 (vport->ovsState == OVS_STATE_NIC_CREATED ||
1036 vport->ovsState == OVS_STATE_CONNECTED)) {
1037 doConvert = TRUE;
1038 } else {
1039 extInfo->vmUUID[0] = 0;
1040 extInfo->vifUUID[0] = 0;
1041 }
1042 #if USE_NEW_VPORT_ADD_WORKFLOW == 0
1043 RtlCopyMemory(extInfo->name, vport->ovsName, vport->ovsNameLen + 1);
1044 #endif
1045 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1046 NdisReleaseSpinLock(gOvsCtrlLock);
1047 if (doConvert) {
1048 #if USE_NEW_VPORT_ADD_WORKFLOW == 1
1049 status = OvsConvertIfCountedStrToAnsiStr(&vport->portFriendlyName,
1050 extInfo->name,
1051 OVS_MAX_PORT_NAME_LENGTH);
1052 if (status != STATUS_SUCCESS) {
1053 OVS_LOG_INFO("Fail to convert NIC name.");
1054 extInfo->vmUUID[0] = 0;
1055 }
1056 #endif
1057
1058 status = OvsConvertIfCountedStrToAnsiStr(&vport->vmName,
1059 extInfo->vmUUID,
1060 OVS_MAX_VM_UUID_LEN);
1061 if (status != STATUS_SUCCESS) {
1062 OVS_LOG_INFO("Fail to convert VM name.");
1063 extInfo->vmUUID[0] = 0;
1064 }
1065
1066 status = OvsConvertIfCountedStrToAnsiStr(&vport->nicName,
1067 extInfo->vifUUID,
1068 OVS_MAX_VIF_UUID_LEN);
1069 if (status != STATUS_SUCCESS) {
1070 OVS_LOG_INFO("Fail to convert nic UUID");
1071 extInfo->vifUUID[0] = 0;
1072 }
1073 /*
1074 * for now ignore status
1075 */
1076 status = STATUS_SUCCESS;
1077 }
1078
1079 ext_info_done:
1080 return status;
1081 }
1082
1083 /*
1084 * --------------------------------------------------------------------------
1085 * Command Handler for 'OVS_WIN_NETDEV_CMD_GET'.
1086 * --------------------------------------------------------------------------
1087 */
1088 NTSTATUS
1089 OvsGetNetdevCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1090 UINT32 *replyLen)
1091 {
1092 NTSTATUS status = STATUS_SUCCESS;
1093 POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1094 POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
1095 NL_ERROR nlError = NL_ERROR_SUCCESS;
1096 OVS_VPORT_GET vportGet;
1097 OVS_VPORT_EXT_INFO info;
1098 LOCK_STATE_EX lockState;
1099
1100 static const NL_POLICY ovsNetdevPolicy[] = {
1101 [OVS_WIN_NETDEV_ATTR_NAME] = { .type = NL_A_STRING,
1102 .minLen = 2,
1103 .maxLen = IFNAMSIZ },
1104 };
1105 PNL_ATTR netdevAttrs[ARRAY_SIZE(ovsNetdevPolicy)];
1106
1107 /* input buffer has been validated while validating transaction dev op. */
1108 ASSERT(usrParamsCtx->inputBuffer != NULL &&
1109 usrParamsCtx->inputLength > sizeof *msgIn);
1110
1111 if (msgOut == NULL || usrParamsCtx->outputLength < sizeof *msgOut) {
1112 return STATUS_INVALID_BUFFER_SIZE;
1113 }
1114
1115 if (!NlAttrParse((PNL_MSG_HDR)msgIn,
1116 NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
1117 NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
1118 ovsNetdevPolicy, netdevAttrs, ARRAY_SIZE(netdevAttrs))) {
1119 return STATUS_INVALID_PARAMETER;
1120 }
1121
1122 OvsAcquireCtrlLock();
1123 if (!gOvsSwitchContext) {
1124 OvsReleaseCtrlLock();
1125 return STATUS_INVALID_PARAMETER;
1126 }
1127
1128 vportGet.portNo = 0;
1129 RtlCopyMemory(&vportGet.name, NlAttrGet(netdevAttrs[OVS_VPORT_ATTR_NAME]),
1130 NlAttrGetSize(netdevAttrs[OVS_VPORT_ATTR_NAME]));
1131
1132 NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState, 0);
1133 status = OvsGetExtInfoIoctl(&vportGet, &info);
1134 if (status == STATUS_DEVICE_DOES_NOT_EXIST) {
1135 nlError = NL_ERROR_NODEV;
1136 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1137 OvsReleaseCtrlLock();
1138 goto cleanup;
1139 }
1140 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1141
1142 status = CreateNetlinkMesgForNetdev(&info, msgIn,
1143 usrParamsCtx->outputBuffer, usrParamsCtx->outputLength,
1144 gOvsSwitchContext->dpNo);
1145 if (status == STATUS_SUCCESS) {
1146 *replyLen = msgOut->nlMsg.nlmsgLen;
1147 }
1148 OvsReleaseCtrlLock();
1149
1150 cleanup:
1151 if (nlError != NL_ERROR_SUCCESS) {
1152 POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
1153 usrParamsCtx->outputBuffer;
1154
1155 BuildErrorMsg(msgIn, msgError, nlError);
1156 *replyLen = msgError->nlMsg.nlmsgLen;
1157 }
1158
1159 return STATUS_SUCCESS;
1160 }
1161
1162
1163 /*
1164 * --------------------------------------------------------------------------
1165 * Utility function to construct an OVS_MESSAGE for the specified vport. The
1166 * OVS_MESSAGE contains the output of a netdev command.
1167 * --------------------------------------------------------------------------
1168 */
1169 static NTSTATUS
1170 CreateNetlinkMesgForNetdev(POVS_VPORT_EXT_INFO info,
1171 POVS_MESSAGE msgIn,
1172 PVOID outBuffer,
1173 UINT32 outBufLen,
1174 int dpIfIndex)
1175 {
1176 NL_BUFFER nlBuffer;
1177 BOOLEAN ok;
1178 OVS_MESSAGE msgOut;
1179 PNL_MSG_HDR nlMsg;
1180 UINT32 netdevFlags = 0;
1181
1182 NlBufInit(&nlBuffer, outBuffer, outBufLen);
1183
1184 BuildReplyMsgFromMsgIn(msgIn, &msgOut, 0);
1185 msgOut.ovsHdr.dp_ifindex = dpIfIndex;
1186
1187 ok = NlMsgPutHead(&nlBuffer, (PCHAR)&msgOut, sizeof msgOut);
1188 if (!ok) {
1189 return STATUS_INSUFFICIENT_RESOURCES;
1190 }
1191
1192 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_PORT_NO,
1193 info->portNo);
1194 if (!ok) {
1195 return STATUS_INSUFFICIENT_RESOURCES;
1196 }
1197
1198 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_TYPE, info->type);
1199 if (!ok) {
1200 return STATUS_INSUFFICIENT_RESOURCES;
1201 }
1202
1203 ok = NlMsgPutTailString(&nlBuffer, OVS_WIN_NETDEV_ATTR_NAME,
1204 info->name);
1205 if (!ok) {
1206 return STATUS_INSUFFICIENT_RESOURCES;
1207 }
1208
1209 ok = NlMsgPutTailUnspec(&nlBuffer, OVS_WIN_NETDEV_ATTR_MAC_ADDR,
1210 (PCHAR)info->macAddress, sizeof (info->macAddress));
1211 if (!ok) {
1212 return STATUS_INSUFFICIENT_RESOURCES;
1213 }
1214
1215 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_MTU, info->mtu);
1216 if (!ok) {
1217 return STATUS_INSUFFICIENT_RESOURCES;
1218 }
1219
1220 if (info->status != OVS_EVENT_CONNECT) {
1221 netdevFlags = OVS_WIN_NETDEV_IFF_UP;
1222 }
1223 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_IF_FLAGS,
1224 netdevFlags);
1225 if (!ok) {
1226 return STATUS_INSUFFICIENT_RESOURCES;
1227 }
1228
1229 /*
1230 * XXX: add netdev_stats when we have the definition available in the
1231 * kernel.
1232 */
1233
1234 nlMsg = (PNL_MSG_HDR)NlBufAt(&nlBuffer, 0, 0);
1235 nlMsg->nlmsgLen = NlBufSize(&nlBuffer);
1236
1237 return STATUS_SUCCESS;
1238 }
1239
1240 static __inline VOID
1241 OvsWaitActivate(POVS_SWITCH_CONTEXT switchContext, ULONG sleepMicroSec)
1242 {
1243 while ((!switchContext->isActivated) &&
1244 (!switchContext->isActivateFailed)) {
1245 /* Wait for the switch to be active and
1246 * the list of ports in OVS to be initialized. */
1247 NdisMSleep(sleepMicroSec);
1248 }
1249 }