enum { QUEUE_MASK = MAX_QUEUE_LEN - 1 };
BUILD_ASSERT_DECL(IS_POW2(MAX_QUEUE_LEN));
+struct dp_netdev_upcall {
+ struct dpif_upcall upcall; /* Queued upcall information. */
+ struct ofpbuf buf; /* ofpbuf instance for upcall.packet. */
+};
+
struct dp_netdev_queue {
- struct dpif_upcall *upcalls[MAX_QUEUE_LEN];
+ struct dp_netdev_upcall upcalls[MAX_QUEUE_LEN];
unsigned int head, tail;
};
/* Maximum port MTU seen so far. */
static int max_mtu = ETH_PAYLOAD_MAX;
-static int get_port_by_number(struct dp_netdev *, uint16_t port_no,
+static int get_port_by_number(struct dp_netdev *, uint32_t port_no,
struct dp_netdev_port **portp);
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,
- const char *type, uint16_t port_no);
-static int do_del_port(struct dp_netdev *, uint16_t port_no);
+ const char *type, uint32_t port_no);
+static int do_del_port(struct dp_netdev *, uint32_t port_no);
static int dpif_netdev_open(const struct dpif_class *, const char *name,
bool create, struct dpif **);
static int dp_netdev_output_userspace(struct dp_netdev *, const struct ofpbuf *,
struct dp_netdev_queue *q = &dp->queues[i];
while (q->tail != q->head) {
- struct dpif_upcall *upcall = q->upcalls[q->tail++ & QUEUE_MASK];
-
- ofpbuf_delete(upcall->packet);
- free(upcall);
+ struct dp_netdev_upcall *u = &q->upcalls[q->tail++ & QUEUE_MASK];
+ ofpbuf_uninit(&u->buf);
}
}
}
static int
do_add_port(struct dp_netdev *dp, const char *devname, const char *type,
- uint16_t port_no)
+ uint32_t port_no)
{
struct dp_netdev_port *port;
struct netdev *netdev;
static int
dpif_netdev_port_add(struct dpif *dpif, struct netdev *netdev,
- uint16_t *port_nop)
+ uint32_t *port_nop)
{
struct dp_netdev *dp = get_dp_netdev(dpif);
int port_no;
- port_no = choose_port(dpif, netdev);
+ if (*port_nop != UINT32_MAX) {
+ if (*port_nop >= MAX_PORTS) {
+ return EFBIG;
+ } else if (dp->ports[*port_nop]) {
+ return EBUSY;
+ }
+ port_no = *port_nop;
+ } else {
+ port_no = choose_port(dpif, netdev);
+ }
if (port_no >= 0) {
*port_nop = port_no;
return do_add_port(dp, netdev_get_name(netdev),
}
static int
-dpif_netdev_port_del(struct dpif *dpif, uint16_t port_no)
+dpif_netdev_port_del(struct dpif *dpif, uint32_t port_no)
{
struct dp_netdev *dp = get_dp_netdev(dpif);
return port_no == OVSP_LOCAL ? EINVAL : do_del_port(dp, port_no);
}
static bool
-is_valid_port_number(uint16_t port_no)
+is_valid_port_number(uint32_t port_no)
{
return port_no < MAX_PORTS;
}
static int
get_port_by_number(struct dp_netdev *dp,
- uint16_t port_no, struct dp_netdev_port **portp)
+ uint32_t port_no, struct dp_netdev_port **portp)
{
if (!is_valid_port_number(port_no)) {
*portp = NULL;
}
static int
-do_del_port(struct dp_netdev *dp, uint16_t port_no)
+do_del_port(struct dp_netdev *dp, uint32_t port_no)
{
struct dp_netdev_port *port;
char *name;
}
static int
-dpif_netdev_port_query_by_number(const struct dpif *dpif, uint16_t port_no,
+dpif_netdev_port_query_by_number(const struct dpif *dpif, uint32_t port_no,
struct dpif_port *dpif_port)
{
struct dp_netdev *dp = get_dp_netdev(dpif);
ofpbuf_reserve(©, DP_NETDEV_HEADROOM);
ofpbuf_put(©, execute->packet->data, execute->packet->size);
- flow_extract(©, 0, 0, -1, &key);
+ flow_extract(©, 0, NULL, -1, &key);
error = dpif_netdev_flow_from_nlattrs(execute->key, execute->key_len,
&key);
if (!error) {
{
struct dp_netdev_queue *q = find_nonempty_queue(dpif);
if (q) {
- struct dpif_upcall *u = q->upcalls[q->tail++ & QUEUE_MASK];
- *upcall = *u;
- free(u);
+ struct dp_netdev_upcall *u = &q->upcalls[q->tail++ & QUEUE_MASK];
+
+ *upcall = u->upcall;
+ upcall->packet = buf;
ofpbuf_uninit(buf);
- *buf = *upcall->packet;
+ *buf = u->buf;
return 0;
} else {
}
\f
static void
-dp_netdev_flow_used(struct dp_netdev_flow *flow, struct flow *key,
- const struct ofpbuf *packet)
+dp_netdev_flow_used(struct dp_netdev_flow *flow, const struct ofpbuf *packet)
{
flow->used = time_msec();
flow->packet_count++;
flow->byte_count += packet->size;
- flow->tcp_flags |= packet_get_tcp_flags(packet, key);
+ flow->tcp_flags |= packet_get_tcp_flags(packet, &flow->key);
}
static void
if (packet->size < ETH_HEADER_LEN) {
return;
}
- flow_extract(packet, 0, 0, port->port_no, &key);
+ flow_extract(packet, 0, NULL, odp_port_to_ofp_port(port->port_no), &key);
flow = dp_netdev_lookup_flow(dp, &key);
if (flow) {
- dp_netdev_flow_used(flow, &key, packet);
+ dp_netdev_flow_used(flow, packet);
dp_netdev_execute_actions(dp, packet, &key,
flow->actions, flow->actions_len);
dp->n_hit++;
static void
dp_netdev_output_port(struct dp_netdev *dp, struct ofpbuf *packet,
- uint16_t out_port)
+ uint32_t out_port)
{
struct dp_netdev_port *p = dp->ports[out_port];
if (p) {
int queue_no, const struct flow *flow, uint64_t arg)
{
struct dp_netdev_queue *q = &dp->queues[queue_no];
+ struct dp_netdev_upcall *u;
struct dpif_upcall *upcall;
struct ofpbuf *buf;
size_t key_len;
return ENOBUFS;
}
- buf = ofpbuf_new(ODPUTIL_FLOW_KEY_BYTES + 2 + packet->size);
+ u = &q->upcalls[q->head++ & QUEUE_MASK];
+
+ buf = &u->buf;
+ ofpbuf_init(buf, ODPUTIL_FLOW_KEY_BYTES + 2 + packet->size);
odp_flow_key_from_flow(buf, flow);
key_len = buf->size;
ofpbuf_pull(buf, key_len);
ofpbuf_reserve(buf, 2);
ofpbuf_put(buf, packet->data, packet->size);
- upcall = xzalloc(sizeof *upcall);
+ upcall = &u->upcall;
upcall->type = queue_no;
upcall->packet = buf;
upcall->key = buf->base;
upcall->key_len = key_len;
upcall->userdata = arg;
- q->upcalls[q->head++ & QUEUE_MASK] = upcall;
-
return 0;
}
case OVS_KEY_ATTR_TUN_ID:
case OVS_KEY_ATTR_PRIORITY:
case OVS_KEY_ATTR_IPV6:
+ case OVS_KEY_ATTR_IPV4_TUNNEL:
/* not implemented */
break;