File: wr.pyx

package info (click to toggle)
rdma-core 33.2-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 13,844 kB
  • sloc: ansic: 145,804; python: 5,688; sh: 2,761; perl: 1,465; makefile: 73
file content (337 lines) | stat: -rw-r--r-- 11,372 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
# SPDX-License-Identifier: (GPL-2.0 OR Linux-OpenIB)
# Copyright (c) 2019 Mellanox Technologies Inc. All rights reserved. See COPYING file

from pyverbs.pyverbs_error import PyverbsUserError, PyverbsError
from pyverbs.base import PyverbsRDMAErrno, inc_rkey
from pyverbs.mr cimport MW, MR, MWBindInfo
cimport pyverbs.libibverbs_enums as e
cimport pyverbs.libibverbs as v
from pyverbs.addr cimport AH
from libc.stdlib cimport free, malloc
from libc.string cimport memcpy


cdef class SGE(PyverbsCM):
    """
    Represents ibv_sge struct. It has a read function to allow users to keep
    track of data. Write function is not provided as a scatter-gather element
    can be using a MR or a DMMR. In case direct (device's) memory is used,
    write can't be done using memcpy that relies on CPU-specific optimizations.
    A SGE has no way to tell which memory it is using.
    """
    def __init__(self, addr, length, lkey):
        """
        Initializes a SGE object.
        :param addr: The address to be used for read/write
        :param length: Available buffer size
        :param lkey: Local key of the used MR/DMMR
        :return: A SGE object
        """
        super().__init__()
        self.sge = <v.ibv_sge*>malloc(sizeof(v.ibv_sge))
        if self.sge == NULL:
            raise PyverbsError('Failed to allocate an SGE')
        self.sge.addr = addr
        self.sge.length = length
        self.sge.lkey = lkey

    def __dealloc(self):
        self.close()

    cpdef close(self):
        free(self.sge)

    cpdef read(self, length, offset):
        """
        Reads <length> bytes of data starting at <offset> bytes from the
        SGE's address.
        :param length: How many bytes to read
        :param offset: Offset from the SGE's address in bytes
        :return: The data written at the SGE's address + offset
        """
        cdef char *sg_data
        cdef int off = offset
        sg_data = <char*>(self.sge.addr + off)
        return sg_data[:length]

    def __str__(self):
        print_format = '{:22}: {:<20}\n'
        return print_format.format('Address', hex(self.sge.addr)) +\
               print_format.format('Length', self.sge.length) +\
               print_format.format('Key', hex(self.sge.lkey))

    @property
    def addr(self):
        return self.sge.addr
    @addr.setter
    def addr(self, val):
        self.sge.addr = val

    @property
    def length(self):
        return self.sge.length
    @length.setter
    def length(self, val):
        self.sge.length = val

    @property
    def lkey(self):
        return self.sge.lkey
    @lkey.setter
    def lkey(self, val):
        self.sge.lkey = val


cdef class RecvWR(PyverbsCM):
    def __init__(self, wr_id=0, num_sge=0, sg=None,
                 RecvWR next_wr=None):
        """
        Initializes a RecvWR object.
        :param wr_id: A user-defined WR ID
        :param num_sge: Size of the scatter-gather array
        :param sg: A scatter-gather array
        :param: next_wr: The next WR in the list
        :return: A RecvWR object
        """
        super().__init__()
        cdef v.ibv_sge *dst
        if num_sge < 1 or sg is None:
            raise PyverbsUserError('A WR needs at least one SGE')
        self.recv_wr.sg_list = <v.ibv_sge*>malloc(num_sge * sizeof(v.ibv_sge))
        if self.recv_wr.sg_list == NULL:
            raise PyverbsRDMAErrno('Failed to malloc SG buffer')
        dst = self.recv_wr.sg_list
        copy_sg_array(dst, sg, num_sge)
        self.recv_wr.num_sge = num_sge
        self.recv_wr.wr_id = wr_id
        if next_wr is not None:
            self.recv_wr.next = &next_wr.recv_wr

    def __dealloc(self):
        self.close()

    cpdef close(self):
        free(self.recv_wr.sg_list)

    def __str__(self):
        print_format = '{:22}: {:<20}\n'
        return print_format.format('WR ID', self.recv_wr.wr_id) +\
               print_format.format('Num SGE', self.recv_wr.num_sge)

    @property
    def next_wr(self):
        if self.recv_wr.next == NULL:
            return None
        val = RecvWR()
        val.recv_wr = self.recv_wr.next[0]
        return val
    @next_wr.setter
    def next_wr(self, RecvWR val not None):
        self.recv_wr.next = &val.recv_wr

    @property
    def wr_id(self):
        return self.recv_wr.wr_id
    @wr_id.setter
    def wr_id(self, val):
        self.recv_wr.wr_id = val

    @property
    def num_sge(self):
        return self.recv_wr.num_sge
    @num_sge.setter
    def num_sge(self, val):
        self.recv_wr.num_sge = val


cdef class SendWR(PyverbsCM):
    def __init__(self, wr_id=0, opcode=e.IBV_WR_SEND, num_sge=0, imm_data=0,
                 sg = None, send_flags=e.IBV_SEND_SIGNALED,
                 SendWR next_wr = None):
        """
        Initialize a SendWR object with user-provided or default values.
        :param wr_id: A user-defined WR ID
        :param opcode: The WR's opcode
        :param num_sge: Number of scatter-gather elements in the WR
        :param imm_data: Immediate data
        :param sg: A SGE element, head of the scatter-gather list
        :param send_flags: Send flags as define in ibv_send_flags enum
        :return: An initialized SendWR object
        """
        cdef v.ibv_sge *dst

        super().__init__()
        mw_opcodes = [e.IBV_WR_LOCAL_INV, e.IBV_WR_BIND_MW,
                      e.IBV_WR_SEND_WITH_INV]
        if opcode not in mw_opcodes and (num_sge < 1 or sg is None):
            raise PyverbsUserError('A WR needs at least one SGE')
        self.send_wr.sg_list = <v.ibv_sge*>malloc(num_sge * sizeof(v.ibv_sge))
        if self.send_wr.sg_list == NULL:
            raise PyverbsRDMAErrno('Failed to malloc SG buffer')
        dst = self.send_wr.sg_list
        copy_sg_array(dst, sg, num_sge)
        self.send_wr.num_sge = num_sge
        self.send_wr.wr_id = wr_id
        if next_wr is not None:
            self.send_wr.next = &next_wr.send_wr
        self.send_wr.opcode = opcode
        self.send_wr.send_flags = send_flags
        self.send_wr.imm_data = imm_data
        self.ah = None

    def __dealloc(self):
        self.close()

    cpdef close(self):
        free(self.send_wr.sg_list)

    def __str__(self):
        print_format = '{:22}: {:<20}\n'
        return print_format.format('WR ID', self.send_wr.wr_id) +\
               print_format.format('Num SGE', self.send_wr.num_sge) +\
               print_format.format('Opcode', self.send_wr.opcode) +\
               print_format.format('Send flags',
                                   send_flags_to_str(self.send_wr.send_flags) +\
               print_format.format('Imm Data', self.send_wr.imm_data))

    @property
    def next_wr(self):
        if self.send_wr.next == NULL:
            return None
        val = SendWR()
        val.send_wr = self.send_wr.next[0]
        return val
    @next_wr.setter
    def next_wr(self, SendWR val not None):
        self.send_wr.next = &val.send_wr

    @property
    def wr_id(self):
        return self.send_wr.wr_id
    @wr_id.setter
    def wr_id(self, val):
        self.send_wr.wr_id = val

    @property
    def num_sge(self):
        return self.send_wr.num_sge
    @num_sge.setter
    def num_sge(self, val):
        self.send_wr.num_sge = val

    @property
    def imm_data(self):
        return self.send_wr.imm_data
    @imm_data.setter
    def imm_data(self, val):
        self.send_wr.imm_data = val

    @property
    def opcode(self):
        return self.send_wr.opcode
    @opcode.setter
    def opcode(self, val):
        self.send_wr.opcode = val

    @property
    def send_flags(self):
        return self.send_wr.send_flags
    @send_flags.setter
    def send_flags(self, val):
        self.send_wr.send_flags = val

    property sg_list:
        def __set__(self, SGE val not None):
            self.send_wr.sg_list = val.sge

    def set_wr_ud(self, AH ah not None, rqpn, rqkey):
        """
        Set the members of the ud struct in the send_wr's wr union.
        :param ah: An address handle object
        :param rqpn: The remote QP number
        :param rqkey: The remote QKey, authorizing access to the destination QP
        :return: None
        """
        self.ah = ah
        self.send_wr.wr.ud.ah = ah.ah
        self.send_wr.wr.ud.remote_qpn = rqpn
        self.send_wr.wr.ud.remote_qkey = rqkey

    def set_wr_rdma(self, rkey, addr):
        """
        Set the members of the rdma struct in the send_wr's wr union, used for
        RDMA extended transport header creation.
        :param rkey: Key to access the specified memory address.
        :param addr: Start address of the buffer
        :return: None
        """
        self.send_wr.wr.rdma.remote_addr = addr
        self.send_wr.wr.rdma.rkey = rkey

    def set_wr_atomic(self, rkey, addr, compare_add, swap=0):
        """
        Set the members of the atomic struct in the send_wr's wr union, used
        for the atomic extended transport header.
        :param rkey: Key to access the specified memory address.
        :param addr: Start address of the buffer
        :param compare_add: The data operand used in the compare portion of the
                            compare and swap operation
        :param swap: The data operand used in atomic operations:
                     - In compare and swap this field is swapped into the
                       addressed buffer
                     - In fetch and add this field is added to the contents of
                       the addressed buffer
        :return: None
        """
        self.send_wr.wr.atomic.remote_addr = addr
        self.send_wr.wr.atomic.rkey = rkey
        self.send_wr.wr.atomic.compare_add = compare_add
        self.send_wr.wr.atomic.swap = swap

    def set_bind_wr(self, MW mw, MWBindInfo bind_info):
        """
        Set the members of the bind_mw struct in the send_wr.
        :param mw: The MW to bind.
        :param bind_info: MWBindInfo object, includes the bind attributes.
        :return: None
        """
        self.send_wr.bind_mw.mw = mw.mw
        # Create the new key from the MW rkey.
        rkey = inc_rkey(mw.rkey)
        self.send_wr.bind_mw.rkey = rkey
        self.send_wr.bind_mw.bind_info = bind_info.info

    @property
    def rkey(self):
        return self.send_wr.bind_mw.rkey

    def set_qp_type_xrc(self, remote_srqn):
        """
        Set the members of the xrc struct in the send_wr's qp_type union, used
        for the XRC extended transport header.
        :param remote_srqn: The XRC SRQ number to be used by the responder fot
                            this packet
        :return: None
        """
        self.send_wr.qp_type.xrc.remote_srqn = remote_srqn

def send_flags_to_str(flags):
    send_flags = {e.IBV_SEND_FENCE: 'IBV_SEND_FENCE',
                  e.IBV_SEND_SIGNALED: 'IBV_SEND_SIGNALED',
                  e.IBV_SEND_SOLICITED: 'IBV_SEND_SOLICITED',
                  e.IBV_SEND_INLINE: 'IBV_SEND_INLINE',
                  e.IBV_SEND_IP_CSUM: 'IBV_SEND_IP_CSUM'}
    flags_str = ''
    for f in send_flags:
        if flags & f:
            flags_str += send_flags[f]
            flags_str += ' '
    return flags_str


cdef copy_sg_array(v.ibv_sge *dst, sg, num_sge):
    cdef v.ibv_sge *src
    for i in range(num_sge):
        src = (<SGE>sg[i]).sge
        memcpy(dst, src, sizeof(v.ibv_sge))
        dst += 1