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 <al...@nicira.com> --- PATCH->V2: - new patch, since parsing RTNLGRP_IPV4_IFADDR/RTNLGRP_IPV6_IFADDR is different from parsing RTNLGRP_LINK, we need to extend to module. --- lib/automake.mk | 4 +- lib/netdev-linux.c | 13 ++- lib/route-table.c | 12 +-- lib/rtnetlink-link.c | 138 ------------------------- lib/rtnetlink.c | 179 +++++++++++++++++++++++++++++++++ lib/{rtnetlink-link.h => rtnetlink.h} | 39 +++---- lib/vlandev.c | 8 +- 7 files changed, 219 insertions(+), 174 deletions(-) delete mode 100644 lib/rtnetlink-link.c create mode 100644 lib/rtnetlink.c rename lib/{rtnetlink-link.h => rtnetlink.h} (64%) diff --git a/lib/automake.mk b/lib/automake.mk index 018e62c..faca968 100644 --- a/lib/automake.mk +++ b/lib/automake.mk @@ -347,8 +347,8 @@ lib_libopenvswitch_la_SOURCES += \ 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 diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index 0656f36..9213d8b 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -66,7 +66,7 @@ #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" @@ -541,7 +541,7 @@ netdev_rxq_linux_cast(const struct netdev_rxq *rx) } 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) @@ -601,9 +601,9 @@ netdev_linux_run(void) 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_); @@ -674,7 +674,7 @@ netdev_linux_changed(struct netdev_linux *dev, 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) { @@ -694,10 +694,9 @@ netdev_linux_update(struct netdev_linux *dev, 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); } diff --git a/lib/route-table.c b/lib/route-table.c index a5a42ca..7d1837c 100644 --- a/lib/route-table.c +++ b/lib/route-table.c @@ -30,7 +30,7 @@ #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); @@ -74,7 +74,7 @@ static void route_table_change(const struct route_table_msg *, void *); 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) @@ -113,7 +113,7 @@ route_table_run(void) { ovs_mutex_lock(&route_table_mutex); if (nln) { - rtnetlink_link_run(); + rtnetlink_run(); nln_run(nln); if (!route_table_valid) { @@ -130,7 +130,7 @@ route_table_wait(void) { ovs_mutex_lock(&route_table_mutex); if (nln) { - rtnetlink_link_wait(); + rtnetlink_wait(); nln_wait(nln); } ovs_mutex_unlock(&route_table_mutex); @@ -278,12 +278,12 @@ route_table_fallback_lookup(ovs_be32 ip_dst OVS_UNUSED, 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 diff --git a/lib/rtnetlink-link.c b/lib/rtnetlink-link.c deleted file mode 100644 index 308338f..0000000 --- a/lib/rtnetlink-link.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * 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); - } -} diff --git a/lib/rtnetlink.c b/lib/rtnetlink.c new file mode 100644 index 0000000..1ecd23b --- /dev/null +++ b/lib/rtnetlink.c @@ -0,0 +1,179 @@ +/* + * 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); + } +} diff --git a/lib/rtnetlink-link.h b/lib/rtnetlink.h similarity index 64% rename from lib/rtnetlink-link.h rename to lib/rtnetlink.h index d0d9a75..f2da394 100644 --- a/lib/rtnetlink-link.h +++ b/lib/rtnetlink.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009 Nicira, Inc. + * 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. @@ -28,36 +28,41 @@ struct nln_notifier; * 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 { + * 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. */ - /* Copied from struct ifinfomsg. */ - int ifi_index; /* Index of network device. */ - - /* Extracted from Netlink attributes. */ + /* 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_link_notifier_register(). */ + * rtnetlink_notifier_register(). */ typedef -void rtnetlink_link_notify_func(const struct rtnetlink_link_change *change, - void *aux); +void rtnetlink_notify_func(const struct rtnetlink_change *change, + void *aux); -bool rtnetlink_link_parse(struct ofpbuf *buf, - struct rtnetlink_link_change *change); +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_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 */ +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 */ diff --git a/lib/vlandev.c b/lib/vlandev.c index 99c99de..d2a3191 100644 --- a/lib/vlandev.c +++ b/lib/vlandev.c @@ -162,7 +162,7 @@ vlandev_get_name(const char *real_dev_name, int vid) /* 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" @@ -171,7 +171,7 @@ static struct nln_notifier *vlan_cache_notifier; 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; @@ -185,8 +185,8 @@ vlandev_linux_refresh(void) 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; } -- 1.7.9.5 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev