[ovs-dev] [PATCH 2/2] lib: Show tunnel egress interface in ovsdb

Ben Pfaff blp at nicira.com
Tue Jan 4 20:31:25 UTC 2011


Thanks.  It looks good.

I only see a misspelling: 'appropraite' should be 'appropriate'.

Please push this whenever you are ready.

On Tue, Jan 04, 2011 at 02:29:14PM -0600, Ethan Jackson wrote:
> I created netdev_vport_reset_[names|routes], changed
> netdev_vport_get_tnl_iface so it doesn't have to check the type, and
> changed remote_ip in vswitch.xml to use <code>
> 
> Ethan
> 
> On Tue, Jan 4, 2011 at 2:08 PM, Ben Pfaff <blp at nicira.com> wrote:
> > How's this version differ from the previous then?
> >
> > On Tue, Jan 04, 2011 at 01:46:08PM -0600, Ethan Jackson wrote:
> >> 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
> >> >
> >>
> >> _______________________________________________
> >> dev mailing list
> >> dev at openvswitch.org
> >> http://openvswitch.org/mailman/listinfo/dev_openvswitch.org
> >




More information about the dev mailing list