[ofw] Latest WinVerbs presentation & .h files.

Sean Hefty sean.hefty at intel.com
Thu Feb 14 12:39:01 PST 2008


Thanks for the feedback

>This is an interesting take on verbs.  Are these IB-specific as you've defined
>them, or are you designing them to also support iWARP devices?

They are not intended to be IB specific, but are intended to expose most IB
features (outside of QP 0/1).

>>typedef union _WV_GID                                   // Network byte order
>>{
>>        UINT8                   Raw[16];
>>        struct
>>        {
>>                UINT64          SubnetPrefix;
>>                UINT64          InterfaceId;
>>        }                       Global;
>>
>>}       WV_GID;
>
>What about multicast GID?

Actually I'm not sure that defining anything beyond 'Raw' is needed.  The UINT64
ends up forcing alignment constraints that can be avoided.

>>typedef enum _WV_DEVICE_CAPABILITIES
>
>While enums types in the DDK headers are generally UPPER_CASE, the enum values
>themselves are MixedCase.

Ooo... StudlyCaps, MyFavorite.  IllChangeThis.

>
>>{
>>        WV_DEVICE_RESIZE_MAX_WR         = 1,
>>        WV_DEVICE_BAD_PKEY_COUNTER      = 1 <<  1,
>>        WV_DEVICE_BAD_QKEY_COUNTER      = 1 <<  2,
>>        WV_DEVICE_RAW_MULTICAST         = 1 <<  3,
>
>Is this needed?

Probably not.

>
>>        WV_DEVICE_PATH_MIGRATION        = 1 <<  4,
>>        WV_DEVICE_CHANGE_PHYSICAL_PORT  = 1 <<  5,
>>        WV_DEVICE_AH_PORT_CHECKING      = 1 <<  6,
>>        WV_DEVICE_QP_STATE_MODIFIER     = 1 <<  7,
>>        WV_DEVICE_SHUTDOWN_PORT         = 1 <<  8,
>>        WV_DEVICE_INIT_TYPE             = 1 <<  9,
>>        WV_DEVICE_PORT_ACTIVE_EVENT     = 1 << 10,
>>        WV_DEVICE_SYSTEM_IMAGE_GUID     = 1 << 11,
>>        WV_DEVICE_RC_RNR_NAK_GENERATION = 1 << 12,
>>        WV_DEVICE_SRQ_RESIZE            = 1 << 13,
>>        WV_DEVICE_BATCH_NOTIFY_CQ       = 1 << 14
>
>What's this?

The ability of the HCA to support notifying the user of a completion only after
'X' entries have been added to the CQ.  OFED refers to it as n_notify_cq.  I
used the term 'batch_notify_cq' instead.

>
>>
>>}       WV_DEVICE_CAPABILITIES;
>>
>>typedef enum _WV_ATOMIC_CAPABILITIES
>>{
>>        WV_ATOMIC_NONE,
>>        WV_ATOMIC_HCA,
>>        WV_ATOMIC_GLOBAL
>>
>>}       WV_ATOMIC_CAPABILITIES;
>>
>>typedef struct _WV_DEVICE_ATTRIBUTES
>>{
>>        UINT8                   FwVersion[64];
>>        UINT64                  NodeGuid;
>>        UINT64                  SystemImageGuid;
>>        UINT64                  MaxMrSize;
>>        UINT64                  PageSizeCapability;
>>        UINT32                  VendorId;
>>        UINT32                  VendorPartId;
>
>Should this be DeviceId?  Should it be moved to the top of the structure?

The structure fields are aligned for better field packing/alignment.  It does
represent the IBAL dev_id, but uses the term 'part ID', to match the term in the
IB spec, which I think is a little clearer.

>>        UINT32                  HwVersion;
>>        UINT32                  MaxQp;
>>        UINT32                  MaxQpWr;
>>        UINT32                  DeviceCapabilityFlags;
>>        UINT32                  MaxSge;
>>        UINT32                  MaxCq;
>>        UINT32                  MaxCqEntries;
>>        UINT32                  MaxMr;
>>        UINT32                  MaxPd;
>>        UINT32                  MaxQpResponderResources;
>>        UINT32                  MaxResponderResources;
>>        UINT32                  MaxQpInitiatorDepth;
>>        WV_ATOMIC_CAPABILITIES  AtomicCapbilities;
>>        UINT32                  MaxMw;
>>        UINT32                  MaxMulticast;
>>        UINT32                  MaxQpAttach;
>>        UINT32                  MaxMulticastQp;
>>        UINT32                  MaxAh;
>>        UINT32                  MaxFmr;
>>        UINT32                  MaxMapPerFmr;
>>        UINT32                  MaxSrq;
>>        UINT32                  MaxSrqWr;
>>        UINT32                  MaxSrqSge;
>>        UINT16                  MaxPkeys;
>>        UINT8                   LocalAckDelay;
>>        UINT8                   PhysPortCount;
>>
>>}       WV_DEVICE_ATTRIBUTES;
>>

>>typedef struct _WV_ADDRESS
>>{
>>        SOCKET_ADDRESS          Address;
>>        UINT64                  DeviceGuid;
>>        UINT16                  PKey;
>>        UINT8                   PortNumber;
>>
>>}       WV_ADDRESS;
>>
>
>You'll want to add #pragma warning(disable:4200) here.
>
>>typedef struct _WV_ADDRESS_LIST
>>{
>>        INT                     Count;
>>        WV_ADDRESS              Address[0];
>>
>>}       WV_ADDRESS_LIST;
>
>You'll want to add #pragma warning(default:4200) here.

I changed this to Address[1] instead, which matches what eventually gets defined
for SOCKET_ADDRESS.  (Yes - I can finally build this now.  There were several
errors.)

>>
>>enum _WV_COMPLETION_FLAGS
>>{
>>        WV_WC_IMMEDIATE         = 1 << 0,
>>        // Reserved             = 1 << 1,
>>        WV_WC_GRH_VALID         = 1 << 2,
>>        WV_WC_VENDOR_MASK       = 0xFFFF0000
>
>What's VENDOR_MASK used for?  Does anyone actually use it historically in other
>stacks that have had it?

I have no idea if it's used.  I'm happy enough removing it until there's a real
need for it.

>
>>
>>}       WV_COMPLETION_FLAGS;
>>
>>typedef struct _WV_COMPLETION
>>{
>>        UINT64                  Reserved;
>
>No need for Reserved.

This was simply to align the completion structure with what IBAL already
provides, but it would be better to remove this, and move the fields around to
minimize the structure size by removing padding.

>
>>        UINT64                  WrId;
>>        WV_COMPLETION_OPCODE    Opcode;
>>        UINT32                  Length;
>>        WV_COMPLETION_STATUS    Status;
>>        UINT64                  VendorCode;
>>
>>        // Receive completion data
>>        WV_COMPLETION_FLAGS     Flags;
>>        UINT32                  ImmediateData;          // Network byte order
>>        UINT32                  SourceQp;               // Network byte order
>
>Qpn vs. Qp?

Qpn

>>        UINT16                  PkeyIndex;
>>        UINT16                  SLid;                   // Network byte order
>>        UINT8                   SL;
>>        UINT8                   DLidPathBits;
>
>What about the QP that a WR completed on?  I'm thinking of the case where an
>app is using an SRQ and wants context of what QP the operation completed on.
>This would require apps to be able to set a context value for a QP that gets
>returned in the WC, haven't gotten to the QP creation to see if you allow a
>context.

They need to get this from the WrId.  I don't want to go overboard on returning
more context than what's really needed to avoid penalizing apps that don't need
it.

>
>>}       WV_COMPLETION;
>>
>>DECLARE_HANDLE(WV_MR_HANDLE);
>>

>>typedef struct _WV_SEND_DATAGRAM
>>{
>>        UINT64                  WrId;
>>        IWVAddressHandle*       pAddressHandle;
>>        WV_SGE*                 pSgl;
>>        UINT32                  nSge;
>>        WV_SEND_FLAGS           Flags;
>>        UINT32                  ImmediateData;          // Network byte order
>>        UINT32                  DestinationQp;          // Network byte order
>
>Qpn vs. Qp?

Qpn

>
>>        UINT32                  DestinationQKey;        // Network byte order
>>        UINT16                  PKeyIndex;
>>
>>}       WV_SEND_DATAGRAM;
>>
>>typedef struct _WV_ATOMIC
>>{
>>        UINT64                  WrId;
>>        UINT64                  Address;
>
>Is this network byte order or host order?  It gets put on the wire, so I'd
>expect it to be network order.

Hmm... good point.  This should probably be network order.

>
>>        WV_SGE*                 pSgl;
>>        UINT32                  nSge;
>>        WV_SEND_FLAGS           Flags;
>>        UINT32                  RKey;
>>        WV_ATOMIC_OPERATION     Operation;
>>        UINT64                  Value1;                 // Network byte order
>>        UINT64                  Value2;                 // Network byte order
>>
>>}       WV_ATOMIC;
>>

>>typedef enum _WV_SRQ_ATTRIBUTE_MASK
>>{
>>        IB_SRQ_MAX_WR   = 1 << 0,
>>        IB_SRQ_LIMIT    = 1 << 1
>>
>>}       WV_SRQ_ATTRIBUTE_MASK;
>>
>>typedef struct _WV_SRQ_ATTRIBUTES
>>{
>>        UINT32                  MaxWr;
>
>Can this ever be zero?

No - see below

>
>>        UINT32                  MaxSge;
>
>Can this ever be zero?

No - see below

>
>>        UINT32                  SrqLimit;
>
>Can you reserve -1 to indicate no change?

Srq::Modify() uses a mask to indicate which fields are changing.

>If the first two of these can be zero and the SrqLimit can have a reserved
>value, is the structure needed or could these be function parameters?  As
>individual function parameters, the attribute mask would go away.

I'll make these parameters.

>
>>
>>}       WV_SRQ_ATTRIBUTES;
>>

>>typedef struct _WV_QP_CREATE
>>{
>>        IWVCompletionQueue*     pSendCq;
>>        IWVCompletionQueue*     pReceiveCq;
>>        IWVSharedReceiveQueue*  pSharedReceiveQueue;
>>
>>        SIZE_T                  SendDepth;
>>        SIZE_T                  SendSge;
>>        SIZE_T                  ReceiveDepth;
>>        SIZE_T                  ReceiveSge;
>>
>>        WV_QP_TYPE              QpType;
>>        BOOL                    SignalSends;
>>
>>}       WV_QP_CREATE;
>
>I have grown to dislike the send/receive terminology because there's so much
>more you can do than send on the send queue.  I prefer active/passive, since
>requests posted to the active queue result in immediate HW processing, while
>requests posted to the passive queue are only processed when a corresponding
>request comes in from a remote peer.

Send/receive is the terminology that's used throughout all specs / docs / email
messages / etc.  Learn to like it again.  :)

>>
>>typedef struct _WV_QP_ATTRIBUTES
>>{
>>        IWVProtectionDomain*    pPd;
>>        IWVCompletionQueue*     pSendCq;
>>        IWVCompletionQueue*     pReceiveCq;
>>        IWVSharedReceiveQueue*  pSharedReceiveQueue;
>
>Is this useful to return?

It's not necessary.  The app could be responsible for remembering it.

>
>>        SIZE_T                  SendDepth;
>>        SIZE_T                  SendSge;
>>        SIZE_T                  ReceiveDepth;
>>        SIZE_T                  ReceiveSge;
>>        SIZE_T                  MaxInlineSend;
>>        SIZE_T                  InitiatorDepth;
>>        SIZE_T                  ResponderResources;
>
>Is there any value in returning InitiatorDepth and ResponderResources?  What
>can a user possibly do with this information?

Does it hurt to return it?

>>
>>        WV_QP_TYPE              QpType;
>>        WV_QP_STATE             CurrentQpState;
>>        WV_QP_STATE             QpState;
>
>What's the difference between these two states?

Modify allows the user to specify the current QP state, along with the desired
QP state.

>
>>        WV_APM_STATE            ApmState;
>>        UINT32                  QpNumber;               // Network byte order
>
>Qpn vs. QpNumber?  You use SendPsn and not SendPsNumber.

I'll switch to Qpn everywhere it's called out.

>
>>        UINT32                  DestinationQpNumber;    // Network byte order
>>        UINT32                  QKey;                   // Network byte order
>>        UINT32                  SendPsn;                // Network byte order
>>        UINT32                  ReceivePsn;             // Network byte order
>>
>>        WV_ADDRESS_VECTOR       PrimaryAddressVector;
>>        WV_ADDRESS_VECTOR       AlternateAddressVector;
>>        BOOL                    SignalSends;
>
>Can this be changed once the QP is created?  If not, is there value in
>returning it?

If path migration is in use, these can change.

>
>>        DWORD                   AccessFlags;
>>        UINT16                  PkeyIndex;
>>
>>        UINT8                   PathMtu;
>>        UINT8                   LocalAckTimeout;
>>        UINT8                   SequenceErrorRetryCount;
>>        UINT8                   RnrRetryCount;
>>
>>}       WV_QP_ATTRIBUTES;
>>

>>typedef struct _WV_CONNECT_PARAM
>>{
>>        const VOID*             pPrivateData;
>>        SIZE_T                  PrivateDataLength;
>>        SIZE_T                  ResponderResources;
>>        SIZE_T                  InitiatorDepth;
>
>I find the iWARP terminology to be a bit easier to understand -
>InboundReadDepth and OutboundReadDepth.

The name needs to include atomic operations in addition to RDMA reads.  I
haven't seen a name that I like yet...

>>        UINT8                   RetryCount;             // Ignored when
>accepting
>>        UINT8                   RnrRetryCount;
>>
>>}       WV_CONNECT_PARAM;
>>

>>#undef INTERFACE
>>#define INTERFACE IWVQueuePair
>>// {a847c13c-e617-489c-b0ab-2da73eb0adfd}
>>DEFINE_GUID(IID_IWVQueuePair, 0xa847c13c, 0xe617, 0x489c,
>>            0xb0, 0xab, 0x2d, 0xa7, 0x3e, 0xb0, 0xad, 0xfd);
>>
>>DECLARE_INTERFACE_(IWVQueuePair, IWVOverlapped)
>>{
>>    // IUnknown methods
>>    __override STDMETHOD(QueryInterface)(
>>        THIS_
>>        REFIID riid,
>>        LPVOID FAR* ppvObj
>>        ) PURE;
>>
>>    __override STDMETHOD_(ULONG,AddRef)(
>>        THIS
>>        ) PURE;
>>
>>    __override STDMETHOD_(ULONG,Release)(
>>        THIS
>>        ) PURE;
>>
>>    // IWVOverlapped methods
>>    __override STDMETHOD(CancelOverlappedRequests)(
>>        THIS
>>        ) PURE;
>>
>>    __override STDMETHOD(GetOverlappedResult)(
>>        THIS_
>>        __inout_opt OVERLAPPED *pOverlapped,
>>        __out SIZE_T *pNumberOfBytesTransferred,
>>        __in BOOL bWait
>>        ) PURE;
>>
>>    // IWVQueuePair methods
>>    STDMETHOD(Query)(
>>        THIS_
>>        __out WV_QP_ATTRIBUTES* pAttributes
>>        ) PURE;
>>
>>    STDMETHOD(Modify)(
>>        THIS_
>>        __in WV_QP_ATTRIBUTES* pAttributes,
>>        __in DWORD Options,
>>        __in OVERLAPPED* pOverlapped
>>        ) PURE;
>>
>>    STDMETHOD(SendDatagram)(
>>        THIS_
>>        __in WV_SEND_DATAGRAM* pDatagram
>>        ) PURE;
>
>I think you should probably have two different QP classes, one for datagrams
>and one for connected QPs.
>SendDatagram and the multicast operations would go into the datagram class, and
>the other operations would go in the connected QP.  The endpoints would then
>have different CreateQp methods.

I should have done this when I separate the endpoints into connected versus
datagram.

>
>>    STDMETHOD(Send)(
>>        THIS_
>>        __in UINT64 WrId,
>>        __in_ecount(nSge) const WV_SGE* pSgl
>>        __in UINT32 nSge,
>>        __in WV_SEND_FLAGS Flags,
>>        __in UINT32 ImmediateData
>>        ) PURE;
>>
>>    STDMETHOD(Read)(
>>        THIS_
>>        __in UINT64 WrId,
>>        __in_ecount(nSge) const WV_SGE* pSgl
>>        __in UINT32 nSge,
>>        __in WV_SEND_FLAGS Flags,
>>        __in UINT64 Address,
>>        __in UINT32 RKey
>>        ) PURE;
>>
>>    STDMETHOD(Write)(
>>        THIS_
>>        __in UINT64 WrId,
>>        __in_ecount(nSge) const WV_SGE* pSgl
>>        __in UINT32 nSge,
>>        __in WV_SEND_FLAGS Flags,
>>        __in UINT64 Address,
>>        __in UINT32 RKey,
>>        __in UINT32 ImmediateData
>>        ) PURE;
>>
>>    STDMETHOD(Atomic)(
>>        THIS_
>>        __in WV_ATOMIC* pAtomic
>
>Why not make these individual parameters like the other functions?  If you
>split up AtomicAdd and AtomicCompareExchange, you end up with 7 and 8
>parameters, respectively.  Write has 7 and BindmemoryWindow has 8, so there's
>precedent. :)

I'll look at that.

>>        ) PURE;
>>
>>    STDMETHOD(PostReceive)(
>>        THIS_
>>        __in UINT64 WrId,
>>        __in_ecount(nSge) const WV_SGE* pSgl
>>        __in UINT32 nSge,
>>        ) PURE;
>>
>>    STDMETHOD(BindMemoryWindow)(
>>        THIS_
>>        __in IWVMemoryWindow* pMw,
>>        __in WV_MR_HANDLE hMr,
>>        __in UINT64 WrID,
>>        __in DWORD AccessFlags,
>>        __in DWORD SendFlags,
>>        __in_bcount(BufferLength) const VOID* pBuffer,
>>        __in SIZE_T BufferLength,
>>        __out UINT32 *RKey
>>        ) PURE;
>
>Where's invalidate?  Or do you just bind to zero length to invalidate?  I guess
>this brings up a broader question of whether you intend to support Type 2
>memory windows, or just Type 1, and whether you plan for this interface to
>support iWARP.  I was going to ask how you were going to support send and
>invalidate, but I guess if all you support is type 1 then it doesn't matter.

Does anything implement type 2 MWs?  The interface should support iWarp.  I can
add in type 2 MWs and FMRs (as defined by the spec) if there's a need, or just
create function stubs.

>
>>    STDMETHOD(AttachMulticast)(
>>        THIS_
>>        __in WV_GID *pGid,
>>        __in UINT16 LID
>>        ) PURE;
>>
>>    STDMETHOD(DetachMulticast)(
>>        THIS_
>>        __in WV_GID *pGid,
>>        __in UINT16 LID
>>        ) PURE;
>
>These two above functions should be part of the datagram QP interface.
>
>>    STDMETHOD(Notify)(
>>        THIS_
>>        __in OVERLAPPED* pOverlapped
>>        ) PURE;
>>
>>    STDMETHOD(GetEvent)(
>>        THIS_
>>        __out WV_QP_EVENT* pEvent
>>        ) PURE;
>>};
>>
>>
>>#undef INTERFACE
>>#define INTERFACE IWVProtectionDomain
>>// {a5633a12-dffc-4060-927d-9a600d7efb63}
>>DEFINE_GUID(IID_IWVProtectionDomain, 0xa5633a12, 0xdffc, 0x4060,
>>            0x92, 0x7d, 0x9a, 0x60, 0x0d, 0x7e, 0xfb, 0x63);
>>
>>DECLARE_INTERFACE_(IWVProtectionDomain, IUnknown)
>>{
>>    // IUnknown methods
>>    __override STDMETHOD(QueryInterface)(
>>        THIS_
>>        REFIID riid,
>>        LPVOID FAR* ppvObj
>>        ) PURE;
>>
>>    __override STDMETHOD_(ULONG,AddRef)(
>>        THIS
>>        ) PURE;
>>
>>    __override STDMETHOD_(ULONG,Release)(
>>        THIS
>>        ) PURE;
>>
>>    // IWVProtectionDomain methods
>>    STDMETHOD(CreateSharedReceiveQueue)(
>>        THIS_
>>        __in WV_SRQ_ATTRIBUTES* pAttributes,
>>        __deref_out IWVSharedReceiveQueue** ppSrq
>>        ) PURE;
>>
>>    STDMETHOD(CreateQueuePair)(
>>        THIS_
>>        __in WV_QP_CREATE* pAttributes,
>>        __deref_out IWVQueuePair** ppQp
>>        ) PURE;
>>
>>    STDMETHOD(RegisterMemory)(
>>        THIS_
>>        __in_bcount(BufferLength) const VOID* pBuffer,
>>        __in SIZE_T BufferLength
>>        __in DWORD AccessFlags,
>
>Access flags on registrations are dumb.  You're trying to protect the app from
>misusing a buffer within its own address space.

You're also protecting against the remote peer from invalid access.  Although I
don't see where I defined what values AccessFlags would have.

>
>>        __in OVERLAPPED* pOverlapped,
>>        __deref_out WV_MR_HANDLE* phMr,
>>        __out UINT32* pLKey,
>
>You don't need the lkey - the MR handle is enough.

The SGE takes the LKey, not the MR_HANDLE.

>
>>        __out UINT32* pRKey
>
>This is going to be a bit hard to handle I think as an overlapped operation if
>you have multiple output parameters.  The overlapped returns directly to the
>user, so the get multiple output buffers you need to do a bunch of extra work
>in the kernel to be able to access the buffer (like pinning it so that you can
>write to it from DISPATCH_LEVEL).  You can't rely on the I/O manager doing all
>this for you.

A memory window bind operation can return the RKey immediately before the send
is processed by the HW.  I don't see why this would be any different.  The
LKey/RKey just aren't usable until the Register operation completes.

>
>One way to work around this is to have a single output buffer that is a
>structure containing the different values you want, but that's a bit ugly.
>
>>        ) PURE;
>>
>>    STDMETHOD(DeregisterMemory)(
>>        THIS_
>>        __in WV_MR_HANDLE hMr,
>>        __in OVERLAPPED* pOverlapped
>>        ) PURE;
>>
>>    STDMETHOD(AllocateMemoryWindow)(
>>        THIS_
>>        __deref_out IWVMemoryWindow** ppMw
>>        ) PURE;
>>
>>    STDMETHOD(CreateAddressHandle)(
>>        THIS_
>>        __in WV_ADDRESS_VECTOR* pAddress,
>>        __deref_out IWVAddressHandle** ppAh
>>        ) PURE;
>>};

>>
>>
>>#undef INTERFACE
>>#define INTERFACE IWVDatagramEndpoint
>>// {1d879de6-f2af-4a8a-8893-52e0ab868130}
>>DEFINE_GUID(IID_IWVDatagramEndpoint, 0x1d879de6, 0xf2af, 0x4a8a,
>>            0x88, 0x93, 0x52, 0xe0, 0xab, 0x86, 0x81, 0x30);
>>
>>DECLARE_INTERFACE_(IWVDatagramEndpoint, IWVEndpoint)
>>{
>>    // IUnknown methods
>>    __override STDMETHOD(QueryInterface)(
>>        THIS_
>>        REFIID riid,
>>        LPVOID FAR* ppvObj
>>        ) PURE;
>>
>>    __override STDMETHOD_(ULONG,AddRef)(
>>        THIS
>>        ) PURE;
>>
>>    __override STDMETHOD_(ULONG,Release)(
>>        THIS
>>        ) PURE;
>>
>>    // IWVOverlapped methods
>>    __override STDMETHOD(CancelOverlappedRequests)(
>>        THIS
>>        ) PURE;
>>
>>    __override STDMETHOD(GetOverlappedResult)(
>>        THIS_
>>        __inout_opt OVERLAPPED *pOverlapped,
>>        __out SIZE_T *pNumberOfBytesTransferred,
>>        __in BOOL bWait
>>        ) PURE;
>>
>>    // IWVEndpoint methods
>>    __override STDMETHOD(BindAddress)(
>>        THIS_
>>        __in const struct sockaddr* pAddress
>>        ) PURE;
>>
>>    __override STDMETHOD(ResolveAddress)(
>>        THIS_
>>        __in const struct sockaddr* pDestinationAddress,
>>        __in DWORD Milliseconds,
>>        __in OVERLAPPED* pOverlapped
>>        ) PURE;
>>
>>    __override STDMETHOD(ResolveRoute)(
>>        THIS_
>>        __in DWORD Milliseconds,
>>        __in OVERLAPPED* pOverlapped
>>        ) PURE;
>>
>>    __override STDMETHOD(CreateQueuePair)(
>>        THIS_
>>        __in IWVProtectionDomain* pPd,
>>        __in WV_QP_CREATE* pAttributes,
>>        __deref_out IWVQueuePair** ppQp
>>        ) PURE;
>>
>>    __override STDMETHOD(Reject)(
>>        THIS_
>>        __in_bcount_opt(PrivateDataLength) const VOID* pPrivateData,
>>        __in SIZE_T PrivateDataLength
>>        ) PURE;
>>
>>    // IWVDatagramEndpoint methods
>>    STDMETHOD(Lookup)(
>>        THIS_
>>        __in_bcount_opt(PrivateDataLength) const VOID* pPrivateData,
>>        __in SIZE_T PrivateDataLength,
>>        __in OVERLAPPED* pOverlapped
>>        ) PURE;
>>
>>    STDMETHOD(Accept)(
>>        THIS_
>>        __in WV_DATAGRAM_PARAM* pParam,
>>        __in OVERLAPPED* pOverlapped
>>        ) PURE;
>>
>>    STDMETHOD(JoinMulticast)(
>>        THIS_
>>        __in const struct sockaddr* pAddress,
>>        __in OVERLAPPED* pOverlapped
>>        ) PURE;
>
>Is a QP required for this to work?  Will it create the QP object if it doesn't
>exist already?  Does it perform the JoinMulticast on the QP after the SA has
>approved the join?

A QP is not required for this to work, only if the user wants to send/receive
data.  :)  The implementation will attach the QP to the multicast group if one
is associated with the endpoint.

I.e. a user could issue a JoinMulticast on an endpoint, wait for it to complete,
then manually attach a bunch of separate QPs to that group.

>
>>    STDMETHOD(LeaveMulticast)(
>>        THIS_
>>        __in const struct sockaddr* pAddress,
>>        __in OVERLAPPED* pOverlapped
>>        ) PURE;
>
>Same as above.
>
>>    STDMETHOD(Query)(
>>        THIS_
>>        __out WV_DATAGRAM_ATTRIBUTES* pAttributes
>>        ) PURE;
>>};
>>
>>
>>#undef INTERFACE
>>#define INTERFACE IWVListen
>>// {5b839fd4-7410-441f-a2d9-5d75b1d8599b}
>>DEFINE_GUID(IID_IWVListen, 0x5b839fd4, 0x7410, 0x441f,
>>            0xa2, 0xd9, 0x5d, 0x75, 0xb1, 0xd8, 0x59, 0x9b);
>>
>>DECLARE_INTERFACE_(IWVListen, IWVOverlapped)
>>{
>>    // IUnknown methods
>>    __override STDMETHOD(QueryInterface)(
>>        THIS_
>>        REFIID riid,
>>        LPVOID FAR* ppvObj
>>        ) PURE;
>>
>>    __override STDMETHOD_(ULONG,AddRef)(
>>        THIS
>>        ) PURE;
>>
>>    __override STDMETHOD_(ULONG,Release)(
>>        THIS
>>        ) PURE;
>>
>>    // IWVOverlapped methods
>>    __override STDMETHOD(CancelOverlappedRequests)(
>>        THIS
>>        ) PURE;
>>
>>    __override STDMETHOD(GetOverlappedResult)(
>>        THIS_
>>        __inout_opt OVERLAPPED *pOverlapped,
>>        __out SIZE_T *pNumberOfBytesTransferred,
>>        __in BOOL bWait
>>        ) PURE;
>>
>>    // IWVListen methods
>>    STDMETHOD(Accept)(
>>        THIS_
>>        __in IWVEndpoint* pEndpoint,
>>        __in OVERLAPPED* pOverlapped
>>        ) PURE;
>
>So the connection sequence is IWVListen->Accept followed by IWVEndpoint-
>>Accept?

Yes

>
>>};
>>
>>
>>#undef INTERFACE
>>#define INTERFACE IWVDevice
>>// {244af78c-b1ac-40e4-9896-271d58d591b8}
>>DEFINE_GUID(IID_IWVDevice, 0x244af78c, 0xb1ac, 0x40e4,
>>            0x98, 0x96, 0x27, 0x1d, 0x58, 0xd5, 0x91, 0xb8);
>>
>>DECLARE_INTERFACE_(IWVDevice, IWVOverlapped)
>>{
>>    // IUnknown methods
>>    __override STDMETHOD(QueryInterface)(
>>        THIS_
>>        REFIID riid,
>>        LPVOID FAR* ppvObj
>>        ) PURE;
>>
>>    __override STDMETHOD_(ULONG,AddRef)(
>>        THIS
>>        ) PURE;
>>
>>    __override STDMETHOD_(ULONG,Release)(
>>        THIS
>>        ) PURE;
>>
>>    // IWVOverlapped methods
>>    __override STDMETHOD(CancelOverlappedRequests)(
>>        THIS
>>        ) PURE;
>>
>>    __override STDMETHOD(GetOverlappedResult)(
>>        THIS_
>>        __inout_opt OVERLAPPED *pOverlapped,
>>        __out SIZE_T *pNumberOfBytesTransferred,
>>        __in BOOL bWait
>>        ) PURE;
>>
>>    // IWVDevice methods
>>    STDMETHOD(Query)(
>>        THIS_
>>        __out_bcount_part_opt(*pBufferSize, *pBufferSize)
>WV_DEVICE_ATTRIBUTES* pAttributes,
>>        __inout SIZE_T* pBufferSize
>>        ) PURE;
>>
>>    STDMETHOD(QueryPort)(
>>        THIS_
>>        __in UINT8 PortNumber,
>>        __out_bcount_part_opt(*pBufferSize, *pBufferSize) WV_PORT_ATTRIBUTES*
>pAttributes,
>>        __inout SIZE_T* pBufferSize
>>        ) PURE;
>>
>>    STDMETHOD(QueryGid)(
>>        THIS_
>>        __in UINT8 PortNumber,
>>        __in DWORD Index,
>>        __out WV_GID* pGid
>>        ) PURE;
>
>Is there any value in being able to get the whole GID table and walking it?

Not that I can think of.

>
>>    STDMETHOD(QueryPkey)(
>>        THIS_
>>        __in UINT8 PortNumber,
>>        __in DWORD Index,
>>        __out UINT16* pPkey
>>        ) PURE;
>
>Same here - support to retrieve the whole PKey table?

Typically a user is looking for a specific PKey or a specific index.  I can add
calls:

FindGid()
FindPKey()

that return the index of a given GID/PKey.

>
>>    STDMETHOD(CreateCompletionQueue)(
>>        THIS_
>>        __inout SIZE_T *pEntries,
>>        __deref_out IWCompletionQueue** ppCq
>>        ) PURE;
>>
>>    STDMETHOD(AllocateProtectionDomain)(
>>        THIS
>>        ) PURE;
>
>Shouldn't this return a IVWProtectionDomain?

Only if the user wants to do anything useful.  :)

>
>>
>>    STDMETHOD(Notify)(
>>        THIS_
>>        __in OVERLAPPED* pOverlapped
>>        ) PURE;
>>
>>    STDMETHOD(GetEvent)(
>>        THIS_
>>        __in WV_DEVICE_EVENT* pEvent
>>        ) PURE;
>>};
>>
>>
>>#undef INTERFACE
>>#define INTERFACE IWVProvider
>>// {6901010c-17af-4894-a1dc-794d3611f262}
>>DEFINE_GUID(IID_IIWVProvider, 0x6901010c, 0x17af, 0x4894,
>>            0xa1, 0xdc, 0x79, 0x4d, 0x36, 0x11, 0xf2, 0x62);
>>
>>DECLARE_INTERFACE_(IWVProvider, IUnknown)
>>{
>>    // IUnknown methods
>>    __override STDMETHOD(QueryInterface)(
>>        THIS_
>>        REFIID riid,
>>        LPVOID FAR* ppvObj
>>        ) PURE;
>>
>>    __override STDMETHOD_(ULONG,AddRef)(
>>        THIS
>>        ) PURE;
>>
>>    __override STDMETHOD_(ULONG,Release)(
>>        THIS
>>        ) PURE;
>>
>>    // IWVProvider methods
>>    STDMETHOD(QueryDeviceList)(
>>        THIS_
>>        __inout_bcount_part_opt(*pBufferSize, *pBufferSize) UINT64* pGuidList,
>>        __inout SIZE_T* pBufferSize
>>        ) PURE;
>>
>>    STDMETHOD(QueryDevice)(
>>        THIS_
>>        __in UINT64 Guid,
>>        __in_bcount_part_opt(*pBufferSize, *pBufferSize) WV_DEVICE_ATTRIBUTES*
>pAttributes,
>>        __inout SIZE_T* pBufferSize
>>        ) PURE;
>>
>>    STDMETHOD(QueryAddressList)(
>>        THIS_
>>        __inout_bcount_part_opt(*pBufferSize, *pBufferSize) WV_ADDRESS_LIST*
>pAddressList,
>>        __inout SIZE_T* pBufferSize
>>        ) PURE;
>>
>>    STDMETHOD(OpenDevice)(
>>        THIS_
>>        __in UINT64 Guid,
>>        __deref_out IWVDevice** ppDevice
>>        ) PURE;
>>
>>    STDMETHOD(CreateConnectEndpoint)(
>>        THIS_
>>        __deref_out IWVConnectEndpoint** ppConnectEndpoint
>>        ) PURE;
>>
>>    STDMETHOD(CreateDatagramEndpoint)(
>>        THIS_
>>        __deref_out IWVDatagramEndpoint** ppDatagramEndpoint
>>        ) PURE;
>>
>>    STDMETHOD(CreateListen)(
>>        THIS
>>        __in const struct sockaddr* pAddress,
>
>What parts of the address can be wildcarded?  If you allow wildcards, do you
>also allow address sharing (i.e. a second listen for a specific address gets
>priority over a wildcard listen?)

The port and/or IP address can be wildcarded.  The sharing depends on what I
implement underneath.  :)

>
>>        __in SIZE_T backlog,
>>        __deref_out IWVListen** ppListen
>>        ) PURE;
>
>How do you distinguish between connected and datagram listens?

I think by the address family, but I need to check into that.

- Sean




More information about the ofw mailing list