RTNLGRP_IPV6_IFADDR.
This commit renames the rtnetlink-link.{c,h} to rtnetlink.{c,h}
and extends the module to support RTNLGRP_IPV4_IFADDR and
RTNLGRP_IPV4_IFADDR multicast groups. A later patch will start
using this module to react to interface address changes.
Signed-off-by: Alex Wang <alexw@nicira.com>
Acked-by: Ben Pfaff <blp@nicira.com>
lib/netlink-socket.h \
lib/ovs-numa.c \
lib/ovs-numa.h \
- lib/rtnetlink-link.c \
- lib/rtnetlink-link.h \
+ lib/rtnetlink.c \
+ lib/rtnetlink.h \
lib/route-table.c \
lib/route-table.h
endif
#include "ovs-atomic.h"
#include "packets.h"
#include "poll-loop.h"
-#include "rtnetlink-link.h"
+#include "rtnetlink.h"
#include "shash.h"
#include "socket-util.h"
#include "sset.h"
}
\f
static void netdev_linux_update(struct netdev_linux *netdev,
- const struct rtnetlink_link_change *)
+ const struct rtnetlink_change *)
OVS_REQUIRES(netdev->mutex);
static void netdev_linux_changed(struct netdev_linux *netdev,
unsigned int ifi_flags, unsigned int mask)
ofpbuf_use_stub(&buf, buf_stub, sizeof buf_stub);
error = nl_sock_recv(sock, &buf, false);
if (!error) {
- struct rtnetlink_link_change change;
+ struct rtnetlink_change change;
- if (rtnetlink_link_parse(&buf, &change)) {
+ if (rtnetlink_parse(&buf, &change)) {
struct netdev *netdev_ = netdev_from_name(change.ifname);
if (netdev_ && is_netdev_linux_class(netdev_->netdev_class)) {
struct netdev_linux *netdev = netdev_linux_cast(netdev_);
static void
netdev_linux_update(struct netdev_linux *dev,
- const struct rtnetlink_link_change *change)
+ const struct rtnetlink_change *change)
OVS_REQUIRES(dev->mutex)
{
if (change->nlmsg_type == RTM_NEWLINK) {
dev->ether_addr_error = 0;
}
- dev->ifindex = change->ifi_index;
+ dev->ifindex = change->if_index;
dev->cache_valid |= VALID_IFINDEX;
dev->get_ifindex_error = 0;
-
} else {
netdev_linux_changed(dev, change->ifi_flags, 0);
}
#include "netlink-socket.h"
#include "ofpbuf.h"
#include "ovs-router.h"
-#include "rtnetlink-link.h"
+#include "rtnetlink.h"
#include "openvswitch/vlog.h"
VLOG_DEFINE_THIS_MODULE(route_table);
static void route_map_clear(void);
static void name_table_init(void);
-static void name_table_change(const struct rtnetlink_link_change *, void *);
+static void name_table_change(const struct rtnetlink_change *, void *);
uint64_t
route_table_get_change_seq(void)
{
ovs_mutex_lock(&route_table_mutex);
if (nln) {
- rtnetlink_link_run();
+ rtnetlink_run();
nln_run(nln);
if (!route_table_valid) {
{
ovs_mutex_lock(&route_table_mutex);
if (nln) {
- rtnetlink_link_wait();
+ rtnetlink_wait();
nln_wait(nln);
}
ovs_mutex_unlock(&route_table_mutex);
static void
name_table_init(void)
{
- name_notifier = rtnetlink_link_notifier_create(name_table_change, NULL);
+ name_notifier = rtnetlink_notifier_create(name_table_change, NULL);
}
static void
-name_table_change(const struct rtnetlink_link_change *change OVS_UNUSED,
+name_table_change(const struct rtnetlink_change *change OVS_UNUSED,
void *aux OVS_UNUSED)
{
/* Changes to interface status can cause routing table changes that some
+++ /dev/null
-/*
- * Copyright (c) 2009, 2010, 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.
- * 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 <config.h>
-
-#include "rtnetlink-link.h"
-
-#include <sys/socket.h>
-#include <linux/rtnetlink.h>
-#include <net/if.h>
-
-#include "netlink.h"
-#include "netlink-notifier.h"
-#include "ofpbuf.h"
-
-static struct nln *nln = NULL;
-static struct rtnetlink_link_change rtn_change;
-
-/* Parses a rtnetlink message 'buf' into 'change'. If 'buf' is unparseable,
- * leaves 'change' untouched and returns false. Otherwise, populates 'change'
- * and returns true. */
-bool
-rtnetlink_link_parse(struct ofpbuf *buf,
- struct rtnetlink_link_change *change)
-{
- bool parsed;
-
- /* 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 policy[] = {
- [IFLA_IFNAME] = { .type = NL_A_STRING, .optional = false },
- [IFLA_MASTER] = { .type = NL_A_U32, .optional = true },
- [IFLA_MTU] = { .type = NL_A_U32, .optional = true },
- [IFLA_ADDRESS] = { .type = NL_A_UNSPEC, .optional = true },
- };
-
- struct nlattr *attrs[ARRAY_SIZE(policy)];
-
- parsed = nl_policy_parse(buf, NLMSG_HDRLEN + sizeof(struct ifinfomsg),
- policy, attrs, ARRAY_SIZE(policy));
-
- if (parsed) {
- const struct nlmsghdr *nlmsg;
- const struct ifinfomsg *ifinfo;
-
- nlmsg = buf->data;
- ifinfo = ofpbuf_at(buf, NLMSG_HDRLEN, sizeof *ifinfo);
-
- change->nlmsg_type = nlmsg->nlmsg_type;
- change->ifi_index = ifinfo->ifi_index;
- change->ifname = nl_attr_get_string(attrs[IFLA_IFNAME]);
- change->ifi_flags = ifinfo->ifi_flags;
- change->master_ifindex = (attrs[IFLA_MASTER]
- ? nl_attr_get_u32(attrs[IFLA_MASTER])
- : 0);
- change->mtu = (attrs[IFLA_MTU]
- ? nl_attr_get_u32(attrs[IFLA_MTU])
- : 0);
-
- if (attrs[IFLA_ADDRESS] &&
- nl_attr_get_size(attrs[IFLA_ADDRESS]) == ETH_ALEN) {
- memcpy(change->addr, nl_attr_get(attrs[IFLA_ADDRESS]), ETH_ALEN);
- } else {
- memset(change->addr, 0, ETH_ALEN);
- }
- }
-
- return parsed;
-}
-
-static bool
-rtnetlink_link_parse_cb(struct ofpbuf *buf, void *change)
-{
- return rtnetlink_link_parse(buf, change);
-}
-
-/* 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_change_seq(), which unlike this function
- * are not Linux-specific.
- *
- * Returns an initialized nln_notifier if successful, NULL otherwise. */
-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,
- &rtn_change);
- }
-
- return nln_notifier_create(nln, (nln_notify_func *) cb, aux);
-}
-
-/* Destroys 'notifier', which must have previously been created with
- * rtnetlink_link_notifier_register(). */
-void
-rtnetlink_link_notifier_destroy(struct nln_notifier *notifier)
-{
- nln_notifier_destroy(notifier);
-}
-
-/* Calls all of the registered notifiers, passing along any as-yet-unreported
- * netdev change events. */
-void
-rtnetlink_link_run(void)
-{
- if (nln) {
- nln_run(nln);
- }
-}
-
-/* Causes poll_block() to wake up when network device change notifications are
- * ready. */
-void
-rtnetlink_link_wait(void)
-{
- if (nln) {
- nln_wait(nln);
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2009 Nicira, Inc.
- *
- * 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.
- */
-
-#ifndef RTNETLINK_LINK_H
-#define RTNETLINK_LINK_H 1
-
-#include <stdbool.h>
-#include <stdint.h>
-#include <linux/if_ether.h>
-
-struct ofpbuf;
-struct nln_notifier;
-
-/* These functions are Linux specific, so they should be used directly only by
- * Linux-specific code. */
-
-/* A digested version of an rtnetlink_link message sent down by the kernel to
- * indicate that a network device has been created, destroyed or changed. */
-struct rtnetlink_link_change {
- /* Copied from struct nlmsghdr. */
- int nlmsg_type; /* e.g. RTM_NEWLINK, RTM_DELLINK. */
-
- /* Copied from struct ifinfomsg. */
- int ifi_index; /* Index of network device. */
-
- /* Extracted from Netlink attributes. */
- const char *ifname; /* Name of network device. */
- int master_ifindex; /* Ifindex of datapath master (0 if none). */
- int mtu; /* Current MTU. */
- uint8_t addr[ETH_ALEN];
- unsigned int ifi_flags; /* Flags of network device. */
-};
-
-/* Function called to report that a netdev has changed. 'change' describes the
- * specific change. It may be null if the buffer of change information
- * overflowed, in which case the function must assume that every device may
- * have changed. 'aux' is as specified in the call to
- * rtnetlink_link_notifier_register(). */
-typedef
-void rtnetlink_link_notify_func(const struct rtnetlink_link_change *change,
- void *aux);
-
-bool rtnetlink_link_parse(struct ofpbuf *buf,
- struct rtnetlink_link_change *change);
-struct nln_notifier *
-rtnetlink_link_notifier_create(rtnetlink_link_notify_func *, void *aux);
-void rtnetlink_link_notifier_destroy(struct nln_notifier *);
-void rtnetlink_link_run(void);
-void rtnetlink_link_wait(void);
-#endif /* rtnetlink-link.h */
--- /dev/null
+/*
+ * Copyright (c) 2009, 2010, 2013, 2015 Nicira, Inc.
+ *
+ * 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 <config.h>
+
+#include "rtnetlink.h"
+
+#include <sys/socket.h>
+#include <linux/rtnetlink.h>
+#include <net/if.h>
+
+#include "netlink.h"
+#include "netlink-notifier.h"
+#include "ofpbuf.h"
+
+static struct nln *nln = NULL;
+static struct rtnetlink_change rtn_change;
+
+/* Returns true if the given netlink msg type corresponds to RTNLGRP_LINK. */
+bool
+rtnetlink_type_is_rtnlgrp_link(uint16_t type)
+{
+ return type == RTM_NEWLINK || type == RTM_DELLINK;
+}
+
+/* Returns true if the given netlink msg type corresponds to
+ * RTNLGRP_IPV4_IFADDR or RTNLGRP_IPV6_IFADDR. */
+bool
+rtnetlink_type_is_rtnlgrp_addr(uint16_t type)
+{
+ return type == RTM_NEWADDR || type == RTM_DELADDR;
+}
+
+/* Parses a rtnetlink message 'buf' into 'change'. If 'buf' is unparseable,
+ * leaves 'change' untouched and returns false. Otherwise, populates 'change'
+ * and returns true. */
+bool
+rtnetlink_parse(struct ofpbuf *buf, struct rtnetlink_change *change)
+{
+ const struct nlmsghdr *nlmsg = buf->data;
+ bool parsed = false;
+
+ if (rtnetlink_type_is_rtnlgrp_link(nlmsg->nlmsg_type)) {
+ /* 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 policy[] = {
+ [IFLA_IFNAME] = { .type = NL_A_STRING, .optional = false },
+ [IFLA_MASTER] = { .type = NL_A_U32, .optional = true },
+ [IFLA_MTU] = { .type = NL_A_U32, .optional = true },
+ [IFLA_ADDRESS] = { .type = NL_A_UNSPEC, .optional = true },
+ };
+
+ struct nlattr *attrs[ARRAY_SIZE(policy)];
+
+ parsed = nl_policy_parse(buf, NLMSG_HDRLEN + sizeof(struct ifinfomsg),
+ policy, attrs, ARRAY_SIZE(policy));
+
+ if (parsed) {
+ const struct ifinfomsg *ifinfo;
+
+ ifinfo = ofpbuf_at(buf, NLMSG_HDRLEN, sizeof *ifinfo);
+
+ change->nlmsg_type = nlmsg->nlmsg_type;
+ change->if_index = ifinfo->ifi_index;
+ change->ifname = nl_attr_get_string(attrs[IFLA_IFNAME]);
+ change->ifi_flags = ifinfo->ifi_flags;
+ change->master_ifindex = (attrs[IFLA_MASTER]
+ ? nl_attr_get_u32(attrs[IFLA_MASTER])
+ : 0);
+ change->mtu = (attrs[IFLA_MTU]
+ ? nl_attr_get_u32(attrs[IFLA_MTU])
+ : 0);
+
+ if (attrs[IFLA_ADDRESS] &&
+ nl_attr_get_size(attrs[IFLA_ADDRESS]) == ETH_ALEN) {
+ memcpy(change->addr, nl_attr_get(attrs[IFLA_ADDRESS]),
+ ETH_ALEN);
+ } else {
+ memset(change->addr, 0, ETH_ALEN);
+ }
+ }
+ } else if (rtnetlink_type_is_rtnlgrp_addr(nlmsg->nlmsg_type)) {
+ /* Policy for RTNLGRP_IPV4_IFADDR/RTNLGRP_IPV6_IFADDR messages.
+ *
+ * There are *many* more fields in these messages, but currently we
+ * only care about these fields. */
+ static const struct nl_policy policy[] = {
+ [IFA_LABEL] = { .type = NL_A_STRING, .optional = false },
+ };
+
+ struct nlattr *attrs[ARRAY_SIZE(policy)];
+
+ parsed = nl_policy_parse(buf, NLMSG_HDRLEN + sizeof(struct ifaddrmsg),
+ policy, attrs, ARRAY_SIZE(policy));
+
+ if (parsed) {
+ const struct ifaddrmsg *ifaddr;
+
+ ifaddr = ofpbuf_at(buf, NLMSG_HDRLEN, sizeof *ifaddr);
+
+ change->nlmsg_type = nlmsg->nlmsg_type;
+ change->if_index = ifaddr->ifa_index;
+ change->ifname = nl_attr_get_string(attrs[IFA_LABEL]);
+ }
+ }
+
+ return parsed;
+}
+
+static bool
+rtnetlink_parse_cb(struct ofpbuf *buf, void *change)
+{
+ return rtnetlink_parse(buf, change);
+}
+
+/* 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_change_seq(), which unlike this function
+ * are not Linux-specific.
+ *
+ * xxx Joins more multicast groups when needed.
+ *
+ * Returns an initialized nln_notifier if successful, NULL otherwise. */
+struct nln_notifier *
+rtnetlink_notifier_create(rtnetlink_notify_func *cb, void *aux)
+{
+ if (!nln) {
+ nln = nln_create(NETLINK_ROUTE, RTNLGRP_LINK, rtnetlink_parse_cb,
+ &rtn_change);
+ }
+
+ return nln_notifier_create(nln, (nln_notify_func *) cb, aux);
+}
+
+/* Destroys 'notifier', which must have previously been created with
+ * rtnetlink_notifier_register(). */
+void
+rtnetlink_notifier_destroy(struct nln_notifier *notifier)
+{
+ nln_notifier_destroy(notifier);
+}
+
+/* Calls all of the registered notifiers, passing along any as-yet-unreported
+ * netdev change events. */
+void
+rtnetlink_run(void)
+{
+ if (nln) {
+ nln_run(nln);
+ }
+}
+
+/* Causes poll_block() to wake up when network device change notifications are
+ * ready. */
+void
+rtnetlink_wait(void)
+{
+ if (nln) {
+ nln_wait(nln);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2009, 2015 Nicira, Inc.
+ *
+ * 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.
+ */
+
+#ifndef RTNETLINK_LINK_H
+#define RTNETLINK_LINK_H 1
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <linux/if_ether.h>
+
+struct ofpbuf;
+struct nln_notifier;
+
+/* These functions are Linux specific, so they should be used directly only by
+ * Linux-specific code. */
+
+/* A digested version of an rtnetlink_link message sent down by the kernel to
+ * indicate that a network device's status (link or address) has been changed.
+ */
+struct rtnetlink_change {
+ /* Copied from struct nlmsghdr. */
+ int nlmsg_type; /* e.g. RTM_NEWLINK, RTM_DELLINK. */
+
+ /* Common attributes. */
+ int if_index; /* Index of network device. */
+ const char *ifname; /* Name of network device. */
+
+ /* Network device link status. */
+ int master_ifindex; /* Ifindex of datapath master (0 if none). */
+ int mtu; /* Current MTU. */
+ uint8_t addr[ETH_ALEN];
+ unsigned int ifi_flags; /* Flags of network device. */
+
+ /* Network device address status. */
+ /* xxx To be added when needed. */
+};
+
+/* Function called to report that a netdev has changed. 'change' describes the
+ * specific change. It may be null if the buffer of change information
+ * overflowed, in which case the function must assume that every device may
+ * have changed. 'aux' is as specified in the call to
+ * rtnetlink_notifier_register(). */
+typedef
+void rtnetlink_notify_func(const struct rtnetlink_change *change,
+ void *aux);
+
+bool rtnetlink_type_is_rtnlgrp_link(uint16_t type);
+bool rtnetlink_type_is_rtnlgrp_addr(uint16_t type);
+bool rtnetlink_parse(struct ofpbuf *buf, struct rtnetlink_change *change);
+struct nln_notifier *
+rtnetlink_notifier_create(rtnetlink_notify_func *, void *aux);
+void rtnetlink_notifier_destroy(struct nln_notifier *);
+void rtnetlink_run(void);
+void rtnetlink_wait(void);
+#endif /* rtnetlink.h */
/* The Linux vlandev implementation. */
#ifdef __linux__
-#include "rtnetlink-link.h"
+#include "rtnetlink.h"
#include <linux/if_vlan.h>
#include <linux/sockios.h>
#include "netdev-linux.h"
static bool cache_valid;
static void
-vlan_cache_cb(const struct rtnetlink_link_change *change OVS_UNUSED,
+vlan_cache_cb(const struct rtnetlink_change *change OVS_UNUSED,
void *aux OVS_UNUSED)
{
cache_valid = false;
FILE *stream;
if (!vlan_cache_notifier) {
- vlan_cache_notifier = rtnetlink_link_notifier_create(vlan_cache_cb,
- NULL);
+ vlan_cache_notifier = rtnetlink_notifier_create(vlan_cache_cb,
+ NULL);
if (!vlan_cache_notifier) {
return EINVAL;
}