#include <sys/ioctl.h>
#include "byte-order.h"
+#include "daemon.h"
+#include "dirs.h"
#include "dpif-linux.h"
#include "hash.h"
#include "hmap.h"
#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;
struct netdev_dev_vport {
struct netdev_dev netdev_dev;
struct ofpbuf *options;
+ int dp_ifindex; /* -1 if unknown. */
+ uint32_t port_no; /* UINT32_MAX if unknown. */
};
struct netdev_vport {
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,
const struct vport_class *vport_class = vport_class_cast(netdev_class);
struct ofpbuf *options = NULL;
struct shash fetched_args;
+ int dp_ifindex;
+ uint32_t port_no;
int error;
shash_init(&fetched_args);
+ dp_ifindex = -1;
+ port_no = UINT32_MAX;
if (!shash_is_empty(args)) {
/* Parse the provided configuration. */
options = ofpbuf_new(64);
name, strerror(error));
} else {
options = ofpbuf_clone_data(reply.options, reply.options_len);
+ dp_ifindex = reply.dp_ifindex;
+ port_no = reply.port_no;
}
ofpbuf_delete(buf);
} else {
shash_is_empty(&fetched_args) ? args : &fetched_args,
netdev_class);
dev->options = options;
+ dev->dp_ifindex = dp_ifindex;
+ dev->port_no = port_no;
*netdev_devp = &dev->netdev_dev;
route_table_register();
return error;
}
+static int
+netdev_vport_send(struct netdev *netdev, const void *data, size_t size)
+{
+ struct netdev_dev *dev_ = netdev_get_dev(netdev);
+ struct netdev_dev_vport *dev = netdev_dev_vport_cast(dev_);
+
+ if (dev->dp_ifindex == -1) {
+ const char *name = netdev_get_name(netdev);
+ struct dpif_linux_vport reply;
+ struct ofpbuf *buf;
+ int error;
+
+ error = dpif_linux_vport_get(name, &reply, &buf);
+ if (error) {
+ VLOG_ERR_RL(&rl, "%s: failed to query vport for send (%s)",
+ name, strerror(error));
+ return error;
+ }
+ dev->dp_ifindex = reply.dp_ifindex;
+ dev->port_no = reply.port_no;
+ ofpbuf_delete(buf);
+ }
+
+ return dpif_linux_vport_send(dev->dp_ifindex, dev->port_no, data, size);
+}
+
static int
netdev_vport_set_etheraddr(struct netdev *netdev,
const uint8_t mac[ETH_ADDR_LEN])
struct list *list;
struct shash_node *shash_node;
- shash_node = shash_find_data(&netdev_vport_notifiers, poll_name);
+ shash_node = shash_find(&netdev_vport_notifiers, poll_name);
if (!shash_node) {
list = xmalloc(sizeof *list);
list_init(list);
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;
*/
use_ssl_cert = shash_find_data(args, "use_ssl_cert");
if (!use_ssl_cert || strcmp(use_ssl_cert, "true")) {
- VLOG_WARN("%s: 'peer_cert' requires 'certificate' argument",
- name);
+ VLOG_ERR("%s: 'peer_cert' requires 'certificate' argument",
+ name);
return EINVAL;
}
ipsec_mech_set = true;
|| !strcmp(node->name, "private_key")
|| !strcmp(node->name, "use_ssl_cert"))) {
/* Ignore options not used by the netdev. */
- } else if (is_gre && (!strcmp(node->name, "key") &&
- !strcmp(node->name, "in_key") &&
+ } else if (is_gre && (!strcmp(node->name, "key") ||
+ !strcmp(node->name, "in_key") ||
!strcmp(node->name, "out_key"))) {
/* Handled separately below. */
} else {
}
if (is_ipsec) {
+ char *file_name = xasprintf("%s/%s", ovs_rundir(),
+ "ovs-monitor-ipsec.pid");
+ pid_t pid = read_pidfile(file_name);
+ free(file_name);
+ if (pid < 0) {
+ VLOG_ERR("%s: IPsec requires the ovs-monitor-ipsec daemon",
+ name);
+ return EINVAL;
+ }
+
if (shash_find(args, "peer_cert") && shash_find(args, "psk")) {
- VLOG_WARN("%s: cannot define both 'peer_cert' and 'psk'", name);
+ VLOG_ERR("%s: cannot define both 'peer_cert' and 'psk'", name);
return EINVAL;
}
if (!ipsec_mech_set) {
- VLOG_WARN("%s: IPsec requires an 'peer_cert' or psk' argument",
- name);
+ VLOG_ERR("%s: IPsec requires an 'peer_cert' or psk' argument",
+ name);
return EINVAL;
}
}
}
if (!daddr) {
- VLOG_WARN("%s: %s type requires valid 'remote_ip' argument",
- name, type);
+ VLOG_ERR("%s: %s type requires valid 'remote_ip' argument",
+ name, type);
return EINVAL;
}
nl_msg_put_be32(options, ODP_TUNNEL_ATTR_DST_IPV4, daddr);
peer = shash_find_data(args, "peer");
if (!peer) {
- VLOG_WARN("%s: patch type requires valid 'peer' argument", name);
+ VLOG_ERR("%s: patch type requires valid 'peer' argument", name);
return EINVAL;
}
if (shash_count(args) > 1) {
- VLOG_WARN("%s: patch type takes only a 'peer' argument", name);
+ VLOG_ERR("%s: patch type takes only a 'peer' argument", name);
return EINVAL;
}
if (strlen(peer) >= IFNAMSIZ) {
- VLOG_WARN("%s: patch 'peer' arg too long", name);
+ VLOG_ERR("%s: patch 'peer' arg too long", name);
return EINVAL;
}
if (!strcmp(name, peer)) {
- VLOG_WARN("%s: patch peer must not be self", name);
+ VLOG_ERR("%s: patch peer must not be self", name);
return EINVAL;
}
}
\f
#define VPORT_FUNCTIONS(GET_STATUS) \
- netdev_vport_init, \
+ NULL, \
netdev_vport_run, \
netdev_vport_wait, \
\
NULL, /* recv_wait */ \
NULL, /* drain */ \
\
- NULL, /* send */ \
+ netdev_vport_send, /* send */ \
NULL, /* send_wait */ \
\
netdev_vport_set_etheraddr, \