long long int used; /* Last used time, in monotonic msecs. */
long long int packet_count; /* Number of packets matched. */
long long int byte_count; /* Number of bytes matched. */
- uint16_t tcp_ctl; /* Bitwise-OR of seen tcp_ctl values. */
+ ovs_be16 tcp_ctl; /* Bitwise-OR of seen tcp_ctl values. */
/* Actions. */
struct nlattr *actions;
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 *,
+static int dp_netdev_output_userspace(struct dp_netdev *, const struct ofpbuf *,
int queue_no, const struct flow *,
uint64_t arg);
static int dp_netdev_execute_actions(struct dp_netdev *,
{
struct dp_netdev *dp = get_dp_netdev(dpif);
memset(stats, 0, sizeof *stats);
+ 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;
uint16_t port_no)
{
struct dp_netdev_port *port;
- struct netdev_options netdev_options;
struct netdev *netdev;
bool internal;
int mtu;
}
/* Open and validate network device. */
- memset(&netdev_options, 0, sizeof netdev_options);
- netdev_options.name = devname;
- netdev_options.ethertype = NETDEV_ETH_TYPE_ANY;
if (dp->class == &dpif_dummy_class) {
- netdev_options.type = "dummy";
+ type = "dummy";
} else if (internal) {
- netdev_options.type = "tap";
+ type = "tap";
}
- error = netdev_open(&netdev_options, &netdev);
+ error = netdev_open(devname, type, &netdev);
if (error) {
return error;
}
/* XXX reject loopback devices */
/* XXX reject non-Ethernet devices */
+ error = netdev_listen(netdev);
+ if (error) {
+ VLOG_ERR("%s: cannot receive packets on this network device (%s)",
+ devname, strerror(errno));
+ netdev_close(netdev);
+ return error;
+ }
+
error = netdev_turn_flags_on(netdev, NETDEV_PROMISC, false);
if (error) {
netdev_close(netdev);
port->internal = internal;
netdev_get_mtu(netdev, &mtu);
- if (mtu > max_mtu) {
+ if (mtu != INT_MAX && mtu > max_mtu) {
max_mtu = mtu;
}
}
break;
- case ODP_ACTION_ATTR_CONTROLLER:
- case ODP_ACTION_ATTR_DROP_SPOOFED_ARP:
+ case ODP_ACTION_ATTR_USERSPACE:
break;
case ODP_ACTION_ATTR_SET_DL_TCI:
uint32_t bucket;
uint32_t offset;
struct nlattr *actions;
- uint32_t keybuf[ODPUTIL_FLOW_KEY_U32S];
+ struct odputil_keybuf keybuf;
struct dpif_flow_stats stats;
};
if (key) {
struct ofpbuf buf;
- ofpbuf_use_stack(&buf, state->keybuf, sizeof state->keybuf);
+ ofpbuf_use_stack(&buf, &state->keybuf, sizeof state->keybuf);
odp_flow_key_from_flow(&buf, &flow->key);
- assert(buf.base == state->keybuf);
*key = buf.data;
*key_len = buf.size;
static int
dpif_netdev_execute(struct dpif *dpif,
+ const struct nlattr *key_attrs, size_t key_len,
const struct nlattr *actions, size_t actions_len,
const struct ofpbuf *packet)
{
* if we don't. */
copy = *packet;
}
+
flow_extract(©, 0, -1, &key);
+ dpif_netdev_flow_from_nlattrs(key_attrs, key_len, &key);
+
error = dp_netdev_execute_actions(dp, ©, &key, actions, actions_len);
if (mutates) {
ofpbuf_uninit(©);
dp->n_hit++;
} else {
dp->n_missed++;
- dp_netdev_output_control(dp, packet, DPIF_UC_MISS, &key, 0);
+ dp_netdev_output_userspace(dp, packet, DPIF_UC_MISS, &key, 0);
}
}
static void
-dp_netdev_run(void)
+dpif_netdev_run(struct dpif *dpif)
{
- struct shash_node *node;
+ struct dp_netdev *dp = get_dp_netdev(dpif);
+ struct dp_netdev_port *port;
struct ofpbuf packet;
ofpbuf_init(&packet, DP_NETDEV_HEADROOM + VLAN_ETH_HEADER_LEN + max_mtu);
- SHASH_FOR_EACH (node, &dp_netdevs) {
- struct dp_netdev *dp = node->data;
- struct dp_netdev_port *port;
-
- LIST_FOR_EACH (port, node, &dp->port_list) {
- int error;
-
- /* Reset packet contents. */
- ofpbuf_clear(&packet);
- ofpbuf_reserve(&packet, DP_NETDEV_HEADROOM);
- error = netdev_recv(port->netdev, &packet);
- if (!error) {
- dp_netdev_port_input(dp, port, &packet);
- } else if (error != EAGAIN && error != EOPNOTSUPP) {
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
- VLOG_ERR_RL(&rl, "error receiving data from %s: %s",
- netdev_get_name(port->netdev), strerror(error));
- }
+ LIST_FOR_EACH (port, node, &dp->port_list) {
+ int error;
+
+ /* Reset packet contents. */
+ ofpbuf_clear(&packet);
+ ofpbuf_reserve(&packet, DP_NETDEV_HEADROOM);
+
+ error = netdev_recv(port->netdev, &packet);
+ if (!error) {
+ dp_netdev_port_input(dp, port, &packet);
+ } else if (error != EAGAIN && error != EOPNOTSUPP) {
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+ VLOG_ERR_RL(&rl, "error receiving data from %s: %s",
+ netdev_get_name(port->netdev), strerror(error));
}
}
ofpbuf_uninit(&packet);
}
static void
-dp_netdev_wait(void)
+dpif_netdev_wait(struct dpif *dpif)
{
- struct shash_node *node;
-
- SHASH_FOR_EACH (node, &dp_netdevs) {
- struct dp_netdev *dp = node->data;
- struct dp_netdev_port *port;
-
- LIST_FOR_EACH (port, node, &dp->port_list) {
- netdev_recv_wait(port->netdev);
- }
- }
-}
-
-
-/* Modify the TCI field of 'packet'. If a VLAN tag is present, its TCI field
- * is replaced by 'tci'. If a VLAN tag is not present, one is added with the
- * TCI field set to 'tci'.
- */
-static void
-dp_netdev_set_dl_tci(struct ofpbuf *packet, uint16_t tci)
-{
- struct vlan_eth_header *veh;
- struct eth_header *eh;
+ struct dp_netdev *dp = get_dp_netdev(dpif);
+ struct dp_netdev_port *port;
- eh = packet->l2;
- if (packet->size >= sizeof(struct vlan_eth_header)
- && eh->eth_type == htons(ETH_TYPE_VLAN)) {
- veh = packet->l2;
- veh->veth_tci = tci;
- } else {
- /* Insert new 802.1Q header. */
- struct vlan_eth_header tmp;
- memcpy(tmp.veth_dst, eh->eth_dst, ETH_ADDR_LEN);
- memcpy(tmp.veth_src, eh->eth_src, ETH_ADDR_LEN);
- tmp.veth_type = htons(ETH_TYPE_VLAN);
- tmp.veth_tci = tci;
- tmp.veth_next_type = eh->eth_type;
-
- veh = ofpbuf_push_uninit(packet, VLAN_HEADER_LEN);
- memcpy(veh, &tmp, sizeof tmp);
- packet->l2 = (char*)packet->l2 - VLAN_HEADER_LEN;
+ LIST_FOR_EACH (port, node, &dp->port_list) {
+ netdev_recv_wait(port->netdev);
}
}
struct ip_header *nh = packet->l3;
ovs_be32 ip = nl_attr_get_be32(a);
uint16_t type = nl_attr_type(a);
- uint32_t *field;
+ ovs_be32 *field;
field = type == ODP_ACTION_ATTR_SET_NW_SRC ? &nh->ip_src : &nh->ip_dst;
- if (key->nw_proto == IP_TYPE_TCP && packet->l7) {
+ if (key->nw_proto == IPPROTO_TCP && packet->l7) {
struct tcp_header *th = packet->l4;
th->tcp_csum = recalc_csum32(th->tcp_csum, *field, ip);
- } else if (key->nw_proto == IP_TYPE_UDP && packet->l7) {
+ } else if (key->nw_proto == IPPROTO_UDP && packet->l7) {
struct udp_header *uh = packet->l4;
if (uh->udp_csum) {
uh->udp_csum = recalc_csum32(uh->udp_csum, *field, ip);
if (!uh->udp_csum) {
- uh->udp_csum = 0xffff;
+ uh->udp_csum = htons(0xffff);
}
}
}
if (is_ip(packet, key)) {
uint16_t type = nl_attr_type(a);
ovs_be16 port = nl_attr_get_be16(a);
- uint16_t *field;
+ ovs_be16 *field;
if (key->nw_proto == IPPROTO_TCP && packet->l7) {
struct tcp_header *th = packet->l4;
}
static int
-dp_netdev_output_control(struct dp_netdev *dp, const struct ofpbuf *packet,
+dp_netdev_output_userspace(struct dp_netdev *dp, const struct ofpbuf *packet,
int queue_no, const struct flow *flow, uint64_t arg)
{
struct dp_netdev_queue *q = &dp->queues[queue_no];
upcall->key_len = key_len;
upcall->userdata = arg;
- q->upcalls[++q->head & QUEUE_MASK] = upcall;
+ q->upcalls[q->head++ & QUEUE_MASK] = upcall;
return 0;
}
-/* Returns true if 'packet' is an invalid Ethernet+IPv4 ARP packet: one with
- * screwy or truncated header fields or one whose inner and outer Ethernet
- * address differ. */
-static bool
-dp_netdev_is_spoofed_arp(struct ofpbuf *packet, const struct flow *key)
-{
- struct arp_eth_header *arp;
- struct eth_header *eth;
- ptrdiff_t l3_size;
-
- if (key->dl_type != htons(ETH_TYPE_ARP)) {
- return false;
- }
-
- l3_size = (char *) ofpbuf_end(packet) - (char *) packet->l3;
- if (l3_size < sizeof(struct arp_eth_header)) {
- return true;
- }
-
- eth = packet->l2;
- arp = packet->l3;
- return (arp->ar_hrd != htons(ARP_HRD_ETHERNET)
- || arp->ar_pro != htons(ARP_PRO_IP)
- || arp->ar_hln != ETH_HEADER_LEN
- || arp->ar_pln != 4
- || !eth_addr_equals(arp->ar_sha, eth->eth_src));
-}
-
static int
dp_netdev_execute_actions(struct dp_netdev *dp,
struct ofpbuf *packet, struct flow *key,
dp_netdev_output_port(dp, packet, nl_attr_get_u32(a));
break;
- case ODP_ACTION_ATTR_CONTROLLER:
- dp_netdev_output_control(dp, packet, DPIF_UC_ACTION,
+ case ODP_ACTION_ATTR_USERSPACE:
+ dp_netdev_output_userspace(dp, packet, DPIF_UC_ACTION,
key, nl_attr_get_u64(a));
break;
case ODP_ACTION_ATTR_SET_DL_TCI:
- dp_netdev_set_dl_tci(packet, nl_attr_get_be16(a));
+ eth_set_vlan_tci(packet, nl_attr_get_be16(a));
break;
case ODP_ACTION_ATTR_STRIP_VLAN:
case ODP_ACTION_ATTR_SET_TP_DST:
dp_netdev_set_tp_port(packet, key, a);
break;
-
- case ODP_ACTION_ATTR_DROP_SPOOFED_ARP:
- if (dp_netdev_is_spoofed_arp(packet, key)) {
- return 0;
- }
}
}
return 0;
const struct dpif_class dpif_netdev_class = {
"netdev",
- dp_netdev_run,
- dp_netdev_wait,
NULL, /* enumerate */
dpif_netdev_open,
dpif_netdev_close,
dpif_netdev_destroy,
+ dpif_netdev_run,
+ dpif_netdev_wait,
dpif_netdev_get_stats,
dpif_netdev_get_drop_frags,
dpif_netdev_set_drop_frags,