Netlink 是内核与用户空间进程通信的一种机制,采用与 UDP socket 非常类似的编程风格。(关于 UDP socket 编程,请看这里)

与 UDP 类似,Netlink 通信也有服务器端和客户端。例如,Linux 内核作为服务器端,已经运行在那里。我们则编写 Netlink 客户端,给内核发消息,并获得我们想要的信息。

例子 1

通过 Netlink,从内核中得到所有网口的名字。

link-list.c:

/*

* Display all network interface names

*/

#include //printf, perror

#include //memset, strlen

#include //exit

#include //close

#include //msghdr

#include //inet_ntop

#include //sockaddr_nl

#include //rtgenmsg,ifinfomsg

#define BUFSIZE 8192

struct nl_req_s {

struct nlmsghdr hdr;

struct rtgenmsg gen;

};

void die(char *s)

{

perror(s);

exit(1);

}

void rtnl_print_link(struct nlmsghdr * h)

{

struct ifinfomsg * iface;

struct rtattr * attr;

int len;

iface = NLMSG_DATA(h);

len = RTM_PAYLOAD(h);

/* loop over all attributes for the NEWLINK message */

for (attr = IFLA_RTA(iface); RTA_OK(attr, len); attr = RTA_NEXT(attr, len))

{

switch (attr->rta_type)

{

case IFLA_IFNAME:

printf("Interface %d : %s\n", iface->ifi_index, (char *)RTA_DATA(attr));

break;

default:

break;

}

}

}

int main(void)

{

struct sockaddr_nl kernel;

int s, end=0, len;

struct msghdr msg;

struct nl_req_s req;

struct iovec io;

char buf[BUFSIZE];

//build kernel netlink address

memset(&kernel, 0, sizeof(kernel));

kernel.nl_family = AF_NETLINK;

kernel.nl_groups = 0;

//create a Netlink socket

if ((s=socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0)

{

die("socket");

}

//build netlink message

memset(&req, 0, sizeof(req));

req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));

req.hdr.nlmsg_type = RTM_GETLINK;

req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;

req.hdr.nlmsg_seq = 1;

req.hdr.nlmsg_pid = getpid();

req.gen.rtgen_family = AF_INET;

memset(&io, 0, sizeof(io));

io.iov_base = &req;

io.iov_len = req.hdr.nlmsg_len;

memset(&msg, 0, sizeof(msg));

msg.msg_iov = &io;

msg.msg_iovlen = 1;

msg.msg_name = &kernel;

msg.msg_namelen = sizeof(kernel);

//send the message

if (sendmsg(s, &msg, 0) < 0)

{

die("sendmsg");

}

//parse reply

while (!end)

{

memset(buf, 0, BUFSIZE);

msg.msg_iov->iov_base = buf;

msg.msg_iov->iov_len = BUFSIZE;

if ((len=recvmsg(s, &msg, 0)) < 0)

{

die("recvmsg");

}

for (struct nlmsghdr * msg_ptr = (struct nlmsghdr *)buf;

NLMSG_OK(msg_ptr, len); msg_ptr = NLMSG_NEXT(msg_ptr, len))

{

switch (msg_ptr->nlmsg_type)

{

case NLMSG_DONE:

end++;

break;

case RTM_NEWLINK:

rtnl_print_link(msg_ptr);

break;

default:

printf("Ignored msg: type=%d, len=%d\n", msg_ptr->nlmsg_type, msg_ptr->nlmsg_len);

break;

}

}

}

close(s);

return 0;

}

# gcc link-list.c -o link-list && ./link-list

Interface 1 : lo

Interface 2 : eth0

例子 2

通过 Netlink,从内核中得到所有网口的 IP 地址。

/*

* Display all IPv4 addresses

*/

#include //printf, perror

#include //memset, strlen

#include //exit

#include //close

#include //msghdr

#include //inet_ntop

#include //sockaddr_nl

#include //rtgenmsg,ifinfomsg

#define BUFSIZE 8192

struct nl_req_s {

struct nlmsghdr hdr;

struct rtgenmsg gen;

};

void die(char *s)

{

perror(s);

exit(1);

}

void rtnl_print_addr(struct nlmsghdr * h)

{

struct ifaddrmsg * addr;

struct rtattr * attr;

int len;

addr = NLMSG_DATA(h);

len = RTM_PAYLOAD(h);

/* loop over all attributes for the NEWLINK message */

for (attr = IFLA_RTA(addr); RTA_OK(attr, len); attr = RTA_NEXT(attr, len))

{

switch (attr->rta_type)

{

case IFA_LABEL:

printf("Interface : %s\n", (char *)RTA_DATA(attr));

break;

case IFA_LOCAL:

{

int ip = *(int*)RTA_DATA(attr);

unsigned char bytes[4];

bytes[0] = ip & 0xFF;

bytes[1] = (ip >> 8) & 0xFF;

bytes[2] = (ip >> 16) & 0xFF;

bytes[3] = (ip >> 24) & 0xFF;

printf("IP Address : %d.%d.%d.%d\n", bytes[0], bytes[1], bytes[2], bytes[3]);

break;

}

default:

break;

}

}

}

int main(void)

{

struct sockaddr_nl kernel;

int s, end=0, len;

struct msghdr msg;

struct nl_req_s req;

struct iovec io;

char buf[BUFSIZE];

//build kernel netlink address

memset(&kernel, 0, sizeof(kernel));

kernel.nl_family = AF_NETLINK;

kernel.nl_groups = 0;

//create a Netlink socket

if ((s=socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0)

{

die("socket");

}

//build netlink message

memset(&req, 0, sizeof(req));

req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));

req.hdr.nlmsg_type = RTM_GETADDR;

req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;

req.hdr.nlmsg_seq = 1;

req.hdr.nlmsg_pid = getpid();

req.gen.rtgen_family = AF_INET;

memset(&io, 0, sizeof(io));

io.iov_base = &req;

io.iov_len = req.hdr.nlmsg_len;

memset(&msg, 0, sizeof(msg));

msg.msg_iov = &io;

msg.msg_iovlen = 1;

msg.msg_name = &kernel;

msg.msg_namelen = sizeof(kernel);

//send the message

if (sendmsg(s, &msg, 0) < 0)

{

die("sendmsg");

}

//parse reply

while (!end)

{

memset(buf, 0, BUFSIZE);

msg.msg_iov->iov_base = buf;

msg.msg_iov->iov_len = BUFSIZE;

if ((len=recvmsg(s, &msg, 0)) < 0)

{

die("recvmsg");

}

for (struct nlmsghdr * msg_ptr = (struct nlmsghdr *)buf;

NLMSG_OK(msg_ptr, len); msg_ptr = NLMSG_NEXT(msg_ptr, len))

{

switch (msg_ptr->nlmsg_type)

{

case NLMSG_DONE:

end++;

break;

case RTM_NEWADDR:

rtnl_print_addr(msg_ptr);

break;

default:

printf("Ignored msg: type=%d, len=%d\n", msg_ptr->nlmsg_type, msg_ptr->nlmsg_len);

break;

}

}

}

close(s);

return 0;

}

# gcc addr-list.c -o addr-list && ./addr-list

IP Address : 127.0.0.1

Interface : lo

IP Address : 10.254.115.149

Interface : eth0

例子 3

通过 Netlink 列出当前系统中主路由表中的所有路由。

/*

* Display all routes

*/

#include //printf, perror

#include //memset, strlen

#include //exit

#include //close

#include //msghdr

#include //inet_ntop

#include //sockaddr_nl,NLMSG_DATA

#include //rtgenmsg,ifinfomsg

#define BUFSIZE 8192

struct nl_req_s {

struct nlmsghdr hdr;

struct rtgenmsg gen;

};

void die(char *s)

{

perror(s);

exit(1);

}

void rtnl_print_route(struct nlmsghdr * h)

{

struct rtmsg * rte = NLMSG_DATA(h);

struct rtattr * attr = RTM_RTA(rte);

int len = RTM_PAYLOAD(h);

char dest[32] = {0};

char gway[32] = {"unspecified"};

if (rte->rtm_table != RT_TABLE_MAIN) {

return;

}

for (; RTA_OK(attr, len); attr = RTA_NEXT(attr, len))

{

switch (attr->rta_type)

{

case RTA_DST:

inet_ntop(AF_INET, RTA_DATA(attr), dest, sizeof(dest));

break;

case RTA_GATEWAY:

inet_ntop(AF_INET, RTA_DATA(attr), gway, sizeof(gway));

break;

default:

break;

}

}

printf("%s/%d gateway %s\n", dest, rte->rtm_dst_len, gway);

}

int main(void)

{

struct sockaddr_nl kernel;

int s, end=0, len;

struct msghdr msg;

struct nl_req_s req;

struct iovec io;

char buf[BUFSIZE];

//build kernel netlink address

memset(&kernel, 0, sizeof(kernel));

kernel.nl_family = AF_NETLINK;

kernel.nl_groups = 0;

//create a Netlink socket

if ((s=socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0)

{

die("socket");

}

//build netlink message

memset(&req, 0, sizeof(req));

req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));

req.hdr.nlmsg_type = RTM_GETROUTE;

req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;

req.hdr.nlmsg_seq = 1;

req.hdr.nlmsg_pid = getpid();

req.gen.rtgen_family = AF_INET;

memset(&io, 0, sizeof(io));

io.iov_base = &req;

io.iov_len = req.hdr.nlmsg_len;

memset(&msg, 0, sizeof(msg));

msg.msg_iov = &io;

msg.msg_iovlen = 1;

msg.msg_name = &kernel;

msg.msg_namelen = sizeof(kernel);

//send the message

if (sendmsg(s, &msg, 0) < 0)

{

die("sendmsg");

}

// parse reply

while (!end)

{

memset(buf, 0, BUFSIZE);

msg.msg_iov->iov_base = buf;

msg.msg_iov->iov_len = BUFSIZE;

if ((len=recvmsg(s, &msg, 0)) < 0)

{

die("recvmsg");

}

for (struct nlmsghdr * msg_ptr = (struct nlmsghdr *)buf;

NLMSG_OK(msg_ptr, len); msg_ptr = NLMSG_NEXT(msg_ptr, len))

{

switch (msg_ptr->nlmsg_type)

{

case NLMSG_DONE:

end++;

break;

case RTM_NEWROUTE:

rtnl_print_route(msg_ptr);

break;

default:

printf("Ignored msg: type=%d, len=%d\n", msg_ptr->nlmsg_type, msg_ptr->nlmsg_len);

break;

}

}

}

close(s);

return 0;

}

# gcc route-list.c -o route-list && ./route-list

/0 gateway 10.254.96.136

10.254.96.0/19 gateway unspecified

例子 4

通过 Netlink 监测主路由表中路由的变化。

/*

* Monitor route change

*/

#include //printf, perror

#include //memset, strlen

#include //exit

#include //close

#include //msghdr

#include //inet_ntop

#include //sockaddr_nl,NLMSG_DATA

#include //rtgenmsg,ifinfomsg

#define BUFSIZE 4096

void die(char *s)

{

perror(s);

exit(1);

}

void print_route(struct nlmsghdr * h)

{

struct rtmsg * rte = NLMSG_DATA(h);

struct rtattr * attr = RTM_RTA(rte);

int len = RTM_PAYLOAD(h);

char dest[32] = {0};

char gway[32] = {"unspecified"};

if (rte->rtm_table != RT_TABLE_MAIN) {

return;

}

for (; RTA_OK(attr, len); attr = RTA_NEXT(attr, len))

{

switch (attr->rta_type)

{

case RTA_DST:

inet_ntop(AF_INET, RTA_DATA(attr), dest, sizeof(dest));

break;

case RTA_GATEWAY:

inet_ntop(AF_INET, RTA_DATA(attr), gway, sizeof(gway));

break;

default:

break;

}

}

if (h->nlmsg_type == RTM_NEWROUTE) {

printf("add ");

}

else if (h->nlmsg_type == RTM_DELROUTE) {

printf("del ");

}

else {

printf("nlmsg_type=%d ", h->nlmsg_type);

}

printf("%s/%d gateway %s\n", dest, rte->rtm_dst_len, gway);

}

int main(void)

{

int s, len;

struct sockaddr_nl me;

char buf[BUFSIZE];

memset(&me, 0, sizeof(me));

if ((s = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0)

{

die("socket");

}

me.nl_family = AF_NETLINK;

me.nl_groups = RTMGRP_IPV4_ROUTE;

if (bind(s,(struct sockaddr *)&me, sizeof(me)) < 0)

{

die("bind");

}

while (1)

{

memset(buf, 0, BUFSIZE);

if ((len=recv(s, buf, BUFSIZE, 0)) < 0)

{

die("recv");

}

for (struct nlmsghdr * msg_ptr = (struct nlmsghdr *)buf;

NLMSG_OK(msg_ptr, len); msg_ptr = NLMSG_NEXT(msg_ptr, len))

{

switch (msg_ptr->nlmsg_type)

{

case RTM_NEWROUTE:

case RTM_DELROUTE:

print_route(msg_ptr);

break;

default:

printf("Ignored msg: type=%d\n", msg_ptr->nlmsg_type);

break;

}

}

}

close(s);

return 0;

}

Terminal 1:

# gcc route-chg.c -o route-chg && ./route-chg

Terminal 2:

# ip route add 199.1.1.0/24 via 10.254.96.136

# ip route del 199.1.1.0/24 via 10.254.96.136

Terminal 1:

# gcc route-chg.c -o route-chg && ./route-chg

add 199.1.1.0/24 gateway 10.254.96.136

del 199.1.1.0/24 gateway 10.254.96.136

例子 5

通过 Netlink 监测网口的变化。

/*

* Monitor network interface change

*/

#include //printf, perror

#include //memset, strlen

#include //exit

#include //close

#include //msghdr

#include //inet_ntop

#include //sockaddr_nl,NLMSG_DATA

#include //rtgenmsg,ifinfomsg

#define BUFSIZE 4096

void die(char *s)

{

perror(s);

exit(1);

}

void print_link(struct nlmsghdr * h)

{

struct ifinfomsg * iface;

struct rtattr * attr;

int len;

iface = NLMSG_DATA(h); //point to payload

len = RTM_PAYLOAD(h);

/* loop over all attributes for the NEWLINK message */

for (attr = IFLA_RTA(iface); RTA_OK(attr, len); attr = RTA_NEXT(attr, len))

{

switch (attr->rta_type)

{

case IFLA_IFNAME:

if (h->nlmsg_type == RTM_NEWLINK) {

printf("add ");

}

else if (h->nlmsg_type == RTM_DELLINK) {

printf("del ");

}

else {

printf("nlmsg_type=%d ", h->nlmsg_type);

}

printf("Interface %d : %s\n", iface->ifi_index, (char *)RTA_DATA(attr));

break;

default:

break;

}

}

}

int main(void)

{

int s, len;

struct sockaddr_nl me;

char buf[BUFSIZE];

memset(&me, 0, sizeof(me));

if ((s = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0)

{

die("socket");

}

int on = 1;

if (setsockopt(s, SOL_NETLINK, NETLINK_LISTEN_ALL_NSID, &on, sizeof(on)) < 0)

{

die("setsockopt");

}

me.nl_family = AF_NETLINK;

me.nl_groups = RTMGRP_LINK;

if (bind(s,(struct sockaddr *)&me, sizeof(me)) < 0)

{

die("bind");

}

while (1)

{

memset(buf, 0, BUFSIZE);

if ((len=recv(s, buf, BUFSIZE, 0)) < 0)

{

die("recv");

}

for (struct nlmsghdr * msg_ptr = (struct nlmsghdr *)buf;

NLMSG_OK(msg_ptr, len); msg_ptr = NLMSG_NEXT(msg_ptr, len))

{

switch (msg_ptr->nlmsg_type)

{

case RTM_NEWLINK:

case RTM_DELLINK:

print_link(msg_ptr);

break;

default:

printf("Ignored msg: type=%d\n", msg_ptr->nlmsg_type);

break;

}

}

}

close(s);

return 0;

}

Terminal 1:

# gcc link-chg.c -o link-chg && ./link-chg

Terminal 2:

# ip link add veth1 type veth

# ip link del veth1 type veth

Terminal 1:

# gcc link-chg.c -o link-chg && ./link-chg

add Interface 8 : veth0

add Interface 9 : veth1

del Interface 9 : veth1

del Interface 8 : veth0

例子 6

通过 Netlink 监测 IP 地址的变化。

/*

* Monitor IP address change

*/

#include //printf, perror

#include //memset, strlen

#include //exit

#include //close

#include //msghdr

#include //inet_ntop

#include //sockaddr_nl,NLMSG_DATA

#include //rtgenmsg,ifinfomsg

#define BUFSIZE 4096

void die(char *s)

{

perror(s);

exit(1);

}

void print_addr(struct nlmsghdr * h)

{

struct ifaddrmsg * addr;

struct rtattr * attr;

int len;

addr = NLMSG_DATA(h);

len = RTM_PAYLOAD(h);

/* loop over all attributes for the NEWLINK message */

for (attr = IFLA_RTA(addr); RTA_OK(attr, len); attr = RTA_NEXT(attr, len))

{

switch (attr->rta_type)

{

case IFA_LABEL:

printf("Interface : %s\n", (char *)RTA_DATA(attr));

break;

case IFA_LOCAL:

{

if (h->nlmsg_type == RTM_NEWADDR) {

printf("add ");

}

else if (h->nlmsg_type == RTM_DELADDR) {

printf("del ");

}

else {

printf("nlmsg_type=%d ", h->nlmsg_type);

}

int ip = *(int*)RTA_DATA(attr);

unsigned char bytes[4];

bytes[0] = ip & 0xFF;

bytes[1] = (ip >> 8) & 0xFF;

bytes[2] = (ip >> 16) & 0xFF;

bytes[3] = (ip >> 24) & 0xFF;

printf("IP Address : %d.%d.%d.%d\n", bytes[0], bytes[1], bytes[2], bytes[3]);

break;

}

default:

break;

}

}

}

int main(void)

{

int s, len;

struct sockaddr_nl me;

char buf[BUFSIZE];

memset(&me, 0, sizeof(me));

if ((s = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0)

{

die("socket");

}

int on = 1;

if (setsockopt(s, SOL_NETLINK, NETLINK_LISTEN_ALL_NSID, &on, sizeof(on)) < 0)

{

die("setsockopt");

}

me.nl_family = AF_NETLINK;

me.nl_groups = RTMGRP_IPV4_IFADDR;

if (bind(s,(struct sockaddr *)&me, sizeof(me)) < 0)

{

die("bind");

}

while (1)

{

memset(buf, 0, BUFSIZE);

if ((len=recv(s, buf, BUFSIZE, 0)) < 0)

{

die("recv");

}

for (struct nlmsghdr * msg_ptr = (struct nlmsghdr *)buf;

NLMSG_OK(msg_ptr, len); msg_ptr = NLMSG_NEXT(msg_ptr, len))

{

switch (msg_ptr->nlmsg_type)

{

case RTM_NEWADDR:

case RTM_DELADDR:

print_addr(msg_ptr);

break;

default:

printf("Ignored msg: type=%d\n", msg_ptr->nlmsg_type);

break;

}

}

}

close(s);

return 0;

}

Terminal 1:

# gcc addr-chg.c -o addr-chg && ./addr-chg

Terminal 2:

# ip address add 20.20.20.2/24 dev eth0

# ip address del 20.20.20.2/24 dev eth0

Terminal 1:

# gcc addr-chg.c -o addr-chg && ./addr-chg

add IP Address : 20.20.20.2

Interface : eth0

del IP Address : 20.20.20.2

Interface : eth0

例子 7

通过 Netlink 监测所有 namespace 中的 IP 地址的变化。

/*

* Monitor IP address change

*/

#include //printf, perror

#include //memset, strlen

#include //exit

#include //close

#include //msghdr

#include //inet_ntop

#include //sockaddr_nl,NLMSG_DATA

#include //rtgenmsg,ifinfomsg

#define BUFSIZE 4096

void die(char *s)

{

perror(s);

exit(1);

}

void print_addr(struct nlmsghdr * h)

{

struct ifaddrmsg * addr;

struct rtattr * attr;

int len;

addr = NLMSG_DATA(h);

len = RTM_PAYLOAD(h);

/* loop over all attributes for the NEWLINK message */

for (attr = IFLA_RTA(addr); RTA_OK(attr, len); attr = RTA_NEXT(attr, l)

{

switch (attr->rta_type)

{

case IFA_LABEL:

printf("Interface : %s\n", (char *)RTA_DATA(attr));

break;

case IFA_LOCAL:

{

if (h->nlmsg_type == RTM_NEWADDR) {

printf("ADD ");

}

else if (h->nlmsg_type == RTM_DELADDR) {

printf("DEL ");

}

else {

printf("nlmsg_type=%d ", h->nlmsg_type);

}

int ip = *(int*)RTA_DATA(attr);

unsigned char bytes[4];

bytes[0] = ip & 0xFF;

bytes[1] = (ip >> 8) & 0xFF;

bytes[2] = (ip >> 16) & 0xFF;

bytes[3] = (ip >> 24) & 0xFF;

printf("IP Address : %d.%d.%d.%d\n", bytes[0], bytes[1], bytes, bytes[3]);

break;

}

default:

break;

}

}

printf("\n");

}

int main(void)

{

int s, len;

struct sockaddr_nl me;

struct msghdr msg;

struct iovec io;

char buf[BUFSIZE];

char cmsgbuf[BUFSIZE];

if ((s = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0)

{

die("socket");

}

int on = 1;

if (setsockopt(s, SOL_NETLINK, NETLINK_LISTEN_ALL_NSID, &on, sizeof(on< 0)

{

die("setsockopt");

}

memset(&me, 0, sizeof(me));

me.nl_family = AF_NETLINK;

me.nl_groups = RTMGRP_IPV4_IFADDR;

if (bind(s,(struct sockaddr *)&me, sizeof(me)) < 0)

{

die("bind");

}

memset(&msg, 0, sizeof(msg));

msg.msg_iov = &io;

msg.msg_iovlen = 1;

msg.msg_name = &me;

msg.msg_namelen = sizeof(me);

msg.msg_control = &cmsgbuf;

msg.msg_controllen = BUFSIZE;

memset(&io, 0, sizeof(io));

msg.msg_iov->iov_base = buf;

msg.msg_iov->iov_len = BUFSIZE;

while (1)

{

memset(buf, 0, BUFSIZE);

memset(cmsgbuf, 0, BUFSIZE);

msg.msg_iov->iov_len = BUFSIZE;

msg.msg_controllen = BUFSIZE;

if ((len=recvmsg(s, &msg, 0)) < 0)

{

die("recvmsg");

}

for (struct cmsghdr * cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSXTHDR(&msg, cmsg))

{

if (cmsg->cmsg_level == SOL_NETLINK &&

cmsg->cmsg_type == NETLINK_LISTEN_ALL_NSID &&

cmsg->cmsg_len == CMSG_LEN(sizeof(int)))

{

int * data = (int *)CMSG_DATA(cmsg);

printf("Namespace ID : %d\n", *data);

}

}

for (struct nlmsghdr * msg_ptr = (struct nlmsghdr *)buf;

NLMSG_OK(msg_ptr, len); msg_ptr = NLMSG_NEXT(msg_ptr, len))

{

switch (msg_ptr->nlmsg_type)

{

case RTM_NEWADDR:

case RTM_DELADDR:

print_addr(msg_ptr);

break;

default:

printf("Ignored msg: type=%d\n", msg_ptr->nlmsg_type);

break;

}

}

}

close(s);

return 0;

}

Terminal 1:

# gcc addr-chg.c -o addr-chg && ./addr-chg

Terminal 2:

# ip netns add red

# ip netns set red 123

# ip netns

red (id: 123)

# ip address add 20.20.20.2/24 dev lo

# ip address del 20.20.20.2/24 dev lo

# ip netns exec red ip address add 20.20.20.3/24 dev lo

# ip netns exec red ip address del 20.20.20.3/24 dev lo

Terminal 1:

# gcc addr-chg.c -o addr-chg && ./addr-chg

ADD IP Address : 20.20.20.2

Interface : lo

DEL IP Address : 20.20.20.2

Interface : lo

Namespace ID : 123

ADD IP Address : 20.20.20.3

Interface : lo

Namespace ID : 123

DEL IP Address : 20.20.20.3

Interface : lo

参考文献

linux netlink 机制,Linux Netlink 编程相关推荐

  1. linux sysctl机制,Linux操作系统sysctl机制的思想与实现

    续<linux的netlink机制>:其实只要同时提供实现一个内核netlink的内核模块和一个定制用户策略的用户空间netlink程序,你就可以完全控制linux内核了,这里内核的net ...

  2. linux模块化机制,Linux模块化机制和module_init

    > 引子:模块化机制优点 模块化机制(module)是Linux系统的一大创新,是Linux驱动开发和运行的基础(当然,module并不仅仅是支撑驱动).其优点在于: 1.在系统运行动态加载模块 ...

  3. linux rcu机制,Linux RCU机制详解 (透彻)

    一:前言 RCU机制出现的比较早,只是在linux kernel中一直到2.5版本的时候才被采用.关于RCU机制,这里就不做过多的介绍了,网上有很多有关RCU介绍和使用的文档.请自行查阅.本文主要是从 ...

  4. linux sysctl机制,Linux系统控制文件 /etc/sysctl.conf

    /etc/sysctl.conf这个目录主要是配置一些系统信息,而且它的内容全部是对应于/proc/sys/这个目录的子目录及文件.这样或许你不理解,先看看我的系统/etc/sysctl.conf这个 ...

  5. c语言linux消息机制,linux消息机制的过程是什么啊,请赐教

    LINUX的安装过程很简单,按照它的提示进行就可以了.重点就是分区那里.通常我们使用双系统,那样我们在LINUX分区的时候不要把WIN分区跟格掉就好,然后要记得分一个SWAP分区,然后根据您的需要进行 ...

  6. linux ns机制,Linux内核API ns_to_timespec

    ns_to_timespec函数功能描述:函数ns_to_timespec( )将参数表示的时间转换成用结构体timespec变量表示的时间,参数的时间单位是纳秒. ns_to_timespec文件包 ...

  7. mono linux 运行机制,linux – Mono如何神奇?

    我正在学习C#,所以我制作了一个名为Hello,World!的C#程序,然后用mono-csc编译并用mono运行它: $mono-csc Hello.cs $mono Hello.exe Hello ...

  8. NetLink机制使用

    前些日子研究如何在Android实现USB-Audio的热插拔,顺带了解了一下netlink机制.netlink在TCP/IP方面用得较多,但根据需要也可用在HDMI/USB等热插拔消息通知.前人已经 ...

  9. 【Linux 内核】Linux 内核特性 ( 组织形式 | 进程调度 | 内核线程 | 多平台虚拟内存管理 | 虚拟文件系统 | 内核模块机制 | 定制系统调用 | 网络模块架构 )

    文章目录 一.Linux 内核特性 1.Linux 内核组织形式 2.Linux 进程调度 3.Linux 内核线程 4.Linux 内核多平台虚拟内存管理 5.Linux 虚拟文件系统 6.Linu ...

最新文章

  1. 计算机网络(NETWORK 部分二) 第1-2天
  2. rabbitmq一:基本概念
  3. 文本挖掘预处理:向量化与Hash Trick
  4. 一文读懂 | 进程并发与同步
  5. TensorFlow2.0(五)--Keras构建Wide Deep模型
  6. Linux进程间通信(匿名管道)
  7. 刷机工具-fastboot
  8. charles V4.2.1版本 破解码
  9. react-native之react-native-vector-icons
  10. exls表格搜索快捷键_excel表格快速查找快捷键
  11. SSL/TLS协议详解(上):密码套件,哈希,加密,密钥交换算法
  12. [Unity][摄像机视角]多个摄像机之间切换
  13. 常用 25/26 Flash 系列器件型号、ID、容量对照表
  14. 上亿会员 为b站会员购众筹项目打下消费基础
  15. JS基础学习--第一周
  16. 原生JS实现点击按钮显示更多内容
  17. 无人驾驶公司实力排名---自动驾驶初创企业排名(roadstar.ai、pony.ai、momenta、景驰和驭势科技等)
  18. Android 开源项目及网址
  19. 微信和淘宝最赤裸的分析
  20. 七牛云对象存储绑定个人域名

热门文章

  1. Pyechart(一) 折线图
  2. onpaste事件的浅谈
  3. 华为手机手指敲击两下屏幕或在屏幕画个圈截图操作技巧
  4. 计算机用户开机默认,开机有两个账户默认登录一个怎么设置_win10怎么设置默认账户登录-系统城...
  5. 准备蓝桥杯--dyx--特殊的数字
  6. 中国泳装(泳装)市场趋势报告、技术动态创新及市场预测
  7. C++学习之全局函数和成员函数
  8. 以太坊客户端Ethereum Wallet与Geth区别简介
  9. 亚马逊跟卖快速出单跟卖方式,跟卖系统
  10. K8S入门系列(26)-K8S之Schedule