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
from libc.stdint cimport uintptr_t
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*>(<uintptr_t>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
|