Skip to content

Commit

Permalink
2024-03-19 TIL 문서 복사
Browse files Browse the repository at this point in the history
Signed-off-by: rlaisqls <rlaisqls@gmail.com>
  • Loading branch information
rlaisqls committed Mar 19, 2024
1 parent bafb139 commit e039bb1
Show file tree
Hide file tree
Showing 4 changed files with 544 additions and 0 deletions.
40 changes: 40 additions & 0 deletions src/content/docs/TIL/OS/linux/BPF/XDP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
title: 'XDP'
lastUpdated: 2024-03-19T23:07:00
---
- XDP(eXpress Data Path) is an eBPF-based high-performance data path used to send and receive network packets at high rates by bypassing most of the operating system networking stack.

### Data path

<img width="883" alt="image" src="https://github.com/rlaisqls/TIL/assets/81006587/c322a547-9858-44ff-880a-acd5859cddaf">

- Packet flow paths in the Linux kernel. XDP bypasses the networking stack and memory allocation for packet metadata.
- The idea behind XDP is to **add an early hook in the RX path of the kernel**, and **let a user supplied eBPF program decide the fate of the packet**.
- The hook is placed in the network interface controller (NIC) driver just after the interrupt processing, and before any memory allocation needed by the network stack itself, because memory allocation can be an expensive operation.
- Due to this design, **XDP can drop 26 million packets per second per cor**e with commodity hardware.

- The eBPF program must pass a preverifier test before being loaded, to avoid executing malicious code in kernel space. The preverifier checks that the program contains no out-of-bounds accesses, loops or global variables.

- The program is allowed to edit the packet data and, after the eBPF program returns, an action code determines what to do with the packet:
- `XDP_PASS`: let the packet continue through the network stack
- `XDP_DROP`: silently drop the packet
- `XDP_ABORTED`: drop the packet with trace point exception
- `XDP_TX`: bounce the packet back to the same NIC it arrived on
- `XDP_REDIRECT`: redirect the packet to another NIC or user space socket via the AF_XDP address family
- XDP requires support in the NIC driver but, as not all drivers support it, it can fallback to a generic implementation, which performs the eBPF processing in the network stack, though with slower performance.

- XDP has infrastructure to offload the eBPF program to a network interface controller which supports it, reducing the CPU load. In 2023, only Netronome cards support it.

- Microsoft is partnering with other companies and adding support for XDP in its MsQuic implementation of the QUIC protocol.

### AF_XDP

- Along with XDP, a new address family entered in the Linux kernel starting 4.18.
- AF_XDP, formerly known as AF_PACKETv4 (which was never included in the mainline kernel), is a raw socket optimized for high performance packet processing and allows zero-copy between kernel and applications.
- As the socket can be used for both receiving and transmitting, it supports high performance network applications purely in user space.

---
reference
- https://prototype-kernel.readthedocs.io/en/latest/networking/XDP/
- https://www.netronome.com/blog/bpf-ebpf-xdp-and-bpfilter-what-are-these-things-and-what-do-they-mean-enterprise/
- https://ebpf.io/
143 changes: 143 additions & 0 deletions src/content/docs/TIL/코드/언어/Rust/Unwrap.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
---
title: 'Unwrap'
lastUpdated: 2024-03-19T23:07:00
---
unwrap을 호출한 객체는 기본적으로 복사를 수행한다. 복사와 소유권 이동 둘다 가능한 시점에서 복사가 발생한다.

```rust
fn main() {
let s = Some(12);

let a = s.unwrap();
println!("{}", a);

let b = s.unwrap();
println!("{}", b);
}
```

복사를 수행하기 위해서는 해당 타입이 Copy 트레잇을 구현해야 한다. 복사가 안된다면 메모리 소유권 이동이 발생한다.

```rust
struct MyStruct{
x:i32,
y:i32,
}

fn main() {
let s = Some(MyStruct {
x: 123,
y: 1,
});

let a = s.unwrap();//소유권 이동 발생, s에는 메모리 소유권 없음
println!("{}", a.x);

let b = s.unwrap();//error
println!("{}", b.x);
}


13 | let s = Some(MyStruct {
| - move occurs because `s` has type `Option<MyStruct>`, which does not implement the `Copy` trait
...
18 | let a = s.unwrap();
| - -------- `s` moved due to this method call
| |
| help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents
...
21 | let b = s.unwrap();
| ^ value used here after move
```

Copy 트레잇을 구현 해주면 복사가 발생하기에 소유권 에러는 발생하지 않는다.

```rust
#[derive(Copy, Clone)]
struct MyStruct{
x:i32,
y:i32,
}

fn main() {
let s = Some(MyStruct {
x: 123,
y: 1,
});

let a = s.unwrap();
println!("{}", a.x);//123

let mut b = s.unwrap();
b.x = 321;
println!("{}", a.x);//123
println!("{}", b.x);//321
}
```

힙 메모리를 담는 타입들은 Copy는 구현되어 있지 않지만 소유권 이동은 가능하다.

```rust
fn main() {
let s = Some(Box::new(1));

let a = s.unwrap();// 소유권 이동 발생, s의 메모리 소유권은 사라짐
println!("{}", *a);

let b = s.unwrap();// error, s는 유효한 메모리를 가지고 있지 않다.
println!("{}", *b);
}
```

복사가 가능한 타입이라면 unwrap 호출시 복사가 발생한다.

```rust
fn main() {
let s = Some(1);

let a = s.unwrap();//메모리 복사
println!("{}", a);

let b = s.unwrap();//Ok
println!("{}", b);
}
```

만약 참조로 인자를 받았다면 unwrap으로 인해 소유권이 없어지는 코드가 작성 되는지 주의해야한다.

```rust
fn Func(a: Option<Box<i32>>) {
let c = a.unwrap();//소유권 이동, a는 더이상 메모리 소유권 없음
println!("{}", c);
// let d = a.unwrap();
// println!("{}", d);
}

fn main() {
let a = Some(Box::new(123));
Func(a);
// println!("{}", a.unwrap());//소유권 이동, a는 더이상 메모리 소유권 없음
}
```

참조로 전달하면 소유권 이동을 막을 수 있지만 unwrap 호출시 as_ref를 이용하여 참조로서 가져오도록 해야한다.

```rust
fn Func(a: &Option<Box<i32>>) {
let c = a.as_ref().unwrap();
// let c = a.unwrap();//error, 참조이기에 소유권 이동 안됨
println!("{}", c);
let d = a.as_ref().unwrap();
println!("{}", d);
}

fn main() {
let a = Some(Box::new(123));
Func(&a);
println!("{}", a.unwrap());
}
```

---
참고
- https://doc.rust-lang.org/rust-by-example/error/option_unwrap.html
33 changes: 33 additions & 0 deletions src/content/docs/TIL/코드/언어/Rust/extern.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
title: 'extern'
lastUpdated: 2024-03-19T23:07:00
---

- Using extern keyword, you can link to or import external code.

- The extern keyword is used in two places in Rust. One is in conjunction with the crate keyword to make your Rust code aware of other Rust crates in your project, i.e., extern crate lazy_static;. The other use is in foreign function interfaces (FFI).

- `extern` is used in two different contexts within FFI. The first is in the form of external blocks, for declaring function interfaces that Rust code can call foreign code by.

```rust
#[link(name = "my_c_library")]
extern "C" {
fn my_c_function(x: i32) -> bool;
}
```

- This code would attempt to link with `libmy_c_library.so` on unix-like systems and my_c_library.dll on Windows at runtime, and panic if it cant find something to link to.

- Rust code could then use `my_c_function` as if it were any other unsafe Rust function. Working with non-Rust languages and FFI is inherently unsafe, so wrappers are usually built around C APIs.

- The mirror use case of FFI is also done via the extern keyword:

```rust
#[no_mangle]
pub extern "C" fn callable_from_c(x: i32) -> bool {
x % 3 == 0
}
```

- If compiled as a dylib, the resulting .so could then be linked to from a C library, and the function could be used as if it was from any other library.

Loading

0 comments on commit e039bb1

Please sign in to comment.