secgateway/Platform/user/configm/config-server/netconfig/bridge/brnetlink.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;
}