Skip to content

Commit

Permalink
ovs: extract ufid and generate the related event.
Browse files Browse the repository at this point in the history
While at it, n_{mask,cache}_hit have been included.

Ideally, this should be done with fexit indexing by sw_flow_key, but
given that is missing, it reuses the existing inflight_exec map.

Signed-off-by: Paolo Valerio <[email protected]>
  • Loading branch information
vlrpl committed Nov 10, 2024
1 parent 8b10c4a commit 0580721
Show file tree
Hide file tree
Showing 13 changed files with 253 additions and 7 deletions.
57 changes: 57 additions & 0 deletions retis-events/src/ovs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ pub enum OvsEventType {
/// Action execution event. It indicates the datapath has executed an action on a packet.
#[serde(rename = "action_execute")]
Action(ActionEvent),

/// Flow lookup event. It indicates the datapath has successfully perfomed a lookup for a key.
#[serde(rename = "flow_lookup")]
DpLookup(LookupEvent),
}

impl EventFmt for OvsEventType {
Expand All @@ -63,6 +67,7 @@ impl EventFmt for OvsEventType {
RecvUpcall(e) => e,
Operation(e) => e,
Action(e) => e,
DpLookup(e) => e,
};

disp.event_fmt(f, format)
Expand Down Expand Up @@ -107,6 +112,58 @@ impl EventFmt for UpcallEvent {
}
}

fn fmt_ufid(ufid: &[u32]) -> String {
format!("{:08x}-{:04x}-{:04x}-{:04x}-{:04x}{:08x}",
ufid[0],
ufid[1] >> 16,
ufid[1] & 0xffff,
ufid[2] >> 16,
ufid[2] & 0xffff,
ufid[3]
)
}

#[event_type]
#[derive(Copy, Default, PartialEq)]
pub struct Ufid(pub [u32; 4]);

impl fmt::Display for Ufid {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:08x}-{:04x}-{:04x}-{:04x}-{:04x}{:08x}",
self.0[0],
self.0[1] >> 16,
self.0[1] & 0xffff,
self.0[2] >> 16,
self.0[2] & 0xffff,
self.0[3])
}

}

/// OVS lookup event
#[event_type]
#[derive(Copy, Default, PartialEq)]
pub struct LookupEvent {
/// Flow UFID.
pub ufid: Ufid,
/// n_mask_hit.
pub n_mask_hit: u32,
/// n_cache_hit.
pub n_cache_hit: u32,
}

impl EventFmt for LookupEvent {
fn event_fmt(&self, f: &mut Formatter, _: &DisplayFormat) -> fmt::Result {
write!(
f,
"ufid {} hit {} (mask) {} (cache)",
self.ufid,
self.n_mask_hit,
self.n_cache_hit,
)
}
}

/// Upcall enqueue event.
#[event_type]
#[derive(Copy, Default, PartialEq)]
Expand Down
11 changes: 11 additions & 0 deletions retis/src/bindings/kernel_flow_tbl_lookup_ret_uapi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/* automatically generated by rust-bindgen 0.70.1 */

pub type __u32 = ::std::os::raw::c_uint;
pub type u32_ = __u32;
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct flow_lookup_ret_event {
pub ufid: [u32_; 4usize],
pub n_mask_hit: u32_,
pub n_cache_hit: u32_,
}
1 change: 1 addition & 0 deletions retis/src/bindings/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ pub(crate) mod kernel_upcall_tp_uapi;
pub(crate) mod ovs_common_uapi;
pub(crate) mod ovs_operation_uapi;
pub(crate) mod user_recv_upcall_uapi;
pub(crate) mod kernel_flow_tbl_lookup_ret_uapi;

pub(crate) mod events_uapi;
use events_uapi::retis_log_event;
Expand Down
2 changes: 2 additions & 0 deletions retis/src/bindings/ovs_common_uapi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ pub struct upcall_context {
#[derive(Debug, Copy, Clone)]
pub struct execute_actions_ctx {
pub skb: *mut ::std::os::raw::c_void,
pub n_mask_hit: *mut u32_,
pub n_cache_hit: *mut u32_,
pub queue_id: u32_,
pub command: bool_,
}
Expand Down
18 changes: 18 additions & 0 deletions retis/src/module/ovs/bpf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use crate::{
bindings::{
kernel_enqueue_uapi::upcall_enqueue_event,
kernel_exec_tp_uapi::{exec_ct, exec_event, exec_output, exec_recirc, exec_track_event},
kernel_flow_tbl_lookup_ret_uapi::flow_lookup_ret_event,
kernel_upcall_ret_uapi::upcall_ret_event,
kernel_upcall_tp_uapi::upcall_event,
ovs_operation_uapi::ovs_operation_event,
Expand Down Expand Up @@ -46,6 +47,8 @@ pub(crate) enum OvsDataType {
RecircAction = 8,
/// Conntrack action.
ConntrackAction = 9,
/// Flow lookup
FlowLookup = 10,
}

impl OvsDataType {
Expand All @@ -62,11 +65,23 @@ impl OvsDataType {
7 => OutputAction,
8 => RecircAction,
9 => ConntrackAction,
10 => FlowLookup,
x => bail!("Can't construct a OvsDataType from {}", x),
})
}
}

pub(super) fn unmarshall_flow_lookup(raw_section: &BpfRawSection) -> Result<OvsEvent> {
let raw = parse_raw_section::<flow_lookup_ret_event>(raw_section)?;
Ok(OvsEvent {
event: OvsEventType::DpLookup(LookupEvent {
ufid: Ufid(raw.ufid),
n_mask_hit: raw.n_mask_hit,
n_cache_hit: raw.n_cache_hit,
}),
})
}

pub(super) fn unmarshall_upcall(raw_section: &BpfRawSection) -> Result<OvsEvent> {
let raw = parse_raw_section::<upcall_event>(raw_section)?;
Ok(OvsEvent {
Expand Down Expand Up @@ -310,6 +325,9 @@ impl RawEventSectionFactory for OvsEventFactory {
OvsDataType::ActionExec => {
event = Some(unmarshall_exec(section)?);
}
OvsDataType::FlowLookup => {
event = Some(unmarshall_flow_lookup(section)?);
}
OvsDataType::ActionExecTrack => unmarshall_exec_track(
section,
event
Expand Down
8 changes: 7 additions & 1 deletion retis/src/module/ovs/bpf/include/ovs_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ enum trace_ovs_data_type {
OVS_DP_ACTION_OUTPUT = 7,
OVS_DP_ACTION_RECIRC = 8,
OVS_DP_ACTION_CONNTRACK = 9,
OVS_FLOW_TBL_LOOKUP_RETURN = 10,
};

/* Used to keep the context of an upcall operation for its upcall enqueue
Expand Down Expand Up @@ -50,12 +51,17 @@ struct {
/* Context saved between the begining and end of ovs_execute_actions calls. */
struct execute_actions_ctx {
BINDING_PTR(struct sk_buff *, skb);
u32 *n_mask_hit;
u32 *n_cache_hit;
u32 queue_id;
bool command;
} __binding;

/* Map used to store context between the begining and end of
* ovs_execute_actions calls. Indexed by pid_tgid. */
* ovs_execute_actions calls. It is also used to extract the ufid
* during the lookup in the regular rx path, meaning it is used also
* for keeping context between the beginning of ovs_dp_process_packet
* and the end of ovs_flow_tbl_lookup_stats. Indexed by pid_tgid. */
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, MAX_INFLIGHT_UPCALLS);
Expand Down
18 changes: 14 additions & 4 deletions retis/src/module/ovs/bpf/kernel_exec_actions.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,36 @@ DEFINE_HOOK(F_AND, RETIS_F_PACKET_PASS,
u32 queue_id;
u64 tid = bpf_get_current_pid_tgid();
struct execute_actions_ctx ectx = {};
struct execute_actions_ctx *pectx;
struct sk_buff *skb;

skb = retis_get_sk_buff(ctx);
if (!skb)
return 0;

pectx = bpf_map_lookup_elem(&inflight_exec, &tid);
if (!pectx)
pectx = &ectx;

queue_id = queue_id_gen_skb(skb);

if (bpf_map_lookup_elem(&flow_exec_tracking, &queue_id)) {
/* Indicate this flow execution is the result of a userspace
* command and store the current queue_id so that further
* actions will use the same one regardless of packet
* modifications. */
ectx.queue_id = queue_id;
ectx.command = true;
pectx->queue_id = queue_id;
pectx->command = true;
}
bpf_map_delete_elem(&flow_exec_tracking, &queue_id);
ectx.skb = skb;

if (!bpf_map_update_elem(&inflight_exec, &tid, &ectx, BPF_ANY))
if (pectx->skb && pectx->skb != skb) {
log_error("skb stored while processing differs when executing actions");
pectx->skb = skb;
}

if ((pectx == &ectx) &&
!bpf_map_update_elem(&inflight_exec, &tid, pectx, BPF_ANY))
return 0;

return 0;
Expand Down
20 changes: 20 additions & 0 deletions retis/src/module/ovs/bpf/kernel_flow_tbl_lookup.bpf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#include <common.h>
#include <ovs_common.h>

/* Hook for kprobe:ovs_flow_tbl_lookup_stats */
DEFINE_HOOK_RAW(
u64 tid = bpf_get_current_pid_tgid();
struct execute_actions_ctx *ectx;

ectx = bpf_map_lookup_elem(&inflight_exec, &tid);
if (!ectx) {
return 0;
}

ectx->n_mask_hit = (u32 *)ctx->regs.reg[3];
ectx->n_cache_hit = (u32 *)ctx->regs.reg[4];

return 0;
)

char __license[] SEC("license") = "GPL";
66 changes: 66 additions & 0 deletions retis/src/module/ovs/bpf/kernel_flow_tbl_lookup_ret.bpf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#include <common.h>
#include <ovs_common.h>

#define MAX_UFID_LENGTH 16

struct flow_lookup_ret_event {
u32 ufid[MAX_UFID_LENGTH / 4];
u32 n_mask_hit;
u32 n_cache_hit;
} __binding;

/* Hook for kretprobe:ovs_flow_tbl_lookup_stats */
DEFINE_HOOK_RAW(
u64 tid = bpf_get_current_pid_tgid();
struct flow_lookup_ret_event *ret;
struct execute_actions_ctx *ectx;
struct sw_flow *flow;
u32 ufid_len = 0;

ectx = bpf_map_lookup_elem(&inflight_exec, &tid);
if (!ectx) {
return 0;
}

flow = (struct sw_flow *)ctx->regs.ret;
if (!flow) {
/* No flows. This is most likely an upcall.
* There's no much we can do other than clean-up
* the map and return.
*/
bpf_map_delete_elem(&inflight_exec, &tid);
return 0;
}

ufid_len = BPF_CORE_READ(flow, id.ufid_len);
if (!ufid_len) {
log_error("Expected ufid representation expected, found key");
return 0;
}

ret = get_event_section(event, COLLECTOR_OVS,
OVS_FLOW_TBL_LOOKUP_RETURN,
sizeof(*ret));
if (!ret)
return 0;

if (BPF_CORE_READ_INTO(&ret->ufid, flow, id.ufid))
log_error("Failed to read the ufid");

/* Only log in case of failure while retrieving ancillary
* informations.
*/
if (bpf_probe_read_kernel(&ret->n_mask_hit, sizeof(ret->n_mask_hit),
ectx->n_mask_hit) < 0) {
log_error("Failed to retrieve n_mask_hit");
}

if (bpf_probe_read_kernel(&ret->n_cache_hit, sizeof(ret->n_cache_hit),
ectx->n_cache_hit) < 0) {
log_error("Failed to retrieve n_cache_hit");
}

return 0;
)

char __license[] SEC("license") = "GPL";
21 changes: 21 additions & 0 deletions retis/src/module/ovs/bpf/kernel_process_packet.bpf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include <common.h>
#include <ovs_common.h>

/* Hook for kprobe:ovs_dp_process_packet. */
DEFINE_HOOK(F_AND, RETIS_ALL_FILTERS,
u64 tid = bpf_get_current_pid_tgid();
struct execute_actions_ctx ectx = {};

ectx.skb = retis_get_sk_buff(ctx);
if (!ectx.skb) {
log_error("Invalid skb while ovs is processing the packet");
return 0;
}

if (!bpf_map_update_elem(&inflight_exec, &tid, &ectx, BPF_ANY))
return 0;

return 0;
)

char __license[] SEC("license") = "GPL";
9 changes: 9 additions & 0 deletions retis/src/module/ovs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@ mod hooks {
pub(super) mod kernel_exec_tp {
include!("bpf/.out/kernel_exec_tp.rs");
}
pub(super) mod kernel_process_packet {
include!("bpf/.out/kernel_process_packet.rs");
}
pub(super) mod kernel_tbl_lookup {
include!("bpf/.out/kernel_flow_tbl_lookup.rs");
}
pub(super) mod kernel_tbl_lookup_ret {
include!("bpf/.out/kernel_flow_tbl_lookup_ret.rs");
}
pub(super) mod kernel_upcall_tp {
include!("bpf/.out/kernel_upcall_tp.rs");
}
Expand Down
Loading

0 comments on commit 0580721

Please sign in to comment.