Você está na página 1de 66

LWIP introduction

nadychen
Outline


Introduction

System Architecture

Memory Management

memp_memory

Pbuf

malloc/free

Protocol

Socket API

How to porting lwip
Introduction

lwIP - A Lightweight TCP/IP stack


A light-weight implementation for TCP/IP

Suitable for embeded system with tens of
kilobytes of free RAM and room for around 40
kilobytes of code ROM

The latest lwip is 1.4.0
Introduction


Features:

IP including packet forwarding over multiple
network interface

TCP with congestion control, RTT estimation
and fast recovery/fast retransmit

Specialized no-copy API for enhanced
performace

Berkely socket API
Outline


Introduction

System Architecture

Memory Management

memp_memory

Pbuf

malloc/free

Protocol

Socket API

How to porting lwip
Architecture

OS Abstraction Layer – Synchronization

1.Mail boxes
2.Mutexes (but mutex is replaced by sem)
3.Counting semaphores
4.Thread
Architecture

OS Abstraction Layer – Protection


void sys_arch_protect(void)

void sys_arch_unprotect(void)

cyg_thread_self

cyg_mutex_lock

cyg_mutex_unlock
Architecture

OS Abstraction Layer – Timer


tcpip_thread

sys_timeouts_mbox_fetch

next_timeout -> timeoutA -> timeoutB -> …

ordered from small to big
Architecture
Application
main()

netconn_* recv_mbox API_LIB

TCPIP api_msg_post API_MSG


api_msg_input
decode
TCPIP_MSG_API recv_tcp recv_udp do_*
tcpip_thread()

TCP_INPUT UDP udp_ TCP_OUTPUT


mbox while(1) send
tcp_write
mbox_fetch tcp_receive tcp_enqueue
tcp_process udp_ tcp_output
tcp_input input tcp_output_segment

ip_input IP
TCPIP_MSG_INPKT
ip_output_if
thread()
Input_

netif->input == tcpip_input netif->output == ecosif_output


ecosif_input netif->linkout == low_level_out
Architecture
Interrupt

input_thread cmd_eth_isr
return CYG_ISR_CALL_DSR
wait
semaphore:delivery cmd_eth_dsr
sc->state |= ETH_DRV_NEEDS_DELIVERY

Does NetDev lwip_dsr_stuff


need to deliver ?
(sc->state with ETH_DRV_NEEDS_DELIVERY)

post
semaphore:delivery
call
sc->funs->deliver == cml_eth_deliver
Architecture
cyg_netdevtab_entry_t
cml_eth_netdev0

device_instance
cme_vif
cml_eth0_priv_data
sc
u16_t unit = 0
macaddr[ETH_ADDR_LEN]
eth_drv_sc
cml_eth_sc0
dev_name = eth0
deiver_private
sc_arpcom
(netif)
{
Ip, netmask, gw
char name[2] = et
u8_t num = 0
state
}
Architecture


How to combine NetDev with ECOS and LWIP?
extern cyg_netdevtab_entry_t __NETDEVTAB__[], __NETDEVTAB_END__
CYG_HAL_TABLE_BEGIN(__NETDEVTAB__, netdev);
CYG_HAL_TABLE_END(__NETDEVTAB_END__, netdev);

Define LABEL:
__NETDEVTAB__ is ”.section ecos.table.netdev.begin”
__NETDEVTAB_END__ is ”.section ecos.table.netdev.finish”
Architecture


How to combine NetDev with ECOS and LWIP?
cyg_netdevtab_entry_t cml_eth_netdev0 CYG_HAL_TABLE_ENTRY(netdev)

Declare variable and assign its section name


cml_eth_netdev0 is ”.section ecos.table.netdev.data”
Architecture


How to combine NetDev with ECOS and LWIP?
target.ld:
.devtab ALIGN (0x4) : { . = .; KEEP(*( SORT (.ecos.table.*))) ; } > ram

sort by .ecos.table.* ,
then __NETDEVTAB__, cml_eth_netdev0, __NETDEVTAB_END__
Outline


Introduction

System Architecture

Memory Management

memp_memory

Pbuf

malloc/free

Protocol

Socket API

How to porting lwip
memp_memory
memp_memory[]
memp_tab[MEMP_MAX]:
stored in link head for each kind of memory

next == 0 memp_num[MEMP_MAX]:
how many blocks?

memp_sizes[MEMP_MAX]:
how many bytes in one block?
… ...

next

memp_tab
[MEMP_PBUF_POOL] next

data
… ...
Pbuf

struct pbuf {
struct pbuf *next;
void *payload;
u16_t tot_len;
u16_t len;
u16_t flags;
u16_t ref;
};
Pbuf


struct pbuf *next;
next pbuf in singly linked pbuf chain

void *payload;
pointer to the actual data in the buffer
Pbuf


u16_t tot_len;
total length of this buffer and all next buffers in
chain belonging to the same packet

u16_t len;
length of this buffer
Pbuf


u16_t flags;
flags telling the type of pbuf

u16_t ref;
reference count
Pbuf


PBUF_POOL:

for driver, fast and suitable for interrupt.

PBUF_RAM:

header is fixed, payload is pointed to the dynamic
memory.

PBUF_ROM:

PBUF_REF:

header is fixed, payload is assigned by caller.
Pbuf PBUF_RAM
Pbuf PBUF_ROM
Pbuf PBUF_POOL
Pbuf Functions


void pbuf_init(void);

struct pbuf *pbuf_alloc(pbuf_layer l, u16_t length, pbuf_flag flag);

void pbuf_realloc((struct pbuf *p, u16_t new_len);

u8_t pbuf_free(struct pbuf *p);

1 → 2 → 3 becomes … 1→3

3 → 3 → 3 becomes 2 → 3 → 3

1 → 1 → 2 becomes … … 1

1 → 1 → 1 becomes … … ...
Pbuf Functions


u8_t pbuf_clen(struct pbuf *p);

count number of pbufs in a chain

void pbuf_ref(struct pbuf *p);

increment the reference count of the pbuf

err_t * pbuf_copy(struct pbuf *p_to, struct pbuf *p_from);

err_t * pbuf_copypartial(struct pbuf *buf, void *dataptr, u16_t len,
u16_t offset);

err_t * pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len);

copy application supplied data into a pbuf
Pbuf Functions


u8_t pbuf_header(struct pbuf *p, s16_t header_size_increment);

next
payload
len
tot_len
flags ref
A negative value decreases the header size

header
header_size_increment

Pbuf Functions


void pbuf_queue(struct pbuf *p, struct pbuf *n);

struct pbuf * pbuf_dequeue(struct pbuf *p);

pbuf_queue(p1,p2); p2 = pbuf_dequeue(p1);
pbuf_queue(p1,p3); … do something ...
pbuf_free(p2);

P1 P2 P3 P1 P2 P3
tot=3 ref=2 ref=2 tot=3 ref=2 ref=2

P1-1 P2-1 P3-1 P1-1 P2-1 P3-1

P1-2 P2-2 P3-2 P1-2 P2-2 P3-2


Pbuf Functions


void pbuf_chain(struct pbuf *h, struct pbuf *t);

struct pbuf * pbuf_dechain(struct pbuf *p);

pbuf_chain(p1,p2); p = pbuf_dechain(p1);
pbuf_chain(p1,p3); (p == P1-1)

P1 P2 P3 P1 P2 P3
tot=9 ref=2 ref=2 tot=1 ref=2 ref=2

P1-1 P1-1
P2-1 P3-1 P2-1 P3-1
ref=2 ref=1

P1-2 P1-2
P2-2 P3-2 P2-2 P3-2
ref=2 ref=2
Pbuf Functions


void pbuf_cat(struct pbuf *h, struct pbuf *t);

pbuf_cat(p1,p2);

P1 P2 P1 P2
tot=3 ref=1 tot=6 ref=1

P1-1 P2-1 P1-1 P2-1

P1-2 P2-2 P1-2 P2-2


malloc/free


target.ld

__heap1 = ALIGN (0x8);

__heap1_end = 0x80000000 + RAM_SIZE*0x100000;

cacheable and RAM_SIZE*1MB

mem.c : void initMem(void)

heapstart = __heap1;

heapsize = __heap1_end - __heap1;
malloc/free
g_nodelist
size:
size of this chunk size = 0 Block0: 16 bytes
preceding: preceding
size of the preceding chunk blink = 0
head node flink
size size = 0 Block1: 32 bytes
g_heapstart preceding
preceding
heapbase node blink
size flink
...
preceding ...
...
blink
...
flink = 0 ...
g_heapend size = 0 Block18: 4 Mbytes
heap preceding
heapend space
blink
... flink
tail node
size blink and flink:
preceding supports a doubly linked list
Outline


Introduction

System Architecture

Memory Management

memp_memory

Pbuf

malloc/free

Protocol

Socket API

How to porting lwip
TCP - States
TCP - States

Table States for TCP


TCP - States
TCP – Congestion Control


Slow start:

When start, congestion window size(cwnd) is one
maximum segment size(mss).

cwnd increases it by 1 mss for each ACK received.

cwnd = cwnd + 1

Congestion avoidance:

cwnd is larger than slow start threshold(ssthresh).

cwnd increases one mss each RTT

cwnd = cwnd + mss*mss/cwnd
TCP - Slow start

Congestion Window
starts with one MSS
TCP - Congestion avoidance
TCP – Congestion Control


Fast retransmit:

If TCP sender receives three duplicate ACK with
the same ACK number

The segment with the next higher sequence
number was dropped

The sender will retransmit the packet that was
presumed dropped before waiting for its timeout.

After fast retransmit, half of current cwnd is saved
as ssthresh, and cwnd will be equal to mss.

ssthresh = cwnd / 2, cwnd = 1

Enter slow start
TCP – Congestion Control


Fast recovery:

After fast recovery, half of current cwnd is saved as
ssthresh, and cwnd will be equal to ssthresh+3.

ssthresh = MAX(cwnd/2, 2)

cwnd = ssthresh + 3

Enter congestion avoidance
TCP – Congestion Control
Congestion Control Mechanisms of TCP
cwnd  1, Slow - start phase, if cwnd  ssthresh
cwnd  1 / cwnd , Congestion avoidance, if cwnd  ssthresh 傳送端
cwnd  
cwnd / 2, if congestion (receive triple - duplicate ACK)
1, upon timer expiry
triple dup-ACK

initial or cwnd ≥ triple


timeout Slow ssthresh Congestion dup-ACK Fast
Start Avoidance Retransmit
接收端

Timeout: ssthresh = cwnd/2, cwnd =1 new ACK

retransmit first
Fast lost packet
Recovery
TCP – Congestion Control

state event action comment


Slow Start ACK cwnd = cwnd + mss cwnd = cwnd * 2
(SS) if(cwnd > ssthresh) each RTT
enter CA
Congestion ACK cwnd = cwnd + cwnd = cwnd + 1
Avoidance mss*mss/cwnd each RTT
(CA)
SS or CA Triple dup-ACK ssthresh = MAX(cwnd/2, 2) Fast recovery
cwnd = ssthresh + 3 mss
enter CA
SS or CA Timeout ssthresh = MAX(cwnd/2, 2) go to slow start
cwnd = 1 mss
enter SS
SS or CA dup-ACK ++pcb->dupacks;
TCP

Application Application layer

tcp_write() tcp_receive()
Transport layer
tcp_enqueue() tcp_process()

tcp_output() tcp_input()

ip_route() ip_output_if() ip_input() Network layer

netif->output() netif->input() Network interface layer


TCP
free pcb tcp_receive()

tcp_timewait_pcbs tcp_listen_pcbs

tcp_input()

tcp_timewait_input() tcp_process() tcp_listen_input()

tcp_slowtmr() tcp_active_pcbs
called every 500 ms

1.Retransmission time-out
2.SYN_RCVD time-out 20 s
3.LAST_ACK time-out 120 s
4.TIME_WAIT time-out 120 s

TCP_MSL=60 s
TCP
UDP

Application Application layer

udp_send()
udp_input() Transport layer

udp_output()

ip_route() ip_output_if() ip_input() Network layer

netif->output() netif->input() Network interface layer


Outline


Introduction

System Architecture

Memory Management

memp_memory

Pbuf

malloc/free

Protocol

Socket API

How to porting lwip
Socket API - 1


#define accept(a,b,c) lwip_accept(a,b,c)

#define bind(a,b,c) lwip_bind(a,b,c)

#define shutdown(a,b) lwip_shutdown(a,b)

#define close(s) lwip_close(s)

#define connect(a,b,c) lwip_connect(a,b,c)

#define getsockname(a,b,c) lwip_getsockname(a,b,c)

#define getpeername(a,b,c) lwip_getpeername(a,b,c)

#define setsockopt(a,b,c,d,e) lwip_setsockopt(a,b,c,d,e)

#define getsockopt(a,b,c,d,e) lwip_getsockopt(a,b,c,d,e)

#define listen(a,b) lwip_listen(a,b)
Socket API - 2


#define recv(a,b,c,d) lwip_recv(a,b,c,d)

#define read(a,b,c) lwip_read(a,b,c)

#define recvfrom(a,b,c,d,e,f) lwip_recvfrom(a,b,c,d,e,f)

#define send(a,b,c,d) lwip_send(a,b,c,d)

#define sendto(a,b,c,d,e,f) lwip_sendto(a,b,c,d,e,f)

#define socket(a,b,c) lwip_socket(a,b,c)

#define write(a,b,c) lwip_write(a,b,c)

#define select(a,b,c,d,e) lwip_select(a,b,c,d,e)

#define ioctlsocket(a,b,c) lwip_ioctl(a,b,c)
Socket API - 3

SOCKET
SOCKETAPI
API lwip_API
lwip_API netconn_API
netconn_API
bind
bind lwip_bind
lwip_bind netconn_bind
netconn_bind
listen
listen lwip_listen
lwip_listen netconn_listen
netconn_listen
connect
connect lwip_connect
lwip_connect netconn_connect
netconn_connect
accept
accept lwip_accept
lwip_accept netconn_accept
netconn_accept
recv
recv lwip_recv
lwip_recv netconn_recv
netconn_recv
send
send lwip_send
lwip_send netconn_send
netconn_send
write
write lwip_write
lwip_write netconn_write
netconn_write
close
close lwip_close
lwip_close netconn_close
netconn_close
Socket API - 4


socket_thread:

Berkely socket API

lwip_XXX

netconn_XXX

tcpip_thread:

do_XXX
Socket API - 5
TASK 1 TASK 2 TASK 3
application
application tcpip_thread
tcpip_thread tcpip_thread
tcpip_thread

socket
socketAPI
API MSG_API
MSG_API MSG_INPKT
MSG_INPKT

lwip_bind
lwip_bind…
… do_bind
do_bind…
… ip_input
ip_input

netconn_bind
netconn_bind…
… raw_input
raw_input

udp_input
udp_input

tcp_input
tcp_input

icmp_input
icmp_input
Socket API - 6
Single Application

TASK
TASK11
(application
(application1)
1) TASK
TASK22
mbox
mbox
recv accept (tcpip_thread)
(tcpip_thread)
mbox mbox

TASK
TASK33
(tcpip_thread)
(tcpip_thread)
Socket API - 7
Multi Application

TASK
TASK11
(application
(application1)
1)
recvmbox acceptmbox

TASK
TASK22
mbox
mbox (tcpip_thread)
(tcpip_thread)
TASK
TASKNN
(application
(applicationN)
N)
recvmbox acceptmbox

TASK
TASK33
(tcpip_thread)
(tcpip_thread)
Socket API - 8


API types:

TYPE 1

CONNECT, BIND, LISTEN, CLOSE,
SEND. WRITE

TYPE 2

ACCEPT, RECV
Socket API - 9

TYPE 1
sys_mbox_fetch
do_connect
do_connect
TCPIP_MSG_API
tcp_connect(){
sys_mbox_post pcb->connected = do_connected
sys_arch_sem_wait pcb->state = SYN_SENT
tcp_enqueue()
netconn_connect mbox
mbox tcp_output()
netconn_connect
}
tcp_input() →
tcp_process(){
switch case: SYN_SENT
pcb->connected
}

do_connected
do_connected
sys_sem_signal
Socket API - 10

TYPE 2
sys_mbox_trypost recv_xxx
recv_xxx
(raw,tcp,udp)
(raw,tcp,udp)
sys_arch_mbox_fetch

lwip_recvfrom
lwip_recvfrom recvmbox
recvmbox
netconn_recv_data
netconn_recv_data pbuf

sys_arch_sem_wait API_EVNET(conn, NETCONN_EVT_RCVPLUS)


sys_sem_signal(&scb->sem)

lwip_select
lwip_select select_cb_list
select_cb_list
fd_set
Outline


Introduction

System Architecture

Memory Management

memp_memory

Pbuf

malloc/free

Protocol

Socket API

How to porting lwip
How to porting lwip


svn co http://asfs/svn/ip3210_bsp/trunk/bsp
ip3210-bsp

svn co http://asfs/svn/assw/trunk/ecos-2.0

download ecos-3.0

porting lwip from ecos-3.0 to ecos-2.0

download lwip-1.4.rc

upgrade lwip to 1.4
How to porting lwip


lwip config

don't copy io/eth/v3_0/cdl/eth_drivers.cdl to ecos-
2.0

ldd ecos-2.0/tools/bin/configtool to show libs what
we need?

use configtool to open ecos.ecc and append
acrospeed template with network

add ”common ethernet support”, but uncheck
”support for stand-alone network stack”

add ”lwip” and check ”Ethernet support”, but
uncheck ”SLIP”, ”PPP” and ”Support loop interface”

set parameters for some buffer size, then save
How to porting lwip
How to porting lwip


CYGPKG_NET_LWIP

gcc compiler option: -fno-builtin

Don't recognize built-in functions that do not begin
with __builtin_ as prefix

Ex: ”printf” doesn't transfer to become ”puts”,
because ”puts” is not implemented.
How to porting lwip


thread priority

input_thread and tcpip_thread

cyg_start() and cyg_scheduler_start()

cyg_start is replaced by os_start in os_api.c

main function is the major thread created by
cyg_start

then cyg_scheduler_start is called by
cyg_start
How to porting lwip

eth_drv_alloc_buf()
pbuf pbuf pbuf
next next next
payload payload payload
... ... ...
ref ref ref
data unused unused
data pbuf pbuf
data data data bufp

... ... ...


data data data
pkt
return for driver 64-byte aligned
for memory
Thank you very much

Você também pode gostar