X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=lib%2Fdpif-linux.c;h=fa8eea6e7a26c3c5ac4ceaa1869a7a774c5f3a73;hb=2c360fbb2777fba6d35599e4b53287e2ecb26fa9;hp=bdc7703697f1e7b9584d4b558c68e4920a72882b;hpb=d0c23a1a57f5bd994d3af124673a218e21528dd3;p=openvswitch diff --git a/lib/dpif-linux.c b/lib/dpif-linux.c index bdc77036..fa8eea6e 100644 --- a/lib/dpif-linux.c +++ b/lib/dpif-linux.c @@ -32,6 +32,7 @@ #include #include +#include "bitmap.h" #include "dpif-provider.h" #include "netdev.h" #include "netdev-vport.h" @@ -52,6 +53,10 @@ VLOG_DEFINE_THIS_MODULE(dpif_linux); +enum { LRU_MAX_PORTS = 1024 }; +enum { LRU_MASK = LRU_MAX_PORTS - 1}; +BUILD_ASSERT_DECL(IS_POW2(LRU_MAX_PORTS)); + struct dpif_linux_dp { /* Generic Netlink header. */ uint8_t cmd; @@ -128,6 +133,12 @@ struct dpif_linux { struct sset changed_ports; /* Ports that have changed. */ struct rtnetlink_notifier port_notifier; bool change_error; + + /* Queue of unused ports. */ + unsigned long *lru_bitmap; + uint16_t lru_ports[LRU_MAX_PORTS]; + size_t lru_head; + size_t lru_tail; }; static struct vlog_rate_limit error_rl = VLOG_RATE_LIMIT_INIT(9999, 5); @@ -158,6 +169,29 @@ dpif_linux_cast(const struct dpif *dpif) return CONTAINER_OF(dpif, struct dpif_linux, dpif); } +static void +dpif_linux_push_port(struct dpif_linux *dp, uint16_t port) +{ + if (port < LRU_MAX_PORTS && !bitmap_is_set(dp->lru_bitmap, port)) { + bitmap_set1(dp->lru_bitmap, port); + dp->lru_ports[dp->lru_head++ & LRU_MASK] = port; + } +} + +static uint32_t +dpif_linux_pop_port(struct dpif_linux *dp) +{ + uint16_t port; + + if (dp->lru_head == dp->lru_tail) { + return UINT32_MAX; + } + + port = dp->lru_ports[dp->lru_tail++ & LRU_MASK]; + bitmap_set0(dp->lru_bitmap, port); + return port; +} + static int dpif_linux_enumerate(struct sset *all_dps) { @@ -235,6 +269,12 @@ open_dpif(const struct dpif_linux_dp *dp, struct dpif **dpifp) dpif->change_error = false; *dpifp = &dpif->dpif; + dpif->lru_head = dpif->lru_tail = 0; + dpif->lru_bitmap = bitmap_allocate(LRU_MAX_PORTS); + bitmap_set1(dpif->lru_bitmap, ODPP_LOCAL); + for (i = 1; i < LRU_MAX_PORTS; i++) { + dpif_linux_push_port(dpif, i); + } return 0; error_free: @@ -248,6 +288,7 @@ dpif_linux_close(struct dpif *dpif_) struct dpif_linux *dpif = dpif_linux_cast(dpif_); rtnetlink_link_notifier_unregister(&dpif->port_notifier); sset_destroy(&dpif->changed_ports); + free(dpif->lru_bitmap); free(dpif); } @@ -336,11 +377,17 @@ dpif_linux_port_add(struct dpif *dpif_, struct netdev *netdev, request.options_len = options->size; } - error = dpif_linux_vport_transact(&request, &reply, &buf); - if (!error) { - *port_nop = reply.port_no; + /* Loop until we find a port that isn't used. */ + do { + request.port_no = dpif_linux_pop_port(dpif); + error = dpif_linux_vport_transact(&request, &reply, &buf); + + if (!error) { + *port_nop = reply.port_no; + } ofpbuf_delete(buf); - } + } while (request.port_no != UINT32_MAX + && (error == EBUSY || error == EFBIG)); return error; } @@ -350,12 +397,18 @@ dpif_linux_port_del(struct dpif *dpif_, uint16_t port_no) { struct dpif_linux *dpif = dpif_linux_cast(dpif_); struct dpif_linux_vport vport; + int error; dpif_linux_vport_init(&vport); vport.cmd = ODP_VPORT_CMD_DEL; vport.dp_ifindex = dpif->dp_ifindex; vport.port_no = port_no; - return dpif_linux_vport_transact(&vport, NULL, NULL); + error = dpif_linux_vport_transact(&vport, NULL, NULL); + + if (!error) { + dpif_linux_push_port(dpif, port_no); + } + return error; } static int @@ -1019,7 +1072,7 @@ dpif_linux_is_internal_device(const char *name) error = dpif_linux_vport_get(name, &reply, &buf); if (!error) { ofpbuf_delete(buf); - } else if (error != ENODEV) { + } else if (error != ENODEV && error != ENOENT) { VLOG_WARN_RL(&error_rl, "%s: vport query failed (%s)", name, strerror(error)); } @@ -1027,6 +1080,34 @@ dpif_linux_is_internal_device(const char *name) return reply.type == ODP_VPORT_TYPE_INTERNAL; } +int +dpif_linux_vport_send(int dp_ifindex, uint32_t port_no, + const void *data, size_t size) +{ + struct odp_header *execute; + struct ofpbuf *buf; + size_t actions_ofs; + int error; + + buf = ofpbuf_new(128 + size); + + nl_msg_put_genlmsghdr(buf, 0, odp_packet_family, NLM_F_REQUEST, + ODP_PACKET_CMD_EXECUTE, 1); + + execute = ofpbuf_put_uninit(buf, sizeof *execute); + execute->dp_ifindex = dp_ifindex; + + nl_msg_put_unspec(buf, ODP_PACKET_ATTR_PACKET, data, size); + + actions_ofs = nl_msg_start_nested(buf, ODP_PACKET_ATTR_ACTIONS); + nl_msg_put_u32(buf, ODP_ACTION_ATTR_OUTPUT, port_no); + nl_msg_end_nested(buf, actions_ofs); + + error = nl_sock_transact(genl_sock, buf, NULL); + ofpbuf_delete(buf); + return error; +} + static void dpif_linux_port_changed(const struct rtnetlink_link_change *change, void *dpif_) @@ -1201,6 +1282,15 @@ dpif_linux_vport_transact(const struct dpif_linux_vport *request, assert((reply != NULL) == (bufp != NULL)); + error = dpif_linux_init(); + if (error) { + if (reply) { + *bufp = NULL; + dpif_linux_vport_init(reply); + } + return error; + } + request_buf = ofpbuf_new(1024); dpif_linux_vport_to_ofpbuf(request, request_buf); error = nl_sock_transact(genl_sock, request_buf, bufp);