[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