如何在Linux下用ioctl/Netlink系统调用在C语言中创建veth对
如何用C语言通过Netlink/ioctl创建Linux veth设备对
结论:完全可以实现
Linux上的ip link命令底层就是通过Netlink系统调用实现的,所以用C语言直接调用Netlink接口完全能创建veth设备对;另外也可以用ioctl方式,但Netlink是更现代、更灵活的标准方案,推荐优先使用。
Netlink实现示例代码
以下是一个完整的C语言示例,通过Netlink创建指定名称的veth设备对:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <linux/netlink.h> #include <linux/rtnetlink.h> #include <linux/if_link.h> #define NLMSG_TAIL(nmsg) ((struct rtattr *) (((char *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) static int add_veth_pair(const char *name1, const char *name2) { int sockfd; struct sockaddr_nl sa; struct nlmsghdr *nlh; struct ifinfomsg *ifm; struct rtattr *rta; char buf[4096]; int ret; // 创建Netlink套接字 sockfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (sockfd < 0) { perror("socket"); return -1; } memset(&sa, 0, sizeof(sa)); sa.nl_family = AF_NETLINK; sa.nl_pid = getpid(); sa.nl_groups = 0; if (bind(sockfd, (struct sockaddr *)&sa, sizeof(sa)) < 0) { perror("bind"); close(sockfd); return -1; } // 构建Netlink消息 nlh = (struct nlmsghdr *)buf; nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); nlh->nlmsg_type = RTM_NEWLINK; nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL; nlh->nlmsg_seq = 1; nlh->nlmsg_pid = getpid(); ifm = NLMSG_DATA(nlh); ifm->ifi_family = AF_UNSPEC; ifm->ifi_type = ARPHRD_ETHER; ifm->ifi_index = 0; ifm->ifi_flags = IFF_UP | IFF_RUNNING | IFF_NOARP; ifm->ifi_change = 0; // 添加主设备名称属性 rta = NLMSG_TAIL(nlh); rta->rta_type = IFLA_IFNAME; rta->rta_len = RTA_LENGTH(strlen(name1) + 1); strcpy(RTA_DATA(rta), name1); nlh->nlmsg_len = NLMSG_ALIGN(nlh->nlmsg_len) + RTA_ALIGN(rta->rta_len); // 添加veth peer关联属性 rta = NLMSG_TAIL(nlh); rta->rta_type = IFLA_LINKINFO; rta->rta_len = RTA_LENGTH(sizeof(struct ifinfomsg)); nlh->nlmsg_len = NLMSG_ALIGN(nlh->nlmsg_len) + RTA_ALIGN(rta->rta_len); struct rtattr *nest = RTA_DATA(rta); nest->rta_type = IFLA_INFO_KIND; nest->rta_len = RTA_LENGTH(strlen("veth") + 1); strcpy(RTA_DATA(nest), "veth"); rta->rta_len += RTA_ALIGN(nest->rta_len); nest = (struct rtattr *)((char *)nest + RTA_ALIGN(nest->rta_len)); nest->rta_type = IFLA_INFO_DATA; nest->rta_len = RTA_LENGTH(sizeof(struct rtattr)); rta->rta_len += RTA_ALIGN(nest->rta_len); struct rtattr *peer = RTA_DATA(nest); peer->rta_type = VETH_INFO_PEER; peer->rta_len = RTA_LENGTH(sizeof(struct ifinfomsg)); nest->rta_len += RTA_ALIGN(peer->rta_len); struct ifinfomsg *peer_ifm = RTA_DATA(peer); peer_ifm->ifi_family = AF_UNSPEC; peer_ifm->ifi_type = ARPHRD_ETHER; peer_ifm->ifi_index = 0; peer_ifm->ifi_flags = IFF_UP | IFF_RUNNING | IFF_NOARP; peer_ifm->ifi_change = 0; struct rtattr *peer_rta = (struct rtattr *)((char *)peer_ifm + NLMSG_ALIGN(sizeof(struct ifinfomsg))); peer_rta->rta_type = IFLA_IFNAME; peer_rta->rta_len = RTA_LENGTH(strlen(name2) + 1); strcpy(RTA_DATA(peer_rta), name2); peer->rta_len += RTA_ALIGN(peer_rta->rta_len); // 发送Netlink请求 ret = send(sockfd, nlh, nlh->nlmsg_len, 0); if (ret < 0) { perror("send"); close(sockfd); return -1; } // 接收内核响应 ret = recv(sockfd, buf, sizeof(buf), 0); if (ret < 0) { perror("recv"); close(sockfd); return -1; } close(sockfd); return 0; } int main(int argc, char *argv[]) { if (argc != 3) { fprintf(stderr, "Usage: %s <veth-name1> <veth-name2>\n", argv[0]); return 1; } if (add_veth_pair(argv[1], argv[2]) != 0) { fprintf(stderr, "Failed to create veth pair\n"); return 1; } printf("Veth pair %s <-> %s created successfully\n", argv[1], argv[2]); return 0; }
编译命令:gcc veth_create.c -o veth_create,运行需要root权限:sudo ./veth_create veth1 veth2。
关于ioctl的说明
ioctl也可以实现veth设备对的创建,但流程更繁琐:需要先创建两个独立的网络设备,再通过SIOCIFLINK等命令手动关联它们,而且这种方式属于较旧的接口,无法灵活处理复杂的设备属性配置,因此实际开发中很少使用。
内容的提问来源于stack exchange,提问作者Shriram S
相关产品推荐
相关产品推荐

