X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fdpif-netdev.c;h=926464e266ff202f6f6c740b2c381b0631cc0633;hb=6ff686f2bc2afcfb0a9ad9793d834979dc9870d6;hp=53574aa03aa910b443a1a3edde20f3fc2f40d13a;hpb=b2fda3effc787f265b5ad5dfa967ac00627bd075;p=sliver-openvswitch.git diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 53574aa03..926464e26 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -91,7 +91,6 @@ struct dp_netdev { long long int n_lost; /* Number of misses not passed to client. */ /* Ports. */ - int n_ports; struct dp_netdev_port *ports[MAX_PORTS]; struct list port_list; unsigned int serial; @@ -146,7 +145,7 @@ static int do_add_port(struct dp_netdev *, const char *devname, 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 *, @@ -204,7 +203,7 @@ create_dp_netdev(const char *name, const struct dpif_class *class, } hmap_init(&dp->flow_table); list_init(&dp->port_list); - error = do_add_port(dp, name, "internal", ODPP_LOCAL); + error = do_add_port(dp, name, "internal", OVSP_LOCAL); if (error) { dp_netdev_free(dp); return error; @@ -265,10 +264,10 @@ dp_netdev_purge_queues(struct dp_netdev *dp) static void dp_netdev_free(struct dp_netdev *dp) { + struct dp_netdev_port *port, *next; + dp_netdev_flow_flush(dp); - while (dp->n_ports > 0) { - struct dp_netdev_port *port = CONTAINER_OF( - dp->port_list.next, struct dp_netdev_port, node); + LIST_FOR_EACH_SAFE (port, next, node, &dp->port_list) { do_del_port(dp, port->port_no); } dp_netdev_purge_queues(dp); @@ -298,10 +297,11 @@ dpif_netdev_destroy(struct dpif *dpif) } static int -dpif_netdev_get_stats(const struct dpif *dpif, struct odp_stats *stats) +dpif_netdev_get_stats(const struct dpif *dpif, struct ovs_dp_stats *stats) { 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; @@ -330,14 +330,13 @@ do_add_port(struct dp_netdev *dp, const char *devname, const char *type, uint16_t port_no) { struct dp_netdev_port *port; - struct netdev_options netdev_options; struct netdev *netdev; bool internal; int mtu; int error; /* XXX reject devices already in some dp_netdev. */ - if (type[0] == '\0' || !strcmp(type, "system")) { + if (type[0] == '\0' || !strcmp(type, "system") || !strcmp(type, "dummy")) { internal = false; } else if (!strcmp(type, "internal")) { internal = true; @@ -347,22 +346,27 @@ do_add_port(struct dp_netdev *dp, const char *devname, const char *type, } /* 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); @@ -374,14 +378,13 @@ do_add_port(struct dp_netdev *dp, const char *devname, const char *type, port->netdev = netdev; port->internal = internal; - netdev_get_mtu(netdev, &mtu); - if (mtu != INT_MAX && mtu > max_mtu) { + error = netdev_get_mtu(netdev, &mtu); + if (!error) { max_mtu = mtu; } list_push_back(&dp->port_list, &port->node); dp->ports[port_no] = port; - dp->n_ports++; dp->serial++; return 0; @@ -408,7 +411,7 @@ static int dpif_netdev_port_del(struct dpif *dpif, uint16_t port_no) { struct dp_netdev *dp = get_dp_netdev(dpif); - return port_no == ODPP_LOCAL ? EINVAL : do_del_port(dp, port_no); + return port_no == OVSP_LOCAL ? EINVAL : do_del_port(dp, port_no); } static bool @@ -459,7 +462,6 @@ do_del_port(struct dp_netdev *dp, uint16_t port_no) list_remove(&port->node); dp->ports[port->port_no] = NULL; - dp->n_ports--; dp->serial++; name = xstrdup(netdev_get_name(port->netdev)); @@ -652,6 +654,12 @@ dpif_netdev_flow_from_nlattrs(const struct nlattr *key, uint32_t key_len, return EINVAL; } + if (flow->in_port < OFPP_MAX + ? flow->in_port >= MAX_PORTS + : flow->in_port != OFPP_LOCAL && flow->in_port != OFPP_NONE) { + return EINVAL; + } + return 0; } @@ -701,43 +709,42 @@ dpif_netdev_validate_actions(const struct nlattr *actions, } switch (type) { - case ODP_ACTION_ATTR_OUTPUT: + case OVS_ACTION_ATTR_OUTPUT: if (nl_attr_get_u32(a) >= MAX_PORTS) { return EINVAL; } break; - case ODP_ACTION_ATTR_CONTROLLER: - case ODP_ACTION_ATTR_DROP_SPOOFED_ARP: + case OVS_ACTION_ATTR_USERSPACE: break; - case ODP_ACTION_ATTR_SET_DL_TCI: + case OVS_ACTION_ATTR_PUSH_VLAN: *mutates = true; if (nl_attr_get_be16(a) & htons(VLAN_CFI)) { return EINVAL; } break; - case ODP_ACTION_ATTR_SET_NW_TOS: + case OVS_ACTION_ATTR_SET_NW_TOS: *mutates = true; if (nl_attr_get_u8(a) & IP_ECN_MASK) { return EINVAL; } break; - case ODP_ACTION_ATTR_STRIP_VLAN: - case ODP_ACTION_ATTR_SET_DL_SRC: - case ODP_ACTION_ATTR_SET_DL_DST: - case ODP_ACTION_ATTR_SET_NW_SRC: - case ODP_ACTION_ATTR_SET_NW_DST: - case ODP_ACTION_ATTR_SET_TP_SRC: - case ODP_ACTION_ATTR_SET_TP_DST: + case OVS_ACTION_ATTR_POP_VLAN: + case OVS_ACTION_ATTR_SET_DL_SRC: + case OVS_ACTION_ATTR_SET_DL_DST: + case OVS_ACTION_ATTR_SET_NW_SRC: + case OVS_ACTION_ATTR_SET_NW_DST: + case OVS_ACTION_ATTR_SET_TP_SRC: + case OVS_ACTION_ATTR_SET_TP_DST: *mutates = true; break; - case ODP_ACTION_ATTR_SET_TUNNEL: - case ODP_ACTION_ATTR_SET_PRIORITY: - case ODP_ACTION_ATTR_POP_PRIORITY: + case OVS_ACTION_ATTR_SET_TUNNEL: + case OVS_ACTION_ATTR_SET_PRIORITY: + case OVS_ACTION_ATTR_POP_PRIORITY: default: return EOPNOTSUPP; } @@ -944,6 +951,7 @@ dpif_netdev_flow_dump_done(const struct dpif *dpif OVS_UNUSED, void *state_) 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) { @@ -975,8 +983,13 @@ dpif_netdev_execute(struct dpif *dpif, * if we don't. */ copy = *packet; } + flow_extract(©, 0, -1, &key); - error = dp_netdev_execute_actions(dp, ©, &key, actions, actions_len); + error = dpif_netdev_flow_from_nlattrs(key_attrs, key_len, &key); + if (!error) { + error = dp_netdev_execute_actions(dp, ©, &key, + actions, actions_len); + } if (mutates) { ofpbuf_uninit(©); } @@ -1085,7 +1098,7 @@ dp_netdev_port_input(struct dp_netdev *dp, struct dp_netdev_port *port, 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); } } @@ -1129,7 +1142,7 @@ dpif_netdev_wait(struct dpif *dpif) } static void -dp_netdev_strip_vlan(struct ofpbuf *packet) +dp_netdev_pop_vlan(struct ofpbuf *packet) { struct vlan_eth_header *veh = packet->l2; if (packet->size >= sizeof *veh @@ -1176,7 +1189,7 @@ dp_netdev_set_nw_addr(struct ofpbuf *packet, const struct flow *key, uint16_t type = nl_attr_type(a); ovs_be32 *field; - field = type == ODP_ACTION_ATTR_SET_NW_SRC ? &nh->ip_src : &nh->ip_dst; + field = type == OVS_ACTION_ATTR_SET_NW_SRC ? &nh->ip_src : &nh->ip_dst; if (key->nw_proto == IPPROTO_TCP && packet->l7) { struct tcp_header *th = packet->l4; th->tcp_csum = recalc_csum32(th->tcp_csum, *field, ip); @@ -1222,13 +1235,13 @@ dp_netdev_set_tp_port(struct ofpbuf *packet, const struct flow *key, if (key->nw_proto == IPPROTO_TCP && packet->l7) { struct tcp_header *th = packet->l4; - field = (type == ODP_ACTION_ATTR_SET_TP_SRC + field = (type == OVS_ACTION_ATTR_SET_TP_SRC ? &th->tcp_src : &th->tcp_dst); th->tcp_csum = recalc_csum16(th->tcp_csum, *field, port); *field = port; } else if (key->nw_proto == IPPROTO_UDP && packet->l7) { struct udp_header *uh = packet->l4; - field = (type == ODP_ACTION_ATTR_SET_TP_SRC + field = (type == OVS_ACTION_ATTR_SET_TP_SRC ? &uh->udp_src : &uh->udp_dst); uh->udp_csum = recalc_csum16(uh->udp_csum, *field, port); *field = port; @@ -1249,7 +1262,7 @@ dp_netdev_output_port(struct dp_netdev *dp, struct ofpbuf *packet, } 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]; @@ -1281,34 +1294,6 @@ 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 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, @@ -1320,49 +1305,44 @@ dp_netdev_execute_actions(struct dp_netdev *dp, NL_ATTR_FOR_EACH_UNSAFE (a, left, actions, actions_len) { switch (nl_attr_type(a)) { - case ODP_ACTION_ATTR_OUTPUT: + case OVS_ACTION_ATTR_OUTPUT: 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 OVS_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: - eth_set_vlan_tci(packet, nl_attr_get_be16(a)); + case OVS_ACTION_ATTR_PUSH_VLAN: + eth_push_vlan(packet, nl_attr_get_be16(a)); break; - case ODP_ACTION_ATTR_STRIP_VLAN: - dp_netdev_strip_vlan(packet); + case OVS_ACTION_ATTR_POP_VLAN: + dp_netdev_pop_vlan(packet); break; - case ODP_ACTION_ATTR_SET_DL_SRC: + case OVS_ACTION_ATTR_SET_DL_SRC: dp_netdev_set_dl_src(packet, nl_attr_get_unspec(a, ETH_ADDR_LEN)); break; - case ODP_ACTION_ATTR_SET_DL_DST: + case OVS_ACTION_ATTR_SET_DL_DST: dp_netdev_set_dl_dst(packet, nl_attr_get_unspec(a, ETH_ADDR_LEN)); break; - case ODP_ACTION_ATTR_SET_NW_SRC: - case ODP_ACTION_ATTR_SET_NW_DST: + case OVS_ACTION_ATTR_SET_NW_SRC: + case OVS_ACTION_ATTR_SET_NW_DST: dp_netdev_set_nw_addr(packet, key, a); break; - case ODP_ACTION_ATTR_SET_NW_TOS: + case OVS_ACTION_ATTR_SET_NW_TOS: dp_netdev_set_nw_tos(packet, key, nl_attr_get_u8(a)); break; - case ODP_ACTION_ATTR_SET_TP_SRC: - case ODP_ACTION_ATTR_SET_TP_DST: + case OVS_ACTION_ATTR_SET_TP_SRC: + case OVS_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; @@ -1399,8 +1379,6 @@ const struct dpif_class dpif_netdev_class = { dpif_netdev_execute, dpif_netdev_recv_get_mask, dpif_netdev_recv_set_mask, - NULL, /* get_sflow_probability */ - NULL, /* set_sflow_probability */ NULL, /* queue_to_priority */ dpif_netdev_recv, dpif_netdev_recv_wait,