From: Ben Pfaff Date: Tue, 28 Jul 2009 20:05:20 +0000 (-0700) Subject: rtnetlink: Move into separate source and header file. X-Git-Tag: v0.99.0~133^2~9 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=559843ed5335c46e4c147086c8534f91b0bfe998;p=sliver-openvswitch.git rtnetlink: Move into separate source and header file. Now that rtnetlink isn't named similarly to netdev_linux, it might as well have its own source and header files to avoid confusing everyone. --- diff --git a/lib/automake.mk b/lib/automake.mk index d129491db..fac9501d1 100644 --- a/lib/automake.mk +++ b/lib/automake.mk @@ -58,7 +58,6 @@ lib_libopenvswitch_a_SOURCES = \ lib/mac-learning.c \ lib/mac-learning.h \ lib/netdev-linux.c \ - lib/netdev-linux.h \ lib/netdev.c \ lib/netdev.h \ lib/odp-util.c \ @@ -82,6 +81,8 @@ lib_libopenvswitch_a_SOURCES = \ lib/random.h \ lib/rconn.c \ lib/rconn.h \ + lib/rtnetlink.c \ + lib/rtnetlink.h \ lib/sat-math.h \ lib/sha1.c \ lib/sha1.h \ @@ -183,6 +184,7 @@ COVERAGE_FILES = \ lib/poll-loop.c \ lib/process.c \ lib/rconn.c \ + lib/rtnetlink.c \ lib/timeval.c \ lib/unixctl.c \ lib/util.c \ diff --git a/lib/dpif-linux.c b/lib/dpif-linux.c index 932ef9e40..4d8c8048d 100644 --- a/lib/dpif-linux.c +++ b/lib/dpif-linux.c @@ -31,9 +31,9 @@ #include #include "dpif-provider.h" -#include "netdev-linux.h" #include "ofpbuf.h" #include "poll-loop.h" +#include "rtnetlink.h" #include "svec.h" #include "util.h" diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index 95d9d9072..3e3404447 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -15,9 +15,6 @@ */ #include - -#include "netdev-linux.h" - #include #include #include @@ -53,6 +50,7 @@ #include "openflow/openflow.h" #include "packets.h" #include "poll-loop.h" +#include "rtnetlink.h" #include "socket-util.h" #include "shash.h" #include "svec.h" @@ -107,17 +105,6 @@ struct netdev_linux_cache { static struct shash cache_map = SHASH_INITIALIZER(&cache_map); static struct rtnetlink_notifier netdev_linux_cache_notifier; -/* Policy for RTNLGRP_LINK messages. - * - * There are *many* more fields in these messages, but currently we only care - * about interface names. */ -static const struct nl_policy rtnlgrp_link_policy[] = { - [IFLA_IFNAME] = { .type = NL_A_STRING, .optional = false }, - [IFLA_MASTER] = { .type = NL_A_U32, .optional = true }, - [IFLA_STATS] = { .type = NL_A_UNSPEC, .optional = true, - .min_len = sizeof(struct rtnl_link_stats) }, -}; - /* An AF_INET socket (used for ioctl operations). */ static int af_inet_sock = -1; @@ -1336,6 +1323,17 @@ const struct netdev_class netdev_tap_class = { static int get_stats_via_netlink(int ifindex, struct netdev_stats *stats) { + /* Policy for RTNLGRP_LINK messages. + * + * There are *many* more fields in these messages, but currently we only + * care about these fields. */ + static const struct nl_policy rtnlgrp_link_policy[] = { + [IFLA_IFNAME] = { .type = NL_A_STRING, .optional = false }, + [IFLA_STATS] = { .type = NL_A_UNSPEC, .optional = true, + .min_len = sizeof(struct rtnl_link_stats) }, + }; + + static struct nl_sock *rtnl_sock; struct ofpbuf request; struct ofpbuf *reply; @@ -1593,146 +1591,3 @@ netdev_linux_do_ioctl(const struct netdev *netdev, struct ifreq *ifr, } return 0; } - -/* rtnetlink socket. */ -static struct nl_sock *notify_sock; - -/* All registered notifiers. */ -static struct list all_notifiers = LIST_INITIALIZER(&all_notifiers); - -static void rtnetlink_report_change(const struct nlmsghdr *, - const struct ifinfomsg *, - struct nlattr *attrs[]); -static void rtnetlink_report_notify_error(void); - -/* Registers 'cb' to be called with auxiliary data 'aux' with network device - * change notifications. The notifier is stored in 'notifier', which the - * caller must not modify or free. - * - * This is probably not the function that you want. You should probably be - * using dpif_port_poll() or netdev_monitor_create(), which unlike this - * function are not Linux-specific. - * - * Returns 0 if successful, otherwise a positive errno value. */ -int -rtnetlink_notifier_register(struct rtnetlink_notifier *notifier, - rtnetlink_notify_func *cb, void *aux) -{ - if (!notify_sock) { - int error = nl_sock_create(NETLINK_ROUTE, RTNLGRP_LINK, 0, 0, - ¬ify_sock); - if (error) { - VLOG_WARN("could not create rtnetlink socket: %s", - strerror(error)); - return error; - } - } else { - /* Catch up on notification work so that the new notifier won't - * receive any stale notifications. */ - rtnetlink_notifier_run(); - } - - list_push_back(&all_notifiers, ¬ifier->node); - notifier->cb = cb; - notifier->aux = aux; - return 0; -} - -/* Cancels notification on 'notifier', which must have previously been - * registered with lxnetdev_notifier_register(). */ -void -rtnetlink_notifier_unregister(struct rtnetlink_notifier *notifier) -{ - list_remove(¬ifier->node); - if (list_is_empty(&all_notifiers)) { - nl_sock_destroy(notify_sock); - notify_sock = NULL; - } -} - -/* Calls all of the registered notifiers, passing along any as-yet-unreported - * netdev change events. */ -void -rtnetlink_notifier_run(void) -{ - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); - - if (!notify_sock) { - return; - } - - for (;;) { - struct nlattr *attrs[ARRAY_SIZE(rtnlgrp_link_policy)]; - struct ofpbuf *buf; - int error; - - error = nl_sock_recv(notify_sock, &buf, false); - if (!error) { - if (nl_policy_parse(buf, NLMSG_HDRLEN + sizeof(struct ifinfomsg), - rtnlgrp_link_policy, - attrs, ARRAY_SIZE(rtnlgrp_link_policy))) { - struct ifinfomsg *ifinfo; - - ifinfo = (void *) ((char *) buf->data + NLMSG_HDRLEN); - rtnetlink_report_change(buf->data, ifinfo, attrs); - } else { - VLOG_WARN_RL(&rl, "received bad rtnl message"); - rtnetlink_report_notify_error(); - } - ofpbuf_delete(buf); - } else if (error == EAGAIN) { - return; - } else { - if (error == ENOBUFS) { - VLOG_WARN_RL(&rl, "rtnetlink receive buffer overflowed"); - } else { - VLOG_WARN_RL(&rl, "error reading rtnetlink socket: %s", - strerror(error)); - } - rtnetlink_report_notify_error(); - } - } -} - -/* Causes poll_block() to wake up when network device change notifications are - * ready. */ -void -rtnetlink_notifier_wait(void) -{ - if (notify_sock) { - nl_sock_wait(notify_sock, POLLIN); - } -} - -static void -rtnetlink_report_change(const struct nlmsghdr *nlmsg, - const struct ifinfomsg *ifinfo, - struct nlattr *attrs[]) -{ - struct rtnetlink_notifier *notifier; - struct rtnetlink_change change; - - COVERAGE_INC(rtnetlink_changed); - - change.nlmsg_type = nlmsg->nlmsg_type; - change.ifi_index = ifinfo->ifi_index; - change.ifname = nl_attr_get_string(attrs[IFLA_IFNAME]); - change.master_ifindex = (attrs[IFLA_MASTER] - ? nl_attr_get_u32(attrs[IFLA_MASTER]) : 0); - - LIST_FOR_EACH (notifier, struct rtnetlink_notifier, node, - &all_notifiers) { - notifier->cb(&change, notifier->aux); - } -} - -static void -rtnetlink_report_notify_error(void) -{ - struct rtnetlink_notifier *notifier; - - LIST_FOR_EACH (notifier, struct rtnetlink_notifier, node, - &all_notifiers) { - notifier->cb(NULL, notifier->aux); - } -} diff --git a/lib/netdev-provider.h b/lib/netdev-provider.h index 752fd82a2..9c880b1c2 100644 --- a/lib/netdev-provider.h +++ b/lib/netdev-provider.h @@ -73,7 +73,7 @@ struct netdev_class { const char *name; /* Called only once, at program startup. Returning an error from this - * function will prevent any network device, of any class, from being + * function will prevent any network device in this class from being * opened. * * This function may be set to null if a network device class needs no diff --git a/lib/netdev.c b/lib/netdev.c index 575291478..dcb63fa02 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -43,7 +43,7 @@ static const struct netdev_class *netdev_classes[] = { &netdev_linux_class, &netdev_tap_class, }; -enum { N_NETDEV_CLASSES = ARRAY_SIZE(netdev_classes) }; +static int n_netdev_classes = ARRAY_SIZE(netdev_classes); /* All open network devices. */ static struct list netdev_list = LIST_INITIALIZER(&netdev_list); @@ -65,16 +65,18 @@ netdev_initialize(void) { static int status = -1; if (status < 0) { - int i; + int i, j; fatal_signal_add_hook(restore_all_flags, NULL, true); status = 0; - for (i = 0; i < N_NETDEV_CLASSES; i++) { + for (i = j = 0; i < n_netdev_classes; i++) { const struct netdev_class *class = netdev_classes[i]; if (class->init) { int retval = class->init(); - if (retval) { + if (!retval) { + netdev_classes[j++] = class; + } else { VLOG_ERR("failed to initialize %s network device " "class: %s", class->name, strerror(retval)); if (!status) { @@ -83,6 +85,7 @@ netdev_initialize(void) } } } + n_netdev_classes = j; } return status; } @@ -95,7 +98,7 @@ void netdev_run(void) { int i; - for (i = 0; i < N_NETDEV_CLASSES; i++) { + for (i = 0; i < n_netdev_classes; i++) { const struct netdev_class *class = netdev_classes[i]; if (class->run) { class->run(); @@ -111,7 +114,7 @@ void netdev_wait(void) { int i; - for (i = 0; i < N_NETDEV_CLASSES; i++) { + for (i = 0; i < n_netdev_classes; i++) { const struct netdev_class *class = netdev_classes[i]; if (class->wait) { class->wait(); @@ -136,11 +139,7 @@ netdev_open(const char *name_, int ethertype, struct netdev **netdevp) int error; int i; - error = netdev_initialize(); - if (error) { - return error; - } - + netdev_initialize(); colon = strchr(name, ':'); if (colon) { *colon = '\0'; @@ -151,7 +150,7 @@ netdev_open(const char *name_, int ethertype, struct netdev **netdevp) suffix = name; } - for (i = 0; i < N_NETDEV_CLASSES; i++) { + for (i = 0; i < n_netdev_classes; i++) { const struct netdev_class *class = netdev_classes[i]; if (!strcmp(prefix, class->prefix)) { error = class->open(name_, suffix, ethertype, &netdev); @@ -220,13 +219,10 @@ netdev_enumerate(struct svec *svec) svec_init(svec); - error = netdev_initialize(); - if (error) { - return error; - } + netdev_initialize(); error = 0; - for (i = 0; i < N_NETDEV_CLASSES; i++) { + for (i = 0; i < n_netdev_classes; i++) { const struct netdev_class *class = netdev_classes[i]; if (class->enumerate) { int retval = class->enumerate(svec); diff --git a/lib/rtnetlink.c b/lib/rtnetlink.c new file mode 100644 index 000000000..29e02f614 --- /dev/null +++ b/lib/rtnetlink.c @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2009 Nicira Networks. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "rtnetlink.h" + +#include +#include +#include +#include +#include + +#include "coverage.h" +#include "netlink.h" +#include "ofpbuf.h" + +#define THIS_MODULE VLM_rtnetlink +#include "vlog.h" + +/* rtnetlink socket. */ +static struct nl_sock *notify_sock; + +/* All registered notifiers. */ +static struct list all_notifiers = LIST_INITIALIZER(&all_notifiers); + +static void rtnetlink_report_change(const struct nlmsghdr *, + const struct ifinfomsg *, + struct nlattr *attrs[]); +static void rtnetlink_report_notify_error(void); + +/* Registers 'cb' to be called with auxiliary data 'aux' with network device + * change notifications. The notifier is stored in 'notifier', which the + * caller must not modify or free. + * + * This is probably not the function that you want. You should probably be + * using dpif_port_poll() or netdev_monitor_create(), which unlike this + * function are not Linux-specific. + * + * Returns 0 if successful, otherwise a positive errno value. */ +int +rtnetlink_notifier_register(struct rtnetlink_notifier *notifier, + rtnetlink_notify_func *cb, void *aux) +{ + if (!notify_sock) { + int error = nl_sock_create(NETLINK_ROUTE, RTNLGRP_LINK, 0, 0, + ¬ify_sock); + if (error) { + VLOG_WARN("could not create rtnetlink socket: %s", + strerror(error)); + return error; + } + } else { + /* Catch up on notification work so that the new notifier won't + * receive any stale notifications. */ + rtnetlink_notifier_run(); + } + + list_push_back(&all_notifiers, ¬ifier->node); + notifier->cb = cb; + notifier->aux = aux; + return 0; +} + +/* Cancels notification on 'notifier', which must have previously been + * registered with lxnetdev_notifier_register(). */ +void +rtnetlink_notifier_unregister(struct rtnetlink_notifier *notifier) +{ + list_remove(¬ifier->node); + if (list_is_empty(&all_notifiers)) { + nl_sock_destroy(notify_sock); + notify_sock = NULL; + } +} + +/* Calls all of the registered notifiers, passing along any as-yet-unreported + * netdev change events. */ +void +rtnetlink_notifier_run(void) +{ + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + + if (!notify_sock) { + return; + } + + for (;;) { + /* Policy for RTNLGRP_LINK messages. + * + * There are *many* more fields in these messages, but currently we + * only care about these fields. */ + static const struct nl_policy rtnetlink_policy[] = { + [IFLA_IFNAME] = { .type = NL_A_STRING, .optional = false }, + [IFLA_MASTER] = { .type = NL_A_U32, .optional = true }, + }; + + struct nlattr *attrs[ARRAY_SIZE(rtnetlink_policy)]; + struct ofpbuf *buf; + int error; + + error = nl_sock_recv(notify_sock, &buf, false); + if (!error) { + if (nl_policy_parse(buf, NLMSG_HDRLEN + sizeof(struct ifinfomsg), + rtnetlink_policy, + attrs, ARRAY_SIZE(rtnetlink_policy))) { + struct ifinfomsg *ifinfo; + + ifinfo = (void *) ((char *) buf->data + NLMSG_HDRLEN); + rtnetlink_report_change(buf->data, ifinfo, attrs); + } else { + VLOG_WARN_RL(&rl, "received bad rtnl message"); + rtnetlink_report_notify_error(); + } + ofpbuf_delete(buf); + } else if (error == EAGAIN) { + return; + } else { + if (error == ENOBUFS) { + VLOG_WARN_RL(&rl, "rtnetlink receive buffer overflowed"); + } else { + VLOG_WARN_RL(&rl, "error reading rtnetlink socket: %s", + strerror(error)); + } + rtnetlink_report_notify_error(); + } + } +} + +/* Causes poll_block() to wake up when network device change notifications are + * ready. */ +void +rtnetlink_notifier_wait(void) +{ + if (notify_sock) { + nl_sock_wait(notify_sock, POLLIN); + } +} + +static void +rtnetlink_report_change(const struct nlmsghdr *nlmsg, + const struct ifinfomsg *ifinfo, + struct nlattr *attrs[]) +{ + struct rtnetlink_notifier *notifier; + struct rtnetlink_change change; + + COVERAGE_INC(rtnetlink_changed); + + change.nlmsg_type = nlmsg->nlmsg_type; + change.ifi_index = ifinfo->ifi_index; + change.ifname = nl_attr_get_string(attrs[IFLA_IFNAME]); + change.master_ifindex = (attrs[IFLA_MASTER] + ? nl_attr_get_u32(attrs[IFLA_MASTER]) : 0); + + LIST_FOR_EACH (notifier, struct rtnetlink_notifier, node, + &all_notifiers) { + notifier->cb(&change, notifier->aux); + } +} + +static void +rtnetlink_report_notify_error(void) +{ + struct rtnetlink_notifier *notifier; + + LIST_FOR_EACH (notifier, struct rtnetlink_notifier, node, + &all_notifiers) { + notifier->cb(NULL, notifier->aux); + } +} diff --git a/lib/netdev-linux.h b/lib/rtnetlink.h similarity index 89% rename from lib/netdev-linux.h rename to lib/rtnetlink.h index 42ea380a6..ca7df7b88 100644 --- a/lib/netdev-linux.h +++ b/lib/rtnetlink.h @@ -14,11 +14,11 @@ * limitations under the License. */ -#ifndef NETDEV_LINUX_H -#define NETDEV_LINUX_H 1 +#ifndef RTNETLINK_H +#define RTNETLINK_H 1 -/* These functions are specific to the Linux implementation of dpif and netdev. - * They should only be used directly by Linux-specific code. */ +/* These functions are Linux specific, so they should be used directly only by + * Linux-specific code. */ #include "list.h" @@ -55,4 +55,4 @@ void rtnetlink_notifier_unregister(struct rtnetlink_notifier *); void rtnetlink_notifier_run(void); void rtnetlink_notifier_wait(void); -#endif /* netdev-linux.h */ +#endif /* rtnetlink.h */ diff --git a/lib/vlog-modules.def b/lib/vlog-modules.def index 63b25cc2e..849c867bd 100644 --- a/lib/vlog-modules.def +++ b/lib/vlog-modules.def @@ -58,6 +58,7 @@ VLOG_MODULE(port_watcher) VLOG_MODULE(proc_net_compat) VLOG_MODULE(process) VLOG_MODULE(rconn) +VLOG_MODULE(rtnetlink) VLOG_MODULE(stp) VLOG_MODULE(stats) VLOG_MODULE(status)