diff --git a/docs/deployment/capture_offloaded_rx_pkts.md b/docs/deployment/capture_offloaded_rx_pkts.md index 6ed7a2983..227025a8c 100644 --- a/docs/deployment/capture_offloaded_rx_pkts.md +++ b/docs/deployment/capture_offloaded_rx_pkts.md @@ -1,5 +1,5 @@ # Feature: capture offloaded rx packets on interfaces -In offloaded mode, packets that are processed by hardware offloed rules cannot be seen anymore even on the software path. To increase the visibility of this type of traffic flows, we use special rte flow rules to instrument packet processing on hardware to duplicate and capture these packets on interfaces. +In offloaded mode, packets that are processed by hardware offload rules cannot be seen anymore even on the software path. To increase the visibility of this type of traffic flows, we use special rte flow rules to instrument packet processing on hardware to duplicate and capture these packets on interfaces. ## What can be achieved and what cannot Through tedious and complex experiment, the following features are identified and thus currently supported: @@ -19,7 +19,7 @@ Capturing must be started via dpservice-cli before the first packets of new flow ``` -./bin/dpservice-cli capture start --sink-node-ip= --udp-src-port= --udp-dst-port= --vf= --pf=0 +./bin/dpservice-cli capture start --sink-node-ip= --udp-src-port= --udp-dst-port= --vf= --pf=0 ``` for example: @@ -27,13 +27,13 @@ for example: ./bin/dpservice-cli capture start --sink-node-ip=abcd:efgh:1234:4321::1 --udp-src-port=3000 --udp-dst-port=3010 --vf=vm-1,vm-2 --pf=0 ``` -The captured packets will be transmitted back to the hypervisors interface (via router) in an encapped format, which is visible on pf0 interface using a regular tcpdump tool. For example, these packets can be dumped to a pcap file using a command: +The captured packets will be transmitted back in an encapped format to the interface (via router) of your selected sink machine, either the hypervisor where dp-service is running or a remote host. These packets are visible on physical interfaces using a regular tcpdump tool. For example, these packets can be dumped to a pcap file using a command: ``` sudo tcpdump -ni any udp dst port 3010 -w test.pcap ``` -The generated test.pcap file can be opened using Wireshark(graphic). As captured packets are encaped as UDP payload, this file can be firstly modified by removingß the first 62 bytes of all packets. +The generated test.pcap file can be opened using Wireshark(graphic). As captured packets are encaped as UDP payload, this file can be firstly modified by removing the first 62 bytes of all packets. ``` editcap -C 62 -F pcap test.pcap test_no_udp.pcap @@ -41,11 +41,16 @@ editcap -C 62 -F pcap test.pcap test_no_udp.pcap The resulted test_no_udp.pcap file can be recognized by wireshark. +The following command is used to stop capturing on all configured interfaces. Note that, to start capturing on a new set of interfaces, this stopping command has to be called first. +``` +/bin/dpservice-cli capture stop +``` + ## How offloaded packets are captured -Offloaded packets are captured by using special rte flow rules, especial the one that enables pkt sampling on the RX side of an interface. The captured packets are encapsulated by prepending extra headers. Despite of 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 following: +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: ``` -| Outter Ether header | Outter IPv6 header | UDP header | Captured Ether frame | +| Outer Ether header | Outer IPv6 header | UDP header | Captured Ether frame | ``` [Figure1](docs/sys_design/pkt_capture_flow_rules-VF.drawio.png) and [Figure2](docs/sys_design/pkt_capture_flow_rules-PF.drawio.png) illustrate the organization of flow rules for VF and PF. The differences between handling VF and PF are empirical. diff --git a/docs/sys_design/pkt_capture_flow_rules.drawio b/docs/sys_design/pkt_capture_flow_rules.drawio deleted file mode 100644 index b3f54612e..000000000 --- a/docs/sys_design/pkt_capture_flow_rules.drawio +++ /dev/null @@ -1,318 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/sys_design/pkt_capture_flow_rules-PF.drawio.png b/docs/sys_design/pkt_capture_flow_rules_PF.drawio.png similarity index 76% rename from docs/sys_design/pkt_capture_flow_rules-PF.drawio.png rename to docs/sys_design/pkt_capture_flow_rules_PF.drawio.png index 8933d6bfe..1b7e9ba3a 100644 Binary files a/docs/sys_design/pkt_capture_flow_rules-PF.drawio.png and b/docs/sys_design/pkt_capture_flow_rules_PF.drawio.png differ diff --git a/docs/sys_design/pkt_capture_flow_rules-VF.drawio.png b/docs/sys_design/pkt_capture_flow_rules_VF.drawio.png similarity index 75% rename from docs/sys_design/pkt_capture_flow_rules-VF.drawio.png rename to docs/sys_design/pkt_capture_flow_rules_VF.drawio.png index f5ac4ab8b..bf43fa20b 100644 Binary files a/docs/sys_design/pkt_capture_flow_rules-VF.drawio.png and b/docs/sys_design/pkt_capture_flow_rules_VF.drawio.png differ diff --git a/include/dp_error.h b/include/dp_error.h index ccb531b41..b94b2acd4 100644 --- a/include/dp_error.h +++ b/include/dp_error.h @@ -38,6 +38,11 @@ const char *dp_strerror_verbose(int error); ERR(ITERATOR, 207) \ ERR(OUT_OF_MEMORY, 208) \ ERR(LIMIT_REACHED, 209) \ + ERR(ALREADY_ACTIVE, 210) \ + ERR(NOT_ACTIVE, 211) \ + ERR(ROLLBACK, 212) \ + ERR(RTE_RULE_ADD, 213) \ + ERR(RTE_RULE_DEL, 214) \ /* Specific errors */ \ ERR(ROUTE_EXISTS, 301) \ ERR(ROUTE_NOT_FOUND, 302) \ @@ -61,16 +66,7 @@ const char *dp_strerror_verbose(int error); ERR(NO_BACKIP, 421) \ ERR(NO_LB, 422) \ ERR(NO_DROP_SUPPORT, 441) \ - ERR(CAPTURE_CANNOT_INIT, 451) \ - ERR(CAPTURE_INIT_CANNOT_ROLLBACK, 452) \ - ERR(CAPTURE_INIT_INVALID_PORT_ID, 453) \ - ERR(CAPTURE_INIT_PORT_NOT_ALLOC, 454) \ - ERR(CAPTURE_INIT_FAILED_SET_PF, 455) \ - ERR(CAPTURE_INIT_FAILED_SET_VF, 456) \ - ERR(CAPTURE_INIT_PORT_ALREADY_SET, 457) \ - ERR(CAPTURE_INIT_FAILED_DEL_DEFAULT, 458) \ - ERR(CAPTURE_INIT_FAILED_RECOVER, 459) \ - ERR(CAPTURE_CANNOT_STOP, 460) \ + #define _DP_GRPC_ERROR_ENUM(NAME, NUMBER) \ DP_GRPC_ERR_##NAME = _DP_GRPC_ERRCODES - NUMBER, diff --git a/include/grpc/dp_grpc_api.h b/include/grpc/dp_grpc_api.h index 3b7534bbb..0634041ae 100644 --- a/include/grpc/dp_grpc_api.h +++ b/include/grpc/dp_grpc_api.h @@ -173,22 +173,17 @@ struct dpgrpc_capture_interface { union { char iface_id[VM_IFACE_ID_MAX_LEN]; uint8_t pf_index; - } interface_info; + } spec; }; -struct dpgrpc_capture_config { +struct dpgrpc_capture { uint8_t dst_addr6[DP_VNF_IPV6_ADDR_SIZE]; - uint8_t filled_interface_info_count; + uint8_t interface_count; uint32_t udp_src_port; uint32_t udp_dst_port; struct dpgrpc_capture_interface interfaces[DP_CAPTURE_MAX_PORT_NUM]; }; -struct dpgrpc_capture_stat { - uint8_t status; - struct dpgrpc_capture_interface interface; -}; - struct dpgrpc_capture_stop { uint16_t port_cnt; }; @@ -231,7 +226,7 @@ struct dpgrpc_request { struct dpgrpc_vni vni_in_use; struct dpgrpc_vni vni_reset; struct dpgrpc_versions get_version; - struct dpgrpc_capture_config start_capture; + struct dpgrpc_capture start_capture; }; }; @@ -269,7 +264,6 @@ struct dpgrpc_reply { struct dpgrpc_fwrule_info fwrule; struct dpgrpc_vni_in_use vni_in_use; struct dpgrpc_versions versions; - struct dpgrpc_capture_stat capture_stat; struct dpgrpc_capture_stop capture_stop; }; }; diff --git a/include/monitoring/dp_monitoring.h b/include/monitoring/dp_monitoring.h index ebe9bd81a..ac17831d6 100644 --- a/include/monitoring/dp_monitoring.h +++ b/include/monitoring/dp_monitoring.h @@ -31,19 +31,21 @@ struct dp_event_msg { } event_entry; }; +struct dp_capture_hdr_config { + uint8_t capture_node_ipv6_addr[16]; + uint32_t capture_udp_src_port; + uint32_t capture_udp_dst_port; +}; + void dp_process_event_msg(struct rte_mbuf *m); -void dp_set_capture_node_ipv6_addr(uint8_t *addr); -void dp_set_capture_udp_src_port(uint32_t port); -void dp_set_capture_udp_dst_port(uint32_t port); -uint8_t *dp_get_capture_node_ipv6_addr(void); -uint16_t dp_get_capture_udp_src_port(void); -uint16_t dp_get_capture_udp_dst_port(void); +void dp_set_capture_hdr_config(uint8_t *addr, uint32_t udp_src_port, uint32_t udp_dst_port); +const struct dp_capture_hdr_config *dp_get_capture_hdr_config(void); void dp_set_capture_enabled(bool enabled); -bool dp_get_capture_enabled(void); +bool dp_is_capture_enabled(void); #ifdef __cplusplus } diff --git a/include/rte_flow/dp_rte_flow_capture.h b/include/rte_flow/dp_rte_flow_capture.h new file mode 100644 index 000000000..8dde6c10b --- /dev/null +++ b/include/rte_flow/dp_rte_flow_capture.h @@ -0,0 +1,32 @@ +#ifndef __INCLUDE_DP_RTE_FLOW_CAPTURE_H__ +#define __INCLUDE_DP_RTE_FLOW_CAPTURE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include "dp_port.h" + + +int dp_install_jump_rule_in_default_group(uint16_t port_id, uint32_t dst_group); + +int dp_enable_port_offload_pkt_capture(uint16_t port_id); +int dp_disable_port_offload_pkt_capture(uint16_t port_id); + +int dp_disable_pkt_capture_on_all_ifaces(void); + +int dp_destroy_default_flow(struct dp_port *port); + +void dp_configure_pkt_capture_action(uint8_t *encaped_mirror_hdr, + struct rte_flow_action_raw_encap *encap_action, + struct rte_flow_action_port_id *port_id_action, + struct rte_flow_action *sub_action); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/rte_flow/dp_rte_flow_init.h b/include/rte_flow/dp_rte_flow_init.h index 864010580..dad2f7255 100644 --- a/include/rte_flow/dp_rte_flow_init.h +++ b/include/rte_flow/dp_rte_flow_init.h @@ -12,23 +12,6 @@ extern "C" { int dp_install_isolated_mode_ipip(int port_id, uint8_t proto_id); -int dp_install_jump_rule_in_default_group(uint16_t port_id, uint32_t group_id); -int dp_install_default_rule_in_capture_group(uint16_t port_id, bool is_on); - - -int dp_turn_on_offload_pkt_capture_on_single_iface(uint16_t port_id); -int dp_turn_off_offload_pkt_capture_on_single_iface(uint16_t port_id); - -int dp_turn_on_offload_pkt_capture_on_all_ifaces(void); -int dp_turn_off_offload_pkt_capture_on_all_ifaces(void); - -int dp_destroy_default_flow(struct dp_port *port); - -void dp_configure_packet_capture_action(uint8_t *encaped_mirror_hdr, - struct rte_flow_action_raw_encap *encap_action, - struct rte_flow_action_port_id *port_id_action, - struct rte_flow_action *sub_action); - #ifdef ENABLE_VIRTSVC int dp_install_isolated_mode_virtsvc(int port_id, uint8_t proto_id, const uint8_t svc_ipv6[16], uint16_t svc_port); #endif diff --git a/proto/dpdk.proto b/proto/dpdk.proto index acc771f09..e52afb3c9 100644 --- a/proto/dpdk.proto +++ b/proto/dpdk.proto @@ -532,7 +532,7 @@ message DeleteFirewallRuleResponse { message CapturedInterface { CaptureInterfaceType interface_type = 1; - oneof interface_info { + oneof spec { bytes vf_name = 2; uint32 pf_index = 3; } @@ -554,7 +554,7 @@ message CaptureStopRequest { message CaptureStopResponse { Status status = 1; - uint32 captured_interface_cnt = 2; + uint32 stopped_interface_cnt = 2; } service DPDKonmetal { diff --git a/src/dp_port.c b/src/dp_port.c index eab9b6bb9..90ce313d4 100644 --- a/src/dp_port.c +++ b/src/dp_port.c @@ -13,6 +13,7 @@ #include "nodes/rx_node.h" #include "rte_flow/dp_rte_flow_init.h" #include "rte_flow/dp_rte_flow.h" +#include "rte_flow/dp_rte_flow_capture.h" #include "monitoring/dp_graphtrace.h" static const struct rte_eth_conf port_conf_default = { @@ -459,7 +460,6 @@ static int dp_install_vf_init_rte_rules(uint32_t port_id) { int ret; - // too long, thus using a ret variable ret = dp_install_jump_rule_in_default_group(port_id, DP_RTE_FLOW_VNET_GROUP); if (DP_FAILED(ret)) { DPS_LOG_ERR("Cannot install default jump rule", DP_LOG_PORTID(port_id), DP_LOG_RET(ret)); @@ -532,7 +532,6 @@ int dp_port_stop(uint16_t port_id) if (!port) return DP_ERROR; - // not really resolve the issue, but let's do it explicitly if (DP_FAILED(dp_destroy_default_flow(port))) return DP_ERROR; diff --git a/src/grpc/dp_async_grpc.cpp b/src/grpc/dp_async_grpc.cpp index e86c15ee8..b50a4ddff 100644 --- a/src/grpc/dp_async_grpc.cpp +++ b/src/grpc/dp_async_grpc.cpp @@ -543,19 +543,19 @@ void CreateNatCall::ParseReply(struct dpgrpc_reply* reply) const char* CaptureStopCall::FillRequest(__rte_unused struct dpgrpc_request* request) { - DPGRPC_LOG_INFO("Stop packet capture"); + DPGRPC_LOG_INFO("Stopping packet capture"); return NULL; } void CaptureStopCall::ParseReply(struct dpgrpc_reply* reply) { - reply_.set_captured_interface_cnt((uint32_t)reply->capture_stop.port_cnt); + reply_.set_stopped_interface_cnt((uint32_t)reply->capture_stop.port_cnt); } const char* CaptureStartCall::FillRequest(struct dpgrpc_request* request) { - DPGRPC_LOG_INFO("Start packet capture", + 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())); @@ -573,10 +573,10 @@ const char* CaptureStartCall::FillRequest(struct dpgrpc_request* request) if (request_.interfaces_size() > DP_CAPTURE_MAX_PORT_NUM) return "Too many interfaces to be captured"; - request->start_capture.filled_interface_info_count = 0; + request->start_capture.interface_count = 0; for (int i = 0; i < request_.interfaces_size(); ++i) { if (!GrpcConv::GrpcToDpCaptureInterfaceType(request_.interfaces(i).interface_type(), &request->start_capture.interfaces[i].type)) { - return "Invalid interface_type"; + return "Invalid interfaces.interface_type"; } switch (request->start_capture.interfaces[i].type) { @@ -584,23 +584,21 @@ const char* CaptureStartCall::FillRequest(struct dpgrpc_request* request) 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->start_capture.interfaces[i].interface_info.iface_id, request_.interfaces(i).vf_name())) + if (SNPRINTF_FAILED(request->start_capture.interfaces[i].spec.iface_id, request_.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())); - // TODO: maybe a validity check here for indexes - request->start_capture.interfaces[i].interface_info.pf_index = request_.interfaces(i).pf_index(); + request->start_capture.interfaces[i].spec.pf_index = request_.interfaces(i).pf_index(); break; } - request->start_capture.filled_interface_info_count++; + request->start_capture.interface_count++; } return NULL; } - void CaptureStartCall::ParseReply(__rte_unused struct dpgrpc_reply* reply) { } @@ -613,7 +611,6 @@ const char* GetNatCall::FillRequest(struct dpgrpc_request* request) return "Invalid interface_id"; return NULL; } - void GetNatCall::ParseReply(struct dpgrpc_reply* reply) { IpAddress *nat_ip; diff --git a/src/grpc/dp_grpc_conv.cpp b/src/grpc/dp_grpc_conv.cpp index e3e0fe7b3..15a44128c 100644 --- a/src/grpc/dp_grpc_conv.cpp +++ b/src/grpc/dp_grpc_conv.cpp @@ -108,7 +108,6 @@ bool GrpcToDpFwallPort(int32_t grpc_port, uint32_t *dp_port) return false; *dp_port = port; return true; - } bool GrpcToDpCaptureInterfaceType(const CaptureInterfaceType& grpc_type, enum dpgrpc_capture_iface_type *dp_capture_iface_type) diff --git a/src/grpc/dp_grpc_impl.c b/src/grpc/dp_grpc_impl.c index 3cf1466af..95ea65d27 100644 --- a/src/grpc/dp_grpc_impl.c +++ b/src/grpc/dp_grpc_impl.c @@ -17,7 +17,7 @@ #include "grpc/dp_grpc_api.h" #include "grpc/dp_grpc_responder.h" #include "monitoring/dp_monitoring.h" -#include "rte_flow/dp_rte_flow_init.h" +#include "rte_flow/dp_rte_flow_capture.h" static uint32_t pfx_counter = 0; @@ -886,41 +886,43 @@ static int dp_process_get_version(struct dp_grpc_responder *responder) static int dp_process_capture_start(struct dp_grpc_responder *responder) { - struct dpgrpc_capture_config *request = &responder->request.start_capture; - struct dpgrpc_capture_stat *reply = dp_grpc_single_reply(responder); - int port_id = -1, status = DP_GRPC_OK; + struct dpgrpc_capture *request = &responder->request.start_capture; + int port_id = -1; + int status = DP_GRPC_OK; - dp_set_capture_node_ipv6_addr(request->dst_addr6); - dp_set_capture_udp_src_port(request->udp_src_port); - dp_set_capture_udp_dst_port(request->udp_dst_port); + if (dp_is_capture_enabled()) + return DP_GRPC_ERR_ALREADY_ACTIVE; + dp_set_capture_hdr_config(request->dst_addr6, request->udp_src_port, request->udp_dst_port); dp_set_capture_enabled(true); - for (int i = 0; i < request->filled_interface_info_count; ++i) { + for (int i = 0; i < request->interface_count; ++i) { switch (request->interfaces[i].type) { case DP_CAPTURE_IFACE_TYPE_SINGLE_VF: - port_id = dp_get_portid_with_vm_handle(request->interfaces[i].interface_info.iface_id); + port_id = dp_get_portid_with_vm_handle(request->interfaces[i].spec.iface_id); break; case DP_CAPTURE_IFACE_TYPE_SINGLE_PF: - //index check is done on the grpc client side - port_id = request->interfaces[i].interface_info.pf_index == 0 ? dp_port_get_pf0_id() : dp_port_get_pf1_id(); + if (request->interfaces[i].spec.pf_index >= DP_MAX_PF_PORTS) + return DP_GRPC_ERR_NOT_FOUND; + port_id = request->interfaces[i].spec.pf_index == 0 ? dp_port_get_pf0_id() : dp_port_get_pf1_id(); break; } if (DP_FAILED(port_id)) { - reply->interface = request->interfaces[i]; - status = DP_GRPC_ERR_CAPTURE_INIT_INVALID_PORT_ID; + DPS_LOG_WARNING("Got invalid port id when initializing capturing", DP_LOG_PORTID(port_id)); + status = DP_GRPC_ERR_NOT_FOUND; break; } - status = dp_turn_on_offload_pkt_capture_on_single_iface(port_id); - if (DP_FAILED(status)) - break; // stop continuing to turn on offload capture on other interfaces + status = dp_enable_port_offload_pkt_capture(port_id); + if (DP_FAILED(status)) // stop continuing to turn on offload capture on other interfaces, if capturing init failed on any port. abort and rollback. + break; } + // try to turn off capture on all interfaces if any of them failed to turn on if (DP_FAILED(status)) { - if (DP_FAILED(dp_turn_off_offload_pkt_capture_on_all_ifaces())) // try to turn off capture on all interfaces - status = DP_GRPC_ERR_CAPTURE_INIT_CANNOT_ROLLBACK; + if (DP_FAILED(dp_disable_pkt_capture_on_all_ifaces())) + status = DP_GRPC_ERR_ROLLBACK; } return status; @@ -929,10 +931,16 @@ static int dp_process_capture_start(struct dp_grpc_responder *responder) static int dp_process_capture_stop(struct dp_grpc_responder *responder) { struct dpgrpc_capture_stop *reply = dp_grpc_single_reply(responder); - int ret = dp_turn_off_offload_pkt_capture_on_all_ifaces(); + int ret; - if (DP_FAILED(ret)) - return DP_GRPC_ERR_CAPTURE_CANNOT_STOP; + if (!dp_is_capture_enabled()) + return DP_GRPC_ERR_NOT_ACTIVE; + + ret = dp_disable_pkt_capture_on_all_ifaces(); + if (DP_FAILED(ret)) { + DPS_LOG_ERR("Failed to stop packet capture on all interfaces"); // it is problematic that we cannot rollback here + return ret; + } reply->port_cnt = ret; return DP_GRPC_OK; @@ -1072,7 +1080,7 @@ void dp_process_request(struct rte_mbuf *m) } if (DP_FAILED(ret)) { - // as gRPC errors are explicitely defined due to API reasons + // as gRPC errors are explicitly defined due to API reasons // extract the proper value from the standard (negative) retvals ret = dp_errcode_to_grpc_errcode(ret); DPGRPC_LOG_WARNING("Failed request", DP_LOG_GRPCREQUEST(responder.request.type), DP_LOG_GRPCRET(ret)); diff --git a/src/meson.build b/src/meson.build index b9ab09b1e..915866359 100644 --- a/src/meson.build +++ b/src/meson.build @@ -33,6 +33,7 @@ dp_sources = [ 'rte_flow/dp_rte_flow.c', 'rte_flow/dp_rte_flow_init.c', 'rte_flow/dp_rte_flow_traffic_forward.c', + 'rte_flow/dp_rte_flow_capture.c', 'dp_argparse.c', 'dp_conf.c', 'dp_error.c', diff --git a/src/monitoring/dp_graphtrace.c b/src/monitoring/dp_graphtrace.c index 4574efb31..77b8052e8 100644 --- a/src/monitoring/dp_graphtrace.c +++ b/src/monitoring/dp_graphtrace.c @@ -20,7 +20,6 @@ int _dp_graphtrace_flags; bool _dp_graphtrace_enabled = false; static struct dp_graphtrace graphtrace; -static bool offload_enabled; static int dp_graphtrace_init_memzone(void) { @@ -44,8 +43,6 @@ static int dp_graphtrace_init_memzone(void) return DP_ERROR; } - offload_enabled = dp_conf_is_offload_enabled(); - return DP_OK; } diff --git a/src/monitoring/dp_monitoring.c b/src/monitoring/dp_monitoring.c index 9f2e11d2f..01cdcb186 100644 --- a/src/monitoring/dp_monitoring.c +++ b/src/monitoring/dp_monitoring.c @@ -2,9 +2,8 @@ #include "dp_log.h" #include "monitoring/dp_event.h" -static uint8_t capture_node_ipv6_addr[16] = {0}; -static uint32_t capture_udp_src_port = 0; -static uint32_t capture_udp_dst_port = 0; + +static struct dp_capture_hdr_config capture_hdr_config = {0}; static bool capture_enabled = false; @@ -24,34 +23,16 @@ void dp_process_event_msg(struct rte_mbuf *m) rte_pktmbuf_free(m); } -void dp_set_capture_node_ipv6_addr(uint8_t *addr) -{ - rte_memcpy(capture_node_ipv6_addr, addr, sizeof(capture_node_ipv6_addr)); -} - -void dp_set_capture_udp_src_port(uint32_t port) -{ - capture_udp_src_port = port; -} - -void dp_set_capture_udp_dst_port(uint32_t port) -{ - capture_udp_dst_port = port; -} - -uint8_t *dp_get_capture_node_ipv6_addr(void) -{ - return capture_node_ipv6_addr; -} - -uint16_t dp_get_capture_udp_src_port(void) +void dp_set_capture_hdr_config(uint8_t *addr, uint32_t udp_src_port, uint32_t udp_dst_port) { - return (uint16_t)capture_udp_src_port; + rte_memcpy(capture_hdr_config.capture_node_ipv6_addr, addr, sizeof(capture_hdr_config.capture_node_ipv6_addr)); + capture_hdr_config.capture_udp_src_port = udp_src_port; + capture_hdr_config.capture_udp_dst_port = udp_dst_port; } -uint16_t dp_get_capture_udp_dst_port(void) +const struct dp_capture_hdr_config *dp_get_capture_hdr_config(void) { - return (uint16_t)capture_udp_dst_port; + return &capture_hdr_config; } void dp_set_capture_enabled(bool enabled) @@ -59,7 +40,7 @@ void dp_set_capture_enabled(bool enabled) capture_enabled = enabled; } -bool dp_get_capture_enabled(void) +bool dp_is_capture_enabled(void) { return capture_enabled; } diff --git a/src/nodes/conntrack_node.c b/src/nodes/conntrack_node.c index 1018648b7..7a7822817 100644 --- a/src/nodes/conntrack_node.c +++ b/src/nodes/conntrack_node.c @@ -51,7 +51,6 @@ static __rte_always_inline rte_edge_t get_next_index(__rte_unused struct rte_nod { struct dp_flow *df = dp_get_flow_ptr(m); struct rte_ipv4_hdr *ipv4_hdr = dp_get_ipv4_hdr(m); - int ret; dp_extract_ipv4_header(df, ipv4_hdr); @@ -68,8 +67,7 @@ static __rte_always_inline rte_edge_t get_next_index(__rte_unused struct rte_nod || df->l4_type == IPPROTO_UDP || df->l4_type == IPPROTO_ICMP ) { - ret = dp_cntrack_handle(m, df); - if (DP_FAILED(ret)) + if (DP_FAILED(dp_cntrack_handle(m, df))) return CONNTRACK_NEXT_DROP; } else { return CONNTRACK_NEXT_DROP; diff --git a/src/nodes/rx_node.c b/src/nodes/rx_node.c index 43e3719f2..041ee0f1f 100644 --- a/src/nodes/rx_node.c +++ b/src/nodes/rx_node.c @@ -19,7 +19,6 @@ struct rx_node_ctx { uint16_t port_id; uint16_t queue_id; bool enabled; - bool is_pf; }; static_assert(sizeof(struct rx_node_ctx) <= RTE_NODE_CTX_SZ, "Rx node context will not fit into the node"); @@ -79,9 +78,6 @@ static int rx_node_init(const struct rte_graph *graph, struct rte_node *node) // save pointer to this node's context for enabling/disabling node_contexts[port_id] = ctx; - - - ctx->is_pf = dp_port_is_pf(port_id); ctx->port_id = port_id; ctx->queue_id = graph->id; ctx->enabled = false; diff --git a/src/rte_flow/dp_rte_flow_capture.c b/src/rte_flow/dp_rte_flow_capture.c new file mode 100644 index 000000000..387867612 --- /dev/null +++ b/src/rte_flow/dp_rte_flow_capture.c @@ -0,0 +1,316 @@ +#include "rte_flow/dp_rte_flow_capture.h" + +#include "dp_error.h" +#include "dp_log.h" +#include "rte_flow/dp_rte_flow_helpers.h" +#include "dp_conf.h" +#include "monitoring/dp_monitoring.h" + +#define DP_RTE_FLOW_CAPTURE_PKT_HDR_SIZE (sizeof(struct rte_ether_hdr) \ + + sizeof(struct rte_ipv6_hdr) \ + + sizeof(struct rte_udp_hdr)) + +// this attribute value is used to install a flow rule in the default group of a VF to switch between the capturing group and vnet group +static const struct rte_flow_attr dp_flow_attr_default_jump_ingress = { + .group = DP_RTE_FLOW_DEFAULT_GROUP, + .priority = 0, + .ingress = 0, + .egress = 0, + .transfer = 1, +}; + +// this attribute value is used to install the flow capturing rule into the capturing group +// transfer flag is set to allow the port action +static const struct rte_flow_attr dp_flow_attr_default_capture_ingress = { + .group = DP_RTE_FLOW_CAPTURE_GROUP, + .priority = 0, + .ingress = 0, + .egress = 0, + .transfer = 1, +}; + +int dp_install_jump_rule_in_default_group(uint16_t port_id, uint32_t dst_group) +{ + struct rte_flow_item pattern[2]; // first is a NULL ethernet header matching, second is the end + int pattern_cnt = 0; + + // jump action from default group to capturing group + struct rte_flow_action_jump jump_action; // #1 + struct rte_flow_action action[2]; // + end + int action_cnt = 0; + + struct rte_flow *flow; + struct dp_port *port; + + port = dp_port_get(port_id); + if (!port) + return DP_GRPC_ERR_NOT_FOUND; + + // all ethernet packets + dp_set_eth_match_all_item(&pattern[pattern_cnt++]); + dp_set_end_flow_item(&pattern[pattern_cnt++]); + + // create actions that jump from the default group + // create jump action + dp_set_jump_group_action(&action[action_cnt++], &jump_action, dst_group); + + // end actions + dp_set_end_action(&action[action_cnt++]); + + // validate and install flow rule + flow = dp_install_rte_flow(port_id, &dp_flow_attr_default_jump_ingress, pattern, action); + if (!flow) + return DP_ERROR; + + port->default_jump_flow = flow; + + DPS_LOG_DEBUG("Installed the default jumping flow rule that destinated to group", DP_LOG_PORTID(port_id), DP_LOG_RTE_GROUP(dst_group)); + return DP_OK; +} + +void dp_configure_pkt_capture_action(uint8_t *encaped_mirror_hdr, + struct rte_flow_action_raw_encap *encap_action, + struct rte_flow_action_port_id *port_id_action, + struct rte_flow_action *sub_action) +{ + struct rte_ether_hdr *encap_eth_hdr = (struct rte_ether_hdr *)encaped_mirror_hdr; + struct rte_ipv6_hdr *new_ipv6_hdr = (struct rte_ipv6_hdr *)(&encaped_mirror_hdr[sizeof(struct rte_ether_hdr)]); + struct rte_udp_hdr *udp_hdr = (struct rte_udp_hdr *)(&encaped_mirror_hdr[sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv6_hdr)]); + int sub_action_cnt = 0; + uint16_t outgoing_port_id = dp_port_get_pf0_id(); + const struct dp_capture_hdr_config *capture_hdr_config = dp_get_capture_hdr_config(); + + rte_ether_addr_copy(dp_get_neigh_mac(outgoing_port_id), &encap_eth_hdr->dst_addr); + rte_ether_addr_copy(dp_get_mac(outgoing_port_id), &encap_eth_hdr->src_addr); + encap_eth_hdr->ether_type = htons(RTE_ETHER_TYPE_IPV6); + + rte_memcpy(new_ipv6_hdr->src_addr, dp_conf_get_underlay_ip(), sizeof(new_ipv6_hdr->src_addr)); + rte_memcpy(new_ipv6_hdr->dst_addr, capture_hdr_config->capture_node_ipv6_addr, sizeof(new_ipv6_hdr->dst_addr)); + new_ipv6_hdr->vtc_flow = htonl(DP_IP6_VTC_FLOW); + new_ipv6_hdr->payload_len = 0; + new_ipv6_hdr->proto = DP_IP_PROTO_UDP; + new_ipv6_hdr->hop_limits = DP_IP6_HOP_LIMIT; + + + udp_hdr->dst_port = htons(capture_hdr_config->capture_udp_dst_port); + udp_hdr->src_port = htons(capture_hdr_config->capture_udp_src_port); + udp_hdr->dgram_cksum = 0; + + dp_set_raw_encap_action(&sub_action[sub_action_cnt++], encap_action, encaped_mirror_hdr, DP_RTE_FLOW_CAPTURE_PKT_HDR_SIZE); + dp_set_send_to_port_action(&sub_action[sub_action_cnt++], port_id_action, outgoing_port_id); // must be a pf port here + dp_set_end_action(&sub_action[sub_action_cnt++]); +} + + +static int dp_install_default_rule_in_capture_group(uint16_t port_id, bool capture_on) +{ + + struct rte_flow_item pattern[2]; // first is a NULL ethernet header matching, second is the end + int pattern_cnt = 0; + + struct rte_flow_action_sample sample_action; // #1 + struct rte_flow_action_jump jump_action; // #2 + struct rte_flow_action action[3]; // + end + int action_cnt = 0; + + struct rte_flow_action_raw_encap encap_action; // #1 + struct rte_flow_action_port_id port_id_action; // #2 + struct rte_flow_action sub_action[3]; // + end + + struct rte_flow *flow; + struct dp_port *port; + uint8_t raw_encap_hdr[DP_RTE_FLOW_CAPTURE_PKT_HDR_SIZE]; + + port = dp_port_get(port_id); + if (!port) + return DP_GRPC_ERR_NOT_FOUND; + + // all ethernet packets + dp_set_eth_match_all_item(&pattern[pattern_cnt++]); + dp_set_end_flow_item(&pattern[pattern_cnt++]); + + // create actions + // create sampling action + if (capture_on) { + dp_configure_pkt_capture_action(raw_encap_hdr, &encap_action, &port_id_action, sub_action); + dp_set_sample_action(&action[action_cnt++], &sample_action, 1, sub_action); // sampling with a ratio less than 1 is not allowed in the eSwitch domain + } + + // create jump group action + dp_set_jump_group_action(&action[action_cnt++], &jump_action, DP_RTE_FLOW_VNET_GROUP); // jump to group DP_RTE_FLOW_VNET_GROUP + + // end actions + dp_set_end_action(&action[action_cnt++]); + + // validate and install flow rule + flow = dp_install_rte_flow(port_id, &dp_flow_attr_default_capture_ingress, pattern, action); + if (!flow) { + DPS_LOG_WARNING("Failed to install default monitoring flow rule", DP_LOG_PORTID(port_id)); + return DP_ERROR; + } + + port->default_capture_flow = flow; + + DPS_LOG_DEBUG("Installed the default monitoring flow rule", DP_LOG_PORTID(port_id)); + return DP_OK; +} + + +int dp_destroy_default_flow(struct dp_port *port) +{ + struct rte_flow_error error; + int ret; + + if (port->default_jump_flow) { + ret = rte_flow_destroy(port->port_id, port->default_jump_flow, &error); + if (DP_FAILED(ret)) { + DPS_LOG_WARNING("Failed to destroy default jump flow", DP_LOG_PORTID(port->port_id), DP_LOG_RET(ret)); + return DP_ERROR; + } + } + + if (port->default_capture_flow) { + ret = rte_flow_destroy(port->port_id, port->default_capture_flow, &error); + if (DP_FAILED(ret)) { + DPS_LOG_WARNING("Failed to destroy default capture flow", DP_LOG_PORTID(port->port_id), DP_LOG_RET(ret)); + return DP_ERROR; + } + } + + return DP_OK; +} + +static int dp_install_pf_default_flow(struct dp_port *port, bool capture_on) +{ + int ret; + + ret = dp_install_default_rule_in_capture_group(port->port_id, capture_on); + if (DP_FAILED(ret)) { + DPS_LOG_WARNING("Failed to install default flow", DP_LOG_PORTID(port->port_id), DP_LOG_RET(ret)); + return DP_ERROR; + } + + return DP_OK; +} + +static int dp_install_vf_default_jump_flow(struct dp_port *port, uint32_t dst_group) +{ + int ret; + + ret = dp_install_jump_rule_in_default_group(port->port_id, dst_group); + if (DP_FAILED(ret)) { + DPS_LOG_WARNING("Failed to install default jump flow", DP_LOG_PORTID(port->port_id), DP_LOG_RET(ret)); + return DP_ERROR; + } + + return DP_OK; +} + +static int dp_install_vf_default_capture_flow(struct dp_port *port) +{ + int ret; + + ret = dp_install_default_rule_in_capture_group(port->port_id, true); + if (DP_FAILED(ret)) { + DPS_LOG_WARNING("Failed to install default capture flow", DP_LOG_PORTID(port->port_id), DP_LOG_RET(ret)); + return DP_ERROR; + } + + return DP_OK; +} + +static int dp_turn_on_offload_pkt_capture(struct dp_port *port) +{ + if (!port || !port->allocated) + return DP_GRPC_ERR_NOT_FOUND; + + if (port->captured) + return DP_GRPC_ERR_ALREADY_ACTIVE; + + if (DP_FAILED(dp_destroy_default_flow(port))) + return DP_GRPC_ERR_RTE_RULE_DEL; + + switch (port->port_type) { + case DP_PORT_PF: + if (DP_FAILED(dp_install_pf_default_flow(port, true))) + return DP_GRPC_ERR_RTE_RULE_ADD; + break; + case DP_PORT_VF: + if (DP_FAILED(dp_install_vf_default_jump_flow(port, DP_RTE_FLOW_CAPTURE_GROUP))) + return DP_GRPC_ERR_RTE_RULE_ADD; + // rollback flow rules if failed on the second one for VF. + if (DP_FAILED(dp_install_vf_default_capture_flow(port))) { + if (DP_FAILED(dp_destroy_default_flow(port))) { + DPS_LOG_ERR("Failed to recover from turning capturing on by destroying previously installed default rule", DP_LOG_PORTID(port->port_id)); + return DP_GRPC_ERR_ROLLBACK; + } + if (DP_FAILED(dp_install_vf_default_jump_flow(port, DP_RTE_FLOW_VNET_GROUP))) { + DPS_LOG_ERR("Failed to recover from turning capturing on by installing default jump rule to the vnet group", DP_LOG_PORTID(port->port_id)); + return DP_GRPC_ERR_ROLLBACK; + } + return DP_GRPC_ERR_RTE_RULE_ADD; + } + break; + } + + port->captured = true; + return DP_GRPC_OK; +} + +static int dp_turn_off_offload_pkt_capture(struct dp_port *port) +{ + if (!port->allocated || !port->captured) + return DP_OK; + + if (DP_FAILED(dp_destroy_default_flow(port))) + return DP_GRPC_ERR_RTE_RULE_DEL; + + switch (port->port_type) { + case DP_PORT_PF: + if (DP_FAILED(dp_install_pf_default_flow(port, false))) + return DP_GRPC_ERR_RTE_RULE_ADD; + break; + case DP_PORT_VF: + if (DP_FAILED(dp_install_vf_default_jump_flow(port, DP_RTE_FLOW_VNET_GROUP))) { + // rollback does not make sense here, but rather to report the error. because the default operation should be without capturing. + DPS_LOG_ERR("Failed to turn capturing off by installing default jump rule to the vnet group on vf", DP_LOG_PORTID(port->port_id)); + return DP_GRPC_ERR_RTE_RULE_ADD; + } + + break; + } + + port->captured = false; + return DP_OK; +} + +int dp_enable_port_offload_pkt_capture(uint16_t port_id) +{ + struct dp_port *port = dp_port_get(port_id); + + return dp_turn_on_offload_pkt_capture(port); +} + +int dp_disable_port_offload_pkt_capture(uint16_t port_id) +{ + struct dp_port *port = dp_port_get(port_id); + + return dp_turn_off_offload_pkt_capture(port); +} + +int dp_disable_pkt_capture_on_all_ifaces(void) +{ + struct dp_ports *ports = get_dp_ports(); + int count = 0; + int ret; + + DP_FOREACH_PORT(ports, port) { + if (port->captured) { + ret = dp_turn_off_offload_pkt_capture(port); + if (DP_FAILED(ret)) + return ret; + count++; + } + } + return count; +} diff --git a/src/rte_flow/dp_rte_flow_init.c b/src/rte_flow/dp_rte_flow_init.c index 440461094..e16f052c8 100644 --- a/src/rte_flow/dp_rte_flow_init.c +++ b/src/rte_flow/dp_rte_flow_init.c @@ -18,24 +18,6 @@ static const struct rte_flow_attr dp_flow_attr_prio_ingress = { .transfer = 0, }; -// it is used to install a flow rule in the default group of a VF to switch between the capturing group and vnet group -static const struct rte_flow_attr dp_flow_attr_default_jump_ingress = { - .group = DP_RTE_FLOW_DEFAULT_GROUP, - .priority = 0, - .ingress = 0, - .egress = 0, - .transfer = 1, -}; - -// it is used to install the flow capturing rule into the capturing group -// transfer flag is set to allow the port action -static const struct rte_flow_attr dp_flow_attr_default_capture_ingress = { - .group = DP_RTE_FLOW_CAPTURE_GROUP, - .priority = 0, - .ingress = 0, - .egress = 0, - .transfer = 1, -}; int dp_install_isolated_mode_ipip(int port_id, uint8_t proto_id) { @@ -63,293 +45,6 @@ int dp_install_isolated_mode_ipip(int port_id, uint8_t proto_id) return DP_OK; } - -int dp_install_jump_rule_in_default_group(uint16_t port_id, uint32_t dst_group) -{ - struct rte_flow_item pattern[2]; // first is a NULL ethernet header matching, second is the end - int pattern_cnt = 0; - - // jump action from default group to capturing group - struct rte_flow_action_jump jump_action; // #1 - struct rte_flow_action action[2]; // + end - int action_cnt = 0; - - struct rte_flow *flow; - struct dp_port *port = dp_port_get_vf(port_id); - - // all ethernet packets - dp_set_eth_match_all_item(&pattern[pattern_cnt++]); - dp_set_end_flow_item(&pattern[pattern_cnt++]); - - // create actions that jump from the default group - // create jump action - dp_set_jump_group_action(&action[action_cnt++], &jump_action, dst_group); - - // end actions - dp_set_end_action(&action[action_cnt++]); - - // validate and install flow rule - flow = dp_install_rte_flow(port_id, &dp_flow_attr_default_jump_ingress, pattern, action); - - if (!flow) - return DP_ERROR; - - port->default_jump_flow = flow; - - DPS_LOG_DEBUG("Installed the default jumping flow rule that destinated to group", DP_LOG_PORTID(port_id), DP_LOG_RTE_GROUP(dst_group)); - return DP_OK; -} - -void dp_configure_packet_capture_action(uint8_t *encaped_mirror_hdr, - struct rte_flow_action_raw_encap *encap_action, - struct rte_flow_action_port_id *port_id_action, - struct rte_flow_action *sub_action) -{ - struct rte_ether_hdr *encap_eth_hdr = (struct rte_ether_hdr *)encaped_mirror_hdr; - struct rte_ipv6_hdr *new_ipv6_hdr = (struct rte_ipv6_hdr *)(&encaped_mirror_hdr[sizeof(struct rte_ether_hdr)]); - struct rte_udp_hdr *udp_hdr = (struct rte_udp_hdr *)(&encaped_mirror_hdr[sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv6_hdr)]); - int sub_action_cnt = 0; - - rte_ether_addr_copy(dp_get_neigh_mac(0), &encap_eth_hdr->dst_addr); - rte_ether_addr_copy(dp_get_mac(0), &encap_eth_hdr->src_addr); - encap_eth_hdr->ether_type = htons(RTE_ETHER_TYPE_IPV6); - - rte_memcpy(new_ipv6_hdr->src_addr, dp_conf_get_underlay_ip(), sizeof(new_ipv6_hdr->src_addr)); - rte_memcpy(new_ipv6_hdr->dst_addr, dp_get_capture_node_ipv6_addr(), sizeof(new_ipv6_hdr->dst_addr)); - new_ipv6_hdr->vtc_flow = htonl(DP_IP6_VTC_FLOW); - new_ipv6_hdr->payload_len = 0; - new_ipv6_hdr->proto = DP_IP_PROTO_UDP; - new_ipv6_hdr->hop_limits = DP_IP6_HOP_LIMIT; - - - udp_hdr->dst_port = htons(dp_get_capture_udp_dst_port()); - udp_hdr->src_port = htons(dp_get_capture_udp_src_port()); - udp_hdr->dgram_cksum = 0; - - dp_set_raw_encap_action(&sub_action[sub_action_cnt++], encap_action, encaped_mirror_hdr, DP_RTE_FLOW_CAPTURE_PKT_HDR_SIZE); - dp_set_send_to_port_action(&sub_action[sub_action_cnt++], port_id_action, dp_port_get_pf0_id()); // must be a pf port here - dp_set_end_action(&sub_action[sub_action_cnt++]); -} - - -int dp_install_default_rule_in_capture_group(uint16_t port_id, bool is_on) -{ - - struct rte_flow_item pattern[2]; // first is a NULL ethernet header matching, second is the end - int pattern_cnt = 0; - - struct rte_flow_action_sample sample_action; // 1 - struct rte_flow_action_jump jump_action; // 2 - struct rte_flow_action action[3]; // + end - int action_cnt = 0; - - struct rte_flow_action_raw_encap encap_action; // 1 - struct rte_flow_action_port_id port_id_action; // 2 - struct rte_flow_action sub_action[3]; - - struct rte_flow *flow; - struct dp_port *port = dp_port_get(port_id); - uint8_t raw_encap_hdr[DP_RTE_FLOW_CAPTURE_PKT_HDR_SIZE]; - - // all ethernet packets - dp_set_eth_match_all_item(&pattern[pattern_cnt++]); - dp_set_end_flow_item(&pattern[pattern_cnt++]); - - // create actions - // create sampling action - if (is_on) { - dp_configure_packet_capture_action(raw_encap_hdr, &encap_action, &port_id_action, sub_action); - dp_set_sample_action(&action[action_cnt++], &sample_action, 1, sub_action); // mirror all packets, without explicite sub sample action - } - - // create jump group action - dp_set_jump_group_action(&action[action_cnt++], &jump_action, DP_RTE_FLOW_VNET_GROUP); // jump to group DP_RTE_FLOW_VNET_GROUP - - // end actions - dp_set_end_action(&action[action_cnt++]); - - // validate and install flow rule - flow = dp_install_rte_flow(port_id, &dp_flow_attr_default_capture_ingress, pattern, action); - - if (!flow) { - DPS_LOG_DEBUG("Failed to install default monitoring flow rule on port %d \n", DP_LOG_PORTID(port_id)); - return DP_ERROR; - } - - port->default_capture_flow = flow; - - DPS_LOG_DEBUG("Installed the default monitoring flow rule", DP_LOG_PORTID(port_id)); - return DP_OK; -} - - -int dp_destroy_default_flow(struct dp_port *port) -{ - struct rte_flow_error error; - int ret; - - if (port->default_jump_flow) { - ret = rte_flow_destroy(port->port_id, port->default_jump_flow, &error); - - if (DP_FAILED(ret)) { - DPS_LOG_WARNING("Failed to destroy default jump flow", DP_LOG_PORTID(port->port_id), DP_LOG_RET(ret)); - return DP_ERROR; - } - } - - if (port->default_capture_flow) { - ret = rte_flow_destroy(port->port_id, port->default_capture_flow, &error); - - if (DP_FAILED(ret)) { - DPS_LOG_WARNING("Failed to destroy default capture flow", DP_LOG_PORTID(port->port_id), DP_LOG_RET(ret)); - return DP_ERROR; - } - } - - return DP_OK; -} - -static int dp_install_pf_default_flow(struct dp_port *port, bool is_on) -{ - int ret; - - ret = dp_install_default_rule_in_capture_group(port->port_id, is_on); - if (DP_FAILED(ret)) { - DPS_LOG_WARNING("Failed to install default flow", DP_LOG_PORTID(port->port_id), DP_LOG_RET(ret)); - return DP_ERROR; - } - - return DP_OK; -} - -static int dp_install_vf_default_jump_flow(struct dp_port *port, uint32_t dst_group) -{ - int ret; - - ret = dp_install_jump_rule_in_default_group(port->port_id, dst_group); - if (DP_FAILED(ret)) { - DPS_LOG_WARNING("Failed to install default jump flow", DP_LOG_PORTID(port->port_id), DP_LOG_RET(ret)); - return DP_ERROR; - } - - return DP_OK; -} - -static int dp_install_vf_default_capture_flow(struct dp_port *port) -{ - int ret; - - ret = dp_install_default_rule_in_capture_group(port->port_id, true); - if (DP_FAILED(ret)) { - DPS_LOG_WARNING("Failed to install default capture flow", DP_LOG_PORTID(port->port_id), DP_LOG_RET(ret)); - return DP_ERROR; - } - - return DP_OK; -} - -static int dp_turn_on_offload_pkt_capture(struct dp_port *port) -{ - if (!port->allocated) - return DP_GRPC_ERR_CAPTURE_INIT_PORT_NOT_ALLOC; - - if (port->captured) - return DP_GRPC_ERR_CAPTURE_INIT_PORT_ALREADY_SET; - - if (DP_FAILED(dp_destroy_default_flow(port))) - return DP_GRPC_ERR_CAPTURE_INIT_FAILED_DEL_DEFAULT; - - switch (port->port_type) { - case DP_PORT_PF: - if (DP_FAILED(dp_install_pf_default_flow(port, true))) - return DP_GRPC_ERR_CAPTURE_INIT_FAILED_SET_PF; - break; - case DP_PORT_VF: - if (DP_FAILED(dp_install_vf_default_jump_flow(port, DP_RTE_FLOW_CAPTURE_GROUP))) - return DP_GRPC_ERR_CAPTURE_INIT_FAILED_SET_VF; - // rollback flow rules if failed on the second one for VF. - if (DP_FAILED(dp_install_vf_default_capture_flow(port))) { - if (DP_FAILED(dp_destroy_default_flow(port))) { - DPS_LOG_ERR("Failed to recover from turning capturing on by destroying previously installed default rule", DP_LOG_PORTID(port->port_id)); - return DP_GRPC_ERR_CAPTURE_INIT_FAILED_RECOVER; - } - if (DP_FAILED(dp_install_vf_default_jump_flow(port, DP_RTE_FLOW_VNET_GROUP))) { - DPS_LOG_ERR("Failed to recover from turning capturing on by installing default jump rule to the vnet group", DP_LOG_PORTID(port->port_id)); - return DP_GRPC_ERR_CAPTURE_INIT_FAILED_RECOVER; - } - return DP_GRPC_ERR_CAPTURE_INIT_FAILED_SET_VF; - } - break; - } - - port->captured = true; - return DP_GRPC_OK; -} - -static int dp_turn_off_offload_pkt_capture(struct dp_port *port) -{ - if (!port->allocated || !port->captured) - return DP_OK; - - if (DP_FAILED(dp_destroy_default_flow(port))) - return DP_ERROR; - - switch (port->port_type) { - case DP_PORT_PF: - if (DP_FAILED(dp_install_pf_default_flow(port, false))) - return DP_ERROR; - break; - case DP_PORT_VF: - if (DP_FAILED(dp_install_vf_default_jump_flow(port, DP_RTE_FLOW_VNET_GROUP))) - return DP_ERROR; - break; - } - - port->captured = false; - return DP_OK; -} - -int dp_turn_on_offload_pkt_capture_on_single_iface(uint16_t port_id) -{ - struct dp_port *port = dp_port_get(port_id); - - return dp_turn_on_offload_pkt_capture(port); -} - -int dp_turn_off_offload_pkt_capture_on_single_iface(uint16_t port_id) -{ - struct dp_port *port = dp_port_get(port_id); - - return dp_turn_off_offload_pkt_capture(port); -} - -int dp_turn_on_offload_pkt_capture_on_all_ifaces(void) -{ - struct dp_ports *ports = get_dp_ports(); - - DP_FOREACH_PORT(ports, port) { - if (DP_FAILED(dp_turn_on_offload_pkt_capture(port))) - return DP_ERROR; - } - - return DP_OK; -} - -int dp_turn_off_offload_pkt_capture_on_all_ifaces(void) -{ - struct dp_ports *ports = get_dp_ports(); - int count = 0; - - DP_FOREACH_PORT(ports, port) { - if (port->captured) { - if (DP_FAILED(dp_turn_off_offload_pkt_capture(port))) - return DP_ERROR; - count++; - } - } - return count; -} - #ifdef ENABLE_VIRTSVC int dp_install_isolated_mode_virtsvc(int port_id, uint8_t proto_id, const uint8_t svc_ipv6[16], rte_be16_t svc_port) { diff --git a/src/rte_flow/dp_rte_flow_traffic_forward.c b/src/rte_flow/dp_rte_flow_traffic_forward.c index ee5bdf896..4f13b0cc4 100644 --- a/src/rte_flow/dp_rte_flow_traffic_forward.c +++ b/src/rte_flow/dp_rte_flow_traffic_forward.c @@ -9,7 +9,7 @@ #define DP_IPIP_ENCAP_HEADER_SIZE (sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv6_hdr)) -// it is used by pf to install a rule to move hairpin packets to the right rx hairpin queue +// this attribute value is used by pf to install a rule to move hairpin packets to the right rx hairpin queue static const struct rte_flow_attr dp_flow_pf_attr_ingress = { .group = DP_RTE_FLOW_DEFAULT_GROUP, .priority = 0, @@ -18,7 +18,7 @@ static const struct rte_flow_attr dp_flow_pf_attr_ingress = { .transfer = 0, }; -// it is used by vf to install a rule to move hairpin packets to the right rx hairpin queue +// this attribute value is used by vf to install a rule to move hairpin packets to the right rx hairpin queue static const struct rte_flow_attr dp_flow_vf_attr_ingress = { .group = DP_RTE_FLOW_DEFAULT_GROUP, .priority = 0, @@ -27,7 +27,7 @@ static const struct rte_flow_attr dp_flow_vf_attr_ingress = { .transfer = 0, }; -// it is used during the encap operation to install a encap/decap rule on pf to process pkts arriving to tx hairpin queue +// this attribute value is used during the encap operation to install a encap/decap rule on pf to process pkts arriving to tx hairpin queue static const struct rte_flow_attr dp_flow_attr_egress = { .group = DP_RTE_FLOW_DEFAULT_GROUP, .priority = 0, @@ -36,7 +36,7 @@ static const struct rte_flow_attr dp_flow_attr_egress = { .transfer = 0, }; -// it is used during the decap operation on pf to install a redirecting rule +// this attribute value is used during the decap operation on pf to install a redirecting rule // to point a specific flow to either capturing rule or vnet rule static const struct rte_flow_attr dp_flow_pf_attr_transfer_capture = { .group = DP_RTE_FLOW_DEFAULT_GROUP, @@ -46,7 +46,7 @@ static const struct rte_flow_attr dp_flow_pf_attr_transfer_capture = { .transfer = 1, }; -// it is used during the decap/decap operation to install a decap/encap rule to transfer pkts +// this attribute value is used during the decap/decap operation to install a decap/encap rule to transfer pkts static const struct rte_flow_attr dp_flow_attr_transfer_multi_stage = { .group = DP_RTE_FLOW_VNET_GROUP, .priority = 0, @@ -55,7 +55,7 @@ static const struct rte_flow_attr dp_flow_attr_transfer_multi_stage = { .transfer = 1, }; -// it is used during the decap/encap operation to install a decap/encap rule to transfer pkts +// this attribute value is used during the decap/encap operation to install a decap/encap rule to transfer pkts static const struct rte_flow_attr dp_flow_attr_transfer_single_stage = { .group = DP_RTE_FLOW_DEFAULT_GROUP, .priority = 0, @@ -353,13 +353,13 @@ static __rte_always_inline int dp_offload_handle_tunnel_decap_traffic(struct rte struct rte_flow_action actions[7]; // + end int action_cnt = 0; - struct rte_flow_action_jump jump_action; // 1 - struct rte_flow_action_age flow_age_capture; // 2 - struct rte_flow_action special_moni_action[3]; + struct rte_flow_action_jump jump_action; // #1 + struct rte_flow_action_age flow_age_capture; // #2 + struct rte_flow_action special_moni_action[3]; // + end int special_moni_action_cnt = 0; // misc variables needed to create the flow - struct flow_age_ctx *agectx, *agectx_capture; + struct flow_age_ctx *agectx, *agectx_capture = NULL; struct rte_flow_action *age_action, *age_action_capture; struct dp_port *port; struct rte_ether_hdr new_eth_hdr; @@ -402,8 +402,8 @@ static __rte_always_inline int dp_offload_handle_tunnel_decap_traffic(struct rte dp_set_end_flow_item(&pattern[pattern_cnt++]); - // create special actions - if ((!cross_pf_port) && dp_port_get(m->port)->captured) { + // create one action to redirect flow packets to the capturing group. + if (!cross_pf_port && dp_port_get(m->port)->captured) { agectx_capture = allocate_agectx(); if (!agectx_capture) return DP_ERROR; @@ -416,7 +416,6 @@ static __rte_always_inline int dp_offload_handle_tunnel_decap_traffic(struct rte dp_set_jump_group_action(&special_moni_action[special_moni_action_cnt++], &jump_action, DP_RTE_FLOW_CAPTURE_GROUP); dp_set_end_action(&special_moni_action[special_moni_action_cnt++]); - // struct rte_flow *sp_flow; if (DP_FAILED(dp_install_rte_flow_with_indirect(m->port, &dp_flow_pf_attr_transfer_capture, pattern, special_moni_action, age_action_capture, df, agectx_capture))) { @@ -424,7 +423,7 @@ static __rte_always_inline int dp_offload_handle_tunnel_decap_traffic(struct rte return DP_ERROR; } - DPS_LOG_DEBUG("Installed special flow rule on PF", DP_LOG_PORTID(m->port)); + DPS_LOG_DEBUG("Installed capturing flow rule on PF", DP_LOG_PORTID(m->port)); } @@ -443,8 +442,12 @@ static __rte_always_inline int dp_offload_handle_tunnel_decap_traffic(struct rte // make flow aging work agectx = allocate_agectx(); - if (!agectx) + if (!agectx) { + if (agectx_capture) + if (DP_FAILED(dp_destroy_rte_flow_agectx(agectx_capture))) + DPS_LOG_ERR("Failed to rollback by removing installed capturing rule on PF", DP_LOG_PORTID(m->port)); return DP_ERROR; + } age_action = &actions[action_cnt++]; dp_set_flow_age_action(age_action, &flow_age, df->conntrack->timeout_value, agectx); @@ -471,6 +474,9 @@ static __rte_always_inline int dp_offload_handle_tunnel_decap_traffic(struct rte age_action, df, agectx)) ) { dp_destroy_rte_flow_agectx(agectx); + if (agectx_capture) + if (DP_FAILED(dp_destroy_rte_flow_agectx(agectx_capture))) + DPS_LOG_ERR("Failed to rollback by removing installed capturing rule on PF", DP_LOG_PORTID(m->port)); return DP_ERROR; } @@ -552,8 +558,6 @@ static __rte_always_inline int dp_offload_handle_local_traffic(struct rte_mbuf * dp_set_end_action(&actions[action_cnt++]); - // TODO: this attribute has not been tested with DPDK 22.11, - // so maybe 'dp_flow_attr_transfer' should be ifdef'd too if (DP_FAILED(dp_install_rte_flow_with_indirect(m->port, &dp_flow_attr_transfer_single_stage, pattern, actions, age_action, df, agectx))