# Lab8 networking
ip of xv6: 10.0.2.15
ip of host: 10.0.2.2
這個 lab 要我們完成 `e1000_transmit()` 和 `e1000_recv()`
### trace code
檔案介紹:
* `kernel/e1000.c`: init, transmiting, receving
* `kernel/e1000_dev.h`: registers and flag by E1000 manual
* `kernel/net.c`, `kernel/net.h`: net stack(IP, UDP, ARP)
* `mbuf`: flexible data structure to hold packets
* `kernel/pci.c`: searches for and E1000 card when boot
需要特別注意的 function: `write()`, `connect()`, `read()`, 尤其是要特別注意他們是如何使用到 `kernel/e1000.c` 的
* `main()`
* `ping()`
* `connect()`
* `k/sysfile.c: sys_connect()`
* `k/sysnet.c: sockalloc()`
* `write()`
* `k/sysfile.c: sys_write()`
* `k/file.c: filewrite()`
* `k/sysnet.c: sockwrite()`
* `k/net.c: net_tx_udp()`
* `k/net.c: net_tx_ip()`
* `k/net.c: net_tx_eth()`
* `k/e1000.c: e1000_transmit()`
* `read()`
* `dns()`
* `k/net.c: net_tx_arp()`
* `k/net.c: net_tx_eth()`
* `k/e1000.c: e1000_transmit()`
當我們針對 `regs` 做動作時,實際上就是在對 e1000 做操作
```
#define TX_RING_SIZE 16
static struct tx_desc tx_ring[TX_RING_SIZE] __attribute__((aligned(16)));
static struct mbuf *tx_mbufs[TX_RING_SIZE];
#define RX_RING_SIZE 16
static struct rx_desc rx_ring[RX_RING_SIZE] __attribute__((aligned(16)));
static struct mbuf *rx_mbufs[RX_RING_SIZE];
```
#### Manual
#### Manual 中對於 receive 的描述,以及如何用 C 語言說出來
在 `e1000_dev.h` 中,它根據了 E1000 3.3.3 定義出這些東西
```C
/* Receive Descriptor bit definitions [E1000 3.2.3.1] */
#define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */
#define E1000_RXD_STAT_EOP 0x02 /* End of Packet */
// [E1000 3.2.3]
struct rx_desc
{
uint64 addr; /* Address of the descriptor's data buffer */
uint16 length; /* Length of data DMAed into data buffer */
uint16 csum; /* Packet checksum */
uint8 status; /* Descriptor status */
uint8 errors; /* Descriptor Errors */
uint16 special;
};
```
根據 3.2.3 and 3.2.3.1
* `addr`: 資料的 address,應該是指到 ring
* `length`: 資料的長度
* `status`: status 中的 DD (Descriptor Done) 需要特別注意 (3.2.3.1)
* ring (`rx_ring`) 的 item 也就是一個又一個的 `rx_desc` (?)
##### receive queue
![Fiqure 3-2]()
* tail pointer is incremented by swoftware.
* head pointer is incremented by hardware.
* if `head` == `tail` then empty
* if queue is full then hw stop receive
* software 可以藉由 descriptor 來決定這個他是不是 valid (不必用一般的 I/O read)
* 只要 `status` != 0, 這就可以 read 了
#### Manual 中對於 transmit 的描述,以及如何用 C 語言說出來
在 `e1000_dev.h` 中,它根據了 E1000 3.3.3 定義出這些東西
```C
/* Transmit Descriptor command definitions [E1000 3.3.3.1] */
#define E1000_TXD_CMD_EOP 0x01 /* End of Packet */
#define E1000_TXD_CMD_RS 0x08 /* Report Status */
/* Transmit Descriptor status definitions [E1000 3.3.3.2] */
#define E1000_TXD_STAT_DD 0x00000001 /* Descriptor Done */
// [E1000 3.3.3]
struct tx_desc
{
uint64 addr;
uint16 length;
uint8 cso;
uint8 cmd;
uint8 status;
uint8 css;
uint16 special;
};
```
根據 3.3.3
* `addr`: 資料的 address, 應該是指到 ring
* `length`: 資料的長度
* `cmd`: 一些設定
* `status`: status 中的 DD (Descriptor Done) 需要特別注意
* ring (`tx_ring`) 的 item 也就是一個又一個的 `tx_desc`(?)
##### transmit queue
![Fiqure 3-4]()
* 新的 descriptor 加到 tail, 並且 tail + 1
#### mbuf
```C
struct mbuf {
struct mbuf *next; // the next mbuf in the chain
char *head; // the current start position of the buffer
unsigned int len; // the length of the buffer
char buf[MBUF_SIZE]; // the backing store
};
```
* mbuf 是一個 linked list
* `head`: circular queue 的 head
* `len`: length of the buffer
例如 transmit 時,我們就需要把這個 `mbuf` 寫到 `regs` 中
## reference
* https://pdos.csail.mit.edu/6.S081/2022/labs/net.html
* https://www.youtube.com/watch?v=Fcjychg4Tvk
* [Xv6 Lab8 Networking 实验记录](https://ttzytt.com/2022/08/xv6_lab8_record/)
* https://github.com/ttzytt/xv6-riscv/blob/net/kernel/e1000.c
* `devintr()`
* `e1000_intr()`
* `e1000_recv()`
### `read()`
* `nettests.c: pipe()`
* `connect()`
* `kernel/sysfile.c: sys_connect()`
* `kernel/sysnet.c: sockalloc()`
* (*f)->type = FD_SOCK;
* `read()`
* `kernel/sysfile.c: sys_read()`
* `kernel/file.c: fileread()`
* `kernel/sysnet.c: sockread()`
* `kernel/net.c: mbufq_pophead()`
```C
struct mbuf *
mbufq_pophead(struct mbufq *q)
{
struct mbuf *head = q->head;
if (!head)
return 0;
q->head = head->next;
return head;
}
```
這個在做的也就只是把 `head` 給 pop 掉而已
下一個問題就是: 這個 `struct mbufq q` 是哪裡來的
* 其實想要寫出這個 lab 了話,並不一定要知道這個問題的答案,
* 想要寫出這個 lab 重點在於:(read)
> interrupt 時,會呼叫到 `e1000_recv()`, 而它就負責把收到的資料放到 `rx_mbufs`
> 等到 `ping()` 呼叫到 `read()` 時,它應該會自己去 `rx_mbufs` 拿資料
## questions
* `e1000_recv(void)`
* `net_rx()` 是做什麼的
* `desc->status = 0` 的原因為何
* `mbufalloc()` 如何運作
## write
接收 `struct mbuf *m`
把東西放到 `tx_ring` and `tx_mbuf` 裡
## write questions
* 為什麼要放到`tx_ring` and `tx_mbuf` 裡,應該放個一個就好(?)
* `mbuffree()` 是作什麼的
* `desc->cmd = E1000_TXD_CMD_RS | E1000_TXD_CMD_EOP` 的來源為何