X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=ofproto%2Fofproto-dpif.c;h=2f8d404b22919156ecdd219edffdc6746500e0f5;hb=d19cedb28fa32091d149749d326707d8405cbbb6;hp=3d9198464826b7c9d41af68f4683756fe49da2a9;hpb=154896e3b99978317d74b5c9847fe07ec01b54b3;p=openvswitch diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 3d919846..2f8d404b 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -43,6 +43,7 @@ #include "ofproto-sflow.h" #include "poll-loop.h" #include "timer.h" +#include "unaligned.h" #include "unixctl.h" #include "vlan-bitmap.h" #include "vlog.h" @@ -170,11 +171,6 @@ struct action_xlate_ctx { * calling action_xlate_ctx_init(). */ void (*resubmit_hook)(struct action_xlate_ctx *, struct rule_dpif *); - /* If true, the speciality of 'flow' should be checked before executing - * its actions. If special_cb returns false on 'flow' rendered - * uninstallable and no actions will be executed. */ - bool check_special; - /* xlate_actions() initializes and uses these members. The client might want * to look at them after it returns. */ @@ -270,6 +266,7 @@ static void facet_update_time(struct ofproto_dpif *, struct facet *, long long int used); static void facet_update_stats(struct ofproto_dpif *, struct facet *, const struct dpif_flow_stats *); +static void facet_reset_dp_stats(struct facet *, struct dpif_flow_stats *); static void facet_push_stats(struct facet *); static void facet_account(struct ofproto_dpif *, struct facet *, uint64_t extra_bytes); @@ -288,6 +285,7 @@ struct ofport_dpif { struct list bundle_node; /* In struct ofbundle's "ports" list. */ struct cfm *cfm; /* Connectivity Fault Management, if any. */ tag_type tag; /* Tag associated with this port. */ + uint32_t bond_stable_id; /* stable_id to use as bond slave, or 0. */ }; static struct ofport_dpif * @@ -299,14 +297,16 @@ ofport_dpif_cast(const struct ofport *ofport) static void port_run(struct ofport_dpif *); static void port_wait(struct ofport_dpif *); -static int set_cfm(struct ofport *, const struct cfm *, - const uint16_t *remote_mps, size_t n_remote_mps); +static int set_cfm(struct ofport *, const struct cfm_settings *); struct ofproto_dpif { struct ofproto up; struct dpif *dpif; int max_ports; + /* Statistics. */ + uint64_t n_matches; + /* Bridging. */ struct netflow *netflow; struct ofproto_sflow *sflow; @@ -351,8 +351,7 @@ static void handle_upcall(struct ofproto_dpif *, struct dpif_upcall *); static int expire(struct ofproto_dpif *); /* Utilities. */ -static int send_packet(struct ofproto_dpif *, - uint32_t odp_port, uint16_t vlan_tci, +static int send_packet(struct ofproto_dpif *, uint32_t odp_port, const struct ofpbuf *packet); /* Global variables. */ @@ -417,6 +416,7 @@ construct(struct ofproto *ofproto_) } ofproto->max_ports = dpif_get_max_ports(ofproto->dpif); + ofproto->n_matches = 0; error = dpif_recv_set_mask(ofproto->dpif, ((1u << DPIF_UC_MISS) | @@ -445,6 +445,10 @@ construct(struct ofproto *ofproto_) ofproto->need_revalidate = false; tag_set_init(&ofproto->revalidate_set); + ofproto->up.tables = xmalloc(sizeof *ofproto->up.tables); + classifier_init(&ofproto->up.tables[0]); + ofproto->up.n_tables = 1; + ofproto_dpif_unixctl_init(); return 0; @@ -586,6 +590,39 @@ flush(struct ofproto *ofproto_) dpif_flow_flush(ofproto->dpif); } +static void +get_features(struct ofproto *ofproto_ OVS_UNUSED, + bool *arp_match_ip, uint32_t *actions) +{ + *arp_match_ip = true; + *actions = ((1u << OFPAT_OUTPUT) | + (1u << OFPAT_SET_VLAN_VID) | + (1u << OFPAT_SET_VLAN_PCP) | + (1u << OFPAT_STRIP_VLAN) | + (1u << OFPAT_SET_DL_SRC) | + (1u << OFPAT_SET_DL_DST) | + (1u << OFPAT_SET_NW_SRC) | + (1u << OFPAT_SET_NW_DST) | + (1u << OFPAT_SET_NW_TOS) | + (1u << OFPAT_SET_TP_SRC) | + (1u << OFPAT_SET_TP_DST) | + (1u << OFPAT_ENQUEUE)); +} + +static void +get_tables(struct ofproto *ofproto_, struct ofp_table_stats *ots) +{ + struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); + struct odp_stats s; + + strcpy(ots->name, "classifier"); + + dpif_get_dp_stats(ofproto->dpif, &s); + put_32aligned_be64(&ots->lookup_count, htonll(s.n_hit + s.n_missed)); + put_32aligned_be64(&ots->matched_count, + htonll(s.n_hit + ofproto->n_matches)); +} + static int set_netflow(struct ofproto *ofproto_, const struct netflow_options *netflow_options) @@ -644,7 +681,7 @@ port_destruct(struct ofport *port_) struct ofproto_dpif *ofproto = ofproto_dpif_cast(port->up.ofproto); bundle_remove(port_); - set_cfm(port_, NULL, NULL, 0); + set_cfm(port_, NULL); if (ofproto->sflow) { ofproto_sflow_del_port(ofproto->sflow, port->odp_port); } @@ -698,26 +735,19 @@ set_sflow(struct ofproto *ofproto_, } static int -set_cfm(struct ofport *ofport_, const struct cfm *cfm, - const uint16_t *remote_mps, size_t n_remote_mps) +set_cfm(struct ofport *ofport_, const struct cfm_settings *s) { struct ofport_dpif *ofport = ofport_dpif_cast(ofport_); int error; - if (!cfm) { + if (!s) { error = 0; } else { if (!ofport->cfm) { - ofport->cfm = cfm_create(); + ofport->cfm = cfm_create(netdev_get_name(ofport->up.netdev)); } - ofport->cfm->mpid = cfm->mpid; - ofport->cfm->interval = cfm->interval; - memcpy(ofport->cfm->maid, cfm->maid, CCM_MAID_LEN); - - cfm_update_remote_mps(ofport->cfm, remote_mps, n_remote_mps); - - if (cfm_configure(ofport->cfm)) { + if (cfm_configure(ofport->cfm, s)) { return 0; } @@ -729,11 +759,11 @@ set_cfm(struct ofport *ofport_, const struct cfm *cfm, } static int -get_cfm(struct ofport *ofport_, const struct cfm **cfmp) +get_cfm_fault(const struct ofport *ofport_) { struct ofport_dpif *ofport = ofport_dpif_cast(ofport_); - *cfmp = ofport->cfm; - return 0; + + return ofport->cfm ? cfm_get_fault(ofport->cfm) : -1; } /* Bundles. */ @@ -792,6 +822,8 @@ bundle_del_port(struct ofport_dpif *port) { struct ofbundle *bundle = port->bundle; + bundle->ofproto->need_revalidate = true; + list_remove(&port->bundle_node); port->bundle = NULL; @@ -812,7 +844,8 @@ bundle_del_port(struct ofport_dpif *port) static bool bundle_add_port(struct ofbundle *bundle, uint32_t ofp_port, - struct lacp_slave_settings *lacp) + struct lacp_slave_settings *lacp, + uint32_t bond_stable_id) { struct ofport_dpif *port; @@ -822,6 +855,7 @@ bundle_add_port(struct ofbundle *bundle, uint32_t ofp_port, } if (port->bundle != bundle) { + bundle->ofproto->need_revalidate = true; if (port->bundle) { bundle_del_port(port); } @@ -836,6 +870,8 @@ bundle_add_port(struct ofbundle *bundle, uint32_t ofp_port, lacp_slave_register(bundle->lacp, port, lacp); } + port->bond_stable_id = bond_stable_id; + return true; } @@ -939,7 +975,8 @@ bundle_set(struct ofproto *ofproto_, void *aux, ok = true; for (i = 0; i < s->n_slaves; i++) { if (!bundle_add_port(bundle, s->slaves[i], - s->lacp ? &s->lacp_slaves[i] : NULL)) { + s->lacp ? &s->lacp_slaves[i] : NULL, + s->bond_stable_ids ? s->bond_stable_ids[i] : 0)) { ok = false; } } @@ -948,7 +985,7 @@ bundle_set(struct ofproto *ofproto_, void *aux, LIST_FOR_EACH_SAFE (port, next_port, bundle_node, &bundle->ports) { for (i = 0; i < s->n_slaves; i++) { - if (s->slaves[i] == odp_port_to_ofp_port(port->odp_port)) { + if (s->slaves[i] == port->up.ofp_port) { goto found; } } @@ -987,13 +1024,11 @@ bundle_set(struct ofproto *ofproto_, void *aux, } } else { bundle->bond = bond_create(s->bond); + ofproto->need_revalidate = true; } LIST_FOR_EACH (port, bundle_node, &bundle->ports) { - uint16_t stable_id = (bundle->lacp - ? lacp_slave_get_port_id(bundle->lacp, port) - : port->odp_port); - bond_slave_register(bundle->bond, port, stable_id, + bond_slave_register(bundle->bond, port, port->bond_stable_id, port->up.netdev); } } else { @@ -1099,7 +1134,11 @@ bundle_run(struct ofbundle *bundle) LIST_FOR_EACH (port, bundle_node, &bundle->ports) { bool may_enable = lacp_slave_may_enable(bundle->lacp, port); - bond_slave_set_lacp_may_enable(bundle->bond, port, may_enable); + + if (may_enable && port->cfm) { + may_enable = !cfm_get_fault(port->cfm); + } + bond_slave_set_may_enable(bundle->bond, port, may_enable); } bond_run(bundle->bond, &bundle->ofproto->revalidate_set, @@ -1314,7 +1353,8 @@ is_mirror_output_bundle(struct ofproto *ofproto_, void *aux) static struct ofport_dpif * get_ofp_port(struct ofproto_dpif *ofproto, uint16_t ofp_port) { - return ofport_dpif_cast(ofproto_get_port(&ofproto->up, ofp_port)); + struct ofport *ofport = ofproto_get_port(&ofproto->up, ofp_port); + return ofport ? ofport_dpif_cast(ofport) : NULL; } static struct ofport_dpif * @@ -1340,14 +1380,11 @@ port_run(struct ofport_dpif *ofport) if (cfm_should_send_ccm(ofport->cfm)) { struct ofpbuf packet; - struct ccm *ccm; ofpbuf_init(&packet, 0); - ccm = eth_compose(&packet, eth_addr_ccm, ofport->up.opp.hw_addr, - ETH_TYPE_CFM, sizeof *ccm); - cfm_compose_ccm(ofport->cfm, ccm); + cfm_compose_ccm(ofport->cfm, &packet, ofport->up.opp.hw_addr); send_packet(ofproto_dpif_cast(ofport->up.ofproto), - ofport->odp_port, 0, &packet); + ofport->odp_port, &packet); ofpbuf_uninit(&packet); } } @@ -1508,19 +1545,19 @@ process_special(struct ofproto_dpif *ofproto, const struct flow *flow, { if (cfm_should_process_flow(flow)) { struct ofport_dpif *ofport = get_ofp_port(ofproto, flow->in_port); - if (ofport && ofport->cfm) { + if (packet && ofport && ofport->cfm) { cfm_process_heartbeat(ofport->cfm, packet); } return true; } else if (flow->dl_type == htons(ETH_TYPE_LACP)) { struct ofport_dpif *port = get_ofp_port(ofproto, flow->in_port); - if (port && port->bundle && port->bundle->lacp) { + if (packet && port && port->bundle && port->bundle->lacp) { const struct lacp_pdu *pdu = parse_lacp_packet(packet); if (pdu) { lacp_process_pdu(port->bundle->lacp, port, pdu); } - return true; } + return true; } return false; } @@ -1540,13 +1577,14 @@ handle_miss_upcall(struct ofproto_dpif *ofproto, struct dpif_upcall *upcall) /* Handle 802.1ag and LACP. */ if (process_special(ofproto, &flow, upcall->packet)) { ofpbuf_delete(upcall->packet); + ofproto->n_matches++; return; } /* Check with in-band control to see if this packet should be sent * to the local port regardless of the flow table. */ if (connmgr_msg_in_hook(ofproto->up.connmgr, &flow, upcall->packet)) { - send_packet(ofproto, OFPP_LOCAL, 0, upcall->packet); + send_packet(ofproto, ODPP_LOCAL, upcall->packet); } facet = facet_lookup_valid(ofproto, &flow); @@ -1594,6 +1632,7 @@ handle_miss_upcall(struct ofproto_dpif *ofproto, struct dpif_upcall *upcall) facet_execute(ofproto, facet, upcall->packet); facet_install(ofproto, facet, false); + ofproto->n_matches++; } static void @@ -1655,7 +1694,7 @@ expire(struct ofproto_dpif *ofproto) expire_facets(ofproto, dp_max_idle); /* Expire OpenFlow flows whose idle_timeout or hard_timeout has passed. */ - cls_cursor_init(&cursor, &ofproto->up.cls, NULL); + cls_cursor_init(&cursor, &ofproto->up.tables[0], NULL); CLS_CURSOR_FOR_EACH_SAFE (rule, next_rule, up.cr, &cursor) { rule_expire(rule); } @@ -2046,6 +2085,12 @@ facet_make_actions(struct ofproto_dpif *p, struct facet *facet, ofpbuf_delete(odp_actions); } +/* Updates 'facet''s flow in the datapath setting its actions to 'actions_len' + * bytes of actions in 'actions'. If 'stats' is non-null, statistics counters + * in the datapath will be zeroed and 'stats' will be updated with traffic new + * since 'facet' was last updated. + * + * Returns 0 if successful, otherwise a positive errno value.*/ static int facet_put__(struct ofproto_dpif *ofproto, struct facet *facet, const struct nlattr *actions, size_t actions_len, @@ -2054,19 +2099,24 @@ facet_put__(struct ofproto_dpif *ofproto, struct facet *facet, struct odputil_keybuf keybuf; enum dpif_flow_put_flags flags; struct ofpbuf key; + int ret; flags = DPIF_FP_CREATE | DPIF_FP_MODIFY; if (stats) { flags |= DPIF_FP_ZERO_STATS; - facet->dp_packet_count = 0; - facet->dp_byte_count = 0; } ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); odp_flow_key_from_flow(&key, &facet->flow); - return dpif_flow_put(ofproto->dpif, flags, key.data, key.size, - actions, actions_len, stats); + ret = dpif_flow_put(ofproto->dpif, flags, key.data, key.size, + actions, actions_len, stats); + + if (stats) { + facet_reset_dp_stats(facet, stats); + } + + return ret; } /* If 'facet' is installable, inserts or re-inserts it into 'p''s datapath. If @@ -2084,6 +2134,12 @@ facet_install(struct ofproto_dpif *p, struct facet *facet, bool zero_stats) } } +static int +vlan_tci_to_openflow_vlan(ovs_be16 vlan_tci) +{ + return vlan_tci != htons(0) ? vlan_tci_to_vid(vlan_tci) : OFP_VLAN_NONE; +} + static void facet_account(struct ofproto_dpif *ofproto, struct facet *facet, uint64_t extra_bytes) @@ -2093,6 +2149,7 @@ facet_account(struct ofproto_dpif *ofproto, const struct nlattr *a; tag_type dummy = 0; unsigned int left; + ovs_be16 vlan_tci; int vlan; total_bytes = facet->byte_count + extra_bytes; @@ -2120,14 +2177,32 @@ facet_account(struct ofproto_dpif *ofproto, if (!ofproto->has_bonded_bundles) { return; } + + /* This loop feeds byte counters to bond_account() for rebalancing to use + * as a basis. We also need to track the actual VLAN on which the packet + * is going to be sent to ensure that it matches the one passed to + * bond_choose_output_slave(). (Otherwise, we will account to the wrong + * hash bucket.) */ + vlan_tci = facet->flow.vlan_tci; NL_ATTR_FOR_EACH_UNSAFE (a, left, facet->actions, facet->actions_len) { - if (nl_attr_type(a) == ODP_ACTION_ATTR_OUTPUT) { - struct ofport_dpif *port; + struct ofport_dpif *port; + switch (nl_attr_type(a)) { + case ODP_ACTION_ATTR_OUTPUT: port = get_odp_port(ofproto, nl_attr_get_u32(a)); if (port && port->bundle && port->bundle->bond) { - bond_account(port->bundle->bond, &facet->flow, vlan, n_bytes); + bond_account(port->bundle->bond, &facet->flow, + vlan_tci_to_openflow_vlan(vlan_tci), n_bytes); } + break; + + case ODP_ACTION_ATTR_STRIP_VLAN: + vlan_tci = htons(0); + break; + + case ODP_ACTION_ATTR_SET_DL_TCI: + vlan_tci = nl_attr_get_be16(a); + break; } } } @@ -2140,16 +2215,17 @@ facet_uninstall(struct ofproto_dpif *p, struct facet *facet) struct odputil_keybuf keybuf; struct dpif_flow_stats stats; struct ofpbuf key; + int error; ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); odp_flow_key_from_flow(&key, &facet->flow); - if (!dpif_flow_del(p->dpif, key.data, key.size, &stats)) { + error = dpif_flow_del(p->dpif, key.data, key.size, &stats); + facet_reset_dp_stats(facet, &stats); + if (!error) { facet_update_stats(p, facet, &stats); } facet->installed = false; - facet->dp_packet_count = 0; - facet->dp_byte_count = 0; } else { assert(facet->dp_packet_count == 0); assert(facet->dp_byte_count == 0); @@ -2168,6 +2244,24 @@ facet_is_controller_flow(struct facet *facet) htons(OFPP_CONTROLLER))); } +/* Resets 'facet''s datapath statistics counters. This should be called when + * 'facet''s statistics are cleared in the datapath. If 'stats' is non-null, + * it should contain the statistics returned by dpif when 'facet' was reset in + * the datapath. 'stats' will be modified to only included statistics new + * since 'facet' was last updated. */ +static void +facet_reset_dp_stats(struct facet *facet, struct dpif_flow_stats *stats) +{ + if (stats && facet->dp_packet_count <= stats->n_packets + && facet->dp_byte_count <= stats->n_bytes) { + stats->n_packets -= facet->dp_packet_count; + stats->n_bytes -= facet->dp_byte_count; + } + + facet->dp_packet_count = 0; + facet->dp_byte_count = 0; +} + /* Folds all of 'facet''s statistics into its rule. Also updates the * accounting ofhook and emits a NetFlow expiration if appropriate. All of * 'facet''s statistics in the datapath should have been zeroed and folded into @@ -2428,7 +2522,8 @@ static struct rule_dpif * rule_dpif_lookup(struct ofproto_dpif *ofproto, const struct flow *flow) { return rule_dpif_cast(rule_from_cls_rule( - classifier_lookup(&ofproto->up.cls, flow))); + classifier_lookup(&ofproto->up.tables[0], + flow))); } static struct rule * @@ -2460,7 +2555,7 @@ rule_construct(struct rule *rule_) } old_rule = rule_dpif_cast(rule_from_cls_rule(classifier_find_rule_exactly( - &ofproto->up.cls, + &ofproto->up.tables[0], &rule->up.cr))); if (old_rule) { ofproto_rule_destroy(&old_rule->up); @@ -2470,7 +2565,7 @@ rule_construct(struct rule *rule_) rule->packet_count = 0; rule->byte_count = 0; list_init(&rule->facets); - classifier_insert(&ofproto->up.cls, &rule->up.cr); + classifier_insert(&ofproto->up.tables[0], &rule->up.cr); ofproto->need_revalidate = true; @@ -2484,7 +2579,7 @@ rule_destruct(struct rule *rule_) struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto); struct facet *facet, *next_facet; - classifier_remove(&ofproto->up.cls, &rule->up.cr); + classifier_remove(&ofproto->up.tables[0], &rule->up.cr); LIST_FOR_EACH_SAFE (facet, next_facet, list_node, &rule->facets) { facet_revalidate(ofproto, facet); } @@ -2570,23 +2665,16 @@ rule_modify_actions(struct rule *rule_, return error; } -/* Sends 'packet' out of port 'odp_port' within 'ofproto'. If 'vlan_tci' is - * zero the packet will not have any 802.1Q hader; if it is nonzero, then the - * packet will be sent with the VLAN TCI specified by 'vlan_tci & ~VLAN_CFI'. - * +/* Sends 'packet' out of port 'odp_port' within 'p'. * Returns 0 if successful, otherwise a positive errno value. */ static int -send_packet(struct ofproto_dpif *ofproto, uint32_t odp_port, uint16_t vlan_tci, +send_packet(struct ofproto_dpif *ofproto, uint32_t odp_port, const struct ofpbuf *packet) { struct ofpbuf odp_actions; int error; ofpbuf_init(&odp_actions, 32); - if (vlan_tci != 0) { - nl_msg_put_u32(&odp_actions, ODP_ACTION_ATTR_SET_DL_TCI, - ntohs(vlan_tci & ~VLAN_CFI)); - } nl_msg_put_u32(&odp_actions, ODP_ACTION_ATTR_OUTPUT, odp_port); error = dpif_execute(ofproto->dpif, odp_actions.data, odp_actions.size, packet); @@ -3069,7 +3157,6 @@ action_xlate_ctx_init(struct action_xlate_ctx *ctx, ctx->flow = *flow; ctx->packet = packet; ctx->resubmit_hook = NULL; - ctx->check_special = true; } static struct ofpbuf * @@ -3085,8 +3172,7 @@ xlate_actions(struct action_xlate_ctx *ctx, ctx->recurse = 0; ctx->last_pop_priority = -1; - if (ctx->check_special - && process_special(ctx->ofproto, &ctx->flow, ctx->packet)) { + if (process_special(ctx->ofproto, &ctx->flow, ctx->packet)) { ctx->may_set_up_flow = false; } else { do_xlate_actions(in, n_in, ctx); @@ -3485,7 +3571,7 @@ is_admissible(struct ofproto_dpif *ofproto, const struct flow *flow, /* Find the port and bundle for the received packet. */ in_port = get_ofp_port(ofproto, flow->in_port); - *in_bundlep = in_bundle = in_port->bundle; + *in_bundlep = in_bundle = in_port ? in_port->bundle : NULL; if (!in_port || !in_bundle) { /* No interface? Something fishy... */ if (have_packet) { @@ -3854,6 +3940,8 @@ const struct ofproto_class ofproto_dpif_class = { run, wait, flush, + get_features, + get_tables, port_alloc, port_construct, port_destruct, @@ -3869,6 +3957,7 @@ const struct ofproto_class ofproto_dpif_class = { port_poll, port_poll_wait, port_is_lacp_current, + NULL, /* rule_choose_table */ rule_alloc, rule_construct, rule_destruct, @@ -3883,7 +3972,7 @@ const struct ofproto_class ofproto_dpif_class = { get_netflow_ids, set_sflow, set_cfm, - get_cfm, + get_cfm_fault, bundle_set, bundle_remove, mirror_set,