-
Notifications
You must be signed in to change notification settings - Fork 653
/
mlx5dv.pyx
1885 lines (1637 loc) · 69.5 KB
/
mlx5dv.pyx
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
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# SPDX-License-Identifier: (GPL-2.0 OR Linux-OpenIB)
# Copyright (c) 2019 Mellanox Technologies, Inc. All rights reserved. See COPYING file
from libc.stdint cimport uintptr_t, uint8_t, uint16_t, uint32_t
from libc.string cimport memcpy, memset
from libc.stdlib cimport calloc, free
from posix.mman cimport munmap
import logging
import weakref
from pyverbs.providers.mlx5.mlx5dv_mkey cimport Mlx5MrInterleaved, Mlx5Mkey, \
Mlx5MkeyConfAttr, Mlx5SigBlockAttr
from pyverbs.providers.mlx5.mlx5dv_crypto cimport Mlx5CryptoLoginAttr, Mlx5CryptoAttr
from pyverbs.pyverbs_error import PyverbsUserError, PyverbsRDMAError, PyverbsError
from pyverbs.providers.mlx5.dr_action cimport DrActionFlowCounter, DrActionDestTir
from pyverbs.providers.mlx5.mlx5dv_sched cimport Mlx5dvSchedLeaf
cimport pyverbs.providers.mlx5.mlx5_enums as dve
cimport pyverbs.providers.mlx5.libmlx5 as dv
from pyverbs.mem_alloc import posix_memalign
from pyverbs.qp cimport QPInitAttrEx, QPEx
from pyverbs.base import PyverbsRDMAErrno
from pyverbs.base cimport close_weakrefs
from pyverbs.wr cimport copy_sg_array
cimport pyverbs.libibverbs_enums as e
from pyverbs.cq cimport CqInitAttrEx
cimport pyverbs.libibverbs as v
from pyverbs.device cimport DM
from pyverbs.addr cimport AH
from pyverbs.pd cimport PD
cdef extern from 'endian.h':
unsigned long htobe16(unsigned long host_16bits)
unsigned long be16toh(unsigned long network_16bits)
unsigned long htobe32(unsigned long host_32bits)
unsigned long be32toh(unsigned long network_32bits)
unsigned long htobe64(unsigned long host_64bits)
unsigned long be64toh(unsigned long network_64bits)
cdef char* _prepare_devx_inbox(in_bytes):
"""
Auxiliary function that allocates inboxes for DevX commands, and fills them
the bytes input.
The allocated box must be freed when it's no longer needed.
:param in_bytes: Stream of bytes of the command's input
:return: The C allocated inbox
"""
cdef char *in_bytes_c = in_bytes
cdef char* in_mailbox = <char*>calloc(1, len(in_bytes))
if in_mailbox == NULL:
raise MemoryError('Failed to allocate memory')
memcpy(in_mailbox, in_bytes_c, len(in_bytes))
return in_mailbox
cdef char* _prepare_devx_outbox(outlen):
"""
Auxiliary function that allocates the outboxes for DevX commands.
The allocated box must be freed when it's no longer needed.
:param outlen: Output command's length in bytes
:return: The C allocated outbox
"""
cdef char* out_mailbox = <char*>calloc(1, outlen)
if out_mailbox == NULL:
raise MemoryError('Failed to allocate memory')
return out_mailbox
cdef uintptr_t copy_data_to_addr(uintptr_t addr, data):
"""
Auxiliary function that copies data to memory at provided address.
:param addr: Address to copy the data to
:param data: Data to copy
:return: The incremented address to the end of the written data
"""
cdef bytes py_bytes = bytes(data)
cdef char *tmp = py_bytes
memcpy(<void *>addr, tmp, len(data))
return addr + len(data)
cdef class Mlx5DVPortAttr(PyverbsObject):
"""
Represents mlx5dv_port struct, which exposes mlx5-specific capabilities,
reported by mlx5dv_query_port()
"""
def __init__(self):
super().__init__()
def __str__(self):
print_format = '{:20}: {:<20}\n'
return print_format.format('flags', hex(self.attr.flags))
@property
def flags(self):
return self.attr.flags
@property
def vport(self):
return self.attr.vport
@property
def vport_vhca_id(self):
return self.attr.vport_vhca_id
@property
def esw_owner_vhca_id(self):
return self.attr.esw_owner_vhca_id
@property
def vport_steering_icm_rx(self):
return self.attr.vport_steering_icm_rx
@property
def vport_steering_icm_tx(self):
return self.attr.vport_steering_icm_tx
@property
def reg_c0_value(self):
return self.attr.reg_c0.value
@property
def reg_c0_mask(self):
return self.attr.reg_c0.mask
cdef class Mlx5DVContextAttr(PyverbsObject):
"""
Represent mlx5dv_context_attr struct. This class is used to open an mlx5
device.
"""
def __init__(self, flags=0, comp_mask=0):
super().__init__()
self.attr.flags = flags
self.attr.comp_mask = comp_mask
def __str__(self):
print_format = '{:20}: {:<20}\n'
return print_format.format('flags', self.attr.flags) +\
print_format.format('comp_mask', self.attr.comp_mask)
@property
def flags(self):
return self.attr.flags
@flags.setter
def flags(self, val):
self.attr.flags = val
@property
def comp_mask(self):
return self.attr.comp_mask
@comp_mask.setter
def comp_mask(self, val):
self.attr.comp_mask = val
cdef class Mlx5DevxObj(PyverbsCM):
"""
Represents mlx5dv_devx_obj C struct.
"""
def __init__(self, Context context, in_, outlen):
"""
Creates a DevX object.
If the object was successfully created, the command's output would be
stored as a memoryview in self.out_view.
:param in_: Bytes of the obj_create command's input data provided in a
device specification format.
(Stream of bytes or __bytes__ is implemented)
:param outlen: Expected output length in bytes
"""
super().__init__()
in_bytes = bytes(in_)
cdef char *in_mailbox = _prepare_devx_inbox(in_bytes)
cdef char *out_mailbox = _prepare_devx_outbox(outlen)
self.obj = dv.mlx5dv_devx_obj_create(context.context, in_mailbox,
len(in_bytes), out_mailbox, outlen)
try:
if self.obj == NULL:
raise PyverbsRDMAErrno('Failed to create DevX object')
self.out_view = memoryview(out_mailbox[:outlen])
status = hex(self.out_view[0])
syndrome = self.out_view[4:8].hex()
if status != hex(0):
raise PyverbsRDMAError('Failed to create DevX object with status'
f'({status}) and syndrome (0x{syndrome})')
finally:
free(in_mailbox)
free(out_mailbox)
self.context = context
self.context.add_ref(self)
self.flow_counter_actions = weakref.WeakSet()
self.dest_tir_actions = weakref.WeakSet()
def query(self, in_, outlen):
"""
Queries the DevX object.
:param in_: Bytes of the obj_query command's input data provided in a
device specification format.
(Stream of bytes or __bytes__ is implemented)
:param outlen: Expected output length in bytes
:return: Bytes of the command's output
"""
in_bytes = bytes(in_)
cdef char *in_mailbox = _prepare_devx_inbox(in_bytes)
cdef char *out_mailbox = _prepare_devx_outbox(outlen)
rc = dv.mlx5dv_devx_obj_query(self.obj, in_mailbox, len(in_bytes),
out_mailbox, outlen)
try:
if rc:
raise PyverbsRDMAError('Failed to query DevX object', rc)
out = <bytes>out_mailbox[:outlen]
finally:
free(in_mailbox)
free(out_mailbox)
return out
def modify(self, in_, outlen):
"""
Modifies the DevX object.
:param in_: Bytes of the obj_modify command's input data provided in a
device specification format.
(Stream of bytes or __bytes__ is implemented)
:param outlen: Expected output length in bytes
:return: Bytes of the command's output
"""
in_bytes = bytes(in_)
cdef char *in_mailbox = _prepare_devx_inbox(in_bytes)
cdef char *out_mailbox = _prepare_devx_outbox(outlen)
rc = dv.mlx5dv_devx_obj_modify(self.obj, in_mailbox, len(in_bytes),
out_mailbox, outlen)
try:
if rc:
raise PyverbsRDMAError('Failed to modify DevX object', rc)
out = <bytes>out_mailbox[:outlen]
finally:
free(in_mailbox)
free(out_mailbox)
return out
cdef add_ref(self, obj):
if isinstance(obj, DrActionFlowCounter):
self.flow_counter_actions.add(obj)
elif isinstance(obj, DrActionDestTir):
self.dest_tir_actions.add(obj)
else:
raise PyverbsError('Unrecognized object type')
@property
def out_view(self):
return self.out_view
@property
def obj(self):
return <object>self.obj
def __dealloc__(self):
self.close()
cpdef close(self):
if self.obj != NULL:
if self.logger:
self.logger.debug('Closing Mlx5DvexObj')
close_weakrefs([self.flow_counter_actions, self.dest_tir_actions])
rc = dv.mlx5dv_devx_obj_destroy(self.obj)
if rc:
raise PyverbsRDMAError('Failed to destroy a DevX object', rc)
self.obj = NULL
self.context = None
cdef class Mlx5Context(Context):
"""
Represent mlx5 context, which extends Context.
"""
def __init__(self, Mlx5DVContextAttr attr not None, name=''):
"""
Open an mlx5 device using the given attributes
:param name: The RDMA device's name (used by parent class)
:param attr: mlx5-specific device attributes
:return: None
"""
super().__init__(name=name, attr=attr)
if not dv.mlx5dv_is_supported(self.device):
raise PyverbsUserError('This is not an MLX5 device')
self.context = dv.mlx5dv_open_device(self.device, &attr.attr)
if self.context == NULL:
raise PyverbsRDMAErrno('Failed to open mlx5 context on {dev}'
.format(dev=self.name))
self.devx_umems = weakref.WeakSet()
self.devx_objs = weakref.WeakSet()
self.devx_eqs = weakref.WeakSet()
def query_mlx5_device(self, comp_mask=-1):
"""
Queries the provider for device-specific attributes.
:param comp_mask: Which attributes to query. Default value is -1. If
not changed by user, pyverbs will pass a bitwise OR
of all available enum entries.
:return: A Mlx5DVContext containing the attributes.
"""
dv_attr = Mlx5DVContext()
if comp_mask == -1:
dv_attr.comp_mask = \
dve.MLX5DV_CONTEXT_MASK_CQE_COMPRESION |\
dve.MLX5DV_CONTEXT_MASK_SWP |\
dve.MLX5DV_CONTEXT_MASK_STRIDING_RQ |\
dve.MLX5DV_CONTEXT_MASK_TUNNEL_OFFLOADS |\
dve.MLX5DV_CONTEXT_MASK_DYN_BFREGS |\
dve.MLX5DV_CONTEXT_MASK_CLOCK_INFO_UPDATE |\
dve.MLX5DV_CONTEXT_MASK_DC_ODP_CAPS |\
dve.MLX5DV_CONTEXT_MASK_FLOW_ACTION_FLAGS |\
dve.MLX5DV_CONTEXT_MASK_DCI_STREAMS |\
dve.MLX5DV_CONTEXT_MASK_WR_MEMCPY_LENGTH |\
dve.MLX5DV_CONTEXT_MASK_CRYPTO_OFFLOAD |\
dve.MLX5DV_CONTEXT_MASK_MAX_DC_RD_ATOM
else:
dv_attr.comp_mask = comp_mask
rc = dv.mlx5dv_query_device(self.context, &dv_attr.dv)
if rc != 0:
raise PyverbsRDMAError(f'Failed to query mlx5 device {self.name}.', rc)
return dv_attr
@staticmethod
def query_mlx5_port(Context ctx, port_num):
dv_attr = Mlx5DVPortAttr()
rc = dv.mlx5dv_query_port(ctx.context, port_num, &dv_attr.attr)
if rc != 0:
raise PyverbsRDMAError(f'Failed to query dv port mlx5 {ctx.name} port {port_num}.', rc)
return dv_attr
@staticmethod
def reserved_qpn_alloc(Context ctx):
"""
Allocate a reserved QP number from firmware.
:param ctx: The device context to issue the action on.
:return: The reserved QP number.
"""
cdef uint32_t qpn
rc = dv.mlx5dv_reserved_qpn_alloc(ctx.context, &qpn)
if rc != 0:
raise PyverbsRDMAError('Failed to alloc reserved QP number.', rc)
return qpn
@staticmethod
def reserved_qpn_dealloc(Context ctx, qpn):
"""
Release the reserved QP number to firmware.
:param ctx: The device context to issue the action on.
:param qpn: The QP number to be deallocated.
"""
rc = dv.mlx5dv_reserved_qpn_dealloc(ctx.context, qpn)
if rc != 0:
raise PyverbsRDMAError(f'Failed to dealloc QP number {qpn}.', rc)
@staticmethod
def crypto_login(Context ctx, Mlx5CryptoLoginAttr login_attr):
"""
Creates a crypto login session
:param ctx: The device context to issue the action on.
:param login_attr: Mlx5CryptoLoginAttr object which contains the
credential to login with and the import KEK to be
used for secured communications.
"""
rc = dv.mlx5dv_crypto_login(ctx.context, &login_attr.mlx5dv_crypto_login_attr)
if rc != 0:
raise PyverbsRDMAError(f'Failed to create crypto login session.', rc)
@staticmethod
def query_login_state(Context ctx):
"""
Queries the state of the current crypto login session.
:param ctx: The device context to issue the action on.
:return: The login state.
"""
cdef dv.mlx5dv_crypto_login_state state
rc = dv.mlx5dv_crypto_login_query_state(ctx.context, &state)
if rc != 0:
raise PyverbsRDMAError(f'Failed to query the crypto login session state.', rc)
return state
@staticmethod
def crypto_logout(Context ctx):
"""
Logs out from the current crypto login session.
:param ctx: The device context to issue the action on.
"""
rc = dv.mlx5dv_crypto_logout(ctx.context)
if rc != 0:
raise PyverbsRDMAError(f'Failed to logout from crypto login session.', rc)
def devx_general_cmd(self, in_, outlen):
"""
Executes a DevX general command according to the input mailbox.
:param in_: Bytes of the general command's input data provided in a
device specification format.
(Stream of bytes or __bytes__ is implemented)
:param outlen: Expected output length in bytes
:return out: Bytes of the general command's output data provided in a
device specification format
"""
in_bytes = bytes(in_)
cdef char *in_mailbox = _prepare_devx_inbox(in_bytes)
cdef char *out_mailbox = _prepare_devx_outbox(outlen)
rc = dv.mlx5dv_devx_general_cmd(self.context, in_mailbox, len(in_bytes),
out_mailbox, outlen)
try:
if rc:
raise PyverbsRDMAError("DevX general command failed", rc)
out = <bytes>out_mailbox[:outlen]
finally:
free(in_mailbox)
free(out_mailbox)
return out
@staticmethod
def device_timestamp_to_ns(Context ctx, device_timestamp):
"""
Convert device timestamp from HCA core clock units to the corresponding
nanosecond units. The function uses mlx5dv_get_clock_info to get the
device clock information.
:param ctx: The device context to issue the action on.
:param device_timestamp: The device timestamp to convert.
:return: Timestamp in nanoseconds
"""
cdef dv.mlx5dv_clock_info *clock_info
clock_info = <dv.mlx5dv_clock_info *>calloc(1, sizeof(dv.mlx5dv_clock_info))
rc = dv.mlx5dv_get_clock_info(ctx.context, clock_info)
if rc != 0:
raise PyverbsRDMAError(f'Failed to get the clock info', rc)
ns_time = dv.mlx5dv_ts_to_ns(clock_info, device_timestamp)
free(clock_info)
return ns_time
def devx_query_eqn(self, vector):
"""
Query EQN for a given vector id.
:param vector: Completion vector number
:return: The device EQ number which relates to the given input vector
"""
cdef uint32_t eqn
rc = dv.mlx5dv_devx_query_eqn(self.context, vector, &eqn)
if rc:
raise PyverbsRDMAError('Failed to query EQN', rc)
return eqn
cdef add_ref(self, obj):
try:
Context.add_ref(self, obj)
except PyverbsError:
if isinstance(obj, Mlx5UMEM):
self.devx_umems.add(obj)
elif isinstance(obj, Mlx5DevxObj):
self.devx_objs.add(obj)
elif isinstance(obj, Mlx5DevxEq):
self.devx_eqs.add(obj)
else:
raise PyverbsError('Unrecognized object type')
def __dealloc__(self):
self.close()
cpdef close(self):
if self.context != NULL:
close_weakrefs([self.pps, self.devx_objs, self.devx_umems, self.devx_eqs])
super(Mlx5Context, self).close()
cdef class Mlx5DVContext(PyverbsObject):
"""
Represents mlx5dv_context struct, which exposes mlx5-specific capabilities,
reported by mlx5dv_query_device.
"""
@property
def version(self):
return self.dv.version
@property
def flags(self):
return self.dv.flags
@property
def comp_mask(self):
return self.dv.comp_mask
@comp_mask.setter
def comp_mask(self, val):
self.dv.comp_mask = val
@property
def cqe_comp_caps(self):
return self.dv.cqe_comp_caps
@property
def sw_parsing_caps(self):
return self.dv.sw_parsing_caps
@property
def striding_rq_caps(self):
return self.dv.striding_rq_caps
@property
def tunnel_offload_caps(self):
return self.dv.tunnel_offloads_caps
@property
def max_dynamic_bfregs(self):
return self.dv.max_dynamic_bfregs
@property
def max_clock_info_update_nsec(self):
return self.dv.max_clock_info_update_nsec
@property
def flow_action_flags(self):
return self.dv.flow_action_flags
@property
def dc_odp_caps(self):
return self.dv.dc_odp_caps
@property
def crypto_caps(self):
return self.dv.crypto_caps
@property
def num_lag_ports(self):
return self.dv.num_lag_ports
@property
def dci_streams_caps(self):
return self.dv.dci_streams_caps
@property
def max_wr_memcpy_length(self):
return self.dv.max_wr_memcpy_length
@property
def max_dc_rd_atom(self):
return self.dv.max_dc_rd_atom
@property
def max_dc_init_rd_atom(self):
return self.dv.max_dc_init_rd_atom
def __str__(self):
print_format = '{:20}: {:<20}\n'
ident_format = ' {:20}: {:<20}\n'
cqe = 'CQE compression caps:\n' +\
ident_format.format('max num',
self.dv.cqe_comp_caps.max_num) +\
ident_format.format('supported formats',
cqe_comp_to_str(self.dv.cqe_comp_caps.supported_format))
swp = 'SW parsing caps:\n' +\
ident_format.format('SW parsing offloads',
swp_to_str(self.dv.sw_parsing_caps.sw_parsing_offloads)) +\
ident_format.format('supported QP types',
qpts_to_str(self.dv.sw_parsing_caps.supported_qpts))
strd = 'Striding RQ caps:\n' +\
ident_format.format('min single stride log num of bytes',
self.dv.striding_rq_caps.min_single_stride_log_num_of_bytes) +\
ident_format.format('max single stride log num of bytes',
self.dv.striding_rq_caps.max_single_stride_log_num_of_bytes) +\
ident_format.format('min single wqe log num of strides',
self.dv.striding_rq_caps.min_single_wqe_log_num_of_strides) +\
ident_format.format('max single wqe log num of strides',
self.dv.striding_rq_caps.max_single_wqe_log_num_of_strides) +\
ident_format.format('supported QP types',
qpts_to_str(self.dv.striding_rq_caps.supported_qpts))
stream = 'DCI stream caps:\n' +\
ident_format.format('max log num concurrent streams',
self.dv.dci_streams_caps.max_log_num_concurent) +\
ident_format.format('max log num errored streams',
self.dv.dci_streams_caps.max_log_num_errored)
return print_format.format('Version', self.dv.version) +\
print_format.format('Flags',
context_flags_to_str(self.dv.flags)) +\
print_format.format('comp mask',
context_comp_mask_to_str(self.dv.comp_mask)) +\
cqe + swp + strd + stream +\
print_format.format('Tunnel offloads caps',
tunnel_offloads_to_str(self.dv.tunnel_offloads_caps)) +\
print_format.format('Max dynamic BF registers',
self.dv.max_dynamic_bfregs) +\
print_format.format('Max clock info update [nsec]',
self.dv.max_clock_info_update_nsec) +\
print_format.format('Flow action flags',
self.dv.flow_action_flags) +\
print_format.format('DC ODP caps', self.dv.dc_odp_caps) +\
print_format.format('Num LAG ports', self.dv.num_lag_ports) +\
print_format.format('Max WR memcpy length', self.dv.max_wr_memcpy_length) +\
print_format.format('Max DC Read Atomic', self.dv.max_dc_rd_atomic) +\
print_format.format('Max DC Init Read Atomic', self.dv.max_dc_init_rd_atomic)
cdef class Mlx5DCIStreamInitAttr(PyverbsObject):
"""
Represents dci_streams struct, which defines initial attributes
for DC QP creation.
"""
def __init__(self, log_num_concurent=0, log_num_errored=0):
"""
Initializes an Mlx5DCIStreamInitAttr object with the given DC
log_num_concurent and log_num_errored.
:param log_num_concurent: Number of dci stream channels.
:param log_num_errored: Number of dci error stream channels
before moving DCI to error.
:return: An initialized object
"""
super().__init__()
self.dci_streams.log_num_concurent = log_num_concurent
self.dci_streams.log_num_errored = log_num_errored
def __str__(self):
print_format = '{:20}: {:<20}\n'
return print_format.format('DCI Stream log_num_concurent', self.dci_streams.log_num_concurent) +\
print_format.format('DCI Stream log_num_errored', self.dci_streams.log_num_errored)
@property
def log_num_concurent(self):
return self.dci_streams.log_num_concurent
@log_num_concurent.setter
def log_num_concurent(self, val):
self.dci_streams.log_num_concurent=val
@property
def log_num_errored(self):
return self.dci_streams.log_num_errored
@log_num_errored.setter
def log_num_errored(self, val):
self.dci_streams.log_num_errored=val
cdef class Mlx5DVDCInitAttr(PyverbsObject):
"""
Represents mlx5dv_dc_init_attr struct, which defines initial attributes
for DC QP creation.
"""
def __init__(self, dc_type=dve.MLX5DV_DCTYPE_DCI, dct_access_key=0, dci_streams=None):
"""
Initializes an Mlx5DVDCInitAttr object with the given DC type and DCT
access key.
:param dc_type: Which DC QP to create (DCI/DCT).
:param dct_access_key: Access key to be used by the DCT
:param dci_streams: Mlx5DCIStreamInitAttr
:return: An initializes object
"""
super().__init__()
self.attr.dc_type = dc_type
self.attr.dct_access_key = dct_access_key
if dci_streams is not None:
self.attr.dci_streams.log_num_concurent=dci_streams.log_num_concurent
self.attr.dci_streams.log_num_errored=dci_streams.log_num_errored
def __str__(self):
print_format = '{:20}: {:<20}\n'
return print_format.format('DC type', dc_type_to_str(self.attr.dc_type)) +\
print_format.format('DCT access key', self.attr.dct_access_key) +\
print_format.format('DCI Stream log_num_concurent', self.attr.dci_streams.log_num_concurent) +\
print_format.format('DCI Stream log_num_errored', self.attr.dci_streams.log_num_errored)
@property
def dc_type(self):
return self.attr.dc_type
@dc_type.setter
def dc_type(self, val):
self.attr.dc_type = val
@property
def dct_access_key(self):
return self.attr.dct_access_key
@dct_access_key.setter
def dct_access_key(self, val):
self.attr.dct_access_key = val
@property
def dci_streams(self):
return self.attr.dci_streams
@dci_streams.setter
def dci_streams(self, val):
self.attr.dci_streams=val
cdef class Mlx5DVQPInitAttr(PyverbsObject):
"""
Represents mlx5dv_qp_init_attr struct, initial attributes used for mlx5 QP
creation.
"""
def __init__(self, comp_mask=0, create_flags=0,
Mlx5DVDCInitAttr dc_init_attr=None, send_ops_flags=0):
"""
Initializes an Mlx5DVQPInitAttr object with the given user data.
:param comp_mask: A bitmask specifying which fields are valid
:param create_flags: A bitwise OR of mlx5dv_qp_create_flags
:param dc_init_attr: Mlx5DVDCInitAttr object
:param send_ops_flags: A bitwise OR of mlx5dv_qp_create_send_ops_flags
:return: An initialized Mlx5DVQPInitAttr object
"""
super().__init__()
self.attr.comp_mask = comp_mask
self.attr.create_flags = create_flags
self.attr.send_ops_flags = send_ops_flags
if dc_init_attr is not None:
self.attr.dc_init_attr.dc_type = dc_init_attr.dc_type
if comp_mask & dve.MLX5DV_QP_INIT_ATTR_MASK_DCI_STREAMS:
self.attr.dc_init_attr.dci_streams = dc_init_attr.dci_streams
else:
self.attr.dc_init_attr.dct_access_key = dc_init_attr.dct_access_key
def __str__(self):
print_format = '{:20}: {:<20}\n'
return print_format.format('Comp mask',
qp_comp_mask_to_str(self.attr.comp_mask)) +\
print_format.format('Create flags',
qp_create_flags_to_str(self.attr.create_flags)) +\
'DC init attr:\n' +\
print_format.format(' DC type',
dc_type_to_str(self.attr.dc_init_attr.dc_type)) +\
print_format.format(' DCI Stream log_num_concurent',
self.attr.dc_init_attr.dci_streams.log_num_concurent) +\
print_format.format(' DCI Stream log_num_errored',
self.attr.dc_init_attr.dci_streams.log_num_errored) +\
print_format.format(' DCT access key',
self.attr.dc_init_attr.dct_access_key) +\
print_format.format('Send ops flags',
send_ops_flags_to_str(self.attr.send_ops_flags))
@property
def comp_mask(self):
return self.attr.comp_mask
@comp_mask.setter
def comp_mask(self, val):
self.attr.comp_mask = val
@property
def create_flags(self):
return self.attr.create_flags
@create_flags.setter
def create_flags(self, val):
self.attr.create_flags = val
@property
def send_ops_flags(self):
return self.attr.send_ops_flags
@send_ops_flags.setter
def send_ops_flags(self, val):
self.attr.send_ops_flags = val
@property
def dc_type(self):
return self.attr.dc_init_attr.dc_type
@dc_type.setter
def dc_type(self, val):
self.attr.dc_init_attr.dc_type = val
@property
def dct_access_key(self):
return self.attr.dc_init_attr.dct_access_key
@dct_access_key.setter
def dct_access_key(self, val):
self.attr.dc_init_attr.dct_access_key = val
@property
def dci_streams(self):
return self.attr.dc_init_attr.dci_streams
@dci_streams.setter
def dci_streams(self, val):
self.attr.dc_init_attr.dci_streams=val
cdef copy_mr_interleaved_array(dv.mlx5dv_mr_interleaved *mr_interleaved_p,
mr_interleaved_lst):
"""
Build C array from the C objects of Mlx5MrInterleaved list and set the
mr_interleaved_p to this array address. The mr_interleaved_p should be
allocated with enough size for those objects.
:param mr_interleaved_p: Pointer to array of mlx5dv_mr_interleaved.
:param mr_interleaved_lst: List of Mlx5MrInterleaved.
"""
num_interleaved = len(mr_interleaved_lst)
cdef dv.mlx5dv_mr_interleaved *tmp
for i in range(num_interleaved):
tmp = &(<Mlx5MrInterleaved>mr_interleaved_lst[i]).mlx5dv_mr_interleaved
memcpy(mr_interleaved_p, tmp, sizeof(dv.mlx5dv_mr_interleaved))
mr_interleaved_p += 1
cdef class Mlx5QP(QPEx):
def __init__(self, Context context, QPInitAttrEx init_attr,
Mlx5DVQPInitAttr dv_init_attr):
"""
Initializes an mlx5 QP according to the user-provided data.
:param context: Context object
:param init_attr: QPInitAttrEx object
:param dv_init_attr: Mlx5DVQPInitAttr object
:return: An initialized Mlx5QP
"""
cdef PD pd
# Initialize the logger here as the parent's __init__ is called after
# the QP is allocated. Allocation can fail, which will lead to exceptions
# thrown during object's teardown.
self.logger = logging.getLogger(self.__class__.__name__)
self.dc_type = dv_init_attr.dc_type if dv_init_attr else 0
if init_attr.pd is not None:
pd = <PD>init_attr.pd
pd.add_ref(self)
self.qp = \
dv.mlx5dv_create_qp(context.context,
&init_attr.attr,
&dv_init_attr.attr if dv_init_attr is not None
else NULL)
if self.qp == NULL:
raise PyverbsRDMAErrno('Failed to create MLX5 QP.\nQPInitAttrEx '
'attributes:\n{}\nMLX5DVQPInitAttr:\n{}'.
format(init_attr, dv_init_attr))
super().__init__(context, init_attr)
def _get_comp_mask(self, dst):
masks = {dve.MLX5DV_DCTYPE_DCT: {'INIT': e.IBV_QP_PKEY_INDEX |
e.IBV_QP_PORT | e.IBV_QP_ACCESS_FLAGS,
'RTR': e.IBV_QP_AV |\
e.IBV_QP_PATH_MTU |\
e.IBV_QP_MIN_RNR_TIMER},
dve.MLX5DV_DCTYPE_DCI: {'INIT': e.IBV_QP_PKEY_INDEX |\
e.IBV_QP_PORT,
'RTR': e.IBV_QP_PATH_MTU,
'RTS': e.IBV_QP_TIMEOUT |\
e.IBV_QP_RETRY_CNT |\
e.IBV_QP_RNR_RETRY | e.IBV_QP_SQ_PSN |\
e.IBV_QP_MAX_QP_RD_ATOMIC}}
if self.dc_type == 0:
return super()._get_comp_mask(dst)
return masks[self.dc_type][dst] | e.IBV_QP_STATE
def wr_set_dc_addr(self, AH ah, remote_dctn, remote_dc_key):
"""
Attach a DC info to the last work request.
:param ah: Address Handle to the requested DCT.
:param remote_dctn: The remote DCT number.
:param remote_dc_key: The remote DC key.
"""
dv.mlx5dv_wr_set_dc_addr(dv.mlx5dv_qp_ex_from_ibv_qp_ex(self.qp_ex),
ah.ah, remote_dctn, remote_dc_key)
def wr_raw_wqe(self, wqe):
"""
Build a raw work request
:param wqe: A Wqe object
"""
cdef void *wqe_ptr = <void *> <uintptr_t> wqe.address
dv.mlx5dv_wr_raw_wqe(dv.mlx5dv_qp_ex_from_ibv_qp_ex(self.qp_ex), wqe_ptr)
def wr_mr_interleaved(self, Mlx5Mkey mkey, access_flags, repeat_count,
mr_interleaved_lst):
"""
Registers an interleaved memory layout by using an indirect mkey and
some interleaved data.
:param mkey: A Mlx5Mkey instance to reg this memory.
:param access_flags: The mkey access flags.
:param repeat_count: Number of times to repeat the interleaved layout.
:param mr_interleaved_lst: List of Mlx5MrInterleaved.
"""
num_interleaved = len(mr_interleaved_lst)
cdef dv.mlx5dv_mr_interleaved *mr_interleaved_p = \
<dv.mlx5dv_mr_interleaved*>calloc(1, num_interleaved * sizeof(dv.mlx5dv_mr_interleaved))
if mr_interleaved_p == NULL:
raise MemoryError('Failed to calloc mr interleaved buffers')
copy_mr_interleaved_array(mr_interleaved_p, mr_interleaved_lst)
dv.mlx5dv_wr_mr_interleaved(dv.mlx5dv_qp_ex_from_ibv_qp_ex(self.qp_ex),
mkey.mlx5dv_mkey, access_flags, repeat_count,
num_interleaved, mr_interleaved_p)
free(mr_interleaved_p)
def wr_mr_list(self, Mlx5Mkey mkey, access_flags, sge_list):
"""
Registers a memory layout based on list of SGE.
:param mkey: A Mlx5Mkey instance to reg this memory.
:param access_flags: The mkey access flags.
:param sge_list: List of SGE.
"""
num_sges = len(sge_list)
cdef v.ibv_sge *sge_p = <v.ibv_sge*>calloc(1, num_sges * sizeof(v.ibv_sge))
if sge_p == NULL:
raise MemoryError('Failed to calloc sge buffers')
copy_sg_array(sge_p, sge_list, num_sges)
dv.mlx5dv_wr_mr_list(dv.mlx5dv_qp_ex_from_ibv_qp_ex(self.qp_ex),
mkey.mlx5dv_mkey, access_flags, num_sges, sge_p)
free(sge_p)
def wr_mkey_configure(self, Mlx5Mkey mkey, num_setters, Mlx5MkeyConfAttr mkey_config):
"""
Create a work request to configure an Mkey
:param mkey: A Mlx5Mkey instance to configure.
:param num_setters: The number of setters that must be called after
this function.
:param attr: The Mkey configuration attributes.
"""
dv.mlx5dv_wr_mkey_configure(dv.mlx5dv_qp_ex_from_ibv_qp_ex(self.qp_ex),
mkey.mlx5dv_mkey, num_setters,
&mkey_config.mlx5dv_mkey_conf_attr)
def wr_set_mkey_access_flags(self, access_flags):
"""
Set the memory protection attributes for an Mkey
:param access_flags: The mkey access flags.
"""
dv.mlx5dv_wr_set_mkey_access_flags(dv.mlx5dv_qp_ex_from_ibv_qp_ex(self.qp_ex),
access_flags)
def wr_set_mkey_layout_list(self, sge_list):
"""
Set a memory layout for an Mkey based on SGE list.
:param sge_list: List of SGE.
"""
num_sges = len(sge_list)
cdef v.ibv_sge *sge_p = <v.ibv_sge*>calloc(1, num_sges * sizeof(v.ibv_sge))
if sge_p == NULL:
raise MemoryError('Failed to calloc sge buffers')
copy_sg_array(sge_p, sge_list, num_sges)
dv.mlx5dv_wr_set_mkey_layout_list(dv.mlx5dv_qp_ex_from_ibv_qp_ex(self.qp_ex),
num_sges, sge_p)
free(sge_p)
def wr_set_mkey_layout_interleaved(self, repeat_count, mr_interleaved_lst):
"""
Set an interleaved memory layout for an Mkey
:param repeat_count: Number of times to repeat the interleaved layout.
:param mr_interleaved_lst: List of Mlx5MrInterleaved.
"""
num_interleaved = len(mr_interleaved_lst)
cdef dv.mlx5dv_mr_interleaved *mr_interleaved_p = \
<dv.mlx5dv_mr_interleaved*>calloc(1, num_interleaved * sizeof(dv.mlx5dv_mr_interleaved))
if mr_interleaved_p == NULL:
raise MemoryError('Failed to calloc mr interleaved buffers')
copy_mr_interleaved_array(mr_interleaved_p, mr_interleaved_lst)
dv.mlx5dv_wr_set_mkey_layout_interleaved(dv.mlx5dv_qp_ex_from_ibv_qp_ex(self.qp_ex),
repeat_count, num_interleaved,
mr_interleaved_p)
free(mr_interleaved_p)
def wr_set_mkey_crypto(self, Mlx5CryptoAttr attr):
"""
Configure a MKey for crypto operation.
:param attr: crypto attributes to set for the mkey.
"""
dv.mlx5dv_wr_set_mkey_crypto(dv.mlx5dv_qp_ex_from_ibv_qp_ex(self.qp_ex),
&attr.mlx5dv_crypto_attr)
def wr_set_mkey_sig_block(self, Mlx5SigBlockAttr block_attr):
"""
Configure a MKEY for block signature (data integrity) operation.
:param block_attr: Block signature attributes to set for the mkey.
"""
dv.mlx5dv_wr_set_mkey_sig_block(dv.mlx5dv_qp_ex_from_ibv_qp_ex(self.qp_ex),
&block_attr.mlx5dv_sig_block_attr)
def wr_memcpy(self, dest_lkey, dest_addr, src_lkey, src_addr, length):
"""
Copies memory data on PCI bus using DMA functionality of the device.
:param dest_lkey: Local key of the mkey to copy data to
:param dest_addr: Memory address to copy data to
:param src_lkey: Local key of the mkey to copy data from
:param src_addr: Memory address to copy data from
:param length: Length of data to be copied
"""
dv.mlx5dv_wr_memcpy(dv.mlx5dv_qp_ex_from_ibv_qp_ex(self.qp_ex),
dest_lkey, dest_addr, src_lkey, src_addr, length)
def cancel_posted_send_wrs(self, wr_id):
"""
Cancel all pending send work requests with supplied wr_id in a QP in
SQD state.
:param wr_id: The WRID to cancel.
:return: Number of work requests that were canceled.
"""
rc = dv.mlx5dv_qp_cancel_posted_send_wrs(dv.mlx5dv_qp_ex_from_ibv_qp_ex(self.qp_ex),
wr_id)
if rc < 0:
raise PyverbsRDMAError(f'Failed to cancel send WRs', -rc)
return rc
def wr_set_dc_addr_stream(self, AH ah, remote_dctn, remote_dc_key, stream_id):
"""
Attach a DC info to the last work request.
:param ah: Address Handle to the requested DCT.
:param remote_dctn: The remote DCT number.
:param remote_dc_key: The remote DC key.
:param stream_id: DCI stream channel_id
"""
dv.mlx5dv_wr_set_dc_addr_stream(dv.mlx5dv_qp_ex_from_ibv_qp_ex(self.qp_ex),
ah.ah, remote_dctn, remote_dc_key,
stream_id)
@staticmethod
def query_lag_port(QP qp):
"""
Queries for port num that the QP desired to use, and the port that
is currently used by the bond for this QP.
:param qp: Queries the port for this QP.
:return: Tuple of the desired port and actual port which used by the HW.