static int lookup_brc_multicast_group(int *multicast_group) { struct nl_sock *sock; struct ofpbuf request, *reply; struct nlattr *attrs[ARRAY_SIZE(brc_multicast_policy)]; int retval; retval = nl_sock_create(NETLINK_GENERIC, &sock); if (retval) { return retval; } ofpbuf_init(&request, 0); nl_msg_put_genlmsghdr(&request, 0, brc_family, NLM_F_REQUEST, BRC_GENL_C_QUERY_MC, 1); retval = nl_sock_transact(sock, &request, &reply); ofpbuf_uninit(&request); if (retval) { nl_sock_destroy(sock); return retval; } if (!nl_policy_parse(reply, NLMSG_HDRLEN + GENL_HDRLEN, brc_multicast_policy, attrs, ARRAY_SIZE(brc_multicast_policy))) { nl_sock_destroy(sock); ofpbuf_delete(reply); return EPROTO; } *multicast_group = nl_attr_get_u32(attrs[BRC_GENL_A_MC_GROUP]); nl_sock_destroy(sock); ofpbuf_delete(reply); return 0; }
/* Closes 'dp'. */ void dpif_close(struct dpif *dp) { if (dp) { nl_sock_destroy(dp->sock); } }
/* Opens a socket for brcompat notifications. Returns 0 if successful, * otherwise a positive errno value. */ static int brc_open(struct nl_sock **sock) { int multicast_group = 0; int retval; retval = nl_lookup_genl_family(BRC_GENL_FAMILY_NAME, &brc_family); if (retval) { return retval; } retval = lookup_brc_multicast_group(&multicast_group); if (retval) { return retval; } retval = nl_sock_create(NETLINK_GENERIC, sock); if (retval) { return retval; } retval = nl_sock_join_mcgroup(*sock, multicast_group); if (retval) { nl_sock_destroy(*sock); *sock = NULL; } return retval; }
/* Looks up the Netlink multicast group and datapath index of a datapath * by either the datapath index or name. If 'dp_idx' points to a value * of '-1', then 'dp_name' is used to lookup the datapath. If successful, * stores the multicast group in '*multicast_group' and the index in * '*dp_idx' and returns 0. Otherwise, returns a positive errno value. */ static int query_datapath(int *dp_idx, int *multicast_group, const char *dp_name) { struct nl_sock *sock; struct ofpbuf request, *reply; struct nlattr *attrs[ARRAY_SIZE(openflow_multicast_policy)]; int retval; retval = nl_sock_create(NETLINK_GENERIC, 0, 0, 0, &sock); if (retval) { return retval; } ofpbuf_init(&request, 0); nl_msg_put_genlmsghdr(&request, sock, 0, openflow_family, NLM_F_REQUEST, DP_GENL_C_QUERY_DP, 1); if (*dp_idx != -1) { nl_msg_put_u32(&request, DP_GENL_A_DP_IDX, *dp_idx); } if (dp_name) { nl_msg_put_string(&request, DP_GENL_A_DP_NAME, dp_name); } retval = nl_sock_transact(sock, &request, &reply); ofpbuf_uninit(&request); if (retval) { nl_sock_destroy(sock); return retval; } if (!nl_policy_parse(reply, NLMSG_HDRLEN + GENL_HDRLEN, openflow_multicast_policy, attrs, ARRAY_SIZE(openflow_multicast_policy))) { nl_sock_destroy(sock); ofpbuf_delete(reply); return EPROTO; } *dp_idx = nl_attr_get_u32(attrs[DP_GENL_A_DP_IDX]); *multicast_group = nl_attr_get_u32(attrs[DP_GENL_A_MC_GROUP]); nl_sock_destroy(sock); ofpbuf_delete(reply); return 0; }
/* Completes Netlink dump operation 'dump', which must have been initialized * with nl_dump_start(). Returns 0 if the dump operation was error-free, * otherwise a positive errno value describing the problem. */ int nl_dump_done(struct nl_dump *dump) { /* Drain any remaining messages that the client didn't read. Otherwise the * kernel will continue to queue them up and waste buffer space. */ while (!dump->status) { struct ofpbuf reply; if (!nl_dump_next(dump, &reply)) { assert(dump->status); } } if (dump->sock) { if (dump->sock->dump) { dump->sock->dump = NULL; } else { nl_sock_destroy(dump->sock); } } ofpbuf_uninit(&dump->buffer); return dump->status == EOF ? 0 : dump->status; }