/*
- * Copyright (c) 2009, 2010, 2011 Nicira Networks.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
/* Passed in by nln_create(). */
int multicast_group; /* Multicast group we listen on. */
- int protocol; /* Protocal passed to nl_sock_create(). */
+ int protocol; /* Protocol passed to nl_sock_create(). */
nln_parse_func *parse; /* Message parsing function. */
void *change; /* Change passed to parse. */
};
+struct nln_notifier {
+ struct nln *nln; /* Parent nln. */
+
+ struct list node;
+ nln_notify_func *cb;
+ void *aux;
+};
+
/* Creates an nln handle which may be used to manage change notifications. The
* created handle will listen for netlink messages on 'multicast_group' using
* netlink protocol 'protocol' (e.g. NETLINK_ROUTE, NETLINK_GENERIC, ...).
}
/* Destroys 'nln' by freeing any memory it has reserved and closing any sockets
- * it has opened. */
+ * it has opened.
+ *
+ * The caller is responsible for destroying any notifiers created by this
+ * 'nln' before destroying 'nln'. */
void
nln_destroy(struct nln *nln)
{
if (nln) {
+ ovs_assert(list_is_empty(&nln->all_notifiers));
nl_sock_destroy(nln->notify_sock);
free(nln);
}
* This is probably not the function you want. You should probably be using
* message specific notifiers like rtnetlink_link_notifier_register().
*
- * Returns 0 if successful, otherwise a positive errno value. */
-int
-nln_notifier_register(struct nln *nln, struct nln_notifier *notifier,
- nln_notify_func *cb, void *aux)
+ * Returns an initialized nln_notifier if successful, otherwise NULL. */
+struct nln_notifier *
+nln_notifier_create(struct nln *nln, nln_notify_func *cb, void *aux)
{
+ struct nln_notifier *notifier;
+
if (!nln->notify_sock) {
struct nl_sock *sock;
int error;
}
if (error) {
nl_sock_destroy(sock);
- VLOG_WARN("could not create netlink socket: %s", strerror(error));
- return error;
+ VLOG_WARN("could not create netlink socket: %s",
+ ovs_strerror(error));
+ return NULL;
}
nln->notify_sock = sock;
} else {
/* Catch up on notification work so that the new notifier won't
* receive any stale notifications. */
- nln_notifier_run(nln);
+ nln_run(nln);
}
+ notifier = xmalloc(sizeof *notifier);
list_push_back(&nln->all_notifiers, ¬ifier->node);
notifier->cb = cb;
notifier->aux = aux;
- return 0;
+ notifier->nln = nln;
+ return notifier;
}
-/* Cancels notification on 'notifier', which must have previously been
- * registered with nln_notifier_register(). */
+/* Destroys 'notifier', which must have previously been created with
+ * nln_notifier_register(). */
void
-nln_notifier_unregister(struct nln *nln, struct nln_notifier *notifier)
+nln_notifier_destroy(struct nln_notifier *notifier)
{
- list_remove(¬ifier->node);
- if (list_is_empty(&nln->all_notifiers)) {
- nl_sock_destroy(nln->notify_sock);
- nln->notify_sock = NULL;
+ if (notifier) {
+ struct nln *nln = notifier->nln;
+
+ list_remove(¬ifier->node);
+ if (list_is_empty(&nln->all_notifiers)) {
+ nl_sock_destroy(nln->notify_sock);
+ nln->notify_sock = NULL;
+ }
+ free(notifier);
}
}
/* Calls all of the registered notifiers, passing along any as-yet-unreported
* change events. */
void
-nln_notifier_run(struct nln *nln)
+nln_run(struct nln *nln)
{
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
nln->has_run = true;
for (;;) {
- struct ofpbuf *buf;
+ uint64_t buf_stub[4096 / 8];
+ struct ofpbuf buf;
int error;
+ 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)) {
+ if (nln->parse(&buf, nln->change)) {
nln_report(nln, nln->change);
} else {
VLOG_WARN_RL(&rl, "received bad netlink message");
nln_report(nln, NULL);
}
- ofpbuf_delete(buf);
+ ofpbuf_uninit(&buf);
} else if (error == EAGAIN) {
return;
} else {
VLOG_WARN_RL(&rl, "netlink receive buffer overflowed");
} else {
VLOG_WARN_RL(&rl, "error reading netlink socket: %s",
- strerror(error));
+ ovs_strerror(error));
}
nln_report(nln, NULL);
}
/* Causes poll_block() to wake up when change notifications are ready. */
void
-nln_notifier_wait(struct nln *nln)
+nln_wait(struct nln *nln)
{
nln->has_run = false;
if (nln->notify_sock) {