Netmap installation and use and user protocol stack implementation

Article directory

  • 1. Install and compile netmap
  • 2. Use netmap
  • 3. How to obtain original data
    • 3.1. Netmap implementation principle
    • 3.2. Protocol stack explanation
    • 3.2. Ethernet protocol
    • 3.3. IP protocol
  • 4. Run and write your own code

1. Install and compile netmap

github address

git clone https://github.com/luigirizzo/netmap

1. Enter the directory

cd netmap-master/LINUX

2. Install the compilation environment

apt-get install build-essential

3. Initialize the configuration environment

./configure

When this interface appears, it is not stuck. You need to wait for a long time to complete. This process may be relatively long. Running to the following indicates success.



4. Compile and install

make & amp; & amp; make install

2. Use netmap

You need to insmod netmap.ko before each use. Then we check ls /dev/netmap -l. If the following device appears, it means the opening is successful.

# Execute in netmap-master/LINUX
insmod netmap.ko
ls /dev/netmap -l

Cancel loading

rmmod netmap

3. How to obtain original data

1. Use raw socket. tcpdump and wireshark are made using this. Raw socket is mainly used to capture packets.
2.dpdk
3. Netmap is a high-performance framework for user-level applications to send and receive raw network data.

3.1. Netmap implementation principle

Original method: transfer data to the network card through the network cable, copy the network card to the kernel protocol stack, unpack the result of the kernel protocol stack, and hand the data to the application layer

Netmap method: After the network card converts the photoelectric signal into a digital signal, it is directly mapped into the memory through mmap. This process is a zero-copy process, so the application can directly operate this memory and the original data.

3.2. Protocol stack explanation

The so-called protocol stack, the stack is first in, last out, such as the upd protocol. After using sendto at the sending end, we first add the upd protocol header to the user data, then go through the network layer, add the ip protocol header, and then go through the data link The path layer, plus the Ethernet frame header, converts the digital signal into a physical signal through the network card and sends it out. After the peer network card receives the photoelectric signal, it converts it into a digital signal, and then unpacks it layer by layer, and finally sends it to our application layer. The data, this process is the same as the stack, first in, last out, protocol family, because there are udp, tcp, icmp, ip and other protocols that form a family, so it is also called a protocol family.

3.2, Ethernet protocol


Ethernet protocol: Both addresses are 6-byte mac addresses. The following 2-byte type distinguishes what protocol.

struct ethhdr {<!-- -->
unsigned char h_dst[ETH_ADDR_LENGTH];
unsigned char h_src[ETH_ADDR_LENGTH];
unsigned short h_proto;
\t
}; // 14

3.3, ip protocol

struct iphdr {<!-- -->

unsigned char hdrlen:4,
version:4; // 0x45
\t\t\t\t  

unsigned char tos;

unsigned short totlen;
\t
unsigned short id;

unsigned short flag_offset; //

unsigned char ttl; //time to live
// 0x1234// htons

unsigned char type;

unsigned short check;

unsigned int sip;
unsigned int dip;

}; // 20

Question 1: Why do we need to implement the user protocol stack when we have the kernel protocol stack?
Question 2: Which layer is the network card data?

The process of mutual conversion from the data link layer to the physical layer does not belong to any of the layers. The main function of the network card is to convert photoelectric signals into digital signals, and digital signals into photoelectric signals.

4. Run and write your own code

#Header file #include<net/netmap_user.h> in the /netmap/sys/ directory
gcc -o nty_udp nty_udp.c
./nty_upd


#include 

#include 
#include 

#define NETMAP_WITH_LIBS

#include 

#pragma pack(1)


#define ETH_ADDR_LENGTH 6

#define PROTO_IP 0x0800
#define PROTO_ARP 0x0806
#define PROTO_UDP 17
#define PROTO_ICMP 1


struct ethhdr {<!-- -->
unsigned char h_dst[ETH_ADDR_LENGTH];
unsigned char h_src[ETH_ADDR_LENGTH];
unsigned short h_proto;
\t
}; // 14


struct iphdr {<!-- -->

unsigned char hdrlen:4,
version:4; // 0x45
\t\t\t\t  

unsigned char tos;

unsigned short totlen;
\t
unsigned short id;

unsigned short flag_offset; //

unsigned char ttl; //time to live
// 0x1234// htons

unsigned char type;

unsigned short check;

unsigned int sip;
unsigned int dip;

}; // 20



struct udphdr {

unsigned short sport;
unsigned short dport;

unsigned short length;
unsigned short check;

}; // 8


struct udppkt {

struct ethhdr eh; // 14
struct iphdr ip; // 20
struct udphdr udp; // 8

unsigned char data[0];

}; // sizeof(struct udppkt) ==


struct arphdr {

unsigned short h_type;
unsigned short h_proto;

unsigned char h_addrlen;
unsigned char h_protolen;

unsigned short oper;

unsigned char smac[ETH_ADDR_LENGTH];
unsigned int sip;

unsigned char dmac[ETH_ADDR_LENGTH];
unsigned int dip;
};

struct arppkt {

struct ethhdr eh;
struct arphdr arp;

};



int str2mac(char *mac, char *str) {

char *p = str;
unsigned char value = 0x0;
int i = 0;

while (p != '\0') {
\t\t
if (*p == ':') {
mac[i + + ] = value;
value = 0x0;
} else {
\t\t\t
unsigned char temp = *p;
if (temp <= '9' & amp; & amp; temp >= '0') {
temp -= '0';
} else if (temp <= 'f' & amp; & amp; temp >= 'a') {
temp -= 'a';
temp + = 10;
} else if (temp <= 'F' & amp; & amp; temp >= 'A') {
temp -= 'A';
temp + = 10;
} else {
break;
}
value <<= 4;
value |= temp;
}
p + + ;
}

mac[i] = value;

return 0;
}



void echo_arp_pkt(struct arppkt *arp, struct arppkt *arp_rt, char *mac) {

memcpy(arp_rt, arp, sizeof(struct arppkt));

memcpy(arp_rt->eh.h_dst, arp->eh.h_src, ETH_ADDR_LENGTH);
str2mac(arp_rt->eh.h_src, mac);
arp_rt->eh.h_proto = arp->eh.h_proto;

arp_rt->arp.h_addrlen = 6;
arp_rt->arp.h_protolen = 4;
arp_rt->arp.oper = htons(2);
\t
str2mac(arp_rt->arp.smac, mac);
arp_rt->arp.sip = arp->arp.dip;
\t
memcpy(arp_rt->arp.dmac, arp->arp.smac, ETH_ADDR_LENGTH);
arp_rt->arp.dip = arp->arp.sip;

}

//
int main() {

struct nm_pkthdr h;
struct nm_desc *nmr = nm_open("netmap:ens33", NULL, 0, NULL);
if (nmr == NULL) return -1;

struct pollfd pfd = {0};
pfd.fd = nmr->fd;
pfd.events = POLLIN;

while (1) {

int ret = poll( & amp;pfd, 1, -1);
if (ret < 0) continue;

if (pfd.revents & amp; POLLIN) {

unsigned char *stream = nm_nextpkt(nmr, & amp;h);

struct ethhdr *eh = (struct ethhdr *)stream;
if (ntohs(eh->h_proto) == PROTO_IP) {

struct udppkt *udp = (struct udppkt *)stream;

if (udp->ip.type == PROTO_UDP) { //

int udplength = ntohs(udp->udp.length);

udp->data[udplength-8] = '\0';

printf("udp --> %s\
", udp->data);

} else if (udp->ip.type == PROTO_ICMP) {

\t\t\t\t\t

}
\t\t\t\t

} else if (ntohs(eh->h_proto) == PROTO_ARP) {

struct arppkt *arp = (struct arppkt *)stream;

struct arppkt arp_rt;

if (arp->arp.dip == inet_addr("192.168.0.123")) { //

echo_arp_pkt(arp, & amp;arp_rt, "00:50:56:33:1c:ca");

nm_inject(nmr, & amp;arp_rt, sizeof(arp_rt));

printf("arp ret\
");
\t\t\t\t
}

}

}

}
\t
\t

}