X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=ofproto%2Fofproto-dpif.c;h=986f9a7a0d4983cda196f1c53ed4a0f2f67ef38c;hb=d445cc16a5ca451bc06a195825153bab87f2e07e;hp=3bc8dd79588f76f62daafd67648e8b7ce7a43d2d;hpb=9583bc14430acc0578c1d00a78143c01d9cf7bee;p=sliver-openvswitch.git diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 3bc8dd795..986f9a7a0 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -69,6 +69,7 @@ COVERAGE_DEFINE(facet_changed_rule); COVERAGE_DEFINE(facet_revalidate); COVERAGE_DEFINE(facet_unexpected); COVERAGE_DEFINE(facet_suppress); +COVERAGE_DEFINE(subfacet_install_fail); struct flow_miss; struct facet; @@ -258,6 +259,16 @@ static void push_all_stats(void); static bool facet_is_controller_flow(struct facet *); +/* Node in 'ofport_dpif''s 'priorities' map. Used to maintain a map from + * 'priority' (the datapath's term for QoS queue) to the dscp bits which all + * traffic egressing the 'ofport' with that priority should be marked with. */ +struct priority_to_dscp { + struct hmap_node hmap_node; /* Node in 'ofport_dpif''s 'priorities' map. */ + uint32_t priority; /* Priority of this queue (see struct flow). */ + + uint8_t dscp; /* DSCP bits to mark outgoing traffic with. */ +}; + /* Linux VLAN device support (e.g. "eth0.10" for VLAN 10.) * * This is deprecated. It is only for compatibility with broken device drivers @@ -267,17 +278,17 @@ static bool facet_is_controller_flow(struct facet *); struct vlan_splinter { struct hmap_node realdev_vid_node; struct hmap_node vlandev_node; - uint16_t realdev_ofp_port; - uint16_t vlandev_ofp_port; + ofp_port_t realdev_ofp_port; + ofp_port_t vlandev_ofp_port; int vid; }; static bool vsp_adjust_flow(const struct ofproto_dpif *, struct flow *); static void vsp_remove(struct ofport_dpif *); -static void vsp_add(struct ofport_dpif *, uint16_t realdev_ofp_port, int vid); +static void vsp_add(struct ofport_dpif *, ofp_port_t realdev_ofp_port, int vid); -static uint16_t odp_port_to_ofp_port(const struct ofproto_dpif *, - uint32_t odp_port); +static ofp_port_t odp_port_to_ofp_port(const struct ofproto_dpif *, + odp_port_t odp_port); static struct ofport_dpif * ofport_dpif_cast(const struct ofport *ofport) @@ -291,6 +302,7 @@ static void port_wait(struct ofport_dpif *); static int set_bfd(struct ofport *, const struct smap *); static int set_cfm(struct ofport *, const struct cfm_settings *); static void ofport_clear_priorities(struct ofport_dpif *); +static void ofport_update_peer(struct ofport_dpif *); static void run_fast_rl(void); struct dpif_completion { @@ -298,6 +310,21 @@ struct dpif_completion { struct ofoperation *op; }; +/* Reasons that we might need to revalidate every facet, and corresponding + * coverage counters. + * + * A value of 0 means that there is no need to revalidate. + * + * It would be nice to have some cleaner way to integrate with coverage + * counters, but with only a few reasons I guess this is good enough for + * now. */ +enum revalidate_reason { + REV_RECONFIGURE = 1, /* Switch configuration changed. */ + REV_STP, /* Spanning tree protocol port status change. */ + REV_PORT_TOGGLED, /* Port enabled or disabled by CFM, LACP, ...*/ + REV_FLOW_TABLE, /* Flow table changed. */ + REV_INCONSISTENCY /* Facet self-check failed. */ +}; COVERAGE_DEFINE(rev_reconfigure); COVERAGE_DEFINE(rev_stp); COVERAGE_DEFINE(rev_port_toggled); @@ -313,12 +340,64 @@ struct drop_key { size_t key_len; }; +struct avg_subfacet_rates { + double add_rate; /* Moving average of new flows created per minute. */ + double del_rate; /* Moving average of flows deleted per minute. */ +}; + +/* All datapaths of a given type share a single dpif backer instance. */ +struct dpif_backer { + char *type; + int refcount; + struct dpif *dpif; + struct timer next_expiration; + struct hmap odp_to_ofport_map; /* ODP port to ofport mapping. */ + + struct simap tnl_backers; /* Set of dpif ports backing tunnels. */ + + /* Facet revalidation flags applying to facets which use this backer. */ + enum revalidate_reason need_revalidate; /* Revalidate every facet. */ + struct tag_set revalidate_set; /* Revalidate only matching facets. */ + + struct hmap drop_keys; /* Set of dropped odp keys. */ + bool recv_set_enable; /* Enables or disables receiving packets. */ + + struct hmap subfacets; + struct governor *governor; + + /* Subfacet statistics. + * + * These keep track of the total number of subfacets added and deleted and + * flow life span. They are useful for computing the flow rates stats + * exposed via "ovs-appctl dpif/show". The goal is to learn about + * traffic patterns in ways that we can use later to improve Open vSwitch + * performance in new situations. */ + long long int created; /* Time when it is created. */ + unsigned max_n_subfacet; /* Maximum number of flows */ + unsigned avg_n_subfacet; /* Average number of flows. */ + long long int avg_subfacet_life; /* Average life span of subfacets. */ + + /* The average number of subfacets... */ + struct avg_subfacet_rates hourly; /* ...over the last hour. */ + struct avg_subfacet_rates daily; /* ...over the last day. */ + struct avg_subfacet_rates lifetime; /* ...over the switch lifetime. */ + long long int last_minute; /* Last time 'hourly' was updated. */ + + /* Number of subfacets added or deleted since 'last_minute'. */ + unsigned subfacet_add_count; + unsigned subfacet_del_count; + + /* Number of subfacets added or deleted from 'created' to 'last_minute.' */ + unsigned long long int total_subfacet_add_count; + unsigned long long int total_subfacet_del_count; +}; + /* All existing ofproto_backer instances, indexed by ofproto->up.type. */ static struct shash all_dpif_backers = SHASH_INITIALIZER(&all_dpif_backers); static void drop_key_clear(struct dpif_backer *); static struct ofport_dpif * -odp_port_to_ofport(const struct dpif_backer *, uint32_t odp_port); +odp_port_to_ofport(const struct dpif_backer *, odp_port_t odp_port); static void update_moving_averages(struct dpif_backer *backer); /* Defer flow mod completion until "ovs-appctl ofproto/unclog"? (Useful only @@ -506,17 +585,18 @@ type_run(const char *type) } else { node = simap_find(&backer->tnl_backers, dp_port); if (!node) { - uint32_t odp_port = UINT32_MAX; + odp_port_t odp_port = ODPP_NONE; if (!dpif_port_add(backer->dpif, iter->up.netdev, &odp_port)) { - simap_put(&backer->tnl_backers, dp_port, odp_port); + simap_put(&backer->tnl_backers, dp_port, + odp_to_u32(odp_port)); node = simap_find(&backer->tnl_backers, dp_port); } } } - iter->odp_port = node ? node->data : OVSP_NONE; + iter->odp_port = node ? u32_to_odp(node->data) : ODPP_NONE; if (tnl_port_reconfigure(&iter->up, iter->odp_port, &iter->tnl_port)) { backer->need_revalidate = REV_RECONFIGURE; @@ -525,7 +605,7 @@ type_run(const char *type) } SIMAP_FOR_EACH (node, &tmp_backers) { - dpif_port_del(backer->dpif, node->data); + dpif_port_del(backer->dpif, u32_to_odp(node->data)); } simap_destroy(&tmp_backers); @@ -799,7 +879,7 @@ close_dpif_backer(struct dpif_backer *backer) /* Datapath port slated for removal from datapath. */ struct odp_garbage { struct list list_node; - uint32_t odp_port; + odp_port_t odp_port; }; static int @@ -925,7 +1005,7 @@ construct(struct ofproto *ofproto_) { struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); struct shash_node *node, *next; - int max_ports; + odp_port_t max_ports; int error; int i; @@ -935,7 +1015,8 @@ construct(struct ofproto *ofproto_) } max_ports = dpif_get_max_ports(ofproto->backer->dpif); - ofproto_init_max_ports(ofproto_, MIN(max_ports, OFPP_MAX)); + ofproto_init_max_ports(ofproto_, u16_to_ofp(MIN(odp_to_u32(max_ports), + ofp_to_u16(OFPP_MAX)))); ofproto->netflow = NULL; ofproto->sflow = NULL; @@ -1096,6 +1177,7 @@ destruct(struct ofproto *ofproto_) struct oftable *table; int i; + ofproto->backer->need_revalidate = REV_RECONFIGURE; hmap_remove(&all_ofproto_dpifs, &ofproto->all_ofproto_dpifs_node); complete_operations(ofproto); @@ -1378,6 +1460,7 @@ port_construct(struct ofport *port_) port->stp_port = NULL; port->stp_state = STP_DISABLED; port->tnl_port = NULL; + port->peer = NULL; hmap_init(&port->priorities); port->realdev_ofp_port = 0; port->vlandev_vid = 0; @@ -1389,7 +1472,8 @@ port_construct(struct ofport *port_) * because the patch port represents an interface that sFlow considers * to be "internal" to the switch as a whole, and therefore not an * candidate for counter polling. */ - port->odp_port = OVSP_NONE; + port->odp_port = ODPP_NONE; + ofport_update_peer(port); return 0; } @@ -1416,7 +1500,7 @@ port_construct(struct ofport *port_) } hmap_insert(&ofproto->backer->odp_to_ofport_map, &port->odp_port_node, - hash_int(port->odp_port, 0)); + hash_int(odp_to_u32(port->odp_port), 0)); } dpif_port_destroy(&dpif_port); @@ -1449,7 +1533,12 @@ port_destruct(struct ofport *port_) ofproto->backer->need_revalidate = REV_RECONFIGURE; } - if (port->odp_port != OVSP_NONE && !port->tnl_port) { + if (port->peer) { + port->peer->peer = NULL; + port->peer = NULL; + } + + if (port->odp_port != ODPP_NONE && !port->tnl_port) { hmap_remove(&ofproto->backer->odp_to_ofport_map, &port->odp_port_node); } @@ -1480,6 +1569,13 @@ port_modified(struct ofport *port_) if (port->cfm) { cfm_set_netdev(port->cfm, port->up.netdev); } + + if (port->tnl_port && tnl_port_reconfigure(&port->up, port->odp_port, + &port->tnl_port)) { + ofproto_dpif_cast(port->up.ofproto)->backer->need_revalidate = true; + } + + ofport_update_peer(port); } static void @@ -1850,14 +1946,16 @@ stp_wait(struct ofproto_dpif *ofproto) } } -/* Returns true if STP should process 'flow'. */ -static bool -stp_should_process_flow(const struct flow *flow) +/* Returns true if STP should process 'flow'. Sets fields in 'wc' that + * were used to make the determination.*/ +bool +stp_should_process_flow(const struct flow *flow, struct flow_wildcards *wc) { + memset(&wc->masks.dl_dst, 0xff, sizeof wc->masks.dl_dst); return eth_addr_equals(flow->dl_dst, eth_addr_stp); } -static void +void stp_process_packet(const struct ofport_dpif *ofport, const struct ofpbuf *packet) { @@ -1881,7 +1979,14 @@ stp_process_packet(const struct ofport_dpif *ofport, } } -struct priority_to_dscp * +int +ofproto_dpif_queue_to_priority(const struct ofproto_dpif *ofproto, + uint32_t queue_id, uint32_t *priority) +{ + return dpif_queue_to_priority(ofproto->backer->dpif, queue_id, priority); +} + +static struct priority_to_dscp * get_priority(const struct ofport_dpif *ofport, uint32_t priority) { struct priority_to_dscp *pdscp; @@ -1896,6 +2001,15 @@ get_priority(const struct ofport_dpif *ofport, uint32_t priority) return NULL; } +bool +ofproto_dpif_dscp_from_priority(const struct ofport_dpif *ofport, + uint32_t priority, uint8_t *dscp) +{ + struct priority_to_dscp *pdscp = get_priority(ofport, priority); + *dscp = pdscp ? pdscp->dscp : 0; + return pdscp != NULL; +} + static void ofport_clear_priorities(struct ofport_dpif *ofport) { @@ -2067,7 +2181,7 @@ bundle_del_port(struct ofport_dpif *port) } static bool -bundle_add_port(struct ofbundle *bundle, uint16_t ofp_port, +bundle_add_port(struct ofbundle *bundle, ofp_port_t ofp_port, struct lacp_slave_settings *lacp) { struct ofport_dpif *port; @@ -2710,14 +2824,14 @@ set_mac_table_config(struct ofproto *ofproto_, unsigned int idle_time, /* Ports. */ struct ofport_dpif * -get_ofp_port(const struct ofproto_dpif *ofproto, uint16_t ofp_port) +get_ofp_port(const struct ofproto_dpif *ofproto, ofp_port_t ofp_port) { struct ofport *ofport = ofproto_get_port(&ofproto->up, ofp_port); return ofport ? ofport_dpif_cast(ofport) : NULL; } struct ofport_dpif * -get_odp_port(const struct ofproto_dpif *ofproto, uint32_t odp_port) +get_odp_port(const struct ofproto_dpif *ofproto, odp_port_t odp_port) { struct ofport_dpif *port = odp_port_to_ofport(ofproto->backer, odp_port); return port && &ofproto->up == port->up.ofproto ? port : NULL; @@ -2733,26 +2847,54 @@ ofproto_port_from_dpif_port(struct ofproto_dpif *ofproto, ofproto_port->ofp_port = odp_port_to_ofp_port(ofproto, dpif_port->port_no); } -struct ofport_dpif * -ofport_get_peer(const struct ofport_dpif *ofport_dpif) +static void +ofport_update_peer(struct ofport_dpif *ofport) { const struct ofproto_dpif *ofproto; - const char *peer; + struct dpif_backer *backer; + const char *peer_name; - peer = netdev_vport_patch_peer(ofport_dpif->up.netdev); - if (!peer) { - return NULL; + if (!netdev_vport_is_patch(ofport->up.netdev)) { + return; + } + + backer = ofproto_dpif_cast(ofport->up.ofproto)->backer; + backer->need_revalidate = true; + + if (ofport->peer) { + ofport->peer->peer = NULL; + ofport->peer = NULL; + } + + peer_name = netdev_vport_patch_peer(ofport->up.netdev); + if (!peer_name) { + return; } HMAP_FOR_EACH (ofproto, all_ofproto_dpifs_node, &all_ofproto_dpifs) { - struct ofport *ofport; + struct ofport *peer_ofport; + struct ofport_dpif *peer; + const char *peer_peer; + + if (ofproto->backer != backer) { + continue; + } + + peer_ofport = shash_find_data(&ofproto->up.port_by_name, peer_name); + if (!peer_ofport) { + continue; + } - ofport = shash_find_data(&ofproto->up.port_by_name, peer); - if (ofport && ofport->ofproto->ofproto_class == &ofproto_dpif_class) { - return ofport_dpif_cast(ofport); + peer = ofport_dpif_cast(peer_ofport); + peer_peer = netdev_vport_patch_peer(peer->up.netdev); + if (peer_peer && !strcmp(netdev_get_name(ofport->up.netdev), + peer_peer)) { + ofport->peer = peer; + ofport->peer->peer = ofport; } + + return; } - return NULL; } static void @@ -2788,12 +2930,6 @@ port_run(struct ofport_dpif *ofport) port_run_fast(ofport); - if (ofport->tnl_port - && tnl_port_reconfigure(&ofport->up, ofport->odp_port, - &ofport->tnl_port)) { - ofproto_dpif_cast(ofport->up.ofproto)->backer->need_revalidate = true; - } - if (ofport->cfm) { int cfm_opup = cfm_get_opup(ofport->cfm); @@ -2892,7 +3028,7 @@ port_add(struct ofproto *ofproto_, struct netdev *netdev) dp_port_name = netdev_vport_get_dpif_port(netdev, namebuf, sizeof namebuf); if (!dpif_port_exists(ofproto->backer->dpif, dp_port_name)) { - uint32_t port_no = UINT32_MAX; + odp_port_t port_no = ODPP_NONE; int error; error = dpif_port_add(ofproto->backer->dpif, netdev, &port_no); @@ -2900,7 +3036,8 @@ port_add(struct ofproto *ofproto_, struct netdev *netdev) return error; } if (netdev_get_tunnel_config(netdev)) { - simap_put(&ofproto->backer->tnl_backers, dp_port_name, port_no); + simap_put(&ofproto->backer->tnl_backers, + dp_port_name, odp_to_u32(port_no)); } } @@ -2913,7 +3050,7 @@ port_add(struct ofproto *ofproto_, struct netdev *netdev) } static int -port_del(struct ofproto *ofproto_, uint16_t ofp_port) +port_del(struct ofproto *ofproto_, ofp_port_t ofp_port) { struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); struct ofport_dpif *ofport = get_ofp_port(ofproto, ofp_port); @@ -3109,6 +3246,13 @@ struct flow_miss_op { uint64_t slow_stub[128 / 8]; /* Buffer for compose_slow_path() */ struct xlate_out xout; bool xout_garbage; /* 'xout' needs to be uninitialized? */ + + struct ofpbuf mask; /* Flow mask for "put" ops. */ + struct odputil_keybuf maskbuf; + + /* If this is a "put" op, then a pointer to the subfacet that should + * be marked as uninstalled if the operation fails. */ + struct subfacet *subfacet; }; /* Sends an OFPT_PACKET_IN message for 'packet' of type OFPR_NO_MATCH to each @@ -3135,38 +3279,6 @@ send_packet_in_miss(struct ofproto_dpif *ofproto, const struct ofpbuf *packet, connmgr_send_packet_in(ofproto->up.connmgr, &pin); } -enum slow_path_reason -process_special(struct ofproto_dpif *ofproto, const struct flow *flow, - const struct ofport_dpif *ofport, const struct ofpbuf *packet) -{ - if (!ofport) { - return 0; - } else if (ofport->cfm && cfm_should_process_flow(ofport->cfm, flow)) { - if (packet) { - cfm_process_heartbeat(ofport->cfm, packet); - } - return SLOW_CFM; - } else if (ofport->bfd && bfd_should_process_flow(flow)) { - if (packet) { - bfd_process_packet(ofport->bfd, flow, packet); - } - return SLOW_BFD; - } else if (ofport->bundle && ofport->bundle->lacp - && flow->dl_type == htons(ETH_TYPE_LACP)) { - if (packet) { - lacp_process_packet(ofport->bundle->lacp, ofport, packet); - } - return SLOW_LACP; - } else if (ofproto->stp && stp_should_process_flow(flow)) { - if (packet) { - stp_process_packet(ofport, packet); - } - return SLOW_STP; - } else { - return 0; - } -} - static struct flow_miss * flow_miss_find(struct hmap *todo, const struct ofproto_dpif *ofproto, const struct flow *flow, uint32_t hash) @@ -3191,8 +3303,8 @@ static void init_flow_miss_execute_op(struct flow_miss *miss, struct ofpbuf *packet, struct flow_miss_op *op) { - if (miss->flow.in_port - != vsp_realdev_to_vlandev(miss->ofproto, miss->flow.in_port, + if (miss->flow.in_port.ofp_port + != vsp_realdev_to_vlandev(miss->ofproto, miss->flow.in_port.ofp_port, miss->flow.vlan_tci)) { /* This packet was received on a VLAN splinter port. We * added a VLAN to the packet to make the packet resemble @@ -3203,11 +3315,13 @@ init_flow_miss_execute_op(struct flow_miss *miss, struct ofpbuf *packet, eth_pop_vlan(packet); } + op->subfacet = NULL; op->xout_garbage = false; op->dpif_op.type = DPIF_OP_EXECUTE; op->dpif_op.u.execute.key = miss->key; op->dpif_op.u.execute.key_len = miss->key_len; op->dpif_op.u.execute.packet = packet; + ofpbuf_use_stack(&op->mask, &op->maskbuf, sizeof op->maskbuf); } /* Helper for handle_flow_miss_without_facet() and @@ -3355,11 +3469,19 @@ handle_flow_miss_with_facet(struct flow_miss *miss, struct facet *facet, subfacet->path = want_path; + ofpbuf_use_stack(&op->mask, &op->maskbuf, sizeof op->maskbuf); + odp_flow_key_from_mask(&op->mask, &facet->xout.wc.masks, + &miss->flow, UINT32_MAX); + op->xout_garbage = false; op->dpif_op.type = DPIF_OP_FLOW_PUT; + op->subfacet = subfacet; put->flags = DPIF_FP_CREATE | DPIF_FP_MODIFY; put->key = miss->key; put->key_len = miss->key_len; + put->mask = op->mask.data; + put->mask_len = op->mask.size; + if (want_path == SF_FAST_PATH) { put->actions = facet->xout.odp_actions.data; put->actions_len = facet->xout.odp_actions.size; @@ -3497,7 +3619,7 @@ static int ofproto_receive(const struct dpif_backer *backer, struct ofpbuf *packet, const struct nlattr *key, size_t key_len, struct flow *flow, enum odp_key_fitness *fitnessp, - struct ofproto_dpif **ofproto, uint32_t *odp_in_port) + struct ofproto_dpif **ofproto, odp_port_t *odp_in_port) { const struct ofport_dpif *port; enum odp_key_fitness fitness; @@ -3510,13 +3632,13 @@ ofproto_receive(const struct dpif_backer *backer, struct ofpbuf *packet, } if (odp_in_port) { - *odp_in_port = flow->in_port; + *odp_in_port = flow->in_port.odp_port; } port = (tnl_port_should_receive(flow) ? ofport_dpif_cast(tnl_port_receive(flow)) - : odp_port_to_ofport(backer, flow->in_port)); - flow->in_port = port ? port->up.ofp_port : OFPP_NONE; + : odp_port_to_ofport(backer, flow->in_port.odp_port)); + flow->in_port.ofp_port = port ? port->up.ofp_port : OFPP_NONE; if (!port) { goto exit; } @@ -3591,7 +3713,7 @@ handle_miss_upcalls(struct dpif_backer *backer, struct dpif_upcall *upcalls, struct flow_miss *miss = &misses[n_misses]; struct flow_miss *existing_miss; struct ofproto_dpif *ofproto; - uint32_t odp_in_port; + odp_port_t odp_in_port; struct flow flow; uint32_t hash; int error; @@ -3620,7 +3742,8 @@ handle_miss_upcalls(struct dpif_backer *backer, struct dpif_upcall *upcalls, hmap_insert(&backer->drop_keys, &drop_key->hmap_node, hash_bytes(drop_key->key, drop_key->key_len, 0)); dpif_flow_put(backer->dpif, DPIF_FP_CREATE | DPIF_FP_MODIFY, - drop_key->key, drop_key->key_len, NULL, 0, NULL); + drop_key->key, drop_key->key_len, + NULL, 0, NULL, 0, NULL); } continue; } @@ -3630,7 +3753,7 @@ handle_miss_upcalls(struct dpif_backer *backer, struct dpif_upcall *upcalls, ofproto->n_missed++; flow_extract(upcall->packet, flow.skb_priority, flow.skb_mark, - &flow.tunnel, flow.in_port, &miss->flow); + &flow.tunnel, &flow.in_port, &miss->flow); /* Add other packets to a to-do list. */ hash = flow_hash(&miss->flow, 0); @@ -3664,8 +3787,18 @@ handle_miss_upcalls(struct dpif_backer *backer, struct dpif_upcall *upcalls, } dpif_operate(backer->dpif, dpif_ops, n_ops); - /* Free memory. */ for (i = 0; i < n_ops; i++) { + if (dpif_ops[i]->error != 0 + && flow_miss_ops[i].dpif_op.type == DPIF_OP_FLOW_PUT + && flow_miss_ops[i].subfacet) { + struct subfacet *subfacet = flow_miss_ops[i].subfacet; + + COVERAGE_INC(subfacet_install_fail); + + subfacet->path = SF_NOT_INSTALLED; + } + + /* Free memory. */ if (flow_miss_ops[i].xout_garbage) { xlate_out_uninit(&flow_miss_ops[i].xout); } @@ -3734,7 +3867,7 @@ handle_sflow_upcall(struct dpif_backer *backer, struct ofproto_dpif *ofproto; union user_action_cookie cookie; struct flow flow; - uint32_t odp_in_port; + odp_port_t odp_in_port; if (ofproto_receive(backer, upcall->packet, upcall->key, upcall->key_len, &flow, NULL, &ofproto, &odp_in_port) @@ -4012,11 +4145,12 @@ update_stats(struct dpif_backer *backer) { const struct dpif_flow_stats *stats; struct dpif_flow_dump dump; - const struct nlattr *key; - size_t key_len; + const struct nlattr *key, *mask; + size_t key_len, mask_len; dpif_flow_dump_start(&dump, backer->dpif); - while (dpif_flow_dump_next(&dump, &key, &key_len, NULL, NULL, &stats)) { + while (dpif_flow_dump_next(&dump, &key, &key_len, + &mask, &mask_len, NULL, NULL, &stats)) { struct subfacet *subfacet; uint32_t key_hash; @@ -4278,7 +4412,7 @@ execute_odp_actions(struct ofproto_dpif *ofproto, const struct flow *flow, ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); odp_flow_key_from_flow(&key, flow, - ofp_port_to_odp_port(ofproto, flow->in_port)); + ofp_port_to_odp_port(ofproto, flow->in_port.ofp_port)); error = dpif_execute(ofproto->backer->dpif, key.data, key.size, odp_actions, actions_len, packet); @@ -4376,7 +4510,7 @@ facet_account(struct facet *facet) switch (nl_attr_type(a)) { case OVS_ACTION_ATTR_OUTPUT: - port = get_odp_port(ofproto, nl_attr_get_u32(a)); + port = get_odp_port(ofproto, nl_attr_get_odp_port(a)); if (port && port->bundle && port->bundle->bond) { bond_account(port->bundle->bond, &facet->flow, vlan_tci_to_vid(vlan_tci), n_bytes); @@ -4699,7 +4833,7 @@ facet_push_stats(struct facet *facet, bool may_learn) facet->prev_byte_count = facet->byte_count; facet->prev_used = facet->used; - in_port = get_ofp_port(ofproto, facet->flow.in_port); + in_port = get_ofp_port(ofproto, facet->flow.in_port.ofp_port); if (in_port && in_port->tnl_port) { netdev_vport_inc_rx(in_port->up.netdev, &stats); } @@ -4905,6 +5039,8 @@ subfacet_install(struct subfacet *subfacet, const struct ofpbuf *odp_actions, enum subfacet_path path = facet->xout.slow ? SF_SLOW_PATH : SF_FAST_PATH; const struct nlattr *actions = odp_actions->data; size_t actions_len = odp_actions->size; + struct odputil_keybuf maskbuf; + struct ofpbuf mask; uint64_t slow_path_stub[128 / 8]; enum dpif_flow_put_flags flags; @@ -4921,14 +5057,21 @@ subfacet_install(struct subfacet *subfacet, const struct ofpbuf *odp_actions, &actions, &actions_len); } + ofpbuf_use_stack(&mask, &maskbuf, sizeof maskbuf); + odp_flow_key_from_mask(&mask, &facet->xout.wc.masks, + &facet->flow, UINT32_MAX); + ret = dpif_flow_put(subfacet->backer->dpif, flags, subfacet->key, - subfacet->key_len, actions, actions_len, stats); + subfacet->key_len, mask.data, mask.size, + actions, actions_len, stats); if (stats) { subfacet_reset_dp_stats(subfacet, stats); } - if (!ret) { + if (ret) { + COVERAGE_INC(subfacet_install_fail); + } else { subfacet->path = path; } return ret; @@ -5029,6 +5172,10 @@ rule_dpif_lookup_in_table(struct ofproto_dpif *ofproto, return NULL; } + if (wc) { + wc->masks.nw_frag |= FLOW_NW_FRAG_MASK; + } + cls = &ofproto->up.tables[table_id].cls; frag = (flow->nw_frag & FLOW_NW_FRAG_ANY) != 0; if (frag && ofproto->up.frag_handling == OFPC_FRAG_NORMAL) { @@ -5053,9 +5200,10 @@ rule_dpif_miss_rule(struct ofproto_dpif *ofproto, const struct flow *flow) { struct ofport_dpif *port; - port = get_ofp_port(ofproto, flow->in_port); + port = get_ofp_port(ofproto, flow->in_port.ofp_port); if (!port) { - VLOG_WARN_RL(&rl, "packet-in on unknown port %"PRIu16, flow->in_port); + VLOG_WARN_RL(&rl, "packet-in on unknown OpenFlow port %"PRIu16, + flow->in_port.ofp_port); return ofproto->miss_rule; } @@ -5227,13 +5375,15 @@ send_packet(const struct ofport_dpif *ofport, struct ofpbuf *packet) struct xlate_out xout; struct xlate_in xin; struct flow flow; + union flow_in_port in_port_; int error; ofpbuf_use_stub(&odp_actions, odp_actions_stub, sizeof odp_actions_stub); ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); /* Use OFPP_NONE as the in_port to avoid special packet processing. */ - flow_extract(packet, 0, 0, NULL, OFPP_NONE, &flow); + in_port_.ofp_port = OFPP_NONE; + flow_extract(packet, 0, 0, NULL, &in_port_, &flow); odp_flow_key_from_flow(&key, &flow, ofp_port_to_odp_port(ofproto, OFPP_LOCAL)); dpif_flow_stats_extract(&flow, packet, time_msec(), &stats); @@ -5290,7 +5440,8 @@ compose_slow_path(const struct ofproto_dpif *ofproto, const struct flow *flow, ofpbuf_use_stack(&buf, stub, stub_size); if (slow & (SLOW_CFM | SLOW_BFD | SLOW_LACP | SLOW_STP)) { - uint32_t pid = dpif_port_get_pid(ofproto->backer->dpif, UINT32_MAX); + uint32_t pid = dpif_port_get_pid(ofproto->backer->dpif, + ODPP_NONE); odp_put_userspace_action(pid, &cookie, sizeof cookie.slow_path, &buf); } else { put_userspace_action(ofproto, &buf, flow, &cookie, @@ -5310,7 +5461,8 @@ put_userspace_action(const struct ofproto_dpif *ofproto, uint32_t pid; pid = dpif_port_get_pid(ofproto->backer->dpif, - ofp_port_to_odp_port(ofproto, flow->in_port)); + ofp_port_to_odp_port(ofproto, + flow->in_port.ofp_port)); return odp_put_userspace_action(pid, cookie, cookie_size, odp_actions); } @@ -5486,7 +5638,8 @@ packet_out(struct ofproto *ofproto_, struct ofpbuf *packet, ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); odp_flow_key_from_flow(&key, flow, - ofp_port_to_odp_port(ofproto, flow->in_port)); + ofp_port_to_odp_port(ofproto, + flow->in_port.ofp_port)); dpif_flow_stats_extract(flow, packet, time_msec(), &stats); @@ -5514,13 +5667,16 @@ set_netflow(struct ofproto *ofproto_, if (netflow_options) { if (!ofproto->netflow) { ofproto->netflow = netflow_create(); + ofproto->backer->need_revalidate = REV_RECONFIGURE; } return netflow_set_options(ofproto->netflow, netflow_options); - } else { + } else if (ofproto->netflow) { + ofproto->backer->need_revalidate = REV_RECONFIGURE; netflow_destroy(ofproto->netflow); ofproto->netflow = NULL; - return 0; } + + return 0; } static void @@ -5640,8 +5796,7 @@ struct trace_ctx { }; static void -trace_format_rule(struct ds *result, uint8_t table_id, int level, - const struct rule_dpif *rule) +trace_format_rule(struct ds *result, int level, const struct rule_dpif *rule) { ds_put_char_multiple(result, '\t', level); if (!rule) { @@ -5650,7 +5805,7 @@ trace_format_rule(struct ds *result, uint8_t table_id, int level, } ds_put_format(result, "Rule: table=%"PRIu8" cookie=%#"PRIx64" ", - table_id, ntohll(rule->up.flow_cookie)); + rule ? rule->up.table_id : 0, ntohll(rule->up.flow_cookie)); cls_rule_format(&rule->up.cr, result); ds_put_char(result, '\n'); @@ -5702,25 +5857,25 @@ trace_format_odp(struct ds *result, int level, const char *title, } static void -trace_resubmit(struct xlate_ctx *ctx, struct rule_dpif *rule) +trace_resubmit(struct xlate_in *xin, struct rule_dpif *rule, int recurse) { - struct trace_ctx *trace = CONTAINER_OF(ctx->xin, struct trace_ctx, xin); + struct trace_ctx *trace = CONTAINER_OF(xin, struct trace_ctx, xin); struct ds *result = trace->result; ds_put_char(result, '\n'); - trace_format_flow(result, ctx->recurse + 1, "Resubmitted flow", trace); - trace_format_regs(result, ctx->recurse + 1, "Resubmitted regs", trace); - trace_format_odp(result, ctx->recurse + 1, "Resubmitted odp", trace); - trace_format_rule(result, ctx->table_id, ctx->recurse + 1, rule); + trace_format_flow(result, recurse + 1, "Resubmitted flow", trace); + trace_format_regs(result, recurse + 1, "Resubmitted regs", trace); + trace_format_odp(result, recurse + 1, "Resubmitted odp", trace); + trace_format_rule(result, recurse + 1, rule); } static void -trace_report(struct xlate_ctx *ctx, const char *s) +trace_report(struct xlate_in *xin, const char *s, int recurse) { - struct trace_ctx *trace = CONTAINER_OF(ctx->xin, struct trace_ctx, xin); + struct trace_ctx *trace = CONTAINER_OF(xin, struct trace_ctx, xin); struct ds *result = trace->result; - ds_put_char_multiple(result, '\t', ctx->recurse); + ds_put_char_multiple(result, '\t', recurse); ds_put_cstr(result, s); ds_put_char(result, '\n'); } @@ -5761,7 +5916,7 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[], * bridge is specified. If function odp_flow_key_from_string() * returns 0, the flow is a odp_flow. If function * parse_ofp_exact_flow() returns 0, the flow is a br_flow. */ - if (!odp_flow_key_from_string(argv[argc - 1], NULL, &odp_key)) { + if (!odp_flow_from_string(argv[argc - 1], NULL, &odp_key, NULL)) { /* If the odp_flow is the second argument, * the datapath name is the first argument. */ if (argc == 3) { @@ -5819,6 +5974,9 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[], if (!packet->size) { flow_compose(packet, &flow); } else { + union flow_in_port in_port_; + + in_port_ = flow.in_port; ds_put_cstr(&result, "Packet: "); s = ofp_packet_to_string(packet->data, packet->size); ds_put_cstr(&result, s); @@ -5827,7 +5985,7 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[], /* Use the metadata from the flow and the packet argument * to reconstruct the flow. */ flow_extract(packet, flow.skb_priority, flow.skb_mark, NULL, - flow.in_port, &flow); + &in_port_, &flow); } } @@ -5852,7 +6010,7 @@ ofproto_trace(struct ofproto_dpif *ofproto, const struct flow *flow, rule = rule_dpif_lookup(ofproto, flow, NULL); - trace_format_rule(ds, 0, 0, rule); + trace_format_rule(ds, 0, rule); if (rule == ofproto->miss_rule) { ds_put_cstr(ds, "\nNo match, flow generates \"packet in\"s.\n"); } else if (rule == ofproto->no_packet_in_rule) { @@ -6092,13 +6250,13 @@ dpif_show_backer(const struct dpif_backer *backer, struct ds *ds) const struct shash_node *node = ports[j]; struct ofport *ofport = node->data; struct smap config; - uint32_t odp_port; + odp_port_t odp_port; ds_put_format(ds, "\t\t%s %u/", netdev_get_name(ofport->netdev), ofport->ofp_port); odp_port = ofp_port_to_odp_port(ofproto, ofport->ofp_port); - if (odp_port != OVSP_NONE) { + if (odp_port != ODPP_NONE) { ds_put_format(ds, "%"PRIu32":", odp_port); } else { ds_put_cstr(ds, "none:"); @@ -6325,7 +6483,7 @@ ofproto_dpif_unixctl_init(void) * widespread use, we will delete these interfaces. */ static int -set_realdev(struct ofport *ofport_, uint16_t realdev_ofp_port, int vid) +set_realdev(struct ofport *ofport_, ofp_port_t realdev_ofp_port, int vid) { struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofport_->ofproto); struct ofport_dpif *ofport = ofport_dpif_cast(ofport_); @@ -6357,9 +6515,9 @@ set_realdev(struct ofport *ofport_, uint16_t realdev_ofp_port, int vid) } static uint32_t -hash_realdev_vid(uint16_t realdev_ofp_port, int vid) +hash_realdev_vid(ofp_port_t realdev_ofp_port, int vid) { - return hash_2words(realdev_ofp_port, vid); + return hash_2words(ofp_to_u16(realdev_ofp_port), vid); } /* Returns the OFP port number of the Linux VLAN device that corresponds to @@ -6369,9 +6527,9 @@ hash_realdev_vid(uint16_t realdev_ofp_port, int vid) * * Unless VLAN splinters are enabled for port 'realdev_ofp_port', this * function just returns its 'realdev_ofp_port' argument. */ -uint16_t +ofp_port_t vsp_realdev_to_vlandev(const struct ofproto_dpif *ofproto, - uint16_t realdev_ofp_port, ovs_be16 vlan_tci) + ofp_port_t realdev_ofp_port, ovs_be16 vlan_tci) { if (!hmap_is_empty(&ofproto->realdev_vid_map)) { int vid = vlan_tci_to_vid(vlan_tci); @@ -6390,11 +6548,12 @@ vsp_realdev_to_vlandev(const struct ofproto_dpif *ofproto, } static struct vlan_splinter * -vlandev_find(const struct ofproto_dpif *ofproto, uint16_t vlandev_ofp_port) +vlandev_find(const struct ofproto_dpif *ofproto, ofp_port_t vlandev_ofp_port) { struct vlan_splinter *vsp; - HMAP_FOR_EACH_WITH_HASH (vsp, vlandev_node, hash_int(vlandev_ofp_port, 0), + HMAP_FOR_EACH_WITH_HASH (vsp, vlandev_node, + hash_int(ofp_to_u16(vlandev_ofp_port), 0), &ofproto->vlandev_map) { if (vsp->vlandev_ofp_port == vlandev_ofp_port) { return vsp; @@ -6413,9 +6572,9 @@ vlandev_find(const struct ofproto_dpif *ofproto, uint16_t vlandev_ofp_port) * Returns 0 and does not modify '*vid' if 'vlandev_ofp_port' is not a Linux * VLAN device. Unless VLAN splinters are enabled, this is what this function * always does.*/ -static uint16_t +static ofp_port_t vsp_vlandev_to_realdev(const struct ofproto_dpif *ofproto, - uint16_t vlandev_ofp_port, int *vid) + ofp_port_t vlandev_ofp_port, int *vid) { if (!hmap_is_empty(&ofproto->vlandev_map)) { const struct vlan_splinter *vsp; @@ -6440,17 +6599,17 @@ vsp_vlandev_to_realdev(const struct ofproto_dpif *ofproto, static bool vsp_adjust_flow(const struct ofproto_dpif *ofproto, struct flow *flow) { - uint16_t realdev; + ofp_port_t realdev; int vid; - realdev = vsp_vlandev_to_realdev(ofproto, flow->in_port, &vid); + realdev = vsp_vlandev_to_realdev(ofproto, flow->in_port.ofp_port, &vid); if (!realdev) { return false; } /* Cause the flow to be processed as if it came in on the real device with * the VLAN device's VLAN ID. */ - flow->in_port = realdev; + flow->in_port.ofp_port = realdev; flow->vlan_tci = htons((vid & VLAN_VID_MASK) | VLAN_CFI); return true; } @@ -6474,7 +6633,7 @@ vsp_remove(struct ofport_dpif *port) } static void -vsp_add(struct ofport_dpif *port, uint16_t realdev_ofp_port, int vid) +vsp_add(struct ofport_dpif *port, ofp_port_t realdev_ofp_port, int vid) { struct ofproto_dpif *ofproto = ofproto_dpif_cast(port->up.ofproto); @@ -6485,7 +6644,7 @@ vsp_add(struct ofport_dpif *port, uint16_t realdev_ofp_port, int vid) vsp = xmalloc(sizeof *vsp); hmap_insert(&ofproto->vlandev_map, &vsp->vlandev_node, - hash_int(port->up.ofp_port, 0)); + hash_int(ofp_to_u16(port->up.ofp_port), 0)); hmap_insert(&ofproto->realdev_vid_map, &vsp->realdev_vid_node, hash_realdev_vid(realdev_ofp_port, vid)); vsp->realdev_ofp_port = realdev_ofp_port; @@ -6498,20 +6657,20 @@ vsp_add(struct ofport_dpif *port, uint16_t realdev_ofp_port, int vid) } } -uint32_t -ofp_port_to_odp_port(const struct ofproto_dpif *ofproto, uint16_t ofp_port) +odp_port_t +ofp_port_to_odp_port(const struct ofproto_dpif *ofproto, ofp_port_t ofp_port) { const struct ofport_dpif *ofport = get_ofp_port(ofproto, ofp_port); - return ofport ? ofport->odp_port : OVSP_NONE; + return ofport ? ofport->odp_port : ODPP_NONE; } static struct ofport_dpif * -odp_port_to_ofport(const struct dpif_backer *backer, uint32_t odp_port) +odp_port_to_ofport(const struct dpif_backer *backer, odp_port_t odp_port) { struct ofport_dpif *port; HMAP_FOR_EACH_IN_BUCKET (port, odp_port_node, - hash_int(odp_port, 0), + hash_int(odp_to_u32(odp_port), 0), &backer->odp_to_ofport_map) { if (port->odp_port == odp_port) { return port; @@ -6521,8 +6680,8 @@ odp_port_to_ofport(const struct dpif_backer *backer, uint32_t odp_port) return NULL; } -static uint16_t -odp_port_to_ofp_port(const struct ofproto_dpif *ofproto, uint32_t odp_port) +static ofp_port_t +odp_port_to_ofp_port(const struct ofproto_dpif *ofproto, odp_port_t odp_port) { struct ofport_dpif *port;