[ovs-dev] [PATCH 2/2] lib: Show tunnel egress interface in ovsdb
Ethan Jackson
ethan at nicira.com
Tue Jan 4 19:46:08 UTC 2011
I ended up not pulling the route stuff out of netdev-vport cause I
want to get this in. I'll submit another patch that does that later
this week.
Ethan
On Tue, Jan 4, 2011 at 1:37 PM, Ethan Jackson <ethan at nicira.com> wrote:
> This commit parses rtnetlink address notifications from the
> kernel in order to display the egress interface of tunnels in the
> database.
>
> Bug #4103.
> ---
> lib/automake.mk | 4 +-
> lib/netdev-dummy.c | 1 +
> lib/netdev-linux.c | 1 +
> lib/netdev-provider.h | 11 ++
> lib/netdev-vport.c | 340 ++++++++++++++++++++++++++++++++++++++++++-
> lib/netdev.c | 10 ++
> lib/netdev.h | 1 +
> lib/rtnetlink-link.c | 5 +-
> lib/rtnetlink-link.h | 5 +
> lib/rtnetlink-route.c | 119 +++++++++++++++
> lib/rtnetlink-route.h | 55 +++++++
> vswitchd/bridge.c | 9 ++
> vswitchd/vswitch.ovsschema | 8 +-
> vswitchd/vswitch.xml | 8 +
> 14 files changed, 565 insertions(+), 12 deletions(-)
> create mode 100644 lib/rtnetlink-route.c
> create mode 100644 lib/rtnetlink-route.h
>
> diff --git a/lib/automake.mk b/lib/automake.mk
> index 4c6a877..f5d23a2 100644
> --- a/lib/automake.mk
> +++ b/lib/automake.mk
> @@ -191,7 +191,9 @@ lib_libopenvswitch_a_SOURCES += \
> lib/rtnetlink.c \
> lib/rtnetlink.h \
> lib/rtnetlink-link.c \
> - lib/rtnetlink-link.h
> + lib/rtnetlink-link.h \
> + lib/rtnetlink-route.c \
> + lib/rtnetlink-route.h
> endif
>
> if HAVE_OPENSSL
> diff --git a/lib/netdev-dummy.c b/lib/netdev-dummy.c
> index ddcbe36..218a022 100644
> --- a/lib/netdev-dummy.c
> +++ b/lib/netdev-dummy.c
> @@ -320,6 +320,7 @@ static const struct netdev_class dummy_class = {
> NULL, /* get_in6 */
> NULL, /* add_router */
> NULL, /* get_next_hop */
> + NULL, /* get_tnl_iface */
> NULL, /* arp_lookup */
>
> netdev_dummy_update_flags,
> diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c
> index 7f9a8e3..5654dd4 100644
> --- a/lib/netdev-linux.c
> +++ b/lib/netdev-linux.c
> @@ -2176,6 +2176,7 @@ netdev_linux_poll_remove(struct netdev_notifier *notifier_)
> netdev_linux_get_in6, \
> netdev_linux_add_router, \
> netdev_linux_get_next_hop, \
> + NULL, /* get_tnl_iface */ \
> netdev_linux_arp_lookup, \
> \
> netdev_linux_update_flags, \
> diff --git a/lib/netdev-provider.h b/lib/netdev-provider.h
> index d955bb1..038f277 100644
> --- a/lib/netdev-provider.h
> +++ b/lib/netdev-provider.h
> @@ -518,6 +518,17 @@ struct netdev_class {
> int (*get_next_hop)(const struct in_addr *host, struct in_addr *next_hop,
> char **netdev_name);
>
> + /* Looks up the name of the interface out of which traffic will egress if
> + * 'netdev' is a tunnel. If unsuccessful, or 'netdev' is not a tunnel,
> + * will return null. This function does not necessarily return the
> + * physical interface out which traffic will egress. Instead it returns
> + * the interface which is assigned 'netdev's remote_ip. This may be an
> + * internal interface such as a bridge port.
> + *
> + * This function may be set to null if 'netdev' is not a tunnel or it is
> + * not supported. */
> + const char *(*get_tnl_iface)(const struct netdev *netdev);
> +
> /* Looks up the ARP table entry for 'ip' on 'netdev' and stores the
> * corresponding MAC address in 'mac'. A return value of ENXIO, in
> * particular, indicates that there is no ARP table entry for 'ip' on
> diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
> index 11db099..3a74d98 100644
> --- a/lib/netdev-vport.c
> +++ b/lib/netdev-vport.c
> @@ -20,21 +20,50 @@
>
> #include <errno.h>
> #include <fcntl.h>
> +#include <sys/socket.h>
> +#include <linux/rtnetlink.h>
> #include <net/if.h>
> #include <sys/ioctl.h>
>
> #include "byte-order.h"
> +#include "hash.h"
> +#include "hmap.h"
> #include "list.h"
> #include "netdev-provider.h"
> +#include "netlink.h"
> +#include "netlink-socket.h"
> +#include "ofpbuf.h"
> #include "openvswitch/datapath-protocol.h"
> #include "openvswitch/tunnel.h"
> #include "packets.h"
> +#include "rtnetlink.h"
> +#include "rtnetlink-route.h"
> +#include "rtnetlink-link.h"
> #include "shash.h"
> #include "socket-util.h"
> #include "vlog.h"
>
> VLOG_DEFINE_THIS_MODULE(netdev_vport);
>
> +static struct hmap name_map;
> +static struct hmap route_map;
> +static struct rtnetlink_notifier netdev_vport_link_notifier;
> +static struct rtnetlink_notifier netdev_vport_route_notifier;
> +
> +struct route_node {
> + struct hmap_node node; /* Node in route_map. */
> + int rta_oif; /* Egress interface index. */
> + uint32_t rta_dst; /* Destination address in host byte order. */
> + unsigned char rtm_dst_len; /* Destination address length. */
> +};
> +
> +struct name_node {
> + struct hmap_node node; /* Node in name_map. */
> + uint32_t ifi_index; /* Kernel interface index. */
> +
> + char ifname[IFNAMSIZ]; /* Interface name. */
> +};
> +
> struct netdev_vport_notifier {
> struct netdev_notifier notifier;
> struct list list_node;
> @@ -66,6 +95,12 @@ static int netdev_vport_create(const struct netdev_class *, const char *,
> const struct shash *, struct netdev_dev **);
> static void netdev_vport_poll_notify(const struct netdev *);
>
> +static void netdev_vport_tnl_iface_init(void);
> +static void netdev_vport_route_change(const struct rtnetlink_route_change *,
> + void *);
> +static void netdev_vport_link_change(const struct rtnetlink_link_change *,
> + void *);
> +
> static bool
> is_vport_class(const struct netdev_class *class)
> {
> @@ -108,6 +143,13 @@ netdev_vport_get_config(const struct netdev *netdev, void *config)
> }
>
> static int
> +netdev_vport_init(void)
> +{
> + netdev_vport_tnl_iface_init();
> + return 0;
> +}
> +
> +static int
> netdev_vport_create(const struct netdev_class *netdev_class, const char *name,
> const struct shash *args,
> struct netdev_dev **netdev_devp)
> @@ -387,6 +429,284 @@ netdev_vport_poll_remove(struct netdev_notifier *notifier_)
>
> free(notifier);
> }
> +
> +static void
> +netdev_vport_run(void)
> +{
> + rtnetlink_link_notifier_run();
> + rtnetlink_route_notifier_run();
> +}
> +
> +static void
> +netdev_vport_wait(void)
> +{
> + rtnetlink_link_notifier_wait();
> + rtnetlink_route_notifier_wait();
> +}
> +
> +/* get_tnl_iface() implementation. */
> +
> +static struct name_node *
> +name_node_lookup(int ifi_index)
> +{
> + struct name_node *nn;
> +
> + HMAP_FOR_EACH_WITH_HASH(nn, node, hash_int(ifi_index, 0), &name_map) {
> + if (nn->ifi_index == ifi_index) {
> + return nn;
> + }
> + }
> +
> + return NULL;
> +}
> +
> +static struct route_node *
> +route_node_lookup(int rta_oif, uint32_t rta_dst, unsigned char rtm_dst_len)
> +{
> + uint32_t hash;
> + struct route_node *rn;
> +
> + hash = hash_3words(rta_oif, rta_dst, rtm_dst_len);
> + HMAP_FOR_EACH_WITH_HASH(rn, node, hash, &route_map) {
> + if (rn->rta_oif == rn->rta_oif &&
> + rn->rta_dst == rn->rta_dst &&
> + rn->rtm_dst_len == rn->rtm_dst_len) {
> + return rn;
> + }
> + }
> +
> + return NULL;
> +}
> +
> +/* Resets the name or route map depending on the value of 'is_name'. Clears
> + * the appropraite map, makes an rtnetlink dump request, and calls the change
> + * callback for each reply from the kernel. One should probably use
> + * netdev_vport_reset_routes or netdev_vport_reset_names instead. */
> +static int
> +netdev_vport_reset_name_else_route(bool is_name)
> +{
> + int error;
> + int nlmsg_type;
> + struct nl_dump dump;
> + struct rtgenmsg *rtmsg;
> + struct ofpbuf request, reply;
> + static struct nl_sock *rtnl_sock;
> +
> + if (is_name) {
> + struct name_node *nn, *nn_next;
> +
> + HMAP_FOR_EACH_SAFE(nn, nn_next, node, &name_map) {
> + hmap_remove(&name_map, &nn->node);
> + free(nn);
> + }
> + } else {
> + struct route_node *rn, *rn_next;
> +
> + HMAP_FOR_EACH_SAFE(rn, rn_next, node, &route_map) {
> + hmap_remove(&route_map, &rn->node);
> + free(rn);
> + }
> + }
> +
> + error = nl_sock_create(NETLINK_ROUTE, 0, 0, 0, &rtnl_sock);
> + if (error) {
> + VLOG_WARN_RL(&rl, "Failed to create NETLINK_ROUTE socket");
> + return error;
> + }
> +
> + ofpbuf_init(&request, 0);
> +
> + nlmsg_type = is_name ? RTM_GETLINK : RTM_GETROUTE;
> + nl_msg_put_nlmsghdr(&request, sizeof *rtmsg, nlmsg_type, NLM_F_REQUEST);
> +
> + rtmsg = ofpbuf_put_zeros(&request, sizeof *rtmsg);
> + rtmsg->rtgen_family = AF_INET;
> +
> + nl_dump_start(&dump, rtnl_sock, &request);
> +
> + while (nl_dump_next(&dump, &reply)) {
> + if (is_name) {
> + struct rtnetlink_link_change change;
> +
> + if (rtnetlink_link_parse(&reply, &change)) {
> + netdev_vport_link_change(&change, NULL);
> + }
> + } else {
> + struct rtnetlink_route_change change;
> +
> + if (rtnetlink_route_parse(&reply, &change)) {
> + netdev_vport_route_change(&change, NULL);
> + }
> + }
> + }
> +
> + error = nl_dump_done(&dump);
> + nl_sock_destroy(rtnl_sock);
> +
> + return error;
> +}
> +
> +static int
> +netdev_vport_reset_routes(void)
> +{
> + return netdev_vport_reset_name_else_route(false);
> +}
> +
> +static int
> +netdev_vport_reset_names(void)
> +{
> + return netdev_vport_reset_name_else_route(true);
> +}
> +
> +static void
> +netdev_vport_route_change(const struct rtnetlink_route_change *change,
> + void *aux OVS_UNUSED)
> +{
> +
> + if (!change) {
> + netdev_vport_reset_routes();
> + } else if (change->nlmsg_type == RTM_NEWROUTE) {
> + uint32_t hash;
> + struct route_node *rn;
> +
> + if (route_node_lookup(change->rta_oif, change->rta_dst,
> + change->rtm_dst_len)) {
> + return;
> + }
> +
> + rn = xzalloc(sizeof *rn);
> + rn->rta_oif = change->rta_oif;
> + rn->rta_dst = change->rta_dst;
> + rn->rtm_dst_len = change->rtm_dst_len;
> +
> + hash = hash_3words(rn->rta_oif, rn->rta_dst, rn->rtm_dst_len);
> + hmap_insert(&route_map, &rn->node, hash);
> + } else if (change->nlmsg_type == RTM_DELROUTE) {
> + struct route_node *rn;
> +
> + rn = route_node_lookup(change->rta_oif, change->rta_dst,
> + change->rtm_dst_len);
> +
> + if (rn) {
> + hmap_remove(&route_map, &rn->node);
> + free(rn);
> + }
> + } else {
> + VLOG_WARN_RL(&rl, "Received unexpected rtnetlink message type %d",
> + change->nlmsg_type);
> + }
> +}
> +
> +static void
> +netdev_vport_link_change(const struct rtnetlink_link_change *change,
> + void *aux OVS_UNUSED)
> +{
> +
> + if (!change) {
> + netdev_vport_reset_names();
> + } else if (change->nlmsg_type == RTM_NEWLINK) {
> + struct name_node *nn;
> +
> + if (name_node_lookup(change->ifi_index)) {
> + return;
> + }
> +
> + nn = xzalloc(sizeof *nn);
> + nn->ifi_index = change->ifi_index;
> +
> + strncpy(nn->ifname, change->ifname, IFNAMSIZ);
> + nn->ifname[IFNAMSIZ - 1] = '\0';
> +
> + hmap_insert(&name_map, &nn->node, hash_int(nn->ifi_index, 0));
> + } else if (change->nlmsg_type == RTM_DELLINK) {
> + struct name_node *nn;
> +
> + nn = name_node_lookup(change->ifi_index);
> +
> + if (nn) {
> + hmap_remove(&name_map, &nn->node);
> + free(nn);
> + }
> +
> + /* Link deletions do not result in all of the RTM_DELROUTE messages one
> + * would expect. For now, go ahead and reset route_map whenever a link
> + * is deleted. */
> + netdev_vport_reset_routes();
> + } else {
> + VLOG_WARN_RL(&rl, "Received unexpected rtnetlink message type %d",
> + change->nlmsg_type);
> + }
> +}
> +
> +static void
> +netdev_vport_tnl_iface_init(void)
> +{
> + static bool tnl_iface_is_init = false;
> +
> + if (!tnl_iface_is_init) {
> + hmap_init(&name_map);
> + hmap_init(&route_map);
> +
> + rtnetlink_link_notifier_register(&netdev_vport_link_notifier,
> + netdev_vport_link_change, NULL);
> +
> + rtnetlink_route_notifier_register(&netdev_vport_route_notifier,
> + netdev_vport_route_change, NULL);
> +
> + netdev_vport_reset_names();
> + netdev_vport_reset_routes();
> + tnl_iface_is_init = true;
> + }
> +}
> +
> +static const char *
> +netdev_vport_get_tnl_iface(const struct netdev *netdev)
> +{
> + int dst_len;
> + uint32_t route;
> + struct netdev_dev_vport *ndv;
> + struct tnl_port_config *config;
> + struct route_node *rn, *rn_def, *rn_iter;
> +
> + ndv = netdev_dev_vport_cast(netdev_get_dev(netdev));
> + config = (struct tnl_port_config *) ndv->config;
> + route = ntohl(config->daddr);
> +
> + dst_len = 0;
> + rn = NULL;
> + rn_def = NULL;
> +
> + HMAP_FOR_EACH(rn_iter, node, &route_map) {
> + if (rn_iter->rtm_dst_len == 0 && rn_iter->rta_dst == 0) {
> + /* Default route. */
> + rn_def = rn_iter;
> + } else if (rn_iter->rtm_dst_len > dst_len) {
> + uint32_t mask = 0xffffffff << (32 - rn_iter->rtm_dst_len);
> + if ((route & mask) == (rn_iter->rta_dst & mask)) {
> + rn = rn_iter;
> + dst_len = rn_iter->rtm_dst_len;
> + }
> + }
> + }
> +
> + if (!rn) {
> + rn = rn_def;
> + }
> +
> + if (rn) {
> + uint32_t hash;
> + struct name_node *nn;
> +
> + hash = hash_int(rn->rta_oif, 0);
> + HMAP_FOR_EACH_WITH_HASH(nn, node, hash, &name_map) {
> + if (nn->ifi_index == rn->rta_oif) {
> + return nn->ifname;
> + }
> + }
> + }
> +
> + return NULL;
> +}
>
> /* Helper functions. */
>
> @@ -604,10 +924,10 @@ parse_patch_config(const struct netdev_dev *dev, const struct shash *args,
> return 0;
> }
>
> -#define VPORT_FUNCTIONS \
> - NULL, /* init */ \
> - NULL, /* run */ \
> - NULL, /* wait */ \
> +#define VPORT_FUNCTIONS(TNL_IFACE) \
> + netdev_vport_init, \
> + netdev_vport_run, \
> + netdev_vport_wait, \
> \
> netdev_vport_create, \
> netdev_vport_destroy, \
> @@ -654,6 +974,7 @@ parse_patch_config(const struct netdev_dev *dev, const struct shash *args,
> NULL, /* get_in6 */ \
> NULL, /* add_router */ \
> NULL, /* get_next_hop */ \
> + TNL_IFACE, \
> NULL, /* arp_lookup */ \
> \
> netdev_vport_update_flags, \
> @@ -665,10 +986,13 @@ void
> netdev_vport_register(void)
> {
> static const struct vport_class vport_classes[] = {
> - { { "gre", VPORT_FUNCTIONS }, parse_tunnel_config },
> - { { "ipsec_gre", VPORT_FUNCTIONS }, parse_tunnel_config },
> - { { "capwap", VPORT_FUNCTIONS }, parse_tunnel_config },
> - { { "patch", VPORT_FUNCTIONS }, parse_patch_config }
> + { { "gre", VPORT_FUNCTIONS(netdev_vport_get_tnl_iface) },
> + parse_tunnel_config },
> + { { "ipsec_gre", VPORT_FUNCTIONS(netdev_vport_get_tnl_iface) },
> + parse_tunnel_config },
> + { { "capwap", VPORT_FUNCTIONS(netdev_vport_get_tnl_iface) },
> + parse_tunnel_config },
> + { { "patch", VPORT_FUNCTIONS(NULL) }, parse_patch_config }
> };
>
> int i;
> diff --git a/lib/netdev.c b/lib/netdev.c
> index c7de906..4b2e59e 100644
> --- a/lib/netdev.c
> +++ b/lib/netdev.c
> @@ -769,6 +769,16 @@ netdev_get_next_hop(const struct netdev *netdev,
> return error;
> }
>
> +const char *
> +netdev_get_tnl_iface(const struct netdev *netdev)
> +{
> + struct netdev_dev *dev = netdev_get_dev(netdev);
> +
> + return (dev->netdev_class->get_tnl_iface
> + ? dev->netdev_class->get_tnl_iface(netdev)
> + : NULL);
> +}
> +
> /* If 'netdev' has an assigned IPv6 address, sets '*in6' to that address and
> * returns 0. Otherwise, returns a positive errno value and sets '*in6' to
> * all-zero-bits (in6addr_any).
> diff --git a/lib/netdev.h b/lib/netdev.h
> index 6635a55..d7d7097 100644
> --- a/lib/netdev.h
> +++ b/lib/netdev.h
> @@ -141,6 +141,7 @@ int netdev_get_in6(const struct netdev *, struct in6_addr *);
> int netdev_add_router(struct netdev *, struct in_addr router);
> int netdev_get_next_hop(const struct netdev *, const struct in_addr *host,
> struct in_addr *next_hop, char **);
> +const char *netdev_get_tnl_iface(const struct netdev *);
> int netdev_arp_lookup(const struct netdev *, uint32_t ip, uint8_t mac[6]);
>
> int netdev_get_flags(const struct netdev *, enum netdev_flags *);
> diff --git a/lib/rtnetlink-link.c b/lib/rtnetlink-link.c
> index ffd615b..ad83a1d 100644
> --- a/lib/rtnetlink-link.c
> +++ b/lib/rtnetlink-link.c
> @@ -29,7 +29,10 @@
> static struct rtnetlink *rtn = NULL;
> static struct rtnetlink_link_change rtn_change;
>
> -static bool
> +/* 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)
> {
> diff --git a/lib/rtnetlink-link.h b/lib/rtnetlink-link.h
> index 9248b0a..c41612d 100644
> --- a/lib/rtnetlink-link.h
> +++ b/lib/rtnetlink-link.h
> @@ -17,6 +17,9 @@
> #ifndef RTNETLINK_LINK_H
> #define RTNETLINK_LINK_H 1
>
> +#include <stdbool.h>
> +
> +struct ofpbuf;
> struct rtnetlink_notifier;
>
> /* These functions are Linux specific, so they should be used directly only by
> @@ -45,6 +48,8 @@ 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);
> int rtnetlink_link_notifier_register(struct rtnetlink_notifier *,
> rtnetlink_link_notify_func *, void *aux);
> void rtnetlink_link_notifier_unregister(struct rtnetlink_notifier *);
> diff --git a/lib/rtnetlink-route.c b/lib/rtnetlink-route.c
> new file mode 100644
> index 0000000..549236e
> --- /dev/null
> +++ b/lib/rtnetlink-route.c
> @@ -0,0 +1,119 @@
> +/*
> + * Copyright (c) 2009, 2010 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 <config.h>
> +
> +#include "rtnetlink-route.h"
> +
> +#include <arpa/inet.h>
> +#include <sys/socket.h>
> +#include <linux/rtnetlink.h>
> +#include <net/if.h>
> +
> +#include "netlink.h"
> +#include "ofpbuf.h"
> +#include "rtnetlink.h"
> +
> +static struct rtnetlink *rtn = NULL;
> +static struct rtnetlink_route_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_route_parse(struct ofpbuf *buf,
> + struct rtnetlink_route_change *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 },
> + };
> +
> + static struct nlattr *attrs[ARRAY_SIZE(policy)];
> +
> + parsed = nl_policy_parse(buf, NLMSG_HDRLEN + sizeof(struct rtmsg),
> + policy, attrs, ARRAY_SIZE(policy));
> +
> + if (parsed) {
> + const struct nlmsghdr *nlmsg;
> + const struct rtmsg *rtm;
> +
> + nlmsg = buf->data;
> + rtm = (const struct rtmsg *) ((const char *) buf->data + NLMSG_HDRLEN);
> +
> + if (rtm->rtm_family != AF_INET) {
> + return false;
> + }
> +
> + change->nlmsg_type = nlmsg->nlmsg_type;
> + change->rtm_dst_len = rtm->rtm_dst_len;
> + change->rta_oif = nl_attr_get_u32(attrs[RTA_OIF]);
> + change->rta_dst = (attrs[RTA_DST]
> + ? ntohl(nl_attr_get_be32(attrs[RTA_DST]))
> + : 0);
> + }
> +
> + return parsed;
> +}
> +
> +/* Registers 'cb' to be called with auxiliary data 'aux' with route change
> + * notifications. The notifier is stored in 'notifier', which callers must
> + * not modify or free.
> + *
> + * Returns 0 if successful, otherwise a positive errno value. */
> +int
> +rtnetlink_route_notifier_register(struct rtnetlink_notifier *notifier,
> + rtnetlink_route_notify_func *cb, void *aux)
> +{
> + rtnetlink_parse_func *pf = (rtnetlink_parse_func *) rtnetlink_route_parse;
> + rtnetlink_notify_func *nf = (rtnetlink_notify_func *) cb;
> +
> + if (!rtn) {
> + rtn = rtnetlink_create(RTNLGRP_IPV4_ROUTE, pf, &rtn_change);
> + }
> +
> + return rtnetlink_notifier_register(rtn, notifier, nf, aux);
> +}
> +
> +/* Cancels notification on 'notifier', which must have previously been
> + * registered with rtnetlink_route_notifier_register(). */
> +void
> +rtnetlink_route_notifier_unregister(struct rtnetlink_notifier *notifier)
> +{
> + rtnetlink_notifier_unregister(rtn, notifier);
> +}
> +
> +/* Calls all of the registered notifiers, passing along any as-yet-unreported
> + * address change events. */
> +void
> +rtnetlink_route_notifier_run(void)
> +{
> + if (rtn) {
> + rtnetlink_notifier_run(rtn);
> + }
> +}
> +
> +/* Causes poll_block() to wake up when address change notifications are ready.
> + */
> +void
> +rtnetlink_route_notifier_wait(void)
> +{
> + if (rtn) {
> + rtnetlink_notifier_wait(rtn);
> + }
> +}
> diff --git a/lib/rtnetlink-route.h b/lib/rtnetlink-route.h
> new file mode 100644
> index 0000000..c9290d3
> --- /dev/null
> +++ b/lib/rtnetlink-route.h
> @@ -0,0 +1,55 @@
> +/*
> + * 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.
> + */
> +
> +#ifndef RTNETLINK_ROUTE_H
> +#define RTNETLINK_ROUTE_H 1
> +
> +#include <stdbool.h>
> +#include <stdint.h>
> +
> +struct ofpbuf;
> +struct rtnetlink_notifier;
> +
> +/* A digested version of a route message sent down by the kernel to indicate
> + * that a route has changed. */
> +struct rtnetlink_route_change {
> + /* Copied from struct nlmsghdr. */
> + int nlmsg_type; /* e.g. RTM_NEWROUTE, RTM_DELROUTE. */
> +
> + /* Copied from struct rtmsg. */
> + unsigned char rtm_dst_len;
> +
> + /* Extracted from Netlink attributes. */
> + uint32_t rta_dst; /* Destination in host byte order. 0 if missing. */
> + int rta_oif; /* Output interface index. */
> +};
> +
> +/* Function called to report that a route has changed. 'change' describes
> + * the specific change. It may be null, in which case the function must assume
> + * everything has changed. 'aux' is as specified in the call to
> + * rtnetlink_route_notifier_register(). */
> +typedef
> +void rtnetlink_route_notify_func(const struct rtnetlink_route_change *change,
> + void *aux);
> +
> +bool rtnetlink_route_parse(struct ofpbuf *, struct rtnetlink_route_change *);
> +int rtnetlink_route_notifier_register(struct rtnetlink_notifier *,
> + rtnetlink_route_notify_func *, void *aux);
> +void rtnetlink_route_notifier_unregister(struct rtnetlink_notifier *);
> +void rtnetlink_route_notifier_run(void);
> +void rtnetlink_route_notifier_wait(void);
> +
> +#endif /* rtnetlink-route.h */
> diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
> index 96a24fd..d505b53 100644
> --- a/vswitchd/bridge.c
> +++ b/vswitchd/bridge.c
> @@ -1102,6 +1102,14 @@ dpid_from_hash(const void *data, size_t n)
> }
>
> static void
> +iface_refresh_tunnel_egress(struct iface *iface)
> +{
> + const char *name = netdev_get_tnl_iface(iface->netdev);
> +
> + ovsrec_interface_set_tunnel_egress_iface(iface->cfg, name);
> +}
> +
> +static void
> iface_refresh_cfm_stats(struct iface *iface)
> {
> size_t i;
> @@ -1310,6 +1318,7 @@ bridge_run(void)
> struct iface *iface = port->ifaces[j];
> iface_refresh_stats(iface);
> iface_refresh_cfm_stats(iface);
> + iface_refresh_tunnel_egress(iface);
> }
> }
> }
> diff --git a/vswitchd/vswitch.ovsschema b/vswitchd/vswitch.ovsschema
> index a1917ee..d21a85c 100644
> --- a/vswitchd/vswitch.ovsschema
> +++ b/vswitchd/vswitch.ovsschema
> @@ -1,6 +1,6 @@
> {"name": "Open_vSwitch",
> - "version": "1.0.0",
> - "cksum": "514853437 13985",
> + "version": "1.0.1",
> + "cksum": "665434435 14130",
> "tables": {
> "Open_vSwitch": {
> "columns": {
> @@ -147,6 +147,10 @@
> "ingress_policing_burst": {
> "type": {"key": {"type": "integer",
> "minInteger": 0}}},
> + "tunnel_egress_iface": {
> + "type": {"key": {"type": "string"},
> + "min": 0, "max": 1},
> + "ephemeral": true},
> "mac": {
> "type": {"key": {"type": "string"},
> "min": 0, "max": 1}},
> diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml
> index 4aa4649..293634b 100644
> --- a/vswitchd/vswitch.xml
> +++ b/vswitchd/vswitch.xml
> @@ -1102,6 +1102,14 @@
> </dl>
> </column>
>
> + <column name="tunnel_egress_iface">
> + Egress interface for tunnels. Currently only relevant for GRE and
> + CAPWAP tunnels. On Linux systems, this column will show the name of
> + the interface which is responsible for routing traffic destined for the
> + configured <code>remote_ip</code>. This could be an internal interface
> + such as a bridge port.
> + </column>
> +
> <column name="other_config">
> Key-value pairs for rarely used interface features. Currently,
> there are none defined.
> --
> 1.7.2
>
>
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev_openvswitch.org
>
More information about the dev
mailing list