UD模式
UD(Unreliable Datagram)是RDMA的一种传输模式。
AH
AH(Address Handle)是IB传输过程中描述通信节点的信息集合,属性描述如下
struct ibv_ah_attr {
struct ibv_global_route grh;
uint16_t dlid; //dest lid, 仅IB模式有效
uint8_t sl; //service level, 仅IB模式有效
uint8_t src_path_bits; //src lid path bits 仅IB模式有效
uint8_t static_rate; //enum ibv_rate{} 和包的传输速率有关
uint8_t is_global; //grh是否有效
uint8_t port_num; //gid所在的port num, 一般都是1
};
struct ibv_global_route {
union ibv_gid dgid; //dest ip
uint32_t flow_label; //数据报文的标签,在ipv6中是ipv6hdr->flow_labal.
uint8_t sgid_index; //source ip index
uint8_t hop_limit; //等同于ipv4hdr->ttl
uint8_t traffic_class; //等同于ipv4hdr->tos
};
创建AH
(1) 通过ibv_create_ah()接口创建ah
struct ibv_ah *ibv_create_ah(struct ibv_pd *pd, struct ibv_ah_attr *attr);
入参:
Pd |
Protection Domain |
Attr |
ah 属性 |
返回值:
非NULL |
成功 |
NULL | 失败 |
流程如下:
ibv_create_ah()
->driver->ops->create_ah()
->ibv_cmd_create_ah()
->ib_uverbs_create_ah()
ib_uverbs_create_ah()
->rdma_is_port_valid(),检测port_num 是否是有效的
-> fill struct rdma_ah_attr{}
-> rdma_create_user_ah()
->RoCE v2会通过ib_resolve_eth_dmac()查找arp和路由
->_rdma_create_ah()
->driver->ops.create_ah() 完成ah创建
2、通过ibv_create_ah_from_wc() 接口创建ah
struct ibv_ah *ibv_create_ah_from_wc(struct ibv_pd *pd, struct ibv_wc *wc, struct ibv_grh *grh, uint8_t port_num);
说明:根据poll CQ 得到的recv wc创建ah_attr
入参:
Pd |
Protection Domain |
wc |
poll cq得到的recv wc |
grh |
recv wr的前40字节 |
Port_num |
gid所在的port id,一般是1 |
返回值:
非NULL |
成功 |
NULL | 失败 |
流程:
ibv_create_ah_from_wc()
->ibv_init_ah_from_wc()
->ibv_create_ah()
ibv_init_ah_from_wc()
->set_ah_attr_generic_fields() 从wc中获取信息,填充ah_attr
ah_attr->grh.flow_label = be32toh(grh->version_tclass_flow) & 0xFFFFF;
ah_attr->dlid = wc->slid;
ah_attr->sl = wc->sl;
ah_attr->src_path_bits = wc->dlid_path_bits;
ah_attr->port_num = port_num;
->wc->wc_flag一定要带有IBV_WC_GRH 标记,这样才能根据wc填充剩余的ah_attr
->set_ah_attr_by_ipv4() IPv4模式从rqe的起始位置偏移20字节,获取IP hdr,填充ah_attr->grh
->set_ah_attr_by_ipv6()IPv4模式从rqe的起始位置获取IPv6 hdr,填充ah_atr->grh
销毁AH
通过 int ibv_destroy_ah(struct ibv_ah *ah); 销毁AH
入参:
ah | UD ah |
返回值:
0 | 成功 |
非0 | 失败 |
流程:
ibv_destroy_ah()
->driver->ops->destroy_ah()
->ibv_cmd_destroy_ah() 陷入内核
->uverbs_free_ah()
uverbs_free_ah()
->rdma_destroy_ah_user()
->driver->ops.destroy_ah()
->dec reference count;
数据收发
send:
通过ibv_post_send(struct ibv_qp *qp, struct ibv_send_wr *wr,struct ibv_send_wr **bad_wr),填充send data搭配send queue中,完成数据发送
入参:
qp | ud qp |
wr |
work request待发送的数据 |
出参:
bad_wr |
没有填充到queue中的wr |
返回值
0 | success |
其他 | errno |
ud wr 属性:
struct ibv_send_wr {
uint64_t wr_id;
struct ibv_send_wr *next; //下一个wr, 为NULL时截至
struct ibv_sge *sg_list; //当前send wr对应的sge list
int num_sge;
enum ibv_wr_opcode opcode; //IBV_WR_SEND 或 IBV_WR_SEND_WITH_IMM,
unsigned int send_flags;
union {
__be32 imm_data; //send with imm时有效
uint32_t invalidate_rkey;
};
union {
.
.
.
struct {
struct ibv_ah *ah; //ah
uint32_t remote_qpn; //远端的QPn,两端交互得到
uint32_t remote_qkey;//远端的Qkey,用于接收校验,两端交互得到
} ud;
} wr;
.
.
.
};
说明:post send根据struct ibv_ah *ah得到驱动的ah信息,填充wqe的ctrl字段,比如udp sport,traffic_class等信息交给硬件,然后硬件完成组包发送。
recv:
通过ibv_post_recv(struct ibv_qp *qp, struct ibv_recv_wr *wr, struct ibv_recv_wr **bad_wr); 填充recv buf,接收send only/ send only with immediate数据
入参:
qp | ud qp |
wr |
work request,带填充的recv buf |
出参:
bad_wr |
没有填充到queue中的wr |
返回值
0 | success |
其他 | errno |
说明:post recv不区分UD模式和RC模式,只不过需要注意的是UD模式的recv wr的长度接收报文的长度加上40B。这40B是报文的ip hdr空间。
poll cq
通过ibv_poll_cq(struct ibv_cq *cq, int num_entries, struct ibv_wc *wc) 接口处理
入参:
cq |
指定的complete queue |
num_entrie |
wc数组的长度 |
出参:
wc |
work complete |
返回值
大于0 |
wc的实际数量 |
小于0 |
errno |
说明:wc分为send和recv两侧
send侧
struct ibv_wc {
uint64_t wr_id; //对应的send wr
enum ibv_wc_status status; //表示当前send wr是否处理成功
enum ibv_wc_opcode opcode; // IBV_WC_SEND
uint32_t vendor_err;
uint32_t byte_len; //不填充
union {
__be32 imm_data; //不填充
uint32_t invalidated_rkey; //不填充
};
uint32_t qp_num; //本段的QPn
uint32_t src_qp; //不填充
unsigned int wc_flags; //send with imm时 | IBV_WC_WITH_IMM
uint16_t pkey_index; //不填充
uint16_t slid; //不填充
uint8_t sl; //不填充
uint8_t dlid_path_bits; //不填充
};
recv侧
struct ibv_wc {
uint64_t wr_id; //对应的recv wr
enum ibv_wc_status status; //表示当前recv wr是否处理成功
enum ibv_wc_opcode opcode; //IBV_WC_RECV
uint32_t vendor_err;
uint32_t byte_len; //40B加上实际的数据长度,
//rqe的前40B是L3 hdr(struct iphdr/ipv6hdr)
//如果是ipv4 偏移20B位置处取数据
//如果是ipv6 偏移0B位置处取数据
//报文在 偏移40B位置处获取
union {
__be32 imm_data; //send only with immediate时携带
uint32_t invalidated_rkey; //ud模式不支持
};
uint32_t qp_num; //本段的QPn
uint32_t src_qp; //表示发送端的QPn,源自DETH中的source qpn
unsigned int wc_flags; //在UD模式下需要 | IBV_WC_GRH
uint16_t pkey_index; //bth->pkey 默认是65535
uint16_t slid; //source lid 在IB模式下有效
uint8_t sl; //service level 在IB模式下有效
uint8_t dlid_path_bits; //dest lid path bit 在IB模式下有效
};
补充说明:在IB spec中描述到在接收侧的需要给用户一个L3 header和L2 info,L3 header放在rqe中,标准IB是支持的,但是在RoCE v2模式中wc有没有存放l2 info的位置。所以下面这段描述可能存在错误。