X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fnetdev-vport.c;h=ec67aaaae45093727155e5f3184c914537dc0dca;hb=ac4d3bcb46fa0acd0b63f79449432df28569f74f;hp=436be8c67ae1360d85e5b4a046f3cd44bbe2f286;hpb=254f2dc8e3eb18debf4a8f238b9c87cf4d4dbd3f;p=sliver-openvswitch.git diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c index 436be8c67..ec67aaaae 100644 --- a/lib/netdev-vport.c +++ b/lib/netdev-vport.c @@ -26,10 +26,13 @@ #include #include "byte-order.h" +#include "daemon.h" +#include "dirs.h" #include "dpif-linux.h" #include "hash.h" #include "hmap.h" #include "list.h" +#include "netdev-linux.h" #include "netdev-provider.h" #include "netlink.h" #include "netlink-socket.h" @@ -39,23 +42,12 @@ #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; @@ -65,6 +57,9 @@ struct netdev_vport_notifier { 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. */ + unsigned int change_seq; }; struct netdev_vport { @@ -93,9 +88,6 @@ static int tnl_port_config_from_nlattr(const struct nlattr *options, 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 @@ -189,14 +181,6 @@ netdev_vport_get_netdev_type(const struct dpif_linux_vport *vport) return "unknown"; } -static int -netdev_vport_init(void) -{ - netdev_vport_tnl_iface_init(); - route_table_register(); - return 0; -} - static int netdev_vport_create(const struct netdev_class *netdev_class, const char *name, const struct shash *args, @@ -205,10 +189,14 @@ netdev_vport_create(const struct netdev_class *netdev_class, const char *name, 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); @@ -235,6 +223,8 @@ netdev_vport_create(const struct netdev_class *netdev_class, const char *name, 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 { @@ -251,8 +241,12 @@ netdev_vport_create(const struct netdev_class *netdev_class, const char *name, shash_is_empty(&fetched_args) ? args : &fetched_args, netdev_class); dev->options = options; + dev->dp_ifindex = dp_ifindex; + dev->port_no = port_no; + dev->change_seq = 1; *netdev_devp = &dev->netdev_dev; + route_table_register(); } else { ofpbuf_delete(options); } @@ -330,6 +324,32 @@ netdev_vport_set_config(struct netdev_dev *dev_, const struct shash *args) 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]) @@ -399,27 +419,7 @@ netdev_vport_get_stats(const struct netdev *netdev, struct netdev_stats *stats) return EOPNOTSUPP; } - stats->rx_packets = reply.stats->rx_packets; - stats->tx_packets = reply.stats->tx_packets; - stats->rx_bytes = reply.stats->rx_bytes; - stats->tx_bytes = reply.stats->tx_bytes; - stats->rx_errors = reply.stats->rx_errors; - stats->tx_errors = reply.stats->tx_errors; - stats->rx_dropped = reply.stats->rx_dropped; - stats->tx_dropped = reply.stats->tx_dropped; - stats->multicast = reply.stats->multicast; - stats->collisions = reply.stats->collisions; - stats->rx_length_errors = reply.stats->rx_length_errors; - stats->rx_over_errors = reply.stats->rx_over_errors; - stats->rx_crc_errors = reply.stats->rx_crc_errors; - stats->rx_frame_errors = reply.stats->rx_frame_errors; - stats->rx_fifo_errors = reply.stats->rx_fifo_errors; - stats->rx_missed_errors = reply.stats->rx_missed_errors; - stats->tx_aborted_errors = reply.stats->tx_aborted_errors; - stats->tx_carrier_errors = reply.stats->tx_carrier_errors; - stats->tx_fifo_errors = reply.stats->tx_fifo_errors; - stats->tx_heartbeat_errors = reply.stats->tx_heartbeat_errors; - stats->tx_window_errors = reply.stats->tx_window_errors; + netdev_stats_from_rtnl_link_stats64(stats, reply.stats); ofpbuf_delete(buf); @@ -433,27 +433,7 @@ netdev_vport_set_stats(struct netdev *netdev, const struct netdev_stats *stats) struct dpif_linux_vport vport; int err; - rtnl_stats.rx_packets = stats->rx_packets; - rtnl_stats.tx_packets = stats->tx_packets; - rtnl_stats.rx_bytes = stats->rx_bytes; - rtnl_stats.tx_bytes = stats->tx_bytes; - rtnl_stats.rx_errors = stats->rx_errors; - rtnl_stats.tx_errors = stats->tx_errors; - rtnl_stats.rx_dropped = stats->rx_dropped; - rtnl_stats.tx_dropped = stats->tx_dropped; - rtnl_stats.multicast = stats->multicast; - rtnl_stats.collisions = stats->collisions; - rtnl_stats.rx_length_errors = stats->rx_length_errors; - rtnl_stats.rx_over_errors = stats->rx_over_errors; - rtnl_stats.rx_crc_errors = stats->rx_crc_errors; - rtnl_stats.rx_frame_errors = stats->rx_frame_errors; - rtnl_stats.rx_fifo_errors = stats->rx_fifo_errors; - rtnl_stats.rx_missed_errors = stats->rx_missed_errors; - rtnl_stats.tx_aborted_errors = stats->tx_aborted_errors; - rtnl_stats.tx_carrier_errors = stats->tx_carrier_errors; - rtnl_stats.tx_fifo_errors = stats->tx_fifo_errors; - rtnl_stats.tx_heartbeat_errors = stats->tx_heartbeat_errors; - rtnl_stats.tx_window_errors = stats->tx_window_errors; + netdev_stats_to_rtnl_link_stats64(&rtnl_stats, stats); dpif_linux_vport_init(&vport); vport.cmd = ODP_VPORT_CMD_SET; @@ -523,7 +503,7 @@ netdev_vport_poll_add(struct netdev *netdev, 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); @@ -560,139 +540,32 @@ netdev_vport_poll_remove(struct netdev_notifier *notifier_) free(notifier); } +static unsigned int +netdev_vport_change_seq(const struct netdev *netdev) +{ + return netdev_dev_vport_cast(netdev_get_dev(netdev))->change_seq; +} + 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(); } /* 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; + ovs_be32 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, @@ -701,13 +574,8 @@ netdev_vport_get_tnl_iface(const struct netdev *netdev) } 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; @@ -721,6 +589,9 @@ netdev_vport_poll_notify(const struct netdev *netdev) char *poll_name = make_poll_name(netdev); struct list *list = shash_find_data(&netdev_vport_notifiers, poll_name); + struct netdev_dev_vport *ndv; + + ndv = netdev_dev_vport_cast(netdev_get_dev(netdev)); if (list) { struct netdev_vport_notifier *notifier; @@ -731,6 +602,11 @@ netdev_vport_poll_notify(const struct netdev *netdev) } } + ndv->change_seq++; + if (!ndv->change_seq) { + ndv->change_seq++; + } + free(poll_name); } @@ -768,7 +644,7 @@ parse_tunnel_config(const char *name, const char *type, ovs_be32 daddr = htonl(0); uint32_t flags; - flags = TNL_F_PMTUD | TNL_F_HDR_CACHE; + flags = TNL_F_DF_DEFAULT | TNL_F_PMTUD | TNL_F_HDR_CACHE; if (!strcmp(type, "gre")) { is_gre = true; } else if (!strcmp(type, "ipsec_gre")) { @@ -810,6 +686,14 @@ parse_tunnel_config(const char *name, const char *type, if (!strcmp(node->data, "true")) { flags |= TNL_F_CSUM; } + } else if (!strcmp(node->name, "df_inherit")) { + if (!strcmp(node->data, "true")) { + flags |= TNL_F_DF_INHERIT; + } + } else if (!strcmp(node->name, "df_default")) { + if (!strcmp(node->data, "false")) { + flags &= ~TNL_F_DF_DEFAULT; + } } else if (!strcmp(node->name, "pmtud")) { if (!strcmp(node->data, "false")) { flags &= ~TNL_F_PMTUD; @@ -832,8 +716,8 @@ parse_tunnel_config(const char *name, const char *type, */ 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; @@ -845,8 +729,8 @@ parse_tunnel_config(const char *name, const char *type, || !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 { @@ -855,14 +739,24 @@ parse_tunnel_config(const char *name, const char *type, } 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; } } @@ -873,8 +767,8 @@ parse_tunnel_config(const char *name, const char *type, } 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); @@ -982,6 +876,12 @@ unparse_tunnel_config(const char *name OVS_UNUSED, const char *type OVS_UNUSED, if (flags & TNL_F_CSUM) { smap_add(args, "csum", "true"); } + if (flags & TNL_F_DF_INHERIT) { + smap_add(args, "df_inherit", "true"); + } + if (!(flags & TNL_F_DF_DEFAULT)) { + smap_add(args, "df_default", "false"); + } if (!(flags & TNL_F_PMTUD)) { smap_add(args, "pmtud", "false"); } @@ -997,22 +897,22 @@ parse_patch_config(const char *name, const char *type OVS_UNUSED, 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; } @@ -1046,7 +946,7 @@ unparse_patch_config(const char *name OVS_UNUSED, const char *type OVS_UNUSED, } #define VPORT_FUNCTIONS(GET_STATUS) \ - netdev_vport_init, \ + NULL, \ netdev_vport_run, \ netdev_vport_wait, \ \ @@ -1063,7 +963,7 @@ unparse_patch_config(const char *name OVS_UNUSED, const char *type OVS_UNUSED, NULL, /* recv_wait */ \ NULL, /* drain */ \ \ - NULL, /* send */ \ + netdev_vport_send, /* send */ \ NULL, /* send_wait */ \ \ netdev_vport_set_etheraddr, \ @@ -1102,7 +1002,8 @@ unparse_patch_config(const char *name OVS_UNUSED, const char *type OVS_UNUSED, netdev_vport_update_flags, \ \ netdev_vport_poll_add, \ - netdev_vport_poll_remove, + netdev_vport_poll_remove, \ + netdev_vport_change_seq void netdev_vport_register(void)