X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=lib%2Fdpif-netdev.c;h=3975b5a8bba7bc60cbacb82921d34176afef793d;hb=0cc96e48ab2fc573c3b7b69fe5a034bb29dde578;hp=ec971b1398913973d2a9a5f9e42038673da780ac;hpb=1805876e50b89816581dac16d7283bd130b84c72;p=openvswitch diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index ec971b13..3975b5a8 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -99,10 +99,10 @@ struct dp_netdev_flow { flow_t key; /* Statistics. */ - struct timespec used; /* Last used time. */ - 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. */ + struct timespec used; /* Last used time. */ + 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. */ /* Actions. */ union odp_action *actions; @@ -1082,7 +1082,7 @@ dp_netdev_wait(void) /* Modify the TCI field of 'packet'. If a VLAN tag is not present, one - * is added with the TCI field set to 'tci'. If a VLAN tag is present, + * is added with the TCI field set to 'tci'. If a VLAN tag is present, * then 'mask' bits are cleared before 'tci' is logically OR'd into the * TCI field. * @@ -1090,19 +1090,20 @@ dp_netdev_wait(void) * bits outside of 'mask'. */ static void -dp_netdev_modify_vlan_tci(struct ofpbuf *packet, const 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); veh->veth_tci |= htons(tci); } else { /* Insert new 802.1Q header. */ - struct eth_header *eh = packet->l2; 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); @@ -1149,19 +1150,25 @@ dp_netdev_set_dl_dst(struct ofpbuf *packet, const uint8_t dl_addr[ETH_ADDR_LEN]) memcpy(eh->eth_dst, dl_addr, sizeof eh->eth_dst); } +static bool +is_ip(const struct ofpbuf *packet, const flow_t *key) +{ + return key->dl_type == htons(ETH_TYPE_IP) && packet->l4; +} + static void 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)) { + if (is_ip(packet, key)) { struct ip_header *nh = packet->l3; uint32_t *field; field = a->type == ODPAT_SET_NW_SRC ? &nh->ip_src : &nh->ip_dst; - if (key->nw_proto == IP_TYPE_TCP) { + if (key->nw_proto == IP_TYPE_TCP && packet->l7) { struct tcp_header *th = packet->l4; th->tcp_csum = recalc_csum32(th->tcp_csum, *field, a->nw_addr); - } else if (key->nw_proto == IP_TYPE_UDP) { + } else if (key->nw_proto == IP_TYPE_UDP && packet->l7) { struct udp_header *uh = packet->l4; if (uh->udp_csum) { uh->udp_csum = recalc_csum32(uh->udp_csum, *field, a->nw_addr); @@ -1179,7 +1186,7 @@ static void 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)) { + if (is_ip(packet, key)) { struct ip_header *nh = packet->l3; uint8_t *field = &nh->ip_tos; @@ -1196,14 +1203,14 @@ static void 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)) { + if (is_ip(packet, key)) { uint16_t *field; - if (key->nw_proto == IPPROTO_TCP) { + if (key->nw_proto == IPPROTO_TCP && packet->l7) { struct tcp_header *th = packet->l4; field = a->type == ODPAT_SET_TP_SRC ? &th->tcp_src : &th->tcp_dst; th->tcp_csum = recalc_csum16(th->tcp_csum, *field, a->tp_port); *field = a->tp_port; - } else if (key->nw_proto == IPPROTO_UDP) { + } else if (key->nw_proto == IPPROTO_UDP && packet->l7) { struct udp_header *uh = packet->l4; field = a->type == ODPAT_SET_TP_SRC ? &uh->udp_src : &uh->udp_dst; uh->udp_csum = recalc_csum16(uh->udp_csum, *field, a->tp_port); @@ -1218,7 +1225,7 @@ static void dp_netdev_output_port(struct dp_netdev *dp, struct ofpbuf *packet, uint16_t out_port) { - struct dp_netdev_port *p = dp->ports[out_port]; + struct dp_netdev_port *p = dp->ports[out_port]; if (p) { netdev_send(p->netdev, packet); } @@ -1228,15 +1235,15 @@ static void dp_netdev_output_group(struct dp_netdev *dp, uint16_t group, uint16_t in_port, struct ofpbuf *packet) { - struct odp_port_group *g = &dp->groups[group]; - int i; + struct odp_port_group *g = &dp->groups[group]; + int i; - for (i = 0; i < g->n_ports; i++) { + for (i = 0; i < g->n_ports; i++) { uint16_t out_port = g->ports[i]; if (out_port != in_port) { dp_netdev_output_port(dp, packet, out_port); } - } + } } static int @@ -1254,8 +1261,7 @@ dp_netdev_output_control(struct dp_netdev *dp, const struct ofpbuf *packet, } msg_size = sizeof *header + packet->size; - msg = ofpbuf_new(msg_size + DPIF_RECV_MSG_PADDING); - ofpbuf_reserve(msg, DPIF_RECV_MSG_PADDING); + msg = ofpbuf_new_with_headroom(msg_size, DPIF_RECV_MSG_PADDING); header = ofpbuf_put_uninit(msg, sizeof *header); header->type = queue_no; header->length = msg_size; @@ -1267,6 +1273,34 @@ dp_netdev_output_control(struct dp_netdev *dp, const struct ofpbuf *packet, 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, const flow_t *key, @@ -1276,59 +1310,64 @@ dp_netdev_execute_actions(struct dp_netdev *dp, for (i = 0; i < n_actions; i++) { const union odp_action *a = &actions[i]; - switch (a->type) { - case ODPAT_OUTPUT: + switch (a->type) { + case ODPAT_OUTPUT: dp_netdev_output_port(dp, packet, a->output.port); - break; + break; - case ODPAT_OUTPUT_GROUP: - dp_netdev_output_group(dp, a->output_group.group, key->in_port, + case ODPAT_OUTPUT_GROUP: + dp_netdev_output_group(dp, a->output_group.group, key->in_port, packet); - break; + break; - case ODPAT_CONTROLLER: + case ODPAT_CONTROLLER: dp_netdev_output_control(dp, packet, _ODPL_ACTION_NR, key->in_port, a->controller.arg); - break; + break; - case ODPAT_SET_VLAN_VID: - dp_netdev_modify_vlan_tci(packet, key, ntohs(a->vlan_vid.vlan_vid), + case ODPAT_SET_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); + case ODPAT_SET_VLAN_PCP: + 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); - break; + case ODPAT_STRIP_VLAN: + dp_netdev_strip_vlan(packet); + break; - case ODPAT_SET_DL_SRC: + case ODPAT_SET_DL_SRC: dp_netdev_set_dl_src(packet, a->dl_addr.dl_addr); - break; + break; - case ODPAT_SET_DL_DST: + case ODPAT_SET_DL_DST: dp_netdev_set_dl_dst(packet, a->dl_addr.dl_addr); - break; - - case ODPAT_SET_NW_SRC: - case ODPAT_SET_NW_DST: - dp_netdev_set_nw_addr(packet, key, &a->nw_addr); - break; - - case ODPAT_SET_NW_TOS: - dp_netdev_set_nw_tos(packet, key, &a->nw_tos); - break; - - case ODPAT_SET_TP_SRC: - case ODPAT_SET_TP_DST: - dp_netdev_set_tp_port(packet, key, &a->tp_port); - break; - } - } + break; + + case ODPAT_SET_NW_SRC: + case ODPAT_SET_NW_DST: + dp_netdev_set_nw_addr(packet, key, &a->nw_addr); + break; + + case ODPAT_SET_NW_TOS: + dp_netdev_set_nw_tos(packet, key, &a->nw_tos); + break; + + case ODPAT_SET_TP_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; }