X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=lib%2Fdpif-netdev.c;h=eddd18bef0a4da88123724073017d77eb309c6bd;hb=05abb769d32d440dbd521e99484d8418f95431bd;hp=3cecde7112270ab0b1143a74534ebb66e0895b6e;hpb=7fa710e43fdf2dbf7fe41877cf73e04ccc4a7166;p=openvswitch diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 3cecde71..eddd18be 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -32,7 +32,9 @@ #include #include "csum.h" +#include "dpif.h" #include "dpif-provider.h" +#include "dummy.h" #include "flow.h" #include "hmap.h" #include "list.h" @@ -42,7 +44,6 @@ #include "ofpbuf.h" #include "packets.h" #include "poll-loop.h" -#include "queue.h" #include "shash.h" #include "timeval.h" #include "util.h" @@ -62,12 +63,14 @@ enum { DP_NETDEV_HEADROOM = 2 + VLAN_HEADER_LEN }; /* Datapath based on the network device interface from netdev.h. */ struct dp_netdev { + const struct dpif_class *class; char *name; int open_cnt; bool destroyed; bool drop_frags; /* Drop all IP fragments, if true. */ - struct ovs_queue queues[N_QUEUES]; /* Messages queued for dpif_recv(). */ + struct list queues[N_QUEUES]; /* Contain ofpbufs queued for dpif_recv(). */ + size_t queue_len[N_QUEUES]; /* Number of packets in each queue. */ struct hmap flow_table; /* Flow table. */ /* Statistics. */ @@ -88,7 +91,7 @@ struct dp_netdev_port { int port_no; /* Index into dp_netdev's 'ports'. */ struct list node; /* Element in dp_netdev's 'port_list'. */ struct netdev *netdev; - bool internal; /* Internal port (as ODP_PORT_INTERNAL)? */ + bool internal; /* Internal port? */ }; /* A flow in dp_netdev's 'flow_table'. */ @@ -127,19 +130,23 @@ static int get_port_by_name(struct dp_netdev *, const char *devname, struct dp_netdev_port **portp); static void dp_netdev_free(struct dp_netdev *); static void dp_netdev_flow_flush(struct dp_netdev *); -static int do_add_port(struct dp_netdev *, const char *devname, uint16_t flags, - uint16_t port_no); +static int do_add_port(struct dp_netdev *, const char *devname, + const char *type, uint16_t port_no); static int do_del_port(struct dp_netdev *, uint16_t port_no); +static int dpif_netdev_open(const struct dpif_class *, const char *name, + bool create, struct dpif **); static int dp_netdev_output_control(struct dp_netdev *, const struct ofpbuf *, int queue_no, int port_no, uint32_t arg); static int dp_netdev_execute_actions(struct dp_netdev *, struct ofpbuf *, struct flow *, const union odp_action *, int n); +static struct dpif_class dpif_dummy_class; + static struct dpif_netdev * dpif_netdev_cast(const struct dpif *dpif) { - dpif_assert_class(dpif, &dpif_netdev_class); + assert(dpif->dpif_class->open == dpif_netdev_open); return CONTAINER_OF(dpif, struct dpif_netdev, dpif); } @@ -158,8 +165,7 @@ create_dpif_netdev(struct dp_netdev *dp) dp->open_cnt++; dpif = xmalloc(sizeof *dpif); - dpif_init(&dpif->dpif, &dpif_netdev_class, dp->name, - netflow_id >> 8, netflow_id); + dpif_init(&dpif->dpif, dp->class, dp->name, netflow_id >> 8, netflow_id); dpif->dp = dp; dpif->listen_mask = 0; dpif->dp_serial = dp->serial; @@ -168,22 +174,24 @@ create_dpif_netdev(struct dp_netdev *dp) } static int -create_dp_netdev(const char *name, struct dp_netdev **dpp) +create_dp_netdev(const char *name, const struct dpif_class *class, + struct dp_netdev **dpp) { struct dp_netdev *dp; int error; int i; dp = xzalloc(sizeof *dp); + dp->class = class; dp->name = xstrdup(name); dp->open_cnt = 0; dp->drop_frags = false; for (i = 0; i < N_QUEUES; i++) { - queue_init(&dp->queues[i]); + list_init(&dp->queues[i]); } hmap_init(&dp->flow_table); list_init(&dp->port_list); - error = do_add_port(dp, name, ODP_PORT_INTERNAL, ODPP_LOCAL); + error = do_add_port(dp, name, "internal", ODPP_LOCAL); if (error) { dp_netdev_free(dp); return error; @@ -196,7 +204,7 @@ create_dp_netdev(const char *name, struct dp_netdev **dpp) } static int -dpif_netdev_open(const struct dpif_class *class OVS_UNUSED, const char *name, +dpif_netdev_open(const struct dpif_class *class, const char *name, bool create, struct dpif **dpifp) { struct dp_netdev *dp; @@ -206,14 +214,16 @@ dpif_netdev_open(const struct dpif_class *class OVS_UNUSED, const char *name, if (!create) { return ENODEV; } else { - int error = create_dp_netdev(name, &dp); + int error = create_dp_netdev(name, class, &dp); if (error) { return error; } assert(dp != NULL); } } else { - if (create) { + if (dp->class != class) { + return EINVAL; + } else if (create) { return EEXIST; } } @@ -234,7 +244,7 @@ dp_netdev_free(struct dp_netdev *dp) do_del_port(dp, port->port_no); } for (i = 0; i < N_QUEUES; i++) { - queue_destroy(&dp->queues[i]); + ofpbuf_list_delete(&dp->queues[i]); } hmap_destroy(&dp->flow_table); free(dp->name); @@ -297,23 +307,33 @@ dpif_netdev_set_drop_frags(struct dpif *dpif, bool drop_frags) } static int -do_add_port(struct dp_netdev *dp, const char *devname, uint16_t flags, +do_add_port(struct dp_netdev *dp, const char *devname, const char *type, uint16_t port_no) { - bool internal = (flags & ODP_PORT_INTERNAL) != 0; struct dp_netdev_port *port; struct netdev_options netdev_options; struct netdev *netdev; + bool internal; int mtu; int error; /* XXX reject devices already in some dp_netdev. */ + if (type[0] == '\0' || !strcmp(type, "system")) { + internal = false; + } else if (!strcmp(type, "internal")) { + internal = true; + } else { + VLOG_WARN("%s: unsupported port type %s", devname, type); + return EINVAL; + } /* Open and validate network device. */ memset(&netdev_options, 0, sizeof netdev_options); netdev_options.name = devname; netdev_options.ethertype = NETDEV_ETH_TYPE_ANY; - if (internal) { + if (dp->class == &dpif_dummy_class) { + netdev_options.type = "dummy"; + } else if (internal) { netdev_options.type = "tap"; } @@ -349,7 +369,7 @@ do_add_port(struct dp_netdev *dp, const char *devname, uint16_t flags, } static int -dpif_netdev_port_add(struct dpif *dpif, const char *devname, uint16_t flags, +dpif_netdev_port_add(struct dpif *dpif, struct netdev *netdev, uint16_t *port_nop) { struct dp_netdev *dp = get_dp_netdev(dpif); @@ -358,7 +378,8 @@ dpif_netdev_port_add(struct dpif *dpif, const char *devname, uint16_t flags, for (port_no = 0; port_no < MAX_PORTS; port_no++) { if (!dp->ports[port_no]) { *port_nop = port_no; - return do_add_port(dp, devname, flags, port_no); + return do_add_port(dp, netdev_get_name(netdev), + netdev_get_type(netdev), port_no); } } return EFBIG; @@ -438,7 +459,7 @@ answer_port_query(const struct dp_netdev_port *port, struct odp_port *odp_port) ovs_strlcpy(odp_port->devname, netdev_get_name(port->netdev), sizeof odp_port->devname); odp_port->port = port->port_no; - odp_port->flags = port->internal ? ODP_PORT_INTERNAL : 0; + strcpy(odp_port->type, port->internal ? "internal" : "system"); } static int @@ -794,7 +815,7 @@ dpif_netdev_execute(struct dpif *dpif, /* We need a deep copy of 'packet' since we're going to modify its * data. */ ofpbuf_init(©, DP_NETDEV_HEADROOM + packet->size); - copy.data = (char*)copy.base + DP_NETDEV_HEADROOM; + ofpbuf_reserve(©, DP_NETDEV_HEADROOM); ofpbuf_put(©, packet->data, packet->size); } else { /* We still need a shallow copy of 'packet', even though we won't @@ -831,7 +852,7 @@ dpif_netdev_recv_set_mask(struct dpif *dpif, int listen_mask) } } -static struct ovs_queue * +static int find_nonempty_queue(struct dpif *dpif) { struct dpif_netdev *dpif_netdev = dpif_netdev_cast(dpif); @@ -840,20 +861,24 @@ find_nonempty_queue(struct dpif *dpif) int i; for (i = 0; i < N_QUEUES; i++) { - struct ovs_queue *q = &dp->queues[i]; - if (q->n && mask & (1u << i)) { - return q; + struct list *queue = &dp->queues[i]; + if (!list_is_empty(queue) && mask & (1u << i)) { + return i; } } - return NULL; + return -1; } static int dpif_netdev_recv(struct dpif *dpif, struct ofpbuf **bufp) { - struct ovs_queue *q = find_nonempty_queue(dpif); - if (q) { - *bufp = queue_pop_head(q); + int queue_idx = find_nonempty_queue(dpif); + if (queue_idx >= 0) { + struct dp_netdev *dp = get_dp_netdev(dpif); + + *bufp = ofpbuf_from_list(list_pop_front(&dp->queues[queue_idx])); + dp->queue_len[queue_idx]--; + return 0; } else { return EAGAIN; @@ -863,8 +888,7 @@ dpif_netdev_recv(struct dpif *dpif, struct ofpbuf **bufp) static void dpif_netdev_recv_wait(struct dpif *dpif) { - struct ovs_queue *q = find_nonempty_queue(dpif); - if (q) { + if (find_nonempty_queue(dpif) >= 0) { poll_immediate_wake(); } else { /* No messages ready to be received, and dp_wait() will ensure that we @@ -927,8 +951,8 @@ dp_netdev_run(void) int error; /* Reset packet contents. */ - packet.data = (char*)packet.base + DP_NETDEV_HEADROOM; - packet.size = 0; + ofpbuf_clear(&packet); + ofpbuf_reserve(&packet, DP_NETDEV_HEADROOM); error = netdev_recv(port->netdev, &packet); if (!error) { @@ -1001,8 +1025,7 @@ dp_netdev_strip_vlan(struct ofpbuf *packet) memcpy(tmp.eth_src, veh->veth_src, ETH_ADDR_LEN); tmp.eth_type = veh->veth_next_type; - packet->size -= VLAN_HEADER_LEN; - packet->data = (char*)packet->data + VLAN_HEADER_LEN; + ofpbuf_pull(packet, VLAN_HEADER_LEN); packet->l2 = (char*)packet->l2 + VLAN_HEADER_LEN; memcpy(packet->data, &tmp, sizeof tmp); } @@ -1107,12 +1130,11 @@ static int dp_netdev_output_control(struct dp_netdev *dp, const struct ofpbuf *packet, int queue_no, int port_no, uint32_t arg) { - struct ovs_queue *q = &dp->queues[queue_no]; struct odp_msg *header; struct ofpbuf *msg; size_t msg_size; - if (q->n >= MAX_QUEUE_LEN) { + if (dp->queue_len[queue_no] >= MAX_QUEUE_LEN) { dp->n_lost++; return ENOBUFS; } @@ -1125,7 +1147,8 @@ dp_netdev_output_control(struct dp_netdev *dp, const struct ofpbuf *packet, header->port = port_no; header->arg = arg; ofpbuf_put(msg, packet->data, packet->size); - queue_push_tail(q, msg); + list_push_back(&dp->queues[queue_no], &msg->list_node); + dp->queue_len[queue_no]++; return 0; } @@ -1249,3 +1272,13 @@ const struct dpif_class dpif_netdev_class = { dpif_netdev_recv, dpif_netdev_recv_wait, }; + +void +dpif_dummy_register(void) +{ + if (!dpif_dummy_class.type) { + dpif_dummy_class = dpif_netdev_class; + dpif_dummy_class.type = "dummy"; + dp_register_provider(&dpif_dummy_class); + } +}