lib: Show tunnel egress interface in ovsdb
[sliver-openvswitch.git] / lib / rtnetlink.c
1 /*
2  * Copyright (c) 2009, 2010 Nicira Networks.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <config.h>
18
19 #include "rtnetlink.h"
20
21 #include <errno.h>
22 #include <poll.h>
23
24 #include "coverage.h"
25 #include "netlink.h"
26 #include "netlink-socket.h"
27 #include "ofpbuf.h"
28 #include "vlog.h"
29
30 VLOG_DEFINE_THIS_MODULE(rtnetlink);
31
32 COVERAGE_DEFINE(rtnetlink_changed);
33
34 static void rtnetlink_report(struct rtnetlink *rtn, void *change);
35
36 struct rtnetlink {
37     struct nl_sock *notify_sock; /* Rtnetlink socket. */
38     struct list all_notifiers;   /* All rtnetlink notifiers. */
39
40     /* Passed in by rtnetlink_create(). */
41     int multicast_group;         /* Multicast group we listen on. */
42     rtnetlink_parse_func *parse; /* Message parsing function. */
43     void *change;                /* Change passed to parse. */
44 };
45
46 /* Creates an rtnetlink handle which may be used to manage change
47  * notifications.  The created handle will listen for rtnetlink messages on
48  * 'multicast_group'.  Incoming messages will be parsed with 'parse' which will
49  * be passed 'change' as an argument. */
50 struct rtnetlink *
51 rtnetlink_create(int multicast_group, rtnetlink_parse_func *parse,
52                  void *change)
53 {
54     struct rtnetlink *rtn;
55
56     rtn                  = xzalloc(sizeof *rtn);
57     rtn->notify_sock     = 0;
58     rtn->multicast_group = multicast_group;
59     rtn->parse           = parse;
60     rtn->change          = change;
61
62     list_init(&rtn->all_notifiers);
63     return rtn;
64 }
65
66 /* Registers 'cb' to be called with auxiliary data 'aux' with change
67  * notifications.  The notifier is stored in 'notifier', which the caller must
68  * not modify or free.
69  *
70  * This is probably not the function you want.  You should probably be using
71  * message specific notifiers like rtnetlink_link_notifier_register().
72  *
73  * Returns 0 if successful, otherwise a positive errno value. */
74 int
75 rtnetlink_notifier_register(struct rtnetlink *rtn,
76                             struct rtnetlink_notifier *notifier,
77                             rtnetlink_notify_func *cb, void *aux)
78 {
79     if (!rtn->notify_sock) {
80         int error = nl_sock_create(NETLINK_ROUTE, rtn->multicast_group, 0, 0,
81                                    &rtn->notify_sock);
82         if (error) {
83             VLOG_WARN("could not create rtnetlink socket: %s",
84                       strerror(error));
85             return error;
86         }
87     } else {
88         /* Catch up on notification work so that the new notifier won't
89          * receive any stale notifications. */
90         rtnetlink_notifier_run(rtn);
91     }
92
93     list_push_back(&rtn->all_notifiers, &notifier->node);
94     notifier->cb = cb;
95     notifier->aux = aux;
96     return 0;
97 }
98
99 /* Cancels notification on 'notifier', which must have previously been
100  * registered with rtnetlink_notifier_register(). */
101 void
102 rtnetlink_notifier_unregister(struct rtnetlink *rtn,
103                               struct rtnetlink_notifier *notifier)
104 {
105     list_remove(&notifier->node);
106     if (list_is_empty(&rtn->all_notifiers)) {
107         nl_sock_destroy(rtn->notify_sock);
108         rtn->notify_sock = NULL;
109     }
110 }
111
112 /* Calls all of the registered notifiers, passing along any as-yet-unreported
113  * change events. */
114 void
115 rtnetlink_notifier_run(struct rtnetlink *rtn)
116 {
117     static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
118
119     if (!rtn->notify_sock) {
120         return;
121     }
122
123     for (;;) {
124         struct ofpbuf *buf;
125         int error;
126
127         error = nl_sock_recv(rtn->notify_sock, &buf, false);
128         if (!error) {
129             if (rtn->parse(buf, rtn->change)) {
130                 rtnetlink_report(rtn, rtn->change);
131             } else {
132                 VLOG_WARN_RL(&rl, "received bad rtnl message");
133                 rtnetlink_report(rtn, NULL);
134             }
135             ofpbuf_delete(buf);
136         } else if (error == EAGAIN) {
137             return;
138         } else {
139             if (error == ENOBUFS) {
140                 VLOG_WARN_RL(&rl, "rtnetlink receive buffer overflowed");
141             } else {
142                 VLOG_WARN_RL(&rl, "error reading rtnetlink socket: %s",
143                              strerror(error));
144             }
145             rtnetlink_report(rtn, NULL);
146         }
147     }
148 }
149
150 /* Causes poll_block() to wake up when change notifications are ready. */
151 void
152 rtnetlink_notifier_wait(struct rtnetlink *rtn)
153 {
154     if (rtn->notify_sock) {
155         nl_sock_wait(rtn->notify_sock, POLLIN);
156     }
157 }
158
159 static void
160 rtnetlink_report(struct rtnetlink *rtn, void *change)
161 {
162     struct rtnetlink_notifier *notifier;
163
164     if (change) {
165         COVERAGE_INC(rtnetlink_changed);
166     }
167
168     LIST_FOR_EACH (notifier, node, &rtn->all_notifiers) {
169         notifier->cb(change, notifier->aux);
170     }
171 }
172