COVERAGE_DEFINE(nln_changed);
-static void nln_report(struct nln *nln, void *change);
+static void nln_report(const struct nln *nln, void *change, int group);
struct nln {
struct nl_sock *notify_sock; /* Netlink socket. */
bool has_run; /* Guard for run and wait functions. */
/* Passed in by nln_create(). */
- int multicast_group; /* Multicast group we listen on. */
int protocol; /* Protocol passed to nl_sock_create(). */
nln_parse_func *parse; /* Message parsing function. */
void *change; /* Change passed to parse. */
struct nln *nln; /* Parent nln. */
struct ovs_list node;
+ int multicast_group; /* Multicast group we listen on. */
nln_notify_func *cb;
void *aux;
};
* Incoming messages will be parsed with 'parse' which will be passed 'change'
* as an argument. */
struct nln *
-nln_create(int protocol, int multicast_group, nln_parse_func *parse,
- void *change)
+nln_create(int protocol, nln_parse_func *parse, void *change)
{
struct nln *nln;
nln = xzalloc(sizeof *nln);
nln->notify_sock = NULL;
nln->protocol = protocol;
- nln->multicast_group = multicast_group;
nln->parse = parse;
nln->change = change;
nln->has_run = false;
*
* Returns an initialized nln_notifier if successful, otherwise NULL. */
struct nln_notifier *
-nln_notifier_create(struct nln *nln, nln_notify_func *cb, void *aux)
+nln_notifier_create(struct nln *nln, int multicast_group, nln_notify_func *cb,
+ void *aux)
{
struct nln_notifier *notifier;
+ int error;
if (!nln->notify_sock) {
struct nl_sock *sock;
- int error;
error = nl_sock_create(nln->protocol, &sock);
- if (!error) {
- error = nl_sock_join_mcgroup(sock, nln->multicast_group);
- }
if (error) {
- nl_sock_destroy(sock);
VLOG_WARN("could not create netlink socket: %s",
ovs_strerror(error));
return NULL;
nln_run(nln);
}
+ error = nl_sock_join_mcgroup(nln->notify_sock, multicast_group);
+ if (error) {
+ VLOG_WARN("could not join netlink multicast group: %s",
+ ovs_strerror(error));
+ return NULL;
+ }
+
notifier = xmalloc(sizeof *notifier);
- ovs_list_push_back(&nln->all_notifiers, ¬ifier->node);
+ notifier->multicast_group = multicast_group;
notifier->cb = cb;
notifier->aux = aux;
notifier->nln = nln;
+
+ ovs_list_push_back(&nln->all_notifiers, ¬ifier->node);
+
return notifier;
}
{
if (notifier) {
struct nln *nln = notifier->nln;
+ struct nln_notifier *iter;
+ int count = 0;
ovs_list_remove(¬ifier->node);
+
+ /* Leave the group if no other notifier is interested in it. */
+ LIST_FOR_EACH (iter, node, &nln->all_notifiers) {
+ if (iter->multicast_group == notifier->multicast_group) {
+ count++;
+ }
+ }
+ if (count == 0) {
+ nl_sock_leave_mcgroup(nln->notify_sock, notifier->multicast_group);
+ }
+
if (ovs_list_is_empty(&nln->all_notifiers)) {
nl_sock_destroy(nln->notify_sock);
nln->notify_sock = NULL;
ofpbuf_use_stub(&buf, buf_stub, sizeof buf_stub);
error = nl_sock_recv(nln->notify_sock, &buf, false);
if (!error) {
- if (nln->parse(&buf, nln->change)) {
- nln_report(nln, nln->change);
+ int group = nln->parse(&buf, nln->change);
+
+ if (group != 0) {
+ nln_report(nln, nln->change, group);
} else {
- VLOG_WARN_RL(&rl, "received bad netlink message");
- nln_report(nln, NULL);
+ VLOG_WARN_RL(&rl, "unexpected netlink message contents");
+ nln_report(nln, NULL, 0);
}
ofpbuf_uninit(&buf);
} else if (error == EAGAIN) {
if (error == ENOBUFS) {
/* The socket buffer might be full, there could be too many
* notifications, so it makes sense to call nln_report() */
- nln_report(nln, NULL);
+ nln_report(nln, NULL, 0);
VLOG_WARN_RL(&rl, "netlink receive buffer overflowed");
} else {
VLOG_WARN_RL(&rl, "error reading netlink socket: %s",
}
static void
-nln_report(struct nln *nln, void *change)
+nln_report(const struct nln *nln, void *change, int group)
{
struct nln_notifier *notifier;
}
LIST_FOR_EACH (notifier, node, &nln->all_notifiers) {
- notifier->cb(change, notifier->aux);
+ if (!change || group == notifier->multicast_group) {
+ notifier->cb(change, notifier->aux);
+ }
}
}