- if (mon) {
- dpif_close(&mon->dpif);
- nl_sock_destroy(mon->sock);
- }
-}
-
-int
-dpifmon_poll(struct dpifmon *mon, char **devnamep)
-{
- static struct vlog_rate_limit slow_rl = VLOG_RATE_LIMIT_INIT(1, 5);
- static const struct nl_policy rtnlgrp_link_policy[] = {
- [IFLA_IFNAME] = { .type = NL_A_STRING },
- [IFLA_MASTER] = { .type = NL_A_U32, .optional = true },
- };
- struct nlattr *attrs[ARRAY_SIZE(rtnlgrp_link_policy)];
- struct ofpbuf *buf;
- int error;
-
- *devnamep = NULL;
-again:
- error = nl_sock_recv(mon->sock, &buf, false);
- switch (error) {
- case 0:
- if (!nl_policy_parse(buf, NLMSG_HDRLEN + sizeof(struct ifinfomsg),
- rtnlgrp_link_policy,
- attrs, ARRAY_SIZE(rtnlgrp_link_policy))) {
- VLOG_WARN_RL(&slow_rl, "received bad rtnl message");
- error = ENOBUFS;
- } else {
- const char *devname = nl_attr_get_string(attrs[IFLA_IFNAME]);
- bool for_us;
-
- if (attrs[IFLA_MASTER]) {
- uint32_t master_ifindex = nl_attr_get_u32(attrs[IFLA_MASTER]);
- for_us = master_ifindex == mon->local_ifindex;
- } else {
- /* It's for us if that device is one of our ports. This is
- * open-coded instead of using dpif_port_query_by_name() to
- * avoid logging a warning on failure. */
- struct odp_port port;
- memset(&port, 0, sizeof port);
- strncpy(port.devname, devname, sizeof port.devname);
- for_us = !ioctl(mon->dpif.fd, ODP_PORT_QUERY, &port);
- }
-
- if (!for_us) {
- /* Not for us, try again. */
- ofpbuf_delete(buf);
- COVERAGE_INC(dpifmon_poll_false_wakeup);
- goto again;
- }
- COVERAGE_INC(dpifmon_poll_changed);
- *devnamep = xstrdup(devname);
- }
- ofpbuf_delete(buf);
- break;
-
- case EAGAIN:
- /* Nothing to do. */
- break;
-
- case ENOBUFS:
- VLOG_WARN_RL(&slow_rl, "dpifmon socket overflowed");
- break;
-
- default:
- VLOG_WARN_RL(&slow_rl, "error on dpifmon socket: %s", strerror(error));
- break;
- }
- return error;