/*
- * Copyright (c) 2009, 2010, 2011 Nicira Networks.
+ * Copyright (c) 2009, 2010, 2011, 2012 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
int open_cnt;
bool destroyed;
- bool drop_frags; /* Drop all IP fragments, if true. */
struct dp_netdev_queue queues[N_QUEUES];
struct hmap flow_table; /* Flow table. */
/* Statistics. */
- long long int n_frags; /* Number of dropped IP fragments. */
long long int n_hit; /* Number of flow table matches. */
long long int n_missed; /* Number of flow table misses. */
long long int n_lost; /* Number of misses not passed to client. */
dp->class = class;
dp->name = xstrdup(name);
dp->open_cnt = 0;
- dp->drop_frags = false;
for (i = 0; i < N_QUEUES; i++) {
dp->queues[i].head = dp->queues[i].tail = 0;
}
{
struct dp_netdev *dp = get_dp_netdev(dpif);
stats->n_flows = hmap_count(&dp->flow_table);
- stats->n_frags = dp->n_frags;
stats->n_hit = dp->n_hit;
stats->n_missed = dp->n_missed;
stats->n_lost = dp->n_lost;
return 0;
}
-static int
-dpif_netdev_get_drop_frags(const struct dpif *dpif, bool *drop_fragsp)
-{
- struct dp_netdev *dp = get_dp_netdev(dpif);
- *drop_fragsp = dp->drop_frags;
- return 0;
-}
-
-static int
-dpif_netdev_set_drop_frags(struct dpif *dpif, bool drop_frags)
-{
- struct dp_netdev *dp = get_dp_netdev(dpif);
- dp->drop_frags = drop_frags;
- return 0;
-}
-
static int
do_add_port(struct dp_netdev *dp, const char *devname, const char *type,
uint16_t port_no)
}
static int
-dpif_netdev_port_add(struct dpif *dpif, struct netdev *netdev,
- uint16_t *port_nop)
+choose_port(struct dpif *dpif, struct netdev *netdev)
{
struct dp_netdev *dp = get_dp_netdev(dpif);
int port_no;
+ if (dpif->dpif_class == &dpif_dummy_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]) {
- *port_nop = port_no;
- return do_add_port(dp, netdev_get_name(netdev),
- netdev_get_type(netdev), port_no);
+ return port_no;
}
}
+
+ return -1;
+}
+
+static int
+dpif_netdev_port_add(struct dpif *dpif, struct netdev *netdev,
+ uint16_t *port_nop)
+{
+ struct dp_netdev *dp = get_dp_netdev(dpif);
+ int port_no;
+
+ port_no = choose_port(dpif, netdev);
+ if (port_no >= 0) {
+ *port_nop = port_no;
+ return do_add_port(dp, netdev_get_name(netdev),
+ netdev_get_type(netdev), port_no);
+ }
return EFBIG;
}
struct dpif_port *dpif_port)
{
dpif_port->name = xstrdup(netdev_get_name(port->netdev));
- dpif_port->type = xstrdup(port->internal ? "internal" : "system");
+ dpif_port->type = xstrdup(port->internal ? "internal"
+ : netdev_get_type(port->netdev));
dpif_port->port_no = port->port_no;
}
free(state->name);
state->name = xstrdup(netdev_get_name(port->netdev));
dpif_port->name = state->name;
- dpif_port->type = port->internal ? "internal" : "system";
+ dpif_port->type = (char *) (port->internal ? "internal"
+ : netdev_get_type(port->netdev));
dpif_port->port_no = port->port_no;
state->port_no = port_no + 1;
return 0;
ofpbuf_reserve(©, DP_NETDEV_HEADROOM);
ofpbuf_put(©, packet->data, packet->size);
- flow_extract(©, 0, -1, &key);
+ flow_extract(©, 0, 0, -1, &key);
error = dpif_netdev_flow_from_nlattrs(key_attrs, key_len, &key);
if (!error) {
dp_netdev_execute_actions(dp, ©, &key,
return 0;
}
+static int
+dpif_netdev_queue_to_priority(const struct dpif *dpif OVS_UNUSED,
+ uint32_t queue_id, uint32_t *priority)
+{
+ *priority = queue_id;
+ return 0;
+}
+
static struct dp_netdev_queue *
find_nonempty_queue(struct dpif *dpif)
{
if (packet->size < ETH_HEADER_LEN) {
return;
}
- if (flow_extract(packet, 0, port->port_no, &key) && dp->drop_frags) {
- dp->n_frags++;
- return;
- }
-
+ flow_extract(packet, 0, 0, port->port_no, &key);
flow = dp_netdev_lookup_flow(dp, &key);
if (flow) {
dp_netdev_flow_used(flow, &key, packet);
}
}
-static void
-dp_netdev_pop_vlan(struct ofpbuf *packet)
-{
- struct vlan_eth_header *veh = packet->l2;
- if (packet->size >= sizeof *veh
- && veh->veth_type == htons(ETH_TYPE_VLAN)) {
- struct eth_header tmp;
-
- memcpy(tmp.eth_dst, veh->veth_dst, ETH_ADDR_LEN);
- memcpy(tmp.eth_src, veh->veth_src, ETH_ADDR_LEN);
- tmp.eth_type = veh->veth_next_type;
-
- ofpbuf_pull(packet, VLAN_HEADER_LEN);
- packet->l2 = (char*)packet->l2 + VLAN_HEADER_LEN;
- memcpy(packet->data, &tmp, sizeof tmp);
- }
-}
-
static void
dp_netdev_set_dl(struct ofpbuf *packet, const struct ovs_key_ethernet *eth_key)
{
memcpy(eh->eth_dst, eth_key->eth_dst, sizeof eh->eth_dst);
}
-static void
-dp_netdev_set_ip_addr(struct ofpbuf *packet, ovs_be32 *addr, ovs_be32 new_addr)
-{
- struct ip_header *nh = packet->l3;
-
- if (nh->ip_proto == IPPROTO_TCP && packet->l7) {
- struct tcp_header *th = packet->l4;
- th->tcp_csum = recalc_csum32(th->tcp_csum, *addr, new_addr);
- } else if (nh->ip_proto == IPPROTO_UDP && packet->l7) {
- struct udp_header *uh = packet->l4;
- if (uh->udp_csum) {
- uh->udp_csum = recalc_csum32(uh->udp_csum, *addr, new_addr);
- if (!uh->udp_csum) {
- uh->udp_csum = htons(0xffff);
- }
- }
- }
- nh->ip_csum = recalc_csum32(nh->ip_csum, *addr, new_addr);
- *addr = new_addr;
-}
-
-static void
-dp_netdev_set_ip_tos(struct ip_header *nh, uint8_t new_tos)
-{
- uint8_t *field = &nh->ip_tos;
-
- /* Set the DSCP bits and preserve the ECN bits. */
- uint8_t new = new_tos | (nh->ip_tos & IP_ECN_MASK);
-
- nh->ip_csum = recalc_csum16(nh->ip_csum, htons((uint16_t)*field),
- htons((uint16_t) new));
- *field = new;
-}
-
-static void
-dp_netdev_set_ipv4(struct ofpbuf *packet, const struct ovs_key_ipv4 *ipv4_key)
-{
- struct ip_header *nh = packet->l3;
-
- if (nh->ip_src != ipv4_key->ipv4_src) {
- dp_netdev_set_ip_addr(packet, &nh->ip_src, ipv4_key->ipv4_src);
- }
- if (nh->ip_dst != ipv4_key->ipv4_dst) {
- dp_netdev_set_ip_addr(packet, &nh->ip_dst, ipv4_key->ipv4_dst);
- }
- if (nh->ip_tos != ipv4_key->ipv4_tos) {
- dp_netdev_set_ip_tos(nh, ipv4_key->ipv4_tos);
- }
-}
-
-static void
-dp_netdev_set_port(ovs_be16 *port, ovs_be16 new_port, ovs_be16 *csum)
-{
- *csum = recalc_csum16(*csum, *port, new_port);
- *port = new_port;
-}
-
-static void
-dp_netdev_set_tcp_port(struct ofpbuf *packet, const struct ovs_key_tcp *tcp_key)
-{
- struct tcp_header *th = packet->l4;
-
- if (th->tcp_src != tcp_key->tcp_src) {
- dp_netdev_set_port(&th->tcp_src, tcp_key->tcp_src, &th->tcp_csum);
- }
- if (th->tcp_dst != tcp_key->tcp_dst) {
- dp_netdev_set_port(&th->tcp_dst, tcp_key->tcp_dst, &th->tcp_csum);
- }
-}
-
-static void
-dp_netdev_set_udp_port(struct ofpbuf *packet, const struct ovs_key_udp *udp_key)
-{
- struct udp_header *uh = packet->l4;
-
- if (uh->udp_src != udp_key->udp_src) {
- dp_netdev_set_port(&uh->udp_src, udp_key->udp_src, &uh->udp_csum);
- }
- if (uh->udp_dst != udp_key->udp_dst) {
- dp_netdev_set_port(&uh->udp_dst, udp_key->udp_dst, &uh->udp_csum);
- }
-}
-
static void
dp_netdev_output_port(struct dp_netdev *dp, struct ofpbuf *packet,
uint16_t out_port)
execute_set_action(struct ofpbuf *packet, const struct nlattr *a)
{
enum ovs_key_attr type = nl_attr_type(a);
+ const struct ovs_key_ipv4 *ipv4_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:
+ /* not implemented */
break;
case OVS_KEY_ATTR_ETHERNET:
break;
case OVS_KEY_ATTR_IPV4:
- dp_netdev_set_ipv4(packet,
- nl_attr_get_unspec(a, sizeof(struct ovs_key_ipv4)));
+ ipv4_key = nl_attr_get_unspec(a, sizeof(struct ovs_key_ipv4));
+ packet_set_ipv4(packet, ipv4_key->ipv4_src, ipv4_key->ipv4_dst,
+ ipv4_key->ipv4_tos, ipv4_key->ipv4_ttl);
break;
case OVS_KEY_ATTR_TCP:
- dp_netdev_set_tcp_port(packet,
- nl_attr_get_unspec(a, sizeof(struct ovs_key_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);
break;
case OVS_KEY_ATTR_UDP:
- dp_netdev_set_udp_port(packet,
- nl_attr_get_unspec(a, sizeof(struct ovs_key_udp)));
+ udp_key = nl_attr_get_unspec(a, sizeof(struct ovs_key_udp));
+ packet_set_udp_port(packet, udp_key->udp_src, udp_key->udp_dst);
break;
case OVS_KEY_ATTR_UNSPEC:
+ case OVS_KEY_ATTR_ENCAP:
case OVS_KEY_ATTR_ETHERTYPE:
- case OVS_KEY_ATTR_IPV6:
case OVS_KEY_ATTR_IN_PORT:
- case OVS_KEY_ATTR_8021Q:
+ case OVS_KEY_ATTR_VLAN:
case OVS_KEY_ATTR_ICMP:
case OVS_KEY_ATTR_ICMPV6:
case OVS_KEY_ATTR_ARP:
unsigned int left;
NL_ATTR_FOR_EACH_UNSAFE (a, left, actions, actions_len) {
- const struct nlattr *nested;
- const struct ovs_key_8021q *q_key;
+ const struct ovs_action_push_vlan *vlan;
int type = nl_attr_type(a);
switch ((enum ovs_action_attr) type) {
dp_netdev_action_userspace(dp, packet, key, a);
break;
- case OVS_ACTION_ATTR_PUSH:
- nested = nl_attr_get(a);
- assert(nl_attr_type(nested) == OVS_KEY_ATTR_8021Q);
- q_key = nl_attr_get_unspec(nested, sizeof(*q_key));
- eth_push_vlan(packet, q_key->q_tci);
+ case OVS_ACTION_ATTR_PUSH_VLAN:
+ vlan = nl_attr_get(a);
+ eth_push_vlan(packet, vlan->vlan_tci);
break;
- case OVS_ACTION_ATTR_POP:
- assert(nl_attr_get_u16(a) == OVS_KEY_ATTR_8021Q);
- dp_netdev_pop_vlan(packet);
+ case OVS_ACTION_ATTR_POP_VLAN:
+ eth_pop_vlan(packet);
break;
case OVS_ACTION_ATTR_SET:
dp_netdev_sample(dp, packet, key, a);
break;
- case OVS_ACTION_ATTR_SET_PRIORITY:
- case OVS_ACTION_ATTR_POP_PRIORITY:
- /* not implemented */
- break;
-
case OVS_ACTION_ATTR_UNSPEC:
case __OVS_ACTION_ATTR_MAX:
NOT_REACHED();
dpif_netdev_run,
dpif_netdev_wait,
dpif_netdev_get_stats,
- dpif_netdev_get_drop_frags,
- dpif_netdev_set_drop_frags,
dpif_netdev_port_add,
dpif_netdev_port_del,
dpif_netdev_port_query_by_number,
NULL, /* operate */
dpif_netdev_recv_get_mask,
dpif_netdev_recv_set_mask,
- NULL, /* queue_to_priority */
+ dpif_netdev_queue_to_priority,
dpif_netdev_recv,
dpif_netdev_recv_wait,
dpif_netdev_recv_purge,