293 lines
7.6 KiB
C
293 lines
7.6 KiB
C
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <fcntl.h>
|
|
|
|
#include <libnetlink.h>
|
|
#include <linux/rtnetlink.h>
|
|
#include <bits/socket.h>
|
|
#include <net/if.h>
|
|
#include "list.h"
|
|
|
|
#include "rpc_types.h"
|
|
#include "rpc_util.h"
|
|
#include "rpc_common.h"
|
|
#include "brnetlink.h"
|
|
|
|
#include "ipconfig.h"
|
|
#include "brconfig.h"
|
|
#include "libbridge.h"
|
|
|
|
|
|
#define BR_NLMSG_TAIL(nmsg) \
|
|
((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
|
|
#define BR_MIN(a, b) ((a) < (b) ? (a) : (b))
|
|
|
|
int br_seq = 0;
|
|
int br_fd = -1;
|
|
|
|
int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,int alen)
|
|
{
|
|
int len = RTA_LENGTH(alen);
|
|
struct rtattr *rta;
|
|
|
|
if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) {
|
|
printf("addattr_l ERROR: message exceeded bound of %d\n",maxlen);
|
|
return -1;
|
|
}
|
|
rta = BR_NLMSG_TAIL(n);
|
|
rta->rta_type = type;
|
|
rta->rta_len = len;
|
|
memcpy(RTA_DATA(rta), data, alen);
|
|
n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
|
|
return 0;
|
|
}
|
|
|
|
int netlink_socket(unsigned long groups)
|
|
{
|
|
socklen_t addr_len;
|
|
struct sockaddr_nl snl;
|
|
int fd = -1;
|
|
int ret;
|
|
|
|
|
|
fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
|
if (fd < 0) {
|
|
rpc_log_error("Netlink: Cannot open netlink socket : (%s)",strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
ret = fcntl(fd, F_SETFL, O_NONBLOCK);
|
|
if (ret < 0) {
|
|
rpc_log_error("Netlink: Cannot set netlink socket flags : (%s)",strerror(errno));
|
|
close(fd);
|
|
return -1;
|
|
}
|
|
|
|
memset(&snl, 0, sizeof (snl));
|
|
snl.nl_family = AF_NETLINK;
|
|
snl.nl_groups = groups; /*设为0 表示不用多播,其他情况按照设置的组来进行多播,就是会多播到这些组*/
|
|
|
|
ret = bind(fd, (struct sockaddr *) &snl, sizeof (snl));
|
|
if (ret < 0) {
|
|
rpc_log_error("Netlink: Cannot bind netlink socket : (%s)",
|
|
strerror(errno));
|
|
close(fd);
|
|
return -1;
|
|
}
|
|
|
|
addr_len = sizeof (snl);
|
|
ret = getsockname(fd, (struct sockaddr *) &snl, &addr_len);
|
|
if (ret < 0 || addr_len != sizeof (snl)) {
|
|
printf("Netlink: Cannot getsockname : (%s)",strerror(errno));
|
|
close(fd);
|
|
return -1;
|
|
}
|
|
|
|
if (snl.nl_family != AF_NETLINK) {
|
|
printf("Netlink: Wrong address family %d",snl.nl_family);
|
|
close(fd);
|
|
return -1;
|
|
}
|
|
|
|
br_seq = time(NULL);
|
|
return fd;
|
|
}
|
|
|
|
int rtnl_talk(int fd , struct nlmsghdr *n,
|
|
struct nlmsghdr *answer, size_t maxlen)
|
|
{
|
|
int status;
|
|
struct nlmsghdr *h;
|
|
struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
|
|
struct iovec iov = {
|
|
.iov_base = n,
|
|
.iov_len = n->nlmsg_len
|
|
};
|
|
struct msghdr msg = {
|
|
.msg_name = &nladdr,
|
|
.msg_namelen = sizeof(nladdr),
|
|
.msg_iov = &iov,
|
|
.msg_iovlen = 1,
|
|
};
|
|
char buf[32768] = {};
|
|
|
|
n->nlmsg_seq = ++br_seq;
|
|
|
|
if (answer == NULL)
|
|
n->nlmsg_flags |= NLM_F_ACK;
|
|
|
|
status = sendmsg(fd, &msg, 0);
|
|
if (status < 0) {
|
|
perror("Cannot talk to rtnetlink");
|
|
return -1;
|
|
}
|
|
|
|
iov.iov_base = buf;
|
|
while (1) {
|
|
iov.iov_len = sizeof(buf);
|
|
status = recvmsg(fd, &msg, 0);
|
|
|
|
if (status < 0) {
|
|
if (errno == EINTR || errno == EAGAIN)
|
|
continue;
|
|
printf("netlink receive error %s (%d)\n",strerror(errno), errno);
|
|
return -1;
|
|
}
|
|
if (status == 0) {
|
|
printf("EOF on netlink\n");
|
|
return -1;
|
|
}
|
|
if (msg.msg_namelen != sizeof(nladdr)) {
|
|
printf("sender address length == %d\n",msg.msg_namelen);
|
|
exit(1);
|
|
}
|
|
for (h = (struct nlmsghdr *)buf; status >= sizeof(*h); ) {
|
|
int len = h->nlmsg_len;
|
|
int l = len - sizeof(*h);
|
|
|
|
if (l < 0 || len > status) {
|
|
if (msg.msg_flags & MSG_TRUNC) {
|
|
printf("Truncated message\n");
|
|
return -1;
|
|
}
|
|
printf("!!!malformed message: len=%d\n",len);
|
|
exit(1);
|
|
}
|
|
|
|
if (nladdr.nl_pid != 0 ||
|
|
h->nlmsg_seq != br_seq) {
|
|
/* Don't forget to skip that message. */
|
|
status -= NLMSG_ALIGN(len);
|
|
h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
|
|
continue;
|
|
}
|
|
|
|
if (h->nlmsg_type == NLMSG_ERROR) {
|
|
struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(h);
|
|
|
|
if (l < sizeof(struct nlmsgerr)) {
|
|
fprintf(stderr, "ERROR truncated\n");
|
|
} else if (!err->error) {
|
|
if (answer)
|
|
memcpy(answer, h,
|
|
BR_MIN(maxlen, h->nlmsg_len));
|
|
return 0;
|
|
}
|
|
|
|
errno = -err->error;
|
|
return -1;
|
|
}
|
|
|
|
if (answer) {
|
|
memcpy(answer, h,
|
|
BR_MIN(maxlen, h->nlmsg_len));
|
|
return 0;
|
|
}
|
|
|
|
printf("Unexpected reply!!!\n");
|
|
|
|
status -= NLMSG_ALIGN(len);
|
|
h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
|
|
}
|
|
|
|
if (msg.msg_flags & MSG_TRUNC) {
|
|
printf("Message truncated\n");
|
|
continue;
|
|
}
|
|
|
|
if (status) {
|
|
fprintf(stderr, "!!!Remnant of size %d\n", status);
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
void parse_rtattr(struct rtattr **tb, int max, struct rtattr *rta, int len)
|
|
{
|
|
while (RTA_OK(rta, len)) {
|
|
if (rta->rta_type <= max)
|
|
tb[rta->rta_type] = rta;
|
|
rta = RTA_NEXT(rta, len);
|
|
}
|
|
}
|
|
|
|
int get_br_from_port(char *port_name , char *br_name)
|
|
{
|
|
struct {
|
|
struct nlmsghdr n;
|
|
struct ifinfomsg i;
|
|
char buf[1024];
|
|
}req;
|
|
|
|
if(if_nametoindex(port_name) == 0)
|
|
{
|
|
return RET_NOTFOUND;
|
|
}
|
|
|
|
memset(&req,0,sizeof(req));
|
|
|
|
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
|
|
req.n.nlmsg_flags = NLM_F_REQUEST ;
|
|
req.n.nlmsg_type = RTM_GETLINK; /*消息类型*/
|
|
req.i.ifi_family = PF_BRIDGE;
|
|
struct {
|
|
struct nlmsghdr n;
|
|
char buf[16384];
|
|
}answer;
|
|
|
|
memset(&answer,0,sizeof(answer));
|
|
|
|
if(br_fd < 0){
|
|
br_fd = netlink_socket(0);
|
|
}
|
|
|
|
if(br_fd <0){
|
|
printf("netlink_socket failed\n");
|
|
return RET_SYSERR;
|
|
}
|
|
|
|
addattr_l(&req.n, sizeof(req), IFLA_IFNAME, port_name, strlen(port_name)+1);
|
|
if (rtnl_talk(br_fd, &req.n, &answer.n, sizeof(answer)) < 0)
|
|
return RET_SYSERR;
|
|
|
|
struct ifinfomsg *ifi = NLMSG_DATA(&answer.n);
|
|
struct rtattr *tb[IFLA_MAX+1];
|
|
|
|
printf("struct ifinfomsg: ifi_family=%u,ifi_index=%d\n",
|
|
ifi->ifi_family,ifi->ifi_index);
|
|
|
|
|
|
int len = answer.n.nlmsg_len - NLMSG_LENGTH(sizeof (struct ifinfomsg));
|
|
parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
|
|
|
|
printf("enum : IFLA_IFNAME=%s,IFLA_MTU=%d,IFLA_TXQLEN=%d\n",
|
|
(char *)RTA_DATA(tb[IFLA_IFNAME]),
|
|
*(int *)RTA_DATA(tb[IFLA_MTU]),
|
|
*(int *)RTA_DATA(tb[IFLA_TXQLEN]));
|
|
|
|
printf("if_nametoindex:%d\n",if_nametoindex((char *)RTA_DATA(tb[IFLA_IFNAME])));
|
|
|
|
if (tb[IFLA_MASTER]) {
|
|
int master = rta_getattr_u32(tb[IFLA_MASTER]);
|
|
char if_name[INTERFACE_NAMSIZ] = {0};
|
|
|
|
if_indextoname(master, if_name);
|
|
printf("master:%s\n", if_name);
|
|
|
|
if(br_get_bridge_info(if_name, NULL) == 0)
|
|
{
|
|
strncpy(br_name, if_name, BR_NAMSIZ - 1);
|
|
br_name[BR_NAMSIZ - 1] = 0;
|
|
return RET_OK;
|
|
}
|
|
}
|
|
|
|
return RET_NOTFOUND;
|
|
}
|
|
|