#include #include #include #include #include #include #include #include #include #include #include #include "brnetlink.h" #include "ipconfig.h" #include "brconfig.h" #include "rpc_util.h" #include "rpc_common.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; }