A netlink notifier ('nln') already supports multiple notifiers. This
patch allows each of these notifiers to subscribe to a different
multicast group. Sharing a single socket for multiple event types
(each on their own multicast group) provides serialization of events
when reordering of different event types could be problematic. For
example, if a 'create' event and 'delete' event are on different
netlink multicast group, we may want to process those events in the
order in which kernel issued them, rather than in the order we happen
to check for them.
Moving the multicast group argument from nln_create() to
nln_notifier_create() allows each notifier to specify a different
multicast group. The parse callback needs to identify the group the
message belonged to by returning the corresponding group number, or 0
when an parse error occurs.
Signed-off-by: Jarno Rajahalme <[email protected]>
---
lib/netlink-notifier.c | 47 +++++++++++++++++++++++++++++------------------
lib/netlink-notifier.h | 13 +++++++------
lib/route-table.c | 28 ++++++++++++++--------------
lib/rtnetlink-link.c | 9 +++++----
4 files changed, 55 insertions(+), 42 deletions(-)
diff --git a/lib/netlink-notifier.c b/lib/netlink-notifier.c
index 45c9188..bcd6ef1 100644
--- a/lib/netlink-notifier.c
+++ b/lib/netlink-notifier.c
@@ -32,7 +32,7 @@ VLOG_DEFINE_THIS_MODULE(netlink_notifier);
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. */
@@ -40,7 +40,6 @@ struct nln {
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. */
@@ -50,6 +49,7 @@ struct nln_notifier {
struct nln *nln; /* Parent nln. */
struct ovs_list node;
+ int multicast_group; /* Multicast group we listen on. */
nln_notify_func *cb;
void *aux;
};
@@ -60,15 +60,13 @@ struct nln_notifier {
* 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;
@@ -101,20 +99,17 @@ nln_destroy(struct nln *nln)
*
* 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;
@@ -126,11 +121,21 @@ nln_notifier_create(struct nln *nln, nln_notify_func *cb,
void *aux)
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);
- list_push_back(&nln->all_notifiers, ¬ifier->node);
+ notifier->multicast_group = multicast_group;
notifier->cb = cb;
notifier->aux = aux;
notifier->nln = nln;
+
+ list_push_back(&nln->all_notifiers, ¬ifier->node);
+
return notifier;
}
@@ -142,6 +147,8 @@ nln_notifier_destroy(struct nln_notifier *notifier)
if (notifier) {
struct nln *nln = notifier->nln;
+ nl_sock_leave_mcgroup(nln->notify_sock, notifier->multicast_group);
+
list_remove(¬ifier->node);
if (list_is_empty(&nln->all_notifiers)) {
nl_sock_destroy(nln->notify_sock);
@@ -171,11 +178,13 @@ nln_run(struct nln *nln)
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);
+ nln_report(nln, NULL, 0);
}
ofpbuf_uninit(&buf);
} else if (error == EAGAIN) {
@@ -184,7 +193,7 @@ nln_run(struct nln *nln)
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",
@@ -206,7 +215,7 @@ nln_wait(struct nln *nln)
}
static void
-nln_report(struct nln *nln, void *change)
+nln_report(const struct nln *nln, void *change, int group)
{
struct nln_notifier *notifier;
@@ -215,6 +224,8 @@ nln_report(struct nln *nln, void *change)
}
LIST_FOR_EACH (notifier, node, &nln->all_notifiers) {
- notifier->cb(change, notifier->aux);
+ if (!change || group == notifier->multicast_group) {
+ notifier->cb(change, notifier->aux);
+ }
}
}
diff --git a/lib/netlink-notifier.h b/lib/netlink-notifier.h
index 4bd90f1..a6e156d 100644
--- a/lib/netlink-notifier.h
+++ b/lib/netlink-notifier.h
@@ -36,14 +36,15 @@ struct ofpbuf;
typedef void nln_notify_func(const void *change, void *aux);
/* Function called to parse incoming nln notifications. The 'buf' message
- * should be parsed into 'change' as specified in nln_create(). */
-typedef bool nln_parse_func(struct ofpbuf *buf, void *change);
+ * should be parsed into 'change' as specified in nln_create().
+ * Returns the multicast_group the change belongs to, or 0 for a parse error.
+ */
+typedef int nln_parse_func(struct ofpbuf *buf, void *change);
-struct nln *nln_create(int protocol, int multicast_group, nln_parse_func *,
- void *change);
+struct nln *nln_create(int protocol, nln_parse_func *, void *change);
void nln_destroy(struct nln *);
-struct nln_notifier *nln_notifier_create(struct nln *, nln_notify_func *,
- void *aux);
+struct nln_notifier *nln_notifier_create(struct nln *, int multicast_group,
+ nln_notify_func *, void *aux);
void nln_notifier_destroy(struct nln_notifier *);
void nln_run(struct nln *);
void nln_wait(struct nln *);
diff --git a/lib/route-table.c b/lib/route-table.c
index a5a42ca..4c777b8 100644
--- a/lib/route-table.c
+++ b/lib/route-table.c
@@ -69,7 +69,7 @@ static bool route_table_valid = false;
static int route_table_reset(void);
static void route_table_handle_msg(const struct route_table_msg *);
-static bool route_table_parse(struct ofpbuf *, struct route_table_msg *);
+static int route_table_parse(struct ofpbuf *, struct route_table_msg *);
static void route_table_change(const struct route_table_msg *, void *);
static void route_map_clear(void);
@@ -93,12 +93,12 @@ route_table_init(void)
ovs_assert(!route_notifier);
ovs_router_init();
- nln = nln_create(NETLINK_ROUTE, RTNLGRP_IPV4_ROUTE,
- (nln_parse_func *) route_table_parse, &rtmsg);
+ nln = nln_create(NETLINK_ROUTE, (nln_parse_func *) route_table_parse,
+ &rtmsg);
route_notifier =
- nln_notifier_create(nln, (nln_notify_func *) route_table_change,
- NULL);
+ nln_notifier_create(nln, RTNLGRP_IPV4_ROUTE,
+ (nln_notify_func *) route_table_change, NULL);
route_table_reset();
name_table_init();
@@ -171,12 +171,10 @@ route_table_reset(void)
return nl_dump_done(&dump);
}
-
-static bool
+/* Return RTNLGRP_IPV4_ROUTE on success, 0 on parse error. */
+static int
route_table_parse(struct ofpbuf *buf, struct route_table_msg *change)
{
- bool parsed;
-
static const struct nl_policy policy[] = {
[RTA_DST] = { .type = NL_A_U32, .optional = true },
[RTA_OIF] = { .type = NL_A_U32, .optional = false },
@@ -185,8 +183,8 @@ route_table_parse(struct ofpbuf *buf, struct
route_table_msg *change)
struct nlattr *attrs[ARRAY_SIZE(policy)];
- parsed = nl_policy_parse(buf, NLMSG_HDRLEN + sizeof(struct rtmsg),
- policy, attrs, ARRAY_SIZE(policy));
+ bool parsed = nl_policy_parse(buf, NLMSG_HDRLEN + sizeof(struct rtmsg),
+ policy, attrs, ARRAY_SIZE(policy));
if (parsed) {
const struct rtmsg *rtm;
@@ -198,7 +196,7 @@ route_table_parse(struct ofpbuf *buf, struct
route_table_msg *change)
if (rtm->rtm_family != AF_INET) {
VLOG_DBG_RL(&rl, "received non AF_INET rtnetlink route message");
- return false;
+ return 0;
}
memset(change, 0, sizeof *change);
@@ -221,7 +219,7 @@ route_table_parse(struct ofpbuf *buf, struct
route_table_msg *change)
VLOG_DBG_RL(&rl, "Could not find interface name[%u]: %s",
rta_oif, ovs_strerror(error));
- return false;
+ return 0;
}
if (attrs[RTA_DST]) {
@@ -234,9 +232,11 @@ route_table_parse(struct ofpbuf *buf, struct
route_table_msg *change)
} else {
VLOG_DBG_RL(&rl, "received unparseable rtnetlink route message");
+ return 0;
}
- return parsed;
+ /* Success. */
+ return RTNLGRP_IPV4_ROUTE;
}
static void
diff --git a/lib/rtnetlink-link.c b/lib/rtnetlink-link.c
index 308338f..a9e41bf 100644
--- a/lib/rtnetlink-link.c
+++ b/lib/rtnetlink-link.c
@@ -83,10 +83,11 @@ rtnetlink_link_parse(struct ofpbuf *buf,
return parsed;
}
-static bool
+/* Return RTNLGRP_LINK on success, 0 on parse error. */
+static int
rtnetlink_link_parse_cb(struct ofpbuf *buf, void *change)
{
- return rtnetlink_link_parse(buf, change);
+ return rtnetlink_link_parse(buf, change) ? RTNLGRP_LINK : 0;
}
/* Registers 'cb' to be called with auxiliary data 'aux' with network device
@@ -102,11 +103,11 @@ struct nln_notifier *
rtnetlink_link_notifier_create(rtnetlink_link_notify_func *cb, void *aux)
{
if (!nln) {
- nln = nln_create(NETLINK_ROUTE, RTNLGRP_LINK, rtnetlink_link_parse_cb,
+ nln = nln_create(NETLINK_ROUTE, rtnetlink_link_parse_cb,
&rtn_change);
}
- return nln_notifier_create(nln, (nln_notify_func *) cb, aux);
+ return nln_notifier_create(nln, RTNLGRP_LINK, (nln_notify_func *) cb, aux);
}
/* Destroys 'notifier', which must have previously been created with
--
1.7.10.4
_______________________________________________
dev mailing list
[email protected]
http://openvswitch.org/mailman/listinfo/dev