#include "packets.h"
#include "route-table.h"
#include "rtnetlink.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 rtnetlink_notifier netdev_vport_link_notifier;
-
-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;
size_t options_len,
struct nlattr *a[ODP_TUNNEL_ATTR_MAX + 1]);
-static void netdev_vport_tnl_iface_init(void);
-static void netdev_vport_link_change(const struct rtnetlink_link_change *,
- void *);
static const char *netdev_vport_get_tnl_iface(const struct netdev *netdev);
static bool
return "unknown";
}
-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,
static void
netdev_vport_run(void)
{
- rtnetlink_link_notifier_run();
route_table_run();
}
static void
netdev_vport_wait(void)
{
- rtnetlink_link_notifier_wait();
route_table_wait();
}
\f
/* 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;
-}
-
-/* Queries the kernel for fresh data to populate the name map with. */
-static int
-netdev_vport_reset_names(void)
-{
- int error;
- struct nl_dump dump;
- struct rtgenmsg *rtmsg;
- struct ofpbuf request, reply;
- static struct nl_sock *rtnl_sock;
- struct name_node *nn, *nn_next;
-
- HMAP_FOR_EACH_SAFE(nn, nn_next, node, &name_map) {
- hmap_remove(&name_map, &nn->node);
- free(nn);
- }
-
- error = nl_sock_create(NETLINK_ROUTE, &rtnl_sock);
- if (error) {
- VLOG_WARN_RL(&rl, "Failed to create NETLINK_ROUTE socket");
- return error;
- }
-
- ofpbuf_init(&request, 0);
-
- nl_msg_put_nlmsghdr(&request, sizeof *rtmsg, RTM_GETLINK, 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)) {
- struct rtnetlink_link_change change;
-
- if (rtnetlink_link_parse(&reply, &change)) {
- netdev_vport_link_change(&change, NULL);
- }
- }
- nl_sock_destroy(rtnl_sock);
-
- return nl_dump_done(&dump);
-}
-
-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);
- }
-
- } 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);
-
- rtnetlink_link_notifier_register(&netdev_vport_link_notifier,
- netdev_vport_link_change, NULL);
-
- netdev_vport_reset_names();
- tnl_iface_is_init = true;
- }
-}
-
static const char *
netdev_vport_get_tnl_iface(const struct netdev *netdev)
{
struct nlattr *a[ODP_TUNNEL_ATTR_MAX + 1];
- int ifindex;
uint32_t route;
struct netdev_dev_vport *ndv;
+ static char name[IFNAMSIZ];
ndv = netdev_dev_vport_cast(netdev_get_dev(netdev));
if (tnl_port_config_from_nlattr(ndv->options->data, ndv->options->size,
}
route = nl_attr_get_be32(a[ODP_TUNNEL_ATTR_DST_IPV4]);
- if (route_table_get_ifindex(route, &ifindex)) {
- struct name_node *nn;
- HMAP_FOR_EACH_WITH_HASH(nn, node, hash_int(ifindex, 0), &name_map) {
- if (nn->ifi_index == ifindex) {
- return nn->ifname;
- }
- }
+ if (route_table_get_name(route, name)) {
+ return name;
}
return NULL;
}
\f
#define VPORT_FUNCTIONS(GET_STATUS) \
- netdev_vport_init, \
+ NULL, \
netdev_vport_run, \
netdev_vport_wait, \
\
#include "netlink-socket.h"
#include "ofpbuf.h"
#include "rtnetlink.h"
+#include "rtnetlink-link.h"
#include "vlog.h"
VLOG_DEFINE_THIS_MODULE(route_table);
struct route_data rd; /* Data associated with this node. */
};
+struct name_node {
+ struct hmap_node node; /* Node in name_map. */
+ uint32_t ifi_index; /* Kernel interface index. */
+
+ char ifname[IFNAMSIZ]; /* Interface name. */
+};
+
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
static unsigned int register_count = 0;
static struct rtnetlink *rtn = NULL;
static struct route_table_msg rtmsg;
-static struct rtnetlink_notifier notifier;
+static struct rtnetlink_notifier route_notifier;
+static struct rtnetlink_notifier name_notifier;
static bool route_table_valid = false;
+static bool name_table_valid = false;
static struct hmap route_map;
+static struct hmap name_map;
static int route_table_reset(void);
static void route_table_handle_msg(const struct route_table_msg *);
static void route_map_clear(void);
static uint32_t hash_route_data(const struct route_data *);
+static void name_table_init(void);
+static void name_table_uninit(void);
+static int name_table_reset(void);
+static void name_table_change(const struct rtnetlink_link_change *, void *);
+static void name_map_clear(void);
+static struct name_node *name_node_lookup(int ifi_index);
+
+/* Populates 'name' with the name of the interface traffic destined for 'ip'
+ * is likely to egress out of (see route_table_get_ifindex).
+ *
+ * Returns true if successful, otherwise false. */
+bool
+route_table_get_name(ovs_be32 ip, char name[IFNAMSIZ])
+{
+ int ifindex;
+
+ if (!name_table_valid) {
+ name_table_reset();
+ }
+
+ if (route_table_get_ifindex(ip, &ifindex)) {
+ struct name_node *nn;
+
+ nn = name_node_lookup(ifindex);
+ if (nn) {
+ strncpy(name, nn->ifname, IFNAMSIZ);
+ return true;
+ }
+ }
+
+ return false;
+}
+
/* Populates 'ifindex' with the interface index traffic destined for 'ip' is
* likely to egress. There is no hard guarantee that traffic destined for 'ip'
* will egress out the specified interface. 'ifindex' may refer to an
nf = (rtnetlink_notify_func *) route_table_change;
rtn = rtnetlink_create(RTNLGRP_IPV4_ROUTE, pf, &rtmsg);
- rtnetlink_notifier_register(rtn, ¬ifier, nf, NULL);
+ rtnetlink_notifier_register(rtn, &route_notifier, nf, NULL);
hmap_init(&route_map);
route_table_reset();
+ name_table_init();
}
register_count++;
route_map_clear();
hmap_destroy(&route_map);
+ name_table_uninit();
}
}
route_table_run(void)
{
if (rtn) {
+ rtnetlink_link_notifier_run();
rtnetlink_notifier_run(rtn);
}
}
route_table_wait(void)
{
if (rtn) {
+ rtnetlink_link_notifier_wait();
rtnetlink_notifier_wait(rtn);
}
}
{
return hash_bytes(rd, sizeof *rd, 0);
}
+\f
+/* name_table . */
+
+static void
+name_table_init(void)
+{
+ hmap_init(&name_map);
+ rtnetlink_link_notifier_register(&name_notifier, name_table_change, NULL);
+ name_table_valid = false;
+}
+
+static void
+name_table_uninit(void)
+{
+ rtnetlink_link_notifier_unregister(&name_notifier);
+ name_map_clear();
+ hmap_destroy(&name_map);
+}
+
+static int
+name_table_reset(void)
+{
+ int error;
+ struct nl_dump dump;
+ struct rtgenmsg *rtmsg;
+ struct ofpbuf request, reply;
+ static struct nl_sock *rtnl_sock;
+
+ name_table_valid = true;
+ name_map_clear();
+ error = nl_sock_create(NETLINK_ROUTE, &rtnl_sock);
+ if (error) {
+ VLOG_WARN_RL(&rl, "failed to create NETLINK_ROUTE socket");
+ return error;
+ }
+
+ ofpbuf_init(&request, 0);
+ nl_msg_put_nlmsghdr(&request, sizeof *rtmsg, RTM_GETLINK, 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)) {
+ struct rtnetlink_link_change change;
+
+ if (rtnetlink_link_parse(&reply, &change)
+ && change.nlmsg_type == RTM_NEWLINK
+ && !name_node_lookup(change.ifi_index)) {
+ struct name_node *nn;
+
+ nn = xzalloc(sizeof *nn);
+ nn->ifi_index = change.ifi_index;
+ strncpy(nn->ifname, change.ifname, IFNAMSIZ);
+ nn->ifname[IFNAMSIZ] = '\0';
+ hmap_insert(&name_map, &nn->node, hash_int(nn->ifi_index, 0));
+ }
+ }
+ nl_sock_destroy(rtnl_sock);
+ return nl_dump_done(&dump);
+}
+
+static void
+name_table_change(const struct rtnetlink_link_change *change OVS_UNUSED,
+ void *aux OVS_UNUSED)
+{
+ /* Changes to interface status can cause routing table changes that some
+ * versions of the linux kernel do not advertise for some reason. */
+ route_table_valid = false;
+ name_table_valid = false;
+}
+
+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 void
+name_map_clear(void)
+{
+ struct name_node *nn, *nn_next;
+
+ HMAP_FOR_EACH_SAFE(nn, nn_next, node, &name_map) {
+ hmap_remove(&name_map, &nn->node);
+ free(nn);
+ }
+}