#include <fcntl.h>
#include <inttypes.h>
#include <netinet/in.h>
+#include <sys/socket.h>
#include <net/if.h>
#include <stdlib.h>
#include <string.h>
#include "queue.h"
#include "timeval.h"
#include "util.h"
-
#include "vlog.h"
-#define THIS_MODULE VLM_dpif_netdev
+
+VLOG_DEFINE_THIS_MODULE(dpif_netdev)
/* Configuration parameters. */
enum { N_QUEUES = 2 }; /* Number of queues for dpif_recv(). */
flow_t key;
/* Statistics. */
- struct timeval used; /* Last used time, in milliseconds. */
+ struct timespec used; /* Last used time. */
long long int packet_count; /* Number of packets matched. */
long long int byte_count; /* Number of bytes matched. */
- uint8_t ip_tos; /* IP TOS value. */
uint16_t tcp_ctl; /* Bitwise-OR of seen tcp_ctl values. */
/* Actions. */
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 *, flow_t *,
+ struct ofpbuf *, const flow_t *,
const union odp_action *, int n);
static struct dpif_netdev *
memset(&netdev_options, 0, sizeof netdev_options);
netdev_options.name = devname;
netdev_options.ethertype = NETDEV_ETH_TYPE_ANY;
- netdev_options.may_create = true;
if (internal) {
netdev_options.type = "tap";
- } else {
- netdev_options.may_open = true;
}
error = netdev_open(&netdev_options, &netdev);
odp_flow->stats.n_packets = flow->packet_count;
odp_flow->stats.n_bytes = flow->byte_count;
odp_flow->stats.used_sec = flow->used.tv_sec;
- odp_flow->stats.used_nsec = flow->used.tv_usec * 1000;
+ odp_flow->stats.used_nsec = flow->used.tv_nsec;
odp_flow->stats.tcp_flags = TCP_FLAGS(flow->tcp_ctl);
- odp_flow->stats.ip_tos = flow->ip_tos;
+ odp_flow->stats.reserved = 0;
odp_flow->stats.error = 0;
if (odp_flow->n_actions > 0) {
unsigned int n = MIN(odp_flow->n_actions, flow->n_actions);
clear_stats(struct dp_netdev_flow *flow)
{
flow->used.tv_sec = 0;
- flow->used.tv_usec = 0;
+ flow->used.tv_nsec = 0;
flow->packet_count = 0;
flow->byte_count = 0;
- flow->ip_tos = 0;
flow->tcp_ctl = 0;
}
* if we don't. */
copy = *packet;
}
- flow_extract(©, in_port, &flow);
+ flow_extract(©, 0, in_port, &flow);
error = dp_netdev_execute_actions(dp, ©, &flow, actions, n_actions);
if (mutates) {
ofpbuf_uninit(©);
dp_netdev_flow_used(struct dp_netdev_flow *flow, const flow_t *key,
const struct ofpbuf *packet)
{
- time_timeval(&flow->used);
+ time_timespec(&flow->used);
flow->packet_count++;
flow->byte_count += packet->size;
- if (key->dl_type == htons(ETH_TYPE_IP)) {
- struct ip_header *nh = packet->l3;
- flow->ip_tos = nh->ip_tos;
-
- if (key->nw_proto == IPPROTO_TCP) {
- struct tcp_header *th = packet->l4;
- flow->tcp_ctl |= th->tcp_ctl;
- }
+ if (key->dl_type == htons(ETH_TYPE_IP) && key->nw_proto == IPPROTO_TCP) {
+ struct tcp_header *th = packet->l4;
+ flow->tcp_ctl |= th->tcp_ctl;
}
}
struct dp_netdev_flow *flow;
flow_t key;
- if (flow_extract(packet, port->port_no, &key) && dp->drop_frags) {
+ if (packet->size < ETH_HEADER_LEN) {
+ return;
+ }
+ if (flow_extract(packet, 0, port->port_no, &key) && dp->drop_frags) {
dp->n_frags++;
return;
}
* bits outside of 'mask'.
*/
static void
-dp_netdev_modify_vlan_tci(struct ofpbuf *packet, flow_t *key,
- uint16_t tci, uint16_t mask)
+dp_netdev_modify_vlan_tci(struct ofpbuf *packet, uint16_t tci, uint16_t mask)
{
struct vlan_eth_header *veh;
+ struct eth_header *eh;
- if (key->dl_vlan != htons(ODP_VLAN_NONE)) {
+ eh = packet->l2;
+ if (packet->size >= sizeof(struct vlan_eth_header)
+ && eh->eth_type == htons(ETH_TYPE_VLAN)) {
/* Clear 'mask' bits, but maintain other TCI bits. */
veh = packet->l2;
veh->veth_tci &= ~htons(mask);
memcpy(veh, &tmp, sizeof tmp);
packet->l2 = (char*)packet->l2 - VLAN_HEADER_LEN;
}
-
- key->dl_vlan = veh->veth_tci & htons(VLAN_VID_MASK);
}
static void
-dp_netdev_strip_vlan(struct ofpbuf *packet, flow_t *key)
+dp_netdev_strip_vlan(struct ofpbuf *packet)
{
struct vlan_eth_header *veh = packet->l2;
- if (veh->veth_type == htons(ETH_TYPE_VLAN)) {
+ 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);
packet->data = (char*)packet->data + VLAN_HEADER_LEN;
packet->l2 = (char*)packet->l2 + VLAN_HEADER_LEN;
memcpy(packet->data, &tmp, sizeof tmp);
-
- key->dl_vlan = htons(ODP_VLAN_NONE);
}
}
static void
-dp_netdev_set_dl_src(struct ofpbuf *packet, flow_t *key,
- const uint8_t dl_addr[ETH_ADDR_LEN])
+dp_netdev_set_dl_src(struct ofpbuf *packet, const uint8_t dl_addr[ETH_ADDR_LEN])
{
struct eth_header *eh = packet->l2;
memcpy(eh->eth_src, dl_addr, sizeof eh->eth_src);
- memcpy(key->dl_src, dl_addr, sizeof key->dl_src);
}
static void
-dp_netdev_set_dl_dst(struct ofpbuf *packet, flow_t *key,
- const uint8_t dl_addr[ETH_ADDR_LEN])
+dp_netdev_set_dl_dst(struct ofpbuf *packet, const uint8_t dl_addr[ETH_ADDR_LEN])
{
struct eth_header *eh = packet->l2;
memcpy(eh->eth_dst, dl_addr, sizeof eh->eth_dst);
- memcpy(key->dl_dst, dl_addr, sizeof key->dl_dst);
}
static void
-dp_netdev_set_nw_addr(struct ofpbuf *packet, flow_t *key,
+dp_netdev_set_nw_addr(struct ofpbuf *packet, const flow_t *key,
const struct odp_action_nw_addr *a)
{
if (key->dl_type == htons(ETH_TYPE_IP)) {
}
nh->ip_csum = recalc_csum32(nh->ip_csum, *field, a->nw_addr);
*field = a->nw_addr;
-
- if (a->type == ODPAT_SET_NW_SRC) {
- key->nw_src = a->type;
- } else {
- key->nw_dst = a->type;
- }
}
}
static void
-dp_netdev_set_nw_tos(struct ofpbuf *packet, flow_t *key,
+dp_netdev_set_nw_tos(struct ofpbuf *packet, const flow_t *key,
const struct odp_action_nw_tos *a)
{
if (key->dl_type == htons(ETH_TYPE_IP)) {
nh->ip_csum = recalc_csum16(nh->ip_csum, htons((uint16_t)*field),
htons((uint16_t)a->nw_tos));
*field = new;
- key->nw_tos = a->nw_tos;
}
}
static void
-dp_netdev_set_tp_port(struct ofpbuf *packet, flow_t *key,
+dp_netdev_set_tp_port(struct ofpbuf *packet, const flow_t *key,
const struct odp_action_tp_port *a)
{
if (key->dl_type == htons(ETH_TYPE_IP)) {
} else {
return;
}
-
- if (a->type == ODPAT_SET_TP_SRC) {
- key->tp_src = a->tp_port;
- } else {
- key->tp_dst = a->tp_port;
- }
}
}
}
msg_size = sizeof *header + packet->size;
- msg = ofpbuf_new(msg_size);
+ msg = ofpbuf_new(msg_size + DPIF_RECV_MSG_PADDING);
+ ofpbuf_reserve(msg, DPIF_RECV_MSG_PADDING);
header = ofpbuf_put_uninit(msg, sizeof *header);
header->type = queue_no;
header->length = msg_size;
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 odp_flow_key *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, flow_t *key,
+ struct ofpbuf *packet, const flow_t *key,
const union odp_action *actions, int n_actions)
{
int i;
break;
case ODPAT_SET_VLAN_VID:
- dp_netdev_modify_vlan_tci(packet, key, ntohs(a->vlan_vid.vlan_vid),
+ dp_netdev_modify_vlan_tci(packet, ntohs(a->vlan_vid.vlan_vid),
VLAN_VID_MASK);
break;
case ODPAT_SET_VLAN_PCP:
- dp_netdev_modify_vlan_tci(
- packet, key, a->vlan_pcp.vlan_pcp << VLAN_PCP_SHIFT,
- VLAN_PCP_MASK);
+ dp_netdev_modify_vlan_tci(packet,
+ a->vlan_pcp.vlan_pcp << VLAN_PCP_SHIFT,
+ VLAN_PCP_MASK);
break;
case ODPAT_STRIP_VLAN:
- dp_netdev_strip_vlan(packet, key);
+ dp_netdev_strip_vlan(packet);
break;
case ODPAT_SET_DL_SRC:
- dp_netdev_set_dl_src(packet, key, a->dl_addr.dl_addr);
+ dp_netdev_set_dl_src(packet, a->dl_addr.dl_addr);
break;
case ODPAT_SET_DL_DST:
- dp_netdev_set_dl_dst(packet, key, a->dl_addr.dl_addr);
+ dp_netdev_set_dl_dst(packet, a->dl_addr.dl_addr);
break;
case ODPAT_SET_NW_SRC:
case ODPAT_SET_TP_DST:
dp_netdev_set_tp_port(packet, key, &a->tp_port);
break;
+
+ case ODPAT_DROP_SPOOFED_ARP:
+ if (dp_netdev_is_spoofed_arp(packet, key)) {
+ return 0;
+ }
}
}
return 0;
dpif_netdev_recv_set_mask,
NULL, /* get_sflow_probability */
NULL, /* set_sflow_probability */
+ NULL, /* queue_to_priority */
dpif_netdev_recv,
dpif_netdev_recv_wait,
};