linux netlink 机制,Linux Netlink 编程
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 编程相关推荐
- linux sysctl机制,Linux操作系统sysctl机制的思想与实现
续<linux的netlink机制>:其实只要同时提供实现一个内核netlink的内核模块和一个定制用户策略的用户空间netlink程序,你就可以完全控制linux内核了,这里内核的net ...
- linux模块化机制,Linux模块化机制和module_init
> 引子:模块化机制优点 模块化机制(module)是Linux系统的一大创新,是Linux驱动开发和运行的基础(当然,module并不仅仅是支撑驱动).其优点在于: 1.在系统运行动态加载模块 ...
- linux rcu机制,Linux RCU机制详解 (透彻)
一:前言 RCU机制出现的比较早,只是在linux kernel中一直到2.5版本的时候才被采用.关于RCU机制,这里就不做过多的介绍了,网上有很多有关RCU介绍和使用的文档.请自行查阅.本文主要是从 ...
- linux sysctl机制,Linux系统控制文件 /etc/sysctl.conf
/etc/sysctl.conf这个目录主要是配置一些系统信息,而且它的内容全部是对应于/proc/sys/这个目录的子目录及文件.这样或许你不理解,先看看我的系统/etc/sysctl.conf这个 ...
- c语言linux消息机制,linux消息机制的过程是什么啊,请赐教
LINUX的安装过程很简单,按照它的提示进行就可以了.重点就是分区那里.通常我们使用双系统,那样我们在LINUX分区的时候不要把WIN分区跟格掉就好,然后要记得分一个SWAP分区,然后根据您的需要进行 ...
- linux ns机制,Linux内核API ns_to_timespec
ns_to_timespec函数功能描述:函数ns_to_timespec( )将参数表示的时间转换成用结构体timespec变量表示的时间,参数的时间单位是纳秒. ns_to_timespec文件包 ...
- mono linux 运行机制,linux – Mono如何神奇?
我正在学习C#,所以我制作了一个名为Hello,World!的C#程序,然后用mono-csc编译并用mono运行它: $mono-csc Hello.cs $mono Hello.exe Hello ...
- NetLink机制使用
前些日子研究如何在Android实现USB-Audio的热插拔,顺带了解了一下netlink机制.netlink在TCP/IP方面用得较多,但根据需要也可用在HDMI/USB等热插拔消息通知.前人已经 ...
- 【Linux 内核】Linux 内核特性 ( 组织形式 | 进程调度 | 内核线程 | 多平台虚拟内存管理 | 虚拟文件系统 | 内核模块机制 | 定制系统调用 | 网络模块架构 )
文章目录 一.Linux 内核特性 1.Linux 内核组织形式 2.Linux 进程调度 3.Linux 内核线程 4.Linux 内核多平台虚拟内存管理 5.Linux 虚拟文件系统 6.Linu ...
最新文章
- 计算机网络(NETWORK 部分二) 第1-2天
- rabbitmq一:基本概念
- 文本挖掘预处理:向量化与Hash Trick
- 一文读懂 | 进程并发与同步
- TensorFlow2.0(五)--Keras构建Wide Deep模型
- Linux进程间通信(匿名管道)
- 刷机工具-fastboot
- charles V4.2.1版本 破解码
- react-native之react-native-vector-icons
- exls表格搜索快捷键_excel表格快速查找快捷键
- SSL/TLS协议详解(上):密码套件,哈希,加密,密钥交换算法
- [Unity][摄像机视角]多个摄像机之间切换
- 常用 25/26 Flash 系列器件型号、ID、容量对照表
- 上亿会员 为b站会员购众筹项目打下消费基础
- JS基础学习--第一周
- 原生JS实现点击按钮显示更多内容
- 无人驾驶公司实力排名---自动驾驶初创企业排名(roadstar.ai、pony.ai、momenta、景驰和驭势科技等)
- Android 开源项目及网址
- 微信和淘宝最赤裸的分析
- 七牛云对象存储绑定个人域名