A flow in ovs can be accesses by ufid, and in tc by flow handle + priority. We use the protocol number as the priority so we save a map that maps from ovs flow id to/from tc flow handle + protocol. Also added a map to map ovs in_port to/from netdevice.
Signed-off-by: Paul Blakey <pa...@mellanox.com> Signed-off-by: Shahar Klein <shah...@mellanox.com> --- lib/dpif-hw-netlink.c | 291 ++++++++++++++++++++++++++++++++++++++++++++++++++ lib/dpif-hw-netlink.h | 4 + 2 files changed, 295 insertions(+) diff --git a/lib/dpif-hw-netlink.c b/lib/dpif-hw-netlink.c index 5281de7..7394580 100644 --- a/lib/dpif-hw-netlink.c +++ b/lib/dpif-hw-netlink.c @@ -40,10 +40,289 @@ #include "unaligned.h" #include "util.h" #include "openvswitch/vlog.h" +#include "netdev-provider.h" #include "dpif-hw-netlink.h" VLOG_DEFINE_THIS_MODULE(dpif_hw_netlink); +static char * +printufid(const ovs_u128 * ovs_ufid) +{ + static char ufid[64]; + + if (ovs_ufid) + sprintf(ufid, "%x%x%x%x", ovs_ufid->u32[0], ovs_ufid->u32[1], + ovs_ufid->u32[2], ovs_ufid->u32[3]); + else + sprintf(ufid, "(missing_ufid)"); + return ufid; +} + +static inline size_t +hash_ufid(const ovs_u128 * ovs_ufid) +{ + return hash_words64((const uint64_t *) ovs_ufid, + sizeof *ovs_ufid / sizeof (uint64_t), 0); +} + +static inline size_t +hash_port(odp_port_t port) +{ + return hash_int((int) port, 0); +} + +static inline size_t +hash_handle_proto_port(int handle, int protocol, odp_port_t port) +{ + return hash_int(protocol, hash_int(handle, hash_port(port))); +} + +static struct netdev * +port_find(struct dpif_hw_netlink *dpif, odp_port_t port) +{ + struct port_netdev_hash_data *data; + size_t hash = hash_port(port); + struct netdev *res = 0; + + ovs_mutex_lock(&dpif->hash_mutex); + HMAP_FOR_EACH_WITH_HASH(data, node, hash, &dpif->port_to_netdev) { + if (data->port == port) + break; + } + if (data) { + res = data->netdev; + VLOG_DBG + ("found port mapping: port number %d -> port name %s (pointer: %p)\n", + port, res->name, res); + } + ovs_mutex_unlock(&dpif->hash_mutex); + + return res; +} + +static int +port_del_name(struct dpif_hw_netlink *dpif, char *name) +{ + struct port_netdev_hash_data *data; + + ovs_mutex_lock(&dpif->hash_mutex); + HMAP_FOR_EACH(data, node, &dpif->port_to_netdev) { + if (!strcmp(data->netdev->name, name)) + break; + } + if (data) + hmap_remove(&dpif->port_to_netdev, &data->node); + ovs_mutex_unlock(&dpif->hash_mutex); + + free(data); + return data ? 1 : 0; +} + +static int +port_del(struct dpif_hw_netlink *dpif, odp_port_t port) +{ + struct port_netdev_hash_data *data; + size_t hash = hash_port(port); + + ovs_mutex_lock(&dpif->hash_mutex); + HMAP_FOR_EACH_WITH_HASH(data, node, hash, &dpif->port_to_netdev) { + if (data->port == port) + break; + } + if (data) + hmap_remove(&dpif->port_to_netdev, &data->node); + ovs_mutex_unlock(&dpif->hash_mutex); + + free(data); + return data ? 1 : 0; +} + +static int +port_add(struct dpif_hw_netlink *dpif, odp_port_t port, struct netdev *netdev) +{ + struct port_netdev_hash_data *data; + size_t hash = hash_port(port); + int ret = 0; + + if (!netdev || !netdev->name || !port) + return -1; + + if (netdev->netdev_class == &netdev_internal_class) { + if (!strcmp(netdev->name, "skip_hw")) { + tc_set_skip_hw(true); + } + return -1; + } + if (port_del(dpif, port) || port_del_name(dpif, netdev->name)) { + VLOG_DBG + ("%s %d %s (%p) port number %d name: %s, deleted to be replaced\n", + __FILE__, __LINE__, __func__, dpif, port, netdev->name); + ret = 1; + } + + data = malloc(sizeof (struct port_netdev_hash_data)); + data->netdev = netdev; + data->port = port; + + VLOG_DBG + ("%s %d %s (%p): adding new port mapping: %d -> netdev %p name: %s, type: %s, ifindex: %d, hash: %lu\n", + __FILE__, __LINE__, __func__, dpif, port, netdev, netdev->name, + netdev->netdev_class->type, netdev_get_ifindex(netdev), hash); + ovs_mutex_lock(&dpif->hash_mutex); + hmap_insert(&dpif->port_to_netdev, &data->node, hash); + ovs_mutex_unlock(&dpif->hash_mutex); + return ret; +} + +static int +delhandle(struct dpif_hw_netlink *dpif, const ovs_u128 * ovs_ufid) +{ + struct ufid_handle_hash_data *data; + size_t hash; + + if (!ovs_ufid) { + VLOG_ERR("%s %d %s (%p) can't delete missing ufid\n", __FILE__, + __LINE__, __func__, dpif); + return 0; + } + hash = hash_ufid(ovs_ufid); + + VLOG_DBG("%s %d %s (%p): removing %s\n", __FILE__, __LINE__, __func__, + dpif, printufid(ovs_ufid)); + + ovs_mutex_lock(&dpif->hash_mutex); + HMAP_FOR_EACH_WITH_HASH(data, node_ufid, hash, &dpif->ufid_to_handle) { + if (!memcmp(&data->ovs_ufid, ovs_ufid, sizeof (*ovs_ufid))) + break; + } + if (data) { + VLOG_DBG("%s %d %s (%p) ufid %s found! handle: %d, removing it\n", + __FILE__, __LINE__, __func__, dpif, printufid(ovs_ufid), + data->handle); + hmap_remove(&dpif->ufid_to_handle, &data->node_ufid); + hmap_remove(&dpif->handle_to_ufid, &data->node_handle); + free(data); + } + ovs_mutex_unlock(&dpif->hash_mutex); + return data ? 1 : 0; +} + +static int +puthandle(struct dpif_hw_netlink *dpif, const ovs_u128 * ovs_ufid, + struct netdev *in, odp_port_t port, int handle, int protocol) +{ + int ret = 0; + size_t hash_to_ufid = hash_handle_proto_port(handle, protocol, port); + + if (!ovs_ufid) { + VLOG_ERR("%s %d %s (%p) missing UFID!\n", __FILE__, __LINE__, __func__, + dpif); + return 0; + } + + if (delhandle(dpif, ovs_ufid)) + ret = 1; + + struct ufid_handle_hash_data *data = + malloc(sizeof (struct ufid_handle_hash_data)); + data->ovs_ufid = *ovs_ufid; + data->handle = handle; + data->netdev = in; + data->port = port; + data->protocol = protocol; + + ovs_mutex_lock(&dpif->hash_mutex); + hmap_insert(&dpif->ufid_to_handle, &data->node_ufid, hash_ufid(ovs_ufid)); + hmap_insert(&dpif->handle_to_ufid, &data->node_handle, hash_to_ufid); + VLOG_DBG + ("%s %d %s (%p) added mapping %s <-> (handle: %d, protocl: %d, port: %d, indev: %p)\n", + __FILE__, __LINE__, __func__, dpif, printufid(ovs_ufid), handle, + protocol, port, in); + ovs_mutex_unlock(&dpif->hash_mutex); + return ret; +} + +static ovs_u128 * +findufid(struct dpif_hw_netlink *dpif, odp_port_t port, int handle, + int protocol) +{ + struct ufid_handle_hash_data *data; + size_t hash = hash_handle_proto_port(handle, protocol, port); + + VLOG_DBG + ("%s %d %s (%p) finding ufid of (handle: %d, protocol: %d, port: %d), hash: %lu\n", + __FILE__, __LINE__, __func__, dpif, handle, protocol, port, hash); + + ovs_mutex_lock(&dpif->hash_mutex); + HMAP_FOR_EACH_WITH_HASH(data, node_handle, hash, &dpif->handle_to_ufid) { + if (data->handle == handle && data->port == port + && data->protocol == protocol) + break; + } + ovs_mutex_unlock(&dpif->hash_mutex); + + return data ? &data->ovs_ufid : 0; +} + +static int +gethandle(struct dpif_hw_netlink *dpif, const ovs_u128 * ovs_ufid, + struct netdev **in, int *protocol, const char *func, int print) +{ + struct ufid_handle_hash_data *data; + int handle = 0; + size_t hash = 0; + + if (in) + *in = 0; + + if (!ovs_ufid) { + VLOG_DBG("%s %d %s (%p) called by %s without a ufid.\n", __FILE__, + __LINE__, __func__, dpif, func); + return 0; + } else + hash = hash_ufid(ovs_ufid); + + if (print) + VLOG_DBG("%s %d %s (%p) called by %s to find ufid %s\n", __FILE__, + __LINE__, __func__, dpif, func, printufid(ovs_ufid)); + + ovs_mutex_lock(&dpif->hash_mutex); + HMAP_FOR_EACH_WITH_HASH(data, node_ufid, hash, &dpif->ufid_to_handle) { + if (!memcmp(&data->ovs_ufid, ovs_ufid, sizeof (*ovs_ufid))) + break; + } + ovs_mutex_unlock(&dpif->hash_mutex); + + if (data && (!data->handle || !data->netdev || !data->protocol)) { + VLOG_ERR + ("mising handle/dev/protocl for ufid: %s, handle: %d, netdev: %p, protocol: %d\n", + printufid(ovs_ufid), data->handle, data->netdev, data->protocol); + return 0; + } + handle = data ? data->handle : 0; + if (in) + *in = data ? data->netdev : 0; + if (protocol) + *protocol = data ? data->protocol : 0; + if (print && handle) + VLOG_DBG("found ufid: %s, handle: %d, protocol: %d, netdev: %p\n", + printufid(ovs_ufid), handle, data->protocol, data->netdev); + return handle; +} + +static int +get_ovs_port(struct dpif_hw_netlink *dpif, int ifindex) +{ + struct port_netdev_hash_data *data; + + HMAP_FOR_EACH(data, node, &dpif->port_to_netdev) { + if (netdev_get_ifindex(data->netdev) == ifindex) { + return data->port; + } + } + return -1; +} + static struct dpif_hw_netlink * dpif_hw_netlink_cast(const struct dpif *dpif) { @@ -52,6 +331,16 @@ dpif_hw_netlink_cast(const struct dpif *dpif) } static int +initmaps(struct dpif_hw_netlink *dpif) +{ + hmap_init(&dpif->port_to_netdev); + hmap_init(&dpif->ufid_to_handle); + hmap_init(&dpif->handle_to_ufid); + ovs_mutex_init(&dpif->hash_mutex); + return 0; +} + +static int dpif_hw_netlink_open(const struct dpif_class *class OVS_UNUSED, const char *name, bool create, struct dpif **dpifp) { @@ -64,6 +353,8 @@ dpif_hw_netlink_open(const struct dpif_class *class OVS_UNUSED, dpif = xzalloc(sizeof *dpif); + initmaps(dpif); + *CONST_CAST(const char **, &dpif->name) = xstrdup(name); uint16_t netflow_id = hash_string(dpif->name, 0); diff --git a/lib/dpif-hw-netlink.h b/lib/dpif-hw-netlink.h index 42f203e..f44abca 100644 --- a/lib/dpif-hw-netlink.h +++ b/lib/dpif-hw-netlink.h @@ -10,6 +10,10 @@ struct dpif_hw_netlink { struct dpif dpif; struct dpif *lp_dpif_netlink; const char *const name; + struct ovs_mutex hash_mutex; + struct hmap port_to_netdev; + struct hmap ufid_to_handle; + struct hmap handle_to_ufid; }; struct port_netdev_hash_data { -- 1.8.3.1 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev