Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ovs flows #447

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 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,57 @@ impl EventFmt for UpcallEvent {
}
}

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

impl From<[u32; 4]> for Ufid {
fn from(parts: [u32; 4]) -> Self {
Self(parts[0], parts[1], parts[2], parts[3])
}
}

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

/// OVS lookup event
#[event_type]
#[derive(Copy, Default, PartialEq)]
pub struct LookupEvent {
/// flow pointer
pub flow: u64,
/// actions pointer
pub sf_acts: u64,
/// 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) {}/{} flow {:x} sf_acts {:x}",
self.ufid, self.n_mask_hit, self.n_cache_hit, self.flow, self.sf_acts,
)
}
}

/// Upcall enqueue event.
#[event_type]
#[derive(Copy, Default, PartialEq)]
Expand Down
22 changes: 22 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,22 @@
/* automatically generated by rust-bindgen 0.70.1 */

pub type __u32 = ::std::os::raw::c_uint;
pub type u32_ = __u32;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct flow_lookup_ret_event {
pub flow: *mut ::std::os::raw::c_void,
pub sf_acts: *mut ::std::os::raw::c_void,
pub ufid: [u32_; 4usize],
pub n_mask_hit: u32_,
pub n_cache_hit: u32_,
}
impl Default for flow_lookup_ret_event {
fn default() -> Self {
let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
unsafe {
::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
s.assume_init()
}
}
}
1 change: 1 addition & 0 deletions retis/src/bindings/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ pub(crate) mod kernel_exec_tp_uapi;
pub(crate) mod kernel_upcall_ret_uapi;
pub(crate) mod kernel_upcall_tp_uapi;

pub(crate) mod kernel_flow_tbl_lookup_ret_uapi;
pub(crate) mod ovs_common_uapi;
pub(crate) mod ovs_operation_uapi;
pub(crate) mod user_recv_upcall_uapi;
Expand Down
14 changes: 14 additions & 0 deletions retis/src/bindings/ovs_common_uapi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,17 @@ impl Default for execute_actions_ctx {
}
}
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct processing_ctx {
pub skb: *mut ::std::os::raw::c_void,
}
impl Default for processing_ctx {
fn default() -> Self {
let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
unsafe {
::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
s.assume_init()
}
}
}
20 changes: 20 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,25 @@ 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 {
flow: raw.flow as usize as u64,
sf_acts: raw.sf_acts as usize as u64,
ufid: raw.ufid.into(),
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 +327,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
18 changes: 18 additions & 0 deletions 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 @@ -54,6 +55,23 @@ struct execute_actions_ctx {
bool command;
} __binding;

/* Context saved between the begining of ovs_dp_process_packet and the end of
ovs_flow_tbl_lookup_stats. */
struct processing_ctx {
BINDING_PTR(struct sk_buff *, skb);
} __binding;

/* Map used 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);
__type(key, u64);
__type(value, struct processing_ctx);
} inflight_processing SEC(".maps");

/* Map used to store context between the begining and end of
* ovs_execute_actions calls. Indexed by pid_tgid. */
struct {
Expand Down
74 changes: 74 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,74 @@
#include <common.h>
#include <ovs_common.h>

#define MAX_UFID_LENGTH 16

struct flow_lookup_ret_event {
BINDING_PTR(struct sw_flow *, flow);
BINDING_PTR(struct sw_flow_actions *, sf_acts);
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 processing_ctx *pctx;
struct sw_flow *flow;
u32 ufid_len = 0;

pctx = bpf_map_lookup_elem(&inflight_processing, &tid);
if (!pctx)
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.
*/
goto out_clean;

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

ret = get_event_section(event, COLLECTOR_OVS,
OVS_FLOW_TBL_LOOKUP_RETURN,
sizeof(*ret));
if (!ret)
goto out_clean;

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

ret->flow = flow;

if (bpf_core_read(&ret->sf_acts, sizeof(ret->sf_acts), &flow->sf_acts))
log_error("Failed to read sf_acts");

/* Only log in case of failure while retrieving ancillary
* informations.
*/
if (bpf_probe_read_kernel(&ret->n_mask_hit, sizeof(ret->n_mask_hit),
(void *)ctx->regs.reg[3]) < 0) {
log_error("Failed to retrieve n_mask_hit from 0x%p",
ctx->regs.reg[3]);
}

if (bpf_probe_read_kernel(&ret->n_cache_hit, sizeof(ret->n_cache_hit),
(void *)ctx->regs.reg[4]) < 0) {
log_error("Failed to retrieve n_cache_hit from 0x%p",
ctx->regs.reg[4]);
}

out_clean:
bpf_map_delete_elem(&inflight_processing, &tid);
return 0;
)

char __license[] SEC("license") = "GPL";
24 changes: 24 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,24 @@
#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 processing_ctx pctx = {};
long err;

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

if ((err = bpf_map_update_elem(&inflight_processing, &tid, &pctx, BPF_ANY))) {
log_error("Failed to set processing entry at index %lu with err: %lu", tid, err);
return 0;
}

return 0;
)

char __license[] SEC("license") = "GPL";
6 changes: 6 additions & 0 deletions retis/src/module/ovs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ 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_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