这篇文章给大家分享的是有关LINUX中socket与VRF怎么用的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。
LINUX socket与VRF
实验环境如下图所示:
配置如下:
#!/bin/bash sudo ip netns add ns1 sudo ip link add ns1veth2 type veth peer name eth0 netns ns1 sudo ip netns add ns2 sudo ip link add ns2veth2 type veth peer name eth0 netns ns2 sudo ip link set ns1veth2 master vrftest sudo ip link set ns2veth2 master vrftest sudo ip link set ns2veth2 up sudo ip link set ns1veth2 up sudo ip addr add 1.1.1.254/24 dev ns1veth2 sudo ip addr add 2.2.2.254/24 dev ns2veth2 sudo ip netns exec ns2 ip addr add 2.2.2.1/24 dev eth0 sudo ip netns exec ns1 ip addr add 1.1.1.1/24 dev eth0 sudo ip netns exec ns1 ip link set eth0 up sudo ip netns exec ns1 ip link set lo up sudo ip netns exec ns1 ip route add default via 1.1.1.254 dev eth0 sudo ip netns exec ns2 ip link set eth0 up sudo ip netns exec ns2 ip link set lo up sudo ip netns exec ns2 ip route add default via 2.2.2.254 dev eth0
实验使用c语言写了两个套接字交互程序:
服务器:vrfs
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<errno.h> #include<sys/types.h> #include<sys/socket.h> #include<netinet/in.h> #include <unistd.h> #define MAXLINE 4096 int main(int argc, char** argv) { int listenfd, connfd; struct sockaddr_in servaddr; char buff[4096]; int n; int on = 1; if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ){ printf("create socket error: %s(errno: %d)\n",strerror(errno),errno); exit(0); } setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); setsockopt(listenfd, SOL_SOCKET, SO_REUSEPORT, (void *)&on, sizeof(on)); memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(6666); if(argc == 2){ printf("vrf device name: %s\r\n", argv[1]); if(0 > setsockopt(listenfd, SOL_SOCKET, SO_BINDTODEVICE, argv[1], strlen(argv[1])+1)){ printf("bind socket master dev error: %s(errno: %d)\n",strerror(errno),errno); exit(0); } } if( bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){ printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno); exit(0); } if( listen(listenfd, 10) == -1){ printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno); exit(0); } printf("======waiting for client's request======\n"); while(1){ if((connfd = accept(listenfd, (struct sockaddr*)NULL, NULL)) == -1){ printf("accept socket error: %s(errno: %d)",strerror(errno),errno); continue; } n = recv(connfd, buff, MAXLINE, 0); buff[n] = '\0'; printf("recv msg from client: %s\n", buff); close(connfd); } close(listenfd); }
客户端程序:vrfc
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<errno.h> #include<sys/types.h> #include<sys/socket.h> #include<netinet/in.h> #include<unistd.h> #define MAXLINE 4096 #include <arpa/inet.h> int main(int argc, char** argv) { int sockfd, n; char *sendline = "hello vrf"; struct sockaddr_in servaddr; if( argc != 2){ printf("usage: ./client <ipaddress> [master device]\n"); exit(0); } if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){ printf("create socket error: %s(errno: %d)\n", strerror(errno),errno); exit(0); } memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(6666); if( inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0){ printf("inet_pton error for %s\n",argv[1]); exit(0); } if(argc == 3){ printf("vrf device name: %s\r\n", argv[2]); if(0 > setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, argv[2], strlen(argv[2])+1)){ printf("bind socket master dev error: %s(errno: %d)\n",strerror(errno),errno); exit(0); } } if( connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0){ printf("connect error: %s(errno: %d)\n",strerror(errno),errno); exit(0); } printf("send msg to server: hello vrf\n"); if( send(sockfd, sendline, strlen(sendline), 0) < 0) { printf("send msg error: %s(errno: %d)\n", strerror(errno), errno); exit(0); } close(sockfd); exit(0); }
在默认VRF环境下,启动两个进程,监听相同的端口和地址:程序中套接口使用了SO_REUSEADDR和SO_REUSEPORT。查看内核如何处理惊群效应。
console1:
admin@ubuntu:~/vrfsocket$ for i in {0..9}; do ./vrfc 127.0.0.1; done send msg to server: hello vrf send msg to server: hello vrf send msg to server: hello vrf send msg to server: hello vrf send msg to server: hello vrf send msg to server: hello vrf send msg to server: hello vrf send msg to server: hello vrf send msg to server: hello vrf send msg to server: hello vrf admin@ubuntu:~/vrfsocket$
console2:
admin@ubuntu:~/vrfsocket$ ./vrfs ======waiting for client's request====== recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf
console3:
admin@ubuntu:~/vrfsocket$ ./vrfs ======waiting for client's request====== recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf
新内核似乎已经能够处理惊群效应了,收到请求时不再通知所有监听该端口的服务器程序,而是会进行一定的负载均衡调度处理。
admin@ubuntu:~/vrfsocket$ for i in {0..9}; do sudo ./vrfc 127.0.0.1; done send msg to server: hello vrf send msg to server: hello vrf send msg to server: hello vrf send msg to server: hello vrf send msg to server: hello vrf send msg to server: hello vrf send msg to server: hello vrf send msg to server: hello vrf send msg to server: hello vrf send msg to server: hello vrf admin@ubuntu:~/vrfsocket$
console2:
root@ubuntu:/home/admin/vrfsocket# ./vrfs ======waiting for client's request====== recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf
console3:
root@ubuntu:/home/admin/vrfsocket# ./vrfs vrftest vrf device name: vrftest ======waiting for client's request======
结论:服务器监听套接字绑定VRF后,不再处理默认VRF中的请求
console1:
admin@ubuntu:~/vrfsocket$ for i in {0..9}; do sudo ./vrfc 1.1.1.254 vrftest; done vrf device name: vrftest send msg to server: hello vrf vrf device name: vrftest send msg to server: hello vrf vrf device name: vrftest send msg to server: hello vrf vrf device name: vrftest send msg to server: hello vrf vrf device name: vrftest send msg to server: hello vrf vrf device name: vrftest send msg to server: hello vrf vrf device name: vrftest send msg to server: hello vrf vrf device name: vrftest send msg to server: hello vrf vrf device name: vrftest send msg to server: hello vrf vrf device name: vrftest send msg to server: hello vrf admin@ubuntu:~/vrfsocket$
console2:在root用户下运行
root@ubuntu:/home/admin/vrfsocket# ./vrfs ======waiting for client's request======
console3:在root用户下运行。
root@ubuntu:/home/admin/vrfsocket# ./vrfs vrftest vrf device name: vrftest ======waiting for client's request====== recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf
结论:服务器监听套接字不绑定VRF,不能处理非默认VRF中的请求
console1:
admin@ubuntu:~/vrfsocket$ for i in {0..9}; do sudo ./vrfc 127.0.0.1; done send msg to server: hello vrf send msg to server: hello vrf send msg to server: hello vrf send msg to server: hello vrf send msg to server: hello vrf send msg to server: hello vrf send msg to server: hello vrf send msg to server: hello vrf send msg to server: hello vrf send msg to server: hello vrf admin@ubuntu:~/vrfsocket$
console2:
root@ubuntu:/home/admin/vrfsocket# ./vrfs ======waiting for client's request====== recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf
console3:
root@ubuntu:/home/admin/vrfsocket# ./vrfs vrftest vrf device name: vrftest ======waiting for client's request======
console1:
admin@ubuntu:~/vrfsocket$ for i in {0..9}; do sudo ./vrfc 127.0.0.1; done connect error: Connection refused(errno: 111) connect error: Connection refused(errno: 111) connect error: Connection refused(errno: 111) connect error: Connection refused(errno: 111) connect error: Connection refused(errno: 111) connect error: Connection refused(errno: 111) connect error: Connection refused(errno: 111) connect error: Connection refused(errno: 111) connect error: Connection refused(errno: 111) connect error: Connection refused(errno: 111) admin@ubuntu:~/vrfsocket$
console3:
root@ubuntu:/home/admin/vrfsocket# ./vrfs vrftest vrf device name: vrftest ======waiting for client's request======
console1:
admin@ubuntu:~/vrfsocket$ for i in {0..9}; do sudo ./vrfc 1.1.1.254 vrftest; done vrf device name: vrftest send msg to server: hello vrf vrf device name: vrftest send msg to server: hello vrf vrf device name: vrftest send msg to server: hello vrf vrf device name: vrftest send msg to server: hello vrf vrf device name: vrftest send msg to server: hello vrf vrf device name: vrftest send msg to server: hello vrf vrf device name: vrftest send msg to server: hello vrf vrf device name: vrftest send msg to server: hello vrf vrf device name: vrftest send msg to server: hello vrf vrf device name: vrftest send msg to server: hello vrf admin@ubuntu:~/vrfsocket$
console3:
root@ubuntu:/home/admin/vrfsocket# ./vrfs vrftest vrf device name: vrftest ======waiting for client's request====== recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf
console1:
admin@ubuntu:~/vrfsocket$ for i in {0..9}; do sudo ./vrfc 1.1.1.254 vrftest; done vrf device name: vrftest send msg to server: hello vrf vrf device name: vrftest send msg to server: hello vrf vrf device name: vrftest send msg to server: hello vrf vrf device name: vrftest send msg to server: hello vrf vrf device name: vrftest send msg to server: hello vrf vrf device name: vrftest send msg to server: hello vrf vrf device name: vrftest send msg to server: hello vrf vrf device name: vrftest send msg to server: hello vrf vrf device name: vrftest send msg to server: hello vrf vrf device name: vrftest send msg to server: hello vrf admin@ubuntu:~/vrfsocket$
console2:
root@ubuntu:/home/admin/vrfsocket# ./vrfs ======waiting for client's request====== recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf recv msg from client: hello vrf
console3:
root@ubuntu:/home/admin/vrfsocket# ./vrfs vrftest vrf device name: vrftest ======waiting for client's request======
在打开sudo sysctl -w net.ipv4.tcp_l3mdev_accept=1后,默认VRF中的监听套接字能够处理所有VRF中的请求,且优先级高于其它的VRF的监听套接字。
序号 | 结论 |
---|---|
1 | 多个服务器器监听同一地址和端口,内核会进行负载均衡,选择唤醒其中一个进程处理请求。 |
2 | 默认VRF中的服务器进程不能处理非默认VRF中的请求,非默认VRF中的服务器进程不能处理其它VRF中的请求 |
3 | 开启net.ipv4.tcp_l3mdev_accept=1后,默认VRF中的服务器进程可以处理任意VRF中的请求,且优先级最高 |
4 | 开启net.ipv4.tcp_l3mdev_accept=1后,非默认VRF中的服务器进程不能处理其它VRF中的请求,在处理本VRF中的流量时,优先级低于默认VRF中的进程。 |
感谢各位的阅读!关于“LINUX中socket与VRF怎么用”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。