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 *,
return &dpif->dpif;
}
+static int
+choose_port(struct dp_netdev *dp, const char *name)
+{
+ int port_no;
+
+ if (dp->class != &dpif_netdev_class) {
+ const char *p;
+ int start_no = 0;
+
+ /* If the port name begins with "br", start the number search at
+ * 100 to make writing tests easier. */
+ if (!strncmp(name, "br", 2)) {
+ start_no = 100;
+ }
+
+ /* If the port name contains a number, try to assign that port number.
+ * This can make writing unit tests easier because port numbers are
+ * predictable. */
+ for (p = name; *p != '\0'; p++) {
+ if (isdigit((unsigned char) *p)) {
+ port_no = start_no + strtol(p, NULL, 10);
+ if (port_no > 0 && port_no < MAX_PORTS
+ && !dp->ports[port_no]) {
+ return port_no;
+ }
+ break;
+ }
+ }
+ }
+
+ for (port_no = 1; port_no < MAX_PORTS; port_no++) {
+ if (!dp->ports[port_no]) {
+ return port_no;
+ }
+ }
+
+ return -1;
+}
+
static int
create_dp_netdev(const char *name, const struct dpif_class *class,
struct dp_netdev **dpp)
{
struct dp_netdev *dp;
+ int port_no;
int error;
int i;
}
hmap_init(&dp->flow_table);
list_init(&dp->port_list);
- error = do_add_port(dp, name, "internal", OVSP_LOCAL);
+
+ port_no = !strncmp(name, "br", 2) ? choose_port(dp, name) : OVSP_LOCAL;
+ error = do_add_port(dp, name, "internal", port_no);
if (error) {
dp_netdev_free(dp);
return error;
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;
return 0;
}
-static int
-choose_port(struct dpif *dpif, struct netdev *netdev)
-{
- struct dp_netdev *dp = get_dp_netdev(dpif);
- int port_no;
-
- if (dpif->dpif_class != &dpif_netdev_class) {
- /* If the port name contains a number, try to assign that port number.
- * This can make writing unit tests easier because port numbers are
- * predictable. */
- const char *p;
-
- for (p = netdev_get_name(netdev); *p != '\0'; p++) {
- if (isdigit((unsigned char) *p)) {
- port_no = strtol(p, NULL, 10);
- if (port_no > 0 && port_no < MAX_PORTS
- && !dp->ports[port_no]) {
- return port_no;
- }
- break;
- }
- }
- }
-
- for (port_no = 0; port_no < MAX_PORTS; port_no++) {
- if (!dp->ports[port_no]) {
- return port_no;
- }
- }
-
- return -1;
-}
-
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;
- if (*port_nop != UINT16_MAX) {
+ if (*port_nop != UINT32_MAX) {
if (*port_nop >= MAX_PORTS) {
return EFBIG;
} else if (dp->ports[*port_nop]) {
}
port_no = *port_nop;
} else {
- port_no = choose_port(dpif, netdev);
+ port_no = choose_port(dp, netdev_get_name(netdev));
}
if (port_no >= 0) {
*port_nop = port_no;
}
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);
int error;
error = get_port_by_number(dp, port_no, &port);
- if (!error) {
+ if (!error && dpif_port) {
answer_port_query(port, dpif_port);
}
return error;
int error;
error = get_port_by_name(dp, devname, &port);
- if (!error) {
+ if (!error && dpif_port) {
answer_port_query(port, dpif_port);
}
return error;
struct ofpbuf buf;
ofpbuf_use_stack(&buf, &state->keybuf, sizeof state->keybuf);
- odp_flow_key_from_flow(&buf, &flow->key);
+ odp_flow_key_from_flow(&buf, &flow->key, flow->key.in_port);
*key = buf.data;
*key_len = buf.size;
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, odp_port_to_ofp_port(port->port_no), &key);
+ flow_extract(packet, 0, NULL, 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);
- odp_flow_key_from_flow(buf, flow);
+ 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, flow->in_port);
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;
}
{
enum ovs_key_attr type = nl_attr_type(a);
const struct ovs_key_ipv4 *ipv4_key;
+ const struct ovs_key_ipv6 *ipv6_key;
const struct ovs_key_tcp *tcp_key;
const struct ovs_key_udp *udp_key;
switch (type) {
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;
ipv4_key->ipv4_tos, ipv4_key->ipv4_ttl);
break;
+ case OVS_KEY_ATTR_IPV6:
+ ipv6_key = nl_attr_get_unspec(a, sizeof(struct ovs_key_ipv6));
+ packet_set_ipv6(packet, ipv6_key->ipv6_proto, ipv6_key->ipv6_src,
+ ipv6_key->ipv6_dst, ipv6_key->ipv6_tclass,
+ ipv6_key->ipv6_label, ipv6_key->ipv6_hlimit);
+ break;
+
case OVS_KEY_ATTR_TCP:
tcp_key = nl_attr_get_unspec(a, sizeof(struct ovs_key_tcp));
packet_set_tcp_port(packet, tcp_key->tcp_src, tcp_key->tcp_dst);