Skip to content

Commit

Permalink
added possible filter field when setting each interface to capture, a…
Browse files Browse the repository at this point in the history
…dded grpc to get capture op status
  • Loading branch information
byteocean committed Nov 9, 2023
1 parent ac2a3a6 commit 7dd5333
Show file tree
Hide file tree
Showing 8 changed files with 150 additions and 21 deletions.
6 changes: 6 additions & 0 deletions docs/deployment/capture_offloaded_rx_pkts.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ The following command is used to stop capturing on all configured interfaces. No
/bin/dpservice-cli capture stop
```

or before you start capturing, it is also recommended to check the operation status of this capturing feature by using:
```
/bin/dpservice-cli capture status
```
The returned values incude this feature's operation status, as well as the configuration information using the "capture start" subcommand.

## How offloaded packets are captured
Offloaded packets are captured by using special rte flow rules, especially the one that enables packet sampling on the RX side of an interface. The captured packets are encapsulated by prepending extra headers. Despite the fact that captured Ethernet frames are treated as UDP payload, it is flexible to use other customized headers as well. The format of encapsulation is as follows:

Expand Down
1 change: 1 addition & 0 deletions include/grpc/dp_async_grpc.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,5 +185,6 @@ CREATE_CALLCLASS(ResetVni, SingleReplyCall);

CREATE_CALLCLASS(CaptureStart, SingleReplyCall);
CREATE_CALLCLASS(CaptureStop, SingleReplyCall);
CREATE_CALLCLASS(CaptureGetStatus, SingleReplyCall);

#endif
3 changes: 3 additions & 0 deletions include/grpc/dp_grpc_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ enum dpgrpc_request_type {
DP_REQ_TYPE_ResetVni,
DP_REQ_TYPE_CaptureStart,
DP_REQ_TYPE_CaptureStop,
DP_REQ_TYPE_CaptureGetStatus,
};

// in sync with dpdk proto!
Expand Down Expand Up @@ -182,6 +183,7 @@ struct dpgrpc_capture {
uint32_t udp_src_port;
uint32_t udp_dst_port;
struct dpgrpc_capture_interface interfaces[DP_CAPTURE_MAX_PORT_NUM];
bool is_active;
};

struct dpgrpc_capture_stop {
Expand Down Expand Up @@ -265,6 +267,7 @@ struct dpgrpc_reply {
struct dpgrpc_vni_in_use vni_in_use;
struct dpgrpc_versions versions;
struct dpgrpc_capture_stop capture_stop;
struct dpgrpc_capture capture_get;
};
};

Expand Down
26 changes: 23 additions & 3 deletions proto/dpdk.proto
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ enum CaptureInterfaceType {
SINGLE_VF = 1;
}

enum OperationStatus {
ACTIVE = 0;
NOT_ACTIVE = 1;
}

//// STRUCTURES
message Empty {
}
Expand Down Expand Up @@ -532,19 +537,24 @@ message DeleteFirewallRuleResponse {

message CapturedInterface {
CaptureInterfaceType interface_type = 1;
bytes filter = 2;
oneof spec {
bytes vf_name = 2;
uint32 pf_index = 3;
bytes vf_name = 3;
uint32 pf_index = 4;
}
}

message CaptureStartRequest {
message CaptureConfig {
IpAddress sink_node_ip = 1;
uint32 udp_src_port = 2;
uint32 udp_dst_port = 3;
repeated CapturedInterface interfaces = 4;
}

message CaptureStartRequest {
CaptureConfig capture_config = 1;
}

message CaptureStartResponse {
Status status = 1;
}
Expand All @@ -557,6 +567,15 @@ message CaptureStopResponse {
uint32 stopped_interface_cnt = 2;
}

message CaptureGetStatusRequest {
}

message CaptureGetStatusResponse {
Status status = 1;
OperationStatus operation_status = 2;
CaptureConfig capture_config = 3;
}

service DPDKonmetal {
//// INITIALIZATION
// initialized indicates if the DPDK app has been initialized already, if so an UUID is returned.
Expand Down Expand Up @@ -648,4 +667,5 @@ service DPDKonmetal {
//// PACKET CAPTURE
rpc CaptureStart(CaptureStartRequest) returns (CaptureStartResponse) {}
rpc CaptureStop(CaptureStopRequest) returns (CaptureStopResponse) {}
rpc CaptureGetStatus(CaptureGetStatusRequest) returns (CaptureGetStatusResponse) {}
}
80 changes: 62 additions & 18 deletions src/grpc/dp_async_grpc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -552,46 +552,90 @@ void CaptureStopCall::ParseReply(struct dpgrpc_reply* reply)
reply_.set_stopped_interface_cnt((uint32_t)reply->capture_stop.port_cnt);
}

const char* CaptureGetStatusCall::FillRequest(__rte_unused struct dpgrpc_request* request)
{
DPGRPC_LOG_INFO("Getting packet capturing operation's status");

return NULL;
}
void CaptureGetStatusCall::ParseReply(struct dpgrpc_reply* reply)
{
const struct dpgrpc_capture &capture_get = reply->capture_get;
CaptureConfig *capture_config = new CaptureConfig();
CapturedInterface *grpc_iface;
char strbuf[INET6_ADDRSTRLEN];
IpAddress *sink_ip;

if (capture_get.is_active) {
reply_.set_operation_status(OperationStatus::ACTIVE);
capture_config->set_udp_src_port(capture_get.udp_src_port);
capture_config->set_udp_dst_port(capture_get.udp_dst_port);

sink_ip = new IpAddress();
inet_ntop(AF_INET6, capture_get.dst_addr6, strbuf, sizeof(strbuf));
sink_ip->set_address(strbuf);
sink_ip->set_ipver(IpVersion::IPV6);
capture_config->set_allocated_sink_node_ip(sink_ip);

for (int i = 0; i < capture_get.interface_count; ++i) {
grpc_iface = capture_config->add_interfaces();
switch (capture_get.interfaces[i].type) {
case DP_CAPTURE_IFACE_TYPE_SINGLE_PF:
grpc_iface->set_interface_type(CaptureInterfaceType::SINGLE_PF);
grpc_iface->set_pf_index(capture_get.interfaces[i].spec.pf_index);
break;
case DP_CAPTURE_IFACE_TYPE_SINGLE_VF:
grpc_iface->set_interface_type(CaptureInterfaceType::SINGLE_VF);
grpc_iface->set_vf_name(capture_get.interfaces[i].spec.iface_id);
break;
}
}
reply_.set_allocated_capture_config(capture_config);
} else {
reply_.set_operation_status(OperationStatus::NOT_ACTIVE);
}
}

const char* CaptureStartCall::FillRequest(struct dpgrpc_request* request)
{

DPGRPC_LOG_INFO("Starting packet capture",
DP_LOG_IPV6STR(request_.sink_node_ip().address().c_str()),
DP_LOG_PORT(request_.udp_src_port()),
DP_LOG_PORT(request_.udp_dst_port()));
DP_LOG_IPV6STR(request_.capture_config().sink_node_ip().address().c_str()),
DP_LOG_PORT(request_.capture_config().udp_src_port()),
DP_LOG_PORT(request_.capture_config().udp_dst_port()));

if (!GrpcConv::StrToIpv6(request_.sink_node_ip().address(), request->capture_start.dst_addr6))
return "Invalid sink_node_ip";
if (request_.udp_src_port() > UINT16_MAX)
if (request_.capture_config().udp_src_port() > UINT16_MAX)
return "Invalid udp_src_port";
if (request_.udp_dst_port() > UINT16_MAX)
if (request_.capture_config().udp_dst_port() > UINT16_MAX)
return "Invalid udp_dst_port";
if (!GrpcConv::StrToIpv6(request_.capture_config().sink_node_ip().address(), request->capture_start.dst_addr6))
return "Invalid sink_node_ip";

request->capture_start.udp_src_port = request_.udp_src_port();
request->capture_start.udp_dst_port = request_.udp_dst_port();
request->capture_start.udp_src_port = request_.capture_config().udp_src_port();
request->capture_start.udp_dst_port = request_.capture_config().udp_dst_port();

if (request_.interfaces_size() > DP_CAPTURE_MAX_PORT_NUM)
if (request_.capture_config().interfaces_size() > DP_CAPTURE_MAX_PORT_NUM)
return "Too many interfaces to be captured";

request->capture_start.interface_count = 0;
for (int i = 0; i < request_.interfaces_size(); ++i) {
if (!GrpcConv::GrpcToDpCaptureInterfaceType(request_.interfaces(i).interface_type(), &request->capture_start.interfaces[i].type)) {
for (int i = 0; i < request_.capture_config().interfaces_size(); ++i) {
if (!GrpcConv::GrpcToDpCaptureInterfaceType(request_.capture_config().interfaces(i).interface_type(), &request->capture_start.interfaces[i].type)) {
return "Invalid interfaces.interface_type";
}

switch (request->capture_start.interfaces[i].type) {
case DP_CAPTURE_IFACE_TYPE_SINGLE_VF:
DPGRPC_LOG_INFO("Set packet capture interface vf",
DP_LOG_PORT_TYPE(request_.interfaces(i).interface_type()),
DP_LOG_IFACE(request_.interfaces(i).vf_name().c_str()));
if (SNPRINTF_FAILED(request->capture_start.interfaces[i].spec.iface_id, request_.interfaces(i).vf_name()))
DP_LOG_PORT_TYPE(request_.capture_config().interfaces(i).interface_type()),
DP_LOG_IFACE(request_.capture_config().interfaces(i).vf_name().c_str()));
if (SNPRINTF_FAILED(request->capture_start.interfaces[i].spec.iface_id, request_.capture_config().interfaces(i).vf_name()))
return "Invalid interface_id";
break;
case DP_CAPTURE_IFACE_TYPE_SINGLE_PF:
DPGRPC_LOG_INFO("Set packet capture interface pf",
DP_LOG_PORT_TYPE(request_.interfaces(i).interface_type()),
DP_LOG_IFACE_INDEX(request_.interfaces(i).pf_index()));
request->capture_start.interfaces[i].spec.pf_index = request_.interfaces(i).pf_index();
DP_LOG_PORT_TYPE(request_.capture_config().interfaces(i).interface_type()),
DP_LOG_IFACE_INDEX(request_.capture_config().interfaces(i).pf_index()));
request->capture_start.interfaces[i].spec.pf_index = request_.capture_config().interfaces(i).pf_index();
break;
}

Expand Down
14 changes: 14 additions & 0 deletions src/grpc/dp_grpc_conv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,20 @@ bool GrpcToDpCaptureInterfaceType(const CaptureInterfaceType& grpc_type, enum dp
}
}

bool DpCaptureInterfaceTypeToGrpc(CaptureInterfaceType& grpc_type, enum dpgrpc_capture_iface_type dp_capture_iface_type)
{
switch (dp_capture_iface_type) {
case DP_CAPTURE_IFACE_TYPE_SINGLE_PF:
grpc_type = CaptureInterfaceType::SINGLE_PF;
return true;
case DP_CAPTURE_IFACE_TYPE_SINGLE_VF:
grpc_type = CaptureInterfaceType::SINGLE_VF;
return true;
default:
return false;
}
}

const char *Ipv4ToStr(uint32_t ipv4)
{
struct in_addr addr = {
Expand Down
40 changes: 40 additions & 0 deletions src/grpc/dp_grpc_impl.c
Original file line number Diff line number Diff line change
Expand Up @@ -947,6 +947,43 @@ static int dp_process_capture_stop(struct dp_grpc_responder *responder)
return DP_GRPC_OK;
}

static int dp_process_capture_get_status(struct dp_grpc_responder *responder)
{
struct dpgrpc_capture *reply = dp_grpc_single_reply(responder);
struct dp_ports *ports = get_dp_ports();
const struct dp_capture_hdr_config *capture_hdr_config = dp_get_capture_hdr_config();
int count = 0;

reply->is_active = dp_is_capture_enabled();

if (reply->is_active) {
DP_FOREACH_PORT(ports, port) {
if (port->allocated && port->captured) {
if (port->port_type == DP_PORT_PF) {
reply->interfaces[count].type = DP_CAPTURE_IFACE_TYPE_SINGLE_PF;
reply->interfaces[count].spec.pf_index = port->port_id == dp_port_get_pf0_id() ? 0 : 1;
} else {
reply->interfaces[count].type = DP_CAPTURE_IFACE_TYPE_SINGLE_VF;
memcpy(reply->interfaces[count].spec.iface_id, dp_get_vm_machineid(port->port_id), sizeof(port->port_name));
}
count++;
}
// it shouldnot never happen, but just in case
if (count >= DP_CAPTURE_MAX_PORT_NUM) {
DPS_LOG_ERR("Unexpected too many interfaces are captured");
return DP_GRPC_ERR_LIMIT_REACHED;
}
}
}

memcpy(reply->dst_addr6, capture_hdr_config->capture_node_ipv6_addr, sizeof(reply->dst_addr6));
reply->udp_src_port = capture_hdr_config->capture_udp_src_port;
reply->udp_dst_port = capture_hdr_config->capture_udp_dst_port;
reply->interface_count = count;

return DP_GRPC_OK;
}


void dp_process_request(struct rte_mbuf *m)
{
Expand Down Expand Up @@ -1074,6 +1111,9 @@ void dp_process_request(struct rte_mbuf *m)
case DP_REQ_TYPE_CaptureStop:
ret = dp_process_capture_stop(&responder);
break;
case DP_REQ_TYPE_CaptureGetStatus:
ret = dp_process_capture_get_status(&responder);
break;
// DP_REQ_TYPE_CheckInitialized is handled by the gRPC thread
default:
ret = DP_GRPC_ERR_BAD_REQUEST;
Expand Down
1 change: 1 addition & 0 deletions src/grpc/dp_grpc_service.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ void GRPCService::HandleRpcs()
new GetVersionCall();
new CaptureStartCall();
new CaptureStopCall();
new CaptureGetStatusCall();

while (cq_->Next(&tag, &ok) && ok) {
call = static_cast<BaseCall*>(tag);
Expand Down

0 comments on commit 7dd5333

Please sign in to comment.