/** * virNetlinkCommand: * @nlmsg: pointer to netlink message * @respbuf: pointer to pointer where response buffer will be allocated * @respbuflen: pointer to integer holding the size of the response buffer * on return of the function. * @nl_pid: the pid of the process to talk to, i.e., pid = 0 for kernel * * Send the given message to the netlink layer and receive response. * Returns 0 on success, -1 on error. In case of error, no response * buffer will be returned. */ int virNetlinkCommand(struct nl_msg *nl_msg, unsigned char **respbuf, unsigned int *respbuflen, uint32_t src_pid, uint32_t dst_pid) { int rc = 0; struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK, .nl_pid = dst_pid, .nl_groups = 0, }; ssize_t nbytes; struct timeval tv = { .tv_sec = NETLINK_ACK_TIMEOUT_S, }; fd_set readfds; int fd; int n; struct nlmsghdr *nlmsg = nlmsg_hdr(nl_msg); virNetlinkHandle *nlhandle = virNetlinkAlloc(); if (!nlhandle) { virReportSystemError(errno, "%s", _("cannot allocate nlhandle for netlink")); return -1; } if (nl_connect(nlhandle, NETLINK_ROUTE) < 0) { virReportSystemError(errno, "%s", _("cannot connect to netlink socket")); rc = -1; goto error; } nlmsg_set_dst(nl_msg, &nladdr); nlmsg->nlmsg_pid = src_pid ? src_pid : getpid(); nbytes = nl_send_auto_complete(nlhandle, nl_msg); if (nbytes < 0) { virReportSystemError(errno, "%s", _("cannot send to netlink socket")); rc = -1; goto error; } fd = nl_socket_get_fd(nlhandle); FD_ZERO(&readfds); FD_SET(fd, &readfds); n = select(fd + 1, &readfds, NULL, NULL, &tv); if (n <= 0) { if (n < 0) virReportSystemError(errno, "%s", _("error in select call")); if (n == 0) virReportSystemError(ETIMEDOUT, "%s", _("no valid netlink response was received")); rc = -1; goto error; } *respbuflen = nl_recv(nlhandle, &nladdr, respbuf, NULL); if (*respbuflen <= 0) { virReportSystemError(errno, "%s", _("nl_recv failed")); rc = -1; } error: if (rc == -1) { VIR_FREE(*respbuf); *respbuf = NULL; *respbuflen = 0; } virNetlinkFree(nlhandle); return rc; } static void virNetlinkEventServerLock(virNetlinkEventSrvPrivatePtr driver) { virMutexLock(&driver->lock); }
/** * virNetlinkCommand: * @nlmsg: pointer to netlink message * @respbuf: pointer to pointer where response buffer will be allocated * @respbuflen: pointer to integer holding the size of the response buffer * on return of the function. * @src_pid: the pid of the process to send a message * @dst_pid: the pid of the process to talk to, i.e., pid = 0 for kernel * @protocol: netlink protocol * @groups: the group identifier * * Send the given message to the netlink layer and receive response. * Returns 0 on success, -1 on error. In case of error, no response * buffer will be returned. */ int virNetlinkCommand(struct nl_msg *nl_msg, struct nlmsghdr **resp, unsigned int *respbuflen, uint32_t src_pid, uint32_t dst_pid, unsigned int protocol, unsigned int groups) { int ret = -1; struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK, .nl_pid = dst_pid, .nl_groups = 0, }; ssize_t nbytes; struct pollfd fds[1]; int fd; int n; struct nlmsghdr *nlmsg = nlmsg_hdr(nl_msg); virNetlinkHandle *nlhandle = NULL; int len = 0; if (protocol >= MAX_LINKS) { virReportSystemError(EINVAL, _("invalid protocol argument: %d"), protocol); goto cleanup; } if (!(nlhandle = virNetlinkCreateSocket(protocol))) goto cleanup; fd = nl_socket_get_fd(nlhandle); if (fd < 0) { virReportSystemError(errno, "%s", _("cannot get netlink socket fd")); goto cleanup; } if (groups && nl_socket_add_membership(nlhandle, groups) < 0) { virReportSystemError(errno, "%s", _("cannot add netlink membership")); goto cleanup; } nlmsg_set_dst(nl_msg, &nladdr); nlmsg->nlmsg_pid = src_pid ? src_pid : getpid(); nbytes = nl_send_auto_complete(nlhandle, nl_msg); if (nbytes < 0) { virReportSystemError(errno, "%s", _("cannot send to netlink socket")); goto cleanup; } memset(fds, 0, sizeof(fds)); fds[0].fd = fd; fds[0].events = POLLIN; n = poll(fds, ARRAY_CARDINALITY(fds), NETLINK_ACK_TIMEOUT_S); if (n <= 0) { if (n < 0) virReportSystemError(errno, "%s", _("error in poll call")); if (n == 0) virReportSystemError(ETIMEDOUT, "%s", _("no valid netlink response was received")); goto cleanup; } len = nl_recv(nlhandle, &nladdr, (unsigned char **)resp, NULL); if (len == 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nl_recv failed - returned 0 bytes")); goto cleanup; } if (len < 0) { virReportSystemError(errno, "%s", _("nl_recv failed")); goto cleanup; } ret = 0; *respbuflen = len; cleanup: if (ret < 0) { *resp = NULL; *respbuflen = 0; } virNetlinkFree(nlhandle); return ret; } /** * virNetlinkDumpLink: * * @ifname: The name of the interface; only use if ifindex <= 0 * @ifindex: The interface index; may be <= 0 if ifname is given * @data: Gets a pointer to the raw data from netlink. MUST BE FREED BY CALLER! * @nlattr: Pointer to a pointer of netlink attributes that will contain * the results * @src_pid: pid used for nl_pid of the local end of the netlink message * (0 == "use getpid()") * @dst_pid: pid of destination nl_pid if the kernel * is not the target of the netlink message but it is to be * sent to another process (0 if sending to the kernel) * * Get information from netlink about an interface given its name or index. * * Returns 0 on success, -1 on fatal error. */ int virNetlinkDumpLink(const char *ifname, int ifindex, void **nlData, struct nlattr **tb, uint32_t src_pid, uint32_t dst_pid) { int rc = -1; struct nlmsghdr *resp = NULL; struct nlmsgerr *err; struct ifinfomsg ifinfo = { .ifi_family = AF_UNSPEC, .ifi_index = ifindex }; unsigned int recvbuflen; struct nl_msg *nl_msg; if (ifname && ifindex <= 0 && virNetDevGetIndex(ifname, &ifindex) < 0) return -1; ifinfo.ifi_index = ifindex; nl_msg = nlmsg_alloc_simple(RTM_GETLINK, NLM_F_REQUEST); if (!nl_msg) { virReportOOMError(); return -1; } if (nlmsg_append(nl_msg, &ifinfo, sizeof(ifinfo), NLMSG_ALIGNTO) < 0) goto buffer_too_small; if (ifname) { if (nla_put(nl_msg, IFLA_IFNAME, strlen(ifname)+1, ifname) < 0) goto buffer_too_small; } # ifdef RTEXT_FILTER_VF /* if this filter exists in the kernel's netlink implementation, * we need to set it, otherwise the response message will not * contain the IFLA_VFINFO_LIST that we're looking for. */ { uint32_t ifla_ext_mask = RTEXT_FILTER_VF; if (nla_put(nl_msg, IFLA_EXT_MASK, sizeof(ifla_ext_mask), &ifla_ext_mask) < 0) { goto buffer_too_small; } } # endif if (virNetlinkCommand(nl_msg, &resp, &recvbuflen, src_pid, dst_pid, NETLINK_ROUTE, 0) < 0) goto cleanup; if (recvbuflen < NLMSG_LENGTH(0) || resp == NULL) goto malformed_resp; switch (resp->nlmsg_type) { case NLMSG_ERROR: err = (struct nlmsgerr *)NLMSG_DATA(resp); if (resp->nlmsg_len < NLMSG_LENGTH(sizeof(*err))) goto malformed_resp; if (err->error) { virReportSystemError(-err->error, _("error dumping %s (%d) interface"), ifname, ifindex); goto cleanup; } break; case GENL_ID_CTRL: case NLMSG_DONE: rc = nlmsg_parse(resp, sizeof(struct ifinfomsg), tb, IFLA_MAX, NULL); if (rc < 0) goto malformed_resp; break; default: goto malformed_resp; } rc = 0; cleanup: nlmsg_free(nl_msg); if (rc < 0) VIR_FREE(resp); *nlData = resp; return rc; malformed_resp: virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("malformed netlink response message")); goto cleanup; buffer_too_small: virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("allocated netlink buffer is too small")); goto cleanup; }
/** * virNetlinkCommand: * @nlmsg: pointer to netlink message * @respbuf: pointer to pointer where response buffer will be allocated * @respbuflen: pointer to integer holding the size of the response buffer * on return of the function. * @src_pid: the pid of the process to send a message * @dst_pid: the pid of the process to talk to, i.e., pid = 0 for kernel * @protocol: netlink protocol * @groups: the group identifier * * Send the given message to the netlink layer and receive response. * Returns 0 on success, -1 on error. In case of error, no response * buffer will be returned. */ int virNetlinkCommand(struct nl_msg *nl_msg, struct nlmsghdr **resp, unsigned int *respbuflen, uint32_t src_pid, uint32_t dst_pid, unsigned int protocol, unsigned int groups) { int rc = 0; struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK, .nl_pid = dst_pid, .nl_groups = 0, }; ssize_t nbytes; struct pollfd fds[1]; int fd; int n; struct nlmsghdr *nlmsg = nlmsg_hdr(nl_msg); virNetlinkHandle *nlhandle = NULL; if (protocol >= MAX_LINKS) { virReportSystemError(EINVAL, _("invalid protocol argument: %d"), protocol); return -EINVAL; } nlhandle = virNetlinkAlloc(); if (!nlhandle) { virReportSystemError(errno, "%s", _("cannot allocate nlhandle for netlink")); return -1; } if (nl_connect(nlhandle, protocol) < 0) { virReportSystemError(errno, _("cannot connect to netlink socket with protocol %d"), protocol); rc = -1; goto error; } fd = nl_socket_get_fd(nlhandle); if (fd < 0) { virReportSystemError(errno, "%s", _("cannot get netlink socket fd")); rc = -1; goto error; } if (groups && nl_socket_add_membership(nlhandle, groups) < 0) { virReportSystemError(errno, "%s", _("cannot add netlink membership")); rc = -1; goto error; } nlmsg_set_dst(nl_msg, &nladdr); nlmsg->nlmsg_pid = src_pid ? src_pid : getpid(); nbytes = nl_send_auto_complete(nlhandle, nl_msg); if (nbytes < 0) { virReportSystemError(errno, "%s", _("cannot send to netlink socket")); rc = -1; goto error; } memset(fds, 0, sizeof(fds)); fds[0].fd = fd; fds[0].events = POLLIN; n = poll(fds, ARRAY_CARDINALITY(fds), NETLINK_ACK_TIMEOUT_S); if (n <= 0) { if (n < 0) virReportSystemError(errno, "%s", _("error in poll call")); if (n == 0) virReportSystemError(ETIMEDOUT, "%s", _("no valid netlink response was received")); rc = -1; goto error; } *respbuflen = nl_recv(nlhandle, &nladdr, (unsigned char **)resp, NULL); if (*respbuflen <= 0) { virReportSystemError(errno, "%s", _("nl_recv failed")); rc = -1; } error: if (rc == -1) { VIR_FREE(*resp); *resp = NULL; *respbuflen = 0; } virNetlinkFree(nlhandle); return rc; } static void virNetlinkEventServerLock(virNetlinkEventSrvPrivatePtr driver) { virMutexLock(&driver->lock); }
int nlComm(struct nl_msg *nl_msg, unsigned char **respbuf, unsigned int *respbuflen, int nl_pid) { int rc = 0; struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK, .nl_pid = nl_pid, .nl_groups = 0, }; ssize_t nbytes; struct timeval tv = { .tv_sec = NETLINK_ACK_TIMEOUT_S, }; fd_set readfds; int fd; int n; struct nlmsghdr *nlmsg = nlmsg_hdr(nl_msg); struct nl_handle *nlhandle = nl_handle_alloc(); if (!nlhandle) { virReportSystemError(errno, "%s", _("cannot allocate nlhandle for netlink")); return -1; } if (nl_connect(nlhandle, NETLINK_ROUTE) < 0) { virReportSystemError(errno, "%s", _("cannot connect to netlink socket")); rc = -1; goto err_exit; } nlmsg_set_dst(nl_msg, &nladdr); nlmsg->nlmsg_pid = getpid(); nbytes = nl_send_auto_complete(nlhandle, nl_msg); if (nbytes < 0) { virReportSystemError(errno, "%s", _("cannot send to netlink socket")); rc = -1; goto err_exit; } fd = nl_socket_get_fd(nlhandle); FD_ZERO(&readfds); FD_SET(fd, &readfds); n = select(fd + 1, &readfds, NULL, NULL, &tv); if (n <= 0) { if (n < 0) virReportSystemError(errno, "%s", _("error in select call")); if (n == 0) virReportSystemError(ETIMEDOUT, "%s", _("no valid netlink response was received")); rc = -1; goto err_exit; } *respbuflen = nl_recv(nlhandle, &nladdr, respbuf, NULL); if (*respbuflen <= 0) { virReportSystemError(errno, "%s", _("nl_recv failed")); rc = -1; } err_exit: if (rc == -1) { VIR_FREE(*respbuf); *respbuf = NULL; *respbuflen = 0; } nl_handle_destroy(nlhandle); return rc; } #else int nlComm(struct nl_msg *nl_msg ATTRIBUTE_UNUSED, unsigned char **respbuf ATTRIBUTE_UNUSED, unsigned int *respbuflen ATTRIBUTE_UNUSED, int nl_pid ATTRIBUTE_UNUSED) { netlinkError(VIR_ERR_INTERNAL_ERROR, "%s", # if defined(__linux__) && !defined(HAVE_LIBNL) _("nlComm is not supported since libnl was not available")); # else _("nlComm is not supported on non-linux platforms")); # endif return -1; }
struct match_msg *match_nl_alloc_msg(uint8_t type, uint32_t pid, int flags, int size, int family) { struct match_msg *msg; static uint32_t seq = 0; msg = (struct match_msg *) malloc(sizeof(struct match_msg)); if (!msg) return NULL; msg->nlbuf = nlmsg_alloc(); msg->msg = genlmsg_put(msg->nlbuf, 0, seq, family, (int)size, flags, type, NET_MAT_GENL_VERSION); msg->seq = seq++; if (pid) { struct nl_msg *nl_msg = msg->nlbuf; struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK, .nl_pid = pid, .nl_groups = 0, }; nlmsg_set_dst(nl_msg, &nladdr); } return msg; } struct match_msg *match_nl_get_msg(struct nl_sock *nsd, uint8_t cmd, uint32_t pid, unsigned int ifindex, int family) { struct match_msg *msg; sigset_t bs; int err; msg = match_nl_alloc_msg(cmd, pid, NLM_F_REQUEST|NLM_F_ACK, 0, family); if (!msg) { MAT_LOG(ERR, "Error: Allocation failure\n"); return NULL; } nla_put_u32(msg->nlbuf, NET_MAT_IDENTIFIER_TYPE, NET_MAT_IDENTIFIER_IFINDEX); nla_put_u32(msg->nlbuf, NET_MAT_IDENTIFIER, ifindex); nl_send_auto(nsd, msg->nlbuf); match_nl_free_msg(msg); sigemptyset(&bs); sigaddset(&bs, SIGINT); sigprocmask(SIG_UNBLOCK, &bs, NULL); msg = match_nl_recv_msg(nsd, &err); sigprocmask(SIG_BLOCK, &bs, NULL); return msg; } static int match_nl_get_port(struct nl_sock *nsd, uint32_t pid, unsigned int ifindex, int family, uint8_t cmd, struct net_mat_port *ports, uint32_t *port_id, uint32_t *glort) { struct net_mat_port *port_query = NULL; struct match_msg *msg; sigset_t bs; int err; msg = match_nl_alloc_msg(cmd, pid, NLM_F_REQUEST|NLM_F_ACK, 0, family); if (!msg) { MAT_LOG(ERR, "Error: Allocation failure\n"); return -ENOMEM; } if (nla_put_u32(msg->nlbuf, NET_MAT_IDENTIFIER_TYPE, NET_MAT_IDENTIFIER_IFINDEX) || nla_put_u32(msg->nlbuf, NET_MAT_IDENTIFIER, ifindex)) { match_nl_free_msg(msg); return -EMSGSIZE; } err = match_put_ports(msg->nlbuf, ports); if (err) { match_nl_free_msg(msg); return -EMSGSIZE; } nl_send_auto(nsd, msg->nlbuf); match_nl_free_msg(msg); sigemptyset(&bs); sigaddset(&bs, SIGINT); sigprocmask(SIG_UNBLOCK, &bs, NULL); msg = match_nl_recv_msg(nsd, &err); if (msg) { struct nlmsghdr *nlh = msg->msg; struct nlattr *tb[NET_MAT_MAX+1]; int err; err = genlmsg_parse(nlh, 0, tb, NET_MAT_MAX, match_get_tables_policy); if (err < 0) { MAT_LOG(ERR, "Warning: unable to parse pci to lport msg\n"); match_nl_free_msg(msg); return -EINVAL; } if (match_nl_table_cmd_to_type(stdout, true, NET_MAT_PORTS, tb)) { match_nl_free_msg(msg); return -EINVAL; } if (tb[NET_MAT_PORTS]) { err = match_get_ports(stdout, verbose, tb[NET_MAT_PORTS], &port_query); if (err) { match_nl_free_msg(msg); return -EINVAL; } } if (!port_query) { match_nl_free_msg(msg); return -EINVAL; } if (cmd == NET_MAT_PORT_CMD_GET_LPORT) *port_id = port_query[0].port_id; else if (cmd == NET_MAT_PORT_CMD_GET_PHYS_PORT) *port_id = port_query[0].port_phys_id; if (glort) *glort = port_query[0].glort; } match_nl_free_msg(msg); free(port_query); return 0; } int match_nl_pci_lport(struct nl_sock *nsd, uint32_t pid, unsigned int ifindex, int family, uint8_t bus, uint8_t device, uint8_t function, uint32_t *lport, uint32_t *glort) { struct net_mat_port port = {.pci = {0}, .port_id = NET_MAT_PORT_ID_UNSPEC, .mac_addr = 0, .port_phys_id = 0}; struct net_mat_port ports[2] = {{0}, {0}}; int err; ports[0] = ports[1] = port; ports[0].pci.bus = bus; ports[0].pci.device = device; ports[0].pci.function = function; err = match_nl_get_port(nsd, pid, ifindex, family, NET_MAT_PORT_CMD_GET_LPORT, ports, lport, glort); return err; } int match_nl_mac_lport(struct nl_sock *nsd, uint32_t pid, unsigned int ifindex, int family, uint64_t mac, uint32_t *lport, uint32_t *glort) { struct net_mat_port port = {.pci = {0}, .port_id = NET_MAT_PORT_ID_UNSPEC, .mac_addr = 0, .port_phys_id = 0}; struct net_mat_port ports[2] = {{0}, {0}}; int err; ports[0] = ports[1] = port; ports[0].mac_addr = mac; err = match_nl_get_port(nsd, pid, ifindex, family, NET_MAT_PORT_CMD_GET_LPORT, ports, lport, glort); return err; } int match_nl_lport_to_phys_port(struct nl_sock *nsd, uint32_t pid, unsigned int ifindex, int family, uint32_t lport, uint32_t *phys_port, uint32_t *glort) { struct net_mat_port port = {.pci = {0}, .port_id = NET_MAT_PORT_ID_UNSPEC, .mac_addr = 0, .port_phys_id = 0}; struct net_mat_port ports[2] = {{0}, {0}}; int err; ports[0] = ports[1] = port; ports[0].port_id = lport; err = match_nl_get_port(nsd, pid, ifindex, family, NET_MAT_PORT_CMD_GET_PHYS_PORT, ports, phys_port, glort); return err; }