~ubuntu-branches/ubuntu/wily/openvswitch/wily

« back to all changes in this revision

Viewing changes to datapath-windows/ovsext/Vport.c

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2015-08-10 11:35:15 UTC
  • mfrom: (1.1.30)
  • Revision ID: package-import@ubuntu.com-20150810113515-575vj06oq29emxsn
Tags: 2.4.0~git20150810.97bab95-0ubuntu1
* New upstream snapshot from 2.4 branch:
  - d/*: Align any relevant packaging changes with upstream.
* d/*: wrap-and-sort.
* d/openvswitch-{common,vswitch}.install: Correct install location for
  bash completion files.
* d/tests/openflow.py: Explicitly use ovs-testcontroller as provided
  by 2.4.0 release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 "Stt.h"
 
25
#include "IpHelper.h"
 
26
#include "Oid.h"
 
27
#include "Datapath.h"
 
28
 
 
29
#ifdef OVS_DBG_MOD
 
30
#undef OVS_DBG_MOD
 
31
#endif
 
32
#define OVS_DBG_MOD OVS_DBG_VPORT
 
33
#include "Debug.h"
 
34
 
 
35
#define VPORT_NIC_ENTER(_nic) \
 
36
    OVS_LOG_TRACE("Enter: PortId: %x, NicIndex: %d", _nic->PortId, \
 
37
                                                     _nic->NicIndex)
 
38
 
 
39
#define VPORT_NIC_EXIT(_nic) \
 
40
    OVS_LOG_TRACE("Exit: PortId: %x, NicIndex: %d", _nic->PortId, \
 
41
                                                    _nic->NicIndex)
 
42
 
 
43
#define VPORT_PORT_ENTER(_port) \
 
44
    OVS_LOG_TRACE("Enter: PortId: %x", _port->PortId)
 
45
 
 
46
#define VPORT_PORT_EXIT(_port) \
 
47
    OVS_LOG_TRACE("Exit: PortId: %x", _port->PortId)
 
48
 
 
49
#define OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC    100
 
50
 
 
51
/* Context structure used to pass back and forth information to the tunnel
 
52
 * filter threads. */
 
53
typedef struct _OVS_TUNFLT_INIT_CONTEXT {
 
54
    POVS_SWITCH_CONTEXT switchContext;
 
55
    UINT32 outputLength;
 
56
    PVOID outputBuffer;
 
57
    PVOID inputBuffer;
 
58
    POVS_VPORT_ENTRY vport;
 
59
    BOOLEAN hvSwitchPort;
 
60
    BOOLEAN hvDelete;
 
61
    BOOLEAN ovsDelete;
 
62
} OVS_TUNFLT_INIT_CONTEXT, *POVS_TUNFLT_INIT_CONTEXT;
 
63
 
 
64
 
 
65
extern POVS_SWITCH_CONTEXT gOvsSwitchContext;
 
66
 
 
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,
 
74
                                     ULONG sleepMicroSec);
 
75
static NTSTATUS OvsGetExtInfoIoctl(POVS_VPORT_GET vportGet,
 
76
                                   POVS_VPORT_EXT_INFO extInfo);
 
77
static NTSTATUS CreateNetlinkMesgForNetdev(POVS_VPORT_EXT_INFO info,
 
78
                                           POVS_MESSAGE msgIn,
 
79
                                           PVOID outBuffer,
 
80
                                           UINT32 outBufLen,
 
81
                                           int dpIfIndex);
 
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,
 
86
                                     BOOLEAN newPort);
 
87
static NTSTATUS OvsRemoveTunnelVport(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
 
88
                                     POVS_SWITCH_CONTEXT switchContext,
 
89
                                     POVS_VPORT_ENTRY vport,
 
90
                                     BOOLEAN hvDelete,
 
91
                                     BOOLEAN ovsDelete);
 
92
static VOID OvsTunnelVportPendingInit(PVOID context,
 
93
                                      NTSTATUS status,
 
94
                                      UINT32 *replyLen);
 
95
static VOID OvsTunnelVportPendingRemove(PVOID context,
 
96
                                        NTSTATUS status,
 
97
                                        UINT32 *replyLen);
 
98
 
 
99
 
 
100
/*
 
101
 * Functions implemented in relaton to NDIS port manipulation.
 
102
 */
 
103
NDIS_STATUS
 
104
HvCreatePort(POVS_SWITCH_CONTEXT switchContext,
 
105
             PNDIS_SWITCH_PORT_PARAMETERS portParam)
 
106
{
 
107
    POVS_VPORT_ENTRY vport;
 
108
    LOCK_STATE_EX lockState;
 
109
    NDIS_STATUS status = NDIS_STATUS_SUCCESS;
 
110
    BOOLEAN newPort = FALSE;
 
111
 
 
112
    VPORT_PORT_ENTER(portParam);
 
113
 
 
114
    NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
 
115
    /* Lookup by port ID. */
 
116
    vport = OvsFindVportByPortIdAndNicIndex(switchContext,
 
117
                                            portParam->PortId, 0);
 
118
    if (vport != NULL) {
 
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;
 
123
    }
 
124
 
 
125
    /*
 
126
     * Lookup by port name to see if this port with this name had been added
 
127
     * (and deleted) previously.
 
128
     */
 
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;
 
138
    }
 
139
 
 
140
    if (vport != NULL) {
 
141
        ASSERT(vport->isAbsentOnHv);
 
142
        ASSERT(vport->portNo != OVS_DPPORT_NUMBER_INVALID);
 
143
 
 
144
        /*
 
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.
 
148
         */
 
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;
 
155
        }
 
156
        vport->isAbsentOnHv = FALSE;
 
157
    } else {
 
158
        vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
 
159
        if (vport == NULL) {
 
160
            status = NDIS_STATUS_RESOURCES;
 
161
            goto create_port_done;
 
162
        }
 
163
        newPort = TRUE;
 
164
    }
 
165
    OvsInitVportWithPortParam(vport, portParam);
 
166
    InitHvVportCommon(switchContext, vport, newPort);
 
167
 
 
168
create_port_done:
 
169
    NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
 
170
    VPORT_PORT_EXIT(portParam);
 
171
    return status;
 
172
}
 
173
 
 
174
 
 
175
/*
 
176
 * Function updating the port properties
 
177
 */
 
178
NDIS_STATUS
 
179
HvUpdatePort(POVS_SWITCH_CONTEXT switchContext,
 
180
             PNDIS_SWITCH_PORT_PARAMETERS portParam)
 
181
{
 
182
    POVS_VPORT_ENTRY vport;
 
183
    LOCK_STATE_EX lockState;
 
184
    OVS_VPORT_STATE ovsState;
 
185
    NDIS_SWITCH_NIC_STATE nicState;
 
186
 
 
187
    VPORT_PORT_ENTER(portParam);
 
188
 
 
189
    NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
 
190
    vport = OvsFindVportByPortIdAndNicIndex(switchContext,
 
191
                                            portParam->PortId, 0);
 
192
    /*
 
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
 
195
     */
 
196
    if (vport == NULL || (( vport->portType != NdisSwitchPortTypeSynthetic) &&
 
197
        ( vport->portType != NdisSwitchPortTypeEmulated))) {
 
198
        goto update_port_done;
 
199
    }
 
200
 
 
201
    /* Store the nic and the OVS states as Nic Create won't be called */
 
202
    ovsState = vport->ovsState;
 
203
    nicState = vport->nicState;
 
204
 
 
205
    /*
 
206
     * Currently only the port friendly name is being updated
 
207
     * Make sure that no other properties are changed
 
208
     */
 
209
    ASSERT(portParam->PortId == vport->portId);
 
210
    ASSERT(portParam->PortState == vport->portState);
 
211
    ASSERT(portParam->PortType == vport->portType);
 
212
 
 
213
    /*
 
214
     * Call the set parameters function the handle all properties
 
215
     * change in a single place in case future version supports change of
 
216
     * other properties
 
217
     */
 
218
    OvsInitVportWithPortParam(vport, portParam);
 
219
    /* Retore the nic and OVS states */
 
220
    vport->nicState = nicState;
 
221
    vport->ovsState = ovsState;
 
222
 
 
223
update_port_done:
 
224
    NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
 
225
    VPORT_PORT_EXIT(portParam);
 
226
 
 
227
    /* Must always return success */
 
228
    return NDIS_STATUS_SUCCESS;
 
229
}
 
230
 
 
231
VOID
 
232
HvTeardownPort(POVS_SWITCH_CONTEXT switchContext,
 
233
               PNDIS_SWITCH_PORT_PARAMETERS portParam)
 
234
{
 
235
    POVS_VPORT_ENTRY vport;
 
236
    LOCK_STATE_EX lockState;
 
237
 
 
238
    VPORT_PORT_ENTER(portParam);
 
239
 
 
240
    NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
 
241
    vport = OvsFindVportByPortIdAndNicIndex(switchContext,
 
242
                                            portParam->PortId, 0);
 
243
    if (vport) {
 
244
        /* add assertion here */
 
245
        vport->portState = NdisSwitchPortStateTeardown;
 
246
        vport->ovsState = OVS_STATE_PORT_TEAR_DOWN;
 
247
    } else {
 
248
        OVS_LOG_WARN("Vport not present.");
 
249
    }
 
250
    NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
 
251
 
 
252
    VPORT_PORT_EXIT(portParam);
 
253
}
 
254
 
 
255
 
 
256
VOID
 
257
HvDeletePort(POVS_SWITCH_CONTEXT switchContext,
 
258
             PNDIS_SWITCH_PORT_PARAMETERS portParams)
 
259
{
 
260
    POVS_VPORT_ENTRY vport;
 
261
    LOCK_STATE_EX lockState;
 
262
 
 
263
    VPORT_PORT_ENTER(portParams);
 
264
 
 
265
    NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
 
266
    vport = OvsFindVportByPortIdAndNicIndex(switchContext,
 
267
                                            portParams->PortId, 0);
 
268
 
 
269
    /*
 
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.
 
274
    */
 
275
    if (vport) {
 
276
        OvsRemoveAndDeleteVport(NULL, switchContext, vport, TRUE, FALSE);
 
277
    } else {
 
278
        OVS_LOG_WARN("Vport not present.");
 
279
    }
 
280
    NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
 
281
 
 
282
    VPORT_PORT_EXIT(portParams);
 
283
}
 
284
 
 
285
 
 
286
/*
 
287
 * Functions implemented in relaton to NDIS NIC manipulation.
 
288
 */
 
289
NDIS_STATUS
 
290
HvCreateNic(POVS_SWITCH_CONTEXT switchContext,
 
291
            PNDIS_SWITCH_NIC_PARAMETERS nicParam)
 
292
{
 
293
    POVS_VPORT_ENTRY vport;
 
294
    UINT32 portNo = 0;
 
295
    UINT32 event = 0;
 
296
    NDIS_STATUS status = NDIS_STATUS_SUCCESS;
 
297
 
 
298
    LOCK_STATE_EX lockState;
 
299
 
 
300
    VPORT_NIC_ENTER(nicParam);
 
301
 
 
302
    /* Wait for lists to be initialized. */
 
303
    OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
 
304
 
 
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;
 
309
        goto done;
 
310
    }
 
311
 
 
312
    NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
 
313
    vport = OvsFindVportByPortIdAndNicIndex(switchContext, nicParam->PortId, 0);
 
314
    if (vport == NULL) {
 
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;
 
319
        goto add_nic_done;
 
320
    }
 
321
 
 
322
    if (nicParam->NicType == NdisSwitchNicTypeExternal &&
 
323
        nicParam->NicIndex != 0) {
 
324
        POVS_VPORT_ENTRY virtExtVport =
 
325
            (POVS_VPORT_ENTRY)switchContext->virtualExternalVport;
 
326
 
 
327
        vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
 
328
        if (vport == NULL) {
 
329
            status = NDIS_STATUS_RESOURCES;
 
330
            goto add_nic_done;
 
331
        }
 
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);
 
336
            goto add_nic_done;
 
337
        }
 
338
    }
 
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;
 
345
    }
 
346
 
 
347
add_nic_done:
 
348
    NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
 
349
    if (portNo != OVS_DPPORT_NUMBER_INVALID && event) {
 
350
        OvsPostEvent(portNo, event);
 
351
    }
 
352
 
 
353
done:
 
354
    VPORT_NIC_EXIT(nicParam);
 
355
    OVS_LOG_TRACE("Exit: status %8x.\n", status);
 
356
 
 
357
    return status;
 
358
}
 
359
 
 
360
 
 
361
/* Mark already created NIC as connected. */
 
362
VOID
 
363
HvConnectNic(POVS_SWITCH_CONTEXT switchContext,
 
364
             PNDIS_SWITCH_NIC_PARAMETERS nicParam)
 
365
{
 
366
    LOCK_STATE_EX lockState;
 
367
    POVS_VPORT_ENTRY vport;
 
368
    UINT32 portNo = 0;
 
369
 
 
370
    VPORT_NIC_ENTER(nicParam);
 
371
 
 
372
    /* Wait for lists to be initialized. */
 
373
    OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
 
374
 
 
375
    if (!switchContext->isActivated) {
 
376
        OVS_LOG_WARN("Switch is not activated yet.");
 
377
        goto done;
 
378
    }
 
379
 
 
380
    NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
 
381
    vport = OvsFindVportByPortIdAndNicIndex(switchContext,
 
382
                                            nicParam->PortId,
 
383
                                            nicParam->NicIndex);
 
384
 
 
385
    if (!vport) {
 
386
        OVS_LOG_WARN("Vport not present.");
 
387
        NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
 
388
        ASSERT(0);
 
389
        goto done;
 
390
    }
 
391
 
 
392
    vport->ovsState = OVS_STATE_CONNECTED;
 
393
    vport->nicState = NdisSwitchNicStateConnected;
 
394
    portNo = vport->portNo;
 
395
 
 
396
    NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
 
397
 
 
398
    /* XXX only if portNo != INVALID or always? */
 
399
    OvsPostEvent(portNo, OVS_EVENT_LINK_UP);
 
400
 
 
401
    if (nicParam->NicType == NdisSwitchNicTypeInternal) {
 
402
        OvsInternalAdapterUp(portNo, &nicParam->NetCfgInstanceId);
 
403
    }
 
404
 
 
405
done:
 
406
    VPORT_NIC_EXIT(nicParam);
 
407
}
 
408
 
 
409
VOID
 
410
HvUpdateNic(POVS_SWITCH_CONTEXT switchContext,
 
411
            PNDIS_SWITCH_NIC_PARAMETERS nicParam)
 
412
{
 
413
    POVS_VPORT_ENTRY vport;
 
414
    LOCK_STATE_EX lockState;
 
415
 
 
416
    UINT32 status = 0, portNo = 0;
 
417
 
 
418
    VPORT_NIC_ENTER(nicParam);
 
419
 
 
420
    /* Wait for lists to be initialized. */
 
421
    OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
 
422
 
 
423
    if (!switchContext->isActivated) {
 
424
        OVS_LOG_WARN("Switch is not activated yet.");
 
425
        goto update_nic_done;
 
426
    }
 
427
 
 
428
    NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
 
429
    vport = OvsFindVportByPortIdAndNicIndex(switchContext,
 
430
                                            nicParam->PortId,
 
431
                                            nicParam->NicIndex);
 
432
    if (vport == NULL) {
 
433
        NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
 
434
        OVS_LOG_WARN("Vport search failed.");
 
435
        goto update_nic_done;
 
436
    }
 
437
    switch (nicParam->NicType) {
 
438
    case NdisSwitchNicTypeExternal:
 
439
    case NdisSwitchNicTypeInternal:
 
440
        RtlCopyMemory(&vport->netCfgInstanceId, &nicParam->NetCfgInstanceId,
 
441
                      sizeof (GUID));
 
442
        break;
 
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));
 
450
        }
 
451
        break;
 
452
    default:
 
453
        ASSERT(0);
 
454
    }
 
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;
 
460
    }
 
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;
 
466
    }
 
467
 
 
468
    if (vport->mtu != nicParam->MTU) {
 
469
        vport->mtu = nicParam->MTU;
 
470
        status |= OVS_EVENT_MTU_CHANGE;
 
471
    }
 
472
    vport->numaNodeId = nicParam->NumaNodeId;
 
473
    portNo = vport->portNo;
 
474
 
 
475
    NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
 
476
    if (status && portNo) {
 
477
        OvsPostEvent(portNo, status);
 
478
    }
 
479
update_nic_done:
 
480
    VPORT_NIC_EXIT(nicParam);
 
481
}
 
482
 
 
483
 
 
484
VOID
 
485
HvDisconnectNic(POVS_SWITCH_CONTEXT switchContext,
 
486
                PNDIS_SWITCH_NIC_PARAMETERS nicParam)
 
487
{
 
488
    POVS_VPORT_ENTRY vport;
 
489
    UINT32 portNo = 0;
 
490
    LOCK_STATE_EX lockState;
 
491
    BOOLEAN isInternalPort = FALSE;
 
492
 
 
493
    VPORT_NIC_ENTER(nicParam);
 
494
 
 
495
    /* Wait for lists to be initialized. */
 
496
    OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
 
497
 
 
498
    if (!switchContext->isActivated) {
 
499
        OVS_LOG_WARN("Switch is not activated yet.");
 
500
        goto done;
 
501
    }
 
502
 
 
503
    NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
 
504
    vport = OvsFindVportByPortIdAndNicIndex(switchContext,
 
505
                                            nicParam->PortId,
 
506
                                            nicParam->NicIndex);
 
507
 
 
508
    if (!vport) {
 
509
        OVS_LOG_WARN("Vport not present.");
 
510
        NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
 
511
        goto done;
 
512
    }
 
513
 
 
514
    vport->nicState = NdisSwitchNicStateDisconnected;
 
515
    vport->ovsState = OVS_STATE_NIC_CREATED;
 
516
    portNo = vport->portNo;
 
517
 
 
518
    if (vport->ovsType == OVS_VPORT_TYPE_INTERNAL) {
 
519
        isInternalPort = TRUE;
 
520
    }
 
521
 
 
522
    NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
 
523
 
 
524
    /* XXX if portNo != INVALID or always? */
 
525
    OvsPostEvent(portNo, OVS_EVENT_LINK_DOWN);
 
526
 
 
527
    if (isInternalPort) {
 
528
        OvsInternalAdapterDown();
 
529
    }
 
530
 
 
531
done:
 
532
    VPORT_NIC_EXIT(nicParam);
 
533
}
 
534
 
 
535
 
 
536
VOID
 
537
HvDeleteNic(POVS_SWITCH_CONTEXT switchContext,
 
538
            PNDIS_SWITCH_NIC_PARAMETERS nicParam)
 
539
{
 
540
    LOCK_STATE_EX lockState;
 
541
    POVS_VPORT_ENTRY vport;
 
542
    UINT32 portNo = 0;
 
543
 
 
544
    VPORT_NIC_ENTER(nicParam);
 
545
    /* Wait for lists to be initialized. */
 
546
    OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
 
547
 
 
548
    if (!switchContext->isActivated) {
 
549
        OVS_LOG_WARN("Switch is not activated yet.");
 
550
        goto done;
 
551
    }
 
552
 
 
553
    NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
 
554
    vport = OvsFindVportByPortIdAndNicIndex(switchContext,
 
555
                                            nicParam->PortId,
 
556
                                            nicParam->NicIndex);
 
557
 
 
558
    if (!vport) {
 
559
        OVS_LOG_WARN("Vport not present.");
 
560
        NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
 
561
        goto done;
 
562
    }
 
563
 
 
564
    vport->nicState = NdisSwitchNicStateUnknown;
 
565
    vport->ovsState = OVS_STATE_PORT_CREATED;
 
566
 
 
567
    portNo = vport->portNo;
 
568
    if (vport->portType == NdisSwitchPortTypeExternal &&
 
569
        vport->nicIndex != 0) {
 
570
        OvsRemoveAndDeleteVport(NULL, switchContext, vport, TRUE, FALSE);
 
571
    }
 
572
 
 
573
    NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
 
574
    /* XXX if portNo != INVALID or always? */
 
575
    OvsPostEvent(portNo, OVS_EVENT_DISCONNECT);
 
576
 
 
577
done:
 
578
    VPORT_NIC_EXIT(nicParam);
 
579
}
 
580
 
 
581
 
 
582
/*
 
583
 * OVS Vport related functionality.
 
584
 */
 
585
POVS_VPORT_ENTRY
 
586
OvsFindVportByPortNo(POVS_SWITCH_CONTEXT switchContext,
 
587
                     UINT32 portNo)
 
588
{
 
589
    POVS_VPORT_ENTRY vport;
 
590
    PLIST_ENTRY head, link;
 
591
    UINT32 hash = OvsJhashBytes((const VOID *)&portNo, sizeof(portNo),
 
592
                                OVS_HASH_BASIS);
 
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) {
 
597
            return vport;
 
598
        }
 
599
    }
 
600
    return NULL;
 
601
}
 
602
 
 
603
 
 
604
POVS_VPORT_ENTRY
 
605
OvsFindTunnelVportByDstPort(POVS_SWITCH_CONTEXT switchContext,
 
606
                            UINT16 dstPort,
 
607
                            OVS_VPORT_TYPE ovsPortType)
 
608
{
 
609
    POVS_VPORT_ENTRY vport;
 
610
    PLIST_ENTRY head, link;
 
611
    UINT32 hash = OvsJhashBytes((const VOID *)&dstPort, sizeof(dstPort),
 
612
                                OVS_HASH_BASIS);
 
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) {
 
618
            return vport;
 
619
        }
 
620
    }
 
621
    return NULL;
 
622
}
 
623
 
 
624
 
 
625
POVS_VPORT_ENTRY
 
626
OvsFindVportByOvsName(POVS_SWITCH_CONTEXT switchContext,
 
627
                      PSTR name)
 
628
{
 
629
    POVS_VPORT_ENTRY vport;
 
630
    PLIST_ENTRY head, link;
 
631
    UINT32 hash;
 
632
    SIZE_T length = strlen(name) + 1;
 
633
 
 
634
    hash = OvsJhashBytes((const VOID *)name, length, OVS_HASH_BASIS);
 
635
    head = &(switchContext->ovsPortNameHashArray[hash & OVS_VPORT_MASK]);
 
636
 
 
637
    LIST_FORALL(head, link) {
 
638
        vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, ovsNameLink);
 
639
        if (!strcmp(name, vport->ovsName)) {
 
640
            return vport;
 
641
        }
 
642
    }
 
643
 
 
644
    return NULL;
 
645
}
 
646
 
 
647
/* OvsFindVportByHvName: "name" is assumed to be null-terminated */
 
648
POVS_VPORT_ENTRY
 
649
OvsFindVportByHvNameW(POVS_SWITCH_CONTEXT switchContext,
 
650
                      PWSTR wsName, SIZE_T wstrSize)
 
651
{
 
652
    POVS_VPORT_ENTRY vport = NULL;
 
653
    PLIST_ENTRY head, link;
 
654
    UINT i;
 
655
 
 
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);
 
660
 
 
661
            /*
 
662
             * NOTE about portFriendlyName:
 
663
             * If the string is NULL-terminated, the Length member does not
 
664
             * include the terminating NULL character.
 
665
             */
 
666
            if (vport->portFriendlyName.Length == wstrSize &&
 
667
                RtlEqualMemory(wsName, vport->portFriendlyName.String,
 
668
                               vport->portFriendlyName.Length)) {
 
669
                goto Cleanup;
 
670
            }
 
671
 
 
672
            vport = NULL;
 
673
        }
 
674
    }
 
675
 
 
676
    /*
 
677
     * Look in the list of ports that were added from the Hyper-V switch and
 
678
     * deleted.
 
679
     */
 
680
    if (vport == NULL) {
 
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)) {
 
688
                    goto Cleanup;
 
689
                }
 
690
 
 
691
                vport = NULL;
 
692
            }
 
693
        }
 
694
    }
 
695
 
 
696
Cleanup:
 
697
    return vport;
 
698
}
 
699
 
 
700
POVS_VPORT_ENTRY
 
701
OvsFindVportByHvNameA(POVS_SWITCH_CONTEXT switchContext,
 
702
                      PSTR name)
 
703
{
 
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);
 
708
    UINT i;
 
709
 
 
710
    PWSTR wsName = OvsAllocateMemoryWithTag(wstrSize, OVS_VPORT_POOL_TAG);
 
711
    if (!wsName) {
 
712
        return NULL;
 
713
    }
 
714
    for (i = 0; i < length; i++) {
 
715
        wsName[i] = name[i];
 
716
    }
 
717
    vport = OvsFindVportByHvNameW(switchContext, wsName, wstrSize);
 
718
    OvsFreeMemoryWithTag(wsName, OVS_VPORT_POOL_TAG);
 
719
    return vport;
 
720
}
 
721
 
 
722
POVS_VPORT_ENTRY
 
723
OvsFindVportByPortIdAndNicIndex(POVS_SWITCH_CONTEXT switchContext,
 
724
                                NDIS_SWITCH_PORT_ID portId,
 
725
                                NDIS_SWITCH_NIC_INDEX index)
 
726
{
 
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;
 
735
    } else {
 
736
        PLIST_ENTRY head, link;
 
737
        POVS_VPORT_ENTRY vport;
 
738
        UINT32 hash;
 
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) {
 
744
                return vport;
 
745
            }
 
746
        }
 
747
        return NULL;
 
748
    }
 
749
}
 
750
 
 
751
POVS_VPORT_ENTRY
 
752
OvsAllocateVport(VOID)
 
753
{
 
754
    POVS_VPORT_ENTRY vport;
 
755
    vport = (POVS_VPORT_ENTRY)OvsAllocateMemoryWithTag(
 
756
        sizeof(OVS_VPORT_ENTRY), OVS_VPORT_POOL_TAG);
 
757
    if (vport == NULL) {
 
758
        return NULL;
 
759
    }
 
760
    RtlZeroMemory(vport, sizeof (OVS_VPORT_ENTRY));
 
761
    vport->ovsState = OVS_STATE_UNKNOWN;
 
762
    vport->isAbsentOnHv = FALSE;
 
763
    vport->portNo = OVS_DPPORT_NUMBER_INVALID;
 
764
 
 
765
    InitializeListHead(&vport->ovsNameLink);
 
766
    InitializeListHead(&vport->portIdLink);
 
767
    InitializeListHead(&vport->portNoLink);
 
768
 
 
769
    return vport;
 
770
}
 
771
 
 
772
static VOID
 
773
OvsInitVportWithPortParam(POVS_VPORT_ENTRY vport,
 
774
                          PNDIS_SWITCH_PORT_PARAMETERS portParam)
 
775
{
 
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;
 
782
 
 
783
    switch (vport->portType) {
 
784
    case NdisSwitchPortTypeExternal:
 
785
        vport->isExternal = TRUE;
 
786
        vport->ovsType = OVS_VPORT_TYPE_NETDEV;
 
787
        break;
 
788
    case NdisSwitchPortTypeInternal:
 
789
        vport->ovsType = OVS_VPORT_TYPE_INTERNAL;
 
790
        break;
 
791
    case NdisSwitchPortTypeSynthetic:
 
792
    case NdisSwitchPortTypeEmulated:
 
793
        vport->ovsType = OVS_VPORT_TYPE_NETDEV;
 
794
        break;
 
795
    }
 
796
    RtlCopyMemory(&vport->hvPortName, &portParam->PortName,
 
797
                  sizeof (NDIS_SWITCH_PORT_NAME));
 
798
    /* For external and internal ports, 'portFriendlyName' is overwritten
 
799
     * later. */
 
800
    RtlCopyMemory(&vport->portFriendlyName, &portParam->PortFriendlyName,
 
801
                  sizeof(NDIS_SWITCH_PORT_FRIENDLYNAME));
 
802
 
 
803
    switch (vport->portState) {
 
804
    case NdisSwitchPortStateCreated:
 
805
        vport->ovsState = OVS_STATE_PORT_CREATED;
 
806
        break;
 
807
    case NdisSwitchPortStateTeardown:
 
808
        vport->ovsState = OVS_STATE_PORT_TEAR_DOWN;
 
809
        break;
 
810
    case NdisSwitchPortStateDeleted:
 
811
        vport->ovsState = OVS_STATE_PORT_DELETED;
 
812
        break;
 
813
    }
 
814
}
 
815
 
 
816
 
 
817
static VOID
 
818
OvsInitVportWithNicParam(POVS_SWITCH_CONTEXT switchContext,
 
819
                         POVS_VPORT_ENTRY vport,
 
820
                         PNDIS_SWITCH_NIC_PARAMETERS nicParam)
 
821
{
 
822
    ASSERT(vport->portId == nicParam->PortId);
 
823
    ASSERT(vport->ovsState == OVS_STATE_PORT_CREATED);
 
824
 
 
825
    UNREFERENCED_PARAMETER(switchContext);
 
826
 
 
827
    RtlCopyMemory(vport->permMacAddress, nicParam->PermanentMacAddress,
 
828
                  sizeof (nicParam->PermanentMacAddress));
 
829
    RtlCopyMemory(vport->currMacAddress, nicParam->CurrentMacAddress,
 
830
                  sizeof (nicParam->CurrentMacAddress));
 
831
 
 
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));
 
838
    } else {
 
839
        RtlCopyMemory(&vport->netCfgInstanceId, &nicParam->NetCfgInstanceId,
 
840
                      sizeof (nicParam->NetCfgInstanceId));
 
841
    }
 
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;
 
848
 
 
849
    switch (vport->nicState) {
 
850
    case NdisSwitchNicStateCreated:
 
851
        vport->ovsState = OVS_STATE_NIC_CREATED;
 
852
        break;
 
853
    case NdisSwitchNicStateConnected:
 
854
        vport->ovsState = OVS_STATE_CONNECTED;
 
855
        break;
 
856
    case NdisSwitchNicStateDisconnected:
 
857
        vport->ovsState = OVS_STATE_NIC_CREATED;
 
858
        break;
 
859
    case NdisSwitchNicStateDeleted:
 
860
        vport->ovsState = OVS_STATE_PORT_CREATED;
 
861
        break;
 
862
    }
 
863
}
 
864
 
 
865
/*
 
866
 * --------------------------------------------------------------------------
 
867
 * Copies the relevant NDIS port properties from a virtual (pseudo) external
 
868
 * NIC to a physical (real) external NIC.
 
869
 * --------------------------------------------------------------------------
 
870
 */
 
871
static VOID
 
872
OvsInitPhysNicVport(POVS_VPORT_ENTRY physExtVport,
 
873
                    POVS_VPORT_ENTRY virtExtVport,
 
874
                    UINT32 physNicIndex)
 
875
{
 
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;
 
884
 
 
885
    RtlCopyMemory(&physExtVport->hvPortName, &virtExtVport->hvPortName,
 
886
                  sizeof (NDIS_SWITCH_PORT_NAME));
 
887
 
 
888
    /* 'portFriendlyName' is overwritten later. */
 
889
    RtlCopyMemory(&physExtVport->portFriendlyName,
 
890
                  &virtExtVport->portFriendlyName,
 
891
                  sizeof(NDIS_SWITCH_PORT_FRIENDLYNAME));
 
892
 
 
893
    physExtVport->ovsState = OVS_STATE_PORT_CREATED;
 
894
}
 
895
 
 
896
/*
 
897
 * --------------------------------------------------------------------------
 
898
 * Initializes a tunnel vport.
 
899
 * --------------------------------------------------------------------------
 
900
 */
 
901
NTSTATUS
 
902
OvsInitTunnelVport(PVOID userContext,
 
903
                   POVS_VPORT_ENTRY vport,
 
904
                   OVS_VPORT_TYPE ovsType,
 
905
                   UINT16 dstPort)
 
906
{
 
907
    NTSTATUS status = STATUS_SUCCESS;
 
908
    POVS_USER_PARAMS_CONTEXT usrParamsCtx =
 
909
        (POVS_USER_PARAMS_CONTEXT)userContext;
 
910
 
 
911
    vport->isBridgeInternal = FALSE;
 
912
    vport->ovsType = ovsType;
 
913
    vport->ovsState = OVS_STATE_PORT_CREATED;
 
914
    switch (ovsType) {
 
915
    case OVS_VPORT_TYPE_GRE:
 
916
        break;
 
917
    case OVS_VPORT_TYPE_GRE64:
 
918
        break;
 
919
    case OVS_VPORT_TYPE_VXLAN:
 
920
    {
 
921
        POVS_TUNFLT_INIT_CONTEXT tunnelContext = NULL;
 
922
 
 
923
        tunnelContext = OvsAllocateMemoryWithTag(sizeof(*tunnelContext),
 
924
                                                 OVS_VPORT_POOL_TAG);
 
925
        if (tunnelContext == NULL) {
 
926
            status = STATUS_INSUFFICIENT_RESOURCES;
 
927
            break;
 
928
        }
 
929
        tunnelContext->inputBuffer = usrParamsCtx->inputBuffer;
 
930
        tunnelContext->outputBuffer = usrParamsCtx->outputBuffer;
 
931
        tunnelContext->outputLength = usrParamsCtx->outputLength;
 
932
        tunnelContext->vport = vport;
 
933
 
 
934
        status = OvsInitVxlanTunnel(usrParamsCtx->irp,
 
935
                                    vport,
 
936
                                    dstPort,
 
937
                                    OvsTunnelVportPendingInit,
 
938
                                    (PVOID)tunnelContext);
 
939
        if (status != STATUS_PENDING) {
 
940
            OvsFreeMemoryWithTag(tunnelContext, OVS_VPORT_POOL_TAG);
 
941
            tunnelContext = NULL;
 
942
        }
 
943
        break;
 
944
    }
 
945
    case OVS_VPORT_TYPE_STT:
 
946
        status = OvsInitSttTunnel(vport, dstPort);
 
947
        break;
 
948
    default:
 
949
        ASSERT(0);
 
950
    }
 
951
    return status;
 
952
}
 
953
 
 
954
/*
 
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
 * --------------------------------------------------------------------------
 
959
 */
 
960
NTSTATUS
 
961
OvsInitBridgeInternalVport(POVS_VPORT_ENTRY vport)
 
962
{
 
963
    vport->isBridgeInternal = TRUE;
 
964
    vport->ovsType = OVS_VPORT_TYPE_INTERNAL;
 
965
    /* Mark the status to be connected, since there is no other initialization
 
966
     * for this port. */
 
967
    vport->ovsState = OVS_STATE_CONNECTED;
 
968
    return STATUS_SUCCESS;
 
969
}
 
970
 
 
971
/*
 
972
 * --------------------------------------------------------------------------
 
973
 * For external vports 'portFriendlyName' provided by Hyper-V is over-written
 
974
 * by synthetic names.
 
975
 * --------------------------------------------------------------------------
 
976
 */
 
977
static VOID
 
978
AssignNicNameSpecial(POVS_VPORT_ENTRY vport)
 
979
{
 
980
    size_t len;
 
981
 
 
982
    if (vport->portType == NdisSwitchPortTypeExternal) {
 
983
        if (vport->nicIndex == 0) {
 
984
            ASSERT(vport->nicIndex == 0);
 
985
            RtlStringCbPrintfW(vport->portFriendlyName.String,
 
986
                               IF_MAX_STRING_SIZE,
 
987
                               L"%s.virtualAdapter", OVS_DPPORT_EXTERNAL_NAME_W);
 
988
        } else {
 
989
            RtlStringCbPrintfW(vport->portFriendlyName.String,
 
990
                               IF_MAX_STRING_SIZE,
 
991
                               L"%s.%lu", OVS_DPPORT_EXTERNAL_NAME_W,
 
992
                               (UINT32)vport->nicIndex);
 
993
        }
 
994
    } else {
 
995
        RtlStringCbPrintfW(vport->portFriendlyName.String,
 
996
                           IF_MAX_STRING_SIZE,
 
997
                           L"%s", OVS_DPPORT_INTERNAL_NAME_W);
 
998
    }
 
999
 
 
1000
    RtlStringCbLengthW(vport->portFriendlyName.String, IF_MAX_STRING_SIZE,
 
1001
                       &len);
 
1002
    vport->portFriendlyName.Length = (USHORT)len;
 
1003
}
 
1004
 
 
1005
 
 
1006
/*
 
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.
 
1010
 *
 
1011
 * Inserts the port into 'portIdHashArray' and caches the pointer in the
 
1012
 * 'switchContext' if needed.
 
1013
 *
 
1014
 * For external NIC, assigns the name for the NIC.
 
1015
 * --------------------------------------------------------------------------
 
1016
 */
 
1017
static NDIS_STATUS
 
1018
InitHvVportCommon(POVS_SWITCH_CONTEXT switchContext,
 
1019
                  POVS_VPORT_ENTRY vport,
 
1020
                  BOOLEAN newPort)
 
1021
{
 
1022
    UINT32 hash;
 
1023
 
 
1024
    switch (vport->portType) {
 
1025
    case NdisSwitchPortTypeExternal:
 
1026
        /*
 
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.
 
1030
         */
 
1031
        AssignNicNameSpecial(vport);
 
1032
 
 
1033
        if (vport->nicIndex == 0) {
 
1034
            switchContext->virtualExternalPortId = vport->portId;
 
1035
            switchContext->virtualExternalVport = vport;
 
1036
        } else {
 
1037
            switchContext->numPhysicalNics++;
 
1038
        }
 
1039
        break;
 
1040
    case NdisSwitchPortTypeInternal:
 
1041
        ASSERT(vport->isBridgeInternal == FALSE);
 
1042
 
 
1043
        /* Overwrite the 'portFriendlyName' of the internal vport. */
 
1044
        AssignNicNameSpecial(vport);
 
1045
        switchContext->internalPortId = vport->portId;
 
1046
        switchContext->internalVport = vport;
 
1047
        break;
 
1048
    case NdisSwitchPortTypeSynthetic:
 
1049
    case NdisSwitchPortTypeEmulated:
 
1050
        break;
 
1051
    }
 
1052
 
 
1053
    /*
 
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
 
1056
     * OVS userspace.
 
1057
     */
 
1058
    if (vport->portType == NdisSwitchPortTypeExternal &&
 
1059
        vport->nicIndex == 0) {
 
1060
        return NDIS_STATUS_SUCCESS;
 
1061
    }
 
1062
 
 
1063
    /*
 
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.
 
1067
     */
 
1068
    hash = OvsJhashWords(&vport->portId, 1, OVS_HASH_BASIS);
 
1069
    InsertHeadList(&switchContext->portIdHashArray[hash & OVS_VPORT_MASK],
 
1070
                   &vport->portIdLink);
 
1071
    if (newPort) {
 
1072
        switchContext->numHvVports++;
 
1073
    }
 
1074
    return NDIS_STATUS_SUCCESS;
 
1075
}
 
1076
 
 
1077
/*
 
1078
 * --------------------------------------------------------------------------
 
1079
 * Functionality common to any port added from OVS userspace.
 
1080
 *
 
1081
 * Inserts the port into 'portNoHashArray', 'ovsPortNameHashArray' and in
 
1082
 * 'tunnelVportsArray' if appropriate.
 
1083
 * --------------------------------------------------------------------------
 
1084
 */
 
1085
NDIS_STATUS
 
1086
InitOvsVportCommon(POVS_SWITCH_CONTEXT switchContext,
 
1087
                   POVS_VPORT_ENTRY vport)
 
1088
{
 
1089
    UINT32 hash;
 
1090
 
 
1091
    switch(vport->ovsType) {
 
1092
    case OVS_VPORT_TYPE_VXLAN:
 
1093
    case OVS_VPORT_TYPE_STT:
 
1094
    {
 
1095
        UINT16 dstPort = GetPortFromPriv(vport);
 
1096
        hash = OvsJhashBytes(&dstPort,
 
1097
                             sizeof(dstPort),
 
1098
                             OVS_HASH_BASIS);
 
1099
        InsertHeadList(
 
1100
            &gOvsSwitchContext->tunnelVportsArray[hash & OVS_VPORT_MASK],
 
1101
            &vport->tunnelVportLink);
 
1102
        switchContext->numNonHvVports++;
 
1103
        break;
 
1104
    }
 
1105
    case OVS_VPORT_TYPE_INTERNAL:
 
1106
        if (vport->isBridgeInternal) {
 
1107
            switchContext->numNonHvVports++;
 
1108
        }
 
1109
    default:
 
1110
        break;
 
1111
    }
 
1112
 
 
1113
    /*
 
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).
 
1118
     */
 
1119
    hash = OvsJhashWords(&vport->portNo, 1, OVS_HASH_BASIS);
 
1120
    InsertHeadList(&gOvsSwitchContext->portNoHashArray[hash & OVS_VPORT_MASK],
 
1121
                   &vport->portNoLink);
 
1122
 
 
1123
    hash = OvsJhashBytes(vport->ovsName, strlen(vport->ovsName) + 1,
 
1124
                         OVS_HASH_BASIS);
 
1125
    InsertHeadList(
 
1126
        &gOvsSwitchContext->ovsPortNameHashArray[hash & OVS_VPORT_MASK],
 
1127
        &vport->ovsNameLink);
 
1128
 
 
1129
    return STATUS_SUCCESS;
 
1130
}
 
1131
 
 
1132
 
 
1133
/*
 
1134
 * --------------------------------------------------------------------------
 
1135
 * Provides functionality that is partly complementatry to
 
1136
 * InitOvsVportCommon()/InitHvVportCommon().
 
1137
 *
 
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
 * --------------------------------------------------------------------------
 
1143
 */
 
1144
NTSTATUS
 
1145
OvsRemoveAndDeleteVport(PVOID usrParamsContext,
 
1146
                        POVS_SWITCH_CONTEXT switchContext,
 
1147
                        POVS_VPORT_ENTRY vport,
 
1148
                        BOOLEAN hvDelete,
 
1149
                        BOOLEAN ovsDelete)
 
1150
{
 
1151
    POVS_USER_PARAMS_CONTEXT usrParamsCtx =
 
1152
        (POVS_USER_PARAMS_CONTEXT)usrParamsContext;
 
1153
    BOOLEAN hvSwitchPort = FALSE;
 
1154
    BOOLEAN deletedOnOvs = FALSE;
 
1155
    BOOLEAN deletedOnHv = FALSE;
 
1156
 
 
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();
 
1164
            }
 
1165
            hvSwitchPort = TRUE;
 
1166
        }
 
1167
        break;
 
1168
    case OVS_VPORT_TYPE_VXLAN:
 
1169
    {
 
1170
        NTSTATUS status;
 
1171
        status = OvsRemoveTunnelVport(usrParamsCtx, switchContext, vport,
 
1172
                                      hvDelete, ovsDelete);
 
1173
        if (status != STATUS_SUCCESS) {
 
1174
            return status;
 
1175
        }
 
1176
    }
 
1177
    case OVS_VPORT_TYPE_STT:
 
1178
        OvsCleanupSttTunnel(vport);
 
1179
        break;
 
1180
    case OVS_VPORT_TYPE_GRE:
 
1181
    case OVS_VPORT_TYPE_GRE64:
 
1182
        break;
 
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;
 
1194
            }
 
1195
        }
 
1196
        hvSwitchPort = TRUE;
 
1197
    default:
 
1198
        break;
 
1199
    }
 
1200
 
 
1201
    /*
 
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'.
 
1205
     *
 
1206
     * Both 'hvDelete' and 'ovsDelete' can be set to TRUE by the caller.
 
1207
     */
 
1208
    if (vport->isAbsentOnHv == TRUE) {
 
1209
        deletedOnHv = TRUE;
 
1210
    }
 
1211
    if (vport->portNo == OVS_DPPORT_NUMBER_INVALID) {
 
1212
        deletedOnOvs = TRUE;
 
1213
    }
 
1214
 
 
1215
    if (hvDelete && !deletedOnHv) {
 
1216
        vport->isAbsentOnHv = TRUE;
 
1217
 
 
1218
        if (vport->isExternal) {
 
1219
            ASSERT(vport->nicIndex != 0);
 
1220
            ASSERT(switchContext->numPhysicalNics);
 
1221
            switchContext->numPhysicalNics--;
 
1222
        }
 
1223
 
 
1224
        /* Remove the port from the relevant lists. */
 
1225
        RemoveEntryList(&vport->portIdLink);
 
1226
        InitializeListHead(&vport->portIdLink);
 
1227
        deletedOnHv = TRUE;
 
1228
    }
 
1229
    if (ovsDelete && !deletedOnOvs) {
 
1230
        vport->portNo = OVS_DPPORT_NUMBER_INVALID;
 
1231
        vport->ovsName[0] = '\0';
 
1232
 
 
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);
 
1242
        }
 
1243
 
 
1244
        deletedOnOvs = TRUE;
 
1245
    }
 
1246
 
 
1247
    /*
 
1248
     * Deallocate the port if it has been deleted on the Hyper-V switch as well
 
1249
     * as OVS userspace.
 
1250
     */
 
1251
    if (deletedOnHv && deletedOnOvs) {
 
1252
        if (hvSwitchPort) {
 
1253
            switchContext->numHvVports--;
 
1254
        } else {
 
1255
            switchContext->numNonHvVports--;
 
1256
        }
 
1257
        OvsFreeMemoryWithTag(vport, OVS_VPORT_POOL_TAG);
 
1258
    }
 
1259
 
 
1260
    return STATUS_SUCCESS;
 
1261
}
 
1262
 
 
1263
static NTSTATUS
 
1264
OvsRemoveTunnelVport(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
 
1265
                     POVS_SWITCH_CONTEXT switchContext,
 
1266
                     POVS_VPORT_ENTRY vport,
 
1267
                     BOOLEAN hvDelete,
 
1268
                     BOOLEAN ovsDelete)
 
1269
{
 
1270
    POVS_TUNFLT_INIT_CONTEXT tunnelContext = NULL;
 
1271
    PIRP irp = NULL;
 
1272
 
 
1273
    tunnelContext = OvsAllocateMemory(sizeof(*tunnelContext));
 
1274
    if (tunnelContext == NULL) {
 
1275
        return STATUS_INSUFFICIENT_RESOURCES;
 
1276
    }
 
1277
    RtlZeroMemory(tunnelContext, sizeof(*tunnelContext));
 
1278
 
 
1279
    tunnelContext->switchContext = switchContext;
 
1280
    tunnelContext->hvSwitchPort = FALSE;
 
1281
    tunnelContext->hvDelete = hvDelete;
 
1282
    tunnelContext->ovsDelete = ovsDelete;
 
1283
    tunnelContext->vport = vport;
 
1284
 
 
1285
    if (usrParamsCtx) {
 
1286
        tunnelContext->inputBuffer = usrParamsCtx->inputBuffer;
 
1287
        tunnelContext->outputBuffer = usrParamsCtx->outputBuffer;
 
1288
        tunnelContext->outputLength = usrParamsCtx->outputLength;
 
1289
        irp = usrParamsCtx->irp;
 
1290
    }
 
1291
 
 
1292
    return OvsCleanupVxlanTunnel(irp, vport, OvsTunnelVportPendingRemove,
 
1293
                                 tunnelContext);
 
1294
}
 
1295
 
 
1296
 
 
1297
 
 
1298
NDIS_STATUS
 
1299
OvsAddConfiguredSwitchPorts(POVS_SWITCH_CONTEXT switchContext)
 
1300
{
 
1301
    NDIS_STATUS status = NDIS_STATUS_SUCCESS;
 
1302
    ULONG arrIndex;
 
1303
    PNDIS_SWITCH_PORT_PARAMETERS portParam;
 
1304
    PNDIS_SWITCH_PORT_ARRAY portArray = NULL;
 
1305
    POVS_VPORT_ENTRY vport;
 
1306
 
 
1307
    OVS_LOG_TRACE("Enter: switchContext:%p", switchContext);
 
1308
 
 
1309
    status = OvsGetPortsOnSwitch(switchContext, &portArray);
 
1310
    if (status != NDIS_STATUS_SUCCESS) {
 
1311
        goto cleanup;
 
1312
    }
 
1313
 
 
1314
    for (arrIndex = 0; arrIndex < portArray->NumElements; arrIndex++) {
 
1315
         portParam = NDIS_SWITCH_PORT_AT_ARRAY_INDEX(portArray, arrIndex);
 
1316
 
 
1317
         if (portParam->IsValidationPort) {
 
1318
             continue;
 
1319
         }
 
1320
 
 
1321
         vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
 
1322
         if (vport == NULL) {
 
1323
             status = NDIS_STATUS_RESOURCES;
 
1324
             goto cleanup;
 
1325
         }
 
1326
         OvsInitVportWithPortParam(vport, portParam);
 
1327
         status = InitHvVportCommon(switchContext, vport, TRUE);
 
1328
         if (status != NDIS_STATUS_SUCCESS) {
 
1329
             OvsFreeMemoryWithTag(vport, OVS_VPORT_POOL_TAG);
 
1330
             goto cleanup;
 
1331
         }
 
1332
    }
 
1333
 
 
1334
cleanup:
 
1335
    if (status != NDIS_STATUS_SUCCESS) {
 
1336
        OvsClearAllSwitchVports(switchContext);
 
1337
    }
 
1338
 
 
1339
    OvsFreeSwitchPortsArray(portArray);
 
1340
 
 
1341
    OVS_LOG_TRACE("Exit: status: %x", status);
 
1342
 
 
1343
    return status;
 
1344
}
 
1345
 
 
1346
 
 
1347
NDIS_STATUS
 
1348
OvsInitConfiguredSwitchNics(POVS_SWITCH_CONTEXT switchContext)
 
1349
{
 
1350
    NDIS_STATUS status = NDIS_STATUS_SUCCESS;
 
1351
    PNDIS_SWITCH_NIC_ARRAY nicArray = NULL;
 
1352
    ULONG arrIndex;
 
1353
    PNDIS_SWITCH_NIC_PARAMETERS nicParam;
 
1354
    POVS_VPORT_ENTRY vport;
 
1355
 
 
1356
    OVS_LOG_TRACE("Enter: switchContext: %p", switchContext);
 
1357
    /*
 
1358
     * Now, get NIC list.
 
1359
     */
 
1360
    status = OvsGetNicsOnSwitch(switchContext, &nicArray);
 
1361
    if (status != NDIS_STATUS_SUCCESS) {
 
1362
        goto cleanup;
 
1363
    }
 
1364
    for (arrIndex = 0; arrIndex < nicArray->NumElements; ++arrIndex) {
 
1365
 
 
1366
        nicParam = NDIS_SWITCH_NIC_AT_ARRAY_INDEX(nicArray, arrIndex);
 
1367
 
 
1368
        /*
 
1369
         * XXX: Check if the port is configured with a VLAN. Disallow such a
 
1370
         * configuration, since we don't support tag-in-tag.
 
1371
         */
 
1372
 
 
1373
        /*
 
1374
         * XXX: Check if the port is connected to a VF. Disconnect the VF in
 
1375
         * such a case.
 
1376
         */
 
1377
 
 
1378
        if (nicParam->NicType == NdisSwitchNicTypeExternal &&
 
1379
            nicParam->NicIndex != 0) {
 
1380
            POVS_VPORT_ENTRY virtExtVport =
 
1381
                   (POVS_VPORT_ENTRY)switchContext->virtualExternalVport;
 
1382
 
 
1383
            vport = OvsAllocateVport();
 
1384
            if (vport) {
 
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);
 
1390
                    vport = NULL;
 
1391
                }
 
1392
            }
 
1393
        } else {
 
1394
            vport = OvsFindVportByPortIdAndNicIndex(switchContext,
 
1395
                                                    nicParam->PortId,
 
1396
                                                    nicParam->NicIndex);
 
1397
        }
 
1398
        if (vport == NULL) {
 
1399
            OVS_LOG_ERROR("Fail to allocate vport");
 
1400
            continue;
 
1401
        }
 
1402
        OvsInitVportWithNicParam(switchContext, vport, nicParam);
 
1403
        if (nicParam->NicType == NdisSwitchNicTypeInternal) {
 
1404
            OvsInternalAdapterUp(vport->portNo, &nicParam->NetCfgInstanceId);
 
1405
        }
 
1406
    }
 
1407
cleanup:
 
1408
 
 
1409
    OvsFreeSwitchNicsArray(nicArray);
 
1410
 
 
1411
    OVS_LOG_TRACE("Exit: status: %x", status);
 
1412
    return status;
 
1413
}
 
1414
 
 
1415
/*
 
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
 * --------------------------------------------------------------------------
 
1422
 */
 
1423
VOID
 
1424
OvsClearAllSwitchVports(POVS_SWITCH_CONTEXT switchContext)
 
1425
{
 
1426
    for (UINT hash = 0; hash < OVS_MAX_VPORT_ARRAY_SIZE; hash++) {
 
1427
        PLIST_ENTRY head, link, next;
 
1428
 
 
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);
 
1434
        }
 
1435
    }
 
1436
 
 
1437
    /*
 
1438
     * Remove 'virtualExternalVport' as well. This port is not part of the
 
1439
     * 'portIdHashArray'.
 
1440
     */
 
1441
    if (switchContext->virtualExternalVport) {
 
1442
        OvsRemoveAndDeleteVport(NULL, switchContext,
 
1443
            (POVS_VPORT_ENTRY)switchContext->virtualExternalVport, TRUE, TRUE);
 
1444
    }
 
1445
 
 
1446
 
 
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);
 
1457
        }
 
1458
    }
 
1459
 
 
1460
    ASSERT(switchContext->virtualExternalVport == NULL);
 
1461
    ASSERT(switchContext->internalVport == NULL);
 
1462
}
 
1463
 
 
1464
 
 
1465
NTSTATUS
 
1466
OvsConvertIfCountedStrToAnsiStr(PIF_COUNTED_STRING wStr,
 
1467
                                CHAR *str,
 
1468
                                UINT16 maxStrLen)
 
1469
{
 
1470
    ANSI_STRING astr;
 
1471
    UNICODE_STRING ustr;
 
1472
    NTSTATUS status;
 
1473
    UINT32 size;
 
1474
 
 
1475
    ustr.Buffer = wStr->String;
 
1476
    ustr.Length = wStr->Length;
 
1477
    ustr.MaximumLength = IF_MAX_STRING_SIZE;
 
1478
 
 
1479
    astr.Buffer = str;
 
1480
    astr.MaximumLength = maxStrLen;
 
1481
    astr.Length = 0;
 
1482
 
 
1483
    size = RtlUnicodeStringToAnsiSize(&ustr);
 
1484
    if (size > maxStrLen) {
 
1485
        return STATUS_BUFFER_OVERFLOW;
 
1486
    }
 
1487
 
 
1488
    status = RtlUnicodeStringToAnsiString(&astr, &ustr, FALSE);
 
1489
 
 
1490
    ASSERT(status == STATUS_SUCCESS);
 
1491
    if (status != STATUS_SUCCESS) {
 
1492
        return status;
 
1493
    }
 
1494
    ASSERT(astr.Length <= maxStrLen);
 
1495
    str[astr.Length] = 0;
 
1496
    return STATUS_SUCCESS;
 
1497
}
 
1498
 
 
1499
/*
 
1500
 * --------------------------------------------------------------------------
 
1501
 * Utility function that populates a 'OVS_VPORT_EXT_INFO' structure for the
 
1502
 * specified vport.
 
1503
 * --------------------------------------------------------------------------
 
1504
 */
 
1505
NTSTATUS
 
1506
OvsGetExtInfoIoctl(POVS_VPORT_GET vportGet,
 
1507
                   POVS_VPORT_EXT_INFO extInfo)
 
1508
{
 
1509
    POVS_VPORT_ENTRY vport;
 
1510
    size_t len;
 
1511
    LOCK_STATE_EX lockState;
 
1512
    NTSTATUS status = STATUS_SUCCESS;
 
1513
    BOOLEAN doConvert = FALSE;
 
1514
 
 
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);
 
1524
        }
 
1525
    } else {
 
1526
        vport = OvsFindVportByPortNo(gOvsSwitchContext, vportGet->portNo);
 
1527
    }
 
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);
 
1533
        } else {
 
1534
            OVS_LOG_WARN("vport %s does not exist any more", vportGet->name);
 
1535
        }
 
1536
        status = STATUS_DEVICE_DOES_NOT_EXIST;
 
1537
        goto ext_info_done;
 
1538
    }
 
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));
 
1548
    }
 
1549
    extInfo->nicIndex = vport->nicIndex;
 
1550
    extInfo->portId = vport->portId;
 
1551
    extInfo->type = vport->ovsType;
 
1552
    extInfo->mtu = vport->mtu;
 
1553
    /*
 
1554
     * TO be revisit XXX
 
1555
     */
 
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;
 
1560
    } else {
 
1561
       extInfo->status = OVS_EVENT_DISCONNECT;
 
1562
    }
 
1563
    if (extInfo->type == OVS_VPORT_TYPE_NETDEV &&
 
1564
        (vport->ovsState == OVS_STATE_NIC_CREATED  ||
 
1565
         vport->ovsState == OVS_STATE_CONNECTED)) {
 
1566
        doConvert = TRUE;
 
1567
    } else {
 
1568
        extInfo->vmUUID[0] = 0;
 
1569
        extInfo->vifUUID[0] = 0;
 
1570
    }
 
1571
    NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
 
1572
    if (doConvert) {
 
1573
        status = OvsConvertIfCountedStrToAnsiStr(&vport->portFriendlyName,
 
1574
                                                 extInfo->name,
 
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;
 
1579
        }
 
1580
 
 
1581
        status = OvsConvertIfCountedStrToAnsiStr(&vport->vmName,
 
1582
                                                 extInfo->vmUUID,
 
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;
 
1587
        }
 
1588
 
 
1589
        status = OvsConvertIfCountedStrToAnsiStr(&vport->nicName,
 
1590
                                                 extInfo->vifUUID,
 
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;
 
1595
        }
 
1596
        /*
 
1597
         * for now ignore status
 
1598
         */
 
1599
        status = STATUS_SUCCESS;
 
1600
    }
 
1601
 
 
1602
ext_info_done:
 
1603
    return status;
 
1604
}
 
1605
 
 
1606
/*
 
1607
 * --------------------------------------------------------------------------
 
1608
 *  Command Handler for 'OVS_WIN_NETDEV_CMD_GET'.
 
1609
 * --------------------------------------------------------------------------
 
1610
 */
 
1611
NTSTATUS
 
1612
OvsGetNetdevCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
 
1613
                       UINT32 *replyLen)
 
1614
{
 
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;
 
1621
 
 
1622
    static const NL_POLICY ovsNetdevPolicy[] = {
 
1623
        [OVS_WIN_NETDEV_ATTR_NAME] = { .type = NL_A_STRING,
 
1624
                                       .minLen = 2,
 
1625
                                       .maxLen = IFNAMSIZ },
 
1626
    };
 
1627
    PNL_ATTR netdevAttrs[ARRAY_SIZE(ovsNetdevPolicy)];
 
1628
 
 
1629
    /* input buffer has been validated while validating transaction dev op. */
 
1630
    ASSERT(usrParamsCtx->inputBuffer != NULL &&
 
1631
           usrParamsCtx->inputLength > sizeof *msgIn);
 
1632
 
 
1633
    if (msgOut == NULL || usrParamsCtx->outputLength < sizeof *msgOut) {
 
1634
        return STATUS_INVALID_BUFFER_SIZE;
 
1635
    }
 
1636
 
 
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;
 
1642
    }
 
1643
 
 
1644
    vportGet.portNo = 0;
 
1645
    RtlCopyMemory(&vportGet.name, NlAttrGet(netdevAttrs[OVS_VPORT_ATTR_NAME]),
 
1646
                  NlAttrGetSize(netdevAttrs[OVS_VPORT_ATTR_NAME]));
 
1647
 
 
1648
    status = OvsGetExtInfoIoctl(&vportGet, &info);
 
1649
    if (status == STATUS_DEVICE_DOES_NOT_EXIST) {
 
1650
        nlError = NL_ERROR_NODEV;
 
1651
        goto cleanup;
 
1652
    }
 
1653
 
 
1654
    status = CreateNetlinkMesgForNetdev(&info, msgIn,
 
1655
                 usrParamsCtx->outputBuffer, usrParamsCtx->outputLength,
 
1656
                 gOvsSwitchContext->dpNo);
 
1657
    if (status == STATUS_SUCCESS) {
 
1658
        *replyLen = msgOut->nlMsg.nlmsgLen;
 
1659
    }
 
1660
 
 
1661
cleanup:
 
1662
    if (nlError != NL_ERROR_SUCCESS) {
 
1663
        POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
 
1664
            usrParamsCtx->outputBuffer;
 
1665
 
 
1666
        NlBuildErrorMsg(msgIn, msgError, nlError);
 
1667
        *replyLen = msgError->nlMsg.nlmsgLen;
 
1668
    }
 
1669
 
 
1670
    return STATUS_SUCCESS;
 
1671
}
 
1672
 
 
1673
 
 
1674
/*
 
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
 * --------------------------------------------------------------------------
 
1679
 */
 
1680
static NTSTATUS
 
1681
CreateNetlinkMesgForNetdev(POVS_VPORT_EXT_INFO info,
 
1682
                           POVS_MESSAGE msgIn,
 
1683
                           PVOID outBuffer,
 
1684
                           UINT32 outBufLen,
 
1685
                           int dpIfIndex)
 
1686
{
 
1687
    NL_BUFFER nlBuffer;
 
1688
    BOOLEAN ok;
 
1689
    PNL_MSG_HDR nlMsg;
 
1690
    UINT32 netdevFlags = 0;
 
1691
 
 
1692
    NlBufInit(&nlBuffer, outBuffer, outBufLen);
 
1693
 
 
1694
    ok = NlFillOvsMsg(&nlBuffer, msgIn->nlMsg.nlmsgType, NLM_F_MULTI,
 
1695
                      msgIn->nlMsg.nlmsgSeq, msgIn->nlMsg.nlmsgPid,
 
1696
                      msgIn->genlMsg.cmd, msgIn->genlMsg.version,
 
1697
                      dpIfIndex);
 
1698
    if (!ok) {
 
1699
        return STATUS_INVALID_BUFFER_SIZE;
 
1700
    }
 
1701
 
 
1702
    ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_PORT_NO,
 
1703
                         info->portNo);
 
1704
    if (!ok) {
 
1705
        return STATUS_INVALID_BUFFER_SIZE;
 
1706
    }
 
1707
 
 
1708
    ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_TYPE, info->type);
 
1709
    if (!ok) {
 
1710
        return STATUS_INVALID_BUFFER_SIZE;
 
1711
    }
 
1712
 
 
1713
    ok = NlMsgPutTailString(&nlBuffer, OVS_WIN_NETDEV_ATTR_NAME,
 
1714
                            info->name);
 
1715
    if (!ok) {
 
1716
        return STATUS_INVALID_BUFFER_SIZE;
 
1717
    }
 
1718
 
 
1719
    ok = NlMsgPutTailUnspec(&nlBuffer, OVS_WIN_NETDEV_ATTR_MAC_ADDR,
 
1720
             (PCHAR)info->macAddress, sizeof (info->macAddress));
 
1721
    if (!ok) {
 
1722
        return STATUS_INVALID_BUFFER_SIZE;
 
1723
    }
 
1724
 
 
1725
    ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_MTU, info->mtu);
 
1726
    if (!ok) {
 
1727
        return STATUS_INVALID_BUFFER_SIZE;
 
1728
    }
 
1729
 
 
1730
    if (info->status != OVS_EVENT_CONNECT) {
 
1731
        netdevFlags = OVS_WIN_NETDEV_IFF_UP;
 
1732
    }
 
1733
    ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_IF_FLAGS,
 
1734
                         netdevFlags);
 
1735
    if (!ok) {
 
1736
        return STATUS_INVALID_BUFFER_SIZE;
 
1737
    }
 
1738
 
 
1739
    /*
 
1740
     * XXX: add netdev_stats when we have the definition available in the
 
1741
     * kernel.
 
1742
     */
 
1743
 
 
1744
    nlMsg = (PNL_MSG_HDR)NlBufAt(&nlBuffer, 0, 0);
 
1745
    nlMsg->nlmsgLen = NlBufSize(&nlBuffer);
 
1746
 
 
1747
    return STATUS_SUCCESS;
 
1748
}
 
1749
 
 
1750
static __inline VOID
 
1751
OvsWaitActivate(POVS_SWITCH_CONTEXT switchContext, ULONG sleepMicroSec)
 
1752
{
 
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);
 
1758
    }
 
1759
}
 
1760
 
 
1761
static NTSTATUS
 
1762
OvsCreateMsgFromVport(POVS_VPORT_ENTRY vport,
 
1763
                      POVS_MESSAGE msgIn,
 
1764
                      PVOID outBuffer,
 
1765
                      UINT32 outBufLen,
 
1766
                      int dpIfIndex)
 
1767
{
 
1768
    NL_BUFFER nlBuffer;
 
1769
    OVS_VPORT_FULL_STATS vportStats;
 
1770
    BOOLEAN ok;
 
1771
    PNL_MSG_HDR nlMsg;
 
1772
 
 
1773
    NlBufInit(&nlBuffer, outBuffer, outBufLen);
 
1774
 
 
1775
    ok = NlFillOvsMsg(&nlBuffer, msgIn->nlMsg.nlmsgType, NLM_F_MULTI,
 
1776
                      msgIn->nlMsg.nlmsgSeq, msgIn->nlMsg.nlmsgPid,
 
1777
                      msgIn->genlMsg.cmd, msgIn->genlMsg.version,
 
1778
                      dpIfIndex);
 
1779
    if (!ok) {
 
1780
        return STATUS_INVALID_BUFFER_SIZE;
 
1781
    }
 
1782
 
 
1783
    ok = NlMsgPutTailU32(&nlBuffer, OVS_VPORT_ATTR_PORT_NO, vport->portNo);
 
1784
    if (!ok) {
 
1785
        return STATUS_INVALID_BUFFER_SIZE;
 
1786
    }
 
1787
 
 
1788
    ok = NlMsgPutTailU32(&nlBuffer, OVS_VPORT_ATTR_TYPE, vport->ovsType);
 
1789
    if (!ok) {
 
1790
        return STATUS_INVALID_BUFFER_SIZE;
 
1791
    }
 
1792
 
 
1793
    ok = NlMsgPutTailString(&nlBuffer, OVS_VPORT_ATTR_NAME, vport->ovsName);
 
1794
    if (!ok) {
 
1795
        return STATUS_INVALID_BUFFER_SIZE;
 
1796
    }
 
1797
 
 
1798
    /*
 
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.
 
1803
    */
 
1804
 
 
1805
    ok = NlMsgPutTailU32(&nlBuffer, OVS_VPORT_ATTR_UPCALL_PID,
 
1806
                         vport->upcallPid);
 
1807
    if (!ok) {
 
1808
        return STATUS_INVALID_BUFFER_SIZE;
 
1809
    }
 
1810
 
 
1811
    /*stats*/
 
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;
 
1820
 
 
1821
    ok = NlMsgPutTailUnspec(&nlBuffer, OVS_VPORT_ATTR_STATS,
 
1822
                            (PCHAR)&vportStats,
 
1823
                            sizeof(OVS_VPORT_FULL_STATS));
 
1824
    if (!ok) {
 
1825
        return STATUS_INVALID_BUFFER_SIZE;
 
1826
    }
 
1827
 
 
1828
    /*
 
1829
     * XXX: when vxlan udp dest port becomes configurable, we will also need
 
1830
     * to add vport options
 
1831
    */
 
1832
 
 
1833
    nlMsg = (PNL_MSG_HDR)NlBufAt(&nlBuffer, 0, 0);
 
1834
    nlMsg->nlmsgLen = NlBufSize(&nlBuffer);
 
1835
 
 
1836
    return STATUS_SUCCESS;
 
1837
}
 
1838
 
 
1839
static NTSTATUS
 
1840
OvsGetVportDumpNext(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
 
1841
                    UINT32 *replyLen)
 
1842
{
 
1843
    POVS_MESSAGE msgIn;
 
1844
    POVS_OPEN_INSTANCE instance =
 
1845
        (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
 
1846
    LOCK_STATE_EX lockState;
 
1847
    UINT32 i = OVS_MAX_VPORT_ARRAY_SIZE;
 
1848
 
 
1849
    /*
 
1850
     * XXX: this function shares some code with other dump command(s).
 
1851
     * In the future, we will need to refactor the dump functions
 
1852
    */
 
1853
 
 
1854
    ASSERT(usrParamsCtx->devOp == OVS_READ_DEV_OP);
 
1855
 
 
1856
    if (instance->dumpState.ovsMsg == NULL) {
 
1857
        ASSERT(FALSE);
 
1858
        return STATUS_INVALID_DEVICE_STATE;
 
1859
    }
 
1860
 
 
1861
    /* Output buffer has been validated while validating read dev op. */
 
1862
    ASSERT(usrParamsCtx->outputBuffer != NULL);
 
1863
 
 
1864
    msgIn = instance->dumpState.ovsMsg;
 
1865
 
 
1866
    /*
 
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.
 
1871
    */
 
1872
    NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState, 0);
 
1873
 
 
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;
 
1884
 
 
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;
 
1889
 
 
1890
            outIndex = 0;
 
1891
            LIST_FORALL(head, link) {
 
1892
 
 
1893
                /*
 
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.
 
1897
                */
 
1898
                if (outIndex >= inIndex) {
 
1899
                    vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portNoLink);
 
1900
 
 
1901
                    ASSERT(vport->portNo != OVS_DPPORT_NUMBER_INVALID);
 
1902
                    OvsCreateMsgFromVport(vport, msgIn,
 
1903
                                          usrParamsCtx->outputBuffer,
 
1904
                                          usrParamsCtx->outputLength,
 
1905
                                          gOvsSwitchContext->dpNo);
 
1906
                    ++outIndex;
 
1907
                    break;
 
1908
                }
 
1909
 
 
1910
                ++outIndex;
 
1911
            }
 
1912
 
 
1913
            if (vport) {
 
1914
                break;
 
1915
            }
 
1916
 
 
1917
            /*
 
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
 
1920
            */
 
1921
            inIndex = 0;
 
1922
        }
 
1923
 
 
1924
        outBucket = i;
 
1925
 
 
1926
        /* XXX: what about NLMSG_DONE (as msg type)? */
 
1927
        instance->dumpState.index[0] = outBucket;
 
1928
        instance->dumpState.index[1] = outIndex;
 
1929
    }
 
1930
 
 
1931
    NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
 
1932
 
 
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;
 
1937
    } else {
 
1938
        /*
 
1939
         * if i >= OVS_MAX_VPORT_ARRAY_SIZE => vport was not found =>
 
1940
         * it's dump done
 
1941
         */
 
1942
        *replyLen = 0;
 
1943
        /* Free up the dump state, since there's no more data to continue. */
 
1944
        FreeUserDumpState(instance);
 
1945
    }
 
1946
 
 
1947
    return STATUS_SUCCESS;
 
1948
}
 
1949
 
 
1950
static NTSTATUS
 
1951
OvsGetVport(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
 
1952
            UINT32 *replyLen)
 
1953
{
 
1954
    NTSTATUS status = STATUS_SUCCESS;
 
1955
    LOCK_STATE_EX lockState;
 
1956
 
 
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;
 
1964
 
 
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,
 
1968
                                  .minLen = 2,
 
1969
                                  .maxLen = IFNAMSIZ,
 
1970
                                  .optional = TRUE},
 
1971
    };
 
1972
    PNL_ATTR vportAttrs[ARRAY_SIZE(ovsVportPolicy)];
 
1973
 
 
1974
    /* input buffer has been validated while validating write dev op. */
 
1975
    ASSERT(usrParamsCtx->inputBuffer != NULL);
 
1976
 
 
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;
 
1982
    }
 
1983
 
 
1984
    /* Output buffer has been validated while validating transact dev op. */
 
1985
    ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
 
1986
 
 
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]);
 
1991
 
 
1992
        /* the port name is expected to be null-terminated */
 
1993
        ASSERT(portName[portNameLen - 1] == '\0');
 
1994
 
 
1995
        vport = OvsFindVportByOvsName(gOvsSwitchContext, portName);
 
1996
    } else if (vportAttrs[OVS_VPORT_ATTR_PORT_NO] != NULL) {
 
1997
        portNumber = NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_PORT_NO]);
 
1998
 
 
1999
        vport = OvsFindVportByPortNo(gOvsSwitchContext, portNumber);
 
2000
    } else {
 
2001
        nlError = NL_ERROR_INVAL;
 
2002
        NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
 
2003
        goto Cleanup;
 
2004
    }
 
2005
 
 
2006
    if (!vport) {
 
2007
        nlError = NL_ERROR_NODEV;
 
2008
        NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
 
2009
        goto Cleanup;
 
2010
    }
 
2011
 
 
2012
    status = OvsCreateMsgFromVport(vport, msgIn, usrParamsCtx->outputBuffer,
 
2013
                                   usrParamsCtx->outputLength,
 
2014
                                   gOvsSwitchContext->dpNo);
 
2015
    NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
 
2016
 
 
2017
    *replyLen = msgOut->nlMsg.nlmsgLen;
 
2018
 
 
2019
Cleanup:
 
2020
    if (nlError != NL_ERROR_SUCCESS) {
 
2021
        POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
 
2022
            usrParamsCtx->outputBuffer;
 
2023
 
 
2024
        NlBuildErrorMsg(msgIn, msgError, nlError);
 
2025
        *replyLen = msgError->nlMsg.nlmsgLen;
 
2026
    }
 
2027
 
 
2028
    return STATUS_SUCCESS;
 
2029
}
 
2030
 
 
2031
/*
 
2032
 * --------------------------------------------------------------------------
 
2033
 *  Command Handler for 'OVS_VPORT_CMD_GET'.
 
2034
 *
 
2035
 *  The function handles the initial call to setup the dump state, as well as
 
2036
 *  subsequent calls to continue dumping data.
 
2037
 * --------------------------------------------------------------------------
 
2038
*/
 
2039
NTSTATUS
 
2040
OvsGetVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
 
2041
                      UINT32 *replyLen)
 
2042
{
 
2043
    *replyLen = 0;
 
2044
 
 
2045
    switch (usrParamsCtx->devOp) {
 
2046
    case OVS_WRITE_DEV_OP:
 
2047
        return OvsSetupDumpStart(usrParamsCtx);
 
2048
 
 
2049
    case OVS_READ_DEV_OP:
 
2050
        return OvsGetVportDumpNext(usrParamsCtx, replyLen);
 
2051
 
 
2052
    case OVS_TRANSACTION_DEV_OP:
 
2053
        return OvsGetVport(usrParamsCtx, replyLen);
 
2054
 
 
2055
    default:
 
2056
        return STATUS_INVALID_DEVICE_REQUEST;
 
2057
    }
 
2058
 
 
2059
}
 
2060
 
 
2061
static UINT32
 
2062
OvsComputeVportNo(POVS_SWITCH_CONTEXT switchContext)
 
2063
{
 
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;
 
2067
 
 
2068
        vport = OvsFindVportByPortNo(switchContext, i);
 
2069
        if (!vport) {
 
2070
            return i;
 
2071
        }
 
2072
    }
 
2073
 
 
2074
    return OVS_DPPORT_NUMBER_INVALID;
 
2075
}
 
2076
 
 
2077
/*
 
2078
 * --------------------------------------------------------------------------
 
2079
 *  Command Handler for 'OVS_VPORT_CMD_NEW'.
 
2080
 * --------------------------------------------------------------------------
 
2081
 */
 
2082
NTSTATUS
 
2083
OvsNewVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
 
2084
                      UINT32 *replyLen)
 
2085
{
 
2086
    NDIS_STATUS status = STATUS_SUCCESS;
 
2087
    LOCK_STATE_EX lockState;
 
2088
 
 
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;
 
2093
    PCHAR portName;
 
2094
    ULONG portNameLen;
 
2095
    UINT32 portType;
 
2096
    BOOLEAN isBridgeInternal = FALSE;
 
2097
    BOOLEAN vportAllocated = FALSE, vportInitialized = FALSE;
 
2098
    BOOLEAN addInternalPortAsNetdev = FALSE;
 
2099
 
 
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,
 
2104
                                  .optional = FALSE},
 
2105
        [OVS_VPORT_ATTR_UPCALL_PID] = { .type = NL_A_UNSPEC,
 
2106
                                        .optional = FALSE },
 
2107
        [OVS_VPORT_ATTR_OPTIONS] = { .type = NL_A_NESTED, .optional = TRUE },
 
2108
    };
 
2109
 
 
2110
    PNL_ATTR vportAttrs[ARRAY_SIZE(ovsVportPolicy)];
 
2111
 
 
2112
    /* input buffer has been validated while validating write dev op. */
 
2113
    ASSERT(usrParamsCtx->inputBuffer != NULL);
 
2114
 
 
2115
    /* Output buffer has been validated while validating transact dev op. */
 
2116
    ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
 
2117
 
 
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;
 
2123
    }
 
2124
 
 
2125
    portName = NlAttrGet(vportAttrs[OVS_VPORT_ATTR_NAME]);
 
2126
    portNameLen = NlAttrGetSize(vportAttrs[OVS_VPORT_ATTR_NAME]);
 
2127
    portType = NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_TYPE]);
 
2128
 
 
2129
    /* we are expecting null terminated strings to be passed */
 
2130
    ASSERT(portName[portNameLen - 1] == '\0');
 
2131
 
 
2132
    NdisAcquireRWLockWrite(gOvsSwitchContext->dispatchLock, &lockState, 0);
 
2133
 
 
2134
    vport = OvsFindVportByOvsName(gOvsSwitchContext, portName);
 
2135
    if (vport) {
 
2136
        nlError = NL_ERROR_EXIST;
 
2137
        goto Cleanup;
 
2138
    }
 
2139
 
 
2140
    if (portName && portType == OVS_VPORT_TYPE_NETDEV &&
 
2141
        !strcmp(OVS_DPPORT_INTERNAL_NAME_A, portName)) {
 
2142
        addInternalPortAsNetdev = TRUE;
 
2143
    }
 
2144
 
 
2145
    if (portName && portType == OVS_VPORT_TYPE_INTERNAL &&
 
2146
        strcmp(OVS_DPPORT_INTERNAL_NAME_A, portName)) {
 
2147
        isBridgeInternal = TRUE;
 
2148
    }
 
2149
 
 
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);
 
2155
    } else {
 
2156
        ASSERT(OvsIsTunnelVportType(portType) ||
 
2157
               (portType == OVS_VPORT_TYPE_INTERNAL && isBridgeInternal));
 
2158
 
 
2159
        vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
 
2160
        if (vport == NULL) {
 
2161
            nlError = NL_ERROR_NOMEM;
 
2162
            goto Cleanup;
 
2163
        }
 
2164
        vportAllocated = TRUE;
 
2165
 
 
2166
        if (OvsIsTunnelVportType(portType)) {
 
2167
            UINT16 transportPortDest = 0;
 
2168
 
 
2169
            switch (portType) {
 
2170
            case OVS_VPORT_TYPE_VXLAN:
 
2171
                transportPortDest = VXLAN_UDP_PORT;
 
2172
                break;
 
2173
            case OVS_VPORT_TYPE_STT:
 
2174
                transportPortDest = STT_TCP_PORT;
 
2175
                break;
 
2176
            default:
 
2177
                break;
 
2178
            }
 
2179
 
 
2180
            PNL_ATTR attr = NlAttrFindNested(vportAttrs[OVS_VPORT_ATTR_OPTIONS],
 
2181
                                             OVS_TUNNEL_ATTR_DST_PORT);
 
2182
            if (attr) {
 
2183
                transportPortDest = NlAttrGetU16(attr);
 
2184
            }
 
2185
 
 
2186
            status = OvsInitTunnelVport(usrParamsCtx,
 
2187
                                        vport,
 
2188
                                        portType,
 
2189
                                        transportPortDest);
 
2190
 
 
2191
            nlError = NlMapStatusToNlErr(status);
 
2192
        } else {
 
2193
            OvsInitBridgeInternalVport(vport);
 
2194
        }
 
2195
 
 
2196
        vportInitialized = TRUE;
 
2197
 
 
2198
        if (nlError == NL_ERROR_SUCCESS) {
 
2199
            vport->ovsState = OVS_STATE_CONNECTED;
 
2200
            vport->nicState = NdisSwitchNicStateConnected;
 
2201
 
 
2202
            /*
 
2203
             * Allow the vport to be deleted, because there is no
 
2204
             * corresponding hyper-v switch part.
 
2205
             */
 
2206
            vport->isAbsentOnHv = TRUE;
 
2207
        } else {
 
2208
            goto Cleanup;
 
2209
        }
 
2210
    }
 
2211
 
 
2212
    if (!vport) {
 
2213
        nlError = NL_ERROR_INVAL;
 
2214
        goto Cleanup;
 
2215
    }
 
2216
    if (vport->portNo != OVS_DPPORT_NUMBER_INVALID) {
 
2217
        nlError = NL_ERROR_EXIST;
 
2218
        goto Cleanup;
 
2219
    }
 
2220
 
 
2221
    /* Initialize the vport with OVS specific properties. */
 
2222
    if (addInternalPortAsNetdev != TRUE) {
 
2223
        vport->ovsType = portType;
 
2224
    }
 
2225
    if (vportAttrs[OVS_VPORT_ATTR_PORT_NO] != NULL) {
 
2226
        /*
 
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
 
2229
         * userspace.
 
2230
         */
 
2231
        vport->portNo = NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_PORT_NO]);
 
2232
    } else {
 
2233
        vport->portNo = OvsComputeVportNo(gOvsSwitchContext);
 
2234
        if (vport->portNo == OVS_DPPORT_NUMBER_INVALID) {
 
2235
            nlError = NL_ERROR_NOMEM;
 
2236
            goto Cleanup;
 
2237
        }
 
2238
    }
 
2239
 
 
2240
    /* The ovs port name must be uninitialized. */
 
2241
    ASSERT(vport->ovsName[0] == '\0');
 
2242
    ASSERT(portNameLen <= OVS_MAX_PORT_NAME_LENGTH);
 
2243
 
 
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];
 
2247
 
 
2248
    /*
 
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.
 
2253
     */
 
2254
    vport->upcallPid = NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_UPCALL_PID]);
 
2255
 
 
2256
    status = InitOvsVportCommon(gOvsSwitchContext, vport);
 
2257
    ASSERT(status == STATUS_SUCCESS);
 
2258
 
 
2259
    status = OvsCreateMsgFromVport(vport, msgIn, usrParamsCtx->outputBuffer,
 
2260
                                   usrParamsCtx->outputLength,
 
2261
                                   gOvsSwitchContext->dpNo);
 
2262
 
 
2263
    *replyLen = msgOut->nlMsg.nlmsgLen;
 
2264
 
 
2265
Cleanup:
 
2266
    NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
 
2267
 
 
2268
    if ((nlError != NL_ERROR_SUCCESS) && (nlError != NL_ERROR_PENDING)) {
 
2269
        POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
 
2270
            usrParamsCtx->outputBuffer;
 
2271
 
 
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);
 
2278
                        break;
 
2279
                    case OVS_VPORT_TYPE_STT:
 
2280
                        OvsCleanupSttTunnel(vport);
 
2281
                        break;
 
2282
                    default:
 
2283
                        ASSERT(!"Invalid tunnel port type");
 
2284
                    }
 
2285
                }
 
2286
            }
 
2287
            OvsFreeMemoryWithTag(vport, OVS_VPORT_POOL_TAG);
 
2288
        }
 
2289
 
 
2290
        NlBuildErrorMsg(msgIn, msgError, nlError);
 
2291
        *replyLen = msgError->nlMsg.nlmsgLen;
 
2292
    }
 
2293
 
 
2294
    return (status == STATUS_PENDING) ? STATUS_PENDING : STATUS_SUCCESS;
 
2295
}
 
2296
 
 
2297
 
 
2298
/*
 
2299
 * --------------------------------------------------------------------------
 
2300
 *  Command Handler for 'OVS_VPORT_CMD_SET'.
 
2301
 * --------------------------------------------------------------------------
 
2302
 */
 
2303
NTSTATUS
 
2304
OvsSetVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
 
2305
                      UINT32 *replyLen)
 
2306
{
 
2307
    NDIS_STATUS status = STATUS_SUCCESS;
 
2308
    LOCK_STATE_EX lockState;
 
2309
 
 
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;
 
2314
 
 
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,
 
2319
                                  .optional = TRUE },
 
2320
        [OVS_VPORT_ATTR_UPCALL_PID] = { .type = NL_A_UNSPEC,
 
2321
                                        .optional = TRUE },
 
2322
        [OVS_VPORT_ATTR_STATS] = { .type = NL_A_UNSPEC,
 
2323
                                   .minLen = sizeof(OVS_VPORT_FULL_STATS),
 
2324
                                   .maxLen = sizeof(OVS_VPORT_FULL_STATS),
 
2325
                                   .optional = TRUE },
 
2326
        [OVS_VPORT_ATTR_OPTIONS] = { .type = NL_A_NESTED, .optional = TRUE },
 
2327
    };
 
2328
    PNL_ATTR vportAttrs[ARRAY_SIZE(ovsVportPolicy)];
 
2329
 
 
2330
    ASSERT(usrParamsCtx->inputBuffer != NULL);
 
2331
 
 
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;
 
2337
    }
 
2338
 
 
2339
    /* Output buffer has been validated while validating transact dev op. */
 
2340
    ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
 
2341
 
 
2342
    NdisAcquireRWLockWrite(gOvsSwitchContext->dispatchLock, &lockState, 0);
 
2343
    if (vportAttrs[OVS_VPORT_ATTR_NAME] != NULL) {
 
2344
        PSTR portName = NlAttrGet(vportAttrs[OVS_VPORT_ATTR_NAME]);
 
2345
#ifdef DBG
 
2346
        UINT32 portNameLen = NlAttrGetSize(vportAttrs[OVS_VPORT_ATTR_NAME]);
 
2347
#endif
 
2348
        /* the port name is expected to be null-terminated */
 
2349
        ASSERT(portName[portNameLen - 1] == '\0');
 
2350
 
 
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]));
 
2355
    }
 
2356
 
 
2357
    if (!vport) {
 
2358
        nlError = NL_ERROR_NODEV;
 
2359
        goto Cleanup;
 
2360
    }
 
2361
 
 
2362
    /*
 
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.
 
2367
     */
 
2368
    if (vportAttrs[OVS_VPORT_ATTR_UPCALL_PID]) {
 
2369
        vport->upcallPid = NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_UPCALL_PID]);
 
2370
    }
 
2371
 
 
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;
 
2376
            goto Cleanup;
 
2377
        }
 
2378
    }
 
2379
 
 
2380
    if (vportAttrs[OVS_VPORT_ATTR_OPTIONS]) {
 
2381
        OVS_LOG_ERROR("Vport options not supported");
 
2382
        nlError = NL_ERROR_NOTSUPP;
 
2383
        goto Cleanup;
 
2384
    }
 
2385
 
 
2386
    status = OvsCreateMsgFromVport(vport, msgIn, usrParamsCtx->outputBuffer,
 
2387
                                   usrParamsCtx->outputLength,
 
2388
                                   gOvsSwitchContext->dpNo);
 
2389
 
 
2390
    *replyLen = msgOut->nlMsg.nlmsgLen;
 
2391
 
 
2392
Cleanup:
 
2393
    NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
 
2394
 
 
2395
    if (nlError != NL_ERROR_SUCCESS) {
 
2396
        POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
 
2397
            usrParamsCtx->outputBuffer;
 
2398
 
 
2399
        NlBuildErrorMsg(msgIn, msgError, nlError);
 
2400
        *replyLen = msgError->nlMsg.nlmsgLen;
 
2401
    }
 
2402
 
 
2403
    return STATUS_SUCCESS;
 
2404
}
 
2405
 
 
2406
/*
 
2407
 * --------------------------------------------------------------------------
 
2408
 *  Command Handler for 'OVS_VPORT_CMD_DEL'.
 
2409
 * --------------------------------------------------------------------------
 
2410
 */
 
2411
NTSTATUS
 
2412
OvsDeleteVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
 
2413
                         UINT32 *replyLen)
 
2414
{
 
2415
    NDIS_STATUS status = STATUS_SUCCESS;
 
2416
    LOCK_STATE_EX lockState;
 
2417
 
 
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;
 
2424
 
 
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,
 
2428
                                  .optional = TRUE },
 
2429
    };
 
2430
    PNL_ATTR vportAttrs[ARRAY_SIZE(ovsVportPolicy)];
 
2431
 
 
2432
    ASSERT(usrParamsCtx->inputBuffer != NULL);
 
2433
 
 
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;
 
2439
    }
 
2440
 
 
2441
    /* Output buffer has been validated while validating transact dev op. */
 
2442
    ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
 
2443
 
 
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]);
 
2448
 
 
2449
        /* the port name is expected to be null-terminated */
 
2450
        ASSERT(portName[portNameLen - 1] == '\0');
 
2451
 
 
2452
        vport = OvsFindVportByOvsName(gOvsSwitchContext, portName);
 
2453
    }
 
2454
    else if (vportAttrs[OVS_VPORT_ATTR_PORT_NO] != NULL) {
 
2455
        vport = OvsFindVportByPortNo(gOvsSwitchContext,
 
2456
            NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_PORT_NO]));
 
2457
    }
 
2458
 
 
2459
    if (!vport) {
 
2460
        nlError = NL_ERROR_NODEV;
 
2461
        goto Cleanup;
 
2462
    }
 
2463
 
 
2464
    status = OvsCreateMsgFromVport(vport, msgIn, usrParamsCtx->outputBuffer,
 
2465
                                   usrParamsCtx->outputLength,
 
2466
                                   gOvsSwitchContext->dpNo);
 
2467
 
 
2468
    *replyLen = msgOut->nlMsg.nlmsgLen;
 
2469
 
 
2470
    /*
 
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.
 
2473
     */
 
2474
    status = OvsRemoveAndDeleteVport(usrParamsCtx,
 
2475
                                     gOvsSwitchContext,
 
2476
                                     vport,
 
2477
                                     FALSE,
 
2478
                                     TRUE);
 
2479
    if (status) {
 
2480
        nlError = NlMapStatusToNlErr(status);
 
2481
    }
 
2482
 
 
2483
Cleanup:
 
2484
    NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
 
2485
 
 
2486
    if ((nlError != NL_ERROR_SUCCESS) && (nlError != NL_ERROR_PENDING)) {
 
2487
        POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
 
2488
            usrParamsCtx->outputBuffer;
 
2489
 
 
2490
        NlBuildErrorMsg(msgIn, msgError, nlError);
 
2491
        *replyLen = msgError->nlMsg.nlmsgLen;
 
2492
    }
 
2493
 
 
2494
    return (status == STATUS_PENDING) ? STATUS_PENDING : STATUS_SUCCESS;
 
2495
}
 
2496
 
 
2497
static VOID
 
2498
OvsTunnelVportPendingRemove(PVOID context,
 
2499
                            NTSTATUS status,
 
2500
                            UINT32 *replyLen)
 
2501
{
 
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;
 
2510
 
 
2511
    NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
 
2512
 
 
2513
    if (msgIn && msgOut) {
 
2514
        /* Check the received status to reply to the caller. */
 
2515
        if (STATUS_SUCCESS == status) {
 
2516
            OvsCreateMsgFromVport(vport,
 
2517
                                  msgIn,
 
2518
                                  msgOut,
 
2519
                                  tunnelContext->outputLength,
 
2520
                                  switchContext->dpNo);
 
2521
 
 
2522
            *replyLen = msgOut->nlMsg.nlmsgLen;
 
2523
        } else {
 
2524
            POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)msgOut;
 
2525
 
 
2526
            NlBuildErrorMsg(msgIn, msgError, nlError);
 
2527
            *replyLen = msgError->nlMsg.nlmsgLen;
 
2528
        }
 
2529
    }
 
2530
 
 
2531
    ASSERT(vport->isAbsentOnHv == TRUE);
 
2532
    ASSERT(vport->portNo != OVS_DPPORT_NUMBER_INVALID);
 
2533
 
 
2534
    /* Remove the port from the relevant lists. */
 
2535
    switchContext->numNonHvVports--;
 
2536
    RemoveEntryList(&vport->ovsNameLink);
 
2537
    RemoveEntryList(&vport->portNoLink);
 
2538
    RemoveEntryList(&vport->tunnelVportLink);
 
2539
 
 
2540
    if (vport->priv) {
 
2541
        OvsFreeMemoryWithTag(vport->priv, OVS_VXLAN_POOL_TAG);
 
2542
        vport->priv = NULL;
 
2543
    }
 
2544
 
 
2545
    OvsFreeMemoryWithTag(vport, OVS_VPORT_POOL_TAG);
 
2546
 
 
2547
    NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
 
2548
}
 
2549
 
 
2550
static VOID
 
2551
OvsTunnelVportPendingInit(PVOID context,
 
2552
                          NTSTATUS status,
 
2553
                          UINT32 *replyLen)
 
2554
{
 
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;
 
2560
    PCHAR portName;
 
2561
    ULONG portNameLen = 0;
 
2562
    UINT32 portType = 0;
 
2563
    NL_ERROR nlError = NL_ERROR_SUCCESS;
 
2564
    BOOLEAN error = TRUE;
 
2565
 
 
2566
    do {
 
2567
        if (!NT_SUCCESS(status)) {
 
2568
            nlError = NlMapStatusToNlErr(status);
 
2569
            break;
 
2570
        }
 
2571
 
 
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 },
 
2580
        };
 
2581
 
 
2582
        PNL_ATTR vportAttrs[ARRAY_SIZE(ovsVportPolicy)];
 
2583
 
 
2584
        /* input buffer has been validated while validating write dev op. */
 
2585
        ASSERT(msgIn != NULL);
 
2586
 
 
2587
        /* Output buffer has been validated while validating transact dev op. */
 
2588
        ASSERT(msgOut != NULL && tunnelContext->outputLength >= sizeof *msgOut);
 
2589
 
 
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;
 
2595
            break;
 
2596
        }
 
2597
 
 
2598
        portName = NlAttrGet(vportAttrs[OVS_VPORT_ATTR_NAME]);
 
2599
        portNameLen = NlAttrGetSize(vportAttrs[OVS_VPORT_ATTR_NAME]);
 
2600
        portType = NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_TYPE]);
 
2601
 
 
2602
        if (vport->portNo != OVS_DPPORT_NUMBER_INVALID) {
 
2603
            nlError = NL_ERROR_EXIST;
 
2604
            break;
 
2605
        }
 
2606
 
 
2607
        vport->ovsState = OVS_STATE_CONNECTED;
 
2608
        vport->nicState = NdisSwitchNicStateConnected;
 
2609
 
 
2610
        /*
 
2611
         * Allow the vport to be deleted, because there is no
 
2612
         * corresponding hyper-v switch part.
 
2613
         */
 
2614
        vport->isAbsentOnHv = TRUE;
 
2615
 
 
2616
        if (vportAttrs[OVS_VPORT_ATTR_PORT_NO] != NULL) {
 
2617
            /*
 
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
 
2620
             * userspace.
 
2621
             */
 
2622
            vport->portNo =
 
2623
                NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_PORT_NO]);
 
2624
        } else {
 
2625
            vport->portNo =
 
2626
                OvsComputeVportNo(gOvsSwitchContext);
 
2627
            if (vport->portNo == OVS_DPPORT_NUMBER_INVALID) {
 
2628
                nlError = NL_ERROR_NOMEM;
 
2629
                break;
 
2630
            }
 
2631
        }
 
2632
 
 
2633
        /* The ovs port name must be uninitialized. */
 
2634
        ASSERT(vport->ovsName[0] == '\0');
 
2635
        ASSERT(portNameLen <= OVS_MAX_PORT_NAME_LENGTH);
 
2636
 
 
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];
 
2640
 
 
2641
        /*
 
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.
 
2646
         */
 
2647
        vport->upcallPid =
 
2648
            NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_UPCALL_PID]);
 
2649
 
 
2650
        status = InitOvsVportCommon(gOvsSwitchContext, vport);
 
2651
        ASSERT(status == STATUS_SUCCESS);
 
2652
 
 
2653
        OvsCreateMsgFromVport(vport,
 
2654
                              msgIn,
 
2655
                              msgOut,
 
2656
                              tunnelContext->outputLength,
 
2657
                              gOvsSwitchContext->dpNo);
 
2658
 
 
2659
        *replyLen = msgOut->nlMsg.nlmsgLen;
 
2660
 
 
2661
        error = FALSE;
 
2662
    } while (error);
 
2663
 
 
2664
    if (error) {
 
2665
        POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR) msgOut;
 
2666
 
 
2667
        OvsCleanupVxlanTunnel(NULL, vport, NULL, NULL);
 
2668
        OvsFreeMemory(vport);
 
2669
 
 
2670
        NlBuildErrorMsg(msgIn, msgError, nlError);
 
2671
        *replyLen = msgError->nlMsg.nlmsgLen;
 
2672
    }
 
2673
}