开发流程
介绍RPing功能实现的详细流程。
总体流程
RPing功能开发的流程总览如下图所示。

详细步骤
- 初始化RPing功能,启动网络状态监测。
调用HccnRpingInit接口进行RPing功能初始化,对于每一个参与RPing监测功能的NPU,都需要调用一次该接口。且一个进程里,一个NPU仅能调用一次该接口,不支持重复调用。
初始化RPing功能前,首先需要定义HccnRpingInitAttr对象,初始化相关信息,并指定Device,代码片段示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13
// 初始化信息配置 int ipLen = 16; int devId = 4; HccnRpingInitAttr *initAttr = new HccnRpingInitAttr(); initAttr->mode = HCCN_RPING_MODE_ROCE; // 网络类型,当前只支持RoCE类型 initAttr->port = 13886; // 侦听端口,指定一个未使用的端口即可 initAttr->npuNum = 128; // 参与此次探测的全部NPU数量,即需要初始化的NPU个数 initAttr->bufferSize = 4096 * 50; // 配置值需要4K对齐,且必须大于:向每个探测目标的发包数量 * 2048 * 目标NPU数量 initAttr->ipAddr = new char[ipLen]; strcpy(initAttr->ipAddr, deviceIp[devId]); HccnRpingCtx rpingCtx = nullptr; aclrtSetDevice(devId); // 初始化之前需要指定Device HccnRpingInit(devId, initAttr, &rpingCtx); // 调用初始化接口,获取RPingCtx
- 添加探测目标,建立发送端client NPU与接收端target NPU之间的RPing通信链路。
添加探测目标的代码片段示例如下:
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
// 添加探测target char deviceIp[8][16] = { "192.168.99.127", "192.168.99.128", "192.168.99.129", "192.168.99.130", "192.168.99.131", "192.168.99.132", "192.168.99.133", "192.168.99.134" }; int ipLen = 16; int targetNum = devices.size() - 1; HccnRpingTargetInfo *target = new HccnRpingTargetInfo[targetNum]; for (int i = 0; i < devices.size() - 1; i++) { int devTargetId = devices[i]; // 从devices向量中取出target的deviceLogicId target[i].srcPort = 0; // tcp/udp 源端口 target[i].sl = 4; // RDMA网卡的service level , 取值范围:[0,7] target[i].tc = (33 & 0x3f) << 2; // RDMA网卡的traffic class,配置为RoCE报文的DSCP值 * 4 target[i].port = 13886; // socket连接端口,与target device初始化时配置的port一致 target[i].srcIp = new char[ipLen]; target[i].dstIp = new char[ipLen]; strcpy(target[i].srcIp, deviceIp[devClientId]); strcpy(target[i].dstIp, deviceIp[devTargetId]); } if (rpingCtx == nullptr) { printf("rpingCtx is null!\n"); return -1; } HccnRpingAddTarget(rpingCtx, targetNum, target);
HccnRpingAddTarget接口可以按照HccnRpingTargetInfo对象中“dstIp”的值对入参中的target数组去重。targetNum需要与target数组大小一致,否则可能会导致数组访问越界。
- 发起探测请求。
发起探测请求的代码片段示例如下:
1 2 3 4
uint32_t pktNum = 10; // 发给每个target的报文数量 uint32_t interval = 1; // 发送报文的间隔时间,单位为ms uint32_t timeout = 100; // client从发包到收包的等待的最大时长,单位为ms HccnRpingBatchPingStart(rpingCtx, pktNum, interval, timeout);
HccnRpingBatchPingStart接口在发起探测之前会校验HccnRpingInit接口配置的bufferSize值,bufferSize值需要大于“pktNum * 2048 * targetNum”,其中pktnum为向每个探测目标的发包数量,targetNum为该client要探测的target NPU总数。
- 调用HccnRpingGetResult接口获取探测结果。
探测结果以数组的形式呈现,每一个元素中存储的是探测target返回的信息。该接口不支持去重,因此需要确保入参中的“target”不包含重复信息。探测结果中的“state”字段代表了该探测结果的有效性,每个target result都会有一个对应的state,当其值为“HCCN_RPING_RESULT_STATE_VALID”时,代表结果真实有效,否则结果无效。
获取探测结果的代码片段示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// 获取探测结果 HccnRpingResultInfo *result = new HccnRpingResultInfo[targetNum]; HccnResult hccnRet = HCCN_E_AGAIN; while(hccnRet == HCCN_E_AGAIN) { sleep(1); hccnRet = HccnRpingGetResult(rpingCtx, targetNum, target, result); } for (int i = 0; i < targetNum; i++) { printf("txPkt[%u] rxPkt[%u] minRTT[%u] maxRTT[%u] avgRTT[%u] state[%u] payloadLen[%u]\n", result[i].txPkt, // 发送报文数 result[i].rxPkt, // 接收报文数 result[i].minRTT,// 最小收发包时延 result[i].maxRTT,// 最大收发包时延 result[i].avgRTT,// 平均收发包时延 result[i].state);// 获取结果的状态 }
- 中止探测任务
获取结果之后,调用HccnRpingBatchPingStop接口中止探测任务。
1 2
// 中止探测任务 HccnRpingBatchPingStop(rpingCtx);
- 移除探测目标
结束探测任务之前,移除添加的探测目标,断开先前建立的RPing通信链路。
- 该接口调用前须确保没有探测任务在执行。
- 该接口调用前要保证有target信息添加过。
1 2
// 删除探测目标 HccnRpingRemoveTarget(rpingCtx, targetNum, target);
- 释放RPing资源。
进程结束前需要调用HccnRpingDeinit接口释放内存资源。
- 该接口必须在HccnRpingInit接口调用并返回成功的情形下才可以调用,否则会释放不存在的内存资源导致异常。
- 该接口无法重复调用,重复调用会导致对内存的重复释放,可能造成段错误甚至coredump。
1 2
// 释放内存 HccnRpingDeinit(rpingCtx);