]>
Commit | Line | Data |
---|---|---|
c803536e SS |
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" | |
fa1324c9 SG |
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" | |
2b144cbb | 26 | #include "Datapath.h" |
c803536e SS |
27 | |
28 | #ifdef OVS_DBG_MOD | |
29 | #undef OVS_DBG_MOD | |
30 | #endif | |
31 | #define OVS_DBG_MOD OVS_DBG_VPORT | |
fa1324c9 | 32 | #include "Debug.h" |
c803536e SS |
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 | ||
c803536e SS |
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); | |
c803536e SS |
61 | static __inline VOID OvsWaitActivate(POVS_SWITCH_CONTEXT switchContext, |
62 | ULONG sleepMicroSec); | |
be581675 NR |
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); | |
c803536e SS |
70 | |
71 | /* | |
72 | * Functions implemented in relaton to NDIS port manipulation. | |
73 | */ | |
74 | NDIS_STATUS | |
fa048323 AS |
75 | HvCreatePort(POVS_SWITCH_CONTEXT switchContext, |
76 | PNDIS_SWITCH_PORT_PARAMETERS portParam) | |
c803536e SS |
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); | |
8d9f1e0c | 87 | if (vport != NULL && !vport->hvDeleted) { |
c803536e SS |
88 | status = STATUS_DATA_NOT_ACCEPTED; |
89 | goto create_port_done; | |
8d9f1e0c NR |
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 | } | |
c803536e | 96 | } |
8d9f1e0c | 97 | |
c803536e SS |
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 | |
fa048323 AS |
108 | HvTeardownPort(POVS_SWITCH_CONTEXT switchContext, |
109 | PNDIS_SWITCH_PORT_PARAMETERS portParam) | |
c803536e SS |
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 | |
fa048323 | 135 | HvDeletePort(POVS_SWITCH_CONTEXT switchContext, |
611531c1 | 136 | PNDIS_SWITCH_PORT_PARAMETERS portParams) |
c803536e SS |
137 | { |
138 | POVS_VPORT_ENTRY vport; | |
139 | LOCK_STATE_EX lockState; | |
140 | ||
611531c1 | 141 | VPORT_PORT_ENTER(portParams); |
c803536e SS |
142 | |
143 | NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0); | |
144 | vport = OvsFindVportByPortIdAndNicIndex(switchContext, | |
611531c1 NR |
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 | */ | |
c803536e | 153 | if (vport) { |
611531c1 NR |
154 | if (vport->portNo == OVS_DPPORT_NUMBER_INVALID) { |
155 | OvsRemoveAndDeleteVport(switchContext, vport); | |
156 | } else { | |
157 | vport->hvDeleted = TRUE; | |
158 | } | |
c803536e SS |
159 | } else { |
160 | OVS_LOG_WARN("Vport not present."); | |
161 | } | |
162 | NdisReleaseRWLock(switchContext->dispatchLock, &lockState); | |
163 | ||
611531c1 | 164 | VPORT_PORT_EXIT(portParams); |
c803536e SS |
165 | } |
166 | ||
167 | ||
168 | /* | |
169 | * Functions implemented in relaton to NDIS NIC manipulation. | |
170 | */ | |
171 | NDIS_STATUS | |
fa048323 AS |
172 | HvCreateNic(POVS_SWITCH_CONTEXT switchContext, |
173 | PNDIS_SWITCH_NIC_PARAMETERS nicParam) | |
c803536e SS |
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); | |
429d4556 | 230 | if (portNo != OVS_DPPORT_NUMBER_INVALID && event) { |
c803536e SS |
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 | |
fa048323 AS |
244 | HvConnectNic(POVS_SWITCH_CONTEXT switchContext, |
245 | PNDIS_SWITCH_NIC_PARAMETERS nicParam) | |
c803536e SS |
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 | ||
429d4556 | 279 | /* XXX only if portNo != INVALID or always? */ |
c803536e SS |
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 | |
fa048323 AS |
291 | HvUpdateNic(POVS_SWITCH_CONTEXT switchContext, |
292 | PNDIS_SWITCH_NIC_PARAMETERS nicParam) | |
c803536e SS |
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 | |
fa048323 AS |
365 | HvDisconnectNic(POVS_SWITCH_CONTEXT switchContext, |
366 | PNDIS_SWITCH_NIC_PARAMETERS nicParam) | |
c803536e SS |
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 | ||
e00afcf6 | 398 | if (vport->ovsType == OVS_VPORT_TYPE_INTERNAL) { |
c803536e SS |
399 | isInternalPort = TRUE; |
400 | } | |
401 | ||
402 | NdisReleaseRWLock(switchContext->dispatchLock, &lockState); | |
403 | ||
429d4556 | 404 | /* XXX if portNo != INVALID or always? */ |
c803536e SS |
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 | |
fa048323 AS |
417 | HvDeleteNic(POVS_SWITCH_CONTEXT switchContext, |
418 | PNDIS_SWITCH_NIC_PARAMETERS nicParam) | |
c803536e SS |
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); | |
429d4556 | 453 | /* XXX if portNo != INVALID or always? */ |
c803536e SS |
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 | { | |
429d4556 AS |
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; | |
c803536e SS |
477 | } |
478 | } | |
479 | return NULL; | |
480 | } | |
481 | ||
482 | ||
483 | POVS_VPORT_ENTRY | |
484 | OvsFindVportByOvsName(POVS_SWITCH_CONTEXT switchContext, | |
8d9f1e0c | 485 | PSTR name) |
c803536e SS |
486 | { |
487 | POVS_VPORT_ENTRY vport; | |
488 | PLIST_ENTRY head, link; | |
8d9f1e0c NR |
489 | UINT32 hash; |
490 | SIZE_T length = strlen(name) + 1; | |
491 | ||
492 | hash = OvsJhashBytes((const VOID *)name, length, OVS_HASH_BASIS); | |
147c91db | 493 | head = &(switchContext->ovsPortNameHashArray[hash & OVS_VPORT_MASK]); |
8d9f1e0c | 494 | |
c803536e | 495 | LIST_FORALL(head, link) { |
147c91db | 496 | vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, ovsNameLink); |
8d9f1e0c | 497 | if (!strcmp(name, vport->ovsName)) { |
c803536e SS |
498 | return vport; |
499 | } | |
500 | } | |
8d9f1e0c | 501 | |
c803536e SS |
502 | return NULL; |
503 | } | |
504 | ||
1b859c58 AS |
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 | ||
516 | PWSTR wsName = OvsAllocateMemory(wstrSize); | |
517 | if (!wsName) { | |
518 | return NULL; | |
519 | } | |
520 | for (UINT i = 0; i < length; i) { | |
521 | wsName[i] = name[i]; | |
522 | } | |
523 | ||
524 | for (UINT32 i = 0; i < OVS_MAX_VPORT_ARRAY_SIZE; i) { | |
525 | head = &(switchContext->portIdHashArray[i]); | |
526 | LIST_FORALL(head, link) { | |
527 | vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portIdLink); | |
528 | ||
529 | /* | |
530 | * NOTE about portFriendlyName: | |
531 | * If the string is NULL-terminated, the Length member does not | |
532 | * include the terminating NULL character. | |
533 | */ | |
534 | if (vport->portFriendlyName.Length == wstrSize && | |
535 | RtlEqualMemory(wsName, vport->portFriendlyName.String, | |
536 | vport->portFriendlyName.Length)) { | |
537 | goto Cleanup; | |
538 | } | |
539 | ||
540 | vport = NULL; | |
541 | } | |
542 | } | |
543 | ||
544 | Cleanup: | |
545 | OvsFreeMemory(wsName); | |
546 | ||
547 | return vport; | |
548 | } | |
549 | ||
c803536e SS |
550 | POVS_VPORT_ENTRY |
551 | OvsFindVportByPortIdAndNicIndex(POVS_SWITCH_CONTEXT switchContext, | |
552 | NDIS_SWITCH_PORT_ID portId, | |
553 | NDIS_SWITCH_NIC_INDEX index) | |
554 | { | |
555 | if (portId == switchContext->externalPortId) { | |
429d4556 | 556 | return (POVS_VPORT_ENTRY)switchContext->externalVport; |
c803536e SS |
557 | } else if (switchContext->internalPortId == portId) { |
558 | return (POVS_VPORT_ENTRY)switchContext->internalVport; | |
559 | } else { | |
560 | PLIST_ENTRY head, link; | |
561 | POVS_VPORT_ENTRY vport; | |
562 | UINT32 hash; | |
563 | hash = OvsJhashWords((UINT32 *)&portId, 1, OVS_HASH_BASIS); | |
91c261cd | 564 | head = &(switchContext->portIdHashArray[hash & OVS_VPORT_MASK]); |
c803536e | 565 | LIST_FORALL(head, link) { |
91c261cd | 566 | vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portIdLink); |
c803536e SS |
567 | if (portId == vport->portId && index == vport->nicIndex) { |
568 | return vport; | |
569 | } | |
570 | } | |
571 | return NULL; | |
572 | } | |
573 | } | |
574 | ||
8d9f1e0c | 575 | POVS_VPORT_ENTRY |
c803536e SS |
576 | OvsAllocateVport(VOID) |
577 | { | |
578 | POVS_VPORT_ENTRY vport; | |
579 | vport = (POVS_VPORT_ENTRY)OvsAllocateMemory(sizeof (OVS_VPORT_ENTRY)); | |
580 | if (vport == NULL) { | |
581 | return NULL; | |
582 | } | |
583 | RtlZeroMemory(vport, sizeof (OVS_VPORT_ENTRY)); | |
584 | vport->ovsState = OVS_STATE_UNKNOWN; | |
8d9f1e0c | 585 | vport->hvDeleted = FALSE; |
429d4556 AS |
586 | vport->portNo = OVS_DPPORT_NUMBER_INVALID; |
587 | ||
588 | InitializeListHead(&vport->ovsNameLink); | |
589 | InitializeListHead(&vport->portIdLink); | |
590 | InitializeListHead(&vport->portNoLink); | |
591 | ||
c803536e SS |
592 | return vport; |
593 | } | |
594 | ||
595 | static VOID | |
596 | OvsInitVportWithPortParam(POVS_VPORT_ENTRY vport, | |
597 | PNDIS_SWITCH_PORT_PARAMETERS portParam) | |
598 | { | |
c803536e SS |
599 | vport->portType = portParam->PortType; |
600 | vport->portState = portParam->PortState; | |
601 | vport->portId = portParam->PortId; | |
602 | vport->nicState = NdisSwitchNicStateUnknown; | |
e00afcf6 | 603 | vport->isExternal = FALSE; |
c803536e SS |
604 | |
605 | switch (vport->portType) { | |
606 | case NdisSwitchPortTypeExternal: | |
e00afcf6 SG |
607 | vport->isExternal = TRUE; |
608 | vport->ovsType = OVS_VPORT_TYPE_NETDEV; | |
c803536e SS |
609 | break; |
610 | case NdisSwitchPortTypeInternal: | |
e00afcf6 | 611 | vport->ovsType = OVS_VPORT_TYPE_INTERNAL; |
c803536e SS |
612 | break; |
613 | case NdisSwitchPortTypeSynthetic: | |
c803536e | 614 | case NdisSwitchPortTypeEmulated: |
e00afcf6 | 615 | vport->ovsType = OVS_VPORT_TYPE_NETDEV; |
c803536e SS |
616 | break; |
617 | } | |
1b859c58 | 618 | RtlCopyMemory(&vport->hvPortName, &portParam->PortName, |
c803536e | 619 | sizeof (NDIS_SWITCH_PORT_NAME)); |
1b859c58 AS |
620 | |
621 | RtlCopyMemory(&vport->portFriendlyName, &portParam->PortFriendlyName, | |
622 | sizeof(NDIS_SWITCH_PORT_FRIENDLYNAME)); | |
623 | ||
c803536e SS |
624 | switch (vport->portState) { |
625 | case NdisSwitchPortStateCreated: | |
626 | vport->ovsState = OVS_STATE_PORT_CREATED; | |
627 | break; | |
628 | case NdisSwitchPortStateTeardown: | |
629 | vport->ovsState = OVS_STATE_PORT_TEAR_DOWN; | |
630 | break; | |
631 | case NdisSwitchPortStateDeleted: | |
632 | vport->ovsState = OVS_STATE_PORT_DELETED; | |
633 | break; | |
634 | } | |
635 | } | |
636 | ||
637 | ||
638 | static VOID | |
639 | OvsInitVportWithNicParam(POVS_SWITCH_CONTEXT switchContext, | |
640 | POVS_VPORT_ENTRY vport, | |
641 | PNDIS_SWITCH_NIC_PARAMETERS nicParam) | |
642 | { | |
643 | ASSERT(vport->portId == nicParam->PortId); | |
644 | ASSERT(vport->ovsState == OVS_STATE_PORT_CREATED); | |
645 | ||
646 | UNREFERENCED_PARAMETER(switchContext); | |
647 | ||
648 | RtlCopyMemory(vport->permMacAddress, nicParam->PermanentMacAddress, | |
649 | sizeof (nicParam->PermanentMacAddress)); | |
650 | RtlCopyMemory(vport->currMacAddress, nicParam->CurrentMacAddress, | |
651 | sizeof (nicParam->CurrentMacAddress)); | |
652 | ||
653 | if (nicParam->NicType == NdisSwitchNicTypeSynthetic || | |
654 | nicParam->NicType == NdisSwitchNicTypeEmulated) { | |
655 | RtlCopyMemory(vport->vmMacAddress, nicParam->VMMacAddress, | |
656 | sizeof (nicParam->VMMacAddress)); | |
657 | RtlCopyMemory(&vport->vmName, &nicParam->VmName, | |
658 | sizeof (nicParam->VmName)); | |
659 | } else { | |
660 | RtlCopyMemory(&vport->netCfgInstanceId, &nicParam->NetCfgInstanceId, | |
661 | sizeof (nicParam->NetCfgInstanceId)); | |
662 | } | |
663 | RtlCopyMemory(&vport->nicName, &nicParam->NicName, | |
664 | sizeof (nicParam->NicName)); | |
665 | vport->mtu = nicParam->MTU; | |
666 | vport->nicState = nicParam->NicState; | |
667 | vport->nicIndex = nicParam->NicIndex; | |
668 | vport->numaNodeId = nicParam->NumaNodeId; | |
669 | ||
670 | switch (vport->nicState) { | |
671 | case NdisSwitchNicStateCreated: | |
672 | vport->ovsState = OVS_STATE_NIC_CREATED; | |
673 | break; | |
674 | case NdisSwitchNicStateConnected: | |
675 | vport->ovsState = OVS_STATE_CONNECTED; | |
676 | break; | |
677 | case NdisSwitchNicStateDisconnected: | |
678 | vport->ovsState = OVS_STATE_NIC_CREATED; | |
679 | break; | |
680 | case NdisSwitchNicStateDeleted: | |
681 | vport->ovsState = OVS_STATE_PORT_CREATED; | |
682 | break; | |
683 | } | |
684 | } | |
685 | ||
686 | static VOID | |
687 | OvsInitPhysNicVport(POVS_VPORT_ENTRY vport, | |
688 | POVS_VPORT_ENTRY virtVport, | |
689 | UINT32 nicIndex) | |
690 | { | |
c803536e SS |
691 | vport->portType = virtVport->portType; |
692 | vport->portState = virtVport->portState; | |
693 | vport->portId = virtVport->portId; | |
694 | vport->nicState = NdisSwitchNicStateUnknown; | |
e00afcf6 SG |
695 | vport->ovsType = OVS_VPORT_TYPE_NETDEV; |
696 | vport->isExternal = TRUE; | |
c803536e | 697 | vport->nicIndex = (NDIS_SWITCH_NIC_INDEX)nicIndex; |
1b859c58 AS |
698 | |
699 | RtlCopyMemory(&vport->hvPortName, &virtVport->hvPortName, | |
c803536e | 700 | sizeof (NDIS_SWITCH_PORT_NAME)); |
1b859c58 AS |
701 | |
702 | RtlCopyMemory(&vport->portFriendlyName, &virtVport->portFriendlyName, | |
703 | sizeof(NDIS_SWITCH_PORT_FRIENDLYNAME)); | |
704 | ||
c803536e SS |
705 | vport->ovsState = OVS_STATE_PORT_CREATED; |
706 | } | |
8d9f1e0c NR |
707 | |
708 | NDIS_STATUS | |
c803536e | 709 | OvsInitVportCommon(POVS_SWITCH_CONTEXT switchContext, |
429d4556 | 710 | POVS_VPORT_ENTRY vport) |
c803536e SS |
711 | { |
712 | UINT32 hash; | |
429d4556 | 713 | ASSERT(vport->portNo == OVS_DPPORT_NUMBER_INVALID); |
c803536e | 714 | |
c803536e SS |
715 | switch (vport->portType) { |
716 | case NdisSwitchPortTypeExternal: | |
717 | if (vport->nicIndex == 0) { | |
718 | switchContext->externalPortId = vport->portId; | |
719 | switchContext->externalVport = vport; | |
720 | RtlStringCbPrintfA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1, | |
721 | "external.virtualAdapter"); | |
429d4556 | 722 | } else { |
c803536e SS |
723 | switchContext->numPhysicalNics++; |
724 | RtlStringCbPrintfA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1, | |
725 | "external.%lu", (UINT32)vport->nicIndex); | |
726 | } | |
727 | break; | |
728 | case NdisSwitchPortTypeInternal: | |
729 | switchContext->internalPortId = vport->portId; | |
730 | switchContext->internalVport = vport; | |
c803536e SS |
731 | break; |
732 | case NdisSwitchPortTypeSynthetic: | |
c803536e SS |
733 | break; |
734 | case NdisSwitchPortTypeEmulated: | |
c803536e SS |
735 | break; |
736 | } | |
429d4556 | 737 | |
c803536e SS |
738 | if (vport->portType == NdisSwitchPortTypeExternal && |
739 | vport->nicIndex == 0) { | |
740 | return NDIS_STATUS_SUCCESS; | |
741 | } | |
429d4556 AS |
742 | |
743 | /* | |
744 | * NOTE: OvsJhashWords has portId as "1" word. This should be ok, even | |
745 | * though sizeof(NDIS_SWITCH_PORT_ID) = 4, not 2, because the | |
746 | * hyper-v switch seems to use only 2 bytes out of 4. | |
747 | */ | |
c803536e | 748 | hash = OvsJhashWords(&vport->portId, 1, OVS_HASH_BASIS); |
91c261cd AS |
749 | InsertHeadList(&switchContext->portIdHashArray[hash & OVS_VPORT_MASK], |
750 | &vport->portIdLink); | |
c803536e SS |
751 | switchContext->numVports++; |
752 | return NDIS_STATUS_SUCCESS; | |
753 | } | |
754 | ||
8d9f1e0c | 755 | VOID |
c803536e SS |
756 | OvsRemoveAndDeleteVport(POVS_SWITCH_CONTEXT switchContext, |
757 | POVS_VPORT_ENTRY vport) | |
758 | { | |
e00afcf6 | 759 | if (vport->isExternal) { |
c803536e SS |
760 | if (vport->nicIndex == 0) { |
761 | ASSERT(switchContext->numPhysicalNics == 0); | |
762 | switchContext->externalPortId = 0; | |
763 | switchContext->externalVport = NULL; | |
764 | OvsFreeMemory(vport); | |
765 | return; | |
766 | } else { | |
767 | ASSERT(switchContext->numPhysicalNics); | |
768 | switchContext->numPhysicalNics--; | |
769 | } | |
e00afcf6 SG |
770 | } |
771 | ||
772 | switch (vport->ovsType) { | |
773 | case OVS_VPORT_TYPE_INTERNAL: | |
c803536e SS |
774 | switchContext->internalPortId = 0; |
775 | switchContext->internalVport = NULL; | |
776 | OvsInternalAdapterDown(); | |
777 | break; | |
e00afcf6 | 778 | case OVS_VPORT_TYPE_VXLAN: |
c803536e SS |
779 | OvsCleanupVxlanTunnel(vport); |
780 | break; | |
e00afcf6 SG |
781 | case OVS_VPORT_TYPE_GRE: |
782 | case OVS_VPORT_TYPE_GRE64: | |
c803536e | 783 | break; |
e00afcf6 | 784 | case OVS_VPORT_TYPE_NETDEV: |
c803536e SS |
785 | default: |
786 | break; | |
787 | } | |
788 | ||
147c91db | 789 | RemoveEntryList(&vport->ovsNameLink); |
91c261cd | 790 | RemoveEntryList(&vport->portIdLink); |
429d4556 | 791 | RemoveEntryList(&vport->portNoLink); |
c803536e SS |
792 | switchContext->numVports--; |
793 | OvsFreeMemory(vport); | |
794 | } | |
795 | ||
796 | ||
797 | NDIS_STATUS | |
798 | OvsAddConfiguredSwitchPorts(POVS_SWITCH_CONTEXT switchContext) | |
799 | { | |
800 | NDIS_STATUS status = NDIS_STATUS_SUCCESS; | |
801 | ULONG arrIndex; | |
802 | PNDIS_SWITCH_PORT_PARAMETERS portParam; | |
803 | PNDIS_SWITCH_PORT_ARRAY portArray = NULL; | |
804 | POVS_VPORT_ENTRY vport; | |
805 | ||
806 | OVS_LOG_TRACE("Enter: switchContext:%p", switchContext); | |
807 | ||
808 | status = OvsGetPortsOnSwitch(switchContext, &portArray); | |
809 | if (status != NDIS_STATUS_SUCCESS) { | |
810 | goto cleanup; | |
811 | } | |
812 | ||
813 | for (arrIndex = 0; arrIndex < portArray->NumElements; arrIndex++) { | |
814 | portParam = NDIS_SWITCH_PORT_AT_ARRAY_INDEX(portArray, arrIndex); | |
c99e6500 AS |
815 | |
816 | if (portParam->IsValidationPort) { | |
817 | continue; | |
818 | } | |
819 | ||
c803536e SS |
820 | vport = (POVS_VPORT_ENTRY)OvsAllocateVport(); |
821 | if (vport == NULL) { | |
822 | status = NDIS_STATUS_RESOURCES; | |
823 | goto cleanup; | |
824 | } | |
825 | OvsInitVportWithPortParam(vport, portParam); | |
826 | status = OvsInitVportCommon(switchContext, vport); | |
827 | if (status != NDIS_STATUS_SUCCESS) { | |
828 | OvsFreeMemory(vport); | |
829 | goto cleanup; | |
830 | } | |
831 | } | |
832 | cleanup: | |
833 | if (status != NDIS_STATUS_SUCCESS) { | |
834 | OvsClearAllSwitchVports(switchContext); | |
835 | } | |
836 | ||
837 | if (portArray != NULL) { | |
838 | OvsFreeMemory(portArray); | |
839 | } | |
840 | OVS_LOG_TRACE("Exit: status: %x", status); | |
841 | return status; | |
842 | } | |
843 | ||
844 | ||
845 | NDIS_STATUS | |
846 | OvsInitConfiguredSwitchNics(POVS_SWITCH_CONTEXT switchContext) | |
847 | { | |
848 | NDIS_STATUS status = NDIS_STATUS_SUCCESS; | |
849 | PNDIS_SWITCH_NIC_ARRAY nicArray = NULL; | |
850 | ULONG arrIndex; | |
851 | PNDIS_SWITCH_NIC_PARAMETERS nicParam; | |
852 | POVS_VPORT_ENTRY vport; | |
853 | ||
854 | OVS_LOG_TRACE("Enter: switchContext: %p", switchContext); | |
855 | /* | |
856 | * Now, get NIC list. | |
857 | */ | |
858 | status = OvsGetNicsOnSwitch(switchContext, &nicArray); | |
859 | if (status != NDIS_STATUS_SUCCESS) { | |
860 | goto cleanup; | |
861 | } | |
862 | for (arrIndex = 0; arrIndex < nicArray->NumElements; ++arrIndex) { | |
863 | ||
864 | nicParam = NDIS_SWITCH_NIC_AT_ARRAY_INDEX(nicArray, arrIndex); | |
865 | ||
866 | /* | |
867 | * XXX: Check if the port is configured with a VLAN. Disallow such a | |
868 | * configuration, since we don't support tag-in-tag. | |
869 | */ | |
870 | ||
871 | /* | |
872 | * XXX: Check if the port is connected to a VF. Disconnect the VF in | |
873 | * such a case. | |
874 | */ | |
875 | ||
876 | if (nicParam->NicType == NdisSwitchNicTypeExternal && | |
877 | nicParam->NicIndex != 0) { | |
878 | POVS_VPORT_ENTRY virtVport = | |
879 | (POVS_VPORT_ENTRY)switchContext->externalVport; | |
880 | vport = OvsAllocateVport(); | |
881 | if (vport) { | |
882 | OvsInitPhysNicVport(vport, virtVport, nicParam->NicIndex); | |
883 | status = OvsInitVportCommon(switchContext, vport); | |
884 | if (status != NDIS_STATUS_SUCCESS) { | |
885 | OvsFreeMemory(vport); | |
886 | vport = NULL; | |
887 | } | |
888 | } | |
889 | } else { | |
890 | vport = OvsFindVportByPortIdAndNicIndex(switchContext, | |
891 | nicParam->PortId, | |
892 | nicParam->NicIndex); | |
893 | } | |
894 | if (vport == NULL) { | |
895 | OVS_LOG_ERROR("Fail to allocate vport"); | |
896 | continue; | |
897 | } | |
898 | OvsInitVportWithNicParam(switchContext, vport, nicParam); | |
899 | if (nicParam->NicType == NdisSwitchNicTypeInternal) { | |
900 | OvsInternalAdapterUp(vport->portNo, &nicParam->NetCfgInstanceId); | |
901 | } | |
902 | } | |
903 | cleanup: | |
904 | ||
905 | if (nicArray != NULL) { | |
906 | OvsFreeMemory(nicArray); | |
907 | } | |
908 | OVS_LOG_TRACE("Exit: status: %x", status); | |
909 | return status; | |
910 | } | |
911 | ||
912 | VOID | |
913 | OvsClearAllSwitchVports(POVS_SWITCH_CONTEXT switchContext) | |
914 | { | |
429d4556 | 915 | for (UINT hash = 0; hash < OVS_MAX_VPORT_ARRAY_SIZE; hash) { |
53165234 | 916 | PLIST_ENTRY head, link, next; |
c803536e | 917 | |
53165234 NR |
918 | head = &(switchContext->portIdHashArray[hash & OVS_VPORT_MASK]); |
919 | LIST_FORALL_SAFE(head, link, next) { | |
429d4556 | 920 | POVS_VPORT_ENTRY vport; |
53165234 | 921 | vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portIdLink); |
429d4556 | 922 | OvsRemoveAndDeleteVport(switchContext, vport); |
c803536e SS |
923 | } |
924 | } | |
429d4556 | 925 | |
c803536e SS |
926 | if (switchContext->externalVport) { |
927 | OvsRemoveAndDeleteVport(switchContext, | |
928 | (POVS_VPORT_ENTRY)switchContext->externalVport); | |
929 | } | |
930 | } | |
931 | ||
c803536e | 932 | |
c803536e SS |
933 | NTSTATUS |
934 | OvsConvertIfCountedStrToAnsiStr(PIF_COUNTED_STRING wStr, | |
935 | CHAR *str, | |
936 | UINT16 maxStrLen) | |
937 | { | |
938 | ANSI_STRING astr; | |
939 | UNICODE_STRING ustr; | |
940 | NTSTATUS status; | |
941 | UINT32 size; | |
942 | ||
943 | ustr.Buffer = wStr->String; | |
944 | ustr.Length = wStr->Length; | |
945 | ustr.MaximumLength = IF_MAX_STRING_SIZE; | |
946 | ||
947 | astr.Buffer = str; | |
948 | astr.MaximumLength = maxStrLen; | |
949 | astr.Length = 0; | |
950 | ||
951 | size = RtlUnicodeStringToAnsiSize(&ustr); | |
952 | if (size > maxStrLen) { | |
953 | return STATUS_BUFFER_OVERFLOW; | |
954 | } | |
955 | ||
956 | status = RtlUnicodeStringToAnsiString(&astr, &ustr, FALSE); | |
957 | ||
958 | ASSERT(status == STATUS_SUCCESS); | |
959 | if (status != STATUS_SUCCESS) { | |
960 | return status; | |
961 | } | |
962 | ASSERT(astr.Length <= maxStrLen); | |
963 | str[astr.Length] = 0; | |
964 | return STATUS_SUCCESS; | |
965 | } | |
966 | ||
967 | ||
d8cecf58 NR |
968 | /* |
969 | * XXX: Get rid of USE_NEW_VPORT_ADD_WORKFLOW while checking in the code for | |
970 | * new vport add workflow, or set USE_NEW_VPORT_ADD_WORKFLOW to 1. | |
971 | */ | |
8d9f1e0c | 972 | #define USE_NEW_VPORT_ADD_WORKFLOW 1 |
c803536e | 973 | NTSTATUS |
be581675 NR |
974 | OvsGetExtInfoIoctl(POVS_VPORT_GET vportGet, |
975 | POVS_VPORT_EXT_INFO extInfo) | |
c803536e | 976 | { |
c803536e SS |
977 | POVS_VPORT_ENTRY vport; |
978 | size_t len; | |
979 | LOCK_STATE_EX lockState; | |
980 | NTSTATUS status = STATUS_SUCCESS; | |
c803536e SS |
981 | BOOLEAN doConvert = FALSE; |
982 | ||
be581675 | 983 | RtlZeroMemory(extInfo, sizeof (POVS_VPORT_EXT_INFO)); |
c803536e SS |
984 | NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState, |
985 | NDIS_RWL_AT_DISPATCH_LEVEL); | |
be581675 NR |
986 | if (vportGet->portNo == 0) { |
987 | StringCbLengthA(vportGet->name, OVS_MAX_PORT_NAME_LENGTH - 1, &len); | |
d8cecf58 | 988 | #if USE_NEW_VPORT_ADD_WORKFLOW == 0 |
be581675 | 989 | vport = OvsFindVportByOvsName(gOvsSwitchContext, vportGet->name, |
c803536e | 990 | (UINT32)len); |
d8cecf58 NR |
991 | #else |
992 | vport = OvsFindVportByHvName(gOvsSwitchContext, vportGet->name); | |
993 | #endif | |
c803536e | 994 | } else { |
be581675 | 995 | vport = OvsFindVportByPortNo(gOvsSwitchContext, vportGet->portNo); |
c803536e SS |
996 | } |
997 | if (vport == NULL || (vport->ovsState != OVS_STATE_CONNECTED && | |
998 | vport->ovsState != OVS_STATE_NIC_CREATED)) { | |
999 | NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState); | |
1000 | NdisReleaseSpinLock(gOvsCtrlLock); | |
be581675 NR |
1001 | if (vportGet->portNo) { |
1002 | OVS_LOG_WARN("vport %u does not exist any more", vportGet->portNo); | |
c803536e | 1003 | } else { |
be581675 | 1004 | OVS_LOG_WARN("vport %s does not exist any more", vportGet->name); |
c803536e SS |
1005 | } |
1006 | status = STATUS_DEVICE_DOES_NOT_EXIST; | |
1007 | goto ext_info_done; | |
1008 | } | |
be581675 NR |
1009 | extInfo->dpNo = vportGet->dpNo; |
1010 | extInfo->portNo = vport->portNo; | |
1011 | RtlCopyMemory(extInfo->macAddress, vport->currMacAddress, | |
c803536e | 1012 | sizeof (vport->currMacAddress)); |
be581675 | 1013 | RtlCopyMemory(extInfo->permMACAddress, vport->permMacAddress, |
c803536e | 1014 | sizeof (vport->permMacAddress)); |
e00afcf6 | 1015 | if (vport->ovsType == OVS_VPORT_TYPE_NETDEV) { |
be581675 | 1016 | RtlCopyMemory(extInfo->vmMACAddress, vport->vmMacAddress, |
c803536e SS |
1017 | sizeof (vport->vmMacAddress)); |
1018 | } | |
be581675 NR |
1019 | extInfo->nicIndex = vport->nicIndex; |
1020 | extInfo->portId = vport->portId; | |
1021 | extInfo->type = vport->ovsType; | |
1022 | extInfo->mtu = vport->mtu; | |
c803536e SS |
1023 | /* |
1024 | * TO be revisit XXX | |
1025 | */ | |
1026 | if (vport->ovsState == OVS_STATE_NIC_CREATED) { | |
be581675 | 1027 | extInfo->status = OVS_EVENT_CONNECT | OVS_EVENT_LINK_DOWN; |
c803536e | 1028 | } else if (vport->ovsState == OVS_STATE_CONNECTED) { |
be581675 | 1029 | extInfo->status = OVS_EVENT_CONNECT | OVS_EVENT_LINK_UP; |
c803536e | 1030 | } else { |
be581675 | 1031 | extInfo->status = OVS_EVENT_DISCONNECT; |
c803536e | 1032 | } |
be581675 | 1033 | if (extInfo->type == OVS_VPORT_TYPE_NETDEV && |
c803536e SS |
1034 | (vport->ovsState == OVS_STATE_NIC_CREATED || |
1035 | vport->ovsState == OVS_STATE_CONNECTED)) { | |
c803536e SS |
1036 | doConvert = TRUE; |
1037 | } else { | |
be581675 NR |
1038 | extInfo->vmUUID[0] = 0; |
1039 | extInfo->vifUUID[0] = 0; | |
c803536e | 1040 | } |
d8cecf58 | 1041 | #if USE_NEW_VPORT_ADD_WORKFLOW == 0 |
be581675 | 1042 | RtlCopyMemory(extInfo->name, vport->ovsName, vport->ovsNameLen + 1); |
d8cecf58 | 1043 | #endif |
c803536e SS |
1044 | NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState); |
1045 | NdisReleaseSpinLock(gOvsCtrlLock); | |
1046 | if (doConvert) { | |
d8cecf58 NR |
1047 | #if USE_NEW_VPORT_ADD_WORKFLOW == 1 |
1048 | status = OvsConvertIfCountedStrToAnsiStr(&vport->portFriendlyName, | |
1049 | extInfo->name, | |
1050 | OVS_MAX_PORT_NAME_LENGTH); | |
1051 | if (status != STATUS_SUCCESS) { | |
1052 | OVS_LOG_INFO("Fail to convert NIC name."); | |
1053 | extInfo->vmUUID[0] = 0; | |
1054 | } | |
1055 | #endif | |
1056 | ||
1057 | status = OvsConvertIfCountedStrToAnsiStr(&vport->vmName, | |
be581675 | 1058 | extInfo->vmUUID, |
c803536e SS |
1059 | OVS_MAX_VM_UUID_LEN); |
1060 | if (status != STATUS_SUCCESS) { | |
1061 | OVS_LOG_INFO("Fail to convert VM name."); | |
be581675 | 1062 | extInfo->vmUUID[0] = 0; |
c803536e SS |
1063 | } |
1064 | ||
d8cecf58 | 1065 | status = OvsConvertIfCountedStrToAnsiStr(&vport->nicName, |
be581675 | 1066 | extInfo->vifUUID, |
c803536e SS |
1067 | OVS_MAX_VIF_UUID_LEN); |
1068 | if (status != STATUS_SUCCESS) { | |
d8cecf58 | 1069 | OVS_LOG_INFO("Fail to convert nic UUID"); |
be581675 | 1070 | extInfo->vifUUID[0] = 0; |
c803536e SS |
1071 | } |
1072 | /* | |
1073 | * for now ignore status | |
1074 | */ | |
1075 | status = STATUS_SUCCESS; | |
1076 | } | |
c803536e SS |
1077 | |
1078 | ext_info_done: | |
c803536e SS |
1079 | return status; |
1080 | } | |
be581675 | 1081 | |
2b144cbb NR |
1082 | /* |
1083 | * -------------------------------------------------------------------------- | |
1084 | * Command Handler for 'OVS_WIN_NETDEV_CMD_GET'. | |
1085 | * -------------------------------------------------------------------------- | |
1086 | */ | |
1087 | NTSTATUS | |
1088 | OvsGetNetdevCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx, | |
1089 | UINT32 *replyLen) | |
1090 | { | |
be581675 NR |
1091 | NTSTATUS status = STATUS_SUCCESS; |
1092 | POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer; | |
1093 | POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer; | |
1094 | NL_ERROR nlError = NL_ERROR_SUCCESS; | |
1095 | OVS_VPORT_GET vportGet; | |
1096 | OVS_VPORT_EXT_INFO info; | |
1097 | LOCK_STATE_EX lockState; | |
1098 | ||
1099 | static const NL_POLICY ovsNetdevPolicy[] = { | |
1100 | [OVS_WIN_NETDEV_ATTR_NAME] = { .type = NL_A_STRING, | |
1101 | .minLen = 2, | |
1102 | .maxLen = IFNAMSIZ }, | |
1103 | }; | |
1104 | PNL_ATTR netdevAttrs[ARRAY_SIZE(ovsNetdevPolicy)]; | |
1105 | ||
1106 | /* input buffer has been validated while validating transaction dev op. */ | |
1107 | ASSERT(usrParamsCtx->inputBuffer != NULL && | |
1108 | usrParamsCtx->inputLength > sizeof *msgIn); | |
1109 | ||
1110 | if (msgOut == NULL || usrParamsCtx->outputLength < sizeof *msgOut) { | |
1111 | return STATUS_INVALID_BUFFER_SIZE; | |
1112 | } | |
1113 | ||
1114 | if (!NlAttrParse((PNL_MSG_HDR)msgIn, | |
1115 | NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN, | |
1116 | NlMsgAttrsLen((PNL_MSG_HDR)msgIn), | |
1117 | ovsNetdevPolicy, netdevAttrs, ARRAY_SIZE(netdevAttrs))) { | |
1118 | return STATUS_INVALID_PARAMETER; | |
1119 | } | |
1120 | ||
1121 | OvsAcquireCtrlLock(); | |
1122 | if (!gOvsSwitchContext) { | |
1123 | OvsReleaseCtrlLock(); | |
1124 | return STATUS_INVALID_PARAMETER; | |
1125 | } | |
1126 | ||
1127 | vportGet.portNo = 0; | |
1128 | RtlCopyMemory(&vportGet.name, NlAttrGet(netdevAttrs[OVS_VPORT_ATTR_NAME]), | |
1129 | NlAttrGetSize(netdevAttrs[OVS_VPORT_ATTR_NAME])); | |
1130 | ||
1131 | NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState, 0); | |
1132 | status = OvsGetExtInfoIoctl(&vportGet, &info); | |
1133 | if (status == STATUS_DEVICE_DOES_NOT_EXIST) { | |
1134 | nlError = NL_ERROR_NODEV; | |
1135 | NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState); | |
1136 | OvsReleaseCtrlLock(); | |
1137 | goto cleanup; | |
1138 | } | |
1139 | NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState); | |
1140 | ||
1141 | status = CreateNetlinkMesgForNetdev(&info, msgIn, | |
1142 | usrParamsCtx->outputBuffer, usrParamsCtx->outputLength, | |
1143 | gOvsSwitchContext->dpNo); | |
1144 | if (status == STATUS_SUCCESS) { | |
1145 | *replyLen = msgOut->nlMsg.nlmsgLen; | |
1146 | } | |
1147 | OvsReleaseCtrlLock(); | |
1148 | ||
1149 | cleanup: | |
1150 | if (nlError != NL_ERROR_SUCCESS) { | |
1151 | POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR) | |
1152 | usrParamsCtx->outputBuffer; | |
1153 | ||
1154 | BuildErrorMsg(msgIn, msgError, nlError); | |
1155 | *replyLen = msgError->nlMsg.nlmsgLen; | |
1156 | } | |
1157 | ||
1158 | return STATUS_SUCCESS; | |
2b144cbb | 1159 | } |
c803536e SS |
1160 | |
1161 | ||
be581675 NR |
1162 | /* |
1163 | * -------------------------------------------------------------------------- | |
1164 | * Utility function to construct an OVS_MESSAGE for the specified vport. The | |
1165 | * OVS_MESSAGE contains the output of a netdev command. | |
1166 | * -------------------------------------------------------------------------- | |
1167 | */ | |
1168 | static NTSTATUS | |
1169 | CreateNetlinkMesgForNetdev(POVS_VPORT_EXT_INFO info, | |
1170 | POVS_MESSAGE msgIn, | |
1171 | PVOID outBuffer, | |
1172 | UINT32 outBufLen, | |
1173 | int dpIfIndex) | |
1174 | { | |
1175 | NL_BUFFER nlBuffer; | |
1176 | BOOLEAN ok; | |
1177 | OVS_MESSAGE msgOut; | |
1178 | PNL_MSG_HDR nlMsg; | |
1179 | UINT32 netdevFlags = 0; | |
1180 | ||
1181 | NlBufInit(&nlBuffer, outBuffer, outBufLen); | |
1182 | ||
1183 | BuildReplyMsgFromMsgIn(msgIn, &msgOut, 0); | |
1184 | msgOut.ovsHdr.dp_ifindex = dpIfIndex; | |
1185 | ||
1186 | ok = NlMsgPutHead(&nlBuffer, (PCHAR)&msgOut, sizeof msgOut); | |
1187 | if (!ok) { | |
1188 | return STATUS_INSUFFICIENT_RESOURCES; | |
1189 | } | |
1190 | ||
1191 | ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_PORT_NO, | |
1192 | info->portNo); | |
1193 | if (!ok) { | |
1194 | return STATUS_INSUFFICIENT_RESOURCES; | |
1195 | } | |
1196 | ||
1197 | ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_TYPE, info->type); | |
1198 | if (!ok) { | |
1199 | return STATUS_INSUFFICIENT_RESOURCES; | |
1200 | } | |
1201 | ||
1202 | ok = NlMsgPutTailString(&nlBuffer, OVS_WIN_NETDEV_ATTR_NAME, | |
1203 | info->name); | |
1204 | if (!ok) { | |
1205 | return STATUS_INSUFFICIENT_RESOURCES; | |
1206 | } | |
1207 | ||
1208 | ok = NlMsgPutTailUnspec(&nlBuffer, OVS_WIN_NETDEV_ATTR_MAC_ADDR, | |
1209 | (PCHAR)info->macAddress, sizeof (info->macAddress)); | |
1210 | if (!ok) { | |
1211 | return STATUS_INSUFFICIENT_RESOURCES; | |
1212 | } | |
1213 | ||
1214 | ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_MTU, info->mtu); | |
1215 | if (!ok) { | |
1216 | return STATUS_INSUFFICIENT_RESOURCES; | |
1217 | } | |
1218 | ||
1219 | if (info->status != OVS_EVENT_CONNECT) { | |
1220 | netdevFlags = OVS_WIN_NETDEV_IFF_UP; | |
1221 | } | |
1222 | ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_IF_FLAGS, | |
1223 | netdevFlags); | |
1224 | if (!ok) { | |
1225 | return STATUS_INSUFFICIENT_RESOURCES; | |
1226 | } | |
1227 | ||
1228 | /* | |
1229 | * XXX: add netdev_stats when we have the definition available in the | |
1230 | * kernel. | |
1231 | */ | |
1232 | ||
1233 | nlMsg = (PNL_MSG_HDR)NlBufAt(&nlBuffer, 0, 0); | |
1234 | nlMsg->nlmsgLen = NlBufSize(&nlBuffer); | |
1235 | ||
1236 | return STATUS_SUCCESS; | |
1237 | } | |
1238 | ||
c803536e SS |
1239 | static __inline VOID |
1240 | OvsWaitActivate(POVS_SWITCH_CONTEXT switchContext, ULONG sleepMicroSec) | |
1241 | { | |
1242 | while ((!switchContext->isActivated) && | |
1243 | (!switchContext->isActivateFailed)) { | |
1244 | /* Wait for the switch to be active and | |
1245 | * the list of ports in OVS to be initialized. */ | |
1246 | NdisMSleep(sleepMicroSec); | |
1247 | } | |
1248 | } |