X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;ds=sidebyside;f=ofproto%2Fofproto-dpif.c;h=d3cb92b91a0ef89b7901223fb6662dd6e8f8cae5;hb=d78be13bc9767d38affb8816a5f4cd80a0bca5d8;hp=53d7ca4364d2b97ec4024fab9df8704c538fe300;hpb=abe529af477b8311a1fd68c130374bd7442003c3;p=openvswitch diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 53d7ca43..d3cb92b9 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. */ @@ -288,6 +284,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 * @@ -307,6 +304,9 @@ struct ofproto_dpif { 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) @@ -792,6 +829,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 +851,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 +862,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 +877,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 +982,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 +992,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 +1031,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 { @@ -1314,7 +1356,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 * @@ -1347,7 +1390,7 @@ port_run(struct ofport_dpif *ofport) ETH_TYPE_CFM, sizeof *ccm); cfm_compose_ccm(ofport->cfm, ccm); send_packet(ofproto_dpif_cast(ofport->up.ofproto), - ofport->odp_port, 0, &packet); + ofport->odp_port, &packet); ofpbuf_uninit(&packet); } } @@ -1498,7 +1541,7 @@ send_packet_in(struct ofproto_dpif *ofproto, struct dpif_upcall *upcall, pin.reason = upcall->type == DPIF_UC_MISS ? OFPR_NO_MATCH : OFPR_ACTION; pin.buffer_id = 0; /* not yet known */ pin.send_len = upcall->userdata; - connmgr_send_packet_in(ofproto->up.connmgr, upcall, flow, + connmgr_send_packet_in(ofproto->up.connmgr, &pin, flow, clone ? NULL : upcall->packet); } @@ -1540,13 +1583,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 +1638,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 +1700,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); } @@ -2084,6 +2129,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 +2144,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 +2172,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; } } } @@ -2427,7 +2497,9 @@ flow_push_stats(const struct rule_dpif *rule, static struct rule_dpif * rule_dpif_lookup(struct ofproto_dpif *ofproto, const struct flow *flow) { - return rule_dpif_cast(ofproto_rule_lookup(&ofproto->up, flow)); + return rule_dpif_cast(rule_from_cls_rule( + classifier_lookup(&ofproto->up.tables[0], + flow))); } static struct rule * @@ -2449,17 +2521,28 @@ rule_construct(struct rule *rule_) { struct rule_dpif *rule = rule_dpif_cast(rule_); struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto); - struct cls_rule *displaced_rule; + struct rule_dpif *old_rule; + int error; + + error = validate_actions(rule->up.actions, rule->up.n_actions, + &rule->up.cr.flow, ofproto->max_ports); + if (error) { + return error; + } + + old_rule = rule_dpif_cast(rule_from_cls_rule(classifier_find_rule_exactly( + &ofproto->up.tables[0], + &rule->up.cr))); + if (old_rule) { + ofproto_rule_destroy(&old_rule->up); + } rule->used = rule->up.created; rule->packet_count = 0; rule->byte_count = 0; list_init(&rule->facets); + classifier_insert(&ofproto->up.tables[0], &rule->up.cr); - displaced_rule = classifier_insert(&ofproto->up.cls, &rule->up.cr); - if (displaced_rule) { - ofproto_rule_destroy(rule_from_cls_rule(displaced_rule)); - } ofproto->need_revalidate = true; return 0; @@ -2472,20 +2555,11 @@ rule_destruct(struct rule *rule_) struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto); struct facet *facet, *next_facet; - ofproto->need_revalidate = true; + classifier_remove(&ofproto->up.tables[0], &rule->up.cr); LIST_FOR_EACH_SAFE (facet, next_facet, list_node, &rule->facets) { facet_revalidate(ofproto, facet); } -} - -static void -rule_remove(struct rule *rule_) -{ - struct rule_dpif *rule = rule_dpif_cast(rule_); - struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto); - ofproto->need_revalidate = true; - classifier_remove(&ofproto->up.cls, &rule->up.cr); } static void @@ -2508,7 +2582,7 @@ rule_get_stats(struct rule *rule_, uint64_t *packets, uint64_t *bytes) } } -static void +static int rule_execute(struct rule *rule_, struct flow *flow, struct ofpbuf *packet) { struct rule_dpif *rule = rule_dpif_cast(rule_); @@ -2522,7 +2596,7 @@ rule_execute(struct rule *rule_, struct flow *flow, struct ofpbuf *packet) facet = facet_lookup_valid(ofproto, flow); if (facet && facet->rule == rule) { facet_execute(ofproto, facet, packet); - return; + return 0; } /* Otherwise, if 'rule' is in fact the correct rule for 'packet', then @@ -2531,7 +2605,7 @@ rule_execute(struct rule *rule_, struct flow *flow, struct ofpbuf *packet) facet = facet_create(rule, flow, packet); facet_execute(ofproto, facet, packet); facet_install(ofproto, facet, true); - return; + return 0; } /* We can't account anything to a facet. If we were to try, then that @@ -2547,6 +2621,8 @@ rule_execute(struct rule *rule_, struct flow *flow, struct ofpbuf *packet) flow_push_stats(rule, flow, 1, size, rule->used); } ofpbuf_delete(odp_actions); + + return 0; } static int @@ -2565,23 +2641,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); @@ -3064,7 +3133,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 * @@ -3080,8 +3148,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); @@ -3480,7 +3547,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) { @@ -3849,6 +3916,8 @@ const struct ofproto_class ofproto_dpif_class = { run, wait, flush, + get_features, + get_tables, port_alloc, port_construct, port_destruct, @@ -3868,7 +3937,6 @@ const struct ofproto_class ofproto_dpif_class = { rule_construct, rule_destruct, rule_dealloc, - rule_remove, rule_get_stats, rule_execute, rule_modify_actions,